Flask rewrite master
authormathieui <mathieui@mathieui.net>
Wed, 4 Feb 2015 23:06:55 +0000 (00:06 +0100)
committermathieui <mathieui@mathieui.net>
Wed, 4 Feb 2015 23:06:55 +0000 (00:06 +0100)
35 files changed:
LICENCE.txt [new file with mode: 0644]
README.rst [new file with mode: 0644]
debug_run.py [new file with mode: 0755]
make_db.py [new file with mode: 0755]
pleaseshare/__init__.py [new file with mode: 0644]
pleaseshare/app.py [new file with mode: 0644]
pleaseshare/babel.cfg [new file with mode: 0644]
pleaseshare/forms.py [new file with mode: 0644]
pleaseshare/makefile [new file with mode: 0644]
pleaseshare/settings.cfg [new file with mode: 0644]
pleaseshare/static/fonts/DroidSans-Bold-webfont.eot [new file with mode: 0755]
pleaseshare/static/fonts/DroidSans-Bold-webfont.svg [new file with mode: 0755]
pleaseshare/static/fonts/DroidSans-Bold-webfont.ttf [new file with mode: 0755]
pleaseshare/static/fonts/DroidSans-Bold-webfont.woff [new file with mode: 0755]
pleaseshare/static/fonts/DroidSans-webfont.eot [new file with mode: 0755]
pleaseshare/static/fonts/DroidSans-webfont.svg [new file with mode: 0755]
pleaseshare/static/fonts/DroidSans-webfont.ttf [new file with mode: 0755]
pleaseshare/static/fonts/DroidSans-webfont.woff [new file with mode: 0755]
pleaseshare/static/style.css [new file with mode: 0644]
pleaseshare/static_routes.py [new file with mode: 0644]
pleaseshare/tasks.py [new file with mode: 0644]
pleaseshare/templates/about.html [new file with mode: 0644]
pleaseshare/templates/base.html [new file with mode: 0644]
pleaseshare/templates/contact.html [new file with mode: 0644]
pleaseshare/templates/help.html [new file with mode: 0644]
pleaseshare/templates/home.html [new file with mode: 0644]
pleaseshare/templates/tos.html [new file with mode: 0644]
pleaseshare/templates/view.html [new file with mode: 0644]
pleaseshare/torrent/__init__.py [new file with mode: 0644]
pleaseshare/torrent/bencode.py [new file with mode: 0644]
pleaseshare/torrent/common.py [new file with mode: 0644]
pleaseshare/torrent/maketorrent.py [new file with mode: 0644]
pleaseshare/translations/fr/LC_MESSAGES/messages.mo [new file with mode: 0644]
pleaseshare/translations/fr/LC_MESSAGES/messages.po [new file with mode: 0644]
requirements.txt [new file with mode: 0644]

diff --git a/LICENCE.txt b/LICENCE.txt
new file mode 100644 (file)
index 0000000..dba13ed
--- /dev/null
@@ -0,0 +1,661 @@
+                    GNU AFFERO GENERAL PUBLIC LICENSE
+                       Version 3, 19 November 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 Affero General Public License is a free, copyleft license for
+software and other kinds of works, specifically designed to ensure
+cooperation with the community in the case of network server software.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+our General Public Licenses are 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.
+
+  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.
+
+  Developers that use our General Public Licenses protect your rights
+with two steps: (1) assert copyright on the software, and (2) offer
+you this License which gives you legal permission to copy, distribute
+and/or modify the software.
+
+  A secondary benefit of defending all users' freedom is that
+improvements made in alternate versions of the program, if they
+receive widespread use, become available for other developers to
+incorporate.  Many developers of free software are heartened and
+encouraged by the resulting cooperation.  However, in the case of
+software used on network servers, this result may fail to come about.
+The GNU General Public License permits making a modified version and
+letting the public access it on a server without ever releasing its
+source code to the public.
+
+  The GNU Affero General Public License is designed specifically to
+ensure that, in such cases, the modified source code becomes available
+to the community.  It requires the operator of a network server to
+provide the source code of the modified version running there to the
+users of that server.  Therefore, public use of a modified version, on
+a publicly accessible server, gives the public access to the source
+code of the modified version.
+
+  An older license, called the Affero General Public License and
+published by Affero, was designed to accomplish similar goals.  This is
+a different license, not a version of the Affero GPL, but Affero has
+released a new version of the Affero GPL which permits relicensing under
+this license.
+
+  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 Affero 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. Remote Network Interaction; Use with the GNU General Public License.
+
+  Notwithstanding any other provision of this License, if you modify the
+Program, your modified version must prominently offer all users
+interacting with it remotely through a computer network (if your version
+supports such interaction) an opportunity to receive the Corresponding
+Source of your version by providing access to the Corresponding Source
+from a network server at no charge, through some standard or customary
+means of facilitating copying of software.  This Corresponding Source
+shall include the Corresponding Source for any work covered by version 3
+of the GNU General Public License that is incorporated pursuant to the
+following paragraph.
+
+  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 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 work with which it is combined will remain governed by version
+3 of the GNU General Public License.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU Affero 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 Affero 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 Affero 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 Affero 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 Affero 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 Affero General Public License for more details.
+
+    You should have received a copy of the GNU Affero 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 your software can interact with users remotely through a computer
+network, you should also make sure that it provides a way for users to
+get its source.  For example, if your program is a web application, its
+interface could display a "Source" link that leads users to an archive
+of the code.  There are many ways you could offer source, and different
+solutions will be better for different programs; see section 13 for the
+specific requirements.
+
+  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 AGPL, see
+<http://www.gnu.org/licenses/>.
diff --git a/README.rst b/README.rst
new file mode 100644 (file)
index 0000000..c3b58ac
--- /dev/null
@@ -0,0 +1,154 @@
+PleaseShare
+===========
+
+PleaseShare is a file-sharing website that aims to decentralize
+file-sharing through the use of bittorrent, DHT, and webseeds.
+
+
+Get started
+-----------
+
+Retrieve the project from gitorious_ or github_:
+
+.. _gitorious: https://git.gitorious.org/pleaseshare/pleaseshare.git
+.. _github: https://github.com/mathieui/pleaseshare.git
+
+::
+
+    $ git clone git://gitorious.org/pleaseshare/pleaseshare.git
+
+Then install the dependencies (assuming you are using a virtualenv):
+
+::
+
+    $ cd pleaseshare
+    $ pip install -r requirements.txt
+    $ mkdir -p pleaseshare/uploads
+
+Now you can start coding, testing, etc.
+
+Install
+-------
+
+(do the Get started thing before that)
+
+First, edit the variables in pleaseshare/settings.cfg to fit your needs,
+everything is properly documented inside the file, but you MUST consider
+changing the following:
+
+- ``SECRET_KEY`` and ``WTF_CSRF_SECRET_KEY``, both set to the value of a local ``key`` variable
+- ``SQLALCHEMY_DATABASE_URI`` for database connection settings
+- ``MAX_CONTENT_LENGTH`` for the maximal upload file size
+
+Once everything is set, you only have to create the database:
+
+::
+
+    $ ./make_db.py
+
+
+In order to deploy PleaseShare, you can follow the flask `deployment guide`_.
+
+.. _deployment guide: http://flask.pocoo.org/docs/deploying/
+
+My favourite deployment option is uwsgi + nginx/lighttpd
+
+Example uwsgi+nginx deployment
+------------------------------
+
+``uwsgi.ini`` file:
+
+::
+
+    [uwsgi]
+    socket = 127.0.0.1:4444
+    master = true
+    plugin = python3
+    chdir = /home/flask/pleaseshare/
+    module = pleaseshare:app
+    processes = 4
+
+
+
+Nginx configuration section:
+
+:: 
+
+    server {
+        listen                  80;
+        server_name             share.example.com;
+        client_max_body_size    50m;
+
+        location / {
+            include             uwsgi_params;
+            uwsgi_pass          127.0.0.1:4444;
+        }
+    }
+
+    server {
+        listen                  80;
+        server_name             files.example.com;
+        client_max_body_size    200k;
+
+        location / {
+            root                /home/flask/pleaseshare/uploads/;
+            autoindex           off;
+        }
+    }
+
+(assuming ``UPLOAD_FOLDER`` is set to ``"uploads"``, and ``UPLOADED_FILES_URL``
+to ``"http://files.example.com/"``)
+
+
+I also usually use supervisord_ to manage my python web applications:
+
+::
+
+    [program:share]
+    command=uwsgi uwsgi.ini
+    directory=/home/flask/pleaseshare/
+    user=flask
+    redirect_stderr=true
+    autostart=true
+    autorestart=true
+
+
+.. _supervisord: http://supervisord.org/
+
+But manually running ``uwsgi uwsgi.ini`` works too.
+
+
+Misc
+----
+
+Some indications about how webseeds work might be in order.
+
+- When the torrent has a single file, then it’s easy: the webseed is the complete url of the file.
+- When the torrent is multifile, then the webseed url is the url of the parent directory (I’m talking about the torrents in PleaseShare, which are always contained in a parent directory named after the archive name).
+
+For example, you upload a toto.tar.gz archive, you will have a url like /view/48a3-[…]/,
+containing a 'toto' directory, which will contain the files inside the archive.
+
+The webseed url should **not** contain the 'toto' directory, but the parent
+level; and, of course, file indexing should be disabled, or the file generated
+by the webserver might cause problems to some torrent clients.
+
+So let’s say you want to add a source to the torrent using your personal
+webserver (again for the toto.tar.gz torrent), you will have to put something
+like that as a webseed: http://my.example.com/uploads/ which will contain a ``toto``
+directory.
+
+License
+-------
+
+PleaseShare is released under the terms of the `GNU Affero General
+Public License v3`_.
+
+PleaseShare also contains some files from the `Deluge torrent client`_,
+which is licenced under the `GNU General Public Licence v3`_.
+
+.. _GNU Affero General Public License v3 : http://www.gnu.org/licenses/agpl-3.0.html
+.. _Deluge torrent client : http://deluge-torrent.org/
+.. _GNU General Public Licence v3 : https://www.gnu.org/licenses/gpl-3.0.html
+
+
diff --git a/debug_run.py b/debug_run.py
new file mode 100755 (executable)
index 0000000..76406c0
--- /dev/null
@@ -0,0 +1,7 @@
+#!/usr/bin/env python3
+
+from pleaseshare import run 
+
+run(debug=True)
+
+
diff --git a/make_db.py b/make_db.py
new file mode 100755 (executable)
index 0000000..dc0ec9a
--- /dev/null
@@ -0,0 +1,4 @@
+#!/usr/bin/env python3
+
+from pleaseshare import db
+db.create_all()
diff --git a/pleaseshare/__init__.py b/pleaseshare/__init__.py
new file mode 100644 (file)
index 0000000..423eab3
--- /dev/null
@@ -0,0 +1,12 @@
+"""
+PleaseShare module.
+"""
+
+__package__ = "pleaseshare"
+
+__all__ = ['__main__', 'tasks', 'torrent', 'app', 'forms',
+           'static_routes', 'run', 'db']
+
+from pleaseshare.app import run, db, app
+
+__main__ = run
diff --git a/pleaseshare/app.py b/pleaseshare/app.py
new file mode 100644 (file)
index 0000000..3c4d56e
--- /dev/null
@@ -0,0 +1,229 @@
+"""
+PleaseShare main application file
+
+Mostly contains functions that require the app/db and
+therefore couldn’t be split up in another module.
+"""
+import flask
+import logging
+import werkzeug
+import subprocess
+
+log = logging.getLogger(__name__)
+
+from flask import flash
+from flask_wtf.csrf import CsrfProtect
+from flask.ext.sqlalchemy import SQLAlchemy
+from flask.ext.babel import Babel, gettext as _
+
+from uuid import uuid4
+from os import makedirs
+from shutil import rmtree
+from hashlib import sha256
+from urllib.parse import quote
+from os.path import basename, getsize, exists, join as joinpath, realpath, abspath
+
+from pleaseshare.tasks import Archive, create_torrent, parse_form
+from pleaseshare.forms import UploadForm, DeleteForm
+from pleaseshare.static_routes import static_pages
+
+
+app = flask.Flask(__name__)
+app.config.from_pyfile('settings.cfg')
+app.jinja_env.add_extension('jinja2.ext.i18n')
+
+csrf = CsrfProtect(app)
+babel = Babel(app, default_locale='en')
+db = SQLAlchemy(app)
+
+dynamic_pages = flask.Blueprint('dynamic', __name__, template_folder='templates')
+
+@dynamic_pages.route("/view/<filename>")
+def view(filename):
+    """
+    Show the page associated with an upload
+    """
+    upload_obj = db.session.query(Upload).get(filename)
+    if not upload_obj:
+        flash(_('Upload not found'), 'error')
+        return flask.redirect(flask.url_for("dynamic.home"))
+    form = DeleteForm()
+    return flask.render_template("view.html", object=upload_obj, form=form)
+
+@dynamic_pages.route('/delete', methods=['POST'])
+def delete():
+    """
+    Delete an upload (requires a password that matches the one stored)
+    """
+    form = DeleteForm()
+    if not form.validate_on_submit():
+        flash(_('Missing field in deletion form.'), 'error')
+        return flask.redirect(flask.url_for("dynamic.home"))
+    upload_obj = db.session.query(Upload).get(form.object_id.data)
+
+    if not upload_obj:
+        flash(_('Uploaded file %s not found.') % form.object_id.data, 'error')
+        return flask.redirect(flask.url_for("dynamic.home"))
+    if not upload_obj.password:
+        flash(_('Uploaded file %s cannot be deleted (no deletion password exists).') % form.object_id.data, 'error')
+        return flask.redirect(flask.url_for("dynamic.view", filename=form.object_id.data))
+
+    passwd = sha256(form.deletion_password.data.encode('utf-8', errors='ignore')).hexdigest()
+
+    if passwd == upload_obj.password:
+        db.session.delete(upload_obj)
+        db.session.commit()
+        rmtree(joinpath(app.config['UPLOAD_FOLDER'], upload_obj.uuid))
+        flash(_('Upload deleted successfully.'), 'success')
+    else:
+        flash(_('Wrong password'), 'error')
+        return flask.redirect(flask.url_for("dynamic.view", filename=upload_obj.uuid))
+
+    return flask.redirect(flask.url_for("dynamic.home"))
+
+@dynamic_pages.route('/', methods=['GET'])
+def home():
+    """Main page, with the upload form"""
+    form = UploadForm()
+    return flask.render_template("home.html", title="Index", form=form)
+
+@dynamic_pages.route('/upload', methods=["POST"])
+def upload():
+    """Upload target"""
+    form = UploadForm()
+    if not form.validate_on_submit():
+        flash(_('File required.'), 'error')
+        return flask.redirect(flask.url_for("dynamic.home"))
+
+    file = form.file.data
+    params = parse_form(form, app.config)
+    try:
+        upload = handle_uploaded_file(file, params)
+    except Exception:
+        log.error('Unspecified error', exc_info=True)
+        flash(_('Server error'), 'error')
+        return flask.redirect(flask.url_for("dynamic.home"))
+    return flask.redirect(flask.url_for("dynamic.view", filename=upload.uuid))
+
+def handle_uploaded_file(file_storage, params):
+    """
+    Write a file to the disk, and in the database.
+
+    returns the Upload object
+    """
+    uuid = str(uuid4())
+    folder = joinpath(app.config['UPLOAD_FOLDER'], uuid)
+    makedirs(folder)
+    filepath = realpath(abspath(joinpath(folder, werkzeug.secure_filename(file_storage.filename))))
+    filename = basename(filepath)
+    file_storage.save(filepath)
+
+    size = getsize(filepath)
+
+    multifile = False
+    data_path = filepath
+    if params.extract:
+        try:
+            archive = Archive(filepath, allow_compressed=app.config['ALLOW_COMPRESSED'])
+            archive_size = archive.size()
+            if archive_size <= app.config['MAX_CONTENT_LENGTH'] and archive.extract():
+                multifile = True
+                data_path = archive.extracted_location()
+                filename = archive.extracted_name()
+                size = archive_size
+            elif archive_size > app.config['MAX_CONTENT_LENGTH']:
+                flash(_('Extracted archive too big, fallback to single-file upload.'), 'error')
+        except Exception:
+            flash(_('Invalid archive, fallback to single-file upload.'), 'error')
+            log.error('Invalid archive', exc_info=True)
+
+    size = round(size / (1024.0**2), 2)
+    uploaded = Upload(uuid=uuid, name=filename, size=size, private=params.private)
+    uploaded.multifile = multifile
+    relative_url = quote(uploaded.get_file())
+    webseeds = [webseed + relative_url for webseed in  app.config['OTHER_WEBSEEDS']]
+    webseeds.append(app.config['UPLOADED_FILES_URL'] + relative_url)
+    webseeds.extend(params.webseeds)
+
+    torrent = create_torrent(data_path, "Created with pleaseshare", webseeds,
+                             params.trackers, params.private)
+    uploaded.magnet = torrent.save(joinpath(folder, "%s.torrent" % filename))
+    uploaded.description = params.description
+
+    if params.password:
+        uploaded.password = sha256(params.password.encode('utf-8', errors='ignore')).hexdigest()
+    db.session.add(uploaded)
+    db.session.commit()
+    return uploaded
+
+class Upload(db.Model):
+    """A database record describing a specific upload"""
+    __tablename__ = "uploads"
+    uuid = db.Column(db.String(36), primary_key=True)
+    uploader = db.Column(db.String(32), default='Anonymous')
+    name = db.Column(db.String(32))
+    password = db.Column(db.String(64), default='')
+    date = db.Column(db.Date)
+    magnet = db.Column(db.Text(200))
+    description = db.Column(db.Text(500))
+    size = db.Column(db.String(8))
+    private = db.Column(db.Boolean, default=False)
+    multifile = db.Column(db.Boolean, default=False)
+
+    def __str__(self):
+        """Print out object details for debug purposes"""
+        return '%s - %s | %s - %s' % (self.uploader, self.uuid, self.name, self.date)
+
+    __repr__ = __str__
+
+    def get_torrent_file(self):
+        return '%s/%s.torrent' % (self.uuid, self.name)
+
+    def get_direct_torrent_file(self, config):
+        return "%s%s" %  (config['UPLOADED_FILES_URL'], self.get_torrent_file())
+
+    def get_file(self):
+        if self.multifile:
+            return '%s' % (self.uuid)
+        else:
+            return '%s/%s' % (self.uuid, self.name)
+
+    def get_direct_file(self, config):
+        return "%s%s" % (config['UPLOADED_FILES_URL'], self.get_file())
+
+    def get_files(self, config):
+        """
+        Return a pretty file tree, with file sizes, using `tree`.
+        Store the result in a file to avoid frequent subprocess calls.
+        """
+        filelist = joinpath(config['UPLOAD_FOLDER'], self.uuid, 'file_list')
+        folder = joinpath(config['UPLOAD_FOLDER'], self.uuid, self.name)
+        if exists(filelist):
+            with open(filelist, 'r') as fd:
+                return fd.read()
+        else:
+            try:
+                proc = subprocess.Popen(['tree', '--noreport', '-ah', folder], stdout=subprocess.PIPE)
+                res = proc.communicate()[0]
+            except OSError:
+                res = b''
+                log.error('Call to `tree` failed.')
+            output = res.decode('utf-8').split('\n')
+            output[0] = str(self.name)
+            files = '\n'.join(output)
+            with open(filelist, 'w') as fdes:
+                fdes.write(files)
+            return files
+
+
+@babel.localeselector
+def get_locale():
+    """Autodetect the locale of the user"""
+    return flask.request.accept_languages.best_match(['fr', 'en'])
+
+app.register_blueprint(static_pages, url_prefix=app.config['STATIC_PAGES_PREFIX'])
+app.register_blueprint(dynamic_pages, url_prefix=app.config['DYNAMIC_PAGES_PREFIX'])
+
+def run(*args, **kwargs):
+    app.run(*args, **kwargs)
+
diff --git a/pleaseshare/babel.cfg b/pleaseshare/babel.cfg
new file mode 100644 (file)
index 0000000..f0234b3
--- /dev/null
@@ -0,0 +1,3 @@
+[python: **.py]
+[jinja2: **/templates/**.html]
+extensions=jinja2.ext.autoescape,jinja2.ext.with_
diff --git a/pleaseshare/forms.py b/pleaseshare/forms.py
new file mode 100644 (file)
index 0000000..e87b1bc
--- /dev/null
@@ -0,0 +1,31 @@
+"""
+Forms used by pleaseshare
+"""
+from flask_wtf import Form
+from flask_wtf.file import FileField, FileRequired
+
+from flask.ext.babel import lazy_gettext as _
+
+
+from wtforms import TextField, TextAreaField, BooleanField, PasswordField, HiddenField
+from wtforms.validators import DataRequired
+
+class UploadForm(Form):
+    """
+    Form used to upload a new file
+    """
+    uploader_name = TextField(_('Uploader name'), [DataRequired()], default=_('Anonymous'))
+    deletion_password = PasswordField(_('Password (used for deletion)'), default='')
+    file = FileField(_('File to upload'), [FileRequired()])
+    private = BooleanField(_('Private torrent?'), default=False)
+    extract = BooleanField(_('Extract file'), default=False)
+    trackers = TextAreaField(_('Trackers'), default='')
+    webseeds = TextAreaField(_('Webseeds'), default='')
+    description = TextAreaField(_('Short description'), default='')
+
+class DeleteForm(Form):
+    """
+    Form use to delete a previously uploaded file
+    """
+    deletion_password = PasswordField(_('Password for deletion:'))
+    object_id = HiddenField()
diff --git a/pleaseshare/makefile b/pleaseshare/makefile
new file mode 100644 (file)
index 0000000..e7ed155
--- /dev/null
@@ -0,0 +1,6 @@
+trans:
+       pybabel extract -F babel.cfg -o messages.pot .
+       pybabel update -i messages.pot -d translations
+       rm messages.pot
+compiletrans:
+       pybabel compile -d translations
diff --git a/pleaseshare/settings.cfg b/pleaseshare/settings.cfg
new file mode 100644 (file)
index 0000000..9102a46
--- /dev/null
@@ -0,0 +1,62 @@
+# The folder in which the uploaded files will be stored
+# each upload will be in UPLOAD_FOLDER/<uuid4>/.
+UPLOAD_FOLDER = "uploads"
+
+# URL allowing access to UPLOAD_FOLDER (terminated by a /)
+UPLOADED_FILES_URL = 'http://path-to-the-uploads/directory/'
+
+# Allow users to add other trackers in the form
+ALLOW_TRACKERS = True
+
+# Trackers that will be added to every torrent added
+MANDATORY_TRACKERS = []
+
+# Trackers that will be used to fill the form, but
+# can be edited out by a user.
+DEFAULT_TRACKERS = []
+
+# Allow users to specify other webseeds in the form
+ALLOW_WEBSEEDS = True
+
+# Add other mandatory webseeds.
+# For example, if you sync your upload directory between
+# several servers, and serve it with a different hostname,
+# you can add the URL to the upload directory here.
+OTHER_WEBSEEDS = []
+
+# Allow creation of private torrents
+ALLOW_PRIVATE = True
+
+# Allow archive extraction
+ALLOW_MULTIFILE = True
+
+# Allow compressed archives
+ALLOW_COMPRESSED = True
+
+# Show a button for direct HTTP download
+SHOW_DDL_LINK = False
+
+# Enable CSRF protection
+WTF_CSRF_ENABLED = True
+
+# Secret key, used for both flask internals and csrf tokens
+# CHANGE WHEN INSTALLING YOUR APPLICATION
+key = 'change me'
+
+WTF_CSRF_SECRET_KEY = key
+SECRET_KEY = key
+
+# Max upload file size, in bytes
+MAX_CONTENT_LENGTH = 50 * 1024 * 1024
+
+# database configuration, e.g. sqlite:///path/to/file.db
+# or mysql://username:password@server/dbname
+SQLALCHEMY_DATABASE_URI = 'sqlite:////tmp/test.db'
+
+# Prefix if you want to run your application in a subdirectory
+# (e.g. http://example/pleaseshare/) instead of a subdomain
+# (like http://share.example.com). You can of course combine both.
+prefix = ''
+STATIC_PAGES_PREFIX = prefix
+DYNAMIC_PAGES_PREFIX = prefix
+
diff --git a/pleaseshare/static/fonts/DroidSans-Bold-webfont.eot b/pleaseshare/static/fonts/DroidSans-Bold-webfont.eot
new file mode 100755 (executable)
index 0000000..00724ed
Binary files /dev/null and b/pleaseshare/static/fonts/DroidSans-Bold-webfont.eot differ
diff --git a/pleaseshare/static/fonts/DroidSans-Bold-webfont.svg b/pleaseshare/static/fonts/DroidSans-Bold-webfont.svg
new file mode 100755 (executable)
index 0000000..56e94da
--- /dev/null
@@ -0,0 +1,150 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   : Digitized data copyright  2006 Google Corporation
+Foundry     : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+</metadata>
+<defs>
+<font id="webfontSOhoM6aS" horiz-adv-x="1126" >
+<font-face units-per-em="2048" ascent="1638" descent="-410" />
+<missing-glyph horiz-adv-x="530" />
+<glyph unicode=" "  horiz-adv-x="530" />
+<glyph unicode="&#x09;" horiz-adv-x="530" />
+<glyph unicode="&#xa0;" horiz-adv-x="530" />
+<glyph unicode="!" horiz-adv-x="585" d="M117 143q0 41 14 80q10 29 37 51q20 18 55 28.5t70 10.5q33 0 67.5 -10t55.5 -29q23 -20 37 -50.5t14 -80t-14 -77.5q-18 -37 -37 -54q-25 -22 -56 -30q-27 -8 -67 -9q-43 0 -70 9q-31 9 -55 30q-25 20 -37 54q-14 36 -14 77zM121 1462h346l-51 -977h-244z" />
+<glyph unicode="&#x22;" horiz-adv-x="966" d="M133 1462h279l-41 -528h-197zM555 1462h279l-41 -528h-197z" />
+<glyph unicode="#" horiz-adv-x="1320" d="M45 406v206h277l47 232h-252v209h289l77 407h219l-77 -407h198l78 407h215l-78 -407h240v-209h-279l-47 -232h258v-206h-297l-77 -406h-220l78 406h-194l-76 -406h-215l74 406h-238zM539 612h196l47 232h-196z" />
+<glyph unicode="$" d="M98 1044q0 72 29 136q27 59 82 108q52 46 129 74q78 29 170 37v157h137v-151q104 -8 178 -25q90 -20 191 -63l-101 -234q-78 29 -135 47q-55 16 -133 25v-293l39 -14q90 -31 166 -72q74 -39 119 -84q51 -51 69 -102q23 -61 23 -133q0 -78 -27 -140q-27 -63 -78 -110 t-131 -80t-180 -41v-205h-137v201q-86 4 -123 8q-70 8 -104 16q-59 14 -93 27q-41 14 -88 35v264q51 -27 93 -41q33 -12 102 -33q41 -12 106 -26q49 -10 107 -15v318q-4 0 -8 2t-8.5 4t-8.5 4t-8 2q-6 2 -14 6q-86 31 -160 72q-59 33 -113 86q-46 46 -67 104q-23 61 -23 129 zM399 1051q0 -45 27 -78t82 -53v233q-53 -6 -82 -31q-27 -24 -27 -71zM645 328q59 10 86 39q29 33 29 84q0 25 -6 43t-21 32q-16 16 -35 27l-53 27v-252z" />
+<glyph unicode="%" horiz-adv-x="1802" d="M63 1026q0 111 21 193q23 90 61 143q43 59 109 90q65 31 154 31q88 0 151 -31q68 -33 111 -90q45 -61 65 -143q23 -90 23 -193q0 -113 -21 -195q-23 -90 -63 -145q-43 -59 -108.5 -90t-157.5 -31q-84 0 -149.5 31t-108.5 90q-41 55 -64 145.5t-23 194.5zM315 1024 q0 -127 23 -190q23 -61 72 -61.5t73 61.5q23 55 23 190q0 250 -96 250q-49 0 -72 -62q-23 -63 -23 -188zM375 0l811 1462h239l-811 -1462h-239zM1047 442q0 111 20 193q23 90 61 143q43 59 109 90q65 31 154 31q88 0 151 -31q68 -33 111 -90q45 -61 65 -143q23 -90 23 -193 q0 -113 -21 -194q-23 -86 -63 -144q-43 -59 -109 -90q-70 -33 -157 -32q-80 0 -150 32q-61 29 -106 90.5t-66 143.5q-22 90 -22 194zM1298 440q0 -127 23 -190q23 -61 72 -61.5t73 61.5q23 57 23 190q0 250 -96 250q-49 0 -72 -61q-23 -64 -23 -189z" />
+<glyph unicode="&#x26;" horiz-adv-x="1478" d="M82 395q0 76 18 137q16 55 53 108.5t83 90.5q49 41 108 76q-45 57 -65 88q-25 39 -41 84q-20 59 -25 84q-6 43 -6 86q0 78 31 139q33 63 84 105q61 49 131 67q80 23 165 23q88 0 158 -21q72 -20 125 -61q49 -37 82 -101q31 -58 31 -135q0 -66 -23 -127q-20 -53 -59 -106 q-37 -49 -90 -90q-63 -49 -111 -76l260 -268q33 61 62 139q25 66 45 147h317q-20 -78 -35 -120q-18 -55 -49 -127q-18 -41 -61 -125q-27 -53 -78 -121l283 -291h-377l-97 100q-76 -53 -176 -88q-92 -33 -213 -32q-119 0 -217 30q-100 31 -168 84q-70 55 -106 131 q-39 82 -39 170zM403 424q0 -43 17 -80q14 -33 43 -57q28 -25 67 -37q47 -14 84 -14q55 0 111 16q51 14 94 43l-309 330q-55 -45 -80 -90q-27 -48 -27 -111zM489 1122q0 -49 23 -98q18 -41 63 -92q74 41 117 88q39 41 39 104q0 27 -10 52q-8 18 -27 36q-14 14 -36.5 20.5 t-41.5 6.5q-23 0 -45 -6t-41 -19q-16 -10 -30 -36q-11 -19 -11 -56z" />
+<glyph unicode="'" horiz-adv-x="544" d="M133 1462h279l-41 -528h-197z" />
+<glyph unicode="(" horiz-adv-x="692" d="M82 561q0 123 18 246q18 125 56 237q37 117 92 220q53 100 135 198h250q-143 -197 -213 -424q-72 -233 -72 -475q0 -121 19 -237q20 -131 53 -231.5t90 -219.5q43 -90 121 -199h-248q-86 100 -135 193q-57 109 -92 215q-37 114 -56 233q-18 121 -18 244z" />
+<glyph unicode=")" horiz-adv-x="692" d="M61 1462h250q82 -98 135 -198q55 -102 93 -220q37 -113 55 -237q18 -123 18 -246t-18 -244q-18 -120 -55 -233q-35 -106 -93 -215q-49 -92 -135 -193h-248q78 109 121 199q57 119 90 219.5t54 231.5q18 117 18 237q0 242 -72 475q-70 227 -213 424z" />
+<glyph unicode="*" horiz-adv-x="1114" d="M63 1042l39 250l365 -104l-41 368h262l-41 -368l373 104l33 -252l-340 -24l223 -297l-227 -121l-156 313l-137 -311l-236 119l221 297z" />
+<glyph unicode="+" d="M88 612v219h367v369h219v-369h366v-219h-366v-364h-219v364h-367z" />
+<glyph unicode="," horiz-adv-x="593" d="M63 -264q6 23 15.5 65.5l13.5 61.5l29 131l24 129l10.5 62.5t8.5 52.5h280l15 -23l-33 -115q-18 -61 -43 -123q-8 -25 -49 -124q-6 -16 -51 -117h-220z" />
+<glyph unicode="-" horiz-adv-x="657" d="M61 424v250h537v-250h-537z" />
+<glyph unicode="." horiz-adv-x="583" d="M117 143q0 41 14 80q10 29 37 51q20 18 55 28.5t70 10.5q33 0 67.5 -10t55.5 -29q23 -20 37 -50.5t14 -80t-14 -77.5q-18 -37 -37 -54q-25 -22 -56 -30q-27 -8 -67 -9q-43 0 -70 9q-31 9 -55 30q-25 20 -37 54q-14 36 -14 77z" />
+<glyph unicode="/" horiz-adv-x="845" d="M14 0l545 1462h277l-545 -1462h-277z" />
+<glyph unicode="0" d="M63 731q0 182 27 318q27 137 88.5 235t155.5 149.5t229 51.5q125 0 219.5 -51.5t158 -147.5t94 -237.5t30.5 -317.5q0 -182 -27 -315q-29 -141 -88 -238q-57 -92 -157 -147q-94 -51 -230 -51q-127 0 -221 51q-96 53 -156 147q-61 98 -92 238q-31 137 -31 315zM371 731 q0 -252 43 -377t149 -125q104 0 150 125q45 123 45 377t-45 377q-47 127 -150 127q-51 0 -90 -33t-59 -94q-25 -74 -33 -158q-10 -106 -10 -219z" />
+<glyph unicode="1" d="M92 1087l471 375h254v-1462h-309v846v63q0 12 1 37t1 39l4 80q0 14 1 37.5t1 34.5q-2 -2 -7 -8.5t-9 -10.5q-6 -6 -13.5 -12t-15.5 -14q-14 -14 -31 -29q-10 -10 -30 -27l-168 -135z" />
+<glyph unicode="2" d="M78 1274q61 53 94 78q59 43 109 67q63 31 129 47q63 16 159 17q102 0 189 -29q80 -27 141.5 -82t91.5 -131q31 -78 31 -170q0 -84 -31 -164q-31 -82 -82 -155q-47 -68 -121 -150l-145 -151l-176 -177v-14h596v-260h-981v215l344 371l119 129q53 59 90 114q39 57 59 115 q20 55 21 125q0 74 -45 115t-119 41q-80 0 -152 -39q-74 -40 -153 -111z" />
+<glyph unicode="3" d="M57 59v263q35 -18 95 -41q45 -16 100 -31q49 -12 98 -18.5t92 -6.5q82 0 144 17q51 14 90 45q33 27 49 69q14 37 14 88q0 45 -18 82q-18 39 -59 62q-41 25 -109 39q-63 14 -166 14h-104v217h102q88 0 154 16q55 14 96 46q35 27 51 65.5t16 81.5q0 80 -49 123t-153 43 q-43 0 -90 -10q-45 -10 -76 -23q-35 -14 -66 -33q-35 -20 -53 -34l-156 206q57 41 91 58q59 29 108 45q59 18 125 31q55 10 143 10q115 0 197 -23q80 -23 151 -69q61 -41 97 -109q35 -66 35 -147q0 -74 -25 -136q-25 -63 -66 -106q-43 -45 -100 -76q-63 -33 -125 -47v-6 q176 -20 268 -107q90 -84 91 -231q0 -92 -35 -178q-33 -78 -105 -142q-63 -55 -180 -92q-111 -35 -256 -34q-104 0 -221 20q-103 18 -195 59z" />
+<glyph unicode="4" d="M4 303v215l621 944h284v-919h176v-240h-176v-303h-301v303h-604zM276 543h332v248v38q0 8 1 26.5t1 29t1 31t1 32.5l4 64q0 10 1 27.5t1 23.5q0 8 1.5 19.5t1.5 13.5h-9q-2 -4 -41 -88q-18 -41 -51 -95z" />
+<glyph unicode="5" d="M86 59v267q16 -10 82 -37q47 -18 94 -31q63 -16 100 -20q49 -6 95 -7q133 0 205 56q70 55 69 176q0 106 -69.5 163.5t-210.5 57.5q-35 0 -56 -2q-37 -4 -57 -8l-55 -12q-6 -2 -22.5 -5.5t-22.5 -5.5l-123 66l55 745h772v-262h-504l-24 -287q61 12 75 15q43 6 109 6 q92 0 174 -29q74 -27 141 -86q59 -53 94 -139t35 -191q0 -117 -36.5 -213t-108.5 -161q-74 -68 -180 -101q-111 -35 -244 -34q-53 0 -108 6q-70 8 -105 14q-53 10 -94 25q-51 18 -80 34z" />
+<glyph unicode="6" d="M76 621q0 104 12 208q14 117 41 201q29 90 80 176q47 80 127 144q74 59 186 94q111 35 254 35h45q8 0 25.5 -2t25.5 -2q16 0 50 -5q25 -3 43 -6v-247q-27 6 -80 14q-43 6 -86 6q-137 0 -221 -33q-88 -35 -140 -94q-49 -59 -71 -143q-20 -78 -27 -187h12q22 37 49 68 q29 31 66 53q43 27 86 37q45 12 106 12q94 0 170 -30.5t129 -90.5q51 -57 80 -145q29 -90 29 -197q0 -121 -33 -213q-33 -94 -96 -159q-66 -68 -150 -101q-92 -35 -198 -34q-111 0 -203 38.5t-162 116.5q-70 80 -110 201q-39 117 -39 285zM383 510q0 -53 12 -102 q12 -45 39 -91q27 -41 62 -65q37 -25 88 -25q45 0 75.5 14.5t57.5 47.5q25 31 37 80q14 57 14 114q0 104 -45 168q-43 61 -135 62q-47 0 -84 -18.5t-66 -47.5q-25 -25 -41 -63q-14 -35 -14 -74z" />
+<glyph unicode="7" d="M55 1200v260h1008v-194l-533 -1266h-323l520 1200h-672z" />
+<glyph unicode="8" d="M72 371q0 72 22 135q18 55 60 108q33 43 90 84q61 43 108 66q-49 31 -92 67q-39 33 -73.5 82.5t-51.5 98.5q-18 55 -18 118q0 86 37 152q39 70 98 111q63 43 143 65q84 23 170 23q88 0 172 -23q78 -20 142 -65q59 -41 98 -111q35 -61 35 -154q0 -72 -21 -120 q-25 -59 -53 -97q-35 -43 -84 -77t-104 -62q49 -27 114 -70q53 -35 99 -84q41 -45 67 -106q27 -63 27 -133q0 -96 -35 -166t-102 -125q-63 -51 -155.5 -79.5t-199.5 -28.5q-123 0 -211 26q-84 25 -153 78q-61 47 -97 123q-32 72 -32 164zM358 389q0 -40 13 -74 q10 -29 39 -57q25 -25 63 -37q43 -14 88 -14q106 0 157.5 49t51.5 131q0 43 -18 76q-20 37 -45 61q-31 31 -62 54l-70 45l-22 14q-37 -18 -80 -47q-33 -23 -61 -58q-25 -31 -39.5 -65.5t-14.5 -77.5zM408 1106q0 -41 12 -72q12 -29 35 -55q16 -20 49 -41l61 -37q29 14 60 35 q28 18 49 43q23 27 35 55q12 31 12 72q0 37 -12 63q-14 31 -33 48q-23 20 -49 28q-31 10 -64 10q-31 0 -61 -10q-27 -8 -49 -28q-18 -16 -33 -48q-12 -26 -12 -63z" />
+<glyph unicode="9" d="M63 971q0 121 33 213q33 94 97 159q66 68 149 101q92 35 199 35q111 0 202 -39q98 -41 162 -117q72 -86 111 -201q39 -117 39 -284q0 -121 -11 -209q-14 -117 -40.5 -201t-81.5 -176q-47 -80 -127 -143q-74 -59 -187 -95q-111 -35 -254 -34q-6 0 -22.5 1t-24.5 1t-24.5 1 t-24.5 1q-16 0 -49 4q-25 3 -43 6v248q27 -6 80 -15q43 -6 86 -6q139 0 223 33q86 33 137 94q49 57 72 146q20 78 27 184h-13q-22 -37 -49 -68q-29 -31 -65 -53q-45 -27 -86 -37q-49 -12 -107 -12q-95 0 -172 31q-72 29 -127 90t-82 145q-27 82 -27 197zM362 975 q0 -109 46 -168q47 -61 135 -62q47 0 84 18.5t65 47.5q25 25 41 63q14 35 15 74q0 51 -13 101q-14 55 -37 92q-25 39 -63 65q-37 25 -88 25q-45 0 -76 -14.5t-57 -47.5q-27 -35 -39 -79q-13 -49 -13 -115z" />
+<glyph unicode=":" horiz-adv-x="583" d="M117 143q0 41 14 80q10 29 37 51q20 18 55 28.5t70 10.5q33 0 67.5 -10t55.5 -29q23 -20 37 -50.5t14 -80t-14 -77.5q-18 -37 -37 -54q-25 -22 -56 -30q-27 -8 -67 -9q-43 0 -70 9q-31 9 -55 30q-25 20 -37 54q-14 36 -14 77zM117 969q0 41 14 80q10 31 37 53 q20 18 55 28q27 8 70 9q41 0 67 -9q35 -10 55.5 -28.5t37.5 -52.5q14 -31 14 -80q0 -47 -14 -78q-16 -35 -37 -53.5t-55.5 -28.5t-67.5 -10q-35 0 -70 10t-55 29q-27 23 -37 53q-14 39 -14 78z" />
+<glyph unicode=";" horiz-adv-x="593" d="M63 -264q6 23 15.5 65.5l13.5 61.5l29 131l24 129l10.5 62.5t8.5 52.5h280l15 -23l-33 -115q-18 -61 -43 -123q-8 -25 -49 -124q-6 -16 -51 -117h-220zM117 969q0 41 14 80q10 31 37 53q20 18 55 28q27 8 70 9q41 0 67 -9q35 -10 55.5 -28.5t37.5 -52.5q14 -31 14 -80 q0 -47 -14 -78q-16 -35 -37 -53.5t-55.5 -28.5t-67.5 -10q-35 0 -70 10t-55 29q-27 23 -37 53q-14 39 -14 78z" />
+<glyph unicode="&#x3c;" d="M88 641v143l952 496v-240l-643 -317l643 -281v-239z" />
+<glyph unicode="=" d="M88 418v219h952v-219h-952zM88 807v217h952v-217h-952z" />
+<glyph unicode="&#x3e;" d="M88 203v239l643 281l-643 317v240l952 -496v-143z" />
+<glyph unicode="?" horiz-adv-x="937" d="M25 1358q43 25 94 47q59 27 104 41q49 16 110.5 26.5t110.5 10.5q101 0 185 -25q78 -23 139 -72q55 -43 86 -112q31 -68 31 -154q0 -68 -15 -112q-16 -55 -41 -93q-27 -43 -69 -81q-59 -55 -96 -84q-27 -20 -68 -58q-20 -18 -41 -47q-16 -25 -23 -45q-4 -16 -4 -55v-60 h-264v74q0 45 10 92q8 37 33 80q18 31 55 72q37 39 82 74q25 18 70 59q27 23 47 51q16 20 27 53q8 25 8 66q0 57 -39 94q-41 37 -117 37q-68 0 -149 -29q-66 -23 -164 -71zM231 143q0 46 13 80q8 25 39 51q23 20 55 29q37 10 69.5 10t67.5 -10t55 -29q23 -20 37.5 -50.5 t14.5 -80t-15 -77.5q-18 -37 -37 -54q-25 -22 -55 -30q-27 -8 -67 -9q-39 0 -70 9q-29 8 -55 30q-27 25 -39 54q-13 30 -13 77z" />
+<glyph unicode="@" horiz-adv-x="1773" d="M102 602q0 129 27 238q29 119 78 211q51 96 125 176q80 86 168 137q96 57 207 86q113 31 241 31q154 0 291 -51.5t229 -143.5q98 -98 151.5 -229t53.5 -305q0 -92 -22 -189q-20 -86 -70 -166q-47 -74 -115 -118q-70 -45 -163 -46q-41 0 -72 8.5t-62 28.5q-27 18 -47 41 t-32 51h-15q-12 -16 -45 -49q-18 -18 -55 -41q-33 -20 -68 -28q-41 -10 -82 -11q-80 0 -147 29q-66 29 -109 80q-47 57 -67 127q-23 78 -23 162q0 102 31 188q33 90 88 150q59 63 141 96q86 35 187 35q61 0 94 -4q61 -8 92 -15l40 -7t42 -9q20 -4 68 -21l-21 -419 q-2 -14 -2 -43v-27q0 -43 6 -70q4 -23 17 -41q8 -14 24 -22q12 -6 29 -6q37 0 61 26q25 28 43 74q16 43 27 107q8 55 8 131q0 121 -39 227q-37 102 -104.5 170t-159.5 104.5t-203 36.5q-156 0 -270.5 -51t-194.5 -143t-118 -215q-41 -129 -41 -275q0 -135 34 -246 q31 -98 105 -178q68 -74 170 -110q101 -37 233 -37q55 0 115 6q39 4 117 20q84 18 116 29q88 31 107 37v-192q-86 -39 -209 -66q-113 -25 -244 -25q-184 0 -323 52q-150 55 -242 147q-98 98 -149.5 237.5t-51.5 319.5zM711 627q0 -111 39 -162q37 -49 100 -49q37 0 72 20 q33 20 51 56q25 47 31 83q9 49 12 111l12 221q-16 4 -47 8q-18 2 -55 3q-61 0 -101 -25q-41 -25 -65 -66q-25 -39 -37 -94q-12 -53 -12 -106z" />
+<glyph unicode="A" horiz-adv-x="1329" d="M0 0l475 1468h379l477 -1468h-313l-100 348h-504l-101 -348h-313zM489 608h357l-94 320l-19 59q-6 20 -11 43t-13 47q-4 16 -13.5 50t-13.5 50.5t-16 84.5l-11 -52q-8 -41 -14 -63l-9 -31.5t-9.5 -36t-16.5 -63.5l-14 -53q-2 -12 -6 -20.5t-4 -14.5z" />
+<glyph unicode="B" horiz-adv-x="1314" d="M184 0v1462h428q125 0 242 -20q102 -18 174 -62q66 -39 105 -114q37 -70 36 -174q0 -55 -16 -115q-16 -57 -43 -96q-29 -41 -70 -68q-43 -29 -96 -37v-10q53 -12 103 -35q47 -23 83 -61q33 -35 56 -101q20 -59 20 -145q0 -96 -35 -178q-31 -74 -100 -133 q-66 -55 -160 -84q-96 -29 -211 -29h-516zM494 256h182q61 0 102 14q45 16 67.5 39t37.5 64q10 31 10 82q0 47 -10 75q-12 33 -39 58q-29 25 -70 37q-43 12 -106 12h-174v-381zM494 883h161q51 0 97 10q35 8 63 33q27 23 35 51q10 35 10 74q0 84 -53 120q-52 37 -166 37 h-147v-325z" />
+<glyph unicode="C" horiz-adv-x="1304" d="M119 729q0 170 45 305q45 133 133 238q84 100 215 155q129 55 293 56q113 0 219 -27q109 -27 209 -76l-100 -252q-88 43 -164 68q-86 29 -164 29q-88 0 -157.5 -35t-115.5 -98q-43 -61 -69 -158q-25 -92 -25 -207q0 -121 21 -209q20 -86 67 -153q43 -61 113 -95 q68 -33 166 -32q94 0 178 20q102 25 195 57v-260q-33 -14 -95 -35q-31 -10 -96 -22t-100 -14q-70 -4 -111 -4q-170 0 -293 55q-129 57 -204 151q-82 100 -121 235.5t-39 307.5z" />
+<glyph unicode="D" horiz-adv-x="1433" d="M184 0v1462h428q160 0 291 -47q129 -46 221 -135q92 -88 142 -225q49 -135 49 -310q0 -182 -51 -325q-49 -139 -146 -232q-100 -96 -233 -141q-141 -47 -316 -47h-385zM494 256h114q197 0 295 121q98 119 98 360q0 123 -24 211q-23 84 -72 146q-45 57 -114.5 85.5 t-153.5 28.5h-143v-952z" />
+<glyph unicode="E" horiz-adv-x="1146" d="M184 0v1462h842v-254h-532v-321h495v-254h-495v-377h532v-256h-842z" />
+<glyph unicode="F" horiz-adv-x="1122" d="M184 0v1462h838v-254h-533v-377h496v-253h-496v-578h-305z" />
+<glyph unicode="G" horiz-adv-x="1482" d="M119 733q0 168 51 311q49 137 147 236q96 96 239.5 149.5t326.5 53.5q119 0 229.5 -24.5t204.5 -65.5l-103 -248q-76 39 -153 57q-90 23 -180 23q-104 0 -183 -35q-84 -37 -141 -100q-55 -61 -88 -158q-31 -92 -31 -205t21 -197q23 -92 67.5 -155.5t118.5 -100t174 -36.5 q65 0 111 6q57 8 86 14v305h-277v258h580v-758q-78 -25 -117 -34q-76 -20 -123 -27q-86 -12 -133 -16q-71 -6 -147 -6q-164 0 -291 49q-129 51 -213 143q-84 94 -131 236q-45 137 -45 325z" />
+<glyph unicode="H" horiz-adv-x="1484" d="M184 0v1462h310v-573h497v573h309v-1462h-309v631h-497v-631h-310z" />
+<glyph unicode="I" horiz-adv-x="796" d="M66 0v176l178 82v946l-178 82v176h665v-176l-178 -82v-946l178 -82v-176h-665z" />
+<glyph unicode="J" horiz-adv-x="677" d="M-199 -150q25 -6 78 -14q39 -6 88 -6q41 0 86 10q35 8 68 35q31 25 47 66q16 43 16 102v1419h310v-1409q0 -125 -37 -217q-39 -94 -101 -151q-63 -57 -157 -86q-96 -29 -201 -29q-66 0 -115 6q-41 4 -82 16v258z" />
+<glyph unicode="K" horiz-adv-x="1296" d="M184 0v1462h310v-704l122 207l334 497h344l-467 -659l471 -803h-352l-336 608l-116 -86v-522h-310z" />
+<glyph unicode="L" horiz-adv-x="1095" d="M184 0v1462h310v-1206h532v-256h-842z" />
+<glyph unicode="M" horiz-adv-x="1869" d="M184 0v1462h422l316 -1118h6l336 1118h422v-1462h-289v692v60q0 10 1 33.5t1 36t1 38t1 37.5t2 36.5t2 37.5q4 92 6 174h-8l-346 -1145h-285l-321 1147h-9q8 -125 11 -178q2 -25 2 -76l4 -78q0 -12 1 -36.5t1 -35.5v-63v-680h-277z" />
+<glyph unicode="N" horiz-adv-x="1603" d="M184 0v1462h391l574 -1095h6l-6 149q0 10 -2 31.5t-2 34t-1 35t-1 32.5q0 12 -1 34t-1 32v55v692h278v-1462h-393l-575 1106h-9q8 -102 11 -154l6 -135q2 -47 2 -129v-688h-277z" />
+<glyph unicode="O" horiz-adv-x="1546" d="M119 735q0 174 39 309.5t121 235.5q80 98 204.5 151.5t292.5 53.5q166 0 291 -53q121 -51 203 -151.5t121 -238.5q39 -135 39 -309q0 -172 -39 -307q-41 -141 -121 -240q-76 -94 -205 -151q-123 -55 -291 -55t-291 55q-129 57 -204 151q-80 98 -121 240q-39 135 -39 309z M438 733q0 -119 21 -207q23 -98 61 -155q43 -63 105 -97q66 -35 149 -34q86 0 151.5 34.5t104.5 96.5q41 68 60 155q20 102 20 207t-20 207q-18 88 -60 156q-41 66 -102 98q-63 33 -151.5 33t-151.5 -33q-59 -31 -105 -98q-39 -57 -61 -156q-21 -88 -21 -207z" />
+<glyph unicode="P" horiz-adv-x="1224" d="M184 0v1462h406q135 0 244 -32q104 -33 170 -89q68 -59 98 -143q31 -86 31 -192q0 -92 -29 -185q-27 -84 -96.5 -153.5t-174 -108.5t-268.5 -39h-71v-520h-310zM494 774h61q131 0 197 51q68 51 67 170q0 106 -59.5 159.5t-186.5 53.5h-79v-434z" />
+<glyph unicode="Q" horiz-adv-x="1546" d="M119 735q0 174 39 309.5t121 235.5q80 98 204.5 151.5t292.5 53.5q166 0 291 -53q121 -51 203 -151.5t121 -238.5q39 -135 39 -309q0 -119 -19 -223q-18 -100 -59 -191q-40 -86 -99 -153q-55 -63 -141 -111l361 -403h-398l-268 330h-12q-2 0 -5.5 -1t-5.5 -1h-10 q-168 0 -291 55q-129 57 -204 151q-80 98 -121 240q-39 135 -39 309zM438 733q0 -119 21 -207q23 -98 61 -155q43 -63 105 -97q66 -35 149 -34q86 0 151.5 34.5t104.5 96.5q41 68 60 155q20 102 20 207t-20 207q-18 88 -60 156q-41 66 -102 98q-63 33 -151.5 33t-151.5 -33 q-59 -31 -105 -98q-39 -57 -61 -156q-21 -88 -21 -207z" />
+<glyph unicode="R" horiz-adv-x="1288" d="M184 0v1462h400q279 0 415 -108q133 -106 134 -330q0 -76 -21 -135q-25 -70 -53 -109q-37 -51 -76 -84q-37 -33 -92 -59l199 -318l73 -116l64 -103l47 -71l16 -29h-344l-317 561h-135v-561h-310zM494 813h84q133 0 186 51q55 53 55 152q0 106 -59 147q-63 45 -187 45h-79 v-395z" />
+<glyph unicode="S" horiz-adv-x="1071" d="M94 68v288q80 -39 96 -45l101 -39q41 -16 100 -26q55 -10 101 -10q51 0 88 12q43 14 59 31q25 25 33 49q10 31 10 63q0 41 -18 72q-23 37 -48 59q-27 25 -77 53l-99 56l-102 57q-53 31 -109 86q-49 49 -84 121q-35 74 -34 172q0 102 32 176q37 84 93 131q63 53 145 80 q90 29 192 29q53 0 103 -6q37 -4 100 -21q39 -10 101 -33q53 -20 102 -43l-100 -241q-55 27 -84 37q-27 10 -76 26q-27 8 -72 17q-37 6 -72 6q-80 0 -120.5 -41t-40.5 -111q0 -37 12 -65.5t41 -53.5q37 -33 70 -51l106 -59q76 -41 137 -82q59 -39 109 -92 q47 -51 71.5 -114.5t24.5 -149.5q0 -98 -33 -177q-33 -76 -98 -133q-63 -55 -158 -86q-92 -31 -215 -30q-102 0 -205 22q-96 21 -182 66z" />
+<glyph unicode="T" horiz-adv-x="1122" d="M41 1204v258h1042v-258h-366v-1204h-309v1204h-367z" />
+<glyph unicode="U" horiz-adv-x="1464" d="M174 520v942h309v-919q0 -76 17 -137q14 -55 47 -95q31 -37 78 -55q41 -16 110 -16q131 0 189 75q59 78 59 230v917h309v-946q0 -113 -34.5 -213t-104.5 -170q-76 -76 -176 -113q-111 -41 -250 -40q-135 0 -238 38q-106 41 -174 109q-63 63 -104 172q-37 98 -37 221z" />
+<glyph unicode="V" horiz-adv-x="1247" d="M0 1462h313l248 -880q4 -10 14 -58q4 -16 7.5 -38.5t9.5 -49.5q10 -47 18 -94q4 -18 8.5 -46t6.5 -36q2 8 6 36t8 46l18 94q4 18 12.5 52t8.5 36q10 47 14 58l244 880h313l-456 -1462h-338z" />
+<glyph unicode="W" horiz-adv-x="1896" d="M0 1462h305l166 -798q2 -10 8 -46l13 -69q4 -27 14 -80q10 -51 14 -82q4 -23 8 -41t7 -33l8 -57q6 47 8 55q6 35 12 74l12 80l15 76l12 63q2 10 5 22.5t3 16.5l203 819h272l203 -819q2 -4 4 -16.5t4 -22.5l13 -63q2 -12 6 -33l8 -43l12 -80q6 -39 13 -74q2 -8 8 -55 q0 4 2 15.5t3 21.5t3 20q6 34 12 74q4 31 15 82q4 18 8 38.5l8 41.5q6 39 12 69l8 46l166 798h305l-352 -1462h-352l-180 721q-2 4 -5 18.5l-5 24.5q-8 33 -13 59l-12 72q-2 14 -7 37.5t-7 34.5q-8 45 -11 65q-2 25 -6 47q-4 -23 -6 -47q-2 -20 -10 -65q-2 -16 -6 -34 l-8 -36l-13 -72q-6 -34 -12 -61q-2 -8 -5 -23.5t-5 -21.5l-178 -719h-353z" />
+<glyph unicode="X" horiz-adv-x="1282" d="M0 0l444 754l-413 708h342l274 -526l268 526h334l-418 -725l453 -737h-354l-299 553l-299 -553h-332z" />
+<glyph unicode="Y" horiz-adv-x="1193" d="M0 1462h336l262 -602l264 602h334l-444 -893v-569h-308v559z" />
+<glyph unicode="Z" horiz-adv-x="1103" d="M49 0v201l619 1005h-600v256h968v-200l-618 -1006h637v-256h-1006z" />
+<glyph unicode="[" horiz-adv-x="677" d="M143 -324v1786h484v-211h-224v-1364h224v-211h-484z" />
+<glyph unicode="\" horiz-adv-x="845" d="M12 1462h277l545 -1462h-277z" />
+<glyph unicode="]" horiz-adv-x="677" d="M51 -113h223v1364h-223v211h484v-1786h-484v211z" />
+<glyph unicode="^" horiz-adv-x="1089" d="M8 520l438 950h144l495 -950h-239l-322 643l-141 -323l-139 -320h-236z" />
+<glyph unicode="_" horiz-adv-x="841" d="M-4 -184h850v-140h-850v140z" />
+<glyph unicode="`" horiz-adv-x="1181" d="M332 1548v21h342q15 -34 37 -74l45 -82q20 -37 47 -78q6 -8 15 -22.5t16.5 -25.5t13.5 -19v-27h-203l-82 70l-94 86q-47 43 -84 84q-39 42 -53 67z" />
+<glyph unicode="a" horiz-adv-x="1175" d="M86 334q0 176 115 262q113 84 340 94l178 6v84q0 70 -39 102.5t-113 32.5q-78 0 -141 -20q-61 -20 -137 -57l-99 202q82 45 187 74q98 27 213 27q211 0 321.5 -98.5t110.5 -297.5v-745h-213l-59 152h-9q-33 -45 -65 -78q-29 -29 -74 -54q-41 -23 -86 -30 q-55 -10 -113 -10q-66 0 -127 22q-59 23 -100 64q-39 39 -65 110q-25 68 -25 158zM399 332q0 -68 33 -99q35 -31 90 -30q43 0 78 14q31 12 62 43q29 29 43 70t14 96v92l-101 -4q-68 -4 -104 -16q-45 -16 -65 -37q-29 -29 -39 -55q-11 -29 -11 -74z" />
+<glyph unicode="b" horiz-adv-x="1243" d="M160 0v1556h305v-362q0 -45 -2 -72q0 -12 -1 -35.5t-3 -35.5q0 -18 -2 -39t-4 -39h12q29 45 47 65q27 31 63 52q49 29 80 36q45 12 101 13q88 0 157 -37q68 -35 121 -111q53 -74 80 -180q29 -111 29 -250q0 -141 -29 -252q-29 -109 -80 -182q-53 -74 -125 -111 q-74 -37 -161 -36q-55 0 -99 12q-47 14 -78 33q-39 25 -59 45q-25 25 -47 53h-21l-51 -123h-233zM465 563q0 -72 10 -143q8 -63 31 -107q20 -41 59 -63.5t90 -22.5q90 0 133 86t43 252q0 164 -43 248q-43 82 -135 82q-49 0 -86 -18q-35 -18 -57 -56q-25 -41 -33 -94 q-8 -55 -12 -131v-33z" />
+<glyph unicode="c" horiz-adv-x="1021" d="M102 553q0 164 37 278q37 113 107 183q70 68 164 96q98 29 215 29q90 0 172 -20.5t159 -59.5l-88 -232q-70 31 -127 47q-61 18 -116 19q-113 0 -160 -84q-51 -90 -51 -254t51 -248q49 -80 156 -80q84 0 157 23q59 18 146 57v-254q-4 -2 -72 -33q-25 -12 -70 -22 q-49 -12 -75 -14q-53 -4 -82 -4q-125 0 -217 32q-100 35 -164 103q-68 71 -105 178q-37 108 -37 260z" />
+<glyph unicode="d" horiz-adv-x="1243" d="M102 557q0 141 29 252q29 109 80 182.5t127 110.5q74 37 160 37q55 0 100 -13q37 -10 80 -34q41 -25 65 -52q25 -29 50 -65h10q-2 12 -5 38.5t-5 41.5q-4 25 -9 71q-4 53 -4 72v358h305v-1556h-233l-59 145h-13q-25 -37 -49 -65q-29 -33 -61 -51q-41 -23 -80 -35 q-49 -14 -101 -14q-88 0 -157 36q-68 35 -121 111q-53 74 -80 180q-29 111 -29 250zM412 553q0 -166 45 -248t143 -82q55 0 92 18.5t62 55.5q20 31 34 94q12 55 13 131v33q0 72 -10 143q-8 57 -33 107q-20 41 -61.5 63.5t-98.5 22.5q-95 0 -141 -86q-45 -84 -45 -252z" />
+<glyph unicode="e" horiz-adv-x="1189" d="M102 551q0 147 37 258t102.5 182.5t161.5 110.5q92 37 207 37t201 -33q90 -35 152 -98q63 -66 96 -160q33 -92 33 -217v-148h-682q4 -68 20 -116q16 -45 53 -86q34 -37 80 -56q47 -18 109 -18q49 0 96 6q57 8 88 16q57 16 86 26.5t86 39.5v-236q-40 -22 -80 -36 q-29 -10 -86 -23q-76 -14 -96 -16q-70 -4 -115 -4q-117 0 -221 34q-96 33 -174 107q-72 70 -113 178q-41 111 -41 252zM416 686h389q0 51 -12.5 94t-36.5 74q-27 33 -60 49q-37 18 -84 19q-84 0 -135 -58q-53 -59 -61 -178z" />
+<glyph unicode="f" horiz-adv-x="792" d="M41 889v147l168 82v82q0 102 27 178q25 70 73 113q45 41 117 59q59 16 152 17q96 0 155 -15q68 -16 107 -32l-72 -224q-20 8 -66 21q-31 8 -79 8q-59 0 -84 -39q-25 -41 -25 -98v-70h227v-229h-227v-889h-305v889h-168z" />
+<glyph unicode="g" horiz-adv-x="1128" d="M20 -182q0 63 21 106q20 45 55 76q33 29 80 53q27 12 92 31q-16 6 -41 25q-22 15 -37 36q-23 33 -28 48q-10 27 -10 53q0 31 10 57q12 33 26 49q20 25 45 43q12 10 62 41q-86 35 -139 121q-51 82 -52 199q0 94 27 162q29 74 82 120q55 49 135 74q86 27 184 27q29 0 46 -2 l49 -7q8 -2 23.5 -5t21.5 -3q18 -2 33 -6h380v-166l-163 -51q18 -29 28 -70q8 -33 8 -79q0 -88 -26 -156q-29 -72 -80 -121q-49 -47 -133 -76q-82 -29 -187 -28q-33 0 -51 2q-27 2 -39 6q-23 -18 -32 -35q-10 -14 -11 -45q0 -20 13 -33q14 -14 34 -20q27 -8 50 -11 q18 -2 57 -2h174q80 0 145 -18q61 -18 109 -57q43 -37 67.5 -96.5t24.5 -139.5q0 -90 -39 -172q-37 -78 -112 -129q-82 -55 -189 -82q-115 -29 -258 -29q-117 0 -199 21q-80 20 -143 63q-57 39 -84 97q-29 61 -29 129zM285 -158q0 -23 10 -49q8 -20 34.5 -40.5t63.5 -28.5 q45 -10 96 -11q156 0 236 43q78 41 78 119q0 63 -49 84q-47 20 -152 21h-141q-27 0 -57.5 -6.5t-57.5 -22.5q-25 -15 -43 -43q-18 -27 -18 -66zM395 752q0 -94 33 -142q35 -49 104 -49q74 0 105 49t31 141.5t-31 143.5q-31 53 -105 53q-137 1 -137 -196z" />
+<glyph unicode="h" horiz-adv-x="1282" d="M160 0v1556h305v-317q0 -57 -2 -88q0 -14 -1 -43t-3 -43q-2 -16 -5 -46t-3 -44h16q49 86 125 125t172 39q90 0 151 -23q63 -23 115 -74q49 -49 74 -127q27 -84 26 -186v-729h-305v653q0 119 -36.5 180.5t-116.5 61.5q-58 0 -99 -25q-39 -25 -63 -69q-25 -47 -35 -117 q-10 -76 -10 -158v-526h-305z" />
+<glyph unicode="i" horiz-adv-x="624" d="M147 1407q0 43 13 72q10 25 35 45q20 18 53 24q41 8 65 8q23 0 64 -8q33 -6 53 -24q25 -20 35 -45q14 -33 14 -72t-14 -72q-10 -25 -34.5 -45t-53.5 -26q-31 -6 -64 -7q-35 0 -65 7q-29 6 -53.5 26.5t-34.5 44.5q-13 29 -13 72zM160 0v1118h305v-1118h-305z" />
+<glyph unicode="j" horiz-adv-x="624" d="M-82 -227q43 -12 57 -15q37 -4 62 -4q18 0 47 8q23 6 39 27q18 23 27 51q10 37 10 84v1194h305v-1239q0 -78 -19 -145q-18 -63 -63 -116.5t-113 -80.5q-70 -29 -168 -29q-49 0 -100 7q-49 6 -84 18v240zM147 1407q0 43 13 72q10 25 35 45q20 18 53 24q41 8 65 8 q23 0 64 -8q33 -6 53 -24q25 -20 35 -45q14 -33 14 -72t-14 -72q-10 -25 -34.5 -45t-53.5 -26q-31 -6 -64 -7q-35 0 -65 7q-29 6 -53.5 26.5t-34.5 44.5q-13 29 -13 72z" />
+<glyph unicode="k" horiz-adv-x="1206" d="M160 0v1556h305v-694l-16 -254h4l112 170l273 340h344l-404 -485l430 -633h-352l-272 430l-119 -82v-348h-305z" />
+<glyph unicode="l" horiz-adv-x="624" d="M160 0v1556h305v-1556h-305z" />
+<glyph unicode="m" horiz-adv-x="1927" d="M160 0v1118h233l41 -143h17q27 45 57.5 73.5t73.5 51.5q40 22 86 30q41 8 90 9q119 0 196 -39q80 -41 123 -125h25q27 45 57 74q29 25 76 51q40 22 86 30q41 8 92 9q182 0 272.5 -96.5t90.5 -313.5v-729h-306v653q0 119 -36.5 180.5t-112.5 61.5q-109 0 -156 -86 q-45 -84 -45 -248v-561h-305v653q0 119 -37 180.5t-112 61.5q-55 0 -96.5 -24.5t-61.5 -69.5q-25 -51 -33 -117q-10 -76 -10 -158v-526h-305z" />
+<glyph unicode="n" horiz-adv-x="1282" d="M160 0v1118h233l41 -143h17q23 41 59 74q29 25 76 51q40 22 86 30q41 8 94 9q88 0 149 -23q63 -23 115 -74q49 -49 74 -127q27 -84 26 -186v-729h-305v653q0 119 -36.5 180.5t-116.5 61.5q-61 0 -100.5 -24.5t-63.5 -69.5q-23 -43 -33 -117q-10 -76 -10 -158v-526h-305z " />
+<glyph unicode="o" horiz-adv-x="1226" d="M102 561q0 145 35 248q37 109 103 180q72 78 161 113q95 37 215 37q111 0 203 -37t162 -113q68 -74 104 -180q39 -113 39 -248q0 -139 -37 -248q-39 -117 -100 -182q-68 -74 -162 -113q-92 -39 -215 -38q-115 0 -204 38q-94 41 -160 113q-70 76 -107 182q-37 109 -37 248 zM414 561q0 -164 47 -252q45 -84 153 -84q106 0 152 84q47 88 47 252q0 166 -47 250q-45 82 -154 82q-106 0 -151 -82q-47 -84 -47 -250z" />
+<glyph unicode="p" horiz-adv-x="1243" d="M160 -492v1610h248l43 -145h14q25 39 47 63q31 35 63 54q49 29 80 36q45 12 101 13q88 0 157 -37q71 -37 123 -111q49 -70 78 -180.5t29 -249.5q0 -141 -29 -252q-27 -104 -82 -182q-53 -74 -125 -111q-74 -37 -159 -36q-55 0 -99 12q-47 14 -78 33q-39 25 -59 45 q-25 25 -47 53h-16q2 -12 5 -33.5t3 -32.5q2 -16 6 -53q2 -18 2 -43v-453h-305zM465 563q0 -72 10 -143q8 -63 31 -107q20 -41 59 -63.5t90 -22.5q90 0 133 86t43 252q0 164 -43 248q-43 82 -135 82q-49 0 -86 -18q-35 -18 -57 -56q-25 -41 -33 -94q-8 -55 -12 -131v-33z " />
+<glyph unicode="q" horiz-adv-x="1243" d="M102 557q0 141 29 252q29 109 80 182.5t127 110.5q74 37 160 37q55 0 100 -13q41 -10 82 -34.5t65 -51.5q25 -29 50 -65h8l24 143h258v-1610h-305v469q0 29 2 48q0 8 2 26.5t2 28.5q0 16 2.5 32.5t4.5 32.5h-13q-29 -45 -47 -65q-27 -31 -63 -51q-43 -25 -80 -35 q-53 -14 -101 -14q-88 0 -157 36q-71 37 -123 111q-53 74 -80 180q-27 105 -27 250zM414 553q0 -170 45 -252t143 -82q55 0 92 19q41 20 62 55q18 33 32 94q12 55 13 131v37q0 72 -10 143q-10 66 -33 107q-25 43 -62 63q-41 23 -96 23q-95 0 -141 -86q-45 -84 -45 -252z" />
+<glyph unicode="r" horiz-adv-x="888" d="M160 0v1118h231l45 -168h15q25 43 53 78q31 37 61 59q37 27 78 39q43 12 100 13h27q6 0 14.5 -1t12.5 -1t13 -2t13 -2q12 0 17 -3v-286q-4 2 -12 2q-7 2 -11 2q-20 4 -29 4q-6 0 -16 1t-14 1h-25q-63 0 -108 -14q-49 -15 -86 -49q-35 -31 -54 -89q-20 -61 -20 -133v-569 h-305z" />
+<glyph unicode="s" horiz-adv-x="983" d="M98 827q0 80 29 136q31 58 86 98q57 41 133 59q77 18 172 19q96 0 191 -23q80 -20 184 -69l-92 -216q-82 39 -146 60q-72 23 -137 22q-61 0 -90 -22q-27 -20 -27 -60q0 -22 7 -36q6 -14 28 -31q33 -25 60 -37q57 -29 98 -47q71 -31 129 -62q55 -29 96 -69q45 -45 64 -90 q23 -55 22 -127q0 -84 -33 -154q-33 -68 -90 -110q-59 -43 -143 -66q-86 -23 -188 -22q-41 0 -103 4q-45 2 -88 12q-72 16 -82 18q-35 10 -78 31v252q37 -18 88 -39q31 -12 93 -29q45 -12 90 -18q57 -8 80 -8q33 0 69 8q29 6 49 20q16 10 27 33q8 16 8 39q0 22 -6 37 q-6 12 -31 35q-14 12 -67 43q-27 14 -119 57q-88 41 -127 66q-61 39 -88 71q-33 37 -51 93q-17 46 -17 122z" />
+<glyph unicode="t" horiz-adv-x="847" d="M47 889v129l168 102l88 236h195v-238h272v-229h-272v-539q0 -63 32 -96q31 -31 84 -31q41 0 86 10q37 8 82 25v-227q-43 -23 -106 -37q-59 -14 -139 -14q-70 0 -135.5 18t-108.5 59q-47 43 -74 113q-27 68 -26 180v539h-146z" />
+<glyph unicode="u" horiz-adv-x="1282" d="M154 389v729h305v-653q0 -121 37 -182q35 -59 116 -60q59 0 101 25q39 25 63 69q23 43 33 117q10 76 10 158v526h305v-1118h-233l-41 143h-16q-23 -41 -60 -73q-29 -25 -76 -52q-35 -18 -86 -28t-94 -10q-82 0 -149 24q-63 23 -115 74q-49 49 -74 127q-26 84 -26 184z " />
+<glyph unicode="v" horiz-adv-x="1103" d="M0 1118h319l185 -637q14 -43 28 -119q14 -70 17 -110h6q2 49 16 113q16 78 29 116l184 637h320l-395 -1118h-314z" />
+<glyph unicode="w" horiz-adv-x="1650" d="M0 1118h303l113 -495q10 -47 18 -93l19 -110q4 -23 8 -50.5l8 -54.5q8 -66 10 -79h6q0 8 4 49q4 45 9 65q4 35 10 72q8 49 12 70q8 49 10 55q4 27 7 35l122 536h336l117 -536q2 -8 6 -31t6 -37l17 -98q6 -31 14 -103q8 -66 8 -77h6q0 6 4.5 30.5t6.5 42.5q8 49 16 107 q4 18 10 56t11 56q8 51 18 95l117 495h299l-305 -1118h-332l-86 391q-2 6 -5 23.5t-5 25.5l-15 70q-8 39 -16 84q-4 25 -9.5 46.5t-9.5 41.5l-18 100.5t-25 122.5h-6q-8 -47 -20.5 -106.5t-22.5 -116.5l-16 -88q-10 -59 -17 -86q-8 -39 -14 -72q-2 -8 -5 -25.5t-5 -23.5 l-90 -387h-328z" />
+<glyph unicode="x" horiz-adv-x="1120" d="M10 0l379 571l-360 547h346l186 -336l189 336h346l-365 -547l381 -571h-346l-205 362l-205 -362h-346z" />
+<glyph unicode="y" horiz-adv-x="1103" d="M0 1118h334l180 -629q16 -57 23 -110q8 -82 10 -107h6q2 14 6 52q4 41 8 57q2 8 5 28.5t6 28.5q0 4 14 51l176 629h336l-442 -1261q-61 -176 -168 -263q-109 -86 -269 -86q-66 0 -90 5q-41 6 -65 12v242q16 -4 53 -9q41 -4 67 -4q47 0 82 13q33 12 58 36q27 27 43 58 q18 34 30 73l19 56z" />
+<glyph unicode="z" horiz-adv-x="935" d="M55 0v180l457 705h-426v233h772v-198l-442 -687h461v-233h-822z" />
+<glyph unicode="{" horiz-adv-x="743" d="M31 449v239q55 0 110 10q47 8 82 31q34 22 49 55q16 37 15 82v318q0 74 18 127q18 51 70 86q49 34 135 49q92 16 215 16v-225q-37 0 -72 -6q-33 -6 -55.5 -22.5t-34.5 -43t-12 -69.5v-299q-6 -187 -234 -222v-12q117 -18 177 -71q59 -55 57 -150v-299q0 -43 12 -69.5 t35 -43.5q20 -14 55 -20q45 -8 72 -8v-226q-123 0 -215 17q-86 15 -135 49q-51 35 -70 86q-18 53 -18 127v315q0 96 -65.5 137.5t-190.5 41.5z" />
+<glyph unicode="|" d="M455 -465v2015h219v-2015h-219z" />
+<glyph unicode="}" horiz-adv-x="743" d="M31 -98q31 0 71 8q37 8 56 20q23 16 35 43t12 70v299q-2 94 57 150q59 53 176 71v12q-227 34 -233 222v299q0 43 -12.5 69.5t-35 43t-55.5 22.5q-31 6 -71 6v225q125 0 217 -16q84 -14 133 -49q51 -35 70 -86q18 -53 18 -127v-318q0 -51 14 -82q15 -34 49 -55 q35 -23 82 -31q55 -10 111 -10v-239q-125 0 -190.5 -41t-65.5 -138v-315q0 -74 -18 -127q-18 -51 -70 -86q-49 -35 -133 -49q-92 -16 -217 -17v226z" />
+<glyph unicode="~" d="M88 551v231q51 55 115 82q61 27 141 27q39 0 55.5 -2t53.5 -10q33 -8 63 -19q53 -20 84 -33q57 -25 66 -26l53 -17q35 -8 45 -10q14 -2 43 -2q25 0 59 10q31 9 62 25q27 12 59 39q29 23 53 47v-231q-102 -109 -256 -109q-39 0 -55 2q-20 2 -55 10q-33 8 -64 19 q-41 14 -82 32l-32.5 13.5l-32.5 13.5q-27 12 -53 19q-18 4 -43 8q-14 2 -45 2q-25 0 -60 -10q-31 -9 -61 -25q-20 -10 -57.5 -39t-55.5 -47z" />
+<glyph unicode="&#xa2;" d="M143 743.5q0 143.5 27 241.5t82 170q51 68 127 105q80 41 164 51v172h178v-164q39 0 76 -6q49 -8 73 -15q37 -9 68 -18q37 -10 55 -20l-86 -226l-47 19l-55 18l-55 12q-37 4 -52 4q-70 0 -112 -20q-47 -23 -76 -61q-29 -41 -41 -105q-14 -76 -14 -151q0 -172 57 -250 q57 -80 186 -80q76 0 146 18q74 18 121 43v-239q-61 -33 -112.5 -45.5t-131.5 -16.5v-200h-178v206q-92 12 -166 50q-72 37 -125 104q-55 72 -82 166t-27 237.5z" />
+<glyph unicode="&#xa3;" d="M82 0v248q45 18 76 39q27 16 57 51q20 23 35 70q12 40 12 98v145h-178v219h178v195q0 113 31 192q29 78 88 129q61 53 131 74q80 23 168 23q111 0 199 -25q98 -27 170 -57l-93 -230q-57 23 -129 46q-58 18 -122 18q-68 0 -105 -39q-37 -41 -37 -133v-193h334v-219h-334 v-143q0 -49 -14 -96q-12 -41 -35 -70q-18 -23 -49 -47q-23 -18 -53 -35h678v-260h-1008z" />
+<glyph unicode="&#xa5;" d="M8 1462h316l241 -602l244 602h313l-362 -747h194v-178h-245v-138h245v-178h-245v-221h-287v221h-248v178h248v138h-248v178h191z" />
+<glyph unicode="&#xa9;" horiz-adv-x="1703" d="M100 731q0 109 27 201q29 98 76 178q53 90 116.5 153.5t153.5 116.5q80 47 178 76q92 27 201 27t201 -27q98 -29 178 -76q90 -53 153.5 -116.5t116.5 -153.5q47 -80 76 -178q27 -92 27 -200.5t-27 -201.5q-29 -98 -76 -178q-53 -90 -116.5 -153.5t-153.5 -116.5 q-80 -47 -178 -76q-92 -27 -201 -26.5t-201 26.5q-98 29 -178 76q-90 53 -153.5 116.5t-116.5 153.5q-47 80 -76 178q-27 92 -27 201zM242 731q0 -127 49 -237q53 -119 129 -195t194 -129q111 -49 238 -49t238 49q119 53 194.5 129t128.5 195q49 111 49 237.5t-49 237.5 q-53 119 -129 194.5t-194 128.5q-111 49 -238 49t-238 -49q-119 -53 -194.5 -129t-128.5 -194q-49 -111 -49 -238zM461 733q0 94 26 189q25 84 78 147q51 61 131 94q82 35 185 35q80 0 159.5 -22.5t145.5 -55.5l-74 -168q-113 57 -217 58q-96 0 -150 -74q-53 -76 -53 -205 q0 -137 47 -207q49 -74 156 -73q53 0 123 16q65 15 123 43v-191q-58 -28 -117 -43q-55 -14 -135 -14q-104 0 -186 35t-134 94q-55 63 -82 150q-26 81 -26 192z" />
+<glyph unicode="&#xad;" horiz-adv-x="657" d="M61 424v250h537v-250h-537z" />
+<glyph unicode="&#xae;" horiz-adv-x="1703" d="M100 731q0 109 27 201q29 98 76 178q53 90 116.5 153.5t153.5 116.5q80 47 178 76q92 27 201 27t201 -27q98 -29 178 -76q90 -53 153.5 -116.5t116.5 -153.5q47 -80 76 -178q27 -92 27 -200.5t-27 -201.5q-29 -98 -76 -178q-53 -90 -116.5 -153.5t-153.5 -116.5 q-80 -47 -178 -76q-92 -27 -201 -26.5t-201 26.5q-98 29 -178 76q-90 53 -153.5 116.5t-116.5 153.5q-47 80 -76 178q-27 92 -27 201zM242 731q0 -127 49 -237q53 -119 129 -195t194 -129q111 -49 238 -49t238 49q119 53 194.5 129t128.5 195q49 111 49 237.5t-49 237.5 q-53 119 -129 194.5t-194 128.5q-111 49 -238 49t-238 -49q-119 -53 -194.5 -129t-128.5 -194q-49 -111 -49 -238zM543 272v916h264q184 0 266 -70q84 -72 84 -213q0 -96 -39 -149q-41 -57 -104 -84l237 -400h-254l-178 338h-47v-338h-229zM772 778h31q66 0 94.5 29t28.5 94 q0 29 -8 57q-6 25 -22.5 37.5t-39.5 18.5q-25 6 -55 6h-29v-242z" />
+<glyph unicode="&#xb4;" horiz-adv-x="1181" d="M332 1241v27l45 67q33 53 47 78q8 12 45 82q22 40 37 74h342v-21q-16 -23 -33 -43q-43 -49 -47 -53q-27 -29 -57 -57l-64 -58l-59 -53q-16 -14 -31.5 -25.5t-21.5 -17.5h-203z" />
+<glyph unicode="&#x2000;" horiz-adv-x="782" />
+<glyph unicode="&#x2001;" horiz-adv-x="1568" />
+<glyph unicode="&#x2002;" horiz-adv-x="782" />
+<glyph unicode="&#x2003;" horiz-adv-x="1568" />
+<glyph unicode="&#x2004;" horiz-adv-x="522" />
+<glyph unicode="&#x2005;" horiz-adv-x="391" />
+<glyph unicode="&#x2006;" horiz-adv-x="260" />
+<glyph unicode="&#x2007;" horiz-adv-x="260" />
+<glyph unicode="&#x2008;" horiz-adv-x="194" />
+<glyph unicode="&#x2009;" horiz-adv-x="311" />
+<glyph unicode="&#x200a;" horiz-adv-x="86" />
+<glyph unicode="&#x2010;" horiz-adv-x="657" d="M61 424v250h537v-250h-537z" />
+<glyph unicode="&#x2011;" horiz-adv-x="657" d="M61 424v250h537v-250h-537z" />
+<glyph unicode="&#x2012;" horiz-adv-x="657" d="M61 424v250h537v-250h-537z" />
+<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M82 436v230h860v-230h-860z" />
+<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M82 436v230h1884v-230h-1884z" />
+<glyph unicode="&#x2018;" horiz-adv-x="438" d="M23 983l18 61l16 54q12 41 41 123l49 122l52 119h219q-6 -23 -15.5 -65.5l-13.5 -61.5l-29 -131l-24 -129l-10.5 -62.5l-8.5 -51.5h-280z" />
+<glyph unicode="&#x2019;" horiz-adv-x="438" d="M23 961q10 39 28 126l29 132l24 129l10.5 62.5l8.5 51.5h280l15 -22l-33 -115q-18 -61 -43 -123l-49 -125q-6 -16 -51 -116h-219z" />
+<glyph unicode="&#x201c;" horiz-adv-x="905" d="M23 983l18 61l16 54q12 41 41 123l49 122l52 119h219q-6 -23 -15.5 -65.5l-13.5 -61.5l-29 -131l-24 -129l-10.5 -62.5l-8.5 -51.5h-280zM489 983q29 102 33 115l43 123l49 122l52 119h219q-6 -23 -15.5 -65.5l-13.5 -61.5l-29 -131l-24 -129l-10.5 -62.5l-8.5 -51.5 h-280z" />
+<glyph unicode="&#x201d;" horiz-adv-x="905" d="M23 961q10 39 28 126l29 132l24 129l10.5 62.5l8.5 51.5h280l15 -22l-33 -115q-18 -61 -43 -123l-49 -125q-6 -16 -51 -116h-219zM489 961q6 23 15.5 65.5l13.5 60.5l29 132l24 129l10.5 62.5l8.5 51.5h280l15 -22l-33 -115q-18 -61 -43 -123l-49 -125q-6 -16 -51 -116 h-220z" />
+<glyph unicode="&#x2022;" horiz-adv-x="768" d="M98 748q0 84 23 147q20 61 59 96q40 37 92 56q51 18 113 18q58 0 110.5 -18.5t92.5 -55.5q41 -37 61 -96q23 -63 23 -147q0 -82 -23 -146q-20 -57 -61 -98q-35 -35 -92 -55q-52 -18 -111 -19q-61 0 -113 19q-57 20 -92 55q-39 39 -59 98q-23 64 -23 146z" />
+<glyph unicode="&#x2026;" horiz-adv-x="1748" d="M117 143q0 41 14 80q10 29 37 51q20 18 55 28.5t70 10.5q33 0 67.5 -10t55.5 -29q23 -20 37 -50.5t14 -80t-14 -77.5q-18 -37 -37 -54q-25 -22 -56 -30q-27 -8 -67 -9q-43 0 -70 9q-31 9 -55 30q-25 20 -37 54q-14 36 -14 77zM700 143q0 46 13 80q8 25 39 51q23 20 55 29 q37 10 69.5 10t67.5 -10t55 -29q23 -20 37.5 -50.5t14.5 -80t-15 -77.5q-18 -37 -37 -54q-25 -22 -55 -30q-27 -8 -67 -9q-39 0 -70 9q-29 8 -55 30q-27 25 -39 54q-13 30 -13 77zM1284 143q0 41 14 80q10 29 37 51q20 18 55 28.5t70 10.5q31 0 66 -10t55 -29q27 -23 39 -51 q14 -31 14 -80t-14 -77q-16 -35 -39 -54q-25 -22 -55 -30q-27 -8 -66 -9q-43 0 -69 9q-31 9 -56 30q-25 20 -37 54q-14 36 -14 77z" />
+<glyph unicode="&#x202f;" horiz-adv-x="311" />
+<glyph unicode="&#x205f;" horiz-adv-x="391" />
+<glyph unicode="&#x20ac;" d="M66 481v178h118q-4 25 -4 33v29v29q0 6 1 14t1 10h-116v176h133q18 117 65 219.5t115 165.5q66 63 168 103q90 35 215 35q104 0 186 -21q86 -22 166 -61l-98 -232q-68 31 -129 49q-55 16 -125 17q-104 0 -172 -70q-70 -72 -90 -205h362v-176h-377q0 -4 -1 -8t-1 -8v-19 v-18v-29q0 -18 2 -33h314v-178h-297q25 -125 96.5 -184t183.5 -59q76 0 148 16q57 12 127 41v-256q-59 -29 -127 -43q-76 -16 -166 -16q-238 0 -379 131q-139 129 -182 370h-137z" />
+<glyph unicode="&#x2122;" horiz-adv-x="1533" d="M16 1313v149h564v-149h-199v-572h-168v572h-197zM625 741v721h247l160 -510l170 510h240v-721h-168v408v25q0 4 1 15t1 17v35q0 6 1 15.5t1 13.5h-6l-174 -529h-142l-165 529h-7q0 -4 1 -15.5t1 -17.5v-33q0 -6 1 -14t1 -12v-19v-418h-163z" />
+<glyph unicode="&#xe000;" horiz-adv-x="1120" d="M0 1120h1120v-1120h-1120v1120z" />
+<glyph unicode="&#xfb01;" horiz-adv-x="1415" d="M41 889v147l168 82v82q0 102 27 178q25 70 73 113q45 41 117 59q59 16 152 17q96 0 155 -15q68 -16 107 -32l-72 -224q-20 8 -66 21q-31 8 -79 8q-59 0 -84 -39q-25 -41 -25 -98v-70h227v-229h-227v-889h-305v889h-168zM940 1407q0 43 13 72q10 25 35 45q20 18 53 24 q41 8 65 8q23 0 64 -8q33 -6 53 -24q25 -20 35 -45q14 -33 14 -72t-14 -72q-10 -25 -34.5 -45t-53.5 -26q-31 -6 -64 -7q-35 0 -65 7q-29 6 -53.5 26.5t-34.5 44.5q-13 29 -13 72zM953 0v1118h305v-1118h-305z" />
+<glyph unicode="&#xfb02;" horiz-adv-x="1415" d="M41 889v147l168 82v82q0 102 27 178q25 70 73 113q45 41 117 59q59 16 152 17q96 0 155 -15q68 -16 107 -32l-72 -224q-20 8 -66 21q-31 8 -79 8q-59 0 -84 -39q-25 -41 -25 -98v-70h227v-229h-227v-889h-305v889h-168zM953 0v1556h305v-1556h-305z" />
+<glyph unicode="&#xfb03;" horiz-adv-x="2207" d="M41 889v147l168 82v82q0 102 27 178q25 70 73 113q45 41 117 59q59 16 152 17q96 0 155 -15q68 -16 107 -32l-72 -224q-20 8 -66 21q-31 8 -79 8q-59 0 -84 -39q-25 -41 -25 -98v-70h227v-229h-227v-889h-305v889h-168zM834 889v147l168 82v82q0 102 27 178q25 70 73 113 q45 41 117 59q59 16 152 17q96 0 155 -15q68 -16 107 -32l-72 -224q-20 8 -66 21q-31 8 -79 8q-59 0 -84 -39q-25 -41 -25 -98v-70h227v-229h-227v-889h-305v889h-168zM1730 1407q0 43 13 72q10 25 35 45q20 18 53 24q41 8 65 8q23 0 64 -8q33 -6 53 -24q25 -20 35 -45 q14 -33 14 -72t-14 -72q-10 -25 -34.5 -45t-53.5 -26q-31 -6 -64 -7q-35 0 -65 7q-29 6 -53.5 26.5t-34.5 44.5q-13 29 -13 72zM1743 0v1118h305v-1118h-305z" />
+<glyph unicode="&#xfb04;" horiz-adv-x="2207" d="M41 889v147l168 82v82q0 102 27 178q25 70 73 113q45 41 117 59q59 16 152 17q96 0 155 -15q68 -16 107 -32l-72 -224q-20 8 -66 21q-31 8 -79 8q-59 0 -84 -39q-25 -41 -25 -98v-70h227v-229h-227v-889h-305v889h-168zM834 889v147l168 82v82q0 102 27 178q25 70 73 113 q45 41 117 59q59 16 152 17q96 0 155 -15q68 -16 107 -32l-72 -224q-20 8 -66 21q-31 8 -79 8q-59 0 -84 -39q-25 -41 -25 -98v-70h227v-229h-227v-889h-305v889h-168zM1743 0v1556h305v-1556h-305z" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/pleaseshare/static/fonts/DroidSans-Bold-webfont.ttf b/pleaseshare/static/fonts/DroidSans-Bold-webfont.ttf
new file mode 100755 (executable)
index 0000000..5b8183d
Binary files /dev/null and b/pleaseshare/static/fonts/DroidSans-Bold-webfont.ttf differ
diff --git a/pleaseshare/static/fonts/DroidSans-Bold-webfont.woff b/pleaseshare/static/fonts/DroidSans-Bold-webfont.woff
new file mode 100755 (executable)
index 0000000..ae6c5b3
Binary files /dev/null and b/pleaseshare/static/fonts/DroidSans-Bold-webfont.woff differ
diff --git a/pleaseshare/static/fonts/DroidSans-webfont.eot b/pleaseshare/static/fonts/DroidSans-webfont.eot
new file mode 100755 (executable)
index 0000000..c464740
Binary files /dev/null and b/pleaseshare/static/fonts/DroidSans-webfont.eot differ
diff --git a/pleaseshare/static/fonts/DroidSans-webfont.svg b/pleaseshare/static/fonts/DroidSans-webfont.svg
new file mode 100755 (executable)
index 0000000..0ec43d7
--- /dev/null
@@ -0,0 +1,150 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >
+<svg xmlns="http://www.w3.org/2000/svg">
+<metadata>
+This is a custom SVG webfont generated by Font Squirrel.
+Copyright   : Digitized data copyright  2006 Google Corporation
+Foundry     : Ascender Corporation
+Foundry URL : httpwwwascendercorpcom
+</metadata>
+<defs>
+<font id="webfontw7zqO19G" horiz-adv-x="1126" >
+<font-face units-per-em="2048" ascent="1638" descent="-410" />
+<missing-glyph horiz-adv-x="530" />
+<glyph unicode=" "  horiz-adv-x="530" />
+<glyph unicode="&#x09;" horiz-adv-x="530" />
+<glyph unicode="&#xa0;" horiz-adv-x="530" />
+<glyph unicode="!" horiz-adv-x="550" d="M147 111q0 35 11 65q10 29 26 43q20 16 39 23q29 8 51 8q16 0 50 -8q20 -4 41 -23q16 -14 26 -43q10 -31 10 -65q0 -33 -10 -64q-8 -25 -26 -43q-14 -14 -41 -24q-23 -8 -50 -9q-33 0 -51 9q-25 10 -39 24q-18 18 -26 43q-11 31 -11 64zM164 1462h223l-51 -1048h-121z " />
+<glyph unicode="&#x22;" horiz-adv-x="821" d="M133 1462h197l-41 -528h-115zM494 1462h196l-41 -528h-114z" />
+<glyph unicode="#" horiz-adv-x="1320" d="M51 428v137h285l65 328h-274v137h299l82 432h147l-82 -432h293l84 432h144l-84 -432h262v-137h-289l-63 -328h280v-137h-307l-82 -428h-147l84 428h-291l-82 -428h-144l78 428h-258zM483 565h291l64 328h-291z" />
+<glyph unicode="$" d="M123 172v172q59 -27 76 -33q53 -18 92 -28q66 -16 98 -23q43 -8 98 -8v434q-100 35 -155 64q-70 37 -109 75q-43 43 -63.5 96.5t-20.5 129.5q0 68 25 123q25 53 69 96q45 41 111 69q57 25 143 35v180h138v-176q102 -6 184 -26q86 -23 152 -52l-66 -145q-45 20 -127 45 q-66 20 -143 27v-422q92 -33 155 -64q68 -35 113 -75q49 -47 70 -95q23 -55 22.5 -124.5t-24.5 -127.5q-23 -55 -72 -100q-45 -41 -113 -69q-63 -27 -151 -39v-230h-138v221q-33 0 -102 4q-33 2 -98 15q-53 10 -90 20q-43 13 -74 31zM315 1049q0 -39 9 -64q10 -33 28 -53 q20 -23 54 -41q37 -20 81 -37v369q-86 -14 -131 -60q-41 -40 -41 -114zM625 262q94 16 139 63.5t45 120.5q0 29 -10.5 60t-30.5 51.5t-57 40.5q-34 18 -86 37v-373z" />
+<glyph unicode="%" horiz-adv-x="1689" d="M102 1026q0 117 17 193q18 84 55 143t92.5 90t134.5 31q76 0 131 -31q53 -29 94.5 -90.5t59.5 -142.5q18 -86 19 -193q0 -109 -19 -195q-20 -92 -53 -145q-37 -59 -96 -90q-57 -31 -136 -31q-74 0 -129 31q-57 33 -94 90q-39 63 -57 145q-19 86 -19 195zM250 1026 q0 -170 35 -248q37 -82 116 -82q156 0 156 330q0 328 -156 328q-80 0 -116 -82q-35 -78 -35 -246zM362 0l812 1462h157l-811 -1462h-158zM985 440q0 106 19 193q18 90 53 143q37 59 92 90t135 31q76 0 131 -31q57 -33 94 -90q41 -63 58 -143q20 -96 20 -193q0 -109 -18 -194 q-18 -90 -53 -144q-39 -61 -95 -90q-61 -33 -137 -32q-72 0 -131 32q-55 31 -92 90q-41 63 -57 144q-19 85 -19 194zM1133 440q0 -166 36.5 -247.5t114.5 -81.5q156 0 156 329q0 328 -156 328q-78 0 -115 -82q-36 -84 -36 -246z" />
+<glyph unicode="&#x26;" horiz-adv-x="1437" d="M109 381q0 80 20 139q23 66 59 111q49 61 93 94q39 31 127 84q-6 8 -19.5 22.5l-24 26.5t-18.5 25q-29 39 -51 82q-20 39 -37 94q-14 45 -14 106q0 76 24 135q23 51 74 101q43 41 115 63q63 20 157 21q86 0 148 -21q70 -23 112 -63q41 -39 68 -101q25 -59 25 -135 q0 -63 -25 -118q-25 -53 -68 -101q-47 -51 -96 -86q-57 -41 -114 -76l352 -372q25 25 49 59l39 64q14 25 29 73q20 68 24 86h184q-16 -68 -36 -121q-31 -80 -45 -104q-33 -57 -60 -92q-45 -57 -72 -84l277 -293h-225l-168 172q-41 -39 -97 -80q-51 -39 -102 -61 q-55 -25 -117 -37q-72 -14 -139 -14q-109 0 -188 26q-86 29 -141.5 78t-88.5 127q-30 74 -30 170zM299 387q0 -55 18 -100q18 -47 50 -78q29 -29 82 -49q49 -18 108 -19q66 0 107 11q53 12 92 32q45 23 78 47q41 31 67 58l-387 407l-92 -65q-40 -31 -68 -68q-25 -33 -41 -78 q-14 -41 -14 -98zM422 1165q0 -37 8 -67q6 -25 25 -64q10 -23 43 -67q23 -31 61 -70q55 33 103 66q35 25 69 63q25 27 43 68q14 31 14 75q0 35 -12 66q-12 33 -37 53q-27 25 -57 35q-35 12 -74 12q-86 0 -137 -45q-49 -43 -49 -125z" />
+<glyph unicode="'" horiz-adv-x="462" d="M133 1462h197l-41 -528h-115z" />
+<glyph unicode="(" horiz-adv-x="614" d="M82 561q0 123 18 246q18 125 56 237q37 117 92 220q53 100 135 198h172q-137 -188 -213 -424q-72 -223 -72 -475q0 -121 19 -237q20 -131 53 -232q37 -115 88 -219q39 -80 123 -199h-170q-86 100 -135 193q-57 109 -92 215q-37 114 -56 233q-18 121 -18 244z" />
+<glyph unicode=")" horiz-adv-x="614" d="M61 1462h172q76 -92 134 -198q59 -113 94 -220q37 -113 55 -237q18 -123 18.5 -246t-18.5 -244q-18 -120 -55 -233q-31 -96 -94 -215q-53 -98 -134 -193h-170q78 109 121 199q57 119 90 219.5t54 231.5q18 117 18 237q0 242 -72 475q-70 227 -213 424z" />
+<glyph unicode="*" d="M82 1081l29 193l391 -111l-43 393h205l-43 -393l397 111l26 -193l-378 -28l245 -326l-178 -96l-176 358l-158 -358l-184 96l242 326z" />
+<glyph unicode="+" d="M102 647v150h387v389h150v-389h387v-150h-387v-385h-150v385h-387z" />
+<glyph unicode="," horiz-adv-x="512" d="M63 -264q6 23 15.5 65.5l13.5 61.5l29 131l24 129l10.5 62.5t8.5 52.5h198l15 -23l-33 -115q-18 -61 -43 -123q-8 -25 -49 -124q-6 -16 -51 -117h-138z" />
+<glyph unicode="-" horiz-adv-x="657" d="M82 465v168h496v-168h-496z" />
+<glyph unicode="." horiz-adv-x="548" d="M147 111q0 35 11 65q10 29 26 43q20 16 39 23q29 8 51 8q16 0 50 -8q20 -4 41 -23q16 -14 26 -43q10 -31 10 -65q0 -33 -10 -64q-8 -25 -26 -43q-14 -14 -41 -24q-23 -8 -50 -9q-33 0 -51 9q-25 10 -39 24q-18 18 -26 43q-11 31 -11 64z" />
+<glyph unicode="/" horiz-adv-x="763" d="M20 0l545 1462h178l-544 -1462h-179z" />
+<glyph unicode="0" d="M98 733q0 176 25 318q23 135 82 235q55 96 143 147.5t215 51.5q115 0 207 -51q86 -47 145 -146q61 -100 89 -237q29 -147 28 -318q0 -164 -26 -317q-23 -133 -82 -238q-51 -92 -146 -147q-88 -51 -215 -51q-121 0 -205 51q-90 55 -145 147q-59 98 -86 238 q-29 147 -29 317zM283 733q0 -143 16 -262q16 -121 47 -186q35 -76 86 -113t131 -37q76 0 131 37q53 37 88 110.5t49 186.5q16 121 16.5 264.5t-16.5 261.5q-16 113 -49 187q-35 74 -88 110q-55 37 -131 37q-80 0 -131 -37q-52 -37 -86 -110q-31 -66 -47 -187 q-16 -119 -16 -262z" />
+<glyph unicode="1" d="M178 1163l383 299h150v-1462h-176v913v93q0 16 1 47.5t1 48.5l4 94q0 14 1 41t1 37l-31 -31l-25 -24q-14 -12 -28 -27q-8 -8 -17.5 -15.5l-19.5 -15.5l-148 -121z" />
+<glyph unicode="2" d="M96 0v156l350 381l134 147q57 66 100 131q41 61 63.5 129t22.5 141q0 63 -16 105q-18 45 -50 76q-33 33 -73 47q-45 16 -97 16q-96 0 -172 -39q-88 -45 -145 -98l-102 119q40 37 86 67q55 37 100 56q68 29 111 36q59 12 124 13q98 0 173 -27q76 -27 133 -78 q49 -43 82 -123q31 -74 30 -163q0 -88 -26 -162q-29 -80 -74 -152q-51 -82 -111 -149l-139 -156l-281 -299v-8h689v-166h-912z" />
+<glyph unicode="3" d="M82 59v170q88 -47 188 -71q102 -25 195 -25q96 0 160 21q70 23 110 57q43 37 63.5 90t20.5 121q0 70 -26 117q-29 49 -76 79q-51 33 -119 48q-66 14 -160 14h-133v151h133q82 0 144 21q70 23 106 55q43 37 64 88q23 55 22 113q0 52 -18 92q-20 45 -51 70q-39 33 -78 45 q-43 14 -103 14q-109 0 -188 -33q-84 -35 -156 -88l-92 125q31 25 84 58q35 20 102 47q49 18 117 32q61 12 133 13q109 0 189 -27q84 -29 137 -76q57 -51 84 -114q27 -66 27 -146q0 -70 -23 -133t-64 -104q-45 -45 -100 -72q-61 -29 -129 -41v-6q174 -20 268 -113 q92 -90 93 -235q0 -98 -33 -176t-98.5 -137.5t-165.5 -90.5q-109 -33 -240 -32q-109 0 -205 18q-106 20 -182 61z" />
+<glyph unicode="4" d="M23 328v159l663 983h188v-976h213v-166h-213v-328h-176v328h-675zM201 494h497v356q0 18 1 57t1 60q0 82 2 120q0 18 1.5 54.5t3.5 54.5q4 70 4 86h-9q-2 -8 -9 -23.5t-9 -21.5q-6 -16 -22.5 -49t-24.5 -47q-16 -29 -25 -39z" />
+<glyph unicode="5" d="M131 59v172q37 -23 78 -41q43 -18 92 -30q47 -12 100 -19q49 -6 91 -6q80 0 141 19q63 18 104 57q47 45 68 98q23 61 22 140q0 143 -88 218.5t-256 75.5q-39 0 -59 -2q-10 0 -30.5 -4t-31.5 -4q-10 -2 -31.5 -5t-29.5 -3q-10 -2 -27.5 -5t-21.5 -3l-90 57l55 688h690 v-166h-532l-39 -419q53 10 84 14q51 6 125 6q102 0 184 -27q86 -29 149.5 -82t100.5 -135q35 -76 35 -184q0 -115 -33 -205q-31 -86 -102 -153q-63 -61 -166 -97q-100 -35 -226 -34q-51 0 -100 6q-66 8 -96 14q-46 9 -86 25q-47 18 -74 34z" />
+<glyph unicode="6" d="M113 625q0 92 10 209q10 106 37 200q27 90 73 176q45 82 117 144q68 59 170 94q100 35 232 35h43q12 0 45 -4q16 -2 45 -6q25 -4 39 -9v-155q-33 12 -78 18q-43 6 -88 6q-86 0 -158 -22q-76 -25 -119 -60q-53 -43 -84 -94q-35 -57 -55 -119q-20 -63 -31 -139 q-9 -74 -12 -154h12q22 37 49 68q29 31 66 53.5t86 34.5q53 14 106 14q95 0 173 -30q80 -33 131 -86q49 -53 82 -140q31 -82 30 -188q0 -113 -30 -205q-29 -88 -91 -155q-57 -63 -139 -97q-86 -35 -184 -34q-102 0 -187 38q-88 41 -151 119q-66 80 -102 203q-37 119 -37 285 zM295 506q0 -66 18 -133q18 -66 56 -119q39 -55 92 -88t127 -33q63 0 110 21q49 23 84 61q39 45 56 104q20 72 20 152q0 66 -16 125q-14 53 -49 94q-33 39 -84 62q-47 20 -115 20t-123 -24q-57 -27 -94 -60t-60 -86q-22 -51 -22 -96z" />
+<glyph unicode="7" d="M90 1296v166h940v-145l-555 -1317h-194l563 1296h-754z" />
+<glyph unicode="8" d="M106 373q0 72 23 135q18 55 59 108q33 43 90.5 84t110.5 66q-49 31 -92 68q-45 39 -74 81q-37 55 -51 99q-18 55 -18 121q0 88 34 153q37 70 91 109q61 45 131 65q78 23 155 23q80 0 158 -23q76 -23 131 -65.5t90 -110.5q33 -63 33 -153q0 -68 -21 -121q-20 -51 -55 -97 q-41 -51 -82 -79q-49 -34 -104 -62q49 -25 114 -69q47 -33 99 -87q39 -41 69 -106q27 -55 27 -131q0 -94 -33 -166q-35 -78 -94 -127q-63 -53 -145 -80q-90 -29 -187 -28q-115 0 -196.5 26.5t-143.5 77.5q-55 47 -88 125q-31 74 -31 164zM285 371q0 -51 16 -97 q18 -49 49 -77q31 -27 86 -47q51 -18 125 -19q71 0 123 19q59 20 90 49q35 33 53 77q18 47 19 103q0 51 -19 94q-16 35 -57 78q-39 39 -88 67q-88 51 -113 64l-30 14q-127 -61 -190.5 -136.5t-63.5 -188.5zM332 1126q0 -58 18 -98q23 -49 47 -74q33 -33 76 -57 q47 -27 94 -49q18 8 90 49q45 27 74 57q31 35 49 76q18 43 19 96q0 102 -64 154q-66 53 -172 53q-104 0 -167.5 -53.5t-63.5 -153.5z" />
+<glyph unicode="9" d="M106 991q0 113 31 205q29 88 90 156q59 66 139 98.5t184.5 32.5t188.5 -39q88 -41 152 -119q63 -80 100 -201q37 -123 37 -286q0 -92 -10 -209q-10 -106 -37 -201q-27 -90 -74 -176q-45 -82 -116 -143q-68 -59 -170 -95q-100 -35 -232 -34q-6 0 -20.5 1t-22.5 1 q-31 0 -45 2l-45 6q-25 4 -39 8v156q33 -12 80 -19q43 -6 86 -6q133 0 221 47q86 47 139 127q49 76 72 189q20 100 27 225h-13q-22 -37 -49 -68q-29 -31 -65 -53q-47 -27 -86 -37q-49 -12 -107 -12q-100 0 -172 28q-76 31 -131 89q-53 55 -84 139q-29 77 -29 188zM283 991 q0 -66 16 -125q16 -57 49 -96q31 -37 84 -59q47 -20 115 -21q72 0 123 23q53 25 94 61q40 37 61 86q20 47 21 96q0 66 -19 134q-18 70 -55 120q-39 55 -90 86q-53 33 -129 33q-61 0 -109 -20q-53 -23 -86 -62q-37 -43 -55 -106q-20 -72 -20 -150z" />
+<glyph unicode=":" horiz-adv-x="548" d="M147 111q0 35 11 65q10 29 26 43q20 16 39 23q29 8 51 8q16 0 50 -8q20 -4 41 -23q16 -14 26 -43q10 -31 10 -65q0 -33 -10 -64q-8 -25 -26 -43q-14 -14 -41 -24q-23 -8 -50 -9q-33 0 -51 9q-25 10 -39 24q-18 18 -26 43q-11 31 -11 64zM147 987q0 35 11 66q10 29 26 43 q20 16 39 22q29 8 51 8q16 0 50 -8q20 -4 41 -22q16 -14 26 -43q10 -31 10 -66q0 -37 -10 -63.5t-26 -42.5q-14 -14 -41 -25q-23 -8 -50 -8q-33 0 -51 8q-25 10 -39 25q-16 16 -26.5 42.5t-10.5 63.5z" />
+<glyph unicode=";" horiz-adv-x="548" d="M63 -264q6 23 15.5 65.5l13.5 61.5l29 131l24 129l10.5 62.5t8.5 52.5h198l15 -23l-33 -115q-18 -61 -43 -123q-8 -25 -49 -124q-6 -16 -51 -117h-138zM147 987q0 35 11 66q10 29 26 43q20 16 39 22q29 8 51 8q16 0 50 -8q20 -4 41 -22q16 -14 26 -43q10 -31 10 -66 q0 -37 -10 -63.5t-26 -42.5q-14 -14 -41 -25q-23 -8 -50 -8q-33 0 -51 8q-25 10 -39 25q-16 16 -26.5 42.5t-10.5 63.5z" />
+<glyph unicode="&#x3c;" d="M102 662v102l924 481v-160l-735 -364l735 -322v-161z" />
+<glyph unicode="=" d="M102 442v150h924v-150h-924zM102 852v149h924v-149h-924z" />
+<glyph unicode="&#x3e;" d="M102 238v161l736 322l-736 364v160l924 -481v-102z" />
+<glyph unicode="?" horiz-adv-x="870" d="M37 1382q70 37 176 72q88 29 190 29q94 0 168 -25q72 -25 125.5 -74t79.5 -118q29 -74 29 -156q0 -57 -14 -119q-12 -55 -39 -98q-23 -37 -68 -86q-47 -51 -94 -90q-53 -45 -84 -78q-35 -35 -53 -66q-23 -37 -27 -63q-6 -35 -6 -78v-18h-139v37q0 43 8 104q4 37 26 84 q16 37 54 80q27 31 82 80q33 27 81 75q34 34 56 68q25 39 33 74q10 45 10 92q0 51 -15 88q-15 40 -43 68q-27 27 -71.5 43t-98.5 16q-78 0 -157 -27q-70 -23 -146 -59zM233 111q0 35 11 65q10 29 26 43q20 16 39 23q29 8 51 8q16 0 50 -8q20 -4 41 -23q16 -14 26 -43 q10 -31 10 -65q0 -33 -10 -64q-8 -25 -26 -43q-14 -14 -41 -24q-23 -8 -50 -9q-33 0 -51 9q-25 10 -39 24q-18 18 -26 43q-11 31 -11 64z" />
+<glyph unicode="@" horiz-adv-x="1773" d="M109 575q0 184 59 351q57 162 168 280q113 123 266 189q156 68 348 67q150 0 287 -51q131 -49 227.5 -145.5t147.5 -229.5q53 -137 53 -305q0 -57 -10 -125q-10 -72 -27 -119q-16 -51 -47 -104q-20 -37 -68 -84q-35 -35 -86 -57q-47 -20 -106 -21q-47 0 -82 14.5 t-61 40.5q-31 31 -43 58q-16 37 -23 67h-4q-18 -37 -45 -69q-29 -37 -62 -58q-31 -20 -81 -38q-41 -14 -97 -15q-76 0 -137 29q-59 29 -100 78q-39 49 -62 121q-23 74 -22 157q0 101 30 185q33 88 84 145q53 59 135.5 94t176.5 35q29 0 90 -4q35 -2 86 -10q37 -6 76 -17 q53 -14 57 -16l-23 -416q0 -8 -1 -19.5t-1 -15.5v-22v-13v-6q0 -51 11 -88q8 -33 26.5 -53t38.5 -27q29 -8 45 -8q46 0 80 31q37 33 60 82q20 45 34 123q12 71 13 147q0 141 -43 252t-119 186q-78 78 -180.5 117t-227.5 39q-170 0 -299 -55q-127 -53 -215 -156 q-86 -98 -133 -235q-45 -133 -45 -299q0 -154 39 -269q40 -117 117 -196q78 -82 190 -121q117 -41 260 -41q61 0 121 6q43 4 115 21q68 14 104 26q66 20 94 33v-141q-90 -39 -194 -60q-113 -23 -238 -22q-180 0 -319 51t-237.5 149.5t-149.5 237.5t-51 319zM662 602 q0 -131 51 -192q49 -59 135 -60q53 0 94 23q39 20 64 63q29 51 38 99q14 63 17 127l14 253q-23 8 -67 15q-41 6 -80 6q-74 0 -125 -28.5t-82 -76.5q-29 -45 -45 -106q-14 -57 -14 -123z" />
+<glyph unicode="A" horiz-adv-x="1243" d="M0 0l537 1468h170l538 -1468h-190l-160 453h-545l-162 -453h-188zM410 618h426l-148 424l-4 12.5l-4 12.5l-6 18q-2 10 -8.5 25.5t-10.5 32.5l-16 61q-4 18 -9 33.5t-9 30.5q-2 -12 -17 -64l-16 -63q-9 -31 -19 -56q-4 -10 -6 -18t-4 -12t-4 -13z" />
+<glyph unicode="B" horiz-adv-x="1271" d="M199 0v1462h399q117 0 225 -20q100 -18 164 -61.5t98 -114.5q33 -68 33 -174q0 -53 -20 -115q-18 -57 -56 -96q-37 -40 -92 -68t-123 -37v-10q61 -10 129 -35q59 -20 107 -61q45 -39 70 -101q27 -66 26 -145q0 -100 -32.5 -178t-94.5 -133q-63 -57 -149 -84 q-92 -29 -199 -29h-485zM385 158h266q92 0 148 20q66 25 96 55q35 35 51 86q16 53 17 113q0 53 -17 103q-16 47 -53 81q-35 31 -100 52q-61 18 -154 18h-254v-528zM385 842h244q86 0 141 14q59 16 92 45q37 33 51.5 74t14.5 104q0 121 -76 172.5t-244 51.5h-223v-461z" />
+<glyph unicode="C" horiz-adv-x="1234" d="M125 733q0 164 43 303.5t129 237.5q88 100 209 153q125 55 287 56q104 0 206 -23q98 -20 177 -63l-78 -156q-82 39 -137 55q-78 23 -168 23q-106 0 -195 -41q-86 -40 -147 -117q-59 -74 -94 -184.5t-35 -245.5q0 -139 30 -250q31 -113 88 -184q59 -76 148 -115 q86 -39 205 -39q98 0 170 17q66 14 157 41v-162q-35 -14 -78 -27q-41 -12 -81 -18q-57 -8 -91 -10q-66 -4 -108 -4q-164 0 -285 55t-198 151q-76 92 -115 240q-39 145 -39 307z" />
+<glyph unicode="D" horiz-adv-x="1400" d="M199 0v1462h407q152 0 277 -47q127 -47 211 -135q90 -94 135 -225q47 -137 47 -310q0 -193 -47 -325q-51 -143 -139 -232q-98 -98 -224 -141q-135 -47 -301 -47h-366zM385 160h162q264 0 397 145q135 147 135 434q0 147 -32 252q-35 113 -97 176q-68 70 -155 103 q-90 33 -209 33h-201v-1143z" />
+<glyph unicode="E" horiz-adv-x="1079" d="M199 0v1462h759v-164h-573v-452h535v-162h-535v-520h573v-164h-759z" />
+<glyph unicode="F" horiz-adv-x="1005" d="M199 0v1462h759v-164h-573v-516h535v-164h-535v-618h-186z" />
+<glyph unicode="G" horiz-adv-x="1411" d="M125 733q0 170 47 311q45 135 139 236q92 98 224 150q135 53 305 53q106 0 213 -23q104 -23 190 -63l-72 -162q-35 18 -77 33q-29 10 -86 26q-43 12 -90 19q-46 6 -93 6q-119 0 -217 -41q-92 -39 -157 -117q-61 -74 -97 -184q-33 -104 -32 -246q0 -127 28 -237 q31 -117 86 -187q63 -80 156 -121q96 -43 229 -43q55 0 80 2q37 3 68 7q25 2 59 10q27 6 53 10v436h-299v164h484v-717q-37 -12 -111 -32q-37 -10 -115 -23q-39 -6 -125 -14q-63 -6 -139 -6q-156 0 -278 53q-121 53 -203 149q-84 100 -127 238t-43 313z" />
+<glyph unicode="H" horiz-adv-x="1435" d="M199 0v1462h186v-616h666v616h186v-1462h-186v682h-666v-682h-186z" />
+<glyph unicode="I" horiz-adv-x="692" d="M82 0v102l172 41v1176l-172 41v102h530v-102l-172 -41v-1176l172 -41v-102h-530z" />
+<glyph unicode="J" horiz-adv-x="552" d="M-184 -205q25 -6 73 -14q41 -6 84 -6q33 0 74 10q35 8 68 35q35 27 51 67q18 43 18 113v1462h187v-1442q0 -111 -29 -182q-33 -80 -82 -127q-55 -51 -127 -76q-74 -25 -162 -24q-53 0 -90 6q-39 6 -65 18v160z" />
+<glyph unicode="K" horiz-adv-x="1185" d="M199 0v1462h186v-731l121 168l452 563h209l-520 -637l539 -825h-211l-451 698l-139 -114v-584h-186z" />
+<glyph unicode="L" horiz-adv-x="1005" d="M199 0v1462h186v-1296h573v-166h-759z" />
+<glyph unicode="M" horiz-adv-x="1781" d="M199 0v1462h276l412 -1192h6l414 1192h276v-1462h-186v887q0 74 2 119l6 129l6 143h-8l-447 -1278h-153l-443 1280h-8q8 -98 10 -147q6 -109 7 -132q2 -47 2 -127v-874h-172z" />
+<glyph unicode="N" horiz-adv-x="1492" d="M199 0v1462h213l716 -1204h7l-7 150q0 10 -1 31.5t-1 33.5l-4 68q0 12 -1 32.5t-1 30.5v58v800h174v-1462h-215l-719 1210h-8q8 -102 10 -153l7 -135q2 -47 2 -129v-793h-172z" />
+<glyph unicode="O" horiz-adv-x="1519" d="M125 735q0 164 39 309q37 137 117 236q82 100 198 152q123 53 283 53q154 0 272.5 -53.5t198.5 -151.5q78 -96 119 -237.5t41 -309.5q0 -166 -41 -307q-41 -145 -119 -240q-78 -96 -199 -151t-274 -55q-163 0 -283 55q-121 55 -198 151q-76 92 -115 240q-39 145 -39 309z M322 733q0 -127 26 -246q23 -102 80 -186q52 -77 135 -117q86 -41 196.5 -41t196.5 41q83 40 136 117q57 84 79 186q25 111 25 246q0 139 -25 248q-25 104 -77 184q-49 74 -135.5 115t-197 41t-196.5 -41q-84 -41 -137 -115q-55 -77 -80 -184q-26 -117 -26 -248z" />
+<glyph unicode="P" horiz-adv-x="1179" d="M199 0v1462h362q129 0 232 -28q92 -27 159 -84q61 -53 92 -133t31 -183q0 -90 -28.5 -176t-90.5 -147q-63 -63 -165.5 -102.5t-255.5 -39.5h-150v-569h-186zM385 727h129q86 0 162 16q70 14 115 52q49 39 69 92q23 57 23 137q0 143 -82 211q-84 68 -256 68h-160v-576z " />
+<glyph unicode="Q" horiz-adv-x="1517" d="M125 735q0 164 39 309q37 137 117 236q82 100 198 152q123 53 283 53q154 0 272.5 -53.5t198.5 -151.5q78 -96 119 -237.5t41 -309.5q0 -131 -25 -244q-25 -115 -72 -204.5t-118 -155.5q-76 -70 -164 -104q41 -92 112 -166q63 -66 158 -131l-121 -142q-104 74 -190 172 q-84 94 -137 226q-12 -2 -37 -2q-8 0 -20.5 -1t-18.5 -1q-163 0 -283 55q-121 55 -198 151q-76 92 -115 240q-39 145 -39 309zM322 733q0 -127 26 -246q23 -102 80 -186q52 -77 135 -117q86 -41 196.5 -41t196.5 41q83 40 136 117q57 84 79 186q25 111 25 246q0 139 -25 248 q-25 104 -77 184q-49 74 -135.5 115t-197 41t-196.5 -41q-84 -41 -137 -115q-55 -77 -80 -184q-26 -117 -26 -248z" />
+<glyph unicode="R" horiz-adv-x="1206" d="M199 0v1462h356q270 0 393 -102q127 -104 127 -313q0 -88 -24 -152q-25 -61 -66 -110.5t-92 -77.5q-49 -29 -107 -52l398 -655h-219l-351 604h-229v-604h-186zM385 762h164q89 0 153 18q63 18 103 51q41 35 59 87q18 53 19 120q0 74 -21 121q-25 55 -61 82 q-47 33 -105 47q-59 14 -151 15h-160v-541z" />
+<glyph unicode="S" horiz-adv-x="1062" d="M104 49v178q51 -23 78 -32q39 -14 90 -27q49 -12 101 -18q70 -8 100 -9q162 0 236 60q78 61 77 172q0 57 -14 94q-16 41 -51 74q-39 37 -98 65q-61 31 -154 68q-92 35 -154 76q-70 45 -108 94q-41 49 -64 119q-20 61 -20 149q0 86 32.5 157.5t90.5 116.5q61 49 137 72 q80 25 178 25q113 0 213 -23q88 -20 170 -57l-67 -156q-76 33 -148 51q-80 20 -170 21q-119 0 -188 -57q-68 -55 -68 -152q0 -57 14 -98q14 -39 52 -76q27 -27 92 -62q49 -27 141 -63.5t160 -73.5q70 -39 115 -86q47 -49 69 -110q23 -59 23 -150q0 -94 -35 -174 q-34 -77 -98 -129q-66 -53 -156 -80q-96 -29 -207 -28q-113 0 -207 18q-103 20 -162 51z" />
+<glyph unicode="T" horiz-adv-x="1062" d="M20 1298v164h1022v-164h-417v-1298h-187v1298h-418z" />
+<glyph unicode="U" horiz-adv-x="1429" d="M184 520v942h187v-952q0 -175 86 -270q86 -96 262 -97q92 0 153 27q66 29 105 76q40 49 61 116q20 63 21 150v952h186v-948q0 -117 -33 -213q-35 -102 -100 -170q-72 -76 -166 -113q-104 -41 -237 -40q-129 0 -226 38q-98 39 -164 109q-68 70 -102 172q-33 96 -33 221z " />
+<glyph unicode="V" horiz-adv-x="1161" d="M0 1462h197l295 -927l51 -175l37 -159l38 159q12 49 54 181l293 921h198l-489 -1462h-187z" />
+<glyph unicode="W" horiz-adv-x="1808" d="M20 1462h197l223 -889l23 -96l18 -98q6 -33 15 -94q6 -51 12 -84q6 37 12 86q2 18 9.5 54t9.5 48q12 74 20 111q12 55 25 104l225 858h197l229 -856l29 -112l14 -49t14 -60q6 -23 21 -98q12 -61 16 -86q2 18 10 84q8 61 15 94q4 18 9 51t7 49q10 63 21 101l200 882h199 l-367 -1462h-188l-254 938q-14 47 -27 104l-12 51.5l-12 51.5l-23 106q-4 -23 -10 -49t-12 -57l-23 -103q-16 -74 -26 -110l-242 -932h-188z" />
+<glyph unicode="X" horiz-adv-x="1118" d="M0 0l453 764l-422 698h198l332 -559l334 559h190l-421 -692l456 -770h-211l-354 635l-367 -635h-188z" />
+<glyph unicode="Y" horiz-adv-x="1077" d="M0 1462h203l336 -739l340 739h200l-446 -893v-569h-187v559z" />
+<glyph unicode="Z" horiz-adv-x="1103" d="M82 0v145l711 1151h-691v166h899v-145l-710 -1151h731v-166h-940z" />
+<glyph unicode="[" horiz-adv-x="620" d="M164 -324v1786h405v-149h-223v-1487h223v-150h-405z" />
+<glyph unicode="\" horiz-adv-x="763" d="M23 1462h178l544 -1462h-178z" />
+<glyph unicode="]" horiz-adv-x="620" d="M51 -174h223v1487h-223v149h406v-1786h-406v150z" />
+<glyph unicode="^" horiz-adv-x="1089" d="M41 549l459 924h102l447 -924h-160l-338 735l-348 -735h-162z" />
+<glyph unicode="_" horiz-adv-x="841" d="M-4 -184h850v-140h-850v140z" />
+<glyph unicode="`" horiz-adv-x="1181" d="M393 1548v21h219q15 -34 37 -74l45 -82q20 -37 47 -78q6 -8 15.5 -22.5l16.5 -25.5t13 -19v-27h-120q-47 37 -76 70l-80 86q-29 31 -70 84q-35 44 -47 67z" />
+<glyph unicode="a" horiz-adv-x="1085" d="M94 307q0 164 115 252q115 86 352 96l184 7v69q0 70 -14 113t-43 71q-27 27 -67 39t-93 13q-86 0 -155 -25q-82 -29 -137 -57l-64 137q74 40 166 68q96 29 190 28q106 0 177 -20q72 -20 122 -66q45 -39 72 -112q25 -68 25 -168v-752h-131l-37 152h-8q-35 -45 -66 -78 t-72 -54q-41 -23 -88 -30q-55 -10 -110 -10q-61 0 -127 20q-55 18 -101 59q-39 37 -65 103q-25 61 -25 145zM283 305q0 -92 49 -135t127 -43q61 0 112 18q55 20 91 58q39 41 59 98q23 61 22 137v99l-143 -7q-80 -2 -151 -20q-55 -14 -97 -45q-39 -29 -53 -68 q-16 -43 -16 -92z" />
+<glyph unicode="b" horiz-adv-x="1198" d="M174 0v1556h182v-376q0 -10 -1 -35t-1 -39q0 -51 -2 -74l-4 -78h8q18 29 52 66q27 29 67 51q47 25 86 35q49 12 109 12q95 0 172 -37q76 -37 131 -106q51 -66 84 -178q31 -109 30 -246q0 -141 -30 -248q-33 -113 -84 -178q-57 -74 -131 -109q-77 -37 -172 -36 q-49 0 -107 14q-47 12 -86 33q-31 16 -69 51q-23 20 -52 61h-12l-37 -139h-133zM356 551q0 -100 13 -180q12 -76 47 -131q37 -57 86 -82q53 -27 135 -27q133 0 199 109q63 106 63 313q0 209 -63.5 311.5t-200.5 102.5q-82 0 -133 -24.5t-86 -78t-47.5 -131.5t-12.5 -182z " />
+<glyph unicode="c" horiz-adv-x="946" d="M113 542.5q0 149.5 39 266.5q37 111 104 178q72 72 156 100q89 31 190 31q86 0 152 -16q78 -20 125 -43l-54 -154q-14 6 -51 19q-53 18 -57 18t-26.5 5t-33.5 7q-37 4 -55 4q-160 0 -229 -100q-72 -102 -72 -313q0 -213 71.5 -309.5t221.5 -96.5q82 0 147 19 q61 18 119 43v-162q-57 -29 -115 -43q-66 -16 -151 -16q-94 0 -188 32q-89 31 -154 99q-66 70 -102.5 176t-36.5 255.5z" />
+<glyph unicode="d" horiz-adv-x="1198" d="M113 547q0 141 30 248q33 113 84 178q55 72 133 108.5t170 36.5q57 0 107 -12q33 -8 86 -37q37 -20 70 -49q23 -20 51 -62h12l-4 35t-2 31l-4 53q-2 18 -2 43v436h182v-1556h-147l-27 147h-8q-25 -39 -51 -65q-37 -37 -68 -53q-47 -25 -86 -35q-57 -14 -109 -14 q-92 0 -170 36q-80 39 -133 107q-51 66 -84 178q-30 109 -30 246zM301 545q0 -211 64 -312q66 -102 200 -102q74 0 129 23q47 18 84 69q33 45 49 119q12 59 17 164v41q0 100 -13 180q-12 76 -47 131q-37 57 -86 82q-53 27 -135 27q-133 0 -198 -109q-64 -106 -64 -313z" />
+<glyph unicode="e" horiz-adv-x="1095" d="M113 541q0 139 32 243q35 109 95 181q63 76 143 114.5t184 38.5q102 0 178 -35q78 -37 134 -100q51 -59 84 -156q31 -90 30 -200v-113h-692q6 -195 82 -285t227 -90q66 0 95 4q57 8 83 15q43 10 78 24q70 29 78 33v-162l-78 -33q-27 -10 -80 -22t-84 -14q-57 -4 -94 -4 q-109 0 -201 36.5t-157 108.5q-61 68 -100 176q-37 105 -37 240zM305 662h492q0 70 -13 124q-10 51 -43 97q-27 39 -71.5 61.5t-106.5 22.5q-113 0 -180 -78q-66 -73 -78 -227z" />
+<glyph unicode="f" horiz-adv-x="673" d="M29 961v75l194 68v96q0 104 23 178q20 68 65 113q41 41 105 59q55 16 139 17q68 0 109 -11q53 -14 88 -26l-47 -141q-25 10 -68 20q-33 8 -76 8q-39 0 -69.5 -10t-47.5 -33q-20 -27 -28 -65q-10 -47 -10 -107v-104h245v-137h-245v-961h-183v961h-194z" />
+<glyph unicode="g" horiz-adv-x="1060" d="M37 -186q0 55 20 106q18 45 52 78q29 29 77 53q37 18 90 33q-41 16 -69 59q-27 39 -27 95q0 61 33 106q29 41 100 86q-39 16 -77 49q-35 29 -62 72q-25 41 -37 88q-14 57 -14 100q0 88 24 158q25 72 74 121t123 74q80 27 170 26q35 0 76 -6q45 -6 67 -14h363v-113 l-197 -27q29 -35 47.5 -90t18.5 -123q0 -82 -23 -141q-25 -63 -71 -110q-46 -46 -117 -74q-68 -27 -164 -27h-45q-14 0 -35 4q-12 -6 -33 -22q-23 -16 -30 -29q-14 -18 -22.5 -36.5t-8.5 -43.5q0 -28 12 -43q14 -18 33 -26q23 -10 47 -13q18 -2 60 -2h176q94 0 157 -24 q66 -25 105 -64t57.5 -94t18.5 -115q0 -90 -33 -157q-35 -72 -99 -119q-72 -51 -169 -76q-102 -25 -242 -25q-111 0 -187 21q-82 23 -133 61.5t-80 96.5q-26 53 -26 127zM209 -180q0 -39 12 -70q12 -33 43 -53q39 -27 78 -37q57 -14 121 -14q188 0 278 57q92 58 93 166 q0 49 -13 76q-14 31 -39 45q-31 16 -71 22q-46 6 -111 6h-176q-41 0 -74 -8q-41 -10 -69 -30q-31 -23 -52 -60q-20 -39 -20 -100zM301 745.5q0 -118.5 53 -172.5q55 -55 153.5 -55t151.5 55q51 53 52 175q0 125 -51.5 182t-153.5 57q-100 0 -152 -59q-53 -64 -53 -182.5z " />
+<glyph unicode="h" horiz-adv-x="1204" d="M174 0v1556h182v-462l-8 -144h10q23 41 60 74q33 31 76 53q40 22 86 31q51 10 94 10q184 0 276 -96t92 -305v-717h-182v707q0 129 -53 194.5t-164 65.5q-76 0 -135 -27q-57 -27 -90 -76q-31 -47 -47 -125q-14 -70 -15 -170v-569h-182z" />
+<glyph unicode="i" horiz-adv-x="528" d="M160 1395q0 59 30 88q29 27 76 26q23 0 41 -6q20 -8 35 -20q12 -12 23 -37q8 -18 8 -51q0 -58 -31 -86q-33 -29 -76 -29t-76 29q-30 28 -30 86zM174 0v1098h182v-1098h-182z" />
+<glyph unicode="j" horiz-adv-x="528" d="M-68 -319q16 -6 54 -15q28 -6 61 -6q20 0 49 8q20 6 41 27q18 18 27 51q10 37 10 84v1268h182v-1256q0 -84 -16 -139q-20 -66 -53 -104q-37 -43 -92 -68q-51 -23 -129 -23q-49 0 -80 7q-33 6 -54 18v148zM160 1395q0 59 30 88q29 27 76 26q23 0 41 -6q20 -8 35 -20 q12 -12 23 -37q8 -18 8 -51q0 -58 -31 -86q-33 -29 -76 -29t-76 29q-30 28 -30 86z" />
+<glyph unicode="k" horiz-adv-x="1015" d="M174 0v1556h180v-714l-16 -275h4l135 170l293 361h211l-401 -475l428 -623h-209l-336 504l-109 -82v-422h-180z" />
+<glyph unicode="l" horiz-adv-x="528" d="M174 0v1556h182v-1556h-182z" />
+<glyph unicode="m" horiz-adv-x="1832" d="M174 0v1098h148l26 -148h10q27 45 58 74q39 37 71 53q39 20 84 31q47 10 91 10q117 0 200 -45q80 -43 117 -137h8q27 49 62 82q35 31 81 55q49 25 90.5 35t98.5 10q174 0 264 -96q88 -94 88 -305v-717h-182v707q0 129 -49 194.5t-156 65.5q-78 0 -125 -22.5t-82 -70 t-49 -112.5q-14 -63 -14 -156v-606h-183v707q0 129 -49 194.5t-155 65.5q-72 0 -129 -27q-55 -27 -84 -76q-35 -57 -45 -125q-12 -74 -13 -170v-569h-182z" />
+<glyph unicode="n" horiz-adv-x="1204" d="M174 0v1098h148l26 -148h10q23 41 60 74q33 31 76 53q40 22 86 31q51 10 94 10q184 0 276 -96t92 -305v-717h-182v707q0 129 -53 194.5t-164 65.5q-76 0 -135 -27q-57 -27 -90 -76q-31 -47 -47 -125q-14 -70 -15 -170v-569h-182z" />
+<glyph unicode="o" horiz-adv-x="1181" d="M113 551q0 133 34 242q35 106 95 178q61 74 151 110.5t201 36.5q104 0 190 -37q84 -37 150 -110q63 -72 100 -178q35 -98 35 -242q0 -139 -33 -244q-31 -100 -96 -178q-61 -74 -152 -111q-94 -39 -200 -38q-100 0 -191 38q-84 37 -149 111q-61 70 -98 178 q-37 107 -37 244zM301 551q0 -211 67.5 -315.5t223.5 -104.5q154 0 221.5 104.5t67.5 315.5q0 209 -68 313q-66 102 -223 103q-156 0 -221 -103q-68 -104 -68 -313z" />
+<glyph unicode="p" horiz-adv-x="1198" d="M174 -492v1590h148l26 -148h8q18 29 52 66q29 33 67 53q47 25 86 35q57 14 109 14q95 0 172 -37q76 -37 131 -106q51 -66 84 -178q31 -109 30 -246q0 -141 -30 -248q-33 -113 -84 -178q-57 -74 -131 -109q-77 -37 -172 -36q-49 0 -107 14q-47 12 -86 33q-31 16 -69 51 q-23 20 -52 61h-12l4 -34.5t2 -30.5l4 -54q2 -18 2 -43v-469h-182zM356 551q0 -100 13 -180q12 -76 47 -131q37 -57 86 -82q53 -27 135 -27q133 0 199 109q63 106 63 313q0 209 -63.5 311.5t-200.5 102.5q-74 0 -129 -23q-47 -18 -84 -70q-34 -46 -49 -116q-12 -59 -17 -166 v-41z" />
+<glyph unicode="q" horiz-adv-x="1198" d="M113 547q0 141 30 248q33 113 84 178q55 72 133 108.5t170 36.5q49 0 107 -14q47 -12 86 -35q35 -20 67.5 -53t53.5 -66h8l27 148h147v-1590h-182v469q0 29 2 48q0 10 1 20t2 17.5t1 19.5q0 16 2 31.5t4 33.5h-12q-25 -39 -51 -65q-37 -37 -68 -53q-47 -25 -86 -35 q-57 -14 -109 -14q-92 0 -170 36q-80 39 -133 107q-51 66 -84 178q-30 109 -30 246zM301 545q0 -211 64 -312q66 -102 200 -102q74 0 129 23q47 18 84 69q33 45 49 119q12 59 17 164v41q0 100 -13 180q-12 76 -47 131q-37 57 -86 82q-53 27 -135 27q-133 0 -198 -109 q-64 -106 -64 -313z" />
+<glyph unicode="r" horiz-adv-x="815" d="M174 0v1098h148l22 -201h8q23 41 54 84q27 39 63.5 69.5t79.5 49t100 18.5q41 0 66 -2q43 -4 61 -8l-24 -168q-20 4 -58 8q-41 4 -55 4q-57 0 -115 -26q-53 -25 -90 -72q-35 -43 -57 -115q-20 -63 -21 -147v-592h-182z" />
+<glyph unicode="s" horiz-adv-x="923" d="M90 49v166q20 -10 70 -31q45 -18 80 -28q43 -12 86 -19q57 -8 88 -8q72 0 110 10q47 12 74 33q31 25 41 49q14 37 14 65.5t-10 55.5t-37 51q-31 27 -71 49q-37 20 -119 56q-71 31 -129.5 61.5t-98.5 67.5q-41 39 -61 84q-20 47 -21 116q0 72 27 125q25 51 78 90t121 58 q70 18 155 18q100 0 177 -20q86 -23 153 -56l-63 -147q-80 35 -133 51q-63 20 -140 21q-104 0 -151 -33q-49 -33 -49 -96q0 -37 12 -62q16 -31 39 -49q18 -14 76 -45q53 -29 116 -53q102 -45 129 -60q57 -33 97 -67q40 -37 61 -86q20 -47 20 -115q0 -76 -28 -139 q-27 -59 -84 -101q-55 -41 -131 -61q-74 -20 -174 -20q-111 0 -187 18q-84 20 -137 51z" />
+<glyph unicode="t" horiz-adv-x="692" d="M33 961v81l155 78l78 230h105v-252h276v-137h-276v-637q0 -92 32 -146q31 -49 103 -49q27 0 41 2q6 0 20.5 2t22.5 2l20.5 5t18.5 3q16 2 26 7v-138q-14 -6 -32 -12q-29 -8 -45 -10q-8 -2 -24.5 -4t-25.5 -4q-16 -2 -51 -2q-59 0 -115 16q-52 15 -92 55q-39 39 -59 105 q-23 72 -23 168v637h-155z" />
+<glyph unicode="u" horiz-adv-x="1204" d="M164 381v717h182v-707q0 -129 53.5 -194.5t163.5 -65.5q76 0 135 27q55 25 90 75q31 43 48 125q14 70 14 170v570h182v-1098h-147l-27 147h-10q-27 -45 -60 -75q-29 -25 -75 -52q-40 -22 -86 -30q-51 -10 -95 -10q-88 0 -159 22q-68 23 -117 74q-41 45 -68 125 q-24 78 -24 180z" />
+<glyph unicode="v" horiz-adv-x="980" d="M0 1098h188l199 -611q6 -18 27 -86l28 -104q6 -25 14.5 -51.5t14.5 -50.5q14 -57 16 -74h7l18 74q16 66 27 102l28 104q20 68 27 86l199 611h188l-375 -1098h-231z" />
+<glyph unicode="w" horiz-adv-x="1527" d="M20 1098h191l131 -584l9 -44l11 -54q12 -63 19 -103q14 -76 16 -98q2 -12 5.5 -37.5t5.5 -36.5h6q2 14 6 31.5t8 38.5q9 43 18 92q6 27 12.5 50.5t10.5 45.5q4 14 11 41t9 39l179 619h196l172 -619q8 -35 21 -80q10 -37 22 -94q4 -14 21 -92q8 -41 12 -72h6q2 8 5 33 t5 37q10 68 15 94q2 16 9 51l11 56q12 68 21 102l137 584h186l-284 -1098h-215l-168 616q-2 12 -11 41q-4 14 -12 48l-12 51l-12 51l-29 119h-6l-27 -121l-12 -53.5t-12 -49.5q-18 -76 -23 -90l-172 -612h-211z" />
+<glyph unicode="x" horiz-adv-x="1024" d="M35 0l373 563l-353 535h207l250 -410l250 410h207l-355 -535l373 -563h-207l-268 436l-270 -436h-207z" />
+<glyph unicode="y" horiz-adv-x="999" d="M10 1098h189l215 -613l28 -84q8 -20 27 -88q14 -49 23 -86q8 -39 12 -75h6l6 25l10 42q10 43 25 92q16 66 27 97q8 27 15 46t11 33l199 611h188l-434 -1241q-29 -82 -61 -146q-35 -68 -74 -108q-41 -43 -103 -70q-57 -25 -137 -25q-66 0 -90 5q-41 6 -65 12v145 q16 -4 53 -8q41 -4 67 -4q49 0 82 12q41 14 62 33q27 25 45 53q12 20 33 74l57 160z" />
+<glyph unicode="z" horiz-adv-x="901" d="M82 0v125l536 836h-503v137h688v-146l-524 -815h542v-137h-739z" />
+<glyph unicode="{" horiz-adv-x="724" d="M61 492v155q126 0 191 43q66 43 65 146v333q0 80 27 134q27 51 74 90q43 35 114 51q78 18 142 18v-149q-27 0 -72 -8q-37 -6 -55 -23q-23 -20 -35 -49q-12 -31 -12 -78v-332q0 -102 -60 -166q-57 -59 -174 -82v-12q117 -23 174 -82q59 -63 60 -166v-331q0 -47 12 -78 q12 -29 35 -49q18 -16 55 -23q45 -8 72 -8v-150q-72 0 -142 17q-68 16 -114 53q-47 39 -74 90q-27 53 -27 133v334q0 102 -65 146q-65 43 -191 43z" />
+<glyph unicode="|" d="M489 -492v2048h150v-2048h-150z" />
+<glyph unicode="}" horiz-adv-x="724" d="M51 -174q27 0 72 8q37 6 55 23q23 20 35 49q12 31 12 78v331q0 102 60 166q57 59 174 82v12q-117 23 -174 82q-59 63 -60 166v332q0 47 -12 78q-12 29 -35 49q-18 16 -55 23q-45 8 -72 8v149q63 0 142 -18q72 -16 114 -51q47 -39 74 -90q27 -53 27 -134v-333 q0 -49 16 -88q14 -35 49 -58q39 -25 82 -33q55 -10 109 -10v-155q-126 0 -191 -43q-66 -43 -65 -146v-334q0 -80 -27 -133q-27 -51 -74 -90q-47 -37 -114 -53q-70 -16 -142 -17v150z" />
+<glyph unicode="~" d="M102 586v162q102 109 248 108q37 0 53.5 -2t53.5 -10q28 -6 61 -19q43 -16 80 -32.5t64 -26.5q29 -12 51 -18q16 -4 45 -9q14 -2 41 -2q23 0 57 11q31 9 62 24q20 10 57 39q18 14 51 47v-162q-98 -109 -248 -108q-37 0 -53 2t-53 10q-28 6 -62 18q-43 16 -80 33l-65 27 q-28 12 -49 18q-14 4 -43 9q-14 2 -43 2q-31 0 -58 -9q-14 -4 -59 -26q-20 -10 -57 -39q-29 -22 -54 -47z" />
+<glyph unicode="&#xa2;" d="M188 743q0 143 27 242q31 111 74 170q49 68 119 105q76 39 155 51v172h137v-164q72 -4 140 -19q53 -12 114 -40l-53 -154q-37 16 -51 20q-37 12 -57 17q-4 0 -26 5t-34 7q-41 4 -55 4q-160 0 -229 -100q-72 -102 -72 -313t72 -308q74 -98 221 -98q84 0 147 18 q61 18 119 43v-161q-49 -28 -105 -43q-47 -12 -131 -17v-200h-137v206q-88 12 -155 50q-72 39 -119 104q-53 72 -76 166q-25 98 -25 237z" />
+<glyph unicode="&#xa3;" d="M68 0v154q51 14 82 32q35 20 61 54q29 35 43 82q14 45 14 116v213h-198v137h198v324q0 92 29 156q33 74 82 116q53 47 127 72t160 25q102 0 192 -23q84 -20 154 -57l-66 -144q-53 27 -127 49.5t-145 22.5q-41 0 -88 -14q-41 -12 -72 -43q-33 -33 -47 -76 q-16 -49 -16 -113v-295h376v-137h-376v-211q0 -72 -11 -106q-12 -45 -32 -78q-18 -29 -46 -53q-27 -23 -51 -37h748v-166h-991z" />
+<glyph unicode="&#xa5;" d="M29 1462h192l342 -739l346 739h191l-385 -768h239v-137h-301v-158h301v-137h-301v-262h-178v262h-301v137h301v158h-301v137h234z" />
+<glyph unicode="&#xa9;" horiz-adv-x="1703" d="M100 731q0 109 27 201q29 98 76 178q53 90 116.5 153.5t153.5 116.5q80 47 178 76q92 27 201 27t201 -27q98 -29 178 -76q90 -53 153.5 -116.5t116.5 -153.5q47 -80 76 -178q27 -92 27 -200.5t-27 -201.5q-29 -98 -76 -178q-53 -90 -116.5 -153.5t-153.5 -116.5 q-80 -47 -178 -76q-92 -27 -201 -26.5t-201 26.5q-98 29 -178 76q-90 53 -153.5 116.5t-116.5 153.5q-47 80 -76 178q-27 92 -27 201zM209 731q0 -129 51 -250q49 -117 137 -205t205 -137q121 -51 250 -51t250 51q117 49 205 137.5t137 204.5q51 121 51 250t-51 250 q-49 117 -137 205t-205 137q-121 51 -250 51t-250 -51q-117 -49 -205 -137t-137 -205q-51 -121 -51 -250zM479 733q0 104 27 185q27 82 80 143q51 59 129 94q74 33 176 33q59 0 129 -17q59 -14 125 -45l-62 -127q-47 23 -100 39q-45 14 -92 15q-59 0 -108.5 -22.5 t-77.5 -63.5q-37 -51 -50 -101q-16 -66 -16 -135q0 -80 14 -137q16 -66 45 -102q31 -39 78 -62q49 -23 115 -22q12 0 49 4q23 2 57 10q37 8 56 14q8 2 26.5 7.5t26.5 9.5v-131q-16 -8 -49 -21q-18 -8 -51 -14q-39 -8 -56 -11q-41 -4 -65 -4q-104 0 -178 33q-80 35 -127 94 q-53 68 -76 146q-25 86 -25 188z" />
+<glyph unicode="&#xad;" horiz-adv-x="657" d="M82 465v168h496v-168h-496z" />
+<glyph unicode="&#xae;" horiz-adv-x="1703" d="M100 731q0 109 27 201q29 98 76 178q53 90 116.5 153.5t153.5 116.5q80 47 178 76q92 27 201 27t201 -27q98 -29 178 -76q90 -53 153.5 -116.5t116.5 -153.5q47 -80 76 -178q27 -92 27 -200.5t-27 -201.5q-29 -98 -76 -178q-53 -90 -116.5 -153.5t-153.5 -116.5 q-80 -47 -178 -76q-92 -27 -201 -26.5t-201 26.5q-98 29 -178 76q-90 53 -153.5 116.5t-116.5 153.5q-47 80 -76 178q-27 92 -27 201zM209 731q0 -129 51 -250q49 -117 137 -205t205 -137q121 -51 250 -51t250 51q117 49 205 137.5t137 204.5q51 121 51 250t-51 250 q-49 117 -137 205t-205 137q-121 51 -250 51t-250 -51q-117 -49 -205 -137t-137 -205q-51 -121 -51 -250zM586 285v893h233q166 0 248 -66q78 -63 78 -199q0 -43 -15 -86q-12 -37 -34 -65q-18 -25 -52 -49q-25 -18 -59 -33l121 -197l43 -73l37 -64q16 -29 26 -45l11 -16 h-179l-206 352h-95v-352h-157zM743 768h72q90 0 131 37q39 37 39 104q0 74 -41 103q-43 31 -131 30h-70v-274z" />
+<glyph unicode="&#xb4;" horiz-adv-x="1181" d="M393 1241v27l45 67l22.5 36t24.5 42q8 12 45 82q22 40 37 74h219v-21q-12 -23 -47 -67q-31 -39 -71 -84l-78 -86q-29 -33 -76 -70h-121z" />
+<glyph unicode="&#x2000;" horiz-adv-x="782" />
+<glyph unicode="&#x2001;" horiz-adv-x="1568" />
+<glyph unicode="&#x2002;" horiz-adv-x="782" />
+<glyph unicode="&#x2003;" horiz-adv-x="1568" />
+<glyph unicode="&#x2004;" horiz-adv-x="522" />
+<glyph unicode="&#x2005;" horiz-adv-x="391" />
+<glyph unicode="&#x2006;" horiz-adv-x="260" />
+<glyph unicode="&#x2007;" horiz-adv-x="260" />
+<glyph unicode="&#x2008;" horiz-adv-x="194" />
+<glyph unicode="&#x2009;" horiz-adv-x="311" />
+<glyph unicode="&#x200a;" horiz-adv-x="86" />
+<glyph unicode="&#x2010;" horiz-adv-x="657" d="M82 465v168h496v-168h-496z" />
+<glyph unicode="&#x2011;" horiz-adv-x="657" d="M82 465v168h496v-168h-496z" />
+<glyph unicode="&#x2012;" horiz-adv-x="657" d="M82 465v168h496v-168h-496z" />
+<glyph unicode="&#x2013;" horiz-adv-x="1024" d="M82 465v168h860v-168h-860z" />
+<glyph unicode="&#x2014;" horiz-adv-x="2048" d="M82 465v168h1884v-168h-1884z" />
+<glyph unicode="&#x2018;" horiz-adv-x="356" d="M23 983l18 61l16 54q12 41 41 123l49 122l52 119h137q-6 -23 -15.5 -65.5l-13.5 -61.5q-18 -78 -28 -131q-4 -20 -11.5 -63l-11.5 -66q-2 -10 -20 -114h-199z" />
+<glyph unicode="&#x2019;" horiz-adv-x="356" d="M23 961q10 39 28 126l29 132l24 129l10.5 62.5l8.5 51.5h199l14 -22l-33 -115q-18 -61 -43 -123l-49 -125q-6 -16 -51 -116h-137z" />
+<glyph unicode="&#x201c;" horiz-adv-x="741" d="M23 983l18 61l16 54q12 41 41 123l49 122l52 119h137q-6 -23 -15.5 -65.5l-13.5 -61.5q-18 -78 -28 -131q-4 -20 -11.5 -63l-11.5 -66q-2 -10 -20 -114h-199zM408 983l18 61l16 54q12 41 41 123l49 122l52 119h137q-6 -23 -15.5 -65.5l-13.5 -61.5q-18 -78 -28 -131 l-25 -129q-4 -23 -10 -62.5t-8 -51.5h-199z" />
+<glyph unicode="&#x201d;" horiz-adv-x="741" d="M23 961q10 39 28 126l29 132l24 129l10.5 62.5l8.5 51.5h199l14 -22l-33 -115q-18 -61 -43 -123l-49 -125q-6 -16 -51 -116h-137zM408 961q10 39 28 126l29 132l24 129l10.5 62.5l8.5 51.5h199l14 -22l-33 -115q-18 -61 -43 -123l-49 -125q-6 -16 -51 -116h-137z" />
+<glyph unicode="&#x2022;" horiz-adv-x="768" d="M150 748q0 72 18 120q20 53 49 82t76 45q41 14 92 14.5t92 -14.5q47 -16 76 -44.5t49 -82.5q18 -49 19 -120q0 -70 -19 -119q-20 -53 -49 -82q-31 -31 -76 -47q-41 -14 -92 -14.5t-92 14.5q-45 16 -76 47q-29 29 -49 82q-18 49 -18 119z" />
+<glyph unicode="&#x2026;" horiz-adv-x="1646" d="M147 111q0 35 11 65q10 29 26 43q20 16 39 23q29 8 51 8q16 0 50 -8q20 -4 41 -23q16 -14 26 -43q10 -31 10 -65q0 -33 -10 -64q-8 -25 -26 -43q-14 -14 -41 -24q-23 -8 -50 -9q-33 0 -51 9q-25 10 -39 24q-18 18 -26 43q-11 31 -11 64zM696 111q0 35 11 65q10 29 26 43 q20 16 39 23q29 8 51 8q16 0 49 -8q20 -4 41 -23q16 -14 27 -43q10 -31 10 -65q0 -33 -10 -64q-8 -25 -27 -43q-14 -14 -41 -24q-23 -8 -49 -9q-33 0 -51 9q-25 10 -39 24q-18 18 -26 43q-11 31 -11 64zM1245 111q0 35 10 65q10 29 27 43q20 16 41 23q29 8 49 8q16 0 49 -8 q20 -4 41 -23q16 -14 27 -43q10 -31 10 -65q0 -33 -10 -64q-8 -25 -27 -43q-14 -14 -41 -24q-23 -8 -49 -9q-55 0 -90 33q-37 33 -37 107z" />
+<glyph unicode="&#x202f;" horiz-adv-x="311" />
+<glyph unicode="&#x205f;" horiz-adv-x="391" />
+<glyph unicode="&#x20ac;" d="M63 502v137h148q-2 14 -2 39v43q0 8 1 22.5t1 22.5v31h-148v137h160q18 123 62 225q43 100 112 174q70 72 158 111q90 39 207 39q100 0 176 -21q78 -20 160 -71l-80 -146q-57 33 -111 53q-55 20 -131 21q-66 0 -129 -27q-55 -23 -104 -76t-82 -120.5t-51 -161.5h432v-137 h-447q0 -6 -1 -14.5t-1 -14.5v-25v-22v-39q0 -29 2 -43h385v-137h-366q33 -172 127 -266q92 -92 241 -93q70 0 142 17q66 14 127 41v-162q-59 -29 -125 -43q-72 -16 -158 -16q-115 0 -207 36q-88 35 -158 105q-68 68 -110 164q-45 98 -66 217h-164z" />
+<glyph unicode="&#x2122;" horiz-adv-x="1533" d="M37 1354v108h522v-108h-199v-613h-127v613h-196zM625 741v721h186l180 -551l191 551h178v-721h-127v428v25q0 4 1 14.5t1 16.5v35q0 6 1 16t1 14h-6l-195 -549h-100l-186 549h-7q0 -8 1 -16t1 -17q0 -6 1.5 -17t1.5 -15v-27v-18v-439h-123z" />
+<glyph unicode="&#xe000;" horiz-adv-x="1100" d="M0 1100h1100v-1100h-1100v1100z" />
+<glyph unicode="&#xfb01;" horiz-adv-x="1202" d="M29 961v75l194 68v96q0 104 23 178q20 68 65 113q41 41 105 59q55 16 139 17q68 0 109 -11q53 -14 88 -26l-47 -141q-25 10 -68 20q-33 8 -76 8q-39 0 -69.5 -10t-47.5 -33q-20 -27 -28 -65q-10 -47 -10 -107v-104h245v-137h-245v-961h-183v961h-194zM834 1395 q0 59 30 88q29 27 76 26q23 0 41 -6q20 -8 35 -20q12 -12 23 -37q8 -18 8 -51q0 -58 -31 -86q-33 -29 -76 -29t-76 29q-30 28 -30 86zM848 0v1098h182v-1098h-182z" />
+<glyph unicode="&#xfb02;" horiz-adv-x="1202" d="M29 961v75l194 68v96q0 104 23 178q20 68 65 113q41 41 105 59q55 16 139 17q68 0 109 -11q53 -14 88 -26l-47 -141q-25 10 -68 20q-33 8 -76 8q-39 0 -69.5 -10t-47.5 -33q-20 -27 -28 -65q-10 -47 -10 -107v-104h245v-137h-245v-961h-183v961h-194zM848 0v1556h182 v-1556h-182z" />
+<glyph unicode="&#xfb03;" horiz-adv-x="1875" d="M29 961v75l194 68v96q0 104 23 178q20 68 65 113q41 41 105 59q55 16 139 17q68 0 109 -11q53 -14 88 -26l-47 -141q-25 10 -68 20q-33 8 -76 8q-39 0 -69.5 -10t-47.5 -33q-20 -27 -28 -65q-10 -47 -10 -107v-104h245v-137h-245v-961h-183v961h-194zM703 961v75l194 68 v96q0 104 23 178q20 68 65 113q41 41 105 59q55 16 139 17q68 0 109 -11q53 -14 88 -26l-47 -141q-25 10 -68 20q-33 8 -76 8q-39 0 -69.5 -10t-47.5 -33q-20 -27 -28 -65q-10 -47 -10 -107v-104h245v-137h-245v-961h-183v961h-194zM1508 1395q0 59 30 88q29 27 76 26 q23 0 41 -6q20 -8 35 -20q12 -12 23 -37q8 -18 8 -51q0 -58 -31 -86q-33 -29 -76 -29t-76 29q-30 28 -30 86zM1522 0v1098h182v-1098h-182z" />
+<glyph unicode="&#xfb04;" horiz-adv-x="1875" d="M29 961v75l194 68v96q0 104 23 178q20 68 65 113q41 41 105 59q55 16 139 17q68 0 109 -11q53 -14 88 -26l-47 -141q-25 10 -68 20q-33 8 -76 8q-39 0 -69.5 -10t-47.5 -33q-20 -27 -28 -65q-10 -47 -10 -107v-104h245v-137h-245v-961h-183v961h-194zM703 961v75l194 68 v96q0 104 23 178q20 68 65 113q41 41 105 59q55 16 139 17q68 0 109 -11q53 -14 88 -26l-47 -141q-25 10 -68 20q-33 8 -76 8q-39 0 -69.5 -10t-47.5 -33q-20 -27 -28 -65q-10 -47 -10 -107v-104h245v-137h-245v-961h-183v961h-194zM1522 0v1556h182v-1556h-182z" />
+</font>
+</defs></svg> 
\ No newline at end of file
diff --git a/pleaseshare/static/fonts/DroidSans-webfont.ttf b/pleaseshare/static/fonts/DroidSans-webfont.ttf
new file mode 100755 (executable)
index 0000000..9865c6b
Binary files /dev/null and b/pleaseshare/static/fonts/DroidSans-webfont.ttf differ
diff --git a/pleaseshare/static/fonts/DroidSans-webfont.woff b/pleaseshare/static/fonts/DroidSans-webfont.woff
new file mode 100755 (executable)
index 0000000..e382f72
Binary files /dev/null and b/pleaseshare/static/fonts/DroidSans-webfont.woff differ
diff --git a/pleaseshare/static/style.css b/pleaseshare/static/style.css
new file mode 100644 (file)
index 0000000..ec9e23b
--- /dev/null
@@ -0,0 +1,360 @@
+/* Reset */
+
+html, body {
+       margin: 0;
+       padding: 0;
+    text-align: justify;
+}
+
+
+/* Fonts */
+
+@font-face {
+  font-family: 'DroidSansRegular';
+  src: url('fonts/DroidSans-webfont.eot');
+  src:
+       url('fonts/DroidSans-webfont.eot?#iefix') format('embedded-opentype'),
+       url('fonts/DroidSans-webfont.woff') format('woff'),
+       url('fonts/DroidSans-webfont.ttf') format('truetype'),
+       url('fonts/DroidSans-webfont.svg#DroidSansRegular') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+@font-face {
+  font-family: 'DroidSansBold';
+  src: url('fonts/DroidSans-Bold-webfont.eot');
+  src:
+       url('fonts/DroidSans-Bold-webfont.eot?#iefix') format('embedded-opentype'),
+       url('fonts/DroidSans-Bold-webfont.woff') format('woff'),
+       url('fonts/DroidSans-Bold-webfont.ttf') format('truetype'),
+       url('fonts/DroidSans-Bold-webfont.svg#DroidSansBold') format('svg');
+  font-weight: normal;
+  font-style: normal;
+}
+
+
+/* General UI */
+
+html {
+       font: 16px 'DroidSansRegular', Helvetica, Arial, "Liberation Sans", FreeSans, sans-serif;
+}
+
+::selection {
+       background: orange;
+       color: #f5f5f5;
+       text-shadow: none;
+}
+
+::-moz-selection {
+       background: #dd8f00;
+       color: #f5f5f5;
+       text-shadow: none;
+}
+
+.right {
+       float: right;
+}
+
+.left {
+       float: left;
+}
+
+.center {
+       margin: auto;
+       display: block;
+       text-align: center;
+}
+
+.clear, .box div, .box section {
+       clear:both;
+       display: block;
+}
+
+.box section {
+       padding: 0.5em 0;
+}
+
+a {
+       text-decoration: none;
+       color: black;
+}
+
+h2 {
+       position: relative;
+       color: #fff;
+       font-size: 1.5em;
+       float: left;
+       clear: both;
+       padding: 10px 10px 10px 20px;
+       margin: 10px 20px 20px -26px;
+       -moz-box-shadow: 1px 2px 1px rgba(0,0,0,0.2);
+       -webkit-box-shadow: 1px 2px 1px rgba(0,0,0,0.2);
+       -o-box-shadow: 1px 2px 1px rgba(0,0,0,0.2);
+       box-shadow: 1px 2px 1px rgba(0,0,0,0.2);
+       background-color: orange;
+}
+h2:before {
+       content: "";
+       position: absolute;
+       bottom: -10px;
+       left: 0px;
+       border: 5px solid #f68335;
+       border-bottom: 5px solid transparent;
+       border-left: 5px solid transparent;     
+}
+
+p {
+       clear: both;
+       text-align: justify;
+}
+
+p a {
+       color: #0A0A2E;
+       border-bottom: 1px dotted #DD8F6F;
+}
+
+pre {
+       margin: auto;
+       padding: 0.5em;
+    overflow: auto;
+       background: #ddd;
+       color: #555;
+       width: 450px;
+}
+
+
+/* Header */
+
+header {
+       font-family: "Lucida Sans", "Lucida Grande", "Lucida Sans Unicode", Arial, sans-serif;
+       padding: 0.5em;
+       margin: 0;
+       background-color: orange;
+       -webkit-box-shadow: 1px 1px 3px #999;
+          -moz-box-shadow: 1px 1px 3px #999;
+               box-shadow: 1px 1px 3px #999;
+}
+
+header .right {
+       padding-top: .3em;
+       color: #d98c00;
+}
+
+header .right a {
+       text-transform: uppercase;
+       font-weight: bold;
+       color: #976100;
+       
+}
+
+header .right a:hover {
+       text-decoration: none;
+       color: #fff;
+}
+
+header h1 {
+       font-size: 3em;
+       margin: 0;
+
+}
+
+header h1 a {
+       color: rgba(120,120,120, 0.6);
+    text-shadow: 0.5px 2px 3px orange, 0 0 0 #000, 0.5px 1px 2.5px #fff;
+}
+
+header h1 a:hover {
+       text-decoration: none;
+       color: rgba(100,100,100, 0.6);
+}
+
+/* Box content */
+
+section.box {
+       padding: 1em;
+       background: #f5f5f5;
+       width: 600px;
+       margin: 50px auto;
+       border-radius: 4px;
+       -webkit-box-shadow: 1px 1px 5px #ccc;
+       -moz-box-shadow: 1px 1px 5px #ccc;
+       box-shadow: 1px 1px 5px #ccc;
+}
+
+#options {
+       border: 1px solid #ccc;
+       -webkit-box-shadow: inset 1px 1px 5px #ddd;
+       -moz-box-shadow: inset 1px 1px 5px #ddd;
+       box-shadow: inset 1px 1px 5px #ddd;
+       display: none;
+    margin: auto;
+    width: 95%;
+       padding: 1em;
+       margin-top: 10px;
+       text-align: left;
+       border-radius: 2px;
+       -moz-border-radius: 2px;
+       -webkit-border-radius: 2px;
+}
+
+#options:target {
+       display: table;
+}
+
+#send {
+       margin-top: 1em;
+}
+
+.info-ok, .info-important, .info {
+       -webkit-box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
+       -moz-box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
+       box-shadow: inset 0 0 10px rgba(0,0,0,0.5);
+       padding: 0.5em;
+    text-align: center;
+}
+
+.info-important {
+       background: rgba(255, 7, 0, 0.5);
+       color: #fff;
+    text-align: center;
+}
+
+.info-ok {
+       background: rgba(103, 228, 111, 0.5);
+       color: #555;
+}
+
+dl {
+  background: #f5f5f5;
+  padding: 0.5em;
+  margin-bottom: 1em;
+}
+
+dl dt {
+  float: left;
+  clear: left;
+  width: 160px;
+  text-align: right;
+  font-weight: bold;
+}
+
+dl dt:after {
+  content: ":";
+}
+dl dt.link:after {
+    content: "";
+}
+
+dl > dd > input {
+    width: 300px !important;
+}
+
+dl dd {
+  margin: 0 0 0 170px;
+  padding: 0 0 0.5em 0;
+}
+
+
+#options p {
+    display: table-row;
+    margin: auto;
+    clear: both;
+}
+
+#options label {
+    display: table-cell;
+    vertical-align: middle;
+}
+#options input, #options textarea {
+    display: table-cell;
+    margin: 5px;
+    width: 90%;
+}
+
+/* View page */
+
+
+#delete, #delete * {
+       display: inline;
+}
+
+
+/* Gradient */
+
+.box-gradient {
+       position: absolute;
+       width: 100%;
+       min-height: 100%;
+       background: -moz-linear-gradient(left, #CCCCCC 0%, #EEEEEE 50%, #EEEEEE 50%, #CCCCCC 100%);
+       background: -webkit-gradient(linear, left top, right top, color-stop(0%,#CCCCCC),color-stop(50%,#EEEEEE), color-stop(50%,#EEEEEE), color-stop(100%,#CCCCCC));
+}
+
+.box-shadow {
+       position: absolute;
+       left: 50%;
+       margin: 400px 0 0 -290px;
+       bottom: 10px;
+       width: 580px;
+       height: 16px;
+       background: #fff;
+       border-radius: 290px / 8px;
+       -moz-border-radius: 290px / 8px;
+       -webkit-border-radius: 290px / 8px;
+       box-shadow: 0 10px 20px #000;
+       -moz-box-shadow: 0 10px 20px #000;
+       -webkit-box-shadow: 0 10px 20px #000;
+}
+
+
+/* Inputs */
+
+textarea {
+       width: 99%;
+       margin: auto;
+}
+
+input, .button, textarea, select {
+       font-size: 11px;
+       background: #fff;
+       border: 1px solid #ccc;
+       -moz-border-radius: 2px;
+       -webkit-border-radius: 2px;
+       -o-border-radius: 2px;
+       border-radius: 2px;
+}
+
+input[type=text], input[type=password], input[type=file], textarea {
+       box-shadow: 0 1px 2px rgba(0, 0, 0, .15) inset;
+       padding: 0.5em;
+}
+
+input:focus, select:focus, textarea:focus {
+       border: 1px solid #aaa;
+       outline: none;
+}
+
+input[type=submit], .button {
+       background: #eaeaea;
+       background: -webkit-gradient(linear, left top, left bottom, from(#efefef), to(#d8d8d8)) #d8d8d8;
+       background: -moz-linear-gradient(top, #efefef, #d8d8d8) #d8d8d8;
+       border: 1px solid #ababab;
+       box-shadow: 0 1px 2px rgba(0, 0, 0, .1), 0 1px 1px rgba(255, 255, 255, .8) inset;
+       margin: 0;
+       padding: 5px 10px;
+       text-shadow: 0 1px 1px rgba(255, 255, 255, .5);
+       cursor: pointer;
+}
+
+input[type=submit]:hover, input[type=button]:hover, .button:hover {
+       color: #666;
+}
+a.button:hover {
+       border-bottom: 1px solid #ababab;
+}
+
+.button:active, .button:focus, input[type=submit]:active, input[type=submit]:focus, input[type=button]:active, input[type=button]:focus {
+       background: #eee;
+       border-color: #999;
+}
diff --git a/pleaseshare/static_routes.py b/pleaseshare/static_routes.py
new file mode 100644 (file)
index 0000000..fec0aeb
--- /dev/null
@@ -0,0 +1,32 @@
+"""
+Static routes that do not need the application object to work
+"""
+
+import flask
+
+static_pages = flask.Blueprint('static', __name__,
+                               template_folder='templates')
+
+@static_pages.route("/about")
+def about():
+    """About page"""
+    return flask.render_template("about.html")
+
+@static_pages.route("/contact")
+def contact():
+    """Contact page"""
+    return flask.render_template("contact.html")
+
+@static_pages.route("/tos")
+def tos():
+    """Terms of service"""
+    return flask.render_template("tos.html")
+
+@static_pages.route("/help")
+def help():
+    """Help"""
+    return flask.render_template("help.html")
+
+
+
+
diff --git a/pleaseshare/tasks.py b/pleaseshare/tasks.py
new file mode 100644 (file)
index 0000000..eeb95ee
--- /dev/null
@@ -0,0 +1,247 @@
+"""
+Tasks module:
+archive extraction, introspection, POST parameters parsing,
+torrent creation.
+"""
+from os import mkdir, remove, chmod
+from os.path import abspath, basename, dirname, isdir, join as joinpath, realpath
+from shutil import rmtree
+import tarfile
+import zipfile
+import logging
+from functools import singledispatch
+
+log = logging.getLogger(__name__)
+
+from collections import namedtuple
+PostParams = namedtuple('PostParams',
+                        'extract trackers webseeds private '
+                        'uploader password description')
+
+from pleaseshare.torrent import maketorrent
+
+class BadArchive(Exception):
+    """
+    Raised when an archive tries to make a symlink or a relative
+    path outside of its directory.
+    """
+
+class Archive(object):
+    """
+    Wrapper around an archive File type (currently tarfile or zipfile)
+    """
+
+    def __init__(self, location: str, allow_compressed=False):
+
+        self._archive_name = basename(location)
+        self._extracted_name = self._archive_name.split('.')[0]
+        self._dirname = dirname(location)
+
+        if not allow_compressed:
+            self._file = tarfile.TarFile.open(location, mode='r:')
+        else:
+            for ext in ('.tar', '.tar.gz', '.tar.bz2', '.tar.lzma', '.tar.xz'):
+                if self._archive_name.endswith(ext):
+                    self._file = tarfile.TarFile.open(location, mode='r')
+                    break
+            else:
+                self._file = zipfile.ZipFile(location, mode='r')
+
+    def extract(self) -> bool:
+        """
+        Extract the archive
+        returns True if it succeeded, False otherwise
+        """
+        return extract(self._file, joinpath(self._dirname, self._archive_name), self.extracted_location())
+
+    def extracted_name(self) -> str:
+        """Name of the extracted directory"""
+        return self._extracted_name
+
+    def extracted_location(self) -> str:
+        """Path of the extracted directory"""
+        return joinpath(self._dirname, self._extracted_name)
+
+    def archive_location(self) -> str:
+        """Path to the archive"""
+        return joinpath(self._dirname, self._archive_name)
+
+    def size(self) -> int:
+        """Total size of the uncompressed archive"""
+        return size(self._file)
+
+@singledispatch
+def extract(archivefile, name, rep):
+    """To override"""
+    raise NotImplementedError()
+
+@extract.register(tarfile.TarFile)
+def _extract_tar(archivefile: tarfile.TarFile, name: str, rep: str) -> bool:
+    """Extract a tar archive """
+    mkdir(rep, mode=0o711)
+    if not check_archive(archivefile):
+        raise BadArchive("malicious archive")
+    try:
+        for member in archivefile:
+            archivefile.extract(member, rep, set_attrs=False)
+            member_location = joinpath(rep, member.name)
+            # python has no option to use umask while extracting, so…
+            if isdir(member_location):
+                chmod(member_location, 0o711)
+            else:
+                chmod(member_location, 0o644)
+    except: # extraction failed, remove leftover files
+        log.info('Extraction of %s failed, falling back to single-file upload', name, exc_info=True)
+        rmtree(rep)
+        return False
+    else: # remove old tar file
+        remove(name)
+        log.info('Successfully extracted tarfile %s into %s', name, rep)
+        return True
+
+@extract.register(zipfile.ZipFile)
+def _extract_zip(archivefile: zipfile.ZipFile, name: str, rep: str) -> bool:
+    """Extracts a zip file"""
+    mkdir(rep, mode=0o711)
+    try:
+        for member in archivefile.infolist():
+            # zipfile member names are sanitized
+            archivefile.extract(member, rep)
+            member_location = joinpath(rep, member.filename)
+            # python has no option to use umask while extracting, so…
+            if isdir(member_location):
+                chmod(member_location, 0o711)
+            else:
+                chmod(member_location, 0o644)
+    except: # extraction failed, remove leftover files
+        import traceback
+        traceback.print_exc()
+        log.info('Extraction of %s failed, falling back to single-file upload',
+                 name, exc_info=True)
+        rmtree(rep)
+        return False
+    else:
+        remove(name)
+        log.info('Successfully extracted zipfile %s into %s', name, rep)
+        return True
+
+
+@singledispatch
+def size(archivefile):
+    """To override"""
+    raise NotImplementedError()
+
+@size.register(zipfile.ZipFile)
+def _size_zip(archivefile: zipfile.ZipFile) -> int:
+    """Get the size of the uncompressed zip"""
+    size_sum = 0
+    for member in archivefile.infolist():
+        size_sum += member.file_size
+    return size_sum
+
+@size.register(tarfile.TarFile)
+def _size_tar(archivefile: tarfile.TarFile) -> int:
+    """Get the size of the uncompressed tar"""
+    size_sum = 0
+    for member in archivefile:
+        size_sum += member.size
+    return size_sum
+
+def resolved(path_: str) -> str:
+    """Returns the absolute path"""
+    return realpath(abspath(path_))
+
+def badpath(path: str, base: str) -> bool:
+    """Returns True if a path is outside of the base directory"""
+    return not resolved(joinpath(base, path)).startswith(base)
+
+def badlink(info: tarfile.TarInfo, base: str) -> bool:
+    """Resolve sym/hardlinks and perform a badpath check"""
+    tip = resolved(joinpath(base, dirname(info.name)))
+    return badpath(info.linkname, base=tip)
+
+def check_archive(tar_archive: tarfile.TarFile) -> bool:
+    """Check a tar archive to make sure it is not malicious"""
+    base = dirname(tar_archive)
+
+    for file_info in tar_archive:
+        if badpath(file_info.name, base):
+            log.error('illegal path for file %s', file_info.name)
+            return False
+        elif file_info.issym() and badlink(file_info, base):
+            log.error('File %s is a hard link to %s', file_info.name,
+                      file_info.linkname)
+            return False
+        elif file_info.islnk() and badlink(file_info, base):
+            log.error('File %s is a symlink to %s', file_info.name,
+                      file_info.linkname)
+            return False
+    return True
+
+def create_torrent(data_path, comment='', webseeds=None, trackers=None, private=False):
+    """Create a new torrent object"""
+    torrent = maketorrent.TorrentMetadata()
+    torrent.piece_size = 256
+    torrent.data_path = data_path
+    torrent.comment = comment
+    torrent.webseeds = webseeds
+    if trackers:
+        torrent.trackers = trackers
+        if private:
+            torrent.private = private
+    return torrent
+
+def remove_empty_str(list_: list) -> list:
+    """remove empty strings from a list"""
+    return [x for x in list_ if x.strip()]
+
+def format_trackers(tab: list) -> list:
+    """create a list of lists of trackers, for use with the torrent API"""
+    trackers = []
+    for i in tab:
+        trackers.append([i])
+    return trackers
+
+def parse_form(form, config) -> PostParams:
+    """
+    Create an object summarizing the options for the torrent
+    creation.
+    """
+    if config['ALLOW_MULTIFILE']:
+        extract_ = form.extract.data
+    else:
+        extract_ = False
+
+    if config['ALLOW_TRACKERS']:
+        trackers = form.trackers.data.split('\n')[:50]
+        trackers = remove_empty_str(trackers)
+        trackers.extend(config['MANDATORY_TRACKERS'])
+        trackers = format_trackers(trackers)
+    else:
+        if not config['MANDATORY_TRACKERS']:
+            trackers = []
+        else:
+            trackers = format_trackers(config['MANDATORY_TRACKERS'])
+
+    if config['ALLOW_WEBSEEDS']:
+        webseeds = form.webseeds.data.split('\n')[:50]
+        webseeds = remove_empty_str(webseeds)
+    else:
+        webseeds = []
+
+    if config['ALLOW_PRIVATE']:
+        private = form.private.data
+        if private and trackers:
+            private = True
+        else:
+            private = False
+    else:
+        private = False
+
+    uploader = form.uploader_name.data
+    password = form.deletion_password.data
+    description = form.description.data
+
+    return PostParams(extract_, trackers, webseeds, private,
+                      uploader, password, description)
+
diff --git a/pleaseshare/templates/about.html b/pleaseshare/templates/about.html
new file mode 100644 (file)
index 0000000..13168a9
--- /dev/null
@@ -0,0 +1,36 @@
+{% extends "base.html" %}
+
+{% block title %}
+PleaseShare - {{ _('About') }}
+{% endblock %}
+
+{% block body %}
+<div id="infos">
+    <h2>{{ _('What is pleaseshare?') }}</h2>
+    <p>
+    {{ _('Pleaseshare is a file-sharing website, with "sharing" as its core value.') }}
+    </p>
+    <p>
+    {{ _('It means that there won’t be a direct link on your file once you upload it, but pleaseshare
+    will generate a torrent for you, with a webseed. Therefore, people who download the file will
+    always get the best speed available (since there is a webseed, it will be at worst the same
+    speed as if they downloaded it directly via http). It also means that the uploader can use this
+    torrent to seed the file that is already on his computer, thus increasing the download speed for
+    people on the other end.') }}
+    </p>
+    <h2>{{ _('Things to know') }}</h2>
+    <p>
+    {{ _('Please note that pleaseshare relies on the Bittorent DHT, which means that no trackers
+    are needed to get peers.') }}
+    {% if config.ALLOW_TRACKERS %} {{ _('You can provide trackers if you want, but you don’t have to.') }} {% endif %}
+    {% if config.MANDATORY_TRACKERS %} {{ _('Trackers will be added by the server even if you don’t add them.') }} {% endif %}
+    <p>
+    {{ _('You must also understand that, even if pleaseshare allows you to delete the files that you upload on this server, the torrent can still stay active without a webseed.') }}
+    </p>
+    <h2>{{ _('Licence') }}</h2>
+    <p>
+    {{ _('Pleaseshare is licenced under the AGPL v3, with some GPL bits coming from the deluge client.
+    And the source is <a href="https://gitorious.org/pleaseshare" title="pleaseshare source">on gitorious</a>.') }}
+    </p>
+</div>
+{% endblock %}
diff --git a/pleaseshare/templates/base.html b/pleaseshare/templates/base.html
new file mode 100644 (file)
index 0000000..2ccac48
--- /dev/null
@@ -0,0 +1,47 @@
+<!DOCTYPE HTML>
+<html>
+    <head>
+        <title>{% block title %}PleaseShare{% endblock %}</title>
+        <meta charset="utf-8"/>
+        <link rel="stylesheet" href="/static/style.css" type="text/css"/>
+    </head>
+    <body>
+        <div class="box-shadow"></div>
+        <div class="box-gradient">
+        <header>
+        {% block header %}
+            <section class="left">
+            <h1><a href="{{ url_for("dynamic.home") }}">PleaseShare</a></h1>
+            </section>
+            <section class="right">
+            <nav>
+                <a href="{{ url_for("static.help") }}" title="{{ _('Need help?') }}">{{ _('Need help?') }}</a> |
+                <a title="{{ _('About') }}" href="{{ url_for("static.about") }}">{{ _('About') }}</a> |
+                <a title="{{ _('Terms of Service') }}" href="{{ url_for("static.tos") }}">{{ _('ToS') }}</a> |
+                <a title="{{ _('Contact') }}" href="{{ url_for("static.contact") }}">{{ _('Contact') }}</a>
+            </nav>
+            </section>
+            <section class="clear"></section>
+        {% endblock %}
+        </header>
+        {% with errors = get_flashed_messages(category_filter=["error"]) %}
+            {% if errors %}
+                {%- for msg in errors %}
+                <p class="info-important">{{ msg }}</p>
+                {% endfor -%}
+            {% endif %}
+        {% endwith %}
+        {% with success = get_flashed_messages(category_filter=["success"]) %}
+            {% if success %}
+                {%- for msg in success %}
+                <p class="info-ok">{{ msg }}</p>
+                {% endfor -%}
+            {% endif %}
+        {% endwith %}
+
+        <section class="box">
+        {% block body %}{% endblock %}
+        </section>
+        </div>
+    </body>
+</html>
diff --git a/pleaseshare/templates/contact.html b/pleaseshare/templates/contact.html
new file mode 100644 (file)
index 0000000..01f8302
--- /dev/null
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+
+{% block title %}
+PleaseShare - {{ _('Contact') }}
+{% endblock %}
+
+{% block body %}
+<h2>{{ _('Contact') }}</h2>
+<div id="infos">
+    Add contact info here
+</div>
+{% endblock %}
diff --git a/pleaseshare/templates/help.html b/pleaseshare/templates/help.html
new file mode 100644 (file)
index 0000000..705ce13
--- /dev/null
@@ -0,0 +1,93 @@
+{% extends "base.html" %}
+{% block title %}
+Pleaseshare - {{ _('Help') }}
+{% endblock %}
+
+{% block body %}
+<div id="infos">
+    <h2>{{ _('I can only upload one file?') }}</h2>
+    <p>{{ _('Yes, at the moment, due to the limitations of html, it is impossible to upload
+    folders directly.') }}
+    {% if config.ALLOW_MULTIFILE %}
+    {{ _('However, if you upload an archive') }}
+    {% if config.ALLOW_COMPRESSED %}
+    {{ _(' (.zip/.tar, possibly compressed) ') }}
+    {% else %}
+    {{ _(' (.tar, uncompressed) ') }}
+    {% endif %}
+    {{ _('and toggle the option "Extract archive" the torrent will contain the files of
+    this archive, under a subdirectory named after the archive (minus the .extension part).') }}
+    {% endif %}
+    </p>
+    <h2>{{ _('I uploaded a file, what now?') }}</h2>
+    <p>{{ _('You can share it with your friends, of anyone, if you give them a link
+    to this page, to the torrent, or the magnet link.
+    You should also start the torrent into your favorite torrent client, this way,
+    you will be able to share it. If you don’t do that, the download speed for the
+    people who want download the file will be smaller.')}}
+    </p>
+    <h2>{{ _('How do I delete a file if I don’t want to keep sharing it?') }}</h2>
+    <p>{{ _('You have to go to the page for the file and enter the deletion password into
+    the box at the bottom of the page. If you don’t have the password, we have no way
+    of knowing if you are the initial uploader (because this service is entirely anonymous)
+    and therefore we will not be able to comply with your request.
+    <br/>
+    You should also understand that because of the way the torrent network was built, the file
+    cannot be remotely deleted on the computers of the file-sharers. So while the file is gone
+    from the website, it can still be shared and accessible via a saved torrent file or magnet
+    link.') }}
+    </p>
+    <h2>{{ _('I see "magnet link", what’s this?') }}</h2>
+    <p>{{ _('Magnet links are created from the torrent file, in order to have 
+    something easy to share between people, via text messaging or whatever.
+    Technically, your torrent client will search people who have the torrent 
+    file, and download it from them, then download the files in the torrent, 
+    so it always need at least one client which has the torrent.
+    Note that using magnet links does not give you the webseeds, so you are
+    missing one of the advantages of this website (a minimal guaranteed bandwith).') }}
+    </p>
+    <h2>{{ _('What can I do here?') }}</h2>
+    {% if config.ALLOW_MULTIFILE %}
+    <p class="info-ok">{{ _('Multifile torrents are enabled') }}</p>
+    {% else %}
+    <p class="info-important">{{ _('Multifile torrents are disabled') }}</p>
+    {% endif %}
+    {% if config.ALLOW_WEBSEEDS %}
+    <p class="info-ok">{{ _('Adding webseeds to the torrent is enabled') }}</p>
+    {% else %}
+    <p class="info-important">{{ _('Adding webseeds to the torrent is forbidden') }}</p>
+    {% endif %}
+    {% if config.ALLOW_TRACKERS %}
+    <p class="info-ok">{{ _('Adding trackers to the torrent is enabled') }}</p>
+    {% else %}
+    <p class="info-important">{{ _('Adding trackers to the torrent is disabled') }}</p>
+    {% endif %}
+    {% if config.ALLOW_PRIVATE %}
+    <p class="info-ok">{{ _('Creation of private torrents is allowed') }}</p>
+    {% else %}
+    <p class="info-important">{{ _('Creation of private torrents is forbidden') }}</p>
+    {% endif %}
+    {% with maxsize = config.MAX_CONTENT_LENGTH / (1024 ** 2) %}
+    <p class="info">{{ _('The max file size is %(maxsize)s MiB', maxsize=maxsize) }}</p>
+    {% endwith %}
+    {% if config.DEFAULT_TRACKERS %}
+    <div class="info">{{ _('The default trackers are:') }}
+        <ul>
+            {% for tracker in config.DEFAULT_TRACKERS %}
+            <li><a href="{{tracker}}">{{tracker}}</a></li>
+            {% endfor %}
+        </ul>
+    </div>
+    {% endif %}
+    {% if config.MANDATORY_TRACKERS %}
+    <div class="info">{{ _('The forced trackers are:') }}
+        <ul>
+            {% for tracker in config.MANDATORY_TRACKERS %}
+            <li><a href="{{tracker}}">{{tracker}}</a></li>
+            {% endfor %}
+        </ul>
+    </div>
+    {% endif %}
+</div>
+</div>
+{% endblock %}
diff --git a/pleaseshare/templates/home.html b/pleaseshare/templates/home.html
new file mode 100644 (file)
index 0000000..c68b9bb
--- /dev/null
@@ -0,0 +1,91 @@
+{% extends "base.html" %}
+
+{% block title %}
+PleaseShare - {{ _('Upload') }}
+{% endblock %}
+
+{% block body %}
+
+<h2>{{ _('Select a file to upload') }}</h2>
+
+<form method="post" action="{{ url_for("dynamic.upload") }}" enctype="multipart/form-data" id="sendform" name="sendform">
+    {{ form.csrf_token() }}
+    <div class="center">
+        {{ form.file }}
+        <a href="#options" class="button" id="optionsa">Options</a>
+    </div>
+    {% with maxsize = (config.MAX_CONTENT_LENGTH / (1024**2)) %}
+    <p>{{ _('Note: the filesize limit is currently set at %(maxsize)s MiB.', maxsize=maxsize) }}</p>
+    {% endwith %}
+    <div id="options" class="center">
+        <p>{{ form.uploader_name.label }} {{ form.uploader_name }}</p>
+        <p>{{ form.deletion_password.label }} {{ form.deletion_password }}</p>
+        <p>{{ form.description.label }} {{ form.description }}</p>
+        {% if config.ALLOW_WEBSEEDS %}
+            <p>{{ form.webseeds.label }} {{ form.webseeds }}</p>
+        {% endif %}
+        {% if config.ALLOW_TRACKERS%}
+            <p>{{ form.trackers.label }} {{ form.trackers }}</p>
+            {% if config.ALLOW_PRIVATE%}
+            <p>{{ form.private.label }} {{ form.private }}</p>
+            {% endif %}
+        {% endif %}
+        {% if config.ALLOW_MULTIFILE %}
+            <p>{{ form.extract.label }}{{ form.extract }}</p>
+        {% endif %}
+        {% if config.ALLOW_PRIVATE%}
+        <!--<p style="display:block;">{{ _('You can choose to make the torrent private. This is usually
+        when you upload private documents that you do not want to share with everyone.') }}</p>-->
+        {% endif %}
+    </div>
+    <div class="center">
+        <input type="submit" id="send" value="Send file">
+    </div>
+</form>
+
+<h2>{{ _('About PleaseShare') }}</h2>
+
+<p>{{ _('Using PleaseShare is easy:') }}</p>
+<ul>
+    <li>{{ _('You upload a file (or an archive, see the options below);') }}</li>
+    <li>{{ _('You get a <strong>.torrent</strong> and a <strong>magnet link</strong> to share with your friends;') }}</li>
+    <li>{{ _('Subsequent downloads are at least <strong>as fast as</strong> a direct HTTP download: this server acts as a <strong>webseed</strong> for the created torrent.') }}</li>
+</ul>
+
+<p>{{ _('PleaseShare is <a href="http://www.gnu.org/philosophy/free-sw.en.html">free software</a>, <a href="https://gitorious.org/pleaseshare">get the code</a>. More about PleaseShare <a href="%(url_about)s">here</a>. Need <a href="%(url_help)s">help</a>?', url_about=url_for("static.about"), url_help=url_for("static.help")) }}</p>
+
+
+<script>
+var button = document.getElementById("optionsa");
+var form = document.getElementById("sendform");
+button.removeAttribute("href");
+
+function toggle_visibility(id)
+{
+   var e = document.getElementById(id);
+   if(e.style.display == 'table')
+      e.style.display = 'none';
+   else
+      e.style.display = 'table';
+}
+
+button.setAttribute('onclick', 'toggle_visibility("options");');
+{% if not config.MANDATORY_TRACKERS %}
+function check_form()
+{
+    var trackers = document.getElementById('trackers');
+    var priv = document.getElementById('private');
+
+    if (priv.checked && trackers.value.trim() == "")
+    {
+        alert("{{ _('You must specify trackers if you wand to create a private torrent!') }}");
+        return false;
+    }
+    return true;
+}
+
+form.setAttribute("onsubmit", "return check_form();");
+{% endif %}
+</script>
+
+{% endblock %}
diff --git a/pleaseshare/templates/tos.html b/pleaseshare/templates/tos.html
new file mode 100644 (file)
index 0000000..d3f1d8a
--- /dev/null
@@ -0,0 +1,12 @@
+{% extends "base.html" %}
+
+{% block title %}
+PleaseShare - {{ _('Terms of Service') }}
+{% endblock %}
+
+{% block body %}
+<h2>{{ _('Terms of Service') }}</h2>
+<div id="infos">
+    Add the terms of service that fit you here.
+</div>
+{% endblock %}
diff --git a/pleaseshare/templates/view.html b/pleaseshare/templates/view.html
new file mode 100644 (file)
index 0000000..40d4c9d
--- /dev/null
@@ -0,0 +1,44 @@
+{% extends "base.html" %}
+{% block body %}
+<h2>{{ _('Your torrent') }}</h2>
+<div id="description">
+<dl>
+    <dt>{{ _('Name') }}</dt><dd>{{object.name}}</dd>
+    <dt>{{ _('Size') }}</dt><dd>{{object.size}} MiB</dd>
+{% if object.uploader %}
+<dt>{{ _('Uploader') }}</dt><dd>{{object.uploader}}</dd>
+{% endif %}
+{% if object.description %}
+<dt>{{ _('Description') }}</dt><dd>{{object.description}}</dd>
+{% endif %}
+</dl>
+</div>
+{% if object.multifile %}
+<h2>{{ _('Files…') }}</h2>
+<section>
+<pre id="files">{{object.get_files(config)}}</pre>
+</section>
+{% endif %}
+<section id="buttons">
+<dl>
+    <dt class="link"><a class="button" href="{{object.get_direct_torrent_file(config)}}">{{ _('Download .torrent') }}</a></dt>
+    <dd><input type="text" class="link" readonly value="{{object.get_direct_torrent_file(config)}}"/></dd>
+{% if config.SHOW_DDL_LINK and not object.multifile %}
+<dt class="link"><a class="button down" href="{{object.get_direct_file(config)}}">{{ _('Download file') }}</a></dt>
+    <dd><input type="text" class="link" readonly value="{{object.get_direct_file(config)}}"/></dd>
+{% endif %}
+{% if not object.private %}
+    <dt class="link"><a class="button down" href="{{object.magnet}}">{{ _('Magnet link') }}</a></dt>
+    <dd><input class="link" type="text" readonly value="{{object.magnet}}"/></dd>
+{% endif %}
+</dl>
+<br/>
+{% if object.password %}
+<form method="POST" id="delete" action="/delete" id="deletion">
+    {{ form.csrf_token }}
+    <input type="hidden" name="object_id" value="{{object.uuid}}"/>
+    {{ form.deletion_password.label }}{{ form.deletion_password }}<input type="submit"/>
+</form>
+{% endif %}
+</section>
+{% endblock %}
diff --git a/pleaseshare/torrent/__init__.py b/pleaseshare/torrent/__init__.py
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/pleaseshare/torrent/bencode.py b/pleaseshare/torrent/bencode.py
new file mode 100644 (file)
index 0000000..83fbeef
--- /dev/null
@@ -0,0 +1,130 @@
+#coding: utf-8
+# The contents of this file are subject to the Python Software Foundation
+# License Version 2.3 (the License).  You may not copy or use this file, in
+# either source code or executable form, except in compliance with the License.
+# You may obtain a copy of the License at http://www.python.org/license.
+#
+# Software distributed under the License is distributed on an AS IS basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the License
+# for the specific language governing rights and limitations under the
+# License.
+
+# Written by Petru Paler
+
+# Minor modifications made by Andrew Resch to replace the BTFailure errors with Exceptions
+
+import logging
+log = logging.getLogger(__name__)
+
+def decode_int(x, f):
+    f += 1
+    newf = x.index('e', f)
+    n = int(x[f:newf])
+    if x[f] == '-':
+        if x[f + 1] == '0':
+            raise ValueError
+    elif x[f] == '0' and newf != f+1:
+        raise ValueError
+    return (n, newf+1)
+
+def decode_string(x, f):
+    colon = x.index(':', f)
+    n = int(x[f:colon])
+    if x[f] == '0' and colon != f+1:
+        raise ValueError
+    colon += 1
+    return (x[colon:colon+n], colon+n)
+
+def decode_list(x, f):
+    r, f = [], f+1
+    while x[f] != 'e':
+        v, f = decode_func[x[f]](x, f)
+        r.append(v)
+    return (r, f + 1)
+
+def decode_dict(x, f):
+    r, f = {}, f+1
+    while x[f] != 'e':
+        k, f = decode_string(x, f)
+        r[k], f = decode_func[x[f]](x, f)
+    return (r, f + 1)
+
+decode_func = {}
+decode_func['l'] = decode_list
+decode_func['d'] = decode_dict
+decode_func['i'] = decode_int
+decode_func['0'] = decode_string
+decode_func['1'] = decode_string
+decode_func['2'] = decode_string
+decode_func['3'] = decode_string
+decode_func['4'] = decode_string
+decode_func['5'] = decode_string
+decode_func['6'] = decode_string
+decode_func['7'] = decode_string
+decode_func['8'] = decode_string
+decode_func['9'] = decode_string
+
+def bdecode(x):
+    try:
+        r, l = decode_func[x[0]](x, 0)
+    except (IndexError, KeyError, ValueError):
+        raise Exception("not a valid bencoded string")
+
+    return r
+
+class Bencached(object):
+
+    __slots__ = ['bencoded']
+
+    def __init__(self, s):
+        self.bencoded = s
+
+def encode_bencached(x, r):
+    r.append(x.bencoded.encode())
+
+def encode_int(x, r):
+    r.extend((b'i', str(x).encode(), b'e'))
+
+def encode_bool(x, r):
+    if x:
+        encode_int(1, r)
+    else:
+        encode_int(0, r)
+
+def encode_string(x, r):
+    r.extend((str(len(x)).encode(), b':', x))
+
+def encode_utf8(x, r):
+    x = x.encode('utf-8')
+    r.extend((str(len(x)).encode(), b':', x))
+
+def encode_list(x, r):
+    r.append(b'l')
+    for i in x:
+        encode_func[type(i)](i, r)
+    r.append(b'e')
+
+def encode_dict(x, r):
+    r.append(b'd')
+    ilist = x.items()
+    ilist = sorted(ilist)
+    for k, v in ilist:
+        r.extend((str(len(k)).encode(), b':', k.encode()))
+        encode_func[type(v)](v, r)
+    r.append(b'e')
+
+encode_func = {}
+encode_func[Bencached] = encode_bencached
+encode_func[int] = encode_int
+encode_func[int] = encode_int
+encode_func[bytes] = encode_string
+encode_func[str] = encode_utf8
+encode_func[list] = encode_list
+encode_func[tuple] = encode_list
+encode_func[dict] = encode_dict
+encode_func[bool] = encode_bool
+
+def bencode(x):
+    r = []
+    encode_func[type(x)](x, r)
+    return b''.join(r)
diff --git a/pleaseshare/torrent/common.py b/pleaseshare/torrent/common.py
new file mode 100644 (file)
index 0000000..f9bc280
--- /dev/null
@@ -0,0 +1,89 @@
+#coding: utf-8
+#
+# common.py
+#
+# Copyright (C) 2007, 2008 Andrew Resch <andrewresch@gmail.com>
+#
+# Deluge is free software.
+#
+# You may 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.
+#
+# deluge 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 deluge.    If not, write to:
+#      The Free Software Foundation, Inc.,
+#      51 Franklin Street, Fifth Floor
+#      Boston, MA  02110-1301, USA.
+#
+#    In addition, as a special exception, the copyright holders give
+#    permission to link the code of portions of this program with the OpenSSL
+#    library.
+#    You must obey the GNU General Public License in all respects for all of
+#    the code used other than OpenSSL. If you modify file(s) with this
+#    exception, you may extend this exception to your version of the file(s),
+#    but you are not obligated to do so. If you do not wish to do so, delete
+#    this exception statement from your version. If you delete this exception
+#    statement from all source files in the program, then also delete it here.
+#
+#
+
+
+"""Common functions for various parts of Deluge to use."""
+
+import os
+from urllib.parse import quote_plus
+
+def create_magnet_uri(infohash, name=None, trackers=[]):
+    """
+    Creates a magnet uri
+
+    :param infohash: the info-hash of the torrent
+    :type infohash: string
+    :param name: the name of the torrent (optional)
+    :type name: string
+    :param trackers: the trackers to announce to (optional)
+    :type trackers: list of strings
+
+    :returns: a magnet uri string
+    :rtype: string
+
+    """
+    from base64 import b32encode
+    uri = "magnet:?xt=urn:btih:" + infohash.lower()
+    if name:
+        uri = uri + "&dn=" + name
+    if trackers:
+        for t in trackers:
+            uri = uri + "&tr=" + quote_plus(t)
+
+    return uri
+
+def get_path_size(path):
+    """
+    Gets the size in bytes of 'path'
+
+    :param path: the path to check for size
+    :type path: string
+    :returns: the size in bytes of the path or -1 if the path does not exist
+    :rtype: int
+
+    """
+    if not os.path.exists(path):
+        return -1
+
+    if os.path.isfile(path):
+        return os.path.getsize(path)
+
+    dir_size = 0
+    for (p, dirs, files) in os.walk(path):
+        for file in files:
+            filename = os.path.join(p, file)
+            dir_size += os.path.getsize(filename)
+    return dir_size
diff --git a/pleaseshare/torrent/maketorrent.py b/pleaseshare/torrent/maketorrent.py
new file mode 100644 (file)
index 0000000..a1d8e54
--- /dev/null
@@ -0,0 +1,365 @@
+#coding: utf-8
+#
+# maketorrent.py
+#
+# Copyright (C) 2009 Andrew Resch <andrewresch@gmail.com>
+#
+# Deluge is free software.
+#
+# You may 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.
+#
+# deluge 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 deluge.    If not, write to:
+#      The Free Software Foundation, Inc.,
+#      51 Franklin Street, Fifth Floor
+#      Boston, MA  02110-1301, USA.
+#
+#    In addition, as a special exception, the copyright holders give
+#    permission to link the code of portions of this program with the OpenSSL
+#    library.
+#    You must obey the GNU General Public License in all respects for all of
+#    the code used other than OpenSSL. If you modify file(s) with this
+#    exception, you may extend this exception to your version of the file(s),
+#    but you are not obligated to do so. If you do not wish to do so, delete
+#    this exception statement from your version. If you delete this exception
+#    statement from all source files in the program, then also delete it here.
+#
+#
+
+import sys
+import os
+from hashlib import sha1 as sha
+
+from . common import get_path_size, create_magnet_uri
+from . bencode import bencode, bdecode
+
+class InvalidPath(Exception):
+    """
+    Raised when an invalid path is supplied
+    """
+    pass
+
+class InvalidPieceSize(Exception):
+    """
+    Raised when an invalid piece size is set.  Piece sizes must be multiples of
+    16KiB.
+    """
+    pass
+
+class TorrentMetadata(object):
+    """
+    This class is used to create .torrent files.
+
+    ** Usage **
+
+    >>> t = TorrentMetadata()
+    >>> t.data_path = "/tmp/torrent"
+    >>> t.comment = "My Test Torrent"
+    >>> t.trackers = [["http://tracker.openbittorent.com"]]
+    >>> t.save("/tmp/test.torrent")
+
+    """
+    def __init__(self):
+        self.__data_path = None
+        self.__piece_size = 0
+        self.__comment = ""
+        self.__private = False
+        self.__trackers = []
+        self.__webseeds = []
+        self.__pad_files = False
+
+    def save(self, torrent_path, progress=None):
+        """
+        Creates and saves the torrent file to `path`.
+
+        :param torrent_path: where to save the torrent file
+        :type torrent_path: string
+
+        :param progress: a function to be called when a piece is hashed
+        :type progress: function(num_completed, num_pieces)
+
+        :raises InvalidPath: if the data_path has not been set
+
+        :returns: The magnet link
+        :rtype: string
+
+        """
+        if not self.data_path:
+            raise InvalidPath("Need to set a data_path!")
+
+        torrent = {
+            "info": {}
+            }
+
+        if self.comment:
+            torrent["comment"] = self.comment.encode("UTF-8")
+
+        if self.private:
+            torrent["info"]["private"] = True
+
+        if self.trackers:
+            torrent["announce"] = self.trackers[0][0]
+            torrent["announce-list"] = self.trackers
+        else:
+            torrent["announce"] = ""
+
+        if self.webseeds:
+            httpseeds = []
+            webseeds = []
+            for w in self.webseeds:
+                if w.endswith(".php"):
+                    httpseeds.append(w)
+                else:
+                    webseeds.append(w)
+
+            if httpseeds:
+                torrent["httpseeds"] = httpseeds
+            if webseeds:
+                torrent["url-list"] = webseeds
+
+        datasize = get_path_size(self.data_path)
+
+        if self.piece_size:
+            piece_size = self.piece_size * 1024
+        else:
+            # We need to calculate a piece size
+            piece_size = 16384
+            while (datasize / piece_size) > 1024 and piece_size < (8192 * 1024):
+                piece_size *= 2
+
+        # Calculate the number of pieces we will require for the data
+        num_pieces = datasize / piece_size
+        if datasize % piece_size:
+            num_pieces += 1
+
+        torrent["info"]["piece length"] = piece_size
+
+        # Create the info
+        if os.path.isdir(self.data_path):
+            torrent["info"]["name"] = os.path.split(self.data_path)[1]
+            files = []
+            padding_count = 0
+            # Collect a list of file paths and add padding files if necessary
+            for (dirpath, dirnames, filenames) in os.walk(self.data_path):
+                for index, filename in enumerate(filenames):
+                    size = get_path_size(os.path.join(self.data_path, dirpath, filename))
+                    p = dirpath[len(self.data_path):]
+                    p = p.lstrip("/")
+                    p = p.split("/")
+                    if p[0]:
+                        p += [filename]
+                    else:
+                        p = [filename]
+                    files.append((size, p))
+                    # Add a padding file if necessary
+                    if self.pad_files and (index + 1) < len(filenames):
+                        left = size % piece_size
+                        if left:
+                            p = list(p)
+                            p[-1] = "_____padding_file_" + str(padding_count)
+                            files.append((piece_size - left, p))
+                            padding_count += 1
+
+            # Run the progress function with 0 completed pieces
+            if progress:
+                progress(0, num_pieces)
+
+            fs = []
+            pieces = []
+            # Create the piece hashes
+            buf = b""
+            for size, path in files:
+                path = [s.encode("UTF-8") for s in path]
+                fs.append({"length": size, "path": path})
+                if path[-1].startswith(b"_____padding_file_"):
+                    buf += b"\0" * size
+                    pieces.append(sha(buf).digest())
+                    buf = ""
+                    fs[-1]["attr"] = "p"
+                else:
+                    fd = open(os.path.join(self.data_path, *[pa.decode('utf-8') for pa in path]), "rb")
+                    r = fd.read(piece_size - len(buf))
+                    while r:
+                        buf += r
+                        if len(buf) == piece_size:
+                            pieces.append(sha(buf).digest())
+                            # Run the progress function if necessary
+                            if progress:
+                                progress(len(pieces), num_pieces)
+                            buf = b""
+                        else:
+                            break
+                        r = fd.read(piece_size - len(buf))
+                    fd.close()
+
+            if buf:
+                pieces.append(sha(buf).digest())
+                if progress:
+                    progress(len(pieces), num_pieces)
+                buf = ""
+
+            torrent["info"]["pieces"] = b''.join(pieces)
+            torrent["info"]["files"] = fs
+
+        elif os.path.isfile(self.data_path):
+            torrent["info"]["name"] = os.path.split(self.data_path)[1]
+            torrent["info"]["length"] = get_path_size(self.data_path)
+            pieces = []
+
+            fd = open(self.data_path, "rb")
+            r = fd.read(piece_size)
+            while r:
+                pieces.append(sha(r).digest())
+                if progress:
+                    progress(len(pieces), num_pieces)
+
+                r = fd.read(piece_size)
+
+            torrent["info"]["pieces"] = b''.join(pieces)
+
+        # Write out the torrent file
+        wr = open(torrent_path, 'wb')
+        wr.write(bencode(torrent))
+        wr.close()
+        return create_magnet_uri(sha(bencode(torrent["info"])).hexdigest(),
+                torrent['info']['name'],
+                [i[0] for i in self.trackers])
+
+    def get_data_path(self):
+        """
+        The path to the files that the torrent will contain.  It can be either
+        a file or a folder.  This property needs to be set before the torrent
+        file can be created and saved.
+        """
+        return self.__data_path
+
+    def set_data_path(self, path):
+        """
+        :param path: the path to the data
+        :type path: string
+
+        :raises InvalidPath: if the path is not found
+
+        """
+        if os.path.exists(path) and (os.path.isdir(path) or os.path.isfile(path)):
+            self.__data_path = os.path.abspath(path)
+        else:
+            raise InvalidPath("No such file or directory: %s" % path)
+
+    def get_piece_size(self):
+        """
+        The size of pieces in bytes.  The size must be a multiple of 16KiB.
+        If you don't set a piece size, one will be automatically selected to
+        produce a torrent with less than 1024 pieces or the smallest possible
+        with a 8192KiB piece size.
+
+        """
+        return self.__piece_size
+
+    def set_piece_size(self, size):
+        """
+        :param size: the desired piece size in KiBs
+        :type size: int
+
+        :raises InvalidPieceSize: if the piece size is not a multiple of 16 KiB
+
+        """
+        if size % 16 and size:
+            raise InvalidPieceSize("Piece size must be a multiple of 16 KiB")
+        self.__piece_size = size
+
+    def get_comment(self):
+        """
+        Comment is some extra info to be stored in the torrent.  This is
+        typically an informational string.
+        """
+        return self.__comment
+
+    def set_comment(self, comment):
+        """
+        :param comment: an informational string
+        :type comment: string
+        """
+        self.__comment = comment
+
+    def get_private(self):
+        """
+        Private torrents only announce to the tracker and will not use DHT or
+        Peer Exchange.
+
+        See: http://bittorrent.org/beps/bep_0027.html
+
+        """
+        return self.__private
+
+    def set_private(self, private):
+        """
+        :param private: True if the torrent is to be private
+        :type private: bool
+        """
+        self.__private = private
+
+    def get_trackers(self):
+        """
+        The announce trackers is a list of lists.
+
+        See: http://bittorrent.org/beps/bep_0012.html
+
+        """
+        return self.__trackers
+
+    def set_trackers(self, trackers):
+        """
+        :param trackers: a list of lists of trackers, each list is a tier
+        :type trackers: list of list of strings
+        """
+        self.__trackers = trackers
+
+    def get_webseeds(self):
+        """
+        The web seeds can either be:
+        Hoffman-style: http://bittorrent.org/beps/bep_0017.html
+        or,
+        GetRight-style: http://bittorrent.org/beps/bep_0019.html
+
+        If the url ends in '.php' then it will be considered Hoffman-style, if
+        not it will be considered GetRight-style.
+        """
+        return self.__webseeds
+
+    def set_webseeds(self, webseeds):
+        """
+        :param webseeds: the webseeds which can be either Hoffman or GetRight style
+        :type webseeds: list of urls
+        """
+        self.__webseeds = webseeds
+
+    def get_pad_files(self):
+        """
+        If this is True, padding files will be added to align files on piece
+        boundaries.
+        """
+        return self.__pad_files
+
+    def set_pad_files(self, pad):
+        """
+        :param pad: set True to align files on piece boundaries
+        :type pad: bool
+        """
+        self.__pad_files = pad
+
+    data_path = property(get_data_path, set_data_path)
+    piece_size = property(get_piece_size, set_piece_size)
+    comment = property(get_comment, set_comment)
+    private = property(get_private, set_private)
+    trackers = property(get_trackers, set_trackers)
+    webseeds = property(get_webseeds, set_webseeds)
+    pad_files = property(get_pad_files, set_pad_files)
diff --git a/pleaseshare/translations/fr/LC_MESSAGES/messages.mo b/pleaseshare/translations/fr/LC_MESSAGES/messages.mo
new file mode 100644 (file)
index 0000000..6505e65
Binary files /dev/null and b/pleaseshare/translations/fr/LC_MESSAGES/messages.mo differ
diff --git a/pleaseshare/translations/fr/LC_MESSAGES/messages.po b/pleaseshare/translations/fr/LC_MESSAGES/messages.po
new file mode 100644 (file)
index 0000000..827137d
--- /dev/null
@@ -0,0 +1,477 @@
+# French translations for PleaseShare
+# This file is distributed under the same license as the PleaseShare project.
+# Mathieu Pasquet <mathieui@mathieui.net>, 2015.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: VERSION\n"
+"Report-Msgid-Bugs-To: mathieui@mathieui.net\n"
+"POT-Creation-Date: 2015-02-04 23:58+0100\n"
+"PO-Revision-Date: 2015-02-04 10:18+0100\n"
+"Last-Translator: Mathieu Pasquet <mathieui@mathieui.net>\n"
+"Language-Team: fr <LL@li.org>\n"
+"Plural-Forms: nplurals=2; plural=(n > 1)\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=utf-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: Babel 1.3\n"
+
+#: app.py:48
+msgid "Upload not found"
+msgstr "Fichier non trouvé"
+
+#: app.py:60
+msgid "Missing field in deletion form."
+msgstr "Champ non rempli dans le formulaire de suppression."
+
+#: app.py:65
+#, python-format
+msgid "Uploaded file %s not found."
+msgstr "Fichier %s non trouvé."
+
+#: app.py:68
+#, python-format
+msgid "Uploaded file %s cannot be deleted (no deletion password exists)."
+msgstr ""
+"Le fichier %s ne peut pas être supprimé (pas de mot de passe de "
+"suppression)."
+
+#: app.py:77
+msgid "Upload deleted successfully."
+msgstr "Fichier supprimé."
+
+#: app.py:79
+msgid "Wrong password"
+msgstr "Mauvais mot de passe"
+
+#: app.py:95
+msgid "File required."
+msgstr "Fichier requis."
+
+#: app.py:104
+msgid "Server error"
+msgstr "Erreur interne"
+
+#: app.py:135
+msgid "Extracted archive too big, fallback to single-file upload."
+msgstr "Archive trop volumineuse pour être extraite, retour au mode fichier unique."
+
+#: app.py:137
+msgid "Invalid archive, fallback to single-file upload."
+msgstr "Archive invalide, retour au mode fichier unique."
+
+#: forms.py:17
+msgid "Uploader name"
+msgstr "Créateur"
+
+#: forms.py:17
+msgid "Anonymous"
+msgstr "Anonyme"
+
+#: forms.py:18
+msgid "Password (used for deletion)"
+msgstr "Mot de passe"
+
+#: forms.py:19
+msgid "File to upload"
+msgstr "Choisissez un fichier à envoyer"
+
+#: forms.py:20
+msgid "Private torrent?"
+msgstr "Torrent privé ?"
+
+#: forms.py:21
+msgid "Extract file"
+msgstr "Extraire"
+
+#: forms.py:22
+msgid "Trackers"
+msgstr "Trackers"
+
+#: forms.py:23
+msgid "Webseeds"
+msgstr "Sources web"
+
+#: forms.py:24
+msgid "Short description"
+msgstr "Description"
+
+#: forms.py:30
+msgid "Password for deletion:"
+msgstr "Mot de passe de suppression :"
+
+#: templates/about.html:4 templates/base.html:19
+msgid "About"
+msgstr "À propos"
+
+#: templates/about.html:9
+msgid "What is pleaseshare?"
+msgstr "Qu’est-ce que pleaseshare ?"
+
+#: templates/about.html:11
+msgid "Pleaseshare is a file-sharing website, with \"sharing\" as its core value."
+msgstr ""
+"PleaseShare est un site de partage de fichiers, qui dépend également du "
+"partage de fichiers entre ses utilisateurs."
+
+#: templates/about.html:14
+msgid ""
+"It means that there won’t be a direct link on your file once you upload "
+"it, but pleaseshare\n"
+"    will generate a torrent for you, with a webseed. Therefore, people "
+"who download the file will\n"
+"    always get the best speed available (since there is a webseed, it "
+"will be at worst the same\n"
+"    speed as if they downloaded it directly via http). It also means that"
+" the uploader can use this\n"
+"    torrent to seed the file that is already on his computer, thus "
+"increasing the download speed for\n"
+"    people on the other end."
+msgstr ""
+"Cela veut dire que PleaseShare ne va pas fournir de lien direct versvotre"
+" fichier une fois que vous l’aurez envoyé. À la place, PleaseShare va "
+"générer un torrent, qui contient une source web. En utilisant ce torrent,"
+" les gens qui téléchargent le fichier auront une vitesse de "
+"téléchargement optimale (ce sera <strong>au pire</strong> la même vitesse"
+" qu’en téléchargement http direct). Cela veut dire également que la "
+"personne qui envoie le fichier peut directement partager le fichier qui "
+"est présent sur son ordinateur, augmentant d’emblée la vitesse pour les "
+"autres téléchargeurs."
+
+#: templates/about.html:21
+msgid "Things to know"
+msgstr "À savoir"
+
+#: templates/about.html:23
+msgid ""
+"Please note that pleaseshare relies on the Bittorent DHT, which means "
+"that no trackers\n"
+"    are needed to get peers."
+msgstr ""
+"PleaseShare s’appuie sur la DHT Bittorent, ce qui veut dire que des "
+"trackers ne sont pas obligatoires pour trouver des pairs."
+
+#: templates/about.html:25
+msgid "You can provide trackers if you want, but you don’t have to."
+msgstr ""
+"Vous pouvez fournir des trackers si vous voulez, mais ce n’est pas "
+"nécéssaire"
+
+#: templates/about.html:26
+msgid "Trackers will be added by the server even if you don’t add them."
+msgstr "Des trackers seront ajoutés par ce serveur automatiquement."
+
+#: templates/about.html:28
+msgid ""
+"You must also understand that, even if pleaseshare allows you to delete "
+"the files that you upload on this server, the torrent can still stay "
+"active without a webseed."
+msgstr ""
+"Il faut également comprendre que, même si pleaseshare vous permet de "
+"supprimer les fichiers que vous envoyez sur ce serveur, le torent peut "
+"rester actif même sans la source web."
+
+#: templates/about.html:30
+msgid "Licence"
+msgstr "Licence"
+
+#: templates/about.html:32
+msgid ""
+"Pleaseshare is licenced under the AGPL v3, with some GPL bits coming from"
+" the deluge client.\n"
+"    And the source is <a href=\"https://gitorious.org/pleaseshare\" "
+"title=\"pleaseshare source\">on gitorious</a>."
+msgstr ""
+"PleaseShare est sous licence AGPLv3, avec des bouts sous GPL venant du "
+"client deluge. Les sources sont disponibles <a "
+"href=\"https://gitorious.org/pleaseshare\" title=\"pleaseshare "
+"source\">sur gitorious</a>."
+
+#: templates/base.html:18
+msgid "Need help?"
+msgstr "Aide"
+
+#: templates/base.html:20 templates/tos.html:4 templates/tos.html:8
+msgid "Terms of Service"
+msgstr "Conditions d’utilisation"
+
+#: templates/base.html:20
+msgid "ToS"
+msgstr "Conditions"
+
+#: templates/base.html:21 templates/contact.html:4 templates/contact.html:8
+msgid "Contact"
+msgstr "Contact"
+
+#: templates/help.html:3
+msgid "Help"
+msgstr "Aide"
+
+#: templates/help.html:8
+msgid "I can only upload one file?"
+msgstr "Je dois envoyer un seul fichier ?"
+
+#: templates/help.html:9
+msgid ""
+"Yes, at the moment, due to the limitations of html, it is impossible to "
+"upload\n"
+"    folders directly."
+msgstr ""
+"Oui, actuellement les limitations de HTML ne permettent pas de "
+"sélectionner des dossiers directement."
+
+#: templates/help.html:12
+msgid "However, if you upload an archive"
+msgstr "Cependant, si vous envoyez une archive"
+
+#: templates/help.html:14
+msgid " (.zip/.tar, possibly compressed) "
+msgstr " (.zip/.tar, avec ou sans compression) "
+
+#: templates/help.html:16
+msgid " (.tar, uncompressed) "
+msgstr " (.tar, sans compression) "
+
+#: templates/help.html:18
+msgid ""
+"and toggle the option \"Extract archive\" the torrent will contain the "
+"files of\n"
+"    this archive, under a subdirectory named after the archive (minus the"
+" .extension part)."
+msgstr ""
+"et activez l’option \"Extraire\", le torrent contiendra les fichiers de "
+"cette archive, dans un sous-dossier nommé comme l’archive (sans le "
+".extension)."
+
+#: templates/help.html:22
+msgid "I uploaded a file, what now?"
+msgstr "Qu’est-ce que je fais ensuite ?"
+
+#: templates/help.html:23
+msgid ""
+"You can share it with your friends, of anyone, if you give them a link\n"
+"    to this page, to the torrent, or the magnet link.\n"
+"    You should also start the torrent into your favorite torrent client, "
+"this way,\n"
+"    you will be able to share it. If you don’t do that, the download "
+"speed for the\n"
+"    people who want download the file will be smaller."
+msgstr ""
+"Vous pouvez partager le fichier avec vos amis ou qui vous voulez, en leur"
+" fournissant un lien vers la page du fichier, le torrent, ou le lien "
+"magnet. Vous devriez aussi lancer le torrent dans votre client bittorent "
+"favori, cela vous permettra de le partager, et donc d’améliorer la "
+"vitesse de téléchargement du fichier pour les gens à qui vous fournirer "
+"le lien."
+
+#: templates/help.html:29
+msgid "How do I delete a file if I don’t want to keep sharing it?"
+msgstr "Comment supprimer un fichier ?"
+
+#: templates/help.html:30
+msgid ""
+"You have to go to the page for the file and enter the deletion password "
+"into\n"
+"    the box at the bottom of the page. If you don’t have the password, we"
+" have no way\n"
+"    of knowing if you are the initial uploader (because this service is "
+"entirely anonymous)\n"
+"    and therefore we will not be able to comply with your request.\n"
+"    <br/>\n"
+"    You should also understand that because of the way the torrent "
+"network was built, the file\n"
+"    cannot be remotely deleted on the computers of the file-sharers. So "
+"while the file is gone\n"
+"    from the website, it can still be shared and accessible via a saved "
+"torrent file or magnet\n"
+"    link."
+msgstr ""
+"Vous devez aller sur la page correspondant à votre fichier et entrer le "
+"mot de passe de suppression. Si vous n’avez pas entré de mot de passe au "
+"moment de l’envoi, nous n’avons aucun moyen de savoir que c’est vous qui "
+"avez envoyé le fichier (puisque ce service est anonyme). Il faut "
+"également prendre en compte qu’à cause de la façon de fonctionner de "
+"bittorent, supprimer le fichier sur le site ne permet pas  d’empêcher les"
+" gens de partager les torrents/magnet déjà publics."
+
+#: templates/help.html:40
+msgid "I see \"magnet link\", what’s this?"
+msgstr "Qu’est-ce qu’un « lien magnet » ?"
+
+#: templates/help.html:41
+msgid ""
+"Magnet links are created from the torrent file, in order to have \n"
+"    something easy to share between people, via text messaging or "
+"whatever.\n"
+"    Technically, your torrent client will search people who have the "
+"torrent \n"
+"    file, and download it from them, then download the files in the "
+"torrent, \n"
+"    so it always need at least one client which has the torrent.\n"
+"    Note that using magnet links does not give you the webseeds, so you "
+"are\n"
+"    missing one of the advantages of this website (a minimal guaranteed "
+"bandwith)."
+msgstr ""
+"Les liens magnets sont créés à partir du fichier torrent, afin d’avoir "
+"quelque chose de facile à partager avec d’autres gens (via SMS or other)."
+" En pratique, votre client torrent va recherche les gens qui ont le même "
+"torrent, et télécharger les fichiers depuis eux. C’est pourquoi utiliser "
+"les liens magnet nécessite au moins un utilisateur qui a les fichiers. "
+"Utiliser les liens magnet ne permet pas de profiter des avantages offerts"
+" par pleaseshare (vitesse minimale garantie)."
+
+#: templates/help.html:49
+msgid "What can I do here?"
+msgstr "Options disponibles"
+
+#: templates/help.html:51
+msgid "Multifile torrents are enabled"
+msgstr "Les torrents à fichiers multiples sont activés"
+
+#: templates/help.html:53
+msgid "Multifile torrents are disabled"
+msgstr "Les torrents à fichiers multiples sont désactivés"
+
+#: templates/help.html:56
+msgid "Adding webseeds to the torrent is enabled"
+msgstr "Ajouter des sources web dans le torrent est possible"
+
+#: templates/help.html:58
+msgid "Adding webseeds to the torrent is forbidden"
+msgstr "Ajouter des sources web dans le torrent est interdit"
+
+#: templates/help.html:61
+msgid "Adding trackers to the torrent is enabled"
+msgstr "Ajouter des trackers dans le torrent est possible"
+
+#: templates/help.html:63
+msgid "Adding trackers to the torrent is disabled"
+msgstr "Ajouter des trackers dans le torrent est interdit"
+
+#: templates/help.html:66
+msgid "Creation of private torrents is allowed"
+msgstr "Il est possible de créer des torrents privés"
+
+#: templates/help.html:68
+msgid "Creation of private torrents is forbidden"
+msgstr "Il est impossible de créer des torrents privés"
+
+#: templates/help.html:71
+#, python-format
+msgid "The max file size is %(maxsize)s MiB"
+msgstr "La taille maximum des fichiers est de %(maxsize)s Mio"
+
+#: templates/help.html:74
+msgid "The default trackers are:"
+msgstr "Les trackers par défaut sont :"
+
+#: templates/help.html:83
+msgid "The forced trackers are:"
+msgstr "Les trackers ajoutés automatiquement sont :"
+
+#: templates/home.html:4
+msgid "Upload"
+msgstr "Upload"
+
+#: templates/home.html:9
+msgid "Select a file to upload"
+msgstr "Choisissez un fichier à envoyer"
+
+#: templates/home.html:18
+#, python-format
+msgid "Note: the filesize limit is currently set at %(maxsize)s MiB."
+msgstr "Note: Taille max: %(maxsize)s Mio."
+
+#: templates/home.html:37
+msgid ""
+"You can choose to make the torrent private. This is usually\n"
+"        when you upload private documents that you do not want to share "
+"with everyone."
+msgstr ""
+
+#: templates/home.html:46
+msgid "About PleaseShare"
+msgstr "Qu’est-ce que pleaseshare ?"
+
+#: templates/home.html:48
+msgid "Using PleaseShare is easy:"
+msgstr "Utiliser PleaseShare est facile :"
+
+#: templates/home.html:50
+msgid "You upload a file (or an archive, see the options below);"
+msgstr "Vous envoyez un fichier (ou une archive, selon les options activées) ;"
+
+#: templates/home.html:51
+msgid ""
+"You get a <strong>.torrent</strong> and a <strong>magnet link</strong> to"
+" share with your friends;"
+msgstr ""
+"Vous obtenez un fichier <strong>.torrent</strong> et un <strong>lien "
+"magnet</strong> à partager avec vos amis;"
+
+#: templates/home.html:52
+msgid ""
+"Subsequent downloads are at least <strong>as fast as</strong> a direct "
+"HTTP download: this server acts as a <strong>webseed</strong> for the "
+"created torrent."
+msgstr ""
+"Les téléchargements sont ensuite <strong>au moins aussi "
+"rapides</strong>qu’un téléchargement HTP direct, puisque ce serveur sert "
+"de <strong>source web</strong> pour le torrent."
+
+#: templates/home.html:55
+#, python-format
+msgid ""
+"PleaseShare is <a href=\"http://www.gnu.org/philosophy/free-"
+"sw.en.html\">free software</a>, <a "
+"href=\"https://gitorious.org/pleaseshare\">get the code</a>. More about "
+"PleaseShare <a href=\"%(url_about)s\">here</a>. Need <a "
+"href=\"%(url_help)s\">help</a>?"
+msgstr ""
+"PleaseShare est un <a href=\"http://www.gnu.org/philosophy/free-"
+"sw.en.html\">logiciel libre</a>, <a "
+"href=\"https://gitorious.org/pleaseshare\">obtenir le code</a>. Plus "
+"d’informations sur PleaseShare <a href=\"%(url_about)s\">ici</a>. Besoin "
+"d’<a href=\"%(url_help)s\">aide</a> ?"
+
+#: templates/home.html:81
+msgid "You must specify trackers if you wand to create a private torrent!"
+msgstr "Vous devez fournir des trackers si vous voulez un torrent privé !"
+
+#: templates/view.html:3
+msgid "Your torrent"
+msgstr "Votre torrent"
+
+#: templates/view.html:6
+msgid "Name"
+msgstr "Nom"
+
+#: templates/view.html:7
+msgid "Size"
+msgstr "Taille"
+
+#: templates/view.html:9
+msgid "Uploader"
+msgstr "Créateur"
+
+#: templates/view.html:12
+msgid "Description"
+msgstr "Description"
+
+#: templates/view.html:17
+msgid "Files…"
+msgstr "Fichiers…"
+
+#: templates/view.html:24
+msgid "Download .torrent"
+msgstr "Télécharger le .torrent"
+
+#: templates/view.html:27
+msgid "Download file"
+msgstr "Télécharger le fichier"
+
+#: templates/view.html:31
+msgid "Magnet link"
+msgstr "Lien magnet"
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644 (file)
index 0000000..0d9041a
--- /dev/null
@@ -0,0 +1,4 @@
+flask>=0.9
+flask-wtf>=0.9.1
+flask-babel>=0.9
+flask-sqlalchemy>=1.0