@ -0,0 +1,17 @@
|
||||
[run] |
||||
init_cmds = [["./gogs", "web"]] |
||||
watch_all = true |
||||
watch_dirs = [ |
||||
"$WORKDIR/conf/locale", |
||||
"$WORKDIR/cmd", |
||||
"$WORKDIR/models", |
||||
"$WORKDIR/modules", |
||||
"$WORKDIR/routers" |
||||
] |
||||
watch_exts = [".go", ".ini"] |
||||
build_delay = 1500 |
||||
cmds = [ |
||||
["go", "install"], |
||||
["go", "build"], |
||||
["./gogs", "web"] |
||||
] |
@ -1,23 +0,0 @@
|
||||
{ |
||||
"version": 0, |
||||
"gopm": { |
||||
"enable": false, |
||||
"install": false |
||||
}, |
||||
"go_install": true, |
||||
"watch_ext": [], |
||||
"dir_structure": { |
||||
"watch_all": true, |
||||
"controllers": "routers", |
||||
"models": "", |
||||
"others": [ |
||||
"modules", |
||||
"$GOPATH/src/github.com/gogits/logs", |
||||
"$GOPATH/src/github.com/gogits/git" |
||||
] |
||||
}, |
||||
"cmd_args": [ |
||||
"web" |
||||
], |
||||
"envs": [] |
||||
} |
@ -1,9 +0,0 @@
|
||||
## NOTICE |
||||
|
||||
This directory only used for development, and us [go-bindata](https://github.com/jteeuwen/go-bindata) to store in memory for releases. |
||||
|
||||
To apply any change in this directory, install [go-bindata](https://github.com/jteeuwen/go-bindata), and then execute following command in root of source directory: |
||||
|
||||
``` |
||||
$ go-bindata -ignore="\\.DS_Store|README.md" -o modules/bin/conf.go -pkg="bin" conf/... |
||||
``` |
@ -0,0 +1,23 @@
|
||||
Copyright (c) 2014 |
||||
All rights reserved. |
||||
|
||||
Redistribution and use in source and binary forms, with or without |
||||
modification, are permitted provided that the following conditions are met: |
||||
|
||||
* Redistributions of source code must retain the above copyright notice, this |
||||
list of conditions and the following disclaimer. |
||||
|
||||
* Redistributions in binary form must reproduce the above copyright notice, |
||||
this list of conditions and the following disclaimer in the documentation |
||||
and/or other materials provided with the distribution. |
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE |
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
||||
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
@ -0,0 +1,116 @@
|
||||
CC0 1.0 Universal |
||||
|
||||
Statement of Purpose |
||||
|
||||
The laws of most jurisdictions throughout the world automatically confer |
||||
exclusive Copyright and Related Rights (defined below) upon the creator and |
||||
subsequent owner(s) (each and all, an "owner") of an original work of |
||||
authorship and/or a database (each, a "Work"). |
||||
|
||||
Certain owners wish to permanently relinquish those rights to a Work for the |
||||
purpose of contributing to a commons of creative, cultural and scientific |
||||
works ("Commons") that the public can reliably and without fear of later |
||||
claims of infringement build upon, modify, incorporate in other works, reuse |
||||
and redistribute as freely as possible in any form whatsoever and for any |
||||
purposes, including without limitation commercial purposes. These owners may |
||||
contribute to the Commons to promote the ideal of a free culture and the |
||||
further production of creative, cultural and scientific works, or to gain |
||||
reputation or greater distribution for their Work in part through the use and |
||||
efforts of others. |
||||
|
||||
For these and/or other purposes and motivations, and without any expectation |
||||
of additional consideration or compensation, the person associating CC0 with a |
||||
Work (the "Affirmer"), to the extent that he or she is an owner of Copyright |
||||
and Related Rights in the Work, voluntarily elects to apply CC0 to the Work |
||||
and publicly distribute the Work under its terms, with knowledge of his or her |
||||
Copyright and Related Rights in the Work and the meaning and intended legal |
||||
effect of CC0 on those rights. |
||||
|
||||
1. Copyright and Related Rights. A Work made available under CC0 may be |
||||
protected by copyright and related or neighboring rights ("Copyright and |
||||
Related Rights"). Copyright and Related Rights include, but are not limited |
||||
to, the following: |
||||
|
||||
i. the right to reproduce, adapt, distribute, perform, display, communicate, |
||||
and translate a Work; |
||||
|
||||
ii. moral rights retained by the original author(s) and/or performer(s); |
||||
|
||||
iii. publicity and privacy rights pertaining to a person's image or likeness |
||||
depicted in a Work; |
||||
|
||||
iv. rights protecting against unfair competition in regards to a Work, |
||||
subject to the limitations in paragraph 4(a), below; |
||||
|
||||
v. rights protecting the extraction, dissemination, use and reuse of data in |
||||
a Work; |
||||
|
||||
vi. database rights (such as those arising under Directive 96/9/EC of the |
||||
European Parliament and of the Council of 11 March 1996 on the legal |
||||
protection of databases, and under any national implementation thereof, |
||||
including any amended or successor version of such directive); and |
||||
|
||||
vii. other similar, equivalent or corresponding rights throughout the world |
||||
based on applicable law or treaty, and any national implementations thereof. |
||||
|
||||
2. Waiver. To the greatest extent permitted by, but not in contravention of, |
||||
applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and |
||||
unconditionally waives, abandons, and surrenders all of Affirmer's Copyright |
||||
and Related Rights and associated claims and causes of action, whether now |
||||
known or unknown (including existing as well as future claims and causes of |
||||
action), in the Work (i) in all territories worldwide, (ii) for the maximum |
||||
duration provided by applicable law or treaty (including future time |
||||
extensions), (iii) in any current or future medium and for any number of |
||||
copies, and (iv) for any purpose whatsoever, including without limitation |
||||
commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes |
||||
the Waiver for the benefit of each member of the public at large and to the |
||||
detriment of Affirmer's heirs and successors, fully intending that such Waiver |
||||
shall not be subject to revocation, rescission, cancellation, termination, or |
||||
any other legal or equitable action to disrupt the quiet enjoyment of the Work |
||||
by the public as contemplated by Affirmer's express Statement of Purpose. |
||||
|
||||
3. Public License Fallback. Should any part of the Waiver for any reason be |
||||
judged legally invalid or ineffective under applicable law, then the Waiver |
||||
shall be preserved to the maximum extent permitted taking into account |
||||
Affirmer's express Statement of Purpose. In addition, to the extent the Waiver |
||||
is so judged Affirmer hereby grants to each affected person a royalty-free, |
||||
non transferable, non sublicensable, non exclusive, irrevocable and |
||||
unconditional license to exercise Affirmer's Copyright and Related Rights in |
||||
the Work (i) in all territories worldwide, (ii) for the maximum duration |
||||
provided by applicable law or treaty (including future time extensions), (iii) |
||||
in any current or future medium and for any number of copies, and (iv) for any |
||||
purpose whatsoever, including without limitation commercial, advertising or |
||||
promotional purposes (the "License"). The License shall be deemed effective as |
||||
of the date CC0 was applied by Affirmer to the Work. Should any part of the |
||||
License for any reason be judged legally invalid or ineffective under |
||||
applicable law, such partial invalidity or ineffectiveness shall not |
||||
invalidate the remainder of the License, and in such case Affirmer hereby |
||||
affirms that he or she will not (i) exercise any of his or her remaining |
||||
Copyright and Related Rights in the Work or (ii) assert any associated claims |
||||
and causes of action with respect to the Work, in either case contrary to |
||||
Affirmer's express Statement of Purpose. |
||||
|
||||
4. Limitations and Disclaimers. |
||||
|
||||
a. No trademark or patent rights held by Affirmer are waived, abandoned, |
||||
surrendered, licensed or otherwise affected by this document. |
||||
|
||||
b. Affirmer offers the Work as-is and makes no representations or warranties |
||||
of any kind concerning the Work, express, implied, statutory or otherwise, |
||||
including without limitation warranties of title, merchantability, fitness |
||||
for a particular purpose, non infringement, or the absence of latent or |
||||
other defects, accuracy, or the present or absence of errors, whether or not |
||||
discoverable, all to the greatest extent permissible under applicable law. |
||||
|
||||
c. Affirmer disclaims responsibility for clearing rights of other persons |
||||
that may apply to the Work or any use thereof, including without limitation |
||||
any person's Copyright and Related Rights in the Work. Further, Affirmer |
||||
disclaims responsibility for obtaining any necessary consents, permissions |
||||
or other rights required for any use of the Work. |
||||
|
||||
d. Affirmer understands and acknowledges that Creative Commons is not a |
||||
party to this document and has no duty or obligation with respect to this |
||||
CC0 or use of the Work. |
||||
|
||||
For more information, please see |
||||
<http://creativecommons.org/publicdomain/zero/1.0/> |
@ -0,0 +1,203 @@
|
||||
Eclipse Public License - v 1.0 |
||||
|
||||
THE ACCOMPANYING PROGRAM IS PROVIDED UNDER THE TERMS OF THIS ECLIPSE PUBLIC |
||||
LICENSE ("AGREEMENT"). ANY USE, REPRODUCTION OR DISTRIBUTION OF THE PROGRAM |
||||
CONSTITUTES RECIPIENT'S ACCEPTANCE OF THIS AGREEMENT. |
||||
|
||||
1. DEFINITIONS |
||||
|
||||
"Contribution" means: |
||||
|
||||
a) in the case of the initial Contributor, the initial code and documentation |
||||
distributed under this Agreement, and |
||||
b) in the case of each subsequent Contributor: |
||||
i) changes to the Program, and |
||||
ii) additions to the Program; |
||||
|
||||
where such changes and/or additions to the Program originate from and are |
||||
distributed by that particular Contributor. A Contribution 'originates' |
||||
from a Contributor if it was added to the Program by such Contributor |
||||
itself or anyone acting on such Contributor's behalf. Contributions do not |
||||
include additions to the Program which: (i) are separate modules of |
||||
software distributed in conjunction with the Program under their own |
||||
license agreement, and (ii) are not derivative works of the Program. |
||||
|
||||
"Contributor" means any person or entity that distributes the Program. |
||||
|
||||
"Licensed Patents" mean patent claims licensable by a Contributor which are |
||||
necessarily infringed by the use or sale of its Contribution alone or when |
||||
combined with the Program. |
||||
|
||||
"Program" means the Contributions distributed in accordance with this |
||||
Agreement. |
||||
|
||||
"Recipient" means anyone who receives the Program under this Agreement, |
||||
including all Contributors. |
||||
|
||||
2. GRANT OF RIGHTS |
||||
a) Subject to the terms of this Agreement, each Contributor hereby grants |
||||
Recipient a non-exclusive, worldwide, royalty-free copyright license to |
||||
reproduce, prepare derivative works of, publicly display, publicly |
||||
perform, distribute and sublicense the Contribution of such Contributor, |
||||
if any, and such derivative works, in source code and object code form. |
||||
b) Subject to the terms of this Agreement, each Contributor hereby grants |
||||
Recipient a non-exclusive, worldwide, royalty-free patent license under |
||||
Licensed Patents to make, use, sell, offer to sell, import and otherwise |
||||
transfer the Contribution of such Contributor, if any, in source code and |
||||
object code form. This patent license shall apply to the combination of |
||||
the Contribution and the Program if, at the time the Contribution is |
||||
added by the Contributor, such addition of the Contribution causes such |
||||
combination to be covered by the Licensed Patents. The patent license |
||||
shall not apply to any other combinations which include the Contribution. |
||||
No hardware per se is licensed hereunder. |
||||
c) Recipient understands that although each Contributor grants the licenses |
||||
to its Contributions set forth herein, no assurances are provided by any |
||||
Contributor that the Program does not infringe the patent or other |
||||
intellectual property rights of any other entity. Each Contributor |
||||
disclaims any liability to Recipient for claims brought by any other |
||||
entity based on infringement of intellectual property rights or |
||||
otherwise. As a condition to exercising the rights and licenses granted |
||||
hereunder, each Recipient hereby assumes sole responsibility to secure |
||||
any other intellectual property rights needed, if any. For example, if a |
||||
third party patent license is required to allow Recipient to distribute |
||||
the Program, it is Recipient's responsibility to acquire that license |
||||
before distributing the Program. |
||||
d) Each Contributor represents that to its knowledge it has sufficient |
||||
copyright rights in its Contribution, if any, to grant the copyright |
||||
license set forth in this Agreement. |
||||
|
||||
3. REQUIREMENTS |
||||
|
||||
A Contributor may choose to distribute the Program in object code form under |
||||
its own license agreement, provided that: |
||||
|
||||
a) it complies with the terms and conditions of this Agreement; and |
||||
b) its license agreement: |
||||
i) effectively disclaims on behalf of all Contributors all warranties |
||||
and conditions, express and implied, including warranties or |
||||
conditions of title and non-infringement, and implied warranties or |
||||
conditions of merchantability and fitness for a particular purpose; |
||||
ii) effectively excludes on behalf of all Contributors all liability for |
||||
damages, including direct, indirect, special, incidental and |
||||
consequential damages, such as lost profits; |
||||
iii) states that any provisions which differ from this Agreement are |
||||
offered by that Contributor alone and not by any other party; and |
||||
iv) states that source code for the Program is available from such |
||||
Contributor, and informs licensees how to obtain it in a reasonable |
||||
manner on or through a medium customarily used for software exchange. |
||||
|
||||
When the Program is made available in source code form: |
||||
|
||||
a) it must be made available under this Agreement; and |
||||
b) a copy of this Agreement must be included with each copy of the Program. |
||||
Contributors may not remove or alter any copyright notices contained |
||||
within the Program. |
||||
|
||||
Each Contributor must identify itself as the originator of its Contribution, |
||||
if |
||||
any, in a manner that reasonably allows subsequent Recipients to identify the |
||||
originator of the Contribution. |
||||
|
||||
4. COMMERCIAL DISTRIBUTION |
||||
|
||||
Commercial distributors of software may accept certain responsibilities with |
||||
respect to end users, business partners and the like. While this license is |
||||
intended to facilitate the commercial use of the Program, the Contributor who |
||||
includes the Program in a commercial product offering should do so in a manner |
||||
which does not create potential liability for other Contributors. Therefore, |
||||
if a Contributor includes the Program in a commercial product offering, such |
||||
Contributor ("Commercial Contributor") hereby agrees to defend and indemnify |
||||
every other Contributor ("Indemnified Contributor") against any losses, |
||||
damages and costs (collectively "Losses") arising from claims, lawsuits and |
||||
other legal actions brought by a third party against the Indemnified |
||||
Contributor to the extent caused by the acts or omissions of such Commercial |
||||
Contributor in connection with its distribution of the Program in a commercial |
||||
product offering. The obligations in this section do not apply to any claims |
||||
or Losses relating to any actual or alleged intellectual property |
||||
infringement. In order to qualify, an Indemnified Contributor must: |
||||
a) promptly notify the Commercial Contributor in writing of such claim, and |
||||
b) allow the Commercial Contributor to control, and cooperate with the |
||||
Commercial Contributor in, the defense and any related settlement |
||||
negotiations. The Indemnified Contributor may participate in any such claim at |
||||
its own expense. |
||||
|
||||
For example, a Contributor might include the Program in a commercial product |
||||
offering, Product X. That Contributor is then a Commercial Contributor. If |
||||
that Commercial Contributor then makes performance claims, or offers |
||||
warranties related to Product X, those performance claims and warranties are |
||||
such Commercial Contributor's responsibility alone. Under this section, the |
||||
Commercial Contributor would have to defend claims against the other |
||||
Contributors related to those performance claims and warranties, and if a |
||||
court requires any other Contributor to pay any damages as a result, the |
||||
Commercial Contributor must pay those damages. |
||||
|
||||
5. NO WARRANTY |
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, THE PROGRAM IS PROVIDED ON AN |
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR |
||||
IMPLIED INCLUDING, WITHOUT LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, |
||||
NON-INFRINGEMENT, MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each |
||||
Recipient is solely responsible for determining the appropriateness of using |
||||
and distributing the Program and assumes all risks associated with its |
||||
exercise of rights under this Agreement , including but not limited to the |
||||
risks and costs of program errors, compliance with applicable laws, damage to |
||||
or loss of data, programs or equipment, and unavailability or interruption of |
||||
operations. |
||||
|
||||
6. DISCLAIMER OF LIABILITY |
||||
|
||||
EXCEPT AS EXPRESSLY SET FORTH IN THIS AGREEMENT, NEITHER RECIPIENT NOR ANY |
||||
CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING WITHOUT LIMITATION |
||||
LOST PROFITS), HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
||||
ARISING IN ANY WAY OUT OF THE USE OR DISTRIBUTION OF THE PROGRAM OR THE |
||||
EXERCISE OF ANY RIGHTS GRANTED HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY |
||||
OF SUCH DAMAGES. |
||||
|
||||
7. GENERAL |
||||
|
||||
If any provision of this Agreement is invalid or unenforceable under |
||||
applicable law, it shall not affect the validity or enforceability of the |
||||
remainder of the terms of this Agreement, and without further action by the |
||||
parties hereto, such provision shall be reformed to the minimum extent |
||||
necessary to make such provision valid and enforceable. |
||||
|
||||
If Recipient institutes patent litigation against any entity (including a |
||||
cross-claim or counterclaim in a lawsuit) alleging that the Program itself |
||||
(excluding combinations of the Program with other software or hardware) |
||||
infringes such Recipient's patent(s), then such Recipient's rights granted |
||||
under Section 2(b) shall terminate as of the date such litigation is filed. |
||||
|
||||
All Recipient's rights under this Agreement shall terminate if it fails to |
||||
comply with any of the material terms or conditions of this Agreement and does |
||||
not cure such failure in a reasonable period of time after becoming aware of |
||||
such noncompliance. If all Recipient's rights under this Agreement terminate, |
||||
Recipient agrees to cease use and distribution of the Program as soon as |
||||
reasonably practicable. However, Recipient's obligations under this Agreement |
||||
and any licenses granted by Recipient relating to the Program shall continue |
||||
and survive. |
||||
|
||||
Everyone is permitted to copy and distribute copies of this Agreement, but in |
||||
order to avoid inconsistency the Agreement is copyrighted and may only be |
||||
modified in the following manner. The Agreement Steward reserves the right to |
||||
publish new versions (including revisions) of this Agreement from time to |
||||
time. No one other than the Agreement Steward has the right to modify this |
||||
Agreement. The Eclipse Foundation is the initial Agreement Steward. The |
||||
Eclipse Foundation may assign the responsibility to serve as the Agreement |
||||
Steward to a suitable separate entity. Each new version of the Agreement will |
||||
be given a distinguishing version number. The Program (including |
||||
Contributions) may always be distributed subject to the version of the |
||||
Agreement under which it was received. In addition, after a new version of the |
||||
Agreement is published, Contributor may elect to distribute the Program |
||||
(including its Contributions) under the new version. Except as expressly |
||||
stated in Sections 2(a) and 2(b) above, Recipient receives no rights or |
||||
licenses to the intellectual property of any Contributor under this Agreement, |
||||
whether expressly, by implication, estoppel or otherwise. All rights in the |
||||
Program not expressly granted under this Agreement are reserved. |
||||
|
||||
This Agreement is governed by the laws of the State of New York and the |
||||
intellectual property laws of the United States of America. No party to this |
||||
Agreement will bring a legal action under this Agreement more than one year |
||||
after the cause of action arose. Each party waives its rights to a jury trial in |
||||
any resulting litigation. |
@ -0,0 +1,674 @@
|
||||
GNU GENERAL PUBLIC LICENSE |
||||
Version 3, 29 June 2007 |
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
||||
Everyone is permitted to copy and distribute verbatim copies |
||||
of this license document, but changing it is not allowed. |
||||
|
||||
Preamble |
||||
|
||||
The GNU General Public License is a free, copyleft license for |
||||
software and other kinds of works. |
||||
|
||||
The licenses for most software and other practical works are designed |
||||
to take away your freedom to share and change the works. By contrast, |
||||
the GNU General Public License is intended to guarantee your freedom to |
||||
share and change all versions of a program--to make sure it remains free |
||||
software for all its users. We, the Free Software Foundation, use the |
||||
GNU General Public License for most of our software; it applies also to |
||||
any other work released this way by its authors. You can apply it to |
||||
your programs, too. |
||||
|
||||
When we speak of free software, we are referring to freedom, not |
||||
price. Our General Public Licenses are designed to make sure that you |
||||
have the freedom to distribute copies of free software (and charge for |
||||
them if you wish), that you receive source code or can get it if you |
||||
want it, that you can change the software or use pieces of it in new |
||||
free programs, and that you know you can do these things. |
||||
|
||||
To protect your rights, we need to prevent others from denying you |
||||
these rights or asking you to surrender the rights. Therefore, you have |
||||
certain responsibilities if you distribute copies of the software, or if |
||||
you modify it: responsibilities to respect the freedom of others. |
||||
|
||||
For example, if you distribute copies of such a program, whether |
||||
gratis or for a fee, you must pass on to the recipients the same |
||||
freedoms that you received. You must make sure that they, too, receive |
||||
or can get the source code. And you must show them these terms so they |
||||
know their rights. |
||||
|
||||
Developers that use the GNU GPL protect your rights with two steps: |
||||
(1) assert copyright on the software, and (2) offer you this License |
||||
giving you legal permission to copy, distribute and/or modify it. |
||||
|
||||
For the developers' and authors' protection, the GPL clearly explains |
||||
that there is no warranty for this free software. For both users' and |
||||
authors' sake, the GPL requires that modified versions be marked as |
||||
changed, so that their problems will not be attributed erroneously to |
||||
authors of previous versions. |
||||
|
||||
Some devices are designed to deny users access to install or run |
||||
modified versions of the software inside them, although the manufacturer |
||||
can do so. This is fundamentally incompatible with the aim of |
||||
protecting users' freedom to change the software. The systematic |
||||
pattern of such abuse occurs in the area of products for individuals to |
||||
use, which is precisely where it is most unacceptable. Therefore, we |
||||
have designed this version of the GPL to prohibit the practice for those |
||||
products. If such problems arise substantially in other domains, we |
||||
stand ready to extend this provision to those domains in future versions |
||||
of the GPL, as needed to protect the freedom of users. |
||||
|
||||
Finally, every program is threatened constantly by software patents. |
||||
States should not allow patents to restrict development and use of |
||||
software on general-purpose computers, but in those that do, we wish to |
||||
avoid the special danger that patents applied to a free program could |
||||
make it effectively proprietary. To prevent this, the GPL assures that |
||||
patents cannot be used to render the program non-free. |
||||
|
||||
The precise terms and conditions for copying, distribution and |
||||
modification follow. |
||||
|
||||
TERMS AND CONDITIONS |
||||
|
||||
0. Definitions. |
||||
|
||||
"This License" refers to version 3 of the GNU General Public License. |
||||
|
||||
"Copyright" also means copyright-like laws that apply to other kinds of |
||||
works, such as semiconductor masks. |
||||
|
||||
"The Program" refers to any copyrightable work licensed under this |
||||
License. Each licensee is addressed as "you". "Licensees" and |
||||
"recipients" may be individuals or organizations. |
||||
|
||||
To "modify" a work means to copy from or adapt all or part of the work |
||||
in a fashion requiring copyright permission, other than the making of an |
||||
exact copy. The resulting work is called a "modified version" of the |
||||
earlier work or a work "based on" the earlier work. |
||||
|
||||
A "covered work" means either the unmodified Program or a work based |
||||
on the Program. |
||||
|
||||
To "propagate" a work means to do anything with it that, without |
||||
permission, would make you directly or secondarily liable for |
||||
infringement under applicable copyright law, except executing it on a |
||||
computer or modifying a private copy. Propagation includes copying, |
||||
distribution (with or without modification), making available to the |
||||
public, and in some countries other activities as well. |
||||
|
||||
To "convey" a work means any kind of propagation that enables other |
||||
parties to make or receive copies. Mere interaction with a user through |
||||
a computer network, with no transfer of a copy, is not conveying. |
||||
|
||||
An interactive user interface displays "Appropriate Legal Notices" |
||||
to the extent that it includes a convenient and prominently visible |
||||
feature that (1) displays an appropriate copyright notice, and (2) |
||||
tells the user that there is no warranty for the work (except to the |
||||
extent that warranties are provided), that licensees may convey the |
||||
work under this License, and how to view a copy of this License. If |
||||
the interface presents a list of user commands or options, such as a |
||||
menu, a prominent item in the list meets this criterion. |
||||
|
||||
1. Source Code. |
||||
|
||||
The "source code" for a work means the preferred form of the work |
||||
for making modifications to it. "Object code" means any non-source |
||||
form of a work. |
||||
|
||||
A "Standard Interface" means an interface that either is an official |
||||
standard defined by a recognized standards body, or, in the case of |
||||
interfaces specified for a particular programming language, one that |
||||
is widely used among developers working in that language. |
||||
|
||||
The "System Libraries" of an executable work include anything, other |
||||
than the work as a whole, that (a) is included in the normal form of |
||||
packaging a Major Component, but which is not part of that Major |
||||
Component, and (b) serves only to enable use of the work with that |
||||
Major Component, or to implement a Standard Interface for which an |
||||
implementation is available to the public in source code form. A |
||||
"Major Component", in this context, means a major essential component |
||||
(kernel, window system, and so on) of the specific operating system |
||||
(if any) on which the executable work runs, or a compiler used to |
||||
produce the work, or an object code interpreter used to run it. |
||||
|
||||
The "Corresponding Source" for a work in object code form means all |
||||
the source code needed to generate, install, and (for an executable |
||||
work) run the object code and to modify the work, including scripts to |
||||
control those activities. However, it does not include the work's |
||||
System Libraries, or general-purpose tools or generally available free |
||||
programs which are used unmodified in performing those activities but |
||||
which are not part of the work. For example, Corresponding Source |
||||
includes interface definition files associated with source files for |
||||
the work, and the source code for shared libraries and dynamically |
||||
linked subprograms that the work is specifically designed to require, |
||||
such as by intimate data communication or control flow between those |
||||
subprograms and other parts of the work. |
||||
|
||||
The Corresponding Source need not include anything that users |
||||
can regenerate automatically from other parts of the Corresponding |
||||
Source. |
||||
|
||||
The Corresponding Source for a work in source code form is that |
||||
same work. |
||||
|
||||
2. Basic Permissions. |
||||
|
||||
All rights granted under this License are granted for the term of |
||||
copyright on the Program, and are irrevocable provided the stated |
||||
conditions are met. This License explicitly affirms your unlimited |
||||
permission to run the unmodified Program. The output from running a |
||||
covered work is covered by this License only if the output, given its |
||||
content, constitutes a covered work. This License acknowledges your |
||||
rights of fair use or other equivalent, as provided by copyright law. |
||||
|
||||
You may make, run and propagate covered works that you do not |
||||
convey, without conditions so long as your license otherwise remains |
||||
in force. You may convey covered works to others for the sole purpose |
||||
of having them make modifications exclusively for you, or provide you |
||||
with facilities for running those works, provided that you comply with |
||||
the terms of this License in conveying all material for which you do |
||||
not control copyright. Those thus making or running the covered works |
||||
for you must do so exclusively on your behalf, under your direction |
||||
and control, on terms that prohibit them from making any copies of |
||||
your copyrighted material outside their relationship with you. |
||||
|
||||
Conveying under any other circumstances is permitted solely under |
||||
the conditions stated below. Sublicensing is not allowed; section 10 |
||||
makes it unnecessary. |
||||
|
||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law. |
||||
|
||||
No covered work shall be deemed part of an effective technological |
||||
measure under any applicable law fulfilling obligations under article |
||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or |
||||
similar laws prohibiting or restricting circumvention of such |
||||
measures. |
||||
|
||||
When you convey a covered work, you waive any legal power to forbid |
||||
circumvention of technological measures to the extent such circumvention |
||||
is effected by exercising rights under this License with respect to |
||||
the covered work, and you disclaim any intention to limit operation or |
||||
modification of the work as a means of enforcing, against the work's |
||||
users, your or third parties' legal rights to forbid circumvention of |
||||
technological measures. |
||||
|
||||
4. Conveying Verbatim Copies. |
||||
|
||||
You may convey verbatim copies of the Program's source code as you |
||||
receive it, in any medium, provided that you conspicuously and |
||||
appropriately publish on each copy an appropriate copyright notice; |
||||
keep intact all notices stating that this License and any |
||||
non-permissive terms added in accord with section 7 apply to the code; |
||||
keep intact all notices of the absence of any warranty; and give all |
||||
recipients a copy of this License along with the Program. |
||||
|
||||
You may charge any price or no price for each copy that you convey, |
||||
and you may offer support or warranty protection for a fee. |
||||
|
||||
5. Conveying Modified Source Versions. |
||||
|
||||
You may convey a work based on the Program, or the modifications to |
||||
produce it from the Program, in the form of source code under the |
||||
terms of section 4, provided that you also meet all of these conditions: |
||||
|
||||
a) The work must carry prominent notices stating that you modified |
||||
it, and giving a relevant date. |
||||
|
||||
b) The work must carry prominent notices stating that it is |
||||
released under this License and any conditions added under section |
||||
7. This requirement modifies the requirement in section 4 to |
||||
"keep intact all notices". |
||||
|
||||
c) You must license the entire work, as a whole, under this |
||||
License to anyone who comes into possession of a copy. This |
||||
License will therefore apply, along with any applicable section 7 |
||||
additional terms, to the whole of the work, and all its parts, |
||||
regardless of how they are packaged. This License gives no |
||||
permission to license the work in any other way, but it does not |
||||
invalidate such permission if you have separately received it. |
||||
|
||||
d) If the work has interactive user interfaces, each must display |
||||
Appropriate Legal Notices; however, if the Program has interactive |
||||
interfaces that do not display Appropriate Legal Notices, your |
||||
work need not make them do so. |
||||
|
||||
A compilation of a covered work with other separate and independent |
||||
works, which are not by their nature extensions of the covered work, |
||||
and which are not combined with it such as to form a larger program, |
||||
in or on a volume of a storage or distribution medium, is called an |
||||
"aggregate" if the compilation and its resulting copyright are not |
||||
used to limit the access or legal rights of the compilation's users |
||||
beyond what the individual works permit. Inclusion of a covered work |
||||
in an aggregate does not cause this License to apply to the other |
||||
parts of the aggregate. |
||||
|
||||
6. Conveying Non-Source Forms. |
||||
|
||||
You may convey a covered work in object code form under the terms |
||||
of sections 4 and 5, provided that you also convey the |
||||
machine-readable Corresponding Source under the terms of this License, |
||||
in one of these ways: |
||||
|
||||
a) Convey the object code in, or embodied in, a physical product |
||||
(including a physical distribution medium), accompanied by the |
||||
Corresponding Source fixed on a durable physical medium |
||||
customarily used for software interchange. |
||||
|
||||
b) Convey the object code in, or embodied in, a physical product |
||||
(including a physical distribution medium), accompanied by a |
||||
written offer, valid for at least three years and valid for as |
||||
long as you offer spare parts or customer support for that product |
||||
model, to give anyone who possesses the object code either (1) a |
||||
copy of the Corresponding Source for all the software in the |
||||
product that is covered by this License, on a durable physical |
||||
medium customarily used for software interchange, for a price no |
||||
more than your reasonable cost of physically performing this |
||||
conveying of source, or (2) access to copy the |
||||
Corresponding Source from a network server at no charge. |
||||
|
||||
c) Convey individual copies of the object code with a copy of the |
||||
written offer to provide the Corresponding Source. This |
||||
alternative is allowed only occasionally and noncommercially, and |
||||
only if you received the object code with such an offer, in accord |
||||
with subsection 6b. |
||||
|
||||
d) Convey the object code by offering access from a designated |
||||
place (gratis or for a charge), and offer equivalent access to the |
||||
Corresponding Source in the same way through the same place at no |
||||
further charge. You need not require recipients to copy the |
||||
Corresponding Source along with the object code. If the place to |
||||
copy the object code is a network server, the Corresponding Source |
||||
may be on a different server (operated by you or a third party) |
||||
that supports equivalent copying facilities, provided you maintain |
||||
clear directions next to the object code saying where to find the |
||||
Corresponding Source. Regardless of what server hosts the |
||||
Corresponding Source, you remain obligated to ensure that it is |
||||
available for as long as needed to satisfy these requirements. |
||||
|
||||
e) Convey the object code using peer-to-peer transmission, provided |
||||
you inform other peers where the object code and Corresponding |
||||
Source of the work are being offered to the general public at no |
||||
charge under subsection 6d. |
||||
|
||||
A separable portion of the object code, whose source code is excluded |
||||
from the Corresponding Source as a System Library, need not be |
||||
included in conveying the object code work. |
||||
|
||||
A "User Product" is either (1) a "consumer product", which means any |
||||
tangible personal property which is normally used for personal, family, |
||||
or household purposes, or (2) anything designed or sold for incorporation |
||||
into a dwelling. In determining whether a product is a consumer product, |
||||
doubtful cases shall be resolved in favor of coverage. For a particular |
||||
product received by a particular user, "normally used" refers to a |
||||
typical or common use of that class of product, regardless of the status |
||||
of the particular user or of the way in which the particular user |
||||
actually uses, or expects or is expected to use, the product. A product |
||||
is a consumer product regardless of whether the product has substantial |
||||
commercial, industrial or non-consumer uses, unless such uses represent |
||||
the only significant mode of use of the product. |
||||
|
||||
"Installation Information" for a User Product means any methods, |
||||
procedures, authorization keys, or other information required to install |
||||
and execute modified versions of a covered work in that User Product from |
||||
a modified version of its Corresponding Source. The information must |
||||
suffice to ensure that the continued functioning of the modified object |
||||
code is in no case prevented or interfered with solely because |
||||
modification has been made. |
||||
|
||||
If you convey an object code work under this section in, or with, or |
||||
specifically for use in, a User Product, and the conveying occurs as |
||||
part of a transaction in which the right of possession and use of the |
||||
User Product is transferred to the recipient in perpetuity or for a |
||||
fixed term (regardless of how the transaction is characterized), the |
||||
Corresponding Source conveyed under this section must be accompanied |
||||
by the Installation Information. But this requirement does not apply |
||||
if neither you nor any third party retains the ability to install |
||||
modified object code on the User Product (for example, the work has |
||||
been installed in ROM). |
||||
|
||||
The requirement to provide Installation Information does not include a |
||||
requirement to continue to provide support service, warranty, or updates |
||||
for a work that has been modified or installed by the recipient, or for |
||||
the User Product in which it has been modified or installed. Access to a |
||||
network may be denied when the modification itself materially and |
||||
adversely affects the operation of the network or violates the rules and |
||||
protocols for communication across the network. |
||||
|
||||
Corresponding Source conveyed, and Installation Information provided, |
||||
in accord with this section must be in a format that is publicly |
||||
documented (and with an implementation available to the public in |
||||
source code form), and must require no special password or key for |
||||
unpacking, reading or copying. |
||||
|
||||
7. Additional Terms. |
||||
|
||||
"Additional permissions" are terms that supplement the terms of this |
||||
License by making exceptions from one or more of its conditions. |
||||
Additional permissions that are applicable to the entire Program shall |
||||
be treated as though they were included in this License, to the extent |
||||
that they are valid under applicable law. If additional permissions |
||||
apply only to part of the Program, that part may be used separately |
||||
under those permissions, but the entire Program remains governed by |
||||
this License without regard to the additional permissions. |
||||
|
||||
When you convey a copy of a covered work, you may at your option |
||||
remove any additional permissions from that copy, or from any part of |
||||
it. (Additional permissions may be written to require their own |
||||
removal in certain cases when you modify the work.) You may place |
||||
additional permissions on material, added by you to a covered work, |
||||
for which you have or can give appropriate copyright permission. |
||||
|
||||
Notwithstanding any other provision of this License, for material you |
||||
add to a covered work, you may (if authorized by the copyright holders of |
||||
that material) supplement the terms of this License with terms: |
||||
|
||||
a) Disclaiming warranty or limiting liability differently from the |
||||
terms of sections 15 and 16 of this License; or |
||||
|
||||
b) Requiring preservation of specified reasonable legal notices or |
||||
author attributions in that material or in the Appropriate Legal |
||||
Notices displayed by works containing it; or |
||||
|
||||
c) Prohibiting misrepresentation of the origin of that material, or |
||||
requiring that modified versions of such material be marked in |
||||
reasonable ways as different from the original version; or |
||||
|
||||
d) Limiting the use for publicity purposes of names of licensors or |
||||
authors of the material; or |
||||
|
||||
e) Declining to grant rights under trademark law for use of some |
||||
trade names, trademarks, or service marks; or |
||||
|
||||
f) Requiring indemnification of licensors and authors of that |
||||
material by anyone who conveys the material (or modified versions of |
||||
it) with contractual assumptions of liability to the recipient, for |
||||
any liability that these contractual assumptions directly impose on |
||||
those licensors and authors. |
||||
|
||||
All other non-permissive additional terms are considered "further |
||||
restrictions" within the meaning of section 10. If the Program as you |
||||
received it, or any part of it, contains a notice stating that it is |
||||
governed by this License along with a term that is a further |
||||
restriction, you may remove that term. If a license document contains |
||||
a further restriction but permits relicensing or conveying under this |
||||
License, you may add to a covered work material governed by the terms |
||||
of that license document, provided that the further restriction does |
||||
not survive such relicensing or conveying. |
||||
|
||||
If you add terms to a covered work in accord with this section, you |
||||
must place, in the relevant source files, a statement of the |
||||
additional terms that apply to those files, or a notice indicating |
||||
where to find the applicable terms. |
||||
|
||||
Additional terms, permissive or non-permissive, may be stated in the |
||||
form of a separately written license, or stated as exceptions; |
||||
the above requirements apply either way. |
||||
|
||||
8. Termination. |
||||
|
||||
You may not propagate or modify a covered work except as expressly |
||||
provided under this License. Any attempt otherwise to propagate or |
||||
modify it is void, and will automatically terminate your rights under |
||||
this License (including any patent licenses granted under the third |
||||
paragraph of section 11). |
||||
|
||||
However, if you cease all violation of this License, then your |
||||
license from a particular copyright holder is reinstated (a) |
||||
provisionally, unless and until the copyright holder explicitly and |
||||
finally terminates your license, and (b) permanently, if the copyright |
||||
holder fails to notify you of the violation by some reasonable means |
||||
prior to 60 days after the cessation. |
||||
|
||||
Moreover, your license from a particular copyright holder is |
||||
reinstated permanently if the copyright holder notifies you of the |
||||
violation by some reasonable means, this is the first time you have |
||||
received notice of violation of this License (for any work) from that |
||||
copyright holder, and you cure the violation prior to 30 days after |
||||
your receipt of the notice. |
||||
|
||||
Termination of your rights under this section does not terminate the |
||||
licenses of parties who have received copies or rights from you under |
||||
this License. If your rights have been terminated and not permanently |
||||
reinstated, you do not qualify to receive new licenses for the same |
||||
material under section 10. |
||||
|
||||
9. Acceptance Not Required for Having Copies. |
||||
|
||||
You are not required to accept this License in order to receive or |
||||
run a copy of the Program. Ancillary propagation of a covered work |
||||
occurring solely as a consequence of using peer-to-peer transmission |
||||
to receive a copy likewise does not require acceptance. However, |
||||
nothing other than this License grants you permission to propagate or |
||||
modify any covered work. These actions infringe copyright if you do |
||||
not accept this License. Therefore, by modifying or propagating a |
||||
covered work, you indicate your acceptance of this License to do so. |
||||
|
||||
10. Automatic Licensing of Downstream Recipients. |
||||
|
||||
Each time you convey a covered work, the recipient automatically |
||||
receives a license from the original licensors, to run, modify and |
||||
propagate that work, subject to this License. You are not responsible |
||||
for enforcing compliance by third parties with this License. |
||||
|
||||
An "entity transaction" is a transaction transferring control of an |
||||
organization, or substantially all assets of one, or subdividing an |
||||
organization, or merging organizations. If propagation of a covered |
||||
work results from an entity transaction, each party to that |
||||
transaction who receives a copy of the work also receives whatever |
||||
licenses to the work the party's predecessor in interest had or could |
||||
give under the previous paragraph, plus a right to possession of the |
||||
Corresponding Source of the work from the predecessor in interest, if |
||||
the predecessor has it or can get it with reasonable efforts. |
||||
|
||||
You may not impose any further restrictions on the exercise of the |
||||
rights granted or affirmed under this License. For example, you may |
||||
not impose a license fee, royalty, or other charge for exercise of |
||||
rights granted under this License, and you may not initiate litigation |
||||
(including a cross-claim or counterclaim in a lawsuit) alleging that |
||||
any patent claim is infringed by making, using, selling, offering for |
||||
sale, or importing the Program or any portion of it. |
||||
|
||||
11. Patents. |
||||
|
||||
A "contributor" is a copyright holder who authorizes use under this |
||||
License of the Program or a work on which the Program is based. The |
||||
work thus licensed is called the contributor's "contributor version". |
||||
|
||||
A contributor's "essential patent claims" are all patent claims |
||||
owned or controlled by the contributor, whether already acquired or |
||||
hereafter acquired, that would be infringed by some manner, permitted |
||||
by this License, of making, using, or selling its contributor version, |
||||
but do not include claims that would be infringed only as a |
||||
consequence of further modification of the contributor version. For |
||||
purposes of this definition, "control" includes the right to grant |
||||
patent sublicenses in a manner consistent with the requirements of |
||||
this License. |
||||
|
||||
Each contributor grants you a non-exclusive, worldwide, royalty-free |
||||
patent license under the contributor's essential patent claims, to |
||||
make, use, sell, offer for sale, import and otherwise run, modify and |
||||
propagate the contents of its contributor version. |
||||
|
||||
In the following three paragraphs, a "patent license" is any express |
||||
agreement or commitment, however denominated, not to enforce a patent |
||||
(such as an express permission to practice a patent or covenant not to |
||||
sue for patent infringement). To "grant" such a patent license to a |
||||
party means to make such an agreement or commitment not to enforce a |
||||
patent against the party. |
||||
|
||||
If you convey a covered work, knowingly relying on a patent license, |
||||
and the Corresponding Source of the work is not available for anyone |
||||
to copy, free of charge and under the terms of this License, through a |
||||
publicly available network server or other readily accessible means, |
||||
then you must either (1) cause the Corresponding Source to be so |
||||
available, or (2) arrange to deprive yourself of the benefit of the |
||||
patent license for this particular work, or (3) arrange, in a manner |
||||
consistent with the requirements of this License, to extend the patent |
||||
license to downstream recipients. "Knowingly relying" means you have |
||||
actual knowledge that, but for the patent license, your conveying the |
||||
covered work in a country, or your recipient's use of the covered work |
||||
in a country, would infringe one or more identifiable patents in that |
||||
country that you have reason to believe are valid. |
||||
|
||||
If, pursuant to or in connection with a single transaction or |
||||
arrangement, you convey, or propagate by procuring conveyance of, a |
||||
covered work, and grant a patent license to some of the parties |
||||
receiving the covered work authorizing them to use, propagate, modify |
||||
or convey a specific copy of the covered work, then the patent license |
||||
you grant is automatically extended to all recipients of the covered |
||||
work and works based on it. |
||||
|
||||
A patent license is "discriminatory" if it does not include within |
||||
the scope of its coverage, prohibits the exercise of, or is |
||||
conditioned on the non-exercise of one or more of the rights that are |
||||
specifically granted under this License. You may not convey a covered |
||||
work if you are a party to an arrangement with a third party that is |
||||
in the business of distributing software, under which you make payment |
||||
to the third party based on the extent of your activity of conveying |
||||
the work, and under which the third party grants, to any of the |
||||
parties who would receive the covered work from you, a discriminatory |
||||
patent license (a) in connection with copies of the covered work |
||||
conveyed by you (or copies made from those copies), or (b) primarily |
||||
for and in connection with specific products or compilations that |
||||
contain the covered work, unless you entered into that arrangement, |
||||
or that patent license was granted, prior to 28 March 2007. |
||||
|
||||
Nothing in this License shall be construed as excluding or limiting |
||||
any implied license or other defenses to infringement that may |
||||
otherwise be available to you under applicable patent law. |
||||
|
||||
12. No Surrender of Others' Freedom. |
||||
|
||||
If conditions are imposed on you (whether by court order, agreement or |
||||
otherwise) that contradict the conditions of this License, they do not |
||||
excuse you from the conditions of this License. If you cannot convey a |
||||
covered work so as to satisfy simultaneously your obligations under this |
||||
License and any other pertinent obligations, then as a consequence you may |
||||
not convey it at all. For example, if you agree to terms that obligate you |
||||
to collect a royalty for further conveying from those to whom you convey |
||||
the Program, the only way you could satisfy both those terms and this |
||||
License would be to refrain entirely from conveying the Program. |
||||
|
||||
13. Use with the GNU Affero General Public License. |
||||
|
||||
Notwithstanding any other provision of this License, you have |
||||
permission to link or combine any covered work with a work licensed |
||||
under version 3 of the GNU Affero General Public License into a single |
||||
combined work, and to convey the resulting work. The terms of this |
||||
License will continue to apply to the part which is the covered work, |
||||
but the special requirements of the GNU Affero General Public License, |
||||
section 13, concerning interaction through a network will apply to the |
||||
combination as such. |
||||
|
||||
14. Revised Versions of this License. |
||||
|
||||
The Free Software Foundation may publish revised and/or new versions of |
||||
the GNU General Public License from time to time. Such new versions will |
||||
be similar in spirit to the present version, but may differ in detail to |
||||
address new problems or concerns. |
||||
|
||||
Each version is given a distinguishing version number. If the |
||||
Program specifies that a certain numbered version of the GNU General |
||||
Public License "or any later version" applies to it, you have the |
||||
option of following the terms and conditions either of that numbered |
||||
version or of any later version published by the Free Software |
||||
Foundation. If the Program does not specify a version number of the |
||||
GNU General Public License, you may choose any version ever published |
||||
by the Free Software Foundation. |
||||
|
||||
If the Program specifies that a proxy can decide which future |
||||
versions of the GNU General Public License can be used, that proxy's |
||||
public statement of acceptance of a version permanently authorizes you |
||||
to choose that version for the Program. |
||||
|
||||
Later license versions may give you additional or different |
||||
permissions. However, no additional obligations are imposed on any |
||||
author or copyright holder as a result of your choosing to follow a |
||||
later version. |
||||
|
||||
15. Disclaimer of Warranty. |
||||
|
||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY |
||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT |
||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY |
||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, |
||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM |
||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF |
||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
||||
|
||||
16. Limitation of Liability. |
||||
|
||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING |
||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS |
||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY |
||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE |
||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF |
||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD |
||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), |
||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF |
||||
SUCH DAMAGES. |
||||
|
||||
17. Interpretation of Sections 15 and 16. |
||||
|
||||
If the disclaimer of warranty and limitation of liability provided |
||||
above cannot be given local legal effect according to their terms, |
||||
reviewing courts shall apply local law that most closely approximates |
||||
an absolute waiver of all civil liability in connection with the |
||||
Program, unless a warranty or assumption of liability accompanies a |
||||
copy of the Program in return for a fee. |
||||
|
||||
END OF TERMS AND CONDITIONS |
||||
|
||||
How to Apply These Terms to Your New Programs |
||||
|
||||
If you develop a new program, and you want it to be of the greatest |
||||
possible use to the public, the best way to achieve this is to make it |
||||
free software which everyone can redistribute and change under these terms. |
||||
|
||||
To do so, attach the following notices to the program. It is safest |
||||
to attach them to the start of each source file to most effectively |
||||
state the exclusion of warranty; and each file should have at least |
||||
the "copyright" line and a pointer to where the full notice is found. |
||||
|
||||
{one line to give the program's name and a brief idea of what it does.} |
||||
Copyright (C) {year} {name of author} |
||||
|
||||
This program is free software: you can redistribute it and/or modify |
||||
it under the terms of the GNU General Public License as published by |
||||
the Free Software Foundation, either version 3 of the License, or |
||||
(at your option) any later version. |
||||
|
||||
This program is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||||
GNU General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU General Public License |
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
||||
Also add information on how to contact you by electronic and paper mail. |
||||
|
||||
If the program does terminal interaction, make it output a short |
||||
notice like this when it starts in an interactive mode: |
||||
|
||||
{project} Copyright (C) {year} {fullname} |
||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. |
||||
This is free software, and you are welcome to redistribute it |
||||
under certain conditions; type `show c' for details. |
||||
|
||||
The hypothetical commands `show w' and `show c' should show the appropriate |
||||
parts of the General Public License. Of course, your program's commands |
||||
might be different; for a GUI interface, you would use an "about box". |
||||
|
||||
You should also get your employer (if you work as a programmer) or school, |
||||
if any, to sign a "copyright disclaimer" for the program, if necessary. |
||||
For more information on this, and how to apply and follow the GNU GPL, see |
||||
<http://www.gnu.org/licenses/>. |
||||
|
||||
The GNU General Public License does not permit incorporating your program |
||||
into proprietary programs. If your program is a subroutine library, you |
||||
may consider it more useful to permit linking proprietary applications with |
||||
the library. If this is what you want to do, use the GNU Lesser General |
||||
Public License instead of this License. But first, please read |
||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>. |
@ -0,0 +1,13 @@
|
||||
Copyright (c) 2014 |
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any |
||||
purpose with or without fee is hereby granted, provided that the above |
||||
copyright notice and this permission notice appear in all copies. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES |
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF |
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR |
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES |
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN |
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF |
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
@ -0,0 +1,504 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE |
||||
Version 2.1, February 1999 |
||||
|
||||
Copyright (C) 1991, 1999 Free Software Foundation, Inc. |
||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
||||
Everyone is permitted to copy and distribute verbatim copies |
||||
of this license document, but changing it is not allowed. |
||||
|
||||
(This is the first released version of the Lesser GPL. It also counts |
||||
as the successor of the GNU Library Public License, version 2, hence |
||||
the version number 2.1.) |
||||
|
||||
Preamble |
||||
|
||||
The licenses for most software are designed to take away your |
||||
freedom to share and change it. By contrast, the GNU General Public |
||||
Licenses are intended to guarantee your freedom to share and change |
||||
free software--to make sure the software is free for all its users. |
||||
|
||||
This license, the Lesser General Public License, applies to some |
||||
specially designated software packages--typically libraries--of the |
||||
Free Software Foundation and other authors who decide to use it. You |
||||
can use it too, but we suggest you first think carefully about whether |
||||
this license or the ordinary General Public License is the better |
||||
strategy to use in any particular case, based on the explanations below. |
||||
|
||||
When we speak of free software, we are referring to freedom of use, |
||||
not price. Our General Public Licenses are designed to make sure that |
||||
you have the freedom to distribute copies of free software (and charge |
||||
for this service if you wish); that you receive source code or can get |
||||
it if you want it; that you can change the software and use pieces of |
||||
it in new free programs; and that you are informed that you can do |
||||
these things. |
||||
|
||||
To protect your rights, we need to make restrictions that forbid |
||||
distributors to deny you these rights or to ask you to surrender these |
||||
rights. These restrictions translate to certain responsibilities for |
||||
you if you distribute copies of the library or if you modify it. |
||||
|
||||
For example, if you distribute copies of the library, whether gratis |
||||
or for a fee, you must give the recipients all the rights that we gave |
||||
you. You must make sure that they, too, receive or can get the source |
||||
code. If you link other code with the library, you must provide |
||||
complete object files to the recipients, so that they can relink them |
||||
with the library after making changes to the library and recompiling |
||||
it. And you must show them these terms so they know their rights. |
||||
|
||||
We protect your rights with a two-step method: (1) we copyright the |
||||
library, and (2) we offer you this license, which gives you legal |
||||
permission to copy, distribute and/or modify the library. |
||||
|
||||
To protect each distributor, we want to make it very clear that |
||||
there is no warranty for the free library. Also, if the library is |
||||
modified by someone else and passed on, the recipients should know |
||||
that what they have is not the original version, so that the original |
||||
author's reputation will not be affected by problems that might be |
||||
introduced by others. |
||||
|
||||
Finally, software patents pose a constant threat to the existence of |
||||
any free program. We wish to make sure that a company cannot |
||||
effectively restrict the users of a free program by obtaining a |
||||
restrictive license from a patent holder. Therefore, we insist that |
||||
any patent license obtained for a version of the library must be |
||||
consistent with the full freedom of use specified in this license. |
||||
|
||||
Most GNU software, including some libraries, is covered by the |
||||
ordinary GNU General Public License. This license, the GNU Lesser |
||||
General Public License, applies to certain designated libraries, and |
||||
is quite different from the ordinary General Public License. We use |
||||
this license for certain libraries in order to permit linking those |
||||
libraries into non-free programs. |
||||
|
||||
When a program is linked with a library, whether statically or using |
||||
a shared library, the combination of the two is legally speaking a |
||||
combined work, a derivative of the original library. The ordinary |
||||
General Public License therefore permits such linking only if the |
||||
entire combination fits its criteria of freedom. The Lesser General |
||||
Public License permits more lax criteria for linking other code with |
||||
the library. |
||||
|
||||
We call this license the "Lesser" General Public License because it |
||||
does Less to protect the user's freedom than the ordinary General |
||||
Public License. It also provides other free software developers Less |
||||
of an advantage over competing non-free programs. These disadvantages |
||||
are the reason we use the ordinary General Public License for many |
||||
libraries. However, the Lesser license provides advantages in certain |
||||
special circumstances. |
||||
|
||||
For example, on rare occasions, there may be a special need to |
||||
encourage the widest possible use of a certain library, so that it becomes |
||||
a de-facto standard. To achieve this, non-free programs must be |
||||
allowed to use the library. A more frequent case is that a free |
||||
library does the same job as widely used non-free libraries. In this |
||||
case, there is little to gain by limiting the free library to free |
||||
software only, so we use the Lesser General Public License. |
||||
|
||||
In other cases, permission to use a particular library in non-free |
||||
programs enables a greater number of people to use a large body of |
||||
free software. For example, permission to use the GNU C Library in |
||||
non-free programs enables many more people to use the whole GNU |
||||
operating system, as well as its variant, the GNU/Linux operating |
||||
system. |
||||
|
||||
Although the Lesser General Public License is Less protective of the |
||||
users' freedom, it does ensure that the user of a program that is |
||||
linked with the Library has the freedom and the wherewithal to run |
||||
that program using a modified version of the Library. |
||||
|
||||
The precise terms and conditions for copying, distribution and |
||||
modification follow. Pay close attention to the difference between a |
||||
"work based on the library" and a "work that uses the library". The |
||||
former contains code derived from the library, whereas the latter must |
||||
be combined with the library in order to run. |
||||
|
||||
GNU LESSER GENERAL PUBLIC LICENSE |
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION |
||||
|
||||
0. This License Agreement applies to any software library or other |
||||
program which contains a notice placed by the copyright holder or |
||||
other authorized party saying it may be distributed under the terms of |
||||
this Lesser General Public License (also called "this License"). |
||||
Each licensee is addressed as "you". |
||||
|
||||
A "library" means a collection of software functions and/or data |
||||
prepared so as to be conveniently linked with application programs |
||||
(which use some of those functions and data) to form executables. |
||||
|
||||
The "Library", below, refers to any such software library or work |
||||
which has been distributed under these terms. A "work based on the |
||||
Library" means either the Library or any derivative work under |
||||
copyright law: that is to say, a work containing the Library or a |
||||
portion of it, either verbatim or with modifications and/or translated |
||||
straightforwardly into another language. (Hereinafter, translation is |
||||
included without limitation in the term "modification".) |
||||
|
||||
"Source code" for a work means the preferred form of the work for |
||||
making modifications to it. For a library, complete source code means |
||||
all the source code for all modules it contains, plus any associated |
||||
interface definition files, plus the scripts used to control compilation |
||||
and installation of the library. |
||||
|
||||
Activities other than copying, distribution and modification are not |
||||
covered by this License; they are outside its scope. The act of |
||||
running a program using the Library is not restricted, and output from |
||||
such a program is covered only if its contents constitute a work based |
||||
on the Library (independent of the use of the Library in a tool for |
||||
writing it). Whether that is true depends on what the Library does |
||||
and what the program that uses the Library does. |
||||
|
||||
1. You may copy and distribute verbatim copies of the Library's |
||||
complete source code as you receive it, in any medium, provided that |
||||
you conspicuously and appropriately publish on each copy an |
||||
appropriate copyright notice and disclaimer of warranty; keep intact |
||||
all the notices that refer to this License and to the absence of any |
||||
warranty; and distribute a copy of this License along with the |
||||
Library. |
||||
|
||||
You may charge a fee for the physical act of transferring a copy, |
||||
and you may at your option offer warranty protection in exchange for a |
||||
fee. |
||||
|
||||
2. You may modify your copy or copies of the Library or any portion |
||||
of it, thus forming a work based on the Library, and copy and |
||||
distribute such modifications or work under the terms of Section 1 |
||||
above, provided that you also meet all of these conditions: |
||||
|
||||
a) The modified work must itself be a software library. |
||||
|
||||
b) You must cause the files modified to carry prominent notices |
||||
stating that you changed the files and the date of any change. |
||||
|
||||
c) You must cause the whole of the work to be licensed at no |
||||
charge to all third parties under the terms of this License. |
||||
|
||||
d) If a facility in the modified Library refers to a function or a |
||||
table of data to be supplied by an application program that uses |
||||
the facility, other than as an argument passed when the facility |
||||
is invoked, then you must make a good faith effort to ensure that, |
||||
in the event an application does not supply such function or |
||||
table, the facility still operates, and performs whatever part of |
||||
its purpose remains meaningful. |
||||
|
||||
(For example, a function in a library to compute square roots has |
||||
a purpose that is entirely well-defined independent of the |
||||
application. Therefore, Subsection 2d requires that any |
||||
application-supplied function or table used by this function must |
||||
be optional: if the application does not supply it, the square |
||||
root function must still compute square roots.) |
||||
|
||||
These requirements apply to the modified work as a whole. If |
||||
identifiable sections of that work are not derived from the Library, |
||||
and can be reasonably considered independent and separate works in |
||||
themselves, then this License, and its terms, do not apply to those |
||||
sections when you distribute them as separate works. But when you |
||||
distribute the same sections as part of a whole which is a work based |
||||
on the Library, the distribution of the whole must be on the terms of |
||||
this License, whose permissions for other licensees extend to the |
||||
entire whole, and thus to each and every part regardless of who wrote |
||||
it. |
||||
|
||||
Thus, it is not the intent of this section to claim rights or contest |
||||
your rights to work written entirely by you; rather, the intent is to |
||||
exercise the right to control the distribution of derivative or |
||||
collective works based on the Library. |
||||
|
||||
In addition, mere aggregation of another work not based on the Library |
||||
with the Library (or with a work based on the Library) on a volume of |
||||
a storage or distribution medium does not bring the other work under |
||||
the scope of this License. |
||||
|
||||
3. You may opt to apply the terms of the ordinary GNU General Public |
||||
License instead of this License to a given copy of the Library. To do |
||||
this, you must alter all the notices that refer to this License, so |
||||
that they refer to the ordinary GNU General Public License, version 2, |
||||
instead of to this License. (If a newer version than version 2 of the |
||||
ordinary GNU General Public License has appeared, then you can specify |
||||
that version instead if you wish.) Do not make any other change in |
||||
these notices. |
||||
|
||||
Once this change is made in a given copy, it is irreversible for |
||||
that copy, so the ordinary GNU General Public License applies to all |
||||
subsequent copies and derivative works made from that copy. |
||||
|
||||
This option is useful when you wish to copy part of the code of |
||||
the Library into a program that is not a library. |
||||
|
||||
4. You may copy and distribute the Library (or a portion or |
||||
derivative of it, under Section 2) in object code or executable form |
||||
under the terms of Sections 1 and 2 above provided that you accompany |
||||
it with the complete corresponding machine-readable source code, which |
||||
must be distributed under the terms of Sections 1 and 2 above on a |
||||
medium customarily used for software interchange. |
||||
|
||||
If distribution of object code is made by offering access to copy |
||||
from a designated place, then offering equivalent access to copy the |
||||
source code from the same place satisfies the requirement to |
||||
distribute the source code, even though third parties are not |
||||
compelled to copy the source along with the object code. |
||||
|
||||
5. A program that contains no derivative of any portion of the |
||||
Library, but is designed to work with the Library by being compiled or |
||||
linked with it, is called a "work that uses the Library". Such a |
||||
work, in isolation, is not a derivative work of the Library, and |
||||
therefore falls outside the scope of this License. |
||||
|
||||
However, linking a "work that uses the Library" with the Library |
||||
creates an executable that is a derivative of the Library (because it |
||||
contains portions of the Library), rather than a "work that uses the |
||||
library". The executable is therefore covered by this License. |
||||
Section 6 states terms for distribution of such executables. |
||||
|
||||
When a "work that uses the Library" uses material from a header file |
||||
that is part of the Library, the object code for the work may be a |
||||
derivative work of the Library even though the source code is not. |
||||
Whether this is true is especially significant if the work can be |
||||
linked without the Library, or if the work is itself a library. The |
||||
threshold for this to be true is not precisely defined by law. |
||||
|
||||
If such an object file uses only numerical parameters, data |
||||
structure layouts and accessors, and small macros and small inline |
||||
functions (ten lines or less in length), then the use of the object |
||||
file is unrestricted, regardless of whether it is legally a derivative |
||||
work. (Executables containing this object code plus portions of the |
||||
Library will still fall under Section 6.) |
||||
|
||||
Otherwise, if the work is a derivative of the Library, you may |
||||
distribute the object code for the work under the terms of Section 6. |
||||
Any executables containing that work also fall under Section 6, |
||||
whether or not they are linked directly with the Library itself. |
||||
|
||||
6. As an exception to the Sections above, you may also combine or |
||||
link a "work that uses the Library" with the Library to produce a |
||||
work containing portions of the Library, and distribute that work |
||||
under terms of your choice, provided that the terms permit |
||||
modification of the work for the customer's own use and reverse |
||||
engineering for debugging such modifications. |
||||
|
||||
You must give prominent notice with each copy of the work that the |
||||
Library is used in it and that the Library and its use are covered by |
||||
this License. You must supply a copy of this License. If the work |
||||
during execution displays copyright notices, you must include the |
||||
copyright notice for the Library among them, as well as a reference |
||||
directing the user to the copy of this License. Also, you must do one |
||||
of these things: |
||||
|
||||
a) Accompany the work with the complete corresponding |
||||
machine-readable source code for the Library including whatever |
||||
changes were used in the work (which must be distributed under |
||||
Sections 1 and 2 above); and, if the work is an executable linked |
||||
with the Library, with the complete machine-readable "work that |
||||
uses the Library", as object code and/or source code, so that the |
||||
user can modify the Library and then relink to produce a modified |
||||
executable containing the modified Library. (It is understood |
||||
that the user who changes the contents of definitions files in the |
||||
Library will not necessarily be able to recompile the application |
||||
to use the modified definitions.) |
||||
|
||||
b) Use a suitable shared library mechanism for linking with the |
||||
Library. A suitable mechanism is one that (1) uses at run time a |
||||
copy of the library already present on the user's computer system, |
||||
rather than copying library functions into the executable, and (2) |
||||
will operate properly with a modified version of the library, if |
||||
the user installs one, as long as the modified version is |
||||
interface-compatible with the version that the work was made with. |
||||
|
||||
c) Accompany the work with a written offer, valid for at |
||||
least three years, to give the same user the materials |
||||
specified in Subsection 6a, above, for a charge no more |
||||
than the cost of performing this distribution. |
||||
|
||||
d) If distribution of the work is made by offering access to copy |
||||
from a designated place, offer equivalent access to copy the above |
||||
specified materials from the same place. |
||||
|
||||
e) Verify that the user has already received a copy of these |
||||
materials or that you have already sent this user a copy. |
||||
|
||||
For an executable, the required form of the "work that uses the |
||||
Library" must include any data and utility programs needed for |
||||
reproducing the executable from it. However, as a special exception, |
||||
the materials to be distributed need not include anything that is |
||||
normally distributed (in either source or binary form) with the major |
||||
components (compiler, kernel, and so on) of the operating system on |
||||
which the executable runs, unless that component itself accompanies |
||||
the executable. |
||||
|
||||
It may happen that this requirement contradicts the license |
||||
restrictions of other proprietary libraries that do not normally |
||||
accompany the operating system. Such a contradiction means you cannot |
||||
use both them and the Library together in an executable that you |
||||
distribute. |
||||
|
||||
7. You may place library facilities that are a work based on the |
||||
Library side-by-side in a single library together with other library |
||||
facilities not covered by this License, and distribute such a combined |
||||
library, provided that the separate distribution of the work based on |
||||
the Library and of the other library facilities is otherwise |
||||
permitted, and provided that you do these two things: |
||||
|
||||
a) Accompany the combined library with a copy of the same work |
||||
based on the Library, uncombined with any other library |
||||
facilities. This must be distributed under the terms of the |
||||
Sections above. |
||||
|
||||
b) Give prominent notice with the combined library of the fact |
||||
that part of it is a work based on the Library, and explaining |
||||
where to find the accompanying uncombined form of the same work. |
||||
|
||||
8. You may not copy, modify, sublicense, link with, or distribute |
||||
the Library except as expressly provided under this License. Any |
||||
attempt otherwise to copy, modify, sublicense, link with, or |
||||
distribute the Library is void, and will automatically terminate your |
||||
rights under this License. However, parties who have received copies, |
||||
or rights, from you under this License will not have their licenses |
||||
terminated so long as such parties remain in full compliance. |
||||
|
||||
9. You are not required to accept this License, since you have not |
||||
signed it. However, nothing else grants you permission to modify or |
||||
distribute the Library or its derivative works. These actions are |
||||
prohibited by law if you do not accept this License. Therefore, by |
||||
modifying or distributing the Library (or any work based on the |
||||
Library), you indicate your acceptance of this License to do so, and |
||||
all its terms and conditions for copying, distributing or modifying |
||||
the Library or works based on it. |
||||
|
||||
10. Each time you redistribute the Library (or any work based on the |
||||
Library), the recipient automatically receives a license from the |
||||
original licensor to copy, distribute, link with or modify the Library |
||||
subject to these terms and conditions. You may not impose any further |
||||
restrictions on the recipients' exercise of the rights granted herein. |
||||
You are not responsible for enforcing compliance by third parties with |
||||
this License. |
||||
|
||||
11. If, as a consequence of a court judgment or allegation of patent |
||||
infringement or for any other reason (not limited to patent issues), |
||||
conditions are imposed on you (whether by court order, agreement or |
||||
otherwise) that contradict the conditions of this License, they do not |
||||
excuse you from the conditions of this License. If you cannot |
||||
distribute so as to satisfy simultaneously your obligations under this |
||||
License and any other pertinent obligations, then as a consequence you |
||||
may not distribute the Library at all. For example, if a patent |
||||
license would not permit royalty-free redistribution of the Library by |
||||
all those who receive copies directly or indirectly through you, then |
||||
the only way you could satisfy both it and this License would be to |
||||
refrain entirely from distribution of the Library. |
||||
|
||||
If any portion of this section is held invalid or unenforceable under any |
||||
particular circumstance, the balance of the section is intended to apply, |
||||
and the section as a whole is intended to apply in other circumstances. |
||||
|
||||
It is not the purpose of this section to induce you to infringe any |
||||
patents or other property right claims or to contest validity of any |
||||
such claims; this section has the sole purpose of protecting the |
||||
integrity of the free software distribution system which is |
||||
implemented by public license practices. Many people have made |
||||
generous contributions to the wide range of software distributed |
||||
through that system in reliance on consistent application of that |
||||
system; it is up to the author/donor to decide if he or she is willing |
||||
to distribute software through any other system and a licensee cannot |
||||
impose that choice. |
||||
|
||||
This section is intended to make thoroughly clear what is believed to |
||||
be a consequence of the rest of this License. |
||||
|
||||
12. If the distribution and/or use of the Library is restricted in |
||||
certain countries either by patents or by copyrighted interfaces, the |
||||
original copyright holder who places the Library under this License may add |
||||
an explicit geographical distribution limitation excluding those countries, |
||||
so that distribution is permitted only in or among countries not thus |
||||
excluded. In such case, this License incorporates the limitation as if |
||||
written in the body of this License. |
||||
|
||||
13. The Free Software Foundation may publish revised and/or new |
||||
versions of the Lesser General Public License from time to time. |
||||
Such new versions will be similar in spirit to the present version, |
||||
but may differ in detail to address new problems or concerns. |
||||
|
||||
Each version is given a distinguishing version number. If the Library |
||||
specifies a version number of this License which applies to it and |
||||
"any later version", you have the option of following the terms and |
||||
conditions either of that version or of any later version published by |
||||
the Free Software Foundation. If the Library does not specify a |
||||
license version number, you may choose any version ever published by |
||||
the Free Software Foundation. |
||||
|
||||
14. If you wish to incorporate parts of the Library into other free |
||||
programs whose distribution conditions are incompatible with these, |
||||
write to the author to ask for permission. For software which is |
||||
copyrighted by the Free Software Foundation, write to the Free |
||||
Software Foundation; we sometimes make exceptions for this. Our |
||||
decision will be guided by the two goals of preserving the free status |
||||
of all derivatives of our free software and of promoting the sharing |
||||
and reuse of software generally. |
||||
|
||||
NO WARRANTY |
||||
|
||||
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO |
||||
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. |
||||
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR |
||||
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY |
||||
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE |
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE |
||||
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME |
||||
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. |
||||
|
||||
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN |
||||
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY |
||||
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU |
||||
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR |
||||
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE |
||||
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING |
||||
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A |
||||
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF |
||||
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
||||
DAMAGES. |
||||
|
||||
END OF TERMS AND CONDITIONS |
||||
|
||||
How to Apply These Terms to Your New Libraries |
||||
|
||||
If you develop a new library, and you want it to be of the greatest |
||||
possible use to the public, we recommend making it free software that |
||||
everyone can redistribute and change. You can do so by permitting |
||||
redistribution under these terms (or, alternatively, under the terms of the |
||||
ordinary General Public License). |
||||
|
||||
To apply these terms, attach the following notices to the library. It is |
||||
safest to attach them to the start of each source file to most effectively |
||||
convey the exclusion of warranty; and each file should have at least the |
||||
"copyright" line and a pointer to where the full notice is found. |
||||
|
||||
{description} |
||||
Copyright (C) {year} {fullname} |
||||
|
||||
This library is free software; you can redistribute it and/or |
||||
modify it under the terms of the GNU Lesser General Public |
||||
License as published by the Free Software Foundation; either |
||||
version 2.1 of the License, or (at your option) any later version. |
||||
|
||||
This library is distributed in the hope that it will be useful, |
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
Lesser General Public License for more details. |
||||
|
||||
You should have received a copy of the GNU Lesser General Public |
||||
License along with this library; if not, write to the Free Software |
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 |
||||
USA |
||||
|
||||
Also add information on how to contact you by electronic and paper mail. |
||||
|
||||
You should also get your employer (if you work as a programmer) or your |
||||
school, if any, to sign a "copyright disclaimer" for the library, if |
||||
necessary. Here is a sample; alter the names: |
||||
|
||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the |
||||
library `Frob' (a library for tweaking knobs) written by James Random |
||||
Hacker. |
||||
|
||||
{signature of Ty Coon}, 1 April 1990 |
||||
Ty Coon, President of Vice |
||||
|
||||
That's all there is to it! |
@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE |
||||
Version 3, 29 June 2007 |
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
||||
Everyone is permitted to copy and distribute verbatim copies |
||||
of this license document, but changing it is not allowed. |
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates |
||||
the terms and conditions of version 3 of the GNU General Public |
||||
License, supplemented by the additional permissions listed below. |
||||
|
||||
0. Additional Definitions. |
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser |
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU |
||||
General Public License. |
||||
|
||||
"The Library" refers to a covered work governed by this License, |
||||
other than an Application or a Combined Work as defined below. |
||||
|
||||
An "Application" is any work that makes use of an interface provided |
||||
by the Library, but which is not otherwise based on the Library. |
||||
Defining a subclass of a class defined by the Library is deemed a mode |
||||
of using an interface provided by the Library. |
||||
|
||||
A "Combined Work" is a work produced by combining or linking an |
||||
Application with the Library. The particular version of the Library |
||||
with which the Combined Work was made is also called the "Linked |
||||
Version". |
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the |
||||
Corresponding Source for the Combined Work, excluding any source code |
||||
for portions of the Combined Work that, considered in isolation, are |
||||
based on the Application, and not on the Linked Version. |
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the |
||||
object code and/or source code for the Application, including any data |
||||
and utility programs needed for reproducing the Combined Work from the |
||||
Application, but excluding the System Libraries of the Combined Work. |
||||
|
||||
1. Exception to Section 3 of the GNU GPL. |
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License |
||||
without being bound by section 3 of the GNU GPL. |
||||
|
||||
2. Conveying Modified Versions. |
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a |
||||
facility refers to a function or data to be supplied by an Application |
||||
that uses the facility (other than as an argument passed when the |
||||
facility is invoked), then you may convey a copy of the modified |
||||
version: |
||||
|
||||
a) under this License, provided that you make a good faith effort to |
||||
ensure that, in the event an Application does not supply the |
||||
function or data, the facility still operates, and performs |
||||
whatever part of its purpose remains meaningful, or |
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of |
||||
this License applicable to that copy. |
||||
|
||||
3. Object Code Incorporating Material from Library Header Files. |
||||
|
||||
The object code form of an Application may incorporate material from |
||||
a header file that is part of the Library. You may convey such object |
||||
code under terms of your choice, provided that, if the incorporated |
||||
material is not limited to numerical parameters, data structure |
||||
layouts and accessors, or small macros, inline functions and templates |
||||
(ten or fewer lines in length), you do both of the following: |
||||
|
||||
a) Give prominent notice with each copy of the object code that the |
||||
Library is used in it and that the Library and its use are |
||||
covered by this License. |
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license |
||||
document. |
||||
|
||||
4. Combined Works. |
||||
|
||||
You may convey a Combined Work under terms of your choice that, |
||||
taken together, effectively do not restrict modification of the |
||||
portions of the Library contained in the Combined Work and reverse |
||||
engineering for debugging such modifications, if you also do each of |
||||
the following: |
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that |
||||
the Library is used in it and that the Library and its use are |
||||
covered by this License. |
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license |
||||
document. |
||||
|
||||
c) For a Combined Work that displays copyright notices during |
||||
execution, include the copyright notice for the Library among |
||||
these notices, as well as a reference directing the user to the |
||||
copies of the GNU GPL and this license document. |
||||
|
||||
d) Do one of the following: |
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this |
||||
License, and the Corresponding Application Code in a form |
||||
suitable for, and under terms that permit, the user to |
||||
recombine or relink the Application with a modified version of |
||||
the Linked Version to produce a modified Combined Work, in the |
||||
manner specified by section 6 of the GNU GPL for conveying |
||||
Corresponding Source. |
||||
|
||||
1) Use a suitable shared library mechanism for linking with the |
||||
Library. A suitable mechanism is one that (a) uses at run time |
||||
a copy of the Library already present on the user's computer |
||||
system, and (b) will operate properly with a modified version |
||||
of the Library that is interface-compatible with the Linked |
||||
Version. |
||||
|
||||
e) Provide Installation Information, but only if you would otherwise |
||||
be required to provide such information under section 6 of the |
||||
GNU GPL, and only to the extent that such information is |
||||
necessary to install and execute a modified version of the |
||||
Combined Work produced by recombining or relinking the |
||||
Application with a modified version of the Linked Version. (If |
||||
you use option 4d0, the Installation Information must accompany |
||||
the Minimal Corresponding Source and Corresponding Application |
||||
Code. If you use option 4d1, you must provide the Installation |
||||
Information in the manner specified by section 6 of the GNU GPL |
||||
for conveying Corresponding Source.) |
||||
|
||||
5. Combined Libraries. |
||||
|
||||
You may place library facilities that are a work based on the |
||||
Library side by side in a single library together with other library |
||||
facilities that are not Applications and are not covered by this |
||||
License, and convey such a combined library under terms of your |
||||
choice, if you do both of the following: |
||||
|
||||
a) Accompany the combined library with a copy of the same work based |
||||
on the Library, uncombined with any other library facilities, |
||||
conveyed under the terms of this License. |
||||
|
||||
b) Give prominent notice with the combined library that part of it |
||||
is a work based on the Library, and explaining where to find the |
||||
accompanying uncombined form of the same work. |
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License. |
||||
|
||||
The Free Software Foundation may publish revised and/or new versions |
||||
of the GNU Lesser General Public License from time to time. Such new |
||||
versions will be similar in spirit to the present version, but may |
||||
differ in detail to address new problems or concerns. |
||||
|
||||
Each version is given a distinguishing version number. If the |
||||
Library as you received it specifies that a certain numbered version |
||||
of the GNU Lesser General Public License "or any later version" |
||||
applies to it, you have the option of following the terms and |
||||
conditions either of that published version or of any later version |
||||
published by the Free Software Foundation. If the Library as you |
||||
received it does not specify a version number of the GNU Lesser |
||||
General Public License, you may choose any version of the GNU Lesser |
||||
General Public License ever published by the Free Software Foundation. |
||||
|
||||
If the Library as you received it specifies that a proxy can decide |
||||
whether future versions of the GNU Lesser General Public License shall |
||||
apply, that proxy's public statement of acceptance of any version is |
||||
permanent authorization for you to choose that version for the |
||||
Library. |
@ -0,0 +1,362 @@
|
||||
Mozilla Public License, version 2.0 |
||||
|
||||
1. Definitions |
||||
|
||||
1.1. "Contributor" |
||||
|
||||
means each individual or legal entity that creates, contributes to the |
||||
creation of, or owns Covered Software. |
||||
|
||||
1.2. "Contributor Version" |
||||
|
||||
means the combination of the Contributions of others (if any) used by a |
||||
Contributor and that particular Contributor's Contribution. |
||||
|
||||
1.3. "Contribution" |
||||
|
||||
means Covered Software of a particular Contributor. |
||||
|
||||
1.4. "Covered Software" |
||||
|
||||
means Source Code Form to which the initial Contributor has attached the |
||||
notice in Exhibit A, the Executable Form of such Source Code Form, and |
||||
Modifications of such Source Code Form, in each case including portions |
||||
thereof. |
||||
|
||||
1.5. "Incompatible With Secondary Licenses" |
||||
means |
||||
|
||||
a. that the initial Contributor has attached the notice described in |
||||
Exhibit B to the Covered Software; or |
||||
|
||||
b. that the Covered Software was made available under the terms of |
||||
version 1.1 or earlier of the License, but not also under the terms of |
||||
a Secondary License. |
||||
|
||||
1.6. "Executable Form" |
||||
|
||||
means any form of the work other than Source Code Form. |
||||
|
||||
1.7. "Larger Work" |
||||
|
||||
means a work that combines Covered Software with other material, in a |
||||
separate file or files, that is not Covered Software. |
||||
|
||||
1.8. "License" |
||||
|
||||
means this document. |
||||
|
||||
1.9. "Licensable" |
||||
|
||||
means having the right to grant, to the maximum extent possible, whether |
||||
at the time of the initial grant or subsequently, any and all of the |
||||
rights conveyed by this License. |
||||
|
||||
1.10. "Modifications" |
||||
|
||||
means any of the following: |
||||
|
||||
a. any file in Source Code Form that results from an addition to, |
||||
deletion from, or modification of the contents of Covered Software; or |
||||
|
||||
b. any new file in Source Code Form that contains any Covered Software. |
||||
|
||||
1.11. "Patent Claims" of a Contributor |
||||
|
||||
means any patent claim(s), including without limitation, method, |
||||
process, and apparatus claims, in any patent Licensable by such |
||||
Contributor that would be infringed, but for the grant of the License, |
||||
by the making, using, selling, offering for sale, having made, import, |
||||
or transfer of either its Contributions or its Contributor Version. |
||||
|
||||
1.12. "Secondary License" |
||||
|
||||
means either the GNU General Public License, Version 2.0, the GNU Lesser |
||||
General Public License, Version 2.1, the GNU Affero General Public |
||||
License, Version 3.0, or any later versions of those licenses. |
||||
|
||||
1.13. "Source Code Form" |
||||
|
||||
means the form of the work preferred for making modifications. |
||||
|
||||
1.14. "You" (or "Your") |
||||
|
||||
means an individual or a legal entity exercising rights under this |
||||
License. For legal entities, "You" includes any entity that controls, is |
||||
controlled by, or is under common control with You. For purposes of this |
||||
definition, "control" means (a) the power, direct or indirect, to cause |
||||
the direction or management of such entity, whether by contract or |
||||
otherwise, or (b) ownership of more than fifty percent (50%) of the |
||||
outstanding shares or beneficial ownership of such entity. |
||||
|
||||
|
||||
2. License Grants and Conditions |
||||
|
||||
2.1. Grants |
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free, |
||||
non-exclusive license: |
||||
|
||||
a. under intellectual property rights (other than patent or trademark) |
||||
Licensable by such Contributor to use, reproduce, make available, |
||||
modify, display, perform, distribute, and otherwise exploit its |
||||
Contributions, either on an unmodified basis, with Modifications, or |
||||
as part of a Larger Work; and |
||||
|
||||
b. under Patent Claims of such Contributor to make, use, sell, offer for |
||||
sale, have made, import, and otherwise transfer either its |
||||
Contributions or its Contributor Version. |
||||
|
||||
2.2. Effective Date |
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution |
||||
become effective for each Contribution on the date the Contributor first |
||||
distributes such Contribution. |
||||
|
||||
2.3. Limitations on Grant Scope |
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under |
||||
this License. No additional rights or licenses will be implied from the |
||||
distribution or licensing of Covered Software under this License. |
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a |
||||
Contributor: |
||||
|
||||
a. for any code that a Contributor has removed from Covered Software; or |
||||
|
||||
b. for infringements caused by: (i) Your and any other third party's |
||||
modifications of Covered Software, or (ii) the combination of its |
||||
Contributions with other software (except as part of its Contributor |
||||
Version); or |
||||
|
||||
c. under Patent Claims infringed by Covered Software in the absence of |
||||
its Contributions. |
||||
|
||||
This License does not grant any rights in the trademarks, service marks, |
||||
or logos of any Contributor (except as may be necessary to comply with |
||||
the notice requirements in Section 3.4). |
||||
|
||||
2.4. Subsequent Licenses |
||||
|
||||
No Contributor makes additional grants as a result of Your choice to |
||||
distribute the Covered Software under a subsequent version of this |
||||
License (see Section 10.2) or under the terms of a Secondary License (if |
||||
permitted under the terms of Section 3.3). |
||||
|
||||
2.5. Representation |
||||
|
||||
Each Contributor represents that the Contributor believes its |
||||
Contributions are its original creation(s) or it has sufficient rights to |
||||
grant the rights to its Contributions conveyed by this License. |
||||
|
||||
2.6. Fair Use |
||||
|
||||
This License is not intended to limit any rights You have under |
||||
applicable copyright doctrines of fair use, fair dealing, or other |
||||
equivalents. |
||||
|
||||
2.7. Conditions |
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted in |
||||
Section 2.1. |
||||
|
||||
|
||||
3. Responsibilities |
||||
|
||||
3.1. Distribution of Source Form |
||||
|
||||
All distribution of Covered Software in Source Code Form, including any |
||||
Modifications that You create or to which You contribute, must be under |
||||
the terms of this License. You must inform recipients that the Source |
||||
Code Form of the Covered Software is governed by the terms of this |
||||
License, and how they can obtain a copy of this License. You may not |
||||
attempt to alter or restrict the recipients' rights in the Source Code |
||||
Form. |
||||
|
||||
3.2. Distribution of Executable Form |
||||
|
||||
If You distribute Covered Software in Executable Form then: |
||||
|
||||
a. such Covered Software must also be made available in Source Code Form, |
||||
as described in Section 3.1, and You must inform recipients of the |
||||
Executable Form how they can obtain a copy of such Source Code Form by |
||||
reasonable means in a timely manner, at a charge no more than the cost |
||||
of distribution to the recipient; and |
||||
|
||||
b. You may distribute such Executable Form under the terms of this |
||||
License, or sublicense it under different terms, provided that the |
||||
license for the Executable Form does not attempt to limit or alter the |
||||
recipients' rights in the Source Code Form under this License. |
||||
|
||||
3.3. Distribution of a Larger Work |
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice, |
||||
provided that You also comply with the requirements of this License for |
||||
the Covered Software. If the Larger Work is a combination of Covered |
||||
Software with a work governed by one or more Secondary Licenses, and the |
||||
Covered Software is not Incompatible With Secondary Licenses, this |
||||
License permits You to additionally distribute such Covered Software |
||||
under the terms of such Secondary License(s), so that the recipient of |
||||
the Larger Work may, at their option, further distribute the Covered |
||||
Software under the terms of either this License or such Secondary |
||||
License(s). |
||||
|
||||
3.4. Notices |
||||
|
||||
You may not remove or alter the substance of any license notices |
||||
(including copyright notices, patent notices, disclaimers of warranty, or |
||||
limitations of liability) contained within the Source Code Form of the |
||||
Covered Software, except that You may alter any license notices to the |
||||
extent required to remedy known factual inaccuracies. |
||||
|
||||
3.5. Application of Additional Terms |
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support, |
||||
indemnity or liability obligations to one or more recipients of Covered |
||||
Software. However, You may do so only on Your own behalf, and not on |
||||
behalf of any Contributor. You must make it absolutely clear that any |
||||
such warranty, support, indemnity, or liability obligation is offered by |
||||
You alone, and You hereby agree to indemnify every Contributor for any |
||||
liability incurred by such Contributor as a result of warranty, support, |
||||
indemnity or liability terms You offer. You may include additional |
||||
disclaimers of warranty and limitations of liability specific to any |
||||
jurisdiction. |
||||
|
||||
4. Inability to Comply Due to Statute or Regulation |
||||
|
||||
If it is impossible for You to comply with any of the terms of this License |
||||
with respect to some or all of the Covered Software due to statute, |
||||
judicial order, or regulation then You must: (a) comply with the terms of |
||||
this License to the maximum extent possible; and (b) describe the |
||||
limitations and the code they affect. Such description must be placed in a |
||||
text file included with all distributions of the Covered Software under |
||||
this License. Except to the extent prohibited by statute or regulation, |
||||
such description must be sufficiently detailed for a recipient of ordinary |
||||
skill to be able to understand it. |
||||
|
||||
5. Termination |
||||
|
||||
5.1. The rights granted under this License will terminate automatically if You |
||||
fail to comply with any of its terms. However, if You become compliant, |
||||
then the rights granted under this License from a particular Contributor |
||||
are reinstated (a) provisionally, unless and until such Contributor |
||||
explicitly and finally terminates Your grants, and (b) on an ongoing |
||||
basis, if such Contributor fails to notify You of the non-compliance by |
||||
some reasonable means prior to 60 days after You have come back into |
||||
compliance. Moreover, Your grants from a particular Contributor are |
||||
reinstated on an ongoing basis if such Contributor notifies You of the |
||||
non-compliance by some reasonable means, this is the first time You have |
||||
received notice of non-compliance with this License from such |
||||
Contributor, and You become compliant prior to 30 days after Your receipt |
||||
of the notice. |
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent |
||||
infringement claim (excluding declaratory judgment actions, |
||||
counter-claims, and cross-claims) alleging that a Contributor Version |
||||
directly or indirectly infringes any patent, then the rights granted to |
||||
You by any and all Contributors for the Covered Software under Section |
||||
2.1 of this License shall terminate. |
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all end user |
||||
license agreements (excluding distributors and resellers) which have been |
||||
validly granted by You or Your distributors under this License prior to |
||||
termination shall survive termination. |
||||
|
||||
6. Disclaimer of Warranty |
||||
|
||||
Covered Software is provided under this License on an "as is" basis, |
||||
without warranty of any kind, either expressed, implied, or statutory, |
||||
including, without limitation, warranties that the Covered Software is free |
||||
of defects, merchantable, fit for a particular purpose or non-infringing. |
||||
The entire risk as to the quality and performance of the Covered Software |
||||
is with You. Should any Covered Software prove defective in any respect, |
||||
You (not any Contributor) assume the cost of any necessary servicing, |
||||
repair, or correction. This disclaimer of warranty constitutes an essential |
||||
part of this License. No use of any Covered Software is authorized under |
||||
this License except under this disclaimer. |
||||
|
||||
7. Limitation of Liability |
||||
|
||||
Under no circumstances and under no legal theory, whether tort (including |
||||
negligence), contract, or otherwise, shall any Contributor, or anyone who |
||||
distributes Covered Software as permitted above, be liable to You for any |
||||
direct, indirect, special, incidental, or consequential damages of any |
||||
character including, without limitation, damages for lost profits, loss of |
||||
goodwill, work stoppage, computer failure or malfunction, or any and all |
||||
other commercial damages or losses, even if such party shall have been |
||||
informed of the possibility of such damages. This limitation of liability |
||||
shall not apply to liability for death or personal injury resulting from |
||||
such party's negligence to the extent applicable law prohibits such |
||||
limitation. Some jurisdictions do not allow the exclusion or limitation of |
||||
incidental or consequential damages, so this exclusion and limitation may |
||||
not apply to You. |
||||
|
||||
8. Litigation |
||||
|
||||
Any litigation relating to this License may be brought only in the courts |
||||
of a jurisdiction where the defendant maintains its principal place of |
||||
business and such litigation shall be governed by laws of that |
||||
jurisdiction, without reference to its conflict-of-law provisions. Nothing |
||||
in this Section shall prevent a party's ability to bring cross-claims or |
||||
counter-claims. |
||||
|
||||
9. Miscellaneous |
||||
|
||||
This License represents the complete agreement concerning the subject |
||||
matter hereof. If any provision of this License is held to be |
||||
unenforceable, such provision shall be reformed only to the extent |
||||
necessary to make it enforceable. Any law or regulation which provides that |
||||
the language of a contract shall be construed against the drafter shall not |
||||
be used to construe this License against a Contributor. |
||||
|
||||
|
||||
10. Versions of the License |
||||
|
||||
10.1. New Versions |
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section |
||||
10.3, no one other than the license steward has the right to modify or |
||||
publish new versions of this License. Each version will be given a |
||||
distinguishing version number. |
||||
|
||||
10.2. Effect of New Versions |
||||
|
||||
You may distribute the Covered Software under the terms of the version |
||||
of the License under which You originally received the Covered Software, |
||||
or under the terms of any subsequent version published by the license |
||||
steward. |
||||
|
||||
10.3. Modified Versions |
||||
|
||||
If you create software not governed by this License, and you want to |
||||
create a new license for such software, you may create and use a |
||||
modified version of this License if you rename the license and remove |
||||
any references to the name of the license steward (except to note that |
||||
such modified license differs from this License). |
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary |
||||
Licenses If You choose to distribute Source Code Form that is |
||||
Incompatible With Secondary Licenses under the terms of this version of |
||||
the License, the notice described in Exhibit B of this License must be |
||||
attached. |
||||
|
||||
Exhibit A - Source Code Form License Notice |
||||
|
||||
This Source Code Form is subject to the |
||||
terms of the Mozilla Public License, v. |
||||
2.0. If a copy of the MPL was not |
||||
distributed with this file, You can |
||||
obtain one at |
||||
http://mozilla.org/MPL/2.0/. |
||||
|
||||
If it is not possible or desirable to put the notice in a particular file, |
||||
then You may include the notice in a location (such as a LICENSE file in a |
||||
relevant directory) where a recipient would be likely to look for such a |
||||
notice. |
||||
|
||||
You may add additional accurate notices of copyright ownership. |
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice |
||||
|
||||
This Source Code Form is "Incompatible |
||||
With Secondary Licenses", as defined by |
||||
the Mozilla Public License, v. 2.0. |
@ -0,0 +1,177 @@
|
||||
app_desc = A painless self-hosted Git service written in Go |
||||
|
||||
home = Home |
||||
dashboard = Dashboard |
||||
explore = Explore |
||||
help = Help |
||||
sign_in = Sign In |
||||
sign_out = Sign Out |
||||
sign_up = Sign Up |
||||
register = Register |
||||
website = Website |
||||
version = Version |
||||
page = Page |
||||
template = Template |
||||
language = Language |
||||
|
||||
username = Username |
||||
email = E-mail |
||||
password = Password |
||||
re_type = Re-Type |
||||
captcha = Captcha |
||||
|
||||
repository = Repository |
||||
organization = Organization |
||||
mirror = Mirror |
||||
new_repo = New Repository |
||||
new_migrate = New Migration |
||||
new_org = New Organization |
||||
manage_org = Manage Organizations |
||||
admin_panel = Admin Panel |
||||
account_settings = Account Settings |
||||
settings = Settings |
||||
|
||||
news_feed = News Feed |
||||
pull_requests = Pull Requests |
||||
issues = Issues |
||||
|
||||
cancel = Cancel |
||||
|
||||
[home] |
||||
uname_holder = Username or E-mail |
||||
password_holder = Password |
||||
switch_dashboard_context = Switch Dashboard Context |
||||
my_repos = My Repositories |
||||
collaborative_repos = Collaborative Repositories |
||||
my_orgs = My Organizations |
||||
my_mirrors = My Mirrors |
||||
|
||||
[auth] |
||||
create_new_account = Create New Account |
||||
register_hepler_msg = Already have an account? Sign in now! |
||||
disable_register_prompt = Sorry, registration has been disabled. Please contact the site administrator. |
||||
remember_me = Remember Me |
||||
forget_password = Fotget password? |
||||
sign_up_now = Need an account? Sign up now. |
||||
|
||||
[form] |
||||
UserName = Username |
||||
Email = E-mail address |
||||
Password = Password |
||||
Retype = Re-type password |
||||
SSHTitle = SSH key name |
||||
|
||||
require_error = ` cannot be empty.` |
||||
alpha_dash_error = ` must be valid alpha or numeric or dash(-_) characters.` |
||||
alpha_dash_dot_error = ` must be valid alpha or numeric or dash(-_) or dot characters.` |
||||
min_size_error = ` must contain at least %s characters.` |
||||
max_size_error = ` must contain at most %s characters.` |
||||
email_error = ` is not a valid e-mail address.` |
||||
url_error = ` is not a valid URL.` |
||||
unknown_error = Unknown error: |
||||
captcha_incorrect = Captcha didn't match. |
||||
password_not_match = Password and re-type password are not same. |
||||
|
||||
username_been_taken = Username has been already taken. |
||||
repo_name_been_taken = Repository name has been already taken. |
||||
email_been_used = E-mail address has been already used. |
||||
ssh_key_been_used = Public key name has been used. |
||||
illegal_username = Your username contains illegal characters. |
||||
illegal_repo_name = Repository name contains illegal characters. |
||||
username_password_incorrect = Username or password is not correct. |
||||
|
||||
invalid_ssh_key = Sorry, we're not able to verify your SSH key: %s |
||||
|
||||
still_own_repo = Your account still have ownership of repository, you have to delete or transfer them first. |
||||
|
||||
[settings] |
||||
profile = Profile |
||||
password = Password |
||||
ssh_keys = SSH Keys |
||||
social = Social Accounts |
||||
delete = Delete Accoount |
||||
|
||||
public_profile = Public Profile |
||||
profile_desc = Your Email address is public and will be used for any account related notifications, and any web based operations made via the site. |
||||
full_name = Full Name |
||||
website = Website |
||||
location = Location |
||||
update_profile = Update Profile |
||||
update_profile_success = Your profile has been successfully updated. |
||||
|
||||
change_password = Change Password |
||||
old_password = Current Password |
||||
new_password = New Password |
||||
password_incorrect = Current password is not correct. |
||||
change_password_success = Password is changed successfully. You can now sign in via new password. |
||||
|
||||
manage_ssh_keys = Manage SSH Keys |
||||
add_key = Add Key |
||||
ssh_desc = This is a list of SSH keys associated with your account. Remove any keys that you do not recognize. |
||||
ssh_helper = <strong>Need help?</strong> Check out our guide to <a href="https://help.github.com/articles/generating-ssh-keys">generating SSH keys</a> or troubleshoot <a href="https://help.github.com/ssh-issues/">common SSH Problems</a>. |
||||
add_new_key = Add SSH Key |
||||
key_name = Key Name |
||||
key_content = Content |
||||
add_key_success = New SSH Key has been added! |
||||
delete_key = Delete |
||||
add_on = Added on |
||||
last_used = Last used on |
||||
no_activity = No recent activity |
||||
|
||||
manage_social = Manage Associated Social Accounts |
||||
|
||||
delete_account = Delete Your Account |
||||
delete_prompt = The operation will delete your account permanently, and <strong>CANNOT</strong> be undo! |
||||
confirm_delete_account = Confirm Deletion |
||||
|
||||
[repo] |
||||
owner = Owner |
||||
repo_name = Repository Name |
||||
repo_name_helper = Great repository names are short, memorable and <strong>unique</strong>. |
||||
visibility = Visibility |
||||
visiblity_helper = This repository is <span class="label label-red label-radius">Private</span> |
||||
repo_desc = Description |
||||
repo_lang = Language |
||||
repo_lang_helper = Select a .gitignore file |
||||
license = License |
||||
license_helper = Select a license file |
||||
init_readme = Initialize this repository with a README.md |
||||
create_repo = Create Repository |
||||
|
||||
[action] |
||||
create_repo = created repository <a href="/%s">%s</a> |
||||
commit_repo = pushed to <a href="/%s/src/%s">%s</a> at <a href="/%s">%s</a> |
||||
create_issue = opened issue <a href="/%s/issues/%s">%s#%s</a> |
||||
comment_issue = commented on issue <a href="/%s/issues/%s">%s#%s</a> |
||||
|
||||
[tool] |
||||
ago = ago |
||||
from_now = from now |
||||
now = now |
||||
1s = 1 second %s |
||||
1m = 1 mintue %s |
||||
1h = 1 hour %s |
||||
1d = 1 day %s |
||||
1w = 1 week %s |
||||
1mon = 1 month %s |
||||
1y = 1 year %s |
||||
seconds = %d seconds %s |
||||
minutes = %d minutes %s |
||||
hours = %d hours %s |
||||
days = %d days %s |
||||
weeks = %d weeks %s |
||||
months = %d months %s |
||||
years = %d years %s |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,176 @@
|
||||
app_desc = 基于 Go 语言的自助 Git 服务 |
||||
|
||||
home = 首页 |
||||
dashboard = 控制面板 |
||||
explore = 探索 |
||||
help = 帮助 |
||||
sign_in = 登录 |
||||
sign_out = 退出 |
||||
sign_up = 注册 |
||||
register = 注册 |
||||
website = 官方网站 |
||||
version = 当前版本 |
||||
page = 页面 |
||||
template = 模板 |
||||
language = 语言选项 |
||||
|
||||
username = 用户名 |
||||
email = 邮箱 |
||||
password = 密码 |
||||
re_type = 确认密码 |
||||
captcha = 验证码 |
||||
|
||||
repository = 仓库 |
||||
organization = 组织 |
||||
mirror = 镜像 |
||||
new_repo = 创建新的仓库 |
||||
new_migrate = 迁移外部仓库 |
||||
new_org = 创建新的组织 |
||||
manage_org = 管理我的组织 |
||||
admin_panel = 管理面板 |
||||
account_settings = 帐户设置 |
||||
settings = 帐户设置 |
||||
|
||||
news_feed = 最新活动 |
||||
pull_requests = 合并请求 |
||||
issues = 工单管理 |
||||
|
||||
cancel = 取消 |
||||
|
||||
[home] |
||||
uname_holder = 用户名或邮箱 |
||||
password_holder = 密码 |
||||
switch_dashboard_context = 切换控制面板用户 |
||||
my_repos = 我的仓库 |
||||
collaborative_repos = 参与协作的仓库 |
||||
my_orgs = 我的组织 |
||||
my_mirrors = 我的镜像 |
||||
|
||||
[auth] |
||||
create_new_account = 创建帐户 |
||||
register_hepler_msg = 已经注册?立即登录! |
||||
disable_register_prompt = 对不起,注册功能已被关闭。请联系网站管理员。 |
||||
remember_me = 记住登录 |
||||
forget_password = 忘记密码? |
||||
sign_up_now = 还没帐户?马上注册。 |
||||
|
||||
[form] |
||||
UserName = 用户名 |
||||
Email = 邮箱地址 |
||||
Password = 密码 |
||||
Retype = 确认密码 |
||||
SSHTitle = SSH 密钥名称 |
||||
|
||||
require_error = 不能为空。 |
||||
alpha_dash_error = 必须为英文字母、阿拉伯数字或横线(-_)。 |
||||
alpha_dash_dot_error = 必须为英文字母、阿拉伯数字、横线(-_)或点。 |
||||
min_size_error = 长度最小为 %s 个字符。 |
||||
max_size_error = 长度最大为 %s 个字符。 |
||||
email_error = 不是一个有效的邮箱地址。 |
||||
url_error = 不是一个有效的 URL。 |
||||
unknown_error = 未知错误: |
||||
captcha_incorrect = 验证码未匹配。 |
||||
password_not_match = 密码与确认密码未匹配。 |
||||
|
||||
username_been_taken = 用户名已经被占用。 |
||||
repo_name_been_taken = 仓库名称已经被占用。 |
||||
email_been_used = 邮箱地址已经被使用。 |
||||
ssh_key_been_used = SSH 密钥已经被使用。 |
||||
illegal_username = 您的用户名包含非法字符。 |
||||
illegal_repo_name = 仓库名称包含非法字符。 |
||||
username_password_incorrect = 用户名或密码不正确。 |
||||
|
||||
invalid_ssh_key = 很抱歉,我们无法验证您输入的 SSH 密钥:%s |
||||
|
||||
still_own_repo = 您的帐户仍然是某些仓库的拥有者,您必须先转移或删除它们才能执行删除帐户操作! |
||||
|
||||
[settings] |
||||
profile = 个人信息 |
||||
password = 修改密码 |
||||
ssh_keys = 管理 SSH 密钥 |
||||
social = 社交帐号绑定 |
||||
delete = 删除帐户 |
||||
|
||||
public_profile = 公开信息 |
||||
profile_desc = 您的邮箱地址将会被公开,并被用于接收帐户的所有提醒和通知。 |
||||
full_name = 自定义名称 |
||||
website = 个人网站 |
||||
location = 所在地区 |
||||
update_profile = 更新信息 |
||||
update_profile_success = 您的个人信息已经更新成功! |
||||
|
||||
change_password = 修改密码 |
||||
old_password = 当前密码 |
||||
new_password = 新的密码 |
||||
password_incorrect = 当前密码不正确! |
||||
change_password_success = 密码修改成功!您现在可以使用新的密码登录。 |
||||
|
||||
manage_ssh_keys = 管理 SSH 密钥 |
||||
add_key = 增加密钥 |
||||
ssh_desc = 以下是与您帐户所关联的 SSH 密钥,如果您发现有陌生的密钥,请立即删除它! |
||||
ssh_helper = <strong>需要帮助?</strong> 请查看有关 <a href="https://help.github.com/articles/generating-ssh-keys">如何生成 SSH 密钥</a> 或 <a href="https://help.github.com/ssh-issues/">常见 SSH 问题</a> 寻找答案。 |
||||
add_new_key = 增加 SSH 密钥 |
||||
key_name = 密钥名称 |
||||
key_content = 密钥内容 |
||||
add_key_success = 新的 SSH 密钥添加成功! |
||||
delete_key = 删除 |
||||
add_on = 增加于 |
||||
last_used = 上次使用在 |
||||
no_activity = 没有最近活动 |
||||
|
||||
manage_social = 管理关联社交帐户 |
||||
|
||||
delete_account = 删除当前帐户 |
||||
delete_prompt = 删除操作会永久清除您的帐户信息,并且 <strong>不可恢复</strong>! |
||||
confirm_delete_account = 确认删除帐户 |
||||
|
||||
[repo] |
||||
owner = 拥有者 |
||||
repo_name = 仓库名称 |
||||
repo_name_helper = 伟大的仓库名称一般都较短、令人深刻并且 <strong>独一无二</strong> 的。 |
||||
visibility = 可见性 |
||||
visiblity_helper = 本仓库将是 <span class="label label-red label-radius">私有的</span> |
||||
repo_desc = 仓库描述 |
||||
repo_lang = 仓库语言 |
||||
repo_lang_helper = 请选择 .gitignore 文件 |
||||
license = 授权许可 |
||||
license_helper = 请选择授权许可文件 |
||||
init_readme = 使用 README.md 文件初始化仓库 |
||||
create_repo = 创建仓库 |
||||
|
||||
[action] |
||||
create_repo = 创建了仓库 <a href="/%s">%s</a> |
||||
commit_repo = 推送了 <a href="/%s/src/%s">%s</a> 分支的代码到 <a href="/%s">%s</a> |
||||
create_issue = 创建了工单 <a href="/%s/issues/%s">%s#%s</a> |
||||
comment_issue = 评论了工单 <a href="/%s/issues/%s">%s#%s</a> |
||||
|
||||
[tool] |
||||
ago = 之前 |
||||
from_now = 之后 |
||||
now = 现在 |
||||
1s = 1 秒%s |
||||
1m = 1 分钟%s |
||||
1h = 1 小时%s |
||||
1d = 1 天%s |
||||
1w = 1 周%s |
||||
1mon = 1 月%s |
||||
1y = 1 年%s |
||||
seconds = %d 秒%s |
||||
minutes = %d 分钟%s |
||||
hours = %d 小时%s |
||||
days = %d 天%s |
||||
weeks = %d 周%s |
||||
months = %d 月%s |
||||
years = %d 年%s |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,8 +0,0 @@
|
||||
[program:gogs] |
||||
user=git |
||||
command = /home/git/gogs/start.sh |
||||
directory = /home/git/gogs |
||||
autostart = true |
||||
stdout_logfile = /var/gogs.log |
||||
stderr_logfile = /var/gogs-error.log |
||||
environment=HOME="/home/git" |
@ -0,0 +1,36 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"github.com/Unknwon/macaron" |
||||
"github.com/macaron-contrib/i18n" |
||||
|
||||
"github.com/gogits/gogs/modules/middleware/binding" |
||||
) |
||||
|
||||
type AuthenticationForm struct { |
||||
Id int64 `form:"id"` |
||||
Type int `form:"type"` |
||||
AuthName string `form:"name" binding:"Required;MaxSize(50)"` |
||||
Domain string `form:"domain"` |
||||
Host string `form:"host"` |
||||
Port int `form:"port"` |
||||
UseSSL bool `form:"usessl"` |
||||
BaseDN string `form:"base_dn"` |
||||
Attributes string `form:"attributes"` |
||||
Filter string `form:"filter"` |
||||
MsAdSA string `form:"ms_ad_sa"` |
||||
IsActived bool `form:"is_actived"` |
||||
SmtpAuth string `form:"smtpauth"` |
||||
SmtpHost string `form:"smtphost"` |
||||
SmtpPort int `form:"smtpport"` |
||||
Tls bool `form:"tls"` |
||||
AllowAutoRegister bool `form:"allowautoregister"` |
||||
} |
||||
|
||||
func (f *AuthenticationForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
@ -1,33 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"net/http" |
||||
"reflect" |
||||
|
||||
"github.com/go-martini/martini" |
||||
|
||||
"github.com/gogits/gogs/modules/base" |
||||
"github.com/gogits/gogs/modules/middleware/binding" |
||||
) |
||||
|
||||
type AddSSHKeyForm struct { |
||||
KeyName string `form:"keyname" binding:"Required"` |
||||
KeyContent string `form:"key_content" binding:"Required"` |
||||
} |
||||
|
||||
func (f *AddSSHKeyForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"KeyName": "SSH key name", |
||||
"KeyContent": "SSH key content", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *AddSSHKeyForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
@ -0,0 +1,21 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"github.com/Unknwon/macaron" |
||||
"github.com/macaron-contrib/i18n" |
||||
|
||||
"github.com/gogits/gogs/modules/middleware/binding" |
||||
) |
||||
|
||||
type AddSSHKeyForm struct { |
||||
SSHTitle string `form:"title" binding:"Required"` |
||||
Content string `form:"content" binding:"Required"` |
||||
} |
||||
|
||||
func (f *AddSSHKeyForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
@ -1,252 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"net/http" |
||||
"reflect" |
||||
|
||||
"github.com/go-martini/martini" |
||||
|
||||
"github.com/gogits/gogs/modules/base" |
||||
"github.com/gogits/gogs/modules/middleware/binding" |
||||
) |
||||
|
||||
// __________ .__ __
|
||||
// \______ \ ____ ______ ____ _____|__|/ |_ ___________ ___.__.
|
||||
// | _// __ \\____ \ / _ \/ ___/ \ __\/ _ \_ __ < | |
|
||||
// | | \ ___/| |_> > <_> )___ \| || | ( <_> ) | \/\___ |
|
||||
// |____|_ /\___ > __/ \____/____ >__||__| \____/|__| / ____|
|
||||
// \/ \/|__| \/ \/
|
||||
|
||||
type CreateRepoForm struct { |
||||
Uid int64 `form:"uid" binding:"Required"` |
||||
RepoName string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"` |
||||
Private bool `form:"private"` |
||||
Description string `form:"desc" binding:"MaxSize(255)"` |
||||
Language string `form:"language"` |
||||
License string `form:"license"` |
||||
InitReadme bool `form:"initReadme"` |
||||
} |
||||
|
||||
func (f *CreateRepoForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"RepoName": "Repository name", |
||||
"Description": "Description", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *CreateRepoForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
type MigrateRepoForm struct { |
||||
Url string `form:"url" binding:"Url"` |
||||
AuthUserName string `form:"auth_username"` |
||||
AuthPasswd string `form:"auth_password"` |
||||
Uid int64 `form:"uid" binding:"Required"` |
||||
RepoName string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"` |
||||
Mirror bool `form:"mirror"` |
||||
Private bool `form:"private"` |
||||
Description string `form:"desc" binding:"MaxSize(255)"` |
||||
} |
||||
|
||||
func (f *MigrateRepoForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"Url": "Migration URL", |
||||
"RepoName": "Repository name", |
||||
"Description": "Description", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *MigrateRepoForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
type RepoSettingForm struct { |
||||
RepoName string `form:"name" binding:"Required;AlphaDash;MaxSize(100)"` |
||||
Description string `form:"desc" binding:"MaxSize(255)"` |
||||
Website string `form:"site" binding:"Url;MaxSize(100)"` |
||||
Branch string `form:"branch"` |
||||
Interval int `form:"interval"` |
||||
Private bool `form:"private"` |
||||
GoGet bool `form:"goget"` |
||||
} |
||||
|
||||
func (f *RepoSettingForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"RepoName": "Repository name", |
||||
"Description": "Description", |
||||
"Website": "Website address", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *RepoSettingForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
// __ __ ___. .__ .__ __
|
||||
// / \ / \ ____\_ |__ | |__ | |__ ____ | | __
|
||||
// \ \/\/ // __ \| __ \| | \| | \ / _ \| |/ /
|
||||
// \ /\ ___/| \_\ \ Y \ Y ( <_> ) <
|
||||
// \__/\ / \___ >___ /___| /___| /\____/|__|_ \
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type NewWebhookForm struct { |
||||
Url string `form:"url" binding:"Required;Url"` |
||||
ContentType string `form:"content_type" binding:"Required"` |
||||
Secret string `form:"secret""` |
||||
PushOnly bool `form:"push_only"` |
||||
Active bool `form:"active"` |
||||
} |
||||
|
||||
func (f *NewWebhookForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"Url": "Payload URL", |
||||
"ContentType": "Content type", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *NewWebhookForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
// .___
|
||||
// | | ______ ________ __ ____
|
||||
// | |/ ___// ___/ | \_/ __ \
|
||||
// | |\___ \ \___ \| | /\ ___/
|
||||
// |___/____ >____ >____/ \___ >
|
||||
// \/ \/ \/
|
||||
|
||||
type CreateIssueForm struct { |
||||
IssueName string `form:"title" binding:"Required;MaxSize(50)"` |
||||
MilestoneId int64 `form:"milestoneid"` |
||||
AssigneeId int64 `form:"assigneeid"` |
||||
Labels string `form:"labels"` |
||||
Content string `form:"content"` |
||||
} |
||||
|
||||
func (f *CreateIssueForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"IssueName": "Issue name", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *CreateIssueForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
// _____ .__.__ __
|
||||
// / \ |__| | ____ _______/ |_ ____ ____ ____
|
||||
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
|
||||
// / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/
|
||||
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type CreateMilestoneForm struct { |
||||
Title string `form:"title" binding:"Required;MaxSize(50)"` |
||||
Content string `form:"content"` |
||||
Deadline string `form:"due_date"` |
||||
} |
||||
|
||||
func (f *CreateMilestoneForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"Title": "Milestone name", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *CreateMilestoneForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
// .____ ___. .__
|
||||
// | | _____ \_ |__ ____ | |
|
||||
// | | \__ \ | __ \_/ __ \| |
|
||||
// | |___ / __ \| \_\ \ ___/| |__
|
||||
// |_______ (____ /___ /\___ >____/
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type CreateLabelForm struct { |
||||
Title string `form:"title" binding:"Required;MaxSize(50)"` |
||||
Color string `form:"color" binding:"Required;Size(7)"` |
||||
} |
||||
|
||||
func (f *CreateLabelForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"Title": "Label name", |
||||
"Color": "Label color", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *CreateLabelForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
// __________ .__
|
||||
// \______ \ ____ | | ____ _____ ______ ____
|
||||
// | _// __ \| | _/ __ \\__ \ / ___// __ \
|
||||
// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
|
||||
// |____|_ /\___ >____/\___ >____ /____ >\___ >
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type NewReleaseForm struct { |
||||
TagName string `form:"tag_name" binding:"Required"` |
||||
Target string `form:"tag_target" binding:"Required"` |
||||
Title string `form:"title" binding:"Required"` |
||||
Content string `form:"content" binding:"Required"` |
||||
Draft string `form:"draft"` |
||||
Prerelease bool `form:"prerelease"` |
||||
} |
||||
|
||||
func (f *NewReleaseForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"TagName": "Tag name", |
||||
"Target": "Target", |
||||
"Title": "Release title", |
||||
"Content": "Release content", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *NewReleaseForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
type EditReleaseForm struct { |
||||
Target string `form:"tag_target" binding:"Required"` |
||||
Title string `form:"title" binding:"Required"` |
||||
Content string `form:"content" binding:"Required"` |
||||
Draft string `form:"draft"` |
||||
Prerelease bool `form:"prerelease"` |
||||
} |
||||
|
||||
func (f *EditReleaseForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"Target": "Target", |
||||
"Title": "Release title", |
||||
"Content": "Release content", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *EditReleaseForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
@ -0,0 +1,165 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"github.com/Unknwon/macaron" |
||||
"github.com/macaron-contrib/i18n" |
||||
|
||||
"github.com/gogits/gogs/modules/middleware/binding" |
||||
) |
||||
|
||||
// _______________________________________ _________.______________________ _______________.___.
|
||||
// \______ \_ _____/\______ \_____ \ / _____/| \__ ___/\_____ \\______ \__ | |
|
||||
// | _/| __)_ | ___// | \ \_____ \ | | | | / | \| _// | |
|
||||
// | | \| \ | | / | \/ \| | | | / | \ | \\____ |
|
||||
// |____|_ /_______ / |____| \_______ /_______ /|___| |____| \_______ /____|_ // ______|
|
||||
// \/ \/ \/ \/ \/ \/ \/
|
||||
|
||||
type CreateRepoForm struct { |
||||
Uid int64 `form:"uid" binding:"Required"` |
||||
RepoName string `form:"repo_name" binding:"Required;AlphaDash;MaxSize(100)"` |
||||
Private bool `form:"private"` |
||||
Description string `form:"desc" binding:"MaxSize(255)"` |
||||
Gitignore string `form:"gitignore"` |
||||
License string `form:"license"` |
||||
InitReadme bool `form:"init_readme"` |
||||
} |
||||
|
||||
func (f *CreateRepoForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
type MigrateRepoForm struct { |
||||
Url string `form:"url" binding:"Url"` |
||||
AuthUserName string `form:"auth_username"` |
||||
AuthPasswd string `form:"auth_password"` |
||||
Uid int64 `form:"uid" binding:"Required"` |
||||
RepoName string `form:"repo" binding:"Required;AlphaDash;MaxSize(100)"` |
||||
Mirror bool `form:"mirror"` |
||||
Private bool `form:"private"` |
||||
Description string `form:"desc" binding:"MaxSize(255)"` |
||||
} |
||||
|
||||
func (f *MigrateRepoForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
type RepoSettingForm struct { |
||||
RepoName string `form:"name" binding:"Required;AlphaDash;MaxSize(100)"` |
||||
Description string `form:"desc" binding:"MaxSize(255)"` |
||||
Website string `form:"site" binding:"Url;MaxSize(100)"` |
||||
Branch string `form:"branch"` |
||||
Interval int `form:"interval"` |
||||
Private bool `form:"private"` |
||||
GoGet bool `form:"goget"` |
||||
} |
||||
|
||||
func (f *RepoSettingForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
// __ __ ___. .__ .__ __
|
||||
// / \ / \ ____\_ |__ | |__ | |__ ____ | | __
|
||||
// \ \/\/ // __ \| __ \| | \| | \ / _ \| |/ /
|
||||
// \ /\ ___/| \_\ \ Y \ Y ( <_> ) <
|
||||
// \__/\ / \___ >___ /___| /___| /\____/|__|_ \
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type NewWebhookForm struct { |
||||
Url string `form:"url" binding:"Required;Url"` |
||||
ContentType string `form:"content_type" binding:"Required"` |
||||
Secret string `form:"secret""` |
||||
PushOnly bool `form:"push_only"` |
||||
Active bool `form:"active"` |
||||
} |
||||
|
||||
func (f *NewWebhookForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
// .___
|
||||
// | | ______ ________ __ ____
|
||||
// | |/ ___// ___/ | \_/ __ \
|
||||
// | |\___ \ \___ \| | /\ ___/
|
||||
// |___/____ >____ >____/ \___ >
|
||||
// \/ \/ \/
|
||||
|
||||
type CreateIssueForm struct { |
||||
IssueName string `form:"title" binding:"Required;MaxSize(50)"` |
||||
MilestoneId int64 `form:"milestoneid"` |
||||
AssigneeId int64 `form:"assigneeid"` |
||||
Labels string `form:"labels"` |
||||
Content string `form:"content"` |
||||
} |
||||
|
||||
func (f *CreateIssueForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
// _____ .__.__ __
|
||||
// / \ |__| | ____ _______/ |_ ____ ____ ____
|
||||
// / \ / \| | | _/ __ \ / ___/\ __\/ _ \ / \_/ __ \
|
||||
// / Y \ | |_\ ___/ \___ \ | | ( <_> ) | \ ___/
|
||||
// \____|__ /__|____/\___ >____ > |__| \____/|___| /\___ >
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type CreateMilestoneForm struct { |
||||
Title string `form:"title" binding:"Required;MaxSize(50)"` |
||||
Content string `form:"content"` |
||||
Deadline string `form:"due_date"` |
||||
} |
||||
|
||||
func (f *CreateMilestoneForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
// .____ ___. .__
|
||||
// | | _____ \_ |__ ____ | |
|
||||
// | | \__ \ | __ \_/ __ \| |
|
||||
// | |___ / __ \| \_\ \ ___/| |__
|
||||
// |_______ (____ /___ /\___ >____/
|
||||
// \/ \/ \/ \/
|
||||
|
||||
type CreateLabelForm struct { |
||||
Title string `form:"title" binding:"Required;MaxSize(50)"` |
||||
Color string `form:"color" binding:"Required;Size(7)"` |
||||
} |
||||
|
||||
func (f *CreateLabelForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
// __________ .__
|
||||
// \______ \ ____ | | ____ _____ ______ ____
|
||||
// | _// __ \| | _/ __ \\__ \ / ___// __ \
|
||||
// | | \ ___/| |_\ ___/ / __ \_\___ \\ ___/
|
||||
// |____|_ /\___ >____/\___ >____ /____ >\___ >
|
||||
// \/ \/ \/ \/ \/ \/
|
||||
|
||||
type NewReleaseForm struct { |
||||
TagName string `form:"tag_name" binding:"Required"` |
||||
Target string `form:"tag_target" binding:"Required"` |
||||
Title string `form:"title" binding:"Required"` |
||||
Content string `form:"content" binding:"Required"` |
||||
Draft string `form:"draft"` |
||||
Prerelease bool `form:"prerelease"` |
||||
} |
||||
|
||||
func (f *NewReleaseForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
type EditReleaseForm struct { |
||||
Target string `form:"tag_target" binding:"Required"` |
||||
Title string `form:"title" binding:"Required"` |
||||
Content string `form:"content" binding:"Required"` |
||||
Draft string `form:"draft"` |
||||
Prerelease bool `form:"prerelease"` |
||||
} |
||||
|
||||
func (f *EditReleaseForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
@ -1,299 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"net/http" |
||||
"reflect" |
||||
"strings" |
||||
|
||||
"github.com/go-martini/martini" |
||||
|
||||
"github.com/gogits/session" |
||||
|
||||
"github.com/gogits/gogs/models" |
||||
"github.com/gogits/gogs/modules/base" |
||||
"github.com/gogits/gogs/modules/log" |
||||
"github.com/gogits/gogs/modules/middleware/binding" |
||||
"github.com/gogits/gogs/modules/setting" |
||||
) |
||||
|
||||
// Web form interface.
|
||||
type Form interface { |
||||
Name(field string) string |
||||
} |
||||
|
||||
type RegisterForm struct { |
||||
UserName string `form:"username" binding:"Required;AlphaDashDot;MaxSize(30)"` |
||||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` |
||||
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
RetypePasswd string `form:"retypepasswd"` |
||||
LoginType string `form:"logintype"` |
||||
LoginName string `form:"loginname"` |
||||
} |
||||
|
||||
func (f *RegisterForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"UserName": "Username", |
||||
"Email": "E-mail address", |
||||
"Password": "Password", |
||||
"RetypePasswd": "Re-type password", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *RegisterForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { |
||||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errs, data, f) |
||||
} |
||||
|
||||
type LogInForm struct { |
||||
UserName string `form:"username" binding:"Required;MaxSize(35)"` |
||||
Password string `form:"passwd" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
Remember bool `form:"remember"` |
||||
} |
||||
|
||||
func (f *LogInForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"UserName": "Username", |
||||
"Password": "Password", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *LogInForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { |
||||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errs, data, f) |
||||
} |
||||
|
||||
func GetMinMaxSize(field reflect.StructField) string { |
||||
for _, rule := range strings.Split(field.Tag.Get("binding"), ";") { |
||||
if strings.HasPrefix(rule, "MinSize(") || strings.HasPrefix(rule, "MaxSize(") { |
||||
return rule[8 : len(rule)-1] |
||||
} |
||||
} |
||||
return "" |
||||
} |
||||
|
||||
func validate(errs *binding.Errors, data base.TmplData, f Form) { |
||||
if errs.Count() == 0 { |
||||
return |
||||
} else if len(errs.Overall) > 0 { |
||||
for _, err := range errs.Overall { |
||||
log.Error("%s: %v", reflect.TypeOf(f), err) |
||||
} |
||||
return |
||||
} |
||||
|
||||
data["HasError"] = true |
||||
AssignForm(f, data) |
||||
|
||||
typ := reflect.TypeOf(f) |
||||
val := reflect.ValueOf(f) |
||||
|
||||
if typ.Kind() == reflect.Ptr { |
||||
typ = typ.Elem() |
||||
val = val.Elem() |
||||
} |
||||
|
||||
for i := 0; i < typ.NumField(); i++ { |
||||
field := typ.Field(i) |
||||
|
||||
fieldName := field.Tag.Get("form") |
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" { |
||||
continue |
||||
} |
||||
|
||||
if err, ok := errs.Fields[field.Name]; ok { |
||||
data["Err_"+field.Name] = true |
||||
switch err { |
||||
case binding.BindingRequireError: |
||||
data["ErrorMsg"] = f.Name(field.Name) + " cannot be empty" |
||||
case binding.BindingAlphaDashError: |
||||
data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) characters" |
||||
case binding.BindingAlphaDashDotError: |
||||
data["ErrorMsg"] = f.Name(field.Name) + " must be valid alpha or numeric or dash(-_) or dot characters" |
||||
case binding.BindingMinSizeError: |
||||
data["ErrorMsg"] = f.Name(field.Name) + " must contain at least " + GetMinMaxSize(field) + " characters" |
||||
case binding.BindingMaxSizeError: |
||||
data["ErrorMsg"] = f.Name(field.Name) + " must contain at most " + GetMinMaxSize(field) + " characters" |
||||
case binding.BindingEmailError: |
||||
data["ErrorMsg"] = f.Name(field.Name) + " is not a valid e-mail address" |
||||
case binding.BindingUrlError: |
||||
data["ErrorMsg"] = f.Name(field.Name) + " is not a valid URL" |
||||
default: |
||||
data["ErrorMsg"] = "Unknown error: " + err |
||||
} |
||||
return |
||||
} |
||||
} |
||||
} |
||||
|
||||
// AssignForm assign form values back to the template data.
|
||||
func AssignForm(form interface{}, data base.TmplData) { |
||||
typ := reflect.TypeOf(form) |
||||
val := reflect.ValueOf(form) |
||||
|
||||
if typ.Kind() == reflect.Ptr { |
||||
typ = typ.Elem() |
||||
val = val.Elem() |
||||
} |
||||
|
||||
for i := 0; i < typ.NumField(); i++ { |
||||
field := typ.Field(i) |
||||
|
||||
fieldName := field.Tag.Get("form") |
||||
// Allow ignored fields in the struct
|
||||
if fieldName == "-" { |
||||
continue |
||||
} |
||||
|
||||
data[fieldName] = val.Field(i).Interface() |
||||
} |
||||
} |
||||
|
||||
type InstallForm struct { |
||||
Database string `form:"database" binding:"Required"` |
||||
Host string `form:"host"` |
||||
User string `form:"user"` |
||||
Passwd string `form:"passwd"` |
||||
DatabaseName string `form:"database_name"` |
||||
SslMode string `form:"ssl_mode"` |
||||
DatabasePath string `form:"database_path"` |
||||
RepoRootPath string `form:"repo_path"` |
||||
RunUser string `form:"run_user"` |
||||
Domain string `form:"domain"` |
||||
AppUrl string `form:"app_url"` |
||||
AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"` |
||||
AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"` |
||||
SmtpHost string `form:"smtp_host"` |
||||
SmtpEmail string `form:"mailer_user"` |
||||
SmtpPasswd string `form:"mailer_pwd"` |
||||
RegisterConfirm string `form:"register_confirm"` |
||||
MailNotify string `form:"mail_notify"` |
||||
} |
||||
|
||||
func (f *InstallForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"Database": "Database name", |
||||
"AdminName": "Admin user name", |
||||
"AdminPasswd": "Admin password", |
||||
"AdminEmail": "Admin e-maill address", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *InstallForm) Validate(errors *binding.Errors, req *http.Request, context martini.Context) { |
||||
data := context.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errors, data, f) |
||||
} |
||||
|
||||
// SignedInId returns the id of signed in user.
|
||||
func SignedInId(header http.Header, sess session.SessionStore) int64 { |
||||
if !models.HasEngine { |
||||
return 0 |
||||
} |
||||
|
||||
if setting.Service.EnableReverseProxyAuth { |
||||
webAuthUser := header.Get(setting.ReverseProxyAuthUser) |
||||
if len(webAuthUser) > 0 { |
||||
u, err := models.GetUserByName(webAuthUser) |
||||
if err != nil { |
||||
if err != models.ErrUserNotExist { |
||||
log.Error("auth.user.SignedInId(GetUserByName): %v", err) |
||||
} |
||||
return 0 |
||||
} |
||||
return u.Id |
||||
} |
||||
} |
||||
|
||||
uid := sess.Get("userId") |
||||
if uid == nil { |
||||
return 0 |
||||
} |
||||
if id, ok := uid.(int64); ok { |
||||
if _, err := models.GetUserById(id); err != nil { |
||||
if err != models.ErrUserNotExist { |
||||
log.Error("auth.user.SignedInId(GetUserById): %v", err) |
||||
} |
||||
return 0 |
||||
} |
||||
return id |
||||
} |
||||
return 0 |
||||
} |
||||
|
||||
// SignedInUser returns the user object of signed user.
|
||||
func SignedInUser(header http.Header, sess session.SessionStore) *models.User { |
||||
uid := SignedInId(header, sess) |
||||
if uid <= 0 { |
||||
return nil |
||||
} |
||||
|
||||
u, err := models.GetUserById(uid) |
||||
if err != nil { |
||||
log.Error("user.SignedInUser: %v", err) |
||||
return nil |
||||
} |
||||
return u |
||||
} |
||||
|
||||
// IsSignedIn check if any user has signed in.
|
||||
func IsSignedIn(header http.Header, sess session.SessionStore) bool { |
||||
return SignedInId(header, sess) > 0 |
||||
} |
||||
|
||||
type FeedsForm struct { |
||||
UserId int64 `form:"userid" binding:"Required"` |
||||
Page int64 `form:"p"` |
||||
} |
||||
|
||||
type UpdateProfileForm struct { |
||||
UserName string `form:"username" binding:"Required;AlphaDash;MaxSize(30)"` |
||||
FullName string `form:"fullname" binding:"MaxSize(40)"` |
||||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` |
||||
Website string `form:"website" binding:"Url;MaxSize(50)"` |
||||
Location string `form:"location" binding:"MaxSize(50)"` |
||||
Avatar string `form:"avatar" binding:"Required;Email;MaxSize(50)"` |
||||
} |
||||
|
||||
func (f *UpdateProfileForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"UserName": "Username", |
||||
"Email": "E-mail address", |
||||
"Website": "Website address", |
||||
"Location": "Location", |
||||
"Avatar": "Gravatar Email", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *UpdateProfileForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { |
||||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errs, data, f) |
||||
} |
||||
|
||||
type UpdatePasswdForm struct { |
||||
OldPasswd string `form:"oldpasswd" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
NewPasswd string `form:"newpasswd" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
RetypePasswd string `form:"retypepasswd"` |
||||
} |
||||
|
||||
func (f *UpdatePasswdForm) Name(field string) string { |
||||
names := map[string]string{ |
||||
"OldPasswd": "Old password", |
||||
"NewPasswd": "New password", |
||||
"RetypePasswd": "Re-type password", |
||||
} |
||||
return names[field] |
||||
} |
||||
|
||||
func (f *UpdatePasswdForm) Validate(errs *binding.Errors, req *http.Request, ctx martini.Context) { |
||||
data := ctx.Get(reflect.TypeOf(base.TmplData{})).Interface().(base.TmplData) |
||||
validate(errs, data, f) |
||||
} |
@ -0,0 +1,98 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package auth |
||||
|
||||
import ( |
||||
"github.com/Unknwon/macaron" |
||||
"github.com/macaron-contrib/i18n" |
||||
|
||||
"github.com/gogits/gogs/modules/middleware/binding" |
||||
) |
||||
|
||||
type InstallForm struct { |
||||
Database string `form:"database" binding:"Required"` |
||||
Host string `form:"host"` |
||||
User string `form:"user"` |
||||
Passwd string `form:"passwd"` |
||||
DatabaseName string `form:"database_name"` |
||||
SslMode string `form:"ssl_mode"` |
||||
DatabasePath string `form:"database_path"` |
||||
RepoRootPath string `form:"repo_path"` |
||||
RunUser string `form:"run_user"` |
||||
Domain string `form:"domain"` |
||||
AppUrl string `form:"app_url"` |
||||
AdminName string `form:"admin_name" binding:"Required;AlphaDashDot;MaxSize(30)"` |
||||
AdminPasswd string `form:"admin_pwd" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
AdminEmail string `form:"admin_email" binding:"Required;Email;MaxSize(50)"` |
||||
SmtpHost string `form:"smtp_host"` |
||||
SmtpEmail string `form:"mailer_user"` |
||||
SmtpPasswd string `form:"mailer_pwd"` |
||||
RegisterConfirm string `form:"register_confirm"` |
||||
MailNotify string `form:"mail_notify"` |
||||
} |
||||
|
||||
func (f *InstallForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
// _____ ____ _________________ ___
|
||||
// / _ \ | | \__ ___/ | \
|
||||
// / /_\ \| | / | | / ~ \
|
||||
// / | \ | / | | \ Y /
|
||||
// \____|__ /______/ |____| \___|_ /
|
||||
// \/ \/
|
||||
|
||||
type RegisterForm struct { |
||||
UserName string `form:"uname" binding:"Required;AlphaDashDot;MaxSize(35)"` |
||||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` |
||||
Password string `form:"password" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
Retype string `form:"retype"` |
||||
LoginType string `form:"logintype"` |
||||
LoginName string `form:"loginname"` |
||||
} |
||||
|
||||
func (f *RegisterForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
type SignInForm struct { |
||||
UserName string `form:"uname" binding:"Required;MaxSize(35)"` |
||||
Password string `form:"password" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
Remember bool `form:"remember"` |
||||
} |
||||
|
||||
func (f *SignInForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
// __________________________________________.___ _______ ________ _________
|
||||
// / _____/\_ _____/\__ ___/\__ ___/| |\ \ / _____/ / _____/
|
||||
// \_____ \ | __)_ | | | | | |/ | \/ \ ___ \_____ \
|
||||
// / \ | \ | | | | | / | \ \_\ \/ \
|
||||
// /_______ //_______ / |____| |____| |___\____|__ /\______ /_______ /
|
||||
// \/ \/ \/ \/ \/
|
||||
|
||||
type UpdateProfileForm struct { |
||||
UserName string `form:"uname" binding:"Required;MaxSize(35)"` |
||||
FullName string `form:"fullname" binding:"MaxSize(40)"` |
||||
Email string `form:"email" binding:"Required;Email;MaxSize(50)"` |
||||
Website string `form:"website" binding:"Url;MaxSize(50)"` |
||||
Location string `form:"location" binding:"MaxSize(50)"` |
||||
Avatar string `form:"avatar" binding:"Required;Email;MaxSize(50)"` |
||||
} |
||||
|
||||
func (f *UpdateProfileForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
||||
|
||||
type ChangePasswordForm struct { |
||||
OldPassword string `form:"old_password" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
Password string `form:"password" binding:"Required;MinSize(6);MaxSize(30)"` |
||||
Retype string `form:"retype"` |
||||
} |
||||
|
||||
func (f *ChangePasswordForm) Validate(ctx *macaron.Context, errs *binding.Errors, l i18n.Locale) { |
||||
validate(errs, ctx.Data, f, l) |
||||
} |
@ -0,0 +1,201 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Package captcha a middleware that provides captcha service for Macaron.
|
||||
package captcha |
||||
|
||||
import ( |
||||
"fmt" |
||||
"html/template" |
||||
"net/http" |
||||
"path" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/macaron" |
||||
|
||||
"github.com/gogits/cache" |
||||
|
||||
"github.com/gogits/gogs/modules/base" |
||||
"github.com/gogits/gogs/modules/log" |
||||
) |
||||
|
||||
var ( |
||||
defaultChars = []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} |
||||
) |
||||
|
||||
const ( |
||||
// default captcha attributes
|
||||
challengeNums = 6 |
||||
expiration = 600 |
||||
fieldIdName = "captcha_id" |
||||
fieldCaptchaName = "captcha" |
||||
cachePrefix = "captcha_" |
||||
defaultURLPrefix = "/captcha/" |
||||
) |
||||
|
||||
// Captcha struct
|
||||
type Captcha struct { |
||||
store cache.Cache |
||||
|
||||
// url prefix for captcha image
|
||||
URLPrefix string |
||||
|
||||
// specify captcha id input field name
|
||||
FieldIdName string |
||||
// specify captcha result input field name
|
||||
FieldCaptchaName string |
||||
|
||||
// captcha image width and height
|
||||
StdWidth int |
||||
StdHeight int |
||||
|
||||
// captcha chars nums
|
||||
ChallengeNums int |
||||
|
||||
// captcha expiration seconds
|
||||
Expiration int64 |
||||
|
||||
// cache key prefix
|
||||
CachePrefix string |
||||
} |
||||
|
||||
// generate key string
|
||||
func (c *Captcha) key(id string) string { |
||||
return c.CachePrefix + id |
||||
} |
||||
|
||||
// generate rand chars with default chars
|
||||
func (c *Captcha) genRandChars() []byte { |
||||
return base.RandomCreateBytes(c.ChallengeNums, defaultChars...) |
||||
} |
||||
|
||||
// beego filter handler for serve captcha image
|
||||
func (c *Captcha) Handler(ctx *macaron.Context) { |
||||
var chars []byte |
||||
|
||||
id := path.Base(ctx.Req.RequestURI) |
||||
if i := strings.Index(id, "."); i != -1 { |
||||
id = id[:i] |
||||
} |
||||
|
||||
key := c.key(id) |
||||
|
||||
if v, ok := c.store.Get(key).([]byte); ok { |
||||
chars = v |
||||
} else { |
||||
ctx.Status(404) |
||||
ctx.Write([]byte("captcha not found")) |
||||
return |
||||
} |
||||
|
||||
// reload captcha
|
||||
if len(ctx.Query("reload")) > 0 { |
||||
chars = c.genRandChars() |
||||
if err := c.store.Put(key, chars, c.Expiration); err != nil { |
||||
ctx.Status(500) |
||||
ctx.Write([]byte("captcha reload error")) |
||||
log.Error(4, "Reload Create Captcha Error: %v", err) |
||||
return |
||||
} |
||||
} |
||||
|
||||
img := NewImage(chars, c.StdWidth, c.StdHeight) |
||||
if _, err := img.WriteTo(ctx.RW()); err != nil { |
||||
log.Error(4, "Write Captcha Image Error: %v", err) |
||||
} |
||||
} |
||||
|
||||
// tempalte func for output html
|
||||
func (c *Captcha) CreateCaptchaHtml() template.HTML { |
||||
value, err := c.CreateCaptcha() |
||||
if err != nil { |
||||
log.Error(4, "Create Captcha Error: %v", err) |
||||
return "" |
||||
} |
||||
|
||||
// create html
|
||||
return template.HTML(fmt.Sprintf(`<input type="hidden" name="%s" value="%s">`+ |
||||
`<a class="captcha" href="javascript:">`+ |
||||
`<img onclick="this.src=('%s%s.png?reload='+(new Date()).getTime())" class="captcha-img" src="%s%s.png">`+ |
||||
`</a>`, c.FieldIdName, value, c.URLPrefix, value, c.URLPrefix, value)) |
||||
} |
||||
|
||||
// create a new captcha id
|
||||
func (c *Captcha) CreateCaptcha() (string, error) { |
||||
// generate captcha id
|
||||
id := string(base.RandomCreateBytes(15)) |
||||
|
||||
// get the captcha chars
|
||||
chars := c.genRandChars() |
||||
|
||||
// save to store
|
||||
if err := c.store.Put(c.key(id), chars, c.Expiration); err != nil { |
||||
return "", err |
||||
} |
||||
|
||||
return id, nil |
||||
} |
||||
|
||||
// verify from a request
|
||||
func (c *Captcha) VerifyReq(req *http.Request) bool { |
||||
req.ParseForm() |
||||
return c.Verify(req.Form.Get(c.FieldIdName), req.Form.Get(c.FieldCaptchaName)) |
||||
} |
||||
|
||||
// direct verify id and challenge string
|
||||
func (c *Captcha) Verify(id string, challenge string) (success bool) { |
||||
if len(challenge) == 0 || len(id) == 0 { |
||||
return |
||||
} |
||||
|
||||
var chars []byte |
||||
|
||||
key := c.key(id) |
||||
|
||||
if v, ok := c.store.Get(key).([]byte); ok && len(v) == len(challenge) { |
||||
chars = v |
||||
} else { |
||||
return |
||||
} |
||||
|
||||
defer func() { |
||||
// finally remove it
|
||||
c.store.Delete(key) |
||||
}() |
||||
|
||||
// verify challenge
|
||||
for i, c := range chars { |
||||
if c != challenge[i]-48 { |
||||
return |
||||
} |
||||
} |
||||
|
||||
return true |
||||
} |
||||
|
||||
// create a new captcha.Captcha
|
||||
func NewCaptcha(urlPrefix string, store cache.Cache) *Captcha { |
||||
cpt := &Captcha{} |
||||
cpt.store = store |
||||
cpt.FieldIdName = fieldIdName |
||||
cpt.FieldCaptchaName = fieldCaptchaName |
||||
cpt.ChallengeNums = challengeNums |
||||
cpt.Expiration = expiration |
||||
cpt.CachePrefix = cachePrefix |
||||
cpt.StdWidth = stdWidth |
||||
cpt.StdHeight = stdHeight |
||||
|
||||
if len(urlPrefix) == 0 { |
||||
urlPrefix = defaultURLPrefix |
||||
} |
||||
|
||||
if urlPrefix[len(urlPrefix)-1] != '/' { |
||||
urlPrefix += "/" |
||||
} |
||||
|
||||
cpt.URLPrefix = urlPrefix |
||||
|
||||
base.TemplateFuncs["CreateCaptcha"] = cpt.CreateCaptchaHtml |
||||
return cpt |
||||
} |
@ -0,0 +1,487 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package captcha |
||||
|
||||
import ( |
||||
"bytes" |
||||
"image" |
||||
"image/color" |
||||
"image/png" |
||||
"io" |
||||
"math" |
||||
) |
||||
|
||||
const ( |
||||
fontWidth = 11 |
||||
fontHeight = 18 |
||||
blackChar = 1 |
||||
|
||||
// Standard width and height of a captcha image.
|
||||
stdWidth = 240 |
||||
stdHeight = 80 |
||||
// Maximum absolute skew factor of a single digit.
|
||||
maxSkew = 0.7 |
||||
// Number of background circles.
|
||||
circleCount = 20 |
||||
) |
||||
|
||||
var font = [][]byte{ |
||||
{ // 0
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
}, |
||||
{ // 1
|
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 1, 1, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
}, |
||||
{ // 2
|
||||
0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, |
||||
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
}, |
||||
{ // 3
|
||||
0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
}, |
||||
{ // 4
|
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
}, |
||||
{ // 5
|
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
}, |
||||
{ // 6
|
||||
0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, |
||||
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, |
||||
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
||||
1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, |
||||
1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 0, |
||||
1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, |
||||
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
}, |
||||
{ // 7
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, |
||||
1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, |
||||
0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, |
||||
0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, |
||||
0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, |
||||
0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, |
||||
0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, |
||||
}, |
||||
{ // 8
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 0, |
||||
0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, |
||||
0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, |
||||
0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, |
||||
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, |
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
}, |
||||
{ // 9
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, |
||||
0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, |
||||
0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, |
||||
0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, |
||||
0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, |
||||
0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, |
||||
}, |
||||
} |
||||
|
||||
type Image struct { |
||||
*image.Paletted |
||||
numWidth int |
||||
numHeight int |
||||
dotSize int |
||||
} |
||||
|
||||
var prng = &siprng{} |
||||
|
||||
// randIntn returns a pseudorandom non-negative int in range [0, n).
|
||||
func randIntn(n int) int { |
||||
return prng.Intn(n) |
||||
} |
||||
|
||||
// randInt returns a pseudorandom int in range [from, to].
|
||||
func randInt(from, to int) int { |
||||
return prng.Intn(to+1-from) + from |
||||
} |
||||
|
||||
// randFloat returns a pseudorandom float64 in range [from, to].
|
||||
func randFloat(from, to float64) float64 { |
||||
return (to-from)*prng.Float64() + from |
||||
} |
||||
|
||||
func randomPalette() color.Palette { |
||||
p := make([]color.Color, circleCount+1) |
||||
// Transparent color.
|
||||
p[0] = color.RGBA{0xFF, 0xFF, 0xFF, 0x00} |
||||
// Primary color.
|
||||
prim := color.RGBA{ |
||||
uint8(randIntn(129)), |
||||
uint8(randIntn(129)), |
||||
uint8(randIntn(129)), |
||||
0xFF, |
||||
} |
||||
p[1] = prim |
||||
// Circle colors.
|
||||
for i := 2; i <= circleCount; i++ { |
||||
p[i] = randomBrightness(prim, 255) |
||||
} |
||||
return p |
||||
} |
||||
|
||||
// NewImage returns a new captcha image of the given width and height with the
|
||||
// given digits, where each digit must be in range 0-9.
|
||||
func NewImage(digits []byte, width, height int) *Image { |
||||
m := new(Image) |
||||
m.Paletted = image.NewPaletted(image.Rect(0, 0, width, height), randomPalette()) |
||||
m.calculateSizes(width, height, len(digits)) |
||||
// Randomly position captcha inside the image.
|
||||
maxx := width - (m.numWidth+m.dotSize)*len(digits) - m.dotSize |
||||
maxy := height - m.numHeight - m.dotSize*2 |
||||
var border int |
||||
if width > height { |
||||
border = height / 5 |
||||
} else { |
||||
border = width / 5 |
||||
} |
||||
x := randInt(border, maxx-border) |
||||
y := randInt(border, maxy-border) |
||||
// Draw digits.
|
||||
for _, n := range digits { |
||||
m.drawDigit(font[n], x, y) |
||||
x += m.numWidth + m.dotSize |
||||
} |
||||
// Draw strike-through line.
|
||||
m.strikeThrough() |
||||
// Apply wave distortion.
|
||||
m.distort(randFloat(5, 10), randFloat(100, 200)) |
||||
// Fill image with random circles.
|
||||
m.fillWithCircles(circleCount, m.dotSize) |
||||
return m |
||||
} |
||||
|
||||
// encodedPNG encodes an image to PNG and returns
|
||||
// the result as a byte slice.
|
||||
func (m *Image) encodedPNG() []byte { |
||||
var buf bytes.Buffer |
||||
if err := png.Encode(&buf, m.Paletted); err != nil { |
||||
panic(err.Error()) |
||||
} |
||||
return buf.Bytes() |
||||
} |
||||
|
||||
// WriteTo writes captcha image in PNG format into the given writer.
|
||||
func (m *Image) WriteTo(w io.Writer) (int64, error) { |
||||
n, err := w.Write(m.encodedPNG()) |
||||
return int64(n), err |
||||
} |
||||
|
||||
func (m *Image) calculateSizes(width, height, ncount int) { |
||||
// Goal: fit all digits inside the image.
|
||||
var border int |
||||
if width > height { |
||||
border = height / 4 |
||||
} else { |
||||
border = width / 4 |
||||
} |
||||
// Convert everything to floats for calculations.
|
||||
w := float64(width - border*2) |
||||
h := float64(height - border*2) |
||||
// fw takes into account 1-dot spacing between digits.
|
||||
fw := float64(fontWidth + 1) |
||||
fh := float64(fontHeight) |
||||
nc := float64(ncount) |
||||
// Calculate the width of a single digit taking into account only the
|
||||
// width of the image.
|
||||
nw := w / nc |
||||
// Calculate the height of a digit from this width.
|
||||
nh := nw * fh / fw |
||||
// Digit too high?
|
||||
if nh > h { |
||||
// Fit digits based on height.
|
||||
nh = h |
||||
nw = fw / fh * nh |
||||
} |
||||
// Calculate dot size.
|
||||
m.dotSize = int(nh / fh) |
||||
// Save everything, making the actual width smaller by 1 dot to account
|
||||
// for spacing between digits.
|
||||
m.numWidth = int(nw) - m.dotSize |
||||
m.numHeight = int(nh) |
||||
} |
||||
|
||||
func (m *Image) drawHorizLine(fromX, toX, y int, colorIdx uint8) { |
||||
for x := fromX; x <= toX; x++ { |
||||
m.SetColorIndex(x, y, colorIdx) |
||||
} |
||||
} |
||||
|
||||
func (m *Image) drawCircle(x, y, radius int, colorIdx uint8) { |
||||
f := 1 - radius |
||||
dfx := 1 |
||||
dfy := -2 * radius |
||||
xo := 0 |
||||
yo := radius |
||||
|
||||
m.SetColorIndex(x, y+radius, colorIdx) |
||||
m.SetColorIndex(x, y-radius, colorIdx) |
||||
m.drawHorizLine(x-radius, x+radius, y, colorIdx) |
||||
|
||||
for xo < yo { |
||||
if f >= 0 { |
||||
yo-- |
||||
dfy += 2 |
||||
f += dfy |
||||
} |
||||
xo++ |
||||
dfx += 2 |
||||
f += dfx |
||||
m.drawHorizLine(x-xo, x+xo, y+yo, colorIdx) |
||||
m.drawHorizLine(x-xo, x+xo, y-yo, colorIdx) |
||||
m.drawHorizLine(x-yo, x+yo, y+xo, colorIdx) |
||||
m.drawHorizLine(x-yo, x+yo, y-xo, colorIdx) |
||||
} |
||||
} |
||||
|
||||
func (m *Image) fillWithCircles(n, maxradius int) { |
||||
maxx := m.Bounds().Max.X |
||||
maxy := m.Bounds().Max.Y |
||||
for i := 0; i < n; i++ { |
||||
colorIdx := uint8(randInt(1, circleCount-1)) |
||||
r := randInt(1, maxradius) |
||||
m.drawCircle(randInt(r, maxx-r), randInt(r, maxy-r), r, colorIdx) |
||||
} |
||||
} |
||||
|
||||
func (m *Image) strikeThrough() { |
||||
maxx := m.Bounds().Max.X |
||||
maxy := m.Bounds().Max.Y |
||||
y := randInt(maxy/3, maxy-maxy/3) |
||||
amplitude := randFloat(5, 20) |
||||
period := randFloat(80, 180) |
||||
dx := 2.0 * math.Pi / period |
||||
for x := 0; x < maxx; x++ { |
||||
xo := amplitude * math.Cos(float64(y)*dx) |
||||
yo := amplitude * math.Sin(float64(x)*dx) |
||||
for yn := 0; yn < m.dotSize; yn++ { |
||||
r := randInt(0, m.dotSize) |
||||
m.drawCircle(x+int(xo), y+int(yo)+(yn*m.dotSize), r/2, 1) |
||||
} |
||||
} |
||||
} |
||||
|
||||
func (m *Image) drawDigit(digit []byte, x, y int) { |
||||
skf := randFloat(-maxSkew, maxSkew) |
||||
xs := float64(x) |
||||
r := m.dotSize / 2 |
||||
y += randInt(-r, r) |
||||
for yo := 0; yo < fontHeight; yo++ { |
||||
for xo := 0; xo < fontWidth; xo++ { |
||||
if digit[yo*fontWidth+xo] != blackChar { |
||||
continue |
||||
} |
||||
m.drawCircle(x+xo*m.dotSize, y+yo*m.dotSize, r, 1) |
||||
} |
||||
xs += skf |
||||
x = int(xs) |
||||
} |
||||
} |
||||
|
||||
func (m *Image) distort(amplude float64, period float64) { |
||||
w := m.Bounds().Max.X |
||||
h := m.Bounds().Max.Y |
||||
|
||||
oldm := m.Paletted |
||||
newm := image.NewPaletted(image.Rect(0, 0, w, h), oldm.Palette) |
||||
|
||||
dx := 2.0 * math.Pi / period |
||||
for x := 0; x < w; x++ { |
||||
for y := 0; y < h; y++ { |
||||
xo := amplude * math.Sin(float64(y)*dx) |
||||
yo := amplude * math.Cos(float64(x)*dx) |
||||
newm.SetColorIndex(x, y, oldm.ColorIndexAt(x+int(xo), y+int(yo))) |
||||
} |
||||
} |
||||
m.Paletted = newm |
||||
} |
||||
|
||||
func randomBrightness(c color.RGBA, max uint8) color.RGBA { |
||||
minc := min3(c.R, c.G, c.B) |
||||
maxc := max3(c.R, c.G, c.B) |
||||
if maxc > max { |
||||
return c |
||||
} |
||||
n := randIntn(int(max-maxc)) - int(minc) |
||||
return color.RGBA{ |
||||
uint8(int(c.R) + n), |
||||
uint8(int(c.G) + n), |
||||
uint8(int(c.B) + n), |
||||
uint8(c.A), |
||||
} |
||||
} |
||||
|
||||
func min3(x, y, z uint8) (m uint8) { |
||||
m = x |
||||
if y < m { |
||||
m = y |
||||
} |
||||
if z < m { |
||||
m = z |
||||
} |
||||
return |
||||
} |
||||
|
||||
func max3(x, y, z uint8) (m uint8) { |
||||
m = x |
||||
if y > m { |
||||
m = y |
||||
} |
||||
if z > m { |
||||
m = z |
||||
} |
||||
return |
||||
} |
@ -0,0 +1,42 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package captcha |
||||
|
||||
import ( |
||||
"testing" |
||||
|
||||
"github.com/astaxie/beego/utils" |
||||
) |
||||
|
||||
type byteCounter struct { |
||||
n int64 |
||||
} |
||||
|
||||
func (bc *byteCounter) Write(b []byte) (int, error) { |
||||
bc.n += int64(len(b)) |
||||
return len(b), nil |
||||
} |
||||
|
||||
func BenchmarkNewImage(b *testing.B) { |
||||
b.StopTimer() |
||||
d := utils.RandomCreateBytes(challengeNums, defaultChars...) |
||||
b.StartTimer() |
||||
for i := 0; i < b.N; i++ { |
||||
NewImage(d, stdWidth, stdHeight) |
||||
} |
||||
} |
||||
|
||||
func BenchmarkImageWriteTo(b *testing.B) { |
||||
b.StopTimer() |
||||
d := utils.RandomCreateBytes(challengeNums, defaultChars...) |
||||
b.StartTimer() |
||||
counter := &byteCounter{} |
||||
for i := 0; i < b.N; i++ { |
||||
img := NewImage(d, stdWidth, stdHeight) |
||||
img.WriteTo(counter) |
||||
b.SetBytes(counter.n) |
||||
counter.n = 0 |
||||
} |
||||
} |
@ -0,0 +1,267 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package captcha |
||||
|
||||
import ( |
||||
"crypto/rand" |
||||
"encoding/binary" |
||||
"io" |
||||
"sync" |
||||
) |
||||
|
||||
// siprng is PRNG based on SipHash-2-4.
|
||||
type siprng struct { |
||||
mu sync.Mutex |
||||
k0, k1, ctr uint64 |
||||
} |
||||
|
||||
// siphash implements SipHash-2-4, accepting a uint64 as a message.
|
||||
func siphash(k0, k1, m uint64) uint64 { |
||||
// Initialization.
|
||||
v0 := k0 ^ 0x736f6d6570736575 |
||||
v1 := k1 ^ 0x646f72616e646f6d |
||||
v2 := k0 ^ 0x6c7967656e657261 |
||||
v3 := k1 ^ 0x7465646279746573 |
||||
t := uint64(8) << 56 |
||||
|
||||
// Compression.
|
||||
v3 ^= m |
||||
|
||||
// Round 1.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
// Round 2.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
v0 ^= m |
||||
|
||||
// Compress last block.
|
||||
v3 ^= t |
||||
|
||||
// Round 1.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
// Round 2.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
v0 ^= t |
||||
|
||||
// Finalization.
|
||||
v2 ^= 0xff |
||||
|
||||
// Round 1.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
// Round 2.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
// Round 3.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
// Round 4.
|
||||
v0 += v1 |
||||
v1 = v1<<13 | v1>>(64-13) |
||||
v1 ^= v0 |
||||
v0 = v0<<32 | v0>>(64-32) |
||||
|
||||
v2 += v3 |
||||
v3 = v3<<16 | v3>>(64-16) |
||||
v3 ^= v2 |
||||
|
||||
v0 += v3 |
||||
v3 = v3<<21 | v3>>(64-21) |
||||
v3 ^= v0 |
||||
|
||||
v2 += v1 |
||||
v1 = v1<<17 | v1>>(64-17) |
||||
v1 ^= v2 |
||||
v2 = v2<<32 | v2>>(64-32) |
||||
|
||||
return v0 ^ v1 ^ v2 ^ v3 |
||||
} |
||||
|
||||
// rekey sets a new PRNG key, which is read from crypto/rand.
|
||||
func (p *siprng) rekey() { |
||||
var k [16]byte |
||||
if _, err := io.ReadFull(rand.Reader, k[:]); err != nil { |
||||
panic(err.Error()) |
||||
} |
||||
p.k0 = binary.LittleEndian.Uint64(k[0:8]) |
||||
p.k1 = binary.LittleEndian.Uint64(k[8:16]) |
||||
p.ctr = 1 |
||||
} |
||||
|
||||
// Uint64 returns a new pseudorandom uint64.
|
||||
// It rekeys PRNG on the first call and every 64 MB of generated data.
|
||||
func (p *siprng) Uint64() uint64 { |
||||
p.mu.Lock() |
||||
if p.ctr == 0 || p.ctr > 8*1024*1024 { |
||||
p.rekey() |
||||
} |
||||
v := siphash(p.k0, p.k1, p.ctr) |
||||
p.ctr++ |
||||
p.mu.Unlock() |
||||
return v |
||||
} |
||||
|
||||
func (p *siprng) Int63() int64 { |
||||
return int64(p.Uint64() & 0x7fffffffffffffff) |
||||
} |
||||
|
||||
func (p *siprng) Uint32() uint32 { |
||||
return uint32(p.Uint64()) |
||||
} |
||||
|
||||
func (p *siprng) Int31() int32 { |
||||
return int32(p.Uint32() & 0x7fffffff) |
||||
} |
||||
|
||||
func (p *siprng) Intn(n int) int { |
||||
if n <= 0 { |
||||
panic("invalid argument to Intn") |
||||
} |
||||
if n <= 1<<31-1 { |
||||
return int(p.Int31n(int32(n))) |
||||
} |
||||
return int(p.Int63n(int64(n))) |
||||
} |
||||
|
||||
func (p *siprng) Int63n(n int64) int64 { |
||||
if n <= 0 { |
||||
panic("invalid argument to Int63n") |
||||
} |
||||
max := int64((1 << 63) - 1 - (1<<63)%uint64(n)) |
||||
v := p.Int63() |
||||
for v > max { |
||||
v = p.Int63() |
||||
} |
||||
return v % n |
||||
} |
||||
|
||||
func (p *siprng) Int31n(n int32) int32 { |
||||
if n <= 0 { |
||||
panic("invalid argument to Int31n") |
||||
} |
||||
max := int32((1 << 31) - 1 - (1<<31)%uint32(n)) |
||||
v := p.Int31() |
||||
for v > max { |
||||
v = p.Int31() |
||||
} |
||||
return v % n |
||||
} |
||||
|
||||
func (p *siprng) Float64() float64 { return float64(p.Int63()) / (1 << 63) } |
@ -0,0 +1,23 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package captcha |
||||
|
||||
import "testing" |
||||
|
||||
func TestSiphash(t *testing.T) { |
||||
good := uint64(0xe849e8bb6ffe2567) |
||||
cur := siphash(0, 0, 0) |
||||
if cur != good { |
||||
t.Fatalf("siphash: expected %x, got %x", good, cur) |
||||
} |
||||
} |
||||
|
||||
func BenchmarkSiprng(b *testing.B) { |
||||
b.SetBytes(8) |
||||
p := &siprng{} |
||||
for i := 0; i < b.N; i++ { |
||||
p.Uint64() |
||||
} |
||||
} |
@ -0,0 +1,26 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"bytes" |
||||
"errors" |
||||
"io" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
type Blob struct { |
||||
repo *Repository |
||||
*TreeEntry |
||||
} |
||||
|
||||
func (b *Blob) Data() (io.Reader, error) { |
||||
stdout, stderr, err := com.ExecCmdDirBytes(b.repo.Path, "git", "show", b.Id.String()) |
||||
if err != nil { |
||||
return nil, errors.New(string(stderr)) |
||||
} |
||||
return bytes.NewBuffer(stdout), nil |
||||
} |
@ -0,0 +1,78 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"container/list" |
||||
"strings" |
||||
) |
||||
|
||||
// Commit represents a git commit.
|
||||
type Commit struct { |
||||
Tree |
||||
Id sha1 // The id of this commit object
|
||||
Author *Signature |
||||
Committer *Signature |
||||
CommitMessage string |
||||
|
||||
parents []sha1 // sha1 strings
|
||||
} |
||||
|
||||
// Return the commit message. Same as retrieving CommitMessage directly.
|
||||
func (c *Commit) Message() string { |
||||
return c.CommitMessage |
||||
} |
||||
|
||||
func (c *Commit) Summary() string { |
||||
return strings.Split(c.CommitMessage, "\n")[0] |
||||
} |
||||
|
||||
// Return oid of the parent number n (0-based index). Return nil if no such parent exists.
|
||||
func (c *Commit) ParentId(n int) (id sha1, err error) { |
||||
if n >= len(c.parents) { |
||||
err = IdNotExist |
||||
return |
||||
} |
||||
return c.parents[n], nil |
||||
} |
||||
|
||||
// Return parent number n (0-based index)
|
||||
func (c *Commit) Parent(n int) (*Commit, error) { |
||||
id, err := c.ParentId(n) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
parent, err := c.repo.getCommit(id) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return parent, nil |
||||
} |
||||
|
||||
// Return the number of parents of the commit. 0 if this is the
|
||||
// root commit, otherwise 1,2,...
|
||||
func (c *Commit) ParentCount() int { |
||||
return len(c.parents) |
||||
} |
||||
|
||||
func (c *Commit) CommitsBefore() (*list.List, error) { |
||||
return c.repo.getCommitsBefore(c.Id) |
||||
} |
||||
|
||||
func (c *Commit) CommitsBeforeUntil(commitId string) (*list.List, error) { |
||||
ec, err := c.repo.GetCommit(commitId) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return c.repo.CommitsBetween(c, ec) |
||||
} |
||||
|
||||
func (c *Commit) CommitsCount() (int, error) { |
||||
return c.repo.commitsCount(c.Id) |
||||
} |
||||
|
||||
func (c *Commit) GetCommitOfRelPath(relPath string) (*Commit, error) { |
||||
return c.repo.getCommitOfRelPath(c.Id, relPath) |
||||
} |
@ -0,0 +1,36 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
type ArchiveType int |
||||
|
||||
const ( |
||||
ZIP ArchiveType = iota + 1 |
||||
TARGZ |
||||
) |
||||
|
||||
func (c *Commit) CreateArchive(path string, archiveType ArchiveType) error { |
||||
var format string |
||||
switch archiveType { |
||||
case ZIP: |
||||
format = "zip" |
||||
case TARGZ: |
||||
format = "tar.gz" |
||||
default: |
||||
return fmt.Errorf("unknown format: %v", archiveType) |
||||
} |
||||
|
||||
_, stderr, err := com.ExecCmdDir(c.repo.Path, "git", "archive", "--format="+format, "-o", path, c.Id.String()) |
||||
if err != nil { |
||||
return fmt.Errorf("%s", stderr) |
||||
} |
||||
return nil |
||||
} |
@ -0,0 +1,27 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"path/filepath" |
||||
) |
||||
|
||||
// Repository represents a Git repository.
|
||||
type Repository struct { |
||||
Path string |
||||
|
||||
commitCache map[sha1]*Commit |
||||
tagCache map[sha1]*Tag |
||||
} |
||||
|
||||
// OpenRepository opens the repository at the given path.
|
||||
func OpenRepository(repoPath string) (*Repository, error) { |
||||
repoPath, err := filepath.Abs(repoPath) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &Repository{Path: repoPath}, nil |
||||
} |
@ -0,0 +1,38 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"errors" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
func IsBranchExist(repoPath, branchName string) bool { |
||||
_, _, err := com.ExecCmdDir(repoPath, "git", "show-ref", "--verify", "refs/heads/"+branchName) |
||||
return err == nil |
||||
} |
||||
|
||||
func (repo *Repository) IsBranchExist(branchName string) bool { |
||||
return IsBranchExist(repo.Path, branchName) |
||||
} |
||||
|
||||
func (repo *Repository) GetBranches() ([]string, error) { |
||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "show-ref", "--heads") |
||||
if err != nil { |
||||
return nil, errors.New(stderr) |
||||
} |
||||
infos := strings.Split(stdout, "\n") |
||||
branches := make([]string, len(infos)-1) |
||||
for i, info := range infos[:len(infos)-1] { |
||||
parts := strings.Split(info, " ") |
||||
if len(parts) != 2 { |
||||
continue // NOTE: I should believe git will not give me wrong string.
|
||||
} |
||||
branches[i] = strings.TrimPrefix(parts[1], "refs/heads/") |
||||
} |
||||
return branches, nil |
||||
} |
@ -0,0 +1,234 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"bytes" |
||||
"container/list" |
||||
"errors" |
||||
"strings" |
||||
"sync" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
func (repo *Repository) getCommitIdOfRef(refpath string) (string, error) { |
||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "show-ref", "--verify", refpath) |
||||
if err != nil { |
||||
return "", errors.New(stderr) |
||||
} |
||||
return strings.Split(stdout, " ")[0], nil |
||||
} |
||||
|
||||
func (repo *Repository) GetCommitIdOfBranch(branchName string) (string, error) { |
||||
return repo.getCommitIdOfRef("refs/heads/" + branchName) |
||||
} |
||||
|
||||
// get branch's last commit or a special commit by id string
|
||||
func (repo *Repository) GetCommitOfBranch(branchName string) (*Commit, error) { |
||||
commitId, err := repo.GetCommitIdOfBranch(branchName) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return repo.GetCommit(commitId) |
||||
} |
||||
|
||||
// Parse commit information from the (uncompressed) raw
|
||||
// data from the commit object.
|
||||
// \n\n separate headers from message
|
||||
func parseCommitData(data []byte) (*Commit, error) { |
||||
commit := new(Commit) |
||||
commit.parents = make([]sha1, 0, 1) |
||||
// we now have the contents of the commit object. Let's investigate...
|
||||
nextline := 0 |
||||
l: |
||||
for { |
||||
eol := bytes.IndexByte(data[nextline:], '\n') |
||||
switch { |
||||
case eol > 0: |
||||
line := data[nextline : nextline+eol] |
||||
spacepos := bytes.IndexByte(line, ' ') |
||||
reftype := line[:spacepos] |
||||
switch string(reftype) { |
||||
case "tree": |
||||
id, err := NewIdFromString(string(line[spacepos+1:])) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
commit.Tree.Id = id |
||||
case "parent": |
||||
// A commit can have one or more parents
|
||||
oid, err := NewIdFromString(string(line[spacepos+1:])) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
commit.parents = append(commit.parents, oid) |
||||
case "author": |
||||
sig, err := newSignatureFromCommitline(line[spacepos+1:]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
commit.Author = sig |
||||
case "committer": |
||||
sig, err := newSignatureFromCommitline(line[spacepos+1:]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
commit.Committer = sig |
||||
} |
||||
nextline += eol + 1 |
||||
case eol == 0: |
||||
commit.CommitMessage = string(data[nextline+1:]) |
||||
break l |
||||
default: |
||||
break l |
||||
} |
||||
} |
||||
return commit, nil |
||||
} |
||||
|
||||
func (repo *Repository) getCommit(id sha1) (*Commit, error) { |
||||
if repo.commitCache != nil { |
||||
if c, ok := repo.commitCache[id]; ok { |
||||
return c, nil |
||||
} |
||||
} else { |
||||
repo.commitCache = make(map[sha1]*Commit, 10) |
||||
} |
||||
|
||||
data, bytErr, err := com.ExecCmdDirBytes(repo.Path, "git", "cat-file", "-p", id.String()) |
||||
if err != nil { |
||||
return nil, errors.New(string(bytErr)) |
||||
} |
||||
|
||||
commit, err := parseCommitData(data) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
commit.repo = repo |
||||
commit.Id = id |
||||
|
||||
repo.commitCache[id] = commit |
||||
return commit, nil |
||||
} |
||||
|
||||
// Find the commit object in the repository.
|
||||
func (repo *Repository) GetCommit(commitId string) (*Commit, error) { |
||||
id, err := NewIdFromString(commitId) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return repo.getCommit(id) |
||||
} |
||||
|
||||
func (repo *Repository) commitsCount(id sha1) (int, error) { |
||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "rev-list", "--count", id.String()) |
||||
if err != nil { |
||||
return 0, errors.New(stderr) |
||||
} |
||||
return com.StrTo(strings.TrimSpace(stdout)).Int() |
||||
} |
||||
|
||||
// used only for single tree, (]
|
||||
func (repo *Repository) CommitsBetween(last *Commit, before *Commit) (*list.List, error) { |
||||
l := list.New() |
||||
if last == nil || last.ParentCount() == 0 { |
||||
return l, nil |
||||
} |
||||
|
||||
var err error |
||||
cur := last |
||||
for { |
||||
if cur.Id.Equal(before.Id) { |
||||
break |
||||
} |
||||
l.PushBack(cur) |
||||
if cur.ParentCount() == 0 { |
||||
break |
||||
} |
||||
cur, err = cur.Parent(0) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
return l, nil |
||||
} |
||||
|
||||
func (repo *Repository) commitsBefore(lock *sync.Mutex, l *list.List, parent *list.Element, id sha1, limit int) error { |
||||
commit, err := repo.getCommit(id) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
var e *list.Element |
||||
if parent == nil { |
||||
e = l.PushBack(commit) |
||||
} else { |
||||
var in = parent |
||||
for { |
||||
if in == nil { |
||||
break |
||||
} else if in.Value.(*Commit).Id.Equal(commit.Id) { |
||||
return nil |
||||
} else { |
||||
if in.Next() == nil { |
||||
break |
||||
} |
||||
if in.Value.(*Commit).Committer.When.Equal(commit.Committer.When) { |
||||
break |
||||
} |
||||
|
||||
if in.Value.(*Commit).Committer.When.After(commit.Committer.When) && |
||||
in.Next().Value.(*Commit).Committer.When.Before(commit.Committer.When) { |
||||
break |
||||
} |
||||
} |
||||
in = in.Next() |
||||
} |
||||
|
||||
e = l.InsertAfter(commit, in) |
||||
} |
||||
|
||||
var pr = parent |
||||
if commit.ParentCount() > 1 { |
||||
pr = e |
||||
} |
||||
|
||||
for i := 0; i < commit.ParentCount(); i++ { |
||||
id, err := commit.ParentId(i) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
err = repo.commitsBefore(lock, l, pr, id, 0) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (repo *Repository) getCommitsBefore(id sha1) (*list.List, error) { |
||||
l := list.New() |
||||
lock := new(sync.Mutex) |
||||
err := repo.commitsBefore(lock, l, nil, id, 0) |
||||
return l, err |
||||
} |
||||
|
||||
func (repo *Repository) getCommitOfRelPath(id sha1, relPath string) (*Commit, error) { |
||||
stdout, _, err := com.ExecCmdDir(repo.Path, "git", "log", "-1", prettyLogFormat, id.String(), "--", relPath) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
id, err = NewIdFromString(string(stdout)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return repo.getCommit(id) |
||||
} |
@ -0,0 +1,14 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
type ObjectType string |
||||
|
||||
const ( |
||||
COMMIT ObjectType = "commit" |
||||
TREE ObjectType = "tree" |
||||
BLOB ObjectType = "blob" |
||||
TAG ObjectType = "tag" |
||||
) |
@ -0,0 +1,96 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"errors" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
func IsTagExist(repoPath, tagName string) bool { |
||||
_, _, err := com.ExecCmdDir(repoPath, "git", "show-ref", "--verify", "refs/tags/"+tagName) |
||||
return err == nil |
||||
} |
||||
|
||||
func (repo *Repository) IsTagExist(tagName string) bool { |
||||
return IsTagExist(repo.Path, tagName) |
||||
} |
||||
|
||||
// GetTags returns all tags of given repository.
|
||||
func (repo *Repository) GetTags() ([]string, error) { |
||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "tag", "-l") |
||||
if err != nil { |
||||
return nil, errors.New(stderr) |
||||
} |
||||
tags := strings.Split(stdout, "\n") |
||||
return tags[:len(tags)-1], nil |
||||
} |
||||
|
||||
func (repo *Repository) getTag(id sha1) (*Tag, error) { |
||||
if repo.tagCache != nil { |
||||
if t, ok := repo.tagCache[id]; ok { |
||||
return t, nil |
||||
} |
||||
} else { |
||||
repo.tagCache = make(map[sha1]*Tag, 10) |
||||
} |
||||
|
||||
// Get tag type.
|
||||
tp, stderr, err := com.ExecCmdDir(repo.Path, "git", "cat-file", "-t", id.String()) |
||||
if err != nil { |
||||
return nil, errors.New(stderr) |
||||
} |
||||
|
||||
// Tag is a commit.
|
||||
if ObjectType(tp) == COMMIT { |
||||
tag := &Tag{ |
||||
Id: id, |
||||
Object: id, |
||||
Type: string(COMMIT), |
||||
repo: repo, |
||||
} |
||||
repo.tagCache[id] = tag |
||||
return tag, nil |
||||
} |
||||
|
||||
// Tag with message.
|
||||
data, bytErr, err := com.ExecCmdDirBytes(repo.Path, "git", "cat-file", "-p", id.String()) |
||||
if err != nil { |
||||
return nil, errors.New(string(bytErr)) |
||||
} |
||||
|
||||
tag, err := parseTagData(data) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
tag.Id = id |
||||
tag.repo = repo |
||||
|
||||
repo.tagCache[id] = tag |
||||
return tag, nil |
||||
} |
||||
|
||||
// GetTag returns a Git tag by given name.
|
||||
func (repo *Repository) GetTag(tagName string) (*Tag, error) { |
||||
stdout, stderr, err := com.ExecCmdDir(repo.Path, "git", "show-ref", "--tags", tagName) |
||||
if err != nil { |
||||
return nil, errors.New(stderr) |
||||
} |
||||
|
||||
id, err := NewIdFromString(strings.Split(stdout, " ")[0]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
tag, err := repo.getTag(id) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
tag.Name = tagName |
||||
return tag, nil |
||||
} |
@ -0,0 +1,32 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"fmt" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
// Find the tree object in the repository.
|
||||
func (repo *Repository) GetTree(idStr string) (*Tree, error) { |
||||
id, err := NewIdFromString(idStr) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
return repo.getTree(id) |
||||
} |
||||
|
||||
func (repo *Repository) getTree(id sha1) (*Tree, error) { |
||||
treePath := filepathFromSHA1(repo.Path, id.String()) |
||||
if !com.IsFile(treePath) { |
||||
_, _, err := com.ExecCmdDir(repo.Path, "git", "ls-tree", id.String()) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("repo.getTree: %v", ErrNotExist) |
||||
} |
||||
} |
||||
|
||||
return NewTree(repo, id), nil |
||||
} |
@ -0,0 +1,87 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"encoding/hex" |
||||
"errors" |
||||
"fmt" |
||||
"strings" |
||||
) |
||||
|
||||
var ( |
||||
IdNotExist = errors.New("sha1 id not exist") |
||||
) |
||||
|
||||
type sha1 [20]byte |
||||
|
||||
// Return true if s has the same sha1 as caller.
|
||||
// Support 40-length-string, []byte, sha1
|
||||
func (id sha1) Equal(s2 interface{}) bool { |
||||
switch v := s2.(type) { |
||||
case string: |
||||
if len(v) != 40 { |
||||
return false |
||||
} |
||||
return v == id.String() |
||||
case []byte: |
||||
if len(v) != 20 { |
||||
return false |
||||
} |
||||
for i, v := range v { |
||||
if id[i] != v { |
||||
return false |
||||
} |
||||
} |
||||
case sha1: |
||||
for i, v := range v { |
||||
if id[i] != v { |
||||
return false |
||||
} |
||||
} |
||||
default: |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
// Return string (hex) representation of the Oid
|
||||
func (s sha1) String() string { |
||||
result := make([]byte, 0, 40) |
||||
hexvalues := []byte("0123456789abcdef") |
||||
for i := 0; i < 20; i++ { |
||||
result = append(result, hexvalues[s[i]>>4]) |
||||
result = append(result, hexvalues[s[i]&0xf]) |
||||
} |
||||
return string(result) |
||||
} |
||||
|
||||
// Create a new sha1 from a 20 byte slice.
|
||||
func NewId(b []byte) (sha1, error) { |
||||
var id sha1 |
||||
if len(b) != 20 { |
||||
return id, errors.New("Length must be 20") |
||||
} |
||||
|
||||
for i := 0; i < 20; i++ { |
||||
id[i] = b[i] |
||||
} |
||||
return id, nil |
||||
} |
||||
|
||||
// Create a new sha1 from a Sha1 string of length 40.
|
||||
func NewIdFromString(s string) (sha1, error) { |
||||
s = strings.TrimSpace(s) |
||||
var id sha1 |
||||
if len(s) != 40 { |
||||
return id, fmt.Errorf("Length must be 40") |
||||
} |
||||
b, err := hex.DecodeString(s) |
||||
if err != nil { |
||||
return id, err |
||||
} |
||||
|
||||
return NewId(b) |
||||
} |
@ -0,0 +1,40 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"bytes" |
||||
"strconv" |
||||
"time" |
||||
) |
||||
|
||||
// Author and Committer information
|
||||
type Signature struct { |
||||
Email string |
||||
Name string |
||||
When time.Time |
||||
} |
||||
|
||||
// Helper to get a signature from the commit line, which looks like this:
|
||||
// author Patrick Gundlach <gundlach@speedata.de> 1378823654 +0200
|
||||
// but without the "author " at the beginning (this method should)
|
||||
// be used for author and committer.
|
||||
//
|
||||
// FIXME: include timezone!
|
||||
func newSignatureFromCommitline(line []byte) (*Signature, error) { |
||||
sig := new(Signature) |
||||
emailstart := bytes.IndexByte(line, '<') |
||||
sig.Name = string(line[:emailstart-1]) |
||||
emailstop := bytes.IndexByte(line, '>') |
||||
sig.Email = string(line[emailstart+1 : emailstop]) |
||||
timestop := bytes.IndexByte(line[emailstop+2:], ' ') |
||||
timestring := string(line[emailstop+2 : emailstop+2+timestop]) |
||||
seconds, err := strconv.ParseInt(timestring, 10, 64) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
sig.When = time.Unix(seconds, 0) |
||||
return sig, nil |
||||
} |
@ -0,0 +1,67 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"bytes" |
||||
) |
||||
|
||||
// Tag represents a Git tag.
|
||||
type Tag struct { |
||||
Name string |
||||
Id sha1 |
||||
repo *Repository |
||||
Object sha1 // The id of this commit object
|
||||
Type string |
||||
Tagger *Signature |
||||
TagMessage string |
||||
} |
||||
|
||||
func (tag *Tag) Commit() (*Commit, error) { |
||||
return tag.repo.getCommit(tag.Object) |
||||
} |
||||
|
||||
// Parse commit information from the (uncompressed) raw
|
||||
// data from the commit object.
|
||||
// \n\n separate headers from message
|
||||
func parseTagData(data []byte) (*Tag, error) { |
||||
tag := new(Tag) |
||||
// we now have the contents of the commit object. Let's investigate...
|
||||
nextline := 0 |
||||
l: |
||||
for { |
||||
eol := bytes.IndexByte(data[nextline:], '\n') |
||||
switch { |
||||
case eol > 0: |
||||
line := data[nextline : nextline+eol] |
||||
spacepos := bytes.IndexByte(line, ' ') |
||||
reftype := line[:spacepos] |
||||
switch string(reftype) { |
||||
case "object": |
||||
id, err := NewIdFromString(string(line[spacepos+1:])) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
tag.Object = id |
||||
case "type": |
||||
// A commit can have one or more parents
|
||||
tag.Type = string(line[spacepos+1:]) |
||||
case "tagger": |
||||
sig, err := newSignatureFromCommitline(line[spacepos+1:]) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
tag.Tagger = sig |
||||
} |
||||
nextline += eol + 1 |
||||
case eol == 0: |
||||
tag.TagMessage = string(data[nextline+1:]) |
||||
break l |
||||
default: |
||||
break l |
||||
} |
||||
} |
||||
return tag, nil |
||||
} |
@ -0,0 +1,124 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"bytes" |
||||
"errors" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
var ( |
||||
ErrNotExist = errors.New("error not exist") |
||||
) |
||||
|
||||
// A tree is a flat directory listing.
|
||||
type Tree struct { |
||||
Id sha1 |
||||
repo *Repository |
||||
|
||||
// parent tree
|
||||
ptree *Tree |
||||
|
||||
entries Entries |
||||
entriesParsed bool |
||||
} |
||||
|
||||
// Parse tree information from the (uncompressed) raw
|
||||
// data from the tree object.
|
||||
func parseTreeData(tree *Tree, data []byte) ([]*TreeEntry, error) { |
||||
entries := make([]*TreeEntry, 0, 10) |
||||
l := len(data) |
||||
pos := 0 |
||||
for pos < l { |
||||
entry := new(TreeEntry) |
||||
entry.ptree = tree |
||||
step := 6 |
||||
switch string(data[pos : pos+step]) { |
||||
case "100644": |
||||
entry.mode = ModeBlob |
||||
entry.Type = BLOB |
||||
case "100755": |
||||
entry.mode = ModeExec |
||||
entry.Type = BLOB |
||||
case "120000": |
||||
entry.mode = ModeSymlink |
||||
entry.Type = BLOB |
||||
case "160000": |
||||
entry.mode = ModeCommit |
||||
entry.Type = COMMIT |
||||
case "040000": |
||||
entry.mode = ModeTree |
||||
entry.Type = TREE |
||||
default: |
||||
return nil, errors.New("unknown type: " + string(data[pos:pos+step])) |
||||
} |
||||
pos += step + 6 // Skip string type of entry type.
|
||||
|
||||
step = 40 |
||||
id, err := NewIdFromString(string(data[pos : pos+step])) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
entry.Id = id |
||||
pos += step + 1 // Skip half of sha1.
|
||||
|
||||
step = bytes.IndexByte(data[pos:], '\n') |
||||
entry.name = string(data[pos : pos+step]) |
||||
pos += step + 1 |
||||
entries = append(entries, entry) |
||||
} |
||||
return entries, nil |
||||
} |
||||
|
||||
func (t *Tree) SubTree(rpath string) (*Tree, error) { |
||||
if len(rpath) == 0 { |
||||
return t, nil |
||||
} |
||||
|
||||
paths := strings.Split(rpath, "/") |
||||
var err error |
||||
var g = t |
||||
var p = t |
||||
var te *TreeEntry |
||||
for _, name := range paths { |
||||
te, err = p.GetTreeEntryByPath(name) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
g, err = t.repo.getTree(te.Id) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
g.ptree = p |
||||
p = g |
||||
} |
||||
return g, nil |
||||
} |
||||
|
||||
func (t *Tree) ListEntries(relpath string) (Entries, error) { |
||||
if t.entriesParsed { |
||||
return t.entries, nil |
||||
} |
||||
t.entriesParsed = true |
||||
|
||||
stdout, _, err := com.ExecCmdDirBytes(t.repo.Path, |
||||
"git", "ls-tree", t.Id.String()) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
t.entries, err = parseTreeData(t, stdout) |
||||
return t.entries, err |
||||
} |
||||
|
||||
func NewTree(repo *Repository, id sha1) *Tree { |
||||
tree := new(Tree) |
||||
tree.Id = id |
||||
tree.repo = repo |
||||
return tree |
||||
} |
@ -0,0 +1,46 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"fmt" |
||||
"path" |
||||
"strings" |
||||
) |
||||
|
||||
func (t *Tree) GetTreeEntryByPath(relpath string) (*TreeEntry, error) { |
||||
if len(relpath) == 0 { |
||||
return &TreeEntry{ |
||||
Id: t.Id, |
||||
Type: TREE, |
||||
mode: ModeTree, |
||||
}, nil |
||||
// return nil, fmt.Errorf("GetTreeEntryByPath(empty relpath): %v", ErrNotExist)
|
||||
} |
||||
|
||||
relpath = path.Clean(relpath) |
||||
parts := strings.Split(relpath, "/") |
||||
var err error |
||||
tree := t |
||||
for i, name := range parts { |
||||
if i == len(parts)-1 { |
||||
entries, err := tree.ListEntries(path.Dir(relpath)) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
for _, v := range entries { |
||||
if v.name == name { |
||||
return v, nil |
||||
} |
||||
} |
||||
} else { |
||||
tree, err = tree.SubTree(name) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
} |
||||
} |
||||
return nil, fmt.Errorf("GetTreeEntryByPath: %v", ErrNotExist) |
||||
} |
@ -0,0 +1,109 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"sort" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
type EntryMode int |
||||
|
||||
// There are only a few file modes in Git. They look like unix file modes, but they can only be
|
||||
// one of these.
|
||||
const ( |
||||
ModeBlob EntryMode = 0100644 |
||||
ModeExec EntryMode = 0100755 |
||||
ModeSymlink EntryMode = 0120000 |
||||
ModeCommit EntryMode = 0160000 |
||||
ModeTree EntryMode = 0040000 |
||||
) |
||||
|
||||
type TreeEntry struct { |
||||
Id sha1 |
||||
Type ObjectType |
||||
|
||||
mode EntryMode |
||||
name string |
||||
|
||||
ptree *Tree |
||||
|
||||
commited bool |
||||
|
||||
size int64 |
||||
sized bool |
||||
} |
||||
|
||||
func (te *TreeEntry) Name() string { |
||||
return te.name |
||||
} |
||||
|
||||
func (te *TreeEntry) Size() int64 { |
||||
if te.IsDir() { |
||||
return 0 |
||||
} |
||||
|
||||
if te.sized { |
||||
return te.size |
||||
} |
||||
|
||||
stdout, _, err := com.ExecCmdDir(te.ptree.repo.Path, "git", "cat-file", "-s", te.Id.String()) |
||||
if err != nil { |
||||
return 0 |
||||
} |
||||
|
||||
te.sized = true |
||||
te.size = com.StrTo(strings.TrimSpace(stdout)).MustInt64() |
||||
return te.size |
||||
} |
||||
|
||||
func (te *TreeEntry) IsDir() bool { |
||||
return te.mode == ModeTree |
||||
} |
||||
|
||||
func (te *TreeEntry) EntryMode() EntryMode { |
||||
return te.mode |
||||
} |
||||
|
||||
func (te *TreeEntry) Blob() *Blob { |
||||
return &Blob{ |
||||
repo: te.ptree.repo, |
||||
TreeEntry: te, |
||||
} |
||||
} |
||||
|
||||
type Entries []*TreeEntry |
||||
|
||||
var sorter = []func(t1, t2 *TreeEntry) bool{ |
||||
func(t1, t2 *TreeEntry) bool { |
||||
return t1.IsDir() && !t2.IsDir() |
||||
}, |
||||
func(t1, t2 *TreeEntry) bool { |
||||
return t1.name < t2.name |
||||
}, |
||||
} |
||||
|
||||
func (bs Entries) Len() int { return len(bs) } |
||||
func (bs Entries) Swap(i, j int) { bs[i], bs[j] = bs[j], bs[i] } |
||||
func (bs Entries) Less(i, j int) bool { |
||||
t1, t2 := bs[i], bs[j] |
||||
var k int |
||||
for k = 0; k < len(sorter)-1; k++ { |
||||
sort := sorter[k] |
||||
switch { |
||||
case sort(t1, t2): |
||||
return true |
||||
case sort(t2, t1): |
||||
return false |
||||
} |
||||
} |
||||
return sorter[k](t1, t2) |
||||
} |
||||
|
||||
func (bs Entries) Sort() { |
||||
sort.Sort(bs) |
||||
} |
@ -0,0 +1,27 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"path/filepath" |
||||
"strings" |
||||
) |
||||
|
||||
const prettyLogFormat = `--pretty=format:%H` |
||||
|
||||
func RefEndName(refStr string) string { |
||||
index := strings.LastIndex(refStr, "/") |
||||
if index != -1 { |
||||
return refStr[index+1:] |
||||
} |
||||
return refStr |
||||
} |
||||
|
||||
// If the object is stored in its own file (i.e not in a pack file),
|
||||
// this function returns the full path to the object file.
|
||||
// It does not test if the file exists.
|
||||
func filepathFromSHA1(rootdir, sha1 string) string { |
||||
return filepath.Join(rootdir, "objects", sha1[:2], sha1[2:]) |
||||
} |
@ -0,0 +1,43 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package git |
||||
|
||||
import ( |
||||
"errors" |
||||
"strings" |
||||
|
||||
"github.com/Unknwon/com" |
||||
) |
||||
|
||||
// Version represents version of Git.
|
||||
type Version struct { |
||||
Major, Minor, Patch int |
||||
} |
||||
|
||||
// GetVersion returns current Git version installed.
|
||||
func GetVersion() (Version, error) { |
||||
stdout, stderr, err := com.ExecCmd("git", "version") |
||||
if err != nil { |
||||
return Version{}, errors.New(stderr) |
||||
} |
||||
|
||||
infos := strings.Split(stdout, " ") |
||||
if len(infos) < 3 { |
||||
return Version{}, errors.New("not enough output") |
||||
} |
||||
|
||||
v := Version{} |
||||
for i, s := range strings.Split(strings.TrimSpace(infos[2]), ".") { |
||||
switch i { |
||||
case 0: |
||||
v.Major, _ = com.StrTo(s).Int() |
||||
case 1: |
||||
v.Minor, _ = com.StrTo(s).Int() |
||||
case 2: |
||||
v.Patch, _ = com.StrTo(s).Int() |
||||
} |
||||
} |
||||
return v, nil |
||||
} |
@ -0,0 +1,73 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package log |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"log" |
||||
"os" |
||||
"runtime" |
||||
) |
||||
|
||||
type Brush func(string) string |
||||
|
||||
func NewBrush(color string) Brush { |
||||
pre := "\033[" |
||||
reset := "\033[0m" |
||||
return func(text string) string { |
||||
return pre + color + "m" + text + reset |
||||
} |
||||
} |
||||
|
||||
var colors = []Brush{ |
||||
NewBrush("1;36"), // Trace cyan
|
||||
NewBrush("1;34"), // Debug blue
|
||||
NewBrush("1;32"), // Info green
|
||||
NewBrush("1;33"), // Warn yellow
|
||||
NewBrush("1;31"), // Error red
|
||||
NewBrush("1;35"), // Critical purple
|
||||
NewBrush("1;31"), // Fatal red
|
||||
} |
||||
|
||||
// ConsoleWriter implements LoggerInterface and writes messages to terminal.
|
||||
type ConsoleWriter struct { |
||||
lg *log.Logger |
||||
Level int `json:"level"` |
||||
} |
||||
|
||||
// create ConsoleWriter returning as LoggerInterface.
|
||||
func NewConsole() LoggerInterface { |
||||
return &ConsoleWriter{ |
||||
lg: log.New(os.Stdout, "", log.Ldate|log.Ltime), |
||||
Level: TRACE, |
||||
} |
||||
} |
||||
|
||||
func (cw *ConsoleWriter) Init(config string) error { |
||||
return json.Unmarshal([]byte(config), cw) |
||||
} |
||||
|
||||
func (cw *ConsoleWriter) WriteMsg(msg string, skip, level int) error { |
||||
if cw.Level > level { |
||||
return nil |
||||
} |
||||
if runtime.GOOS == "windows" { |
||||
cw.lg.Println(msg) |
||||
} else { |
||||
cw.lg.Println(colors[level](msg)) |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (_ *ConsoleWriter) Destroy() { |
||||
} |
||||
|
||||
func (_ *ConsoleWriter) Flush() { |
||||
|
||||
} |
||||
|
||||
func init() { |
||||
Register("console", NewConsole) |
||||
} |
@ -0,0 +1,237 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package log |
||||
|
||||
import ( |
||||
"encoding/json" |
||||
"errors" |
||||
"fmt" |
||||
"io/ioutil" |
||||
"log" |
||||
"os" |
||||
"path/filepath" |
||||
"strings" |
||||
"sync" |
||||
"time" |
||||
) |
||||
|
||||
// FileLogWriter implements LoggerInterface.
|
||||
// It writes messages by lines limit, file size limit, or time frequency.
|
||||
type FileLogWriter struct { |
||||
*log.Logger |
||||
mw *MuxWriter |
||||
// The opened file
|
||||
Filename string `json:"filename"` |
||||
|
||||
Maxlines int `json:"maxlines"` |
||||
maxlines_curlines int |
||||
|
||||
// Rotate at size
|
||||
Maxsize int `json:"maxsize"` |
||||
maxsize_cursize int |
||||
|
||||
// Rotate daily
|
||||
Daily bool `json:"daily"` |
||||
Maxdays int64 `json:"maxdays` |
||||
daily_opendate int |
||||
|
||||
Rotate bool `json:"rotate"` |
||||
|
||||
startLock sync.Mutex // Only one log can write to the file
|
||||
|
||||
Level int `json:"level"` |
||||
} |
||||
|
||||
// an *os.File writer with locker.
|
||||
type MuxWriter struct { |
||||
sync.Mutex |
||||
fd *os.File |
||||
} |
||||
|
||||
// write to os.File.
|
||||
func (l *MuxWriter) Write(b []byte) (int, error) { |
||||
l.Lock() |
||||
defer l.Unlock() |
||||
return l.fd.Write(b) |
||||
} |
||||
|
||||
// set os.File in writer.
|
||||
func (l *MuxWriter) SetFd(fd *os.File) { |
||||
if l.fd != nil { |
||||
l.fd.Close() |
||||
} |
||||
l.fd = fd |
||||
} |
||||
|
||||
// create a FileLogWriter returning as LoggerInterface.
|
||||
func NewFileWriter() LoggerInterface { |
||||
w := &FileLogWriter{ |
||||
Filename: "", |
||||
Maxlines: 1000000, |
||||
Maxsize: 1 << 28, //256 MB
|
||||
Daily: true, |
||||
Maxdays: 7, |
||||
Rotate: true, |
||||
Level: TRACE, |
||||
} |
||||
// use MuxWriter instead direct use os.File for lock write when rotate
|
||||
w.mw = new(MuxWriter) |
||||
// set MuxWriter as Logger's io.Writer
|
||||
w.Logger = log.New(w.mw, "", log.Ldate|log.Ltime) |
||||
return w |
||||
} |
||||
|
||||
// Init file logger with json config.
|
||||
// config like:
|
||||
// {
|
||||
// "filename":"log/gogs.log",
|
||||
// "maxlines":10000,
|
||||
// "maxsize":1<<30,
|
||||
// "daily":true,
|
||||
// "maxdays":15,
|
||||
// "rotate":true
|
||||
// }
|
||||
func (w *FileLogWriter) Init(config string) error { |
||||
if err := json.Unmarshal([]byte(config), w); err != nil { |
||||
return err |
||||
} |
||||
if len(w.Filename) == 0 { |
||||
return errors.New("config must have filename") |
||||
} |
||||
return w.StartLogger() |
||||
} |
||||
|
||||
// start file logger. create log file and set to locker-inside file writer.
|
||||
func (w *FileLogWriter) StartLogger() error { |
||||
fd, err := w.createLogFile() |
||||
if err != nil { |
||||
return err |
||||
} |
||||
w.mw.SetFd(fd) |
||||
if err = w.initFd(); err != nil { |
||||
return err |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (w *FileLogWriter) docheck(size int) { |
||||
w.startLock.Lock() |
||||
defer w.startLock.Unlock() |
||||
if w.Rotate && ((w.Maxlines > 0 && w.maxlines_curlines >= w.Maxlines) || |
||||
(w.Maxsize > 0 && w.maxsize_cursize >= w.Maxsize) || |
||||
(w.Daily && time.Now().Day() != w.daily_opendate)) { |
||||
if err := w.DoRotate(); err != nil { |
||||
fmt.Fprintf(os.Stderr, "FileLogWriter(%q): %s\n", w.Filename, err) |
||||
return |
||||
} |
||||
} |
||||
w.maxlines_curlines++ |
||||
w.maxsize_cursize += size |
||||
} |
||||
|
||||
// write logger message into file.
|
||||
func (w *FileLogWriter) WriteMsg(msg string, skip, level int) error { |
||||
if level < w.Level { |
||||
return nil |
||||
} |
||||
n := 24 + len(msg) // 24 stand for the length "2013/06/23 21:00:22 [T] "
|
||||
w.docheck(n) |
||||
w.Logger.Println(msg) |
||||
return nil |
||||
} |
||||
|
||||
func (w *FileLogWriter) createLogFile() (*os.File, error) { |
||||
// Open the log file
|
||||
return os.OpenFile(w.Filename, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0660) |
||||
} |
||||
|
||||
func (w *FileLogWriter) initFd() error { |
||||
fd := w.mw.fd |
||||
finfo, err := fd.Stat() |
||||
if err != nil { |
||||
return fmt.Errorf("get stat: %s\n", err) |
||||
} |
||||
w.maxsize_cursize = int(finfo.Size()) |
||||
w.daily_opendate = time.Now().Day() |
||||
if finfo.Size() > 0 { |
||||
content, err := ioutil.ReadFile(w.Filename) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
w.maxlines_curlines = len(strings.Split(string(content), "\n")) |
||||
} else { |
||||
w.maxlines_curlines = 0 |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
// DoRotate means it need to write file in new file.
|
||||
// new file name like xx.log.2013-01-01.2
|
||||
func (w *FileLogWriter) DoRotate() error { |
||||
_, err := os.Lstat(w.Filename) |
||||
if err == nil { // file exists
|
||||
// Find the next available number
|
||||
num := 1 |
||||
fname := "" |
||||
for ; err == nil && num <= 999; num++ { |
||||
fname = w.Filename + fmt.Sprintf(".%s.%03d", time.Now().Format("2006-01-02"), num) |
||||
_, err = os.Lstat(fname) |
||||
} |
||||
// return error if the last file checked still existed
|
||||
if err == nil { |
||||
return fmt.Errorf("rotate: cannot find free log number to rename %s\n", w.Filename) |
||||
} |
||||
|
||||
// block Logger's io.Writer
|
||||
w.mw.Lock() |
||||
defer w.mw.Unlock() |
||||
|
||||
fd := w.mw.fd |
||||
fd.Close() |
||||
|
||||
// close fd before rename
|
||||
// Rename the file to its newfound home
|
||||
if err = os.Rename(w.Filename, fname); err != nil { |
||||
return fmt.Errorf("Rotate: %s\n", err) |
||||
} |
||||
|
||||
// re-start logger
|
||||
if err = w.StartLogger(); err != nil { |
||||
return fmt.Errorf("Rotate StartLogger: %s\n", err) |
||||
} |
||||
|
||||
go w.deleteOldLog() |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func (w *FileLogWriter) deleteOldLog() { |
||||
dir := filepath.Dir(w.Filename) |
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { |
||||
if !info.IsDir() && info.ModTime().Unix() < (time.Now().Unix()-60*60*24*w.Maxdays) { |
||||
if strings.HasPrefix(filepath.Base(path), filepath.Base(w.Filename)) { |
||||
os.Remove(path) |
||||
} |
||||
} |
||||
return nil |
||||
}) |
||||
} |
||||
|
||||
// destroy file logger, close file writer.
|
||||
func (w *FileLogWriter) Destroy() { |
||||
w.mw.fd.Close() |
||||
} |
||||
|
||||
// flush file logger.
|
||||
// there are no buffering messages in file logger in memory.
|
||||
// flush file means sync file from disk.
|
||||
func (w *FileLogWriter) Flush() { |
||||
w.mw.fd.Sync() |
||||
} |
||||
|
||||
func init() { |
||||
Register("file", NewFileWriter) |
||||
} |
@ -1,52 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package middleware |
||||
|
||||
import ( |
||||
"fmt" |
||||
"log" |
||||
"net/http" |
||||
"runtime" |
||||
"time" |
||||
|
||||
"github.com/go-martini/martini" |
||||
|
||||
"github.com/gogits/gogs/modules/setting" |
||||
) |
||||
|
||||
var isWindows bool |
||||
|
||||
func init() { |
||||
isWindows = runtime.GOOS == "windows" |
||||
} |
||||
|
||||
func Logger() martini.Handler { |
||||
return func(res http.ResponseWriter, req *http.Request, ctx martini.Context, log *log.Logger) { |
||||
if setting.DisableRouterLog { |
||||
return |
||||
} |
||||
|
||||
start := time.Now() |
||||
log.Printf("Started %s %s", req.Method, req.URL.Path) |
||||
|
||||
rw := res.(martini.ResponseWriter) |
||||
ctx.Next() |
||||
|
||||
content := fmt.Sprintf("Completed %v %s in %v", rw.Status(), http.StatusText(rw.Status()), time.Since(start)) |
||||
if !isWindows { |
||||
switch rw.Status() { |
||||
case 200: |
||||
content = fmt.Sprintf("\033[1;32m%s\033[0m", content) |
||||
case 304: |
||||
content = fmt.Sprintf("\033[1;33m%s\033[0m", content) |
||||
case 404: |
||||
content = fmt.Sprintf("\033[1;31m%s\033[0m", content) |
||||
case 500: |
||||
content = fmt.Sprintf("\033[1;36m%s\033[0m", content) |
||||
} |
||||
} |
||||
log.Println(content) |
||||
} |
||||
} |
@ -1,281 +0,0 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// foked from https://github.com/martini-contrib/render/blob/master/render.go
|
||||
package middleware |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/json" |
||||
"fmt" |
||||
"html/template" |
||||
"io" |
||||
"io/ioutil" |
||||
"net/http" |
||||
"os" |
||||
"path/filepath" |
||||
"time" |
||||
|
||||
"github.com/go-martini/martini" |
||||
|
||||
"github.com/gogits/gogs/modules/base" |
||||
) |
||||
|
||||
const ( |
||||
ContentType = "Content-Type" |
||||
ContentLength = "Content-Length" |
||||
ContentJSON = "application/json" |
||||
ContentHTML = "text/html" |
||||
ContentXHTML = "application/xhtml+xml" |
||||
defaultCharset = "UTF-8" |
||||
) |
||||
|
||||
var helperFuncs = template.FuncMap{ |
||||
"yield": func() (string, error) { |
||||
return "", fmt.Errorf("yield called with no layout defined") |
||||
}, |
||||
} |
||||
|
||||
type Delims struct { |
||||
Left string |
||||
Right string |
||||
} |
||||
|
||||
type RenderOptions struct { |
||||
Directory string |
||||
Layout string |
||||
Extensions []string |
||||
Funcs []template.FuncMap |
||||
Delims Delims |
||||
Charset string |
||||
IndentJSON bool |
||||
HTMLContentType string |
||||
} |
||||
|
||||
type HTMLOptions struct { |
||||
Layout string |
||||
} |
||||
|
||||
func Renderer(options ...RenderOptions) martini.Handler { |
||||
opt := prepareOptions(options) |
||||
cs := prepareCharset(opt.Charset) |
||||
t := compile(opt) |
||||
return func(res http.ResponseWriter, req *http.Request, c martini.Context) { |
||||
var tc *template.Template |
||||
if martini.Env == martini.Dev { |
||||
|
||||
tc = compile(opt) |
||||
} else { |
||||
|
||||
tc, _ = t.Clone() |
||||
} |
||||
|
||||
rd := &Render{res, req, tc, opt, cs, base.TmplData{}, time.Time{}} |
||||
|
||||
rd.Data["TmplLoadTimes"] = func() string { |
||||
if rd.startTime.IsZero() { |
||||
return "" |
||||
} |
||||
return fmt.Sprint(time.Since(rd.startTime).Nanoseconds()/1e6) + "ms" |
||||
} |
||||
|
||||
c.Map(rd.Data) |
||||
c.Map(rd) |
||||
} |
||||
} |
||||
|
||||
func prepareCharset(charset string) string { |
||||
if len(charset) != 0 { |
||||
return "; charset=" + charset |
||||
} |
||||
|
||||
return "; charset=" + defaultCharset |
||||
} |
||||
|
||||
func prepareOptions(options []RenderOptions) RenderOptions { |
||||
var opt RenderOptions |
||||
if len(options) > 0 { |
||||
opt = options[0] |
||||
} |
||||
|
||||
if len(opt.Directory) == 0 { |
||||
opt.Directory = "templates" |
||||
} |
||||
if len(opt.Extensions) == 0 { |
||||
opt.Extensions = []string{".tmpl"} |
||||
} |
||||
if len(opt.HTMLContentType) == 0 { |
||||
opt.HTMLContentType = ContentHTML |
||||
} |
||||
|
||||
return opt |
||||
} |
||||
|
||||
func compile(options RenderOptions) *template.Template { |
||||
dir := options.Directory |
||||
t := template.New(dir) |
||||
t.Delims(options.Delims.Left, options.Delims.Right) |
||||
|
||||
template.Must(t.Parse("Martini")) |
||||
|
||||
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error { |
||||
r, err := filepath.Rel(dir, path) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
ext := filepath.Ext(r) |
||||
for _, extension := range options.Extensions { |
||||
if ext == extension { |
||||
|
||||
buf, err := ioutil.ReadFile(path) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
|
||||
name := (r[0 : len(r)-len(ext)]) |
||||
tmpl := t.New(filepath.ToSlash(name)) |
||||
|
||||
for _, funcs := range options.Funcs { |
||||
tmpl = tmpl.Funcs(funcs) |
||||
} |
||||
|
||||
template.Must(tmpl.Funcs(helperFuncs).Parse(string(buf))) |
||||
break |
||||
} |
||||
} |
||||
|
||||
return nil |
||||
}) |
||||
|
||||
return t |
||||
} |
||||
|
||||
type Render struct { |
||||
http.ResponseWriter |
||||
req *http.Request |
||||
t *template.Template |
||||
opt RenderOptions |
||||
compiledCharset string |
||||
|
||||
Data base.TmplData |
||||
|
||||
startTime time.Time |
||||
} |
||||
|
||||
func (r *Render) JSON(status int, v interface{}) { |
||||
var result []byte |
||||
var err error |
||||
if r.opt.IndentJSON { |
||||
result, err = json.MarshalIndent(v, "", " ") |
||||
} else { |
||||
result, err = json.Marshal(v) |
||||
} |
||||
if err != nil { |
||||
http.Error(r, err.Error(), 500) |
||||
return |
||||
} |
||||
|
||||
r.Header().Set(ContentType, ContentJSON+r.compiledCharset) |
||||
r.WriteHeader(status) |
||||
r.Write(result) |
||||
} |
||||
|
||||
func (r *Render) JSONString(v interface{}) (string, error) { |
||||
var result []byte |
||||
var err error |
||||
if r.opt.IndentJSON { |
||||
result, err = json.MarshalIndent(v, "", " ") |
||||
} else { |
||||
result, err = json.Marshal(v) |
||||
} |
||||
if err != nil { |
||||
return "", err |
||||
} |
||||
return string(result), nil |
||||
} |
||||
|
||||
func (r *Render) renderBytes(name string, binding interface{}, htmlOpt ...HTMLOptions) (*bytes.Buffer, error) { |
||||
opt := r.prepareHTMLOptions(htmlOpt) |
||||
|
||||
if len(opt.Layout) > 0 { |
||||
r.addYield(name, binding) |
||||
name = opt.Layout |
||||
} |
||||
|
||||
out, err := r.execute(name, binding) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return out, nil |
||||
} |
||||
|
||||
func (r *Render) HTML(status int, name string, binding interface{}, htmlOpt ...HTMLOptions) { |
||||
r.startTime = time.Now() |
||||
|
||||
out, err := r.renderBytes(name, binding, htmlOpt...) |
||||
if err != nil { |
||||
http.Error(r, err.Error(), http.StatusInternalServerError) |
||||
return |
||||
} |
||||
|
||||
r.Header().Set(ContentType, r.opt.HTMLContentType+r.compiledCharset) |
||||
r.WriteHeader(status) |
||||
io.Copy(r, out) |
||||
} |
||||
|
||||
func (r *Render) HTMLString(name string, binding interface{}, htmlOpt ...HTMLOptions) (string, error) { |
||||
if out, err := r.renderBytes(name, binding, htmlOpt...); err != nil { |
||||
return "", err |
||||
} else { |
||||
return out.String(), nil |
||||
} |
||||
} |
||||
|
||||
func (r *Render) Error(status int, message ...string) { |
||||
r.WriteHeader(status) |
||||
if len(message) > 0 { |
||||
r.Write([]byte(message[0])) |
||||
} |
||||
} |
||||
|
||||
func (r *Render) Redirect(location string, status ...int) { |
||||
code := http.StatusFound |
||||
if len(status) == 1 { |
||||
code = status[0] |
||||
} |
||||
|
||||
http.Redirect(r, r.req, location, code) |
||||
} |
||||
|
||||
func (r *Render) Template() *template.Template { |
||||
return r.t |
||||
} |
||||
|
||||
func (r *Render) execute(name string, binding interface{}) (*bytes.Buffer, error) { |
||||
buf := new(bytes.Buffer) |
||||
return buf, r.t.ExecuteTemplate(buf, name, binding) |
||||
} |
||||
|
||||
func (r *Render) addYield(name string, binding interface{}) { |
||||
funcs := template.FuncMap{ |
||||
"yield": func() (template.HTML, error) { |
||||
buf, err := r.execute(name, binding) |
||||
|
||||
return template.HTML(buf.String()), err |
||||
}, |
||||
} |
||||
r.t.Funcs(funcs) |
||||
} |
||||
|
||||
func (r *Render) prepareHTMLOptions(htmlOpt []HTMLOptions) HTMLOptions { |
||||
if len(htmlOpt) > 0 { |
||||
return htmlOpt[0] |
||||
} |
||||
|
||||
return HTMLOptions{ |
||||
Layout: r.opt.Layout, |
||||
} |
||||
} |
@ -1,127 +0,0 @@
|
||||
// Copyright 2013 The Martini Authors. All rights reserved.
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package middleware |
||||
|
||||
import ( |
||||
"log" |
||||
"net/http" |
||||
"path" |
||||
"runtime" |
||||
"strings" |
||||
|
||||
"github.com/go-martini/martini" |
||||
|
||||
"github.com/gogits/gogs/modules/setting" |
||||
) |
||||
|
||||
// StaticOptions is a struct for specifying configuration options for the martini.Static middleware.
|
||||
type StaticOptions struct { |
||||
// Prefix is the optional prefix used to serve the static directory content
|
||||
Prefix string |
||||
// SkipLogging will disable [Static] log messages when a static file is served.
|
||||
SkipLogging bool |
||||
// IndexFile defines which file to serve as index if it exists.
|
||||
IndexFile string |
||||
// Expires defines which user-defined function to use for producing a HTTP Expires Header
|
||||
// https://developers.google.com/speed/docs/insights/LeverageBrowserCaching
|
||||
Expires func() string |
||||
} |
||||
|
||||
func prepareStaticOptions(options []StaticOptions) StaticOptions { |
||||
var opt StaticOptions |
||||
if len(options) > 0 { |
||||
opt = options[0] |
||||
} |
||||
|
||||
// Defaults
|
||||
if len(opt.IndexFile) == 0 { |
||||
opt.IndexFile = "index.html" |
||||
} |
||||
// Normalize the prefix if provided
|
||||
if opt.Prefix != "" { |
||||
// Ensure we have a leading '/'
|
||||
if opt.Prefix[0] != '/' { |
||||
opt.Prefix = "/" + opt.Prefix |
||||
} |
||||
// Remove any trailing '/'
|
||||
opt.Prefix = strings.TrimRight(opt.Prefix, "/") |
||||
} |
||||
return opt |
||||
} |
||||
|
||||
// Static returns a middleware handler that serves static files in the given directory.
|
||||
func Static(directory string, staticOpt ...StaticOptions) martini.Handler { |
||||
if runtime.GOOS == "windows" { |
||||
if len(directory) < 2 || directory[1] != ':' { |
||||
directory = path.Join(setting.StaticRootPath, directory) |
||||
} |
||||
} else if !path.IsAbs(directory) { |
||||
directory = path.Join(setting.StaticRootPath, directory) |
||||
} |
||||
|
||||
dir := http.Dir(directory) |
||||
opt := prepareStaticOptions(staticOpt) |
||||
|
||||
return func(res http.ResponseWriter, req *http.Request, log *log.Logger) { |
||||
if req.Method != "GET" && req.Method != "HEAD" { |
||||
return |
||||
} |
||||
file := req.URL.Path |
||||
// if we have a prefix, filter requests by stripping the prefix
|
||||
if opt.Prefix != "" { |
||||
if !strings.HasPrefix(file, opt.Prefix) { |
||||
return |
||||
} |
||||
file = file[len(opt.Prefix):] |
||||
if file != "" && file[0] != '/' { |
||||
return |
||||
} |
||||
} |
||||
f, err := dir.Open(file) |
||||
if err != nil { |
||||
// discard the error?
|
||||
return |
||||
} |
||||
defer f.Close() |
||||
|
||||
fi, err := f.Stat() |
||||
if err != nil { |
||||
return |
||||
} |
||||
|
||||
// try to serve index file
|
||||
if fi.IsDir() { |
||||
// redirect if missing trailing slash
|
||||
if !strings.HasSuffix(req.URL.Path, "/") { |
||||
http.Redirect(res, req, req.URL.Path+"/", http.StatusFound) |
||||
return |
||||
} |
||||
|
||||
file = path.Join(file, opt.IndexFile) |
||||
f, err = dir.Open(file) |
||||
if err != nil { |
||||
return |
||||
} |
||||
defer f.Close() |
||||
|
||||
fi, err = f.Stat() |
||||
if err != nil || fi.IsDir() { |
||||
return |
||||
} |
||||
} |
||||
|
||||
if !opt.SkipLogging { |
||||
log.Println("[Static] Serving " + file) |
||||
} |
||||
|
||||
// Add an Expires header to the static content
|
||||
if opt.Expires != nil { |
||||
res.Header().Set("Expires", opt.Expires()) |
||||
} |
||||
|
||||
http.ServeContent(res, req, file, fi.ModTime(), f) |
||||
} |
||||
} |
@ -0,0 +1,119 @@
|
||||
// Copyright 2014 The Gogs Authors. All rights reserved.
|
||||
// Use of this source code is governed by a MIT-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Prototype, git client looks like do not recognize req.Reply.
|
||||
package ssh |
||||
|
||||
import ( |
||||
"fmt" |
||||
"io/ioutil" |
||||
"net" |
||||
"os" |
||||
"os/exec" |
||||
"strings" |
||||
|
||||
"code.google.com/p/go.crypto/ssh" |
||||
|
||||
"github.com/Unknwon/com" |
||||
|
||||
"github.com/gogits/gogs-ng/modules/log" |
||||
) |
||||
|
||||
func handleServerConn(keyId string, chans <-chan ssh.NewChannel) { |
||||
for newChan := range chans { |
||||
if newChan.ChannelType() != "session" { |
||||
newChan.Reject(ssh.UnknownChannelType, "unknown channel type") |
||||
continue |
||||
} |
||||
channel, requests, err := newChan.Accept() |
||||
if err != nil { |
||||
log.Error(3, "Could not accept channel: %v", err) |
||||
continue |
||||
} |
||||
|
||||
go func(in <-chan *ssh.Request) { |
||||
defer channel.Close() |
||||
for req := range in { |
||||
ok, payload := false, strings.TrimLeft(string(req.Payload), "\x00") |
||||
fmt.Println("Request:", req.Type, req.WantReply, payload) |
||||
switch req.Type { |
||||
case "env": |
||||
args := strings.Split(strings.Replace(payload, "\x00", "", -1), "\v") |
||||
if len(args) != 2 { |
||||
break |
||||
} |
||||
args[0] = strings.TrimLeft(args[0], "\x04") |
||||
_, _, err := com.ExecCmdBytes("env", args[0]+"="+args[1]) |
||||
if err != nil { |
||||
log.Error(3, "env: %v", err) |
||||
channel.Stderr().Write([]byte(err.Error())) |
||||
break |
||||
} |
||||
ok = true |
||||
case "exec": |
||||
os.Setenv("SSH_ORIGINAL_COMMAND", strings.TrimLeft(payload, "'(")) |
||||
log.Info("Payload: %v", strings.TrimLeft(payload, "'(")) |
||||
cmd := exec.Command("/Users/jiahuachen/Applications/Go/src/github.com/gogits/gogs-ng/gogs-ng", "serv", "key-"+keyId) |
||||
cmd.Stdout = channel |
||||
cmd.Stdin = channel |
||||
cmd.Stderr = channel.Stderr() |
||||
if err := cmd.Run(); err != nil { |
||||
log.Error(3, "exec: %v", err) |
||||
} else { |
||||
ok = true |
||||
} |
||||
} |
||||
fmt.Println("Done:", ok) |
||||
req.Reply(ok, nil) // BUG: Git on Mac seems not know this reply and hang?
|
||||
} |
||||
fmt.Println("Done!!!") |
||||
}(requests) |
||||
} |
||||
} |
||||
|
||||
func listen(config *ssh.ServerConfig, port string) { |
||||
listener, err := net.Listen("tcp", "0.0.0.0:"+port) |
||||
if err != nil { |
||||
panic(err) |
||||
} |
||||
for { |
||||
// Once a ServerConfig has been configured, connections can be accepted.
|
||||
conn, err := listener.Accept() |
||||
if err != nil { |
||||
log.Error(3, "Fail to accept incoming connection: %v", err) |
||||
continue |
||||
} |
||||
// Before use, a handshake must be performed on the incoming net.Conn.
|
||||
sConn, chans, reqs, err := ssh.NewServerConn(conn, config) |
||||
if err != nil { |
||||
log.Error(3, "Fail to handshake: %v", err) |
||||
continue |
||||
} |
||||
// The incoming Request channel must be serviced.
|
||||
go ssh.DiscardRequests(reqs) |
||||
go handleServerConn(sConn.Permissions.Extensions["key-id"], chans) |
||||
} |
||||
} |
||||
|
||||
// Listen starts a SSH server listens on given port.
|
||||
func Listen(port string) { |
||||
config := &ssh.ServerConfig{ |
||||
PublicKeyCallback: func(conn ssh.ConnMetadata, key ssh.PublicKey) (*ssh.Permissions, error) { |
||||
// keyCache[string(ssh.MarshalAuthorizedKey(key))] = 2
|
||||
return &ssh.Permissions{Extensions: map[string]string{"key-id": "2"}}, nil |
||||
}, |
||||
} |
||||
|
||||
privateBytes, err := ioutil.ReadFile("/Users/jiahuachen/.ssh/id_rsa") |
||||
if err != nil { |
||||
panic("failed to load private key") |
||||
} |
||||
private, err := ssh.ParsePrivateKey(privateBytes) |
||||
if err != nil { |
||||
panic("failed to parse private key") |
||||
} |
||||
config.AddHostKey(private) |
||||
|
||||
go listen(config, port) |
||||
} |
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 96 KiB |
@ -0,0 +1 @@
|
||||
.hljs{display:block;overflow-x:auto;padding:.5em;color:#333;background:#f8f8f8}.hljs-comment,.hljs-template_comment,.diff .hljs-header,.hljs-javadoc{color:#998;font-style:italic}.hljs-keyword,.css .rule .hljs-keyword,.hljs-winutils,.javascript .hljs-title,.nginx .hljs-title,.hljs-subst,.hljs-request,.hljs-status{color:#333;font-weight:bold}.hljs-number,.hljs-hexcolor,.ruby .hljs-constant{color:#099}.hljs-string,.hljs-tag .hljs-value,.hljs-phpdoc,.tex .hljs-formula{color:#d14}.hljs-title,.hljs-id,.coffeescript .hljs-params,.scss .hljs-preprocessor{color:#900;font-weight:bold}.javascript .hljs-title,.lisp .hljs-title,.clojure .hljs-title,.hljs-subst{font-weight:normal}.hljs-class .hljs-title,.haskell .hljs-type,.vhdl .hljs-literal,.tex .hljs-command{color:#458;font-weight:bold}.hljs-tag,.hljs-tag .hljs-title,.hljs-rules .hljs-property,.django .hljs-tag .hljs-keyword{color:#000080;font-weight:normal}.hljs-attribute,.hljs-variable,.lisp .hljs-body{color:#008080}.hljs-regexp{color:#009926}.hljs-symbol,.ruby .hljs-symbol .hljs-string,.lisp .hljs-keyword,.tex .hljs-special,.hljs-prompt{color:#990073}.hljs-built_in,.lisp .hljs-title,.clojure .hljs-built_in{color:#0086b3}.hljs-preprocessor,.hljs-pragma,.hljs-pi,.hljs-doctype,.hljs-shebang,.hljs-cdata{color:#999;font-weight:bold}.hljs-deletion{background:#fdd}.hljs-addition{background:#dfd}.diff .hljs-change{background:#0086b3}.hljs-chunk{color:#aaa} |
@ -0,0 +1,814 @@
|
||||
* { |
||||
padding: 0; |
||||
margin: 0; |
||||
} |
||||
html { |
||||
font-size: 13px; |
||||
font-family: Helvetica, "Microsoft Yahei", Menlo, Monaco, Consolas, "Courier New", monospace; |
||||
-ms-text-size-adjust: 100%; |
||||
-webkit-text-size-adjust: 100%; |
||||
line-height: 24px; |
||||
color: #444444; |
||||
background-color: #fafafa; |
||||
} |
||||
input, |
||||
textarea, |
||||
select, |
||||
option, |
||||
button { |
||||
font-family: Helvetica, "Microsoft Yahei", Menlo, Monaco, Consolas, "Courier New", monospace; |
||||
} |
||||
article, |
||||
aside, |
||||
details, |
||||
figcaption, |
||||
figure, |
||||
footer, |
||||
header, |
||||
main, |
||||
nav, |
||||
section, |
||||
summary, |
||||
.block { |
||||
display: block; |
||||
} |
||||
.inline { |
||||
display: inline; |
||||
} |
||||
.inline-block { |
||||
display: inline-block; |
||||
} |
||||
.dis-table { |
||||
display: table; |
||||
} |
||||
.dis-table-cell { |
||||
display: table-cell; |
||||
} |
||||
.dis-flex { |
||||
display: flex; |
||||
} |
||||
audio, |
||||
canvas, |
||||
progress, |
||||
video { |
||||
display: inline-block; |
||||
vertical-align: baseline; |
||||
} |
||||
audio:not([controls]) { |
||||
display: none; |
||||
height: 0; |
||||
} |
||||
[hidden], |
||||
template .hidden { |
||||
display: none; |
||||
} |
||||
.opacity { |
||||
opacity: 0; |
||||
} |
||||
.opacity-half { |
||||
opacity: .5; |
||||
} |
||||
a, |
||||
.text-link { |
||||
color: #428bca; |
||||
text-decoration: none; |
||||
} |
||||
a:hover, |
||||
.text-link:hover { |
||||
color: #399ade; |
||||
text-decoration: none; |
||||
} |
||||
a:focus, |
||||
.text-link:focus { |
||||
outline: none; |
||||
} |
||||
b, |
||||
strong, |
||||
.text-bold { |
||||
font-weight: bold; |
||||
} |
||||
dfn, |
||||
.text-italic { |
||||
font-style: italic; |
||||
} |
||||
h1, |
||||
.text-h1 { |
||||
font-size: 2em; |
||||
margin-bottom: 0.67em; |
||||
} |
||||
h2, |
||||
.text-h2 { |
||||
font-size: 1.6em; |
||||
margin-bottom: 0.625em; |
||||
} |
||||
h3, |
||||
.text-h3 { |
||||
font: 1.2em; |
||||
margin-bottom: 0.5em; |
||||
} |
||||
h4, |
||||
h5, |
||||
h6, |
||||
.text-h4, |
||||
.text-h5, |
||||
.text-h6 { |
||||
font-size: 1em; |
||||
margin-bottom: .3em; |
||||
} |
||||
small, |
||||
.text-small { |
||||
font-size: .8em; |
||||
} |
||||
sub, |
||||
sup, |
||||
.text-sup, |
||||
.text-sub { |
||||
font-size: .7em; |
||||
line-height: 0; |
||||
position: relative; |
||||
vertical-align: baseline; |
||||
} |
||||
sup, |
||||
.text-sup { |
||||
top: -0.5em; |
||||
} |
||||
sub, |
||||
.text-sub { |
||||
bottom: -0.25em; |
||||
} |
||||
.figure, |
||||
.blockquote { |
||||
margin: 1em 1.5em; |
||||
} |
||||
pre { |
||||
overflow: auto; |
||||
margin: 0; |
||||
padding: .4em 1em; |
||||
} |
||||
code, |
||||
kbd, |
||||
pre, |
||||
samp { |
||||
font-family: monospace, monospace; |
||||
font-size: 1em; |
||||
} |
||||
.text-left { |
||||
text-align: left; |
||||
} |
||||
.text-right { |
||||
text-align: right; |
||||
} |
||||
.text-center { |
||||
text-align: center; |
||||
} |
||||
.list-no-style { |
||||
list-style: none; |
||||
} |
||||
img { |
||||
border: none; |
||||
} |
||||
svg:not(:root) { |
||||
overflow: hidden; |
||||
} |
||||
label { |
||||
font-weight: bold; |
||||
} |
||||
input, |
||||
.ipt { |
||||
padding: .6em; |
||||
line-height: normal; |
||||
border: 1px solid #bbbbbb; |
||||
} |
||||
input:focus, |
||||
.ipt:focus { |
||||
background-color: #f2fffc; |
||||
outline: none; |
||||
} |
||||
button { |
||||
overflow: visible; |
||||
padding: .6em 1.2em; |
||||
} |
||||
button, |
||||
select { |
||||
text-transform: none; |
||||
} |
||||
button:focus, |
||||
select:focus { |
||||
outline: none; |
||||
} |
||||
button, |
||||
input[type="button"], |
||||
input[type="reset"], |
||||
input[type="submit"] { |
||||
-webkit-appearance: button; |
||||
-moz-appearance: button; |
||||
cursor: pointer; |
||||
background-color: #888888; |
||||
color: #fafafa; |
||||
border: none; |
||||
} |
||||
button:hover, |
||||
input[type="button"]:hover, |
||||
input[type="reset"]:hover, |
||||
input[type="submit"]:hover { |
||||
background-color: #444444; |
||||
color: #ffffff; |
||||
} |
||||
button[disabled], |
||||
html input[disabled] { |
||||
cursor: default; |
||||
} |
||||
button::-moz-focus-inner, |
||||
input::-moz-focus-inner { |
||||
border: 0; |
||||
padding: 0; |
||||
} |
||||
input[type="checkbox"], |
||||
input[type="radio"] { |
||||
box-sizing: border-box; |
||||
padding: 0; |
||||
} |
||||
input[type="search"] { |
||||
-webkit-appearance: textfield; |
||||
-moz-appearance: textfield; |
||||
-moz-box-sizing: content-box; |
||||
-webkit-box-sizing: content-box; |
||||
box-sizing: content-box; |
||||
} |
||||
fieldset { |
||||
border: 1px solid #bbbbbb; |
||||
margin: 0 2px; |
||||
padding: 0.4em 0.8em 0.8em; |
||||
} |
||||
legend { |
||||
border: 0; |
||||
padding: 0; |
||||
} |
||||
textarea { |
||||
overflow: auto; |
||||
border: 1px solid #bbbbbb; |
||||
padding: .6em; |
||||
} |
||||
textarea:focus { |
||||
background-color: #f2fffc; |
||||
outline: none; |
||||
} |
||||
optgroup { |
||||
font-weight: bold; |
||||
} |
||||
table { |
||||
border-collapse: collapse; |
||||
border-spacing: 0; |
||||
} |
||||
td, |
||||
th { |
||||
padding: 0; |
||||
} |
||||
hr { |
||||
-moz-box-sizing: content-box; |
||||
box-sizing: content-box; |
||||
height: 0; |
||||
border: none; |
||||
border-bottom: 1px solid #dddddd; |
||||
margin-bottom: .75em; |
||||
} |
||||
p code { |
||||
color: #b63b2c; |
||||
} |
||||
.radius { |
||||
border-radius: .25em; |
||||
} |
||||
.text-truncate { |
||||
overflow: hidden; |
||||
text-overflow: ellipsis; |
||||
white-space: nowrap; |
||||
display: inline-block; |
||||
vertical-align: top; |
||||
} |
||||
pre { |
||||
line-height: 1.6; |
||||
overflow: auto; |
||||
padding: 0; |
||||
} |
||||
.left { |
||||
float: left; |
||||
} |
||||
.right { |
||||
float: right; |
||||
} |
||||
.clear::after { |
||||
clear: both; |
||||
content: " "; |
||||
width: 0; |
||||
height: 0; |
||||
display: block; |
||||
} |
||||
.hide { |
||||
display: none; |
||||
} |
||||
.grid-1-12 { |
||||
width: 8.33%; |
||||
} |
||||
.grid-2-12, |
||||
.grid-1-6 { |
||||
width: 16.67%; |
||||
} |
||||
.grid-3-12, |
||||
.grid-1-4 { |
||||
width: 25%; |
||||
} |
||||
.grid-4-12, |
||||
.grid-1-3 { |
||||
width: 33%; |
||||
} |
||||
.grid-5-12 { |
||||
width: 41.67%; |
||||
} |
||||
.grid-6-12, |
||||
.grid-1-2 { |
||||
width: 50%; |
||||
} |
||||
.grid-7-12 { |
||||
width: 58.33%; |
||||
} |
||||
.grid-8-12, |
||||
.grid-2-3 { |
||||
width: 66.67%; |
||||
} |
||||
.grid-9-12, |
||||
.grid-3-4 { |
||||
width: 75%; |
||||
} |
||||
.grid-10-12, |
||||
.grid-5-6 { |
||||
width: 83.33%; |
||||
} |
||||
.grid-11-12 { |
||||
width: 91.67%; |
||||
} |
||||
*[class*="grid-"] { |
||||
box-sizing: content-box; |
||||
} |
||||
.grid-1-5 { |
||||
width: 20%; |
||||
} |
||||
.grid-2-5 { |
||||
width: 40%; |
||||
} |
||||
.grid-3-5 { |
||||
width: 60%; |
||||
} |
||||
.grid-4-5 { |
||||
width: 80%; |
||||
} |
||||
.btn-small { |
||||
font-size: 10.8px; |
||||
padding: .4em .9em; |
||||
} |
||||
.btn-large { |
||||
font-size: 14.4px; |
||||
} |
||||
.btn-green { |
||||
background-color: #65ad4e; |
||||
border: 1px solid #65ad4e; |
||||
} |
||||
.btn-green:hover { |
||||
background-color: #71bf57; |
||||
color: #FFF; |
||||
} |
||||
.btn-blue { |
||||
background-color: #428bca; |
||||
border: 1px solid #428bca; |
||||
} |
||||
.btn-blue:hover { |
||||
background-color: #539cdb; |
||||
color: #FFF; |
||||
} |
||||
.btn-red { |
||||
background-color: #d9453d; |
||||
border: 1px solid #d9453d; |
||||
} |
||||
.btn-red:hover { |
||||
background-color: #ff635a; |
||||
color: #FFF; |
||||
} |
||||
.btn-orange { |
||||
background-color: #df7514; |
||||
border: 1px solid #df7514; |
||||
} |
||||
.btn-orange:hover { |
||||
background-color: #df8229; |
||||
color: #FFF; |
||||
} |
||||
.btn-black { |
||||
background-color: #444444; |
||||
border: 1px solid #444444; |
||||
} |
||||
.btn-black:hover { |
||||
background-color: #383838; |
||||
color: #FFF; |
||||
} |
||||
.btn-gray { |
||||
background-color: #f0f0f0; |
||||
color: #444444; |
||||
border: 1px solid #d0d0d0; |
||||
} |
||||
.btn-gray:hover { |
||||
background-color: #fafafa; |
||||
color: #444444; |
||||
} |
||||
.btn-active { |
||||
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1) inset, 0 0 4px rgba(0, 0, 0, 0.15) inset; |
||||
} |
||||
.btn-radius { |
||||
border-radius: .25em; |
||||
} |
||||
.btn-left-radius { |
||||
border-top-left-radius: .25em; |
||||
border-bottom-left-radius: .25em; |
||||
} |
||||
.btn-right-radius { |
||||
border-top-right-radius: .25em; |
||||
border-bottom-right-radius: .25em; |
||||
} |
||||
.btn-block { |
||||
display: block; |
||||
width: 100%; |
||||
box-sizing: content-box; |
||||
text-align: center; |
||||
} |
||||
.btn-disabled { |
||||
opacity: .6; |
||||
cursor: not-allowed; |
||||
box-shadow: none; |
||||
background-image: none !important; |
||||
border: none; |
||||
} |
||||
.btn-disabled:hover { |
||||
background-image: none !important; |
||||
color: #ffffff; |
||||
} |
||||
.ipt:focus { |
||||
border-color: #428bca; |
||||
} |
||||
.ipt-radius { |
||||
border-radius: .25em; |
||||
} |
||||
.ipt-small { |
||||
font-size: 9.6px; |
||||
} |
||||
.ipt-large { |
||||
font-size: 14.4px; |
||||
} |
||||
.ipt-disabled, |
||||
input[disabled] { |
||||
background-color: #f2f2f2 !important; |
||||
color: #888; |
||||
cursor: not-allowed; |
||||
} |
||||
.ipt-disabled:focus, |
||||
input[disabled]:focus { |
||||
background-color: #f2f2f2 !important; |
||||
} |
||||
.ipt-readonly:focus, |
||||
input[readonly]:focus { |
||||
background-color: #f2f2f2 !important; |
||||
} |
||||
.ipt-error { |
||||
border-color: #b63b2c !important; |
||||
background-color: #fff0f0 !important; |
||||
} |
||||
.form label { |
||||
margin-right: 1em; |
||||
} |
||||
.form .help { |
||||
color: #999999; |
||||
padding-top: .6em; |
||||
display: inline-block; |
||||
} |
||||
.form-stack label { |
||||
display: block; |
||||
} |
||||
.form-stack .field { |
||||
margin-bottom: 1em; |
||||
} |
||||
.form-align label, |
||||
.form-align .form-label { |
||||
display: inline-block; |
||||
width: 120px; |
||||
text-align: right; |
||||
margin-right: 1em; |
||||
} |
||||
.form-align .field { |
||||
margin-bottom: 1em; |
||||
} |
||||
label.req:after { |
||||
content: "*"; |
||||
color: #d9453d; |
||||
} |
||||
ul.menu > li { |
||||
list-style: none; |
||||
} |
||||
ul.menu > li > a { |
||||
padding: .8em 1.2em; |
||||
} |
||||
ul.menu > li > a:hover { |
||||
background-color: #eaeaea; |
||||
color: #444444; |
||||
} |
||||
ul.menu > li.current > a, |
||||
ul.menu > li.hover > a { |
||||
color: #444444; |
||||
} |
||||
ul.menu > li.head { |
||||
font-weight: bold; |
||||
padding: .8em 1.2em; |
||||
} |
||||
ul.menu > li.down:hover > ul.menu-down { |
||||
display: block; |
||||
} |
||||
ul.menu > li.border-bottom { |
||||
border-bottom: 1px solid #bbbbbb; |
||||
height: 0; |
||||
margin: .5em 0; |
||||
} |
||||
ul.menu-line > li, |
||||
ul.menu-line > li > a { |
||||
display: inline-block; |
||||
} |
||||
ul.menu-line > li.down { |
||||
position: relative; |
||||
} |
||||
ul.menu-line > li.down > a:after { |
||||
content: "\25BE"; |
||||
margin-left: .4em; |
||||
} |
||||
ul.menu-line > li.down > ul.menu-down { |
||||
top: 2.1em; |
||||
width: 150%; |
||||
} |
||||
ul.menu-line > li.hover { |
||||
position: relative; |
||||
} |
||||
ul.menu-line > li.hover > a:after { |
||||
position: absolute; |
||||
content: "\25B4"; |
||||
left: 50%; |
||||
bottom: -1.1em; |
||||
margin-left: -4px; |
||||
} |
||||
ul.menu-vertical > li > a, |
||||
ul.menu-down > li > a, |
||||
ul.menu-vertical > li.head, |
||||
ul.menu-down > li.head { |
||||
display: block; |
||||
padding: .4em 1.2em; |
||||
} |
||||
ul.menu-vertical > li.down, |
||||
ul.menu-down > li.down { |
||||
position: relative; |
||||
} |
||||
ul.menu-vertical > li.down > a:after, |
||||
ul.menu-down > li.down > a:after { |
||||
content: "\25B8"; |
||||
position: absolute; |
||||
right: .6em; |
||||
} |
||||
ul.menu-vertical > li.hover, |
||||
ul.menu-down > li.hover { |
||||
position: relative; |
||||
} |
||||
ul.menu-vertical > li.hover > a:after, |
||||
ul.menu-down > li.hover > a:after { |
||||
content: "\25B8"; |
||||
position: absolute; |
||||
left: .5em; |
||||
} |
||||
ul.menu-border, |
||||
ul.menu-down { |
||||
border: 1px solid #bbbbbb; |
||||
} |
||||
ul.menu-border > li.head, |
||||
ul.menu-down > li.head { |
||||
border-bottom: 1px solid #bbbbbb; |
||||
} |
||||
ul.menu-down { |
||||
position: absolute; |
||||
display: none; |
||||
z-index: 99; |
||||
box-shadow: 0 0 2px #666666; |
||||
background-color: #ffffff; |
||||
} |
||||
ul.menu-radius { |
||||
border-radius: .3em; |
||||
} |
||||
ul.menu-radius > li:first-child { |
||||
border-top-left-radius: .3em; |
||||
border-top-right-radius: .3em; |
||||
} |
||||
ul.menu-radius > li:first-child > a { |
||||
border-top-left-radius: .2em; |
||||
border-top-right-radius: .2em; |
||||
} |
||||
ul.menu-radius > li:last-child { |
||||
border-bottom-left-radius: .3em; |
||||
border-bottom-right-radius: .3em; |
||||
} |
||||
ul.menu-radius > li:last-child > a { |
||||
border-bottom-left-radius: .2em; |
||||
border-bottom-right-radius: .2em; |
||||
} |
||||
.drop { |
||||
position: relative; |
||||
} |
||||
.drop:hover > .drop-down { |
||||
position: absolute; |
||||
top: 0; |
||||
left: 0; |
||||
width: 200%; |
||||
display: block; |
||||
} |
||||
.drop > .drop-down { |
||||
display: none; |
||||
border: 1px solid #bbbbbb; |
||||
box-shadow: 0 0 3px #666666; |
||||
background-color: #ffffff; |
||||
} |
||||
.drop-bottom:after { |
||||
content: "\25BE"; |
||||
margin-left: .4em; |
||||
} |
||||
.drop-top:after { |
||||
content: "\25B4"; |
||||
margin-left: .4em; |
||||
} |
||||
.panel { |
||||
border: 1px solid #cccccc; |
||||
} |
||||
.panel .panel-header { |
||||
font-size: 16px; |
||||
padding: .6em 1.2em; |
||||
background-color: #eeeeee; |
||||
border-bottom: 1px solid #cccccc; |
||||
} |
||||
.panel .panel-body .panel-desc { |
||||
margin-bottom: 20px; |
||||
} |
||||
.panel .panel-content { |
||||
padding: 1em 1.2em; |
||||
} |
||||
.panel .panel-footer { |
||||
padding: .6em 1.2em; |
||||
background-color: #eeeeee; |
||||
border-top: 1px solid #cccccc; |
||||
} |
||||
.panel.panel-radius { |
||||
border-radius: .3em; |
||||
} |
||||
.panel.panel-radius .panel-header { |
||||
border-top-left-radius: .3em; |
||||
border-top-right-radius: .3em; |
||||
} |
||||
.panel.panel-radius .panel-footer { |
||||
border-bottom-left-radius: .3em; |
||||
border-bottom-right-radius: .3em; |
||||
} |
||||
.panel.panel-warning { |
||||
border-color: #F0C36D; |
||||
} |
||||
.panel.panel-warning > .panel-header { |
||||
background-color: #F9EDBE; |
||||
border-color: #F0C36D; |
||||
} |
||||
.label { |
||||
padding: 2px 6px; |
||||
color: #ffffff; |
||||
} |
||||
.label-red { |
||||
background-color: #d9453d; |
||||
} |
||||
.label-blue { |
||||
background-color: #428bca; |
||||
} |
||||
.label-gray { |
||||
background-color: #999999; |
||||
} |
||||
.label-green { |
||||
background-color: #65ad4e; |
||||
} |
||||
.label-orange { |
||||
background-color: #df7514; |
||||
} |
||||
.label-black { |
||||
background-color: #444444; |
||||
} |
||||
.label-radius { |
||||
border-radius: .2em; |
||||
} |
||||
.label-link { |
||||
color: #ffffff; |
||||
} |
||||
.label-link:hover { |
||||
color: #ffffff; |
||||
} |
||||
.breads .bread:after { |
||||
content: "/"; |
||||
font-weight: bold; |
||||
margin: 0 4px 0 7px; |
||||
color: #444444; |
||||
} |
||||
.breads .bread:last-child:after { |
||||
content: ""; |
||||
margin: 0; |
||||
} |
||||
.alert { |
||||
padding: .6em 1.5em; |
||||
margin-bottom: 10px; |
||||
} |
||||
.alert i { |
||||
margin-right: 8px; |
||||
} |
||||
.alert-radius { |
||||
border-radius: .25em; |
||||
} |
||||
.alert-red { |
||||
color: #d9453d; |
||||
border: 1px solid #be2d25; |
||||
background-color: #fae9e8; |
||||
} |
||||
.alert-blue { |
||||
color: #428bca; |
||||
border: 1px solid #3071a9; |
||||
background-color: #f5f9fc; |
||||
} |
||||
.alert-green { |
||||
color: #65ad4e; |
||||
border: 1px solid #508a3e; |
||||
background-color: #edf6eb; |
||||
} |
||||
.alert-gray { |
||||
color: #999999; |
||||
border: 1px solid #808080; |
||||
background-color: #f2f2f2; |
||||
} |
||||
.alert-orange { |
||||
color: #df7514; |
||||
border: 1px solid #b05c10; |
||||
background-color: #fcecdd; |
||||
} |
||||
table th, |
||||
table td { |
||||
padding: .3em .6em; |
||||
line-height: 30px; |
||||
} |
||||
.table-border { |
||||
border: 1px solid #d6d6d6; |
||||
} |
||||
.table-border tr { |
||||
border-top: 1px solid #eaeaea; |
||||
} |
||||
.table-border tr th, |
||||
.table-border tr td { |
||||
border-top: 1px solid #eaeaea; |
||||
} |
||||
.table-border tr:first-child { |
||||
border-top: none; |
||||
} |
||||
.table-border thead { |
||||
border-bottom: 1px solid #d6d6d6; |
||||
} |
||||
.table-block { |
||||
width: 100%; |
||||
box-sizing: border-box; |
||||
} |
||||
.table-radius { |
||||
border-collapse: separate !important; |
||||
border-radius: .3em; |
||||
} |
||||
.table-radius thead:first-child { |
||||
border-top-left-radius: .3em; |
||||
border-top-right-radius: .3em; |
||||
} |
||||
.table-radius thead:first-child tr:first-child { |
||||
border-top-left-radius: .3em; |
||||
} |
||||
.table-radius thead:first-child tr:first-child > th:first-child { |
||||
border-top-left-radius: .3em; |
||||
} |
||||
.table-radius thead:first-child tr:first-child > th:last-child { |
||||
border-top-right-radius: .3em; |
||||
} |
||||
.table-radius tbody { |
||||
border-bottom-left-radius: .3em; |
||||
border-bottom-right-radius: .3em; |
||||
} |
||||
.table-radius tbody tr:last-child { |
||||
border-bottom-left-radius: .3em; |
||||
border-bottom-right-radius: .3em; |
||||
} |
||||
.table-radius tbody tr:last-child > td:first-child { |
||||
border-bottom-left-radius: .3em; |
||||
} |
||||
.table-radius tbody tr:last-child > td:last-child { |
||||
border-bottom-right-radius: .3em; |
||||
} |
After Width: | Height: | Size: 248 KiB |