diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..579aa61 --- /dev/null +++ b/.gitignore @@ -0,0 +1,28 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +artifacts +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Config files +.webextrc +.webextrc.* diff --git a/.prettierrc.yml b/.prettierrc.yml new file mode 100644 index 0000000..7dc5d17 --- /dev/null +++ b/.prettierrc.yml @@ -0,0 +1,6 @@ +singleQuote: true +trailingComma: all +endOfLine: lf +printWidth: 100 +tabWidth: 2 +arrowParens: avoid diff --git a/LICENSE b/LICENSE index f288702..b4ce07f 100644 --- a/LICENSE +++ b/LICENSE @@ -1,674 +1,21 @@ - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 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 General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Programs - - If you develop a new program, and you want it to be of the greatest -possible use to the public, the best way to achieve this is to make it -free software which everyone can redistribute and change under these terms. - - To do so, attach the following notices to the program. It is safest -to attach them to the start of each source file to most effectively -state the exclusion of warranty; and each file should have at least -the "copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This program is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - -Also add information on how to contact you by electronic and paper mail. - - If the program does terminal interaction, make it output a short -notice like this when it starts in an interactive mode: - - Copyright (C) - This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. - This is free software, and you are welcome to redistribute it - under certain conditions; type `show c' for details. - -The hypothetical commands `show w' and `show c' should show the appropriate -parts of the General Public License. Of course, your program's commands -might be different; for a GUI interface, you would use an "about box". - - You should also get your employer (if you work as a programmer) or school, -if any, to sign a "copyright disclaimer" for the program, if necessary. -For more information on this, and how to apply and follow the GNU GPL, see -. - - The GNU General Public License does not permit incorporating your program -into proprietary programs. If your program is a subroutine library, you -may consider it more useful to permit linking proprietary applications with -the library. If this is what you want to do, use the GNU Lesser General -Public License instead of this License. But first, please read -. +MIT License + +Copyright (c) 2022 Alex Khrisanfov + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index 6d94366..2304c08 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,33 @@ # Web Activity Time Tracker Add to Chrome +⚠️⚠️⚠️ **Important notice! The Chrome extension has been sold. So I am not responsible for any changes to the functionality of the extension.** ⚠️⚠️⚠️ + +**The new version is available on the Chrome Store https://chromewebstore.google.com/detail/timespy-block-websites-po/ggomgkmpcnmfhgmpfaphkbmnokllflom** + +[![Chrome Web Store](https://img.shields.io/chrome-web-store/d/hhfnghjdeddcfegfekjeihfmbjenlomm.svg?&label=Chrome%20users&ogo=google-chrome&logoColor=white)](https://chrome.google.com/webstore/detail/web-activity-time-tracker/hhfnghjdeddcfegfekjeihfmbjenlomm) +[![Chrome Web Store](https://img.shields.io/chrome-web-store/rating/hhfnghjdeddcfegfekjeihfmbjenlomm?&logoColor=white;label=Rating)](https://chrome.google.com/webstore/detail/web-activity-time-tracker/hhfnghjdeddcfegfekjeihfmbjenlomm) +[![Chrome Web Store](https://img.shields.io/chrome-web-store/v/hhfnghjdeddcfegfekjeihfmbjenlomm.svg?&logo=google-chrome&logoColor=white)](https://chrome.google.com/webstore/detail/web-activity-time-tracker/hhfnghjdeddcfegfekjeihfmbjenlomm) + +[![Microsoft Edge Store](https://img.shields.io/badge/dynamic/json?label=Edge%20users&query=%24.activeInstallCount&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Feepmlmdenlkkjieghjmedjahpofieogf&color=gree)](https://microsoftedge.microsoft.com/addons/detail/web-activity-time-tracker/eepmlmdenlkkjieghjmedjahpofieogf) +[![Microsoft Edge Store](https://img.shields.io/badge/dynamic/json?label=Rating&suffix=/5&color=gree&query=%24.averageRating&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Feepmlmdenlkkjieghjmedjahpofieogf)](https://microsoftedge.microsoft.com/addons/detail/web-activity-time-tracker/eepmlmdenlkkjieghjmedjahpofieogf) +[![Microsoft Edge Store](https://img.shields.io/badge/dynamic/json?label=Microsoft%20Edge&prefix=v&query=%24.version&url=https%3A%2F%2Fmicrosoftedge.microsoft.com%2Faddons%2Fgetproductdetailsbycrxid%2Feepmlmdenlkkjieghjmedjahpofieogf&logo=microsoft-edge)](https://microsoftedge.microsoft.com/addons/detail/web-activity-time-tracker/eepmlmdenlkkjieghjmedjahpofieogf) + Web Activity Time Tracker keeps track of how much time you spend on the web and presents the stats in a useful and intuitive way. You can set a daily visit limit for sites and block it after the expiration of the limit. -Extension uses only local [chrome.storage API](https://developer.chrome.com/apps/storage) chrome.storage API to store data and it does't send data anywhere. +Extension uses only local [chrome.storage API](https://developer.chrome.com/apps/storage) chrome.storage API to store data and it doesn't send data anywhere. + +![image](https://user-images.githubusercontent.com/23387046/206865140-875bf7ab-a59e-42e3-bb9e-e348e8b85749.png) ![image](https://user-images.githubusercontent.com/23387046/206865174-aa409efe-495d-450e-a8ea-1d97024c9e23.png) + +You can see your daily stats. + +![image](https://github.com/Stigmatoz/web-activity-time-tracker/assets/23387046/d67c812c-2ba4-4ef8-a685-ab5fd77c7fbe) + + +And you can see your overall stats. + +![image](https://github.com/Stigmatoz/web-activity-time-tracker/assets/23387046/6ea4547e-8bc6-4df7-ba0c-b5b330117270) -![image](https://user-images.githubusercontent.com/23387046/68947288-242bf100-07c6-11ea-8b08-184be2dd306a.png) If you have suggestions or problems using the extension, please [submit a bug or a feature request](https://github.com/Stigmatoz/web-activity-time-tracker/issues). @@ -20,6 +42,10 @@ Web Activity Time Tracker is available via the official [Chrome Web Store](https 3. Click on the "Load unpacked extension..." button. 4. Browse to the src directory of the unarchived folder and confirm. +# Run + +```pnpm run dev``` + # License -This work is licensed under a GNU General Public License v3.0 +This work is licensed under an MIT License. diff --git a/package.json b/package.json new file mode 100644 index 0000000..9690984 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "web-activity-time-tracker", + "private": true, + "version": "1.0.0", + "type": "module", + "scripts": { + "dev": "vite build --watch --mode development", + "start": "vite build --watch --mode production", + "format": "prettier --write .", + "script:zip": "vite build --mode production && powershell scripts/zip.ps1" + }, + "dependencies": { + "@vueuse/core": "^10.11.1", + "chart.js": "^4.4.7", + "d3": "^7.9.0", + "date-fns": "^2.30.0", + "rollup-plugin-copy": "^3.5.0", + "vue": "^3.5.13", + "vue-chartjs": "^5.3.2", + "vue-i18n": "^9.14.2" + }, + "devDependencies": { + "@intlify/unplugin-vue-i18n": "^0.12.3", + "@kyvg/vue3-notification": "^2.9.1", + "@types/d3": "^7.4.3", + "@types/webextension-polyfill": "^0.10.7", + "@vitejs/plugin-vue": "^4.6.2", + "@vuepic/vue-datepicker": "^5.4.0", + "typescript": "^5.7.2", + "vite": "^4.5.5", + "vite-plugin-web-extension": "^4.0.0", + "vue-tsc": "^2.2.0", + "webextension-polyfill": "^0.10.0" + } +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..b18b78f --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3129 @@ +lockfileVersion: 5.4 + +specifiers: + '@intlify/unplugin-vue-i18n': ^0.12.3 + '@kyvg/vue3-notification': ^2.9.1 + '@types/d3': ^7.4.3 + '@types/webextension-polyfill': ^0.10.7 + '@vitejs/plugin-vue': ^4.6.2 + '@vuepic/vue-datepicker': ^5.4.0 + '@vueuse/core': ^10.11.1 + chart.js: ^4.4.7 + d3: ^7.9.0 + date-fns: ^2.30.0 + rollup-plugin-copy: ^3.5.0 + typescript: ^5.7.2 + vite: ^4.5.5 + vite-plugin-web-extension: ^4.0.0 + vue: ^3.5.13 + vue-chartjs: ^5.3.2 + vue-i18n: ^9.14.2 + vue-tsc: ^2.2.0 + webextension-polyfill: ^0.10.0 + +dependencies: + '@vueuse/core': 10.11.1_vue@3.5.13 + chart.js: 4.4.7 + d3: 7.9.0 + date-fns: 2.30.0 + rollup-plugin-copy: 3.5.0 + vue: 3.5.13_typescript@5.7.2 + vue-chartjs: 5.3.2_chart.js@4.4.7+vue@3.5.13 + vue-i18n: 9.14.2_vue@3.5.13 + +devDependencies: + '@intlify/unplugin-vue-i18n': 0.12.3_vue-i18n@9.14.2 + '@kyvg/vue3-notification': 2.9.1_vue@3.5.13 + '@types/d3': 7.4.3 + '@types/webextension-polyfill': 0.10.7 + '@vitejs/plugin-vue': 4.6.2_vite@4.5.5+vue@3.5.13 + '@vuepic/vue-datepicker': 5.4.0_vue@3.5.13 + typescript: 5.7.2 + vite: 4.5.5 + vite-plugin-web-extension: 4.3.1 + vue-tsc: 2.2.0_typescript@5.7.2 + webextension-polyfill: 0.10.0 + +packages: + + /@babel/code-frame/7.26.2: + resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-validator-identifier': 7.25.9 + js-tokens: 4.0.0 + picocolors: 1.1.1 + dev: true + + /@babel/helper-string-parser/7.25.9: + resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + engines: {node: '>=6.9.0'} + + /@babel/helper-validator-identifier/7.25.9: + resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + engines: {node: '>=6.9.0'} + + /@babel/parser/7.26.3: + resolution: {integrity: sha512-WJ/CvmY8Mea8iDXo6a7RK2wbmJITT5fN3BEkRuFlxVyNx8jOKIIhmC4fSkTcPcf8JyavbBwIe6OpiCOBXt/IcA==} + engines: {node: '>=6.0.0'} + hasBin: true + dependencies: + '@babel/types': 7.26.3 + + /@babel/runtime/7.24.7: + resolution: {integrity: sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + dev: true + + /@babel/runtime/7.26.0: + resolution: {integrity: sha512-FDSOghenHTiToteC/QRlv2q3DhPZ/oOXTBoirfWNx1Cx3TMVcGWQtMMmQcSvb/JjpNeGzx8Pq/b4fKEJuWm1sw==} + engines: {node: '>=6.9.0'} + dependencies: + regenerator-runtime: 0.14.1 + + /@babel/types/7.26.3: + resolution: {integrity: sha512-vN5p+1kl59GVKMvTHt55NzzmYVxprfJD+ql7U9NFIfKCBkYE55LYtS+WtPlaYOyzydrKI8Nezd+aZextrd+FMA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/helper-string-parser': 7.25.9 + '@babel/helper-validator-identifier': 7.25.9 + + /@devicefarmer/adbkit-logcat/2.1.3: + resolution: {integrity: sha512-yeaGFjNBc/6+svbDeul1tNHtNChw6h8pSHAt5D+JsedUrMTN7tla7B15WLDyekxsuS2XlZHRxpuC6m92wiwCNw==} + engines: {node: '>= 4'} + dev: true + + /@devicefarmer/adbkit-monkey/1.2.1: + resolution: {integrity: sha512-ZzZY/b66W2Jd6NHbAhLyDWOEIBWC11VizGFk7Wx7M61JZRz7HR9Cq5P+65RKWUU7u6wgsE8Lmh9nE4Mz+U2eTg==} + engines: {node: '>= 0.10.4'} + dev: true + + /@devicefarmer/adbkit/3.2.6: + resolution: {integrity: sha512-8lO1hSeTgtxcOHhp4tTWq/JaOysp5KNbbyFoxNEBnwkCDZu/Bji3ZfOaG++Riv9jN6c9bgdLBOZqJTC5VJPRKQ==} + engines: {node: '>= 0.10.4'} + hasBin: true + dependencies: + '@devicefarmer/adbkit-logcat': 2.1.3 + '@devicefarmer/adbkit-monkey': 1.2.1 + bluebird: 3.7.2 + commander: 9.5.0 + debug: 4.3.7 + node-forge: 1.3.1 + split: 1.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /@esbuild/android-arm/0.18.20: + resolution: {integrity: sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-arm64/0.18.20: + resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/android-x64/0.18.20: + resolution: {integrity: sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-arm64/0.18.20: + resolution: {integrity: sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/darwin-x64/0.18.20: + resolution: {integrity: sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-arm64/0.18.20: + resolution: {integrity: sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/freebsd-x64/0.18.20: + resolution: {integrity: sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm/0.18.20: + resolution: {integrity: sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-arm64/0.18.20: + resolution: {integrity: sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ia32/0.18.20: + resolution: {integrity: sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-loong64/0.18.20: + resolution: {integrity: sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-mips64el/0.18.20: + resolution: {integrity: sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-ppc64/0.18.20: + resolution: {integrity: sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-riscv64/0.18.20: + resolution: {integrity: sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-s390x/0.18.20: + resolution: {integrity: sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/linux-x64/0.18.20: + resolution: {integrity: sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /@esbuild/netbsd-x64/0.18.20: + resolution: {integrity: sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/openbsd-x64/0.18.20: + resolution: {integrity: sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: true + optional: true + + /@esbuild/sunos-x64/0.18.20: + resolution: {integrity: sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-arm64/0.18.20: + resolution: {integrity: sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-ia32/0.18.20: + resolution: {integrity: sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@esbuild/win32-x64/0.18.20: + resolution: {integrity: sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: true + optional: true + + /@intlify/bundle-utils/7.5.1_vue-i18n@9.14.2: + resolution: {integrity: sha512-UovJl10oBIlmYEcWw+VIHdKY5Uv5sdPG0b/b6bOYxGLln3UwB75+2dlc0F3Fsa0RhoznQ5Rp589/BZpABpE4Xw==} + engines: {node: '>= 14.16'} + peerDependencies: + petite-vue-i18n: '*' + vue-i18n: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + dependencies: + '@intlify/message-compiler': 9.14.2 + '@intlify/shared': 9.14.2 + acorn: 8.14.0 + escodegen: 2.1.0 + estree-walker: 2.0.2 + jsonc-eslint-parser: 2.4.0 + magic-string: 0.30.17 + mlly: 1.7.3 + source-map-js: 1.2.1 + vue-i18n: 9.14.2_vue@3.5.13 + yaml-eslint-parser: 1.2.3 + dev: true + + /@intlify/core-base/9.14.2: + resolution: {integrity: sha512-DZyQ4Hk22sC81MP4qiCDuU+LdaYW91A6lCjq8AWPvY3+mGMzhGDfOCzvyR6YBQxtlPjFqMoFk9ylnNYRAQwXtQ==} + engines: {node: '>= 16'} + dependencies: + '@intlify/message-compiler': 9.14.2 + '@intlify/shared': 9.14.2 + + /@intlify/message-compiler/9.14.2: + resolution: {integrity: sha512-YsKKuV4Qv4wrLNsvgWbTf0E40uRv+Qiw1BeLQ0LAxifQuhiMe+hfTIzOMdWj/ZpnTDj4RSZtkXjJM7JDiiB5LQ==} + engines: {node: '>= 16'} + dependencies: + '@intlify/shared': 9.14.2 + source-map-js: 1.2.1 + + /@intlify/shared/9.14.2: + resolution: {integrity: sha512-uRAHAxYPeF+G5DBIboKpPgC/Waecd4Jz8ihtkpJQD5ycb5PwXp0k/+hBGl5dAjwF7w+l74kz/PKA8r8OK//RUw==} + engines: {node: '>= 16'} + + /@intlify/shared/9.3.0-beta.24: + resolution: {integrity: sha512-AKxJ8s7eKIQWkNaf4wyyoLRwf4puCuQgjSChlDJm5JBEt6T8HGgnYTJLRXu6LD/JACn3Qwu6hM/XRX1c9yvjmQ==} + engines: {node: '>= 16'} + dev: true + + /@intlify/unplugin-vue-i18n/0.12.3_vue-i18n@9.14.2: + resolution: {integrity: sha512-0riPtSfTM58JmGNMmJho/aHD2z3K24BESYAmkLvKlo61/LbaPvnjYU1DbSbJEm6bSjE2oEjUj+di3QaYxXei/w==} + engines: {node: '>= 14.16'} + peerDependencies: + petite-vue-i18n: '*' + vue-i18n: '*' + vue-i18n-bridge: '*' + peerDependenciesMeta: + petite-vue-i18n: + optional: true + vue-i18n: + optional: true + vue-i18n-bridge: + optional: true + dependencies: + '@intlify/bundle-utils': 7.5.1_vue-i18n@9.14.2 + '@intlify/shared': 9.3.0-beta.24 + '@rollup/pluginutils': 5.1.4 + '@vue/compiler-sfc': 3.5.13 + debug: 4.4.0 + fast-glob: 3.3.2 + js-yaml: 4.1.0 + json5: 2.2.3 + pathe: 1.1.2 + picocolors: 1.1.1 + source-map-js: 1.2.1 + unplugin: 1.16.0 + vue-i18n: 9.14.2_vue@3.5.13 + transitivePeerDependencies: + - rollup + - supports-color + dev: true + + /@jridgewell/sourcemap-codec/1.5.0: + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + /@kurkle/color/0.3.4: + resolution: {integrity: sha512-M5UknZPHRu3DEDWoipU6sE8PdkZ6Z/S+v4dD+Ke8IaNlpdSQah50lz1KtcFBa2vsdOnwbbnxJwVM4wty6udA5w==} + dev: false + + /@kyvg/vue3-notification/2.9.1_vue@3.5.13: + resolution: {integrity: sha512-FsY8g25tQetr3etnarxHtCeNFKssH8sheFu13LyL2JJmOOel437QqKV5n4RBDDDTIo55iKgIVYXeojliXYdEhw==} + peerDependencies: + vue: ^3.0.0 + dependencies: + vue: 3.5.13_typescript@5.7.2 + dev: true + + /@nodelib/fs.scandir/2.1.5: + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + /@nodelib/fs.stat/2.0.5: + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + /@nodelib/fs.walk/1.2.8: + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.18.0 + + /@pnpm/config.env-replace/1.1.0: + resolution: {integrity: sha512-htyl8TWnKL7K/ESFa1oW2UB5lVDxuF5DpM7tBi6Hu2LNL3mWkIzNLG6N4zoCUP1lCKNxWy/3iu8mS8MvToGd6w==} + engines: {node: '>=12.22.0'} + dev: true + + /@pnpm/network.ca-file/1.0.2: + resolution: {integrity: sha512-YcPQ8a0jwYU9bTdJDpXjMi7Brhkr1mXsXrUJvjqM2mQDgkRiz8jFaQGOdaLxgjtUfQgZhKy/O3cG/YwmgKaxLA==} + engines: {node: '>=12.22.0'} + dependencies: + graceful-fs: 4.2.10 + dev: true + + /@pnpm/npm-conf/2.3.1: + resolution: {integrity: sha512-c83qWb22rNRuB0UaVCI0uRPNRr8Z0FWnEIvT47jiHAmOIUHbBOg5XvV7pM5x+rKn9HRpjxquDbXYSXr3fAKFcw==} + engines: {node: '>=12'} + dependencies: + '@pnpm/config.env-replace': 1.1.0 + '@pnpm/network.ca-file': 1.0.2 + config-chain: 1.1.13 + dev: true + + /@rollup/pluginutils/5.1.4: + resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.6 + estree-walker: 2.0.2 + picomatch: 4.0.2 + dev: true + + /@sindresorhus/is/5.6.0: + resolution: {integrity: sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==} + engines: {node: '>=14.16'} + dev: true + + /@szmarczak/http-timer/5.0.1: + resolution: {integrity: sha512-+PmQX0PiAYPMeVYe237LJAYvOMYW1j2rH5YROyS3b4CTVJum34HfRvKvAzozHAQG0TnHNdUfY9nCeUyRAs//cw==} + engines: {node: '>=14.16'} + dependencies: + defer-to-connect: 2.0.1 + dev: true + + /@types/d3-array/3.2.1: + resolution: {integrity: sha512-Y2Jn2idRrLzUfAKV2LyRImR+y4oa2AntrgID95SHJxuMUrkNXmanDSed71sRNZysveJVt1hLLemQZIady0FpEg==} + dev: true + + /@types/d3-axis/3.0.6: + resolution: {integrity: sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-brush/3.0.6: + resolution: {integrity: sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-chord/3.0.6: + resolution: {integrity: sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==} + dev: true + + /@types/d3-color/3.1.3: + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + dev: true + + /@types/d3-contour/3.0.6: + resolution: {integrity: sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/geojson': 7946.0.15 + dev: true + + /@types/d3-delaunay/6.0.4: + resolution: {integrity: sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==} + dev: true + + /@types/d3-dispatch/3.0.6: + resolution: {integrity: sha512-4fvZhzMeeuBJYZXRXrRIQnvUYfyXwYmLsdiN7XXmVNQKKw1cM8a5WdID0g1hVFZDqT9ZqZEY5pD44p24VS7iZQ==} + dev: true + + /@types/d3-drag/3.0.7: + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-dsv/3.0.7: + resolution: {integrity: sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==} + dev: true + + /@types/d3-ease/3.0.2: + resolution: {integrity: sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==} + dev: true + + /@types/d3-fetch/3.0.7: + resolution: {integrity: sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==} + dependencies: + '@types/d3-dsv': 3.0.7 + dev: true + + /@types/d3-force/3.0.10: + resolution: {integrity: sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==} + dev: true + + /@types/d3-format/3.0.4: + resolution: {integrity: sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==} + dev: true + + /@types/d3-geo/3.1.0: + resolution: {integrity: sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==} + dependencies: + '@types/geojson': 7946.0.15 + dev: true + + /@types/d3-hierarchy/3.1.7: + resolution: {integrity: sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==} + dev: true + + /@types/d3-interpolate/3.0.4: + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + dependencies: + '@types/d3-color': 3.1.3 + dev: true + + /@types/d3-path/3.1.0: + resolution: {integrity: sha512-P2dlU/q51fkOc/Gfl3Ul9kicV7l+ra934qBFXCFhrZMOL6du1TM0pm1ThYvENukyOn5h9v+yMJ9Fn5JK4QozrQ==} + dev: true + + /@types/d3-polygon/3.0.2: + resolution: {integrity: sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==} + dev: true + + /@types/d3-quadtree/3.0.6: + resolution: {integrity: sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==} + dev: true + + /@types/d3-random/3.0.3: + resolution: {integrity: sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==} + dev: true + + /@types/d3-scale-chromatic/3.1.0: + resolution: {integrity: sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==} + dev: true + + /@types/d3-scale/4.0.8: + resolution: {integrity: sha512-gkK1VVTr5iNiYJ7vWDI+yUFFlszhNMtVeneJ6lUTKPjprsvLLI9/tgEGiXJOnlINJA8FyA88gfnQsHbybVZrYQ==} + dependencies: + '@types/d3-time': 3.0.4 + dev: true + + /@types/d3-selection/3.0.11: + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + dev: true + + /@types/d3-shape/3.1.6: + resolution: {integrity: sha512-5KKk5aKGu2I+O6SONMYSNflgiP0WfZIQvVUMan50wHsLG1G94JlxEVnCpQARfTtzytuY0p/9PXXZb3I7giofIA==} + dependencies: + '@types/d3-path': 3.1.0 + dev: true + + /@types/d3-time-format/4.0.3: + resolution: {integrity: sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==} + dev: true + + /@types/d3-time/3.0.4: + resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} + dev: true + + /@types/d3-timer/3.0.2: + resolution: {integrity: sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==} + dev: true + + /@types/d3-transition/3.0.9: + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + dependencies: + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3-zoom/3.0.8: + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + dev: true + + /@types/d3/7.4.3: + resolution: {integrity: sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==} + dependencies: + '@types/d3-array': 3.2.1 + '@types/d3-axis': 3.0.6 + '@types/d3-brush': 3.0.6 + '@types/d3-chord': 3.0.6 + '@types/d3-color': 3.1.3 + '@types/d3-contour': 3.0.6 + '@types/d3-delaunay': 6.0.4 + '@types/d3-dispatch': 3.0.6 + '@types/d3-drag': 3.0.7 + '@types/d3-dsv': 3.0.7 + '@types/d3-ease': 3.0.2 + '@types/d3-fetch': 3.0.7 + '@types/d3-force': 3.0.10 + '@types/d3-format': 3.0.4 + '@types/d3-geo': 3.1.0 + '@types/d3-hierarchy': 3.1.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-path': 3.1.0 + '@types/d3-polygon': 3.0.2 + '@types/d3-quadtree': 3.0.6 + '@types/d3-random': 3.0.3 + '@types/d3-scale': 4.0.8 + '@types/d3-scale-chromatic': 3.1.0 + '@types/d3-selection': 3.0.11 + '@types/d3-shape': 3.1.6 + '@types/d3-time': 3.0.4 + '@types/d3-time-format': 4.0.3 + '@types/d3-timer': 3.0.2 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + dev: true + + /@types/estree/1.0.6: + resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + dev: true + + /@types/fs-extra/8.1.5: + resolution: {integrity: sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==} + dependencies: + '@types/node': 22.10.2 + dev: false + + /@types/geojson/7946.0.15: + resolution: {integrity: sha512-9oSxFzDCT2Rj6DfcHF8G++jxBKS7mBqXl5xrRW+Kbvjry6Uduya2iiwqHPhVXpasAVMBYKkEPGgKhd3+/HZ6xA==} + dev: true + + /@types/glob/7.2.0: + resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} + dependencies: + '@types/minimatch': 5.1.2 + '@types/node': 22.10.2 + dev: false + + /@types/http-cache-semantics/4.0.4: + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + dev: true + + /@types/minimatch/3.0.5: + resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} + dev: true + + /@types/minimatch/5.1.2: + resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + dev: false + + /@types/node/22.10.2: + resolution: {integrity: sha512-Xxr6BBRCAOQixvonOye19wnzyDiUtTeqldOOmj3CkeblonbccA12PFwlufvRdrpjXxqnmUaeiU5EOA+7s5diUQ==} + dependencies: + undici-types: 6.20.0 + + /@types/web-bluetooth/0.0.20: + resolution: {integrity: sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==} + dev: false + + /@types/webextension-polyfill/0.10.7: + resolution: {integrity: sha512-10ql7A0qzBmFB+F+qAke/nP1PIonS0TXZAOMVOxEUsm+lGSW6uwVcISFNa0I4Oyj0884TZVWGGMIWeXOVSNFHw==} + dev: true + + /@vitejs/plugin-vue/4.6.2_vite@4.5.5+vue@3.5.13: + resolution: {integrity: sha512-kqf7SGFoG+80aZG6Pf+gsZIVvGSCKE98JbiWqcCV9cThtg91Jav0yvYFC9Zb+jKetNGF6ZKeoaxgZfND21fWKw==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.0.0 || ^5.0.0 + vue: ^3.2.25 + dependencies: + vite: 4.5.5 + vue: 3.5.13_typescript@5.7.2 + dev: true + + /@volar/language-core/2.4.11: + resolution: {integrity: sha512-lN2C1+ByfW9/JRPpqScuZt/4OrUUse57GLI6TbLgTIqBVemdl1wNcZ1qYGEo2+Gw8coYLgCy7SuKqn6IrQcQgg==} + dependencies: + '@volar/source-map': 2.4.11 + dev: true + + /@volar/source-map/2.4.11: + resolution: {integrity: sha512-ZQpmafIGvaZMn/8iuvCFGrW3smeqkq/IIh9F1SdSx9aUl0J4Iurzd6/FhmjNO5g2ejF3rT45dKskgXWiofqlZQ==} + dev: true + + /@volar/typescript/2.4.11: + resolution: {integrity: sha512-2DT+Tdh88Spp5PyPbqhyoYavYCPDsqbHLFwcUI9K1NlY1YgUJvujGdrqUp0zWxnW7KWNTr3xSpMuv2WnaTKDAw==} + dependencies: + '@volar/language-core': 2.4.11 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 + dev: true + + /@vue/compiler-core/3.5.13: + resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + dependencies: + '@babel/parser': 7.26.3 + '@vue/shared': 3.5.13 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + /@vue/compiler-dom/3.5.13: + resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + dependencies: + '@vue/compiler-core': 3.5.13 + '@vue/shared': 3.5.13 + + /@vue/compiler-sfc/3.5.13: + resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + dependencies: + '@babel/parser': 7.26.3 + '@vue/compiler-core': 3.5.13 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.4.49 + source-map-js: 1.2.1 + + /@vue/compiler-ssr/3.5.13: + resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/shared': 3.5.13 + + /@vue/compiler-vue2/2.7.16: + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + dev: true + + /@vue/devtools-api/6.6.4: + resolution: {integrity: sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==} + + /@vue/language-core/2.2.0_typescript@5.7.2: + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@volar/language-core': 2.4.11 + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.13 + alien-signals: 0.4.10 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + typescript: 5.7.2 + dev: true + + /@vue/reactivity/3.5.13: + resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + dependencies: + '@vue/shared': 3.5.13 + + /@vue/runtime-core/3.5.13: + resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/shared': 3.5.13 + + /@vue/runtime-dom/3.5.13: + resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + dependencies: + '@vue/reactivity': 3.5.13 + '@vue/runtime-core': 3.5.13 + '@vue/shared': 3.5.13 + csstype: 3.1.3 + + /@vue/server-renderer/3.5.13_vue@3.5.13: + resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + peerDependencies: + vue: 3.5.13 + dependencies: + '@vue/compiler-ssr': 3.5.13 + '@vue/shared': 3.5.13 + vue: 3.5.13_typescript@5.7.2 + + /@vue/shared/3.5.13: + resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + + /@vuepic/vue-datepicker/5.4.0_vue@3.5.13: + resolution: {integrity: sha512-9f1ZqRDfak/UmBbD81BdqMDpUku2YphTwQXG8DF6hsrjIXsq5sX7BWJB6LhyVgvX9QFrSyFIp4fsHE3UFofZ7A==} + engines: {node: '>=14'} + peerDependencies: + vue: '>=3.2.0' + dependencies: + date-fns: 2.30.0 + date-fns-tz: 1.3.8_date-fns@2.30.0 + vue: 3.5.13_typescript@5.7.2 + dev: true + + /@vueuse/core/10.11.1_vue@3.5.13: + resolution: {integrity: sha512-guoy26JQktXPcz+0n3GukWIy/JDNKti9v6VEMu6kV2sYBsWuGiTU8OWdg+ADfUbHg3/3DlqySDe7JmdHrktiww==} + dependencies: + '@types/web-bluetooth': 0.0.20 + '@vueuse/metadata': 10.11.1 + '@vueuse/shared': 10.11.1_vue@3.5.13 + vue-demi: 0.14.10_vue@3.5.13 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@vueuse/metadata/10.11.1: + resolution: {integrity: sha512-IGa5FXd003Ug1qAZmyE8wF3sJ81xGLSqTqtQ6jaVfkeZ4i5kS2mwQF61yhVqojRnenVew5PldLyRgvdl4YYuSw==} + dev: false + + /@vueuse/shared/10.11.1_vue@3.5.13: + resolution: {integrity: sha512-LHpC8711VFZlDaYUXEBbFBCQ7GS3dVU9mjOhhMhXP6txTV4EhYQg/KGnQuvt/sPAtoUKq7VVUnL6mVtFoL42sA==} + dependencies: + vue-demi: 0.14.10_vue@3.5.13 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /acorn-jsx/5.3.2_acorn@8.14.0: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + dependencies: + acorn: 8.14.0 + dev: true + + /acorn/8.14.0: + resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + engines: {node: '>=0.4.0'} + hasBin: true + dev: true + + /adm-zip/0.5.16: + resolution: {integrity: sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ==} + engines: {node: '>=12.0'} + dev: true + + /ajv/8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + dev: true + + /alien-signals/0.4.10: + resolution: {integrity: sha512-7S60rz/mMjz0Djq1VI9rd4bGqKNgxTUGE6k7kwrRO6tF95qt1S3ohz1qaQisvUsfbGh7yXnm6DPRrOhOl1ho1A==} + dev: true + + /ansi-align/3.0.1: + resolution: {integrity: sha512-IOfwwBF5iczOjp/WeY4YxyjqAFMQoZufdQWDd19SEExbVLNXqvpzSJ/M7Za4/sCPmQ0+GRquoA7bGcINcxew6w==} + dependencies: + string-width: 4.2.3 + dev: true + + /ansi-regex/5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: true + + /ansi-regex/6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + dev: true + + /ansi-styles/6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + dev: true + + /any-promise/1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + dev: true + + /argparse/2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + dev: true + + /array-differ/4.0.0: + resolution: {integrity: sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /array-union/2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + dev: false + + /array-union/3.0.1: + resolution: {integrity: sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==} + engines: {node: '>=12'} + dev: true + + /async-lock/1.4.1: + resolution: {integrity: sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==} + dev: true + + /async/3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + dev: true + + /at-least-node/1.0.0: + resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} + engines: {node: '>= 4.0.0'} + dev: true + + /balanced-match/1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + /bluebird/3.7.2: + resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} + dev: true + + /boolbase/1.0.0: + resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + dev: true + + /boxen/7.1.1: + resolution: {integrity: sha512-2hCgjEmP8YLWQ130n2FerGv7rYpfBmnmp9Uy2Le1vge6X3gZIfSmEzP5QTDElFxcvVcXlEn8Aq6MU/PZygIOog==} + engines: {node: '>=14.16'} + dependencies: + ansi-align: 3.0.1 + camelcase: 7.0.1 + chalk: 5.4.1 + cli-boxes: 3.0.0 + string-width: 5.1.2 + type-fest: 2.19.0 + widest-line: 4.0.1 + wrap-ansi: 8.1.0 + dev: true + + /brace-expansion/1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + /brace-expansion/2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + dependencies: + balanced-match: 1.0.2 + dev: true + + /braces/3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + + /buffer-from/1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + dev: true + + /bunyan/1.8.15: + resolution: {integrity: sha512-0tECWShh6wUysgucJcBAoYegf3JJoZWibxdqhTm7OHPeT42qdjkZ29QCMcKwbgU1kiH+auSIasNRXMLWXafXig==} + engines: {'0': node >=0.10.0} + hasBin: true + optionalDependencies: + dtrace-provider: 0.8.8 + moment: 2.30.1 + mv: 2.1.1 + safe-json-stringify: 1.2.0 + dev: true + + /cacheable-lookup/7.0.0: + resolution: {integrity: sha512-+qJyx4xiKra8mZrcwhjMRMUhD5NR1R8esPkzIYxX96JiecFoxAXFuz/GpR3+ev4PE1WamHip78wV0vcmPQtp8w==} + engines: {node: '>=14.16'} + dev: true + + /cacheable-request/10.2.14: + resolution: {integrity: sha512-zkDT5WAF4hSSoUgyfg5tFIxz8XQK+25W/TLVojJTMKBaxevLBBtLxgqguAuVQB8PVW79FVjHcU+GJ9tVbDZ9mQ==} + engines: {node: '>=14.16'} + dependencies: + '@types/http-cache-semantics': 4.0.4 + get-stream: 6.0.1 + http-cache-semantics: 4.1.1 + keyv: 4.5.4 + mimic-response: 4.0.0 + normalize-url: 8.0.1 + responselike: 3.0.0 + dev: true + + /camelcase/7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} + engines: {node: '>=14.16'} + dev: true + + /chalk/5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + dev: true + + /charenc/0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + dev: true + + /chart.js/4.4.7: + resolution: {integrity: sha512-pwkcKfdzTMAU/+jNosKhNL2bHtJc/sSmYgVbuGTEDhzkrhmyihmP7vUc/5ZK9WopidMDHNe3Wm7jOd/WhuHWuw==} + engines: {pnpm: '>=8'} + dependencies: + '@kurkle/color': 0.3.4 + dev: false + + /chrome-launcher/1.1.0: + resolution: {integrity: sha512-rJYWeEAERwWIr3c3mEVXwNiODPEdMRlRxHc47B1qHPOolHZnkj7rMv1QSUfPoG6MgatWj5AxSpnKKR4QEwEQIQ==} + engines: {node: '>=12.13.0'} + hasBin: true + dependencies: + '@types/node': 22.10.2 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: true + + /ci-info/3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + dev: true + + /cli-boxes/3.0.0: + resolution: {integrity: sha512-/lzGpEWL/8PfI0BmBOPRwp0c/wFNX1RdUML3jK/RcSBA9T8mZDdQpqYBKtCFTOfQbwPqWEOpjqW+Fnayc0969g==} + engines: {node: '>=10'} + dev: true + + /colorette/1.4.0: + resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} + dev: false + + /commander/2.9.0: + resolution: {integrity: sha512-bmkUukX8wAOjHdN26xj5c4ctEV22TQ7dQYhSmuckKhToXrkUn0iIaolHdIxYYqD55nhpSPA9zPQ1yP57GdXP2A==} + engines: {node: '>= 0.6.x'} + dependencies: + graceful-readlink: 1.0.1 + dev: true + + /commander/7.2.0: + resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} + engines: {node: '>= 10'} + dev: false + + /commander/9.5.0: + resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} + engines: {node: ^12.20.0 || >=14} + dev: true + + /concat-map/0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + /concat-stream/1.6.2: + resolution: {integrity: sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==} + engines: {'0': node >= 0.8} + dependencies: + buffer-from: 1.1.2 + inherits: 2.0.4 + readable-stream: 2.3.8 + typedarray: 0.0.6 + dev: true + + /confbox/0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + dev: true + + /config-chain/1.1.13: + resolution: {integrity: sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ==} + dependencies: + ini: 1.3.8 + proto-list: 1.2.4 + dev: true + + /configstore/6.0.0: + resolution: {integrity: sha512-cD31W1v3GqUlQvbBCGcXmd2Nj9SvLDOP1oQ0YFuLETufzSPaKp11rYBsSOm7rCsW3OnIRAFM3OxRhceaXNYHkA==} + engines: {node: '>=12'} + dependencies: + dot-prop: 6.0.1 + graceful-fs: 4.2.11 + unique-string: 3.0.0 + write-file-atomic: 3.0.3 + xdg-basedir: 5.1.0 + dev: true + + /core-util-is/1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + dev: true + + /crypt/0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + dev: true + + /crypto-random-string/4.0.0: + resolution: {integrity: sha512-x8dy3RnvYdlUcPOjkEHqozhiwzKNSq7GcPuXFbnyMOCHxX8V3OgIg/pYuabl2sbUPfIJaeAQB7PMOK8DFIdoRA==} + engines: {node: '>=12'} + dependencies: + type-fest: 1.4.0 + dev: true + + /css-select/5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.2.1 + nth-check: 2.1.1 + dev: true + + /css-what/6.1.0: + resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + engines: {node: '>= 6'} + dev: true + + /cssom/0.5.0: + resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==} + dev: true + + /csstype/3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + /d3-array/3.2.4: + resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} + engines: {node: '>=12'} + dependencies: + internmap: 2.0.3 + dev: false + + /d3-axis/3.0.0: + resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} + engines: {node: '>=12'} + dev: false + + /d3-brush/3.0.0: + resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1_d3-selection@3.0.0 + dev: false + + /d3-chord/3.0.1: + resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-color/3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + dev: false + + /d3-contour/4.0.2: + resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-delaunay/6.0.4: + resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} + engines: {node: '>=12'} + dependencies: + delaunator: 5.0.1 + dev: false + + /d3-dispatch/3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + dev: false + + /d3-drag/3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + dev: false + + /d3-dsv/3.0.1: + resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} + engines: {node: '>=12'} + hasBin: true + dependencies: + commander: 7.2.0 + iconv-lite: 0.6.3 + rw: 1.3.3 + dev: false + + /d3-ease/3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + dev: false + + /d3-fetch/3.0.1: + resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} + engines: {node: '>=12'} + dependencies: + d3-dsv: 3.0.1 + dev: false + + /d3-force/3.0.0: + resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-quadtree: 3.0.1 + d3-timer: 3.0.1 + dev: false + + /d3-format/3.1.0: + resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + engines: {node: '>=12'} + dev: false + + /d3-geo/3.1.1: + resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-hierarchy/3.1.2: + resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} + engines: {node: '>=12'} + dev: false + + /d3-interpolate/3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + dev: false + + /d3-path/3.1.0: + resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} + engines: {node: '>=12'} + dev: false + + /d3-polygon/3.0.1: + resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} + engines: {node: '>=12'} + dev: false + + /d3-quadtree/3.0.1: + resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} + engines: {node: '>=12'} + dev: false + + /d3-random/3.0.1: + resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} + engines: {node: '>=12'} + dev: false + + /d3-scale-chromatic/3.1.0: + resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} + engines: {node: '>=12'} + dependencies: + d3-color: 3.1.0 + d3-interpolate: 3.0.1 + dev: false + + /d3-scale/4.0.2: + resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-format: 3.1.0 + d3-interpolate: 3.0.1 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + dev: false + + /d3-selection/3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + dev: false + + /d3-shape/3.2.0: + resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} + engines: {node: '>=12'} + dependencies: + d3-path: 3.1.0 + dev: false + + /d3-time-format/4.1.0: + resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} + engines: {node: '>=12'} + dependencies: + d3-time: 3.1.0 + dev: false + + /d3-time/3.1.0: + resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + dev: false + + /d3-timer/3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + dev: false + + /d3-transition/3.0.1_d3-selection@3.0.0: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + dev: false + + /d3-zoom/3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1_d3-selection@3.0.0 + dev: false + + /d3/7.9.0: + resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} + engines: {node: '>=12'} + dependencies: + d3-array: 3.2.4 + d3-axis: 3.0.0 + d3-brush: 3.0.0 + d3-chord: 3.0.1 + d3-color: 3.1.0 + d3-contour: 4.0.2 + d3-delaunay: 6.0.4 + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-dsv: 3.0.1 + d3-ease: 3.0.1 + d3-fetch: 3.0.1 + d3-force: 3.0.0 + d3-format: 3.1.0 + d3-geo: 3.1.1 + d3-hierarchy: 3.1.2 + d3-interpolate: 3.0.1 + d3-path: 3.1.0 + d3-polygon: 3.0.1 + d3-quadtree: 3.0.1 + d3-random: 3.0.1 + d3-scale: 4.0.2 + d3-scale-chromatic: 3.1.0 + d3-selection: 3.0.0 + d3-shape: 3.2.0 + d3-time: 3.1.0 + d3-time-format: 4.1.0 + d3-timer: 3.0.1 + d3-transition: 3.0.1_d3-selection@3.0.0 + d3-zoom: 3.0.0 + dev: false + + /date-fns-tz/1.3.8_date-fns@2.30.0: + resolution: {integrity: sha512-qwNXUFtMHTTU6CFSFjoJ80W8Fzzp24LntbjFFBgL/faqds4e5mo9mftoRLgr3Vi1trISsg4awSpYVsOQCRnapQ==} + peerDependencies: + date-fns: '>=2.0.0' + dependencies: + date-fns: 2.30.0 + dev: true + + /date-fns/2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} + dependencies: + '@babel/runtime': 7.26.0 + + /de-indent/1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + dev: true + + /debounce/1.2.1: + resolution: {integrity: sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug==} + dev: true + + /debug/2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.0.0 + dev: true + + /debug/4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /debug/4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + dependencies: + ms: 2.1.3 + dev: true + + /decompress-response/6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} + engines: {node: '>=10'} + dependencies: + mimic-response: 3.1.0 + dev: true + + /deep-extend/0.6.0: + resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} + engines: {node: '>=4.0.0'} + dev: true + + /defer-to-connect/2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} + dev: true + + /delaunator/5.0.1: + resolution: {integrity: sha512-8nvh+XBe96aCESrGOqMp/84b13H9cdKbG5P2ejQCh4d4sK9RL4371qou9drQjMhvnPmhWl5hnmqbEE0fXr9Xnw==} + dependencies: + robust-predicates: 3.0.2 + dev: false + + /dir-glob/3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + dependencies: + path-type: 4.0.0 + dev: false + + /dom-serializer/2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.5.0 + dev: true + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + dev: true + + /domhandler/5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: true + + /domutils/3.2.1: + resolution: {integrity: sha512-xWXmuRnN9OMP6ptPd2+H0cCbcYBULa5YDTbMm/2lvkWvNA3O4wcW+GvzooqBuNM8yy6pl3VIAeJTUUWUbfI5Fw==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: true + + /dot-prop/6.0.1: + resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} + engines: {node: '>=10'} + dependencies: + is-obj: 2.0.0 + dev: true + + /dtrace-provider/0.8.8: + resolution: {integrity: sha512-b7Z7cNtHPhH9EJhNNbbeqTcXB8LGFFZhq1PGgEvpeHlzd36bhbdTWoE/Ba/YguqpBSlAPKnARWhVlhunCMwfxg==} + engines: {node: '>=0.10'} + requiresBuild: true + dependencies: + nan: 2.22.0 + dev: true + optional: true + + /eastasianwidth/0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /emoji-regex/8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: true + + /emoji-regex/9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + + /entities/4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + /error-ex/1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + dependencies: + is-arrayish: 0.2.1 + dev: true + + /es6-error/4.1.1: + resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + dev: true + + /esbuild/0.18.20: + resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.18.20 + '@esbuild/android-arm64': 0.18.20 + '@esbuild/android-x64': 0.18.20 + '@esbuild/darwin-arm64': 0.18.20 + '@esbuild/darwin-x64': 0.18.20 + '@esbuild/freebsd-arm64': 0.18.20 + '@esbuild/freebsd-x64': 0.18.20 + '@esbuild/linux-arm': 0.18.20 + '@esbuild/linux-arm64': 0.18.20 + '@esbuild/linux-ia32': 0.18.20 + '@esbuild/linux-loong64': 0.18.20 + '@esbuild/linux-mips64el': 0.18.20 + '@esbuild/linux-ppc64': 0.18.20 + '@esbuild/linux-riscv64': 0.18.20 + '@esbuild/linux-s390x': 0.18.20 + '@esbuild/linux-x64': 0.18.20 + '@esbuild/netbsd-x64': 0.18.20 + '@esbuild/openbsd-x64': 0.18.20 + '@esbuild/sunos-x64': 0.18.20 + '@esbuild/win32-arm64': 0.18.20 + '@esbuild/win32-ia32': 0.18.20 + '@esbuild/win32-x64': 0.18.20 + dev: true + + /escape-goat/4.0.0: + resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} + engines: {node: '>=12'} + dev: true + + /escape-string-regexp/4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + dev: true + + /escodegen/2.1.0: + resolution: {integrity: sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==} + engines: {node: '>=6.0'} + hasBin: true + dependencies: + esprima: 4.0.1 + estraverse: 5.3.0 + esutils: 2.0.3 + optionalDependencies: + source-map: 0.6.1 + dev: true + + /eslint-visitor-keys/3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + + /espree/9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.14.0 + acorn-jsx: 5.3.2_acorn@8.14.0 + eslint-visitor-keys: 3.4.3 + dev: true + + /esprima/4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + dev: true + + /estraverse/5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + dev: true + + /estree-walker/2.0.2: + resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} + + /esutils/2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + dev: true + + /fast-deep-equal/3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + dev: true + + /fast-glob/3.3.2: + resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} + engines: {node: '>=8.6.0'} + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + /fast-uri/3.0.3: + resolution: {integrity: sha512-aLrHthzCjH5He4Z2H9YZ+v6Ujb9ocRuW6ZzkJQOrTxleEijANq4v1TsaPaVG1PZcuurEzrLcWRyYBYXD5cEiaw==} + dev: true + + /fastq/1.18.0: + resolution: {integrity: sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==} + dependencies: + reusify: 1.0.4 + + /fill-range/7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + + /firefox-profile/4.6.0: + resolution: {integrity: sha512-I9rAm1w8U3CdhgO4EzTJsCvgcbvynZn9lOySkZf78wUdUIQH2w9QOKf3pAX+THt2XMSSR3kJSuM8P7bYux9j8g==} + hasBin: true + dependencies: + adm-zip: 0.5.16 + fs-extra: 9.0.1 + ini: 2.0.0 + minimist: 1.2.8 + xml2js: 0.5.0 + dev: true + + /form-data-encoder/2.1.4: + resolution: {integrity: sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==} + engines: {node: '>= 14.17'} + dev: true + + /fs-extra/10.1.0: + resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} + engines: {node: '>=12'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra/11.2.0: + resolution: {integrity: sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + dev: true + + /fs-extra/8.1.0: + resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} + engines: {node: '>=6 <7 || >=8'} + dependencies: + graceful-fs: 4.2.11 + jsonfile: 4.0.0 + universalify: 0.1.2 + dev: false + + /fs-extra/9.0.1: + resolution: {integrity: sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==} + engines: {node: '>=10'} + dependencies: + at-least-node: 1.0.0 + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 1.0.0 + dev: true + + /fs.realpath/1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + dev: false + + /fsevents/2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + requiresBuild: true + dev: true + optional: true + + /fx-runner/1.4.0: + resolution: {integrity: sha512-rci1g6U0rdTg6bAaBboP7XdRu01dzTAaKXxFf+PUqGuCv6Xu7o8NZdY1D5MvKGIjb6EdS1g3VlXOgksir1uGkg==} + hasBin: true + dependencies: + commander: 2.9.0 + shell-quote: 1.7.3 + spawn-sync: 1.0.15 + when: 3.7.7 + which: 1.2.4 + winreg: 0.0.12 + dev: true + + /get-stream/6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + dev: true + + /glob-parent/5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + dependencies: + is-glob: 4.0.3 + + /glob-to-regexp/0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true + + /glob/6.0.4: + resolution: {integrity: sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==} + deprecated: Glob versions prior to v9 are no longer supported + dependencies: + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: true + optional: true + + /glob/7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + dev: false + + /global-dirs/3.0.1: + resolution: {integrity: sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==} + engines: {node: '>=10'} + dependencies: + ini: 2.0.0 + dev: true + + /globby/10.0.1: + resolution: {integrity: sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==} + engines: {node: '>=8'} + dependencies: + '@types/glob': 7.2.0 + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.2 + glob: 7.2.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + dev: false + + /got/12.6.1: + resolution: {integrity: sha512-mThBblvlAF1d4O5oqyvN+ZxLAYwIJK7bpMxgYqPD9okW0C3qm5FFn7k811QrcuEBwaogR3ngOFoCfs6mRv7teQ==} + engines: {node: '>=14.16'} + dependencies: + '@sindresorhus/is': 5.6.0 + '@szmarczak/http-timer': 5.0.1 + cacheable-lookup: 7.0.0 + cacheable-request: 10.2.14 + decompress-response: 6.0.0 + form-data-encoder: 2.1.4 + get-stream: 6.0.1 + http2-wrapper: 2.2.1 + lowercase-keys: 3.0.0 + p-cancelable: 3.0.0 + responselike: 3.0.0 + dev: true + + /graceful-fs/4.2.10: + resolution: {integrity: sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==} + dev: true + + /graceful-fs/4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + /graceful-readlink/1.0.1: + resolution: {integrity: sha512-8tLu60LgxF6XpdbK8OW3FA+IfTNBn1ZHGHKF4KQbEeSkajYw5PlYJcKluntgegDPTg8UkHjpet1T82vk6TQ68w==} + dev: true + + /growly/1.3.0: + resolution: {integrity: sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw==} + dev: true + + /has-yarn/3.0.0: + resolution: {integrity: sha512-IrsVwUHhEULx3R8f/aA8AHuEzAorplsab/v8HBzEiIukwq5i/EC+xmOW+HfP1OaDP+2JkgT1yILHN2O3UFIbcA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /he/1.2.0: + resolution: {integrity: sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==} + hasBin: true + dev: true + + /html-escaper/3.0.3: + resolution: {integrity: sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==} + dev: true + + /htmlparser2/8.0.2: + resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.1 + entities: 4.5.0 + dev: true + + /http-cache-semantics/4.1.1: + resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + dev: true + + /http2-wrapper/2.2.1: + resolution: {integrity: sha512-V5nVw1PAOgfI3Lmeaj2Exmeg7fenjhRUgz1lPSezy1CuhPYbgQtbQj4jZfEAEMlaL+vupsvhjqCyjzob0yxsmQ==} + engines: {node: '>=10.19.0'} + dependencies: + quick-lru: 5.1.1 + resolve-alpn: 1.2.1 + dev: true + + /iconv-lite/0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + dependencies: + safer-buffer: 2.1.2 + dev: false + + /ignore/5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + dev: false + + /immediate/3.0.6: + resolution: {integrity: sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==} + dev: true + + /import-lazy/4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + dev: true + + /imurmurhash/0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + dev: true + + /inflight/1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + /inherits/2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + /ini/1.3.8: + resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} + dev: true + + /ini/2.0.0: + resolution: {integrity: sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==} + engines: {node: '>=10'} + dev: true + + /internmap/2.0.3: + resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} + engines: {node: '>=12'} + dev: false + + /is-absolute/0.1.7: + resolution: {integrity: sha512-Xi9/ZSn4NFapG8RP98iNPMOeaV3mXPisxKxzKtHVqr3g56j/fBn+yZmnxSVAA8lmZbl2J9b/a4kJvfU3hqQYgA==} + engines: {node: '>=0.10.0'} + dependencies: + is-relative: 0.1.3 + dev: true + + /is-arrayish/0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + dev: true + + /is-buffer/1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + dev: true + + /is-ci/3.0.1: + resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} + hasBin: true + dependencies: + ci-info: 3.9.0 + dev: true + + /is-docker/2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + dev: true + + /is-extglob/2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + /is-fullwidth-code-point/3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: true + + /is-glob/4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + dependencies: + is-extglob: 2.1.1 + + /is-installed-globally/0.4.0: + resolution: {integrity: sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==} + engines: {node: '>=10'} + dependencies: + global-dirs: 3.0.1 + is-path-inside: 3.0.3 + dev: true + + /is-npm/6.0.0: + resolution: {integrity: sha512-JEjxbSmtPSt1c8XTkVrlujcXdKV1/tvuQ7GwKcAlyiVLeYFQ2VHat8xfrDJsIkhCdF/tZ7CiIR3sy141c6+gPQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /is-number/7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + /is-obj/2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + dev: true + + /is-path-inside/3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + + /is-plain-object/2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + dependencies: + isobject: 3.0.1 + dev: true + + /is-plain-object/3.0.1: + resolution: {integrity: sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==} + engines: {node: '>=0.10.0'} + dev: false + + /is-primitive/3.0.1: + resolution: {integrity: sha512-GljRxhWvlCNRfZyORiH77FwdFwGcMO620o37EOYC0ORWdq+WYNVqW0w2Juzew4M+L81l6/QS3t5gkkihyRqv9w==} + engines: {node: '>=0.10.0'} + dev: true + + /is-relative/0.1.3: + resolution: {integrity: sha512-wBOr+rNM4gkAZqoLRJI4myw5WzzIdQosFAAbnvfXP5z1LyzgAI3ivOKehC5KfqlQJZoihVhirgtCBj378Eg8GA==} + engines: {node: '>=0.10.0'} + dev: true + + /is-typedarray/1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + dev: true + + /is-wsl/2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + dependencies: + is-docker: 2.2.1 + dev: true + + /is-yarn-global/0.4.1: + resolution: {integrity: sha512-/kppl+R+LO5VmhYSEWARUFjodS25D68gvj8W7z0I7OWhUla5xWu8KL6CtB2V0R6yqhnRgbcaREMr4EEM6htLPQ==} + engines: {node: '>=12'} + dev: true + + /isarray/1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + dev: true + + /isexe/1.1.2: + resolution: {integrity: sha512-d2eJzK691yZwPHcv1LbeAOa91yMJ9QmfTgSO1oXB65ezVhXQsxBac2vEB4bMVms9cGzaA99n6V2viHMq82VLDw==} + dev: true + + /isexe/2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + dev: true + + /isobject/3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + dev: true + + /js-tokens/4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + dev: true + + /js-yaml/4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + dependencies: + argparse: 2.0.1 + dev: true + + /json-buffer/3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + dev: true + + /json-parse-even-better-errors/3.0.2: + resolution: {integrity: sha512-fi0NG4bPjCHunUJffmLd0gxssIgkNmArMvis4iNah6Owg1MCJjWhEcDLmsK6iGkJq3tHwbDkTlce70/tmXN4cQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + + /json-schema-traverse/1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + dev: true + + /json5/2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + dev: true + + /jsonc-eslint-parser/2.4.0: + resolution: {integrity: sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + acorn: 8.14.0 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + semver: 7.6.3 + dev: true + + /jsonfile/4.0.0: + resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + optionalDependencies: + graceful-fs: 4.2.11 + dev: false + + /jsonfile/6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + dev: true + + /jszip/3.10.1: + resolution: {integrity: sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==} + dependencies: + lie: 3.3.0 + pako: 1.0.11 + readable-stream: 2.3.8 + setimmediate: 1.0.5 + dev: true + + /keyv/4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + dependencies: + json-buffer: 3.0.1 + dev: true + + /latest-version/7.0.0: + resolution: {integrity: sha512-KvNT4XqAMzdcL6ka6Tl3i2lYeFDgXNCuIX+xNx6ZMVR1dFq+idXd9FLKNMOIx0t9mJ9/HudyX4oZWXZQ0UJHeg==} + engines: {node: '>=14.16'} + dependencies: + package-json: 8.1.1 + dev: true + + /lie/3.3.0: + resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} + dependencies: + immediate: 3.0.6 + dev: true + + /lighthouse-logger/2.0.1: + resolution: {integrity: sha512-ioBrW3s2i97noEmnXxmUq7cjIcVRjT5HBpAYy8zE11CxU9HqlWHHeRxfeN1tn8F7OEMVPIC9x1f8t3Z7US9ehQ==} + dependencies: + debug: 2.6.9 + marky: 1.2.5 + transitivePeerDependencies: + - supports-color + dev: true + + /lines-and-columns/2.0.4: + resolution: {integrity: sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /linkedom/0.14.26: + resolution: {integrity: sha512-mK6TrydfFA7phrnp+1j57ycBwFI5bGSW6YXlw9acHoqF+mP/y+FooEYYyniOt5Ot57FSKB3iwmnuQ1UUyNLm5A==} + dependencies: + css-select: 5.1.0 + cssom: 0.5.0 + html-escaper: 3.0.3 + htmlparser2: 8.0.2 + uhyphen: 0.2.0 + dev: true + + /lodash.uniq/4.5.0: + resolution: {integrity: sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==} + dev: true + + /lodash.uniqby/4.7.0: + resolution: {integrity: sha512-e/zcLx6CSbmaEgFHCA7BnoQKyCtKMxnuWrJygbwPs/AIn+IMKl66L8/s+wBUn5LRw2pZx3bUHibiV1b6aTWIww==} + dev: true + + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + + /lowercase-keys/3.0.0: + resolution: {integrity: sha512-ozCC6gdQ+glXOQsveKD0YsDy8DSQFjDTz4zyzEHNV5+JP5D62LmfDZ6o1cycFx9ouG940M5dE8C8CTewdj2YWQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /magic-string/0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + /make-error/1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + dev: true + + /marky/1.2.5: + resolution: {integrity: sha512-q9JtQJKjpsVxCRVgQ+WapguSbKC3SQ5HEzFGPAJMStgh3QjCawp00UKv3MTTAArTmGmmPUvllHZoNbZ3gs0I+Q==} + dev: true + + /md5/2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + dependencies: + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + dev: true + + /merge2/1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + /micromatch/4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + /mimic-response/3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} + dev: true + + /mimic-response/4.0.0: + resolution: {integrity: sha512-e5ISH9xMYU0DzrT+jl8q2ze9D6eWBto+I8CNpe+VI+K2J/F/k3PdkdTdz4wvGVH4NTpo+NRYTVIuMQEMMcsLqg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: true + + /minimatch/3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + dependencies: + brace-expansion: 1.1.11 + + /minimatch/9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + + /minimist/1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + dev: true + + /mkdirp/0.5.6: + resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} + hasBin: true + dependencies: + minimist: 1.2.8 + dev: true + optional: true + + /mkdirp/3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /mlly/1.7.3: + resolution: {integrity: sha512-xUsx5n/mN0uQf4V548PKQ+YShA4/IW0KI1dZhrNrPCLG+xizETbHTkOa1f8/xut9JRPp8kQuMnz0oqwkTiLo/A==} + dependencies: + acorn: 8.14.0 + pathe: 1.1.2 + pkg-types: 1.2.1 + ufo: 1.5.4 + dev: true + + /moment/2.30.1: + resolution: {integrity: sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==} + requiresBuild: true + dev: true + optional: true + + /ms/2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + dev: true + + /ms/2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + dev: true + + /muggle-string/0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + dev: true + + /multimatch/6.0.0: + resolution: {integrity: sha512-I7tSVxHGPlmPN/enE3mS1aOSo6bWBfls+3HmuEeCUBCE7gWnm3cBXCBkpurzFjVRwC6Kld8lLaZ1Iv5vOcjvcQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + '@types/minimatch': 3.0.5 + array-differ: 4.0.0 + array-union: 3.0.1 + minimatch: 3.1.2 + dev: true + + /mv/2.1.1: + resolution: {integrity: sha512-at/ZndSy3xEGJ8i0ygALh8ru9qy7gWW1cmkaqBN29JmMlIvM//MEO9y1sk/avxuwnPcfhkejkLsuPxH81BrkSg==} + engines: {node: '>=0.8.0'} + requiresBuild: true + dependencies: + mkdirp: 0.5.6 + ncp: 2.0.0 + rimraf: 2.4.5 + dev: true + optional: true + + /mz/2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + dev: true + + /nan/2.22.0: + resolution: {integrity: sha512-nbajikzWTMwsW+eSsNm3QwlOs7het9gGJU5dDZzRTQGk03vyBOauxgI4VakDzE0PtsGTmXPsXTbbjVhRwR5mpw==} + dev: true + optional: true + + /nanoid/3.3.8: + resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + /ncp/2.0.0: + resolution: {integrity: sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==} + hasBin: true + dev: true + optional: true + + /node-forge/1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + dev: true + + /node-notifier/10.0.1: + resolution: {integrity: sha512-YX7TSyDukOZ0g+gmzjB6abKu+hTGvO8+8+gIFDsRCU2t8fLV/P2unmt+LGFaIa4y64aX98Qksa97rgz4vMNeLQ==} + dependencies: + growly: 1.3.0 + is-wsl: 2.2.0 + semver: 7.6.3 + shellwords: 0.1.1 + uuid: 8.3.2 + which: 2.0.2 + dev: true + + /normalize-url/8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + dev: true + + /nth-check/2.1.1: + resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + dependencies: + boolbase: 1.0.0 + dev: true + + /object-assign/4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + dev: true + + /once/1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + dependencies: + wrappy: 1.0.2 + + /os-shim/0.1.3: + resolution: {integrity: sha512-jd0cvB8qQ5uVt0lvCIexBaROw1KyKm5sbulg2fWOHjETisuCzWyt+eTZKEMs8v6HwzoGs8xik26jg7eCM6pS+A==} + engines: {node: '>= 0.4.0'} + dev: true + + /p-cancelable/3.0.0: + resolution: {integrity: sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==} + engines: {node: '>=12.20'} + dev: true + + /package-json/8.1.1: + resolution: {integrity: sha512-cbH9IAIJHNj9uXi196JVsRlt7cHKak6u/e6AkL/bkRelZ7rlL3X1YKxsZwa36xipOEKAsdtmaG6aAJoM1fx2zA==} + engines: {node: '>=14.16'} + dependencies: + got: 12.6.1 + registry-auth-token: 5.0.3 + registry-url: 6.0.1 + semver: 7.6.3 + dev: true + + /pako/1.0.11: + resolution: {integrity: sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==} + dev: true + + /parse-json/7.1.1: + resolution: {integrity: sha512-SgOTCX/EZXtZxBE5eJ97P4yGM5n37BwRU+YMsH4vNzFqJV/oWFXXCmwFlgWUM4PrakybVOueJJ6pwHqSVhTFDw==} + engines: {node: '>=16'} + dependencies: + '@babel/code-frame': 7.26.2 + error-ex: 1.3.2 + json-parse-even-better-errors: 3.0.2 + lines-and-columns: 2.0.4 + type-fest: 3.13.1 + dev: true + + /path-browserify/1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + dev: true + + /path-is-absolute/1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + /path-type/4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + dev: false + + /pathe/1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: true + + /picocolors/1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + /picomatch/2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + /picomatch/4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + dev: true + + /pkg-types/1.2.1: + resolution: {integrity: sha512-sQoqa8alT3nHjGuTjuKgOnvjo4cljkufdtLMnO2LBP/wRwuDlo1tkaEdMxCRhyGRPacv/ztlZgDPm2b7FAmEvw==} + dependencies: + confbox: 0.1.8 + mlly: 1.7.3 + pathe: 1.1.2 + dev: true + + /postcss/8.4.49: + resolution: {integrity: sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.8 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + /process-nextick-args/2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + dev: true + + /promise-toolbox/0.21.0: + resolution: {integrity: sha512-NV8aTmpwrZv+Iys54sSFOBx3tuVaOBvvrft5PNppnxy9xpU/akHbaWIril22AB22zaPgrgwKdD0KsrM0ptUtpg==} + engines: {node: '>=6'} + dependencies: + make-error: 1.3.6 + dev: true + + /proto-list/1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: true + + /pupa/3.1.0: + resolution: {integrity: sha512-FLpr4flz5xZTSJxSeaheeMKN/EDzMdK7b8PTOC6a5PYFKTucWbdqjgqaEyH0shFiSJrVB1+Qqi4Tk19ccU6Aug==} + engines: {node: '>=12.20'} + dependencies: + escape-goat: 4.0.0 + dev: true + + /queue-microtask/1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: true + + /rc/1.2.8: + resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} + hasBin: true + dependencies: + deep-extend: 0.6.0 + ini: 1.3.8 + minimist: 1.2.8 + strip-json-comments: 2.0.1 + dev: true + + /readable-stream/2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + dev: true + + /regenerator-runtime/0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + + /registry-auth-token/5.0.3: + resolution: {integrity: sha512-1bpc9IyC+e+CNFRaWyn77tk4xGG4PPUyfakSmA6F6cvUDjrm58dfyJ3II+9yb10EDkHoy1LaPSmHaWLOH3m6HA==} + engines: {node: '>=14'} + dependencies: + '@pnpm/npm-conf': 2.3.1 + dev: true + + /registry-url/6.0.1: + resolution: {integrity: sha512-+crtS5QjFRqFCoQmvGduwYWEBng99ZvmFvF+cUJkGYF1L1BfU8C6Zp9T7f5vPAwyLkUExpvK+ANVZmGU49qi4Q==} + engines: {node: '>=12'} + dependencies: + rc: 1.2.8 + dev: true + + /require-from-string/2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + dev: true + + /resolve-alpn/1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + dev: true + + /responselike/3.0.0: + resolution: {integrity: sha512-40yHxbNcl2+rzXvZuVkrYohathsSJlMTXKryG5y8uciHv1+xDLHQpgjG64JUO9nrEq2jGLH6IZ8BcZyw3wrweg==} + engines: {node: '>=14.16'} + dependencies: + lowercase-keys: 3.0.0 + dev: true + + /reusify/1.0.4: + resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + /rimraf/2.4.5: + resolution: {integrity: sha512-J5xnxTyqaiw06JjMftq7L9ouA448dw/E7dKghkP9WpKNuwmARNNg+Gk8/u5ryb9N/Yo2+z3MCwuqFK/+qPOPfQ==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + dependencies: + glob: 6.0.4 + dev: true + optional: true + + /robust-predicates/3.0.2: + resolution: {integrity: sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==} + dev: false + + /rollup-plugin-copy/3.5.0: + resolution: {integrity: sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==} + engines: {node: '>=8.3'} + dependencies: + '@types/fs-extra': 8.1.5 + colorette: 1.4.0 + fs-extra: 8.1.0 + globby: 10.0.1 + is-plain-object: 3.0.1 + dev: false + + /rollup/3.29.5: + resolution: {integrity: sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} + hasBin: true + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /run-parallel/1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + dependencies: + queue-microtask: 1.2.3 + + /rw/1.3.3: + resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} + dev: false + + /safe-buffer/5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + dev: true + + /safe-json-stringify/1.2.0: + resolution: {integrity: sha512-gH8eh2nZudPQO6TytOvbxnuhYBOvDBBLW52tz5q6X58lJcd/tkmqFR+5Z9adS8aJtURSXWThWy/xJtJwixErvg==} + requiresBuild: true + dev: true + optional: true + + /safer-buffer/2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + dev: false + + /sax/1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + dev: true + + /semver-diff/4.0.0: + resolution: {integrity: sha512-0Ju4+6A8iOnpL/Thra7dZsSlOHYAHIeMxfhWQRI1/VLcT3WDBZKKtQt/QkBOsiIN9ZpuvHE6cGZ0x4glCMmfiA==} + engines: {node: '>=12'} + dependencies: + semver: 7.6.3 + dev: true + + /semver/7.6.3: + resolution: {integrity: sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==} + engines: {node: '>=10'} + hasBin: true + dev: true + + /set-value/4.1.0: + resolution: {integrity: sha512-zTEg4HL0RwVrqcWs3ztF+x1vkxfm0lP+MQQFPiMJTKVceBwEV0A569Ou8l9IYQG8jOZdMVI1hGsc0tmeD2o/Lw==} + engines: {node: '>=11.0'} + dependencies: + is-plain-object: 2.0.4 + is-primitive: 3.0.1 + dev: true + + /setimmediate/1.0.5: + resolution: {integrity: sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==} + dev: true + + /shell-quote/1.7.3: + resolution: {integrity: sha512-Vpfqwm4EnqGdlsBFNmHhxhElJYrdfcxPThu+ryKS5J8L/fhAwLazFZtq+S+TWZ9ANj2piSQLGj6NQg+lKPmxrw==} + dev: true + + /shellwords/0.1.1: + resolution: {integrity: sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==} + dev: true + + /signal-exit/3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: true + + /slash/3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + dev: false + + /source-map-js/1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + /source-map-support/0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + dev: true + + /source-map/0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + dev: true + + /spawn-sync/1.0.15: + resolution: {integrity: sha512-9DWBgrgYZzNghseho0JOuh+5fg9u6QWhAWa51QC7+U5rCheZ/j1DrEZnyE0RBBRqZ9uEXGPgSSM0nky6burpVw==} + requiresBuild: true + dependencies: + concat-stream: 1.6.2 + os-shim: 0.1.3 + dev: true + + /split/1.0.1: + resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} + dependencies: + through: 2.3.8 + dev: true + + /string-width/4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: true + + /string-width/5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + + /string_decoder/1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + dependencies: + safe-buffer: 5.1.2 + dev: true + + /strip-ansi/6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: true + + /strip-ansi/7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + dependencies: + ansi-regex: 6.1.0 + dev: true + + /strip-bom/5.0.0: + resolution: {integrity: sha512-p+byADHF7SzEcVnLvc/r3uognM1hUhObuHXxJcgLCfD194XAkaLbjq3Wzb0N5G2tgIjH0dgT708Z51QxMeu60A==} + engines: {node: '>=12'} + dev: true + + /strip-json-comments/2.0.1: + resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} + engines: {node: '>=0.10.0'} + dev: true + + /strip-json-comments/5.0.1: + resolution: {integrity: sha512-0fk9zBqO67Nq5M/m45qHCJxylV/DhBlIOVExqgOMiCCrzrhU6tCibRXNqE3jwJLftzE9SNuZtYbpzcO+i9FiKw==} + engines: {node: '>=14.16'} + dev: true + + /thenify-all/1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + dependencies: + thenify: 3.3.1 + dev: true + + /thenify/3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + dependencies: + any-promise: 1.3.0 + dev: true + + /through/2.3.8: + resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} + dev: true + + /tmp/0.2.3: + resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} + engines: {node: '>=14.14'} + dev: true + + /to-regex-range/5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + dependencies: + is-number: 7.0.0 + + /type-fest/1.4.0: + resolution: {integrity: sha512-yGSza74xk0UG8k+pLh5oeoYirvIiWo5t0/o3zHHAO2tRDiZcxWP7fywNlXhqb6/r6sWvwi+RsyQMWhVLe4BVuA==} + engines: {node: '>=10'} + dev: true + + /type-fest/2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + dev: true + + /type-fest/3.13.1: + resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} + engines: {node: '>=14.16'} + dev: true + + /typedarray-to-buffer/3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + dependencies: + is-typedarray: 1.0.0 + dev: true + + /typedarray/0.0.6: + resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} + dev: true + + /typescript/5.7.2: + resolution: {integrity: sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==} + engines: {node: '>=14.17'} + hasBin: true + + /ufo/1.5.4: + resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + dev: true + + /uhyphen/0.2.0: + resolution: {integrity: sha512-qz3o9CHXmJJPGBdqzab7qAYuW8kQGKNEuoHFYrBwV6hWIMcpAmxDLXojcHfFr9US1Pe6zUswEIJIbLI610fuqA==} + dev: true + + /undici-types/6.20.0: + resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + + /unique-string/3.0.0: + resolution: {integrity: sha512-VGXBUVwxKMBUznyffQweQABPRRW1vHZAbadFZud4pLFAqRGvv/96vafgjWFqzourzr8YonlQiPgH0YCJfawoGQ==} + engines: {node: '>=12'} + dependencies: + crypto-random-string: 4.0.0 + dev: true + + /universalify/0.1.2: + resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} + engines: {node: '>= 4.0.0'} + dev: false + + /universalify/1.0.0: + resolution: {integrity: sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug==} + engines: {node: '>= 10.0.0'} + dev: true + + /universalify/2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + dev: true + + /unplugin/1.16.0: + resolution: {integrity: sha512-5liCNPuJW8dqh3+DM6uNM2EI3MLLpCKp/KY+9pB5M2S2SR2qvvDHhKgBOaTWEbZTAws3CXfB0rKTIolWKL05VQ==} + engines: {node: '>=14.0.0'} + dependencies: + acorn: 8.14.0 + webpack-virtual-modules: 0.6.2 + dev: true + + /update-notifier/6.0.2: + resolution: {integrity: sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==} + engines: {node: '>=14.16'} + dependencies: + boxen: 7.1.1 + chalk: 5.4.1 + configstore: 6.0.0 + has-yarn: 3.0.0 + import-lazy: 4.0.0 + is-ci: 3.0.1 + is-installed-globally: 0.4.0 + is-npm: 6.0.0 + is-yarn-global: 0.4.1 + latest-version: 7.0.0 + pupa: 3.1.0 + semver: 7.6.3 + semver-diff: 4.0.0 + xdg-basedir: 5.1.0 + dev: true + + /util-deprecate/1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + dev: true + + /uuid/8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: true + + /vite-plugin-web-extension/4.3.1: + resolution: {integrity: sha512-yG/07Rzk70SxLUQIfZMbNm0472gbFPkoPCAJvcGhyblTrg0FPSKfkQJ4yug0//IxoYCaTv5WIcNJCuVntUz4rQ==} + engines: {node: '>=16'} + dependencies: + ajv: 8.17.1 + async-lock: 1.4.1 + fs-extra: 10.1.0 + json5: 2.2.3 + linkedom: 0.14.26 + lodash.uniq: 4.5.0 + lodash.uniqby: 4.7.0 + md5: 2.3.0 + vite: 4.5.5 + web-ext-run: 0.2.2 + webextension-polyfill: 0.10.0 + yaml: 2.6.1 + transitivePeerDependencies: + - '@types/node' + - bufferutil + - less + - lightningcss + - sass + - stylus + - sugarss + - supports-color + - terser + - utf-8-validate + dev: true + + /vite/4.5.5: + resolution: {integrity: sha512-ifW3Lb2sMdX+WU91s3R0FyQlAyLxOzCSCP37ujw0+r5POeHPwe6udWVIElKQq8gk3t7b8rkmvqC6IHBpCff4GQ==} + engines: {node: ^14.18.0 || >=16.0.0} + hasBin: true + peerDependencies: + '@types/node': '>= 14' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + dependencies: + esbuild: 0.18.20 + postcss: 8.4.49 + rollup: 3.29.5 + optionalDependencies: + fsevents: 2.3.3 + dev: true + + /vscode-uri/3.0.8: + resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} + dev: true + + /vue-chartjs/5.3.2_chart.js@4.4.7+vue@3.5.13: + resolution: {integrity: sha512-NrkbRRoYshbXbWqJkTN6InoDVwVb90C0R7eAVgMWcB9dPikbruaOoTFjFYHE/+tNPdIe6qdLCDjfjPHQ0fw4jw==} + peerDependencies: + chart.js: ^4.1.1 + vue: ^3.0.0-0 || ^2.7.0 + dependencies: + chart.js: 4.4.7 + vue: 3.5.13_typescript@5.7.2 + dev: false + + /vue-demi/0.14.10_vue@3.5.13: + resolution: {integrity: sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + peerDependencies: + '@vue/composition-api': ^1.0.0-rc.1 + vue: ^3.0.0-0 || ^2.6.0 + peerDependenciesMeta: + '@vue/composition-api': + optional: true + dependencies: + vue: 3.5.13_typescript@5.7.2 + dev: false + + /vue-i18n/9.14.2_vue@3.5.13: + resolution: {integrity: sha512-JK9Pm80OqssGJU2Y6F7DcM8RFHqVG4WkuCqOZTVsXkEzZME7ABejAUqUdA931zEBedc4thBgSUWxeQh4uocJAQ==} + engines: {node: '>= 16'} + peerDependencies: + vue: ^3.0.0 + dependencies: + '@intlify/core-base': 9.14.2 + '@intlify/shared': 9.14.2 + '@vue/devtools-api': 6.6.4 + vue: 3.5.13_typescript@5.7.2 + + /vue-tsc/2.2.0_typescript@5.7.2: + resolution: {integrity: sha512-gtmM1sUuJ8aSb0KoAFmK9yMxb8TxjewmxqTJ1aKphD5Cbu0rULFY6+UQT51zW7SpUcenfPUuflKyVwyx9Qdnxg==} + hasBin: true + peerDependencies: + typescript: '>=5.0.0' + dependencies: + '@volar/typescript': 2.4.11 + '@vue/language-core': 2.2.0_typescript@5.7.2 + typescript: 5.7.2 + dev: true + + /vue/3.5.13_typescript@5.7.2: + resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.5.13 + '@vue/compiler-sfc': 3.5.13 + '@vue/runtime-dom': 3.5.13 + '@vue/server-renderer': 3.5.13_vue@3.5.13 + '@vue/shared': 3.5.13 + typescript: 5.7.2 + + /watchpack/2.4.1: + resolution: {integrity: sha512-8wrBCMtVhqcXP2Sup1ctSkga6uc2Bx0IIvKyT7yTFier5AXHooSI+QyQQAtTb7+E0IUCCKyTFmXqdqgum2XWGg==} + engines: {node: '>=10.13.0'} + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + dev: true + + /web-ext-run/0.2.2: + resolution: {integrity: sha512-GD59q5/1wYQJXTHrljMZaBa3cCz+Jj3FMDLYgKyAa34TPcHSuMaGqp7TcLJ66PCe43C3hmbEAZd8QCpAB34eiw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + dependencies: + '@babel/runtime': 7.24.7 + '@devicefarmer/adbkit': 3.2.6 + bunyan: 1.8.15 + chrome-launcher: 1.1.0 + debounce: 1.2.1 + es6-error: 4.1.1 + firefox-profile: 4.6.0 + fs-extra: 11.2.0 + fx-runner: 1.4.0 + mkdirp: 3.0.1 + multimatch: 6.0.0 + mz: 2.7.0 + node-notifier: 10.0.1 + parse-json: 7.1.1 + promise-toolbox: 0.21.0 + set-value: 4.1.0 + source-map-support: 0.5.21 + strip-bom: 5.0.0 + strip-json-comments: 5.0.1 + tmp: 0.2.3 + update-notifier: 6.0.2 + watchpack: 2.4.1 + ws: 8.18.0 + zip-dir: 2.0.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: true + + /webextension-polyfill/0.10.0: + resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} + dev: true + + /webpack-virtual-modules/0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + dev: true + + /when/3.7.7: + resolution: {integrity: sha512-9lFZp/KHoqH6bPKjbWqa+3Dg/K/r2v0X/3/G2x4DBGchVS2QX2VXL3cZV994WQVnTM1/PD71Az25nAzryEUugw==} + dev: true + + /which/1.2.4: + resolution: {integrity: sha512-zDRAqDSBudazdfM9zpiI30Fu9ve47htYXcGi3ln0wfKu2a7SmrT6F3VDoYONu//48V8Vz4TdCRNPjtvyRO3yBA==} + hasBin: true + dependencies: + is-absolute: 0.1.7 + isexe: 1.1.2 + dev: true + + /which/2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + dependencies: + isexe: 2.0.0 + dev: true + + /widest-line/4.0.1: + resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} + engines: {node: '>=12'} + dependencies: + string-width: 5.1.2 + dev: true + + /winreg/0.0.12: + resolution: {integrity: sha512-typ/+JRmi7RqP1NanzFULK36vczznSNN8kWVA9vIqXyv8GhghUlwhGp1Xj3Nms1FsPcNnsQrJOR10N58/nQ9hQ==} + dev: true + + /wrap-ansi/8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + + /wrappy/1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + /write-file-atomic/3.0.3: + resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} + dependencies: + imurmurhash: 0.1.4 + is-typedarray: 1.0.0 + signal-exit: 3.0.7 + typedarray-to-buffer: 3.1.5 + dev: true + + /ws/8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: true + + /xdg-basedir/5.1.0: + resolution: {integrity: sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==} + engines: {node: '>=12'} + dev: true + + /xml2js/0.5.0: + resolution: {integrity: sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==} + engines: {node: '>=4.0.0'} + dependencies: + sax: 1.4.1 + xmlbuilder: 11.0.1 + dev: true + + /xmlbuilder/11.0.1: + resolution: {integrity: sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==} + engines: {node: '>=4.0'} + dev: true + + /yaml-eslint-parser/1.2.3: + resolution: {integrity: sha512-4wZWvE398hCP7O8n3nXKu/vdq1HcH01ixYlCREaJL5NUMwQ0g3MaGFUBNSlmBtKmhbtVG/Cm6lyYmSVTEVil8A==} + engines: {node: ^14.17.0 || >=16.0.0} + dependencies: + eslint-visitor-keys: 3.4.3 + lodash: 4.17.21 + yaml: 2.6.1 + dev: true + + /yaml/2.6.1: + resolution: {integrity: sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==} + engines: {node: '>= 14'} + hasBin: true + dev: true + + /zip-dir/2.0.0: + resolution: {integrity: sha512-uhlsJZWz26FLYXOD6WVuq+fIcZ3aBPGo/cFdiLlv3KNwpa52IF3ISV8fLhQLiqVu5No3VhlqlgthN6gehil1Dg==} + dependencies: + async: 3.2.6 + jszip: 3.10.1 + dev: true diff --git a/src/icons/128x128.png b/public/128x128.png similarity index 100% rename from src/icons/128x128.png rename to public/128x128.png diff --git a/src/icons/16x16.png b/public/16x16.png similarity index 100% rename from src/icons/16x16.png rename to public/16x16.png diff --git a/src/icons/32x32.png b/public/32x32.png similarity index 100% rename from src/icons/32x32.png rename to public/32x32.png diff --git a/src/icons/48x48.png b/public/48x48.png similarity index 100% rename from src/icons/48x48.png rename to public/48x48.png diff --git a/scripts/zip.ps1 b/scripts/zip.ps1 new file mode 100644 index 0000000..3e258e5 --- /dev/null +++ b/scripts/zip.ps1 @@ -0,0 +1,7 @@ +$sourceFolder = ".\dist\*" +$targetFolder = ".\artifacts" +If (!(test-path -PathType container $targetFolder)) { + New-Item -ItemType Directory -Path $targetFolder +} +$version = $(node -pe "require('./src/manifest.json').version") +Compress-Archive -Path $sourceFolder -DestinationPath $targetFolder/web-activity-time-tracker-$version.zip \ No newline at end of file diff --git a/src/_locales/de/messages.json b/src/_locales/de/messages.json new file mode 100644 index 0000000..c9f366d --- /dev/null +++ b/src/_locales/de/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Websites sperren, Pomodoro & Webanalyse" + }, + "extDescription": { + "message": "Verfolgen und begrenzen Sie die Zeit Ihrer Webaktivitäten und blockieren Sie den Zugang zu den Websites." + }, + "settings": { + "message": "Einstellungen" + }, + "today": { + "message": "Heute" + }, + "allTime": { + "message": "Gesamte Zeit" + }, + "byDays": { + "message": "Täglich" + }, + "noData": { + "message": "Keine Daten verfügbar" + }, + "noDataForPeriod": { + "message": "Keine Daten für den ausgewählten Zeitraum" + }, + "showAll": { + "message": "Alle Websites anzeigen" + }, + "sortBy": { + "message": "Sortieren nach" + }, + "usageTime": { + "message": "Verwendungszeit" + }, + "session": { + "message": "Sitzung" + }, + "someSession": { + "message": "Sitzungen" + }, + "sessions": { + "message": "Sitzungen" + }, + "days": { + "message": "Tage" + }, + "aggregate": { + "message": "Gesammelte Daten seit" + }, + "websites": { + "message": "Webseiten" + }, + "cannotOpenFile": { + "message": "Aufgrund des Sicherheitsprotokolls können Sie eine lokale Datei nicht öffnen" + }, + "document": { + "message": "Dokument" + }, + "limit": { + "message": "Limit" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "Der erste aktive Tag" + }, + "numberOfActiveDays": { + "message": "Gesamtzahl der aktiven Tage" + }, + "totalNumberOfDays": { + "message": "Alle Tage" + }, + "todayTime": { + "message": "Gesamtzeit heute" + }, + "averageTime": { + "message": "Durchschnittliche Zeit an aktiven Tagen" + }, + "averageDailyUsage": { + "message": "Durchschnittliche tägliche Nutzung" + }, + "mostActiveDay": { + "message": "Der aktivste Tag" + }, + "mostInactiveDay": { + "message": "Der inaktivste Tag" + }, + "todayInclude": { + "message": "Der heutige Tag ist in der Statistik enthalten. Aus der Statistik ausschließen." + }, + "todayEcclude": { + "message": "Der heutige Tag ist aus der Statistik ausgeschlossen. In die Statistik einbeziehen." + }, + "averageTimeByDays": { + "message": "Durchschnittliche Zeit für ausgewählte Tage" + }, + "exportToCsv": { + "message": "Als CSV exportieren" + }, + "week": { + "message": "Diese Woche" + }, + "month": { + "message": "Diesen Monat" + }, + "lastMonth": { + "message": "Letzter Monat" + }, + "generalSettings": { + "message": "Einstellungen" + }, + "whiteListSettings": { + "message": "Weiße Liste" + }, + "limitsSettings": { + "message": "Beschränkungen" + }, + "notificationsSettings": { + "message": "Benachrichtigungen" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Pomodoro Einstellungen" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "Die Pomodoro-Methode ist eine Zeitmanagementtechnik, die auf dem Wechsel von konzentrierten Arbeits- und Ruhephasen basiert. Bei der klassischen Pomodoro-Methode dauert die Arbeitsphase 25 Minuten und die Ruhephase 5 Minuten." + }, + "pomodoroExplanationIcon": { + "message": "Wenn der Pomodoro-Modus aktiviert ist und der Betriebsmodus aktiv ist, sehen Sie dieses Symbol", + "description": "Während der Ruhezeiten sehen Sie dieses Erweiterungssymbol" + }, + "pomodoroExplanationTime": { + "message": "Während des Pomodoro-Modus berücksichtigt die Erweiterung weiterhin die Zeit, die Sie auf den Seiten verbracht haben, alle Grenzen und Benachrichtigungen funktionieren." + }, + "pomodoroExplanationStop": { + "message": "Nach dem Drücken von 'Stop' werden die Betriebs- und Ruhezeiten auf Null zurückgesetzt." + }, + "pomodoroWork": { + "message": "Zeitraum der Arbeit" + }, + "pomodoroRest": { + "message": "Ruhezeit" + }, + "pomodoroFrequency": { + "message": "Anzahl der Wiederholungen" + }, + "start": { + "message": "Starten Sie" + }, + "stop": { + "message": "Stop" + }, + "pomodoroIsEnabled": { + "message": "Der Pomodoro-Modus ist aktiviert" + }, + "pomodoroSoundAfter": { + "message": "Ton nach vollständiger Periode" + }, + "clickToPreview": { + "message": "Zum Anhören klicken" + }, + "sound": { + "message": "Ton" + }, + "aboutSettings": { + "message": "Über die Erweiterung" + }, + "viewTimeInBadge": { + "message": "Zeitindikator anzeigen", + "description": "Die aktuellen Informationen zur \"verbrauchten Zeit\" im Kurzformat anzeigen" + }, + "deferringDescription": { + "message": "Die Sperre kann nur einmal pro Tag um 5 Minuten verschoben werden" + }, + "allowDeferringBlock": { + "message": "Verzögerung der Sperre um 5 Minuten zulassen", + "description": "Nachdem die Site gesperrt wurde, können Sie die Sperrung einmal täglich um 5 Minuten verschieben" + }, + "intervalInactivity": { + "message": "Zeiterfassung stoppen, bei Inaktivität für:", + "description": "Betrifft alle Aktionen mit der Maus oder der Tastatur" + }, + "exportToCsvSetting": { + "message": "Ihre Webaktivitätsdaten als CSV-Datei exportieren", + "description": "Ihre Webaktivitäten für einen beliebigen Zeitraum exportieren" + }, + "sec": { + "message": "Sekunden" + }, + "min": { + "message": "Minute" + }, + "2min": { + "message": "Minuten" + }, + "mins": { + "message": "Minuten" + }, + "whiteList": { + "message": "Aktivität und Zeit für diese Websites werden nicht erfasst." + }, + "addWebsite": { + "message": "Website hinzufügen" + }, + "enterWebsite": { + "message": "Namen der Website eingeben..." + }, + "enterNotification": { + "message": "Text für die Benachrichtigung eingeben..." + }, + "limits": { + "message": "Tägliche Zugriffsbeschränkungen für Websites", + "description": "Legen Sie die maximale Zeit fest, die pro Tag für den Besuch der Website zulässig ist. Nach dieser Zeit wird die Website gesperrt." + }, + "limitsTip": { + "message": "Setzen Sie die Blockierungszeit auf 0 Stunden 0 Minuten, um die Website sofort zu blockieren." + }, + "save": { + "message": "Speichern" + }, + "showDailyNotification": { + "message": "Tägliche Zusammenfassung als Benachrichtigung", + "description": "Am Ende jedes Tages erhalten Sie eine Benachrichtigung mit einer Zusammenfassung Ihrer täglichen Nutzung." + }, + "notificationTime": { + "message": "Benachrichtigungen für Websites", + "description": "Jedes Mal eine Benachrichtigung anzeigen, wenn Sie den angegebenen Zeitraum auf einer Website verbringen." + }, + "notificationMessage": { + "message": "Benachrichtigungstext", + "description": "Dieser Text wird in der Benachrichtigung für Websites angezeigt" + }, + "notificationTimeSetting": { + "message": "Tägliche Zusammenfassung um folgende Uhrzeit anzeigen:" + }, + "github": { + "message": "Feedback zur Erweiterung geben oder ein Problem melden: " + }, + "question": { + "message": "Eine Frage stellen oder Verbesserungen vorschlagen: " + }, + "supportForm": { + "message": "Unterstützungsformular" + }, + "doYouEnjoy": { + "message": "Gefällt Ihnen diese Erweiterung?" + }, + "review": { + "message": "Schreiben Sie eine Bewertung!" + }, + "block": { + "message": "Sie haben Ihr tägliches Nutzungslimit erreicht für " + }, + "5mins": { + "message": "+ 5 Minuten" + }, + "todayUsageTime": { + "message": "Bisherige Gesamtnutzungszeit " + }, + "comparedToYesterday": { + "message": " im Vergleich zu gestern " + }, + "mostVisited": { + "message": "Die meistbesuchte Website " + }, + "dashboard": { + "message": "Übersicht" + }, + "timeChartDescription": { + "message": "Dies ist eine stundenweise Zeitleiste für den Tag" + }, + "enjoyAndReview": { + "message": "Gefällt Ihnen diese Erweiterung?", + "description": "Web Activity Time Tracker bewerten" + }, + "removeAllData": { + "message": "Alle Daten entfernen", + "description": "Alle Daten und Statistiken der besuchten Websites für immer löschen." + }, + "remove": { + "message": "Löschen" + }, + "removeAllDataConfirm": { + "message": "Sind Sie sicher, dass Sie alle Daten löschen möchten?" + }, + "cancel": { + "message": "Abbrechen" + }, + "backupAndRestore": { + "message": "Sicherung und Wiederherstellen", + "description": "Sie können eine Sicherungskopie aller Daten für alle besuchten Websites herunterladen" + }, + "backup": { + "message": "Sicherung" + }, + "restore": { + "message": "Wiederherstellen" + }, + "welcome": { + "message": "Willkommen bei Web Activity Time Tracker", + "description": "Web Activity Time Tracker ist eine open-source, kostenlose und werbefreie Erweiterung, mit der Sie die Zeit, die Sie für das Durchsuchen von Websites aufgewendet haben, und die Anzahl der Besuche nachverfolgen können." + }, + "getStarted": { + "message": "Anleitung" + }, + "welcomeStart": { + "message": "Sie können die Erweiterung in nur 3 einfachen Schritten schnell verwenden" + }, + "pinIcon": { + "message": "Pin das Symbol" + }, + "pinIconPart1": { + "message": "Um diese Erweiterung bequemer zu verwenden, können Sie das Symbol an die Symbolleiste anheften. Klicken Sie auf das Symbol" + }, + "pinIconPart2": { + "message": "und klicken Sie dann auf das Pin-Symbol" + }, + "browse": { + "message": "Durchsuchen Sie alle Websites", + "description": "Wenn Sie eine Website besuchen, werden Sie sehen, dass die Uhrzeit auf dem Symbol angezeigt wird, genau wie hier" + }, + "seeData": { + "message": "Zeigen Sie Ihre Daten auf der Popup-Seite und im Dashboard an", + "description": "Klicken Sie auf das Erweiterungssymbol, um eine Popup-Seite zu öffnen, und Sie können die mit einem Kreisdiagramm gerenderten Daten für heute, für alle Zeiten oder für Tage lesen. In einem Popup-Fenster können Sie das Dashboard öffnen, und es zeigt Ihnen die heutige Zeit nach Stunden an. Und Sie können ein tägliches Zeitlimit für alle Websites festlegen, Benachrichtigungen für Websites festlegen oder Daten in CSV exportieren." + }, + "close": { + "message": "Schließen" + }, + "useExtension": { + "message": "Verwenden Sie die Erweiterung" + }, + "next": { + "message": "Weiter" + }, + "showChangelog": { + "message": "Änderungsliste anzeigen", + "description": "Zeigen Sie die Liste der Änderungen nach dem Aktualisieren der Erweiterung an" + }, + "byHours": { + "message": "Stundenweise" + }, + "intervals": { + "message": "Intervalle" + }, + "intervalsChart": { + "message": "Nur Zeitintervalle größer als", + "description": "werden angezeigt" + }, + "promoClearYoutube": { + "message": "Möchten Sie Kurzfilme, Kommentare, empfohlene Videos, Abonnements und andere YouTube-Ablenkungen blockieren? Wir haben eine weitere Erweiterung erstellt, mit der Sie YouTube ohne Ablenkung ansehen können.", + "description": "Versuchen Clean YouTube" + }, + "completelyBlocked": { + "message": "Vollständig blockiert", + "description": "Vollständig blockieren" + }, + "tryMyOtherApps": { + "message": "Probieren Sie meine anderen Apps aus" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Chrome-Erweiterung, die YouTube-Shorts, empfohlene Videos, Kommentare, Feeds, Homepage-Empfehlungen und andere Ablenkungen ausblenden kann. Sieh dir YouTube ohne Ablenkungen an." + }, + "darkTheme": { + "message": "Dunkles Thema" + }, + "cleanYoutube_promo": { + "message": "Probieren Sie unsere neue Erweiterung Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Möchten Sie Kurzfilme, empfohlene Videos und Kommentare auf YouTube ausblenden?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube ist ein YouTube™-Inhaltsblocker." + }, + "cleanYoutube_features": { + "message": "Unsere Funktionen:" + }, + "cleanYoutube_features1": { + "message": "Clean Mode - Nur Videoplayer auf der Seite anzeigen" + }, + "cleanYoutube_features2": { + "message": "Kurze Videos, Kommentare und verwandte Videos ausblenden. 15+ Optionen." + }, + "cleanYoutube_features3": { + "message": "AutoPlay deaktivieren" + }, + "cleanYoutube_features4": { + "message": "Endscreen-Karten deaktivieren" + }, + "cleanYoutube_features5": { + "message": "Schwarz/Weiß-Modus" + }, + "try": { + "message": "Testen Sie" + }, + "donate":{ + "message": "Spende" + }, + "enjoy":{ + "message": "Haben Sie Spaß an Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker ist eine kostenlose Erweiterung. Sie können mich für die weitere Entwicklung mit Kryptowährung unterstützen." + }, + "thanks":{ + "message": "Vielen Dank dafür! 🙏" + }, + "coin":{ + "message": "Münze" + }, + "chain":{ + "message": "Kette" + }, + "address":{ + "message": "Adresse" + } +} \ No newline at end of file diff --git a/src/_locales/en/messages.json b/src/_locales/en/messages.json new file mode 100644 index 0000000..216b4c1 --- /dev/null +++ b/src/_locales/en/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Block Websites, Pomodoro & Web Analytics" + }, + "extDescription": { + "message": "Track time of your web activity, limit and block distracting websites. Monitor your web usage." + }, + "settings": { + "message": "Settings" + }, + "today": { + "message": "Today" + }, + "allTime": { + "message": "Total time" + }, + "byDays": { + "message": "Daily" + }, + "noData": { + "message": "No data" + }, + "noDataForPeriod": { + "message": "No data for the selected period" + }, + "showAll": { + "message": "Show all the websites" + }, + "sortBy": { + "message": "Sorting by" + }, + "usageTime": { + "message": "Usage Time" + }, + "session": { + "message": "session" + }, + "someSession": { + "message": "sessions" + }, + "sessions": { + "message": "Sessions" + }, + "days": { + "message": "days" + }, + "aggregate": { + "message": "Aggregate data since" + }, + "websites": { + "message": "websites" + }, + "cannotOpenFile": { + "message": "You cannot open a local file due to security protocol" + }, + "document": { + "message": "Document" + }, + "limit": { + "message": "Limit" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "The first active day" + }, + "numberOfActiveDays": { + "message": "Number of active days" + }, + "totalNumberOfDays": { + "message": "Total number of days" + }, + "todayTime": { + "message": "All the time today" + }, + "averageTime": { + "message": "Average time for active days" + }, + "averageDailyUsage": { + "message": "Average daily usage" + }, + "mostActiveDay": { + "message": "The most active day" + }, + "mostInactiveDay": { + "message": "The most inactive day" + }, + "todayInclude": { + "message": "Today is included in the statistics. Click to exclude." + }, + "todayEcclude": { + "message": "Today is excluded from the statistics. Click to include." + }, + "averageTimeByDays": { + "message": "Average time on selected days" + }, + "exportToCsv": { + "message": "Export to CSV" + }, + "week": { + "message": "This week" + }, + "month": { + "message": "This month" + }, + "lastMonth": { + "message": "Last month" + }, + "generalSettings": { + "message": "Settings" + }, + "whiteListSettings": { + "message": "Whitelist" + }, + "limitsSettings": { + "message": "Limits" + }, + "notificationsSettings": { + "message": "Notifications" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Pomodoro Settings" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "The Pomodoro method is a time management technique based on alternating periods of focused work and rest. According to the classics of the Pomodoro method, the work period lasts 25 minutes, the rest period is 5 minutes." + }, + "pomodoroExplanationIcon": { + "message": "When Pomodoro mode is on and operation mode is active, you will see this icon", + "description": "During rest periods, you will see this extension icon" + }, + "pomodoroExplanationTime": { + "message": "During Pomodoro mode, the extension continues to take into account the time you spent on the sites, all limits and notifications work." + }, + "pomodoroExplanationStop": { + "message": "After clicking 'Stop', work and rest time is reset to zero." + }, + "pomodoroWork": { + "message": "Period of work" + }, + "pomodoroRest": { + "message": "Period of rest" + }, + "pomodoroFrequency": { + "message": "Number of repetitions" + }, + "start": { + "message": "Run" + }, + "stop": { + "message": "Stop" + }, + "pomodoroIsEnabled": { + "message": "Pomodoro Mode is enabled" + }, + "pomodoroSoundAfter": { + "message": "Sound after complete period" + }, + "clickToPreview": { + "message": "Click to listen" + }, + "sound": { + "message": "Sound" + }, + "aboutSettings": { + "message": "About" + }, + "viewTimeInBadge": { + "message": "Display time tracker in icon", + "description": "You are able to see current 'spent time' information in short format on the extension icon" + }, + "deferringDescription": { + "message": "You can postpone the blocking for 5 minutes only once during the day" + }, + "allowDeferringBlock": { + "message": "Allow deferring block for 5 minutes", + "description": "After the site is blocked, you can postpone the blocking for 5 minutes during the day only once" + }, + "intervalInactivity": { + "message": "Stop the tracker if there is no action for", + "description": "These are any actions with the mouse or keyboard" + }, + "exportToCsvSetting": { + "message": "Exporting your web activity data to CSV", + "description": "You can export your web activity for any date range" + }, + "sec": { + "message": "seconds" + }, + "min": { + "message": "minute" + }, + "2min": { + "message": "minutes" + }, + "mins": { + "message": "minutes" + }, + "whiteList": { + "message": "Activity and spent time for these websites will not be tracked" + }, + "addWebsite": { + "message": "Add Website" + }, + "enterWebsite": { + "message": "Enter website name..." + }, + "enterNotification": { + "message": "Enter notification message..." + }, + "limits": { + "message": "Daily access restrictions for the websites", + "description": "Set the maximum time allowed to visit the website per day. After this time, the site will be blocked." + }, + "limitsTip": { + "message": "If you set the blocking time to 0 hours 0 minutes, the website will be blocked immediately" + }, + "save": { + "message": "Save" + }, + "showDailyNotification": { + "message": "Daily Summary Notifications", + "description": "At the end of each day, you will receive a notification with a summary of your daily usage" + }, + "notificationTime": { + "message": "Notifications for websites", + "description": "Show notifications every time you spend a selected period of time on the website" + }, + "notificationMessage": { + "message": "Notification message", + "description": "You will see this message in notification for websites every time" + }, + "notificationTimeSetting": { + "message": "Notification time with summary information about your daily usage" + }, + "github": { + "message": "Leave your feedback or report an issue on " + }, + "question": { + "message": "You can also ask questions and leave your suggestions" + }, + "supportForm": { + "message": "support form" + }, + "doYouEnjoy": { + "message": "Do you enjoy Web Activity Time Tracker?" + }, + "review": { + "message": "Leave a review!" + }, + "promoClearYoutube": { + "message": "Would you like to block shorts, comments, recommended videos, subscriptions, and other YouTube distractions? We've created another extension that will help you watch YouTube without distractions.", + "description": "Try Clean Youtube" + }, + "block": { + "message": "You've reached your limit for today on " + }, + "5mins": { + "message": "+ 5 minutes" + }, + "todayUsageTime": { + "message": "Total usage time for today " + }, + "comparedToYesterday": { + "message": " compared to yesterday " + }, + "mostVisited": { + "message": "Most visited website " + }, + "dashboard": { + "message": "Dashboard" + }, + "timeChartDescription": { + "message": "This is a chart of time during the day by the hour" + }, + "enjoyAndReview": { + "message": "Enjoying the extension?", + "description": "Rate Web Activity Time Tracker" + }, + "removeAllData": { + "message": "Remove all data", + "description": "You can delete all data and statistics of visited websites for all time" + }, + "remove": { + "message": "Remove" + }, + "removeAllDataConfirm": { + "message": "Are you sure you want to delete all data?" + }, + "cancel": { + "message": "Cancel" + }, + "backupAndRestore": { + "message": "Backup and restore", + "description": "You can download a backup copy of all data for all visited sites" + }, + "backup": { + "message": "Backup" + }, + "restore": { + "message": "Restore" + }, + "welcome": { + "message": "Welcome to Web Activity Time Tracker", + "description": "Web Activity Time Tracker is open-source, free and no ads extension, which can help you track the time you spent on browsing websites and the count of visit." + }, + "getStarted": { + "message": "Get started" + }, + "welcomeStart": { + "message": "You can quickly start using the extension in just 3 easy steps" + }, + "pinIcon": { + "message": "Pin the icon" + }, + "pinIconPart1": { + "message": "To use this extension more conveniently, you can pin the icon to toolbar. Click the icon" + }, + "pinIconPart2": { + "message": "and then click the pin icon" + }, + "browse": { + "message": "Browse any websites", + "description": "When you visit any website, you will see that the time is displayed on the icon, just like here" + }, + "seeData": { + "message": "View your data on the popup page and on the dashboard", + "description": "Click on the extension icon to open a popup page and you will be able to read the data visualized using a pie chart, for today, for all time or by day. In the popup window, you can open the dashboard and it will show you today's time by the clock. And you can set a daily time limit for any websites, notifications for websites, or export data to CSV." + }, + "close": { + "message": "Close" + }, + "useExtension": { + "message": "Use the extension" + }, + "next": { + "message": "Next" + }, + "showChangelog": { + "message": "Show changelog", + "description": "Show the list of changes after updating extension" + }, + "byHours": { + "message": "Hourly" + }, + "intervals": { + "message": "Intervals" + }, + "intervalsChart": { + "message": "Only time intervals greater than", + "description": "are shown" + }, + "completelyBlocked": { + "message": "Completely Blocked", + "description": "Completely Block" + }, + "tryMyOtherApps": { + "message": "Try my other apps" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Chrome extension that can hide YouTube shorts, recomended videos, comments, feed, homepage recommendations and other distractions. Watch YouTube free of distractions." + }, + "darkTheme": { + "message": "Dark theme" + }, + "cleanYoutube_promo": { + "message": "Try our new extension Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Would you like to hide shorts, recommended videos, comments on YouTube?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube is a YouTube™ content blocker." + }, + "cleanYoutube_features": { + "message": "Our features:" + }, + "cleanYoutube_features1": { + "message": "Clean Mode - Show only Video Player on Page" + }, + "cleanYoutube_features2": { + "message": "Hide Shorts, Comments, Related Videos. 15+ options." + }, + "cleanYoutube_features3": { + "message": "Disable AutoPlay" + }, + "cleanYoutube_features4": { + "message": "Disable End Screen Cards" + }, + "cleanYoutube_features5": { + "message": "Black and White Mode" + }, + "try": { + "message": "Try" + }, + "donate": { + "message": "Donate" + }, + "enjoy":{ + "message": "Do you enjoy Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker is free extension. You can support me for the further development with cryptocurrency." + }, + "thanks":{ + "message": "Thank you! 🙏" + }, + "coin":{ + "message": "Coin" + }, + "chain":{ + "message": "Chain" + }, + "address":{ + "message": "Address" + } +} diff --git a/src/_locales/es/messages.json b/src/_locales/es/messages.json new file mode 100644 index 0000000..c607eb2 --- /dev/null +++ b/src/_locales/es/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Sitios bloqueados, Pomodoro y análisis web" + }, + "extDescription": { + "message": "Controla el tiempo de tu actividad web, limita y bloquea los sitios web que te distraen. Monitoriza tu uso de la web." + }, + "settings": { + "message": "Ajustes" + }, + "today": { + "message": "Hoy" + }, + "allTime": { + "message": "Tiempo total" + }, + "byDays": { + "message": "Diario" + }, + "noData": { + "message": "Sin datos" + }, + "noDataForPeriod": { + "message": "No hay datos para el periodo seleccionado" + }, + "showAll": { + "message": "Mostrar todos los sitios web" + }, + "sortBy": { + "message": "Clasificación por" + }, + "usageTime": { + "message": "Tiempo de uso" + }, + "session": { + "message": "sesión" + }, + "someSession": { + "message": "sesiones" + }, + "sessions": { + "message": "Sesiones" + }, + "days": { + "message": "días" + }, + "aggregate": { + "message": "Datos agregados desde" + }, + "websites": { + "message": "sitios web" + }, + "cannotOpenFile": { + "message": "No se puede abrir un archivo local debido al protocolo de seguridad" + }, + "document": { + "message": "Documento" + }, + "limit": { + "message": "Límite" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "El primer día activo" + }, + "numberOfActiveDays": { + "message": "Número de días activos" + }, + "totalNumberOfDays": { + "message": "Número total de días" + }, + "todayTime": { + "message": "Todo el tiempo hoy" + }, + "averageTime": { + "message": "Tiempo medio de los días activos" + }, + "averageDailyUsage": { + "message": "Uso medio diario" + }, + "mostActiveDay": { + "message": "El día más activo" + }, + "mostInactiveDay": { + "message": "El día más inactivo" + }, + "todayInclude": { + "message": "Hoy está incluido en las estadísticas. Haga clic para excluir." + }, + "todayEcclude": { + "message": "El día de hoy está excluido de las estadísticas. Haga clic para incluir." + }, + "averageTimeByDays": { + "message": "Tiempo medio en los días seleccionados" + }, + "exportToCsv": { + "message": "Exportar a CSV" + }, + "week": { + "message": "Esta semana" + }, + "month": { + "message": "Este mes" + }, + "lastMonth": { + "message": "El mes pasado" + }, + "generalSettings": { + "message": "Ajustes" + }, + "whiteListSettings": { + "message": "ListaBlanca" + }, + "limitsSettings": { + "message": "Límites" + }, + "notificationsSettings": { + "message": "Notificaciones" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Ajustes Pomodoro" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "El método Pomodoro es una técnica de gestión del tiempo basada en la alternancia de periodos de trabajo concentrado y de descanso. Según los clásicos del método Pomodoro, el periodo de trabajo dura 25 minutos, el de descanso 5 minutos." + }, + "pomodoroExplanationIcon": { + "message": "Cuando el modo Pomodoro está activado y el modo de funcionamiento está activo, verá este icono", + "description": "Durante los periodos de descanso, verá este icono de extensión" + }, + "pomodoroExplanationTime": { + "message": "Durante el modo Pomodoro, la extensión sigue teniendo en cuenta el tiempo que pasó en los sitios, todos los límites y las notificaciones de trabajo." + }, + "pomodoroExplanationStop": { + "message": "Tras pulsar 'Parar', el tiempo de trabajo y de descanso se pone a cero." + }, + "pomodoroWork": { + "message": "Período de trabajo" + }, + "pomodoroRest": { + "message": "Periodo de descanso" + }, + "pomodoroFrequency": { + "message": "Número de repeticiones" + }, + "start": { + "message": "Ejecutar" + }, + "stop": { + "message": "Stop" + }, + "pomodoroIsEnabled": { + "message": "Modo Pomodoro activado" + }, + "pomodoroSoundAfter": { + "message": "Sonido tras periodo completo" + }, + "clickToPreview": { + "message": "Haga clic para escuchar" + }, + "sound": { + "message": "Sonido" + }, + "aboutSettings": { + "message": "Acerca de" + }, + "viewTimeInBadge": { + "message": "Mostrar el cronómetro en un icono", + "description": "En el icono de extensión puede ver la información actual sobre el 'tiempo transcurrido' en formato abreviado" + }, + "deferringDescription": { + "message": "Puedes posponer el bloqueo durante 5 minutos sólo una vez al día" + }, + "allowDeferringBlock": { + "message": "Permitir el bloqueo diferido durante 5 minutos", + "description": "Una vez bloqueado el sitio, puede posponer el bloqueo durante 5 minutos a lo largo del día una sola vez" + }, + "intervalInactivity": { + "message": "Detener el rastreador si no hay ninguna acción para", + "description": "Se trata de cualquier acción con el ratón o el teclado" + }, + "exportToCsvSetting": { + "message": "Exportación de los datos de actividad web a CSV", + "description": "Puede exportar su actividad web para cualquier intervalo de fechas" + }, + "sec": { + "message": "segundos" + }, + "min": { + "message": "minuto" + }, + "2min": { + "message": "minutos" + }, + "mins": { + "message": "minutos" + }, + "whiteList": { + "message": "La actividad y el tiempo de permanencia en estos sitios web no se rastrearán." + }, + "addWebsite": { + "message": "Añadir sitio web" + }, + "enterWebsite": { + "message": "Introduzca el nombre del sitio web..." + }, + "enterNotification": { + "message": "Introducir mensaje de notificación..." + }, + "limits": { + "message": "Restricciones diarias de acceso a los sitios web", + "description": "Establezca el tiempo máximo permitido para visitar el sitio web al día. Transcurrido este tiempo, el sitio se bloqueará." + }, + "limitsTip": { + "message": "Si establece el tiempo de bloqueo en 0 horas 0 minutos, el sitio web se bloqueará inmediatamente" + }, + "save": { + "message": "Guardar" + }, + "showDailyNotification": { + "message": "Notificaciones diarias resumidas", + "description": "Al final de cada día, recibirás una notificación con un resumen de tu uso diario" + }, + "notificationTime": { + "message": "Notificaciones para sitios web", + "description": "Mostrar notificaciones cada vez que pase un periodo de tiempo seleccionado en el sitio web." + }, + "notificationMessage": { + "message": "Mensaje de notificación", + "description": "Verás este mensaje en la notificación de sitios web cada vez que" + }, + "notificationTimeSetting": { + "message": "Hora de notificación con información resumida sobre su uso diario" + }, + "github": { + "message": "Deje su opinión o informe de un problema en" + }, + "question": { + "message": "También puede hacer preguntas y dejar sus sugerencias" + }, + "supportForm": { + "message": "formulario de asistencia" + }, + "doYouEnjoy": { + "message": "¿Te gusta Web Activity Time Tracker?" + }, + "review": { + "message": "Deja tu opinión" + }, + "promoClearYoutube": { + "message": "¿Te gustaría bloquear los cortos, los comentarios, los vídeos recomendados, las suscripciones y otras distracciones de YouTube? Hemos creado otra extensión que te ayudará a ver YouTube sin distracciones.", + "description": "Prueba Clean YouTube" + }, + "block": { + "message": "Has alcanzado tu límite por hoy en" + }, + "5mins": { + "message": "+ 5 minutos" + }, + "todayUsageTime": { + "message": "Tiempo total de uso para hoy " + }, + "comparedToYesterday": { + "message": " en comparación con ayer " + }, + "mostVisited": { + "message": "Sitio web más visitado " + }, + "dashboard": { + "message": "Cuadro de mandos" + }, + "timeChartDescription": { + "message": "Este es un gráfico del tiempo durante el día por horas" + }, + "enjoyAndReview": { + "message": "¿Disfrutando de la ampliación?", + "description": "Valora Web Activity Time Tracker" + }, + "removeAllData": { + "message": "Eliminar todos los datos", + "description": "Puede borrar todos los datos y estadísticas de los sitios web visitados para siempre" + }, + "remove": { + "message": "Eliminar" + }, + "removeAllDataConfirm": { + "message": "¿Estás seguro de que quieres borrar todos los datos?" + }, + "cancel": { + "message": "Cancelar" + }, + "backupAndRestore": { + "message": "Copia de seguridad y restauración", + "description": "Puedes descargar una copia de seguridad de todos los datos de todos los sitios visitados" + }, + "backup": { + "message": "Copia de seguridad" + }, + "restore": { + "message": "Restaurar" + }, + "welcome": { + "message": "Bienvenido a Web Activity Time Tracker", + "description": "Web Activity Time Tracker es una extensión de código abierto, gratuita y sin publicidad, que puede ayudarte a controlar el tiempo que pasas navegando por páginas web y el recuento de visitas." + }, + "getStarted": { + "message": "Empezar" + }, + "welcomeStart": { + "message": "Puede empezar a utilizar rápidamente la extensión en sólo 3 sencillos pasos" + }, + "pinIcon": { + "message": "Anclar el icono" + }, + "pinIconPart1": { + "message": "Para utilizar esta extensión más cómodamente, puede fijar el icono a la barra de herramientas. Haga clic en el icono" + }, + "pinIconPart2": { + "message": "y, a continuación, haga clic en el icono de la chincheta" + }, + "browse": { + "message": "Navegar por cualquier sitio web", + "description": "Cuando visite cualquier sitio web, verá que la hora aparece en el icono, como aquí" + }, + "seeData": { + "message": "Visualiza tus datos en la página emergente y en el cuadro de mandos", + "description": "Haz clic en el icono de la extensión para abrir una página emergente y podrás leer los datos visualizados mediante un gráfico circular, para hoy, para todo el tiempo o por día. En la ventana emergente, puedes abrir el panel de control y te mostrará el tiempo de hoy según el reloj. Y puedes establecer un límite de tiempo diario para cualquier sitio web, notificaciones para sitios web o exportar los datos a CSV." + }, + "close": { + "message": "Cerrar" + }, + "useExtension": { + "message": "Utilizar la extensión" + }, + "next": { + "message": "Siguiente" + }, + "showChangelog": { + "message": "Mostrar el registro de cambios", + "description": "Mostrar la lista de cambios tras actualizar la extensión" + }, + "byHours": { + "message": "Por hora" + }, + "intervals": { + "message": "Intervalos" + }, + "intervalsChart": { + "message": "Sólo los intervalos de tiempo superiores a", + "description": "se muestran" + }, + "completelyBlocked": { + "message": "Completamente bloqueado", + "description": "Completamente bloqueado" + }, + "tryMyOtherApps": { + "message": "Pruebe mis otras aplicaciones" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Extensión de Chrome que puede ocultar los cortos de YouTube, los vídeos recomendados, los comentarios, el feed, las recomendaciones de la página de inicio y otras distracciones. Vea YouTube sin distracciones." + }, + "darkTheme": { + "message": "Tema oscuro" + }, + "cleanYoutube_promo": { + "message": "Prueba nuestra nueva extensión Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Te gustaría ocultar cortos, vídeos recomendados, comentarios en YouTube?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube es un bloqueador de contenido de YouTube™." + }, + "cleanYoutube_features": { + "message": "Nuestras características:" + }, + "cleanYoutube_features1": { + "message": "Modo Limpio - Muestra sólo el reproductor de vídeo en la página" + }, + "cleanYoutube_features2": { + "message": "Ocultar cortos, comentarios, vídeos relacionados. Más de 15 opciones." + }, + "cleanYoutube_features3": { + "message": "Desactivar reproducción automática" + }, + "cleanYoutube_features4": { + "message": "Desactivar tarjetas de fin de pantalla" + }, + "cleanYoutube_features5": { + "message": "Modo Blanco y Negro" + }, + "try": { + "message": "Pruebe" + }, + "donate":{ + "message": "Donación" + }, + "enjoy":{ + "message": "¿Te gusta Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker es una extensión gratuita. Usted me puede apoyar para el desarrollo futuro con cryptocurrency." + }, + "thanks":{ + "message": "Muchas gracias! 🙏" + }, + "coin":{ + "message": "Moneda" + }, + "chain":{ + "message": "Cadena" + }, + "address":{ + "message": "Dirección" + } +} diff --git a/src/_locales/ja/messages.json b/src/_locales/ja/messages.json new file mode 100644 index 0000000..86f408f --- /dev/null +++ b/src/_locales/ja/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "ウェブ活動時間トラッカー - ブロックウェブサイト,ポモドーロ&ウ:ェブ分析" + }, + "extDescription": { + "message": "あなたのウェブ活動の時間を追跡し,制限し,気が散るウェブサイトをブロックします。あなたのウェブ利用を監視します。" + }, + "settings": { + "message": "設定" + }, + "today": { + "message": "今日" + }, + "allTime": { + "message": "合計時間" + }, + "byDays": { + "message": "毎日" + }, + "noData": { + "message": "データなし" + }, + "noDataForPeriod": { + "message": "選択された期間のデータがありません" + }, + "showAll": { + "message": "すべてのウェブサイトを表示" + }, + "sortBy": { + "message": "ソート順" + }, + "usageTime": { + "message": "使用時間" + }, + "session": { + "message": "セッション" + }, + "someSession": { + "message": "セッション" + }, + "sessions": { + "message": "セッション" + }, + "days": { + "message": "日数" + }, + "aggregate": { + "message": "からの集計データ" + }, + "websites": { + "message": "ウェブサイト" + }, + "cannotOpenFile": { + "message": "セキュリティ・プロトコルのため,ローカル・ファイルを開けません。" + }, + "docmument": { + "message": "ドキュメント" + }, + "limit": { + "message": "リミット" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "最初の活動日" + }, + "numberOfActiveDays": { + "message": "アクティブな日数" + }, + "totalNumberOfDays": { + "message": "合計日数" + }, + "todayTime": { + "message": "今日のすべての時間" + }, + "averageTime": { + "message": "アクティブな日の平均時間" + }, + "averageDailyUsage": { + "message": "1日の平均使用量" + }, + "mostActiveDay": { + "message": "最もアクティブな日" + }, + "mostInactiveDay": { + "message": "最もアクティブでない日" + }, + "todayInclude": { + "message": "今日は統計に含まれます。除外するにはクリックしてください。" + }, + "todayEcclude": { + "message": "今日は統計から除外されています。クリックすると含まれます。" + }, + "averageTimeByDays": { + "message": "選択した日の平均時間" + }, + "exportToCsv": { + "message": "CSVにエクスポート" + }, + "week": { + "message": "今週" + }, + "month": { + "message": "今月" + }, + "lastMonth": { + "message": "今月" + }, + "generalSettings": { + "message": "設定" + }, + "whiteListSettings": { + "message": "ホワイトリスト" + }, + "limitsSettings": { + "message": "制限" + }, + "notificationsSettings": { + "message": "通知" + }, + "pomodoroMode": { + "message": "ポモドーロ" + }, + "pomodoroSettings": { + "message": "ポモドーロ設定" + }, + "pomodoro": { + "message": "ポモドーロ", + "description": "ポモドーロ法は,集中した作業と休息を交互に繰り返すことに基づく時間管理手法である。ポモドーロ法の古典によれば,作業時間は25分,休憩時間は5分である。" + }, + "pomodoroExplanationIcon": { + "message": "ポモドーロモードがオンで,操作モードがアクティブなとき,このアイコンを見ることができます,", + "description": "休憩時間中は,この拡張アイコンが表示されます" + }, + "pomodoroExplanationTime": { + "message": "ポモドーロモードの間,エクステンションはサイトに費やした時間を考慮し続け,すべての制限と通知作業を行います。" + }, + "pomodoroExplanationStop": { + "message": "停止」をクリックすると、作業時間と休憩時間はゼロにリセットされる。" + }, + "pomodoroWork": { + "message": "仕事の期間" + }, + "pomodoroRest": { + "message": "休息期間" + }, + "pomodoroFrequency": { + "message": "繰り返し回数" + }, + "start": { + "message": "実行" + }, + "stop": { + "message": "停止" + }, + "pomodoroIsEnabled": { + "message": "ポモドーロモードは有効です" + }, + "pomodoroSoundAfter": { + "message": "期間終了後の音" + }, + "clickToPreview": { + "message": "クリックで試聴" + }, + "sound": { + "message": "サウンド" + }, + "aboutSettings": { + "message": "について" + }, + "viewTimeInBadge": { + "message": "アイコンにタイムトラッカーを表示する,", + "description": "拡張機能アイコンをクリックすると、現在の「滞在時間」情報を短いフォーマットで見ることができます。" + }, + "deferringDescription": { + "message": "一日のうち一度だけ,5分間だけブロック時間を延期することができます。" + }, + "allowDeferringBlock": { + "message": "5分間のブロック延期を許可", + "description": "サイトがブロックされた後,一度だけ日中5分間ブロックを延期できる" + }, + "intervalInactivity": { + "message": "のアクションがない場合,トラッカーを停止します,", + "description": "マウスやキーボードによるアクション" + }, + "exportToCsvSetting": { + "message": "WebアクティビティデータをCSVにエクスポートします,", + "説明": "任意の日付範囲のウェブ活動をエクスポートできます。" + }, + "sec": { + "message": "秒" + }, + "min": { + "message": "分" + }, + "2min": { + "message": "分" + }, + "mins": { + "message": "分" + }, + "whiteList": { + "message": "これらのウェブサイトのアクティビティと滞在時間は追跡されません。" + }, + "addWebsite": { + "message": "ウェブサイトを追加" + }, + "enterWebsite": { + "message": "ウェブサイト名を入力してください..." + }, + "enterNotification": { + "message": "通知messageを入力..." + }, + "limits": { + "message": "ウェブサイトの毎日のアクセス制限", + "description": "1日にウェブサイトにアクセスできる最大時間を設定します。この時間を過ぎると,サイトはブロックされます。" + }, + "limitsTip": { + "message": "ブロック時間を0時間0分に設定した場合,ウェブサイトは直ちにブロックされます。" + }, + "save": { + "message": "保存" + }, + "showDailyNotification": { + "message": "デイリーサマリー通知", + "description": "一日の終わりに,一日の使用量を要約した通知を受け取ります" + }, + "notificationTime": { + "message": "ウェブサイトの通知", + "description": "選択した時間をウェブサイトに費やすたびに通知を表示する" + }, + "notificationMessage": { + "message": "通知メッセージ", + "description": "ウェブサイトの通知で毎回このmessageが表示されます" + }, + "notificationTimeSetting": { + "message": "1日の利用状況についてのサマリー情報を通知時間に表示" + }, + "github": { + "message": "ご意見をお寄せください。" + }, + "question": { + "message": "質問や提案を残すこともできます。" + }, + "supportForm": { + "message": "サポートフォーム" + }, + "doYouEnjoy": { + "message": "Web Activity Time Trackerを楽しんでいますか?" + }, + "review": { + "message": "レビューを書く" + }, + "promoClearYoutube": { + "message": "ショートフィルム,コメント,おすすめ動画,購読,その他のYouTubeの邪魔なものをブロックしたいですか?気晴らしにYouTubeを見るのに役立つ別の拡張機能を作りました。", + "description": "クリーンユーチューブを試す" + }, + "block": { + "message": "で今日の制限に達した。" + }, + "5mins": { + "message": "+5分" + }, + "todayUsageTime": { + "message": "今日の総使用時間" + }, + "comparedToYesterday": { + "message": " 昨日との比較 " + }, + "mostVisited": { + "message": "最も訪問されたウェブサイト" + }, + "dashboard": { + "message": "ダッシュボード" + }, + "timeChartDescription": { + "message": "日中の時間を時間単位で表したチャートです" + }, + "enjoyAndReview": { + "message": "エクステンションを楽しんでいますか?", + "description": "ウェブ活動時間トラッカーを評価する" + }, + "removeAllData": { + "message": "すべてのデータを削除する,", + "description": "訪問したウェブサイトのすべてのデータと統計情報を削除することができます。" + }, + "remove": { + "message": "削除" + }, + "removeAllDataConfirm": { + "message": "本当に全データを削除しますか?" + }, + "cancel": { + "message": "キャンセル" + }, + "backupAndRestore": { + "message": "バックアップとリストア", + "説明": "訪問したすべてのサイトのすべてのデータのバックアップコピーをダウンロードすることができます。" + }, + "backup": { + "message": "バックアップ" + }, + "restore": { + "message": "リストア" + }, + "welcome": { + "message": "Web Activity Time Trackerへようこそ", + "description": "Web Activity Time Trackerは、オープンソース、無料広告なしの拡張機能で、ウェブサイトの閲覧に費やした時間や訪問回数を記録することができます。" + }, + "getStarted": { + "message": "スタート" + }, + "welcomeStart": { + "message": "簡単な3ステップで、すぐに拡張機能を使い始めることができます。" + }, + "pinIcon": { + "message": "アイコンをピン留めする" + }, + "pinIconPart1": { + "message": "この拡張機能をより便利に使用するには、アイコンをツールバーに固定します。アイコンをクリック" + }, + "pinIconPart2": { + "message": "をクリックし、ピンのアイコンをクリックします。" + }, + "browse": { + "message": "任意のウェブサイトをブラウズする,", + "description": "ウェブサイトにアクセスすると,アイコンに時刻が表示されます。" + }, + "seeData": { + "message": "ポップアップページとダッシュボードでデータを見る", + "description": "拡張機能のアイコンをクリックすると,ポップアップページが開き,円グラフを使って視覚化されたデータを,今日,すべての時間,または日ごとに読むことができます。ポップアップウィンドウでは,ダッシュボードを開くことができ,時計で今日の時間を表示します。また,任意のウェブサイトに対して1日の時間制限を設定したり,ウェブサイトに対する通知を設定したり,データをCSVにエクスポートしたりすることができます。" + }, + "close": { + "message": "閉じる" + }, + "useExtension": { + "message": "拡張機能を使用する" + }, + "next": { + "message": "次" + }, + "showChangelog": { + "message": "変更履歴を表示", + "description": "エクステンションの更新後に変更点の一覧を表示する" + }, + "byHours": { + "message": "時間単位" + }, + "interval": { + "message": "間隔" + }, + "intervalsChart": { + "message": "より大きい時間間隔のみ", + "description": "が表示される。" + }, + "completelyBlocked": { + "message": "完全にブロックされました,", + "description": "完全にブロック" + }, + "tryMyOtherApps": { + "message": "他のアプリを試す" + }, + "clearYoutube": { + "message": "YouTubeをクリーン", + "description": "YouTubeのショートムービー,おすすめビデオ,コメント,フィード,ホームページのおすすめやその他の邪魔なものを隠すことができるChrome拡張機能です。気晴らしにYouTubeを見よう。" + }, + "darkTheme": { + "message": "ダークテーマ" + }, + "cleanYoutube_promo": { + "message": "新しい拡張機能Clean Youtubeをお試しください" + }, + "cleanYoutube_description": { + "message": "YouTubeのショートフィルム,おすすめ動画,コメントを非表示にしますか?" + }, + "cleanYoutube_description2": { + "message": "クリーンYoutubeはYouTube™コンテンツブロッカーです。" + }, + "cleanYoutube_features": { + "message": "私たちの機能:" + }, + "cleanYoutube_features1": { + "message": "クリーンモード - ページに動画プレーヤーのみを表示" + }, + "cleanYoutube_features2": { + "message": "ショートカット、コメント、関連ビデオを隠す。15以上のオプション" + }, + "cleanYoutube_features3": { + "message": "自動再生を無効にする" + }, + "cleanYoutube_features4": { + "message": "終了画面カードを無効にする" + }, + "cleanYoutube_features5": { + "message": "白黒モード" + }, + "try": { + "message": "トライ" + }, + "donate": { + "message": "寄付する" + }, + "enjoy":{ + "message": "Web Activity Time Trackerを楽しんでいますか?" + }, + "canDonate":{ + "message": "Web Activity Time Trackerは無料の拡張機能です。さらなる開発のために、暗号通貨でご支援ください。" + }, + "thanks":{ + "message": "ありがとうございます! 🙏" + }, + "coin":{ + "message": "コイン" + }, + "chain":{ + "message": "チェーン" + }, + "address":{ + "message": "アドレス" + } +} diff --git a/src/_locales/ru/messages.json b/src/_locales/ru/messages.json new file mode 100644 index 0000000..29768c3 --- /dev/null +++ b/src/_locales/ru/messages.json @@ -0,0 +1,432 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - Блокировка сайтов, Pomodoro и \u0412\u0435\u0431 аналитика" + }, + "extDescription": { + "message": "Отслеживайте время вашей веб-активности и блокируйте отвлекающие сайты. Следите за тем, сколько времени вы проводите на сайтах." + }, + "settings": { + "message": "Настройки" + }, + "today": { + "message": "Сегодня" + }, + "allTime": { + "message": "\u0417\u0430 все время" + }, + "byDays": { + "message": "По дням" + }, + "noData": { + "message": "Нет данных" + }, + "noDataForPeriod": { + "message": "Нет данных за выбранный период" + }, + "showAll": { + "message": "Показать все сайты" + }, + "sortBy": { + "message": "Сортировать по" + }, + "usageTime": { + "message": "Время использования" + }, + "session": { + "message": "сессия" + }, + "someSession": { + "message": "сессий" + }, + "sessions": { + "message": "Сессии" + }, + "days": { + "message": "дней" + }, + "aggregate": { + "message": "Данные \u0441 " + }, + "websites": { + "message": "сайтов" + }, + "cannotOpenFile": { + "message": "Вы не можете открыть локальный файл из-за правил безопасности" + }, + "document": { + "message": "Документ" + }, + "limit": { + "message": "Лимит" + }, + "d": { + "message": "д" + }, + "h": { + "message": "ч" + }, + "m": { + "message": "мин" + }, + "s": { + "message": "\u0441\u0435к" + }, + "firstActiveDay": { + "message": "Первый активный день" + }, + "numberOfActiveDays": { + "message": "\u0412\u0441\u0435\u0433\u043E активных дней" + }, + "totalNumberOfDays": { + "message": "\u0412\u0441\u0435\u0433\u043E дней" + }, + "todayTime": { + "message": "Общее время сегодня" + }, + "averageTime": { + "message": "Среднее время по активным дням" + }, + "averageDailyUsage": { + "message": "Среднее ежедневное использование" + }, + "mostActiveDay": { + "message": "Самый активный день" + }, + "mostInactiveDay": { + "message": "Самый неактивный день" + }, + "todayInclude": { + "message": "Сегодняшний день включен в статистику. Нажмите, если хотите исключить из статистики." + }, + "todayEcclude": { + "message": "Сегодняшний день исключен из статистику. Нажмите, если хотите включить в статистику." + }, + "averageTimeByDays": { + "message": "Среднее время по выбранным дням" + }, + "exportToCsv": { + "message": "Экспортировать в CSV" + }, + "week": { + "message": "Эта неделя" + }, + "month": { + "message": "Этот месяц" + }, + "lastMonth": { + "message": "Последний месяц" + }, + "generalSettings": { + "message": "Настройки" + }, + "whiteListSettings": { + "message": "Белый список" + }, + "limitsSettings": { + "message": "Лимиты" + }, + "notificationsSettings": { + "message": "Уведомления" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Настройки Pomodoro" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "Метод Pomodoro — это техника тайм-менеджмента, завязанная на чередовании периодов сфокусированной работы и отдыха. По классике метода помодоро период работы длится 25 минут, период отдыха 5 минут." + }, + "pomodoroExplanationIcon": { + "message": "Когда режим Pomodoro включен и активен режим работы, то вы будете видеть эту иконку", + "description": "В периоды отдыха вы будете видеть эту иконку расширения" + }, + "pomodoroExplanationTime": { + "message": "Во время режима Pomodoro, расширение продолжает учитывать время, которые вы провели на сайтах,работают все лимиты и уведомления." + }, + "pomodoroExplanationStop": { + "message": "После нажатия 'Остановить', время работы и отдыха обнуляется." + }, + "pomodoroWork": { + "message": "Период работы" + }, + "pomodoroRest": { + "message": "Период отдыха" + }, + "pomodoroFrequency": { + "message": "Количество повторов" + }, + "start": { + "message": "Запустить" + }, + "stop": { + "message": "Остановить" + }, + "pomodoroIsEnabled": { + "message": "Режим Pomodoro включен" + }, + "pomodoroSoundAfter": { + "message": "Воспроизведение после завершения периода" + }, + "clickToPreview": { + "message": "Нажмите для прослушивания" + }, + "sound": { + "message": "Мелодия" + }, + "aboutSettings": { + "message": "\u041E программе" + }, + "viewTimeInBadge": { + "message": "Показывать индикатор времени", + "description": "Вы можете увидеть текущее затраченное время в сокращенном формате на значке расширения" + }, + "deferringDescription": { + "message": "Вы можете отложить блокировку на 5 минут только один раз в течение дня" + }, + "allowDeferringBlock": { + "message": "Разрешить отсрочку блокировки на 5 минут", + "description": "После того, как сайт будет заблокирован, вы можете один раз в течение дня отложить блокировку на 5 минут" + }, + "intervalInactivity": { + "message": "Остановить трекер, если нет никаких действий в течение:", + "description": "Это любые действия \u0441 помощью мыши или клавиатуры" + }, + "exportToCsvSetting": { + "message": "Экспорт данных вашей веб-активности в формат CSV", + "description": "Вы можете экспортировать свою веб-активность для любого диапазона дат" + }, + "sec": { + "message": "секунд" + }, + "min": { + "message": "минута" + }, + "2min": { + "message": "минуты" + }, + "mins": { + "message": "минут" + }, + "whiteList": { + "message": "Активность и время для этих сайтов отслеживаться не будут" + }, + "addWebsite": { + "message": "Добавить сайт" + }, + "enterWebsite": { + "message": "Введите сайт..." + }, + "enterNotification": { + "message": "Введите текст уведомления..." + }, + "limits": { + "message": "Ежедневные ограничения доступа к сайтам", + "description": "Установите максимальное время, разрешенное для посещения сайта в день. По истечении этого времени сайт будет заблокирован." + }, + "limitsTip": { + "message": "Если вы установите время блокировки на 0 часов 0 минут, сайт будет немедленно заблокирован" + }, + "save": { + "message": "Сохранить" + }, + "showDailyNotification": { + "message": "Ежедневные итоговые уведомления", + "description": "\u0412 конце каждого дня вы будете получать уведомление \u0441 краткой информацией \u043E вашем ежедневном использовании" + }, + "notificationTimeSetting": { + "message": "Время показа уведомления \u0441 краткой информацией \u043E вашем ежедневном использовании" + }, + "notificationTime": { + "message": "Уведомления для сайтов", + "description": "Показывать уведомления каждый раз, когда вы проводите указанный период времени на сайте" + }, + "notificationMessage": { + "message": "Текст уведомления", + "description": "Вы будете видеть это сообщение в уведомлении для сайтов" + }, + "github": { + "message": "Если \u0443 вас есть вопрос или вы хотели бы сообщить \u043E проблеме, вы можете сделать это на" + }, + "question": { + "message": "Также вы можете задать вопросы или оставить свои предложения " + }, + "supportForm": { + "message": "поддержка" + }, + "doYouEnjoy": { + "message": "Вам нравится Web Activity Time Tracker?" + }, + "review": { + "message": "Оставьте отзыв!" + }, + "block": { + "message": "Вы достигли лимита использования сегодня на " + }, + "5mins": { + "message": "+ 5 минут" + }, + "todayUsageTime": { + "message": "Общее время использования на сегодняшний день " + }, + "comparedToYesterday": { + "message": " по сравнению \u0441\u043e вчерашним днем " + }, + "mostVisited": { + "message": "Самый посещаемый сайт " + }, + "dashboard": { + "message": "Дашборд" + }, + "timeChartDescription": { + "message": "Это график времени в течение дня по часам" + }, + "enjoyAndReview": { + "message": "Вам нравится расширение?", + "description": "Оцените Web Activity Time Tracker" + }, + "promoClearYoutube": { + "message": "Хотели бы вы блокировать шортсы, комментарии, рекомендованные видео, подписки и другие отвлекающие элементы YouTube? Мы создали еще одно расширение, которое поможет вам смотреть YouTube без отвлекающих факторов.", + "description": "Попробовать Clean YouTube" + }, + "removeAllData": { + "message": "Удалить все данные", + "description": "Вы можете удалить все данные и статистику посещенных сайтов за все время" + }, + "remove": { + "message": "Удалить" + }, + "removeAllDataConfirm": { + "message": "Вы уверены, что хотите удалить все данные, включая статистику посещенных сайтов?" + }, + "cancel": { + "message": "Отмена" + }, + "backupAndRestore": { + "message": "Резервное копирование и восстановление", + "description": "Вы можете скачать резервную копию всех данных по всем посещенным сайтам" + }, + "backup": { + "message": "Скачать резервную копию" + }, + "restore": { + "message": "Восстановить из резервной копиии" + }, + "welcome": { + "message": "Добро пожаловать в Web Activity Time Tracker", + "description": "Web Activity Time Tracker это бесплатное, без рекламы и \u0441 открытым исходным кодом расширение, которое поможем вам отслеживать время, потраченное вами на просмотр веб-сайтов, и покажет количество посещений." + }, + "getStarted": { + "message": "Руководство" + }, + "welcomeStart": { + "message": "Вы можете быстро начать использовать расширение всего за 3 простых шага" + }, + "pinIcon": { + "message": "Закрепите значок" + }, + "pinIconPart1": { + "message": "Чтобы более удобно использовать это расширение, вы можете прикрепить значок к панели инструментов. Нажмите на значок" + }, + "pinIconPart2": { + "message": "и затем нажмите на значок закрепления" + }, + "browse": { + "message": "Просматривайте любые веб-сайты", + "description": "При посещении любого веб-сайта вы увидите, что время отображается на значке, точно так же, как здесь" + }, + "seeData": { + "message": "Просматривайте ваши данные на всплывающей странице и на панели мониторинга", + "description": "Нажмите на значок расширения, чтобы открыть всплывающую страницу, и вы сможете увидеть данные посещения сайтов за сегодня, за все время и по дням. Во всплывающем окне вы можете открыть панель мониторинга, и вы увидите сегодняшнее время по часам. Там же вы можете установить ежедневное ограничение по времени для любых веб-сайтов, уведомления для веб-сайтов или экспортировать данные в CSV." + }, + "close": { + "message": "Закрыть" + }, + "useExtension": { + "message": "Начать пользоваться" + }, + "next": { + "message": "Продолжить" + }, + "showChangelog": { + "message": "Показывать список изменений", + "description": "Показывать список изменений после обновления расширения" + }, + "byHours": { + "message": "По часам" + }, + "intervals": { + "message": "Интервалы", + "description": "Отображаются только временные интервалы, превышающие 5 секунд" + }, + "intervalsChart": { + "message": "Отображаются только временные интервалы, превышающие", + "description": "" + }, + "completelyBlocked": { + "message": "Полностью заблокирован", + "description": "Полностью заблокировать" + }, + "tryMyOtherApps": { + "message": "Попробуйте другие мои приложения" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Расширение для Chrome, которое может скрывать шортс YouTube, рекомендуемые видео, комментарии, ленту новостей, рекомендации по домашней странице и другие отвлекающие факторы. Смотрите YouTube без отвлекающих факторов." + }, + "darkTheme": { + "message": "Темная тема" + }, + "cleanYoutube_promo": { + "message": "Попробуйте наше новое расширение Clean Youtube" + }, + "cleanYoutube_description": { + "message": "Хотите скрыть шортсы, рекомендуемые видео, комментарии на YouTube?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube - это блокировщик контента YouTube™." + }, + "cleanYoutube_features": { + "message": "Наши возможности:" + }, + "cleanYoutube_features1": { + "message": "Clean Mode - покажите только видеоплеер на странице" + }, + "cleanYoutube_features2": { + "message": "Скрыть шортсы, комментарии, связанные видео. 15+ опций." + }, + "cleanYoutube_features3": { + "message": "Отключить автовоспроизведение" + }, + "cleanYoutube_features4": { + "message": "Отключить карточки в конце видео" + }, + "cleanYoutube_features5": { + "message": "Черно-белый режим" + }, + "try": { + "message": "Попробовать" + }, + "donate":{ + "message": "Donate" + }, + "enjoy":{ + "message": "Нравится ли вам Web Activity Time Tracker?" + }, + "canDonate":{ + "message": "Web Activity Time Tracker - это бесплатное расширение. Вы можете поддержать меня для дальнейшего развития с помощью криптовалюты." + }, + "thanks":{ + "message": "Спасибо! 🙏" + }, + "coin":{ + "message": "Монета" + }, + "chain":{ + "message": "Цепочка" + }, + "address":{ + "message": "Адрес" + } +} diff --git a/src/_locales/zh_CN/messages.json b/src/_locales/zh_CN/messages.json new file mode 100644 index 0000000..673e348 --- /dev/null +++ b/src/_locales/zh_CN/messages.json @@ -0,0 +1,431 @@ +{ + "extName": { + "message": "Web Activity Time Tracker - 封鎖網站、Pomodoro 與網頁分析" + }, + "extDescription": { + "message": "追踪和限制您的网站活动时间,并阻止访问网站。监控您的网站使用情况" + }, + "settings": { + "message": "设置" + }, + "today": { + "message": "今天" + }, + "allTime": { + "message": "总时间" + }, + "byDays": { + "message": "每天" + }, + "noData": { + "message": "无数据" + }, + "noDataForPeriod": { + "message": "所选时间段内无数据" + }, + "showAll": { + "message": "显示所有网站" + }, + "sortBy": { + "message": "排序" + }, + "usageTime": { + "message": "使用时间" + }, + "session": { + "message": "会话" + }, + "someSession": { + "message": "会话" + }, + "sessions": { + "message": "会话" + }, + "days": { + "message": "天" + }, + "aggregate": { + "message": "汇总数据自" + }, + "websites": { + "message": "网站" + }, + "cannotOpenFile": { + "message": "由于安全协议,您无法打开本地文件" + }, + "document": { + "message": "文件" + }, + "limit": { + "message": "限制" + }, + "d": { + "message": "d" + }, + "h": { + "message": "h" + }, + "m": { + "message": "m" + }, + "s": { + "message": "s" + }, + "firstActiveDay": { + "message": "第一个活动日" + }, + "numberOfActiveDays": { + "message": "活动天数" + }, + "totalNumberOfDays": { + "message": "总天数" + }, + "todayTime": { + "message": "今天所有的时间" + }, + "averageTime": { + "message": "活动日的平均时间" + }, + "averageDailyUsage": { + "message": "平均每日使用量" + }, + "mostActiveDay": { + "message": "最活跃的一天" + }, + "mostInactiveDay": { + "message": "最不活跃的一天" + }, + "todayInclude": { + "message": "今天包含在统计数据中。点击以排除。" + }, + "todayEcclude": { + "message": "今天不包含在统计数据中。点击以包含。" + }, + "averageTimeByDays": { + "message": "所选日期的平均时间" + }, + "exportToCsv": { + "message": "导出 CSV" + }, + "week": { + "message": "本周" + }, + "month": { + "message": "本月" + }, + "lastMonth": { + "message": "上月" + }, + "generalSettings": { + "message": "设置" + }, + "whiteListSettings": { + "message": "白名单" + }, + "limitsSettings": { + "message": "限制" + }, + "notificationsSettings": { + "message": "通知" + }, + "pomodoroMode": { + "message": "Pomodoro" + }, + "pomodoroSettings": { + "message": "Pomodoro 设置" + }, + "pomodoro": { + "message": "Pomodoro", + "description": "Pomodoro 工作法是一种时间管理技术,以交替集中工作和休息为基础。根据经典的 Pomodoro 方法,工作时间为 25 分钟,休息时间为 5 分钟。" + }, + "pomodoroExplanationIcon": { + "message": "启用 Pomodoro 模式并激活操作模式后,您将看到以下图标", + "description": "在休息时间,您会看到这个扩展图标" + }, + "pomodoroExplanationTime": { + "message": "在 Pomodoro 模式下,扩展会继续考虑你在网站上花费的时间、所有限制和通知。" + }, + "pomodoroExplanationStop": { + "message": "按下 '停止' 键后,运行时间和休息时间将重置为零" + }, + "pomodoroWork": { + "message": "工作期限" + }, + "pomodoroRest": { + "message": "休息时间" + }, + "pomodoroFrequency": { + "message": "重复次数" + }, + "start": { + "message": "启动" + }, + "stop": { + "message": "停止" + }, + "pomodoroIsEnabled": { + "message": "番茄钟模式已启用" + }, + "pomodoroSoundAfter": { + "message": "完整时段后的声音" + }, + "clickToPreview": { + "message": "点击收听" + }, + "sound": { + "message": "声音" + }, + "aboutSettings": { + "message": "关于" + }, + "viewTimeInBadge": { + "message": "在图标中显示时间跟踪器", + "description": "您可以在扩展程序图标上以简短格式查看当前的“花费时间”信息。" + }, + "deferringDescription": { + "message": "您一天只能将拦截推迟 5 分钟一次。" + }, + "allowDeferringBlock": { + "message": "允许推迟拦截 5 分钟", + "description": "站点被拦截后,您一天中只能将拦截推迟 5 分钟一次。" + }, + "intervalInactivity": { + "message": "如果没有操作,则停止跟踪器:", + "description": "可以是使用鼠标或键盘进行的任何操作" + }, + "exportToCsvSetting": { + "message": "将您的网站活动数据导出为 CSV 格式", + "description": "您可以导出任何日期范围内的网站活动。" + }, + "sec": { + "message": "秒" + }, + "min": { + "message": "分钟" + }, + "2min": { + "message": "分钟" + }, + "mins": { + "message": "分钟" + }, + "whiteList": { + "message": "这些网站的活动和花费时间将不会被跟踪。" + }, + "addWebsite": { + "message": "添加网站" + }, + "enterWebsite": { + "message": "输入网站名称..." + }, + "enterNotification": { + "message": "输入通知消息..." + }, + "limits": { + "message": "网站的每日访问限制", + "description": "设置每天允许访问网站的最长时间。超过此时间后,该网站将被拦截。" + }, + "limitsTip": { + "message": "如果您将拦截时间设置为 0 小时 0 分钟,那么该网站将立即被拦截。" + }, + "save": { + "message": "保存" + }, + "showDailyNotification": { + "message": "每日摘要通知", + "description": "每天结束时,您将收到一条通知,其中包含您的每日使用情况摘要。" + }, + "notificationTime": { + "message": "网站通知", + "description": "每次在网站上花费特定时间时显示通知。" + }, + "notificationMessage": { + "message": "通知消息", + "description": "每次在网站通知中,您都会看到这条消息。" + }, + "notificationTimeSetting": { + "message": "包含有关您日常使用情况的摘要信息的通知时间:" + }, + "github": { + "message": "在以下位置留下您的反馈或报告问题:" + }, + "question": { + "message": "您还可以提问并留下您的建议。" + }, + "supportForm": { + "message": "支持表单" + }, + "doYouEnjoy": { + "message": "您喜欢 Web Activity Time Tracker 吗?" + }, + "review": { + "message": "留下评论吧!" + }, + "block": { + "message": "您今天已达到限制在 " + }, + "5mins": { + "message": "再加 5 分钟" + }, + "todayUsageTime": { + "message": "今天的总使用时间" + }, + "comparedToYesterday": { + "message": " 与昨天相比 " + }, + "mostVisited": { + "message": "访问最多的网站 " + }, + "dashboard": { + "message": "仪表板" + }, + "timeChartDescription": { + "message": "这是按小时显示一天时间的图表。" + }, + "enjoyAndReview": { + "message": "喜欢这个扩展程序吗?", + "description": "给 Web Activity Time Tracker 评分" + }, + "removeAllData": { + "message": "删除所有数据", + "description": "您可以删除所有访问过网站的所有数据和统计信息。" + }, + "remove": { + "message": "删除" + }, + "removeAllDataConfirm": { + "message": "您确定要删除所有数据吗?" + }, + "cancel": { + "message": "取消" + }, + "backupAndRestore": { + "message": "备份和恢复", + "description": "您可以下载所有访问过网站的所有数据的备份副本。" + }, + "backup": { + "message": "备份" + }, + "restore": { + "message": "恢复" + }, + "welcome": { + "message": "欢迎使用 Web Activity Time Tracker", + "description": "Web Activity Time Tracker 是一款开源免费无广告的扩展程序,它可以帮助您跟踪在浏览网站上花费的时间和访问次数。" + }, + "getStarted": { + "message": "开始使用" + }, + "welcomeStart": { + "message": "您可以通过三个简单的步骤快速开始使用扩展程序:" + }, + "pinIcon": { + "message": "固定图标" + }, + "pinIconPart1": { + "message": "为了更方便地使用此扩展程序,您可以将图标固定到工具栏上。点击图标:" + }, + "pinIconPart2": { + "message": "然后点击固定图标。" + }, + "browse": { + "message": "浏览任何网站", + "description": "当您访问任何网站时,您会看到时间显示在图标上,就像这里一样:" + }, + "seeData": { + "message": "在弹出页面和仪表板上查看您的数据", + "description": "点击扩展图标以打开弹出页面,您将能够使用饼图读取数据可视化信息,包括今天、所有时间或按天分类。在弹出窗口中,您可以打开仪表板,它将按时钟显示您今天的时间。您还可以为任何网站设置每日时间限制、网站通知或导出数据到 CSV。" + }, + "close": { + "message": "关闭" + }, + "useExtension": { + "message": "使用扩展程序" + }, + "next": { + "message": "接下来" + }, + "showChangelog": { + "message": "显示更新日志", + "description": "显示更新扩展程序后的更改列表" + }, + "byHours": { + "message": "每小时" + }, + "intervals": { + "message": "时间间隔" + }, + "intervalsChart": { + "message": "只有时间间隔大于", + "description": "展示" + }, + "promoClearYoutube": { + "message": "您想屏蔽短片、评论、推荐视频、订阅和其他 YouTube 干扰内容吗? 我们创建了另一个扩展程序,可帮助您不受干扰地观看 YouTube", + "description": "嘗試 Clean YouTube" + }, + "completelyBlocked": { + "message": "完全封锁", + "description": "完全封锁" + }, + "tryMyOtherApps": { + "message": "试试我的其他应用程序" + }, + "clearYoutube": { + "message": "Clean YouTube", + "description": "Chrome扩展程序,可以隐藏YouTube短片,推荐视频,评论,feed,主页推荐和其他分心。 观看YouTube免费分心。" + }, + "darkTheme": { + "message": "黑暗主题" + }, + "cleanYoutube_promo": { + "message": "试试我们的新扩展 Clean Youtube" + }, + "cleanYoutube_description": { + "message": "想隐藏 YouTube 上的短片、推荐视频和评论?" + }, + "cleanYoutube_description2": { + "message": "Clean Youtube 是一款 YouTube™ 内容拦截器。" + }, + "cleanYoutube_features": { + "message": "我们的特色" + }, + "cleanYoutube_features1": { + "message": "清洁模式--只显示页面上的视频播放器" + }, + "cleanYoutube_features2": { + "message": "隐藏短片、评论和相关视频。15+ 个选项。" + }, + "cleanYoutube_features3": { + "message": "禁用自动播放" + }, + "cleanYoutube_features4": { + "message": "禁用结束屏幕卡片" + }, + "cleanYoutube_features5": { + "message": "黑白模式" + }, + "try": { + "message": "试用" + }, + "donate":{ + "message": "捐赠" + }, + "enjoy":{ + "message": "您喜欢 Web Activity Time Tracker 吗" + }, + "canDonate":{ + "message": "Web Activity Time Tracker 是永久免费的扩展。您可以使用加密货币支持我进一步开发。" + }, + "thanks":{ + "message": "谢谢! 🙏" + }, + "coin":{ + "message": "币" + }, + "chain":{ + "message": "链" + }, + "address":{ + "message": "币链地址" + } +} diff --git a/src/assets/clear-youtube-promo.png b/src/assets/clear-youtube-promo.png new file mode 100644 index 0000000..e0f07e8 Binary files /dev/null and b/src/assets/clear-youtube-promo.png differ diff --git a/src/assets/css/dark.css b/src/assets/css/dark.css new file mode 100644 index 0000000..b976124 --- /dev/null +++ b/src/assets/css/dark.css @@ -0,0 +1,91 @@ +.dark{ + background-color: #303030; + color: white; +} +.dark .headerBlock .header { + color: #ffffff !important; +} +.dark .headerBlock .icons-block a:hover{ + filter: invert(40%) sepia(94%) saturate(3371%) hue-rotate(227deg) brightness(99%) contrast(92%); +} +.dark .headerBlock .icons-block a.filter img { + filter: invert(100%) sepia(17%) saturate(0%) hue-rotate(24deg) brightness(103%) contrast(102%); +} +.dark .header-block { + background-color: #616161; +} +.dark .tab-item .progress-bar{ + border: 1.5px rgb(107 107 107) solid; +} +.dark .tab-item:hover{ + border: 1px rgb(107 107 107) solid; +} +.dark .tab-item .links .link{ + filter: invert(100%) sepia(17%) saturate(0%) hue-rotate(24deg) brightness(103%) contrast(102%); +} +.dark .stats-block .block p{ + color: #b9b9b9 !important; +} +.dark .stats-block .block .header { + background-color: #595959; + color: rgb(255 255 255); +} +.dark .stats-block.block .header{ + background-color: #595959; + color: rgb(255 255 255); +} +.dark .stats-block.block p{ + color: #b9b9b9 !important; +} +.dark .expander-body{ + background-color: #595959 !important; +} +.dark .expander .header span{ + color: #b9b9b9 !important; +} +.dark .expander.total { + background-color: #6f6f6f !important; +} +.dark .url-list{ + border: 1px solid #494949 !important; +} +.dark .header span{ + color: rgb(255 255 255); +} +.dark .settings-tab label[name="tabName"] img{ + background-color: grey; + border-radius: 10px; + padding: 5px; +} +.dark .settings-tab label[name="tabName"]{ + background-color: #303030 !important; + color: #f7f7f7; +} +.dark .settings-content{ + background-color: #303030 !important; + border-left: 1px solid #494949 !important; +} +.dark .app-block{ + background-color: #919191 !important; +} +.dark .app-block .title{ + color: rgb(255, 255, 255); +} +.dark .app-block .description{ + color: white !important; +} +.dark .settings-tab label[name="tabName"]:hover, .dark [type='radio']:checked ~ label{ + background-color: #666666 !important; +} +.dark .container p.value{ + color: black; +} +.dark .review-block p{ + color:#303030; +} +.dark .pomodoro-popup-block p{ + color:#303030; +} +.dark .promo{ + color: black !important; +} \ No newline at end of file diff --git a/src/assets/css/dashboard.css b/src/assets/css/dashboard.css new file mode 100644 index 0000000..daaebce --- /dev/null +++ b/src/assets/css/dashboard.css @@ -0,0 +1,327 @@ +body { + font-family: 'Segoe UI', Tahoma, sans-serif !important; + color: #262626; + background-color: #eee; + margin: 0; +} + +.container { + width: 850px; + margin: 10px auto; +} + +.title { + font-size: 18px; + font-weight: 600; +} + +.setting-header { + font-weight: 600; + font-size: 16px; +} + +.description { + font-size: 14px; + color: grey; + margin: 7px 0 15px 0; + font-weight: normal; +} + +.url-list { + border-radius: 3px; + border: 1px solid #ccc; + width: 655px; + min-height: 300px; + cursor: pointer; + list-style: none; + padding-left: 10px; + max-height: 600px; + overflow: auto; +} + +.url-list li { + font-size: 14px; +} + +.url-list li span{ + font-weight: 600; + margin-left: 10px; +} + +input[type='number'],input[type='text'] { + height: 36px; + padding: 0 0 0 5px; + width: 400px; + border-radius: 3px; + border: 1px solid #ccc; +} + +input[type='button'].small-btn { + padding: 0 5px; + width: 120px; +} + +.option { + min-width: 170px; + color: #444; + background: #fff; + border-radius: 3px; + margin: 0; + padding: 10px 30px 10px 15px; + font-size: 14px; + border-color: #ccc; + position: relative; + cursor: pointer; +} + +.header { + grid-area: h; + margin: 0 0 10px; + font-size: 20px; +} + +a { + color: #3477db; + text-decoration: none; + cursor: pointer; +} + +label { + font-size: 14px; +} + +[type='checkbox']:not(:checked), +[type='checkbox']:checked { + position: absolute; + opacity: 0; + pointer-events: none; +} + +[type='checkbox'] + span { + position: relative; + padding-left: 30px; + cursor: pointer; + display: inline-block; + height: 25px; + line-height: 25px; + font-size: 14px; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +[type='checkbox'] + span:before, +[type='checkbox']:not(.filled-in) + span:after { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 18px; + height: 18px; + z-index: 0; + border: 2px solid #5a5a5a; + border-radius: 1px; + margin-top: 3px; +} + +[type='checkbox']:not(:checked):disabled + span:before { + border: none; + background-color: rgba(0, 0, 0, 0.42); +} + +[type='checkbox']:checked:disabled + span:before { + border-right: 2px solid rgba(0, 0, 0, 0.42); + border-bottom: 2px solid rgba(0, 0, 0, 0.42); +} + +[type='checkbox'].filled-in + span:after { + border-radius: 2px; +} + +[type='checkbox'].filled-in + span:before, +[type='checkbox'].filled-in + span:after { + content: ''; + left: 0; + position: absolute; + z-index: 1; +} + +[type='checkbox'].filled-in:not(:checked) + span:before { + width: 0; + height: 0; + border: 3px solid transparent; + left: 6px; + top: 10px; + -webkit-transform: rotateZ(37deg); + transform: rotateZ(37deg); + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type='checkbox'].filled-in:not(:checked) + span:after { + height: 17px; + width: 17px; + background-color: transparent; + border: 2px solid #5a5a5a; + top: 0px; + z-index: 0; +} + +[type='checkbox'].filled-in:checked + span:before { + top: -3px; + left: -2px; + width: 7px; + height: 12px; + border-top: 3px solid transparent; + border-left: 3px solid transparent; + border-right: 3px solid #fff; + border-bottom: 3px solid #fff; + -webkit-transform: rotateZ(35deg); + transform: rotateZ(35deg); + -webkit-transform-origin: 100% 100%; + transform-origin: 100% 100%; +} + +[type='checkbox'].filled-in:checked + span:after { + top: 0; + width: 17px; + height: 17px; + border: 2px solid #3477db; + background-color: #3477db; + z-index: 0; +} + +.hidden { + display: none !important; +} + +.notify { + width: 220px; + height: 27px; + margin: auto; + background-color: rgb(21, 104, 0); + color: rgb(255, 255, 255); + text-align: center; + font-weight: 600; + border-radius: 5px; + position: fixed; + z-index: 1; + top: 10px; + right: 20px; + font-size: 15px; + white-space: nowrap; + padding: 10px; +} + +.block { + display: block; +} + +.readonly-input { + cursor: default; + border: 0; + display: block; +} + +.setting-notify-block { + width: 450px; + height: 100px; + margin-top: 15px; + background-color: rgb(175, 175, 175); + border-radius: 10px; +} + +.setting-notify-block .setting-notify-title { + padding: 15px 20px 5px 0; + font-weight: 700; + color: #ffffff; + font-size: 15px; + text-align: left; + display: block; +} + +.setting-notify-block .setting-notify-message { + padding: 3px 20px 5px 0; + font-size: 14px; + display: block; + width: 320px; +} +.setting-notify-block .setting-notify-message-g { + padding: 0 30px 5px 0; + color: rgb(199, 199, 199); + font-size: 11px; + display: block; +} + +.setting-notify-block .setting-notify-img { + height: 50px; + padding: 25px 15px 25px 25px; +} + +.setting-notify-block .setting-notify-message-block { + display: inline-block; + position: absolute; +} + +.settings-tabs { +} +.settings-tab { + clear: both; + width: 286px; +} +.settings-tab label[name='tabName'] { + background: #eee; + padding: 5px 0 5px 20px; + font-size: 16px; + vertical-align: middle; + width: 266px; + height: 40px; + display: table-cell; + cursor: pointer; +} +.settings-tab label[name='tabName']:hover { + background-color: #cccccc !important; +} +.settings-tab [type='radio'] { + display: none; +} +.settings-tab img{ + vertical-align: middle; + margin-right: 10px; +} +.settings-content { + position: absolute; + top: 0; + left: 286px; + background: white; + right: 0; + bottom: 0; + padding: 50px; + border-left: 1px solid #ccc; + overflow-y: auto; +} +.settings-content span { + animation: 0.5s ease-out 0s 1 slideInFromTop; +} +[type='radio']:checked ~ label { + background: white; + border-bottom: 2px solid #8bc34a; + z-index: 2; +} +[type='radio']:checked ~ label ~ .settings-content { + z-index: 1; +} +.settings-item { + margin-bottom: 30px; +} +.url-list img { + vertical-align: middle; + margin-right: 10px; + cursor: pointer; +} + +.url-list .time-value { + margin-top: 5px; + margin-left: 55px; +} diff --git a/src/assets/css/general.css b/src/assets/css/general.css new file mode 100644 index 0000000..d15af6b --- /dev/null +++ b/src/assets/css/general.css @@ -0,0 +1,168 @@ +:root { + --main-color: #6ebf5d; + --popup-header: #efefef; + --progress-bar: #428bff; +} + +.no-data { + text-align: center; + font-size: 16px; + font-weight: 600; + margin-top: 30%; +} + +.float-right { + float: right; +} +.d-inline-block { + display: inline-block; +} +.mt-0 { + margin-top: 0; +} +.mt-20 { + margin-top: 20px; +} +.mt-30 { + margin-top: 30px; +} +.mb-20 { + margin-bottom: 20px; +} +.ml-5 { + margin-left: 5px; +} +.ml-10 { + margin-left: 10px; +} +.mr-10 { + margin-right: 10px; +} +.ml-20 { + margin-left: 20px; +} +.mr-20 { + margin-right: 20px; +} +.mr-5 { + margin-right: 5px; +} +.pr-5 { + padding-right: 5px; +} +.p-5 { + padding: 5px; +} +.text-right { + text-align: right; +} +.text-center { + text-align: center; +} + +.mt-10 { + margin-top: 10px; +} + +.mt-15 { + margin-top: 15px; +} +select { + border-color: #ccc; + border-radius: 5px; +} +.w-100 { + width: 100%; +} +input[type='button'] { + background: #5377af; + color: #fff; + border-radius: 7px; + height: 36px; + line-height: 35px; + padding: 0 20px; + border: 0; + font-size: 14px; + font-weight: 500; + cursor: pointer; + min-width: 80px; + text-align: center; + width: 200px; +} + +input[type='button']:hover { + background: #314158; + text-decoration: none; +} + +input[type='button'].alert { + background: #fe5c5c !important; +} + +input[type='button'].info { + background: #ffffff !important; + color: black; + border: 1px solid rgb(151, 151, 151); +} + +input[type='button'][disabled] { + border: 1px solid #999999; + background-color: #cccccc; + color: #666666; +} +.modal { + display: block; + position: fixed; + z-index: 1; + left: 0; + top: 0; + width: 100%; + height: 100%; + overflow: auto; + background-color: rgb(0,0,0); + background-color: rgba(0,0,0,0.4); +} + +.modal-content { + background-color: #fefefe; + margin: 15% auto; + padding: 20px; + border: 1px solid #888; + width: 40%; + border-radius: 10px; +} + +.modal-content p{ + font-size: 18px; + font-weight: 600; +} + +.close { + color: #aaa; + float: right; + font-size: 28px; + font-weight: bold; +} + +.close:hover, +.close:focus { + color: black; + text-decoration: none; + cursor: pointer; +} +.no-data .date-picker { + font-weight: normal; + text-align: center; + width: 250px; + margin: auto; + margin-top: 15px; +} +.date-block .date-picker { + width: 250px; +} +.font-bold{ + font-weight: 600; +} +.font-16{ + font-size: 16px; +} \ No newline at end of file diff --git a/src/assets/css/main.css b/src/assets/css/main.css new file mode 100644 index 0000000..955b6c4 --- /dev/null +++ b/src/assets/css/main.css @@ -0,0 +1,223 @@ +::-webkit-scrollbar-track { + border-radius: 10px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar { + width: 7px; + background-color: #f5f5f5; +} + +::-webkit-scrollbar-thumb { + border-radius: 10px; + background-color: #7c7c7c; +} +html, +body { + width: 600px; + height: 590px; + padding: 0; + margin: 0; +} +.tabs { +} +.tabs input[name='tab-control'] { + display: none; +} +.tabs .content section h2, +.tabs ul li label { + + font-size: 15px; + color: #428bff; +} +.tabs ul { + list-style-type: none; + padding-left: 0; + display: flex; + flex-direction: row; + margin-bottom: 10px; + justify-content: space-between; + align-items: flex-end; + flex-wrap: wrap; +} +.tabs ul li { + box-sizing: border-box; + flex: 1; + width: 25%; + padding: 0 10px; + text-align: center; +} +.tabs ul li label { + transition: all 0.3s ease-in-out; + color: #929daf; + padding: 5px auto; + overflow: hidden; + display: block; + cursor: pointer; + transition: all 0.2s ease-in-out; + white-space: nowrap; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} +.tabs ul li label br { + display: none; +} +.tabs ul li label img { + filter: brightness(0) saturate(100%) invert(67%) sepia(15%) saturate(342%) hue-rotate(178deg) + brightness(91%) contrast(89%); + vertical-align: bottom; + margin-right: 0.2em; + transition: all 0.2s ease-in-out; +} +.tabs ul li label:hover, +.tabs ul li label:focus, +.tabs ul li label:active { + outline: 0; + color: #bec5cf; +} +.tabs ul li label:hover img, +.tabs ul li label:focus img, +.tabs ul li label:active img { + filter: #bec5cf; +} +.tabs .slider { + position: relative; + width: 25%; + transition: all 0.33s cubic-bezier(0.38, 0.8, 0.32, 1.07); +} +.tabs .slider .indicator { + position: relative; + width: 50px; + max-width: 100%; + margin: 0 auto; + height: 4px; + background: #428bff; + border-radius: 1px; +} +.tabs .content { + margin-top: 10px; +} +.tabs .content section { + display: none; + -webkit-animation-name: content; + animation-name: content; + -webkit-animation-direction: normal; + animation-direction: normal; + -webkit-animation-duration: 0.3s; + animation-duration: 0.3s; + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + -webkit-animation-iteration-count: 1; + animation-iteration-count: 1; + line-height: 1.4; +} +.tabs .content section h2 { + color: #428bff; + display: none; +} +.tabs .content section h2::after { + content: ''; + position: relative; + display: block; + width: 30px; + height: 3px; + background: #428bff; + margin-top: 5px; + left: 1px; +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ ul > li:nth-child(1) > label { + cursor: default; + color: #428bff; +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ ul > li:nth-child(1) > label img { + filter: brightness(0) saturate(100%) invert(59%) sepia(82%) saturate(4677%) hue-rotate(202deg) + brightness(103%) contrast(101%); +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ .slider { + transform: translateX(17%); +} +.tabs input[name='tab-control']:nth-of-type(1):checked ~ .content > section:nth-child(1) { + display: block; +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ ul > li:nth-child(2) > label { + cursor: default; + color: #428bff; +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ ul > li:nth-child(2) > label img { + filter: brightness(0) saturate(100%) invert(59%) sepia(82%) saturate(4677%) hue-rotate(202deg) + brightness(103%) contrast(101%); +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ .slider { + transform: translateX(150%); +} +.tabs input[name='tab-control']:nth-of-type(2):checked ~ .content > section:nth-child(2) { + display: block; +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ ul > li:nth-child(3) > label { + cursor: default; + color: #428bff; +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ ul > li:nth-child(3) > label img { + filter: brightness(0) saturate(100%) invert(59%) sepia(82%) saturate(4677%) hue-rotate(202deg) + brightness(103%) contrast(101%); +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ .slider { + transform: translateX(290%); +} +.tabs input[name='tab-control']:nth-of-type(3):checked ~ .content > section:nth-child(3) { + display: block; +} +@-webkit-keyframes content { + from { + opacity: 0; + transform: translateY(5%); + } + to { + opacity: 1; + transform: translateY(0%); + } +} +@keyframes content { + from { + opacity: 0; + transform: translateY(5%); + } + to { + opacity: 1; + transform: translateY(0%); + } +} +.tabs ul li label { + white-space: initial; +} +.tabs ul li label img { + height: 1.2em; +} +.tooltip { + position: relative; + display: inline-block; + vertical-align: middle; +} +.tooltip .tooltiptext { + font-size: 11px; + font-weight: 500; + visibility: hidden; + width: 180px; + background-color: #555; + color: #fff; + text-align: center; + padding: 10px 10px; + border-radius: 6px; + position: absolute; + z-index: 1; + transform: translate(-55%) translateY(-125%); + opacity: 0; + transition: opacity 0.3s; +} +.tooltip:hover .tooltiptext { + visibility: visible; + opacity: 1; +} diff --git a/src/assets/icons/128x128.png b/src/assets/icons/128x128.png new file mode 100644 index 0000000..8915f31 Binary files /dev/null and b/src/assets/icons/128x128.png differ diff --git a/src/assets/icons/16x16.png b/src/assets/icons/16x16.png new file mode 100644 index 0000000..4916da6 Binary files /dev/null and b/src/assets/icons/16x16.png differ diff --git a/src/assets/icons/32x32.png b/src/assets/icons/32x32.png new file mode 100644 index 0000000..f6812bb Binary files /dev/null and b/src/assets/icons/32x32.png differ diff --git a/src/assets/icons/48x48.png b/src/assets/icons/48x48.png new file mode 100644 index 0000000..336d1ef Binary files /dev/null and b/src/assets/icons/48x48.png differ diff --git a/src/assets/icons/by-hours.svg b/src/assets/icons/by-hours.svg new file mode 100644 index 0000000..da7c058 --- /dev/null +++ b/src/assets/icons/by-hours.svg @@ -0,0 +1,4 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/by-intervals.svg b/src/assets/icons/by-intervals.svg new file mode 100644 index 0000000..9c151bd --- /dev/null +++ b/src/assets/icons/by-intervals.svg @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/src/assets/icons/clear-youtube-logo.svg b/src/assets/icons/clear-youtube-logo.svg new file mode 100644 index 0000000..5854613 --- /dev/null +++ b/src/assets/icons/clear-youtube-logo.svg @@ -0,0 +1,11 @@ + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/close.svg b/src/assets/icons/close.svg new file mode 100644 index 0000000..79b0d2f --- /dev/null +++ b/src/assets/icons/close.svg @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/dark-mode.svg b/src/assets/icons/dark-mode.svg new file mode 100644 index 0000000..c2f0dce --- /dev/null +++ b/src/assets/icons/dark-mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/dashboard.svg b/src/assets/icons/dashboard.svg new file mode 100644 index 0000000..099ec8c --- /dev/null +++ b/src/assets/icons/dashboard.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/assets/icons/delete.png b/src/assets/icons/delete.png new file mode 100644 index 0000000..1899aff Binary files /dev/null and b/src/assets/icons/delete.png differ diff --git a/src/assets/icons/details-link.svg b/src/assets/icons/details-link.svg new file mode 100644 index 0000000..339e00b --- /dev/null +++ b/src/assets/icons/details-link.svg @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/donate.png b/src/assets/icons/donate.png new file mode 100644 index 0000000..8f90408 Binary files /dev/null and b/src/assets/icons/donate.png differ diff --git a/src/assets/icons/donation-qr.png b/src/assets/icons/donation-qr.png new file mode 100644 index 0000000..06f400e Binary files /dev/null and b/src/assets/icons/donation-qr.png differ diff --git a/src/assets/icons/edit.svg b/src/assets/icons/edit.svg new file mode 100644 index 0000000..c06b44d --- /dev/null +++ b/src/assets/icons/edit.svg @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/icons/empty.png b/src/assets/icons/empty.png similarity index 100% rename from src/icons/empty.png rename to src/assets/icons/empty.png diff --git a/src/assets/icons/extension.svg b/src/assets/icons/extension.svg new file mode 100644 index 0000000..0897782 --- /dev/null +++ b/src/assets/icons/extension.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/icon.png b/src/assets/icons/icon.png new file mode 100644 index 0000000..9c86246 Binary files /dev/null and b/src/assets/icons/icon.png differ diff --git a/src/assets/icons/light-mode.svg b/src/assets/icons/light-mode.svg new file mode 100644 index 0000000..cff0d6f --- /dev/null +++ b/src/assets/icons/light-mode.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/no-today.svg b/src/assets/icons/no-today.svg new file mode 100644 index 0000000..9933b25 --- /dev/null +++ b/src/assets/icons/no-today.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/open-link.svg b/src/assets/icons/open-link.svg new file mode 100644 index 0000000..ad17a47 --- /dev/null +++ b/src/assets/icons/open-link.svg @@ -0,0 +1,202 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/pin.svg b/src/assets/icons/pin.svg new file mode 100644 index 0000000..2a91ad0 --- /dev/null +++ b/src/assets/icons/pin.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/pomodoro-rest.png b/src/assets/icons/pomodoro-rest.png new file mode 100644 index 0000000..5c8a25e Binary files /dev/null and b/src/assets/icons/pomodoro-rest.png differ diff --git a/src/assets/icons/pomodoro.png b/src/assets/icons/pomodoro.png new file mode 100644 index 0000000..1bca502 Binary files /dev/null and b/src/assets/icons/pomodoro.png differ diff --git a/src/assets/icons/pomodoro.svg b/src/assets/icons/pomodoro.svg new file mode 100644 index 0000000..d3ec461 --- /dev/null +++ b/src/assets/icons/pomodoro.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/preloader.gif b/src/assets/icons/preloader.gif new file mode 100644 index 0000000..32ac2b4 Binary files /dev/null and b/src/assets/icons/preloader.gif differ diff --git a/src/assets/icons/s-about.svg b/src/assets/icons/s-about.svg new file mode 100644 index 0000000..bb28eac --- /dev/null +++ b/src/assets/icons/s-about.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-dashboard.svg b/src/assets/icons/s-dashboard.svg new file mode 100644 index 0000000..fc057b7 --- /dev/null +++ b/src/assets/icons/s-dashboard.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-limits.svg b/src/assets/icons/s-limits.svg new file mode 100644 index 0000000..3b0ce8d --- /dev/null +++ b/src/assets/icons/s-limits.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-notifications.svg b/src/assets/icons/s-notifications.svg new file mode 100644 index 0000000..1303469 --- /dev/null +++ b/src/assets/icons/s-notifications.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-settings.svg b/src/assets/icons/s-settings.svg new file mode 100644 index 0000000..1734f08 --- /dev/null +++ b/src/assets/icons/s-settings.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/s-whitelist.svg b/src/assets/icons/s-whitelist.svg new file mode 100644 index 0000000..0774698 --- /dev/null +++ b/src/assets/icons/s-whitelist.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/assets/icons/settings.svg b/src/assets/icons/settings.svg new file mode 100644 index 0000000..4096f43 --- /dev/null +++ b/src/assets/icons/settings.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/assets/icons/start.svg b/src/assets/icons/start.svg new file mode 100644 index 0000000..144f821 --- /dev/null +++ b/src/assets/icons/start.svg @@ -0,0 +1,17 @@ + + + + + play + Created with Sketch Beta. + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/icons/stop.svg b/src/assets/icons/stop.svg new file mode 100644 index 0000000..8d35481 --- /dev/null +++ b/src/assets/icons/stop.svg @@ -0,0 +1,17 @@ + + + + + stop + Created with Sketch Beta. + + + + + + + + + + + \ No newline at end of file diff --git a/src/icons/success.png b/src/assets/icons/success.png similarity index 100% rename from src/icons/success.png rename to src/assets/icons/success.png diff --git a/src/assets/icons/today.svg b/src/assets/icons/today.svg new file mode 100644 index 0000000..dc0427e --- /dev/null +++ b/src/assets/icons/today.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/icons/trackerjam-logo.png b/src/assets/icons/trackerjam-logo.png new file mode 100644 index 0000000..dc6d052 Binary files /dev/null and b/src/assets/icons/trackerjam-logo.png differ diff --git a/src/assets/initial.jpg b/src/assets/initial.jpg new file mode 100644 index 0000000..d70547a Binary files /dev/null and b/src/assets/initial.jpg differ diff --git a/src/assets/pin-tutorial.png b/src/assets/pin-tutorial.png new file mode 100644 index 0000000..ebece96 Binary files /dev/null and b/src/assets/pin-tutorial.png differ diff --git a/src/assets/pomodoro-sounds/1.mp3 b/src/assets/pomodoro-sounds/1.mp3 new file mode 100644 index 0000000..2c4babb Binary files /dev/null and b/src/assets/pomodoro-sounds/1.mp3 differ diff --git a/src/assets/pomodoro-sounds/10.mp3 b/src/assets/pomodoro-sounds/10.mp3 new file mode 100644 index 0000000..371a5b8 Binary files /dev/null and b/src/assets/pomodoro-sounds/10.mp3 differ diff --git a/src/assets/pomodoro-sounds/11.mp3 b/src/assets/pomodoro-sounds/11.mp3 new file mode 100644 index 0000000..e000b73 Binary files /dev/null and b/src/assets/pomodoro-sounds/11.mp3 differ diff --git a/src/assets/pomodoro-sounds/12.mp3 b/src/assets/pomodoro-sounds/12.mp3 new file mode 100644 index 0000000..b949f38 Binary files /dev/null and b/src/assets/pomodoro-sounds/12.mp3 differ diff --git a/src/assets/pomodoro-sounds/13.mp3 b/src/assets/pomodoro-sounds/13.mp3 new file mode 100644 index 0000000..a255ca5 Binary files /dev/null and b/src/assets/pomodoro-sounds/13.mp3 differ diff --git a/src/assets/pomodoro-sounds/2.mp3 b/src/assets/pomodoro-sounds/2.mp3 new file mode 100644 index 0000000..2e526e3 Binary files /dev/null and b/src/assets/pomodoro-sounds/2.mp3 differ diff --git a/src/assets/pomodoro-sounds/3.mp3 b/src/assets/pomodoro-sounds/3.mp3 new file mode 100644 index 0000000..185ddb4 Binary files /dev/null and b/src/assets/pomodoro-sounds/3.mp3 differ diff --git a/src/assets/pomodoro-sounds/4.mp3 b/src/assets/pomodoro-sounds/4.mp3 new file mode 100644 index 0000000..4fcab3f Binary files /dev/null and b/src/assets/pomodoro-sounds/4.mp3 differ diff --git a/src/assets/pomodoro-sounds/5.mp3 b/src/assets/pomodoro-sounds/5.mp3 new file mode 100644 index 0000000..8009774 Binary files /dev/null and b/src/assets/pomodoro-sounds/5.mp3 differ diff --git a/src/assets/pomodoro-sounds/6.mp3 b/src/assets/pomodoro-sounds/6.mp3 new file mode 100644 index 0000000..21d0827 Binary files /dev/null and b/src/assets/pomodoro-sounds/6.mp3 differ diff --git a/src/assets/pomodoro-sounds/7.mp3 b/src/assets/pomodoro-sounds/7.mp3 new file mode 100644 index 0000000..901fc3d Binary files /dev/null and b/src/assets/pomodoro-sounds/7.mp3 differ diff --git a/src/assets/pomodoro-sounds/8.mp3 b/src/assets/pomodoro-sounds/8.mp3 new file mode 100644 index 0000000..8843950 Binary files /dev/null and b/src/assets/pomodoro-sounds/8.mp3 differ diff --git a/src/assets/pomodoro-sounds/9.mp3 b/src/assets/pomodoro-sounds/9.mp3 new file mode 100644 index 0000000..59845ea Binary files /dev/null and b/src/assets/pomodoro-sounds/9.mp3 differ diff --git a/src/background.ts b/src/background.ts new file mode 100644 index 0000000..88ffeb1 --- /dev/null +++ b/src/background.ts @@ -0,0 +1,92 @@ +import Browser from 'webextension-polyfill'; +import { initTracker } from './tracker'; +import { logger } from './utils/logger'; +import { scheduleJobs } from './jobs/sheduler'; +import { Settings } from './functions/settings'; +import { StorageParams } from './storage/storage-params'; +import { injectStorage } from './storage/inject-storage'; +import { todayLocalDate } from './utils/date'; +import { checkPomodoro } from './functions/pomodoro'; +import { Messages } from './utils/messages'; +import { injectTabsRepositorySingleton } from './repository/inject-tabs-repository'; + +logger.log('Start background script'); +let pomodoroTimer: number; + +self.onerror = err => { + console.error('Unhandled error:', err); +}; + +Browser.storage.onChanged.addListener(async (changes, namespace) => { + for (var key in changes) { + if (Object.values(StorageParams).includes(key as StorageParams)) + await Settings.getInstance().reloadSetting(key as StorageParams); + + if (key == StorageParams.IS_POMODORO_ENABLED) { + const value = changes[StorageParams.IS_POMODORO_ENABLED].newValue; + pomodoro(value); + } + } +}); + +Browser.runtime.setUninstallURL('https://webtracker.online/goodbye.html'); + +Browser.runtime.onInstalled.addListener(async details => { + if (details.reason == 'install') { + logger.log('Extension installed:', details); + const settingsStorage = injectStorage(); + await settingsStorage.saveValue(StorageParams.INSTALL_DATE, todayLocalDate()); + + const initialPageUrl = Browser.runtime.getURL('src/welcome.html'); + await Browser.tabs.create({ + url: initialPageUrl, + active: true, + }); + } + if (details.reason == 'update' && !details.previousVersion) { + const showChangelog = (await Settings.getInstance().getSetting( + StorageParams.SHOW_CHANGELOG, + )) as boolean; + if (showChangelog) + await Browser.tabs.create({ + url: 'https://webtracker.online/releasenotes.html', + active: true, + }); + } +}); + +Browser.runtime.onStartup.addListener(() => { + logger.log(`onStartup event`); +}); + +Browser.windows.onFocusChanged.addListener(() => { + logger.log('onFocusChanged'); +}); + +async function pomodoro(value?: boolean) { + if (value == undefined) { + const settingsStorage = injectStorage(); + value = await settingsStorage.getValue(StorageParams.IS_POMODORO_ENABLED); + } + if (value == true) pomodoroTimer = setInterval(checkPomodoro, 1000); + else clearInterval(pomodoroTimer); +} + +pomodoro(); +scheduleJobs(); +initTracker(); + +Browser.runtime.onMessage.addListener(async message => { + if (message == Messages.ClearAllData) { + const storage = injectStorage(); + const repo = await injectTabsRepositorySingleton(); + repo.removeAllTabs(); + await storage.saveTabs([]); + } + if (message.message == Messages.Restore) { + const storage = injectStorage(); + await storage.saveTabs(message.data); + const repo = await injectTabsRepositorySingleton(); + repo.initAsync(); + } +}); diff --git a/src/block.html b/src/block.html index 8979524..1b72d23 100644 --- a/src/block.html +++ b/src/block.html @@ -1,24 +1,15 @@ - + + + + + + Access to the site is limited - Web Activity Time Tracker + - - - Access to the site is limited - - - - - + + + - -
- -

Time limit

-
You've reached today your limit on
-
Your current daily limit is -
-
-

Web Activity Time Tracker

- - - \ No newline at end of file + + diff --git a/src/block.ts b/src/block.ts new file mode 100644 index 0000000..fd1c16d --- /dev/null +++ b/src/block.ts @@ -0,0 +1,7 @@ +import Block from './pages/Block.vue'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Block); +app.use(i18n); +app.mount('body'); diff --git a/src/components/About.vue b/src/components/About.vue new file mode 100644 index 0000000..0938fe8 --- /dev/null +++ b/src/components/About.vue @@ -0,0 +1,47 @@ + + + + + + + diff --git a/src/components/BadgeIcons.vue b/src/components/BadgeIcons.vue new file mode 100644 index 0000000..16d920d --- /dev/null +++ b/src/components/BadgeIcons.vue @@ -0,0 +1,58 @@ + + + + + + + diff --git a/src/components/ByDays.vue b/src/components/ByDays.vue new file mode 100644 index 0000000..fc9e607 --- /dev/null +++ b/src/components/ByDays.vue @@ -0,0 +1,206 @@ + + + + + + + diff --git a/src/components/ByDaysChart.vue b/src/components/ByDaysChart.vue new file mode 100644 index 0000000..1e6d699 --- /dev/null +++ b/src/components/ByDaysChart.vue @@ -0,0 +1,103 @@ + + + + + + + diff --git a/src/components/Dashboad.vue b/src/components/Dashboad.vue new file mode 100644 index 0000000..b386e74 --- /dev/null +++ b/src/components/Dashboad.vue @@ -0,0 +1,93 @@ + + + + + + + diff --git a/src/components/DashboadContainer.vue b/src/components/DashboadContainer.vue new file mode 100644 index 0000000..c56c334 --- /dev/null +++ b/src/components/DashboadContainer.vue @@ -0,0 +1,30 @@ + + + + + + + diff --git a/src/components/Donation.vue b/src/components/Donation.vue new file mode 100644 index 0000000..f3eed24 --- /dev/null +++ b/src/components/Donation.vue @@ -0,0 +1,46 @@ + + + + + + + diff --git a/src/components/DonutChart.vue b/src/components/DonutChart.vue new file mode 100644 index 0000000..fe8b9b8 --- /dev/null +++ b/src/components/DonutChart.vue @@ -0,0 +1,97 @@ + + + + + + + diff --git a/src/components/Expander.vue b/src/components/Expander.vue new file mode 100644 index 0000000..b66e900 --- /dev/null +++ b/src/components/Expander.vue @@ -0,0 +1,108 @@ + + + + + + + diff --git a/src/components/Favicon.vue b/src/components/Favicon.vue new file mode 100644 index 0000000..f3a54b4 --- /dev/null +++ b/src/components/Favicon.vue @@ -0,0 +1,45 @@ + + + + + + + diff --git a/src/components/GeneralSettings.vue b/src/components/GeneralSettings.vue new file mode 100644 index 0000000..d76ce8c --- /dev/null +++ b/src/components/GeneralSettings.vue @@ -0,0 +1,298 @@ + + + + + + + diff --git a/src/components/HourlyChart.vue b/src/components/HourlyChart.vue new file mode 100644 index 0000000..b2dbcb5 --- /dev/null +++ b/src/components/HourlyChart.vue @@ -0,0 +1,213 @@ + + + + + diff --git a/src/components/Limits.vue b/src/components/Limits.vue new file mode 100644 index 0000000..79900b0 --- /dev/null +++ b/src/components/Limits.vue @@ -0,0 +1,36 @@ + + + + + + + diff --git a/src/components/ListWithTime.vue b/src/components/ListWithTime.vue new file mode 100644 index 0000000..bf9fda8 --- /dev/null +++ b/src/components/ListWithTime.vue @@ -0,0 +1,218 @@ + + + + + + + diff --git a/src/components/MyApps.vue b/src/components/MyApps.vue new file mode 100644 index 0000000..28da6ea --- /dev/null +++ b/src/components/MyApps.vue @@ -0,0 +1,78 @@ + + + + + + + diff --git a/src/components/NoDataByDays.vue b/src/components/NoDataByDays.vue new file mode 100644 index 0000000..836d1bd --- /dev/null +++ b/src/components/NoDataByDays.vue @@ -0,0 +1,17 @@ + + + + + diff --git a/src/components/Notifications.vue b/src/components/Notifications.vue new file mode 100644 index 0000000..e334edd --- /dev/null +++ b/src/components/Notifications.vue @@ -0,0 +1,142 @@ + + + + + + + diff --git a/src/components/OverallStatistics.vue b/src/components/OverallStatistics.vue new file mode 100644 index 0000000..e968f2b --- /dev/null +++ b/src/components/OverallStatistics.vue @@ -0,0 +1,192 @@ + + + + + + + diff --git a/src/components/Pomodoro.vue b/src/components/Pomodoro.vue new file mode 100644 index 0000000..be9a086 --- /dev/null +++ b/src/components/Pomodoro.vue @@ -0,0 +1,254 @@ + + + + + + + diff --git a/src/components/PomodoroInfo.vue b/src/components/PomodoroInfo.vue new file mode 100644 index 0000000..a3b24df --- /dev/null +++ b/src/components/PomodoroInfo.vue @@ -0,0 +1,72 @@ + + + + + + + diff --git a/src/components/PomodoroSoundsSelector.vue b/src/components/PomodoroSoundsSelector.vue new file mode 100644 index 0000000..1527172 --- /dev/null +++ b/src/components/PomodoroSoundsSelector.vue @@ -0,0 +1,69 @@ + + + + + + + diff --git a/src/components/PromoCleanYoutubeModal.vue b/src/components/PromoCleanYoutubeModal.vue new file mode 100644 index 0000000..abb0511 --- /dev/null +++ b/src/components/PromoCleanYoutubeModal.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/components/PromoClearYouTube.vue b/src/components/PromoClearYouTube.vue new file mode 100644 index 0000000..6bba3f5 --- /dev/null +++ b/src/components/PromoClearYouTube.vue @@ -0,0 +1,82 @@ + + + + + + + diff --git a/src/components/Review.vue b/src/components/Review.vue new file mode 100644 index 0000000..45cfebe --- /dev/null +++ b/src/components/Review.vue @@ -0,0 +1,90 @@ + + + + + + + diff --git a/src/components/TabItem.vue b/src/components/TabItem.vue new file mode 100644 index 0000000..a543f89 --- /dev/null +++ b/src/components/TabItem.vue @@ -0,0 +1,179 @@ + + + + + + + diff --git a/src/components/TabItemHeader.vue b/src/components/TabItemHeader.vue new file mode 100644 index 0000000..d2c6311 --- /dev/null +++ b/src/components/TabItemHeader.vue @@ -0,0 +1,93 @@ + + + + + + + diff --git a/src/components/TabList.vue b/src/components/TabList.vue new file mode 100644 index 0000000..b9dfd5f --- /dev/null +++ b/src/components/TabList.vue @@ -0,0 +1,167 @@ + + + + + + + diff --git a/src/components/TimeIntervalChart.vue b/src/components/TimeIntervalChart.vue new file mode 100644 index 0000000..f10c3ed --- /dev/null +++ b/src/components/TimeIntervalChart.vue @@ -0,0 +1,248 @@ + + + + + + + diff --git a/src/components/WebsiteStats.vue b/src/components/WebsiteStats.vue new file mode 100644 index 0000000..5412730 --- /dev/null +++ b/src/components/WebsiteStats.vue @@ -0,0 +1,144 @@ + + + + + + + diff --git a/src/components/WebsiteStatsDetails.vue b/src/components/WebsiteStatsDetails.vue new file mode 100644 index 0000000..e205021 --- /dev/null +++ b/src/components/WebsiteStatsDetails.vue @@ -0,0 +1,67 @@ + + + + + + + diff --git a/src/components/WhiteList.vue b/src/components/WhiteList.vue new file mode 100644 index 0000000..b58a6ec --- /dev/null +++ b/src/components/WhiteList.vue @@ -0,0 +1,99 @@ + + + + + + + diff --git a/src/compositions/useExtensionPage.ts b/src/compositions/useExtensionPage.ts new file mode 100644 index 0000000..70ff3b1 --- /dev/null +++ b/src/compositions/useExtensionPage.ts @@ -0,0 +1,48 @@ +import { computed, ref } from 'vue'; +import { SettingsTab } from '../utils/enums'; +import { getStringTab } from '../utils/extension-tabs'; + +export const QUERY_PARAMS_DASHBOARD = 'dashboard.html'; +export const QUERY_PARAMS_TAB = 'tab'; +export const QUERY_PARAMS_TAB_LIMITS = 'limits'; +export const QUERY_PARAMS_BLOCK = 'block.html'; +export const QUERY_PARAMS_BLOCK_DOMAIN = 'domain'; + +export function useExtensionPage() { + const urlObj = ref(new URL(location.href)); + + const isLimitPage = computed( + () => + urlObj.value.hostname == __APP_ID__ && + urlObj.value.pathname.includes(QUERY_PARAMS_DASHBOARD) && + urlObj.value.searchParams.get(QUERY_PARAMS_TAB) == QUERY_PARAMS_TAB_LIMITS, + ); + + const isBlockPage = computed( + () => + urlObj.value.hostname == __APP_ID__ && + urlObj.value.pathname.includes(QUERY_PARAMS_BLOCK) && + urlObj.value.searchParams.get(QUERY_PARAMS_BLOCK_DOMAIN)?.includes('youtube.com'), + ); + + function updateTab(tab: SettingsTab) { + let targetTab = getStringTab(tab); + const currentTab = urlObj.value.searchParams.get(QUERY_PARAMS_TAB); + if (window.history.replaceState && currentTab) { + const sourceUrl = `tab=${currentTab}`; + const targetUrl = `tab=${targetTab}`; + window.history.replaceState( + location.href, + document.title, + location.href.replace(sourceUrl, targetUrl), + ); + urlObj.value = new URL(location.href); + } + } + + return { + isLimitPage, + isBlockPage, + updateTab, + }; +} diff --git a/src/compositions/usePromoExtension.ts b/src/compositions/usePromoExtension.ts new file mode 100644 index 0000000..b96ca5b --- /dev/null +++ b/src/compositions/usePromoExtension.ts @@ -0,0 +1,45 @@ +import { computed } from 'vue'; +import { Restriction } from '../entity/restriction'; +import { injectStorage } from '../storage/inject-storage'; +import { StorageParams } from '../storage/storage-params'; +import { useExtensionPage } from './useExtensionPage'; + +export const QUERY_PARAMS_DASHBOARD = 'dashboard.html'; +export const QUERY_PARAMS_DASHBOARD_TAB = 'tab'; +export const QUERY_PARAMS_DASHBOARD_TAB_SETTINGS = 'settings'; +export const QUERY_PARAMS_BLOCK = 'block.html'; +export const QUERY_PARAMS_BLOCK_DOMAIN = 'domain'; + +export async function usePromoExtension() { + const settingsStorage = injectStorage(); + const extensionPage = useExtensionPage(); + + const hasReviewOnLimits = await settingsStorage.getValue( + StorageParams.PROMO_CLEAR_YOUTUBE_ON_LIMITS, + ); + const hasReviewOnBlock = await settingsStorage.getValue( + StorageParams.PROMO_CLEAR_YOUTUBE_ON_BLOCK, + ); + + const whitelist = Object.values( + await settingsStorage.getValue(StorageParams.RESTRICTION_LIST, []), + ) as Restriction[]; + + const isIncludeYoutube = computed( + () => whitelist.find(x => x.domain == 'youtube.com') != undefined, + ); + + const showOnLimitPage = computed( + () => + (hasReviewOnLimits == undefined || hasReviewOnLimits == false) && + extensionPage.isLimitPage.value && + isIncludeYoutube.value, + ); + const showOnBlockPage = computed( + () => + (hasReviewOnBlock == undefined || hasReviewOnBlock == false) && + extensionPage.isBlockPage.value, + ); + + return showOnLimitPage.value || showOnBlockPage.value; +} diff --git a/src/dashboard.html b/src/dashboard.html new file mode 100644 index 0000000..b0deec1 --- /dev/null +++ b/src/dashboard.html @@ -0,0 +1,17 @@ + + + + + + + Web Activity Time Tracker - Dashboard + + + + + + + + + + diff --git a/src/dashboard.ts b/src/dashboard.ts new file mode 100644 index 0000000..1d55780 --- /dev/null +++ b/src/dashboard.ts @@ -0,0 +1,12 @@ +import Settings from './pages/Dashboard.vue'; +import Notifications from '@kyvg/vue3-notification'; +import VueDatePicker from '@vuepic/vue-datepicker'; +import '@vuepic/vue-datepicker/dist/main.css'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Settings); +app.use(Notifications); +app.use(i18n); +app.component('VueDatePicker', VueDatePicker); +app.mount('body'); diff --git a/src/dto/currentTabItem.ts b/src/dto/currentTabItem.ts new file mode 100644 index 0000000..eeed770 --- /dev/null +++ b/src/dto/currentTabItem.ts @@ -0,0 +1,6 @@ +export interface CurrentTabItem { + url: string; + favicon: string | undefined; + summaryTime: number; + sessions: number; +} diff --git a/src/dto/daySummary.ts b/src/dto/daySummary.ts new file mode 100644 index 0000000..29c136e --- /dev/null +++ b/src/dto/daySummary.ts @@ -0,0 +1,7 @@ +export type DaySummary = { + time: number | undefined; + timeYesterDay: number | undefined; + percentageFromYesterday: string | undefined; + mostVisitedSite: string | undefined; + mostVisitedSiteTime: number | undefined; +}; diff --git a/src/dto/tabListSummary.ts b/src/dto/tabListSummary.ts new file mode 100644 index 0000000..400fa39 --- /dev/null +++ b/src/dto/tabListSummary.ts @@ -0,0 +1,44 @@ +import { Tab } from '../entity/tab'; +import { CurrentTabItem } from './currentTabItem'; + +export interface OverallStats extends TabListSummary { + firstDay: Date; + activeDaysTotal: number; + daysTotal: number; + todaySummaryTime: number; + averageTimeByActiveDays: number; + mostActiveDay: ActiveDay; + mostInactiveDay: ActiveDay; + mostActiveDayExceptToday: ActiveDay | null; + mostInactiveDayExceptToday: ActiveDay | null; +} + +export interface ActiveDay { + date: Date; + summaryTime: number; +} + +export interface TabListSummary { + tabs: Tab[]; + summaryTime: number; + chart: DataForChart; +} + +export interface DataForChart { + timeForChart: number[]; + sitesForChart: string[]; +} + +export interface TabListByDays { + days: DayTabs[]; + averageTime: number; + summaryTime: number; + sessions: number; +} + +export interface DayTabs { + day: string; + tabs: CurrentTabItem[]; + time: number; + sessions: number; +} diff --git a/src/entity/baseTimeList.ts b/src/entity/baseTimeList.ts new file mode 100644 index 0000000..42dfe28 --- /dev/null +++ b/src/entity/baseTimeList.ts @@ -0,0 +1,4 @@ +export interface BaseTimeList { + domain: string; + time: number; +} diff --git a/src/entity/deffering.ts b/src/entity/deffering.ts new file mode 100644 index 0000000..0e58c8e --- /dev/null +++ b/src/entity/deffering.ts @@ -0,0 +1,12 @@ +import { MINUTE } from '../utils/time'; +import { BaseTimeList } from './baseTimeList'; + +export class Deffering implements BaseTimeList { + domain: string; + time: number; + + constructor(domain: string, minutes: number) { + this.domain = domain; + this.time = Date.now() + minutes * MINUTE; + } +} diff --git a/src/entity/notification.ts b/src/entity/notification.ts new file mode 100644 index 0000000..c3ab1d2 --- /dev/null +++ b/src/entity/notification.ts @@ -0,0 +1,12 @@ +import { convertHHMMToSeconds } from '../utils/converter'; +import { BaseTimeList } from './baseTimeList'; + +export class Notifications implements BaseTimeList { + domain: string; + time: number; + + constructor(domain: string, hours: number, minutes: number) { + this.domain = domain; + this.time = convertHHMMToSeconds(hours, minutes); + } +} diff --git a/src/entity/restriction.ts b/src/entity/restriction.ts new file mode 100644 index 0000000..7fe84ae --- /dev/null +++ b/src/entity/restriction.ts @@ -0,0 +1,11 @@ +import { convertHHMMToSeconds } from '../utils/converter'; + +export class Restriction { + domain: string; + time: number; + + constructor(domain: string, hours: number, minutes: number) { + this.domain = domain; + this.time = convertHHMMToSeconds(hours, minutes); + } +} diff --git a/src/entity/tab.ts b/src/entity/tab.ts new file mode 100644 index 0000000..bd674da --- /dev/null +++ b/src/entity/tab.ts @@ -0,0 +1,81 @@ +import { todayLocalDate } from '../utils/date'; +import { logger } from '../utils/logger'; + +export class Tab implements ISerializable { + url: string = ''; + favicon: string | undefined = ''; + summaryTime: number = 0; + counter: number = 0; + days: TabDay[] = []; + + init(url: string) { + this.url = url; + } + + incSummaryTime(): void { + this.summaryTime += 1; + + const day = this.days.find(x => x.date == todayLocalDate()); + if (day === undefined) { + const newTab = this.addNewDay(); + newTab.incSummaryTime(); + } else day.incSummaryTime(); + } + + incCounter(): void { + this.counter += 1; + if (__DEV__) logger.log(`Counter ${this.url} - ${this.counter}`); + const day = this.days.find(x => x.date == todayLocalDate()); + if (day === undefined) { + const newTab = this.addNewDay(); + newTab.incCounter(); + } else day.incCounter(); + } + + addNewDay(): TabDay { + const newTabDay = new TabDay(); + newTabDay.init(todayLocalDate()); + this.days.push(newTabDay); + return newTabDay; + } + + deserialize(input: Tab) { + this.url = input.url; + this.counter = input.counter; + this.favicon = input.favicon; + this.summaryTime = input.summaryTime; + if (input.days?.length > 0) this.days = input.days.map(x => new TabDay().deserialize(x)); + + return this; + } + + setFavicon(favicon: string | undefined) { + this.favicon = favicon; + } +} + +export class TabDay implements ISerializable { + counter: number = 0; + date: string = ''; + summary: number = 0; + + init(date: string) { + this.date = date; + } + + incSummaryTime(): void { + this.summary += 1; + } + + incCounter(): void { + this.counter += 1; + } + + deserialize(input: TabDay): TabDay { + this.counter = input.counter; + this.date = input.date; + this.summary = input.summary; + + return this; + } +} diff --git a/src/entity/time-interval.ts b/src/entity/time-interval.ts new file mode 100644 index 0000000..b002443 --- /dev/null +++ b/src/entity/time-interval.ts @@ -0,0 +1,46 @@ +import { logger } from '../utils/logger'; + +export class TimeInterval implements ISerializable { + domain: string = ''; + intervals: string[] = []; + day: string = ''; + + init(day: string, domain: string) { + this.domain = domain; + this.intervals = []; + this.day = day; + } + + addInterval() { + const stringDate = this.getCurrentStringDate(); + this.intervals.push(stringDate + '-' + stringDate); + logger.log(`Add interval ${this.domain} - ${stringDate} - ${stringDate}`); + } + + closeInterval() { + const stringDate = this.getCurrentStringDate(); + const currentInterval = this.intervals[this.intervals.length - 1]; + if (currentInterval != null) { + if (currentInterval.split('-')[0] == currentInterval.split('-')[1]) { + this.intervals.pop(); + this.intervals.push(currentInterval.split('-')[0] + '-' + stringDate); + logger.log( + `Close interval ${this.domain} - ${currentInterval.split('-')[0]} - ${stringDate}`, + ); + } + } + } + + deserialize(input: TimeInterval): TimeInterval { + this.domain = input.domain; + this.day = input.day; + this.intervals = input.intervals; + + return this; + } + + private getCurrentStringDate(): string { + const date = new Date(); + return date.getHours() + ':' + date.getMinutes() + ':' + date.getSeconds(); + } +} diff --git a/src/functions/black-list.ts b/src/functions/black-list.ts new file mode 100644 index 0000000..a06d188 --- /dev/null +++ b/src/functions/black-list.ts @@ -0,0 +1,10 @@ +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { extractHostname } from '../utils/extract-hostname'; +import { Settings } from './settings'; + +export async function isInBlackList(url: string): Promise { + const blackList = (await Settings.getInstance().getSetting(StorageParams.BLACK_LIST)) as string[]; + const array = Object.values(blackList); + return array?.find(x => isDomainEquals(extractHostname(x), extractHostname(url))) !== undefined; +} diff --git a/src/functions/current-tab.ts b/src/functions/current-tab.ts new file mode 100644 index 0000000..079be59 --- /dev/null +++ b/src/functions/current-tab.ts @@ -0,0 +1,8 @@ +import Browser from 'webextension-polyfill'; + +export async function getCurrentTab() { + const tabs = await Browser.tabs.query({ active: true, currentWindow: true }); + // since only one tab should be active and in the current window at once + // the return variable should only have one entry + return tabs[0]; +} diff --git a/src/functions/deferList.ts b/src/functions/deferList.ts new file mode 100644 index 0000000..8bd60b3 --- /dev/null +++ b/src/functions/deferList.ts @@ -0,0 +1,41 @@ +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { Settings } from './settings'; +import { Deffering } from '../entity/deffering'; +import { injectStorage } from '../storage/inject-storage'; +import { MINUTE } from '../utils/time'; +import { log } from '../utils/logger'; +import { millisecondsInHour } from 'date-fns'; + +export async function isInDeferList(url: string): Promise { + const deferList = (await Settings.getInstance().getSetting( + StorageParams.BLOCK_DEFERRAL_TIME, + )) as Deffering[]; + const item = deferList?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) log(`Deferring time ${url} ${new Date(item.time)}`); + return item != undefined && item.time > Date.now(); +} + +export async function canDefering(url: string): Promise { + const deferList = (await Settings.getInstance().getSetting( + StorageParams.BLOCK_DEFERRAL_TIME, + )) as Deffering[]; + const item = deferList?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) log(`Deferring time ${url} ${new Date(item.time)}`); + if (item == undefined) return true; + + return item != undefined && Date.now() - new Date(item.time).getTime() > millisecondsInHour * 24; +} + +export async function defering(url: string, timeInMinutes: number): Promise { + const settingsStorage = injectStorage(); + + const deferList = (await Settings.getInstance().getSetting( + StorageParams.BLOCK_DEFERRAL_TIME, + )) as Deffering[]; + const item = deferList?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) item.time = Date.now() + timeInMinutes * MINUTE; + else deferList.push(new Deffering(url, 5)); + + await settingsStorage.saveValue(StorageParams.BLOCK_DEFERRAL_TIME, deferList); +} diff --git a/src/functions/limit-list.ts b/src/functions/limit-list.ts new file mode 100644 index 0000000..9286ec1 --- /dev/null +++ b/src/functions/limit-list.ts @@ -0,0 +1,55 @@ +import { Restriction } from '../entity/restriction'; +import { Tab } from '../entity/tab'; +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { todayLocalDate } from '../utils/date'; +import { isInDeferList } from './deferList'; +import { log } from '../utils/logger'; +import { Settings } from './settings'; + +export type LimitExceed = { + IsLimitExceeded: boolean; + LimitTime: number | null; +}; + +export async function isLimitExceeded(url: string, tab: Tab): Promise { + const limitList = (await Settings.getInstance().getSetting( + StorageParams.RESTRICTION_LIST, + )) as Restriction[]; + const array = Object.values(limitList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) { + const date = tab.days.find(x => x.date == todayLocalDate()); + if (date != undefined) { + if (date.summary >= item.time) { + log(`Limit Exceeded: website ${url} limit ${item.time} summary time ${date.summary}`); + if (await isInDeferList(url)) { + log(`Page ${url} is in deffering list`); + return { + IsLimitExceeded: false, + LimitTime: null, + }; + } + + return { + IsLimitExceeded: true, + LimitTime: item.time, + }; + } + } + } + + return { + IsLimitExceeded: false, + LimitTime: null, + }; +} + +export async function isDomainInLimits(url: string): Promise { + const limitList = (await Settings.getInstance().getSetting( + StorageParams.RESTRICTION_LIST, + )) as Restriction[]; + const array = Object.values(limitList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + return item != undefined; +} diff --git a/src/functions/playSound.ts b/src/functions/playSound.ts new file mode 100644 index 0000000..61eb7f2 --- /dev/null +++ b/src/functions/playSound.ts @@ -0,0 +1,7 @@ +import Browser from 'webextension-polyfill'; +import { PomodoroSounds } from '../utils/pomodoro'; + +export function playSound(sound: PomodoroSounds) { + const myAudio = new Audio(Browser.runtime.getURL(`assets/pomodoro-sounds/${sound}`)); + myAudio.play(); +} diff --git a/src/functions/pomodoro.ts b/src/functions/pomodoro.ts new file mode 100644 index 0000000..7a1764e --- /dev/null +++ b/src/functions/pomodoro.ts @@ -0,0 +1,145 @@ +import { addSeconds } from 'date-fns'; +import { injectStorage } from '../storage/inject-storage'; +import { StorageParams } from '../storage/storage-params'; +import { useBadge, BadgeIcon, BadgeColor } from './useBadge'; +import { Settings } from './settings'; +import Browser from 'webextension-polyfill'; +import { logger } from '../utils/logger'; +import { Messages } from '../utils/messages'; +import { isDateEqual } from '../utils/date'; +import { createOffscreen } from '../offscreen/index'; + +export async function checkPomodoro() { + type PomodoroPeriod = { + period: Period; + isTargetPeriod: boolean; + isTargetPeriodFinishedNow: boolean; + }; + + enum Period { + work = 'WORK', + rest = 'REST', + finished = 'FINISH', + } + + function isTargetPeriod(period: Period): PomodoroPeriod { + let isPomodoroTargetPeriodEnd; + for (let index = 1; index <= frequency; index++) { + let ind = period == Period.work ? index - 1 : index; + const plusWorkingTime = workTime * ind; + const plusRestTime = (restTime + 1) * (index - 1); + const isPomodoroTargetPeriodStart = addSeconds(startTime, plusWorkingTime + plusRestTime); + isPomodoroTargetPeriodEnd = addSeconds(startTime, plusWorkingTime + plusRestTime + workTime); + const isTargetPeriod = + now >= isPomodoroTargetPeriodStart && + (addSeconds(now, -1) <= isPomodoroTargetPeriodEnd || now <= isPomodoroTargetPeriodEnd); + + if (isTargetPeriod) { + return { + period: period, + isTargetPeriod: isTargetPeriod, + isTargetPeriodFinishedNow: + isDateEqual(addSeconds(now, -1), isPomodoroTargetPeriodEnd) || + isDateEqual(now, isPomodoroTargetPeriodEnd), + }; + } + } + return { + period: Period.finished, + isTargetPeriod: false, + isTargetPeriodFinishedNow: false, + }; + } + + async function play(period: Period) { + function getSound() { + switch (period) { + case Period.work: + return StorageParams.POMODORO_AUDIO_AFTER_WORK; + case Period.rest: + return StorageParams.POMODORO_AUDIO_AFTER_REST; + case Period.finished: + return StorageParams.POMODORO_AUDIO_AFTER_FINISHED; + } + } + logger.log(`[Pomodoro] ${period}`); + const sound = await storage.getValue(getSound()); + await createOffscreen(); + await Browser.runtime.sendMessage({ + message: Messages.PlayAudio, + sound: sound, + offscreen: true, + }); + } + + const storage = injectStorage(); + const isPomodoroEnabled = (await Settings.getInstance().getSetting( + StorageParams.IS_POMODORO_ENABLED, + )) as boolean; + + if (!isPomodoroEnabled) return; + + const startTime = new Date( + (await Settings.getInstance().getSetting(StorageParams.POMODORO_START_TIME)) as string, + ); + const workTime = (await Settings.getInstance().getSetting( + StorageParams.POMODORO_INTERVAL_WORK, + )) as number; + const restTime = (await Settings.getInstance().getSetting( + StorageParams.POMODORO_INTERVAL_REST, + )) as number; + const frequency = (await Settings.getInstance().getSetting( + StorageParams.POMODORO_FREQUENCY, + )) as number; + + const now = new Date(); + + const pomodoroEndTime = addSeconds(startTime, workTime * frequency + restTime * frequency); + + const activeTab = await Browser.tabs.query({ active: true }); + + if (now >= pomodoroEndTime) { + if (isDateEqual(now, pomodoroEndTime)) { + logger.log(`[Pomodoro] Pomodoro finished`); + await play(Period.finished); + } + + await storage.saveValue(StorageParams.IS_POMODORO_ENABLED, false); + await storage.saveValue(StorageParams.POMODORO_START_TIME, null); + await useBadge({ + tabId: activeTab[0].id, + text: null, + color: BadgeColor.none, + icon: BadgeIcon.default, + }); + return; + } + + let target = isTargetPeriod(Period.work); + const isWork = target.isTargetPeriod; + + if (isWork) { + await useBadge({ + tabId: activeTab[0].id, + text: null, + color: BadgeColor.none, + icon: BadgeIcon.pomodoroWorkingTime, + }); + } else { + target = isTargetPeriod(Period.rest); + if (target.isTargetPeriod) { + await useBadge({ + tabId: activeTab[0].id, + text: null, + color: BadgeColor.none, + icon: BadgeIcon.pomodoroRestTime, + }); + } + } + + if (target.isTargetPeriodFinishedNow) await play(target.period); + + return { + isWork, + }; +} diff --git a/src/functions/settings.ts b/src/functions/settings.ts new file mode 100644 index 0000000..1266c1e --- /dev/null +++ b/src/functions/settings.ts @@ -0,0 +1,34 @@ +import { injectStorage } from '../storage/inject-storage'; +import { StorageParams, getDefaultValue } from '../storage/storage-params'; + +export class Settings { + private static instance: Settings; + private _settings = new Map(); + + constructor() { + if (Settings.instance) { + throw new Error('Error - use Settings.getInstance()'); + } + } + + static getInstance(): Settings { + Settings.instance = Settings.instance || new Settings(); + return Settings.instance; + } + + async getSetting(param: StorageParams) { + if (this._settings.has(param)) return this._settings.get(param); + else return await this.getValue(param); + } + + async reloadSetting(param: StorageParams) { + await this.getValue(param); + } + + private async getValue(param: StorageParams) { + const storage = injectStorage(); + const value = await storage.getValue(param, getDefaultValue(param)); + this._settings.set(param, value); + return value; + } +} diff --git a/src/functions/useAllTabListSummary.ts b/src/functions/useAllTabListSummary.ts new file mode 100644 index 0000000..aee301b --- /dev/null +++ b/src/functions/useAllTabListSummary.ts @@ -0,0 +1,146 @@ +import { ActiveDay, OverallStats } from '../dto/tabListSummary'; +import { Tab, TabDay } from '../entity/tab'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { SortingBy } from '../utils/enums'; +import { daysBetween } from '../utils/time'; +import { todayLocalDate } from '../utils/date'; + +export async function useAllTabListSummary(sortingBy: SortingBy): Promise { + const repo = await injectTabsRepository(); + const unSortedTabs = repo.getTabs(); + let tabs: Tab[] = []; + + if (unSortedTabs.length == 0) return null; + const todayTabs = unSortedTabs?.filter(x => x.days.find(s => s.date === todayLocalDate())); + + const summaryTimeListForToday = todayTabs.map(function (tab) { + return tab.days.find(day => day.date === todayLocalDate())!.summary; + }); + + const todaySummaryTime = + summaryTimeListForToday != undefined && summaryTimeListForToday.length > 0 + ? summaryTimeListForToday.reduce(function (a, b) { + return a + b; + }) + : 0; + + tabs = unSortedTabs.sort(function (a: Tab, b: Tab) { + return b.summaryTime - a.summaryTime; + }); + + let days: TabDay[] = []; + tabs.map(function (tab) { + return tab.days.forEach(function (day) { + const existDay = days.find(x => x.date == day.date); + if (!existDay) days.push(day); + else { + existDay.summary += day.summary; + existDay.counter += day.counter; + } + }); + }); + + days = days.sort(function (a, b) { + return new Date(a.date).valueOf() - new Date(b.date).valueOf(); + }); + + const mostDayExceptToday = fillMostListWithoutToday(days); + + const firstDay = new Date(days[0].date); + const activeDaysTotal = days.length; + + if (sortingBy == SortingBy.Sessions) + tabs = unSortedTabs.sort(function (a: Tab, b: Tab) { + return b.counter - a.counter; + }); + + const summaryTimeList = tabs?.map(function (tab) { + return tab.summaryTime; + }); + const siteList = tabs?.map(function (tab) { + return tab.url; + }); + const timeForChart = summaryTimeList?.slice(0, 10); + const sitesForChart = siteList?.slice(0, 10); + + const summaryTime = + summaryTimeList != undefined && summaryTimeList.length > 0 + ? summaryTimeList.reduce(function (a, b) { + return a + b; + }) + : 0; + + const averageTimeByActiveDays = Math.round(summaryTime / activeDaysTotal); + const daysTotal = daysBetween(firstDay, new Date(days[days.length - 1].date)); + + const mostDay = fillMostList(days); + + return { + firstDay: firstDay, + daysTotal: daysTotal, + activeDaysTotal: activeDaysTotal, + todaySummaryTime: todaySummaryTime, + averageTimeByActiveDays: averageTimeByActiveDays, + mostActiveDay: mostDay.mostActiveDayObj, + mostInactiveDay: mostDay.mostInactiveDayObj, + mostActiveDayExceptToday: + mostDayExceptToday != null ? mostDayExceptToday.mostActiveDayObjExceptToday : null, + mostInactiveDayExceptToday: + mostDayExceptToday != null ? mostDayExceptToday.mostInactiveDayObjExceptToday : null, + tabs: tabs, + summaryTime: summaryTime, + chart: { + timeForChart, + sitesForChart, + }, + }; +} + +function fillMostDay(mostDat: TabDay): ActiveDay { + return { + date: new Date(mostDat.date), + summaryTime: mostDat.summary, + }; +} + +function fillMostListWithoutToday(days: TabDay[]) { + const daysWithoutToday = days + .filter(x => x.date != todayLocalDate()) + .sort(function (a, b) { + return new Date(a.date).valueOf() - new Date(b.date).valueOf(); + }); + + const sortedByTimeDaysWithoutToday = daysWithoutToday.sort(function (a, b) { + return a.summary - b.summary; + }); + + if (sortedByTimeDaysWithoutToday.length == 0) return null; + const mostActiveDayExceptToday = + sortedByTimeDaysWithoutToday[sortedByTimeDaysWithoutToday.length - 1]; + const mostActiveDayObjExceptToday = fillMostDay(mostActiveDayExceptToday); + + const mostInactiveDayExceptToday = sortedByTimeDaysWithoutToday[0]; + const mostInactiveDayObjExceptToday = fillMostDay(mostInactiveDayExceptToday); + + return { + mostActiveDayObjExceptToday, + mostInactiveDayObjExceptToday, + }; +} + +function fillMostList(days: TabDay[]) { + const sortedByTimeDays = days.sort(function (a, b) { + return a.summary - b.summary; + }); + + const mostActiveDay = sortedByTimeDays[sortedByTimeDays.length - 1]; + const mostActiveDayObj = fillMostDay(mostActiveDay); + + const mostInactiveDay = sortedByTimeDays[0]; + const mostInactiveDayObj = fillMostDay(mostInactiveDay); + + return { + mostActiveDayObj, + mostInactiveDayObj, + }; +} diff --git a/src/functions/useBadge.ts b/src/functions/useBadge.ts new file mode 100644 index 0000000..8854b25 --- /dev/null +++ b/src/functions/useBadge.ts @@ -0,0 +1,42 @@ +import Browser from 'webextension-polyfill'; + +export interface BadgeState { + text: string | null; + color: BadgeColor; + tabId?: number; + icon?: BadgeIcon; +} + +export enum BadgeIcon { + default = '/128x128.png', + pomodoroWorkingTime = '/assets/icons/pomodoro.png', + pomodoroRestTime = '/assets/icons/pomodoro-rest.png', +} + +export enum BadgeColor { + red = '#fdb8b8', + green = '#6ec05e', + blue = '#1a73e8', + none = '#000', +} + +export async function useBadge(badge: BadgeState): Promise { + if (badge.color != BadgeColor.none) + await Browser.action.setBadgeBackgroundColor({ color: badge.color }); + await Browser.action.setBadgeText({ + tabId: badge.tabId, + text: badge.text, + }); + if (badge.icon) { + await Browser.action.setIcon({ + path: badge.icon, + }); + await Browser.action.setBadgeText({ + tabId: badge.tabId, + text: badge.text, + }); + } else + await Browser.action.setIcon({ + path: BadgeIcon.default, + }); +} diff --git a/src/functions/useBlockPage.ts b/src/functions/useBlockPage.ts new file mode 100644 index 0000000..e209d7c --- /dev/null +++ b/src/functions/useBlockPage.ts @@ -0,0 +1,21 @@ +import Browser from 'webextension-polyfill'; +import { buildBlockQuery } from '../utils/block-page'; +import { NO_FAVICON } from '../utils/consts'; + +export async function useBlockPage( + domain: string, + url: string, + limitTime: number, + summaryCounter: number, + favIconUrl: string | undefined, +): Promise { + const favicon = + favIconUrl == undefined || favIconUrl == '' || favIconUrl.startsWith('chrome://favicon/') + ? NO_FAVICON + : favIconUrl; + const blockUrl = + Browser.runtime.getURL('src/block.html') + + buildBlockQuery(domain, url, limitTime, summaryCounter, favicon); + const tab = await Browser.tabs.query({ currentWindow: true, active: true }); + await Browser.tabs.update(tab[0].id, { url: blockUrl }); +} diff --git a/src/functions/useDailyIntervals.ts b/src/functions/useDailyIntervals.ts new file mode 100644 index 0000000..534c9e6 --- /dev/null +++ b/src/functions/useDailyIntervals.ts @@ -0,0 +1,48 @@ +import { TimeInterval } from '../entity/time-interval'; +import { injectStorage } from '../storage/inject-storage'; +import { StorageDeserializeParam } from '../storage/storage-params'; +import { todayLocalDate } from '../utils/date'; + +export async function useDailyIntervals() { + async function closeInterval(domain: string | null): Promise { + if (domain == null) return; + const storage = injectStorage(); + const timeIntervalList = (await storage.getDeserializeList( + StorageDeserializeParam.TIMEINTERVAL_LIST, + )) as TimeInterval[]; + const item = timeIntervalList?.find(x => x.domain === domain && x.day == todayLocalDate()); + item?.closeInterval(); + await storage.saveIntervalList(timeIntervalList); + } + + async function addInterval(domain: string | null): Promise { + if (domain == null) return; + + const storage = injectStorage(); + let timeIntervalList = (await storage.getDeserializeList( + StorageDeserializeParam.TIMEINTERVAL_LIST, + )) as TimeInterval[]; + if (timeIntervalList == undefined) timeIntervalList = []; + const item = timeIntervalList?.find(x => x.domain === domain && x.day == todayLocalDate()); + if (item != undefined) { + if (item.day == todayLocalDate()) item.addInterval(); + else { + const newInterval = new TimeInterval(); + newInterval.init(todayLocalDate(), domain); + newInterval.addInterval(); + timeIntervalList.push(newInterval); + } + } else { + const newInterval = new TimeInterval(); + newInterval.init(todayLocalDate(), domain); + newInterval.addInterval(); + timeIntervalList.push(newInterval); + } + await storage.saveIntervalList(timeIntervalList); + } + + return { + closeInterval, + addInterval, + }; +} diff --git a/src/functions/useFile.ts b/src/functions/useFile.ts new file mode 100644 index 0000000..cf18b01 --- /dev/null +++ b/src/functions/useFile.ts @@ -0,0 +1,15 @@ +export enum FileType { + CSV = 'text/csv', + JSON = 'application/json', +} + +export function useFile(data: string, type: FileType, fileName: string) { + const file = new Blob([data], { type: type }); + let downloadLink; + downloadLink = document.createElement('a'); + downloadLink.download = fileName; + downloadLink.href = window.URL.createObjectURL(file); + downloadLink.style.display = 'none'; + document.body.appendChild(downloadLink); + downloadLink.click(); +} diff --git a/src/functions/useImportToCsv.ts b/src/functions/useImportToCsv.ts new file mode 100644 index 0000000..71c3412 --- /dev/null +++ b/src/functions/useImportToCsv.ts @@ -0,0 +1,35 @@ +import { DayTabs } from '../dto/tabListSummary'; +import { useTabListByDays } from './useTabListByDays'; + +const CSV_HEADER = 'Date,WebSite,Time(sec),Sessions\r\n'; + +export async function useImportToCsvWithData(days: DayTabs[] | undefined): Promise { + return getCsv(days); +} + +export async function useImportToCsv(dateFrom: Date, dateTo: Date): Promise { + const summary = await useTabListByDays(dateFrom, dateTo); + if (summary == null) return CSV_HEADER; + + return getCsv(summary.days); +} + +function getCsv(days: DayTabs[] | undefined) { + let str = CSV_HEADER; + + if (days != undefined && days.length > 0) { + days.forEach(day => { + let newLine = ''; + day.tabs.forEach(tab => { + newLine += day.day + ','; + newLine += tab.url + ','; + newLine += tab.summaryTime + ','; + newLine += tab.sessions; + newLine += '\r\n'; + }); + str += newLine + '\r\n'; + }); + } + + return str; +} diff --git a/src/functions/useNotification.ts b/src/functions/useNotification.ts new file mode 100644 index 0000000..8ccba80 --- /dev/null +++ b/src/functions/useNotification.ts @@ -0,0 +1,23 @@ +import Browser from 'webextension-polyfill'; +import { SECOND } from '../utils/time'; + +export enum NotificationType { + DailySummaryNotification = 'daily-summary-notification', + WebSiteNotification = 'website-notification', +} + +export async function useNotification( + notificationType: NotificationType, + title: string, + message: string, +): Promise { + await Browser.notifications.clear(notificationType); + await new Promise(res => setTimeout(res, 3 * SECOND)); + return Browser.notifications.create(notificationType, { + type: 'basic', + title: title, + message: message, + iconUrl: Browser.runtime.getURL('128x128.png'), + isClickable: false, + }); +} diff --git a/src/functions/useNotificationList.ts b/src/functions/useNotificationList.ts new file mode 100644 index 0000000..c4eb402 --- /dev/null +++ b/src/functions/useNotificationList.ts @@ -0,0 +1,49 @@ +import { Notifications } from '../entity/notification'; +import { Tab } from '../entity/tab'; +import { StorageParams } from '../storage/storage-params'; +import { isDomainEquals } from '../utils/common'; +import { todayLocalDate } from '../utils/date'; +import { log } from '../utils/logger'; +import { Settings } from './settings'; + +export type LimitExceed = { + IsLimitExceeded: boolean; + LimitTime: number | null; +}; + +export function useNotificationList() { + async function isNeedToShowNotification(url: string, tab: Tab): Promise { + const notificationList = (await Settings.getInstance().getSetting( + StorageParams.NOTIFICATION_LIST, + )) as Notifications[]; + const array = Object.values(notificationList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + if (item != undefined) { + const date = tab.days.find(x => x.date == todayLocalDate()); + if (date != undefined) { + if (date.summary != 0 && (date.summary == item.time || date.summary % item.time == 0)) { + log( + `Time for notification: website ${url} time ${item.time} summary time ${date.summary}`, + ); + return true; + } + } + } + + return false; + } + + async function isDomainInNotificationsLimit(url: string): Promise { + const notificationList = (await Settings.getInstance().getSetting( + StorageParams.NOTIFICATION_LIST, + )) as Notifications[]; + const array = Object.values(notificationList); + const item = array?.find(x => isDomainEquals(x.domain, url)); + return item != undefined; + } + + return { + isNeedToShowNotification, + isDomainInNotificationsLimit, + }; +} diff --git a/src/functions/useRemoveAllData.ts b/src/functions/useRemoveAllData.ts new file mode 100644 index 0000000..99809ec --- /dev/null +++ b/src/functions/useRemoveAllData.ts @@ -0,0 +1,9 @@ +import Browser from 'webextension-polyfill'; +import { injectStorage } from '../storage/inject-storage'; +import { Messages } from '../utils/messages'; + +export async function useRemoveAllData() { + const storage = injectStorage(); + await storage.saveIntervalList([]); + await Browser.runtime.sendMessage(Messages.ClearAllData); +} diff --git a/src/functions/useRestoreData.ts b/src/functions/useRestoreData.ts new file mode 100644 index 0000000..fe01044 --- /dev/null +++ b/src/functions/useRestoreData.ts @@ -0,0 +1,12 @@ +import Browser from 'webextension-polyfill'; +import { Messages } from '../utils/messages'; + +export async function useRestoreData(json: string) { + if (json != null && json != undefined && json != '') { + const data = JSON.parse(json); + await Browser.runtime.sendMessage({ + message: Messages.Restore, + data: data, + }); + } +} diff --git a/src/functions/useTabListByDays.ts b/src/functions/useTabListByDays.ts new file mode 100644 index 0000000..0e8525c --- /dev/null +++ b/src/functions/useTabListByDays.ts @@ -0,0 +1,97 @@ +import { CurrentTabItem } from '../dto/currentTabItem'; +import { DayTabs, TabListByDays } from '../dto/tabListSummary'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { isSameDay } from 'date-fns'; + +export async function useTabListByDays( + dateFrom: Date, + dateTo: Date, +): Promise { + const repo = await injectTabsRepository(); + const unSortedTabs = repo.getTabs(); + let daysTabs: DayTabs[] = []; + + if (unSortedTabs.length == 0) return null; + + const isTheSameDay = isSameDay(dateFrom, dateTo); + + const unSortedTabsByDays = unSortedTabs.filter(x => + isTheSameDay + ? x.days.find(s => isSameDay(new Date(s.date), dateFrom)) != undefined + : x.days.find(s => new Date(s.date) >= dateFrom && new Date(s.date) <= dateTo) != undefined, + ); + + if (unSortedTabsByDays.length == 0) + return { + days: [], + averageTime: 0, + summaryTime: 0, + sessions: 0, + }; + + unSortedTabsByDays.forEach(tab => { + tab.days.forEach(day => { + if ( + (new Date(day.date) >= dateFrom && new Date(day.date) <= dateTo) || + (isTheSameDay && isSameDay(new Date(day.date), dateFrom)) + ) { + let dayTab = daysTabs.find(x => x.day == day.date); + if (dayTab == undefined) { + dayTab = { + day: day.date, + tabs: [], + time: day.summary, + sessions: day.counter, + }; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: day.counter, + summaryTime: day.summary, + }); + daysTabs.push(dayTab); + } else { + dayTab.time += day.summary; + dayTab.sessions += day.counter; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: day.counter, + summaryTime: day.summary, + }); + } + } + }); + }); + + daysTabs.sort(function (a, b) { + return new Date(a.day).valueOf() - new Date(b.day).valueOf(); + }); + + daysTabs.forEach(dayTab => { + dayTab.tabs.sort(function (a: CurrentTabItem, b: CurrentTabItem) { + return b.summaryTime - a.summaryTime; + }); + }); + + const summaryTime = daysTabs + .map(x => x.time) + .reduce(function (a, b) { + return a + b; + }); + + const totalSessions = daysTabs + .map(x => x.sessions) + .reduce(function (a, b) { + return a + b; + }); + + const averageTime = Math.round(summaryTime / daysTabs.length); + + return { + days: daysTabs, + summaryTime: summaryTime, + averageTime: averageTime, + sessions: totalSessions, + }; +} diff --git a/src/functions/useTabStatsByDays.ts b/src/functions/useTabStatsByDays.ts new file mode 100644 index 0000000..e85b03a --- /dev/null +++ b/src/functions/useTabStatsByDays.ts @@ -0,0 +1,94 @@ +import { CurrentTabItem } from '../dto/currentTabItem'; +import { DayTabs, TabListByDays } from '../dto/tabListSummary'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { isSameDay } from 'date-fns'; + +export async function useTabStatsByDays( + dateFrom: Date, + dateTo: Date, + domain: string, +): Promise { + const repo = await injectTabsRepository(); + const tab = repo.getTab(domain); + let daysTabs: DayTabs[] = []; + + if (tab == undefined) return null; + + const isTheSameDay = isSameDay(dateFrom, dateTo); + + const unSortedTabsByDays = isTheSameDay + ? tab.days.filter(s => isSameDay(new Date(s.date), dateFrom)) + : tab.days.filter(s => new Date(s.date) >= dateFrom && new Date(s.date) <= dateTo); + + if (unSortedTabsByDays.length == 0) + return { + days: [], + averageTime: 0, + summaryTime: 0, + sessions: 0, + }; + + unSortedTabsByDays.forEach(tabDay => { + if ( + (new Date(tabDay.date) >= dateFrom && new Date(tabDay.date) <= dateTo) || + (isTheSameDay && isSameDay(new Date(tabDay.date), dateFrom)) + ) { + let dayTab = daysTabs.find(x => x.day == tabDay.date); + if (dayTab == undefined) { + dayTab = { + day: tabDay.date, + tabs: [], + time: tabDay.summary, + sessions: tabDay.counter, + }; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: tabDay.counter, + summaryTime: tabDay.summary, + }); + daysTabs.push(dayTab); + } else { + dayTab.time += tabDay.summary; + dayTab.sessions += tabDay.counter; + dayTab.tabs.push({ + favicon: tab.favicon, + url: tab.url, + sessions: tabDay.counter, + summaryTime: tabDay.summary, + }); + } + } + }); + + daysTabs.sort(function (a, b) { + return new Date(a.day).valueOf() - new Date(b.day).valueOf(); + }); + + daysTabs.forEach(dayTab => { + dayTab.tabs.sort(function (a: CurrentTabItem, b: CurrentTabItem) { + return b.summaryTime - a.summaryTime; + }); + }); + + const summaryTime = daysTabs + .map(x => x.time) + .reduce(function (a, b) { + return a + b; + }); + + const totalSessions = daysTabs + .map(x => x.sessions) + .reduce(function (a, b) { + return a + b; + }); + + const averageTime = Math.round(summaryTime / daysTabs.length); + + return { + days: daysTabs, + summaryTime: summaryTime, + averageTime: averageTime, + sessions: totalSessions, + }; +} diff --git a/src/functions/useTodayTabListSummary.ts b/src/functions/useTodayTabListSummary.ts new file mode 100644 index 0000000..fcd6afd --- /dev/null +++ b/src/functions/useTodayTabListSummary.ts @@ -0,0 +1,47 @@ +import { TabListSummary } from '../dto/tabListSummary'; +import { Tab } from '../entity/tab'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { SortingBy } from '../utils/enums'; +import { todayLocalDate } from '../utils/date'; + +export async function useTodayTabListSummary(sortingBy: SortingBy): Promise { + const repo = await injectTabsRepository(); + const unSortedTabs = repo.getTodayTabs(); + let tabs: Tab[] = []; + + if (unSortedTabs.length == 0) return null; + + tabs = unSortedTabs.sort(function (a: Tab, b: Tab) { + return sortingBy == SortingBy.UsageTime + ? b.days.find(s => s.date === todayLocalDate())!.summary - + a.days.find(s => s.date === todayLocalDate())!.summary + : b.days.find(s => s.date === todayLocalDate())!.counter - + a.days.find(s => s.date === todayLocalDate())!.counter; + }); + + const summaryTimeList = tabs?.map(function (tab) { + return tab.days.find(day => day.date === todayLocalDate())!.summary; + }); + + const siteList = tabs?.map(function (tab) { + return tab.url; + }); + + const timeForChart = summaryTimeList?.slice(0, 10); + const sitesForChart = siteList?.slice(0, 10); + + const summaryTime = + summaryTimeList != undefined && summaryTimeList.length > 0 + ? summaryTimeList.reduce(function (a, b) { + return a + b; + }) + : 0; + return { + tabs, + summaryTime, + chart: { + timeForChart, + sitesForChart, + }, + }; +} diff --git a/src/functions/useWebUsageSummaryForDay.ts b/src/functions/useWebUsageSummaryForDay.ts new file mode 100644 index 0000000..242e0e6 --- /dev/null +++ b/src/functions/useWebUsageSummaryForDay.ts @@ -0,0 +1,63 @@ +import { Tab } from '../entity/tab'; +import { injectTabsRepository } from '../repository/inject-tabs-repository'; +import { todayLocalDate } from '../utils/date'; +import { DaySummary } from '../dto/daySummary'; +import { startOfYesterday } from 'date-fns'; +import { getPercentage } from '../utils/common'; +import { ITabsRepository } from '../repository/tabs-repository-interface'; + +export async function useWebUsageSummaryForDay(): Promise { + const repo = await injectTabsRepository(); + + const unSortedTabs = repo.getTabs(); + if (unSortedTabs.length == 0) return null; + + const dataToday = getData(todayLocalDate(), repo); + const dataYesterday = getData(startOfYesterday().toLocaleDateString('en-US'), repo); + + return { + time: dataToday == null ? 0 : dataToday.time, + mostVisitedSite: dataToday?.mostVisitedSite, + mostVisitedSiteTime: dataToday?.mostVisitedSiteTime, + timeYesterDay: dataYesterday == null ? 0 : dataYesterday.time, + percentageFromYesterday: + dataToday == null + ? '0%' + : dataYesterday == null + ? '100%' + : `${getPercentage(dataToday.time, dataYesterday.time)}%`, + }; +} + +function getData(date: string, repo: ITabsRepository) { + const unSortedTabs = repo.getTabs(); + if (unSortedTabs.length == 0) return null; + + const targetTabs = unSortedTabs.filter(x => x.days.find(s => s.date === date)); + if (targetTabs.length == 0) return null; + + const tabs = targetTabs.sort(function (a: Tab, b: Tab) { + return b.days.find(s => s.date === date)!.summary - a.days.find(s => s.date === date)!.summary; + }); + + const summaryTimeList = tabs?.map(function (tab) { + return tab.days.find(day => day.date === date)!.summary; + }); + + const summaryTime = + summaryTimeList != undefined && summaryTimeList.length > 0 + ? summaryTimeList.reduce(function (a, b) { + return a + b; + }) + : 0; + + const mostVisitedTab = tabs[0]; + const mostVisitedSite = mostVisitedTab.url; + const mostVisitedSiteTime = mostVisitedTab.days.find(s => s.date === date)?.summary!; + + return { + time: summaryTime, + mostVisitedSite: mostVisitedSite, + mostVisitedSiteTime: mostVisitedSiteTime, + }; +} diff --git a/src/icons/bmc-new-btn-logo.svg b/src/icons/bmc-new-btn-logo.svg deleted file mode 100644 index d7b9b32..0000000 --- a/src/icons/bmc-new-btn-logo.svg +++ /dev/null @@ -1,29 +0,0 @@ - - - - Group - Created with Sketch. - - - - - - \ No newline at end of file diff --git a/src/icons/delete.png b/src/icons/delete.png deleted file mode 100644 index d5160c2..0000000 Binary files a/src/icons/delete.png and /dev/null differ diff --git a/src/icons/edit.png b/src/icons/edit.png deleted file mode 100644 index e80f09d..0000000 Binary files a/src/icons/edit.png and /dev/null differ diff --git a/src/icons/eye.png b/src/icons/eye.png deleted file mode 100644 index 0a358a7..0000000 Binary files a/src/icons/eye.png and /dev/null differ diff --git a/src/icons/heat-map-16.png b/src/icons/heat-map-16.png deleted file mode 100644 index 60afb64..0000000 Binary files a/src/icons/heat-map-16.png and /dev/null differ diff --git a/src/icons/information.svg b/src/icons/information.svg deleted file mode 100644 index 0bd40ae..0000000 --- a/src/icons/information.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/icons/limit.png b/src/icons/limit.png deleted file mode 100644 index b42bb6c..0000000 Binary files a/src/icons/limit.png and /dev/null differ diff --git a/src/icons/pie-chart.png b/src/icons/pie-chart.png deleted file mode 100644 index fa2f378..0000000 Binary files a/src/icons/pie-chart.png and /dev/null differ diff --git a/src/icons/time.svg b/src/icons/time.svg deleted file mode 100644 index c4f9923..0000000 --- a/src/icons/time.svg +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/index.html b/src/index.html deleted file mode 100644 index 9fbcf49..0000000 --- a/src/index.html +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - Web Activity Time Tracker - - - - - - - - - - - - - - - - - - - - - -
-

Web Activity Time Tracker

-
- -
-

Overall stats

-
-
-
-
First day
-
-
-
-
Last day
-
-
-
-
-
-
Active days
-
-
-
-
Days in total
-
-
-
-
-
-
Today
-
-
-
-
All-time
-
-
-
-
-
-
Most active day
-
-
-
-
-
-
-
Most inactive day
-
-
-
-
-
-
-
-
- -
-
- -
-
-
-
-
- - - - \ No newline at end of file diff --git a/src/jobs/daily-summary-notification.ts b/src/jobs/daily-summary-notification.ts new file mode 100644 index 0000000..d17c449 --- /dev/null +++ b/src/jobs/daily-summary-notification.ts @@ -0,0 +1,34 @@ +import { useWebUsageSummaryForDay } from '../functions/useWebUsageSummaryForDay'; +import { convertLimitTimeToString } from '../utils/converter'; +import { Settings } from '../functions/settings'; +import { StorageParams } from '../storage/storage-params'; +import { NotificationType, useNotification } from '../functions/useNotification'; +import { getMessagesFromLocale } from '../plugins/i18n'; + +export async function dailySummaryNotification() { + const showDailyNotification = (await Settings.getInstance().getSetting( + StorageParams.DAILY_NOTIFICATION, + )) as boolean; + + if (showDailyNotification) { + const data = await useWebUsageSummaryForDay(); + if (data == null) return; + + const title = `${ + getMessagesFromLocale()['todayUsageTime']['message'] + }${convertLimitTimeToString(data.time!)}`; + const messageWithMostVisitedWebsite = + data.mostVisitedSite == undefined + ? '' + : `${data.mostVisitedSite} ${ + getMessagesFromLocale()['mostVisited']['message'] + }${convertLimitTimeToString(data.mostVisitedSiteTime!)}`; + + const message = [ + `${data.percentageFromYesterday}${getMessagesFromLocale()['comparedToYesterday']['message']}`, + messageWithMostVisitedWebsite, + ].join('\n'); + + return await useNotification(NotificationType.DailySummaryNotification, title, message); + } +} diff --git a/src/jobs/remove-time-intervals.ts b/src/jobs/remove-time-intervals.ts new file mode 100644 index 0000000..0fe83cb --- /dev/null +++ b/src/jobs/remove-time-intervals.ts @@ -0,0 +1,23 @@ +import { StorageDeserializeParam } from '../storage/storage-params'; +import { injectStorage } from '../storage/inject-storage'; +import { TimeInterval } from '../entity/time-interval'; +import { todayLocalDate } from '../utils/date'; + +export async function removeOldTimeIntervals() { + const storage = injectStorage(); + let timeIntervalList = (await storage.getDeserializeList( + StorageDeserializeParam.TIMEINTERVAL_LIST, + )) as TimeInterval[]; + if (timeIntervalList == undefined) timeIntervalList = []; + const arrayToRemove: number[] = []; + timeIntervalList.forEach(interval => { + if (new Date(interval.day) < new Date(todayLocalDate())) + arrayToRemove.push(timeIntervalList.indexOf(interval)); + }); + + arrayToRemove.forEach(index => { + if (index > -1) timeIntervalList.splice(index, 1); + }); + + await storage.saveIntervalList(timeIntervalList); +} diff --git a/src/jobs/sheduler.ts b/src/jobs/sheduler.ts new file mode 100644 index 0000000..43f4204 --- /dev/null +++ b/src/jobs/sheduler.ts @@ -0,0 +1,71 @@ +import Browser, { Alarms } from 'webextension-polyfill'; +import { log } from '../utils/logger'; +import { StorageParams } from '../storage/storage-params'; +import { DAY_MINUTES, SECOND, getNextTimeOfDay } from '../utils/time'; +import { Settings } from '../functions/settings'; +import { dailySummaryNotification } from './daily-summary-notification'; +import { removeOldTimeIntervals } from './remove-time-intervals'; +import { startOfTomorrow } from 'date-fns'; +import { Messages } from '../utils/messages'; + +export enum JobId { + DailySummaryNotification = '@alarm/daily-summary-notification', + RemoveOldTimeIntervals = '@alarm/remove-old-time-intervals', +} + +export function scheduleJobs(): void { + Browser.alarms.onAlarm.addListener(async alarm => { + log(`[schedule-jobs] Alarm ${alarm.name} triggered`, alarm); + switch (alarm.name) { + case JobId.DailySummaryNotification: { + await dailySummaryNotification(); + break; + } + case JobId.RemoveOldTimeIntervals: { + await removeOldTimeIntervals(); + break; + } + } + log(`[schedule-jobs] ${alarm.name} finished`); + }); + + Browser.runtime.onMessage.addListener(message => { + if (message == Messages.RescheduleJobs) rescheduleJobs(); + }); + + rescheduleJobs(); +} + +async function rescheduleJobs(): Promise { + log('Reschedule jobs'); + const dailySummaryNotificationTime = (await Settings.getInstance().getSetting( + StorageParams.DAILY_SUMMARY_NOTIFICATION_TIME, + )) as number; + await Browser.alarms.clear(JobId.DailySummaryNotification); + const nextTime = getNextTimeOfDay(dailySummaryNotificationTime * SECOND); + log(`[schedule-jobs] ${JobId.DailySummaryNotification} start time ${new Date(nextTime)}`); + Browser.alarms.create(JobId.DailySummaryNotification, { + when: nextTime, + periodInMinutes: DAY_MINUTES, + }); + + await createAlarmIfMissing(JobId.RemoveOldTimeIntervals, { + when: startOfTomorrow().getTime(), + periodInMinutes: DAY_MINUTES, + }); +} + +async function createAlarmIfMissing( + name: string, + alarmInfo: Alarms.CreateAlarmInfoType, +): Promise { + const existing = await Browser.alarms.get(name).catch(() => undefined); + if (existing == null) { + log( + `[schedule-jobs] ${name} start time ${ + alarmInfo.when != undefined ? new Date(alarmInfo.when) : null + }`, + ); + Browser.alarms.create(name, alarmInfo); + } +} diff --git a/src/manifest.json b/src/manifest.json index 8fbd0bd..64b8888 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -1,48 +1,37 @@ { - "manifest_version": 2, - - "name": "Web Activity Time Tracker", - "short_name": "Web Time Tracker", - "version": "1.3.4", - "minimum_chrome_version": "26", - - "description": "Track and limit time your activity in the browser every day.", - - "options_page": "options.html", - - "icons": { - "16": "icons/16x16.png", - "32": "icons/32x32.png", - "48": "icons/48x48.png", - "128": "icons/128x128.png" - }, - "permissions": [ - "tabs", - "activeTab", - "storage", - "idle", - "chrome://favicon/*", - "webNavigation", - "unlimitedStorage" - ], - "optional_permissions": [ - "https://www.youtube.com/*", - "notifications" - ], - "offline_enabled": true, - "background": { - "scripts": ["scripts/common.js", - "scripts/storage.js", - "scripts/activity.js", - "scripts/tab.js", - "scripts/timeInterval.js", - "scripts/background.js", - "scripts/restriction.js"], - "persistent": false - }, - "browser_action": { - "default_popup": "index.html", - "default_title": "Web Activity Time Tracker", - "default_icon": "icons/48x48.png" - } -} \ No newline at end of file + "manifest_version": 3, + "name": "__MSG_extName__", + "short_name": "Web Tracker", + "version": "2.2.2", + "description": "__MSG_extDescription__", + "options_page": "src/dashboard.html", + "default_locale": "en", + "icons": { + "16": "16x16.png", + "32": "32x32.png", + "48": "48x48.png", + "128": "128x128.png" + }, + "permissions": [ + "tabs", + "activeTab", + "storage", + "idle", + "unlimitedStorage", + "alarms", + "notifications", + "offscreen" + ], + "offline_enabled": true, + "background": { + "service_worker": "src/background.ts" + }, + "action": { + "default_popup": "src/popup.html", + "default_title": "Web Activity Time Tracker" + }, + "web_accessible_resources": [{ + "resources": ["assets/pomodoro-sounds/*.mp3"], + "matches": [""] + }] +} diff --git a/src/offscreen.html b/src/offscreen.html new file mode 100644 index 0000000..9c5de41 --- /dev/null +++ b/src/offscreen.html @@ -0,0 +1,14 @@ + + + + + + + Offscreen + + + + + + + diff --git a/src/offscreen.ts b/src/offscreen.ts new file mode 100644 index 0000000..b4c0574 --- /dev/null +++ b/src/offscreen.ts @@ -0,0 +1,23 @@ +import Browser from 'webextension-polyfill'; +import { Messages } from './utils/messages'; + +console.log('ofscreen'); + +Browser.runtime.onMessage.addListener(msg => { + console.log('ofscreen message'); + if (msg.message == Messages.PlayAudio) { + if (msg.offscreen == undefined) return; + + playAudio(msg.sound); + } +}); + +function playAudio(sound: string) { + const audio = document.querySelector('audio'); + if (!audio) return; + + const path = Browser.runtime.getURL(`../assets/pomodoro-sounds/${sound}`); + audio.src = path; + audio.volume = 1; + audio.play(); +} diff --git a/src/offscreen/index.ts b/src/offscreen/index.ts new file mode 100644 index 0000000..6f8fd85 --- /dev/null +++ b/src/offscreen/index.ts @@ -0,0 +1,12 @@ +import Browser from 'webextension-polyfill'; + +export async function createOffscreen() { + const path = 'src/offscreen.html'; + const offscreenUrl = Browser.runtime.getURL(path); + if (await chrome.offscreen.hasDocument()) return; + await chrome.offscreen.createDocument({ + url: offscreenUrl, + reasons: ['AUDIO_PLAYBACK'], + justification: 'Play audio sounds', + }); +} diff --git a/src/options.html b/src/options.html deleted file mode 100644 index 639111b..0000000 --- a/src/options.html +++ /dev/null @@ -1,209 +0,0 @@ - - - - - - Web Activity Time Tracker - - - - - - - - - - - - -
-
-

Web Activity Time Tracker

-
- -
-
- -
- -
- An activity is an action with a mouse or keyboard -
-
- -
-
-
- -
-
- -
- Activity for these domains not will tracked -
-
-
    -
    -
    - - -
    - -
    -
    - -
    -
    - - -
    - -
    -
    -
    - -
    -
    - -
    -
    - - - -
    -
    - - - \ No newline at end of file diff --git a/src/pages/Block.vue b/src/pages/Block.vue new file mode 100644 index 0000000..4355405 --- /dev/null +++ b/src/pages/Block.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/src/pages/Dashboard.vue b/src/pages/Dashboard.vue new file mode 100644 index 0000000..27362cb --- /dev/null +++ b/src/pages/Dashboard.vue @@ -0,0 +1,272 @@ + + + + + diff --git a/src/pages/Popup.vue b/src/pages/Popup.vue new file mode 100644 index 0000000..51d8460 --- /dev/null +++ b/src/pages/Popup.vue @@ -0,0 +1,190 @@ + + + + + diff --git a/src/pages/Welcome.vue b/src/pages/Welcome.vue new file mode 100644 index 0000000..67e57e2 --- /dev/null +++ b/src/pages/Welcome.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts new file mode 100644 index 0000000..dfc5ada --- /dev/null +++ b/src/plugins/i18n.ts @@ -0,0 +1,35 @@ +import { createI18n } from 'vue-i18n'; +import Browser from 'webextension-polyfill'; +import en from '../_locales/en/messages.json'; +import ru from '../_locales/ru/messages.json'; +import de from '../_locales/de/messages.json'; +import zh from '../_locales/zh_CN/messages.json'; +import es from '../_locales/es/messages.json'; +import ja from '../_locales/ja/messages.json'; + +const locales = { + en, + ru, + de, + zh, + es, + ja, +}; + +export type Languages = keyof typeof locales; + +const i18n = createI18n({ + legacy: false, + locale: Browser.i18n.getUILanguage(), + fallbackLocale: 'en', + globalInjection: true, + messages: locales, +}); + +export default i18n; + +export function getMessagesFromLocale() { + let locale = i18n.global.locale.value; + if (Object.keys(locales).indexOf(locale) == -1) locale = 'en'; + return i18n.global.getLocaleMessage(locale); +} diff --git a/src/popup.html b/src/popup.html new file mode 100644 index 0000000..6fa1948 --- /dev/null +++ b/src/popup.html @@ -0,0 +1,17 @@ + + + + + + + Popup + + + + + + + + + + diff --git a/src/popup.ts b/src/popup.ts new file mode 100644 index 0000000..42ccbf5 --- /dev/null +++ b/src/popup.ts @@ -0,0 +1,10 @@ +import Popup from './pages/Popup.vue'; +import VueDatePicker from '@vuepic/vue-datepicker'; +import '@vuepic/vue-datepicker/dist/main.css'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Popup); +app.component('VueDatePicker', VueDatePicker); +app.use(i18n); +app.mount('body'); diff --git a/src/repository/inject-tabs-repository.ts b/src/repository/inject-tabs-repository.ts new file mode 100644 index 0000000..44de742 --- /dev/null +++ b/src/repository/inject-tabs-repository.ts @@ -0,0 +1,21 @@ +import { ITabsRepository } from './tabs-repository-interface'; +import { TabsRepository } from './tabs-repository'; + +let instanse: ITabsRepository | null = null; + +async function createAndInitInstance() { + let repo = new TabsRepository(); + await repo.initAsync(); + return repo; +} + +export async function injectTabsRepositorySingleton(): Promise { + if (instanse == null) { + instanse = await createAndInitInstance(); + } + return instanse; +} + +export async function injectTabsRepository(): Promise { + return createAndInitInstance(); +} diff --git a/src/repository/tabs-repository-interface.ts b/src/repository/tabs-repository-interface.ts new file mode 100644 index 0000000..9f708c7 --- /dev/null +++ b/src/repository/tabs-repository-interface.ts @@ -0,0 +1,10 @@ +import { Tab } from '../entity/tab'; + +export interface ITabsRepository { + initAsync(): void; + getTabs(): Tab[]; + removeAllTabs(): void; + getTodayTabs(): Tab[]; + getTab(domain: string): Tab | undefined; + addTab(domain: string): Promise; +} diff --git a/src/repository/tabs-repository.ts b/src/repository/tabs-repository.ts new file mode 100644 index 0000000..740dd13 --- /dev/null +++ b/src/repository/tabs-repository.ts @@ -0,0 +1,48 @@ +import { ITabsRepository } from './tabs-repository-interface'; +import { Tab } from '../entity/tab'; +import { injectStorage } from '../storage/inject-storage'; +import { isInBlackList } from '../functions/black-list'; +import { StorageDeserializeParam } from '../storage/storage-params'; +import { todayLocalDate } from '../utils/date'; + +export class TabsRepository implements ITabsRepository { + private tabs: Tab[]; + + constructor() { + this.tabs = []; + } + + async initAsync() { + this.tabs = (await injectStorage().getDeserializeList(StorageDeserializeParam.TABS)) as Tab[]; + } + + getTabs(): Tab[] { + return this.tabs; + } + + removeAllTabs(): void { + this.tabs = []; + } + + getTodayTabs(): Tab[] { + return this.tabs.filter(x => x.days.find(s => s.date === todayLocalDate())); + } + + getTab(domain: string): Tab | undefined { + return this.tabs?.find(x => x.url === domain); + } + + async addTab(domain: string): Promise { + const tabFromStorage = this.getTab(domain); + const isInBlackListFlag = await isInBlackList(domain); + + if (!isInBlackListFlag && !tabFromStorage) { + const newTab = new Tab(); + newTab.init(domain); + this.tabs.push(newTab); + return newTab; + } + + return undefined; + } +} diff --git a/src/scripts/activity.js b/src/scripts/activity.js deleted file mode 100644 index 15a562e..0000000 --- a/src/scripts/activity.js +++ /dev/null @@ -1,155 +0,0 @@ -'use strict'; - -class Activity { - addTab(tab) { - if (this.isValidPage(tab) === true) { - if (tab.id && (tab.id != 0)) { - tabs = tabs || []; - var domain = this.extractHostname(tab.url); - var isDifferentUrl = false; - if (currentTab !== tab.url) { - isDifferentUrl = true; - } - - if (this.isNewUrl(domain) && !this.isInBlackList(domain)) { - var favicon = tab.favIconUrl; - if (favicon === undefined) { - favicon = 'chrome://favicon/' + domain; - } - var newTab = new Tab(domain, favicon); - tabs.push(newTab); - } - - if (isDifferentUrl && !this.isInBlackList(domain)) { - this.setCurrentActiveTab(domain); - var tabUrl = this.getTab(domain); - if (tabUrl !== undefined) - tabUrl.incCounter(); - this.addTimeInterval(domain); - } - } - } else this.closeIntervalForCurrentTab(); - } - - isValidPage(tab) { - if (!tab || !tab.url || (tab.url.indexOf('http:') == -1 && tab.url.indexOf('https:') == -1) - || tab.url.indexOf('chrome://') !== -1 - || tab.url.indexOf('chrome-extension://') !== -1) - return false; - return true; - } - - isInBlackList(domain) { - if (setting_black_list !== undefined && setting_black_list.length > 0) - return setting_black_list.find(o => isDomainEquals(this.extractHostname(o), this.extractHostname(domain))) !== undefined; - else return false; - } - - isLimitExceeded(domain, tab) { - if (setting_restriction_list !== undefined && setting_restriction_list.length > 0) { - var item = setting_restriction_list.find(o => isDomainEquals(this.extractHostname(o.domain), this.extractHostname(domain))); - if (item !== undefined) { - var today = new Date().toLocaleDateString("en-US"); - var data = tab.days.find(x => x.date == today); - if (data !== undefined) { - var todayTimeUse = data.summary; - if (todayTimeUse >= item.time) { - return true; - } - } - } - } - return false; - } - - isNewUrl(domain) { - if (tabs.length > 0) - return tabs.find(o => o.url === domain) === undefined; - else return true; - } - - getTab(domain) { - if (tabs !== undefined) - return tabs.find(o => o.url === domain); - } - - extractHostname(url) { - var hostname; - - if (url.indexOf("//") > -1) { - hostname = url.split('/')[2]; - } - else { - hostname = url.split('/')[0]; - } - - hostname = hostname.split(':')[0]; - hostname = hostname.split('?')[0]; - - return hostname; - } - - updateFavicon(tab) { - var domain = this.extractHostname(tab.url); - var currentTab = this.getTab(domain); - if (currentTab !== null && currentTab !== undefined) { - if (tab.favIconUrl !== undefined && tab.favIconUrl !== currentTab.favicon) { - currentTab.favicon = tab.favIconUrl; - } - } - } - - setCurrentActiveTab(domain) { - this.closeIntervalForCurrentTab(); - currentTab = domain; - this.addTimeInterval(domain); - } - - clearCurrentActiveTab() { - this.closeIntervalForCurrentTab(); - currentTab = ''; - } - - addTimeInterval(domain) { - var item = timeIntervalList.find(o => o.domain === domain && o.day == new Date().toLocaleDateString("en-US")); - if (item != undefined) { - if (item.day == new Date().toLocaleDateString("en-US")) - item.addInterval(); - else { - var newInterval = new TimeInterval(new Date().toLocaleDateString("en-US"), domain); - newInterval.addInterval(); - timeIntervalList.push(newInterval); - } - } else { - var newInterval = new TimeInterval(new Date().toLocaleDateString("en-US"), domain); - newInterval.addInterval(); - timeIntervalList.push(newInterval); - } - } - - closeIntervalForCurrentTab() { - if (currentTab !== '') { - var item = timeIntervalList.find(o => o.domain === currentTab && o.day == new Date().toLocaleDateString("en-US")); - if (item != undefined) - item.closeInterval(); - } - currentTab = ''; - } - - isNeedNotifyView(domain, tab){ - if (setting_notification_list !== undefined && setting_notification_list.length > 0) { - var item = setting_notification_list.find(o => isDomainEquals(this.extractHostname(o.domain), this.extractHostname(domain))); - if (item !== undefined) { - var today = new Date().toLocaleDateString("en-US"); - var data = tab.days.find(x => x.date == today); - if (data !== undefined) { - var todayTimeUse = data.summary; - if (todayTimeUse == item.time || todayTimeUse % item.time == 0) { - return true; - } - } - } - } - return false; - } -}; \ No newline at end of file diff --git a/src/scripts/background.js b/src/scripts/background.js deleted file mode 100644 index ed691d6..0000000 --- a/src/scripts/background.js +++ /dev/null @@ -1,357 +0,0 @@ -'use strict'; - -var tabs; -var timeIntervalList; -var currentTab; -var isNeedDeleteTimeIntervalFromTabs = false; -var activity = new Activity(); -var storage = new LocalStorage(); - -var setting_black_list; -var setting_restriction_list; -var setting_interval_save; -var setting_interval_inactivity; -var setting_view_in_badge; -var setting_notification_list; -var setting_notification_message; - -var isHasPermissioForYouTube; -var isHasPermissioForNotification; - -function updateSummaryTime() { - setInterval(backgroundCheck, SETTINGS_INTERVAL_CHECK_DEFAULT); -} - -function updateStorage() { - setInterval(backgroundUpdateStorage, SETTINGS_INTERVAL_SAVE_STORAGE_DEFAULT); -} - -function backgroundCheck() { - chrome.windows.getLastFocused({ populate: true }, function (currentWindow) { - if (currentWindow.focused) { - var activeTab = currentWindow.tabs.find(t => t.active === true); - if (activeTab !== undefined && activity.isValidPage(activeTab)) { - var activeUrl = activity.extractHostname(activeTab.url); - var tab = activity.getTab(activeUrl); - if (tab === undefined) { - activity.addTab(activeTab); - } - - if (activity.isInBlackList(activeUrl)) { - chrome.browserAction.setBadgeBackgroundColor({ color: '#FF0000' }) - chrome.browserAction.setBadgeText({ - tabId: activeTab.id, - text: 'n/a' - }); - } else { - if (tab !== undefined) { - if (currentTab !== tab.url) { - activity.setCurrentActiveTab(tab.url); - } - chrome.idle.queryState(parseInt(setting_interval_inactivity), function (state) { - if (state === 'active') { - mainTRacker(activeUrl, tab, activeTab); - } - else checkDOM(state, activeUrl, tab, activeTab); - }); - } - } - } - } else activity.closeIntervalForCurrentTab(); - }); -} - -function mainTRacker(activeUrl, tab, activeTab) { - if (activity.isLimitExceeded(activeUrl, tab)) { - setBlockPageToCurrent(activeUrl); - } - if (!activity.isInBlackList(activeUrl)) { - if (activity.isNeedNotifyView(activeUrl, tab)) { - if (isHasPermissioForNotification) { - showNotification(activeUrl, tab); - } else { - checkPermissionsForNotifications(showNotification, activeUrl, tab); - } - } - tab.incSummaryTime(); - } - if (setting_view_in_badge === true) { - chrome.browserAction.setBadgeBackgroundColor({ color: [0, 0, 0, 0] }) - var today = new Date().toLocaleDateString("en-US"); - var summary = tab.days.find(s => s.date === today).summary; - chrome.browserAction.setBadgeText({ - tabId: activeTab.id, - text: String(convertSummaryTimeToBadgeString(summary)) - }); - } else { - chrome.browserAction.setBadgeBackgroundColor({ color: [0, 0, 0, 0] }) - chrome.browserAction.setBadgeText({ - tabId: activeTab.id, - text: '' - }); - } -} - -function showNotification(activeUrl, tab) { - chrome.notifications.clear('watt-site-notification', function (wasCleared) { - if (!wasCleared) { - console.log('!wasCleared'); - - chrome.notifications.create( - 'watt-site-notification', { - type: 'basic', - iconUrl: 'icons/128x128.png', - title: "Web Activity Time Tracker", - contextMessage: activeUrl + ' ' + convertShortSummaryTimeToString(tab.getTodayTime()), - message: setting_notification_message - }, function (notificationId) { - console.log(notificationId); - chrome.notifications.clear('watt-site-notification', function (wasCleared) { - if (wasCleared) - notificationAction(activeUrl, tab); - }); - }); - } else { - notificationAction(activeUrl, tab); - } - }); -} - -function notificationAction(activeUrl, tab){ - chrome.notifications.create( - 'watt-site-notification', { - type: 'basic', - iconUrl: 'icons/128x128.png', - title: "Web Activity Time Tracker", - contextMessage: activeUrl + ' ' + convertShortSummaryTimeToString(tab.getTodayTime()), - message: setting_notification_message - }); -} - -function setBlockPageToCurrent(activeUrl) { - var blockUrl = chrome.runtime.getURL("block.html") + '?url=' + activeUrl; - chrome.tabs.query({ currentWindow: true, active: true }, function (tab) { - chrome.tabs.update(tab.id, { url: blockUrl }); - }); -} - -function isVideoPlayedOnPage() { - var videoElement = document.getElementsByTagName('video')[0]; - if (videoElement !== undefined && videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2) { - return true; - } - else return false; -} - -function checkDOM(state, activeUrl, tab, activeTab) { - if (state === 'idle' && isDomainEquals(activeUrl, "youtube.com")) { - trackForYT(mainTRacker, activeUrl, tab, activeTab); - } - else activity.closeIntervalForCurrentTab(); -} - -function trackForYT(callback, activeUrl, tab, activeTab) { - if (isHasPermissioForYouTube) { - executeScript(callback, activeUrl, tab, activeTab); - } else { - checkPermissionsForYT(executeScript, activity.closeIntervalForCurrentTab, callback, activeUrl, tab, activeTab); - } -} - -function executeScript(callback, activeUrl, tab, activeTab) { - chrome.tabs.executeScript({ code: "var videoElement = document.getElementsByTagName('video')[0]; (videoElement !== undefined && videoElement.currentTime > 0 && !videoElement.paused && !videoElement.ended && videoElement.readyState > 2);" }, (results) => { - if (results !== undefined && results[0] !== undefined && results[0] === true) - callback(activeUrl, tab, activeTab); - else activity.closeIntervalForCurrentTab(); - }); -} - -function backgroundUpdateStorage() { - if (tabs != undefined && tabs.length > 0) - storage.saveTabs(tabs); - if (timeIntervalList != undefined && timeIntervalList.length > 0) - storage.saveValue(STORAGE_TIMEINTERVAL_LIST, timeIntervalList); -} - -function setDefaultSettings() { - storage.saveValue(SETTINGS_INTERVAL_INACTIVITY, SETTINGS_INTERVAL_INACTIVITY_DEFAULT); - storage.saveValue(SETTINGS_INTERVAL_RANGE, SETTINGS_INTERVAL_RANGE_DEFAULT); - storage.saveValue(SETTINGS_VIEW_TIME_IN_BADGE, SETTINGS_VIEW_TIME_IN_BADGE_DEFAULT); - storage.saveValue(SETTINGS_INTERVAL_SAVE_STORAGE, SETTINGS_INTERVAL_SAVE_STORAGE_DEFAULT); - storage.saveValue(STORAGE_NOTIFICATION_MESSAGE, STORAGE_NOTIFICATION_MESSAGE_DEFAULT); -} - -function checkSettingsImEmpty() { - chrome.storage.local.getBytesInUse(['inactivity_interval'], function (item) { - if (item == 0) { - setDefaultSettings(); - } - }); -} - -function setDefaultValueForNewSettings() { - loadNotificationMessage(); -} - -function addListener() { - chrome.tabs.onActivated.addListener(function (info) { - chrome.tabs.get(info.tabId, function (tab) { - activity.addTab(tab); - }); - }); - - chrome.webNavigation.onCompleted.addListener(function (details) { - chrome.tabs.get(details.tabId, function (tab) { - activity.updateFavicon(tab); - }); - }); - chrome.runtime.onInstalled.addListener(function (details) { - if (details.reason == 'install') { - setDefaultSettings(); - } - if (details.reason == 'update') { - checkSettingsImEmpty(); - setDefaultValueForNewSettings(); - isNeedDeleteTimeIntervalFromTabs = true; - } - }); - chrome.storage.onChanged.addListener(function (changes, namespace) { - for (var key in changes) { - if (key === STORAGE_BLACK_LIST) { - loadBlackList(); - } - if (key === STORAGE_RESTRICTION_LIST) { - loadRestrictionList(); - } - if (key === STORAGE_NOTIFICATION_LIST) { - loadNotificationList(); - } - if (key === STORAGE_NOTIFICATION_MESSAGE) { - loadNotificationMessage(); - } - if (key === SETTINGS_INTERVAL_INACTIVITY) { - storage.getValue(SETTINGS_INTERVAL_INACTIVITY, function (item) { setting_interval_inactivity = item; }); - } - if (key === SETTINGS_VIEW_TIME_IN_BADGE) { - storage.getValue(SETTINGS_VIEW_TIME_IN_BADGE, function (item) { setting_view_in_badge = item; }); - } - } - }); - - chrome.runtime.setUninstallURL("https://docs.google.com/forms/d/e/1FAIpQLSdImHtvey6sg5mzsQwWfAQscgZOOV52blSf9HkywSXJhuQQHg/viewform"); -} - -function loadTabs() { - storage.loadTabs(STORAGE_TABS, function (items) { - tabs = []; - if (items != undefined) { - for (var i = 0; i < items.length; i++) { - tabs.push(new Tab(items[i].url, items[i].favicon, items[i].days, items[i].summaryTime, items[i].counter)); - } - if (isNeedDeleteTimeIntervalFromTabs) - deleteTimeIntervalFromTabs(); - } - }); -} - -function deleteTimeIntervalFromTabs() { - tabs.forEach(function (item) { - item.days.forEach(function (day) { - if (day.time != undefined) - day.time = []; - }) - }) -} - -function deleteYesterdayTimeInterval() { - timeIntervalList = timeIntervalList.filter(x => x.day == new Date().toLocaleDateString("en-US")); -} - -function loadBlackList() { - storage.getValue(STORAGE_BLACK_LIST, function (items) { - setting_black_list = items; - }) -} - -function loadTimeIntervals() { - storage.getValue(STORAGE_TIMEINTERVAL_LIST, function (items) { - timeIntervalList = []; - if (items != undefined) { - for (var i = 0; i < items.length; i++) { - timeIntervalList.push(new TimeInterval(items[i].day, items[i].domain, items[i].intervals)); - } - deleteYesterdayTimeInterval(); - } - }); -} - -function loadRestrictionList() { - storage.getValue(STORAGE_RESTRICTION_LIST, function (items) { - setting_restriction_list = items; - }) -} - -function loadNotificationList() { - storage.getValue(STORAGE_NOTIFICATION_LIST, function (items) { - setting_notification_list = items; - }); -} - -function loadNotificationMessage() { - storage.getValue(STORAGE_NOTIFICATION_MESSAGE, function (item) { - setting_notification_message = item; - if (isEmpty(setting_notification_message)) { - storage.saveValue(STORAGE_NOTIFICATION_MESSAGE, STORAGE_NOTIFICATION_MESSAGE_DEFAULT); - setting_notification_message = STORAGE_NOTIFICATION_MESSAGE_DEFAULT; - } - }); -} - -function loadSettings() { - storage.getValue(SETTINGS_INTERVAL_INACTIVITY, function (item) { setting_interval_inactivity = item; }); - storage.getValue(SETTINGS_VIEW_TIME_IN_BADGE, function (item) { setting_view_in_badge = item; }); -} - -function loadAddDataFromStorage() { - loadTabs(); - loadTimeIntervals(); - loadBlackList(); - loadRestrictionList(); - loadNotificationList(); - loadNotificationMessage(); - loadSettings(); -} - -function loadPermissions() { - checkPermissionsForYT(); - checkPermissionsForNotifications(); -} - -function checkPermissionsForYT(callbackIfTrue, callbackIfFalse, ...props) { - chrome.permissions.contains({ - permissions: ['tabs'], - origins: ["https://www.youtube.com/*"] - }, function (result) { - if (callbackIfTrue != undefined && result) - callbackIfTrue(...props); - if (callbackIfFalse != undefined && !result) - callbackIfFalse(); - isHasPermissioForYouTube = result; - }); -} - -function checkPermissionsForNotifications(callback, ...props) { - chrome.permissions.contains({ - permissions: ["notifications"] - }, function (result) { - if (callback != undefined && result) - callback(...props); - isHasPermissioForNotification = result; - }); -} - -loadPermissions(); -addListener(); -loadAddDataFromStorage(); -updateSummaryTime(); -updateStorage(); \ No newline at end of file diff --git a/src/scripts/block.js b/src/scripts/block.js deleted file mode 100644 index 97c8c80..0000000 --- a/src/scripts/block.js +++ /dev/null @@ -1,18 +0,0 @@ -var storage = new LocalStorage(); -var restrictionList = []; - -document.addEventListener('DOMContentLoaded', function () { - var url = new URL(document.URL); - var blockSiteUrl = url.searchParams.get("url"); - document.getElementById('site').innerText = blockSiteUrl; - - storage.getValue(STORAGE_RESTRICTION_LIST, function (items) { - restrictionList = items; - if (restrictionList === undefined) - restrictionList = []; - var currentItem = restrictionList.find(x => isDomainEquals(x.domain, blockSiteUrl)); - if (currentItem !== undefined){ - document.getElementById('limit').innerText = convertShortSummaryTimeToString(currentItem.time); - } - }); -}); \ No newline at end of file diff --git a/src/scripts/chart/chart-core.js b/src/scripts/chart/chart-core.js deleted file mode 100644 index b0374fb..0000000 --- a/src/scripts/chart/chart-core.js +++ /dev/null @@ -1,476 +0,0 @@ -function donutChart() { - var width, - height, - margin = { top: 10, right: 10, bottom: 10, left: 10 }, - colour = d3.scaleOrdinal(d3.schemeCategory20), // colour scheme - variable, // value in data that will dictate proportions on chart - category, // compare data by - padAngle, // effectively dictates the gap between slices - floatFormat = d3.format('.4r'), - cornerRadius, // sets how rounded the corners are on each slice - percentFormat = d3.format(',.2%'); - - function chart(selection) { - selection.each(function (data) { - // generate chart - - // =========================================================================================== - // Set up constructors for making donut. See https://github.com/d3/d3-shape/blob/master/README.md - var radius = 135; - - // creates a new pie generator - var pie = d3.pie() - .value(function (d) { return floatFormat(d[variable]); }) - .sort(null); - - // contructs and arc generator. This will be used for the donut. The difference between outer and inner - // radius will dictate the thickness of the donut - var arc = d3.arc() - .outerRadius(radius * 0.9) - .innerRadius(radius * 0.6) - .cornerRadius(cornerRadius) - .padAngle(padAngle); - - // this arc is used for aligning the text labels - var outerArc = d3.arc() - .outerRadius(radius * 0.9) - .innerRadius(radius * 0.9); - // =========================================================================================== - - var tempAngle; - var tempOffset = { - x: 1, - y: 0.95 - }; - // =========================================================================================== - // append the svg object to the selection - var svg = selection.append('svg') - .attr('width', width + margin.left + margin.right) - .attr('height', height + margin.top + margin.bottom) - .attr('class', 'backColorChart') - .append('g') - .attr('transform', 'translate(' + (width / 2 - 105) + ',' + (height / 2 + 12) + ')'); - // =========================================================================================== - - // =========================================================================================== - // g elements to keep elements within svg modular - svg.append('g').attr('class', 'slices'); - svg.append('g').attr('class', 'labelName'); - svg.append('g').attr('class', 'lines'); - // =========================================================================================== - - // =========================================================================================== - // add and colour the donut slices - var path = svg.select('.slices') - .datum(data).selectAll('path') - .data(pie) - .enter().append('path') - .attr('fill', function (d) { return colour(d.data[category]); }) - .attr('d', arc) - .attr('id', function (d) { return d.data[category]; }); - // =========================================================================================== - - var legendG = svg.selectAll(".legend") // note appending it to mySvg and not svg to make positioning easier - .data(pie(data)) - .enter().append("g") - .attr("transform", function (d, i) { - return "translate(" + (130) + "," + (i * 20 - 80) + ")"; // place each legend on the right and bump each one down 15 pixels - }) - .attr("class", "legend"); - - legendG.append("rect") // make a matching color rect - .attr("width", 10) - .attr("height", 10) - .attr("fill", function (d, i) { - return colour(d.data[category]); - }); - - legendG.append("text") // add the text - .text(function (d) { - return d.data.url; - }) - .style("font-size", 13) - .attr("y", 10) - .attr("x", 13); - - // =========================================================================================== - // add tooltip to mouse events on slices and labels - d3.selectAll('.labelName text, .slices path').call(toolTip); - // =========================================================================================== - - // =========================================================================================== - // Functions - - // calculates the angle for the middle of a slice - function midAngle(d) { return d.startAngle + (d.endAngle - d.startAngle) / 2; } - - // function that creates and adds the tool tip to a selected element - function toolTip(selection) { - - // add tooltip (svg circle element) when mouse enters label or slice - selection.on('mouseenter', function (data) { - d3.selectAll('.toolCircle').remove(); - svg.append('text') - .attr('class', 'toolCircle') - .attr('dy', -15) // hard-coded. can adjust this to adjust text vertical alignment in tooltip - .html(toolTipHTML(data)) // add text to the circle. - .style('font-size', '.9em') - .style('text-anchor', 'middle'); // centres text in tooltip - - svg.append('circle') - .attr('class', 'toolCircle') - .attr('r', radius * 0.55) // radius of tooltip circle - .style('fill', colour(data.data[category])) // colour based on category mouse is over - .style('fill-opacity', 0.35); - - }); - - // remove the tooltip when mouse leaves the slice/label - // selection.on('mouseout', function () { - // d3.selectAll('.toolCircle').remove(); - // }); - } - - // function to create the HTML string for the tool tip. Loops through each key in data object - // and returns the html string key: value - function toolTipHTML(data) { - - var tip = '', - i = 0; - - for (var key in data.data) { - - // if value is a number, format it as a percentage - var value = (!isNaN(parseFloat(data.data[key]))) ? percentFormat(data.data[key]) : data.data[key]; - if (key === 'summary') - value = convertSummaryTimeToString(data.data[key]); - if (key === 'visits' && data.data[key] !== undefined) - value = data.data[key] + ' visits'; - var className = ''; - if (key === 'percentage') - className = 'class="percentageValue"'; - - // leave off 'dy' attr for first tspan so the 'dy' attr on text element works. The 'dy' attr on - // tspan effectively imitates a line break. - if (i === 0) tip += '' + value + ''; - else tip += '' + value + ''; - i++; - } - - return tip; - } - - function angleIsInRangeDifference(tempAngle, currentAngle, difference) { - return currentAngle < (tempAngle + difference) && currentAngle > (tempAngle - difference); - } - // =========================================================================================== - - }); - } - - chart.width = function (value) { - if (!arguments.length) return width; - width = value; - return chart; - }; - - chart.height = function (value) { - if (!arguments.length) return height; - height = value; - return chart; - }; - - chart.margin = function (value) { - if (!arguments.length) return margin; - margin = value; - return chart; - }; - - chart.radius = function (value) { - if (!arguments.length) return radius; - radius = value; - return chart; - }; - - chart.padAngle = function (value) { - if (!arguments.length) return padAngle; - padAngle = value; - return chart; - }; - - chart.cornerRadius = function (value) { - if (!arguments.length) return cornerRadius; - cornerRadius = value; - return chart; - }; - - chart.colour = function (value) { - if (!arguments.length) return colour; - colour = value; - return chart; - }; - - chart.variable = function (value) { - if (!arguments.length) return variable; - variable = value; - return chart; - }; - - chart.category = function (value) { - if (!arguments.length) return category; - category = value; - return chart; - }; - - return chart; -} - -function barChart(data) { - var margin = { top: 25, right: 5, bottom: 25, left: 5 }, - width = 555, - height = 160; - - // set the ranges - var x = d3.scaleBand() - .range([0, width]) - .padding(0.1); - var y = d3.scaleLinear() - .range([height, 0]); - - // append the svg object to the body of the page - // append a 'group' element to 'svg' - // moves the 'group' element to the top left margin - var svg = d3.select("#barChart").append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", - "translate(" + margin.left + "," + margin.top + ")"); - - var tip = d3.tip() - .attr('class', 'd3-tip') - .offset([-10, 0]) - .html(function (d) { - if (data.length > 9) - return "" + new Date(d.date).toLocaleDateString() + "
    " + convertShortSummaryTimeToString(d.total) + ""; - else - return "" + convertShortSummaryTimeToString(d.total) + ""; - }); - - svg.call(tip); - - // Scale the range of the data in the domains - x.domain(data.map(function (d) { return new Date(d.date).toLocaleDateString(); })); - y.domain([0, d3.max(data, function (d) { return d.total; })]); - - // append the rectangles for the bar chart - svg.selectAll(".bar") - .data(data) - .enter().append("rect") - .attr("class", "bar") - .attr("x", function (d) { return x(new Date(d.date).toLocaleDateString()); }) - .attr("width", x.bandwidth()) - .attr("y", function (d) { return y(d.total); }) - .attr("height", function (d) { return height - y(d.total); }) - .on('mouseover', tip.show) - .on('mouseout', tip.hide); - - // add the x Axis - svg.append("g") - .attr("transform", "translate(0," + height + ")") - .call(d3.axisBottom(x)); - - if (data.length > 9) - document.querySelectorAll('#barChart g.tick ').forEach(element => { element.remove() }); -} - -function drawIntervalChart(data) { - data.forEach(function (item) { - var hFrom = getHourFrom(item.interval); - var hTo = getHourTo(item.interval); - if (hFrom != hTo) { - var sourceTimeFrom = item.interval.split('-')[0].split(':'); - var sourceTimeTo = item.interval.split('-')[1].split(':'); - var timeTo = sourceTimeFrom[0] + ":" + 59 + ":" + 59; - var timeFrom = sourceTimeTo[0] + ":" + 00 + ":" + 00; - data.push({ "domain": item.domain, "interval": item.interval.split('-')[0] + "-" + timeTo }); - data.push({ "domain": item.domain, "interval": timeFrom + "-" + item.interval.split('-')[1] }); - } - }); - - var margin = { top: 5, right: 10, bottom: 20, left: 20 }, - width = 580 - margin.left - margin.right, - height = 410 - margin.top - margin.bottom; - - //linear 24 hour scale - var y = d3.scaleLinear() - .domain([0, 60]) - .range([height, 0]); - - //vertical axis - var yAxis = d3.axisLeft() - .ticks(10) - .scale(y); - - var x = d3.scaleLinear() - .domain([0, 24]) - .range([0, width]); - - //vertical axis - var xAxis = d3.axisBottom() - .ticks(24) - .scale(x) - - var tickDistance = 4.38; - - var tooltip = d3.select("#timeChart") - .append("div") - .style("opacity", 0) - .style("display", "none") - .style("position", "absolute") - .attr("class", "tooltip") - .style("background-color", "white") - .style("border", "solid") - .style("border-width", "1px") - .style("border-radius", "5px") - .style("padding", "5px") - - // Three function that change the tooltip when user hover / move / leave a cell - var mouseover = function (d) { - tooltip - .style("opacity", 1) - .style("display", "block") - d3.select(this) - .style("stroke", "black") - .style("stroke-width", "0.5px") - .style("opacity", 1) - } - var mousemove = function (d) { - tooltip - .html(d.domain + "
    " + d.interval) - .style("left", (d3.mouse(this)[0]) + 10 + "px") - .style("top", (d3.mouse(this)[1]) + 30 + "px") - } - var mouseleave = function (d) { - tooltip - .style("opacity", 0) - .style("display", "none") - d3.select(this) - .style("stroke", "none") - .style("opacity", 0.8) - } - - //create the svg - var svg = d3.select("#timeChart").append("svg") - .attr("width", width + margin.left + margin.right) - .attr("height", height + margin.top + margin.bottom) - .append("g") - .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); - - //draw the axis. - svg.append("g") - .attr("class", "x axis") - .attr("transform", "translate(0," + height + ")") - .attr("class", "label") - .call(xAxis) - .append("text") - .text("Value"); - - // Add a y-axis with label. - svg.append("g") - .attr("class", "y axis") - .call(yAxis) - .append("text") - .attr("class", "label") - .attr("y", 6) - .attr("dy", ".71em") - .attr("text-anchor", "end") - .attr("transform", "rotate(-90)") - .text("Value"); - - svg.append("g") - .attr("class", "grid") - .attr("transform", "translate(0," + height + ")") - .call(make_x_axis() - .tickSize(-height, 0, 0) - ) - - svg.append("g") - .attr("class", "grid") - .call(make_y_axis() - .tickSize(-width, 0, 0) - ) - - //draw the bars, offset y and bar height based on data - svg.selectAll(".bar") - .data(data) - .enter() - .append("rect") - .style("fill", "orangered") - .style("stroke", "#f1f1f1") - .style("stroke-width", "1") - .attr("class", "bar") - .attr("x", function (d) { - return x(getHourFrom(d.interval)) + 2; - }) - .attr("width", 20) - .attr("y", function (d) { - return y(getMinutesTo(d.interval)) - 1; - }) - .attr("height", function (d) { - var offset = getMinutesTo(d.interval) - getMinutesFrom(d.interval); - if (offset == 0){ - var offsetSeconds = getSecondsTo(d.interval) - getSecondsFrom(d.interval); - if (offsetSeconds <= 3) - return 0; - else - return 1; - } - else return offset * tickDistance; - }) - .on("mouseover", mouseover) - .on("mousemove", mousemove) - .on("mouseleave", mouseleave); - - function make_x_axis() { - return d3.axisBottom() - .scale(x) - .ticks(24) - } - - function make_y_axis() { - return d3.axisLeft() - .scale(y) - .ticks(10) - } - - function getHourFrom(interval) { - var time = interval.split('-')[0]; - return time.split(':')[0]; - } - - function getHourTo(interval) { - var time = interval.split('-')[1]; - return time.split(':')[0]; - } - - function getMinutesFrom(interval) { - var time = interval.split('-')[0]; - return time.split(':')[1]; - } - - function getMinutesTo(interval) { - var time = interval.split('-')[1]; - return time.split(':')[1]; - } - - function getSecondsFrom(interval) { - var time = interval.split('-')[0]; - return time.split(':')[2]; - } - - function getSecondsTo(interval) { - var time = interval.split('-')[1]; - return time.split(':')[2]; - } -} \ No newline at end of file diff --git a/src/scripts/chart/d3.v4.min.js b/src/scripts/chart/d3.v4.min.js deleted file mode 100644 index 97ea67c..0000000 --- a/src/scripts/chart/d3.v4.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n(t.d3=t.d3||{})}(this,function(I){"use strict";function a(t,n){return t>>1;o(t[i],n)<0?e=i+1:r=i}return e},right:function(t,n,e,r){for(null==e&&(e=0),null==r&&(r=t.length);e>>1;0>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):(n=Xs.exec(t))?At(parseInt(n[1],16)):(n=Vs.exec(t))?new Rt(n[1],n[2],n[3],1):(n=$s.exec(t))?new Rt(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Ws.exec(t))?Ct(n[1],n[2],n[3],n[4]):(n=Zs.exec(t))?Ct(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Gs.exec(t))?Lt(n[1],n[2]/100,n[3]/100,1):(n=Qs.exec(t))?Lt(n[1],n[2]/100,n[3]/100,n[4]):Js.hasOwnProperty(t)?At(Js[t]):"transparent"===t?new Rt(NaN,NaN,NaN,0):null}function At(t){return new Rt(t>>16&255,t>>8&255,255&t,1)}function Ct(t,n,e,r){return r<=0&&(t=n=e=NaN),new Rt(t,n,e,r)}function zt(t){return t instanceof St||(t=Et(t)),t?new Rt((t=t.rgb()).r,t.g,t.b,t.opacity):new Rt}function Pt(t,n,e,r){return 1===arguments.length?zt(t):new Rt(t,n,e,null==r?1:r)}function Rt(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function Lt(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||1<=e?t=n=NaN:n<=0&&(t=NaN),new Dt(t,n,e,r)}function qt(t,n,e,r){return 1===arguments.length?function(t){if(t instanceof Dt)return new Dt(t.h,t.s,t.l,t.opacity);if(t instanceof St||(t=Et(t)),!t)return new Dt;if(t instanceof Dt)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),u=NaN,a=o-i,c=(o+i)/2;return a?(u=n===o?(e-r)/a+6*(ea&&(i=r.slice(a,i),s[c]?s[c]+=i:s[++c]=i),(n=n[0])===(e=e[0])?s[c]?s[c]+=e:s[++c]=e:(s[++c]=null,f.push({i:c,x:un(n,e)})),a=Nf.lastIndex;return ae._time&&(r=e._time),(t=e)._next):(n=e._next,e._next=null,t?t._next=n:mf=n);xf=t,Nn(r)}(),Bf=0}}function Tn(){var t=jf.now(),n=t-Yf;IfWf)throw new Error("too late; already scheduled");return e}function An(t,n){var e=Cn(t,n);if(e.state>Gf)throw new Error("too late; already started");return e}function Cn(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function zn(t,n){var e,r,i,o=t.__transition,u=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>Gf&&e.stateMath.abs(t[1]-C[1])?v=!0:d=!0),C=t,p=!0,Vn(),n()}function n(){var t;switch(l=C[0]-A[0],h=C[1]-A[1],y){case xl:case ml:m&&(l=Math.max(T-r,Math.min(k-a,l)),i=r+l,c=a+l),x&&(h=Math.max(N-o,Math.min(S-s,h)),u=o+h,f=s+h);break;case bl:m<0?(l=Math.max(T-r,Math.min(k-r,l)),i=r+l,c=a):0=o?c=!0:10===(n=r.charCodeAt(u++))?s=!0:13===n&&(s=!0,10===r.charCodeAt(u)&&++u),r.slice(e+1,t-1).replace(/""/g,'"')}for(;u=(o=(v+_)/2))?v=o:_=o,(f=e>=(u=(g+y)/2))?g=u:y=u,!(p=(i=p)[l=f<<1|s]))return i[l]=d,t;if(a=+t._x.call(null,p.data),c=+t._y.call(null,p.data),n===a&&e===c)return d.next=p,i?i[l]=d:t._root=d,t;for(;i=i?i[l]=new Array(4):t._root=new Array(4),(s=n>=(o=(v+_)/2))?v=o:_=o,(f=e>=(u=(g+y)/2))?g=u:y=u,(l=f<<1|s)==(h=(u<=c)<<1|o<=a););return i[h]=p,i[l]=d,t}function xe(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function be(t){return t[0]}function we(t){return t[1]}function Me(t,n,e){var r=new Te(null==n?be:n,null==e?we:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function Te(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Ne(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}function ke(t){return t.x+t.vx}function Se(t){return t.y+t.vy}function Ee(t){return t.index}function Ae(t,n){var e=t.get(n);if(!e)throw new Error("missing: "+n);return e}function Ce(t){return t.x}function ze(t){return t.y}function Pe(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[1i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}function qe(t){return new De(t)}function De(t){if(!(n=ih.exec(t)))throw new Error("invalid format: "+t);var n,e=n[1]||" ",r=n[2]||">",i=n[3]||"-",o=n[4]||"",u=!!n[5],a=n[6]&&+n[6],c=!!n[7],s=n[8]&&+n[8].slice(1),f=n[9]||"";"n"===f?(c=!0,f="g"):rh[f]||(f=""),(u||"0"===e&&"="===r)&&(u=!0,e="0",r="="),this.fill=e,this.align=r,this.sign=i,this.symbol=o,this.zero=u,this.width=a,this.comma=c,this.precision=s,this.type=f}function Ue(t){return t}function Oe(t){function u(t){function n(t){var n,e,r,i=_,o=y;if("c"===g)o=m(t)+o,t="";else{var u=(t=+t)<0;if(t=m(Math.abs(t),v),u&&0==+t&&(u=!1),i=(u?"("===l?l:"-":"-"===l||"("===l?"":l)+i,o=("s"===g?uh[8+nh/3]:"")+o+(u&&"("===l?")":""),x)for(n=-1,e=t.length;++n>1)+i+t+o+c.slice(a);break;default:t=c+i+t+o}return M(t)}var s=(t=qe(t)).fill,f=t.align,l=t.sign,e=t.symbol,h=t.zero,p=t.width,d=t.comma,v=t.precision,g=t.type,_="$"===e?r[0]:"#"===e&&/[boxX]/.test(g)?"0"+g.toLowerCase():"",y="$"===e?r[1]:/[%p]/.test(g)?i:"",m=rh[g],x=!g||/[defgprs%]/.test(g);return v=null==v?g?6:12:/[gprs]/.test(g)?Math.max(1,Math.min(21,v)):Math.max(0,Math.min(20,v)),n.toString=function(){return t+""},n}var n,a,c,b=t.grouping&&t.thousands?(a=t.grouping,c=t.thousands,function(t,n){for(var e=t.length,r=[],i=0,o=a[0],u=0;0n));)o=a[i=(i+1)%a.length];return r.reverse().join(c)}):Ue,r=t.currency,w=t.decimal,M=t.numerals?(n=t.numerals,function(t){return t.replace(/[0-9]/g,function(t){return n[+t]})}):Ue,i=t.percent||"%";return{format:u,formatPrefix:function(t,n){var e=u(((t=qe(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor(Re(n)/3))),i=Math.pow(10,-r),o=uh[8+r/3];return function(t){return e(i*t)+o}}}}function Fe(t){return oh=Oe(t),I.format=oh.format,I.formatPrefix=oh.formatPrefix,oh}function Ie(t){return Math.max(0,-Re(Math.abs(t)))}function Ye(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor(Re(n)/3)))-Re(Math.abs(t)))}function Be(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,Re(n)-Re(t))+1}function He(){return new je}function je(){this.reset()}function Xe(t,n,e){var r=t.s=n+e,i=r-n,o=r-i;t.t=n-o+(e-i)}function Ve(t){return 1vh&&(vh=o):s^(a*gh<(c=(c+360)%360-180)&&cyr(hh,dh)&&(dh=t):yr(t,dh)>yr(hh,dh)&&(hh=t):hh<=dh?(tyr(hh,dh)&&(dh=t):yr(t,dh)>yr(hh,dh)&&(hh=t)}else xh.push(bh=[hh=t,dh=t]);nFh&&(hh=-(dh=180)),bh[0]=hh,bh[1]=dh,mh=null}function yr(t,n){return(n-=t)<0?n+360:n}function mr(t,n){return t[0]-n[0]}function xr(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:nk}function d(t,n,e){var r=[1,0,0],i=ar(or(t),or(n)),o=ur(i,i),u=i[0],a=o-u*u;if(!a)return!e&&t;var c=k*o/a,s=-k*u/a,f=ar(r,i),l=sr(r,c);cr(l,sr(i,s));var h=f,p=ur(l,h),d=ur(h,h),v=p*p-d*(ur(l,l)-1);if(!(v<0)){var g=ep(v),_=sr(h,(-p-g)/d);if(cr(_,l),_=ir(_),!e)return _;var y,m=t[0],x=n[0],b=t[1],w=n[1];xFh;return $r(p,function(a){var c,s,f,l,h;return{lineStart:function(){l=f=!1,h=1},point:function(t,n){var e,r=[t,n],i=p(t,n),o=g?i?0:v(t,n):i?v(t+(t<0?Ih:-Ih),n):0;if(!c&&(l=f=i)&&a.lineStart(),i!==f&&(!(e=d(c,r))||Br(c,e)||Br(r,e))&&(r[0]+=Fh,r[1]+=Fh,i=p(r[0],r[1])),i!==f)h=0,i?(a.lineStart(),e=d(r,c),a.point(e[0],e[1])):(e=d(c,r),a.point(e[0],e[1]),a.lineEnd()),c=e;else if(_&&c&&g^i){var u;o&s||!(u=d(r,c,!0))||(h=0,g?(a.lineStart(),a.point(u[0][0],u[0][1]),a.point(u[1][0],u[1][1]),a.lineEnd()):(a.point(u[1][0],u[1][1]),a.lineEnd(),a.lineStart(),a.point(u[0][0],u[0][1])))}!i||c&&Br(c,r)||a.point(r[0],r[1]),c=r,f=i,s=o},lineEnd:function(){f&&a.lineEnd(),c=null},clean:function(){return h|(l&&f)<<1}}},function(t,n,e,r){Fr(r,i,o,e,t,n)},g?[0,-i]:[-Ih,i-Ih])}function Qr(_,y,m,x){function b(t,n){return _<=t&&t<=m&&y<=n&&n<=x}function w(t,n,e,r){var i=0,o=0;if(null==t||(i=u(t,e))!==(o=u(n,e))||a(t,n)<0^0Fh}).map(f)).concat(N(Gh(a/v)*v,u,v).filter(function(t){return Vh(t%_)>Fh}).map(l))}var e,r,i,o,u,a,c,s,f,l,h,p,d=10,v=d,g=90,_=360,y=2.5;return n.lines=function(){return t().map(function(t){return{type:"LineString",coordinates:t}})},n.outline=function(){return{type:"Polygon",coordinates:[h(o).concat(p(c).slice(1),h(i).reverse().slice(1),p(s).reverse().slice(1))]}},n.extent=function(t){return arguments.length?n.extentMajor(t).extentMinor(t):n.extentMinor()},n.extentMajor=function(t){return arguments.length?(o=+t[0][0],i=+t[1][0],s=+t[0][1],c=+t[1][1],id){f-=a;break}d=p}_.push(u={value:f,dice:cvg){var a=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*a-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*a-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>vg){var s=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,f=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*s+t._x1*t._l23_2a-n*t._l12_2a)/f,u=(u*s+t._y1*t._l23_2a-e*t._l12_2a)/f}t._context.bezierCurveTo(r,i,o,u,t._x2,t._y2)}function wc(t,n){this._context=t,this._alpha=n}function Mc(t,n){this._context=t,this._alpha=n}function Tc(t,n){this._context=t,this._alpha=n}function Nc(t){this._context=t}function kc(t){return t<0?-1:1}function Sc(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),u=(e-t._y1)/(i||r<0&&-0),a=(o*i+u*r)/(r+i);return(kc(o)+kc(u))*Math.min(Math.abs(o),Math.abs(u),.5*Math.abs(a))||0}function Ec(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function Ac(t,n,e){var r=t._x0,i=t._y0,o=t._x1,u=t._y1,a=(o-r)/3;t._context.bezierCurveTo(r+a,i+a*n,o-a,u-a*e,o,u)}function Cc(t){this._context=t}function zc(t){this._context=new Pc(t)}function Pc(t){this._context=t}function Rc(t){this._context=t}function Lc(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),u=new Array(r);for(o[i[0]=0]=2,u[0]=t[0]+2*t[1],n=1;n=i)return}else c=[v,e];o=[v,i]}else{if(c){if(c[1]=i)return}else c=[(e-a)/u,e];o=[(i-a)/u,i]}else{if(c){if(c[1]=r)return}else c=[n,u*n+a];o=[r,u*r+a]}else{if(c){if(c[0]Jg)a=a.L;else{if(!((i=o-function(t,n){var e=t.N;if(e)return as(e,n);var r=t.site;return r[1]===n?r[0]:1/0}(a,u))>Jg)){-JgJg||Math.abs(i[0][1]-i[1][1])>Jg)||delete Zg[o]})(u,a,c,s),function(t,n,e,r){var i,o,u,a,c,s,f,l,h,p,d,v,g,_,y=$g.length,m=!0;for(i=0;iJg||Math.abs(v-h)>Jg)&&(c.splice(a,0,Zg.push(Gc(u,p,Math.abs(d-t)h||(o=c.y0)>p||(u=c.x1)=(a=(d+g)/2))?d=a:g=a,(f=u>=(c=(v+_)/2))?v=c:_=c,!(p=(n=p)[l=f<<1|s]))return this;if(!p.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;p.data!==t;)if(!(p=(r=p).next))return this;return(i=p.next)&&delete p.next,r?i?r.next=i:delete r.next:n?(i?n[l]=i:delete n[l],(p=n[0]||n[1]||n[2]||n[3])&&p===(n[3]||n[2]||n[1]||n[0])&&!p.length&&(e?e[h]=p:this._root=p)):this._root=i,this},th.removeAll=function(t){for(var n=0,e=t.length;n=^]))?([+\-\( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?([a-z%])?$/i;qe.prototype=De.prototype,De.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(null==this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(null==this.precision?"":"."+Math.max(0,0|this.precision))+this.type};var oh,uh=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];Fe({decimal:".",thousands:",",grouping:[3],currency:["$",""]}),je.prototype={constructor:je,reset:function(){this.s=this.t=0},add:function(t){Xe(Oh,t,this.t),Xe(this,Oh.s,this.s),this.s?this.t+=Oh.t:this.s=Oh.t},valueOf:function(){return this.s}};var ah,ch,sh,fh,lh,hh,ph,dh,vh,gh,_h,yh,mh,xh,bh,wh,Mh,Th,Nh,kh,Sh,Eh,Ah,Ch,zh,Ph,Rh,Lh,qh,Dh,Uh,Oh=new je,Fh=1e-6,Ih=Math.PI,Yh=Ih/2,Bh=Ih/4,Hh=2*Ih,jh=180/Ih,Xh=Ih/180,Vh=Math.abs,$h=Math.atan,Wh=Math.atan2,Zh=Math.cos,Gh=Math.ceil,Qh=Math.exp,Jh=Math.log,Kh=Math.pow,tp=Math.sin,np=Math.sign||function(t){return 0Fh?$h((tp(r)*(a=Zh(o))*tp(i)-tp(o)*(u=Zh(r))*tp(e))/(u*a*c)):(r+o)/2,l.point(v,d),l.lineEnd(),l.lineStart(),l.point(s,d),h=0),l.point(p=t,d=n),v=s},lineEnd:function(){l.lineEnd(),p=d=NaN},clean:function(){return 2-h}}},function(t,n,e,r){var i;if(null==t)i=e*Yh,r.point(-Ih,i),r.point(0,i),r.point(Ih,i),r.point(Ih,0),r.point(Ih,-i),r.point(0,-i),r.point(-Ih,-i),r.point(-Ih,0),r.point(-Ih,i);else if(Vh(t[0]-n[0])>Fh){var o=t[0]Fh&&0<--i);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},eo.invert=Vi($e),ro.invert=Vi(function(t){return 2*$h(t)}),io.invert=function(t,n){return[-n,2*$h(Qh(t))-Yh]},po.prototype=so.prototype={constructor:po,count:function(){return this.eachAfter(co)},each:function(t){var n,e,r,i,o=this,u=[o];do{for(n=u.reverse(),u=[];o=n.pop();)if(t(o),e=o.children)for(r=0,i=e.length;r=e)return null;for(var r=u-c.site[0],i=a-c.site[1],l=r*r+i*i;c=s.cells[n=f],f=null,c.halfedges.forEach(function(t){var n=s.edges[t],e=n.left;if(e!==c.site&&e||(e=n.right)){var r=u-e[0],i=a-e[1],o=r*r+i*i;oa;)c.pop(),--s;var f,l=new Array(s+1);for(n=0;n<=s;++n)(f=l[n]=[]).x0=0=v.length)return null!=p&&t.sort(p),null!=d?d(t):t;for(var n,o,u,a=-1,c=t.length,s=v[e++],f=ce(),l=r();++av.length)return t;var i,o=u[r-1];return null!=d&&r>=v.length?i=t.entries():(i=[],t.each(function(t,n){i.push({key:n,values:e(t,r)})})),null!=o?i.sort(function(t,n){return o(t.key,n.key)}):i}(h(t,0,le,he),0)},key:function(t){return v.push(t),n},sortKeys:function(t){return u[v.length-1]=t,n},sortValues:function(t){return p=t,n},rollup:function(t){return d=t,n}}},I.set=de,I.map=ce,I.keys=function(t){var n=[];for(var e in t)n.push(e);return n},I.values=function(t){var n=[];for(var e in t)n.push(t[e]);return n},I.entries=function(t){var n=[];for(var e in t)n.push({key:e,value:t[e]});return n},I.color=Et,I.rgb=Pt,I.hsl=qt,I.lab=Ft,I.hcl=Xt,I.cubehelix=$t,I.dispatch=z,I.drag=function(){function d(t){t.on("mousedown.drag",n).filter(g).on("touchstart.drag",i).on("touchmove.drag",o).on("touchend.drag touchcancel.drag",u).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function n(){if(!l&&h.apply(this,arguments)){var t=a("mouse",p.apply(this,arguments),pt,this,arguments);t&&(ct(I.event.view).on("mousemove.drag",e,!0).on("mouseup.drag",r,!0),_t(I.event.view),vt(),f=!1,c=I.event.clientX,s=I.event.clientY,t("start"))}}function e(){if(gt(),!f){var t=I.event.clientX-c,n=I.event.clientY-s;f=xl.index){var c=h-o.x-o.vx,s=p-o.y-o.vy,f=c*c+s*s;ft.r&&(t.r=t[n].r)}function e(){if(o){var t,n,e=o.length;for(u=new Array(e),t=0;tyr(r[0],r[1])&&(r[1]=i[1]),yr(i[0],r[1])>yr(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(u=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(a=yr(r[1],i[0]))>u&&(u=a,hh=i[0],dh=r[1])}return xh=bh=null,hh===1/0||ph===1/0?[[NaN,NaN],[NaN,NaN]]:[[hh,ph],[dh,vh]]},I.geoCentroid=function(t){wh=Mh=Th=Nh=kh=Sh=Eh=Ah=Ch=zh=Ph=0,Ke(t,lp);var n=Ch,e=zh,r=Ph,i=n*n+e*e+r*r;return i<1e-12&&(n=Sh,e=Eh,r=Ah,Mhe.x&&(e=t),t.depth>r.depth&&(r=t)});var i=n===e?1:m(n,e)/2,o=i-n.x,u=h/(e.x+i+o),a=p/(r.depth||1);c.eachBefore(function(t){t.x=(t.x+o)*u,t.y=t.depth*a})}return c}function s(u){var t=u.children,n=u.parent.children,e=u.i?n[u.i-1]:null;if(t){!function(t){for(var n,e=0,r=0,i=u.children,o=i.length;0<=--o;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}();var r=(t[0].z+t[t.length-1].z)/2;e?(u.z=e.z+m(u._,e._),u.m=u.z-r):u.z=r}else e&&(u.z=e.z+m(u._,e._));u.parent.A=function(t,n,e){if(n){for(var r,i=t,o=t,u=n,a=i.parent.children[0],c=i.m,s=o.m,f=u.m,l=a.m;u=Fo(u),i=Oo(i),u&&i;)a=Oo(a),(o=Fo(o)).a=t,0<(r=u.z+f-i.z-c+m(u._,i._))&&(_=t,y=e,h=(g=u).a.parent===_.parent?g.a:y,void 0,v=(d=r)/((p=t).i-h.i),p.c-=v,p.s+=d,h.c+=v,p.z+=d,p.m+=d,c+=r,s+=r),f+=u.m,c+=i.m,l+=a.m,s+=o.m;u&&!Fo(o)&&(o.t=u,o.m+=f-s),i&&!Oo(a)&&(a.t=i,a.m+=c-l,e=t)}var h,p,d,v,g,_,y;return e}(u,e,u.parent.A||n[0])}function f(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function l(t){t.x*=h,t.y=t.depth*p}var m=Uo,h=1,p=1,d=null;return n.separation=function(t){return arguments.length?(m=t,n):m},n.size=function(t){return arguments.length?(d=!1,h=+t[0],p=+t[1],n):d?null:[h,p]},n.nodeSize=function(t){return arguments.length?(d=!0,h=+t[0],p=+t[1],n):d?[h,p]:null},n},I.treemap=function(){function n(t){return t.x0=t.y0=0,t.x1=i,t.y1=o,t.eachBefore(e),a=[0],r&&t.eachBefore(Ro),t}function e(t){var n=a[t.depth],e=t.x0+n,r=t.y0+n,i=t.x1-n,o=t.y1-n;i>>1;m[p]a!=avg?(y+=S*=p?1:-1,m-=S):(x=0,y=m=(f+l)/2),(b-=2*E)>vg?(g+=E*=p?1:-1,_-=E):(b=0,g=_=(f+l)/2)}var A=s*fg(g),C=s*pg(g),z=c*fg(m),P=c*pg(m);if(vgZf&&e.name===n)return new Ln([[t]],yl,n,+r);return null},I.interrupt=zn,I.voronoi=function(){function n(r){return new ss(r.map(function(t,n){var e=[Math.round(i(t,n,r)/Jg)*Jg,Math.round(o(t,n,r)/Jg)*Jg];return e.index=n,e.data=t,e}),e)}var i=Bc,o=Hc,e=null;return n.polygons=function(t){return n(t).polygons()},n.links=function(t){return n(t).links()},n.triangles=function(t){return n(t).triangles()},n.x=function(t){return arguments.length?(i="function"==typeof t?t:Yc(+t),n):i},n.y=function(t){return arguments.length?(o="function"==typeof t?t:Yc(+t),n):o},n.extent=function(t){return arguments.length?(e=null==t?null:[[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]],n):e&&[[e[0][0],e[0][1]],[e[1][0],e[1][1]]]},n.size=function(t){return arguments.length?(e=null==t?null:[[0,0],[+t[0],+t[1]]],n):e&&[e[1][0]-e[0][0],e[1][1]-e[0][1]]},n},I.zoom=function(){function u(t){t.property("__zoom",_s).on("wheel.zoom",n).on("mousedown.zoom",e).on("dblclick.zoom",r).filter(x).on("touchstart.zoom",i).on("touchmove.zoom",c).on("touchend.zoom touchcancel.zoom",s).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function p(t,n){return(n=Math.max(b[0],Math.min(b[1],n)))===t.k?t:new ls(n,t.x,t.y)}function d(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new ls(t.k,r,i)}function f(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function o(t,c,s){t.on("start.zoom",function(){v(this,arguments).start()}).on("interrupt.zoom end.zoom",function(){v(this,arguments).end()}).tween("zoom",function(){var t=arguments,r=v(this,t),n=_.apply(this,t),i=s||f(n),o=Math.max(n[1][0]-n[0][0],n[1][1]-n[0][1]),e=this.__zoom,u="function"==typeof c?c.apply(this,t):c,a=T(e.invert(i).concat(o/e.k),u.invert(i).concat(o/u.k));return function(t){if(1===t)t=u;else{var n=a(t),e=o/n[2];t=new ls(e,i[0]-n[0]*e,i[1]-n[1]*e)}r.zoom(null,t)}})}function v(t,n){for(var e,r=0,i=N.length;r 0) - resultTimeValue = hour * 3600; - resultTimeValue += min * 60; - - return resultTimeValue; -} - -function convertSummaryTimeToBadgeString(summaryTime) { - var sec = (summaryTime); - var min = (summaryTime / 60).toFixed(0); - var hours = (summaryTime / (60 * 60)).toFixed(0); - var days = (summaryTime / (60 * 60 * 24)).toFixed(0); - - if (sec < 60) { - return sec + "s"; - } else if (min < 60) { - return min + "m"; - } else if (hours < 24) { - return hours + "h"; - } else { - return days + "d" - } -} - -function convertShortSummaryTimeToString(summaryTime) { - var hours = Math.floor(summaryTime / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - - hours = zeroAppend(hours); - mins = zeroAppend(mins); - - return hours + 'h : ' + mins + 'm'; -} - -function convertShortSummaryTimeToLongString(summaryTime) { - var hours = Math.floor(summaryTime / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - - hours = zeroAppend(hours); - mins = zeroAppend(mins); - - return hours + ' hour ' + mins + ' minutes'; -} - -function getArrayTime(summaryTime) { - var days = Math.floor(summaryTime / 3600 / 24); - var totalHours = summaryTime % (3600 * 24); - var hours = Math.floor(totalHours / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - var seconds = totalSeconds % 60; - - days = zeroAppend(days); - hours = zeroAppend(hours); - mins = zeroAppend(mins); - seconds = zeroAppend(seconds); - - return {'days': days, - 'hours': hours, - 'mins': mins, - 'seconds': seconds}; -} - -function convertSummaryTimeToString(summaryTime) { - var days = Math.floor(summaryTime / 3600 / 24); - var totalHours = summaryTime % (3600 * 24); - var hours = Math.floor(totalHours / 3600); - var totalSeconds = summaryTime % 3600; - var mins = Math.floor(totalSeconds / 60); - var seconds = totalSeconds % 60; - - hours = zeroAppend(hours); - mins = zeroAppend(mins); - seconds = zeroAppend(seconds); - - if (days > 0) - return days + 'd ' + hours + 'h ' + mins + 'm ' + seconds + 's'; - else return hours + 'h ' + mins + 'm ' + seconds + 's'; -} - -function zeroAppend(time) { - if (time < 10) - return '0' + time; - else return time; -} - -function isDateInRange(dateStr, range) { - return new Date(dateStr) >= range.from && new Date(dateStr) <= range.to; -} - -function isCorrectDate(range){ - return range.from.getFullYear() >= 2019 && range.to.getFullYear() >= 2019; -} - -function getDateFromRange(range) { - switch (range) { - case 'days2': return 2; - case 'days3': return 3; - case 'days4': return 4; - case 'days5': return 5; - case 'days6': return 6; - case 'days7': return 7; - case 'month1': return 30; - case 'month2': return 60; - case 'month3': return 90; - } -} - -function isDomainEquals(first, second) { - if (first === second) - return true; - else { - var resultUrl = function (url) { - if (url.indexOf('www.') > -1) - return url.split('www.')[1]; - return url; - }; - - if (resultUrl(first) === resultUrl(second)) - return true; - else return false; - } -} - -function treatAsUTC(date) { - var result = new Date(date); - result.setMinutes(result.getMinutes() - result.getTimezoneOffset()); - return result; -} - -function daysBetween(startDate, endDate) { - var millisecondsPerDay = 24 * 60 * 60 * 1000; - return ((treatAsUTC(endDate) - treatAsUTC(startDate)) / millisecondsPerDay) + 1; -} diff --git a/src/scripts/picker/clockpicker.min.js b/src/scripts/picker/clockpicker.min.js deleted file mode 100644 index 5283942..0000000 --- a/src/scripts/picker/clockpicker.min.js +++ /dev/null @@ -1 +0,0 @@ -!function(){var P,t,i,e,x=window.jQuery,o=x(window),S=x(document),s="http://www.w3.org/2000/svg",E="SVGAngle"in window&&((i=document.createElement("div")).innerHTML="",t=(i.firstChild&&i.firstChild.namespaceURI)==s,i.innerHTML="",t),c="transition"in(e=document.createElement("div").style)||"WebkitTransition"in e||"MozTransition"in e||"msTransition"in e||"OTransition"in e,n="ontouchstart"in window,D="mousedown"+(n?" touchstart":""),I="mousemove.clockpicker"+(n?" touchmove.clockpicker":""),B="mouseup.clockpicker"+(n?" touchend.clockpicker":""),d=navigator.vibrate?"vibrate":navigator.webkitVibrate?"webkitVibrate":null;function z(t){return document.createElementNS(s,t)}function O(t){return(t<10?"0":"")+t}var j=0;var L=100,U=80,W=13,N=c?350:1,X=['
    ','
    ','
    ',''," : ",'','',"
    ",'
    ','
    ','
    ','
    ','
    ',"
    ",'',"","
    ","
    "].join("");function a(t,h){var i,e,s=x(X),u=s.find(".clockpicker-plate"),o=s.find(".clockpicker-hours"),c=s.find(".clockpicker-minutes"),n=s.find(".clockpicker-am-pm-block"),a="INPUT"===t.prop("tagName"),r=a?t:t.find("input"),p=t.find(".input-group-addon"),k=this;if(this.id=(e=++j+"",(i="cp")?i+e:e),this.element=t,this.options=h,this.isAppended=!1,this.isShown=!1,this.currentView="hours",this.isInput=a,this.input=r,this.addon=p,this.popover=s,this.plate=u,this.hoursView=o,this.minutesView=c,this.amPmBlock=n,this.spanHours=s.find(".clockpicker-span-hours"),this.spanMinutes=s.find(".clockpicker-span-minutes"),this.spanAmPm=s.find(".clockpicker-span-am-pm"),this.amOrPm="PM",h.twelvehour){var l=['
    ','",'","
    "].join("");x(l);x('').on("click",function(){k.amOrPm="AM",x(".clockpicker-span-am-pm").empty().append("AM")}).appendTo(this.amPmBlock),x('').on("click",function(){k.amOrPm="PM",x(".clockpicker-span-am-pm").empty().append("PM")}).appendTo(this.amPmBlock)}h.autoclose||x('").click(x.proxy(this.done,this)).appendTo(s),"top"!==h.placement&&"bottom"!==h.placement||"top"!==h.align&&"bottom"!==h.align||(h.align="left"),"left"!==h.placement&&"right"!==h.placement||"left"!==h.align&&"right"!==h.align||(h.align="top"),s.addClass(h.placement),s.addClass("clockpicker-align-"+h.align),this.spanHours.click(x.proxy(this.toggleView,this,"hours")),this.spanMinutes.click(x.proxy(this.toggleView,this,"minutes")),r.on("focus.clockpicker click.clockpicker",x.proxy(this.show,this)),p.on("click.clockpicker",x.proxy(this.toggle,this));var d,f,v,m,b=x('
    ');if(h.twelvehour)for(d=1;d<13;d+=1)f=b.clone(),v=d/6*Math.PI,m=U,f.css("font-size","120%"),f.css({left:L+Math.sin(v)*m-W,top:L-Math.cos(v)*m-W}),f.html(0===d?"00":d),o.append(f),f.on(D,w);else for(d=0;d<24;d+=1){f=b.clone(),v=d/6*Math.PI;var g=0=0&&n0&&t-1 in e)}var E=function(e){var t,n,r,i,o,a,s,u,l,c,f,p,d,h,g,y,v,m,x,b="sizzle"+1*new Date,w=e.document,T=0,C=0,E=ae(),k=ae(),S=ae(),D=function(e,t){return e===t&&(f=!0),0},N={}.hasOwnProperty,A=[],j=A.pop,q=A.push,L=A.push,H=A.slice,O=function(e,t){for(var n=0,r=e.length;n+~]|"+M+")"+M+"*"),z=new RegExp("="+M+"*([^\\]'\"]*?)"+M+"*\\]","g"),X=new RegExp(W),U=new RegExp("^"+R+"$"),V={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+I),PSEUDO:new RegExp("^"+W),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("^(?:"+P+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},G=/^(?:input|select|textarea|button)$/i,Y=/^h\d$/i,Q=/^[^{]+\{\s*\[native \w/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/[+~]/,Z=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ee=function(e,t,n){var r="0x"+t-65536;return r!==r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},te=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ne=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},re=function(){p()},ie=me(function(e){return!0===e.disabled&&("form"in e||"label"in e)},{dir:"parentNode",next:"legend"});try{L.apply(A=H.call(w.childNodes),w.childNodes),A[w.childNodes.length].nodeType}catch(e){L={apply:A.length?function(e,t){q.apply(e,H.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function oe(e,t,r,i){var o,s,l,c,f,h,v,m=t&&t.ownerDocument,T=t?t.nodeType:9;if(r=r||[],"string"!=typeof e||!e||1!==T&&9!==T&&11!==T)return r;if(!i&&((t?t.ownerDocument||t:w)!==d&&p(t),t=t||d,g)){if(11!==T&&(f=J.exec(e)))if(o=f[1]){if(9===T){if(!(l=t.getElementById(o)))return r;if(l.id===o)return r.push(l),r}else if(m&&(l=m.getElementById(o))&&x(t,l)&&l.id===o)return r.push(l),r}else{if(f[2])return L.apply(r,t.getElementsByTagName(e)),r;if((o=f[3])&&n.getElementsByClassName&&t.getElementsByClassName)return L.apply(r,t.getElementsByClassName(o)),r}if(n.qsa&&!S[e+" "]&&(!y||!y.test(e))){if(1!==T)m=t,v=e;else if("object"!==t.nodeName.toLowerCase()){(c=t.getAttribute("id"))?c=c.replace(te,ne):t.setAttribute("id",c=b),s=(h=a(e)).length;while(s--)h[s]="#"+c+" "+ve(h[s]);v=h.join(","),m=K.test(e)&&ge(t.parentNode)||t}if(v)try{return L.apply(r,m.querySelectorAll(v)),r}catch(e){}finally{c===b&&t.removeAttribute("id")}}}return u(e.replace(B,"$1"),t,r,i)}function ae(){var e=[];function t(n,i){return e.push(n+" ")>r.cacheLength&&delete t[e.shift()],t[n+" "]=i}return t}function se(e){return e[b]=!0,e}function ue(e){var t=d.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function le(e,t){var n=e.split("|"),i=n.length;while(i--)r.attrHandle[n[i]]=t}function ce(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 fe(e){return function(t){return"input"===t.nodeName.toLowerCase()&&t.type===e}}function pe(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function de(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&ie(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function he(e){return se(function(t){return t=+t,se(function(n,r){var i,o=e([],n.length,t),a=o.length;while(a--)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function ge(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}n=oe.support={},o=oe.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},p=oe.setDocument=function(e){var t,i,a=e?e.ownerDocument||e:w;return a!==d&&9===a.nodeType&&a.documentElement?(d=a,h=d.documentElement,g=!o(d),w!==d&&(i=d.defaultView)&&i.top!==i&&(i.addEventListener?i.addEventListener("unload",re,!1):i.attachEvent&&i.attachEvent("onunload",re)),n.attributes=ue(function(e){return e.className="i",!e.getAttribute("className")}),n.getElementsByTagName=ue(function(e){return e.appendChild(d.createComment("")),!e.getElementsByTagName("*").length}),n.getElementsByClassName=Q.test(d.getElementsByClassName),n.getById=ue(function(e){return h.appendChild(e).id=b,!d.getElementsByName||!d.getElementsByName(b).length}),n.getById?(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){return e.getAttribute("id")===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){var n=t.getElementById(e);return n?[n]:[]}}):(r.filter.ID=function(e){var t=e.replace(Z,ee);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},r.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&g){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[]}}),r.find.TAG=n.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):n.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},r.find.CLASS=n.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&g)return t.getElementsByClassName(e)},v=[],y=[],(n.qsa=Q.test(d.querySelectorAll))&&(ue(function(e){h.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&y.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||y.push("\\["+M+"*(?:value|"+P+")"),e.querySelectorAll("[id~="+b+"-]").length||y.push("~="),e.querySelectorAll(":checked").length||y.push(":checked"),e.querySelectorAll("a#"+b+"+*").length||y.push(".#.+[+~]")}),ue(function(e){e.innerHTML="";var t=d.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&y.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&y.push(":enabled",":disabled"),h.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&y.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),y.push(",.*:")})),(n.matchesSelector=Q.test(m=h.matches||h.webkitMatchesSelector||h.mozMatchesSelector||h.oMatchesSelector||h.msMatchesSelector))&&ue(function(e){n.disconnectedMatch=m.call(e,"*"),m.call(e,"[s!='']:x"),v.push("!=",W)}),y=y.length&&new RegExp(y.join("|")),v=v.length&&new RegExp(v.join("|")),t=Q.test(h.compareDocumentPosition),x=t||Q.test(h.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},D=t?function(e,t){if(e===t)return f=!0,0;var r=!e.compareDocumentPosition-!t.compareDocumentPosition;return r||(1&(r=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!n.sortDetached&&t.compareDocumentPosition(e)===r?e===d||e.ownerDocument===w&&x(w,e)?-1:t===d||t.ownerDocument===w&&x(w,t)?1:c?O(c,e)-O(c,t):0:4&r?-1:1)}:function(e,t){if(e===t)return f=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===d?-1:t===d?1:i?-1:o?1:c?O(c,e)-O(c,t):0;if(i===o)return ce(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?ce(a[r],s[r]):a[r]===w?-1:s[r]===w?1:0},d):d},oe.matches=function(e,t){return oe(e,null,null,t)},oe.matchesSelector=function(e,t){if((e.ownerDocument||e)!==d&&p(e),t=t.replace(z,"='$1']"),n.matchesSelector&&g&&!S[t+" "]&&(!v||!v.test(t))&&(!y||!y.test(t)))try{var r=m.call(e,t);if(r||n.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(e){}return oe(t,d,null,[e]).length>0},oe.contains=function(e,t){return(e.ownerDocument||e)!==d&&p(e),x(e,t)},oe.attr=function(e,t){(e.ownerDocument||e)!==d&&p(e);var i=r.attrHandle[t.toLowerCase()],o=i&&N.call(r.attrHandle,t.toLowerCase())?i(e,t,!g):void 0;return void 0!==o?o:n.attributes||!g?e.getAttribute(t):(o=e.getAttributeNode(t))&&o.specified?o.value:null},oe.escape=function(e){return(e+"").replace(te,ne)},oe.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},oe.uniqueSort=function(e){var t,r=[],i=0,o=0;if(f=!n.detectDuplicates,c=!n.sortStable&&e.slice(0),e.sort(D),f){while(t=e[o++])t===e[o]&&(i=r.push(o));while(i--)e.splice(r[i],1)}return c=null,e},i=oe.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else while(t=e[r++])n+=i(t);return n},(r=oe.selectors={cacheLength:50,createPseudo:se,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(Z,ee),e[3]=(e[3]||e[4]||e[5]||"").replace(Z,ee),"~="===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]||oe.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]&&oe.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return V.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=a(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(Z,ee).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=E[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&E(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=oe.attr(r,e);return null==i?"!="===t:!t||(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i.replace($," ")+" ").indexOf(n)>-1:"|="===t&&(i===n||i.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,d,h,g=o!==a?"nextSibling":"previousSibling",y=t.parentNode,v=s&&t.nodeName.toLowerCase(),m=!u&&!s,x=!1;if(y){if(o){while(g){p=t;while(p=p[g])if(s?p.nodeName.toLowerCase()===v:1===p.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?y.firstChild:y.lastChild],a&&m){x=(d=(l=(c=(f=(p=y)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1])&&l[2],p=d&&y.childNodes[d];while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if(1===p.nodeType&&++x&&p===t){c[e]=[T,d,x];break}}else if(m&&(x=d=(l=(c=(f=(p=t)[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]||[])[0]===T&&l[1]),!1===x)while(p=++d&&p&&p[g]||(x=d=0)||h.pop())if((s?p.nodeName.toLowerCase()===v:1===p.nodeType)&&++x&&(m&&((c=(f=p[b]||(p[b]={}))[p.uniqueID]||(f[p.uniqueID]={}))[e]=[T,x]),p===t))break;return(x-=i)===r||x%r==0&&x/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||oe.error("unsupported pseudo: "+e);return i[b]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?se(function(e,n){var r,o=i(e,t),a=o.length;while(a--)e[r=O(e,o[a])]=!(n[r]=o[a])}):function(e){return i(e,0,n)}):i}},pseudos:{not:se(function(e){var t=[],n=[],r=s(e.replace(B,"$1"));return r[b]?se(function(e,t,n,i){var o,a=r(e,null,i,[]),s=e.length;while(s--)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),t[0]=null,!n.pop()}}),has:se(function(e){return function(t){return oe(e,t).length>0}}),contains:se(function(e){return e=e.replace(Z,ee),function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:se(function(e){return U.test(e||"")||oe.error("unsupported lang: "+e),e=e.replace(Z,ee).toLowerCase(),function(t){var n;do{if(n=g?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===h},focus:function(e){return e===d.activeElement&&(!d.hasFocus||d.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:de(!1),disabled:de(!0),checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,!0===e.selected},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Y.test(e.nodeName)},input:function(e){return G.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:he(function(){return[0]}),last:he(function(e,t){return[t-1]}),eq:he(function(e,t,n){return[n<0?n+t:n]}),even:he(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:he(function(e,t,n){for(var r=n<0?n+t:n;++r1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function be(e,t,n){for(var r=0,i=t.length;r-1&&(o[l]=!(a[l]=f))}}else v=we(v===a?v.splice(h,v.length):v),i?i(null,a,v,u):L.apply(a,v)})}function Ce(e){for(var t,n,i,o=e.length,a=r.relative[e[0].type],s=a||r.relative[" "],u=a?1:0,c=me(function(e){return e===t},s,!0),f=me(function(e){return O(t,e)>-1},s,!0),p=[function(e,n,r){var i=!a&&(r||n!==l)||((t=n).nodeType?c(e,n,r):f(e,n,r));return t=null,i}];u1&&xe(p),u>1&&ve(e.slice(0,u-1).concat({value:" "===e[u-2].type?"*":""})).replace(B,"$1"),n,u0,i=e.length>0,o=function(o,a,s,u,c){var f,h,y,v=0,m="0",x=o&&[],b=[],w=l,C=o||i&&r.find.TAG("*",c),E=T+=null==w?1:Math.random()||.1,k=C.length;for(c&&(l=a===d||a||c);m!==k&&null!=(f=C[m]);m++){if(i&&f){h=0,a||f.ownerDocument===d||(p(f),s=!g);while(y=e[h++])if(y(f,a||d,s)){u.push(f);break}c&&(T=E)}n&&((f=!y&&f)&&v--,o&&x.push(f))}if(v+=m,n&&m!==v){h=0;while(y=t[h++])y(x,b,a,s);if(o){if(v>0)while(m--)x[m]||b[m]||(b[m]=j.call(u));b=we(b)}L.apply(u,b),c&&!o&&b.length>0&&v+t.length>1&&oe.uniqueSort(u)}return c&&(T=E,l=w),x};return n?se(o):o}return s=oe.compile=function(e,t){var n,r=[],i=[],o=S[e+" "];if(!o){t||(t=a(e)),n=t.length;while(n--)(o=Ce(t[n]))[b]?r.push(o):i.push(o);(o=S(e,Ee(i,r))).selector=e}return o},u=oe.select=function(e,t,n,i){var o,u,l,c,f,p="function"==typeof e&&e,d=!i&&a(e=p.selector||e);if(n=n||[],1===d.length){if((u=d[0]=d[0].slice(0)).length>2&&"ID"===(l=u[0]).type&&9===t.nodeType&&g&&r.relative[u[1].type]){if(!(t=(r.find.ID(l.matches[0].replace(Z,ee),t)||[])[0]))return n;p&&(t=t.parentNode),e=e.slice(u.shift().value.length)}o=V.needsContext.test(e)?0:u.length;while(o--){if(l=u[o],r.relative[c=l.type])break;if((f=r.find[c])&&(i=f(l.matches[0].replace(Z,ee),K.test(u[0].type)&&ge(t.parentNode)||t))){if(u.splice(o,1),!(e=i.length&&ve(u)))return L.apply(n,i),n;break}}}return(p||s(e,d))(i,t,!g,n,!t||K.test(e)&&ge(t.parentNode)||t),n},n.sortStable=b.split("").sort(D).join("")===b,n.detectDuplicates=!!f,p(),n.sortDetached=ue(function(e){return 1&e.compareDocumentPosition(d.createElement("fieldset"))}),ue(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||le("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),n.attributes&&ue(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||le("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),ue(function(e){return null==e.getAttribute("disabled")})||le(P,function(e,t,n){var r;if(!n)return!0===e[t]?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),oe}(e);w.find=E,w.expr=E.selectors,w.expr[":"]=w.expr.pseudos,w.uniqueSort=w.unique=E.uniqueSort,w.text=E.getText,w.isXMLDoc=E.isXML,w.contains=E.contains,w.escapeSelector=E.escape;var k=function(e,t,n){var r=[],i=void 0!==n;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&w(e).is(n))break;r.push(e)}return r},S=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},D=w.expr.match.needsContext;function N(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}var A=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return g(t)?w.grep(e,function(e,r){return!!t.call(e,r,e)!==n}):t.nodeType?w.grep(e,function(e){return e===t!==n}):"string"!=typeof t?w.grep(e,function(e){return u.call(t,e)>-1!==n}):w.filter(t,e,n)}w.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?w.find.matchesSelector(r,e)?[r]:[]:w.find.matches(e,w.grep(t,function(e){return 1===e.nodeType}))},w.fn.extend({find:function(e){var t,n,r=this.length,i=this;if("string"!=typeof e)return this.pushStack(w(e).filter(function(){for(t=0;t1?w.uniqueSort(n):n},filter:function(e){return this.pushStack(j(this,e||[],!1))},not:function(e){return this.pushStack(j(this,e||[],!0))},is:function(e){return!!j(this,"string"==typeof e&&D.test(e)?w(e):e||[],!1).length}});var q,L=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(w.fn.init=function(e,t,n){var i,o;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:L.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof w?t[0]:t,w.merge(this,w.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:r,!0)),A.test(i[1])&&w.isPlainObject(t))for(i in t)g(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(o=r.getElementById(i[2]))&&(this[0]=o,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):g(e)?void 0!==n.ready?n.ready(e):e(w):w.makeArray(e,this)}).prototype=w.fn,q=w(r);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};w.fn.extend({has:function(e){var t=w(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&w.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?w.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?u.call(w(e),this[0]):u.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(w.uniqueSort(w.merge(this.get(),w(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}w.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return k(e,"parentNode")},parentsUntil:function(e,t,n){return k(e,"parentNode",n)},next:function(e){return P(e,"nextSibling")},prev:function(e){return P(e,"previousSibling")},nextAll:function(e){return k(e,"nextSibling")},prevAll:function(e){return k(e,"previousSibling")},nextUntil:function(e,t,n){return k(e,"nextSibling",n)},prevUntil:function(e,t,n){return k(e,"previousSibling",n)},siblings:function(e){return S((e.parentNode||{}).firstChild,e)},children:function(e){return S(e.firstChild)},contents:function(e){return N(e,"iframe")?e.contentDocument:(N(e,"template")&&(e=e.content||e),w.merge([],e.childNodes))}},function(e,t){w.fn[e]=function(n,r){var i=w.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=w.filter(r,i)),this.length>1&&(O[e]||w.uniqueSort(i),H.test(e)&&i.reverse()),this.pushStack(i)}});var M=/[^\x20\t\r\n\f]+/g;function R(e){var t={};return w.each(e.match(M)||[],function(e,n){t[n]=!0}),t}w.Callbacks=function(e){e="string"==typeof e?R(e):w.extend({},e);var t,n,r,i,o=[],a=[],s=-1,u=function(){for(i=i||e.once,r=t=!0;a.length;s=-1){n=a.shift();while(++s-1)o.splice(n,1),n<=s&&s--}),this},has:function(e){return e?w.inArray(e,o)>-1:o.length>0},empty:function(){return o&&(o=[]),this},disable:function(){return i=a=[],o=n="",this},disabled:function(){return!o},lock:function(){return i=a=[],n||t||(o=n=""),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=[e,(n=n||[]).slice?n.slice():n],a.push(n),t||u()),this},fire:function(){return l.fireWith(this,arguments),this},fired:function(){return!!r}};return l};function I(e){return e}function W(e){throw e}function $(e,t,n,r){var i;try{e&&g(i=e.promise)?i.call(e).done(t).fail(n):e&&g(i=e.then)?i.call(e,t,n):t.apply(void 0,[e].slice(r))}catch(e){n.apply(void 0,[e])}}w.extend({Deferred:function(t){var n=[["notify","progress",w.Callbacks("memory"),w.Callbacks("memory"),2],["resolve","done",w.Callbacks("once memory"),w.Callbacks("once memory"),0,"resolved"],["reject","fail",w.Callbacks("once memory"),w.Callbacks("once memory"),1,"rejected"]],r="pending",i={state:function(){return r},always:function(){return o.done(arguments).fail(arguments),this},"catch":function(e){return i.then(null,e)},pipe:function(){var e=arguments;return w.Deferred(function(t){w.each(n,function(n,r){var i=g(e[r[4]])&&e[r[4]];o[r[1]](function(){var e=i&&i.apply(this,arguments);e&&g(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[r[0]+"With"](this,i?[e]:arguments)})}),e=null}).promise()},then:function(t,r,i){var o=0;function a(t,n,r,i){return function(){var s=this,u=arguments,l=function(){var e,l;if(!(t=o&&(r!==W&&(s=void 0,u=[e]),n.rejectWith(s,u))}};t?c():(w.Deferred.getStackHook&&(c.stackTrace=w.Deferred.getStackHook()),e.setTimeout(c))}}return w.Deferred(function(e){n[0][3].add(a(0,e,g(i)?i:I,e.notifyWith)),n[1][3].add(a(0,e,g(t)?t:I)),n[2][3].add(a(0,e,g(r)?r:W))}).promise()},promise:function(e){return null!=e?w.extend(e,i):i}},o={};return w.each(n,function(e,t){var a=t[2],s=t[5];i[t[1]]=a.add,s&&a.add(function(){r=s},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),a.add(t[3].fire),o[t[0]]=function(){return o[t[0]+"With"](this===o?void 0:this,arguments),this},o[t[0]+"With"]=a.fireWith}),i.promise(o),t&&t.call(o,o),o},when:function(e){var t=arguments.length,n=t,r=Array(n),i=o.call(arguments),a=w.Deferred(),s=function(e){return function(n){r[e]=this,i[e]=arguments.length>1?o.call(arguments):n,--t||a.resolveWith(r,i)}};if(t<=1&&($(e,a.done(s(n)).resolve,a.reject,!t),"pending"===a.state()||g(i[n]&&i[n].then)))return a.then();while(n--)$(i[n],s(n),a.reject);return a.promise()}});var B=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;w.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&B.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},w.readyException=function(t){e.setTimeout(function(){throw t})};var F=w.Deferred();w.fn.ready=function(e){return F.then(e)["catch"](function(e){w.readyException(e)}),this},w.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--w.readyWait:w.isReady)||(w.isReady=!0,!0!==e&&--w.readyWait>0||F.resolveWith(r,[w]))}}),w.ready.then=F.then;function _(){r.removeEventListener("DOMContentLoaded",_),e.removeEventListener("load",_),w.ready()}"complete"===r.readyState||"loading"!==r.readyState&&!r.documentElement.doScroll?e.setTimeout(w.ready):(r.addEventListener("DOMContentLoaded",_),e.addEventListener("load",_));var z=function(e,t,n,r,i,o,a){var s=0,u=e.length,l=null==n;if("object"===x(n)){i=!0;for(s in n)z(e,t,s,n[s],!0,o,a)}else if(void 0!==r&&(i=!0,g(r)||(a=!0),l&&(a?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(w(e),n)})),t))for(;s1,null,!0)},removeData:function(e){return this.each(function(){K.remove(this,e)})}}),w.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=J.get(e,t),n&&(!r||Array.isArray(n)?r=J.access(e,t,w.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=w.queue(e,t),r=n.length,i=n.shift(),o=w._queueHooks(e,t),a=function(){w.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return J.get(e,n)||J.access(e,n,{empty:w.Callbacks("once memory").add(function(){J.remove(e,[t+"queue",n])})})}}),w.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]+)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
    "],col:[2,"","
    "],tr:[2,"","
    "],td:[3,"","
    "],_default:[0,"",""]};ge.optgroup=ge.option,ge.tbody=ge.tfoot=ge.colgroup=ge.caption=ge.thead,ge.th=ge.td;function ye(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&N(e,t)?w.merge([e],n):n}function ve(e,t){for(var n=0,r=e.length;n-1)i&&i.push(o);else if(l=w.contains(o.ownerDocument,o),a=ye(f.appendChild(o),"script"),l&&ve(a),n){c=0;while(o=a[c++])he.test(o.type||"")&&n.push(o)}return f}!function(){var e=r.createDocumentFragment().appendChild(r.createElement("div")),t=r.createElement("input");t.setAttribute("type","radio"),t.setAttribute("checked","checked"),t.setAttribute("name","t"),e.appendChild(t),h.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,e.innerHTML="",h.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var be=r.documentElement,we=/^key/,Te=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ce=/^([^.]*)(?:\.(.+)|)/;function Ee(){return!0}function ke(){return!1}function Se(){try{return r.activeElement}catch(e){}}function De(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)De(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=ke;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return w().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=w.guid++)),e.each(function(){w.event.add(this,t,i,r,n)})}w.event={global:{},add:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.get(e);if(y){n.handler&&(n=(o=n).handler,i=o.selector),i&&w.find.matchesSelector(be,i),n.guid||(n.guid=w.guid++),(u=y.events)||(u=y.events={}),(a=y.handle)||(a=y.handle=function(t){return"undefined"!=typeof w&&w.event.triggered!==t.type?w.event.dispatch.apply(e,arguments):void 0}),l=(t=(t||"").match(M)||[""]).length;while(l--)d=g=(s=Ce.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=w.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=w.event.special[d]||{},c=w.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&w.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(e,r,h,a)||e.addEventListener&&e.addEventListener(d,a)),f.add&&(f.add.call(e,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),w.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,y=J.hasData(e)&&J.get(e);if(y&&(u=y.events)){l=(t=(t||"").match(M)||[""]).length;while(l--)if(s=Ce.exec(t[l])||[],d=g=s[1],h=(s[2]||"").split(".").sort(),d){f=w.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,y.handle)||w.removeEvent(e,d,y.handle),delete u[d])}else for(d in u)w.event.remove(e,d+t[l],n,r,!0);w.isEmptyObject(u)&&J.remove(e,"handle events")}},dispatch:function(e){var t=w.event.fix(e),n,r,i,o,a,s,u=new Array(arguments.length),l=(J.get(this,"events")||{})[t.type]||[],c=w.event.special[t.type]||{};for(u[0]=t,n=1;n=1))for(;l!==this;l=l.parentNode||this)if(1===l.nodeType&&("click"!==e.type||!0!==l.disabled)){for(o=[],a={},n=0;n-1:w.find(i,this,null,[l]).length),a[i]&&o.push(r);o.length&&s.push({elem:l,handlers:o})}return l=this,u\x20\t\r\n\f]*)[^>]*)\/>/gi,Ae=/\s*$/g;function Le(e,t){return N(e,"table")&&N(11!==t.nodeType?t:t.firstChild,"tr")?w(e).children("tbody")[0]||e:e}function He(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Oe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Pe(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(J.hasData(e)&&(o=J.access(e),a=J.set(t,o),l=o.events)){delete a.handle,a.events={};for(i in l)for(n=0,r=l[i].length;n1&&"string"==typeof y&&!h.checkClone&&je.test(y))return e.each(function(i){var o=e.eq(i);v&&(t[0]=y.call(this,i,o.html())),Re(o,t,n,r)});if(p&&(i=xe(t,e[0].ownerDocument,!1,e,r),o=i.firstChild,1===i.childNodes.length&&(i=o),o||r)){for(u=(s=w.map(ye(i,"script"),He)).length;f")},clone:function(e,t,n){var r,i,o,a,s=e.cloneNode(!0),u=w.contains(e.ownerDocument,e);if(!(h.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||w.isXMLDoc(e)))for(a=ye(s),r=0,i=(o=ye(e)).length;r0&&ve(a,!u&&ye(e,"script")),s},cleanData:function(e){for(var t,n,r,i=w.event.special,o=0;void 0!==(n=e[o]);o++)if(Y(n)){if(t=n[J.expando]){if(t.events)for(r in t.events)i[r]?w.event.remove(n,r):w.removeEvent(n,r,t.handle);n[J.expando]=void 0}n[K.expando]&&(n[K.expando]=void 0)}}}),w.fn.extend({detach:function(e){return Ie(this,e,!0)},remove:function(e){return Ie(this,e)},text:function(e){return z(this,function(e){return void 0===e?w.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=e)})},null,e,arguments.length)},append:function(){return Re(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||Le(this,e).appendChild(e)})},prepend:function(){return Re(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=Le(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return Re(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++)1===e.nodeType&&(w.cleanData(ye(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return w.clone(this,e,t)})},html:function(e){return z(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Ae.test(e)&&!ge[(de.exec(e)||["",""])[1].toLowerCase()]){e=w.htmlPrefilter(e);try{for(;n=0&&(u+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-o-u-s-.5))),u}function et(e,t,n){var r=$e(e),i=Fe(e,t,r),o="border-box"===w.css(e,"boxSizing",!1,r),a=o;if(We.test(i)){if(!n)return i;i="auto"}return a=a&&(h.boxSizingReliable()||i===e.style[t]),("auto"===i||!parseFloat(i)&&"inline"===w.css(e,"display",!1,r))&&(i=e["offset"+t[0].toUpperCase()+t.slice(1)],a=!0),(i=parseFloat(i)||0)+Ze(e,t,n||(o?"border":"content"),a,r,i)+"px"}w.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Fe(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=G(t),u=Xe.test(t),l=e.style;if(u||(t=Je(s)),a=w.cssHooks[t]||w.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:l[t];"string"==(o=typeof n)&&(i=ie.exec(n))&&i[1]&&(n=ue(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(w.cssNumber[s]?"":"px")),h.clearCloneStyle||""!==n||0!==t.indexOf("background")||(l[t]="inherit"),a&&"set"in a&&void 0===(n=a.set(e,n,r))||(u?l.setProperty(t,n):l[t]=n))}},css:function(e,t,n,r){var i,o,a,s=G(t);return Xe.test(t)||(t=Je(s)),(a=w.cssHooks[t]||w.cssHooks[s])&&"get"in a&&(i=a.get(e,!0,n)),void 0===i&&(i=Fe(e,t,r)),"normal"===i&&t in Ve&&(i=Ve[t]),""===n||n?(o=parseFloat(i),!0===n||isFinite(o)?o||0:i):i}}),w.each(["height","width"],function(e,t){w.cssHooks[t]={get:function(e,n,r){if(n)return!ze.test(w.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?et(e,t,r):se(e,Ue,function(){return et(e,t,r)})},set:function(e,n,r){var i,o=$e(e),a="border-box"===w.css(e,"boxSizing",!1,o),s=r&&Ze(e,t,r,a,o);return a&&h.scrollboxSize()===o.position&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(o[t])-Ze(e,t,"border",!1,o)-.5)),s&&(i=ie.exec(n))&&"px"!==(i[3]||"px")&&(e.style[t]=n,n=w.css(e,t)),Ke(e,n,s)}}}),w.cssHooks.marginLeft=_e(h.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Fe(e,"marginLeft"))||e.getBoundingClientRect().left-se(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),w.each({margin:"",padding:"",border:"Width"},function(e,t){w.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+oe[r]+t]=o[r]||o[r-2]||o[0];return i}},"margin"!==e&&(w.cssHooks[e+t].set=Ke)}),w.fn.extend({css:function(e,t){return z(this,function(e,t,n){var r,i,o={},a=0;if(Array.isArray(t)){for(r=$e(e),i=t.length;a1)}});function tt(e,t,n,r,i){return new tt.prototype.init(e,t,n,r,i)}w.Tween=tt,tt.prototype={constructor:tt,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||w.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(w.cssNumber[n]?"":"px")},cur:function(){var e=tt.propHooks[this.prop];return e&&e.get?e.get(this):tt.propHooks._default.get(this)},run:function(e){var t,n=tt.propHooks[this.prop];return this.options.duration?this.pos=t=w.easing[this.easing](e,this.options.duration*e,0,1,this.options.duration):this.pos=t=e,this.now=(this.end-this.start)*t+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),n&&n.set?n.set(this):tt.propHooks._default.set(this),this}},tt.prototype.init.prototype=tt.prototype,tt.propHooks={_default:{get:function(e){var t;return 1!==e.elem.nodeType||null!=e.elem[e.prop]&&null==e.elem.style[e.prop]?e.elem[e.prop]:(t=w.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){w.fx.step[e.prop]?w.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[w.cssProps[e.prop]]&&!w.cssHooks[e.prop]?e.elem[e.prop]=e.now:w.style(e.elem,e.prop,e.now+e.unit)}}},tt.propHooks.scrollTop=tt.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},w.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},w.fx=tt.prototype.init,w.fx.step={};var nt,rt,it=/^(?:toggle|show|hide)$/,ot=/queueHooks$/;function at(){rt&&(!1===r.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(at):e.setTimeout(at,w.fx.interval),w.fx.tick())}function st(){return e.setTimeout(function(){nt=void 0}),nt=Date.now()}function ut(e,t){var n,r=0,i={height:e};for(t=t?1:0;r<4;r+=2-t)i["margin"+(n=oe[r])]=i["padding"+n]=e;return t&&(i.opacity=i.width=e),i}function lt(e,t,n){for(var r,i=(pt.tweeners[t]||[]).concat(pt.tweeners["*"]),o=0,a=i.length;o1)},removeAttr:function(e){return this.each(function(){w.removeAttr(this,e)})}}),w.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?w.prop(e,t,n):(1===o&&w.isXMLDoc(e)||(i=w.attrHooks[t.toLowerCase()]||(w.expr.match.bool.test(t)?dt:void 0)),void 0!==n?null===n?void w.removeAttr(e,t):i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:(e.setAttribute(t,n+""),n):i&&"get"in i&&null!==(r=i.get(e,t))?r:null==(r=w.find.attr(e,t))?void 0:r)},attrHooks:{type:{set:function(e,t){if(!h.radioValue&&"radio"===t&&N(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r=0,i=t&&t.match(M);if(i&&1===e.nodeType)while(n=i[r++])e.removeAttribute(n)}}),dt={set:function(e,t,n){return!1===t?w.removeAttr(e,n):e.setAttribute(n,n),n}},w.each(w.expr.match.bool.source.match(/\w+/g),function(e,t){var n=ht[t]||w.find.attr;ht[t]=function(e,t,r){var i,o,a=t.toLowerCase();return r||(o=ht[a],ht[a]=i,i=null!=n(e,t,r)?a:null,ht[a]=o),i}});var gt=/^(?:input|select|textarea|button)$/i,yt=/^(?:a|area)$/i;w.fn.extend({prop:function(e,t){return z(this,w.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[w.propFix[e]||e]})}}),w.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&w.isXMLDoc(e)||(t=w.propFix[t]||t,i=w.propHooks[t]),void 0!==n?i&&"set"in i&&void 0!==(r=i.set(e,n,t))?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){var t=w.find.attr(e,"tabindex");return t?parseInt(t,10):gt.test(e.nodeName)||yt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),h.optSelected||(w.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),w.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){w.propFix[this.toLowerCase()]=this});function vt(e){return(e.match(M)||[]).join(" ")}function mt(e){return e.getAttribute&&e.getAttribute("class")||""}function xt(e){return Array.isArray(e)?e:"string"==typeof e?e.match(M)||[]:[]}w.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).addClass(e.call(this,t,mt(this)))});if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])r.indexOf(" "+o+" ")<0&&(r+=o+" ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(g(e))return this.each(function(t){w(this).removeClass(e.call(this,t,mt(this)))});if(!arguments.length)return this.attr("class","");if((t=xt(e)).length)while(n=this[u++])if(i=mt(n),r=1===n.nodeType&&" "+vt(i)+" "){a=0;while(o=t[a++])while(r.indexOf(" "+o+" ")>-1)r=r.replace(" "+o+" "," ");i!==(s=vt(r))&&n.setAttribute("class",s)}return this},toggleClass:function(e,t){var n=typeof e,r="string"===n||Array.isArray(e);return"boolean"==typeof t&&r?t?this.addClass(e):this.removeClass(e):g(e)?this.each(function(n){w(this).toggleClass(e.call(this,n,mt(this),t),t)}):this.each(function(){var t,i,o,a;if(r){i=0,o=w(this),a=xt(e);while(t=a[i++])o.hasClass(t)?o.removeClass(t):o.addClass(t)}else void 0!==e&&"boolean"!==n||((t=mt(this))&&J.set(this,"__className__",t),this.setAttribute&&this.setAttribute("class",t||!1===e?"":J.get(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;t=" "+e+" ";while(n=this[r++])if(1===n.nodeType&&(" "+vt(mt(n))+" ").indexOf(t)>-1)return!0;return!1}});var bt=/\r/g;w.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=g(e),this.each(function(n){var i;1===this.nodeType&&(null==(i=r?e.call(this,n,w(this).val()):e)?i="":"number"==typeof i?i+="":Array.isArray(i)&&(i=w.map(i,function(e){return null==e?"":e+""})),(t=w.valHooks[this.type]||w.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return(t=w.valHooks[i.type]||w.valHooks[i.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:"string"==typeof(n=i.value)?n.replace(bt,""):null==n?"":n}}}),w.extend({valHooks:{option:{get:function(e){var t=w.find.attr(e,"value");return null!=t?t:vt(w.text(e))}},select:{get:function(e){var t,n,r,i=e.options,o=e.selectedIndex,a="select-one"===e.type,s=a?null:[],u=a?o+1:i.length;for(r=o<0?u:a?o:0;r-1)&&(n=!0);return n||(e.selectedIndex=-1),o}}}}),w.each(["radio","checkbox"],function(){w.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=w.inArray(w(e).val(),t)>-1}},h.checkOn||(w.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})}),h.focusin="onfocusin"in e;var wt=/^(?:focusinfocus|focusoutblur)$/,Tt=function(e){e.stopPropagation()};w.extend(w.event,{trigger:function(t,n,i,o){var a,s,u,l,c,p,d,h,v=[i||r],m=f.call(t,"type")?t.type:t,x=f.call(t,"namespace")?t.namespace.split("."):[];if(s=h=u=i=i||r,3!==i.nodeType&&8!==i.nodeType&&!wt.test(m+w.event.triggered)&&(m.indexOf(".")>-1&&(m=(x=m.split(".")).shift(),x.sort()),c=m.indexOf(":")<0&&"on"+m,t=t[w.expando]?t:new w.Event(m,"object"==typeof t&&t),t.isTrigger=o?2:3,t.namespace=x.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+x.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:w.makeArray(n,[t]),d=w.event.special[m]||{},o||!d.trigger||!1!==d.trigger.apply(i,n))){if(!o&&!d.noBubble&&!y(i)){for(l=d.delegateType||m,wt.test(l+m)||(s=s.parentNode);s;s=s.parentNode)v.push(s),u=s;u===(i.ownerDocument||r)&&v.push(u.defaultView||u.parentWindow||e)}a=0;while((s=v[a++])&&!t.isPropagationStopped())h=s,t.type=a>1?l:d.bindType||m,(p=(J.get(s,"events")||{})[t.type]&&J.get(s,"handle"))&&p.apply(s,n),(p=c&&s[c])&&p.apply&&Y(s)&&(t.result=p.apply(s,n),!1===t.result&&t.preventDefault());return t.type=m,o||t.isDefaultPrevented()||d._default&&!1!==d._default.apply(v.pop(),n)||!Y(i)||c&&g(i[m])&&!y(i)&&((u=i[c])&&(i[c]=null),w.event.triggered=m,t.isPropagationStopped()&&h.addEventListener(m,Tt),i[m](),t.isPropagationStopped()&&h.removeEventListener(m,Tt),w.event.triggered=void 0,u&&(i[c]=u)),t.result}},simulate:function(e,t,n){var r=w.extend(new w.Event,n,{type:e,isSimulated:!0});w.event.trigger(r,null,t)}}),w.fn.extend({trigger:function(e,t){return this.each(function(){w.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return w.event.trigger(e,t,n,!0)}}),h.focusin||w.each({focus:"focusin",blur:"focusout"},function(e,t){var n=function(e){w.event.simulate(t,e.target,w.event.fix(e))};w.event.special[t]={setup:function(){var r=this.ownerDocument||this,i=J.access(r,t);i||r.addEventListener(e,n,!0),J.access(r,t,(i||0)+1)},teardown:function(){var r=this.ownerDocument||this,i=J.access(r,t)-1;i?J.access(r,t,i):(r.removeEventListener(e,n,!0),J.remove(r,t))}}});var Ct=e.location,Et=Date.now(),kt=/\?/;w.parseXML=function(t){var n;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){n=void 0}return n&&!n.getElementsByTagName("parsererror").length||w.error("Invalid XML: "+t),n};var St=/\[\]$/,Dt=/\r?\n/g,Nt=/^(?:submit|button|image|reset|file)$/i,At=/^(?:input|select|textarea|keygen)/i;function jt(e,t,n,r){var i;if(Array.isArray(t))w.each(t,function(t,i){n||St.test(e)?r(e,i):jt(e+"["+("object"==typeof i&&null!=i?t:"")+"]",i,n,r)});else if(n||"object"!==x(t))r(e,t);else for(i in t)jt(e+"["+i+"]",t[i],n,r)}w.param=function(e,t){var n,r=[],i=function(e,t){var n=g(t)?t():t;r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(Array.isArray(e)||e.jquery&&!w.isPlainObject(e))w.each(e,function(){i(this.name,this.value)});else for(n in e)jt(n,e[n],t,i);return r.join("&")},w.fn.extend({serialize:function(){return w.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=w.prop(this,"elements");return e?w.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!w(this).is(":disabled")&&At.test(this.nodeName)&&!Nt.test(e)&&(this.checked||!pe.test(e))}).map(function(e,t){var n=w(this).val();return null==n?null:Array.isArray(n)?w.map(n,function(e){return{name:t.name,value:e.replace(Dt,"\r\n")}}):{name:t.name,value:n.replace(Dt,"\r\n")}}).get()}});var qt=/%20/g,Lt=/#.*$/,Ht=/([?&])_=[^&]*/,Ot=/^(.*?):[ \t]*([^\r\n]*)$/gm,Pt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Mt=/^(?:GET|HEAD)$/,Rt=/^\/\//,It={},Wt={},$t="*/".concat("*"),Bt=r.createElement("a");Bt.href=Ct.href;function Ft(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var r,i=0,o=t.toLowerCase().match(M)||[];if(g(n))while(r=o[i++])"+"===r[0]?(r=r.slice(1)||"*",(e[r]=e[r]||[]).unshift(n)):(e[r]=e[r]||[]).push(n)}}function _t(e,t,n,r){var i={},o=e===Wt;function a(s){var u;return i[s]=!0,w.each(e[s]||[],function(e,s){var l=s(t,n,r);return"string"!=typeof l||o||i[l]?o?!(u=l):void 0:(t.dataTypes.unshift(l),a(l),!1)}),u}return a(t.dataTypes[0])||!i["*"]&&a("*")}function zt(e,t){var n,r,i=w.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((i[n]?e:r||(r={}))[n]=t[n]);return r&&w.extend(!0,e,r),e}function Xt(e,t,n){var r,i,o,a,s=e.contents,u=e.dataTypes;while("*"===u[0])u.shift(),void 0===r&&(r=e.mimeType||t.getResponseHeader("Content-Type"));if(r)for(i in s)if(s[i]&&s[i].test(r)){u.unshift(i);break}if(u[0]in n)o=u[0];else{for(i in n){if(!u[0]||e.converters[i+" "+u[0]]){o=i;break}a||(a=i)}o=o||a}if(o)return o!==u[0]&&u.unshift(o),n[o]}function Ut(e,t,n,r){var i,o,a,s,u,l={},c=e.dataTypes.slice();if(c[1])for(a in e.converters)l[a.toLowerCase()]=e.converters[a];o=c.shift();while(o)if(e.responseFields[o]&&(n[e.responseFields[o]]=t),!u&&r&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),u=o,o=c.shift())if("*"===o)o=u;else if("*"!==u&&u!==o){if(!(a=l[u+" "+o]||l["* "+o]))for(i in l)if((s=i.split(" "))[1]===o&&(a=l[u+" "+s[0]]||l["* "+s[0]])){!0===a?a=l[i]:!0!==l[i]&&(o=s[0],c.unshift(s[1]));break}if(!0!==a)if(a&&e["throws"])t=a(t);else try{t=a(t)}catch(e){return{state:"parsererror",error:a?e:"No conversion from "+u+" to "+o}}}return{state:"success",data:t}}w.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ct.href,type:"GET",isLocal:Pt.test(Ct.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":$t,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":w.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?zt(zt(e,w.ajaxSettings),t):zt(w.ajaxSettings,e)},ajaxPrefilter:Ft(It),ajaxTransport:Ft(Wt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,p,d,h=w.ajaxSetup({},n),g=h.context||h,y=h.context&&(g.nodeType||g.jquery)?w(g):w.event,v=w.Deferred(),m=w.Callbacks("once memory"),x=h.statusCode||{},b={},T={},C="canceled",E={readyState:0,getResponseHeader:function(e){var t;if(c){if(!s){s={};while(t=Ot.exec(a))s[t[1].toLowerCase()]=t[2]}t=s[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return c?a:null},setRequestHeader:function(e,t){return null==c&&(e=T[e.toLowerCase()]=T[e.toLowerCase()]||e,b[e]=t),this},overrideMimeType:function(e){return null==c&&(h.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)E.always(e[E.status]);else for(t in e)x[t]=[x[t],e[t]];return this},abort:function(e){var t=e||C;return i&&i.abort(t),k(0,t),this}};if(v.promise(E),h.url=((t||h.url||Ct.href)+"").replace(Rt,Ct.protocol+"//"),h.type=n.method||n.type||h.method||h.type,h.dataTypes=(h.dataType||"*").toLowerCase().match(M)||[""],null==h.crossDomain){l=r.createElement("a");try{l.href=h.url,l.href=l.href,h.crossDomain=Bt.protocol+"//"+Bt.host!=l.protocol+"//"+l.host}catch(e){h.crossDomain=!0}}if(h.data&&h.processData&&"string"!=typeof h.data&&(h.data=w.param(h.data,h.traditional)),_t(It,h,n,E),c)return E;(f=w.event&&h.global)&&0==w.active++&&w.event.trigger("ajaxStart"),h.type=h.type.toUpperCase(),h.hasContent=!Mt.test(h.type),o=h.url.replace(Lt,""),h.hasContent?h.data&&h.processData&&0===(h.contentType||"").indexOf("application/x-www-form-urlencoded")&&(h.data=h.data.replace(qt,"+")):(d=h.url.slice(o.length),h.data&&(h.processData||"string"==typeof h.data)&&(o+=(kt.test(o)?"&":"?")+h.data,delete h.data),!1===h.cache&&(o=o.replace(Ht,"$1"),d=(kt.test(o)?"&":"?")+"_="+Et+++d),h.url=o+d),h.ifModified&&(w.lastModified[o]&&E.setRequestHeader("If-Modified-Since",w.lastModified[o]),w.etag[o]&&E.setRequestHeader("If-None-Match",w.etag[o])),(h.data&&h.hasContent&&!1!==h.contentType||n.contentType)&&E.setRequestHeader("Content-Type",h.contentType),E.setRequestHeader("Accept",h.dataTypes[0]&&h.accepts[h.dataTypes[0]]?h.accepts[h.dataTypes[0]]+("*"!==h.dataTypes[0]?", "+$t+"; q=0.01":""):h.accepts["*"]);for(p in h.headers)E.setRequestHeader(p,h.headers[p]);if(h.beforeSend&&(!1===h.beforeSend.call(g,E,h)||c))return E.abort();if(C="abort",m.add(h.complete),E.done(h.success),E.fail(h.error),i=_t(Wt,h,n,E)){if(E.readyState=1,f&&y.trigger("ajaxSend",[E,h]),c)return E;h.async&&h.timeout>0&&(u=e.setTimeout(function(){E.abort("timeout")},h.timeout));try{c=!1,i.send(b,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,r,s){var l,p,d,b,T,C=n;c||(c=!0,u&&e.clearTimeout(u),i=void 0,a=s||"",E.readyState=t>0?4:0,l=t>=200&&t<300||304===t,r&&(b=Xt(h,E,r)),b=Ut(h,b,E,l),l?(h.ifModified&&((T=E.getResponseHeader("Last-Modified"))&&(w.lastModified[o]=T),(T=E.getResponseHeader("etag"))&&(w.etag[o]=T)),204===t||"HEAD"===h.type?C="nocontent":304===t?C="notmodified":(C=b.state,p=b.data,l=!(d=b.error))):(d=C,!t&&C||(C="error",t<0&&(t=0))),E.status=t,E.statusText=(n||C)+"",l?v.resolveWith(g,[p,C,E]):v.rejectWith(g,[E,C,d]),E.statusCode(x),x=void 0,f&&y.trigger(l?"ajaxSuccess":"ajaxError",[E,h,l?p:d]),m.fireWith(g,[E,C]),f&&(y.trigger("ajaxComplete",[E,h]),--w.active||w.event.trigger("ajaxStop")))}return E},getJSON:function(e,t,n){return w.get(e,t,n,"json")},getScript:function(e,t){return w.get(e,void 0,t,"script")}}),w.each(["get","post"],function(e,t){w[t]=function(e,n,r,i){return g(n)&&(i=i||r,r=n,n=void 0),w.ajax(w.extend({url:e,type:t,dataType:i,data:n,success:r},w.isPlainObject(e)&&e))}}),w._evalUrl=function(e){return w.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},w.fn.extend({wrapAll:function(e){var t;return this[0]&&(g(e)&&(e=e.call(this[0])),t=w(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return g(e)?this.each(function(t){w(this).wrapInner(e.call(this,t))}):this.each(function(){var t=w(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=g(e);return this.each(function(n){w(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){w(this).replaceWith(this.childNodes)}),this}}),w.expr.pseudos.hidden=function(e){return!w.expr.pseudos.visible(e)},w.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},w.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Vt={0:200,1223:204},Gt=w.ajaxSettings.xhr();h.cors=!!Gt&&"withCredentials"in Gt,h.ajax=Gt=!!Gt,w.ajaxTransport(function(t){var n,r;if(h.cors||Gt&&!t.crossDomain)return{send:function(i,o){var a,s=t.xhr();if(s.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(a in t.xhrFields)s[a]=t.xhrFields[a];t.mimeType&&s.overrideMimeType&&s.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(a in i)s.setRequestHeader(a,i[a]);n=function(e){return function(){n&&(n=r=s.onload=s.onerror=s.onabort=s.ontimeout=s.onreadystatechange=null,"abort"===e?s.abort():"error"===e?"number"!=typeof s.status?o(0,"error"):o(s.status,s.statusText):o(Vt[s.status]||s.status,s.statusText,"text"!==(s.responseType||"text")||"string"!=typeof s.responseText?{binary:s.response}:{text:s.responseText},s.getAllResponseHeaders()))}},s.onload=n(),r=s.onerror=s.ontimeout=n("error"),void 0!==s.onabort?s.onabort=r:s.onreadystatechange=function(){4===s.readyState&&e.setTimeout(function(){n&&r()})},n=n("abort");try{s.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),w.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),w.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(e){return w.globalEval(e),e}}}),w.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),w.ajaxTransport("script",function(e){if(e.crossDomain){var t,n;return{send:function(i,o){t=w(" + + diff --git a/src/welcome.ts b/src/welcome.ts new file mode 100644 index 0000000..c7d5b0e --- /dev/null +++ b/src/welcome.ts @@ -0,0 +1,7 @@ +import Welcome from './pages/Welcome.vue'; +import { createApp } from 'vue'; +import i18n from './plugins/i18n'; + +const app = createApp(Welcome); +app.use(i18n); +app.mount('body'); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..280fa00 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Node", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ESNext", "DOM"], + "skipLibCheck": true, + "noEmit": true, + }, + "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/tsconfig.node.json b/tsconfig.node.json new file mode 100644 index 0000000..9d31e2a --- /dev/null +++ b/tsconfig.node.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/vite.config.ts b/vite.config.ts new file mode 100644 index 0000000..cf14fdb --- /dev/null +++ b/vite.config.ts @@ -0,0 +1,73 @@ +import { defineConfig } from 'vite'; +import path from 'path'; +import vue from '@vitejs/plugin-vue'; +import webExtension, { readJsonFile } from 'vite-plugin-web-extension'; +import VueI18nPlugin from '@intlify/unplugin-vue-i18n/vite'; +import copy from 'rollup-plugin-copy'; + +const APP_ID = { + chrome: 'hhfnghjdeddcfegfekjeihfmbjenlomm', + edge: 'eepmlmdenlkkjieghjmedjahpofieogf', +}; +const browser = process.env.TARGET || 'chrome'; + +function generateManifest() { + const manifest = readJsonFile('src/manifest.json'); + const pkg = readJsonFile('package.json'); + return { + name: pkg.name, + description: pkg.description, + version: pkg.version, + ...manifest, + }; +} + +// https://vitejs.dev/config/ +export default defineConfig(({ mode }) => ({ + build: { + assetsInlineLimit: 1024, + rollupOptions: { + output: { + assetFileNames: assetInfo => { + let extType = assetInfo.name.split('.').at(1); + if (/png|jpe?g|svg|gif|tiff|bmp|ico/i.test(extType)) { + extType = 'icons'; + } + return `assets/${extType}/[name][extname]`; + }, + }, + }, + + emptyOutDir: false, + sourcemap: mode === 'development' ? 'inline' : false, + minify: mode === 'development' ? false : true, + }, + define: { + 'process.env': process.env, + __EXTENSION_MODE__: JSON.stringify(mode), + __DEV__: mode === 'development', + __PROD__: mode === 'production', + __APP_ID__: JSON.stringify(APP_ID[browser]), + __BROWSER__: JSON.stringify(browser), + }, + plugins: [ + vue(), + VueI18nPlugin({ + include: path.resolve(__dirname, '..', 'src/assets/_locales/*'), + }), + webExtension({ + manifest: generateManifest, + watchFilePaths: ['package.json', 'manifest.json'], + additionalInputs: ['src/block.html', 'src/welcome.html', 'src/offscreen.html'], + }), + copy({ + targets: [ + { src: 'src/_locales', dest: 'dist' }, + { src: 'src/assets/pomodoro-sounds', dest: 'dist/assets' }, + ], + }), + ], + optimizeDeps: { + include: ['vue', 'webextension-polyfill'], + }, +}));