diff --git a/package-lock.json b/package-lock.json index 9cd8639894..e09fb8ad03 100644 --- a/package-lock.json +++ b/package-lock.json @@ -903,10 +903,6 @@ "resolved": "src/backend", "link": true }, - "node_modules/@heyputer/gui": { - "resolved": "src/gui", - "link": true - }, "node_modules/@heyputer/kv.js": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@heyputer/kv.js/-/kv.js-0.1.6.tgz", @@ -13712,6 +13708,7 @@ }, "src/gui": { "version": "2.3.0", + "extraneous": true, "license": "AGPL-3.0-only", "workspaces": [ "src/*" diff --git a/src/dev-center/LICENSE.txt b/src/dev-center/LICENSE.txt new file mode 100644 index 0000000000..bae94e189e --- /dev/null +++ b/src/dev-center/LICENSE.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + 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. + + + Copyright (C) + + 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 . + +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 +. \ No newline at end of file diff --git a/src/dev-center/README.md b/src/dev-center/README.md new file mode 100644 index 0000000000..ab2eb8a417 --- /dev/null +++ b/src/dev-center/README.md @@ -0,0 +1,52 @@ +

+ +

+ +

Dev Center

+

The easiest way to publish and manage web apps.

+ +

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ + +

Screenshot 2024-07-07 at 5 29 24 PM

+ +
+ + +## Dev Center + +Dev Center is a Puter app that allows you to publish and manage web apps. It is built with Puter SDK and is available on [Puter.com](https://puter.com/app/dev-center) as well as [the self-hosted Puter](https://github.com/heyPuter/puter/). + +
+ +## License + +Dev Center is licensed under the [AGPL-3.0 license](./LICENSE.txt). + + +
+ +## Icons + +[jolloficons](https://github.com/gbmillz/jolloficons) under MIT license. + +[Credit Card & Payment Icons](https://github.com/aaronfagan/svg-credit-card-payment-icons) under Apache-2.0 license. + +[Bootstrap Icons](https://icons.getbootstrap.com/) under MIT license. + +[svg-spinners](https://github.com/n3r4zzurr0/svg-spinners) under MIT license. diff --git a/src/dev-center/coming-soon.html b/src/dev-center/coming-soon.html new file mode 100644 index 0000000000..ef274d2e03 --- /dev/null +++ b/src/dev-center/coming-soon.html @@ -0,0 +1,54 @@ + + + + + + + + + + +

Coming Soon!

+

Are you the developer of this app? Please deploy via Dev Center.

+ + diff --git a/src/dev-center/css/normalize.css b/src/dev-center/css/normalize.css new file mode 100644 index 0000000000..192eb9ce43 --- /dev/null +++ b/src/dev-center/css/normalize.css @@ -0,0 +1,349 @@ +/*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ + +/* Document + ========================================================================== */ + +/** + * 1. Correct the line height in all browsers. + * 2. Prevent adjustments of font size after orientation changes in iOS. + */ + +html { + line-height: 1.15; /* 1 */ + -webkit-text-size-adjust: 100%; /* 2 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers. + */ + +body { + margin: 0; +} + +/** + * Render the `main` element consistently in IE. + */ + +main { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * Remove the gray background on active links in IE 10. + */ + +a { + background-color: transparent; +} + +/** + * 1. Remove the bottom border in Chrome 57- + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10. + */ + +img { + border-style: none; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers. + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: inherit; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * Correct the inability to style clickable types in iOS and Safari. + */ + +button, +[type="button"], +[type="reset"], +[type="submit"] { + -webkit-appearance: button; +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Correct the padding in Firefox. + */ + +fieldset { + padding: 0.35em 0.75em 0.625em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Remove the default vertical scrollbar in IE 10+. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10. + * 2. Remove the padding in IE 10. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in Edge, IE 10+, and Firefox. + */ + +details { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Misc + ========================================================================== */ + +/** + * Add the correct display in IE 10+. + */ + +template { + display: none; +} + +/** + * Add the correct display in IE 10. + */ + +[hidden] { + display: none; +} diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css new file mode 100644 index 0000000000..e4c7a4ba5b --- /dev/null +++ b/src/dev-center/css/style.css @@ -0,0 +1,1015 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + +* { + font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +html { + width: 100vw; + height: 100vh; + background-color: #eff1f5 +} + +body{ + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + flex: 1; +} +/* ------------------------------------ + Button + ------------------------------------*/ + +.button { + color: #666666; + background-color: #eeeeee; + border-color: #eeeeee; + font-size: 14px; + text-decoration: none; + text-align: center; + line-height: 40px; + height: 35px; + padding: 0 25px; + margin: 0; + display: inline-block; + appearance: none; + cursor: pointer; + border: none; + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; + border-color: #b9b9b9; + border-style: solid; + border-width: 1px; + line-height: 35px; + background: -webkit-gradient(linear, left top, left bottom, from(#f6f6f6), to(#e1e1e1)); + background: linear-gradient(#f6f6f6, #e1e1e1); + -webkit-box-shadow: inset 0px 1px 0px rgb(255 255 255 / 30%), 0 1px 2px rgb(0 0 0 / 15%); + box-shadow: inset 0px 1px 0px rgb(255 255 255 / 30%), 0 1px 2px rgb(0 0 0 / 15%); + border-radius: 4px; + outline: none; + + /* Disable user select */ + -webkit-touch-callout: none !important; + -webkit-user-select: none !important; + -khtml-user-select: none !important; + -moz-user-select: none !important; + -ms-user-select: none !important; + user-select: none !important; +} + +.button:focus-visible { + border-color: rgb(118 118 118); +} + +.button:active, .button.active, .button.is-active, .button.has-open-contextmenu { + text-decoration: none; + background-color: #eeeeee; + border-color: #cfcfcf; + color: #a9a9a9; + -webkit-transition-duration: 0s; + transition-duration: 0s; + -webkit-box-shadow: inset 0 1px 3px rgb(0 0 0 / 20%); + box-shadow: inset 0px 2px 3px rgb(0 0 0 / 36%), 0px 1px 0px white; +} + +.button.disabled, .button.is-disabled, .button:disabled { + top: 0 !important; + background: #EEE !important; + border: 1px solid #DDD !important; + text-shadow: 0 1px 1px white !important; + color: #CCC !important; + cursor: default !important; + appearance: none !important; + pointer-events: none; +} + +.button-action.disabled, .button-action.is-disabled, .button-action:disabled { + background: #55a975 !important; + border: 1px solid #60ab7d !important; + text-shadow: none !important; + color: #CCC !important; +} + +.button-primary.disabled, .button-primary.is-disabled, .button-primary:disabled { + background: #8fc2e7 !important; + border: 1px solid #98adbd !important; + text-shadow: none !important; + color: #f5f5f5 !important; +} + +.button-block { + width: 100%; +} + +.button-primary { + border-color: #088ef0; + background: -webkit-gradient(linear, left top, left bottom, from(#34a5f8), to(#088ef0)); + background: linear-gradient(#34a5f8, #088ef0); + color: white; +} + +.button-primary:active, .button-primary.active, .button-primary.is-active, .button-primary-flat:active, .button-primary-flat.active, .button-primary-flat.is-active { + background-color: #2798eb; + border-color: #2798eb; + color: #bedef5; +} + +.button-action { + border-color: #08bf4e; + background: -webkit-gradient(linear, left top, left bottom, from(#0dca47), to(#05c04e)); + background: linear-gradient(#0dca47, #05c04e); + color: white; +} + +.button-action:active, .button-action.active, .button-action.is-active, .button-action-flat:active, .button-action-flat.active, .button-action-flat.is-active { + background-color: #27eb41; + border-color: #27eb41; + color: #bef5ca; +} + +.button-danger { + border-color: #f00808; + background: -webkit-gradient(linear, left top, left bottom, from(#f83434), to(#f00808)); + background: linear-gradient(#f83434, #f00808); + color: white; +} + +.button-giant { + font-size: 28px; + height: 70px; + line-height: 70px; + padding: 0 70px; +} + +.button-jumbo { + font-size: 24px; + height: 60px; + line-height: 60px; + padding: 0 60px; +} + +.button-large { + font-size: 20px; + height: 50px; + line-height: 50px; + padding: 0 50px; +} + +.button-normal { + font-size: 16px; + height: 40px; + line-height: 38px; + padding: 0 40px; +} + +.button-small { + height: 30px; + line-height: 29px; + padding: 0 30px; +} + +.button-tiny { + font-size: 9.6px; + height: 24px; + line-height: 24px; + padding: 0 24px; +} + +a { + color: #0d6efd; + text-decoration: none; +} + +a:hover { + text-decoration: underline; +} + +.hidden { + display: none; +} + +section { + padding: 10px; + overflow: hidden; + width: 100%; + padding-right: 20px; + padding-left: 20px; + box-sizing: border-box; +} +#app-list{ + display: none; +} +#app-list-table > thead{ + font-size:14px; background-color: #f7fafc; border-top: 1px solid #DDD; text-transform: uppercase; color: #6d767d; + cursor: default; +} +.app-card { + padding: 12px; + border-top: 1px solid #d8dce5; + border-radius: 0; + clear: both; + background: white; + overflow: hidden; + position: relative; +} + +.app-card:hover { + background-color: #e8eff66e; +} +.app-card.active { + background-color: #e8eff6; +} + +.app-card:hover .app-row-toolbar{ + display: block; +} + +.app-card h1 { + margin-top: 0; + color: #657188; + font-weight: 400; + font-size: 25px; +} + +#create-app-success { + height: calc(100vh - 40px); + overflow: hidden; + text-align: center; + display: flex; + flex-direction: column; + justify-content: center; + box-sizing: border-box; +} + +label, input[type="text"] { + display: block; +} + +#delete-app { + cursor: pointer; + float: left; + margin-top: 30px; + color: red; + font-size: 13px; +} + +#delete-app:hover { + text-decoration: underline; +} + +input[type="text"], textarea { + display: block; + width: 100%; + height: 34px; + padding: 6px 12px; + font-size: 14px; + line-height: 1.42857143; + color: #000000; + background-color: #fff; + background-image: none; + border: 1px solid #ccc; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%); + box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%); + -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + -webkit-transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s; + transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s, -webkit-box-shadow ease-in-out .15s; + box-sizing: border-box; +} + +textarea { + height: 200px; +} + +label { + margin-top: 20px; + font-size: 15px; +} + +.error { + border: 1px solid red; + color: red; + padding: 10px; + border-radius: 3px; +} + +.success { + border: 1px solid rgb(43 151 43); + color: rgb(7 135 7); + padding: 15px; + border-radius: 3px; + background: #ddf3dd; +} +#edit-app{ + display: none; +} +#create-app-error, #edit-app-error, #jip-error { + display: none; +} + +#edit-app-success { + position: relative; + display: none; +} + +.link-span { + cursor: pointer; +} + +.link-span:hover { + text-decoration: underline; +} + +#new-app-icon, #edit-app-icon { + width: 80px; + height: 80px; + border: 1px solid; + background-repeat: no-repeat; + background-position: center; + background-size: cover; + cursor: pointer; + background-image: url(../img/app.svg); + background-color: white; +} + +#new-app-icon-delete, #edit-app-icon-delete { + display: none; + color: red; + cursor: pointer; + width: 100px; +} + +#new-app-icon-delete:hover, #edit-app-icon-delete:hover { + text-decoration: underline; +} + +#change-app-icon { + width: 80px; + height: 80px; + background-color: rgb(0 0 0 / 37%); + color: white; + display: none; + flex-direction: column; + justify-content: center; + align-items: center; + text-align: center; + font-size: 15px; + font-weight: bold; +} + +#new-app-icon:hover #change-app-icon { + display: flex; +} + +.edit-app, .open-app-btn, .app-card-link, .delete-app, .add-app-to-desktop, .delete-app-settings { + color: #000000; + cursor: pointer; + font-size: 13px; +} +.delete-app, .delete-app-settings{ + color: red; +} +.edit-app:hover, .open-app-btn:hover, .app-card-link:hover img, +.delete-app-settings:hover, +.delete-app:hover, .add-app-to-desktop:hover { + text-decoration: underline; +} + +.app-card-link:hover{ + text-decoration: underline; +} + +.edit-app img { + width: 25px; + height: 25px; +} + +#new-app-filetype-associations, #edit-app-filetype-associations { + font-family: monospace; +} + +.sidebar { + position: fixed; + top: 0; + bottom: 0; + left: 0; + z-index: 1000; + display: block; + padding: 20px; + overflow-x: hidden; + overflow-y: auto; + background-color: white; + border-right: 1px solid #e1e1e1; + width: 250px; + color: rgb(51, 51, 51); + font-weight: 400; +} + +.sidebar-nav { + padding-left: 0; + list-style: none; + margin-right: -21px; + margin-bottom: 20px; + margin-left: -20px; + margin-top: 0; +} + +.sidebar-nav>li { + position: relative; + display: block; + padding: 10px 20px; + cursor: pointer; +} + +.sidebar-nav>li.active { + color: #fff; + background-color: #3273dc; +} + +.sidebar hr { + margin-top: 20px; + margin-bottom: 20px; + border: 0; + border-top: 1px solid #eeeeee; +} + +.main { + width: calc(100% - 265px); + left: 250px; + top: 0px; + position: absolute; + box-sizing: border-box; + padding: 20px; + padding-right: 0; + display: flex; + flex-direction: column; +} + +.main>section { + background-color: white; + box-shadow: 0px 0px 3px #E1E1E1; + border: 1px solid #e1e1e1; + border-radius: 3px; +} + +.link-to-docs{ + color: #586373; + font-size: 15px; +} +.link-to-docs, .link-to-docs:hover { + text-decoration: none; +} +.link-to-docs img{ + width: 12px; + margin-bottom: -1px; +} +.tab-btn { + background-size: 20px; + background-repeat: no-repeat; + display: block; + background-position: 20px; + padding-left: 50px !important; +} + +.tab-btn.active[data-tab="apps"] { + background-image: url(../img/apps-outline-white.svg); +} + +.tab-btn[data-tab="apps"] { + background-image: url(../img/apps-outline-black.svg); +} + +.tab-btn[data-tab="payout-method"] { + background-image: url(../img/wallet.svg); +} + +.tab-btn.active[data-tab="payout-method"] { + background-image: url(../img/wallet-white.svg); +} + +.app-icon { + margin-bottom: 0; + width: 65px; + height: 65px; + float: left; + margin-right: 10px; + border: 1px solid #CCC; + background-color: #f6faff; + border-radius: 3px; + padding: 3px; + box-sizing: border-box; +} + +#no-apps-notice, #loading { + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + box-sizing: border-box; + background: none; + border: none; + box-shadow: none; + height: calc(100vh - 100px); +} + +.table { + width: 100%; + max-width: 100%; + margin-bottom: 20px; +} + +table { + background-color: transparent; +} + +table { + border-collapse: collapse; + border-spacing: 0; +} + +.table>caption+thead>tr:first-child>th, .table>colgroup+thead>tr:first-child>th, .table>thead:first-child>tr:first-child>th, .table>caption+thead>tr:first-child>td, .table>colgroup+thead>tr:first-child>td, .table>thead:first-child>tr:first-child>td { + border-top: 0; +} + +.table>thead>tr>th { + border-bottom: 1px solid #ddd; +} + +.table>thead>tr>th { + vertical-align: bottom; + border-bottom: 2px solid #ddd; +} + +.table>thead>tr>th, .table>tbody>tr>th, .table>tfoot>tr>th, .table>thead>tr>td, .table>tbody>tr>td, .table>tfoot>tr>td { + padding: 8px; + line-height: 1.42857143; + vertical-align: top; +} +.table>thead>tr>th{ + padding: 5px; +} +th { + text-align: left; + padding-bottom: 0 !important; +} + +td, th { + padding: 0; +} +th.sorted{ + color:black; +} +.app-card-title { + font-size: 16px; + display: block; + margin: 0; + font-weight: 500; + color: #414b56; + cursor: pointer; + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; + max-width: 350px; + margin-bottom: 0; +} + +.app-card-link { + display: inline-block; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + color: #0074ff; + opacity: 1; +} + +#payout-method-email { + margin-top: 13px; + margin-left: 5px; + font-size: 18px; + display: inline-block; +} + +#join-incentive-program { + padding: 0; + display: none; + margin-bottom: 30px; +} + +#jip-success { + padding: 20px; + position: relative; + display: none; + padding: 20px 35px 30px; + color: #094509; + background-color: #e6ffe6; +} + +.close-message { + position: absolute; + right: 15px; + top: 10px; + font-size: 25px; + opacity: 0.5; + cursor: pointer; +} + +.close-message:hover { + opacity: 1; +} + +.disable-user-select { + cursor: default; + -webkit-touch-callout: none !important; + -webkit-user-select: none !important; + -khtml-user-select: none !important; + -moz-user-select: none !important; + -ms-user-select: none !important; + user-select: none !important; +} + +.my-apps-title { + font-size: 27px; + margin-top: 0px; + float: left; + font-weight: 500; + margin-bottom: 15px; + color: #394254; +} + +.app-row-toolbar{ + margin-top: -7px; + display: none; + width: 350px; +} + +.app-row-toolbar img { + opacity: 0.5; +} + +.app-row-toolbar img:hover { + opacity: 1; +} + +ol { + counter-reset: olcounter; + margin: 0; + padding: 0; + list-style-type: none; + margin-top: 25px; + margin-bottom: 20px; +} + +ol li { + list-style-type: none; + position: relative; + margin-bottom: 10px; + padding-bottom: 20px; + font-size: 16px; + position: relative; + margin-bottom: 10px; + padding-left: 35px; + padding-top: 3px; +} + +ol li:before { + counter-increment: olcounter; + content: counter(olcounter); + margin-right: 5px; + font-size: 80%; + background-color: #8296af; + color: white; + font-weight: bold; + border-radius: 2px; + position: absolute; + left: 0; + top: 0; + text-align: center; + padding: 3px; + width: 20px; + font-size: 15px; +} +.sort-arrow{ + display: none; + padding: 3px; +} + +.disable-user-select { + cursor: default; + -webkit-touch-callout: none !important; + -webkit-user-select: none !important; + -khtml-user-select: none !important; + -moz-user-select: none !important; + -ms-user-select: none !important; + user-select: none !important; +} + +#new-app-title, #new-app-name, #edit-app-title, #edit-app-name{ + max-width: 300px; +} +.app-uid{ + font-family: monospace; +} +.app-url{ + font-size: 15px; +} + +.section-tab-buttons{ + border-bottom: 1px solid #ddd; + padding-left: 0; + margin-bottom: 20px; + list-style: none; + box-sizing: border-box; + height: 44px; +} +.section-tab-buttons > li { + float: left; + margin-bottom: -1px; + position: relative; + display: block; +} +.section-tab-buttons > li > span { + position: relative; + display: block; + padding: 10px 15px; + margin-right: 5px; + line-height: 1.42857143; + border: 1px solid transparent; + border-radius: 4px 4px 0 0; + color: #5a5a5a; +} +.section-tab-buttons > li:hover > span{ + cursor: pointer; + border-bottom:none; + background-color:#f7f7f7; +} +.section-tab-buttons > li.active > span{ + color: #000000; + cursor: default; + background-color: #fff; + border: 1px solid #ddd; + border-bottom-color: transparent; +} +.section-tab{ + display: none; +} +.section-tab.active{ + display: block; +} + +.drop-area{ + width: 100%; + height: 300px; + background: #f7f7f742; + border: 2px dashed #CCC; + border-radius: 5px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + cursor: default; + font-size: 20px; + color: #717171; + transition: all 0.3s ease; + text-align: center; + box-sizing: border-box; +} +.drop-area-ready-to-deploy{ + background: #ebf6ff; + color: #0074ce; + border: 2px solid #0074ce; +} +.drop-area-hover{ + border:2px dashed black; + background-color: #f2f2f2; + color: black; +} +.deploy-btn{ + margin-bottom: 20px; + margin-top:10px; +} +.deploy-success-msg{ + display: none; + margin-bottom: 10px; + position: relative; +} +#earn-money{ + max-width:600px; + position: relative; + color: #3d4750; + font-smoothing: antialiased; + -webkit-font-smoothing: antialiased; + -moz-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + padding: 40px; + box-sizing: border-box; +} +#earn-money::backdrop { + background-color: rgba(0, 0, 0, 0.4); +} + +.create-an-app-btn{ + float:right; margin-bottom: 10px; +} +.create-an-app-btn img{ + width: 20px; + margin-bottom: -5px; + margin-right: 10px; +} +.jip-submit-btn{ + float: left; + margin-top: 10px; + margin-bottom: 20px; +} +.ip-terms-notice{ + font-size: 12px; margin-top: 20px; margin-bottom: 0; +} +.app-list-nav{ + overflow: hidden; margin-bottom: 40px; margin-top: 10px; +} +.back-to-main-btn{ + float:right; margin-bottom: 10px; +} +.edit-app-navbar{ + overflow: hidden; margin-bottom: 60px; margin-top: 20px; +} +.app-title{ + margin-top:0px; + margin-bottom: 0; +} +.close-success-msg{ + float: right; + font-size: 20px; + cursor: pointer; + line-height: 16px; + position: absolute; + top: 5px; + right: 10px; +} + +.close-success-msg:hover{ + color: black; +} +.th-name{ + padding-left: 10px !important; +} +.edit-app-save-btn{ + float: right; + margin-top: 20px; + margin-bottom: 20px; +} +input:read-only { + background-color: rgb(242 242 242); +} + +dialog{ + border: 1px solid #CCC; + border-radius: 5px; + box-shadow: 0px 0px 5px #949494; + outline: none; +} +.new-app-modal, .deleting-app-modal, .loading-modal{ + padding: 60px 50px; + width: 150px; + text-align: center; +} + +.insta-deploy-to-new-app, .insta-deploy-to-existing-app{ + float: left; + width: 190px; + height: 220px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + cursor: pointer; + border: 2px solid #cdcdcd; + padding: 10px; + border-radius: 5px; + color: #5f5e5e; + font-size: 18px; +} +.insta-deploy-to-new-app:hover, .insta-deploy-to-existing-app:hover{ + border: 2px solid #0074ce; + color: #00477d; + background-color: #f3faff; +} +.insta-deploy-to-new-app{ + margin-right: 15px; +} +.insta-deploy-cancel, .insta-deploy-existing-app-back{ + clear: both; + margin-top: 15px; + font-size: 13px; + color: #626262; + cursor: pointer; + display: inline-block; +} +.insta-deploy-existing-app-back{ + margin: 0; + position: absolute; + top: 10px; + right: 12px; +} +.insta-deploy-cancel:hover, .insta-deploy-existing-app-back:hover{ + color: #000; +} +.insta-deploy-app-selector{ + height: 70px; + overflow: hidden; + cursor: pointer; + padding: 10px; + border-radius: 5px; + background: #eeeeee63; + margin-bottom: 10px; + box-sizing: border-box; + border: 2px solid transparent; +} +.insta-deploy-app-selector:hover{ + background-color: #EEE; +} +.insta-deploy-app-selector.active{ + background-color: #e3ebf0; + border: 2px solid #0074ce +} + +.insta-deploy-app-icon{ + width: 50px; + height: 50px; + float:left; + margin-right:20px; +} +.insta-deploy-existing-app-list{ + height: 300px; + width: 300px; + overflow-y: scroll; + overflow-x: hidden; + border: 1px solid #EEE; + border-radius: 5px; + padding: 10px; + box-shadow: 1px 2px 5px inset #EEE; + +} + +.insta-deploy-existing-app-list::-webkit-scrollbar { + display: none; +} + +.no-existing-apps{ + margin-top: 20px; + font-size: 15px; + color: #777777; + text-align: center; + cursor: default; +} + +.search { + border-radius: 5px; + background-repeat: no-repeat; + width: 100%; + box-sizing: border-box; + background-color: white; + padding: 5px; + background-size: 20px; + background-position-y: center; + background-position-x: 5px; + padding-left: 35px; + padding-right: 35px; + border: 2px solid #CCC; +} + +.search-clear { + display: none; + position: absolute; + right: 6px; + top: 6px; + opacity: 0.3; + height: 20px; +} + +.search-clear:hover { + opacity: 1; +} diff --git a/src/dev-center/img/app-outline-black.svg b/src/dev-center/img/app-outline-black.svg new file mode 100644 index 0000000000..01b34c7639 --- /dev/null +++ b/src/dev-center/img/app-outline-black.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/dev-center/img/app-outline-white.svg b/src/dev-center/img/app-outline-white.svg new file mode 100644 index 0000000000..76fccc1a66 --- /dev/null +++ b/src/dev-center/img/app-outline-white.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/dev-center/img/app.svg b/src/dev-center/img/app.svg new file mode 100644 index 0000000000..a2461f009f --- /dev/null +++ b/src/dev-center/img/app.svg @@ -0,0 +1,295 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + diff --git a/src/dev-center/img/apps-black.svg b/src/dev-center/img/apps-black.svg new file mode 100644 index 0000000000..1a64c7561b --- /dev/null +++ b/src/dev-center/img/apps-black.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/dev-center/img/apps-outline-black.svg b/src/dev-center/img/apps-outline-black.svg new file mode 100644 index 0000000000..af0d1d0a27 --- /dev/null +++ b/src/dev-center/img/apps-outline-black.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/dev-center/img/apps-outline-white.svg b/src/dev-center/img/apps-outline-white.svg new file mode 100644 index 0000000000..93eca8bfbd --- /dev/null +++ b/src/dev-center/img/apps-outline-white.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/dev-center/img/close.svg b/src/dev-center/img/close.svg new file mode 100644 index 0000000000..fdcc4e8243 --- /dev/null +++ b/src/dev-center/img/close.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/dev-center/img/dev-center.svg b/src/dev-center/img/dev-center.svg new file mode 100644 index 0000000000..abc6d75898 --- /dev/null +++ b/src/dev-center/img/dev-center.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/dev-center/img/external-link.svg b/src/dev-center/img/external-link.svg new file mode 100644 index 0000000000..03f68d5582 --- /dev/null +++ b/src/dev-center/img/external-link.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/dev-center/img/loading.svg b/src/dev-center/img/loading.svg new file mode 100644 index 0000000000..792e72959a --- /dev/null +++ b/src/dev-center/img/loading.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/dev-center/img/magnifier-outline.svg b/src/dev-center/img/magnifier-outline.svg new file mode 100644 index 0000000000..331805416f --- /dev/null +++ b/src/dev-center/img/magnifier-outline.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/dev-center/img/money-bag-white.svg b/src/dev-center/img/money-bag-white.svg new file mode 100644 index 0000000000..acac0725d7 --- /dev/null +++ b/src/dev-center/img/money-bag-white.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/dev-center/img/money-bag.svg b/src/dev-center/img/money-bag.svg new file mode 100644 index 0000000000..fb94cc5641 --- /dev/null +++ b/src/dev-center/img/money-bag.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/dev-center/img/paypal.svg b/src/dev-center/img/paypal.svg new file mode 100644 index 0000000000..def61935eb --- /dev/null +++ b/src/dev-center/img/paypal.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/dev-center/img/settings.svg b/src/dev-center/img/settings.svg new file mode 100644 index 0000000000..30cfaa386f --- /dev/null +++ b/src/dev-center/img/settings.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/dev-center/img/users.svg b/src/dev-center/img/users.svg new file mode 100644 index 0000000000..341861a40d --- /dev/null +++ b/src/dev-center/img/users.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/dev-center/img/views.svg b/src/dev-center/img/views.svg new file mode 100644 index 0000000000..393b485db1 --- /dev/null +++ b/src/dev-center/img/views.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/dev-center/img/wallet-white.svg b/src/dev-center/img/wallet-white.svg new file mode 100644 index 0000000000..40e167f07c --- /dev/null +++ b/src/dev-center/img/wallet-white.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/dev-center/img/wallet.svg b/src/dev-center/img/wallet.svg new file mode 100644 index 0000000000..6c9d247db6 --- /dev/null +++ b/src/dev-center/img/wallet.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/dev-center/index.html b/src/dev-center/index.html new file mode 100644 index 0000000000..26e191fd13 --- /dev/null +++ b/src/dev-center/index.html @@ -0,0 +1,255 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +

Developers earn money on Puter!

+

Follow the steps below to start earning money on Puter:

+
    +
  1. Publish as many apps as you want on Puter.
  2. +
  3. We automatically review every app continuously. Qualified apps are automatically added to our Incentive Program to earn money.
  4. +
  5. You will earn money every time your approved apps are opened by users.
  6. +
+ +
+ Questions? Contact us: hi@puter.com + Incentive Program Terms +
+ + + + +
+
+

Great News!

+

You are approved to join the Puter Incentive Program: A revolutionary, invite-only program to earn money every time your apps are opened!

+

Please use the following form to join the program.

+
+
+
+ +
+
+ + +
+ +
+ + +
+
+ +
+ + +
+
+ +

By clicking Join Now, you agree to our Incentive Program Terms.

+ +
+
+
+

🎉 Congratulations!

+

You have successfully joined the Puter Incentive Program. You will start earning money from your eligible apps.

+

Please do not hesitate to contact us at hey@puter.com should you have any questions.

+ +
+
+ + + + + + + + + + + + + + + + + + + +
+
+ + + + + + +

Creating new app...

+
+ + + + + + +

Deleting app...

+
+ + + + + + +

Loading...

+
+ + + + + + +

Deploy to:

+
+
New App
+
An Existing App
+
+ Cancel +
+ + + Back +

Select app to deploy to:

+
+ +
Cancel
+
+ + + + +
+
+

My Apps

+ + +
+ +
+ + +
+ + + + + + + + + + + + + + + + +
AppUsersOpensCreated
+
+
+ + + + + + + + + + + \ No newline at end of file diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js new file mode 100644 index 0000000000..c154f26ce3 --- /dev/null +++ b/src/dev-center/js/dev-center.js @@ -0,0 +1,1844 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + +let URLParams = new URLSearchParams(window.location.search); +let domain = 'puter.com', authUsername; +let source_path +let apps = []; +let sortBy = 'created_at'; +let sortDirection = 'desc'; +const dev_center_uid = 'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77'; +let developer; +let activeTab = 'apps'; +let currently_editing_app; +let dropped_items; +let search_query; + +const deploying_spinner = ``; +const loading_spinner = ``; +const drop_area_placeholder = `

Drop your app folder and files here to deploy.

HTML, JS, CSS, ...

`; +const index_missing_error = `Please upload an 'index.html' file or if you're uploading a directory, make sure it contains an 'index.html' file at its root.` + +// authUsername +if (URLParams.has('puter.auth.username')) { + authUsername = URLParams.get('puter.auth.username'); +} else { + //todo error and terminate +} + +// source_path +if (URLParams.has('source_path')) { + source_path = URLParams.get('source_path'); +} else { + source_path = null; +} + +// domain and APIOrigin +if (URLParams.has('puter.domain')) { + domain = URLParams.get('puter.domain') +} + +$(document).ready(function () { + $('#loading').show(); + + // get dev profile + setTimeout(function () { + puter.ui.onLaunchedWithItems(async function (items) { + source_path = items[0].path; + // if source_path is provided, this means that the user is creating a new app/updating an existing app + // by deploying an existing Puter folder. So we create the app and deploy it. + if (source_path) { + // todo if there are no apps, go straight to creating a new app + $('.insta-deploy-modal').get(0).showModal(); + // set item name + $('.insta-deploy-item-name').html(html_encode(items[0].name)); + } + }) + + puter.apps.getDeveloperProfile(async function (dev_profile) { + developer = dev_profile; + if (dev_profile.approved_for_incentive_program && !dev_profile.joined_incentive_program) { + $('#join-incentive-program').show(); + } + + // show earn money c2a only if dev is not approved for incentive program or has already joined + if (!dev_profile.approved_for_incentive_program || dev_profile.joined_incentive_program) { + puter.kv.get('earn-money-c2a-closed').then((value) => { + if (value?.result || value === true || value === "true") + return; + + $('#earn-money').get(0).showModal(); + }); + } + + // get apps + puter.apps.list().then((resp) => { + apps = resp; + + // hide loading + $('#loading').hide(); + + // set apps + if (apps.length > 0) { + if (activeTab === 'apps') { + $('#no-apps-notice').hide(); + $('#app-list').show(); + } + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + sort_apps(); + } else { + $('#no-apps-notice').show(); + } + }) + // show payout method tab if dev has joined incentive program + if (dev_profile.joined_incentive_program) { + $('.tab-btn[data-tab="payout-method"]').show(); + $('#payout-method-email').html(dev_profile.paypal); + } + }) + }, 1000); +}); + +function refresh_app_list(show_loading = false) { + if (show_loading) + $('#loading').show(); + // get apps + setTimeout(function () { + puter.apps.list().then((apps_res) => { + $('#loading').hide(); + apps = apps_res; + if (apps.length > 0) { + if (activeTab === 'apps') { + $('#no-apps-notice').hide(); + $('#app-list').show(); + } + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + sort_apps(); + } else { + $('#no-apps-notice').show(); + $('#app-list').hide() + } + }) + }, show_loading ? 1000 : 0); +} + +$(document).on('click', '.tab-btn', function (e) { + $('section:not(.sidebar)').hide(); + $('.tab-btn').removeClass('active'); + $(this).addClass('active'); + $('section[data-tab="' + $(this).attr('data-tab') + '"]').show(); + + // ------------------------------ + // Apps tab + // ------------------------------ + if ($(this).attr('data-tab') === 'apps') { + refresh_app_list(); + activeTab = 'apps'; + } + // ------------------------------ + // Payout Method tab + // ------------------------------ + else if ($(this).attr('data-tab') === 'payout-method') { + activeTab = 'payout-method'; + $('#loading').show(); + setTimeout(function () { + puter.apps.getDeveloperProfile(function (dev_profile) { + // show payout method tab if dev has joined incentive program + if (dev_profile.joined_incentive_program) { + $('#payout-method-email').html(dev_profile.paypal); + } + $('#loading').hide(); + if (activeTab === 'payout-method') + $('#tab-payout-method').show(); + }) + }, 1000); + } +}) + +$(document).on('click', '.create-an-app-btn', async function (e) { + let title = await puter.ui.prompt('Please enter a title for your app:', 'My Awesome App'); + + if (title.length > 60) { + puter.ui.alert(`Title cannot be longer than 60.`, [ + { + label: 'Ok', + }, + ]); + // todo go back to create an app prompt and prefill the title input with the title the user entered + return; + } + else if (title) { + create_app(title); + } +}) + +async function create_app(title, source_path = null, items = null) { + // name + let name = slugify(title + '-' + Math.random().toString(36).substring(2), { + lower: true, + strict: true, + }); + + // icon + let icon = await getBase64ImageFromUrl('./img/app.svg'); + + // open the 'Creting new app...' modal + let start_ts = Date.now(); + $('.new-app-modal').get(0).showModal(); + + //---------------------------------------------------- + // Create app + //---------------------------------------------------- + puter.apps.create({ + title: title, + name: name, + indexURL: 'https://dev-center.puter.com/coming-soon.html', + icon: icon, + description: ' ', + maximizeOnStart: false, + background: false, + }) + .then(async (app) => { + let app_dir; + // ---------------------------------------------------- + // Create app directory in AppData + // ---------------------------------------------------- + app_dir = await puter.fs.mkdir( + `/${authUsername}/AppData/${dev_center_uid}/${app.uid}`, + { overwrite: true, recursive: true, rename: false } + ); + // ---------------------------------------------------- + // Create a router for the app with a fresh hostname + // ---------------------------------------------------- + const route = await puter.hosting.create(name, app_dir.path); + + // ---------------------------------------------------- + // Update the app with the new hostname + // ---------------------------------------------------- + puter.apps.update(app.name, { + title: title, + name: name, + indexURL: source_path ? `https://${name}.puter.site` : 'https://dev-center.puter.com/coming-soon.html', + icon: icon, + description: ' ', + maximizeOnStart: false, + background: false, + }).then(async (app) => { + // refresh app list + puter.apps.list().then(async (resp) => { + apps = resp; + // Close the 'Creting new app...' modal + // but make sure it was shown for at least 2 seconds + setTimeout(() => { + // open edit app section + edit_app_section(app.name); + // set drop area if source_path was provided or items were dropped + if (source_path || items) { + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + } + $('.new-app-modal').get(0).close(); + // deploy app if source_path was provided + if (source_path) { + deploy(app, source_path); + } else if (items) { + deploy(app, items); + } + + }, (Date.now() - start_ts) > 2000 ? 1 : 2000 - (Date.now() - start_ts)); + }) + }).catch(async (err) => { + console.log(err); + }) + // ---------------------------------------------------- + // Create a "shortcut" on the desktop + // ---------------------------------------------------- + puter.fs.upload(new File([], app.title), + `/${authUsername}/Desktop`, + { + name: app.title, + dedupeName: true, + overwrite: false, + appUID: app.uid, + } + ) + }).catch(async (err) => { + $('#create-app-error').show(); + $('#create-app-error').html(err.message); + // scroll to top so that user sees error message + document.body.scrollTop = document.documentElement.scrollTop = 0; + }) +} + +$(document).on('click', '.deploy-btn', function (e) { + deploy(currently_editing_app, dropped_items); +}) + +$(document).on('click', '.edit-app, .got-to-edit-app', function (e) { + const cur_app_name = $(this).attr('data-app-name') + edit_app_section(cur_app_name); +}) + +$(document).on('click', '.delete-app', async function (e) { + let app_uid = $(this).attr('data-app-uid'); + let app_title = $(this).attr('data-app-title'); + let app_name = $(this).attr('data-app-name'); + + // confirm delete + const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete "${html_encode(app_title)}"?`, + [ + { + label: 'Yes, delete permanently', + value: 'delete', + type: 'danger', + }, + { + label: 'Cancel' + }, + ] + ); + + if (alert_resp === 'delete') { + let init_ts = Date.now(); + $('.deleting-app-modal')?.get(0)?.showModal(); + puter.apps.delete(app_name).then(async (app) => { + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + $(`.app-card[data-uid="${app_uid}"]`).fadeOut(200, function name(params) { + $(this).remove(); + if ($(`.app-card`).length === 0) { + $('section:not(.sidebar)').hide(); + $('#no-apps-notice').show(); + } else { + $('section:not(.sidebar)').hide(); + $('#app-list').show(); + } + }); + }, + // make sure the modal was shown for at least 2 seconds + (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts)); + + // get app directory + puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + returnSubdomains: true, + }).then(async (stat) => { + // delete subdomain associated with the app dir + puter.hosting.delete(stat.subdomains[0].subdomain) + // delete app directory + puter.fs.delete( + `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + { recursive: true } + ) + }) + }).catch(async (err) => { + setTimeout(() => { + + $('.deleting-app-modal')?.get(0)?.close(); + puter.ui.alert(err?.message, [ + { + label: 'Ok', + }, + ]); + }, + // make sure the modal was shown for at least 2 seconds + (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts)); + }) + } +}) + +// generate app link +function applink(app) { + return `https://${domain}/app/${app.name}`; +} + +//---------------------------------------------------- +// Generate the 'App Settings' section +//---------------------------------------------------- +function generate_edit_app_section(app) { + if(app.result) + app = app.result; + + let h = ``; + h += ` +
+
+ +

${html_encode(app.title)}

+
+ Open + + Add Shortcut to Desktop + + Delete +
+ ${html_encode(applink(app))} +
+ +
+ +
    +
  • Deploy
  • +
  • Settings
  • +
+ +
+
+ New version deployed successfully 🎉× +

Give it a try!

+
+
${drop_area_placeholder}
+ +
+ +
+
+
+
App has been successfully updated.×
+ + + + + + + + + + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
Change App Icon
+
+ Remove icon + + + + + +

A comma-separated list of file type specifiers. For example if you include .txt, your apps could be opened when a user clicks on a TXT file.

+ + + +
+
+ ` + return h; +} + +async function edit_app_section(cur_app_name) { + $('section:not(.sidebar)').hide(); + $('.tab-btn').removeClass('active'); + $('.tab-btn[data-tab="apps"]').addClass('active'); + + let cur_app = await puter.apps.get(cur_app_name); + currently_editing_app = cur_app; + + // generate edit app section + let edit_app_section_html = generate_edit_app_section(cur_app); + $('#edit-app').html(edit_app_section_html); + $('#edit-app').show(); + + // -------------------------------------------------------- + // Dragster + // -------------------------------------------------------- + let drop_area_content = drop_area_placeholder; + + $('.drop-area').dragster({ + enter: function (dragsterEvent, event) { + drop_area_content = $('.drop-area').html(); + $('.drop-area').addClass('drop-area-hover'); + $('.drop-area').html(drop_area_placeholder); + }, + leave: function (dragsterEvent, event) { + $('.drop-area').html(drop_area_content); + $('.drop-area').removeClass('drop-area-hover'); + }, + drop: async function (dragsterEvent, event) { + const e = event.originalEvent; + e.stopPropagation(); + e.preventDefault(); + + // hide previous success message + $('.deploy-success-msg').fadeOut(); + + // remove hover class + $('.drop-area').removeClass('drop-area-hover'); + + //---------------------------------------------------- + // Puter items dropped + //---------------------------------------------------- + if (e.detail?.items?.length > 0) { + let items = e.detail.items; + + // ---------------------------------------------------- + // one file dropped + // ---------------------------------------------------- + if (items.length === 1 && !items[0].isDirectory) { + if (items[0].name.toLowerCase() === 'index.html') { + dropped_items = items[0].path; + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + drop_area_content = `

index.html

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // enable deploy button + $('.deploy-btn').removeClass('disabled'); + + } else { + puter.ui.alert(`You need to have an index.html file in your deployment.`, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + } + return; + } + // ---------------------------------------------------- + // one directory dropped + // ---------------------------------------------------- + else if (items.length === 1 && items[0].isDirectory) { + let children = await puter.fs.readdir(items[0].path); + // check if index.html exists, if found, deploy entire directory + for (let child of children) { + if (child.name === 'index.html') { + // deploy(currently_editing_app, items[0].path); + dropped_items = items[0].path; + let rootItems = ''; + + if (children.length === 1) + rootItems = children[0].name; + else if (children.length === 2) + rootItems = children[0].name + ', ' + children[1].name; + else if (children.length === 3) + rootItems = children[0].name + ', ' + children[1].name + ', and' + children[1].name; + else if (children.length > 3) + rootItems = children[0].name + ', ' + children[1].name + ', and ' + (children.length - 2) + ' more item' + (children.length - 2 > 1 ? 's' : ''); + + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + drop_area_content = `

${rootItems}

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // enable deploy button + $('.deploy-btn').removeClass('disabled'); + return; + } + } + + // no index.html in directory + puter.ui.alert(index_missing_error, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + } + + return false; + } + + //----------------------------------------------------------------------------- + // Local items dropped + //----------------------------------------------------------------------------- + if (!e.dataTransfer || !e.dataTransfer.items || e.dataTransfer.items.length === 0) + return; + + // get dropped items + dropped_items = await puter.ui.getEntriesFromDataTransferItems(e.dataTransfer.items); + + // generate a flat array of full paths from the dropped items + let paths = []; + for (let item of dropped_items) { + paths.push('/' + (item.fullPath ?? item.filepath)); + } + + // generate a directory tree from the paths + let tree = generateDirTree(paths); + + dropped_items = setRootDirTree(tree, dropped_items); + + // alert if no index.html in root + if (!hasRootIndexHtml(tree)) { + puter.ui.alert(index_missing_error, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + return; + } + + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // generate a list of items in the root in the form of a string (e.g. /index.html, /css/style.css) with maximum of 3 items + let rootItems = ''; + + if (rootKeys.length === 1) + rootItems = rootKeys[0]; + else if (rootKeys.length === 2) + rootItems = rootKeys[0] + ', ' + rootKeys[1]; + else if (rootKeys.length === 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and' + rootKeys[1]; + else if (rootKeys.length > 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and ' + (rootKeys.length - 2) + ' more item' + (rootKeys.length - 2 > 1 ? 's' : ''); + + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + drop_area_content = `

${rootItems}

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // enable deploy button + $('.deploy-btn').removeClass('disabled'); + + return false; + } + }); + + // Focus on the first input + $('#edit-app-title').focus(); +} + +$('.jip-submit-btn').on('click', async function (e) { + const first_name = $('#jip-first-name').val(); + const last_name = $('#jip-last-name').val(); + const paypal = $('#jip-paypal').val(); + let error; + + if (first_name === '' || last_name === '' || paypal === '') + error = `All fields are required.`; + else if (first_name.length > 100) + error = `First Name cannot be longer than ${100}.`; + else if (last_name.length > 100) + error = `Last Name cannot be longer than ${100}.`; + else if (paypal.length > 100) + error = `Paypal cannot be longer than ${100}.`; + // check if email is valid + else if (!validateEmail(paypal)) + error = `Paypal email must be a valid email address.`; + + // error? + if (error) { + $('#jip-error').show(); + $('#jip-error').html(error); + document.body.scrollTop = document.documentElement.scrollTop = 0; + return; + } + + // disable submit button + $('.jip-submit-btn').prop('disabled', true); + + $.ajax({ + url: puter.APIOrigin + "/jip", + type: 'POST', + async: true, + contentType: "application/json", + data: JSON.stringify({ + first_name: first_name, + last_name: last_name, + paypal: paypal, + }), + headers: { + "Authorization": "Bearer " + puter.authToken + }, + success: function () { + $('#jip-success').show(); + $('#jip-form').hide(); + //enable submit button + $('.jip-submit-btn').prop('disabled', false); + // update dev profile + $('#payout-method-email').html(paypal); + // show payout method tab + $('.tab-btn[data-tab="payout-method"]').show(); + }, + error: function (err) { + $('#jip-error').show(); + $('#jip-error').html(err.message); + // scroll to top so that user sees error message + document.body.scrollTop = document.documentElement.scrollTop = 0; + // enable submit button + $('.jip-submit-btn').prop('disabled', false); + } + }) +}) + +$(document).on('click', '.edit-app-save-btn', async function (e) { + const title = $('#edit-app-title').val(); + const name = $('#edit-app-name').val(); + const index_url = $('#edit-app-index-url').val(); + const description = $('#edit-app-description').val(); + const uid = $('#edit-app-uid').val(); + let filetype_associations = $('#edit-app-filetype-associations').val(); + + let icon; + + let error; + + //validation + if (title === '') + error = `Title is required.`; + else if (title.length > 60) + error = `Title cannot be longer than ${60}.`; + else if (name === '') + error = `Name is required.`; + else if (name.length > 60) + error = `Name cannot be longer than ${60}.`; + else if (index_url === '') + error = `Index URL is required.`; + else if (!name.match(/^[a-zA-Z0-9-_-]+$/)) + error = `Name can only contain letters, numbers, dash (-) and underscore (_).`; + else if (!is_valid_url(index_url)) + error = `Index URL must be a valid url.`; + else if (!index_url.toLowerCase().startsWith('https://') && !index_url.toLowerCase().startsWith('http://')) + error = `Index URL must start with 'https://' or 'http://'.`; + + // download icon from URL + else { + let icon_url = $('#edit-app-icon').attr('data-url'); + let icon_base64 = $('#edit-app-icon').attr('data-base64'); + + if(icon_base64){ + icon = icon_base64; + }else if (icon_url) { + icon = await getBase64ImageFromUrl(icon_url); + let app_max_icon_size = 5 * 1024 * 1024; + if (icon.length > app_max_icon_size) + error = `Icon cannot be larger than ${byte_format(app_max_icon_size)}`; + // make sure icon is an image + else if (!icon.startsWith('data:image/') && !icon.startsWith('data:application/octet-stream')) + error = `Icon must be an image.`; + }else{ + icon = null; + } + } + + // error? + if (error) { + $('#edit-app-error').show(); + $('#edit-app-error').html(error); + document.body.scrollTop = document.documentElement.scrollTop = 0; + return; + } + + // parse filetype_associations + filetype_associations = filetype_associations.split(',').map(element => element.trim()); + // disable submit button + $('.edit-app-save-btn').prop('disabled', true); + + puter.apps.update(currently_editing_app.name, { + title: title, + name: name, + indexURL: index_url, + icon: icon, + description: description, + maximizeOnStart: $('#edit-app-maximize-on-start').is(":checked"), + background: $('#edit-app-background').is(":checked"), + metadata: { + fullpage_on_landing: $('#edit-app-fullpage-on-landing').is(":checked"), + }, + filetypeAssociations: filetype_associations, + }).then(async (app) => { + currently_editing_app = app; + $('#edit-app-error').hide(); + $('#edit-app-success').show(); + document.body.scrollTop = document.documentElement.scrollTop = 0; + // Re-enable submit button + $('.edit-app-save-btn').prop('disabled', false); + // Update open-app-btn + $(`.open-app-btn[data-app-uid="${uid}"]`).attr('data-app-name', app.name); + // Update title + $(`.app-title[data-uid="${uid}"]`).html(html_encode(app.title)); + // Update app link + $(`.app-url[data-uid="${uid}"]`).html(applink(app)); + $(`.app-url[data-uid="${uid}"]`).attr('href', applink(app)); + // Update icons + $(`.app-icon[data-uid="${uid}"]`).attr('src', html_encode(app.icon ? app.icon : './img/app.svg')); + $(`[data-app-uid="${uid}"]`).attr('data-app-title', html_encode(app.title)); + $(`[data-app-name="${uid}"]`).attr('data-app-name', html_encode(app.name)); + }).catch((err) => { + + $('#edit-app-success').hide(); + $('#edit-app-error').show(); + $('#edit-app-error').html(err.error?.message); + // scroll to top so that user sees error message + document.body.scrollTop = document.documentElement.scrollTop = 0; + // re-enable submit button + $('.edit-app-save-btn').prop('disabled', false); + }) +}) + +$(document).on('click', '.open-app-btn', async function (e) { + puter.ui.launchApp($(this).attr('data-app-name')) +}) + +$('#earn-money-c2a-close').click(async function (e) { + $('#earn-money').get(0).close(); + puter.kv.set('earn-money-c2a-closed', 'true') +}) + +$('#earn-money::backdrop').click(async function (e) { + alert(); + $('#earn-money').get(0).close(); + puter.kv.set('earn-money-c2a-closed', 'true') +}) + + + +$(document).on('click', '.edit-app-open-app-btn', async function (e) { + puter.ui.launchApp($(this).attr('data-app-name')) +}) + +$(document).on('click', '.delete-app-settings', async function (e) { + let app_uid = $(this).attr('data-app-uid'); + let app_name = $(this).attr('data-app-name'); + let app_title = $(this).attr('data-app-title'); + + // confirm delete + const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete "${html_encode(app_title)}"?`, + [ + { + label: 'Yes, delete permanently', + value: 'delete', + type: 'danger', + }, + { + label: 'Cancel' + }, + ] + ); + + if (alert_resp === 'delete') { + let init_ts = Date.now(); + $('.deleting-app-modal')?.get(0)?.showModal(); + puter.apps.delete(app_name).then(async (app) => { + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + $('.back-to-main-btn').trigger('click'); + }, + // make sure the modal was shown for at least 2 seconds + (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts)); + // get app directory + puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + returnSubdomains: true, + }).then(async (stat) => { + // delete subdomain associated with the app dir + puter.hosting.delete(stat.subdomains[0].subdomain) + // delete app directory + puter.fs.delete( + `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + { recursive: true } + ) + }) + }).catch(async (err) => { + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + puter.ui.alert(err?.message, [ + { + label: 'Ok', + }, + ]); + }, + (Date.now() - init_ts) > 2000 ? 1 : (2000 - (Date.now() - init_ts))); + }) + } +}) + +$(document).on('click', '.edit-app', async function (e) { + $('#edit-app-uid').val($(this).attr('data-app-uid')); +}) + +$(document).on('click', '.back-to-main-btn', function (e) { + $('section:not(.sidebar)').hide(); + $('.tab-btn').removeClass('active'); + $('.tab-btn[data-tab="apps"]').addClass('active'); + + // get apps + $('#loading').show(); + setTimeout(function () { + puter.apps.list().then((apps_res) => { + $('#loading').hide(); + apps = apps_res; + if (apps.length > 0) { + if (activeTab === 'apps') { + $('#no-apps-notice').hide(); + $('#app-list').show(); + } + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + sort_apps() + } else + $('#no-apps-notice').show(); + }) + }, 1000); +}) + +// https://stackoverflow.com/a/43467144/1764493 +function is_valid_url(string) { + let url; + + try { + url = new URL(string); + } catch (_) { + return false; + } + + return url.protocol === "http:" || url.protocol === "https:"; +} + +$(document).on('click', '#edit-app-icon-delete', async function (e) { + $('#edit-app-icon').css('background-image', ``); + $('#edit-app-icon').removeAttr('data-url'); + $('#edit-app-icon').removeAttr('data-base64'); + $('#edit-app-icon-delete').hide(); +}) + +$(document).on('click', '#edit-app-icon', async function (e) { + const res2 = await puter.ui.showOpenFilePicker({ + accept: "image/*", + }); + + const icon = await puter.fs.read(res2.path); + // convert blob to base64 + const reader = new FileReader(); + reader.readAsDataURL(icon); + + reader.onloadend = function () { + let image = reader.result; + // Get file extension + let fileExtension = res2.name.split('.').pop(); + // Get MIME type + let mimeType = getMimeType(fileExtension); + // Replace MIME type in the data URL + image = image.replace('data:application/octet-stream;base64', `data:image/${mimeType};base64`); + + $('#edit-app-icon').css('background-image', `url(${image})`); + $('#edit-app-icon').attr('data-base64', image); + $('#edit-app-icon-delete').show(); + } +}) + +async function getBase64ImageFromUrl(imageUrl) { + var res = await fetch(imageUrl); + var blob = await res.blob(); + + return new Promise((resolve, reject) => { + var reader = new FileReader(); + reader.addEventListener("load", function () { + resolve(reader.result); + }, false); + + reader.onerror = () => { + return reject(this); + }; + reader.readAsDataURL(blob); + }) +} + +function generate_app_card(app) { + let h = ``; + h += ``; + // check box + h += ``; + h += `
`; + h += ``; + h += `
`; + h += ``; + // App info + h += ``; + // Icon + h += `
`; + // Info + h += `
`; + // Title + h += `

${html_encode(app.title)}

`; + h += `${html_encode(applink(app))}`; + + // toolbar + h += `
`; + + // Open + h += `Open`; + h += ``; + + // Settings + h += `Settings`; + h += ``; + + // add to desktop + h += `Add Shortcut to Desktop` + h += ``; + + // Delete + h += `Delete`; + h += `
`; + h += ``; + + // users count + h += ``; + h += `${number_format((app.stats.referral_count ?? 0) + app.stats.user_count)}`; + h += ``; + + // opens + h += ``; + h += `${number_format(app.stats.open_count)}`; + h += ``; + + // Created + h += ``; + h += `${moment(app.created_at).format('MMM Do, YYYY')}`; + h += ``; + + h += ``; + // // Open App + // h += ``; + // // Settings + // h += ``; + // "Approved for incentive program" + if (app.approved_for_incentive_program) + h += `✔ Incentive Program`; + h += ``; + h += ``; + return h; +} + + +/** + * Formats a binary-byte integer into the human-readable form with units. + * + * @param {integer} bytes + * @returns + */ +window.byte_format = (bytes) => { + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + if (bytes === 0) return '0 Byte'; + const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; +}; + +function validateEmail(email) { + var re = /\S+@\S+\.\S+/; + return re.test(email); +} + +/** + * Formats a number with grouped thousands. + * + * @param {number|string} number - The number to be formatted. If a string is provided, it must only contain numerical characters, plus and minus signs, and the letter 'E' or 'e' (for scientific notation). + * @param {number} decimals - The number of decimal points. If a non-finite number is provided, it defaults to 0. + * @param {string} [dec_point='.'] - The character used for the decimal point. Defaults to '.' if not provided. + * @param {string} [thousands_sep=','] - The character used for the thousands separator. Defaults to ',' if not provided. + * @returns {string} The formatted number with grouped thousands, using the specified decimal point and thousands separator characters. + * @throws {TypeError} If the `number` parameter cannot be converted to a finite number, or if the `decimals` parameter is non-finite and cannot be converted to an absolute number. + */ +function number_format(number, decimals, dec_point, thousands_sep) { + // Strip all characters but numerical ones. + number = (number + '').replace(/[^0-9+\-Ee.]/g, ''); + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), + sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, + dec = (typeof dec_point === 'undefined') ? '.' : dec_point, + s = '', + toFixedFix = function (n, prec) { + var k = Math.pow(10, prec); + return '' + Math.round(n * k) / k; + }; + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.'); + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); + } + if ((s[1] || '').length < prec) { + s[1] = s[1] || ''; + s[1] += new Array(prec - s[1].length + 1).join('0'); + } + return s.join(dec); +} + +$(document).on('click', '.close-message', function () { + $($(this).attr('data-target')).fadeOut(); +}); + +$('th.sort').on('click', function (e) { + // determine what column to sort by + const sortByColumn = $(this).attr('data-column'); + + // toggle sort direction + if (sortByColumn === sortBy) { + if (sortDirection === 'asc') + sortDirection = 'desc'; + else + sortDirection = 'asc'; + } + else { + sortBy = sortByColumn; + sortDirection = 'desc'; + } + + // update arrow + $('.sort-arrow').css('display', 'none'); + $('#app-list-table').find('th').removeClass('sorted'); + $(this).find('.sort-arrow-' + sortDirection).css('display', 'inline'); + $(this).addClass('sorted'); + + sort_apps(); +}); + +function sort_apps() { + let sorted_apps; + + // sort + if (sortDirection === 'asc') + sorted_apps = apps.sort((a, b) => a[sortBy] > b[sortBy] ? 1 : -1); + else + sorted_apps = apps.sort((a, b) => a[sortBy] < b[sortBy] ? 1 : -1); + + // refresh app list + $('.app-card').remove(); + sorted_apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + + // show apps that match search_query and hide apps that don't + if (search_query) { + // show apps that match search_query and hide apps that don't + apps.forEach((app) => { + if (app.title.toLowerCase().includes(search_query.toLowerCase())) { + $(`.app-card[data-name="${html_encode(app.name)}"]`).show(); + } else { + $(`.app-card[data-name="${html_encode(app.name)}"]`).hide(); + } + }) + } +} + +window.deploy = async function (app, items) { + let appdata_dir, current_app_dir; + + // disable deploy button + $('.deploy-btn').addClass('disabled'); + + // change drop area text + $('.drop-area').html(deploying_spinner + '
Deploying (0%)
'); + + if (typeof items === 'string' && (items.startsWith('/') || items.startsWith('~'))) { + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + } + + // -------------------------------------------------------------------- + // Get current directory, we need to delete the existing hostname + // later on + // -------------------------------------------------------------------- + try { + current_app_dir = await puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app.uid ?? app.uuid}`, + returnSubdomains: true + }); + } catch (err) { + console.log(err); + } + + // -------------------------------------------------------------------- + // Delete existing hostnames attached to this app directory if they exist + // -------------------------------------------------------------------- + if (current_app_dir?.subdomains.length > 0) { + for (let subdomain of current_app_dir?.subdomains) { + puter.hosting.delete(subdomain.subdomain) + } + } + + // -------------------------------------------------------------------- + // Delete existing app directory + // -------------------------------------------------------------------- + try { + await puter.fs.delete(current_app_dir.path) + } catch (err) { + console.log(err); + } + + // -------------------------------------------------------------------- + // Make an app directory under AppData + // if the directory already exists, it should be overwritten + // -------------------------------------------------------------------- + try { + appdata_dir = await puter.fs.mkdir( + // path + `/${authUsername}/AppData/${dev_center_uid}/${app.uid ?? app.uuid}`, + // options + { overwrite: true, recursive: true, rename: false } + ) + } catch (err) { + console.log(err); + } + + // -------------------------------------------------------------------- + // (A) Puter Items: If 'items' is a string and starts with /, it's a path to a Puter item + // -------------------------------------------------------------------- + if (typeof items === 'string' && (items.startsWith('/') || items.startsWith('~'))) { + // perform stat on 'items' + const stat = await puter.fs.stat(items); + + // Puter Directory + // Perform readdir on 'items' + // todo there is apparently a bug in Puter where sometimes path is literally missing from the items + // returned by readdir. This is the 'path' that readdit didn't return a path for: "~/Desktop/particle-clicker-master" + if (stat.is_dir) { + const files = await puter.fs.readdir(items); + // copy the 'files' to the app directory + if (files.length > 0) { + for (let file of files) { + // perform copy + await puter.fs.copy( + file.path, + appdata_dir.path, + { overwrite: true } + ); + // update progress + $('.deploy-percent').text(`(${Math.round((files.indexOf(file) / files.length) * 100)}%)`); + } + } + } + // Puter File + else { + // copy the 'files' to the app directory + await puter.fs.copy( + items, + appdata_dir.path, + { overwrite: true } + ); + } + + // generate new hostname with a random suffix + let hostname = `${currently_editing_app.name}-${(Math.random() + 1).toString(36).substring(7)}`; + + // -------------------------------------------------------------------- + // Create a router for the app with the fresh hostname + // we change hostname every time to prevent caching issues + // -------------------------------------------------------------------- + puter.hosting.create(hostname, appdata_dir.path).then(async (res) => { + // TODO this endpoint needs to be able to update only the specified fields + puter.apps.update(currently_editing_app.name, { + indexURL: `https://${hostname}.puter.site`, + title: currently_editing_app.title, + name: currently_editing_app.name, + icon: currently_editing_app.icon, + description: currently_editing_app.description, + maximizeOnStart: currently_editing_app.maximize_on_start, + background: currently_editing_app.background, + filetypeAssociations: currently_editing_app.filetype_associations, + }) + // set the 'Index URL' field for the 'Settings' tab + $('#edit-app-index-url').val(`https://${hostname}.puter.site`); + // show success message + $('.deploy-success-msg').show(); + // reset drop area + reset_drop_area(); + }) + } + + // -------------------------------------------------------------------- + // (B) Local Items: Upload new deploy + // -------------------------------------------------------------------- + else { + puter.fs.upload( + items, + `/${authUsername}/AppData/${dev_center_uid}/${currently_editing_app.uid}`, + { + dedupeName: false, + overwrite: false, + parsedDataTransferItems: true, + createMissingAncestors: true, + progress: function (operation_id, op_progress) { + $('.deploy-percent').text(`(${op_progress}%)`); + }, + }).then(async (uploaded) => { + // new hostname + let hostname = `${currently_editing_app.name}-${(Math.random() + 1).toString(36).substring(7)}`; + + // ---------------------------------------- + // Create a router for the app with a fresh hostname + // we change hostname every time to prevent caching issues + // ---------------------------------------- + puter.hosting.create(hostname, appdata_dir.path).then(async (res) => { + // TODO this endpoint needs to be able to update only the specified fields + puter.apps.update(currently_editing_app.name, { + indexURL: `https://${hostname}.puter.site`, + title: currently_editing_app.title, + name: currently_editing_app.name, + icon: currently_editing_app.icon, + description: currently_editing_app.description, + maximizeOnStart: currently_editing_app.maximize_on_start, + background: currently_editing_app.background, + filetypeAssociations: currently_editing_app.filetype_associations, + }) + // set the 'Index URL' field for the 'Settings' tab + $('#edit-app-index-url').val(`https://${hostname}.puter.site`); + // show success message + $('.deploy-success-msg').show(); + // reset drop area + reset_drop_area() + }) + }) + } +} + +$(document).on('click', '.section-tab-btn', function (e) { + // hide all tabs + $('.section-tab').hide(); + // show section + $('.section-tab[data-tab="' + $(this).attr('data-tab') + '"]').show(); + // remove active class from all tab buttons + $('.section-tab-btn').removeClass('active'); + // add active class to clicked tab button + $(this).addClass('active'); +}) + +function generateDirTree(paths) { + const root = {}; + + for (let path of paths) { + let parts = path.split('/'); + let currentNode = root; + for (let part of parts) { + if (!part) continue; // skip empty parts, especially leading one + if (!currentNode[part]) { + currentNode[part] = {}; + } + currentNode = currentNode[part]; + } + } + + return root; +} + +function setRootDirTree(tree, items) { + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // If there's only one object in the root, check if it's non-empty and return it + if (rootKeys.length === 1 && typeof tree[rootKeys[0]] === 'object' && Object.keys(tree[rootKeys[0]]).length > 0) { + let newItems = []; + for (let item of items) { + if (item.fullPath) + item.finalPath = item.fullPath.replace(rootKeys[0], ''); + else if (item.path) + item.path = item.path.replace(rootKeys[0], ''); + else + item.filepath = item.filepath.replace(rootKeys[0], ''); + + newItems.push(item); + } + return newItems; + } else { + return items; + } +} + +function hasRootIndexHtml(tree) { + // Check if index.html exists in the root + if (tree['index.html']) { + return true; + } + + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // If there's only one directory in the root, check if index.html exists in that directory + if (rootKeys.length === 1 && typeof tree[rootKeys[0]] === 'object' && tree[rootKeys[0]]['index.html']) { + return true; + } + + return false; +} + +$(document).on('click', '.close-success-msg', function (e) { + $(this).closest('div').fadeOut(); +}) + +$(document).on('click', '.open-app', function (e) { + puter.ui.launchApp($(this).attr('data-app-name')); +}) + +$(document).on('click', '.insta-deploy-to-new-app', async function (e) { + $('.insta-deploy-modal').get(0).close(); + let title = await puter.ui.prompt('Please enter a title for your app:', 'My Awesome App'); + + if (title.length > 60) { + puter.ui.alert(`Title cannot be longer than 60.`, [ + { + label: 'Ok', + }, + ]); + // todo go back to create an app prompt and prefill the title input with the title the user entered + $('.insta-deploy-modal').get(0).showModal(); + } + else if (title) { + if (source_path) { + create_app(title, source_path); + source_path = null; + } else { + create_app(title, null, dropped_items); + dropped_items = null; + } + } else + $('.insta-deploy-modal').get(0).showModal(); + + return; + +}) + +$(document).on('click', '.insta-deploy-to-existing-app', function (e) { + $('.insta-deploy-modal').get(0).close(); + $('.insta-deploy-existing-app-select').get(0).showModal(); + $('.insta-deploy-existing-app-list').html(`
${loading_spinner}
`); + puter.apps.list().then((apps) => { + setTimeout(() => { + $('.insta-deploy-existing-app-list').html(''); + if (apps.length === 0) + $('.insta-deploy-existing-app-list').html(` +
+ + You have no existing apps. +
+ `); + else { + for (let app of apps) { + $('.insta-deploy-existing-app-list').append( + `
+ + ${html_encode(app.title)} +
+ ${number_format((app.stats.referral_count ?? 0) + app.stats.user_count)} + ${number_format(app.stats.open_count)} +
+
` + ); + } + } + }, 500); + }) + + // todo reset .insta-deploy-existing-app-list on close +}) + +$(document).on('click', '.insta-deploy-app-selector', function (e) { + $('.insta-deploy-app-selector').removeClass('active'); + $(this).addClass('active'); + + // enable deploy button + $('.insta-deploy-existing-app-deploy-btn').removeClass('disabled'); +}) + +$(document).on('click', '.insta-deploy-existing-app-deploy-btn', function (e) { + $('.insta-deploy-existing-app-deploy-btn').addClass('disabled'); + $('.insta-deploy-existing-app-select')?.get(0)?.close(); + // load the 'App Settings' section + edit_app_section($('.insta-deploy-app-selector.active').attr('data-name')); + + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + let drop_area_content = `

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // deploy + deploy({ uid: $(e.target).attr('data-uid') }, source_path ?? dropped_items); + $('.insta-deploy-existing-app-list').html(''); +}) + +$(document).on('click', '.insta-deploy-cancel', function (e) { + $(this).closest('dialog')?.get(0)?.close(); +}) +$(document).on('click', '.insta-deploy-existing-app-back', function (e) { + $('.insta-deploy-existing-app-select')?.get(0)?.close(); + $('.insta-deploy-modal')?.get(0)?.showModal(); + // disable deploy button + $('.insta-deploy-existing-app-deploy-btn').addClass('disabled'); + + // todo disable the 'an existing app' option if there are no existing apps +}) + + +$(document).on('click', '.add-app-to-desktop', function (e) { + let app_title = $(this).attr('data-app-title'); + let app_uid = $(this).attr('data-app-uid'); + + puter.fs.upload( + new File([], app_title), + `/${authUsername}/Desktop`, + { + name: app_title, + dedupeName: true, + overwrite: false, + appUID: app_uid, + }).then(async (uploaded) => { + puter.ui.alert(`"${app_title}" shortcut has been added to your desktop.`, [ + { + label: 'Ok', + type: 'primary', + }, + ], { + type: 'success', + }); + }) + +}) + +function reset_drop_area() { + dropped_items = null; + $('.drop-area').html(drop_area_placeholder); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); +} + +$('body').on('dragover', function (event) { + // skip if the user is dragging something over the drop area + if ($(event.target).hasClass('drop-area')) + return; + + event.preventDefault(); // Prevent the default behavior + event.stopPropagation(); // Stop the event from propagating +}); + +// Developers can drop items anywhere on the page to deploy them +$('body').on('drop', async function (event) { + // skip if the user is dragging something over the drop area + if ($(event.target).hasClass('drop-area')) + return; + + // prevent default behavior + event.preventDefault(); + event.stopPropagation(); + + // retrieve puter items from the event + if (event.detail?.items?.length > 0) { + dropped_items = event.detail.items; + source_path = dropped_items[0].path; + // by deploying an existing Puter folder. So we create the app and deploy it. + if (source_path) { + // todo if there are no apps, go straight to creating a new app + $('.insta-deploy-modal').get(0).showModal(); + // set item name + $('.insta-deploy-item-name').html(html_encode(dropped_items[0].name)); + } + } + //----------------------------------------------------------------------------- + // Local items dropped + //----------------------------------------------------------------------------- + const e = event.originalEvent; + if (!e.dataTransfer || !e.dataTransfer.items || e.dataTransfer.items.length === 0) + return; + + // Get dropped items + dropped_items = await puter.ui.getEntriesFromDataTransferItems(e.dataTransfer.items); + + // Generate a flat array of full paths from the dropped items + let paths = []; + for (let item of dropped_items) { + paths.push('/' + (item.fullPath ?? item.filepath)); + } + + // Generate a directory tree from the paths + let tree = generateDirTree(paths); + + dropped_items = setRootDirTree(tree, dropped_items); + + // Alert if no index.html in root + if (!hasRootIndexHtml(tree)) { + puter.ui.alert(index_missing_error, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + return; + } + + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // Generate a list of items in the root in the form of a string (e.g. /index.html, /css/style.css) with maximum of 3 items + let rootItems = ''; + + if (rootKeys.length === 1) + rootItems = rootKeys[0]; + else if (rootKeys.length === 2) + rootItems = rootKeys[0] + ', ' + rootKeys[1]; + else if (rootKeys.length === 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and' + rootKeys[1]; + else if (rootKeys.length > 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and ' + (rootKeys.length - 2) + ' more item' + (rootKeys.length - 2 > 1 ? 's' : ''); + + // Show insta-deploy modal + $('.insta-deploy-modal').get(0)?.showModal(); + + // Set item name + $('.insta-deploy-item-name').html(html_encode(rootItems)); +}); + +$('.insta-deploy-existing-app-select').on('close', function (e) { + $('.insta-deploy-existing-app-list').html(''); +}) + +$('.refresh-app-list').on('click', function (e) { + $('.loading-modal').get(0)?.showModal(); + + puter.apps.list().then((resp) => { + setTimeout(() => { + apps = resp; + + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + + // preserve search query + if (search_query) { + // show apps that match search_query and hide apps that don't + apps.forEach((app) => { + if (app.title.toLowerCase().includes(search_query.toLowerCase())) { + $(`.app-card[data-name="${app.name}"]`).show(); + } else { + $(`.app-card[data-name="${app.name}"]`).hide(); + } + }) + } + + // preserve sort + sort_apps(); + + $('.loading-modal').get(0).close(); + }, 1000); + }) +}) + +$(document).on('click', '.search', function (e) { + e.stopPropagation(); + e.preventDefault(); + // don't let click bubble up to window + e.stopImmediatePropagation(); +}) + +$(document).on('input change keyup keypress keydown paste cut', '.search', function (e) { + // search apps for query + search_query = $(this).val().toLowerCase(); + if (search_query === '') { + // hide 'clear search' button + $('.search-clear').hide(); + // show all apps again + $(`.app-card`).show(); + } else { + // show 'clear search' button + $('.search-clear').show(); + // show apps that match search_query and hide apps that don't + apps.forEach((app) => { + if (app.title.toLowerCase().includes(search_query.toLowerCase())) { + $(`.app-card[data-name="${app.name}"]`).show(); + } else { + $(`.app-card[data-name="${app.name}"]`).hide(); + } + }) + } +}) + +$(document).on('click', '.search-clear', function (e) { + $('.search').val(''); + $('.search').trigger('change'); + $('.search').focus(); + search_query = ''; +}) + +$(document).on('change', '.app-checkbox', function (e) { + // determine if select-all checkbox should be checked, indeterminate, or unchecked + if ($('.app-checkbox:checked').length === $('.app-checkbox').length) { + $('.select-all-apps').prop('indeterminate', false); + $('.select-all-apps').prop('checked', true); + } else if ($('.app-checkbox:checked').length > 0) { + $('.select-all-apps').prop('indeterminate', true); + $('.select-all-apps').prop('checked', false); + } + else { + $('.select-all-apps').prop('indeterminate', false); + $('.select-all-apps').prop('checked', false); + } + + // activate row + if ($(this).is(':checked')) + $(this).closest('tr').addClass('active'); + else + $(this).closest('tr').removeClass('active'); + + // enable delete button if at least one checkbox is checked + if ($('.app-checkbox:checked').length > 0) + $('.delete-apps-btn').removeClass('disabled'); + else + $('.delete-apps-btn').addClass('disabled'); + +}) + +$(document).on('click', '.delete-apps-btn', async function (e) { + // show confirmation alert + let resp = await puter.ui.alert(`Are you sure you want to delete the selected apps?`, [ + { + label: 'Delete', + type: 'danger', + value: 'delete', + }, + { + label: 'Cancel', + }, + ], { + type: 'warning', + }); + + if (resp === 'delete') { + // disable delete button + $('.delete-apps-btn').addClass('disabled'); + + // show 'deleting' modal + $('.deleting-app-modal')?.get(0)?.showModal(); + + let start_ts = Date.now(); + const apps = $('.app-checkbox:checked').toArray(); + + // delete all checked apps + for (let app of apps) { + // get app uid + const app_uid = $(app).attr('data-app-uid'); + const app_name = $(app).attr('data-app-name'); + + // delete app + await puter.apps.delete(app_name) + + // remove app card + $(`.app-card[data-uid="${app_uid}"]`).fadeOut(200, function name(params) { + $(this).remove(); + if ($(`.app-card`).length === 0) { + $('section:not(.sidebar)').hide(); + $('#no-apps-notice').show(); + } else { + $('section:not(.sidebar)').hide(); + $('#app-list').show(); + } + }); + + try{ + // get app directory + const stat = await puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + returnSubdomains: true + }); + // delete subdomain associated with the app directory + if(stat?.subdomains[0]?.subdomain){ + await puter.hosting.delete(stat.subdomains[0].subdomain) + } + // delete app directory + await puter.fs.delete( + `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + { recursive: true } + ) + } catch(err) { + console.log(err); + } + } + + // close 'deleting' modal + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + // uncheck all checkboxes + $('.app-checkbox').prop('checked', false); + // disable delete button + $('.delete-apps-btn').addClass('disabled'); + // reset the 'select all' checkbox + $('.select-all-apps').prop('indeterminate', false); + $('.select-all-apps').prop('checked', false); + }, (start_ts - Date.now()) > 500 ? 0 : 500); + } +}) + +$(document).on('change', '.select-all-apps', function (e) { + if ($(this).is(':checked')) { + $('.app-checkbox').prop('checked', true); + $('.app-card').addClass('active'); + $('.delete-apps-btn').removeClass('disabled'); + } else { + $('.app-checkbox').prop('checked', false); + $('.app-card').removeClass('active'); + $('.delete-apps-btn').addClass('disabled'); + } +}) + +// Function to map file extensions to MIME types +function getMimeType(extension) { + const mimeTypes = { + jpg: 'jpeg', + jpeg: 'jpeg', + png: 'png', + gif: 'gif', + bmp: 'bmp', + webp: 'webp', + svg: 'svg+xml', + tiff: 'tiff', + ico: 'vnd.microsoft.icon' + }; + + return mimeTypes[extension.toLowerCase()] || 'octet-stream'; +} \ No newline at end of file diff --git a/src/dev-center/js/html-entities.js b/src/dev-center/js/html-entities.js new file mode 100644 index 0000000000..c233cb01ee --- /dev/null +++ b/src/dev-center/js/html-entities.js @@ -0,0 +1 @@ +(()=>{"use strict";var r,e={563:function(r,e,a){var t=this&&this.__assign||function(){return(t=Object.assign||function(r){for(var e,a=1,t=arguments.length;a'"&]/g,nonAscii:/(?:[<>'"&\u0080-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,nonAsciiPrintable:/(?:[<>'"&\x01-\x08\x11-\x15\x17-\x1F\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,extensive:/(?:[\x01-\x0c\x0e-\x1f\x21-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7d\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g},n={mode:"specialChars",level:"all",numeric:"decimal"};e.encode=function(r,e){var a=void 0===(u=(c=void 0===e?n:e).mode)?"specialChars":u,t=void 0===(m=c.numeric)?"decimal":m,o=c.level;if(!r)return"";var c,u,p=i[a],d=s[void 0===o?"all":o].characters,g="hexadecimal"===t;if(p.lastIndex=0,c=p.exec(r)){u="";var m=0;do{m!==c.index&&(u+=r.substring(m,c.index));var f=d[o=c[0]];if(!f){var h=o.length>1?l.getCodePoint(o,0):o.charCodeAt(0);f=(g?"&#x"+h.toString(16):"&#"+h)+";"}u+=f,m=c.index+o.length}while(c=p.exec(r));m!==r.length&&(u+=r.substring(m))}else u=r;return u};var u={scope:"body",level:"all"},p=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);/g,d=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+)[;=]?/g,g={xml:{strict:p,attribute:d,body:o.bodyRegExps.xml},html4:{strict:p,attribute:d,body:o.bodyRegExps.html4},html5:{strict:p,attribute:d,body:o.bodyRegExps.html5}},m=t(t({},g),{all:g.html5}),f=String.fromCharCode,h=f(65533),b={level:"all"};e.decodeEntity=function(r,e){var a=void 0===(t=(void 0===e?b:e).level)?"all":t;if(!r)return"";var t=r,o=(r[r.length-1],s[a].entities[r]);if(o)t=o;else if("&"===r[0]&&"#"===r[1]){var i=r[2],n="x"==i||"X"==i?parseInt(r.substr(3),16):parseInt(r.substr(2));t=n>=1114111?h:n>65535?l.fromCodePoint(n):f(c.numericUnicodeMap[n]||n)}return t},e.decode=function(r,e){var a=void 0===e?u:e,t=a.level,o=void 0===t?"all":t,i=a.scope,n=void 0===i?"xml"===o?"strict":"body":i;if(!r)return"";var p=m[o][n],d=s[o].entities,g="attribute"===n,b="strict"===n;p.lastIndex=0;var v,q=p.exec(r);if(q){v="";var y=0;do{y!==q.index&&(v+=r.substring(y,q.index));var w=q[0],x=w,A=w[w.length-1];if(g&&"="===A)x=w;else if(b&&";"!==A)x=w;else{var E=d[w];if(E)x=E;else if("&"===w[0]&&"#"===w[1]){var D=w[2],k="x"==D||"X"==D?parseInt(w.substr(3),16):parseInt(w.substr(2));x=k>=1114111?h:k>65535?l.fromCodePoint(k):f(c.numericUnicodeMap[k]||k)}}v+=x,y=q.index+w.length}while(q=p.exec(r));y!==r.length&&(v+=r.substring(y))}else v=r;return v}},81:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.bodyRegExps={xml:/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html4:/&(?:nbsp|iexcl|cent|pound|curren|yen|brvbar|sect|uml|copy|ordf|laquo|not|shy|reg|macr|deg|plusmn|sup2|sup3|acute|micro|para|middot|cedil|sup1|ordm|raquo|frac14|frac12|frac34|iquest|Agrave|Aacute|Acirc|Atilde|Auml|Aring|AElig|Ccedil|Egrave|Eacute|Ecirc|Euml|Igrave|Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde|Ouml|times|Oslash|Ugrave|Uacute|Ucirc|Uuml|Yacute|THORN|szlig|agrave|aacute|acirc|atilde|auml|aring|aelig|ccedil|egrave|eacute|ecirc|euml|igrave|iacute|icirc|iuml|eth|ntilde|ograve|oacute|ocirc|otilde|ouml|divide|oslash|ugrave|uacute|ucirc|uuml|yacute|thorn|yuml|quot|amp|lt|gt|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html5:/&(?:AElig|AMP|Aacute|Acirc|Agrave|Aring|Atilde|Auml|COPY|Ccedil|ETH|Eacute|Ecirc|Egrave|Euml|GT|Iacute|Icirc|Igrave|Iuml|LT|Ntilde|Oacute|Ocirc|Ograve|Oslash|Otilde|Ouml|QUOT|REG|THORN|Uacute|Ucirc|Ugrave|Uuml|Yacute|aacute|acirc|acute|aelig|agrave|amp|aring|atilde|auml|brvbar|ccedil|cedil|cent|copy|curren|deg|divide|eacute|ecirc|egrave|eth|euml|frac12|frac14|frac34|gt|iacute|icirc|iexcl|igrave|iquest|iuml|laquo|lt|macr|micro|middot|nbsp|not|ntilde|oacute|ocirc|ograve|ordf|ordm|oslash|otilde|ouml|para|plusmn|pound|quot|raquo|reg|sect|shy|sup1|sup2|sup3|szlig|thorn|times|uacute|ucirc|ugrave|uml|uuml|yacute|yen|yuml|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g},e.namedReferences={xml:{entities:{"<":"<",">":">",""":'"',"'":"'","&":"&"},characters:{"<":"<",">":">",'"':""","'":"'","&":"&"}},html4:{entities:{"'":"'"," ":" "," ":" ","¡":"¡","¡":"¡","¢":"¢","¢":"¢","£":"£","£":"£","¤":"¤","¤":"¤","¥":"¥","¥":"¥","¦":"¦","¦":"¦","§":"§","§":"§","¨":"¨","¨":"¨","©":"©","©":"©","ª":"ª","ª":"ª","«":"«","«":"«","¬":"¬","¬":"¬","­":"­","­":"­","®":"®","®":"®","¯":"¯","¯":"¯","°":"°","°":"°","±":"±","±":"±","²":"²","²":"²","³":"³","³":"³","´":"´","´":"´","µ":"µ","µ":"µ","¶":"¶","¶":"¶","·":"·","·":"·","¸":"¸","¸":"¸","¹":"¹","¹":"¹","º":"º","º":"º","»":"»","»":"»","¼":"¼","¼":"¼","½":"½","½":"½","¾":"¾","¾":"¾","¿":"¿","¿":"¿","À":"À","À":"À","Á":"Á","Á":"Á","Â":"Â","Â":"Â","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","Å":"Å","Å":"Å","Æ":"Æ","Æ":"Æ","Ç":"Ç","Ç":"Ç","È":"È","È":"È","É":"É","É":"É","Ê":"Ê","Ê":"Ê","Ë":"Ë","Ë":"Ë","Ì":"Ì","Ì":"Ì","Í":"Í","Í":"Í","Î":"Î","Î":"Î","Ï":"Ï","Ï":"Ï","Ð":"Ð","Ð":"Ð","Ñ":"Ñ","Ñ":"Ñ","Ò":"Ò","Ò":"Ò","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","Õ":"Õ","Õ":"Õ","Ö":"Ö","Ö":"Ö","×":"×","×":"×","Ø":"Ø","Ø":"Ø","Ù":"Ù","Ù":"Ù","Ú":"Ú","Ú":"Ú","Û":"Û","Û":"Û","Ü":"Ü","Ü":"Ü","Ý":"Ý","Ý":"Ý","Þ":"Þ","Þ":"Þ","ß":"ß","ß":"ß","à":"à","à":"à","á":"á","á":"á","â":"â","â":"â","ã":"ã","ã":"ã","ä":"ä","ä":"ä","å":"å","å":"å","æ":"æ","æ":"æ","ç":"ç","ç":"ç","è":"è","è":"è","é":"é","é":"é","ê":"ê","ê":"ê","ë":"ë","ë":"ë","ì":"ì","ì":"ì","í":"í","í":"í","î":"î","î":"î","ï":"ï","ï":"ï","ð":"ð","ð":"ð","ñ":"ñ","ñ":"ñ","ò":"ò","ò":"ò","ó":"ó","ó":"ó","ô":"ô","ô":"ô","õ":"õ","õ":"õ","ö":"ö","ö":"ö","÷":"÷","÷":"÷","ø":"ø","ø":"ø","ù":"ù","ù":"ù","ú":"ú","ú":"ú","û":"û","û":"û","ü":"ü","ü":"ü","ý":"ý","ý":"ý","þ":"þ","þ":"þ","ÿ":"ÿ","ÿ":"ÿ",""":'"',""":'"',"&":"&","&":"&","<":"<","<":"<",">":">",">":">","Œ":"Œ","œ":"œ","Š":"Š","š":"š","Ÿ":"Ÿ","ˆ":"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€","ƒ":"ƒ","Α":"Α","Β":"Β","Γ":"Γ","Δ":"Δ","Ε":"Ε","Ζ":"Ζ","Η":"Η","Θ":"Θ","Ι":"Ι","Κ":"Κ","Λ":"Λ","Μ":"Μ","Ν":"Ν","Ξ":"Ξ","Ο":"Ο","Π":"Π","Ρ":"Ρ","Σ":"Σ","Τ":"Τ","Υ":"Υ","Φ":"Φ","Χ":"Χ","Ψ":"Ψ","Ω":"Ω","α":"α","β":"β","γ":"γ","δ":"δ","ε":"ε","ζ":"ζ","η":"η","θ":"θ","ι":"ι","κ":"κ","λ":"λ","μ":"μ","ν":"ν","ξ":"ξ","ο":"ο","π":"π","ρ":"ρ","ς":"ς","σ":"σ","τ":"τ","υ":"υ","φ":"φ","χ":"χ","ψ":"ψ","ω":"ω","ϑ":"ϑ","ϒ":"ϒ","ϖ":"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄","℘":"℘","ℑ":"ℑ","ℜ":"ℜ","™":"™","ℵ":"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","⟨":"〈","⟩":"〉","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"},characters:{"'":"'"," ":" ","¡":"¡","¢":"¢","£":"£","¤":"¤","¥":"¥","¦":"¦","§":"§","¨":"¨","©":"©",ª:"ª","«":"«","¬":"¬","­":"­","®":"®","¯":"¯","°":"°","±":"±","²":"²","³":"³","´":"´",µ:"µ","¶":"¶","·":"·","¸":"¸","¹":"¹",º:"º","»":"»","¼":"¼","½":"½","¾":"¾","¿":"¿",À:"À",Á:"Á",Â:"Â",Ã:"Ã",Ä:"Ä",Å:"Å",Æ:"Æ",Ç:"Ç",È:"È",É:"É",Ê:"Ê",Ë:"Ë",Ì:"Ì",Í:"Í",Î:"Î",Ï:"Ï",Ð:"Ð",Ñ:"Ñ",Ò:"Ò",Ó:"Ó",Ô:"Ô",Õ:"Õ",Ö:"Ö","×":"×",Ø:"Ø",Ù:"Ù",Ú:"Ú",Û:"Û",Ü:"Ü",Ý:"Ý",Þ:"Þ",ß:"ß",à:"à",á:"á",â:"â",ã:"ã",ä:"ä",å:"å",æ:"æ",ç:"ç",è:"è",é:"é",ê:"ê",ë:"ë",ì:"ì",í:"í",î:"î",ï:"ï",ð:"ð",ñ:"ñ",ò:"ò",ó:"ó",ô:"ô",õ:"õ",ö:"ö","÷":"÷",ø:"ø",ù:"ù",ú:"ú",û:"û",ü:"ü",ý:"ý",þ:"þ",ÿ:"ÿ",'"':""","&":"&","<":"<",">":">",Œ:"Œ",œ:"œ",Š:"Š",š:"š",Ÿ:"Ÿ",ˆ:"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€",ƒ:"ƒ",Α:"Α",Β:"Β",Γ:"Γ",Δ:"Δ",Ε:"Ε",Ζ:"Ζ",Η:"Η",Θ:"Θ",Ι:"Ι",Κ:"Κ",Λ:"Λ",Μ:"Μ",Ν:"Ν",Ξ:"Ξ",Ο:"Ο",Π:"Π",Ρ:"Ρ",Σ:"Σ",Τ:"Τ",Υ:"Υ",Φ:"Φ",Χ:"Χ",Ψ:"Ψ",Ω:"Ω",α:"α",β:"β",γ:"γ",δ:"δ",ε:"ε",ζ:"ζ",η:"η",θ:"θ",ι:"ι",κ:"κ",λ:"λ",μ:"μ",ν:"ν",ξ:"ξ",ο:"ο",π:"π",ρ:"ρ",ς:"ς",σ:"σ",τ:"τ",υ:"υ",φ:"φ",χ:"χ",ψ:"ψ",ω:"ω",ϑ:"ϑ",ϒ:"ϒ",ϖ:"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄",℘:"℘",ℑ:"ℑ",ℜ:"ℜ","™":"™",ℵ:"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","〈":"⟨","〉":"⟩","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"}},html5:{entities:{"Æ":"Æ","Æ":"Æ","&":"&","&":"&","Á":"Á","Á":"Á","Ă":"Ă","Â":"Â","Â":"Â","А":"А","𝔄":"𝔄","À":"À","À":"À","Α":"Α","Ā":"Ā","⩓":"⩓","Ą":"Ą","𝔸":"𝔸","⁡":"⁡","Å":"Å","Å":"Å","𝒜":"𝒜","≔":"≔","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","∖":"∖","⫧":"⫧","⌆":"⌆","Б":"Б","∵":"∵","ℬ":"ℬ","Β":"Β","𝔅":"𝔅","𝔹":"𝔹","˘":"˘","ℬ":"ℬ","≎":"≎","Ч":"Ч","©":"©","©":"©","Ć":"Ć","⋒":"⋒","ⅅ":"ⅅ","ℭ":"ℭ","Č":"Č","Ç":"Ç","Ç":"Ç","Ĉ":"Ĉ","∰":"∰","Ċ":"Ċ","¸":"¸","·":"·","ℭ":"ℭ","Χ":"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮","ℂ":"ℂ","∐":"∐","∳":"∳","⨯":"⨯","𝒞":"𝒞","⋓":"⋓","≍":"≍","ⅅ":"ⅅ","⤑":"⤑","Ђ":"Ђ","Ѕ":"Ѕ","Џ":"Џ","‡":"‡","↡":"↡","⫤":"⫤","Ď":"Ď","Д":"Д","∇":"∇","Δ":"Δ","𝔇":"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄","ⅆ":"ⅆ","𝔻":"𝔻","¨":"¨","⃜":"⃜","≐":"≐","∯":"∯","¨":"¨","⇓":"⇓","⇐":"⇐","⇔":"⇔","⫤":"⫤","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧","⇓":"⇓","𝒟":"𝒟","Đ":"Đ","Ŋ":"Ŋ","Ð":"Ð","Ð":"Ð","É":"É","É":"É","Ě":"Ě","Ê":"Ê","Ê":"Ê","Э":"Э","Ė":"Ė","𝔈":"𝔈","È":"È","È":"È","∈":"∈","Ē":"Ē","◻":"◻","▫":"▫","Ę":"Ę","𝔼":"𝔼","Ε":"Ε","⩵":"⩵","≂":"≂","⇌":"⇌","ℰ":"ℰ","⩳":"⩳","Η":"Η","Ë":"Ë","Ë":"Ë","∃":"∃","ⅇ":"ⅇ","Ф":"Ф","𝔉":"𝔉","◼":"◼","▪":"▪","𝔽":"𝔽","∀":"∀","ℱ":"ℱ","ℱ":"ℱ","Ѓ":"Ѓ",">":">",">":">","Γ":"Γ","Ϝ":"Ϝ","Ğ":"Ğ","Ģ":"Ģ","Ĝ":"Ĝ","Г":"Г","Ġ":"Ġ","𝔊":"𝔊","⋙":"⋙","𝔾":"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳","𝒢":"𝒢","≫":"≫","Ъ":"Ъ","ˇ":"ˇ","^":"^","Ĥ":"Ĥ","ℌ":"ℌ","ℋ":"ℋ","ℍ":"ℍ","─":"─","ℋ":"ℋ","Ħ":"Ħ","≎":"≎","≏":"≏","Е":"Е","IJ":"IJ","Ё":"Ё","Í":"Í","Í":"Í","Î":"Î","Î":"Î","И":"И","İ":"İ","ℑ":"ℑ","Ì":"Ì","Ì":"Ì","ℑ":"ℑ","Ī":"Ī","ⅈ":"ⅈ","⇒":"⇒","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢","Į":"Į","𝕀":"𝕀","Ι":"Ι","ℐ":"ℐ","Ĩ":"Ĩ","І":"І","Ï":"Ï","Ï":"Ï","Ĵ":"Ĵ","Й":"Й","𝔍":"𝔍","𝕁":"𝕁","𝒥":"𝒥","Ј":"Ј","Є":"Є","Х":"Х","Ќ":"Ќ","Κ":"Κ","Ķ":"Ķ","К":"К","𝔎":"𝔎","𝕂":"𝕂","𝒦":"𝒦","Љ":"Љ","<":"<","<":"<","Ĺ":"Ĺ","Λ":"Λ","⟪":"⟪","ℒ":"ℒ","↞":"↞","Ľ":"Ľ","Ļ":"Ļ","Л":"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⇐":"⇐","⇔":"⇔","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲","𝔏":"𝔏","⋘":"⋘","⇚":"⇚","Ŀ":"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶","⟸":"⟸","⟺":"⟺","⟹":"⟹","𝕃":"𝕃","↙":"↙","↘":"↘","ℒ":"ℒ","↰":"↰","Ł":"Ł","≪":"≪","⤅":"⤅","М":"М"," ":" ","ℳ":"ℳ","𝔐":"𝔐","∓":"∓","𝕄":"𝕄","ℳ":"ℳ","Μ":"Μ","Њ":"Њ","Ń":"Ń","Ň":"Ň","Ņ":"Ņ","Н":"Н","​":"​","​":"​","​":"​","​":"​","≫":"≫","≪":"≪"," ":"\n","𝔑":"𝔑","⁠":"⁠"," ":" ","ℕ":"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤","𝒩":"𝒩","Ñ":"Ñ","Ñ":"Ñ","Ν":"Ν","Œ":"Œ","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","О":"О","Ő":"Ő","𝔒":"𝔒","Ò":"Ò","Ò":"Ò","Ō":"Ō","Ω":"Ω","Ο":"Ο","𝕆":"𝕆","“":"“","‘":"‘","⩔":"⩔","𝒪":"𝒪","Ø":"Ø","Ø":"Ø","Õ":"Õ","Õ":"Õ","⨷":"⨷","Ö":"Ö","Ö":"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂","П":"П","𝔓":"𝔓","Φ":"Φ","Π":"Π","±":"±","ℌ":"ℌ","ℙ":"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∷":"∷","∝":"∝","𝒫":"𝒫","Ψ":"Ψ",""":'"',""":'"',"𝔔":"𝔔","ℚ":"ℚ","𝒬":"𝒬","⤐":"⤐","®":"®","®":"®","Ŕ":"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖","Ř":"Ř","Ŗ":"Ŗ","Р":"Р","ℜ":"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯","ℜ":"ℜ","Ρ":"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓","⇒":"⇒","ℝ":"ℝ","⥰":"⥰","⇛":"⇛","ℛ":"ℛ","↱":"↱","⧴":"⧴","Щ":"Щ","Ш":"Ш","Ь":"Ь","Ś":"Ś","⪼":"⪼","Š":"Š","Ş":"Ş","Ŝ":"Ŝ","С":"С","𝔖":"𝔖","↓":"↓","←":"←","→":"→","↑":"↑","Σ":"Σ","∘":"∘","𝕊":"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔","𝒮":"𝒮","⋆":"⋆","⋐":"⋐","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∋":"∋","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇","⋑":"⋑","Þ":"Þ","Þ":"Þ","™":"™","Ћ":"Ћ","Ц":"Ц"," ":"\t","Τ":"Τ","Ť":"Ť","Ţ":"Ţ","Т":"Т","𝔗":"𝔗","∴":"∴","Θ":"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈","𝕋":"𝕋","⃛":"⃛","𝒯":"𝒯","Ŧ":"Ŧ","Ú":"Ú","Ú":"Ú","↟":"↟","⥉":"⥉","Ў":"Ў","Ŭ":"Ŭ","Û":"Û","Û":"Û","У":"У","Ű":"Ű","𝔘":"𝔘","Ù":"Ù","Ù":"Ù","Ū":"Ū","_":"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎","Ų":"Ų","𝕌":"𝕌","↑":"↑","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","⇑":"⇑","⇕":"⇕","↖":"↖","↗":"↗","ϒ":"ϒ","Υ":"Υ","Ů":"Ů","𝒰":"𝒰","Ũ":"Ũ","Ü":"Ü","Ü":"Ü","⊫":"⊫","⫫":"⫫","В":"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ","𝔙":"𝔙","𝕍":"𝕍","𝒱":"𝒱","⊪":"⊪","Ŵ":"Ŵ","⋀":"⋀","𝔚":"𝔚","𝕎":"𝕎","𝒲":"𝒲","𝔛":"𝔛","Ξ":"Ξ","𝕏":"𝕏","𝒳":"𝒳","Я":"Я","Ї":"Ї","Ю":"Ю","Ý":"Ý","Ý":"Ý","Ŷ":"Ŷ","Ы":"Ы","𝔜":"𝔜","𝕐":"𝕐","𝒴":"𝒴","Ÿ":"Ÿ","Ж":"Ж","Ź":"Ź","Ž":"Ž","З":"З","Ż":"Ż","​":"​","Ζ":"Ζ","ℨ":"ℨ","ℤ":"ℤ","𝒵":"𝒵","á":"á","á":"á","ă":"ă","∾":"∾","∾̳":"∾̳","∿":"∿","â":"â","â":"â","´":"´","´":"´","а":"а","æ":"æ","æ":"æ","⁡":"⁡","𝔞":"𝔞","à":"à","à":"à","ℵ":"ℵ","ℵ":"ℵ","α":"α","ā":"ā","⨿":"⨿","&":"&","&":"&","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∠":"∠","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","Å":"Å","⍼":"⍼","ą":"ą","𝕒":"𝕒","≈":"≈","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'","≈":"≈","≊":"≊","å":"å","å":"å","𝒶":"𝒶","*":"*","≈":"≈","≍":"≍","ã":"ã","ã":"ã","ä":"ä","ä":"ä","∳":"∳","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⌅":"⌅","⎵":"⎵","⎶":"⎶","≌":"≌","б":"б","„":"„","∵":"∵","∵":"∵","⦰":"⦰","϶":"϶","ℬ":"ℬ","β":"β","ℶ":"ℶ","≬":"≬","𝔟":"𝔟","⋂":"⋂","◯":"◯","⋃":"⋃","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⋁":"⋁","⋀":"⋀","⤍":"⤍","⧫":"⧫","▪":"▪","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐","𝕓":"𝕓","⊥":"⊥","⊥":"⊥","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","─":"─","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","‵":"‵","˘":"˘","¦":"¦","¦":"¦","𝒷":"𝒷","⁏":"⁏","∽":"∽","⋍":"⋍","\":"\\","⧅":"⧅","⟈":"⟈","•":"•","•":"•","≎":"≎","⪮":"⪮","≏":"≏","≏":"≏","ć":"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","ˇ":"ˇ","⩍":"⩍","č":"č","ç":"ç","ç":"ç","ĉ":"ĉ","⩌":"⩌","⩐":"⩐","ċ":"ċ","¸":"¸","¸":"¸","⦲":"⦲","¢":"¢","¢":"¢","·":"·","𝔠":"𝔠","ч":"ч","✓":"✓","✓":"✓","χ":"χ","○":"○","⧃":"⧃","ˆ":"ˆ","≗":"≗","↺":"↺","↻":"↻","®":"®","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","≗":"≗","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣","♣":"♣",":":":","≔":"≔","≔":"≔",",":",","@":"@","∁":"∁","∘":"∘","∁":"∁","ℂ":"ℂ","≅":"≅","⩭":"⩭","∮":"∮","𝕔":"𝕔","∐":"∐","©":"©","©":"©","℗":"℗","↵":"↵","✗":"✗","𝒸":"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋞":"⋞","⋟":"⋟","⋎":"⋎","⋏":"⋏","¤":"¤","¤":"¤","↶":"↶","↷":"↷","⋎":"⋎","⋏":"⋏","∲":"∲","∱":"∱","⌭":"⌭","⇓":"⇓","⥥":"⥥","†":"†","ℸ":"ℸ","↓":"↓","‐":"‐","⊣":"⊣","⤏":"⤏","˝":"˝","ď":"ď","д":"д","ⅆ":"ⅆ","‡":"‡","⇊":"⇊","⩷":"⩷","°":"°","°":"°","δ":"δ","⦱":"⦱","⥿":"⥿","𝔡":"𝔡","⇃":"⇃","⇂":"⇂","⋄":"⋄","⋄":"⋄","♦":"♦","♦":"♦","¨":"¨","ϝ":"ϝ","⋲":"⋲","÷":"÷","÷":"÷","÷":"÷","⋇":"⋇","⋇":"⋇","ђ":"ђ","⌞":"⌞","⌍":"⌍","$":"$","𝕕":"𝕕","˙":"˙","≐":"≐","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌆":"⌆","↓":"↓","⇊":"⇊","⇃":"⇃","⇂":"⇂","⤐":"⤐","⌟":"⌟","⌌":"⌌","𝒹":"𝒹","ѕ":"ѕ","⧶":"⧶","đ":"đ","⋱":"⋱","▿":"▿","▾":"▾","⇵":"⇵","⥯":"⥯","⦦":"⦦","џ":"џ","⟿":"⟿","⩷":"⩷","≑":"≑","é":"é","é":"é","⩮":"⩮","ě":"ě","≖":"≖","ê":"ê","ê":"ê","≕":"≕","э":"э","ė":"ė","ⅇ":"ⅇ","≒":"≒","𝔢":"𝔢","⪚":"⪚","è":"è","è":"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧","ℓ":"ℓ","⪕":"⪕","⪗":"⪗","ē":"ē","∅":"∅","∅":"∅","∅":"∅"," ":" "," ":" "," ":" ","ŋ":"ŋ"," ":" ","ę":"ę","𝕖":"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱","ε":"ε","ε":"ε","ϵ":"ϵ","≖":"≖","≕":"≕","≂":"≂","⪖":"⪖","⪕":"⪕","=":"=","≟":"≟","≡":"≡","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱","ℯ":"ℯ","≐":"≐","≂":"≂","η":"η","ð":"ð","ð":"ð","ë":"ë","ë":"ë","€":"€","!":"!","∃":"∃","ℰ":"ℰ","ⅇ":"ⅇ","≒":"≒","ф":"ф","♀":"♀","ffi":"ffi","ff":"ff","ffl":"ffl","𝔣":"𝔣","fi":"fi","fj":"fj","♭":"♭","fl":"fl","▱":"▱","ƒ":"ƒ","𝕗":"𝕗","∀":"∀","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","½":"½","⅓":"⅓","¼":"¼","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢","𝒻":"𝒻","≧":"≧","⪌":"⪌","ǵ":"ǵ","γ":"γ","ϝ":"ϝ","⪆":"⪆","ğ":"ğ","ĝ":"ĝ","г":"г","ġ":"ġ","≥":"≥","⋛":"⋛","≥":"≥","≧":"≧","⩾":"⩾","⩾":"⩾","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔","𝔤":"𝔤","≫":"≫","⋙":"⋙","ℷ":"ℷ","ѓ":"ѓ","≷":"≷","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪊":"⪊","⪈":"⪈","⪈":"⪈","≩":"≩","⋧":"⋧","𝕘":"𝕘","`":"`","ℊ":"ℊ","≳":"≳","⪎":"⪎","⪐":"⪐",">":">",">":">","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⪆":"⪆","⥸":"⥸","⋗":"⋗","⋛":"⋛","⪌":"⪌","≷":"≷","≳":"≳","≩︀":"≩︀","≩︀":"≩︀","⇔":"⇔"," ":" ","½":"½","ℋ":"ℋ","ъ":"ъ","↔":"↔","⥈":"⥈","↭":"↭","ℏ":"ℏ","ĥ":"ĥ","♥":"♥","♥":"♥","…":"…","⊹":"⊹","𝔥":"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪","𝕙":"𝕙","―":"―","𝒽":"𝒽","ℏ":"ℏ","ħ":"ħ","⁃":"⁃","‐":"‐","í":"í","í":"í","⁣":"⁣","î":"î","î":"î","и":"и","е":"е","¡":"¡","¡":"¡","⇔":"⇔","𝔦":"𝔦","ì":"ì","ì":"ì","ⅈ":"ⅈ","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩","ij":"ij","ī":"ī","ℑ":"ℑ","ℐ":"ℐ","ℑ":"ℑ","ı":"ı","⊷":"⊷","Ƶ":"Ƶ","∈":"∈","℅":"℅","∞":"∞","⧝":"⧝","ı":"ı","∫":"∫","⊺":"⊺","ℤ":"ℤ","⊺":"⊺","⨗":"⨗","⨼":"⨼","ё":"ё","į":"į","𝕚":"𝕚","ι":"ι","⨼":"⨼","¿":"¿","¿":"¿","𝒾":"𝒾","∈":"∈","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳","∈":"∈","⁢":"⁢","ĩ":"ĩ","і":"і","ï":"ï","ï":"ï","ĵ":"ĵ","й":"й","𝔧":"𝔧","ȷ":"ȷ","𝕛":"𝕛","𝒿":"𝒿","ј":"ј","є":"є","κ":"κ","ϰ":"ϰ","ķ":"ķ","к":"к","𝔨":"𝔨","ĸ":"ĸ","х":"х","ќ":"ќ","𝕜":"𝕜","𝓀":"𝓀","⇚":"⇚","⇐":"⇐","⤛":"⤛","⤎":"⤎","≦":"≦","⪋":"⪋","⥢":"⥢","ĺ":"ĺ","⦴":"⦴","ℒ":"ℒ","λ":"λ","⟨":"⟨","⦑":"⦑","⟨":"⟨","⪅":"⪅","«":"«","«":"«","←":"←","⇤":"⇤","⤟":"⤟","⤝":"⤝","↩":"↩","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍","ľ":"ľ","ļ":"ļ","⌈":"⌈","{":"{","л":"л","⤶":"⤶","“":"“","„":"„","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","←":"←","↢":"↢","↽":"↽","↼":"↼","⇇":"⇇","↔":"↔","⇆":"⇆","⇋":"⇋","↭":"↭","⋋":"⋋","⋚":"⋚","≤":"≤","≦":"≦","⩽":"⩽","⩽":"⩽","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⪅":"⪅","⋖":"⋖","⋚":"⋚","⪋":"⪋","≶":"≶","≲":"≲","⥼":"⥼","⌊":"⌊","𝔩":"𝔩","≶":"≶","⪑":"⪑","↽":"↽","↼":"↼","⥪":"⥪","▄":"▄","љ":"љ","≪":"≪","⇇":"⇇","⌞":"⌞","⥫":"⥫","◺":"◺","ŀ":"ŀ","⎰":"⎰","⎰":"⎰","≨":"≨","⪉":"⪉","⪉":"⪉","⪇":"⪇","⪇":"⪇","≨":"≨","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟦":"⟦","⟵":"⟵","⟷":"⟷","⟼":"⟼","⟶":"⟶","↫":"↫","↬":"↬","⦅":"⦅","𝕝":"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","_":"_","◊":"◊","◊":"◊","⧫":"⧫","(":"(","⦓":"⦓","⇆":"⇆","⌟":"⌟","⇋":"⇋","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹","𝓁":"𝓁","↰":"↰","≲":"≲","⪍":"⪍","⪏":"⪏","[":"[","‘":"‘","‚":"‚","ł":"ł","<":"<","<":"<","⪦":"⪦","⩹":"⩹","⋖":"⋖","⋋":"⋋","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⊴":"⊴","◂":"◂","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","≨︀":"≨︀","∺":"∺","¯":"¯","¯":"¯","♂":"♂","✠":"✠","✠":"✠","↦":"↦","↦":"↦","↧":"↧","↤":"↤","↥":"↥","▮":"▮","⨩":"⨩","м":"м","—":"—","∡":"∡","𝔪":"𝔪","℧":"℧","µ":"µ","µ":"µ","∣":"∣","*":"*","⫰":"⫰","·":"·","·":"·","−":"−","⊟":"⊟","∸":"∸","⨪":"⨪","⫛":"⫛","…":"…","∓":"∓","⊧":"⊧","𝕞":"𝕞","∓":"∓","𝓂":"𝓂","∾":"∾","μ":"μ","⊸":"⊸","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","≫̸":"≫̸","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","≪̸":"≪̸","⇏":"⇏","⊯":"⊯","⊮":"⊮","∇":"∇","ń":"ń","∠⃒":"∠⃒","≉":"≉","⩰̸":"⩰̸","≋̸":"≋̸","ʼn":"ʼn","≉":"≉","♮":"♮","♮":"♮","ℕ":"ℕ"," ":" "," ":" ","≎̸":"≎̸","≏̸":"≏̸","⩃":"⩃","ň":"ň","ņ":"ņ","≇":"≇","⩭̸":"⩭̸","⩂":"⩂","н":"н","–":"–","≠":"≠","⇗":"⇗","⤤":"⤤","↗":"↗","↗":"↗","≐̸":"≐̸","≢":"≢","⤨":"⤨","≂̸":"≂̸","∄":"∄","∄":"∄","𝔫":"𝔫","≧̸":"≧̸","≱":"≱","≱":"≱","≧̸":"≧̸","⩾̸":"⩾̸","⩾̸":"⩾̸","≵":"≵","≯":"≯","≯":"≯","⇎":"⇎","↮":"↮","⫲":"⫲","∋":"∋","⋼":"⋼","⋺":"⋺","∋":"∋","њ":"њ","⇍":"⇍","≦̸":"≦̸","↚":"↚","‥":"‥","≰":"≰","↚":"↚","↮":"↮","≰":"≰","≦̸":"≦̸","⩽̸":"⩽̸","⩽̸":"⩽̸","≮":"≮","≴":"≴","≮":"≮","⋪":"⋪","⋬":"⋬","∤":"∤","𝕟":"𝕟","¬":"¬","¬":"¬","∉":"∉","⋹̸":"⋹̸","⋵̸":"⋵̸","∉":"∉","⋷":"⋷","⋶":"⋶","∌":"∌","∌":"∌","⋾":"⋾","⋽":"⋽","∦":"∦","∦":"∦","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","⊀":"⊀","⋠":"⋠","⪯̸":"⪯̸","⊀":"⊀","⪯̸":"⪯̸","⇏":"⇏","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸","↛":"↛","⋫":"⋫","⋭":"⋭","⊁":"⊁","⋡":"⋡","⪰̸":"⪰̸","𝓃":"𝓃","∤":"∤","∦":"∦","≁":"≁","≄":"≄","≄":"≄","∤":"∤","∦":"∦","⋢":"⋢","⋣":"⋣","⊄":"⊄","⫅̸":"⫅̸","⊈":"⊈","⊂⃒":"⊂⃒","⊈":"⊈","⫅̸":"⫅̸","⊁":"⊁","⪰̸":"⪰̸","⊅":"⊅","⫆̸":"⫆̸","⊉":"⊉","⊃⃒":"⊃⃒","⊉":"⊉","⫆̸":"⫆̸","≹":"≹","ñ":"ñ","ñ":"ñ","≸":"≸","⋪":"⋪","⋬":"⋬","⋫":"⋫","⋭":"⋭","ν":"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","↖":"↖","↖":"↖","⤧":"⤧","Ⓢ":"Ⓢ","ó":"ó","ó":"ó","⊛":"⊛","⊚":"⊚","ô":"ô","ô":"ô","о":"о","⊝":"⊝","ő":"ő","⨸":"⨸","⊙":"⊙","⦼":"⦼","œ":"œ","⦿":"⦿","𝔬":"𝔬","˛":"˛","ò":"ò","ò":"ò","⧁":"⧁","⦵":"⦵","Ω":"Ω","∮":"∮","↺":"↺","⦾":"⦾","⦻":"⦻","‾":"‾","⧀":"⧀","ō":"ō","ω":"ω","ο":"ο","⦶":"⦶","⊖":"⊖","𝕠":"𝕠","⦷":"⦷","⦹":"⦹","⊕":"⊕","∨":"∨","↻":"↻","⩝":"⩝","ℴ":"ℴ","ℴ":"ℴ","ª":"ª","ª":"ª","º":"º","º":"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛","ℴ":"ℴ","ø":"ø","ø":"ø","⊘":"⊘","õ":"õ","õ":"õ","⊗":"⊗","⨶":"⨶","ö":"ö","ö":"ö","⌽":"⌽","∥":"∥","¶":"¶","¶":"¶","∥":"∥","⫳":"⫳","⫽":"⫽","∂":"∂","п":"п","%":"%",".":".","‰":"‰","⊥":"⊥","‱":"‱","𝔭":"𝔭","φ":"φ","ϕ":"ϕ","ℳ":"ℳ","☎":"☎","π":"π","⋔":"⋔","ϖ":"ϖ","ℏ":"ℏ","ℎ":"ℎ","ℏ":"ℏ","+":"+","⨣":"⨣","⊞":"⊞","⨢":"⨢","∔":"∔","⨥":"⨥","⩲":"⩲","±":"±","±":"±","⨦":"⨦","⨧":"⨧","±":"±","⨕":"⨕","𝕡":"𝕡","£":"£","£":"£","≺":"≺","⪳":"⪳","⪷":"⪷","≼":"≼","⪯":"⪯","≺":"≺","⪷":"⪷","≼":"≼","⪯":"⪯","⪹":"⪹","⪵":"⪵","⋨":"⋨","≾":"≾","′":"′","ℙ":"ℙ","⪵":"⪵","⪹":"⪹","⋨":"⋨","∏":"∏","⌮":"⌮","⌒":"⌒","⌓":"⌓","∝":"∝","∝":"∝","≾":"≾","⊰":"⊰","𝓅":"𝓅","ψ":"ψ"," ":" ","𝔮":"𝔮","⨌":"⨌","𝕢":"𝕢","⁗":"⁗","𝓆":"𝓆","ℍ":"ℍ","⨖":"⨖","?":"?","≟":"≟",""":'"',""":'"',"⇛":"⇛","⇒":"⇒","⤜":"⤜","⤏":"⤏","⥤":"⥤","∽̱":"∽̱","ŕ":"ŕ","√":"√","⦳":"⦳","⟩":"⟩","⦒":"⦒","⦥":"⦥","⟩":"⟩","»":"»","»":"»","→":"→","⥵":"⥵","⇥":"⇥","⤠":"⤠","⤳":"⤳","⤞":"⤞","↪":"↪","↬":"↬","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","ℚ":"ℚ","⤍":"⤍","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐","ř":"ř","ŗ":"ŗ","⌉":"⌉","}":"}","р":"р","⤷":"⤷","⥩":"⥩","”":"”","”":"”","↳":"↳","ℜ":"ℜ","ℛ":"ℛ","ℜ":"ℜ","ℝ":"ℝ","▭":"▭","®":"®","®":"®","⥽":"⥽","⌋":"⌋","𝔯":"𝔯","⇁":"⇁","⇀":"⇀","⥬":"⥬","ρ":"ρ","ϱ":"ϱ","→":"→","↣":"↣","⇁":"⇁","⇀":"⇀","⇄":"⇄","⇌":"⇌","⇉":"⇉","↝":"↝","⋌":"⋌","˚":"˚","≓":"≓","⇄":"⇄","⇌":"⇌","‏":"‏","⎱":"⎱","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⟧":"⟧","⦆":"⦆","𝕣":"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","⇉":"⇉","›":"›","𝓇":"𝓇","↱":"↱","]":"]","’":"’","’":"’","⋌":"⋌","⋊":"⋊","▹":"▹","⊵":"⊵","▸":"▸","⧎":"⧎","⥨":"⥨","℞":"℞","ś":"ś","‚":"‚","≻":"≻","⪴":"⪴","⪸":"⪸","š":"š","≽":"≽","⪰":"⪰","ş":"ş","ŝ":"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓","≿":"≿","с":"с","⋅":"⋅","⊡":"⊡","⩦":"⩦","⇘":"⇘","⤥":"⤥","↘":"↘","↘":"↘","§":"§","§":"§",";":";","⤩":"⤩","∖":"∖","∖":"∖","✶":"✶","𝔰":"𝔰","⌢":"⌢","♯":"♯","щ":"щ","ш":"ш","∣":"∣","∥":"∥","­":"­","­":"­","σ":"σ","ς":"ς","ς":"ς","∼":"∼","⩪":"⩪","≃":"≃","≃":"≃","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","←":"←","∖":"∖","⨳":"⨳","⧤":"⧤","∣":"∣","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀","ь":"ь","/":"/","⧄":"⧄","⌿":"⌿","𝕤":"𝕤","♠":"♠","♠":"♠","∥":"∥","⊓":"⊓","⊓︀":"⊓︀","⊔":"⊔","⊔︀":"⊔︀","⊏":"⊏","⊑":"⊑","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊐":"⊐","⊒":"⊒","□":"□","□":"□","▪":"▪","▪":"▪","→":"→","𝓈":"𝓈","∖":"∖","⌣":"⌣","⋆":"⋆","☆":"☆","★":"★","ϵ":"ϵ","ϕ":"ϕ","¯":"¯","⊂":"⊂","⫅":"⫅","⪽":"⪽","⊆":"⊆","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⊂":"⊂","⊆":"⊆","⫅":"⫅","⊊":"⊊","⫋":"⫋","⫇":"⫇","⫕":"⫕","⫓":"⫓","≻":"≻","⪸":"⪸","≽":"≽","⪰":"⪰","⪺":"⪺","⪶":"⪶","⋩":"⋩","≿":"≿","∑":"∑","♪":"♪","¹":"¹","¹":"¹","²":"²","²":"²","³":"³","³":"³","⊃":"⊃","⫆":"⫆","⪾":"⪾","⫘":"⫘","⊇":"⊇","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⊃":"⊃","⊇":"⊇","⫆":"⫆","⊋":"⊋","⫌":"⫌","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤦":"⤦","↙":"↙","↙":"↙","⤪":"⤪","ß":"ß","ß":"ß","⌖":"⌖","τ":"τ","⎴":"⎴","ť":"ť","ţ":"ţ","т":"т","⃛":"⃛","⌕":"⌕","𝔱":"𝔱","∴":"∴","∴":"∴","θ":"θ","ϑ":"ϑ","ϑ":"ϑ","≈":"≈","∼":"∼"," ":" ","≈":"≈","∼":"∼","þ":"þ","þ":"þ","˜":"˜","×":"×","×":"×","⊠":"⊠","⨱":"⨱","⨰":"⨰","∭":"∭","⤨":"⤨","⊤":"⊤","⌶":"⌶","⫱":"⫱","𝕥":"𝕥","⫚":"⫚","⤩":"⤩","‴":"‴","™":"™","▵":"▵","▿":"▿","◃":"◃","⊴":"⊴","≜":"≜","▹":"▹","⊵":"⊵","◬":"◬","≜":"≜","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢","𝓉":"𝓉","ц":"ц","ћ":"ћ","ŧ":"ŧ","≬":"≬","↞":"↞","↠":"↠","⇑":"⇑","⥣":"⥣","ú":"ú","ú":"ú","↑":"↑","ў":"ў","ŭ":"ŭ","û":"û","û":"û","у":"у","⇅":"⇅","ű":"ű","⥮":"⥮","⥾":"⥾","𝔲":"𝔲","ù":"ù","ù":"ù","↿":"↿","↾":"↾","▀":"▀","⌜":"⌜","⌜":"⌜","⌏":"⌏","◸":"◸","ū":"ū","¨":"¨","¨":"¨","ų":"ų","𝕦":"𝕦","↑":"↑","↕":"↕","↿":"↿","↾":"↾","⊎":"⊎","υ":"υ","ϒ":"ϒ","υ":"υ","⇈":"⇈","⌝":"⌝","⌝":"⌝","⌎":"⌎","ů":"ů","◹":"◹","𝓊":"𝓊","⋰":"⋰","ũ":"ũ","▵":"▵","▴":"▴","⇈":"⇈","ü":"ü","ü":"ü","⦧":"⦧","⇕":"⇕","⫨":"⫨","⫩":"⫩","⊨":"⊨","⦜":"⦜","ϵ":"ϵ","ϰ":"ϰ","∅":"∅","ϕ":"ϕ","ϖ":"ϖ","∝":"∝","↕":"↕","ϱ":"ϱ","ς":"ς","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀","ϑ":"ϑ","⊲":"⊲","⊳":"⊳","в":"в","⊢":"⊢","∨":"∨","⊻":"⊻","≚":"≚","⋮":"⋮","|":"|","|":"|","𝔳":"𝔳","⊲":"⊲","⊂⃒":"⊂⃒","⊃⃒":"⊃⃒","𝕧":"𝕧","∝":"∝","⊳":"⊳","𝓋":"𝓋","⫋︀":"⫋︀","⊊︀":"⊊︀","⫌︀":"⫌︀","⊋︀":"⊋︀","⦚":"⦚","ŵ":"ŵ","⩟":"⩟","∧":"∧","≙":"≙","℘":"℘","𝔴":"𝔴","𝕨":"𝕨","℘":"℘","≀":"≀","≀":"≀","𝓌":"𝓌","⋂":"⋂","◯":"◯","⋃":"⋃","▽":"▽","𝔵":"𝔵","⟺":"⟺","⟷":"⟷","ξ":"ξ","⟸":"⟸","⟵":"⟵","⟼":"⟼","⋻":"⋻","⨀":"⨀","𝕩":"𝕩","⨁":"⨁","⨂":"⨂","⟹":"⟹","⟶":"⟶","𝓍":"𝓍","⨆":"⨆","⨄":"⨄","△":"△","⋁":"⋁","⋀":"⋀","ý":"ý","ý":"ý","я":"я","ŷ":"ŷ","ы":"ы","¥":"¥","¥":"¥","𝔶":"𝔶","ї":"ї","𝕪":"𝕪","𝓎":"𝓎","ю":"ю","ÿ":"ÿ","ÿ":"ÿ","ź":"ź","ž":"ž","з":"з","ż":"ż","ℨ":"ℨ","ζ":"ζ","𝔷":"𝔷","ж":"ж","⇝":"⇝","𝕫":"𝕫","𝓏":"𝓏","‍":"‍","‌":"‌"},characters:{Æ:"Æ","&":"&",Á:"Á",Ă:"Ă",Â:"Â",А:"А",𝔄:"𝔄",À:"À",Α:"Α",Ā:"Ā","⩓":"⩓",Ą:"Ą",𝔸:"𝔸","⁡":"⁡",Å:"Å",𝒜:"𝒜","≔":"≔",Ã:"Ã",Ä:"Ä","∖":"∖","⫧":"⫧","⌆":"⌆",Б:"Б","∵":"∵",ℬ:"ℬ",Β:"Β",𝔅:"𝔅",𝔹:"𝔹","˘":"˘","≎":"≎",Ч:"Ч","©":"©",Ć:"Ć","⋒":"⋒",ⅅ:"ⅅ",ℭ:"ℭ",Č:"Č",Ç:"Ç",Ĉ:"Ĉ","∰":"∰",Ċ:"Ċ","¸":"¸","·":"·",Χ:"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮",ℂ:"ℂ","∐":"∐","∳":"∳","⨯":"⨯",𝒞:"𝒞","⋓":"⋓","≍":"≍","⤑":"⤑",Ђ:"Ђ",Ѕ:"Ѕ",Џ:"Џ","‡":"‡","↡":"↡","⫤":"⫤",Ď:"Ď",Д:"Д","∇":"∇",Δ:"Δ",𝔇:"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄",ⅆ:"ⅆ",𝔻:"𝔻","¨":"¨","⃜":"⃜","≐":"≐","⇓":"⇓","⇐":"⇐","⇔":"⇔","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧",𝒟:"𝒟",Đ:"Đ",Ŋ:"Ŋ",Ð:"Ð",É:"É",Ě:"Ě",Ê:"Ê",Э:"Э",Ė:"Ė",𝔈:"𝔈",È:"È","∈":"∈",Ē:"Ē","◻":"◻","▫":"▫",Ę:"Ę",𝔼:"𝔼",Ε:"Ε","⩵":"⩵","≂":"≂","⇌":"⇌",ℰ:"ℰ","⩳":"⩳",Η:"Η",Ë:"Ë","∃":"∃",ⅇ:"ⅇ",Ф:"Ф",𝔉:"𝔉","◼":"◼","▪":"▪",𝔽:"𝔽","∀":"∀",ℱ:"ℱ",Ѓ:"Ѓ",">":">",Γ:"Γ",Ϝ:"Ϝ",Ğ:"Ğ",Ģ:"Ģ",Ĝ:"Ĝ",Г:"Г",Ġ:"Ġ",𝔊:"𝔊","⋙":"⋙",𝔾:"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳",𝒢:"𝒢","≫":"≫",Ъ:"Ъ",ˇ:"ˇ","^":"^",Ĥ:"Ĥ",ℌ:"ℌ",ℋ:"ℋ",ℍ:"ℍ","─":"─",Ħ:"Ħ","≏":"≏",Е:"Е",IJ:"IJ",Ё:"Ё",Í:"Í",Î:"Î",И:"И",İ:"İ",ℑ:"ℑ",Ì:"Ì",Ī:"Ī",ⅈ:"ⅈ","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢",Į:"Į",𝕀:"𝕀",Ι:"Ι",ℐ:"ℐ",Ĩ:"Ĩ",І:"І",Ï:"Ï",Ĵ:"Ĵ",Й:"Й",𝔍:"𝔍",𝕁:"𝕁",𝒥:"𝒥",Ј:"Ј",Є:"Є",Х:"Х",Ќ:"Ќ",Κ:"Κ",Ķ:"Ķ",К:"К",𝔎:"𝔎",𝕂:"𝕂",𝒦:"𝒦",Љ:"Љ","<":"<",Ĺ:"Ĺ",Λ:"Λ","⟪":"⟪",ℒ:"ℒ","↞":"↞",Ľ:"Ľ",Ļ:"Ļ",Л:"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲",𝔏:"𝔏","⋘":"⋘","⇚":"⇚",Ŀ:"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶",𝕃:"𝕃","↙":"↙","↘":"↘","↰":"↰",Ł:"Ł","≪":"≪","⤅":"⤅",М:"М"," ":" ",ℳ:"ℳ",𝔐:"𝔐","∓":"∓",𝕄:"𝕄",Μ:"Μ",Њ:"Њ",Ń:"Ń",Ň:"Ň",Ņ:"Ņ",Н:"Н","​":"​","\n":" ",𝔑:"𝔑","⁠":"⁠"," ":" ",ℕ:"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤",𝒩:"𝒩",Ñ:"Ñ",Ν:"Ν",Œ:"Œ",Ó:"Ó",Ô:"Ô",О:"О",Ő:"Ő",𝔒:"𝔒",Ò:"Ò",Ō:"Ō",Ω:"Ω",Ο:"Ο",𝕆:"𝕆","“":"“","‘":"‘","⩔":"⩔",𝒪:"𝒪",Ø:"Ø",Õ:"Õ","⨷":"⨷",Ö:"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂",П:"П",𝔓:"𝔓",Φ:"Φ",Π:"Π","±":"±",ℙ:"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∝":"∝",𝒫:"𝒫",Ψ:"Ψ",'"':""",𝔔:"𝔔",ℚ:"ℚ",𝒬:"𝒬","⤐":"⤐","®":"®",Ŕ:"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖",Ř:"Ř",Ŗ:"Ŗ",Р:"Р",ℜ:"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯",Ρ:"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓",ℝ:"ℝ","⥰":"⥰","⇛":"⇛",ℛ:"ℛ","↱":"↱","⧴":"⧴",Щ:"Щ",Ш:"Ш",Ь:"Ь",Ś:"Ś","⪼":"⪼",Š:"Š",Ş:"Ş",Ŝ:"Ŝ",С:"С",𝔖:"𝔖","↑":"↑",Σ:"Σ","∘":"∘",𝕊:"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔",𝒮:"𝒮","⋆":"⋆","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇",Þ:"Þ","™":"™",Ћ:"Ћ",Ц:"Ц","\t":" ",Τ:"Τ",Ť:"Ť",Ţ:"Ţ",Т:"Т",𝔗:"𝔗","∴":"∴",Θ:"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈",𝕋:"𝕋","⃛":"⃛",𝒯:"𝒯",Ŧ:"Ŧ",Ú:"Ú","↟":"↟","⥉":"⥉",Ў:"Ў",Ŭ:"Ŭ",Û:"Û",У:"У",Ű:"Ű",𝔘:"𝔘",Ù:"Ù",Ū:"Ū",_:"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎",Ų:"Ų",𝕌:"𝕌","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","↖":"↖","↗":"↗",ϒ:"ϒ",Υ:"Υ",Ů:"Ů",𝒰:"𝒰",Ũ:"Ũ",Ü:"Ü","⊫":"⊫","⫫":"⫫",В:"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ",𝔙:"𝔙",𝕍:"𝕍",𝒱:"𝒱","⊪":"⊪",Ŵ:"Ŵ","⋀":"⋀",𝔚:"𝔚",𝕎:"𝕎",𝒲:"𝒲",𝔛:"𝔛",Ξ:"Ξ",𝕏:"𝕏",𝒳:"𝒳",Я:"Я",Ї:"Ї",Ю:"Ю",Ý:"Ý",Ŷ:"Ŷ",Ы:"Ы",𝔜:"𝔜",𝕐:"𝕐",𝒴:"𝒴",Ÿ:"Ÿ",Ж:"Ж",Ź:"Ź",Ž:"Ž",З:"З",Ż:"Ż",Ζ:"Ζ",ℨ:"ℨ",ℤ:"ℤ",𝒵:"𝒵",á:"á",ă:"ă","∾":"∾","∾̳":"∾̳","∿":"∿",â:"â",а:"а",æ:"æ",𝔞:"𝔞",à:"à",ℵ:"ℵ",α:"α",ā:"ā","⨿":"⨿","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","⍼":"⍼",ą:"ą",𝕒:"𝕒","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'",å:"å",𝒶:"𝒶","*":"*",ã:"ã",ä:"ä","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⎶":"⎶",б:"б","„":"„","⦰":"⦰",β:"β",ℶ:"ℶ","≬":"≬",𝔟:"𝔟","◯":"◯","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⤍":"⤍","⧫":"⧫","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐",𝕓:"𝕓","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","¦":"¦",𝒷:"𝒷","⁏":"⁏","\\":"\","⧅":"⧅","⟈":"⟈","•":"•","⪮":"⪮",ć:"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","⩍":"⩍",č:"č",ç:"ç",ĉ:"ĉ","⩌":"⩌","⩐":"⩐",ċ:"ċ","⦲":"⦲","¢":"¢",𝔠:"𝔠",ч:"ч","✓":"✓",χ:"χ","○":"○","⧃":"⧃",ˆ:"ˆ","≗":"≗","↺":"↺","↻":"↻","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣",":":":",",":",","@":"@","∁":"∁","⩭":"⩭",𝕔:"𝕔","℗":"℗","↵":"↵","✗":"✗",𝒸:"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋎":"⋎","⋏":"⋏","¤":"¤","∱":"∱","⌭":"⌭","⥥":"⥥","†":"†",ℸ:"ℸ","‐":"‐","⤏":"⤏",ď:"ď",д:"д","⇊":"⇊","⩷":"⩷","°":"°",δ:"δ","⦱":"⦱","⥿":"⥿",𝔡:"𝔡","♦":"♦",ϝ:"ϝ","⋲":"⋲","÷":"÷","⋇":"⋇",ђ:"ђ","⌞":"⌞","⌍":"⌍",$:"$",𝕕:"𝕕","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌟":"⌟","⌌":"⌌",𝒹:"𝒹",ѕ:"ѕ","⧶":"⧶",đ:"đ","⋱":"⋱","▿":"▿","⦦":"⦦",џ:"џ","⟿":"⟿",é:"é","⩮":"⩮",ě:"ě","≖":"≖",ê:"ê","≕":"≕",э:"э",ė:"ė","≒":"≒",𝔢:"𝔢","⪚":"⪚",è:"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧",ℓ:"ℓ","⪕":"⪕","⪗":"⪗",ē:"ē","∅":"∅"," ":" "," ":" "," ":" ",ŋ:"ŋ"," ":" ",ę:"ę",𝕖:"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱",ε:"ε",ϵ:"ϵ","=":"=","≟":"≟","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱",ℯ:"ℯ",η:"η",ð:"ð",ë:"ë","€":"€","!":"!",ф:"ф","♀":"♀",ffi:"ffi",ff:"ff",ffl:"ffl",𝔣:"𝔣",fi:"fi",fj:"fj","♭":"♭",fl:"fl","▱":"▱",ƒ:"ƒ",𝕗:"𝕗","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","⅓":"⅓","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢",𝒻:"𝒻","⪌":"⪌",ǵ:"ǵ",γ:"γ","⪆":"⪆",ğ:"ğ",ĝ:"ĝ",г:"г",ġ:"ġ","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔",𝔤:"𝔤",ℷ:"ℷ",ѓ:"ѓ","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪈":"⪈","⋧":"⋧",𝕘:"𝕘",ℊ:"ℊ","⪎":"⪎","⪐":"⪐","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⥸":"⥸","≩︀":"≩︀",ъ:"ъ","⥈":"⥈","↭":"↭",ℏ:"ℏ",ĥ:"ĥ","♥":"♥","…":"…","⊹":"⊹",𝔥:"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪",𝕙:"𝕙","―":"―",𝒽:"𝒽",ħ:"ħ","⁃":"⁃",í:"í",î:"î",и:"и",е:"е","¡":"¡",𝔦:"𝔦",ì:"ì","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩",ij:"ij",ī:"ī",ı:"ı","⊷":"⊷",Ƶ:"Ƶ","℅":"℅","∞":"∞","⧝":"⧝","⊺":"⊺","⨗":"⨗","⨼":"⨼",ё:"ё",į:"į",𝕚:"𝕚",ι:"ι","¿":"¿",𝒾:"𝒾","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳",ĩ:"ĩ",і:"і",ï:"ï",ĵ:"ĵ",й:"й",𝔧:"𝔧",ȷ:"ȷ",𝕛:"𝕛",𝒿:"𝒿",ј:"ј",є:"є",κ:"κ",ϰ:"ϰ",ķ:"ķ",к:"к",𝔨:"𝔨",ĸ:"ĸ",х:"х",ќ:"ќ",𝕜:"𝕜",𝓀:"𝓀","⤛":"⤛","⤎":"⤎","⪋":"⪋","⥢":"⥢",ĺ:"ĺ","⦴":"⦴",λ:"λ","⦑":"⦑","⪅":"⪅","«":"«","⤟":"⤟","⤝":"⤝","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍",ľ:"ľ",ļ:"ļ",л:"л","⤶":"⤶","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","⇇":"⇇","⋋":"⋋","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⋖":"⋖","⥼":"⥼",𝔩:"𝔩","⪑":"⪑","⥪":"⥪","▄":"▄",љ:"љ","⥫":"⥫","◺":"◺",ŀ:"ŀ","⎰":"⎰","≨":"≨","⪉":"⪉","⪇":"⪇","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟼":"⟼","↬":"↬","⦅":"⦅",𝕝:"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","◊":"◊","(":"(","⦓":"⦓","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹",𝓁:"𝓁","⪍":"⪍","⪏":"⪏","‚":"‚",ł:"ł","⪦":"⪦","⩹":"⩹","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","∺":"∺","¯":"¯","♂":"♂","✠":"✠","▮":"▮","⨩":"⨩",м:"м","—":"—",𝔪:"𝔪","℧":"℧",µ:"µ","⫰":"⫰","−":"−","⨪":"⨪","⫛":"⫛","⊧":"⊧",𝕞:"𝕞",𝓂:"𝓂",μ:"μ","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","⇏":"⇏","⊯":"⊯","⊮":"⊮",ń:"ń","∠⃒":"∠⃒","⩰̸":"⩰̸","≋̸":"≋̸",ʼn:"ʼn","♮":"♮","⩃":"⩃",ň:"ň",ņ:"ņ","⩭̸":"⩭̸","⩂":"⩂",н:"н","–":"–","⇗":"⇗","⤤":"⤤","≐̸":"≐̸","⤨":"⤨",𝔫:"𝔫","↮":"↮","⫲":"⫲","⋼":"⋼","⋺":"⋺",њ:"њ","≦̸":"≦̸","↚":"↚","‥":"‥",𝕟:"𝕟","¬":"¬","⋹̸":"⋹̸","⋵̸":"⋵̸","⋷":"⋷","⋶":"⋶","⋾":"⋾","⋽":"⋽","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸",𝓃:"𝓃","⊄":"⊄","⫅̸":"⫅̸","⊅":"⊅","⫆̸":"⫆̸",ñ:"ñ",ν:"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","⤧":"⤧",ó:"ó",ô:"ô",о:"о",ő:"ő","⨸":"⨸","⦼":"⦼",œ:"œ","⦿":"⦿",𝔬:"𝔬","˛":"˛",ò:"ò","⧁":"⧁","⦵":"⦵","⦾":"⦾","⦻":"⦻","⧀":"⧀",ō:"ō",ω:"ω",ο:"ο","⦶":"⦶",𝕠:"𝕠","⦷":"⦷","⦹":"⦹","∨":"∨","⩝":"⩝",ℴ:"ℴ",ª:"ª",º:"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛",ø:"ø","⊘":"⊘",õ:"õ","⨶":"⨶",ö:"ö","⌽":"⌽","¶":"¶","⫳":"⫳","⫽":"⫽",п:"п","%":"%",".":".","‰":"‰","‱":"‱",𝔭:"𝔭",φ:"φ",ϕ:"ϕ","☎":"☎",π:"π",ϖ:"ϖ",ℎ:"ℎ","+":"+","⨣":"⨣","⨢":"⨢","⨥":"⨥","⩲":"⩲","⨦":"⨦","⨧":"⨧","⨕":"⨕",𝕡:"𝕡","£":"£","⪳":"⪳","⪷":"⪷","⪹":"⪹","⪵":"⪵","⋨":"⋨","′":"′","⌮":"⌮","⌒":"⌒","⌓":"⌓","⊰":"⊰",𝓅:"𝓅",ψ:"ψ"," ":" ",𝔮:"𝔮",𝕢:"𝕢","⁗":"⁗",𝓆:"𝓆","⨖":"⨖","?":"?","⤜":"⤜","⥤":"⥤","∽̱":"∽̱",ŕ:"ŕ","⦳":"⦳","⦒":"⦒","⦥":"⦥","»":"»","⥵":"⥵","⤠":"⤠","⤳":"⤳","⤞":"⤞","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐",ř:"ř",ŗ:"ŗ",р:"р","⤷":"⤷","⥩":"⥩","↳":"↳","▭":"▭","⥽":"⥽",𝔯:"𝔯","⥬":"⥬",ρ:"ρ",ϱ:"ϱ","⇉":"⇉","⋌":"⋌","˚":"˚","‏":"‏","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⦆":"⦆",𝕣:"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","›":"›",𝓇:"𝓇","⋊":"⋊","▹":"▹","⧎":"⧎","⥨":"⥨","℞":"℞",ś:"ś","⪴":"⪴","⪸":"⪸",š:"š",ş:"ş",ŝ:"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓",с:"с","⋅":"⋅","⩦":"⩦","⇘":"⇘","§":"§",";":";","⤩":"⤩","✶":"✶",𝔰:"𝔰","♯":"♯",щ:"щ",ш:"ш","­":"­",σ:"σ",ς:"ς","⩪":"⩪","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","⨳":"⨳","⧤":"⧤","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀",ь:"ь","/":"/","⧄":"⧄","⌿":"⌿",𝕤:"𝕤","♠":"♠","⊓︀":"⊓︀","⊔︀":"⊔︀",𝓈:"𝓈","☆":"☆","⊂":"⊂","⫅":"⫅","⪽":"⪽","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⫇":"⫇","⫕":"⫕","⫓":"⫓","♪":"♪","¹":"¹","²":"²","³":"³","⫆":"⫆","⪾":"⪾","⫘":"⫘","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤪":"⤪",ß:"ß","⌖":"⌖",τ:"τ",ť:"ť",ţ:"ţ",т:"т","⌕":"⌕",𝔱:"𝔱",θ:"θ",ϑ:"ϑ",þ:"þ","×":"×","⨱":"⨱","⨰":"⨰","⌶":"⌶","⫱":"⫱",𝕥:"𝕥","⫚":"⫚","‴":"‴","▵":"▵","≜":"≜","◬":"◬","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢",𝓉:"𝓉",ц:"ц",ћ:"ћ",ŧ:"ŧ","⥣":"⥣",ú:"ú",ў:"ў",ŭ:"ŭ",û:"û",у:"у",ű:"ű","⥾":"⥾",𝔲:"𝔲",ù:"ù","▀":"▀","⌜":"⌜","⌏":"⌏","◸":"◸",ū:"ū",ų:"ų",𝕦:"𝕦",υ:"υ","⇈":"⇈","⌝":"⌝","⌎":"⌎",ů:"ů","◹":"◹",𝓊:"𝓊","⋰":"⋰",ũ:"ũ",ü:"ü","⦧":"⦧","⫨":"⫨","⫩":"⫩","⦜":"⦜","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀",в:"в","⊻":"⊻","≚":"≚","⋮":"⋮",𝔳:"𝔳",𝕧:"𝕧",𝓋:"𝓋","⦚":"⦚",ŵ:"ŵ","⩟":"⩟","≙":"≙",℘:"℘",𝔴:"𝔴",𝕨:"𝕨",𝓌:"𝓌",𝔵:"𝔵",ξ:"ξ","⋻":"⋻",𝕩:"𝕩",𝓍:"𝓍",ý:"ý",я:"я",ŷ:"ŷ",ы:"ы","¥":"¥",𝔶:"𝔶",ї:"ї",𝕪:"𝕪",𝓎:"𝓎",ю:"ю",ÿ:"ÿ",ź:"ź",ž:"ž",з:"з",ż:"ż",ζ:"ζ",𝔷:"𝔷",ж:"ж","⇝":"⇝",𝕫:"𝕫",𝓏:"𝓏","‍":"‍","‌":"‌"}}}},687:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.numericUnicodeMap={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},967:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.fromCodePoint=String.fromCodePoint||function(r){return String.fromCharCode(Math.floor((r-65536)/1024)+55296,(r-65536)%1024+56320)},e.getCodePoint=String.prototype.codePointAt?function(r,e){return r.codePointAt(e)}:function(r,e){return 1024*(r.charCodeAt(e)-55296)+r.charCodeAt(e+1)-56320+65536},e.highSurrogateFrom=55296,e.highSurrogateTo=56319}},a={};function t(r){var o=a[r];if(void 0!==o)return o.exports;var c=a[r]={exports:{}};return e[r].call(c.exports,c,c.exports,t),c.exports}t.n=r=>{var e=r&&r.__esModule?()=>r.default:()=>r;return t.d(e,{a:e}),e},t.d=(r,e)=>{for(var a in e)t.o(e,a)&&!t.o(r,a)&&Object.defineProperty(r,a,{enumerable:!0,get:e[a]})},t.o=(r,e)=>Object.prototype.hasOwnProperty.call(r,e),r=t(563),window.html_encode=r.encode,window.html_decode=r.decode})(); \ No newline at end of file diff --git a/src/dev-center/js/jquery-3.6.0.min.js b/src/dev-center/js/jquery-3.6.0.min.js new file mode 100644 index 0000000000..c4c6022f29 --- /dev/null +++ b/src/dev-center/js/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0":"greater","|":"or","¢":"cent","£":"pound","¤":"currency","¥":"yen","©":"(c)","ª":"a","®":"(r)","º":"o","À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","Æ":"AE","Ç":"C","È":"E","É":"E","Ê":"E","Ë":"E","Ì":"I","Í":"I","Î":"I","Ï":"I","Ð":"D","Ñ":"N","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","Ù":"U","Ú":"U","Û":"U","Ü":"U","Ý":"Y","Þ":"TH","ß":"ss","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","æ":"ae","ç":"c","è":"e","é":"e","ê":"e","ë":"e","ì":"i","í":"i","î":"i","ï":"i","ð":"d","ñ":"n","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","ù":"u","ú":"u","û":"u","ü":"u","ý":"y","þ":"th","ÿ":"y","Ā":"A","ā":"a","Ă":"A","ă":"a","Ą":"A","ą":"a","Ć":"C","ć":"c","Č":"C","č":"c","Ď":"D","ď":"d","Đ":"DJ","đ":"dj","Ē":"E","ē":"e","Ė":"E","ė":"e","Ę":"e","ę":"e","Ě":"E","ě":"e","Ğ":"G","ğ":"g","Ģ":"G","ģ":"g","Ĩ":"I","ĩ":"i","Ī":"i","ī":"i","Į":"I","į":"i","İ":"I","ı":"i","Ķ":"k","ķ":"k","Ļ":"L","ļ":"l","Ľ":"L","ľ":"l","Ł":"L","ł":"l","Ń":"N","ń":"n","Ņ":"N","ņ":"n","Ň":"N","ň":"n","Ō":"O","ō":"o","Ő":"O","ő":"o","Œ":"OE","œ":"oe","Ŕ":"R","ŕ":"r","Ř":"R","ř":"r","Ś":"S","ś":"s","Ş":"S","ş":"s","Š":"S","š":"s","Ţ":"T","ţ":"t","Ť":"T","ť":"t","Ũ":"U","ũ":"u","Ū":"u","ū":"u","Ů":"U","ů":"u","Ű":"U","ű":"u","Ų":"U","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","ź":"z","Ż":"Z","ż":"z","Ž":"Z","ž":"z","Ə":"E","ƒ":"f","Ơ":"O","ơ":"o","Ư":"U","ư":"u","Lj":"LJ","lj":"lj","Nj":"NJ","nj":"nj","Ș":"S","ș":"s","Ț":"T","ț":"t","ə":"e","˚":"o","Ά":"A","Έ":"E","Ή":"H","Ί":"I","Ό":"O","Ύ":"Y","Ώ":"W","ΐ":"i","Α":"A","Β":"B","Γ":"G","Δ":"D","Ε":"E","Ζ":"Z","Η":"H","Θ":"8","Ι":"I","Κ":"K","Λ":"L","Μ":"M","Ν":"N","Ξ":"3","Ο":"O","Π":"P","Ρ":"R","Σ":"S","Τ":"T","Υ":"Y","Φ":"F","Χ":"X","Ψ":"PS","Ω":"W","Ϊ":"I","Ϋ":"Y","ά":"a","έ":"e","ή":"h","ί":"i","ΰ":"y","α":"a","β":"b","γ":"g","δ":"d","ε":"e","ζ":"z","η":"h","θ":"8","ι":"i","κ":"k","λ":"l","μ":"m","ν":"n","ξ":"3","ο":"o","π":"p","ρ":"r","ς":"s","σ":"s","τ":"t","υ":"y","φ":"f","χ":"x","ψ":"ps","ω":"w","ϊ":"i","ϋ":"y","ό":"o","ύ":"y","ώ":"w","Ё":"Yo","Ђ":"DJ","Є":"Ye","І":"I","Ї":"Yi","Ј":"J","Љ":"LJ","Њ":"NJ","Ћ":"C","Џ":"DZ","А":"A","Б":"B","В":"V","Г":"G","Д":"D","Е":"E","Ж":"Zh","З":"Z","И":"I","Й":"J","К":"K","Л":"L","М":"M","Н":"N","О":"O","П":"P","Р":"R","С":"S","Т":"T","У":"U","Ф":"F","Х":"H","Ц":"C","Ч":"Ch","Ш":"Sh","Щ":"Sh","Ъ":"U","Ы":"Y","Ь":"","Э":"E","Ю":"Yu","Я":"Ya","а":"a","б":"b","в":"v","г":"g","д":"d","е":"e","ж":"zh","з":"z","и":"i","й":"j","к":"k","л":"l","м":"m","н":"n","о":"o","п":"p","р":"r","с":"s","т":"t","у":"u","ф":"f","х":"h","ц":"c","ч":"ch","ш":"sh","щ":"sh","ъ":"u","ы":"y","ь":"","э":"e","ю":"yu","я":"ya","ё":"yo","ђ":"dj","є":"ye","і":"i","ї":"yi","ј":"j","љ":"lj","њ":"nj","ћ":"c","ѝ":"u","џ":"dz","Ґ":"G","ґ":"g","Ғ":"GH","ғ":"gh","Қ":"KH","қ":"kh","Ң":"NG","ң":"ng","Ү":"UE","ү":"ue","Ұ":"U","ұ":"u","Һ":"H","һ":"h","Ә":"AE","ә":"ae","Ө":"OE","ө":"oe","Ա":"A","Բ":"B","Գ":"G","Դ":"D","Ե":"E","Զ":"Z","Է":"E\'","Ը":"Y\'","Թ":"T\'","Ժ":"JH","Ի":"I","Լ":"L","Խ":"X","Ծ":"C\'","Կ":"K","Հ":"H","Ձ":"D\'","Ղ":"GH","Ճ":"TW","Մ":"M","Յ":"Y","Ն":"N","Շ":"SH","Չ":"CH","Պ":"P","Ջ":"J","Ռ":"R\'","Ս":"S","Վ":"V","Տ":"T","Ր":"R","Ց":"C","Փ":"P\'","Ք":"Q\'","Օ":"O\'\'","Ֆ":"F","և":"EV","ء":"a","آ":"aa","أ":"a","ؤ":"u","إ":"i","ئ":"e","ا":"a","ب":"b","ة":"h","ت":"t","ث":"th","ج":"j","ح":"h","خ":"kh","د":"d","ذ":"th","ر":"r","ز":"z","س":"s","ش":"sh","ص":"s","ض":"dh","ط":"t","ظ":"z","ع":"a","غ":"gh","ف":"f","ق":"q","ك":"k","ل":"l","م":"m","ن":"n","ه":"h","و":"w","ى":"a","ي":"y","ً":"an","ٌ":"on","ٍ":"en","َ":"a","ُ":"u","ِ":"e","ْ":"","٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","پ":"p","چ":"ch","ژ":"zh","ک":"k","گ":"g","ی":"y","۰":"0","۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","฿":"baht","ა":"a","ბ":"b","გ":"g","დ":"d","ე":"e","ვ":"v","ზ":"z","თ":"t","ი":"i","კ":"k","ლ":"l","მ":"m","ნ":"n","ო":"o","პ":"p","ჟ":"zh","რ":"r","ს":"s","ტ":"t","უ":"u","ფ":"f","ქ":"k","ღ":"gh","ყ":"q","შ":"sh","ჩ":"ch","ც":"ts","ძ":"dz","წ":"ts","ჭ":"ch","ხ":"kh","ჯ":"j","ჰ":"h","Ṣ":"S","ṣ":"s","Ẁ":"W","ẁ":"w","Ẃ":"W","ẃ":"w","Ẅ":"W","ẅ":"w","ẞ":"SS","Ạ":"A","ạ":"a","Ả":"A","ả":"a","Ấ":"A","ấ":"a","Ầ":"A","ầ":"a","Ẩ":"A","ẩ":"a","Ẫ":"A","ẫ":"a","Ậ":"A","ậ":"a","Ắ":"A","ắ":"a","Ằ":"A","ằ":"a","Ẳ":"A","ẳ":"a","Ẵ":"A","ẵ":"a","Ặ":"A","ặ":"a","Ẹ":"E","ẹ":"e","Ẻ":"E","ẻ":"e","Ẽ":"E","ẽ":"e","Ế":"E","ế":"e","Ề":"E","ề":"e","Ể":"E","ể":"e","Ễ":"E","ễ":"e","Ệ":"E","ệ":"e","Ỉ":"I","ỉ":"i","Ị":"I","ị":"i","Ọ":"O","ọ":"o","Ỏ":"O","ỏ":"o","Ố":"O","ố":"o","Ồ":"O","ồ":"o","Ổ":"O","ổ":"o","Ỗ":"O","ỗ":"o","Ộ":"O","ộ":"o","Ớ":"O","ớ":"o","Ờ":"O","ờ":"o","Ở":"O","ở":"o","Ỡ":"O","ỡ":"o","Ợ":"O","ợ":"o","Ụ":"U","ụ":"u","Ủ":"U","ủ":"u","Ứ":"U","ứ":"u","Ừ":"U","ừ":"u","Ử":"U","ử":"u","Ữ":"U","ữ":"u","Ự":"U","ự":"u","Ỳ":"Y","ỳ":"y","Ỵ":"Y","ỵ":"y","Ỷ":"Y","ỷ":"y","Ỹ":"Y","ỹ":"y","–":"-","‘":"\'","’":"\'","“":"\\\"","”":"\\\"","„":"\\\"","†":"+","•":"*","…":"...","₠":"ecu","₢":"cruzeiro","₣":"french franc","₤":"lira","₥":"mill","₦":"naira","₧":"peseta","₨":"rupee","₩":"won","₪":"new shequel","₫":"dong","€":"euro","₭":"kip","₮":"tugrik","₯":"drachma","₰":"penny","₱":"peso","₲":"guarani","₳":"austral","₴":"hryvnia","₵":"cedi","₸":"kazakhstani tenge","₹":"indian rupee","₺":"turkish lira","₽":"russian ruble","₿":"bitcoin","℠":"sm","™":"tm","∂":"d","∆":"delta","∑":"sum","∞":"infinity","♥":"love","元":"yuan","円":"yen","﷼":"rial","ﻵ":"laa","ﻷ":"laa","ﻹ":"lai","ﻻ":"la"}') + var locales = JSON.parse('{"bg":{"Й":"Y","Ц":"Ts","Щ":"Sht","Ъ":"A","Ь":"Y","й":"y","ц":"ts","щ":"sht","ъ":"a","ь":"y"},"de":{"Ä":"AE","ä":"ae","Ö":"OE","ö":"oe","Ü":"UE","ü":"ue","ß":"ss","%":"prozent","&":"und","|":"oder","∑":"summe","∞":"unendlich","♥":"liebe"},"es":{"%":"por ciento","&":"y","<":"menor que",">":"mayor que","|":"o","¢":"centavos","£":"libras","¤":"moneda","₣":"francos","∑":"suma","∞":"infinito","♥":"amor"},"fr":{"%":"pourcent","&":"et","<":"plus petit",">":"plus grand","|":"ou","¢":"centime","£":"livre","¤":"devise","₣":"franc","∑":"somme","∞":"infini","♥":"amour"},"pt":{"%":"porcento","&":"e","<":"menor",">":"maior","|":"ou","¢":"centavo","∑":"soma","£":"libra","∞":"infinito","♥":"amor"},"uk":{"И":"Y","и":"y","Й":"Y","й":"y","Ц":"Ts","ц":"ts","Х":"Kh","х":"kh","Щ":"Shch","щ":"shch","Г":"H","г":"h"},"vi":{"Đ":"D","đ":"d"},"da":{"Ø":"OE","ø":"oe","Å":"AA","å":"aa","%":"procent","&":"og","|":"eller","$":"dollar","<":"mindre end",">":"større end"},"nb":{"&":"og","Å":"AA","Æ":"AE","Ø":"OE","å":"aa","æ":"ae","ø":"oe"},"it":{"&":"e"},"nl":{"&":"en"},"sv":{"&":"och","Å":"AA","Ä":"AE","Ö":"OE","å":"aa","ä":"ae","ö":"oe"}}') + + function replace (string, options) { + if (typeof string !== 'string') { + throw new Error('slugify: string argument expected') + } + + options = (typeof options === 'string') + ? {replacement: options} + : options || {} + + var locale = locales[options.locale] || {} + + var replacement = options.replacement === undefined ? '-' : options.replacement + + var trim = options.trim === undefined ? true : options.trim + + var slug = string.normalize().split('') + // replace characters based on charMap + .reduce(function (result, ch) { + var appendChar = locale[ch] || charMap[ch] || ch; + if (appendChar === replacement) { + appendChar = ' '; + } + return result + appendChar + // remove not allowed characters + .replace(options.remove || /[^\w\s$*_+~.()'"!\-:@]+/g, '') + }, ''); + + if (options.strict) { + slug = slug.replace(/[^A-Za-z0-9\s]/g, ''); + } + + if (trim) { + slug = slug.trim() + } + + // Replace spaces with replacement character, treating multiple consecutive + // spaces as a single space. + slug = slug.replace(/\s+/g, replacement); + + if (options.lower) { + slug = slug.toLowerCase() + } + + return slug + } + + replace.extend = function (customMap) { + Object.assign(charMap, customMap) + } + + return replace +}))