diff --git a/.circleci/config.yml b/.circleci/config.yml new file mode 100644 index 0000000..f6478ba --- /dev/null +++ b/.circleci/config.yml @@ -0,0 +1,102 @@ +# Deployment is configured following these instructions: +# https://circleci.com/blog/deploying-documentation-to-github-pages-with-continuous-integration/ + +version: 2 + +jobs: + test: + working_directory: ~/repo + docker: + - image: circleci/openjdk:11-jdk-stretch-node-browsers + environment: + - CHROME_BIN: "/usr/bin/google-chrome" + steps: + - checkout + - restore_cache: + keys: + - build_cache-{{ checksum "package.json" }}-{{ checksum "shadow-cljs.edn" }} + - run: + name: Install dependencies + command: npm install + - run: + name: Test + command: npm test + - save_cache: + paths: + - node_modules + - .shadow-cljs + - ~/.m2 + - ~/.npm + key: build_cache-{{ checksum "package.json" }}-{{ checksum "shadow-cljs.edn" }} + build: + working_directory: ~/repo + docker: + - image: circleci/openjdk:11-jdk-stretch-node-browsers + steps: + - checkout + - restore_cache: + keys: + - build_cache-{{ checksum "package.json" }}-{{ checksum "shadow-cljs.edn" }} + - run: + name: Install dependencies + command: npm install + - run: + name: Build SPA + command: npm run build + - save_cache: + paths: + - node_modules + - .shadow-cljs + - ~/.m2 + - ~/.npm + key: build_cache-{{ checksum "package.json" }}-{{ checksum "shadow-cljs.edn" }} + - persist_to_workspace: + root: /home/circleci/repo/public + paths: + - "*" + deploy: + working_directory: ~/repo + docker: + - image: circleci/openjdk:11-jdk-stretch-node-browsers + steps: + - add_ssh_keys: + fingerprints: + - "85:2f:28:0f:b9:45:b8:f1:0f:c2:0a:1c:5e:4d:a2:06" + - checkout + - attach_workspace: + at: /home/circleci/repo/public + - restore_cache: + keys: + - build_cache-{{ checksum "package.json" }}-{{ checksum "shadow-cljs.edn" }} + - run: + name: Install dependencies + command: npm install + - run: + name: Deploy to gh-pages branch + command: | + git config user.email "build@circleci.com" + git config user.name "ci-build" + npm run deploy + +workflows: + version: 2 + test-build-deploy: + jobs: + - test: + filters: + branches: + ignore: + - gh-pages + - build: + requires: + - test + filters: + branches: + ignore: + - gh-pages + - deploy: + requires: + - build + filters: + branches: + only: master diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f528101 --- /dev/null +++ b/.gitignore @@ -0,0 +1,76 @@ +.nrepl-port +.rebel_readline_history +.shadow-cljs/ +node_modules/ +public/* + +# Created by https://www.gitignore.io/api/emacs + +### Emacs ### +# -*- mode: gitignore; -*- +*~ +\#*\# +/.emacs.desktop +/.emacs.desktop.lock +*.elc +auto-save-list +tramp +.\#* + +# Org-mode +.org-id-locations +*_archive + +# flymake-mode +*_flymake.* + +# eshell files +/eshell/history +/eshell/lastdir + +# elpa packages +/elpa/ + +# reftex files +*.rel + +# AUCTeX auto folder +/auto/ + +# cask packages +.cask/ +dist/ + +# Flycheck +flycheck_*.el + +# server auth directory +/server/ + +# projectiles files +.projectile +projectile-bookmarks.eld + +# directory configuration +.dir-locals.el + +# saveplace +places + +# url cache +url/cache/ + +# cedet +ede-projects.el + +# smex +smex-items + +# company-statistics +company-statistics-cache.el + +# anaconda-mode +anaconda-mode/ + + +# End of https://www.gitignore.io/api/emacs diff --git a/.joker b/.joker new file mode 100644 index 0000000..e0557b9 --- /dev/null +++ b/.joker @@ -0,0 +1,2 @@ +{:known-macros [cljs.test/deftest] + :known-namespaces [cljs.core]} \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..94a9ed0 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,674 @@ + 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 +. diff --git a/README.md b/README.md new file mode 100644 index 0000000..cbc6af4 --- /dev/null +++ b/README.md @@ -0,0 +1,79 @@ +# Airsonic Web Client [![CircleCI](https://circleci.com/gh/heyarne/airsonic-ui.svg?style=svg)](https://circleci.com/gh/heyarne/airsonic-ui) [![Greenkeeper badge](https://badges.greenkeeper.io/heyarne/airsonic-ui.svg)](https://greenkeeper.io/) + +This repository contains an alternative web frontend for [airsonic](https://github.com/airsonic/airsonic). The goal is to eventually be able to fully replace the current web interface. + +## Implemented So Far + +* Login with persisting credentials +* Browse your library by newest / most recently played / starred +* Browse artists alphabetically +* A currently playing queue with next, previous, repeat and shuffle +* Information about the current track with the ability to seek + +## How Do I Host This Myself? + +There are two options: + +- You build it yourself by cloning the repository and running `npm run build` +- You grab a pre-built version from the [gh-pages branch](https://github.com/heyarne/airsonic-ui/tree/gh-pages) (just click the download button) + +The files you receive either way should be identical. There's [an article about setting up nginx](https://github.com/heyarne/airsonic-ui/wiki/Self%E2%80%93hosting) in the repository wiki. + +If you have any questions please ask them in the [airsonic matrix channel](https://riot.im/app/#/room/#airsonic:matrix.org). + +## Development + +The project is written in [ClojureScript](https://clojurescript.org/) and uses [re-frame](https://github.com/Day8/re-frame) for structure and peace of mind. The build tool is [shadow-cljs](https://shadow-cljs.github.io/docs/UsersGuide.html), which offers nice editor integration and interoparibility with the whole JavaScript ecosystem. +If you haven't worked with re-frame: I highly recommend it. Good resources are the project's [docs](https://github.com/Day8/re-frame/tree/master/docs) and a [post about its building blocks](https://purelyfunctional.tv/guide/re-frame-building-blocks/). + +To build the project make sure you have Node.js (v22.0.0), npm, [entr](https://github.com/eradman/entr) and Java 8 installed in your system. + +``` +# after cloning the project, first install all dependencies +$ npm install + +# start a continuous build with hot-code-reloading and continuous testing +# first build takes a while. open http://localhost:8080 +$ npm run dev +``` + +All other build tasks are defined in the `package.json` (more below). + +### Editor Integration + +Integrating shadow-cljs with your editor helps tremendously with development. After having run `npm run dev` as described above you can connect to the REPL and get features like in-editor code execution and code completion / documentation lookup. For further information see [this part of the shadow-cljs user guide](https://shadow-cljs.github.io/docs/UsersGuide.html#_editor_integration). Recommended editors and plugins are Calva for VSCode and CIDER for Emacs (comes with Spacemacs). Make sure to open `localhost:8080` in the browser after starting the `dev:cljs` task to execute ClojureScript code in a live REPL. + +### re-frame-10x + +re-frame-10x is a debugger that is bundled with the app in development mode. Once you have the build running, hit `Ctrl + h` and the re-frame-10x window will show up: + +![re-frame-10x in action](./docs/re-frame-10x.png) + +It provides you with tools to inspect the state of the application, undo and replay events, debug performance issues and more. + +## Tests + +This project uses [karma](https://karma-runner.github.io/) for tests. There is a check inside `karma.conf.js` to see whether Firefox is installed (via `which firefox` which probably breaks on Windows 🤷); if that command doesn't fail it will be used as the test runner. Otherwise Chrome will be used. If you have Chromium installed, make sure to set the `CHROME_BIN` environment variable to point to Chromium. + +``` +# run tests once +$ npm test +``` + +**Note:** If you want nice console output in your tests, make sure to `(enable-console-print!)`. You can call `println` afterwards like you're used to. + +## Deployment + +``` +# build and optimize the code once for production +$ npm run build + +# publishes everything via gh-pages +$ npm run deploy +``` + +There is continuous deployment set up on [circleci](https://circleci.com/gh/heyarne/airsonic-ui) that builds and deploys to `gh-pages` after a commit to the `master` branch. + +**Note:** If you have a continuous build running and run `npm run build` or `npm run deploy`, it will delete the compiled tests, causing the continuous tests to not run anymore. This can be fixed by running `npm test` again. + +All build artifacts land in `/public`. Don't change anything in there as changes will be overwritten. diff --git a/app/js/main.js b/app/js/main.js deleted file mode 100644 index f5110d4..0000000 --- a/app/js/main.js +++ /dev/null @@ -1,1476 +0,0 @@ -var shadow$provide = {}; -if(typeof Math.imul == "undefined" || (Math.imul(0xffffffff,5) == 0)) { - Math.imul = function (a, b) { - var ah = (a >>> 16) & 0xffff; - var al = a & 0xffff; - var bh = (b >>> 16) & 0xffff; - var bl = b & 0xffff; - // the shift by 0 fixes the sign on the high part - // the final |0 converts the unsigned value into a signed value - return ((al * bl) + (((ah * bl + al * bh) << 16) >>> 0)|0); - } -} -(function(){ -shadow$provide.module$node_modules$object_assign$index=function(k,u,q,r,n,H){var B=Object.getOwnPropertySymbols,g=Object.prototype.hasOwnProperty,z=Object.prototype.propertyIsEnumerable;r.exports=function(){try{if(!Object.assign)return!1;var g=new String("abc");g[5]="de";if("5"===Object.getOwnPropertyNames(g)[0])return!1;var k={};for(g=0;10>g;g++)k["_"+String.fromCharCode(g)]=g;if("0123456789"!==Object.getOwnPropertyNames(k).map(function(g){return k[g]}).join(""))return!1;var h={};"abcdefghijklmnopqrst".split("").forEach(function(g){h[g]= -g});return"abcdefghijklmnopqrst"!==Object.keys(Object.assign({},h)).join("")?!1:!0}catch(fa){return!1}}()?Object.assign:function(k,n){if(null===k||void 0===k)throw new TypeError("Object.assign cannot be called with null or undefined");var h=Object(k);for(var m,q=1;qL.length&&L.push(f)}function ua(f,y,h,t){var k=typeof f;if("undefined"===k||"boolean"===k)f=null;var m=!1;if(null===f)m=!0;else switch(k){case "string":case "number":m= -!0;break;case "object":switch(f.$$typeof){case X:case qb:m=!0}}if(m)return h(t,f,""===y?"."+U(f,0):y),1;m=0;y=""===y?".":y+":";if(Array.isArray(f))for(var L=0;L=f){k=g;break}g=g.next}while(g!==h);null===k?k=h:k===h&&(h=q,B());f=k.previous;f.next=k.previous=q;q.next=k;q.previous=f}}function z(){if(-1===x&&null!==h&&1===h.priorityLevel){za=!0;try{do g();while(null!==h&&1===h.priorityLevel)}finally{za=!1,null!==h?B():ua=!1}}}function m(k){za=!0;var f=fa;fa=k;try{if(k)for(;null!==h;){var m=n.unstable_now();if(h.expirationTime<=m){do g();while(null!==h&&h.expirationTime<=m)}else break}else if(null!==h){do g();while(null!== -h&&!ja())}}finally{za=!1,fa=f,null!==h?B():ua=!1,z()}}function F(g){A=Y(function(f){Za(P);g(f)});P=U(function(){ia(A);g(n.unstable_now())},100)}Object.defineProperty(n,"__esModule",{value:!0});var h=null,fa=!1,N=3,x=-1,ra=-1,za=!1,ua=!1,na=Date,U="function"===typeof setTimeout?setTimeout:void 0,Za="function"===typeof clearTimeout?clearTimeout:void 0,Y="function"===typeof requestAnimationFrame?requestAnimationFrame:void 0,ia="function"===typeof cancelAnimationFrame?cancelAnimationFrame:void 0,A,P; -if("object"===typeof performance&&"function"===typeof performance.now){var t=performance;n.unstable_now=function(){return t.now()}}else n.unstable_now=function(){return na.now()};u=null;"undefined"!==typeof window?u=window:"undefined"!==typeof k&&(u=k);if(u&&u._schedMock){k=u._schedMock;var X=k[0];var qb=k[1];var ja=k[2];n.unstable_now=k[3]}else if("undefined"===typeof window||"function"!==typeof MessageChannel){var ka=null,ab=function(g){if(null!==ka)try{ka(g)}finally{ka=null}};X=function(g){null!== -ka?setTimeout(X,0,g):(ka=g,setTimeout(ab,0,!1))};qb=function(){ka=null};ja=function(){return!1}}else{"undefined"!==typeof console&&("function"!==typeof Y&&console.error("This browser doesn't support requestAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"),"function"!==typeof ia&&console.error("This browser doesn't support cancelAnimationFrame. Make sure that you load a polyfill in older browsers. https://fb.me/react-polyfills"));var va=null,wa=!1, -ha=-1,I=!1,Xa=!1,La=0,ta=33,sa=33;ja=function(){return La<=n.unstable_now()};k=new MessageChannel;var Ya=k.port2;k.port1.onmessage=function(){wa=!1;var g=va,f=ha;va=null;ha=-1;var h=n.unstable_now(),k=!1;if(0>=La-h)if(-1!==f&&f<=h)k=!0;else{I||(I=!0,F($a));va=g;ha=f;return}if(null!==g){Xa=!0;try{g(k)}finally{Xa=!1}}};var $a=function(g){if(null!==va){F($a);var f=g-La+sa;ff&&(f=8),sa=f -f?Ya.postMessage(void 0):I||(I=!0,F($a))};qb=function(){va=null;wa=!1;ha=-1}}n.unstable_ImmediatePriority=1;n.unstable_UserBlockingPriority=2;n.unstable_NormalPriority=3;n.unstable_IdlePriority=5;n.unstable_LowPriority=4;n.unstable_runWithPriority=function(g,f){switch(g){case 1:case 2:case 3:case 4:case 5:break;default:g=3}var h=N,k=x;N=g;x=n.unstable_now();try{return f()}finally{N=h,x=k,z()}};n.unstable_scheduleCallback=function(g,f){var k=-1!==x?x:n.unstable_now();if("object"===typeof f&&null!== -f&&"number"===typeof f.timeout)f=k+f.timeout;else switch(N){case 1:f=k+-1;break;case 2:f=k+250;break;case 5:f=k+1073741823;break;case 4:f=k+1E4;break;default:f=k+5E3}g={callback:g,priorityLevel:N,expirationTime:f,next:null,previous:null};if(null===h)h=g.next=g.previous=g,B();else{k=null;var m=h;do{if(m.expirationTime>f){k=m;break}m=m.next}while(m!==h);null===k?k=h:k===h&&(h=g,B());f=k.previous;f.next=k.previous=g;g.next=k;g.previous=f}return g};n.unstable_cancelCallback=function(g){var f=g.next;if(null!== -f){if(f===g)h=null;else{g===h&&(h=f);var k=g.previous;k.next=f;f.previous=k}g.next=g.previous=null}};n.unstable_wrapCallback=function(g){var f=N;return function(){var k=N,h=x;N=f;x=n.unstable_now();try{return g.apply(this,arguments)}finally{N=k,x=h,z()}}};n.unstable_getCurrentPriorityLevel=function(){return N};n.unstable_shouldYield=function(){return!fa&&(null!==h&&h.expirationTimethis.eventPool.length&&this.eventPool.push(a)}function ta(a){a.eventPool=[];a.getPooled=Xa;a.release=La}function sa(a,b){switch(a){case "keyup":return-1!==Ch.indexOf(b.keyCode); -case "keydown":return 229!==b.keyCode;case "keypress":case "mousedown":case "blur":return!0;default:return!1}}function Ya(a){a=a.detail;return"object"===typeof a&&"data"in a?a.data:null}function $a(a,b){switch(a){case "compositionend":return Ya(b);case "keypress":if(32!==b.which)return null;mf=!0;return nf;case "textInput":return a=b.data,a===nf&&mf?null:a;default:return null}}function L(a,b){if(Cb)return"compositionend"===a||!Ld&&sa(a,b)?(a=va(),Pc=Kd=bb=null,Cb=!1,a):null;switch(a){case "paste":return null; -case "keypress":if(!(b.ctrlKey||b.altKey||b.metaKey)||b.ctrlKey&&b.altKey){if(b.char&&1b}return!1}function la(a,b,c,d,e){this.acceptsBooleans=2===b||3===b||4===b;this.attributeName=d;this.attributeNamespace=e;this.mustUseProperty=c;this.propertyName=a;this.type=b}function Td(a){return a[1].toUpperCase()}function Ud(a,b,c,d){var e=Q.hasOwnProperty(b)?Q[b]:null;(null!==e?0===e.type:d?0:2Yc.length&&Yc.push(a)}}}function Mf(a){Object.prototype.hasOwnProperty.call(a,Zc)||(a[Zc]=Vh++,Nf[a[Zc]]={});return Nf[a[Zc]]}function $d(a){a=a||("undefined"!==typeof document?document:void 0);if("undefined"===typeof a)return null;try{return a.activeElement||a.body}catch(b){return a.body}} -function Of(a){for(;a&&a.firstChild;)a=a.firstChild;return a}function Pf(a,b){var c=Of(a);a=0;for(var d;c;){if(3===c.nodeType){d=a+c.textContent.length;if(a<=b&&d>=b)return{node:c,offset:b-a};a=d}a:{for(;c;){if(c.nextSibling){c=c.nextSibling;break a}c=c.parentNode}c=void 0}c=Of(c)}}function Qf(a,b){return a&&b?a===b?!0:a&&3===a.nodeType?!1:b&&3===b.nodeType?Qf(a,b.parentNode):"contains"in a?a.contains(b):a.compareDocumentPosition?!!(a.compareDocumentPosition(b)&16):!1:!1}function Rf(){for(var a=window, -b=$d();b instanceof a.HTMLIFrameElement;){try{a=b.contentDocument.defaultView}catch(c){break}b=$d(a.document)}return b}function ae(a){var b=a&&a.nodeName&&a.nodeName.toLowerCase();return b&&("input"===b&&("text"===a.type||"search"===a.type||"tel"===a.type||"url"===a.type||"password"===a.type)||"textarea"===b||"true"===a.contentEditable)}function Sf(a,b){var c=b.window===b?b.document:9===b.nodeType?b:b.ownerDocument;if(be||null==Gb||Gb!==$d(c))return null;c=Gb;"selectionStart"in c&&ae(c)?c={start:c.selectionStart, -end:c.selectionEnd}:(c=(c.ownerDocument&&c.ownerDocument.defaultView||window).getSelection(),c={anchorNode:c.anchorNode,anchorOffset:c.anchorOffset,focusNode:c.focusNode,focusOffset:c.focusOffset});return hc&&fc(hc,c)?null:(hc=c,a=I.getPooled(Tf.select,ce,a,b),a.type="select",a.target=Gb,ja(a),a)}function Wh(a){var b="";$c.Children.forEach(a,function(a){null!=a&&(b+=a)});return b}function de(a,b){a=T({children:void 0},b);if(b=Wh(b.children))a.children=b;return a}function Hb(a,b,c,d){a=a.options;if(b){b= -{};for(var e=0;e=b.length?void 0:g("93"),b=b[0]),c=b),null==c&&(c=""));a._wrapperState={initialValue:fb(c)}}function Vf(a,b){var c=fb(b.value),d=fb(b.defaultValue);null!=c&&(c=""+c,c!==a.value&&(a.value=c),null==b.defaultValue&&a.defaultValue!==c&&(a.defaultValue=c));null!=d&&(a.defaultValue=""+d)}function Wf(a){var b=a.textContent;b===a._wrapperState.initialValue&&(a.value=b)}function Xf(a){switch(a){case "svg":return"http://www.w3.org/2000/svg"; -case "math":return"http://www.w3.org/1998/Math/MathML";default:return"http://www.w3.org/1999/xhtml"}}function fe(a,b){return null==a||"http://www.w3.org/1999/xhtml"===a?Xf(b):"http://www.w3.org/2000/svg"===a&&"foreignObject"===b?"http://www.w3.org/1999/xhtml":a}function ic(a,b){if(b){var c=a.firstChild;if(c&&c===a.lastChild&&3===c.nodeType){c.nodeValue=b;return}}a.textContent=b}function Yf(a,b,c){return null==b||"boolean"===typeof b||""===b?"":c||"number"!==typeof b||0===b||jc.hasOwnProperty(a)&& -jc[a]?(""+b).trim():b+"px"}function Zf(a,b){a=a.style;for(var c in b)if(b.hasOwnProperty(c)){var d=0===c.indexOf("--"),e=Yf(c,b[c],d);"float"===c&&(c="cssFloat");d?a.setProperty(c,e):a[c]=e}}function ge(a,b){b&&(Xh[a]&&(null!=b.children||null!=b.dangerouslySetInnerHTML?g("137",a,""):void 0),null!=b.dangerouslySetInnerHTML&&(null!=b.children?g("60"):void 0,"object"===typeof b.dangerouslySetInnerHTML&&"__html"in b.dangerouslySetInnerHTML?void 0:g("61")),null!=b.style&&"object"!==typeof b.style?g("62", -""):void 0)}function he(a,b){if(-1===a.indexOf("-"))return"string"===typeof b.is;switch(a){case "annotation-xml":case "color-profile":case "font-face":case "font-face-src":case "font-face-uri":case "font-face-format":case "font-face-name":case "missing-glyph":return!1;default:return!0}}function Na(a,b){a=9===a.nodeType||11===a.nodeType?a:a.ownerDocument;var c=Mf(a);b=Hd[b];for(var d=0;dIb||(a.current=ke[Ib],ke[Ib]=null,Ib--)}function ma(a,b){Ib++;ke[Ib]=a.current;a.current=b}function Jb(a,b){var c=a.type.contextTypes;if(!c)return gb;var d=a.stateNode;if(d&&d.__reactInternalMemoizedUnmaskedChildContext=== -b)return d.__reactInternalMemoizedMaskedChildContext;var e={},l;for(l in c)e[l]=b[l];d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext=b,a.__reactInternalMemoizedMaskedChildContext=e);return e}function aa(a){a=a.childContextTypes;return null!==a&&void 0!==a}function bd(a){Z(oa,a);Z(ba,a)}function le(a){Z(oa,a);Z(ba,a)}function cg(a,b,c){ba.current!==gb?g("168"):void 0;ma(ba,b,a);ma(oa,c,a)}function dg(a,b,c){var d=a.stateNode;a=b.childContextTypes;if("function"!==typeof d.getChildContext)return c; -d=d.getChildContext();for(var e in d)e in a?void 0:g("108",db(b)||"Unknown",e);return T({},c,d)}function cd(a){var b=a.stateNode;b=b&&b.__reactInternalMemoizedMergedChildContext||gb;sb=ba.current;ma(ba,b,a);ma(oa,oa.current,a);return!0}function eg(a,b,c){var d=a.stateNode;d?void 0:g("169");c?(b=dg(a,b,sb),d.__reactInternalMemoizedMergedChildContext=b,Z(oa,a),Z(ba,a),ma(ba,b,a)):Z(oa,a);ma(oa,c,a)}function fg(a){return function(b){try{return a(b)}catch(c){}}}function Zh(a){if("undefined"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__)return!1; -var b=__REACT_DEVTOOLS_GLOBAL_HOOK__;if(b.isDisabled||!b.supportsFiber)return!0;try{var c=b.inject(a);me=fg(function(a){return b.onCommitFiberRoot(c,a)});ne=fg(function(a){return b.onCommitFiberUnmount(c,a)})}catch(d){}return!0}function $h(a,b,c,d){this.tag=a;this.key=c;this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null;this.index=0;this.ref=null;this.pendingProps=b;this.contextDependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null;this.mode=d;this.effectTag= -0;this.lastEffect=this.firstEffect=this.nextEffect=null;this.childExpirationTime=this.expirationTime=0;this.alternate=null}function Aa(a,b,c,d){return new $h(a,b,c,d)}function oe(a){a=a.prototype;return!(!a||!a.isReactComponent)}function ai(a){if("function"===typeof a)return oe(a)?1:0;if(void 0!==a&&null!==a){a=a.$$typeof;if(a===Qd)return 11;if(a===Rd)return 14}return 2}function tb(a,b){var c=a.alternate;null===c?(c=Aa(a.tag,b,a.key,a.mode),c.elementType=a.elementType,c.type=a.type,c.stateNode=a.stateNode, -c.alternate=a,a.alternate=c):(c.pendingProps=b,c.effectTag=0,c.nextEffect=null,c.firstEffect=null,c.lastEffect=null);c.childExpirationTime=a.childExpirationTime;c.expirationTime=a.expirationTime;c.child=a.child;c.memoizedProps=a.memoizedProps;c.memoizedState=a.memoizedState;c.updateQueue=a.updateQueue;c.contextDependencies=a.contextDependencies;c.sibling=a.sibling;c.index=a.index;c.ref=a.ref;return c}function dd(a,b,c,d,e,l){var p=2;d=a;if("function"===typeof a)oe(a)&&(p=1);else if("string"===typeof a)p= -5;else a:switch(a){case eb:return hb(c.children,e,l,b);case Od:return gg(c,e|3,l,b);case Pd:return gg(c,e|2,l,b);case Rc:return a=Aa(12,c,b,e|4),a.elementType=Rc,a.type=Rc,a.expirationTime=l,a;case Sc:return a=Aa(13,c,b,e),a.elementType=Sc,a.type=Sc,a.expirationTime=l,a;default:if("object"===typeof a&&null!==a)switch(a.$$typeof){case uf:p=10;break a;case tf:p=9;break a;case Qd:p=11;break a;case Rd:p=14;break a;case vf:p=16;d=null;break a}g("130",null==a?a:typeof a,"")}b=Aa(p,c,b,e);b.elementType= -a;b.type=d;b.expirationTime=l;return b}function hb(a,b,c,d){a=Aa(7,a,d,b);a.expirationTime=c;return a}function gg(a,b,c,d){a=Aa(8,a,d,b);b=0===(b&1)?Pd:Od;a.elementType=b;a.type=b;a.expirationTime=c;return a}function pe(a,b,c){a=Aa(6,a,null,b);a.expirationTime=c;return a}function qe(a,b,c){b=Aa(4,null!==a.children?a.children:[],a.key,b);b.expirationTime=c;b.stateNode={containerInfo:a.containerInfo,pendingChildren:null,implementation:a.implementation};return b}function lc(a,b){a.didError=!1;var c= -a.earliestPendingTime;0===c?a.earliestPendingTime=a.latestPendingTime=b:cb&&(a.latestPendingTime=b);ed(b,a)}function hg(a,b){a.didError=!1;a.latestPingedTime>=b&&(a.latestPingedTime=0);var c=a.earliestPendingTime,d=a.latestPendingTime;c===b?a.earliestPendingTime=d===b?a.latestPendingTime=0:d:d===b&&(a.latestPendingTime=c);c=a.earliestSuspendedTime;d=a.latestSuspendedTime;0===c?a.earliestSuspendedTime=a.latestSuspendedTime=b:cb&&(a.latestSuspendedTime=b);ed(b,a)}function ig(a,b){var c=a.earliestPendingTime;a=a.earliestSuspendedTime;c>b&&(b=c);a>b&&(b=a);return b}function ed(a,b){var c=b.earliestSuspendedTime,d=b.latestSuspendedTime,e=b.earliestPendingTime,l=b.latestPingedTime;e=0!==e?e:l;0===e&&(0===a||da&&(a=c);b.nextExpirationTimeToWorkOn=e;b.expirationTime=a}function xa(a,b){if(a&&a.defaultProps){b=T({},b);a=a.defaultProps;for(var c in a)void 0===b[c]&&(b[c]=a[c])}return b}function bi(a){var b= -a._result;switch(a._status){case 1:return b;case 2:throw b;case 0:throw b;default:a._status=0;b=a._ctor;b=b();b.then(function(b){0===a._status&&(b=b.default,a._status=1,a._result=b)},function(b){0===a._status&&(a._status=2,a._result=b)});switch(a._status){case 1:return a._result;case 2:throw a._result;}a._result=b;throw b;}}function fd(a,b,c,d){b=a.memoizedState;c=c(d,b);c=null===c||void 0===c?b:T({},b,c);a.memoizedState=c;d=a.updateQueue;null!==d&&0===a.expirationTime&&(d.baseState=c)}function jg(a, -b,c,d,e,l,p){a=a.stateNode;return"function"===typeof a.shouldComponentUpdate?a.shouldComponentUpdate(d,l,p):b.prototype&&b.prototype.isPureReactComponent?!fc(c,d)||!fc(e,l):!0}function kg(a,b,c){var d=!1,e=gb,l=b.contextType;"object"===typeof l&&null!==l?l=Ba(l):(e=aa(b)?sb:ba.current,d=b.contextTypes,l=(d=null!==d&&void 0!==d)?Jb(a,e):gb);b=new b(c,l);a.memoizedState=null!==b.state&&void 0!==b.state?b.state:null;b.updater=gd;a.stateNode=b;b._reactInternalFiber=a;d&&(a=a.stateNode,a.__reactInternalMemoizedUnmaskedChildContext= -e,a.__reactInternalMemoizedMaskedChildContext=l);return b}function lg(a,b,c,d){a=b.state;"function"===typeof b.componentWillReceiveProps&&b.componentWillReceiveProps(c,d);"function"===typeof b.UNSAFE_componentWillReceiveProps&&b.UNSAFE_componentWillReceiveProps(c,d);b.state!==a&&gd.enqueueReplaceState(b,b.state,null)}function re(a,b,c,d){var e=a.stateNode;e.props=c;e.state=a.memoizedState;e.refs=mg;var l=b.contextType;"object"===typeof l&&null!==l?e.context=Ba(l):(l=aa(b)?sb:ba.current,e.context= -Jb(a,l));l=a.updateQueue;null!==l&&(mc(a,l,c,e,d),e.state=a.memoizedState);l=b.getDerivedStateFromProps;"function"===typeof l&&(fd(a,b,l,c),e.state=a.memoizedState);"function"===typeof b.getDerivedStateFromProps||"function"===typeof e.getSnapshotBeforeUpdate||"function"!==typeof e.UNSAFE_componentWillMount&&"function"!==typeof e.componentWillMount||(b=e.state,"function"===typeof e.componentWillMount&&e.componentWillMount(),"function"===typeof e.UNSAFE_componentWillMount&&e.UNSAFE_componentWillMount(), -b!==e.state&&gd.enqueueReplaceState(e,e.state,null),l=a.updateQueue,null!==l&&(mc(a,l,c,e,d),e.state=a.memoizedState));"function"===typeof e.componentDidMount&&(a.effectTag|=4)}function nc(a,b,c){a=c.ref;if(null!==a&&"function"!==typeof a&&"object"!==typeof a){if(c._owner){c=c._owner;var d=void 0;c&&(1!==c.tag?g("309"):void 0,d=c.stateNode);d?void 0:g("147",a);var e=""+a;if(null!==b&&null!==b.ref&&"function"===typeof b.ref&&b.ref._stringRef===e)return b.ref;b=function(a){var b=d.refs;b===mg&&(b=d.refs= -{});null===a?delete b[e]:b[e]=a};b._stringRef=e;return b}"string"!==typeof a?g("284"):void 0;c._owner?void 0:g("290",a)}return a}function hd(a,b){"textarea"!==a.type&&g("31","[object Object]"===Object.prototype.toString.call(b)?"object with keys {"+Object.keys(b).join(", ")+"}":b,"")}function ng(a){function b(b,c){if(a){var d=b.lastEffect;null!==d?(d.nextEffect=c,b.lastEffect=c):b.firstEffect=b.lastEffect=c;c.nextEffect=null;c.effectTag=8}}function c(c,d){if(!a)return null;for(;null!==d;)b(c,d),d= -d.sibling;return null}function d(a,b){for(a=new Map;null!==b;)null!==b.key?a.set(b.key,b):a.set(b.index,b),b=b.sibling;return a}function e(a,b,c){a=tb(a,b,c);a.index=0;a.sibling=null;return a}function l(b,c,d){b.index=d;if(!a)return c;d=b.alternate;if(null!==d)return d=d.index,dG?(O=h,h=null):O=h.sibling;var m=q(e,h,g[G],f);if(null===m){null===h&&(h=O);break}a&&h&&null===m.alternate&&b(e,h);p=l(m,p,G);null===C?k=m:C.sibling=m;C=m;h=O}if(G===g.length)return c(e,h),k;if(null===h){for(;GO?(m=G,G=null):m=G.sibling;var w=q(e,G,J.value,k);if(null===w){G||(G=m);break}a&&G&&null===w.alternate&&b(e,G);p=l(w,p,O); -null===h?C=w:h.sibling=w;h=w;G=m}if(J.done)return c(e,G),C;if(null===G){for(;!J.done;O++,J=f.next())J=n(e,J.value,k),null!==J&&(p=l(J,p,O),null===h?C=J:h.sibling=J,h=J);return C}for(G=d(e,G);!J.done;O++,J=f.next())J=r(G,e,O,J.value,k),null!==J&&(a&&null!==J.alternate&&G.delete(null===J.key?O:J.key),p=l(J,p,O),null===h?C=J:h.sibling=J,h=J);a&&G.forEach(function(a){return b(e,a)});return C}return function(a,d,l,f){var C="object"===typeof l&&null!==l&&l.type===eb&&null===l.key;C&&(l=l.props.children); -var h="object"===typeof l&&null!==l;if(h)switch(l.$$typeof){case id:a:{h=l.key;for(C=d;null!==C;){if(C.key===h)if(7===C.tag?l.type===eb:C.elementType===l.type){c(a,C.sibling);d=e(C,l.type===eb?l.props.children:l.props,f);d.ref=nc(a,C,l);d.return=a;a=d;break a}else{c(a,C);break}else b(a,C);C=C.sibling}l.type===eb?(d=hb(l.props.children,a.mode,f,l.key),d.return=a,a=d):(f=dd(l.type,l.key,l.props,null,a.mode,f),f.ref=nc(a,d,l),f.return=a,a=f)}return p(a);case Fb:a:{for(C=l.key;null!==d;){if(d.key===C)if(4=== -d.tag&&d.stateNode.containerInfo===l.containerInfo&&d.stateNode.implementation===l.implementation){c(a,d.sibling);d=e(d,l.children||[],f);d.return=a;a=d;break a}else{c(a,d);break}else b(a,d);d=d.sibling}d=qe(l,a.mode,f);d.return=a;a=d}return p(a)}if("string"===typeof l||"number"===typeof l)return l=""+l,null!==d&&6===d.tag?(c(a,d.sibling),d=e(d,l,f),d.return=a,a=d):(c(a,d),d=pe(l,a.mode,f),d.return=a,a=d),p(a);if(jd(l))return t(a,d,l,f);if(cc(l))return v(a,d,l,f);h&&hd(a,l);if("undefined"===typeof l&& -!C)switch(a.tag){case 1:case 0:f=a.type,g("152",f.displayName||f.name||"Component")}return c(a,d)}}function ub(a){a===oc?g("174"):void 0;return a}function te(a,b){ma(pc,b,a);ma(qc,a,a);ma(Ca,oc,a);var c=b.nodeType;switch(c){case 9:case 11:b=(b=b.documentElement)?b.namespaceURI:fe(null,"");break;default:c=8===c?b.parentNode:b,b=c.namespaceURI||null,c=c.tagName,b=fe(b,c)}Z(Ca,a);ma(Ca,b,a)}function Kb(a){Z(Ca,a);Z(qc,a);Z(pc,a)}function og(a){ub(pc.current);var b=ub(Ca.current),c=fe(b,a.type);b!==c&& -(ma(qc,a,a),ma(Ca,c,a))}function ue(a){qc.current===a&&(Z(Ca,a),Z(qc,a))}function Da(){g("307")}function ve(a,b){if(null===b)return!1;for(var c=0;cuc&&(uc=m)):l=h.eagerReducer===a?h.eagerState:a(l,h.action);p=h;h=h.next}while(null!==h&&h!==d);k||(f=p,e=l);rb(l,b.memoizedState)||(Pa=!0);b.memoizedState=l;b.baseUpdate=f;b.baseState=e;c.eagerReducer=a;c.eagerState=l}return[b.memoizedState,c.dispatch]}function ze(a,b,c,d){a={tag:a,create:b,destroy:c,deps:d,next:null}; -null===Fa?(Fa={lastEffect:null},Fa.lastEffect=a.next=a):(b=Fa.lastEffect,null===b?Fa.lastEffect=a.next=a:(c=b.next,b.next=a,a.next=c,Fa.lastEffect=a));return a}function Ae(a,b,c,d){var e=Nb();vc|=a;e.memoizedState=ze(b,c,void 0,void 0===d?null:d)}function Be(a,b,c,d){var e=wc();d=void 0===d?null:d;var l=void 0;if(null!==R){var p=R.memoizedState;l=p.destroy;if(null!==d&&ve(d,p.deps)){ze(Ob,c,l,d);return}}vc|=a;e.memoizedState=ze(b,c,l,d)}function sg(a,b){if("function"===typeof b)return a=a(),b(a), -function(){b(null)};if(null!==b&&void 0!==b)return a=a(),b.current=a,function(){b.current=null}}function tg(){}function ug(a,b,c){25>tc?void 0:g("301");var d=a.alternate;if(a===ib||null!==d&&d===ib)if(sc=!0,a={expirationTime:rc,action:c,eagerReducer:null,eagerState:null,next:null},null===Oa&&(Oa=new Map),c=Oa.get(b),void 0===c)Oa.set(b,a);else{for(b=c;null!==b.next;)b=b.next;b.next=a}else{Pb();var e=Qa();e=Qb(e,a);var l={expirationTime:e,action:c,eagerReducer:null,eagerState:null,next:null},p=b.last; -if(null===p)l.next=l;else{var f=p.next;null!==f&&(l.next=f);p.next=l}b.last=l;if(0===a.expirationTime&&(null===d||0===d.expirationTime)&&(d=b.eagerReducer,null!==d))try{var h=b.eagerState,k=d(h,c);l.eagerReducer=d;l.eagerState=k;if(rb(k,h))return}catch(J){}finally{}jb(a,e)}}function vg(a,b){var c=Aa(5,null,null,0);c.elementType="DELETED";c.type="DELETED";c.stateNode=b;c.return=a;c.effectTag=8;null!==a.lastEffect?(a.lastEffect.nextEffect=c,a.lastEffect=c):a.firstEffect=a.lastEffect=c}function wg(a, -b){switch(a.tag){case 5:var c=a.type;b=1!==b.nodeType||c.toLowerCase()!==b.nodeName.toLowerCase()?null:b;return null!==b?(a.stateNode=b,!0):!1;case 6:return b=""===a.pendingProps||3!==b.nodeType?null:b,null!==b?(a.stateNode=b,!0):!1;default:return!1}}function xg(a){if(Ra){var b=kb;if(b){var c=b;if(!wg(a,b)){b=je(c);if(!b||!wg(a,b)){a.effectTag|=2;Ra=!1;ya=a;return}vg(ya,c)}ya=a;kb=bg(b)}else a.effectTag|=2,Ra=!1,ya=a}}function yg(a){for(a=a.return;null!==a&&5!==a.tag&&3!==a.tag;)a=a.return;ya=a}function Ce(a){if(a!== -ya)return!1;if(!Ra)return yg(a),Ra=!0,!1;var b=a.type;if(5!==a.tag||"head"!==b&&"body"!==b&&!ie(b,a.memoizedProps))for(b=kb;b;)vg(a,b),b=je(b);yg(a);kb=ya?je(a.stateNode):null;return!0}function pa(a,b,c,d){b.child=null===a?De(b,null,c,d):Rb(b,a.child,c,d)}function zg(a,b,c,d,e){c=c.render;var l=b.ref;Sb(b,e);d=we(a,b,c,d,l,e);if(null!==a&&!Pa)return b.updateQueue=a.updateQueue,b.effectTag&=-517,a.expirationTime<=e&&(a.expirationTime=0),Sa(a,b,e);b.effectTag|=1;pa(a,b,d,e);return b.child}function Ag(a, -b,c,d,e,l){if(null===a){var p=c.type;if("function"===typeof p&&!oe(p)&&void 0===p.defaultProps&&null===c.compare&&void 0===c.defaultProps)return b.tag=15,b.type=p,Bg(a,b,p,d,e,l);a=dd(c.type,null,d,null,b.mode,l);a.ref=b.ref;a.return=b;return b.child=a}p=a.child;if(e=c)return Fg(a,b,c);b=Sa(a,b,c);return null!==b?b.sibling:null}}return Sa(a,b,c)}}else Pa=!1;b.expirationTime=0;switch(b.tag){case 2:d= -b.elementType;null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2);a=b.pendingProps;var e=Jb(b,ba.current);Sb(b,c);e=we(null,b,d,a,e,c);b.effectTag|=1;if("object"===typeof e&&null!==e&&"function"===typeof e.render&&void 0===e.$$typeof){b.tag=1;ye();if(aa(d)){var l=!0;cd(b)}else l=!1;b.memoizedState=null!==e.state&&void 0!==e.state?e.state:null;var p=d.getDerivedStateFromProps;"function"===typeof p&&fd(b,d,p,a);e.updater=gd;b.stateNode=e;e._reactInternalFiber=b;re(b,d,a,c);b=Fe(null,b,d,!0, -l,c)}else b.tag=0,pa(null,b,e,c),b=b.child;return b;case 16:e=b.elementType;null!==a&&(a.alternate=null,b.alternate=null,b.effectTag|=2);l=b.pendingProps;a=bi(e);b.type=a;e=b.tag=ai(a);l=xa(a,l);p=void 0;switch(e){case 0:p=Ee(null,b,a,l,c);break;case 1:p=Dg(null,b,a,l,c);break;case 11:p=zg(null,b,a,l,c);break;case 14:p=Ag(null,b,a,xa(a.type,l),d,c);break;default:g("306",a,"")}return p;case 0:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:xa(d,e),Ee(a,b,d,e,c);case 1:return d=b.type,e=b.pendingProps, -e=b.elementType===d?e:xa(d,e),Dg(a,b,d,e,c);case 3:Eg(b);d=b.updateQueue;null===d?g("282"):void 0;e=b.memoizedState;e=null!==e?e.element:null;mc(b,d,b.pendingProps,null,c);d=b.memoizedState.element;if(d===e)kb=ya=null,Ra=!1,b=Sa(a,b,c);else{e=b.stateNode;if(e=(null===a||null===a.child)&&e.hydrate)kb=bg(b.stateNode.containerInfo),ya=b,e=Ra=!0;e?(b.effectTag|=2,b.child=De(b,null,d,c)):(pa(a,b,d,c),kb=ya=null,Ra=!1);b=b.child}return b;case 5:return og(b),null===a&&xg(b),d=b.type,e=b.pendingProps,l=null!== -a?a.memoizedProps:null,p=e.children,ie(d,e)?p=null:null!==l&&ie(d,l)&&(b.effectTag|=16),Cg(a,b),1!==c&&b.mode&1&&e.hidden?(b.expirationTime=b.childExpirationTime=1,b=null):(pa(a,b,p,c),b=b.child),b;case 6:return null===a&&xg(b),null;case 13:return Fg(a,b,c);case 4:return te(b,b.stateNode.containerInfo),d=b.pendingProps,null===a?b.child=Rb(b,null,d,c):pa(a,b,d,c),b.child;case 11:return d=b.type,e=b.pendingProps,e=b.elementType===d?e:xa(d,e),zg(a,b,d,e,c);case 7:return pa(a,b,b.pendingProps,c),b.child; -case 8:return pa(a,b,b.pendingProps.children,c),b.child;case 12:return pa(a,b,b.pendingProps.children,c),b.child;case 10:a:{d=b.type._context;e=b.pendingProps;p=b.memoizedProps;l=e.value;Gg(b,l);if(null!==p){var f=p.value;l=rb(f,l)?0:("function"===typeof d._calculateChangedBits?d._calculateChangedBits(f,l):1073741823)|0;if(0===l){if(p.children===e.children&&!oa.current){b=Sa(a,b,c);break a}}else for(f=b.child,null!==f&&(f.return=b);null!==f;){var h=f.contextDependencies;if(null!==h){p=f.child;for(var k= -h.first;null!==k;){if(k.context===d&&0!==(k.observedBits&l)){1===f.tag&&(k=mb(c),k.tag=ld,Ta(f,k));f.expirationTime=b&&(Pa=!0);a.contextDependencies=null}function Ba(a, -b){if(yc!==a&&!1!==b&&0!==b){if("number"!==typeof b||1073741823===b)yc=a,b=1073741823;b={context:a,observedBits:b,next:null};null===vb?(null===xc?g("308"):void 0,vb=b,xc.contextDependencies={first:b,expirationTime:0}):vb=vb.next=b}return a._currentValue}function md(a){return{baseState:a,firstUpdate:null,lastUpdate:null,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function Ie(a){return{baseState:a.baseState,firstUpdate:a.firstUpdate, -lastUpdate:a.lastUpdate,firstCapturedUpdate:null,lastCapturedUpdate:null,firstEffect:null,lastEffect:null,firstCapturedEffect:null,lastCapturedEffect:null}}function mb(a){return{expirationTime:a,tag:Hg,payload:null,callback:null,next:null,nextEffect:null}}function nd(a,b){null===a.lastUpdate?a.firstUpdate=a.lastUpdate=b:(a.lastUpdate.next=b,a.lastUpdate=b)}function Ta(a,b){var c=a.alternate;if(null===c){var d=a.updateQueue,e=null;null===d&&(d=a.updateQueue=md(a.memoizedState))}else d=a.updateQueue, -e=c.updateQueue,null===d?null===e?(d=a.updateQueue=md(a.memoizedState),e=c.updateQueue=md(c.memoizedState)):d=a.updateQueue=Ie(e):null===e&&(e=c.updateQueue=Ie(d));null===e||d===e?nd(d,b):null===d.lastUpdate||null===e.lastUpdate?(nd(d,b),nd(e,b)):(nd(d,b),e.lastUpdate=b)}function Ig(a,b){var c=a.updateQueue;c=null===c?a.updateQueue=md(a.memoizedState):Jg(a,c);null===c.lastCapturedUpdate?c.firstCapturedUpdate=c.lastCapturedUpdate=b:(c.lastCapturedUpdate.next=b,c.lastCapturedUpdate=b)}function Jg(a, -b){var c=a.alternate;null!==c&&b===c.updateQueue&&(b=a.updateQueue=Ie(b));return b}function Kg(a,b,c,d,e,l){switch(c.tag){case Lg:return a=c.payload,"function"===typeof a?a.call(l,d,e):a;case Je:a.effectTag=a.effectTag&-2049|64;case Hg:a=c.payload;e="function"===typeof a?a.call(l,d,e):a;if(null===e||void 0===e)break;return T({},d,e);case ld:lb=!0}return d}function mc(a,b,c,d,e){lb=!1;b=Jg(a,b);for(var l=b.baseState,g=null,f=0,h=b.firstUpdate,k=l;null!==h;){var m=h.expirationTime;mf&&(f=e),h>f&&(f=h),l=l.sibling;b.childExpirationTime=f}if(null!==M)return M;null!==c&&0===(c.effectTag&1024)&&(null===c.firstEffect&& -(c.firstEffect=a.firstEffect),null!==a.lastEffect&&(null!==c.lastEffect&&(c.lastEffect.nextEffect=a.firstEffect),c.lastEffect=a.lastEffect),1=u)t=0;else if(-1===t||ub?0:b)):(a.pendingCommitExpirationTime=d,a.finishedWork=c)}}function wb(a,b){for(var c=a.return;null!==c;){switch(c.tag){case 1:var d=c.stateNode;if("function"===typeof c.type.getDerivedStateFromError||"function"===typeof d.componentDidCatch&&(null===nb||!nb.has(d))){a=od(b,a);a=Vg(c,a,1073741823);Ta(c, -a);jb(c,1073741823);return}break;case 3:a=od(b,a);a=Ke(c,a,1073741823);Ta(c,a);jb(c,1073741823);return}c=c.return}3===a.tag&&(c=od(b,a),c=Ke(a,c,1073741823),Ta(a,c),jb(a,1073741823))}function Qb(a,b){0!==Bc?a=Bc:ob?a=td?1073741823:da:b.mode&1?(a=Tb?1073741822-10*(((1073741822-a+15)/10|0)+1):1073741822-25*(((1073741822-a+500)/25|0)+1),null!==Ga&&a===da&&--a):a=1073741823;Tb&&(0===Ua||a=d){a.didError=!1;b=a.latestPingedTime;if(0===b||b>c)a.latestPingedTime=c;ed(c,a);c=a.expirationTime;0!==c&&rd(a,c)}}function ii(a,b){var c=a.stateNode;null!==c&&c.delete(b);b=Qa();b=Qb(b,a);a=dh(a,b);null!==a&&(lc(a,b),b=a.expirationTime,0!==b&&rd(a,b))}function dh(a,b){a.expirationTimeda&&Wg(),lc(a,b),ob&&!td&&Ga===a||rd(a,a.expirationTime),Cc>oi&&(Cc=0,g("185")))}function eh(a,b,c,d,e){var f=Bc;Bc=1073741823;try{return a(b,c,d,e)}finally{Bc=f}}function Dc(){Ha=1073741822-((pb.unstable_now()-Ue)/10|0)}function fh(a, -b){if(0!==ud){if(ba.expirationTime&&(a.expirationTime=b);S||(W?xd&&(Ja=a,V=1073741823,yd(a,1073741823,!1)):1073741823===b?Va(1073741823,!1):fh(a,b))}function wd(){var a=0,b=null;if(null!==ea)for(var c=ea,d=Ia;null!==d;){var e=d.expirationTime;if(0===e){null===c||null===ea?g("244"):void 0;if(d===d.nextScheduledRoot){Ia=ea=d.nextScheduledRoot=null;break}else if(d===Ia)Ia=e=d.nextScheduledRoot, -ea.nextScheduledRoot=e,d.nextScheduledRoot=null;else if(d===ea){ea=c;ea.nextScheduledRoot=Ia;d.nextScheduledRoot=null;break}else c.nextScheduledRoot=d.nextScheduledRoot,d.nextScheduledRoot=null;d=c.nextScheduledRoot}else{e>a&&(a=e,b=d);if(d===ea)break;if(1073741823===a)break;c=d;d=d.nextScheduledRoot}}Ja=b;V=a}function sd(){return zd?!0:pb.unstable_shouldYield()?zd=!0:!1}function pi(){try{if(!sd()&&null!==Ia){Dc();var a=Ia;do{var b=a.expirationTime;0!==b&&Ha<=b&&(a.nextExpirationTimeToWorkOn=Ha); -a=a.nextScheduledRoot}while(a!==Ia)}Va(0,!0)}finally{zd=!1}}function Va(a,b){wd();if(b)for(Dc(),Ub=Ha;null!==Ja&&0!==V&&a<=V&&!(zd&&Ha>V);)yd(Ja,V,Ha>V),wd(),Dc(),Ub=Ha;else for(;null!==Ja&&0!==V&&a<=V;)yd(Ja,V,!1),wd();b&&(ud=0,vd=null);0!==V&&fh(Ja,V);Cc=0;Ve=null;if(null!==Vb)for(a=Vb,Vb=null,b=0;b=c&&(null===Vb?Vb=[d]:Vb.push(d),d._defer))a.finishedWork= -b,a.expirationTime=0;else{a.finishedWork=null;a===Ve?Cc++:(Ve=a,Cc=0);td=ob=!0;a.current===b?g("177"):void 0;c=a.pendingCommitExpirationTime;0===c?g("261"):void 0;a.pendingCommitExpirationTime=0;d=b.expirationTime;var e=b.childExpirationTime;d=e>d?e:d;a.didError=!1;0===d?(a.earliestPendingTime=0,a.latestPendingTime=0,a.earliestSuspendedTime=0,a.latestSuspendedTime=0,a.latestPingedTime=0):(dd?a.earliestPendingTime=a.latestPendingTime= -0:a.earliestPendingTime>d&&(a.earliestPendingTime=a.latestPendingTime)),e=a.earliestSuspendedTime,0===e?lc(a,d):de&&lc(a,d));ed(0,a);bh.current=null;1w&&(F=w,w=E,E=F),F=Pf(K,E),z=Pf(K,w),F&&z&&(1!==D.rangeCount||D.anchorNode!==F.node||D.anchorOffset!==F.offset||D.focusNode!==z.node||D.focusOffset!==z.offset)&&(A=A.createRange(),A.setStart(F.node,F.offset),D.removeAllRanges(),E>w?(D.addRange(A),D.extend(z.node,z.offset)):(A.setEnd(z.node, -z.offset),D.addRange(A))))));A=[];for(D=K;D=D.parentNode;)1===D.nodeType&&A.push({element:D,left:D.scrollLeft,top:D.scrollTop});"function"===typeof K.focus&&K.focus();for(K=0;KI?b:I;0===b&&(nb=null);a.expirationTime= -b;a.finishedWork=null}}function Le(a){null===Ja?g("246"):void 0;Ja.expirationTime=0;Wb||(Wb=!0,Ad=a)}function ih(a,b){var c=W;W=!0;try{return a(b)}finally{(W=c)||S||Va(1073741823,!1)}}function jh(a,b){if(W&&!xd){xd=!0;try{return a(b)}finally{xd=!1}}return a(b)}function kh(a,b,c){if(Tb)return a(b,c);W||S||0===Ua||(Va(Ua,!1),Ua=0);var d=Tb,e=W;W=Tb=!0;try{return a(b,c)}finally{Tb=d,(W=e)||S||Va(1073741823,!1)}}function lh(a,b,c,d,e){var f=b.current;a:if(c){c=c._reactInternalFiber;b:{2===gc(c)&&1=== -c.tag?void 0:g("170");var h=c;do{switch(h.tag){case 3:h=h.stateNode.context;break b;case 1:if(aa(h.type)){h=h.stateNode.__reactInternalMemoizedMergedChildContext;break b}}h=h.return}while(null!==h);g("171");h=void 0}if(1===c.tag){var k=c.type;if(aa(k)){c=dg(c,k,h);break a}}c=h}else c=gb;null===b.context?b.context=c:b.pendingContext=c;b=e;e=mb(d);e.payload={element:a};b=void 0===b?null:b;null!==b&&(e.callback=b);Pb();Ta(f,e);jb(f,d);return d}function Ye(a,b,c,d){var e=b.current,f=Qa();e=Qb(f,e);return lh(a, -b,c,e,d)}function Ze(a){a=a.current;if(!a.child)return null;switch(a.child.tag){case 5:return a.child.stateNode;default:return a.child.stateNode}}function vi(a,b,c){var d=3=$e&&(b=$e-1);this._expirationTime=$e=b;this._root=a;this._callbacks=this._next=null;this._hasChildren=this._didComplete= -!1;this._children=null;this._defer=!0}function Yb(){this._callbacks=null;this._didCommit=!1;this._onCommit=this._onCommit.bind(this)}function Zb(a,b,c){b=Aa(3,null,null,b?3:0);a={current:b,containerInfo:a,pendingChildren:null,pingCache:null,earliestPendingTime:0,latestPendingTime:0,earliestSuspendedTime:0,latestSuspendedTime:0,latestPingedTime:0,didError:!1,pendingCommitExpirationTime:0,finishedWork:null,timeoutHandle:-1,context:null,pendingContext:null,hydrate:c,nextExpirationTimeToWorkOn:0,expirationTime:0, -firstBatch:null,nextScheduledRoot:null};this._internalRoot=b.stateNode=a}function $b(a){return!(!a||1!==a.nodeType&&9!==a.nodeType&&11!==a.nodeType&&(8!==a.nodeType||" react-mount-point-unstable "!==a.nodeValue))}function wi(a,b){b||(b=a?9===a.nodeType?a.documentElement:a.firstChild:null,b=!(!b||1!==b.nodeType||!b.hasAttribute("data-reactroot")));if(!b)for(var c;c=a.lastChild;)a.removeChild(c);return new Zb(a,!1,b)}function Cd(a,b,c,d,e){var f=c._reactRootContainer;if(f){if("function"===typeof e){var h= -e;e=function(){var a=Ze(f._internalRoot);h.call(a)}}null!=a?f.legacy_renderSubtreeIntoContainer(a,b,e):f.render(b,e)}else{f=c._reactRootContainer=wi(c,d);if("function"===typeof e){var g=e;e=function(){var a=Ze(f._internalRoot);g.call(a)}}jh(function(){null!=a?f.legacy_renderSubtreeIntoContainer(a,b,e):f.render(b,e)})}return Ze(f._internalRoot)}function mh(a,b){var c=2=Gc),nf=String.fromCharCode(32),Wa={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend", -"keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"}, -dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},mf=!1,Cb=!1,Ai={eventTypes:Wa,extractEvents:function(a,b,c,d){var e=void 0,f=void 0;if(Ld)a:{switch(a){case "compositionstart":e=Wa.compositionStart;break a;case "compositionend":e=Wa.compositionEnd;break a;case "compositionupdate":e=Wa.compositionUpdate;break a}e=void 0}else Cb?sa(a,c)&&(e=Wa.compositionEnd):"keydown"===a&&229===c.keyCode&&(e=Wa.compositionStart);e?(of&&"ko"!==c.locale&&(Cb||e!==Wa.compositionStart? -e===Wa.compositionEnd&&Cb&&(f=va()):(bb=d,Kd="value"in bb?bb.value:bb.textContent,Cb=!0)),e=xi.getPooled(e,b,c,d),f?e.data=f:(f=Ya(c),null!==f&&(e.data=f)),ja(e),f=e):f=null;(a=zi?$a(a,c):L(a,c))?(b=yi.getPooled(Wa.beforeInput,b,c,d),b.data=a,ja(b)):b=null;return null===f?b:null===b?f:[f,b]}},Md=null,Db=null,Eb=null,Nd=!1,Dh={color:!0,date:!0,datetime:!0,"datetime-local":!0,email:!0,month:!0,number:!0,password:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0},yb=$c.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED; -yb.hasOwnProperty("ReactCurrentDispatcher")||(yb.ReactCurrentDispatcher={current:null});var Fh=/^(.*)[\\\/]/,qa="function"===typeof Symbol&&Symbol.for,id=qa?Symbol.for("react.element"):60103,Fb=qa?Symbol.for("react.portal"):60106,eb=qa?Symbol.for("react.fragment"):60107,Pd=qa?Symbol.for("react.strict_mode"):60108,Rc=qa?Symbol.for("react.profiler"):60114,uf=qa?Symbol.for("react.provider"):60109,tf=qa?Symbol.for("react.context"):60110,Od=qa?Symbol.for("react.concurrent_mode"):60111,Qd=qa?Symbol.for("react.forward_ref"): -60112,Sc=qa?Symbol.for("react.suspense"):60113,Rd=qa?Symbol.for("react.memo"):60115,vf=qa?Symbol.for("react.lazy"):60116,sf="function"===typeof Symbol&&Symbol.iterator,Hh=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/, -wf=Object.prototype.hasOwnProperty,yf={},xf={},Q={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(a){Q[a]=new la(a,0,!1,a,null)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(a){var b=a[0];Q[b]=new la(b,1,!1,a[1],null)});["contentEditable","draggable","spellCheck","value"].forEach(function(a){Q[a]=new la(a, -2,!1,a.toLowerCase(),null)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(a){Q[a]=new la(a,2,!1,a,null)});"allowFullScreen async autoFocus autoPlay controls default defer disabled formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(a){Q[a]=new la(a,3,!1,a.toLowerCase(),null)});["checked","multiple","muted","selected"].forEach(function(a){Q[a]=new la(a,3,!0,a,null)}); -["capture","download"].forEach(function(a){Q[a]=new la(a,4,!1,a,null)});["cols","rows","size","span"].forEach(function(a){Q[a]=new la(a,6,!1,a,null)});["rowSpan","start"].forEach(function(a){Q[a]=new la(a,5,!1,a.toLowerCase(),null)});var bf=/[\-:]([a-z])/g;"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(a){var b= -a.replace(bf,Td);Q[b]=new la(b,1,!1,a,null)});"xlink:actuate xlink:arcrole xlink:href xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(a){var b=a.replace(bf,Td);Q[b]=new la(b,1,!1,a,"http://www.w3.org/1999/xlink")});["xml:base","xml:lang","xml:space"].forEach(function(a){var b=a.replace(bf,Td);Q[b]=new la(b,1,!1,a,"http://www.w3.org/XML/1998/namespace")});Q.tabIndex=new la("tabIndex",1,!1,"tabindex",null);var Df={change:{phasedRegistrationNames:{bubbled:"onChange",captured:"onChangeCapture"}, -dependencies:"blur change click focus input keydown keyup selectionchange".split(" ")}},dc=null,ec=null,cf=!1;cb&&(cf=jf("input")&&(!document.documentMode||9=document.documentMode,Tf={select:{phasedRegistrationNames:{bubbled:"onSelect",captured:"onSelectCapture"},dependencies:"blur contextmenu dragend focus keydown keyup mousedown mouseup selectionchange".split(" ")}}, -Gb=null,ce=null,hc=null,be=!1,Pi={eventTypes:Tf,extractEvents:function(a,b,c,d){var e=d.window===d?d.document:9===d.nodeType?d:d.ownerDocument,f;if(!(f=!e)){a:{e=Mf(e);f=Hd.onSelect;for(var h=0;h= -b;)c=d,d=d._next;a._next=d;null!==c&&(c._next=a)}return a};df=ih;ef=kh;ff=function(){S||0===Ua||(Va(Ua,!1),Ua=0)};var yh={createPortal:mh,findDOMNode:function(a){if(null==a)return null;if(1===a.nodeType)return a;var b=a._reactInternalFiber;void 0===b&&("function"===typeof a.render?g("188"):g("268",Object.keys(a)));a=Hf(b);return a=null===a?null:a.stateNode},hydrate:function(a,b,c){$b(b)?void 0:g("200");return Cd(null,a,b,!0,c)},render:function(a,b,c){$b(b)?void 0:g("200");return Cd(null,a,b,!1,c)}, -unstable_renderSubtreeIntoContainer:function(a,b,c,d){$b(c)?void 0:g("200");null==a||void 0===a._reactInternalFiber?g("38"):void 0;return Cd(a,b,c,!1,d)},unmountComponentAtNode:function(a){$b(a)?void 0:g("40");return a._reactRootContainer?(jh(function(){Cd(null,null,a,!1,function(){a._reactRootContainer=null})}),!0):!1},unstable_createPortal:function(){return mh.apply(void 0,arguments)},unstable_batchedUpdates:ih,unstable_interactiveUpdates:kh,flushSync:function(a,b){S?g("187"):void 0;var c=W;W=!0; -try{return eh(a,b)}finally{W=c,Va(1073741823,!1)}},unstable_createRoot:function(a,b){$b(a)?void 0:g("299","unstable_createRoot");return new Zb(a,!0,null!=b&&!0===b.hydrate)},unstable_flushControlled:function(a){var b=W;W=!0;try{eh(a)}finally{(W=b)||S||Va(1073741823,!1)}},__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED:{Events:[Za,Y,ia,af.injectEventPluginsByName,Gd,ja,function(a){ra(a,qb)},y,Ka,Vc,na]}};(function(a){var b=a.findFiberByHostInstance;return Zh(T({},a,{overrideProps:null,currentDispatcherRef:yb.ReactCurrentDispatcher, -findHostInstanceByFiber:function(a){a=Hf(a);return null===a?null:a.stateNode},findFiberByHostInstance:function(a){return b?b(a):null}}))})({findFiberByHostInstance:U,bundleType:0,version:"16.8.1",rendererPackageName:"react-dom"});var zh={default:yh},Ah=zh&&yh||zh;r.exports=Ah.default||Ah}; -shadow$provide.module$node_modules$react_dom$index=function(k,u,q,r,n,H){function B(){if("undefined"!==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(B)}catch(g){console.error(g)}}B();r.exports=q("module$node_modules$react_dom$cjs$react_dom_production_min")}; -shadow$provide.module$node_modules$string_hash$index=function(k,u,q,r,n,H){r.exports=function(k){for(var g=5381,n=k.length;n;)g=33*g^k.charCodeAt(--n);return g>>>0}}; -shadow$provide.module$node_modules$$hugojosefson$color_hash$src$index=function(k,u,q,r,n,H){var B=q("module$node_modules$string_hash$index"),g=function(g){var k="#";g.forEach(function(h){16>h&&(k+=0);k+=h.toString(16)});return k},z=function(g,k,h){g/=360;var m=.5>h?h*(1+k):h+k-h*k,n=2*h-m;return[g+1/3,g,g-1/3].map(function(h){0>h&&h++;1h?m:h<2/3?n+6*(m-n)*(2/3-h):n;return Math.round(255*h)})};k=function(g){g=g||{};var k=[g.lightness,g.saturation].map(function(h){h=h|| -[.35,.5,.65];return"[object Array]"===Object.prototype.toString.call(h)?h.concat():[h]});this.L=k[0];this.S=k[1];"number"===typeof g.hue&&(g.hue={min:g.hue,max:g.hue});"object"===typeof g.hue&&"[object Array]"!==Object.prototype.toString.call(g.hue)&&(g.hue=[g.hue]);"undefined"===typeof g.hue&&(g.hue=[]);this.hueRanges=g.hue.map(function(h){return{min:"undefined"===typeof h.min?0:h.min,max:"undefined"===typeof h.max?360:h.max}});this.hash=g.hash||B};k.prototype.hsl=function(g){g=this.hash(g);if(this.hueRanges.length){var k= -this.hueRanges[g%this.hueRanges.length];k=g/this.hueRanges.length%727*(k.max-k.min)/727+k.min}else k=g%359;g=parseInt(g/360);var h=this.S[g%this.S.length];g=parseInt(g/this.S.length);return[k,h,this.L[g%this.L.length]]};k.prototype.rgb=function(g){g=this.hsl(g);return z.apply(this,g)};k.prototype.hex=function(k){k=this.rgb(k);return g(k)};r.exports=k}; -var h,aa=aa||{},ba=this;function da(a){return"string"==typeof a}function fa(a,b){a=a.split(".");var c=ba;a[0]in c||!c.execScript||c.execScript("var "+a[0]);for(var d;a.length&&(d=a.shift());)a.length||void 0===b?c=c[d]&&c[d]!==Object.prototype[d]?c[d]:c[d]={}:c[d]=b}function ia(){} -function ka(a){var b=typeof a;if("object"==b)if(a){if(a instanceof Array)return"array";if(a instanceof Object)return b;var c=Object.prototype.toString.call(a);if("[object Window]"==c)return"object";if("[object Array]"==c||"number"==typeof a.length&&"undefined"!=typeof a.splice&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("splice"))return"array";if("[object Function]"==c||"undefined"!=typeof a.call&&"undefined"!=typeof a.propertyIsEnumerable&&!a.propertyIsEnumerable("call"))return"function"}else return"null"; -else if("function"==b&&"undefined"==typeof a.call)return"object";return b}function la(a){var b=ka(a);return"array"==b||"object"==b&&"number"==typeof a.length}function ma(a){return"function"==ka(a)}function na(a){var b=typeof a;return"object"==b&&null!=a||"function"==b}function pa(a){return a[qa]||(a[qa]=++ra)}var qa="closure_uid_"+(1E9*Math.random()>>>0),ra=0;function sa(a,b,c){return a.call.apply(a.bind,arguments)} -function ta(a,b,c){if(!a)throw Error();if(2b?1:0}function Ba(a){return String(a.charAt(0)).toUpperCase()+String(a.substr(1)).toLowerCase()};function Da(a){Da[" "](a);return a}Da[" "]=ia;function Ea(a,b,c){return Object.prototype.hasOwnProperty.call(a,b)?a[b]:a[b]=c(b)};function Fa(a,b){this.za=a|0;this.Ja=b|0}var Ga={},Ha={};function Ia(a){return Ea(Ga,a,function(a){return new Fa(a,0>a?-1:0)})}function Ja(a){a|=0;return-128<=a&&128>a?Ia(a):new Fa(a,0>a?-1:0)}function Ka(a){return isNaN(a)?Ia(0):a<=-La?Ma():a+1>=La?Na():0>a?Ka(-a).ka():new Fa(a%Oa|0,a/Oa|0)}function Pa(a,b){return new Fa(a,b)} -function Qa(a,b){if(0==a.length)throw Error("number format error: empty string");b=b||10;if(2>b||36f?(f=Ka(Math.pow(b,f)),d=d.multiply(f).add(Ka(g))):(d=d.multiply(c),d=d.add(Ka(g)))}return d} -var Oa=4294967296,La=Oa*Oa/2;function Na(){return Ea(Ha,Ra,function(){return Pa(-1,2147483647)})}function Ma(){return Ea(Ha,Sa,function(){return Pa(0,-2147483648)})}function Ta(){return Ea(Ha,Ua,function(){return Ja(16777216)})}h=Fa.prototype;h.Pd=function(){return this.za};h.Yb=function(){return this.Ja*Oa+(0<=this.za?this.za:Oa+this.za)}; -h.toString=function(a){a=a||10;if(2>a||36>>0).toString(a);b=e;if(b.gb())return f+d;for(;6>f.length;)f="0"+f;d=""+f+d}};h.gb=function(){return 0==this.Ja&&0==this.za};h.ma=function(){return 0>this.Ja}; -h.kf=function(){return 1==(this.za&1)};h.ob=function(a){return this.Ja==a.Ja&&this.za==a.za};h.ed=function(a){return 0>this.compare(a)};h.mf=function(a){return 0>=this.compare(a)};h.he=function(a){return 0>>16,c=this.Ja&65535,d=this.za>>>16,e=a.Ja>>>16,f=a.Ja&65535,g=a.za>>>16;a=(this.za&65535)+(a.za&65535);g=(a>>>16)+(d+g);d=g>>>16;d+=c+f;b=(d>>>16)+(b+e)&65535;return Pa((g&65535)<<16|a&65535,b<<16|d&65535)};h.sc=function(a){return this.add(a.ka())}; -h.multiply=function(a){if(this.gb()||a.gb())return Ia(0);if(this.ob(Ma()))return a.kf()?Ma():Ia(0);if(a.ob(Ma()))return this.kf()?Ma():Ia(0);if(this.ma())return a.ma()?this.ka().multiply(a.ka()):this.ka().multiply(a).ka();if(a.ma())return this.multiply(a.ka()).ka();if(this.ed(Ta())&&a.ed(Ta()))return Ka(this.Yb()*a.Yb());var b=this.Ja>>>16,c=this.Ja&65535,d=this.za>>>16,e=this.za&65535,f=a.Ja>>>16,g=a.Ja&65535,k=a.za>>>16;a=a.za&65535;var n=e*a;var q=(n>>>16)+d*a;var r=q>>>16;q=(q&65535)+e*k;r+=q>>> -16;r+=c*a;var v=r>>>16;r=(r&65535)+d*k;v+=r>>>16;r=(r&65535)+e*g;v=v+(r>>>16)+(b*a+c*k+d*g+e*f)&65535;return Pa((q&65535)<<16|n&65535,v<<16|r&65535)}; -function Wa(a,b){if(b.gb())throw Error("division by zero");if(a.gb())return Ia(0);if(a.ob(Ma())){if(b.ob(Ia(1))||b.ob(Ia(-1)))return Ma();if(b.ob(Ma()))return Ia(1);var c=Wa(a.Fc(1),b).shiftLeft(1);if(c.ob(Ia(0)))return b.ma()?Ia(1):Ia(-1);a=a.sc(b.multiply(c));return c.add(Wa(a,b))}if(b.ob(Ma()))return Ia(0);if(a.ma())return b.ma()?Wa(a.ka(),b.ka()):Wa(a.ka(),b).ka();if(b.ma())return Wa(a,b.ka()).ka();for(var d=Ia(0);a.hf(b);){c=Math.max(1,Math.floor(a.Yb()/b.Yb()));var e=Math.ceil(Math.log(c)/Math.LN2); -e=48>=e?1:Math.pow(2,e-48);for(var f=Ka(c),g=f.multiply(b);g.ma()||g.he(a);)c-=e,f=Ka(c),g=f.multiply(b);f.gb()&&(f=Ia(1));d=d.add(f);a=a.sc(g)}return d}h.nf=function(){return Pa(~this.za,~this.Ja)};h.and=function(a){return Pa(this.za&a.za,this.Ja&a.Ja)};h.or=function(a){return Pa(this.za|a.za,this.Ja|a.Ja)};h.xor=function(a){return Pa(this.za^a.za,this.Ja^a.Ja)};h.shiftLeft=function(a){a&=63;if(0==a)return this;var b=this.za;return 32>a?Pa(b<>>32-a):Pa(0,b<a?Pa(this.za>>>a|b<<32-a,b>>a):Pa(b>>a-32,0<=b?0:-1)};function Xa(a,b){b&=63;if(0==b)return a;var c=a.Ja;return 32>b?Pa(a.za>>>b|c<<32-b,c>>>b):32==b?Pa(c,0):Pa(c>>>b-32,0)}var Ra=1,Sa=2,Ua=6;function Ya(a,b){this.pa=[];this.pb=b;for(var c=!0,d=a.length-1;0<=d;d--){var e=a[d]|0;c&&e==b||(this.pa[d]=e,c=!1)}}var Za={};function $a(a){if(-128<=a&&128>a){var b=Za[a];if(b)return b}b=new Ya([a|0],0>a?-1:0);-128<=a&&128>a&&(Za[a]=b);return b}function ab(a){if(isNaN(a)||!isFinite(a))return bb;if(0>a)return ab(-a).ka();for(var b=[],c=1,d=0;a>=c;d++)b[d]=a/c|0,c*=cb;return new Ya(b,0)}var cb=4294967296,bb=$a(0),eb=$a(1),fb=$a(16777216);h=Ya.prototype; -h.Pd=function(){return 0a||36>>0).toString(a);c=e;if(c.gb())return f+d;for(;6>f.length;)f="0"+f;d=""+f+d}};function gb(a,b){return 0>b?0:bthis.compare(a)};h.mf=function(a){return 0>=this.compare(a)}; -h.compare=function(a){a=this.sc(a);return a.ma()?-1:a.gb()?0:1};h.ka=function(){return this.nf().add(eb)};h.add=function(a){for(var b=Math.max(this.pa.length,a.pa.length),c=[],d=0,e=0;e<=b;e++){var f=d+(gb(this,e)&65535)+(gb(a,e)&65535),g=(f>>>16)+(gb(this,e)>>>16)+(gb(a,e)>>>16);d=g>>>16;f&=65535;g&=65535;c[e]=g<<16|f}return new Ya(c,c[c.length-1]&-2147483648?-1:0)};h.sc=function(a){return this.add(a.ka())}; -h.multiply=function(a){if(this.gb()||a.gb())return bb;if(this.ma())return a.ma()?this.ka().multiply(a.ka()):this.ka().multiply(a).ka();if(a.ma())return this.multiply(a.ka()).ka();if(this.ed(fb)&&a.ed(fb))return ab(this.Yb()*a.Yb());for(var b=this.pa.length+a.pa.length,c=[],d=0;d<2*b;d++)c[d]=0;for(d=0;d>>16,g=gb(this,d)&65535,k=gb(a,e)>>>16,n=gb(a,e)&65535;c[2*d+2*e]+=g*n;jb(c,2*d+2*e);c[2*d+2*e+1]+=f*n;jb(c,2*d+2*e+1);c[2*d+2*e+ -1]+=g*k;jb(c,2*d+2*e+1);c[2*d+2*e+2]+=f*k;jb(c,2*d+2*e+2)}for(d=0;d>>16,a[b]&=65535,b++} -function ib(a,b){if(b.gb())throw Error("division by zero");if(a.gb())return bb;if(a.ma())return b.ma()?ib(a.ka(),b.ka()):ib(a.ka(),b).ka();if(b.ma())return ib(a,b.ka()).ka();if(30=e?1:Math.pow(2,e-48);f=ab(d);for(var g=f.multiply(b);g.ma()||g.he(a);)d-=e,f=ab(d),g=f.multiply(b);f.gb()&&(f=eb);c=c.add(f);a=a.sc(g)}return c}h.nf=function(){for(var a=this.pa.length,b=[],c=0;c>5;a%=32;for(var c=this.pa.length+b+(0>>32-a:gb(this,e-b);return new Ya(d,this.pb)}; -h.Fc=function(a){var b=a>>5;a%=32;for(var c=this.pa.length-b,d=[],e=0;e>>a|gb(this,e+b+1)<<32-a:gb(this,e+b);return new Ya(d,this.pb)};function kb(a){var b=[],c=0,d;for(d in a)b[c++]=a[d];return b}function lb(a){var b=[],c=0,d;for(d in a)b[c++]=d;return b}var mb="constructor hasOwnProperty isPrototypeOf propertyIsEnumerable toLocaleString toString valueOf".split(" ");function nb(a,b){for(var c,d,e=1;eb?null:da(a)?a.charAt(b):a[b]}function tb(a){return Array.prototype.concat.apply([],arguments)}function ub(a){var b=a.length;if(0b?1:a2*this.ya&&Fb(this),!0):!1}; -function Fb(a){if(a.ya!=a.kb.length){for(var b=0,c=0;bb)throw Error("Bad port number "+b);a.gd=b}else a.gd=null} -function Ob(a,b,c){Mb(a);b instanceof Qb?(a.Ub=b,a.Ub.uf(a.Db)):(c||(b=Rb(b,Xb)),a.Ub=new Qb(b,a.Db))}h.getQuery=function(){return this.Ub.toString()};h.removeParameter=function(a){Mb(this);this.Ub.remove(a);return this};function Mb(a){if(a.th)throw Error("Tried to modify a read-only Uri");}h.uf=function(a){this.Db=a;this.Ub&&this.Ub.uf(a)};function Pb(a,b){return a?b?decodeURI(a.replace(/%25/g,"%2525")):decodeURIComponent(a):""} -function Rb(a,b,c){return da(a)?(a=encodeURI(a).replace(b,Yb),c&&(a=a.replace(/%25([0-9a-fA-F]{2})/g,"%$1")),a):null}function Yb(a){a=a.charCodeAt(0);return"%"+(a>>4&15).toString(16)+(a&15).toString(16)}var Sb=/[#\/\?@]/g,Ub=/[#\?:]/g,Tb=/[#\?]/g,Xb=/[#\?@]/g,Vb=/#/g;function Qb(a,b){this.ya=this.Ka=null;this.ub=a||null;this.Db=!!b}function Zb(a){a.Ka||(a.Ka=new Eb,a.ya=0,a.ub&&Jb(a.ub,function(b,c){a.add(decodeURIComponent(b.replace(/\+/g," ")),c)}))}h=Qb.prototype;h.Yf=function(){Zb(this);return this.ya}; -h.add=function(a,b){Zb(this);this.ub=null;a=$b(this,a);var c=this.Ka.get(a);c||this.Ka.set(a,c=[]);c.push(b);this.ya+=1;return this};h.remove=function(a){Zb(this);a=$b(this,a);return this.Ka.yd(a)?(this.ub=null,this.ya-=this.Ka.get(a).length,this.Ka.remove(a)):!1};h.clear=function(){this.Ka=this.ub=null;this.ya=0};h.Id=function(){Zb(this);return 0==this.ya};h.yd=function(a){Zb(this);a=$b(this,a);return this.Ka.yd(a)}; -h.forEach=function(a,b){Zb(this);this.Ka.forEach(function(c,d){qb(c,function(c){a.call(b,c,d,this)},this)},this)};h.vb=function(){Zb(this);for(var a=this.Ka.Mb(),b=this.Ka.vb(),c=[],d=0;d>>16&65535)*d+c*(b>>>16&65535)<<16>>>0)|0};function de(a){a=ce(a|0,-862048943);return ce(a<<15|a>>>-15,461845907)}function ee(a,b){a=(a|0)^(b|0);return ce(a<<13|a>>>-13,5)+-430675100|0}function fe(a,b){a=(a|0)^b;a=ce(a^a>>>16,-2048144789);a=ce(a^a>>>13,-1028477387);return a^a>>>16} -function ge(a){a:{var b=1;for(var c=0;;)if(b>2)}function me(a,b){return b instanceof a} -function ne(a){return a instanceof w}function oe(a,b){if(a.lb===b.lb)return 0;var c=uc(a.ib);if(p(c?b.ib:c))return-1;if(p(a.ib)){if(uc(b.ib))return 1;c=wb(a.ib,b.ib);return 0===c?wb(a.name,b.name):c}return wb(a.name,b.name)}function w(a,b,c,d,e){this.ib=a;this.name=b;this.lb=c;this.Yc=d;this.mb=e;this.l=2154168321;this.N=4096}h=w.prototype;h.toString=function(){return this.lb};h.equiv=function(a){return this.M(null,a)};h.M=function(a,b){return b instanceof w?this.lb===b.lb:!1}; -h.call=function(){function a(a,b,c){return x.h?x.h(b,this,c):x.call(null,b,this,c)}function b(a,b){return x.g?x.g(b,this):x.call(null,b,this)}var c=null;c=function(c,e,f){switch(arguments.length){case 2:return b.call(this,c,e);case 3:return a.call(this,c,e,f)}throw Error("Invalid arity: "+(arguments.length-1));};c.g=b;c.h=a;return c}();h.apply=function(a,b){return this.call.apply(this,[this].concat(Gc(b)))};h.a=function(a){return x.g?x.g(a,this):x.call(null,a,this)}; -h.g=function(a,b){return x.h?x.h(a,this,b):x.call(null,a,this,b)};h.W=function(){return this.mb};h.X=function(a,b){return new w(this.ib,this.name,this.lb,this.Yc,b)};h.V=function(){var a=this.Yc;return null!=a?a:this.Yc=a=le(ge(this.name),je(this.ib))};h.rd=function(){return this.name};h.sd=function(){return this.ib};h.U=function(a,b){return Fd(b,this.lb)}; -var pe=function pe(a){switch(arguments.length){case 1:return pe.a(arguments[0]);case 2:return pe.g(arguments[0],arguments[1]);default:throw Error(["Invalid arity: ",t.a(arguments.length)].join(""));}};pe.a=function(a){for(;;){if(a instanceof w)return a;if("string"===typeof a){var b=a.indexOf("/");return 1>b?pe.g(null,a):pe.g(a.substring(0,b),a.substring(b+1,a.length))}if(a instanceof O)a=a.Ca;else throw Error("no conversion to symbol");}}; -pe.g=function(a,b){var c=null!=a?[t.a(a),"/",t.a(b)].join(""):b;return new w(a,b,c,null,null)};pe.F=2;function qe(a){return null!=a?a.N&131072||l===a.wi?!0:a.N?!1:zc(Yd,a):zc(Yd,a)}function z(a){if(null==a)return null;if(null!=a&&(a.l&8388608||l===a.Sf))return zd(a);if(sc(a)||"string"===typeof a)return 0===a.length?null:new B(a,0,null);if(zc(yd,a))return zd(a);throw Error([t.a(a)," is not ISeqable"].join(""));} -function C(a){if(null==a)return null;if(null!=a&&(a.l&64||l===a.J))return Wc(a);a=z(a);return null==a?null:Wc(a)}function re(a){return null!=a?null!=a&&(a.l&64||l===a.J)?Xc(a):(a=z(a))?a.Ea(null):se:se}function D(a){return null==a?null:null!=a&&(a.l&128||l===a.Yd)?ih(a):z(re(a))} -var G=function G(a){switch(arguments.length){case 1:return G.a(arguments[0]);case 2:return G.g(arguments[0],arguments[1]);default:for(var c=[],d=arguments.length,e=0;;)if(e=d)return-1;!(0c&&(c+=d,c=0>c?0:c);for(;;)if(cc?d+c:c;for(;;)if(0<=c){if(G.g(Pe?Pe(a,c):Qe.call(null,a,c),b))return c;--c}else return-1}function Se(a,b){this.o=a;this.I=b}Se.prototype.ja=function(){return this.Ia?0:a};h.kc=function(){var a=this.ea(null);return 0b)throw Error("Index out of bounds");a:for(;;){if(null==a)throw Error("Index out of bounds"); -if(0===b){if(z(a)){a=C(a);break a}throw Error("Index out of bounds");}if(Oe(a)){a=Uc.g(a,b);break a}if(z(a))a=D(a),--b;else throw Error("Index out of bounds");}return a}if(zc(Tc,a))return Uc.g(a,b);throw Error(["nth not supported on this type ",t.a(Cc(Ac(a)))].join(""));} -function N(a,b,c){if("number"!==typeof b)throw Error("Index argument to nth must be a number.");if(null==a)return c;if(null!=a&&(a.l&16||l===a.Qf))return Uc.h(a,b,c);if(sc(a))return-1b?c:ef(a,b,c);if(zc(Tc,a))return Uc.h(a,b,c);throw Error(["nth not supported on this type ",t.a(Cc(Ac(a)))].join(""));} -var x=function x(a){switch(arguments.length){case 2:return x.g(arguments[0],arguments[1]);case 3:return x.h(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",t.a(arguments.length)].join(""));}};x.g=function(a,b){return null==a?null:null!=a&&(a.l&256||l===a.Vg)?$c.g(a,b):sc(a)?null!=b&&ba:a instanceof Ya?a.ma():a instanceof Fa?a.ma():!1}function Mf(a){return If(a)?!(0>a):a instanceof Ya?uc(a.ma()):a instanceof Fa?uc(a.ma()):!1}function Nf(a){return"number"===typeof a}function Of(a){return"number"===typeof a}function Pf(a,b){return x.h(a,b,Af)===Af?!1:!0} -function Qf(a,b){if(a===b)return 0;if(null==a)return-1;if(null==b)return 1;if("number"===typeof a){if("number"===typeof b)return wb(a,b);throw Error(["Cannot compare ",t.a(a)," to ",t.a(b)].join(""));}if(null!=a?a.N&2048||l===a.bc||(a.N?0:zc(Pd,a)):zc(Pd,a))return Qd(a,b);if("string"!==typeof a&&!sc(a)&&!0!==a&&!1!==a||Ac(a)!==Ac(b))throw Error(["Cannot compare ",t.a(a)," to ",t.a(b)].join(""));return wb(a,b)} -function Rf(a,b){var c=I(a),d=I(b);if(cd)a=1;else if(0===c)a=0;else a:for(d=0;;){var e=Qf(Pe(a,d),Pe(b,d));if(0===e&&d+1b?a:b};ig.j=function(a,b,c){return Ic(ig,a>b?a:b,c)};ig.H=function(a){var b=C(a),c=D(a);a=C(c);c=D(c);return this.j(b,a,c)};ig.F=2; -function jg(a){if("number"===typeof a)return String.fromCharCode(a);if("string"===typeof a&&1===a.length)return a;throw Error("Argument to char must be a character or number");}function kg(a){return 0<=a?Math.floor(a):Math.ceil(a)}function lg(a,b){return(a%b+b)%b}function mg(a,b){return kg((a-a%b)/b)}function ng(a,b){return a-b*mg(a,b)}function og(a){a-=a>>1&1431655765;a=(a&858993459)+(a>>2&858993459);return 16843009*(a+(a>>4)&252645135)>>24}function pg(a){return 0===a} -var t=function t(a){switch(arguments.length){case 0:return t.v();case 1:return t.a(arguments[0]);default:for(var c=[],d=arguments.length,e=0;;)if(eb)a[b]=C(c),b+=1,c=D(c);else return a;else{for(b=0;;)if(1>b)a[b]=null,b+=1;else break;return a}}function Sg(a,b){if(Me(b))return I(b);var c=0;for(b=z(b);;)if(null!=b&&cd:e))c[d]=a.next(),d+=1;else return Og(new Lg(c,0,d),uh.a?uh.a(a):uh.call(null,a))}else return null},null,null)};function vh(a){this.buffer=th;this._next=qh;this.Ye=!1;this.$b=null;this.vf=a;this.Nh=!1} -vh.prototype.step=function(){if(this._next!==qh)return!0;for(;;)if(this._next===qh)if(this.buffer.Id()){if(this.Ye)return!1;if(this.vf.ja()){if(this.Nh)var a=P(this.$b,Ve(null,this.vf.next()));else a=this.vf.next(),a=this.$b.g?this.$b.g(null,a):this.$b.call(null,null,a);Ee(a)&&(this.$b.a?this.$b.a(null):this.$b.call(null,null),this.Ye=!0)}else this.$b.a?this.$b.a(null):this.$b.call(null,null),this.Ye=!0}else this._next=this.buffer.remove();else return!0};vh.prototype.ja=function(){return this.step()}; -vh.prototype.next=function(){if(this.ja()){var a=this._next;this._next=qh;return a}throw Error("No such element");};vh.prototype.remove=function(){return Error("Unsupported operation")};vh.prototype[Dc]=function(){return ue(this)}; -function wh(a,b){var c=new vh(b);c.$b=function(){var b=function(a){return function(){function b(b,c){a.buffer=a.buffer.add(c);return b}var c=null;c=function(a,c){switch(arguments.length){case 0:return null;case 1:return a;case 2:return b.call(this,a,c)}throw Error("Invalid arity: "+arguments.length);};c.v=function(){return null};c.a=function(a){return a};c.g=b;return c}()}(c);return a.a?a.a(b):a.call(null,b)}();return c} -function xh(a,b){for(;;){if(null==z(b))return!0;var c=C(b);c=a.a?a.a(c):a.call(null,c);if(p(c))b=D(b);else return!1}}function yh(a,b){for(;;)if(b=z(b)){var c=C(b);c=a.a?a.a(c):a.call(null,c);if(p(c))return c;b=D(b)}else return null}function zh(a){if(If(a))return 0===(a&1);throw Error(["Argument must be an integer: ",t.a(a)].join(""));} -function Ah(a){return function(){function b(b,c){return uc(a.g?a.g(b,c):a.call(null,b,c))}function c(b){return uc(a.a?a.a(b):a.call(null,b))}function d(){return uc(a.v?a.v():a.call(null))}var e=null,f=function(){function b(a,b,d){var e=null;if(2a?0:a-1>>>5<<5}function ri(a,b,c){for(;;){if(0===b)return c;var d=oi(a);d.o[0]=c;c=d;b-=5}}var si=function si(a,b,c,d){var f=pi(c),g=a.D-1>>>b&31;5===b?f.o[g]=d:(c=c.o[g],null!=c?(b-=5,a=si.w?si.w(a,b,c,d):si.call(null,a,b,c,d)):a=ri(null,b-5,d),f.o[g]=a);return f};function ti(a,b){throw Error(["No item ",t.a(a)," in vector of length ",t.a(b)].join(""));} -function ui(a,b){if(b>=qi(a))return a.hb;var c=a.root;for(a=a.shift;;)if(0>>a&31];a=d}else return c.o}function vi(a,b){return 0<=b&&b>>b&31;b-=5;c=c.o[k];a=wi.R?wi.R(a,b,c,d,e):wi.call(null,a,b,c,d,e);g.o[k]=a}return g},xi=function xi(a,b,c){var e=a.D-2>>>b&31;if(5=this.D)return new B(this.hb,0,null);a:{var a=this.root;for(var b=this.shift;;)if(0this.D-qi(this)){a=this.hb.length;for(var c=Array(a+1),d=0;;)if(d>>5>1<b)return new Q(null,b,5,T,a,null);for(var c=32,d=(new Q(null,32,5,T,a.slice(0,32),null)).ad(null);;)if(cb)return null;a=this.start+b;return ab||this.end<=this.start+b?ti(b,this.end-this.start):Uc.g(this.Fa,this.start+b)};h.ha=function(a,b,c){return 0>b||this.end<=this.start+b?c:Uc.h(this.Fa,this.start+b,c)}; -h.Ib=function(a,b,c){a=this.start+b;if(0>b||this.end+1<=a)throw Error(["Index ",t.a(b)," out of bounds [0,",t.a(this.ea(null)),"]"].join(""));b=this.meta;c=ff.h(this.Fa,a,c);var d=this.start,e=this.end;a+=1;a=e>a?e:a;return Qi.R?Qi.R(b,c,d,a,null):Qi.call(null,b,c,d,a,null)};h.eb=function(){return null!=this.Fa&&l===this.Fa.Qe?zi(this.Fa,this.start,this.end):new nh(this)};h.W=function(){return this.meta};h.Pa=function(){return new Pi(this.meta,this.Fa,this.start,this.end,this.G)}; -h.ea=function(){return this.end-this.start};h.lc=function(){return Uc.g(this.Fa,this.end-1)};h.mc=function(){if(this.start===this.end)throw Error("Can't pop empty vector");var a=this.meta,b=this.Fa,c=this.start,d=this.end-1;return Qi.R?Qi.R(a,b,c,d,null):Qi.call(null,a,b,c,d,null)};h.kc=function(){return this.start!==this.end?new Te(this,this.end-this.start-1,null):null};h.V=function(){var a=this.G;return null!=a?a:this.G=a=we(this)};h.M=function(a,b){return Ue(this,b)}; -h.la=function(){return rd(bf,this.meta)};h.wa=function(a,b){return null!=this.Fa&&l===this.Fa.Qe?Ai(this.Fa,b,this.start,this.end):He(this,b)};h.xa=function(a,b,c){return null!=this.Fa&&l===this.Fa.Qe?Bi(this.Fa,b,c,this.start,this.end):Ie(this,b,c)};h.Aa=function(a,b,c){if("number"===typeof b)return this.Ib(null,b,c);throw Error("Subvec's key for assoc must be a number.");}; -h.Z=function(){var a=this;return function(b){return function e(d){return d===a.end?null:Ve(Uc.g(a.Fa,d),new Ig(null,function(){return function(){return e(d+1)}}(b),null,null))}}(this)(a.start)};h.X=function(a,b){return b===this.meta?this:Qi.R?Qi.R(b,this.Fa,this.start,this.end,this.G):Qi.call(null,b,this.Fa,this.start,this.end,this.G)};h.da=function(a,b){a=this.meta;b=md(this.Fa,this.end,b);var c=this.start,d=this.end+1;return Qi.R?Qi.R(a,b,c,d,null):Qi.call(null,a,b,c,d,null)}; -h.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.T(null,c);case 3:return this.ha(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.g=function(a,c){return this.T(null,c)};a.h=function(a,c,d){return this.ha(null,c,d)};return a}();h.apply=function(a,b){return this.call.apply(this,[this].concat(Gc(b)))};h.a=function(a){return this.T(null,a)};h.g=function(a,b){return this.ha(null,a,b)};Pi.prototype[Dc]=function(){return ue(this)}; -function Qi(a,b,c,d,e){for(;;)if(b instanceof Pi)c=b.start+c,d=b.start+d,b=b.Fa;else{if(!xf(b))throw Error("v must satisfy IVector");var f=I(b);if(0>c||0>d||c>f||d>f)throw Error("Index out of bounds");return new Pi(a,b,c,d,e)}}var Ri=function Ri(a){switch(arguments.length){case 2:return Ri.g(arguments[0],arguments[1]);case 3:return Ri.h(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",t.a(arguments.length)].join(""));}};Ri.g=function(a,b){return Ri.h(a,b,I(a))}; -Ri.h=function(a,b,c){return Qi(null,a,b|0,c|0,null)};Ri.F=3;function Si(a,b){return a===b.ra?b:new ni(a,Gc(b.o))}function Ei(a){return new ni({},Gc(a.o))}function Fi(a){var b=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];zf(a,0,b,0,a.length);return b} -var Ti=function Ti(a,b,c,d){c=Si(a.root.ra,c);var f=a.D-1>>>b&31;if(5===b)a=d;else{var g=c.o[f];null!=g?(b-=5,a=Ti.w?Ti.w(a,b,g,d):Ti.call(null,a,b,g,d)):a=ri(a.root.ra,b-5,d)}c.o[f]=a;return c};function Di(a,b,c,d){this.D=a;this.shift=b;this.root=c;this.hb=d;this.N=88;this.l=275}h=Di.prototype; -h.Jc=function(a,b){if(this.root.ra){if(32>this.D-qi(this))this.hb[this.D&31]=b;else{a=new ni(this.root.ra,this.hb);var c=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];c[0]=b;this.hb=c;this.D>>>5>1<>>d&31;d=k(d-5,g.o[f]);g.o[f]=d}return g}}(a)(a.shift,a.root)}();a.root=d}return a}if(b===a.D)return a.Jc(null,c);throw Error(["Index ",t.a(b)," out of bounds for TransientVector of length",t.a(a.D)].join(""));}throw Error("assoc! after persistent!");} -h.ea=function(){if(this.root.ra)return this.D;throw Error("count after persistent!");};h.T=function(a,b){if(this.root.ra)return vi(this,b)[b&31];throw Error("nth after persistent!");};h.ha=function(a,b,c){return 0<=b&&b=a)return new m(this.meta,this.D-1,c,null);G.g(b,this.o[d])?d+=2:(c[e]=this.o[d],c[e+1]=this.o[d+1],e+=2,d+=2)}}else return this}; -h.Aa=function(a,b,c){a=ej(this.o,b);if(-1===a){if(this.Db?4:2*(b+1));zf(this.o,0,c,0,2*b);return new vj(a,this.ta,c)};h.Gd=function(){return wj?wj(this.o):xj.call(null,this.o)};h.Sc=function(a,b){return tj(this.o,a,b)};h.Qc=function(a,b,c,d){var e=1<<(b>>>a&31);if(0===(this.ta&e))return d;var f=og(this.ta&e-1);e=this.o[2*f];f=this.o[2*f+1];return null==e?f.Qc(a+5,b,c,d):pj(c,e)?f:d}; -h.Ob=function(a,b,c,d,e,f){var g=1<<(c>>>b&31),k=og(this.ta&g-1);if(0===(this.ta&g)){var n=og(this.ta);if(2*n>>b&31]=yj.Ob(a,b+5,c,d,e,f);for(e=d=0;;)if(32>d)0===(this.ta>>> -d&1)?d+=1:(k[d]=null!=this.o[e]?yj.Ob(a,b+5,ke(this.o[e]),this.o[e],this.o[e+1],f):this.o[e+1],e+=2,d+=1);else break;return new zj(a,n+1,k)}b=Array(2*(n+4));zf(this.o,0,b,0,2*k);b[2*k]=d;b[2*k+1]=e;zf(this.o,2*k,b,2*(k+1),2*(n-k));f.C=!0;a=this.Mc(a);a.o=b;a.ta|=g;return a}n=this.o[2*k];g=this.o[2*k+1];if(null==n)return n=g.Ob(a,b+5,c,d,e,f),n===g?this:sj(this,a,2*k+1,n);if(pj(d,n))return e===g?this:sj(this,a,2*k+1,e);f.C=!0;f=b+5;d=Aj?Aj(a,f,n,g,c,d,e):Bj.call(null,a,f,n,g,c,d,e);e=2*k;k=2*k+1;a= -this.Mc(a);a.o[e]=null;a.o[k]=d;return a}; -h.Nb=function(a,b,c,d,e){var f=1<<(b>>>a&31),g=og(this.ta&f-1);if(0===(this.ta&f)){var k=og(this.ta);if(16<=k){g=[null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null];g[b>>>a&31]=yj.Nb(a+5,b,c,d,e);for(d=c=0;;)if(32>c)0===(this.ta>>>c&1)?c+=1:(g[c]=null!=this.o[d]?yj.Nb(a+5,ke(this.o[d]),this.o[d],this.o[d+1],e):this.o[d+1],d+=2,c+=1);else break;return new zj(null,k+1,g)}a=Array(2*(k+1));zf(this.o, -0,a,0,2*g);a[2*g]=c;a[2*g+1]=d;zf(this.o,2*g,a,2*(g+1),2*(k-g));e.C=!0;return new vj(null,this.ta|f,a)}var n=this.o[2*g];f=this.o[2*g+1];if(null==n)return k=f.Nb(a+5,b,c,d,e),k===f?this:new vj(null,this.ta,qj(this.o,2*g+1,k));if(pj(c,n))return d===f?this:new vj(null,this.ta,qj(this.o,2*g+1,d));e.C=!0;e=this.ta;k=this.o;a+=5;a=Cj?Cj(a,n,f,b,c,d):Bj.call(null,a,n,f,b,c,d);c=2*g;g=2*g+1;d=Gc(k);d[c]=null;d[g]=a;return new vj(null,e,d)}; -h.Fd=function(a,b,c,d){var e=1<<(b>>>a&31);if(0===(this.ta&e))return d;var f=og(this.ta&e-1);e=this.o[2*f];f=this.o[2*f+1];return null==e?f.Fd(a+5,b,c,d):pj(c,e)?new Ci(e,f,null):d};h.Hd=function(a,b,c){var d=1<<(b>>>a&31);if(0===(this.ta&d))return this;var e=og(this.ta&d-1),f=this.o[2*e],g=this.o[2*e+1];return null==f?(a=g.Hd(a+5,b,c),a===g?this:null!=a?new vj(null,this.ta,qj(this.o,2*e+1,a)):this.ta===d?null:new vj(null,this.ta^d,rj(this.o,e))):pj(c,f)?new vj(null,this.ta^d,rj(this.o,e)):this}; -h.eb=function(){return new uj(this.o)};var yj=new vj(null,0,[]);function Dj(a){this.o=a;this.I=0;this.Qb=null}Dj.prototype.ja=function(){for(var a=this.o.length;;){if(null!=this.Qb&&this.Qb.ja())return!0;if(this.I>>a&31];return null!=e?e.Qc(a+5,b,c,d):d}; -h.Ob=function(a,b,c,d,e,f){var g=c>>>b&31,k=this.o[g];if(null==k)return a=sj(this,a,g,yj.Ob(a,b+5,c,d,e,f)),a.D+=1,a;b=k.Ob(a,b+5,c,d,e,f);return b===k?this:sj(this,a,g,b)};h.Nb=function(a,b,c,d,e){var f=b>>>a&31,g=this.o[f];if(null==g)return new zj(null,this.D+1,qj(this.o,f,yj.Nb(a+5,b,c,d,e)));a=g.Nb(a+5,b,c,d,e);return a===g?this:new zj(null,this.D,qj(this.o,f,a))};h.Fd=function(a,b,c,d){var e=this.o[b>>>a&31];return null!=e?e.Fd(a+5,b,c,d):d}; -h.Hd=function(a,b,c){var d=b>>>a&31,e=this.o[d];if(null!=e){a=e.Hd(a+5,b,c);if(a===e)d=this;else if(null==a)if(8>=this.D)a:{e=this.o;a=e.length;b=Array(2*(this.D-1));c=0;for(var f=1,g=0;;)if(ca?d:pj(c,this.o[a])?this.o[a+1]:d}; -h.Ob=function(a,b,c,d,e,f){if(c===this.oc){b=Gj(this.o,this.D,d);if(-1===b){if(this.o.length>2*this.D)return b=2*this.D,c=2*this.D+1,a=this.Mc(a),a.o[b]=d,a.o[c]=e,f.C=!0,a.D+=1,a;c=this.o.length;b=Array(c+2);zf(this.o,0,b,0,c);b[c]=d;b[c+1]=e;f.C=!0;d=this.D+1;a===this.ra?(this.o=b,this.D=d,a=this):a=new Hj(this.ra,this.oc,d,b);return a}return this.o[b+1]===e?this:sj(this,a,b+1,e)}return(new vj(a,1<<(this.oc>>>b&31),[null,this,null,null])).Ob(a,b,c,d,e,f)}; -h.Nb=function(a,b,c,d,e){return b===this.oc?(a=Gj(this.o,this.D,c),-1===a?(a=2*this.D,b=Array(a+2),zf(this.o,0,b,0,a),b[a]=c,b[a+1]=d,e.C=!0,new Hj(null,this.oc,this.D+1,b)):G.g(this.o[a+1],d)?this:new Hj(null,this.oc,this.D,qj(this.o,a+1,d))):(new vj(null,1<<(this.oc>>>a&31),[null,this])).Nb(a,b,c,d,e)};h.Fd=function(a,b,c,d){a=Gj(this.o,this.D,c);return 0>a?d:pj(c,this.o[a])?new Ci(this.o[a],this.o[a+1],null):d}; -h.Hd=function(a,b,c){a=Gj(this.o,this.D,c);return-1===a?this:1===this.D?null:new Hj(null,this.oc,this.D-1,rj(this.o,mg(a,2)))};h.eb=function(){return new uj(this.o)};function Bj(a){switch(arguments.length){case 6:return Cj(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5]);case 7:return Aj(arguments[0],arguments[1],arguments[2],arguments[3],arguments[4],arguments[5],arguments[6]);default:throw Error(["Invalid arity: ",t.a(arguments.length)].join(""));}} -function Cj(a,b,c,d,e,f){var g=ke(b);if(g===d)return new Hj(null,g,2,[b,c,e,f]);var k=new oj;return yj.Nb(a,g,b,c,k).Nb(a,d,e,f,k)}function Aj(a,b,c,d,e,f,g){var k=ke(c);if(k===e)return new Hj(null,k,2,[c,d,f,g]);var n=new oj;return yj.Ob(a,b,k,c,d,n).Ob(a,b,e,f,g,n)}function Ij(a,b,c,d,e){this.meta=a;this.Rb=b;this.I=c;this.Y=d;this.G=e;this.l=32374988;this.N=0}h=Ij.prototype;h.toString=function(){return be(this)};h.equiv=function(a){return this.M(null,a)}; -h.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return H(this,a,0);case 2:return H(this,a,c)}throw Error("Invalid arity: "+arguments.length);};a.a=function(a){return H(this,a,0)};a.g=function(a,c){return H(this,a,c)};return a}(); -h.lastIndexOf=function(){function a(a){return Re(this,a,I(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Re(this,b,d)}throw Error("Invalid arity: "+arguments.length);};b.a=a;b.g=function(a,b){return Re(this,a,b)};return b}();h.W=function(){return this.meta};h.Ha=function(){if(null==this.Y){var a=this.Rb,b=this.I+2;return Jj?Jj(a,b,null):xj.call(null,a,b,null)}a=this.Rb;b=this.I;var c=D(this.Y);return Jj?Jj(a,b,c):xj.call(null,a,b,c)}; -h.V=function(){var a=this.G;return null!=a?a:this.G=a=we(this)};h.M=function(a,b){return Ue(this,b)};h.la=function(){return se};h.wa=function(a,b){return We(b,this)};h.xa=function(a,b,c){return Ye(b,c,this)};h.Ba=function(){return null==this.Y?new Ci(this.Rb[this.I],this.Rb[this.I+1],null):C(this.Y)}; -h.Ea=function(){var a=this,b=null==a.Y?function(){var b=a.Rb,d=a.I+2;return Jj?Jj(b,d,null):xj.call(null,b,d,null)}():function(){var b=a.Rb,d=a.I,e=D(a.Y);return Jj?Jj(b,d,e):xj.call(null,b,d,e)}();return null!=b?b:se};h.Z=function(){return this};h.X=function(a,b){return b===this.meta?this:new Ij(b,this.Rb,this.I,this.Y,this.G)};h.da=function(a,b){return Ve(b,this)};Ij.prototype[Dc]=function(){return ue(this)}; -function xj(a){switch(arguments.length){case 1:return wj(arguments[0]);case 3:return Jj(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",t.a(arguments.length)].join(""));}}function wj(a){return Jj(a,0,null)}function Jj(a,b,c){if(null==c)for(c=a.length;;)if(bthis.D?I(D(this))+1:this.D};h.V=function(){var a=this.G;return null!=a?a:this.G=a=we(this)};h.M=function(a,b){return Ue(this,b)};h.la=function(){return se};h.wa=function(a,b){return We(b,this)};h.xa=function(a,b,c){return Ye(b,c,this)};h.Ba=function(){return of(this.stack)};h.Ea=function(){var a=C(this.stack);a=Rj(this.Gc?a.right:a.left,D(this.stack),this.Gc);return null!=a?new Sj(null,a,this.Gc,this.D-1,null):se};h.Z=function(){return this}; -h.X=function(a,b){return b===this.meta?this:new Sj(b,this.stack,this.Gc,this.D,this.G)};h.da=function(a,b){return Ve(b,this)};Sj.prototype[Dc]=function(){return ue(this)};function Tj(a,b,c){return new Sj(null,Rj(a,null,b),b,c,null)}function Uj(a,b,c,d){return c instanceof Vj?c.left instanceof Vj?new Vj(c.key,c.C,c.left.gc(),new Wj(a,b,c.right,d)):c.right instanceof Vj?new Vj(c.right.key,c.right.C,new Wj(c.key,c.C,c.left,c.right.left),new Wj(a,b,c.right.right,d)):new Wj(a,b,c,d):new Wj(a,b,c,d)} -function Xj(a,b,c,d){return d instanceof Vj?d.right instanceof Vj?new Vj(d.key,d.C,new Wj(a,b,c,d.left),d.right.gc()):d.left instanceof Vj?new Vj(d.left.key,d.left.C,new Wj(a,b,c,d.left.left),new Wj(d.key,d.C,d.left.right,d.right)):new Wj(a,b,c,d):new Wj(a,b,c,d)} -function Yj(a,b,c,d){if(c instanceof Vj)return new Vj(a,b,c.gc(),d);if(d instanceof Wj)return Xj(a,b,c,d.Md());if(d instanceof Vj&&d.left instanceof Wj)return new Vj(d.left.key,d.left.C,new Wj(a,b,c,d.left.left),Xj(d.key,d.C,d.left.right,d.right.Md()));throw Error("red-black tree invariant violation");} -function Zj(a,b,c,d){if(d instanceof Vj)return new Vj(a,b,c,d.gc());if(c instanceof Wj)return Uj(a,b,c.Md(),d);if(c instanceof Vj&&c.right instanceof Wj)return new Vj(c.right.key,c.right.C,Uj(c.key,c.C,c.left.Md(),c.right.left),new Wj(a,b,c.right.right,d));throw Error("red-black tree invariant violation");} -var ak=function ak(a,b,c){var e=null!=a.left?function(){var e=a.left;return ak.h?ak.h(e,b,c):ak.call(null,e,b,c)}():c;if(Ee(e))return e;var f=function(){var c=a.key,f=a.C;return b.h?b.h(e,c,f):b.call(null,e,c,f)}();if(Ee(f))return f;if(null!=a.right){var g=a.right;return ak.h?ak.h(g,b,f):ak.call(null,g,b,f)}return f};function Wj(a,b,c,d){this.key=a;this.C=b;this.left=c;this.right=d;this.G=null;this.l=166619935;this.N=0}h=Wj.prototype; -h.ic=function(a,b){switch(b){case 0:return new Ci(0,this.key,null);case 1:return new Ci(1,this.C,null);default:return null}};h.lastIndexOf=function(){function a(a){return Re(this,a,I(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Re(this,b,d)}throw Error("Invalid arity: "+arguments.length);};b.a=a;b.g=function(a,b){return Re(this,a,b)};return b}(); -h.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return H(this,a,0);case 2:return H(this,a,c)}throw Error("Invalid arity: "+arguments.length);};a.a=function(a){return H(this,a,0)};a.g=function(a,c){return H(this,a,c)};return a}();h.Cf=function(a){return a.Hf(this)};h.Md=function(){return new Vj(this.key,this.C,this.left,this.right)};h.gc=function(){return this};h.Bf=function(a){return a.Gf(this)};h.replace=function(a,b,c,d){return new Wj(a,b,c,d)}; -h.Gf=function(a){return new Wj(a.key,a.C,this,a.right)};h.Hf=function(a){return new Wj(a.key,a.C,a.left,this)};h.Sc=function(a,b){return ak(this,a,b)};h.aa=function(a,b){return this.ha(null,b,null)};h.P=function(a,b,c){return this.ha(null,b,c)};h.T=function(a,b){if(0===b)return this.key;if(1===b)return this.C;throw Error("Index out of bounds");};h.ha=function(a,b,c){return 0===b?this.key:1===b?this.C:c};h.Ib=function(a,b,c){return(new Q(null,2,5,T,[this.key,this.C],null)).Ib(null,b,c)};h.W=function(){return null}; -h.ea=function(){return 2};h.Ue=function(){return this.key};h.Ve=function(){return this.C};h.lc=function(){return this.C};h.mc=function(){return new Q(null,1,5,T,[this.key],null)};h.kc=function(){return new B([this.C,this.key],0,null)};h.V=function(){var a=this.G;return null!=a?a:this.G=a=we(this)};h.M=function(a,b){return Ue(this,b)};h.la=function(){return null};h.wa=function(a,b){return He(this,b)};h.xa=function(a,b,c){return Ie(this,b,c)}; -h.Aa=function(a,b,c){return ff.h(new Q(null,2,5,T,[this.key,this.C],null),b,c)};h.Z=function(){return new B([this.key,this.C],0,null)};h.X=function(a,b){return rd(new Q(null,2,5,T,[this.key,this.C],null),b)};h.da=function(a,b){return new Q(null,3,5,T,[this.key,this.C,b],null)}; -h.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.T(null,c);case 3:return this.ha(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.g=function(a,c){return this.T(null,c)};a.h=function(a,c,d){return this.ha(null,c,d)};return a}();h.apply=function(a,b){return this.call.apply(this,[this].concat(Gc(b)))};h.a=function(a){return this.T(null,a)};h.g=function(a,b){return this.ha(null,a,b)};Wj.prototype[Dc]=function(){return ue(this)}; -function Vj(a,b,c,d){this.key=a;this.C=b;this.left=c;this.right=d;this.G=null;this.l=166619935;this.N=0}h=Vj.prototype;h.ic=function(a,b){switch(b){case 0:return new Ci(0,this.key,null);case 1:return new Ci(1,this.C,null);default:return null}}; -h.lastIndexOf=function(){function a(a){return Re(this,a,I(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Re(this,b,d)}throw Error("Invalid arity: "+arguments.length);};b.a=a;b.g=function(a,b){return Re(this,a,b)};return b}(); -h.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return H(this,a,0);case 2:return H(this,a,c)}throw Error("Invalid arity: "+arguments.length);};a.a=function(a){return H(this,a,0)};a.g=function(a,c){return H(this,a,c)};return a}();h.Cf=function(a){return new Vj(this.key,this.C,this.left,a)};h.Md=function(){throw Error("red-black tree invariant violation");};h.gc=function(){return new Wj(this.key,this.C,this.left,this.right)}; -h.Bf=function(a){return new Vj(this.key,this.C,a,this.right)};h.replace=function(a,b,c,d){return new Vj(a,b,c,d)};h.Gf=function(a){return this.left instanceof Vj?new Vj(this.key,this.C,this.left.gc(),new Wj(a.key,a.C,this.right,a.right)):this.right instanceof Vj?new Vj(this.right.key,this.right.C,new Wj(this.key,this.C,this.left,this.right.left),new Wj(a.key,a.C,this.right.right,a.right)):new Wj(a.key,a.C,this,a.right)}; -h.Hf=function(a){return this.right instanceof Vj?new Vj(this.key,this.C,new Wj(a.key,a.C,a.left,this.left),this.right.gc()):this.left instanceof Vj?new Vj(this.left.key,this.left.C,new Wj(a.key,a.C,a.left,this.left.left),new Wj(this.key,this.C,this.left.right,this.right)):new Wj(a.key,a.C,a.left,this)};h.Sc=function(a,b){return ak(this,a,b)};h.aa=function(a,b){return this.ha(null,b,null)};h.P=function(a,b,c){return this.ha(null,b,c)}; -h.T=function(a,b){if(0===b)return this.key;if(1===b)return this.C;throw Error("Index out of bounds");};h.ha=function(a,b,c){return 0===b?this.key:1===b?this.C:c};h.Ib=function(a,b,c){return(new Q(null,2,5,T,[this.key,this.C],null)).Ib(null,b,c)};h.W=function(){return null};h.ea=function(){return 2};h.Ue=function(){return this.key};h.Ve=function(){return this.C};h.lc=function(){return this.C};h.mc=function(){return new Q(null,1,5,T,[this.key],null)}; -h.kc=function(){return new B([this.C,this.key],0,null)};h.V=function(){var a=this.G;return null!=a?a:this.G=a=we(this)};h.M=function(a,b){return Ue(this,b)};h.la=function(){return null};h.wa=function(a,b){return He(this,b)};h.xa=function(a,b,c){return Ie(this,b,c)};h.Aa=function(a,b,c){return ff.h(new Q(null,2,5,T,[this.key,this.C],null),b,c)};h.Z=function(){return new B([this.key,this.C],0,null)};h.X=function(a,b){return rd(new Q(null,2,5,T,[this.key,this.C],null),b)}; -h.da=function(a,b){return new Q(null,3,5,T,[this.key,this.C,b],null)};h.call=function(){var a=null;a=function(a,c,d){switch(arguments.length){case 2:return this.T(null,c);case 3:return this.ha(null,c,d)}throw Error("Invalid arity: "+(arguments.length-1));};a.g=function(a,c){return this.T(null,c)};a.h=function(a,c,d){return this.ha(null,c,d)};return a}();h.apply=function(a,b){return this.call.apply(this,[this].concat(Gc(b)))};h.a=function(a){return this.T(null,a)}; -h.g=function(a,b){return this.ha(null,a,b)};Vj.prototype[Dc]=function(){return ue(this)}; -var bk=function bk(a,b,c,d,e){if(null==b)return new Vj(c,d,null,null);var g=function(){var d=b.key;return a.g?a.g(c,d):a.call(null,c,d)}();if(0===g)return e[0]=b,null;if(0>g)return g=function(){var g=b.left;return bk.R?bk.R(a,g,c,d,e):bk.call(null,a,g,c,d,e)}(),null!=g?b.Bf(g):null;g=function(){var g=b.right;return bk.R?bk.R(a,g,c,d,e):bk.call(null,a,g,c,d,e)}();return null!=g?b.Cf(g):null},ck=function ck(a,b){if(null==a)return b;if(null==b)return a;if(a instanceof Vj){if(b instanceof Vj){var d=function(){var d= -a.right,f=b.left;return ck.g?ck.g(d,f):ck.call(null,d,f)}();return d instanceof Vj?new Vj(d.key,d.C,new Vj(a.key,a.C,a.left,d.left),new Vj(b.key,b.C,d.right,b.right)):new Vj(a.key,a.C,a.left,new Vj(b.key,b.C,d,b.right))}return new Vj(a.key,a.C,a.left,function(){var d=a.right;return ck.g?ck.g(d,b):ck.call(null,d,b)}())}if(b instanceof Vj)return new Vj(b.key,b.C,function(){var d=b.left;return ck.g?ck.g(a,d):ck.call(null,a,d)}(),b.right);d=function(){var d=a.right,f=b.left;return ck.g?ck.g(d,f):ck.call(null, -d,f)}();return d instanceof Vj?new Vj(d.key,d.C,new Wj(a.key,a.C,a.left,d.left),new Wj(b.key,b.C,d.right,b.right)):Yj(a.key,a.C,a.left,new Wj(b.key,b.C,d,b.right))},dk=function dk(a,b,c,d){if(null!=b){var f=function(){var d=b.key;return a.g?a.g(c,d):a.call(null,c,d)}();if(0===f)return d[0]=b,ck(b.left,b.right);if(0>f)return f=function(){var f=b.left;return dk.w?dk.w(a,f,c,d):dk.call(null,a,f,c,d)}(),null!=f||null!=d[0]?b.left instanceof Wj?Yj(b.key,b.C,f,b.right):new Vj(b.key,b.C,f,b.right):null; -f=function(){var f=b.right;return dk.w?dk.w(a,f,c,d):dk.call(null,a,f,c,d)}();return null!=f||null!=d[0]?b.right instanceof Wj?Zj(b.key,b.C,b.left,f):new Vj(b.key,b.C,b.left,f):null}return null},ek=function ek(a,b,c,d){var f=b.key,g=a.g?a.g(c,f):a.call(null,c,f);return 0===g?b.replace(f,d,b.left,b.right):0>g?b.replace(f,b.C,function(){var f=b.left;return ek.w?ek.w(a,f,c,d):ek.call(null,a,f,c,d)}(),b.right):b.replace(f,b.C,b.left,function(){var f=b.right;return ek.w?ek.w(a,f,c,d):ek.call(null,a,f, -c,d)}())};function fk(a,b,c,d,e){this.tb=a;this.fc=b;this.D=c;this.meta=d;this.G=e;this.l=418776847;this.N=8192}h=fk.prototype;h.ic=function(a,b){return gk(this,b)};h.forEach=function(a){for(var b=z(this),c=null,d=0,e=0;;)if(ed?c.left:c.right}else return null}h.has=function(a){return Pf(this,a)}; -h.aa=function(a,b){return this.P(null,b,null)};h.P=function(a,b,c){a=gk(this,b);return null!=a?a.C:c};h.Hb=function(a,b,c){return null!=this.fc?Fe(ak(this.fc,b,c)):c};h.W=function(){return this.meta};h.Pa=function(){return new fk(this.tb,this.fc,this.D,this.meta,this.G)};h.ea=function(){return this.D};h.kc=function(){return 0(a.a?a.a(c):a.call(null,c))?b:c};yk.j=function(a,b,c,d){return Ic(function(b,c){return yk.h(a,b,c)},yk.h(a,b,c),d)};yk.H=function(a){var b=C(a),c=D(a);a=C(c);var d=D(c);c=C(d);d=D(d);return this.j(b,a,c,d)};yk.F=3;function zk(a,b,c){return new Ig(null,function(){var d=z(c);return d?Ve(Ph.g(a,d),zk(a,b,Qh(b,d))):null},null,null)}function ep(a,b,c){this.start=a;this.step=b;this.count=c;this.l=82;this.N=0}h=ep.prototype;h.ea=function(){return this.count}; -h.Ba=function(){return this.start};h.T=function(a,b){return this.start+b*this.step};h.ha=function(a,b,c){return 0<=b&&b=this.count)throw Error("-drop-first of empty chunk");return new ep(this.start+this.step,this.step,this.count-1)};function Ak(a,b,c){this.I=a;this.end=b;this.step=c}Ak.prototype.ja=function(){return 0this.end};Ak.prototype.next=function(){var a=this.I;this.I+=this.step;return a}; -function Bk(a,b,c,d,e,f,g){this.meta=a;this.start=b;this.end=c;this.step=d;this.hc=e;this.Gh=f;this.G=g;this.l=32375006;this.N=140800}h=Bk.prototype;h.toString=function(){return be(this)};h.equiv=function(a){return this.M(null,a)};h.indexOf=function(){var a=null;a=function(a,c){switch(arguments.length){case 1:return H(this,a,0);case 2:return H(this,a,c)}throw Error("Invalid arity: "+arguments.length);};a.a=function(a){return H(this,a,0)};a.g=function(a,c){return H(this,a,c)};return a}(); -h.lastIndexOf=function(){function a(a){return Re(this,a,I(this))}var b=null;b=function(b,d){switch(arguments.length){case 1:return a.call(this,b);case 2:return Re(this,b,d)}throw Error("Invalid arity: "+arguments.length);};b.a=a;b.g=function(a,b){return Re(this,a,b)};return b}();function Tq(a){if(null==a.hc){var b=a.ea(null);32this.end&&0===this.step)return this.start;throw Error("Index out of bounds");};h.ha=function(a,b,c){return 0<=b&&bthis.end&&0===this.step?this.start:c};h.eb=function(){return new Ak(this.start,this.end,this.step)};h.W=function(){return this.meta};h.Pa=function(){return new Bk(this.meta,this.start,this.end,this.step,this.hc,this.Gh,this.G)}; -h.Ha=function(){return 0this.end?new Bk(null,this.start+this.step,this.end,this.step,null,null,null):null};h.ea=function(){return Math.ceil((this.end-this.start)/this.step)};h.V=function(){var a=this.G;return null!=a?a:this.G=a=we(this)};h.M=function(a,b){return Ue(this,b)};h.la=function(){return se};h.wa=function(a,b){return He(this,b)}; -h.xa=function(a,b,c){for(a=this.start;;)if(0this.end){c=b.g?b.g(c,a):b.call(null,c,a);if(Ee(c))return u(c);a+=this.step}else return c};h.Ba=function(){return this.start};h.Ea=function(){var a=this.Ha(null);return null==a?se:a};h.Z=function(){return this};h.Re=function(){Tq(this);return this.hc};h.Wd=function(){Tq(this);return null==this.Gh?se:this.Gh};h.X=function(a,b){return b===this.meta?this:new Bk(b,this.start,this.end,this.step,this.hc,this.Gh,this.G)}; -h.da=function(a,b){return Ve(b,this)};h.Of=function(){return z(this.Wd(null))};Bk.prototype[Dc]=function(){return ue(this)};function Ck(a,b){return Dk(a,b)}function Dk(a,b){return b<=a?se:new Bk(null,a,b,1,null,null,null)}function Ek(a,b){return new Ig(null,function(){var c=z(b);return c?Ve(C(c),Ek(a,Qh(a,c))):null},null,null)}function Fk(a){return Nd(Ic(function(a,c){return Wg(a,c,x.h(a,c,0)+1)},Ld(U),a))} -function Gk(a,b){return function(){function c(c,d,e){return new Q(null,2,5,T,[a.h?a.h(c,d,e):a.call(null,c,d,e),b.h?b.h(c,d,e):b.call(null,c,d,e)],null)}function d(c,d){return new Q(null,2,5,T,[a.g?a.g(c,d):a.call(null,c,d),b.g?b.g(c,d):b.call(null,c,d)],null)}function e(c){return new Q(null,2,5,T,[a.a?a.a(c):a.call(null,c),b.a?b.a(c):b.call(null,c)],null)}function f(){return new Q(null,2,5,T,[a.v?a.v():a.call(null),b.v?b.v():b.call(null)],null)}var g=null,k=function(){function c(a,b,c,e){var f=null; -if(3hc)return Fd(a,"#");Fd(a,c);if(0===pc.a(f))z(g)&&Fd(a,function(){var a=Pk.a(f);return p(a)?a:"..."}());else{if(z(g)){var n=C(g);b.h?b.h(n,a,f):b.call(null,n,a,f)}for(var q=D(g),r=pc.a(f)-1;;)if(!q||null!=r&&0===r){z(q)&&0===r&&(Fd(a,d),Fd(a,function(){var a=Pk.a(f);return p(a)?a:"..."}()));break}else{Fd(a,d);var v=C(q);c=a;g=f;b.h?b.h(v,c,g):b.call(null,v,c,g);var y=D(q);c=r-1;q=y;r=c}}return Fd(a,e)}finally{hc=k}} -function Qk(a,b){b=z(b);for(var c=null,d=0,e=0;;)if(eI(a)?a.toUpperCase():[t.a(a.substring(0,1).toUpperCase()),t.a(a.substring(1))].join("")}function JA(a){if("string"===typeof a)return a;a=Hg(a);var b=yA(a,/-/);var c=z(b);b=C(c);c=D(c);return p(HA.a?HA.a(b):HA.call(null,b))?a:bh(t,b,Oh.g(IA,c))} -function KA(a){var b=function(){var b=function(){var b=jf(a);return b?(b=a.displayName,p(b)?b:a.name):b}();if(p(b))return b;b=function(){var b=null!=a?a.N&4096||l===a.Rf?!0:!1:!1;return b?Hg(a):b}();if(p(b))return b;b=nf(a);return vf(b)?Nx.a(b):null}();return wA(t.a(b),"$",".")}var LA=!1;var MA=sA("module$node_modules$create_react_class$index",{});var NA={};if("undefined"===typeof BA||"undefined"===typeof FA||"undefined"===typeof NA||"undefined"===typeof OA)var OA=0;function PA(a){return setTimeout(a,16)}var QA=GA?function(){var a=window,b=a.requestAnimationFrame;if(p(b))return b;b=a.webkitRequestAnimationFrame;if(p(b))return b;b=a.mozRequestAnimationFrame;if(p(b))return b;a=a.msRequestAnimationFrame;return p(a)?a:PA}():PA;function RA(a,b){return a.cljsMountOrder-b.cljsMountOrder} -if("undefined"===typeof BA||"undefined"===typeof FA||"undefined"===typeof NA||"undefined"===typeof SA)var SA=function(){return null};function TA(){this.ve=!1}function yG(a,b){var c=a[b];if(null==c)return null;a[b]=null;a=c.length;for(b=0;;)if(b=d&&a.push(nC(c));return a}}(e),[b,c],a))}};var qC=sA("module$node_modules$react_dom$index",{});var rC={};if("undefined"===typeof BA||"undefined"===typeof rC||"undefined"===typeof sC)var sC=null;if("undefined"===typeof BA||"undefined"===typeof rC||"undefined"===typeof uC)var uC=Kh(U);function vC(a,b){var c=LA;LA=!0;try{var d=a.v?a.v():a.call(null);return qC.render(d,b,function(){return function(){var c=LA;LA=!1;try{return Mh.w(uC,ff,b,new Q(null,2,5,T,[a,b],null)),yG(UA,"afterRender"),null}finally{LA=c}}}(d,b,c,!0))}finally{LA=c}}function wC(a,b){return vC(a,b)} -function xC(){var a=new Q(null,1,5,T,[yC],null),b=document.getElementById("app");mB();return vC(function(){return nC(jf(a)?a.v?a.v():a.call(null):a)},b)}aC=function(a){return qC.findDOMNode(a)};fa("reagent.core.force_update_all",function(){mB();mB();for(var a=z(ij(u(uC))),b=null,c=0,d=0;;)if(dd?c:d}()))))}function GD(a,b){return new Q(null,3,5,T,[gh(ZA.g(a,b)),gh(ZA.g(b,a)),gh(YA.g(a,b))],null)} -var HD=function HD(a){if(null!=a&&null!=a.fh)return a.fh(a);var c=HD[ka(null==a?null:a)];if(null!=c)return c.a?c.a(a):c.call(null,a);c=HD._;if(null!=c)return c.a?c.a(a):c.call(null,a);throw Bc("EqualityPartition.equality-partition",a);},ID=function ID(a,b){if(null!=a&&null!=a.eh)return a.eh(a,b);var d=ID[ka(null==a?null:a)];if(null!=d)return d.g?d.g(a,b):d.call(null,a,b);d=ID._;if(null!=d)return d.g?d.g(a,b):d.call(null,a,b);throw Bc("Diff.diff-similar",a);};HD["null"]=function(){return kA}; -HD.string=function(){return kA};HD.number=function(){return kA};HD.array=function(){return Ey};HD["function"]=function(){return kA};HD["boolean"]=function(){return kA};HD._=function(a){return(null!=a?a.l&1024||l===a.Wg||(a.l?0:zc(dd,a)):zc(dd,a))?jx:(null!=a?a.l&4096||l===a.Yg||(a.l?0:zc(hd,a)):zc(hd,a))?wo:(null!=a?a.l&16777216||l===a.We||(a.l?0:zc(Ad,a)):zc(Ad,a))?Ey:kA};ID["null"]=function(a,b){return AD(a,b)};ID.string=function(a,b){return AD(a,b)};ID.number=function(a,b){return AD(a,b)}; -ID.array=function(a,b){return FD(a,b)};ID["function"]=function(a,b){return AD(a,b)};ID["boolean"]=function(a,b){return AD(a,b)};ID._=function(a,b){var c=function(){var b=HD(a);b=b instanceof O?b.Ca:null;switch(b){case "atom":return AD;case "set":return GD;case "sequential":return FD;case "map":return ED;default:throw Error(["No matching clause: ",t.a(b)].join(""));}}();return c.g?c.g(a,b):c.call(null,a,b)}; -function DD(a,b){return G.g(a,b)?new Q(null,3,5,T,[null,null,a],null):G.g(HD(a),HD(b))?ID(a,b):AD(a,b)};YC(M([Kz,rw,nv,function(a){NC(nm,M(["Handling re-frame event:",ZC(a,Lo)]));return a},Yu,function(a){var b=ZC(a,Lo),c=ZC(a,gz);a:{var d=Af;for(var e=a,f=z(new Q(null,2,5,T,[Oo,gz],null));;)if(null!=f){e=x.h(e,C(f),d);if(d===e){d=ms;break a}f=D(f)}else{d=e;break a}}G.g(d,ms)?NC(nm,M(["No :db changes caused by:",b])):(d=DD(c,d),c=N(d,0,null),d=N(d,1,null),null!=c||null!=d?(NC(Fw,M(["db clojure.data/diff for:",b])),NC(nm,M(["only before:",c])),NC(nm,M(["only after :",d])),MC(jA)):NC(nm,M(["no app-db changes caused by:", -b])));return a}]));YC(M([Kz,tr,nv,function(a){return ji(ki.w(a,new Q(null,2,5,T,[Sx,Lo],null),Ri,1),new Q(null,2,5,T,[Sx,Px],null),ZC(a,Lo))},Yu,function(a){return ji(OC(a,new Q(null,2,5,T,[Sx,Px],null)),new Q(null,2,5,T,[Sx,Lo],null),ZC(a,Px))}]));function JD(a){return YC(M([Kz,Nw,nv,function(b){var c=Sx.a(b),d=null!=c&&(c.l&64||l===c.J)?P(W,c):c;c=x.g(d,gz);d=x.g(d,Lo);c=a.g?a.g(c,d):a.call(null,c,d);return ji(b,new Q(null,2,5,T,[Oo,gz],null),c)}]))} -function KD(a){return YC(M([Kz,or,nv,function(b){var c=Sx.a(b);c=null!=c&&(c.l&64||l===c.J)?P(W,c):c;var d=x.g(c,Lo);return ff.h(b,Oo,a.g?a.g(c,d):a.call(null,c,d))}]))};Dh.g(TC,Py);Dh.g(TC,Fy);Dh.g(TC,hr);var LD=function LD(a){switch(arguments.length){case 2:return LD.g(arguments[0],arguments[1]);case 3:return LD.h(arguments[0],arguments[1],arguments[2]);default:throw Error(["Invalid arity: ",t.a(arguments.length)].join(""));}};LD.g=function(a,b){return LD.h(a,null,b)};LD.h=function(a,b,c){b=new Q(null,4,5,T,[zD,uD,b,JD(c)],null);return SC(Lo,a,ci(rc,ei(b)))};LD.F=3;function MD(a,b){ND(a,null,b)} -function ND(a,b,c){b=new Q(null,4,5,T,[zD,uD,b,KD(c)],null);SC(Lo,a,ci(rc,ei(b)))}Dh.g(TC,Lo);function OD(a){switch(a){case 0:return"No Error";case 1:return"Access denied to content document";case 2:return"File not found";case 3:return"Firefox silently errored";case 4:return"Application custom error";case 5:return"An exception occurred";case 6:return"Http response at 400 or 500 level";case 7:return"Request was aborted";case 8:return"Request timed out";case 9:return"The resource is not available offline";default:return"Unrecognized error code"}};var PD=function PD(a,b,c){if(null!=a&&null!=a.Fe)return a.Fe(a,b,c);var e=PD[ka(null==a?null:a)];if(null!=e)return e.h?e.h(a,b,c):e.call(null,a,b,c);e=PD._;if(null!=e)return e.h?e.h(a,b,c):e.call(null,a,b,c);throw Bc("AjaxImpl.-js-ajax-request",a);},QD=function QD(a){if(null!=a&&null!=a.Ie)return a.Ie(a);var c=QD[ka(null==a?null:a)];if(null!=c)return c.a?c.a(a):c.call(null,a);c=QD._;if(null!=c)return c.a?c.a(a):c.call(null,a);throw Bc("AjaxResponse.-status",a);},RD=function RD(a){if(null!=a&&null!= -a.Je)return a.Je(a);var c=RD[ka(null==a?null:a)];if(null!=c)return c.a?c.a(a):c.call(null,a);c=RD._;if(null!=c)return c.a?c.a(a):c.call(null,a);throw Bc("AjaxResponse.-status-text",a);},SD=function SD(a){if(null!=a&&null!=a.Ge)return a.Ge(a);var c=SD[ka(null==a?null:a)];if(null!=c)return c.a?c.a(a):c.call(null,a);c=SD._;if(null!=c)return c.a?c.a(a):c.call(null,a);throw Bc("AjaxResponse.-body",a);},TD=function TD(a,b){if(null!=a&&null!=a.He)return a.He(a,b);var d=TD[ka(null==a?null:a)];if(null!=d)return d.g? -d.g(a,b):d.call(null,a,b);d=TD._;if(null!=d)return d.g?d.g(a,b):d.call(null,a,b);throw Bc("AjaxResponse.-get-response-header",a);},UD=function UD(a){if(null!=a&&null!=a.Ke)return a.Ke(a);var c=UD[ka(null==a?null:a)];if(null!=c)return c.a?c.a(a):c.call(null,a);c=UD._;if(null!=c)return c.a?c.a(a):c.call(null,a);throw Bc("AjaxResponse.-was-aborted",a);},VD=function VD(a,b){if(null!=a&&null!=a.md)return a.md(a,b);var d=VD[ka(null==a?null:a)];if(null!=d)return d.g?d.g(a,b):d.call(null,a,b);d=VD._;if(null!= -d)return d.g?d.g(a,b):d.call(null,a,b);throw Bc("Interceptor.-process-request",a);},WD=function WD(a,b){if(null!=a&&null!=a.nd)return a.nd(a,b);var d=WD[ka(null==a?null:a)];if(null!=d)return d.g?d.g(a,b):d.call(null,a,b);d=WD._;if(null!=d)return d.g?d.g(a,b):d.call(null,a,b);throw Bc("Interceptor.-process-response",a);};function XD(a){throw Error(t.a(a));};function YD(a){return a instanceof O?Hg(a):a}var ZD=encodeURIComponent;function $D(a){var b=N(a,0,null);a=N(a,1,null);return[t.a(YD(b)),"\x3d",t.a(ZD.a?ZD.a(a):ZD.call(null,a))].join("")}function aE(a){return function(b,c){return new Q(null,2,5,T,[a.a?a.a(b):a.call(null,b),c],null)}} -function bE(a){var b=function(){var b=p(a)?a:$x,d=b instanceof O?b.Ca:null;switch(d){case "java":return function(){return function(){return null}}(b,d);case "rails":return function(){return function(){return""}}(b,d);case "indexed":return dg;default:throw Error(["No matching clause: ",t.a(d)].join(""));}}();return aE(b)} -function cE(a,b){var c=N(b,0,null);b=N(b,1,null);var d=YD(c);c=p(null)?p(c)?[t.a(null),"[",t.a(d),"]"].join(""):null:d;d=dE(a,c);return"string"===typeof b?new Q(null,1,5,T,[new Q(null,2,5,T,[c,b],null)],null):b instanceof O?new Q(null,1,5,T,[new Q(null,2,5,T,[c,Hg(b)],null)],null):vf(b)?ai(d,M([z(b)])):uf(b)?ai(d,M([Hh(a,z(b))])):new Q(null,1,5,T,[new Q(null,2,5,T,[c,b],null)],null)} -function dE(a,b){return function(c){var d=N(c,0,null);c=N(c,1,null);var e=YD(d);d=p(b)?p(d)?[t.a(b),"[",t.a(e),"]"].join(""):b:e;e=dE(a,d);return"string"===typeof c?new Q(null,1,5,T,[new Q(null,2,5,T,[d,c],null)],null):c instanceof O?new Q(null,1,5,T,[new Q(null,2,5,T,[d,Hg(c)],null)],null):vf(c)?ai(e,M([z(c)])):uf(c)?ai(e,M([Hh(a,z(c))])):new Q(null,1,5,T,[new Q(null,2,5,T,[d,c],null)],null)}}function eE(a,b){return xA("\x26",Oh.g($D,cE(bE(a),new Q(null,2,5,T,[null,b],null))))};function fE(a){return yh(tk([a]),new Q(null,6,5,T,[200,201,202,204,205,206],null))}var gE=function gE(a){for(var c=[],d=arguments.length,e=0;;)if(e>2)}var CE={},DE=0; -function EE(a){var b=0;if(null!=a.forEach)a.forEach(function(a,c){b=(b+(FE(c)^FE(a)))%4503599627370496});else for(var c=sE(a),d=0;da.size)return!1;a.Af++;return 32=a.length){if(b){var d=a;a=[];for(b=0;b>(-2*b&6)):0)d="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/\x3d".indexOf(d); -c=f}a=c.length;b=new Uint8Array(a);for(d=0;dd;d+=2,c-=8)b|=parseInt(a.substring(d,d+2),16)<d;d+=2,c-=8)e|=parseInt(a.substring(d,d+2),16)<d;d+=2,c-=8)b|=parseInt(a.substring(d, -d+2),16)<d;d+=2,c-=8)e|=parseInt(a.substring(d,d+2),16)<a.length&&this.Fb.Dh){d=[];for(c=1;cc.length&&this.Fb.Dh){var f=[];for(d=0;d=b.length&&a.$c.Dh){f=[];for(e=0;e>8-d%1*8)){c=a.charCodeAt(d+=.75);if(255parseFloat(UI)){wG=String(WI);break a}}wG=UI}var AG={}; -function BG(a){return Ea(AG,a,function(){for(var b=0,c=ya(String(wG)).split("."),d=ya(String(a)).split("."),e=Math.max(c.length,d.length),f=0;0==b&&f=a.keyCode)a.keyCode=-1}catch(b){}};var KG="closure_listenable_"+(1E6*Math.random()|0),LG=0;function MG(a,b,c,d,e){this.listener=a;this.proxy=null;this.src=b;this.type=c;this.capture=!!d;this.Dc=e;this.key=++LG;this.hd=this.Td=!1}function NG(a){a.hd=!0;a.listener=null;a.proxy=null;a.src=null;a.Dc=null};function OG(a){this.src=a;this.Eb={};this.ye=0}OG.prototype.add=function(a,b,c,d,e){var f=a.toString();a=this.Eb[f];a||(a=this.Eb[f]=[],this.ye++);var g=PG(a,b,d,e);-1d.keyCode||void 0!=d.returnValue)){a:{var e=!1;if(0==d.keyCode)try{d.keyCode=-1;break a}catch(g){e=!0}if(e||void 0==d.returnValue)d.returnValue=!0}d=[];for(e=b.currentTarget;e;e=e.parentNode)d.push(e);a=a.type;for(e=d.length-1;!b.Vc&&0<=e;e--){b.currentTarget=d[e];var f=dH(d[e],a,!0,b);c=c&&f}for(e=0;!b.Vc&&e>>0);function WG(a){if(ma(a))return a;a[fH]||(a[fH]=function(b){return a.handleEvent(b)});return a[fH]};function gH(){mG.call(this);this.Nc=new OG(this);this.Gg=this;this.lg=null}wa(gH,mG);gH.prototype[KG]=!0;gH.prototype.addEventListener=function(a,b,c,d){UG(this,a,b,c,d)};gH.prototype.removeEventListener=function(a,b,c,d){bH(this,a,b,c,d)}; -gH.prototype.dispatchEvent=function(a){var b,c=this.lg;if(c)for(b=[];c;c=c.lg)b.push(c);c=this.Gg;var d=a.type||a;if(da(a))a=new IG(a,c);else if(a instanceof IG)a.target=a.target||c;else{var e=a;a=new IG(d,c);nb(a,e)}e=!0;if(b)for(var f=b.length-1;!a.Vc&&0<=f;f--){var g=a.currentTarget=b[f];e=hH(g,d,!0,a)&&e}a.Vc||(g=a.currentTarget=c,e=hH(g,d,!0,a)&&e,a.Vc||(e=hH(g,d,!1,a)&&e));if(b)for(f=0;!a.Vc&&fRp.a(a)&&Pf(vk(c),d)}function yJ(a,b){return ff.h(a,b,function(){var c=x.g(a,b);return p(c)?c:0}()+1)} -function zJ(a,b,c){if(p(a)){var d=kJ(a);if(p(d))return qJ(d,b);if(Hf(a))return p(null)?a.a?a.a(b):a.call(null,b):p(a.a?a.a(b):a.call(null,b))?b:qs;throw Error([bl(M([c]),kc())," is not a fn, expected predicate fn"].join(""));}return b}function uJ(a,b){a=oJ.a(a);return!pJ(ZI(a,b))}function AJ(a){return a instanceof O?zI.j(M([a])):G.g(vq,C(a))?BJ(1,re(a)):G.g(Iu,C(a))?P(yI,Oh.g(AJ,re(a))):null} -function BJ(a,b){return uI.j(M([yI.j(M([vI.j(M([a,I(b)])),BI.j(M([Oh.g(AJ,b)]))])),function(a){var b=N(a,0,null);a=N(a,1,null);return P(yI,Ph.g(b,a))}]))}function nJ(a,b){return CJ(a,b,null,null,null)} -function CJ(a,b,c,d,e){if(p(eJ(b)))return p(c)?sJ(b,c):b;if(p(fJ(b)))return jJ(b,c);if(zg(b))return a=kJ(b),p(c)?sJ(a,c):a;if("undefined"===typeof bc||"undefined"===typeof aI||"undefined"===typeof RI||"undefined"===typeof OK)OK=function(a,b,c,d,e,r){this.form=a;this.ec=b;this.ba=c;this.Ze=d;this.Dg=e;this.Rh=r;this.l=393216;this.N=0},OK.prototype.X=function(a,b){return new OK(this.form,this.ec,this.ba,this.Ze,this.Dg,b)},OK.prototype.W=function(){return this.Rh},OK.prototype.zb=function(){return this}, -OK.prototype.Ab=function(){return this},OK.prototype.Kc=l,OK.prototype.zc=function(a,b){a=this.ec.a?this.ec.a(b):this.ec.call(null,b);return p(this.Ze)?a:p(a)?b:qs},OK.prototype.Ac=function(){if(p(this.ba))var a=this.ba.v?this.ba.v():this.ba.call(null);else a=this.ec,a=sf(a)?tI.j(M([a])):x.g(u(QI),a);return a},OK.prototype.Bc=function(a,b){return CJ(this.form,this.ec,b,this.Ze,this.Dg)},OK.Pc=function(){return new Q(null,6,5,T,[Fu,lo,ix,tu,ys,ny],null)},OK.nc=!0,OK.Jb="cljs.spec.alpha/t_cljs$spec$alpha6637", -OK.yc=function(a,b){return Fd(b,"cljs.spec.alpha/t_cljs$spec$alpha6637")};return new OK(a,b,c,d,e,U)} -function DJ(a,b,c){var d=new jl(function(){return gi(oJ,b,a)}),e=I(b);if("undefined"===typeof bc||"undefined"===typeof aI||"undefined"===typeof RI||"undefined"===typeof PK)PK=function(a,b,c,d,e,r){this.forms=a;this.qc=b;this.ba=c;this.rc=d;this.D=e;this.Sh=r;this.l=393216;this.N=0},PK.prototype.X=function(){return function(a,b){return new PK(this.forms,this.qc,this.ba,this.rc,this.D,b)}}(d,e),PK.prototype.W=function(){return function(){return this.Sh}}(d,e),PK.prototype.zb=function(){return function(){return this}}(d, -e),PK.prototype.Ab=function(){return function(){return this}}(d,e),PK.prototype.Kc=l,PK.prototype.zc=function(){return function(a,b){a=u(this.rc);if(xf(b)&&G.g(I(b),this.D))for(var c=b,d=0;;){if(G.g(d,this.D))return c;var e=b.a?b.a(d):b.call(null,d),f=ZI(a.a?a.a(d):a.call(null,d),e);if(pJ(f))return qs;c=f===e?c:ff.h(c,d,f);d+=1}else return qs}}(d,e),PK.prototype.Ac=function(a,b){return function(c,d,e,f){if(p(this.ba))return this.ba.v?this.ba.v():this.ba.call(null);c=Oh.w(function(){return function(a, -b,c){return tJ(b,d,af.g(e,a),f,c)}}(this,a,b),Dk(0,I(this.qc)),this.qc,this.forms);return xh(dg,c)?P(yI,c):null}}(d,e),PK.prototype.Bc=function(){return function(a,b){return DJ(this.forms,this.qc,b)}}(d,e),PK.Pc=function(){return function(){return new Q(null,6,5,T,[Un,Xq,ix,Mu,Nt,qy],null)}}(d,e),PK.nc=!0,PK.Jb="cljs.spec.alpha/t_cljs$spec$alpha6663",PK.yc=function(){return function(a,b){return Fd(b,"cljs.spec.alpha/t_cljs$spec$alpha6663")}}(d,e);return new PK(a,b,c,d,e,U)} -function EJ(a,b){return new Ci(a,b,null)}function FJ(a,b,c){var d=z(b);C(d);D(d);d=z(c);C(d);D(d);for(d=c;;){c=a;b=z(b);a=C(b);b=D(b);var e=z(d);d=C(e);e=D(e);var f=d;d=e;if(p(a)){c=zJ(a,c,f);if(pJ(c))return qs;a=c}else return c}}var GJ=new m(null,4,[uv,bf,lq,sk,Pw,se,Mq,U],null); -function HJ(a,b,c,d){var e=null!=c&&(c.l&64||l===c.J)?P(W,c):c,f=x.g(e,lA),g=x.g(e,en),k=x.h(e,aq,20),n=x.g(e,Zq),q=x.g(e,In),r=x.g(e,Fx),v=x.g(e,Fs),y=x.g(e,jv),A=x.g(e,ux),E=x.g(e,sv),F=x.g(e,Et),J=x.g(e,eA),K=x.g(e,Dq),R=p(K)?df(K):x.g(GJ,g),V=new jl(function(){return function(){return oJ.a(b)}}(R,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K)),ea=function(a,b){return function(a){return uJ(u(b),a)}}(R,V,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),oa=function(){return p(y)?y:function(){return function(a){return a}}(y,R, -V,ea,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K)}(),S=function(){return function(a,b,c,d){return af.g(a,d)}}(R,V,ea,oa,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),ja=function(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,V,S){return function(ha){return xf(ha)&&(uc(S)||xf(S))?new Q(null,3,5,T,[dg,function(){return function(a,b,c,d){return c===d?a:ff.h(a,b,d)}}(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,V,S),dg],null):p(function(){var a=vf(ha);return a?(a=p(R)?uc(S):R,p(a)?a:vf(S)):a}())?new Q(null,3,5,T,[p(y)?df:dg,function(a,b,c,d, -e,f,g,k,n,q,r,v,y){return function(a,b,c,d){return c===d&&uc(y)?a:ff.h(a,Pe(p(y)?d:c,0),Pe(d,1))}}(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,V,S),dg],null):qg(S)||Ef(S)||uc(S)&&(qg(ha)||Ef(ha))?new Q(null,3,5,T,[df,e,sg],null):new Q(null,3,5,T,[function(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,S,V){return function(a){return df(p(V)?V:a)}}(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,V,S),e,dg],null)}}(R,V,ea,oa,S,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K);if("undefined"===typeof bc||"undefined"===typeof aI||"undefined"=== -typeof RI||"undefined"===typeof SK)SK=function(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,S,V,ea,oa,ja,RN){this.form=a;this.ne=b;this.Ng=c;this.Kh=d;this.ba=e;this.ge=f;this.ec=g;this.ee=k;this.hh=n;this.yh=q;this.Hg=r;this.Ud=v;this.lh=y;this.Wf=A;this.Pi=E;this.Ag=F;this.xh=J;this.ff=K;this.count=R;this.fd=S;this.Sb=V;this.kind=ea;this.Vf=oa;this.gh=ja;this.Li=RN;this.l=393216;this.N=0},SK.prototype.X=function(){return function(a,b){return new SK(this.form,this.ne,this.Ng,this.Kh,this.ba,this.ge,this.ec, -this.ee,this.hh,this.yh,this.Hg,this.Ud,this.lh,this.Wf,this.Pi,this.Ag,this.xh,this.ff,this.count,this.fd,this.Sb,this.kind,this.Vf,this.gh,b)}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),SK.prototype.W=function(){return function(){return this.Li}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),SK.prototype.zb=function(){return function(){return this}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),SK.prototype.Ab=function(){return function(){return this}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r, -v,y,A,E,F,J,K),SK.prototype.Kc=l,SK.prototype.zc=function(){return function(a,b){a=u(this.Ag);if(uc(this.ee.a?this.ee.a(b):this.ee.call(null,b)))return qs;if(p(this.Vf)){var c=this.Ud.a?this.Ud.a(b):this.Ud.call(null,b),d=N(c,0,null),e=N(c,1,null);c=N(c,2,null);var f=d.a?d.a(b):d.call(null,b);d=0;var g=z(b);b=z(g);C(b);D(b);for(b=f;;){var k=g;f=z(k);g=C(f);f=D(f);if(k){k=ZI(a,g);if(pJ(k))return qs;b=e.w?e.w(b,d,g,k):e.call(null,b,d,g,k);d+=1;g=f}else return c.a?c.a(b):c.call(null,b)}}else if(Oe(b))for(e= -kg(I(b)/101),e=1>e?1:e,d=0;;){if(d>=I(b))return b;if(uJ(a,Pe(b,d)))d+=e;else return qs}else for(d=0,e=z(b),c=z(e),C(c),D(c);;){g=z(e);c=C(g);f=D(g);g=c;k=e;if(null==k||G.g(d,101))return b;if(uJ(a,g))e=f,d+=1;else return qs}}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),SK.prototype.Ac=function(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,S,V,ea){return function(oa,ha,ja,ua){var ca=this;if(p(ca.ba))return ca.ba.v?ca.ba.v():ca.ba.call(null);oa=tJ(ca.ec,ha,ja,ua,ca.form);return uI.j(M([p(ca.ff)?zI.j(M([ca.ff])): -p(ca.kind)?sI.j(M([function(){return function(a){return qf(a)?a:df(a)}}(oa,this,a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,S,V,ea),tJ(ca.kind,ha,ja,ua,ca.form)])):zI.j(M([bf])),function(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,S,V,ea,oa,ha){return function(ja){return sI.j(M([function(){return function(a){return xf(ja)?a:Fh.g(ja,a)}}(a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,S,V,ea,oa,ha),p(ca.Wf)?p(ca.count)?rI.j(M([a,new m(null,2,[su,ca.count,bu,100],null)])):rI.j(M([a,new m(null,3,[Gu,function(){var a=ca.fd; -return p(a)?a:0}(),sq,function(){var a=ca.ne;if(p(a))return a;a=ca.ge;var b=ca.fd;b=2*(p(b)?b:0);return a>b?a:b}(),bu,100],null)])):p(ca.count)?qI.j(M([a,ca.count])):p(function(){var a=ca.fd;return p(a)?a:ca.ne}())?qI.j(M([a,function(){var a=ca.fd;return p(a)?a:0}(),function(){var a=ca.ne;if(p(a))return a;a=ca.ge;var b=ca.fd;b=2*(p(b)?b:0);return a>b?a:b}()])):qI.j(M([a,0,ca.ge]))]))}}(oa,this,a,b,c,d,e,f,g,k,n,q,r,v,y,A,E,F,J,K,R,S,V,ea)]))}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),SK.prototype.Bc= -function(){return function(a,b){return HJ(this.form,this.ec,this.Sb,b)}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),SK.Pc=function(){return function(){return new Q(null,25,5,T,[Fu,Gn,Ut,Zv,ix,qw,lo,Mp,wm,qo,cq,ow,zt,yw,iF,$z,mo,wv,Sp,zq,Vy,Es,ov,jn,Ix],null)}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A,E,F,J,K),SK.nc=!0,SK.Jb="cljs.spec.alpha/t_cljs$spec$alpha6877",SK.yc=function(){return function(a,b){return Fd(b,"cljs.spec.alpha/t_cljs$spec$alpha6877")}}(R,V,ea,oa,S,ja,c,e,e,f,g,k,n,q,r,v,y,A, -E,F,J,K);return new SK(a,f,ea,e,d,k,b,n,q,g,S,ja,r,v,c,V,oa,R,A,E,e,F,J,K,U)}function IJ(a){return new m(null,2,[Gp,$t,iw,a],null)}function JJ(a){a=null!=a&&(a.l&64||l===a.J)?P(W,a):a;a=x.g(a,Gp);return G.g($t,a)} -var KJ=function KJ(a){var c=null!=a&&(a.l&64||l===a.J)?P(W,a):a,d=x.g(c,tn);a=z(d);var e=C(a);a=D(a);var f=x.g(c,Gm),g=z(f),k=C(g);g=D(g);var n=x.g(c,Lr),q=z(n);C(q);q=D(q);var r=x.g(c,iw);c=x.g(c,Uz);return xh(dg,d)?JJ(e)?(d=iw.a(e),d=af.g(r,p(f)?gf([k,d]):d),a?(a=new m(null,4,[tn,a,Gm,g,Lr,q,iw,d],null),KJ.a?KJ.a(a):KJ.call(null,a)):IJ(d)):new m(null,6,[Gp,rs,tn,d,iw,r,Gm,f,Lr,n,Uz,c],null):null};function LJ(a,b,c){return KJ(new m(null,4,[Gm,a,tn,b,Lr,c,iw,U],null))} -function MJ(a,b,c,d,e){return p(a)?(d=new m(null,5,[Gp,xy,am,b,Cx,d,Lr,e,Kz,Ol()],null),JJ(a)?ff.j(d,cm,b,M([iw,af.g(c,iw.a(a))])):ff.j(d,cm,a,M([iw,c]))):null} -function NJ(a,b,c,d){return p(p(b)?b:c)?(a=bi(function(a){a=C(a);return d.a?d.a(a):d.call(null,a)},Oh.w(Mi,a,function(){var a=z(b);return a?a:Yh(null)}(),function(){var a=z(c);return a?a:Yh(null)}())),new Q(null,3,5,T,[z(Oh.g(C,a)),p(b)?z(Oh.g(Ze,a)):null,p(c)?z(Oh.g(function(){return function(a){return Pe(a,2)}}(a),a)):null],null)):new Q(null,3,5,T,[z(bi(d,a)),b,c],null)} -function OJ(a,b,c){var d=NJ(a,b,c,dg);b=N(d,0,null);c=z(b);a=C(c);c=D(c);var e=N(d,1,null),f=N(e,0,null);d=N(d,2,null);return p(b)?(b=new m(null,4,[Gp,Nm,tn,b,Gm,e,Lr,d],null),null==c?p(f)?JJ(a)?IJ(EJ(f,iw.a(a))):b:a:b):null}function PJ(a,b){return p(p(a)?b:a)?OJ(M([a,b]),null,null):p(a)?a:b} -var QJ=function QJ(a){a=dJ(a);var c=null!=a&&(a.l&64||l===a.J)?P(W,a):a,d=x.g(c,Gp),e=x.g(c,tn);a=x.g(c,cm);var f=x.g(c,am);c=x.g(c,Lr);if(G.g($t,d))return!0;if(G.g(null,d))return null;if(G.g(Hm,d))return d=QJ.a?QJ.a(a):QJ.call(null,a),p(d)?(a=FJ(RJ(a),e,D(c)),!pJ(a)):d;if(G.g(xy,d))return(e=a===f)?e:QJ.a?QJ.a(a):QJ.call(null,a);if(G.g(rs,d))return xh(QJ,e);if(G.g(Nm,d))return yh(QJ,e);throw Error(["No matching clause: ",t.a(d)].join(""));},RJ=function RJ(a){a=dJ(a);var c=null!=a&&(a.l&64||l===a.J)? -P(W,a):a;a=x.g(c,tn);var d=z(a),e=C(d);D(d);var f=x.g(c,Gm),g=N(f,0,null),k=x.g(c,Gp);d=x.g(c,cm);var n=x.g(c,iw);c=x.g(c,Lr);if(G.g($t,k))return n;if(G.g(null,k))return null;if(G.g(Hm,k))return e=RJ.a?RJ.a(d):RJ.call(null,d),(f=G.g(e,dn))?d=f:(d=Gp.a(dJ(d)),f=new qk(null,new m(null,2,[xy,null,rs,null],null),null),d=f.a?f.a(d):f.call(null,d),d=p(d)?qf(e):d,d=p(d)?d:null),p(d)?dn:FJ(e,a,c);if(G.g(xy,k))return SJ(d,n,g);if(G.g(rs,k))return SJ(e,n,g);if(G.g(Nm,k))return c=NJ(a,f,c,QJ),a=N(c,0,null), -a=N(a,0,null),c=N(c,1,null),c=N(c,0,null),a=null==a?dn:RJ.a?RJ.a(a):RJ.call(null,a),p(c)?EJ(c,a):a;throw Error(["No matching clause: ",t.a(k)].join(""));}; -function SJ(a,b,c){var d=dJ(a);a=null!=d&&(d.l&64||l===d.J)?P(W,d):d;var e=x.g(a,Gp),f=x.g(a,tn),g=x.g(a,Cx);d=function(a,d,e,f,g,y){return function(){var a=RJ(e);if(qf(a))return b;a=p(c)?gf([c,a]):a;var d=p(y)?Fh:af;return d.g?d.g(b,a):d.call(null,b,a)}}(d,a,a,e,f,g);if(G.g(null,e))return b;if(G.g(Nm,e)||G.g($t,e)||G.g(Hm,e))return a=RJ(a),G.g(a,dn)?b:af.g(b,p(c)?gf([c,a]):a);if(G.g(xy,e)||G.g(rs,e))return d();throw Error(["No matching clause: ",t.a(e)].join(""));} -var TJ=function TJ(a,b){var d=dJ(a),e=null!=d&&(d.l&64||l===d.J)?P(W,d):d,f=x.g(e,Lr),g=x.g(e,am);a=x.g(e,tn);var k=z(a),n=C(k),q=D(k),r=x.g(e,iw),v=x.g(e,Gp),y=x.g(e,Cx),A=x.g(e,Gm),E=z(A),F=C(E),J=D(E),K=x.g(e,Uq),R=x.g(e,cm);if(p(e)){if(G.g($t,v))return null;if(G.g(null,v))return a=zJ(e,b,e),pJ(a)?null:IJ(a);if(G.g(Hm,v))return d=TJ.g?TJ.g(R,b):TJ.call(null,R,b),p(d)?G.g($t,Gp.a(d))?(a=FJ(RJ(d),a,D(f)),pJ(a)?null:IJ(a)):new m(null,5,[Gp,Hm,cm,d,Uq,K,tn,a,Lr,f],null):null;if(G.g(rs,v))return PJ(KJ(new m(null, -4,[tn,Ve(TJ.g?TJ.g(n,b):TJ.call(null,n,b),q),Gm,A,Lr,f,iw,r],null)),p(QJ(n))?function(){var a=KJ(new m(null,4,[tn,q,Gm,J,Lr,D(f),iw,SJ(n,r,F)],null));return TJ.g?TJ.g(a,b):TJ.call(null,a,b)}():null);if(G.g(Nm,v))return OJ(Oh.g(function(){return function(a){return TJ.g?TJ.g(a,b):TJ.call(null,a,b)}}(v,d,e,e,f,g,a,k,n,q,n,q,a,r,v,y,A,E,F,J,F,J,A,K,R),a),A,f);if(G.g(xy,v))return PJ(MJ(TJ.g?TJ.g(R,b):TJ.call(null,R,b),g,r,y,f),p(QJ(R))?function(){var a=MJ(g,g,SJ(R,r,null),y,f);return TJ.g?TJ.g(a,b):TJ.call(null, -a,b)}():null);throw Error(["No matching clause: ",t.a(v)].join(""));}return null}; -function UJ(a){a=dJ(a);var b=null!=a&&(a.l&64||l===a.J)?P(W,a):a;x.g(b,tn);a=x.g(b,Lr);var c=x.g(b,Uz),d=x.g(b,Gp),e=x.g(b,Cx),f=x.g(b,Gm),g=x.g(b,Jr),k=x.g(b,Uq);x.g(b,cm);if(p(b)){if(G.g($t,d))return null;if(G.g(null,d))return b;if(G.g(Hm,d))return Ve(Lm,Ve(k,a));if(G.g(rs,d))return p(c)?a=new cf(null,hz,new cf(null,c,null,1,null),2,null):(b=z(f),a=Ve(go,ai(Mi,M([b?b:Yh(Cv),a])))),a;if(G.g(Nm,d))return p(g)?new cf(null,pz,new cf(null,g,null,1,null),2,null):Ve(es,ai(Mi,M([f,a])));if(G.g(xy,d))return new cf(null, -p(e)?hz:lp,new cf(null,a,null,1,null),2,null);throw Error(["No matching clause: ",t.a(d)].join(""));}return null} -var VJ=function VJ(a,b,c,d,e){var g=dJ(a),k=null!=g&&(g.l&64||l===g.J)?P(W,g):g,n=x.g(k,tn),q=x.g(k,Lr),r=x.g(k,am),v=x.g(k,iw),y=x.g(k,hx),A=x.g(k,Gp),E=x.g(k,Cx),F=x.g(k,Gm);a=x.g(k,cm);var J=x.g(k,Kz);d=p(J)?yJ(d,J):d;var K=function(a,d,e,g,k,n,q,r,v,y,A,E,F,J){return function(K,R,S){return Oh.w(function(a,d,e,g,k,n,q,r,v,y,A,E,F,J){return function(K,R,S){if(p(p(J)?p(F)?p(R)?xJ(J,F,c,R):R:F:J))return null;if(p(F))return lI(new jl(function(a,d,e,g,k,n,q,r,v,y,A,E,F,J){return function(){var a=p(R)? -af.g(c,R):c,d=p(S)?S:K;return VJ.R?VJ.R(K,b,a,J,d):VJ.call(null,K,b,a,J,d)}}(a,d,e,g,k,n,q,r,v,y,A,E,F,J)));var V=p(R)?af.g(c,R):c,ea=p(S)?S:K;return VJ.R?VJ.R(K,b,V,J,ea):VJ.call(null,K,b,V,J,ea)}}(a,d,e,g,k,n,q,r,v,y,A,E,F,J),K,function(){var a=z(R);return a?a:Yh(null)}(),function(){var a=z(S);return a?a:Yh(null)}())}}(g,k,k,n,q,r,v,y,A,E,F,a,J,d),R=function(){var a=x.g(b,c);return p(a)?G.g($v,A)?sI.j(M([Mi,a])):G.g(null,A)?sI.j(M([Mi,a])):a:null}();if(p(R))return R;var V=p(y)?y.v?y.v():y.call(null): -null;if(p(V))return V;if(p(k)){if(G.g($t,A))return G.g(v,dn)?zI.j(M([bf])):zI.j(M([new Q(null,1,5,T,[v],null)]));if(G.g(null,A))return e=tJ(k,b,c,d,e),p(e)?sI.j(M([Mi,e])):null;if(G.g(Hm,A))return g=UJ(a),VJ.R?VJ.R(a,b,c,d,g):VJ.call(null,a,b,c,d,g);if(G.g(rs,A))return a=K(n,F,q),xh(dg,a)?P(OI,a):null;if(G.g(Nm,A))return a=ci(rc,K(n,F,q)),qf(a)?null:wI.j(M([a]));if(G.g(xy,A)){if(xJ(d,J,new Q(null,1,5,T,[J],null),J))return zI.j(M([bf]));e=VJ.R?VJ.R(r,b,c,d,q):VJ.call(null,r,b,c,d,q);if(p(e)){var ea= -e;return sI.j(M([function(){return function(a){return P(Ug,a)}}(ea,e,A,V,R,g,k,k,n,q,r,v,y,A,E,F,a,J,d,K),qI.j(M([ea]))]))}return null}throw Error(["No matching clause: ",t.a(A)].join(""));}return null};function WJ(a,b){for(;;){var c=z(b),d=C(c);c=D(c);if(qf(b))return p(QJ(a))?(a=RJ(a),G.g(a,dn)?null:a):qs;a=TJ(a,d);if(p(a))b=c;else return qs}} -var jJ=function jJ(a,b){if("undefined"===typeof bc||"undefined"===typeof aI||"undefined"===typeof RI||"undefined"===typeof TK)TK=function(a,b,f){this.Vb=a;this.ba=b;this.Mi=f;this.l=393216;this.N=0},TK.prototype.X=function(a,b){return new TK(this.Vb,this.ba,b)},TK.prototype.W=function(){return this.Mi},TK.prototype.zb=function(){return this},TK.prototype.Ab=function(){return this},TK.prototype.Kc=l,TK.prototype.zc=function(a,b){return null==b||uf(b)?WJ(this.Vb,z(b)):qs},TK.prototype.Ac=function(a, -b,f,g){return p(this.ba)?this.ba.v?this.ba.v():this.ba.call(null):VJ(this.Vb,b,f,g,UJ(this.Vb))},TK.prototype.Bc=function(a,b){return jJ.g?jJ.g(this.Vb,b):jJ.call(null,this.Vb,b)},TK.Pc=function(){return new Q(null,3,5,T,[Np,ix,Yy],null)},TK.nc=!0,TK.Jb="cljs.spec.alpha/t_cljs$spec$alpha7181",TK.yc=function(a,b){return Fd(b,"cljs.spec.alpha/t_cljs$spec$alpha7181")};return new TK(a,b,U)}; -function XJ(a,b){var c=vJ(Dy.a(b),null);c=fI(M([new Q(null,1,5,T,[c],null),function(){return function(c){var d=qJ(Dy.a(b),c);if(pJ(d))d=null;else{c=P(a,c);c=qJ(iw.a(b),c);var f=!pJ(c);f?p(By.a(b))?(f=By.a(b),d=!pJ(zJ(f,new m(null,2,[Dy,d,iw,c],null),Az))):d=!0:d=f}return d}}(c)]));c=dI(M([21,c]));c=br.a(hu.a(c));return p(c)?N(c,0,null):a} -var YJ=function YJ(a,b,c,d,e,f,g){var n=new m(null,3,[Dy,a,iw,c,By,e],null);if("undefined"===typeof bc||"undefined"===typeof aI||"undefined"===typeof RI||"undefined"===typeof UK)UK=function(a,b,c,d,e,f,g,n,K){this.Le=a;this.Ee=b;this.ue=c;this.sf=d;this.ef=e;this.df=f;this.ba=g;this.rc=n;this.Ni=K;this.l=393472;this.N=0},UK.prototype.X=function(){return function(a,b){return new UK(this.Le,this.Ee,this.ue,this.sf,this.ef,this.df,this.ba,this.rc,b)}}(n),UK.prototype.W=function(){return function(){return this.Ni}}(n), -UK.prototype.aa=function(){return function(a,b){return x.g(this.rc,b)}}(n),UK.prototype.P=function(){return function(a,b,c){return x.h(this.rc,b,c)}}(n),UK.prototype.zb=function(){return function(){return this}}(n),UK.prototype.Ab=function(){return function(){return this}}(n),UK.prototype.Kc=l,UK.prototype.zc=function(){return function(a,b){return Hf(b)?b===XJ(b,this.rc)?b:qs:qs}}(n),UK.prototype.Ac=function(a){return function(b,c){var d=this;return p(d.ba)?d.ba.v?d.ba.v():d.ba.call(null):zI.j(M([function(){return function(){function a(a){var c= -null;if(0=Number(c)?a:a=-1Number(a)?"-":0<=b.indexOf("+")?"+":0<=b.indexOf(" ")?" ":"";0<=Number(a)&&(d=f+d);if(isNaN(c)||d.length>=Number(c))return d;d=isNaN(e)?Math.abs(Number(a)).toString():Math.abs(Number(a)).toFixed(e);a=Number(c)-d.length-f.length;0<=b.indexOf("-",0)?d=f+d+za(" ", -a):(b=0<=b.indexOf("0",0)?"0":" ",d=f+za(b,a)+d);return d},d:function(a,b,c,d,e,f,g,k){return sK.f(parseInt(a,10),b,c,d,0,f,g,k)}};sK.i=sK.d;sK.u=sK.d;var tK={};function uK(a,b){return Ic(function(b,d){b=N(d,0,null);d=N(d,1,null);return p(a.a?a.a(d):a.call(null,d))?new De(new Q(null,2,5,T,[b,d],null)):null},null,Hh(Mi,b))}function vK(a){for(var b=[],c=arguments.length,d=0;;)if(dVo.a(c)?li(a,Vo,Ce):a}}(a,c,d),e),ff.h(b,Vo,Vo.a(d)+1))}}(c,d,e))};var XK={};if("undefined"===typeof tK||"undefined"===typeof BK||"undefined"===typeof XK||"undefined"===typeof YK)var YK=Kh(null);function ZK(a){return 0 -*/ -Object.keys||(Object.keys=function(a){if(a!==Object(a))throw new TypeError("Object.keys called on a non-object");var b=[],c;for(c in a)Object.prototype.hasOwnProperty.call(a,c)&&b.push(c);return b});var YL=Array.isArray||function(a){return!!a&&"[object Array]"==toString.call(a)};function ZL(a){for(var b=Array(a.length),c=0;c -*/ -function dM(a){for(var b in a)return!1;return!0}function eM(a){var b={};if(!da(a))return b;a=a.trim().replace(/^(\?|#|&)/,"");if(!a)return b;a=a.split("\x26");for(var c=0;cb?"":a.substring(b+1)}return null}function nM(a,b){return a.Qd?"#"+b:a.xe?a.xe.Ei(b,a.Kd,a.xb.location):a.Kd+b+a.xb.location.search} -iM.prototype.qe=function(a){if(this.bf){var b=lM(this);if("popstate"==a.type||b!=this.$f)this.$f=b,this.dispatchEvent(new hM(kM(this),!0))}};var pM=function pM(a,b,c,d){if(null!=a&&null!=a.Jf)return a.Jf(a,b,c,d);var f=pM[ka(null==a?null:a)];if(null!=f)return f.w?f.w(a,b,c,d):f.call(null,a,b,c,d);f=pM._;if(null!=f)return f.w?f.w(a,b,c,d):f.call(null,a,b,c,d);throw Bc("IRouter.-navigate",a);},qM=function qM(a){if(null!=a&&null!=a.Me)return a.Me(a);var c=qM[ka(null==a?null:a)];if(null!=c)return c.a?c.a(a):c.call(null,a);c=qM._;if(null!=c)return c.a?c.a(a):c.call(null,a);throw Bc("IPathRepr.-repr",a);};qM["null"]=function(){return""}; -qM.object=function(a){return t.a(a)};qM.number=function(a){return a};qM.string=function(a){return a};O.prototype.Me=function(){return Hg(this)};Q.prototype.Me=function(){return Hc(Oh.g(qM,this))};function rM(a){return p(a)?cg(function(a,c,d){a[ql(c,rl)]=qM(d);return a},{},a):null}function sM(a){return p(a)?Nd(Ic(function(b,c){var d=a[c];return p(YL(d))?Wg(b,Gg.a(c),Yf(d)):Wg(b,Gg.a(c),d)},Ld(U),null!=a?Object.keys(a):[])):null} -function tM(a,b){var c=b;-1!==c.indexOf("?")?(b=c.split("?"),c=b[0],b=eM(b[1])):b=null;for(var d=a.items,e=a=null,f=0;fthis.jd){var a=this.Y.charAt(this.jd);this.jd+=1;return a}return null}; -OM.prototype.xd=function(){return this.yg>this.jd?this.Y.charAt(this.jd):null};function PM(a,b){this.qg=a;this.Ic=b;this.Gb=this.Ne=1}PM.prototype.Lc=function(){var a=this.Gba?'..."':'"',d=b.length;return['"',t.a(b.substring(0,ad?"...}":"}")});Ml(UM,wo,function(a,b){return TM(a,b,"#{","}")});Ml(UM,tw,function(a,b){return TM(a,b,"[","]")}); -Ml(UM,Kl,function(a,b){return bl(M([Ac(b)]),kc())});function aN(a){return UM.g?UM.g(!1,a):UM.call(null,!1,a)};function bN(a,b,c){b=new m(null,2,[Ap,Fr,Sq,b],null);a=QM(a)?ff.j(b,us,NM(a),M([jm,LM(a),wq,MM(a)])):b;var d=us.a(a);b=jm.a(a);var e=wq.a(a);d=p(d)?[t.a(d)," "].join(""):null;b=p(b)?["[line ",t.a(b),", col ",t.a(e),"]"].join(""):null;c=dh(t,d,b,p(p(d)?d:b)?" ":null,c);throw Rl(c,a);}function cN(a,b){return bN(a,Cp,M([P(t,b)]))}function dN(a,b){return bN(a,Vn,M([P(t,b)]))}function eN(a,b){return bN(a,Jw,M([P(t,b)]))} -function fN(a,b,c,d){cN(a,M(["The map literal starting with ",aN(C(d)),p(b)?[" on line ",t.a(b)," column ",t.a(c)].join(""):null," contains ",I(d)," form(s). Map literals must contain an even number of forms."]))}function gN(a,b,c){return cN(a,M(["Invalid ",Hg(b),": ",c,"."]))}function hN(a,b,c){return cN(a,M(["Invalid character: ",c," found while reading ",Hg(b),"."]))} -function iN(a,b){a:{var c=um instanceof O?um.Ca:null;switch(c){case "regex":c='#"';break a;case "string":c='"';break a;default:throw Error(["No matching clause: ",t.a(c)].join(""));}}return eN(a,M(["Unexpected EOF reading ",Hg(um)," starting ",bh(t,c,b),"."]))}function jN(a,b){return dN(a,M(["Invalid digit ",b," in unicode character."]))}function kN(a){return cN(a,M(["Octal escape sequence must be in range [0, 377]."]))} -function lN(a,b){b=function(a){return function f(a){return new Ig(null,function(){for(var b=a;;)if(b=z(b)){if(yf(b)){var c=Sd(b),e=I(c),q=Mg(e);a:for(var r=0;;)if(rc?(b=c.toString(16),a=cN(a,M(["Invalid character literal \\u",b,"."]))):a=b,a;if(p(0==b.lastIndexOf("o",0))){--c;if(3a.getLength())a=a.append("0");else{a=a.toString();break a}a=eO(a);return p(a)?a:0}();q=(G.g(q,"-")?-1:1)*(60*function(){var a=eO(r);return p(a)?a:0}()+function(){var a=eO(v);return p(a)?a:0}());return new Q(null,8,5,T,[y,fO(1,A,12,"timestamp month field must be in range 1..12"),fO(1,a,function(){var a=0===lg(y,4)&&(0!==lg(y,100)||0===lg(y,400));return cO.g?cO.g(A,a):cO.call(null,A,a)}(),"timestamp day field must be in range 1..last day in month"), -fO(0,b,23,"timestamp hour field must be in range 0..23"),fO(0,c,59,"timestamp minute field must be in range 0..59"),fO(0,E,G.g(c,59)?60:59,"timestamp second field must be in range 0..60"),fO(0,F,999,"timestamp millisecond field must be in range 0..999"),q],null)} -var hO=Kh(null),iO=Kh(mk.j(M([new m(null,4,[Ex,function(a){if("string"===typeof a){var b=gO(a);if(p(b)){a=N(b,0,null);var c=N(b,1,null),d=N(b,2,null),e=N(b,3,null),f=N(b,4,null),g=N(b,5,null),k=N(b,6,null);b=N(b,7,null);b=new Date(Date.UTC(a,c-1,d,e,f,g,k)-6E4*b)}else throw Error(["Unrecognized date/time syntax: ",t.a(a)].join(""));return b}throw Error("Instance literal expects a string for its timestamp.");},Gs,function(a){if("string"===typeof a)return new Nl(a.toLowerCase(),null);throw Error("UUID literal expects a string as its representation."); -},Ms,function(a){if(xf(a))return Fh.g(Yi,a);throw Error("Queue literal expects a vector for its elements.");},Kw,function(a){if(xf(a)){var b=[];a=z(a);for(var c=null,d=0,e=0;;)if(e$/,""),new Q(null,2,5,T,[Jk,new m(null,1,[Dw,new m(null,1,[Kx,a],null)],null)],null)):null}function kP(a){return new Q(null,3,5,T,[iP,new m(null,1,[tp,Lq.a(a)],null),"See on last.fm"],null)} -function lP(a){a=["https://musicbrainz.org/artist/",t.a(px.a(a))].join("");return new Q(null,3,5,T,[iP,new m(null,1,[tp,a],null),"See on musicbrainz"],null)}function mP(a){return qf(nk(a,new Q(null,2,5,T,[Lq,px],null)))?null:new Q(null,3,5,T,[wu,p(Lq.a(a))?new Q(null,2,5,T,[kP,a],null):null,p(px.a(a))?new Q(null,2,5,T,[lP,a],null):null],null)} -function nP(a){var b=null!=a&&(a.l&64||l===a.J)?P(W,a):a,c=x.g(b,Eu);return new Q(null,2,5,T,[Gr,function(){return function(a,b,c){return function n(d){return new Ig(null,function(){return function(){for(;;){var a=z(d);if(a){if(yf(a)){var b=Sd(a),c=I(b),e=Mg(c);a:for(var f=0;;)if(fa?1:a}(),function(){var a=d+2+1,b=f+1;return a.control{flex-shrink:0}.field.is-grouped>.control:not(:last-child){margin-bottom:0;margin-right:0.75rem}.field.is-grouped>.control.is-expanded{flex-grow:1;flex-shrink:1}.field.is-grouped.is-grouped-centered{justify-content:center}.field.is-grouped.is-grouped-right{justify-content:flex-end}.field.is-grouped.is-grouped-multiline{flex-wrap:wrap}.field.is-grouped.is-grouped-multiline>.control:last-child,.field.is-grouped.is-grouped-multiline>.control:not(:last-child){margin-bottom:0.75rem}.field.is-grouped.is-grouped-multiline:last-child{margin-bottom:-0.75rem}.field.is-grouped.is-grouped-multiline:not(:last-child){margin-bottom:0}@media screen and (min-width: 769px), print{.field.is-horizontal{display:flex}}.field-label .label{font-size:inherit}@media screen and (max-width: 768px){.field-label{margin-bottom:0.5rem}}@media screen and (min-width: 769px), print{.field-label{flex-basis:0;flex-grow:1;flex-shrink:0;margin-right:1.5rem;text-align:right}.field-label.is-small{font-size:.75rem;padding-top:0.375em}.field-label.is-normal{padding-top:0.375em}.field-label.is-medium{font-size:1.25rem;padding-top:0.375em}.field-label.is-large{font-size:1.5rem;padding-top:0.375em}}.field-body .field .field{margin-bottom:0}@media screen and (min-width: 769px), print{.field-body{display:flex;flex-basis:0;flex-grow:5;flex-shrink:1}.field-body .field{margin-bottom:0}.field-body>.field{flex-shrink:1}.field-body>.field:not(.is-narrow){flex-grow:1}.field-body>.field:not(:last-child){margin-right:0.75rem}}.control{box-sizing:border-box;clear:both;font-size:1rem;position:relative;text-align:left}.control.has-icons-left .input:focus ~ .icon,.control.has-icons-left .select:focus ~ .icon,.control.has-icons-right .input:focus ~ .icon,.control.has-icons-right .select:focus ~ .icon{color:#7a7a7a}.control.has-icons-left .input.is-small ~ .icon,.control.has-icons-left .select.is-small ~ .icon,.control.has-icons-right .input.is-small ~ .icon,.control.has-icons-right .select.is-small ~ .icon{font-size:.75rem}.control.has-icons-left .input.is-medium ~ .icon,.control.has-icons-left .select.is-medium ~ .icon,.control.has-icons-right .input.is-medium ~ .icon,.control.has-icons-right .select.is-medium ~ .icon{font-size:1.25rem}.control.has-icons-left .input.is-large ~ .icon,.control.has-icons-left .select.is-large ~ .icon,.control.has-icons-right .input.is-large ~ .icon,.control.has-icons-right .select.is-large ~ .icon{font-size:1.5rem}.control.has-icons-left .icon,.control.has-icons-right .icon{color:#dbdbdb;height:2.25em;pointer-events:none;position:absolute;top:0;width:2.25em;z-index:4}.control.has-icons-left .input,.control.has-icons-left .select select{padding-left:2.25em}.control.has-icons-left .icon.is-left{left:0}.control.has-icons-right .input,.control.has-icons-right .select select{padding-right:2.25em}.control.has-icons-right .icon.is-right{right:0}.control.is-loading::after{position:absolute !important;right:0.625em;top:0.625em;z-index:4}.control.is-loading.is-small:after{font-size:.75rem}.control.is-loading.is-medium:after{font-size:1.25rem}.control.is-loading.is-large:after{font-size:1.5rem}.icon{align-items:center;display:inline-flex;justify-content:center;height:1.5rem;width:1.5rem}.icon.is-small{height:1rem;width:1rem}.icon.is-medium{height:2rem;width:2rem}.icon.is-large{height:3rem;width:3rem}.image{display:block;position:relative}.image img{display:block;height:auto;width:100%}.image img.is-rounded{border-radius:290486px}.image.is-square img,.image.is-square .has-ratio,.image.is-1by1 img,.image.is-1by1 .has-ratio,.image.is-5by4 img,.image.is-5by4 .has-ratio,.image.is-4by3 img,.image.is-4by3 .has-ratio,.image.is-3by2 img,.image.is-3by2 .has-ratio,.image.is-5by3 img,.image.is-5by3 .has-ratio,.image.is-16by9 img,.image.is-16by9 .has-ratio,.image.is-2by1 img,.image.is-2by1 .has-ratio,.image.is-3by1 img,.image.is-3by1 .has-ratio,.image.is-4by5 img,.image.is-4by5 .has-ratio,.image.is-3by4 img,.image.is-3by4 .has-ratio,.image.is-2by3 img,.image.is-2by3 .has-ratio,.image.is-3by5 img,.image.is-3by5 .has-ratio,.image.is-9by16 img,.image.is-9by16 .has-ratio,.image.is-1by2 img,.image.is-1by2 .has-ratio,.image.is-1by3 img,.image.is-1by3 .has-ratio{height:100%;width:100%}.image.is-square,.image.is-1by1{padding-top:100%}.image.is-5by4{padding-top:80%}.image.is-4by3{padding-top:75%}.image.is-3by2{padding-top:66.6666%}.image.is-5by3{padding-top:60%}.image.is-16by9{padding-top:56.25%}.image.is-2by1{padding-top:50%}.image.is-3by1{padding-top:33.3333%}.image.is-4by5{padding-top:125%}.image.is-3by4{padding-top:133.3333%}.image.is-2by3{padding-top:150%}.image.is-3by5{padding-top:166.6666%}.image.is-9by16{padding-top:177.7777%}.image.is-1by2{padding-top:200%}.image.is-1by3{padding-top:300%}.image.is-16x16{height:16px;width:16px}.image.is-24x24{height:24px;width:24px}.image.is-32x32{height:32px;width:32px}.image.is-48x48{height:48px;width:48px}.image.is-64x64{height:64px;width:64px}.image.is-96x96{height:96px;width:96px}.image.is-128x128{height:128px;width:128px}.notification{background-color:#f5f5f5;border-radius:4px;padding:1.25rem 2.5rem 1.25rem 1.5rem;position:relative}.notification a:not(.button):not(.dropdown-item){color:currentColor;text-decoration:underline}.notification strong{color:currentColor}.notification code,.notification pre{background:#fff}.notification pre code{background:transparent}.notification>.delete{position:absolute;right:0.5rem;top:0.5rem}.notification .title,.notification .subtitle,.notification .content{color:currentColor}.notification.is-white{background-color:#fff;color:#0a0a0a}.notification.is-black{background-color:#0a0a0a;color:#fff}.notification.is-light{background-color:#f5f5f5;color:#363636}.notification.is-dark{background-color:#363636;color:#f5f5f5}.notification.is-primary{background-color:#00d1b2;color:#fff}.notification.is-link{background-color:#3273dc;color:#fff}.notification.is-info{background-color:#209cee;color:#fff}.notification.is-success{background-color:#23d160;color:#fff}.notification.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.notification.is-danger{background-color:#ff3860;color:#fff}.progress{-moz-appearance:none;-webkit-appearance:none;border:none;border-radius:290486px;display:block;height:1rem;overflow:hidden;padding:0;width:100%}.progress::-webkit-progress-bar{background-color:#dbdbdb}.progress::-webkit-progress-value{background-color:#4a4a4a}.progress::-moz-progress-bar{background-color:#4a4a4a}.progress::-ms-fill{background-color:#4a4a4a;border:none}.progress:indeterminate{animation-duration:1.5s;animation-iteration-count:infinite;animation-name:moveIndeterminate;animation-timing-function:linear;background-color:#dbdbdb;background-image:linear-gradient(to right, #4a4a4a 30%, #dbdbdb 30%);background-position:top left;background-repeat:no-repeat;background-size:150% 150%}.progress:indeterminate::-webkit-progress-bar{background-color:transparent}.progress:indeterminate::-moz-progress-bar{background-color:transparent}.progress.is-white::-webkit-progress-value{background-color:#fff}.progress.is-white::-moz-progress-bar{background-color:#fff}.progress.is-white::-ms-fill{background-color:#fff}.progress.is-white:indeterminate{background-image:linear-gradient(to right, #fff 30%, #dbdbdb 30%)}.progress.is-black::-webkit-progress-value{background-color:#0a0a0a}.progress.is-black::-moz-progress-bar{background-color:#0a0a0a}.progress.is-black::-ms-fill{background-color:#0a0a0a}.progress.is-black:indeterminate{background-image:linear-gradient(to right, #0a0a0a 30%, #dbdbdb 30%)}.progress.is-light::-webkit-progress-value{background-color:#f5f5f5}.progress.is-light::-moz-progress-bar{background-color:#f5f5f5}.progress.is-light::-ms-fill{background-color:#f5f5f5}.progress.is-light:indeterminate{background-image:linear-gradient(to right, #f5f5f5 30%, #dbdbdb 30%)}.progress.is-dark::-webkit-progress-value{background-color:#363636}.progress.is-dark::-moz-progress-bar{background-color:#363636}.progress.is-dark::-ms-fill{background-color:#363636}.progress.is-dark:indeterminate{background-image:linear-gradient(to right, #363636 30%, #dbdbdb 30%)}.progress.is-primary::-webkit-progress-value{background-color:#00d1b2}.progress.is-primary::-moz-progress-bar{background-color:#00d1b2}.progress.is-primary::-ms-fill{background-color:#00d1b2}.progress.is-primary:indeterminate{background-image:linear-gradient(to right, #00d1b2 30%, #dbdbdb 30%)}.progress.is-link::-webkit-progress-value{background-color:#3273dc}.progress.is-link::-moz-progress-bar{background-color:#3273dc}.progress.is-link::-ms-fill{background-color:#3273dc}.progress.is-link:indeterminate{background-image:linear-gradient(to right, #3273dc 30%, #dbdbdb 30%)}.progress.is-info::-webkit-progress-value{background-color:#209cee}.progress.is-info::-moz-progress-bar{background-color:#209cee}.progress.is-info::-ms-fill{background-color:#209cee}.progress.is-info:indeterminate{background-image:linear-gradient(to right, #209cee 30%, #dbdbdb 30%)}.progress.is-success::-webkit-progress-value{background-color:#23d160}.progress.is-success::-moz-progress-bar{background-color:#23d160}.progress.is-success::-ms-fill{background-color:#23d160}.progress.is-success:indeterminate{background-image:linear-gradient(to right, #23d160 30%, #dbdbdb 30%)}.progress.is-warning::-webkit-progress-value{background-color:#ffdd57}.progress.is-warning::-moz-progress-bar{background-color:#ffdd57}.progress.is-warning::-ms-fill{background-color:#ffdd57}.progress.is-warning:indeterminate{background-image:linear-gradient(to right, #ffdd57 30%, #dbdbdb 30%)}.progress.is-danger::-webkit-progress-value{background-color:#ff3860}.progress.is-danger::-moz-progress-bar{background-color:#ff3860}.progress.is-danger::-ms-fill{background-color:#ff3860}.progress.is-danger:indeterminate{background-image:linear-gradient(to right, #ff3860 30%, #dbdbdb 30%)}.progress.is-small{height:.75rem}.progress.is-medium{height:1.25rem}.progress.is-large{height:1.5rem}@keyframes moveIndeterminate{from{background-position:200% 0}to{background-position:-200% 0}}.table{background-color:#fff;color:#363636}.table td,.table th{border:1px solid #dbdbdb;border-width:0 0 1px;padding:0.5em 0.75em;vertical-align:top}.table td.is-white,.table th.is-white{background-color:#fff;border-color:#fff;color:#0a0a0a}.table td.is-black,.table th.is-black{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.table td.is-light,.table th.is-light{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.table td.is-dark,.table th.is-dark{background-color:#363636;border-color:#363636;color:#f5f5f5}.table td.is-primary,.table th.is-primary{background-color:#00d1b2;border-color:#00d1b2;color:#fff}.table td.is-link,.table th.is-link{background-color:#3273dc;border-color:#3273dc;color:#fff}.table td.is-info,.table th.is-info{background-color:#209cee;border-color:#209cee;color:#fff}.table td.is-success,.table th.is-success{background-color:#23d160;border-color:#23d160;color:#fff}.table td.is-warning,.table th.is-warning{background-color:#ffdd57;border-color:#ffdd57;color:rgba(0,0,0,0.7)}.table td.is-danger,.table th.is-danger{background-color:#ff3860;border-color:#ff3860;color:#fff}.table td.is-narrow,.table th.is-narrow{white-space:nowrap;width:1%}.table td.is-selected,.table th.is-selected{background-color:#00d1b2;color:#fff}.table td.is-selected a,.table td.is-selected strong,.table th.is-selected a,.table th.is-selected strong{color:currentColor}.table th{color:#363636;text-align:left}.table tr.is-selected{background-color:#00d1b2;color:#fff}.table tr.is-selected a,.table tr.is-selected strong{color:currentColor}.table tr.is-selected td,.table tr.is-selected th{border-color:#fff;color:currentColor}.table thead{background-color:rgba(0,0,0,0)}.table thead td,.table thead th{border-width:0 0 2px;color:#363636}.table tfoot{background-color:rgba(0,0,0,0)}.table tfoot td,.table tfoot th{border-width:2px 0 0;color:#363636}.table tbody{background-color:rgba(0,0,0,0)}.table tbody tr:last-child td,.table tbody tr:last-child th{border-bottom-width:0}.table.is-bordered td,.table.is-bordered th{border-width:1px}.table.is-bordered tr:last-child td,.table.is-bordered tr:last-child th{border-bottom-width:1px}.table.is-fullwidth{width:100%}.table.is-hoverable tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover{background-color:#fafafa}.table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even){background-color:#f5f5f5}.table.is-narrow td,.table.is-narrow th{padding:0.25em 0.5em}.table.is-striped tbody tr:not(.is-selected):nth-child(even){background-color:#fafafa}.table-container{-webkit-overflow-scrolling:touch;overflow:auto;overflow-y:hidden;max-width:100%}.tags{align-items:center;display:flex;flex-wrap:wrap;justify-content:flex-start}.tags .tag{margin-bottom:0.5rem}.tags .tag:not(:last-child){margin-right:0.5rem}.tags:last-child{margin-bottom:-0.5rem}.tags:not(:last-child){margin-bottom:1rem}.tags.are-medium .tag:not(.is-normal):not(.is-large){font-size:1rem}.tags.are-large .tag:not(.is-normal):not(.is-medium){font-size:1.25rem}.tags.has-addons .tag{margin-right:0}.tags.has-addons .tag:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.tags.has-addons .tag:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.tags.is-centered{justify-content:center}.tags.is-centered .tag{margin-right:0.25rem;margin-left:0.25rem}.tags.is-right{justify-content:flex-end}.tags.is-right .tag:not(:first-child){margin-left:0.5rem}.tags.is-right .tag:not(:last-child){margin-right:0}.tags.has-addons .tag{margin-right:0}.tags.has-addons .tag:not(:first-child){margin-left:0;border-bottom-left-radius:0;border-top-left-radius:0}.tags.has-addons .tag:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.tag:not(body){align-items:center;background-color:#f5f5f5;border-radius:4px;color:#4a4a4a;display:inline-flex;font-size:.75rem;height:2em;justify-content:center;line-height:1.5;padding-left:0.75em;padding-right:0.75em;white-space:nowrap}.tag:not(body) .delete{margin-left:0.25rem;margin-right:-0.375rem}.tag:not(body).is-white{background-color:#fff;color:#0a0a0a}.tag:not(body).is-black{background-color:#0a0a0a;color:#fff}.tag:not(body).is-light{background-color:#f5f5f5;color:#363636}.tag:not(body).is-dark{background-color:#363636;color:#f5f5f5}.tag:not(body).is-primary{background-color:#00d1b2;color:#fff}.tag:not(body).is-link{background-color:#3273dc;color:#fff}.tag:not(body).is-info{background-color:#209cee;color:#fff}.tag:not(body).is-success{background-color:#23d160;color:#fff}.tag:not(body).is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.tag:not(body).is-danger{background-color:#ff3860;color:#fff}.tag:not(body).is-normal{font-size:.75rem}.tag:not(body).is-medium{font-size:1rem}.tag:not(body).is-large{font-size:1.25rem}.tag:not(body) .icon:first-child:not(:last-child){margin-left:-0.375em;margin-right:0.1875em}.tag:not(body) .icon:last-child:not(:first-child){margin-left:0.1875em;margin-right:-0.375em}.tag:not(body) .icon:first-child:last-child{margin-left:-0.375em;margin-right:-0.375em}.tag:not(body).is-delete{margin-left:1px;padding:0;position:relative;width:2em}.tag:not(body).is-delete::before,.tag:not(body).is-delete::after{background-color:currentColor;content:"";display:block;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%) rotate(45deg);transform-origin:center center}.tag:not(body).is-delete::before{height:1px;width:50%}.tag:not(body).is-delete::after{height:50%;width:1px}.tag:not(body).is-delete:hover,.tag:not(body).is-delete:focus{background-color:#e8e8e8}.tag:not(body).is-delete:active{background-color:#dbdbdb}.tag:not(body).is-rounded{border-radius:290486px}a.tag:hover{text-decoration:underline}.title,.subtitle{word-break:break-word}.title em,.title span,.subtitle em,.subtitle span{font-weight:inherit}.title sub,.subtitle sub{font-size:.75em}.title sup,.subtitle sup{font-size:.75em}.title .tag,.subtitle .tag{vertical-align:middle}.title{color:#363636;font-size:2rem;font-weight:600;line-height:1.125}.title strong{color:inherit;font-weight:inherit}.title+.highlight{margin-top:-0.75rem}.title:not(.is-spaced)+.subtitle{margin-top:-1.25rem}.title.is-1{font-size:3rem}.title.is-2{font-size:2.5rem}.title.is-3{font-size:2rem}.title.is-4{font-size:1.5rem}.title.is-5{font-size:1.25rem}.title.is-6{font-size:1rem}.title.is-7{font-size:.75rem}.subtitle{color:#4a4a4a;font-size:1.25rem;font-weight:400;line-height:1.25}.subtitle strong{color:#363636;font-weight:600}.subtitle:not(.is-spaced)+.title{margin-top:-1.25rem}.subtitle.is-1{font-size:3rem}.subtitle.is-2{font-size:2.5rem}.subtitle.is-3{font-size:2rem}.subtitle.is-4{font-size:1.5rem}.subtitle.is-5{font-size:1.25rem}.subtitle.is-6{font-size:1rem}.subtitle.is-7{font-size:.75rem}.heading{display:block;font-size:11px;letter-spacing:1px;margin-bottom:5px;text-transform:uppercase}.highlight{font-weight:400;max-width:100%;overflow:hidden;padding:0}.highlight pre{overflow:auto;max-width:100%}.number{align-items:center;background-color:#f5f5f5;border-radius:290486px;display:inline-flex;font-size:1.25rem;height:2em;justify-content:center;margin-right:1.5rem;min-width:2.5em;padding:0.25rem 0.5rem;text-align:center;vertical-align:top}.breadcrumb{font-size:1rem;white-space:nowrap}.breadcrumb a{align-items:center;color:#3273dc;display:flex;justify-content:center;padding:0 .75em}.breadcrumb a:hover{color:#363636}.breadcrumb li{align-items:center;display:flex}.breadcrumb li:first-child a{padding-left:0}.breadcrumb li.is-active a{color:#363636;cursor:default;pointer-events:none}.breadcrumb li+li::before{color:#b5b5b5;content:"\0002f"}.breadcrumb ul,.breadcrumb ol{align-items:flex-start;display:flex;flex-wrap:wrap;justify-content:flex-start}.breadcrumb .icon:first-child{margin-right:0.5em}.breadcrumb .icon:last-child{margin-left:0.5em}.breadcrumb.is-centered ol,.breadcrumb.is-centered ul{justify-content:center}.breadcrumb.is-right ol,.breadcrumb.is-right ul{justify-content:flex-end}.breadcrumb.is-small{font-size:.75rem}.breadcrumb.is-medium{font-size:1.25rem}.breadcrumb.is-large{font-size:1.5rem}.breadcrumb.has-arrow-separator li+li::before{content:"\02192"}.breadcrumb.has-bullet-separator li+li::before{content:"\02022"}.breadcrumb.has-dot-separator li+li::before{content:"\000b7"}.breadcrumb.has-succeeds-separator li+li::before{content:"\0227B"}.card{background-color:#fff;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);color:#4a4a4a;max-width:100%;position:relative}.card-header{background-color:rgba(0,0,0,0);align-items:stretch;box-shadow:0 1px 2px rgba(10,10,10,0.1);display:flex}.card-header-title{align-items:center;color:#363636;display:flex;flex-grow:1;font-weight:700;padding:0.75rem}.card-header-title.is-centered{justify-content:center}.card-header-icon{align-items:center;cursor:pointer;display:flex;justify-content:center;padding:0.75rem}.card-image{display:block;position:relative}.card-content{background-color:rgba(0,0,0,0);padding:1.5rem}.card-footer{background-color:rgba(0,0,0,0);border-top:1px solid #dbdbdb;align-items:stretch;display:flex}.card-footer-item{align-items:center;display:flex;flex-basis:0;flex-grow:1;flex-shrink:0;justify-content:center;padding:0.75rem}.card-footer-item:not(:last-child){border-right:1px solid #dbdbdb}.card .media:not(:last-child){margin-bottom:0.75rem}.dropdown{display:inline-flex;position:relative;vertical-align:top}.dropdown.is-active .dropdown-menu,.dropdown.is-hoverable:hover .dropdown-menu{display:block}.dropdown.is-right .dropdown-menu{left:auto;right:0}.dropdown.is-up .dropdown-menu{bottom:100%;padding-bottom:4px;padding-top:initial;top:auto}.dropdown-menu{display:none;left:0;min-width:12rem;padding-top:4px;position:absolute;top:100%;z-index:20}.dropdown-content{background-color:#fff;border-radius:4px;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);padding-bottom:0.5rem;padding-top:0.5rem}.dropdown-item{color:#4a4a4a;display:block;font-size:0.875rem;line-height:1.5;padding:0.375rem 1rem;position:relative}a.dropdown-item,button.dropdown-item{padding-right:3rem;text-align:left;white-space:nowrap;width:100%}a.dropdown-item:hover,button.dropdown-item:hover{background-color:#f5f5f5;color:#0a0a0a}a.dropdown-item.is-active,button.dropdown-item.is-active{background-color:#3273dc;color:#fff}.dropdown-divider{background-color:#dbdbdb;border:none;display:block;height:1px;margin:0.5rem 0}.level{align-items:center;justify-content:space-between}.level code{border-radius:4px}.level img{display:inline-block;vertical-align:top}.level.is-mobile{display:flex}.level.is-mobile .level-left,.level.is-mobile .level-right{display:flex}.level.is-mobile .level-left+.level-right{margin-top:0}.level.is-mobile .level-item:not(:last-child){margin-bottom:0;margin-right:0.75rem}.level.is-mobile .level-item:not(.is-narrow){flex-grow:1}@media screen and (min-width: 769px), print{.level{display:flex}.level>.level-item:not(.is-narrow){flex-grow:1}}.level-item{align-items:center;display:flex;flex-basis:auto;flex-grow:0;flex-shrink:0;justify-content:center}.level-item .title,.level-item .subtitle{margin-bottom:0}@media screen and (max-width: 768px){.level-item:not(:last-child){margin-bottom:0.75rem}}.level-left,.level-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.level-left .level-item.is-flexible,.level-right .level-item.is-flexible{flex-grow:1}@media screen and (min-width: 769px), print{.level-left .level-item:not(:last-child),.level-right .level-item:not(:last-child){margin-right:0.75rem}}.level-left{align-items:center;justify-content:flex-start}@media screen and (max-width: 768px){.level-left+.level-right{margin-top:1.5rem}}@media screen and (min-width: 769px), print{.level-left{display:flex}}.level-right{align-items:center;justify-content:flex-end}@media screen and (min-width: 769px), print{.level-right{display:flex}}.list{background-color:#fff;border-radius:4px;box-shadow:0 2px 3px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1)}.list-item{display:block;padding:0.5em 1em}.list-item:not(a){color:#4a4a4a}.list-item:first-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-item:last-child{border-top-left-radius:4px;border-top-right-radius:4px}.list-item:not(:last-child){border-bottom:1px solid #dbdbdb}.list-item.is-active{background-color:#3273dc;color:#fff}a.list-item{background-color:#f5f5f5;cursor:pointer}.media{align-items:flex-start;display:flex;text-align:left}.media .content:not(:last-child){margin-bottom:0.75rem}.media .media{border-top:1px solid rgba(219,219,219,0.5);display:flex;padding-top:0.75rem}.media .media .content:not(:last-child),.media .media .control:not(:last-child){margin-bottom:0.5rem}.media .media .media{padding-top:0.5rem}.media .media .media+.media{margin-top:0.5rem}.media+.media{border-top:1px solid rgba(219,219,219,0.5);margin-top:1rem;padding-top:1rem}.media.is-large+.media{margin-top:1.5rem;padding-top:1.5rem}.media-left,.media-right{flex-basis:auto;flex-grow:0;flex-shrink:0}.media-left{margin-right:1rem}.media-right{margin-left:1rem}.media-content{flex-basis:auto;flex-grow:1;flex-shrink:1;text-align:left}@media screen and (max-width: 768px){.media-content{overflow-x:auto}}.menu{font-size:1rem}.menu.is-small{font-size:.75rem}.menu.is-medium{font-size:1.25rem}.menu.is-large{font-size:1.5rem}.menu-list{line-height:1.25}.menu-list a{border-radius:2px;color:#4a4a4a;display:block;padding:0.5em 0.75em}.menu-list a:hover{background-color:#f5f5f5;color:#363636}.menu-list a.is-active{background-color:#3273dc;color:#fff}.menu-list li ul{border-left:1px solid #dbdbdb;margin:0.75em;padding-left:0.75em}.menu-label{color:#7a7a7a;font-size:0.75em;letter-spacing:0.1em;text-transform:uppercase}.menu-label:not(:first-child){margin-top:1em}.menu-label:not(:last-child){margin-bottom:1em}.message{background-color:#f5f5f5;border-radius:4px;font-size:1rem}.message strong{color:currentColor}.message a:not(.button):not(.tag):not(.dropdown-item){color:currentColor;text-decoration:underline}.message.is-small{font-size:.75rem}.message.is-medium{font-size:1.25rem}.message.is-large{font-size:1.5rem}.message.is-white{background-color:#fff}.message.is-white .message-header{background-color:#fff;color:#0a0a0a}.message.is-white .message-body{border-color:#fff;color:#4d4d4d}.message.is-black{background-color:#fafafa}.message.is-black .message-header{background-color:#0a0a0a;color:#fff}.message.is-black .message-body{border-color:#0a0a0a;color:#090909}.message.is-light{background-color:#fafafa}.message.is-light .message-header{background-color:#f5f5f5;color:#363636}.message.is-light .message-body{border-color:#f5f5f5;color:#505050}.message.is-dark{background-color:#fafafa}.message.is-dark .message-header{background-color:#363636;color:#f5f5f5}.message.is-dark .message-body{border-color:#363636;color:#2a2a2a}.message.is-primary{background-color:#f5fffd}.message.is-primary .message-header{background-color:#00d1b2;color:#fff}.message.is-primary .message-body{border-color:#00d1b2;color:#021310}.message.is-link{background-color:#f6f9fe}.message.is-link .message-header{background-color:#3273dc;color:#fff}.message.is-link .message-body{border-color:#3273dc;color:#22509a}.message.is-info{background-color:#f6fbfe}.message.is-info .message-header{background-color:#209cee;color:#fff}.message.is-info .message-body{border-color:#209cee;color:#12537e}.message.is-success{background-color:#f6fef9}.message.is-success .message-header{background-color:#23d160;color:#fff}.message.is-success .message-body{border-color:#23d160;color:#0e301a}.message.is-warning{background-color:#fffdf5}.message.is-warning .message-header{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.message.is-warning .message-body{border-color:#ffdd57;color:#3b3108}.message.is-danger{background-color:#fff5f7}.message.is-danger .message-header{background-color:#ff3860;color:#fff}.message.is-danger .message-body{border-color:#ff3860;color:#cd0930}.message-header{align-items:center;background-color:#4a4a4a;border-radius:4px 4px 0 0;color:#fff;display:flex;font-weight:700;justify-content:space-between;line-height:1.25;padding:0.75em 1em;position:relative}.message-header .delete{flex-grow:0;flex-shrink:0;margin-left:0.75em}.message-header+.message-body{border-width:0;border-top-left-radius:0;border-top-right-radius:0}.message-body{border-color:#dbdbdb;border-radius:4px;border-style:solid;border-width:0 0 0 4px;color:#4a4a4a;padding:1.25em 1.5em}.message-body code,.message-body pre{background-color:#fff}.message-body pre code{background-color:rgba(0,0,0,0)}.modal{align-items:center;display:none;flex-direction:column;justify-content:center;overflow:hidden;position:fixed;z-index:40}.modal.is-active{display:flex}.modal-background{background-color:rgba(10,10,10,0.86)}.modal-content,.modal-card{margin:0 20px;max-height:calc(100vh - 160px);overflow:auto;position:relative;width:100%}@media screen and (min-width: 769px), print{.modal-content,.modal-card{margin:0 auto;max-height:calc(100vh - 40px);width:640px}}.modal-close{background:none;height:40px;position:fixed;right:20px;top:20px;width:40px}.modal-card{display:flex;flex-direction:column;max-height:calc(100vh - 40px);overflow:hidden;-ms-overflow-y:visible}.modal-card-head,.modal-card-foot{align-items:center;background-color:#f5f5f5;display:flex;flex-shrink:0;justify-content:flex-start;padding:20px;position:relative}.modal-card-head{border-bottom:1px solid #dbdbdb;border-top-left-radius:6px;border-top-right-radius:6px}.modal-card-title{color:#363636;flex-grow:1;flex-shrink:0;font-size:1.5rem;line-height:1}.modal-card-foot{border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:1px solid #dbdbdb}.modal-card-foot .button:not(:last-child){margin-right:10px}.modal-card-body{-webkit-overflow-scrolling:touch;background-color:#fff;flex-grow:1;flex-shrink:1;overflow:auto;padding:20px}.navbar{background-color:#fff;min-height:3.25rem;position:relative;z-index:30}.navbar.is-white{background-color:#fff;color:#0a0a0a}.navbar.is-white .navbar-brand>.navbar-item,.navbar.is-white .navbar-brand .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-brand>a.navbar-item:hover,.navbar.is-white .navbar-brand>a.navbar-item.is-active,.navbar.is-white .navbar-brand .navbar-link:hover,.navbar.is-white .navbar-brand .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-brand .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-burger{color:#0a0a0a}@media screen and (min-width: 1088px){.navbar.is-white .navbar-start>.navbar-item,.navbar.is-white .navbar-start .navbar-link,.navbar.is-white .navbar-end>.navbar-item,.navbar.is-white .navbar-end .navbar-link{color:#0a0a0a}.navbar.is-white .navbar-start>a.navbar-item:hover,.navbar.is-white .navbar-start>a.navbar-item.is-active,.navbar.is-white .navbar-start .navbar-link:hover,.navbar.is-white .navbar-start .navbar-link.is-active,.navbar.is-white .navbar-end>a.navbar-item:hover,.navbar.is-white .navbar-end>a.navbar-item.is-active,.navbar.is-white .navbar-end .navbar-link:hover,.navbar.is-white .navbar-end .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-start .navbar-link::after,.navbar.is-white .navbar-end .navbar-link::after{border-color:#0a0a0a}.navbar.is-white .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-white .navbar-item.has-dropdown.is-active .navbar-link{background-color:#f2f2f2;color:#0a0a0a}.navbar.is-white .navbar-dropdown a.navbar-item.is-active{background-color:#fff;color:#0a0a0a}}.navbar.is-black{background-color:#0a0a0a;color:#fff}.navbar.is-black .navbar-brand>.navbar-item,.navbar.is-black .navbar-brand .navbar-link{color:#fff}.navbar.is-black .navbar-brand>a.navbar-item:hover,.navbar.is-black .navbar-brand>a.navbar-item.is-active,.navbar.is-black .navbar-brand .navbar-link:hover,.navbar.is-black .navbar-brand .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-burger{color:#fff}@media screen and (min-width: 1088px){.navbar.is-black .navbar-start>.navbar-item,.navbar.is-black .navbar-start .navbar-link,.navbar.is-black .navbar-end>.navbar-item,.navbar.is-black .navbar-end .navbar-link{color:#fff}.navbar.is-black .navbar-start>a.navbar-item:hover,.navbar.is-black .navbar-start>a.navbar-item.is-active,.navbar.is-black .navbar-start .navbar-link:hover,.navbar.is-black .navbar-start .navbar-link.is-active,.navbar.is-black .navbar-end>a.navbar-item:hover,.navbar.is-black .navbar-end>a.navbar-item.is-active,.navbar.is-black .navbar-end .navbar-link:hover,.navbar.is-black .navbar-end .navbar-link.is-active{background-color:#000;color:#fff}.navbar.is-black .navbar-start .navbar-link::after,.navbar.is-black .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-black .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-black .navbar-item.has-dropdown.is-active .navbar-link{background-color:#000;color:#fff}.navbar.is-black .navbar-dropdown a.navbar-item.is-active{background-color:#0a0a0a;color:#fff}}.navbar.is-light{background-color:#f5f5f5;color:#363636}.navbar.is-light .navbar-brand>.navbar-item,.navbar.is-light .navbar-brand .navbar-link{color:#363636}.navbar.is-light .navbar-brand>a.navbar-item:hover,.navbar.is-light .navbar-brand>a.navbar-item.is-active,.navbar.is-light .navbar-brand .navbar-link:hover,.navbar.is-light .navbar-brand .navbar-link.is-active{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-brand .navbar-link::after{border-color:#363636}.navbar.is-light .navbar-burger{color:#363636}@media screen and (min-width: 1088px){.navbar.is-light .navbar-start>.navbar-item,.navbar.is-light .navbar-start .navbar-link,.navbar.is-light .navbar-end>.navbar-item,.navbar.is-light .navbar-end .navbar-link{color:#363636}.navbar.is-light .navbar-start>a.navbar-item:hover,.navbar.is-light .navbar-start>a.navbar-item.is-active,.navbar.is-light .navbar-start .navbar-link:hover,.navbar.is-light .navbar-start .navbar-link.is-active,.navbar.is-light .navbar-end>a.navbar-item:hover,.navbar.is-light .navbar-end>a.navbar-item.is-active,.navbar.is-light .navbar-end .navbar-link:hover,.navbar.is-light .navbar-end .navbar-link.is-active{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-start .navbar-link::after,.navbar.is-light .navbar-end .navbar-link::after{border-color:#363636}.navbar.is-light .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-light .navbar-item.has-dropdown.is-active .navbar-link{background-color:#e8e8e8;color:#363636}.navbar.is-light .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#363636}}.navbar.is-dark{background-color:#363636;color:#f5f5f5}.navbar.is-dark .navbar-brand>.navbar-item,.navbar.is-dark .navbar-brand .navbar-link{color:#f5f5f5}.navbar.is-dark .navbar-brand>a.navbar-item:hover,.navbar.is-dark .navbar-brand>a.navbar-item.is-active,.navbar.is-dark .navbar-brand .navbar-link:hover,.navbar.is-dark .navbar-brand .navbar-link.is-active{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-brand .navbar-link::after{border-color:#f5f5f5}.navbar.is-dark .navbar-burger{color:#f5f5f5}@media screen and (min-width: 1088px){.navbar.is-dark .navbar-start>.navbar-item,.navbar.is-dark .navbar-start .navbar-link,.navbar.is-dark .navbar-end>.navbar-item,.navbar.is-dark .navbar-end .navbar-link{color:#f5f5f5}.navbar.is-dark .navbar-start>a.navbar-item:hover,.navbar.is-dark .navbar-start>a.navbar-item.is-active,.navbar.is-dark .navbar-start .navbar-link:hover,.navbar.is-dark .navbar-start .navbar-link.is-active,.navbar.is-dark .navbar-end>a.navbar-item:hover,.navbar.is-dark .navbar-end>a.navbar-item.is-active,.navbar.is-dark .navbar-end .navbar-link:hover,.navbar.is-dark .navbar-end .navbar-link.is-active{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-start .navbar-link::after,.navbar.is-dark .navbar-end .navbar-link::after{border-color:#f5f5f5}.navbar.is-dark .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-dark .navbar-item.has-dropdown.is-active .navbar-link{background-color:#292929;color:#f5f5f5}.navbar.is-dark .navbar-dropdown a.navbar-item.is-active{background-color:#363636;color:#f5f5f5}}.navbar.is-primary{background-color:#00d1b2;color:#fff}.navbar.is-primary .navbar-brand>.navbar-item,.navbar.is-primary .navbar-brand .navbar-link{color:#fff}.navbar.is-primary .navbar-brand>a.navbar-item:hover,.navbar.is-primary .navbar-brand>a.navbar-item.is-active,.navbar.is-primary .navbar-brand .navbar-link:hover,.navbar.is-primary .navbar-brand .navbar-link.is-active{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-burger{color:#fff}@media screen and (min-width: 1088px){.navbar.is-primary .navbar-start>.navbar-item,.navbar.is-primary .navbar-start .navbar-link,.navbar.is-primary .navbar-end>.navbar-item,.navbar.is-primary .navbar-end .navbar-link{color:#fff}.navbar.is-primary .navbar-start>a.navbar-item:hover,.navbar.is-primary .navbar-start>a.navbar-item.is-active,.navbar.is-primary .navbar-start .navbar-link:hover,.navbar.is-primary .navbar-start .navbar-link.is-active,.navbar.is-primary .navbar-end>a.navbar-item:hover,.navbar.is-primary .navbar-end>a.navbar-item.is-active,.navbar.is-primary .navbar-end .navbar-link:hover,.navbar.is-primary .navbar-end .navbar-link.is-active{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-start .navbar-link::after,.navbar.is-primary .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-primary .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-primary .navbar-item.has-dropdown.is-active .navbar-link{background-color:#00b89c;color:#fff}.navbar.is-primary .navbar-dropdown a.navbar-item.is-active{background-color:#00d1b2;color:#fff}}.navbar.is-link{background-color:#3273dc;color:#fff}.navbar.is-link .navbar-brand>.navbar-item,.navbar.is-link .navbar-brand .navbar-link{color:#fff}.navbar.is-link .navbar-brand>a.navbar-item:hover,.navbar.is-link .navbar-brand>a.navbar-item.is-active,.navbar.is-link .navbar-brand .navbar-link:hover,.navbar.is-link .navbar-brand .navbar-link.is-active{background-color:#2366d1;color:#fff}.navbar.is-link .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-burger{color:#fff}@media screen and (min-width: 1088px){.navbar.is-link .navbar-start>.navbar-item,.navbar.is-link .navbar-start .navbar-link,.navbar.is-link .navbar-end>.navbar-item,.navbar.is-link .navbar-end .navbar-link{color:#fff}.navbar.is-link .navbar-start>a.navbar-item:hover,.navbar.is-link .navbar-start>a.navbar-item.is-active,.navbar.is-link .navbar-start .navbar-link:hover,.navbar.is-link .navbar-start .navbar-link.is-active,.navbar.is-link .navbar-end>a.navbar-item:hover,.navbar.is-link .navbar-end>a.navbar-item.is-active,.navbar.is-link .navbar-end .navbar-link:hover,.navbar.is-link .navbar-end .navbar-link.is-active{background-color:#2366d1;color:#fff}.navbar.is-link .navbar-start .navbar-link::after,.navbar.is-link .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-link .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-link .navbar-item.has-dropdown.is-active .navbar-link{background-color:#2366d1;color:#fff}.navbar.is-link .navbar-dropdown a.navbar-item.is-active{background-color:#3273dc;color:#fff}}.navbar.is-info{background-color:#209cee;color:#fff}.navbar.is-info .navbar-brand>.navbar-item,.navbar.is-info .navbar-brand .navbar-link{color:#fff}.navbar.is-info .navbar-brand>a.navbar-item:hover,.navbar.is-info .navbar-brand>a.navbar-item.is-active,.navbar.is-info .navbar-brand .navbar-link:hover,.navbar.is-info .navbar-brand .navbar-link.is-active{background-color:#118fe4;color:#fff}.navbar.is-info .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-burger{color:#fff}@media screen and (min-width: 1088px){.navbar.is-info .navbar-start>.navbar-item,.navbar.is-info .navbar-start .navbar-link,.navbar.is-info .navbar-end>.navbar-item,.navbar.is-info .navbar-end .navbar-link{color:#fff}.navbar.is-info .navbar-start>a.navbar-item:hover,.navbar.is-info .navbar-start>a.navbar-item.is-active,.navbar.is-info .navbar-start .navbar-link:hover,.navbar.is-info .navbar-start .navbar-link.is-active,.navbar.is-info .navbar-end>a.navbar-item:hover,.navbar.is-info .navbar-end>a.navbar-item.is-active,.navbar.is-info .navbar-end .navbar-link:hover,.navbar.is-info .navbar-end .navbar-link.is-active{background-color:#118fe4;color:#fff}.navbar.is-info .navbar-start .navbar-link::after,.navbar.is-info .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-info .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-info .navbar-item.has-dropdown.is-active .navbar-link{background-color:#118fe4;color:#fff}.navbar.is-info .navbar-dropdown a.navbar-item.is-active{background-color:#209cee;color:#fff}}.navbar.is-success{background-color:#23d160;color:#fff}.navbar.is-success .navbar-brand>.navbar-item,.navbar.is-success .navbar-brand .navbar-link{color:#fff}.navbar.is-success .navbar-brand>a.navbar-item:hover,.navbar.is-success .navbar-brand>a.navbar-item.is-active,.navbar.is-success .navbar-brand .navbar-link:hover,.navbar.is-success .navbar-brand .navbar-link.is-active{background-color:#20bc56;color:#fff}.navbar.is-success .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-burger{color:#fff}@media screen and (min-width: 1088px){.navbar.is-success .navbar-start>.navbar-item,.navbar.is-success .navbar-start .navbar-link,.navbar.is-success .navbar-end>.navbar-item,.navbar.is-success .navbar-end .navbar-link{color:#fff}.navbar.is-success .navbar-start>a.navbar-item:hover,.navbar.is-success .navbar-start>a.navbar-item.is-active,.navbar.is-success .navbar-start .navbar-link:hover,.navbar.is-success .navbar-start .navbar-link.is-active,.navbar.is-success .navbar-end>a.navbar-item:hover,.navbar.is-success .navbar-end>a.navbar-item.is-active,.navbar.is-success .navbar-end .navbar-link:hover,.navbar.is-success .navbar-end .navbar-link.is-active{background-color:#20bc56;color:#fff}.navbar.is-success .navbar-start .navbar-link::after,.navbar.is-success .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-success .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-success .navbar-item.has-dropdown.is-active .navbar-link{background-color:#20bc56;color:#fff}.navbar.is-success .navbar-dropdown a.navbar-item.is-active{background-color:#23d160;color:#fff}}.navbar.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>.navbar-item,.navbar.is-warning .navbar-brand .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand>a.navbar-item:hover,.navbar.is-warning .navbar-brand>a.navbar-item.is-active,.navbar.is-warning .navbar-brand .navbar-link:hover,.navbar.is-warning .navbar-brand .navbar-link.is-active{background-color:#ffd83d;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-brand .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-burger{color:rgba(0,0,0,0.7)}@media screen and (min-width: 1088px){.navbar.is-warning .navbar-start>.navbar-item,.navbar.is-warning .navbar-start .navbar-link,.navbar.is-warning .navbar-end>.navbar-item,.navbar.is-warning .navbar-end .navbar-link{color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start>a.navbar-item:hover,.navbar.is-warning .navbar-start>a.navbar-item.is-active,.navbar.is-warning .navbar-start .navbar-link:hover,.navbar.is-warning .navbar-start .navbar-link.is-active,.navbar.is-warning .navbar-end>a.navbar-item:hover,.navbar.is-warning .navbar-end>a.navbar-item.is-active,.navbar.is-warning .navbar-end .navbar-link:hover,.navbar.is-warning .navbar-end .navbar-link.is-active{background-color:#ffd83d;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-start .navbar-link::after,.navbar.is-warning .navbar-end .navbar-link::after{border-color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-warning .navbar-item.has-dropdown.is-active .navbar-link{background-color:#ffd83d;color:rgba(0,0,0,0.7)}.navbar.is-warning .navbar-dropdown a.navbar-item.is-active{background-color:#ffdd57;color:rgba(0,0,0,0.7)}}.navbar.is-danger{background-color:#ff3860;color:#fff}.navbar.is-danger .navbar-brand>.navbar-item,.navbar.is-danger .navbar-brand .navbar-link{color:#fff}.navbar.is-danger .navbar-brand>a.navbar-item:hover,.navbar.is-danger .navbar-brand>a.navbar-item.is-active,.navbar.is-danger .navbar-brand .navbar-link:hover,.navbar.is-danger .navbar-brand .navbar-link.is-active{background-color:#ff1f4b;color:#fff}.navbar.is-danger .navbar-brand .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-burger{color:#fff}@media screen and (min-width: 1088px){.navbar.is-danger .navbar-start>.navbar-item,.navbar.is-danger .navbar-start .navbar-link,.navbar.is-danger .navbar-end>.navbar-item,.navbar.is-danger .navbar-end .navbar-link{color:#fff}.navbar.is-danger .navbar-start>a.navbar-item:hover,.navbar.is-danger .navbar-start>a.navbar-item.is-active,.navbar.is-danger .navbar-start .navbar-link:hover,.navbar.is-danger .navbar-start .navbar-link.is-active,.navbar.is-danger .navbar-end>a.navbar-item:hover,.navbar.is-danger .navbar-end>a.navbar-item.is-active,.navbar.is-danger .navbar-end .navbar-link:hover,.navbar.is-danger .navbar-end .navbar-link.is-active{background-color:#ff1f4b;color:#fff}.navbar.is-danger .navbar-start .navbar-link::after,.navbar.is-danger .navbar-end .navbar-link::after{border-color:#fff}.navbar.is-danger .navbar-item.has-dropdown:hover .navbar-link,.navbar.is-danger .navbar-item.has-dropdown.is-active .navbar-link{background-color:#ff1f4b;color:#fff}.navbar.is-danger .navbar-dropdown a.navbar-item.is-active{background-color:#ff3860;color:#fff}}.navbar>.container,.navbar>.notifications:not(:empty){align-items:stretch;display:flex;min-height:3.25rem;width:100%}.navbar.has-shadow{box-shadow:0 2px 0 0 #f5f5f5}.navbar.is-fixed-bottom,.navbar.is-fixed-top{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom{bottom:0}.navbar.is-fixed-bottom.has-shadow{box-shadow:0 -2px 0 0 #f5f5f5}.navbar.is-fixed-top{top:0}html.has-navbar-fixed-top,body.has-navbar-fixed-top{padding-top:3.25rem}html.has-navbar-fixed-bottom,body.has-navbar-fixed-bottom{padding-bottom:3.25rem}.navbar-brand,.navbar-tabs{align-items:stretch;display:flex;flex-shrink:0;min-height:3.25rem}.navbar-brand a.navbar-item:hover{background-color:transparent}.navbar-tabs{-webkit-overflow-scrolling:touch;max-width:100vw;overflow-x:auto;overflow-y:hidden}.navbar-burger{color:#4a4a4a;cursor:pointer;display:block;height:3.25rem;position:relative;width:3.25rem;margin-left:auto}.navbar-burger span{background-color:currentColor;display:block;height:1px;left:calc(50% - 8px);position:absolute;transform-origin:center;transition-duration:86ms;transition-property:background-color, opacity, transform;transition-timing-function:ease-out;width:16px}.navbar-burger span:nth-child(1){top:calc(50% - 6px)}.navbar-burger span:nth-child(2){top:calc(50% - 1px)}.navbar-burger span:nth-child(3){top:calc(50% + 4px)}.navbar-burger:hover{background-color:rgba(0,0,0,0.05)}.navbar-burger.is-active span:nth-child(1){transform:translateY(5px) rotate(45deg)}.navbar-burger.is-active span:nth-child(2){opacity:0}.navbar-burger.is-active span:nth-child(3){transform:translateY(-5px) rotate(-45deg)}.navbar-menu{display:none}.navbar-item,.navbar-link{color:#4a4a4a;display:block;line-height:1.5;padding:0.5rem 0.75rem;position:relative}.navbar-item .icon:only-child,.navbar-link .icon:only-child{margin-left:-0.25rem;margin-right:-0.25rem}a.navbar-item,.navbar-link{cursor:pointer}a.navbar-item:hover,a.navbar-item.is-active,.navbar-link:hover,.navbar-link.is-active{background-color:#fafafa;color:#3273dc}.navbar-item{display:block;flex-grow:0;flex-shrink:0}.navbar-item img{max-height:1.75rem}.navbar-item.has-dropdown{padding:0}.navbar-item.is-expanded{flex-grow:1;flex-shrink:1}.navbar-item.is-tab{border-bottom:1px solid transparent;min-height:3.25rem;padding-bottom:calc(0.5rem - 1px)}.navbar-item.is-tab:hover{background-color:rgba(0,0,0,0);border-bottom-color:#3273dc}.navbar-item.is-tab.is-active{background-color:rgba(0,0,0,0);border-bottom-color:#3273dc;border-bottom-style:solid;border-bottom-width:3px;color:#3273dc;padding-bottom:calc(0.5rem - 3px)}.navbar-content{flex-grow:1;flex-shrink:1}.navbar-link:not(.is-arrowless){padding-right:2.5em}.navbar-link:not(.is-arrowless)::after{border-color:#3273dc;margin-top:-0.375em;right:1.125em}.navbar-dropdown{font-size:0.875rem;padding-bottom:0.5rem;padding-top:0.5rem}.navbar-dropdown .navbar-item{padding-left:1.5rem;padding-right:1.5rem}.navbar-divider{background-color:#f5f5f5;border:none;display:none;height:2px;margin:0.5rem 0}@media screen and (max-width: 1087px){.navbar>.container,.navbar>.notifications:not(:empty){display:block}.navbar-brand .navbar-item,.navbar-tabs .navbar-item{align-items:center;display:flex}.navbar-link::after{display:none}.navbar-menu{background-color:#fff;box-shadow:0 8px 16px rgba(10,10,10,0.1);padding:0.5rem 0}.navbar-menu.is-active{display:block}.navbar.is-fixed-bottom-touch,.navbar.is-fixed-top-touch{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-touch{bottom:0}.navbar.is-fixed-bottom-touch.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-touch{top:0}.navbar.is-fixed-top .navbar-menu,.navbar.is-fixed-top-touch .navbar-menu{-webkit-overflow-scrolling:touch;max-height:calc(100vh - 3.25rem);overflow:auto}html.has-navbar-fixed-top-touch,body.has-navbar-fixed-top-touch{padding-top:3.25rem}html.has-navbar-fixed-bottom-touch,body.has-navbar-fixed-bottom-touch{padding-bottom:3.25rem}}@media screen and (min-width: 1088px){.navbar,.navbar-menu,.navbar-start,.navbar-end{align-items:stretch;display:flex}.navbar{min-height:3.25rem}.navbar.is-spaced{padding:1rem 2rem}.navbar.is-spaced .navbar-start,.navbar.is-spaced .navbar-end{align-items:center}.navbar.is-spaced a.navbar-item,.navbar.is-spaced .navbar-link{border-radius:4px}.navbar.is-transparent a.navbar-item:hover,.navbar.is-transparent a.navbar-item.is-active,.navbar.is-transparent .navbar-link:hover,.navbar.is-transparent .navbar-link.is-active{background-color:transparent !important}.navbar.is-transparent .navbar-item.has-dropdown.is-active .navbar-link,.navbar.is-transparent .navbar-item.has-dropdown.is-hoverable:hover .navbar-link{background-color:transparent !important}.navbar.is-transparent .navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar.is-transparent .navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#3273dc}.navbar-burger{display:none}.navbar-item,.navbar-link{align-items:center;display:flex}.navbar-item{display:flex}.navbar-item.has-dropdown{align-items:stretch}.navbar-item.has-dropdown-up .navbar-link::after{transform:rotate(135deg) translate(0.25em, -0.25em)}.navbar-item.has-dropdown-up .navbar-dropdown{border-bottom:2px solid #dbdbdb;border-radius:6px 6px 0 0;border-top:none;bottom:100%;box-shadow:0 -8px 8px rgba(10,10,10,0.1);top:auto}.navbar-item.is-active .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown{display:block}.navbar.is-spaced .navbar-item.is-active .navbar-dropdown,.navbar-item.is-active .navbar-dropdown.is-boxed,.navbar.is-spaced .navbar-item.is-hoverable:hover .navbar-dropdown,.navbar-item.is-hoverable:hover .navbar-dropdown.is-boxed{opacity:1;pointer-events:auto;transform:translateY(0)}.navbar-menu{flex-grow:1;flex-shrink:0}.navbar-start{justify-content:flex-start;margin-right:auto}.navbar-end{justify-content:flex-end;margin-left:auto}.navbar-dropdown{background-color:#fff;border-bottom-left-radius:6px;border-bottom-right-radius:6px;border-top:2px solid #dbdbdb;box-shadow:0 8px 8px rgba(10,10,10,0.1);display:none;font-size:0.875rem;left:0;min-width:100%;position:absolute;top:100%;z-index:20}.navbar-dropdown .navbar-item{padding:0.375rem 1rem;white-space:nowrap}.navbar-dropdown a.navbar-item{padding-right:3rem}.navbar-dropdown a.navbar-item:hover{background-color:#f5f5f5;color:#0a0a0a}.navbar-dropdown a.navbar-item.is-active{background-color:#f5f5f5;color:#3273dc}.navbar.is-spaced .navbar-dropdown,.navbar-dropdown.is-boxed{border-radius:6px;border-top:none;box-shadow:0 8px 8px rgba(10,10,10,0.1),0 0 0 1px rgba(10,10,10,0.1);display:block;opacity:0;pointer-events:none;top:calc(100% + (-4px));transform:translateY(-5px);transition-duration:86ms;transition-property:opacity, transform}.navbar-dropdown.is-right{left:auto;right:0}.navbar-divider{display:block}.navbar>.container .navbar-brand,.navbar>.notifications:not(:empty) .navbar-brand,.container>.navbar .navbar-brand,.notifications:not(:empty)>.navbar .navbar-brand{margin-left:-.75rem}.navbar>.container .navbar-menu,.navbar>.notifications:not(:empty) .navbar-menu,.container>.navbar .navbar-menu,.notifications:not(:empty)>.navbar .navbar-menu{margin-right:-.75rem}.navbar.is-fixed-bottom-desktop,.navbar.is-fixed-top-desktop{left:0;position:fixed;right:0;z-index:30}.navbar.is-fixed-bottom-desktop{bottom:0}.navbar.is-fixed-bottom-desktop.has-shadow{box-shadow:0 -2px 3px rgba(10,10,10,0.1)}.navbar.is-fixed-top-desktop{top:0}html.has-navbar-fixed-top-desktop,body.has-navbar-fixed-top-desktop{padding-top:3.25rem}html.has-navbar-fixed-bottom-desktop,body.has-navbar-fixed-bottom-desktop{padding-bottom:3.25rem}html.has-spaced-navbar-fixed-top,body.has-spaced-navbar-fixed-top{padding-top:5.25rem}html.has-spaced-navbar-fixed-bottom,body.has-spaced-navbar-fixed-bottom{padding-bottom:5.25rem}a.navbar-item.is-active,.navbar-link.is-active{color:#0a0a0a}a.navbar-item.is-active:not(:hover),.navbar-link.is-active:not(:hover){background-color:rgba(0,0,0,0)}.navbar-item.has-dropdown:hover .navbar-link,.navbar-item.has-dropdown.is-active .navbar-link{background-color:#fafafa}}.hero.is-fullheight-with-navbar{min-height:calc(100vh - 3.25rem)}.pagination{font-size:1rem;margin:-.25rem}.pagination.is-small{font-size:.75rem}.pagination.is-medium{font-size:1.25rem}.pagination.is-large{font-size:1.5rem}.pagination.is-rounded .pagination-previous,.pagination.is-rounded .pagination-next{padding-left:1em;padding-right:1em;border-radius:290486px}.pagination.is-rounded .pagination-link{border-radius:290486px}.pagination,.pagination-list{align-items:center;display:flex;justify-content:center;text-align:center}.pagination-previous,.pagination-next,.pagination-link,.pagination-ellipsis{font-size:1em;padding-left:0.5em;padding-right:0.5em;justify-content:center;margin:0.25rem;text-align:center}.pagination-previous,.pagination-next,.pagination-link{border-color:#dbdbdb;color:#363636;min-width:2.25em}.pagination-previous:hover,.pagination-next:hover,.pagination-link:hover{border-color:#b5b5b5;color:#363636}.pagination-previous:focus,.pagination-next:focus,.pagination-link:focus{border-color:#3273dc}.pagination-previous:active,.pagination-next:active,.pagination-link:active{box-shadow:inset 0 1px 2px rgba(10,10,10,0.2)}.pagination-previous[disabled],.pagination-next[disabled],.pagination-link[disabled]{background-color:#dbdbdb;border-color:#dbdbdb;box-shadow:none;color:#7a7a7a;opacity:0.5}.pagination-previous,.pagination-next{padding-left:0.75em;padding-right:0.75em;white-space:nowrap}.pagination-link.is-current{background-color:#3273dc;border-color:#3273dc;color:#fff}.pagination-ellipsis{color:#b5b5b5;pointer-events:none}.pagination-list{flex-wrap:wrap}@media screen and (max-width: 768px){.pagination{flex-wrap:wrap}.pagination-previous,.pagination-next{flex-grow:1;flex-shrink:1}.pagination-list li{flex-grow:1;flex-shrink:1}}@media screen and (min-width: 769px), print{.pagination-list{flex-grow:1;flex-shrink:1;justify-content:flex-start;order:1}.pagination-previous{order:2}.pagination-next{order:3}.pagination{justify-content:space-between}.pagination.is-centered .pagination-previous{order:1}.pagination.is-centered .pagination-list{justify-content:center;order:2}.pagination.is-centered .pagination-next{order:3}.pagination.is-right .pagination-previous{order:1}.pagination.is-right .pagination-next{order:2}.pagination.is-right .pagination-list{justify-content:flex-end;order:3}}.panel{font-size:1rem}.panel:not(:last-child){margin-bottom:1.5rem}.panel-heading,.panel-tabs,.panel-block{border-bottom:1px solid #dbdbdb;border-left:1px solid #dbdbdb;border-right:1px solid #dbdbdb}.panel-heading:first-child,.panel-tabs:first-child,.panel-block:first-child{border-top:1px solid #dbdbdb}.panel-heading{background-color:#f5f5f5;border-radius:4px 4px 0 0;color:#363636;font-size:1.25em;font-weight:300;line-height:1.25;padding:0.5em 0.75em}.panel-tabs{align-items:flex-end;display:flex;font-size:0.875em;justify-content:center}.panel-tabs a{border-bottom:1px solid #dbdbdb;margin-bottom:-1px;padding:0.5em}.panel-tabs a.is-active{border-bottom-color:#4a4a4a;color:#363636}.panel-list a{color:#4a4a4a}.panel-list a:hover{color:#3273dc}.panel-block{align-items:center;color:#363636;display:flex;justify-content:flex-start;padding:0.5em 0.75em}.panel-block input[type="checkbox"]{margin-right:0.75em}.panel-block>.control{flex-grow:1;flex-shrink:1;width:100%}.panel-block.is-wrapped{flex-wrap:wrap}.panel-block.is-active{border-left-color:#3273dc;color:#363636}.panel-block.is-active .panel-icon{color:#3273dc}a.panel-block,label.panel-block{cursor:pointer}a.panel-block:hover,label.panel-block:hover{background-color:#f5f5f5}.panel-icon{display:inline-block;font-size:14px;height:1em;line-height:1em;text-align:center;vertical-align:top;width:1em;color:#7a7a7a;margin-right:0.75em}.panel-icon .fa{font-size:inherit;line-height:inherit}.tabs{-webkit-overflow-scrolling:touch;align-items:stretch;display:flex;font-size:1rem;justify-content:space-between;overflow:hidden;overflow-x:auto;white-space:nowrap}.tabs a{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;color:#4a4a4a;display:flex;justify-content:center;margin-bottom:-1px;padding:0.5em 1em;vertical-align:top}.tabs a:hover{border-bottom-color:#363636;color:#363636}.tabs li{display:block}.tabs li.is-active a{border-bottom-color:#3273dc;color:#3273dc}.tabs ul{align-items:center;border-bottom-color:#dbdbdb;border-bottom-style:solid;border-bottom-width:1px;display:flex;flex-grow:1;flex-shrink:0;justify-content:flex-start}.tabs ul.is-left{padding-right:0.75em}.tabs ul.is-center{flex:none;justify-content:center;padding-left:0.75em;padding-right:0.75em}.tabs ul.is-right{justify-content:flex-end;padding-left:0.75em}.tabs .icon:first-child{margin-right:0.5em}.tabs .icon:last-child{margin-left:0.5em}.tabs.is-centered ul{justify-content:center}.tabs.is-right ul{justify-content:flex-end}.tabs.is-boxed a{border:1px solid transparent;border-radius:4px 4px 0 0}.tabs.is-boxed a:hover{background-color:#f5f5f5;border-bottom-color:#dbdbdb}.tabs.is-boxed li.is-active a{background-color:#fff;border-color:#dbdbdb;border-bottom-color:rgba(0,0,0,0) !important}.tabs.is-fullwidth li{flex-grow:1;flex-shrink:0}.tabs.is-toggle a{border-color:#dbdbdb;border-style:solid;border-width:1px;margin-bottom:0;position:relative}.tabs.is-toggle a:hover{background-color:#f5f5f5;border-color:#b5b5b5;z-index:2}.tabs.is-toggle li+li{margin-left:-1px}.tabs.is-toggle li:first-child a{border-radius:4px 0 0 4px}.tabs.is-toggle li:last-child a{border-radius:0 4px 4px 0}.tabs.is-toggle li.is-active a{background-color:#3273dc;border-color:#3273dc;color:#fff;z-index:1}.tabs.is-toggle ul{border-bottom:none}.tabs.is-toggle.is-toggle-rounded li:first-child a{border-bottom-left-radius:290486px;border-top-left-radius:290486px;padding-left:1.25em}.tabs.is-toggle.is-toggle-rounded li:last-child a{border-bottom-right-radius:290486px;border-top-right-radius:290486px;padding-right:1.25em}.tabs.is-small{font-size:.75rem}.tabs.is-medium{font-size:1.25rem}.tabs.is-large{font-size:1.5rem}.column{display:block;flex-basis:0;flex-grow:1;flex-shrink:1;padding:.75rem}.columns.is-mobile>.column.is-narrow{flex:none}.columns.is-mobile>.column.is-full{flex:none;width:100%}.columns.is-mobile>.column.is-three-quarters{flex:none;width:75%}.columns.is-mobile>.column.is-two-thirds{flex:none;width:66.6666%}.columns.is-mobile>.column.is-half{flex:none;width:50%}.columns.is-mobile>.column.is-one-third{flex:none;width:33.3333%}.columns.is-mobile>.column.is-one-quarter{flex:none;width:25%}.columns.is-mobile>.column.is-one-fifth{flex:none;width:20%}.columns.is-mobile>.column.is-two-fifths{flex:none;width:40%}.columns.is-mobile>.column.is-three-fifths{flex:none;width:60%}.columns.is-mobile>.column.is-four-fifths{flex:none;width:80%}.columns.is-mobile>.column.is-offset-three-quarters{margin-left:75%}.columns.is-mobile>.column.is-offset-two-thirds{margin-left:66.6666%}.columns.is-mobile>.column.is-offset-half{margin-left:50%}.columns.is-mobile>.column.is-offset-one-third{margin-left:33.3333%}.columns.is-mobile>.column.is-offset-one-quarter{margin-left:25%}.columns.is-mobile>.column.is-offset-one-fifth{margin-left:20%}.columns.is-mobile>.column.is-offset-two-fifths{margin-left:40%}.columns.is-mobile>.column.is-offset-three-fifths{margin-left:60%}.columns.is-mobile>.column.is-offset-four-fifths{margin-left:80%}.columns.is-mobile>.column.is-1{flex:none;width:8.33333%}.columns.is-mobile>.column.is-offset-1{margin-left:8.33333%}.columns.is-mobile>.column.is-2{flex:none;width:16.66667%}.columns.is-mobile>.column.is-offset-2{margin-left:16.66667%}.columns.is-mobile>.column.is-3{flex:none;width:25%}.columns.is-mobile>.column.is-offset-3{margin-left:25%}.columns.is-mobile>.column.is-4{flex:none;width:33.33333%}.columns.is-mobile>.column.is-offset-4{margin-left:33.33333%}.columns.is-mobile>.column.is-5{flex:none;width:41.66667%}.columns.is-mobile>.column.is-offset-5{margin-left:41.66667%}.columns.is-mobile>.column.is-6{flex:none;width:50%}.columns.is-mobile>.column.is-offset-6{margin-left:50%}.columns.is-mobile>.column.is-7{flex:none;width:58.33333%}.columns.is-mobile>.column.is-offset-7{margin-left:58.33333%}.columns.is-mobile>.column.is-8{flex:none;width:66.66667%}.columns.is-mobile>.column.is-offset-8{margin-left:66.66667%}.columns.is-mobile>.column.is-9{flex:none;width:75%}.columns.is-mobile>.column.is-offset-9{margin-left:75%}.columns.is-mobile>.column.is-10{flex:none;width:83.33333%}.columns.is-mobile>.column.is-offset-10{margin-left:83.33333%}.columns.is-mobile>.column.is-11{flex:none;width:91.66667%}.columns.is-mobile>.column.is-offset-11{margin-left:91.66667%}.columns.is-mobile>.column.is-12{flex:none;width:100%}.columns.is-mobile>.column.is-offset-12{margin-left:100%}@media screen and (max-width: 768px){.column.is-narrow-mobile{flex:none}.column.is-full-mobile{flex:none;width:100%}.column.is-three-quarters-mobile{flex:none;width:75%}.column.is-two-thirds-mobile{flex:none;width:66.6666%}.column.is-half-mobile{flex:none;width:50%}.column.is-one-third-mobile{flex:none;width:33.3333%}.column.is-one-quarter-mobile{flex:none;width:25%}.column.is-one-fifth-mobile{flex:none;width:20%}.column.is-two-fifths-mobile{flex:none;width:40%}.column.is-three-fifths-mobile{flex:none;width:60%}.column.is-four-fifths-mobile{flex:none;width:80%}.column.is-offset-three-quarters-mobile{margin-left:75%}.column.is-offset-two-thirds-mobile{margin-left:66.6666%}.column.is-offset-half-mobile{margin-left:50%}.column.is-offset-one-third-mobile{margin-left:33.3333%}.column.is-offset-one-quarter-mobile{margin-left:25%}.column.is-offset-one-fifth-mobile{margin-left:20%}.column.is-offset-two-fifths-mobile{margin-left:40%}.column.is-offset-three-fifths-mobile{margin-left:60%}.column.is-offset-four-fifths-mobile{margin-left:80%}.column.is-1-mobile{flex:none;width:8.33333%}.column.is-offset-1-mobile{margin-left:8.33333%}.column.is-2-mobile{flex:none;width:16.66667%}.column.is-offset-2-mobile{margin-left:16.66667%}.column.is-3-mobile{flex:none;width:25%}.column.is-offset-3-mobile{margin-left:25%}.column.is-4-mobile{flex:none;width:33.33333%}.column.is-offset-4-mobile{margin-left:33.33333%}.column.is-5-mobile{flex:none;width:41.66667%}.column.is-offset-5-mobile{margin-left:41.66667%}.column.is-6-mobile{flex:none;width:50%}.column.is-offset-6-mobile{margin-left:50%}.column.is-7-mobile{flex:none;width:58.33333%}.column.is-offset-7-mobile{margin-left:58.33333%}.column.is-8-mobile{flex:none;width:66.66667%}.column.is-offset-8-mobile{margin-left:66.66667%}.column.is-9-mobile{flex:none;width:75%}.column.is-offset-9-mobile{margin-left:75%}.column.is-10-mobile{flex:none;width:83.33333%}.column.is-offset-10-mobile{margin-left:83.33333%}.column.is-11-mobile{flex:none;width:91.66667%}.column.is-offset-11-mobile{margin-left:91.66667%}.column.is-12-mobile{flex:none;width:100%}.column.is-offset-12-mobile{margin-left:100%}}@media screen and (min-width: 769px), print{.column.is-narrow,.column.is-narrow-tablet{flex:none}.column.is-full,.column.is-full-tablet{flex:none;width:100%}.column.is-three-quarters,.column.is-three-quarters-tablet{flex:none;width:75%}.column.is-two-thirds,.column.is-two-thirds-tablet{flex:none;width:66.6666%}.column.is-half,.column.is-half-tablet{flex:none;width:50%}.column.is-one-third,.column.is-one-third-tablet{flex:none;width:33.3333%}.column.is-one-quarter,.column.is-one-quarter-tablet{flex:none;width:25%}.column.is-one-fifth,.column.is-one-fifth-tablet{flex:none;width:20%}.column.is-two-fifths,.column.is-two-fifths-tablet{flex:none;width:40%}.column.is-three-fifths,.column.is-three-fifths-tablet{flex:none;width:60%}.column.is-four-fifths,.column.is-four-fifths-tablet{flex:none;width:80%}.column.is-offset-three-quarters,.column.is-offset-three-quarters-tablet{margin-left:75%}.column.is-offset-two-thirds,.column.is-offset-two-thirds-tablet{margin-left:66.6666%}.column.is-offset-half,.column.is-offset-half-tablet{margin-left:50%}.column.is-offset-one-third,.column.is-offset-one-third-tablet{margin-left:33.3333%}.column.is-offset-one-quarter,.column.is-offset-one-quarter-tablet{margin-left:25%}.column.is-offset-one-fifth,.column.is-offset-one-fifth-tablet{margin-left:20%}.column.is-offset-two-fifths,.column.is-offset-two-fifths-tablet{margin-left:40%}.column.is-offset-three-fifths,.column.is-offset-three-fifths-tablet{margin-left:60%}.column.is-offset-four-fifths,.column.is-offset-four-fifths-tablet{margin-left:80%}.column.is-1,.column.is-1-tablet{flex:none;width:8.33333%}.column.is-offset-1,.column.is-offset-1-tablet{margin-left:8.33333%}.column.is-2,.column.is-2-tablet{flex:none;width:16.66667%}.column.is-offset-2,.column.is-offset-2-tablet{margin-left:16.66667%}.column.is-3,.column.is-3-tablet{flex:none;width:25%}.column.is-offset-3,.column.is-offset-3-tablet{margin-left:25%}.column.is-4,.column.is-4-tablet{flex:none;width:33.33333%}.column.is-offset-4,.column.is-offset-4-tablet{margin-left:33.33333%}.column.is-5,.column.is-5-tablet{flex:none;width:41.66667%}.column.is-offset-5,.column.is-offset-5-tablet{margin-left:41.66667%}.column.is-6,.column.is-6-tablet{flex:none;width:50%}.column.is-offset-6,.column.is-offset-6-tablet{margin-left:50%}.column.is-7,.column.is-7-tablet{flex:none;width:58.33333%}.column.is-offset-7,.column.is-offset-7-tablet{margin-left:58.33333%}.column.is-8,.column.is-8-tablet{flex:none;width:66.66667%}.column.is-offset-8,.column.is-offset-8-tablet{margin-left:66.66667%}.column.is-9,.column.is-9-tablet{flex:none;width:75%}.column.is-offset-9,.column.is-offset-9-tablet{margin-left:75%}.column.is-10,.column.is-10-tablet{flex:none;width:83.33333%}.column.is-offset-10,.column.is-offset-10-tablet{margin-left:83.33333%}.column.is-11,.column.is-11-tablet{flex:none;width:91.66667%}.column.is-offset-11,.column.is-offset-11-tablet{margin-left:91.66667%}.column.is-12,.column.is-12-tablet{flex:none;width:100%}.column.is-offset-12,.column.is-offset-12-tablet{margin-left:100%}}@media screen and (max-width: 1087px){.column.is-narrow-touch{flex:none}.column.is-full-touch{flex:none;width:100%}.column.is-three-quarters-touch{flex:none;width:75%}.column.is-two-thirds-touch{flex:none;width:66.6666%}.column.is-half-touch{flex:none;width:50%}.column.is-one-third-touch{flex:none;width:33.3333%}.column.is-one-quarter-touch{flex:none;width:25%}.column.is-one-fifth-touch{flex:none;width:20%}.column.is-two-fifths-touch{flex:none;width:40%}.column.is-three-fifths-touch{flex:none;width:60%}.column.is-four-fifths-touch{flex:none;width:80%}.column.is-offset-three-quarters-touch{margin-left:75%}.column.is-offset-two-thirds-touch{margin-left:66.6666%}.column.is-offset-half-touch{margin-left:50%}.column.is-offset-one-third-touch{margin-left:33.3333%}.column.is-offset-one-quarter-touch{margin-left:25%}.column.is-offset-one-fifth-touch{margin-left:20%}.column.is-offset-two-fifths-touch{margin-left:40%}.column.is-offset-three-fifths-touch{margin-left:60%}.column.is-offset-four-fifths-touch{margin-left:80%}.column.is-1-touch{flex:none;width:8.33333%}.column.is-offset-1-touch{margin-left:8.33333%}.column.is-2-touch{flex:none;width:16.66667%}.column.is-offset-2-touch{margin-left:16.66667%}.column.is-3-touch{flex:none;width:25%}.column.is-offset-3-touch{margin-left:25%}.column.is-4-touch{flex:none;width:33.33333%}.column.is-offset-4-touch{margin-left:33.33333%}.column.is-5-touch{flex:none;width:41.66667%}.column.is-offset-5-touch{margin-left:41.66667%}.column.is-6-touch{flex:none;width:50%}.column.is-offset-6-touch{margin-left:50%}.column.is-7-touch{flex:none;width:58.33333%}.column.is-offset-7-touch{margin-left:58.33333%}.column.is-8-touch{flex:none;width:66.66667%}.column.is-offset-8-touch{margin-left:66.66667%}.column.is-9-touch{flex:none;width:75%}.column.is-offset-9-touch{margin-left:75%}.column.is-10-touch{flex:none;width:83.33333%}.column.is-offset-10-touch{margin-left:83.33333%}.column.is-11-touch{flex:none;width:91.66667%}.column.is-offset-11-touch{margin-left:91.66667%}.column.is-12-touch{flex:none;width:100%}.column.is-offset-12-touch{margin-left:100%}}@media screen and (min-width: 1088px){.column.is-narrow-desktop{flex:none}.column.is-full-desktop{flex:none;width:100%}.column.is-three-quarters-desktop{flex:none;width:75%}.column.is-two-thirds-desktop{flex:none;width:66.6666%}.column.is-half-desktop{flex:none;width:50%}.column.is-one-third-desktop{flex:none;width:33.3333%}.column.is-one-quarter-desktop{flex:none;width:25%}.column.is-one-fifth-desktop{flex:none;width:20%}.column.is-two-fifths-desktop{flex:none;width:40%}.column.is-three-fifths-desktop{flex:none;width:60%}.column.is-four-fifths-desktop{flex:none;width:80%}.column.is-offset-three-quarters-desktop{margin-left:75%}.column.is-offset-two-thirds-desktop{margin-left:66.6666%}.column.is-offset-half-desktop{margin-left:50%}.column.is-offset-one-third-desktop{margin-left:33.3333%}.column.is-offset-one-quarter-desktop{margin-left:25%}.column.is-offset-one-fifth-desktop{margin-left:20%}.column.is-offset-two-fifths-desktop{margin-left:40%}.column.is-offset-three-fifths-desktop{margin-left:60%}.column.is-offset-four-fifths-desktop{margin-left:80%}.column.is-1-desktop{flex:none;width:8.33333%}.column.is-offset-1-desktop{margin-left:8.33333%}.column.is-2-desktop{flex:none;width:16.66667%}.column.is-offset-2-desktop{margin-left:16.66667%}.column.is-3-desktop{flex:none;width:25%}.column.is-offset-3-desktop{margin-left:25%}.column.is-4-desktop{flex:none;width:33.33333%}.column.is-offset-4-desktop{margin-left:33.33333%}.column.is-5-desktop{flex:none;width:41.66667%}.column.is-offset-5-desktop{margin-left:41.66667%}.column.is-6-desktop{flex:none;width:50%}.column.is-offset-6-desktop{margin-left:50%}.column.is-7-desktop{flex:none;width:58.33333%}.column.is-offset-7-desktop{margin-left:58.33333%}.column.is-8-desktop{flex:none;width:66.66667%}.column.is-offset-8-desktop{margin-left:66.66667%}.column.is-9-desktop{flex:none;width:75%}.column.is-offset-9-desktop{margin-left:75%}.column.is-10-desktop{flex:none;width:83.33333%}.column.is-offset-10-desktop{margin-left:83.33333%}.column.is-11-desktop{flex:none;width:91.66667%}.column.is-offset-11-desktop{margin-left:91.66667%}.column.is-12-desktop{flex:none;width:100%}.column.is-offset-12-desktop{margin-left:100%}}@media screen and (min-width: 1280px){.column.is-narrow-widescreen{flex:none}.column.is-full-widescreen{flex:none;width:100%}.column.is-three-quarters-widescreen{flex:none;width:75%}.column.is-two-thirds-widescreen{flex:none;width:66.6666%}.column.is-half-widescreen{flex:none;width:50%}.column.is-one-third-widescreen{flex:none;width:33.3333%}.column.is-one-quarter-widescreen{flex:none;width:25%}.column.is-one-fifth-widescreen{flex:none;width:20%}.column.is-two-fifths-widescreen{flex:none;width:40%}.column.is-three-fifths-widescreen{flex:none;width:60%}.column.is-four-fifths-widescreen{flex:none;width:80%}.column.is-offset-three-quarters-widescreen{margin-left:75%}.column.is-offset-two-thirds-widescreen{margin-left:66.6666%}.column.is-offset-half-widescreen{margin-left:50%}.column.is-offset-one-third-widescreen{margin-left:33.3333%}.column.is-offset-one-quarter-widescreen{margin-left:25%}.column.is-offset-one-fifth-widescreen{margin-left:20%}.column.is-offset-two-fifths-widescreen{margin-left:40%}.column.is-offset-three-fifths-widescreen{margin-left:60%}.column.is-offset-four-fifths-widescreen{margin-left:80%}.column.is-1-widescreen{flex:none;width:8.33333%}.column.is-offset-1-widescreen{margin-left:8.33333%}.column.is-2-widescreen{flex:none;width:16.66667%}.column.is-offset-2-widescreen{margin-left:16.66667%}.column.is-3-widescreen{flex:none;width:25%}.column.is-offset-3-widescreen{margin-left:25%}.column.is-4-widescreen{flex:none;width:33.33333%}.column.is-offset-4-widescreen{margin-left:33.33333%}.column.is-5-widescreen{flex:none;width:41.66667%}.column.is-offset-5-widescreen{margin-left:41.66667%}.column.is-6-widescreen{flex:none;width:50%}.column.is-offset-6-widescreen{margin-left:50%}.column.is-7-widescreen{flex:none;width:58.33333%}.column.is-offset-7-widescreen{margin-left:58.33333%}.column.is-8-widescreen{flex:none;width:66.66667%}.column.is-offset-8-widescreen{margin-left:66.66667%}.column.is-9-widescreen{flex:none;width:75%}.column.is-offset-9-widescreen{margin-left:75%}.column.is-10-widescreen{flex:none;width:83.33333%}.column.is-offset-10-widescreen{margin-left:83.33333%}.column.is-11-widescreen{flex:none;width:91.66667%}.column.is-offset-11-widescreen{margin-left:91.66667%}.column.is-12-widescreen{flex:none;width:100%}.column.is-offset-12-widescreen{margin-left:100%}}@media screen and (min-width: 1472px){.column.is-narrow-fullhd{flex:none}.column.is-full-fullhd{flex:none;width:100%}.column.is-three-quarters-fullhd{flex:none;width:75%}.column.is-two-thirds-fullhd{flex:none;width:66.6666%}.column.is-half-fullhd{flex:none;width:50%}.column.is-one-third-fullhd{flex:none;width:33.3333%}.column.is-one-quarter-fullhd{flex:none;width:25%}.column.is-one-fifth-fullhd{flex:none;width:20%}.column.is-two-fifths-fullhd{flex:none;width:40%}.column.is-three-fifths-fullhd{flex:none;width:60%}.column.is-four-fifths-fullhd{flex:none;width:80%}.column.is-offset-three-quarters-fullhd{margin-left:75%}.column.is-offset-two-thirds-fullhd{margin-left:66.6666%}.column.is-offset-half-fullhd{margin-left:50%}.column.is-offset-one-third-fullhd{margin-left:33.3333%}.column.is-offset-one-quarter-fullhd{margin-left:25%}.column.is-offset-one-fifth-fullhd{margin-left:20%}.column.is-offset-two-fifths-fullhd{margin-left:40%}.column.is-offset-three-fifths-fullhd{margin-left:60%}.column.is-offset-four-fifths-fullhd{margin-left:80%}.column.is-1-fullhd{flex:none;width:8.33333%}.column.is-offset-1-fullhd{margin-left:8.33333%}.column.is-2-fullhd{flex:none;width:16.66667%}.column.is-offset-2-fullhd{margin-left:16.66667%}.column.is-3-fullhd{flex:none;width:25%}.column.is-offset-3-fullhd{margin-left:25%}.column.is-4-fullhd{flex:none;width:33.33333%}.column.is-offset-4-fullhd{margin-left:33.33333%}.column.is-5-fullhd{flex:none;width:41.66667%}.column.is-offset-5-fullhd{margin-left:41.66667%}.column.is-6-fullhd{flex:none;width:50%}.column.is-offset-6-fullhd{margin-left:50%}.column.is-7-fullhd{flex:none;width:58.33333%}.column.is-offset-7-fullhd{margin-left:58.33333%}.column.is-8-fullhd{flex:none;width:66.66667%}.column.is-offset-8-fullhd{margin-left:66.66667%}.column.is-9-fullhd{flex:none;width:75%}.column.is-offset-9-fullhd{margin-left:75%}.column.is-10-fullhd{flex:none;width:83.33333%}.column.is-offset-10-fullhd{margin-left:83.33333%}.column.is-11-fullhd{flex:none;width:91.66667%}.column.is-offset-11-fullhd{margin-left:91.66667%}.column.is-12-fullhd{flex:none;width:100%}.column.is-offset-12-fullhd{margin-left:100%}}.columns{margin-left:-.75rem;margin-right:-.75rem;margin-top:-.75rem}.columns:last-child{margin-bottom:-.75rem}.columns:not(:last-child){margin-bottom:calc(1.5rem - .75rem)}.columns.is-centered{justify-content:center}.columns.is-gapless{margin-left:0;margin-right:0;margin-top:0}.columns.is-gapless>.column{margin:0;padding:0 !important}.columns.is-gapless:not(:last-child){margin-bottom:1.5rem}.columns.is-gapless:last-child{margin-bottom:0}.columns.is-mobile{display:flex}.columns.is-multiline{flex-wrap:wrap}.columns.is-vcentered{align-items:center}@media screen and (min-width: 769px), print{.columns:not(.is-desktop){display:flex}}@media screen and (min-width: 1088px){.columns.is-desktop{display:flex}}.columns.is-variable{--columnGap: 0.75rem;margin-left:calc(-1 * var(--columnGap));margin-right:calc(-1 * var(--columnGap))}.columns.is-variable .column{padding-left:var(--columnGap);padding-right:var(--columnGap)}.columns.is-variable.is-0{--columnGap: 0rem}@media screen and (max-width: 768px){.columns.is-variable.is-0-mobile{--columnGap: 0rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-0-tablet{--columnGap: 0rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-0-tablet-only{--columnGap: 0rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-0-touch{--columnGap: 0rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-0-desktop{--columnGap: 0rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-0-desktop-only{--columnGap: 0rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-0-widescreen{--columnGap: 0rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-0-widescreen-only{--columnGap: 0rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-0-fullhd{--columnGap: 0rem}}.columns.is-variable.is-1{--columnGap: .25rem}@media screen and (max-width: 768px){.columns.is-variable.is-1-mobile{--columnGap: .25rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-1-tablet{--columnGap: .25rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-1-tablet-only{--columnGap: .25rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-1-touch{--columnGap: .25rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-1-desktop{--columnGap: .25rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-1-desktop-only{--columnGap: .25rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-1-widescreen{--columnGap: .25rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-1-widescreen-only{--columnGap: .25rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-1-fullhd{--columnGap: .25rem}}.columns.is-variable.is-2{--columnGap: .5rem}@media screen and (max-width: 768px){.columns.is-variable.is-2-mobile{--columnGap: .5rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-2-tablet{--columnGap: .5rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-2-tablet-only{--columnGap: .5rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-2-touch{--columnGap: .5rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-2-desktop{--columnGap: .5rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-2-desktop-only{--columnGap: .5rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-2-widescreen{--columnGap: .5rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-2-widescreen-only{--columnGap: .5rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-2-fullhd{--columnGap: .5rem}}.columns.is-variable.is-3{--columnGap: .75rem}@media screen and (max-width: 768px){.columns.is-variable.is-3-mobile{--columnGap: .75rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-3-tablet{--columnGap: .75rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-3-tablet-only{--columnGap: .75rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-3-touch{--columnGap: .75rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-3-desktop{--columnGap: .75rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-3-desktop-only{--columnGap: .75rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-3-widescreen{--columnGap: .75rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-3-widescreen-only{--columnGap: .75rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-3-fullhd{--columnGap: .75rem}}.columns.is-variable.is-4{--columnGap: 1rem}@media screen and (max-width: 768px){.columns.is-variable.is-4-mobile{--columnGap: 1rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-4-tablet{--columnGap: 1rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-4-tablet-only{--columnGap: 1rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-4-touch{--columnGap: 1rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-4-desktop{--columnGap: 1rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-4-desktop-only{--columnGap: 1rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-4-widescreen{--columnGap: 1rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-4-widescreen-only{--columnGap: 1rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-4-fullhd{--columnGap: 1rem}}.columns.is-variable.is-5{--columnGap: 1.25rem}@media screen and (max-width: 768px){.columns.is-variable.is-5-mobile{--columnGap: 1.25rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-5-tablet{--columnGap: 1.25rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-5-tablet-only{--columnGap: 1.25rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-5-touch{--columnGap: 1.25rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-5-desktop{--columnGap: 1.25rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-5-desktop-only{--columnGap: 1.25rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-5-widescreen{--columnGap: 1.25rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-5-widescreen-only{--columnGap: 1.25rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-5-fullhd{--columnGap: 1.25rem}}.columns.is-variable.is-6{--columnGap: 1.5rem}@media screen and (max-width: 768px){.columns.is-variable.is-6-mobile{--columnGap: 1.5rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-6-tablet{--columnGap: 1.5rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-6-tablet-only{--columnGap: 1.5rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-6-touch{--columnGap: 1.5rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-6-desktop{--columnGap: 1.5rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-6-desktop-only{--columnGap: 1.5rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-6-widescreen{--columnGap: 1.5rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-6-widescreen-only{--columnGap: 1.5rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-6-fullhd{--columnGap: 1.5rem}}.columns.is-variable.is-7{--columnGap: 1.75rem}@media screen and (max-width: 768px){.columns.is-variable.is-7-mobile{--columnGap: 1.75rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-7-tablet{--columnGap: 1.75rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-7-tablet-only{--columnGap: 1.75rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-7-touch{--columnGap: 1.75rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-7-desktop{--columnGap: 1.75rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-7-desktop-only{--columnGap: 1.75rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-7-widescreen{--columnGap: 1.75rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-7-widescreen-only{--columnGap: 1.75rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-7-fullhd{--columnGap: 1.75rem}}.columns.is-variable.is-8{--columnGap: 2rem}@media screen and (max-width: 768px){.columns.is-variable.is-8-mobile{--columnGap: 2rem}}@media screen and (min-width: 769px), print{.columns.is-variable.is-8-tablet{--columnGap: 2rem}}@media screen and (min-width: 769px) and (max-width: 1087px){.columns.is-variable.is-8-tablet-only{--columnGap: 2rem}}@media screen and (max-width: 1087px){.columns.is-variable.is-8-touch{--columnGap: 2rem}}@media screen and (min-width: 1088px){.columns.is-variable.is-8-desktop{--columnGap: 2rem}}@media screen and (min-width: 1088px) and (max-width: 1279px){.columns.is-variable.is-8-desktop-only{--columnGap: 2rem}}@media screen and (min-width: 1280px){.columns.is-variable.is-8-widescreen{--columnGap: 2rem}}@media screen and (min-width: 1280px) and (max-width: 1471px){.columns.is-variable.is-8-widescreen-only{--columnGap: 2rem}}@media screen and (min-width: 1472px){.columns.is-variable.is-8-fullhd{--columnGap: 2rem}}.tile{align-items:stretch;display:block;flex-basis:0;flex-grow:1;flex-shrink:1;min-height:min-content}.tile.is-ancestor{margin-left:-0.75rem;margin-right:-0.75rem;margin-top:-0.75rem}.tile.is-ancestor:last-child{margin-bottom:-0.75rem}.tile.is-ancestor:not(:last-child){margin-bottom:0.75rem}.tile.is-child{margin:0 !important}.tile.is-parent{padding:0.75rem}.tile.is-vertical{flex-direction:column}.tile.is-vertical>.tile.is-child:not(:last-child){margin-bottom:1.5rem !important}@media screen and (min-width: 769px), print{.tile:not(.is-child){display:flex}.tile.is-1{flex:none;width:8.33333%}.tile.is-2{flex:none;width:16.66667%}.tile.is-3{flex:none;width:25%}.tile.is-4{flex:none;width:33.33333%}.tile.is-5{flex:none;width:41.66667%}.tile.is-6{flex:none;width:50%}.tile.is-7{flex:none;width:58.33333%}.tile.is-8{flex:none;width:66.66667%}.tile.is-9{flex:none;width:75%}.tile.is-10{flex:none;width:83.33333%}.tile.is-11{flex:none;width:91.66667%}.tile.is-12{flex:none;width:100%}}.hero{align-items:stretch;display:flex;flex-direction:column;justify-content:space-between}.hero .navbar{background:none}.hero .tabs ul{border-bottom:none}.hero.is-white{background-color:#fff;color:#0a0a0a}.hero.is-white a:not(.button):not(.dropdown-item):not(.tag),.hero.is-white strong{color:inherit}.hero.is-white .title{color:#0a0a0a}.hero.is-white .subtitle{color:rgba(10,10,10,0.9)}.hero.is-white .subtitle a:not(.button),.hero.is-white .subtitle strong{color:#0a0a0a}@media screen and (max-width: 1087px){.hero.is-white .navbar-menu{background-color:#fff}}.hero.is-white .navbar-item,.hero.is-white .navbar-link{color:rgba(10,10,10,0.7)}.hero.is-white a.navbar-item:hover,.hero.is-white a.navbar-item.is-active,.hero.is-white .navbar-link:hover,.hero.is-white .navbar-link.is-active{background-color:#f2f2f2;color:#0a0a0a}.hero.is-white .tabs a{color:#0a0a0a;opacity:0.9}.hero.is-white .tabs a:hover{opacity:1}.hero.is-white .tabs li.is-active a{opacity:1}.hero.is-white .tabs.is-boxed a,.hero.is-white .tabs.is-toggle a{color:#0a0a0a}.hero.is-white .tabs.is-boxed a:hover,.hero.is-white .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-white .tabs.is-boxed li.is-active a,.hero.is-white .tabs.is-boxed li.is-active a:hover,.hero.is-white .tabs.is-toggle li.is-active a,.hero.is-white .tabs.is-toggle li.is-active a:hover{background-color:#0a0a0a;border-color:#0a0a0a;color:#fff}.hero.is-white.is-bold{background-image:linear-gradient(141deg, #e6e6e6 0%, #fff 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-white.is-bold .navbar-menu{background-image:linear-gradient(141deg, #e6e6e6 0%, #fff 71%, #fff 100%)}}.hero.is-black{background-color:#0a0a0a;color:#fff}.hero.is-black a:not(.button):not(.dropdown-item):not(.tag),.hero.is-black strong{color:inherit}.hero.is-black .title{color:#fff}.hero.is-black .subtitle{color:rgba(255,255,255,0.9)}.hero.is-black .subtitle a:not(.button),.hero.is-black .subtitle strong{color:#fff}@media screen and (max-width: 1087px){.hero.is-black .navbar-menu{background-color:#0a0a0a}}.hero.is-black .navbar-item,.hero.is-black .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-black a.navbar-item:hover,.hero.is-black a.navbar-item.is-active,.hero.is-black .navbar-link:hover,.hero.is-black .navbar-link.is-active{background-color:#000;color:#fff}.hero.is-black .tabs a{color:#fff;opacity:0.9}.hero.is-black .tabs a:hover{opacity:1}.hero.is-black .tabs li.is-active a{opacity:1}.hero.is-black .tabs.is-boxed a,.hero.is-black .tabs.is-toggle a{color:#fff}.hero.is-black .tabs.is-boxed a:hover,.hero.is-black .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-black .tabs.is-boxed li.is-active a,.hero.is-black .tabs.is-boxed li.is-active a:hover,.hero.is-black .tabs.is-toggle li.is-active a,.hero.is-black .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#0a0a0a}.hero.is-black.is-bold{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}@media screen and (max-width: 768px){.hero.is-black.is-bold .navbar-menu{background-image:linear-gradient(141deg, #000 0%, #0a0a0a 71%, #181616 100%)}}.hero.is-light{background-color:#f5f5f5;color:#363636}.hero.is-light a:not(.button):not(.dropdown-item):not(.tag),.hero.is-light strong{color:inherit}.hero.is-light .title{color:#363636}.hero.is-light .subtitle{color:rgba(54,54,54,0.9)}.hero.is-light .subtitle a:not(.button),.hero.is-light .subtitle strong{color:#363636}@media screen and (max-width: 1087px){.hero.is-light .navbar-menu{background-color:#f5f5f5}}.hero.is-light .navbar-item,.hero.is-light .navbar-link{color:rgba(54,54,54,0.7)}.hero.is-light a.navbar-item:hover,.hero.is-light a.navbar-item.is-active,.hero.is-light .navbar-link:hover,.hero.is-light .navbar-link.is-active{background-color:#e8e8e8;color:#363636}.hero.is-light .tabs a{color:#363636;opacity:0.9}.hero.is-light .tabs a:hover{opacity:1}.hero.is-light .tabs li.is-active a{opacity:1}.hero.is-light .tabs.is-boxed a,.hero.is-light .tabs.is-toggle a{color:#363636}.hero.is-light .tabs.is-boxed a:hover,.hero.is-light .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-light .tabs.is-boxed li.is-active a,.hero.is-light .tabs.is-boxed li.is-active a:hover,.hero.is-light .tabs.is-toggle li.is-active a,.hero.is-light .tabs.is-toggle li.is-active a:hover{background-color:#363636;border-color:#363636;color:#f5f5f5}.hero.is-light.is-bold{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}@media screen and (max-width: 768px){.hero.is-light.is-bold .navbar-menu{background-image:linear-gradient(141deg, #dfd8d9 0%, #f5f5f5 71%, #fff 100%)}}.hero.is-dark{background-color:#363636;color:#f5f5f5}.hero.is-dark a:not(.button):not(.dropdown-item):not(.tag),.hero.is-dark strong{color:inherit}.hero.is-dark .title{color:#f5f5f5}.hero.is-dark .subtitle{color:rgba(245,245,245,0.9)}.hero.is-dark .subtitle a:not(.button),.hero.is-dark .subtitle strong{color:#f5f5f5}@media screen and (max-width: 1087px){.hero.is-dark .navbar-menu{background-color:#363636}}.hero.is-dark .navbar-item,.hero.is-dark .navbar-link{color:rgba(245,245,245,0.7)}.hero.is-dark a.navbar-item:hover,.hero.is-dark a.navbar-item.is-active,.hero.is-dark .navbar-link:hover,.hero.is-dark .navbar-link.is-active{background-color:#292929;color:#f5f5f5}.hero.is-dark .tabs a{color:#f5f5f5;opacity:0.9}.hero.is-dark .tabs a:hover{opacity:1}.hero.is-dark .tabs li.is-active a{opacity:1}.hero.is-dark .tabs.is-boxed a,.hero.is-dark .tabs.is-toggle a{color:#f5f5f5}.hero.is-dark .tabs.is-boxed a:hover,.hero.is-dark .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-dark .tabs.is-boxed li.is-active a,.hero.is-dark .tabs.is-boxed li.is-active a:hover,.hero.is-dark .tabs.is-toggle li.is-active a,.hero.is-dark .tabs.is-toggle li.is-active a:hover{background-color:#f5f5f5;border-color:#f5f5f5;color:#363636}.hero.is-dark.is-bold{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}@media screen and (max-width: 768px){.hero.is-dark.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1f191a 0%, #363636 71%, #46403f 100%)}}.hero.is-primary{background-color:#00d1b2;color:#fff}.hero.is-primary a:not(.button):not(.dropdown-item):not(.tag),.hero.is-primary strong{color:inherit}.hero.is-primary .title{color:#fff}.hero.is-primary .subtitle{color:rgba(255,255,255,0.9)}.hero.is-primary .subtitle a:not(.button),.hero.is-primary .subtitle strong{color:#fff}@media screen and (max-width: 1087px){.hero.is-primary .navbar-menu{background-color:#00d1b2}}.hero.is-primary .navbar-item,.hero.is-primary .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-primary a.navbar-item:hover,.hero.is-primary a.navbar-item.is-active,.hero.is-primary .navbar-link:hover,.hero.is-primary .navbar-link.is-active{background-color:#00b89c;color:#fff}.hero.is-primary .tabs a{color:#fff;opacity:0.9}.hero.is-primary .tabs a:hover{opacity:1}.hero.is-primary .tabs li.is-active a{opacity:1}.hero.is-primary .tabs.is-boxed a,.hero.is-primary .tabs.is-toggle a{color:#fff}.hero.is-primary .tabs.is-boxed a:hover,.hero.is-primary .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-primary .tabs.is-boxed li.is-active a,.hero.is-primary .tabs.is-boxed li.is-active a:hover,.hero.is-primary .tabs.is-toggle li.is-active a,.hero.is-primary .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#00d1b2}.hero.is-primary.is-bold{background-image:linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%)}@media screen and (max-width: 768px){.hero.is-primary.is-bold .navbar-menu{background-image:linear-gradient(141deg, #009e6c 0%, #00d1b2 71%, #00e7eb 100%)}}.hero.is-link{background-color:#3273dc;color:#fff}.hero.is-link a:not(.button):not(.dropdown-item):not(.tag),.hero.is-link strong{color:inherit}.hero.is-link .title{color:#fff}.hero.is-link .subtitle{color:rgba(255,255,255,0.9)}.hero.is-link .subtitle a:not(.button),.hero.is-link .subtitle strong{color:#fff}@media screen and (max-width: 1087px){.hero.is-link .navbar-menu{background-color:#3273dc}}.hero.is-link .navbar-item,.hero.is-link .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-link a.navbar-item:hover,.hero.is-link a.navbar-item.is-active,.hero.is-link .navbar-link:hover,.hero.is-link .navbar-link.is-active{background-color:#2366d1;color:#fff}.hero.is-link .tabs a{color:#fff;opacity:0.9}.hero.is-link .tabs a:hover{opacity:1}.hero.is-link .tabs li.is-active a{opacity:1}.hero.is-link .tabs.is-boxed a,.hero.is-link .tabs.is-toggle a{color:#fff}.hero.is-link .tabs.is-boxed a:hover,.hero.is-link .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-link .tabs.is-boxed li.is-active a,.hero.is-link .tabs.is-boxed li.is-active a:hover,.hero.is-link .tabs.is-toggle li.is-active a,.hero.is-link .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#3273dc}.hero.is-link.is-bold{background-image:linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%)}@media screen and (max-width: 768px){.hero.is-link.is-bold .navbar-menu{background-image:linear-gradient(141deg, #1577c6 0%, #3273dc 71%, #4366e5 100%)}}.hero.is-info{background-color:#209cee;color:#fff}.hero.is-info a:not(.button):not(.dropdown-item):not(.tag),.hero.is-info strong{color:inherit}.hero.is-info .title{color:#fff}.hero.is-info .subtitle{color:rgba(255,255,255,0.9)}.hero.is-info .subtitle a:not(.button),.hero.is-info .subtitle strong{color:#fff}@media screen and (max-width: 1087px){.hero.is-info .navbar-menu{background-color:#209cee}}.hero.is-info .navbar-item,.hero.is-info .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-info a.navbar-item:hover,.hero.is-info a.navbar-item.is-active,.hero.is-info .navbar-link:hover,.hero.is-info .navbar-link.is-active{background-color:#118fe4;color:#fff}.hero.is-info .tabs a{color:#fff;opacity:0.9}.hero.is-info .tabs a:hover{opacity:1}.hero.is-info .tabs li.is-active a{opacity:1}.hero.is-info .tabs.is-boxed a,.hero.is-info .tabs.is-toggle a{color:#fff}.hero.is-info .tabs.is-boxed a:hover,.hero.is-info .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-info .tabs.is-boxed li.is-active a,.hero.is-info .tabs.is-boxed li.is-active a:hover,.hero.is-info .tabs.is-toggle li.is-active a,.hero.is-info .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#209cee}.hero.is-info.is-bold{background-image:linear-gradient(141deg, #04a6d7 0%, #209cee 71%, #3287f5 100%)}@media screen and (max-width: 768px){.hero.is-info.is-bold .navbar-menu{background-image:linear-gradient(141deg, #04a6d7 0%, #209cee 71%, #3287f5 100%)}}.hero.is-success{background-color:#23d160;color:#fff}.hero.is-success a:not(.button):not(.dropdown-item):not(.tag),.hero.is-success strong{color:inherit}.hero.is-success .title{color:#fff}.hero.is-success .subtitle{color:rgba(255,255,255,0.9)}.hero.is-success .subtitle a:not(.button),.hero.is-success .subtitle strong{color:#fff}@media screen and (max-width: 1087px){.hero.is-success .navbar-menu{background-color:#23d160}}.hero.is-success .navbar-item,.hero.is-success .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-success a.navbar-item:hover,.hero.is-success a.navbar-item.is-active,.hero.is-success .navbar-link:hover,.hero.is-success .navbar-link.is-active{background-color:#20bc56;color:#fff}.hero.is-success .tabs a{color:#fff;opacity:0.9}.hero.is-success .tabs a:hover{opacity:1}.hero.is-success .tabs li.is-active a{opacity:1}.hero.is-success .tabs.is-boxed a,.hero.is-success .tabs.is-toggle a{color:#fff}.hero.is-success .tabs.is-boxed a:hover,.hero.is-success .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-success .tabs.is-boxed li.is-active a,.hero.is-success .tabs.is-boxed li.is-active a:hover,.hero.is-success .tabs.is-toggle li.is-active a,.hero.is-success .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#23d160}.hero.is-success.is-bold{background-image:linear-gradient(141deg, #12af2f 0%, #23d160 71%, #2ce28a 100%)}@media screen and (max-width: 768px){.hero.is-success.is-bold .navbar-menu{background-image:linear-gradient(141deg, #12af2f 0%, #23d160 71%, #2ce28a 100%)}}.hero.is-warning{background-color:#ffdd57;color:rgba(0,0,0,0.7)}.hero.is-warning a:not(.button):not(.dropdown-item):not(.tag),.hero.is-warning strong{color:inherit}.hero.is-warning .title{color:rgba(0,0,0,0.7)}.hero.is-warning .subtitle{color:rgba(0,0,0,0.9)}.hero.is-warning .subtitle a:not(.button),.hero.is-warning .subtitle strong{color:rgba(0,0,0,0.7)}@media screen and (max-width: 1087px){.hero.is-warning .navbar-menu{background-color:#ffdd57}}.hero.is-warning .navbar-item,.hero.is-warning .navbar-link{color:rgba(0,0,0,0.7)}.hero.is-warning a.navbar-item:hover,.hero.is-warning a.navbar-item.is-active,.hero.is-warning .navbar-link:hover,.hero.is-warning .navbar-link.is-active{background-color:#ffd83d;color:rgba(0,0,0,0.7)}.hero.is-warning .tabs a{color:rgba(0,0,0,0.7);opacity:0.9}.hero.is-warning .tabs a:hover{opacity:1}.hero.is-warning .tabs li.is-active a{opacity:1}.hero.is-warning .tabs.is-boxed a,.hero.is-warning .tabs.is-toggle a{color:rgba(0,0,0,0.7)}.hero.is-warning .tabs.is-boxed a:hover,.hero.is-warning .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-warning .tabs.is-boxed li.is-active a,.hero.is-warning .tabs.is-boxed li.is-active a:hover,.hero.is-warning .tabs.is-toggle li.is-active a,.hero.is-warning .tabs.is-toggle li.is-active a:hover{background-color:rgba(0,0,0,0.7);border-color:rgba(0,0,0,0.7);color:#ffdd57}.hero.is-warning.is-bold{background-image:linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%)}@media screen and (max-width: 768px){.hero.is-warning.is-bold .navbar-menu{background-image:linear-gradient(141deg, #ffaf24 0%, #ffdd57 71%, #fffa70 100%)}}.hero.is-danger{background-color:#ff3860;color:#fff}.hero.is-danger a:not(.button):not(.dropdown-item):not(.tag),.hero.is-danger strong{color:inherit}.hero.is-danger .title{color:#fff}.hero.is-danger .subtitle{color:rgba(255,255,255,0.9)}.hero.is-danger .subtitle a:not(.button),.hero.is-danger .subtitle strong{color:#fff}@media screen and (max-width: 1087px){.hero.is-danger .navbar-menu{background-color:#ff3860}}.hero.is-danger .navbar-item,.hero.is-danger .navbar-link{color:rgba(255,255,255,0.7)}.hero.is-danger a.navbar-item:hover,.hero.is-danger a.navbar-item.is-active,.hero.is-danger .navbar-link:hover,.hero.is-danger .navbar-link.is-active{background-color:#ff1f4b;color:#fff}.hero.is-danger .tabs a{color:#fff;opacity:0.9}.hero.is-danger .tabs a:hover{opacity:1}.hero.is-danger .tabs li.is-active a{opacity:1}.hero.is-danger .tabs.is-boxed a,.hero.is-danger .tabs.is-toggle a{color:#fff}.hero.is-danger .tabs.is-boxed a:hover,.hero.is-danger .tabs.is-toggle a:hover{background-color:rgba(10,10,10,0.1)}.hero.is-danger .tabs.is-boxed li.is-active a,.hero.is-danger .tabs.is-boxed li.is-active a:hover,.hero.is-danger .tabs.is-toggle li.is-active a,.hero.is-danger .tabs.is-toggle li.is-active a:hover{background-color:#fff;border-color:#fff;color:#ff3860}.hero.is-danger.is-bold{background-image:linear-gradient(141deg, #ff0561 0%, #ff3860 71%, #ff5257 100%)}@media screen and (max-width: 768px){.hero.is-danger.is-bold .navbar-menu{background-image:linear-gradient(141deg, #ff0561 0%, #ff3860 71%, #ff5257 100%)}}.hero.is-small .hero-body{padding-bottom:1.5rem;padding-top:1.5rem}@media screen and (min-width: 769px), print{.hero.is-medium .hero-body{padding-bottom:9rem;padding-top:9rem}}@media screen and (min-width: 769px), print{.hero.is-large .hero-body{padding-bottom:18rem;padding-top:18rem}}.hero.is-halfheight .hero-body,.hero.is-fullheight .hero-body,.hero.is-fullheight-with-navbar .hero-body{align-items:center;display:flex}.hero.is-halfheight .hero-body>.container,.hero.is-halfheight .hero-body>.notifications:not(:empty),.hero.is-fullheight .hero-body>.container,.hero.is-fullheight .hero-body>.notifications:not(:empty),.hero.is-fullheight-with-navbar .hero-body>.container,.hero.is-fullheight-with-navbar .hero-body>.notifications:not(:empty){flex-grow:1;flex-shrink:1}.hero.is-halfheight{min-height:50vh}.hero.is-fullheight{min-height:100vh}.hero-video{overflow:hidden}.hero-video video{left:50%;min-height:100%;min-width:100%;position:absolute;top:50%;transform:translate3d(-50%, -50%, 0)}.hero-video.is-transparent{opacity:0.3}@media screen and (max-width: 768px){.hero-video{display:none}}.hero-buttons{margin-top:1.5rem}@media screen and (max-width: 768px){.hero-buttons .button{display:flex}.hero-buttons .button:not(:last-child){margin-bottom:0.75rem}}@media screen and (min-width: 769px), print{.hero-buttons{display:flex;justify-content:center}.hero-buttons .button:not(:last-child){margin-right:1.5rem}}.hero-head,.hero-foot{flex-grow:0;flex-shrink:0}.hero-body{flex-grow:1;flex-shrink:0;padding:3rem 1.5rem}.section{padding:3rem 1.5rem}@media screen and (min-width: 1088px){.section.is-medium{padding:9rem 1.5rem}.section.is-large{padding:18rem 1.5rem}}.footer{background-color:#fafafa;padding:3rem 1.5rem 6rem}@font-face{font-family:'Icons';src:url("../fonts/open-iconic.eot");src:url("../fonts/open-iconic.eot?#iconic-sm") format("embedded-opentype"),url("../fonts/open-iconic.woff") format("woff"),url("../fonts/open-iconic.ttf") format("truetype"),url("../fonts/open-iconic.otf") format("opentype"),url("../fonts/open-iconic.svg#iconic-sm") format("svg");font-weight:normal;font-style:normal}.oi[data-glyph].oi-text-replace{font-size:0;line-height:0}.oi[data-glyph].oi-text-replace:before{width:1em;text-align:center}.oi[data-glyph]:before{position:relative;top:1px;font-family:'Icons';display:inline-block;speak:none;line-height:1;vertical-align:baseline;font-weight:normal;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.oi[data-glyph]:empty:before{width:1em;text-align:center;box-sizing:content-box}.oi[data-glyph].oi-align-left:before{text-align:left}.oi[data-glyph].oi-align-right:before{text-align:right}.oi[data-glyph].oi-align-center:before{text-align:center}.oi[data-glyph].oi-flip-horizontal:before{-webkit-transform:scale(-1, 1);-ms-transform:scale(-1, 1);transform:scale(-1, 1)}.oi[data-glyph].oi-flip-vertical:before{-webkit-transform:scale(1, -1);-ms-transform:scale(-1, 1);transform:scale(1, -1)}.oi[data-glyph].oi-flip-horizontal-vertical:before{-webkit-transform:scale(-1, -1);-ms-transform:scale(-1, 1);transform:scale(-1, -1)}.oi[data-glyph=account-login]:before{content:'\e000'}.oi[data-glyph=account-logout]:before{content:'\e001'}.oi[data-glyph=action-redo]:before{content:'\e002'}.oi[data-glyph=action-undo]:before{content:'\e003'}.oi[data-glyph=align-center]:before{content:'\e004'}.oi[data-glyph=align-left]:before{content:'\e005'}.oi[data-glyph=align-right]:before{content:'\e006'}.oi[data-glyph=aperture]:before{content:'\e007'}.oi[data-glyph=arrow-bottom]:before{content:'\e008'}.oi[data-glyph=arrow-circle-bottom]:before{content:'\e009'}.oi[data-glyph=arrow-circle-left]:before{content:'\e00a'}.oi[data-glyph=arrow-circle-right]:before{content:'\e00b'}.oi[data-glyph=arrow-circle-top]:before{content:'\e00c'}.oi[data-glyph=arrow-left]:before{content:'\e00d'}.oi[data-glyph=arrow-right]:before{content:'\e00e'}.oi[data-glyph=arrow-thick-bottom]:before{content:'\e00f'}.oi[data-glyph=arrow-thick-left]:before{content:'\e010'}.oi[data-glyph=arrow-thick-right]:before{content:'\e011'}.oi[data-glyph=arrow-thick-top]:before{content:'\e012'}.oi[data-glyph=arrow-top]:before{content:'\e013'}.oi[data-glyph=audio-spectrum]:before{content:'\e014'}.oi[data-glyph=audio]:before{content:'\e015'}.oi[data-glyph=badge]:before{content:'\e016'}.oi[data-glyph=ban]:before{content:'\e017'}.oi[data-glyph=bar-chart]:before{content:'\e018'}.oi[data-glyph=basket]:before{content:'\e019'}.oi[data-glyph=battery-empty]:before{content:'\e01a'}.oi[data-glyph=battery-full]:before{content:'\e01b'}.oi[data-glyph=beaker]:before{content:'\e01c'}.oi[data-glyph=bell]:before{content:'\e01d'}.oi[data-glyph=bluetooth]:before{content:'\e01e'}.oi[data-glyph=bold]:before{content:'\e01f'}.oi[data-glyph=bolt]:before{content:'\e020'}.oi[data-glyph=book]:before{content:'\e021'}.oi[data-glyph=bookmark]:before{content:'\e022'}.oi[data-glyph=box]:before{content:'\e023'}.oi[data-glyph=briefcase]:before{content:'\e024'}.oi[data-glyph=british-pound]:before{content:'\e025'}.oi[data-glyph=browser]:before{content:'\e026'}.oi[data-glyph=brush]:before{content:'\e027'}.oi[data-glyph=bug]:before{content:'\e028'}.oi[data-glyph=bullhorn]:before{content:'\e029'}.oi[data-glyph=calculator]:before{content:'\e02a'}.oi[data-glyph=calendar]:before{content:'\e02b'}.oi[data-glyph=camera-slr]:before{content:'\e02c'}.oi[data-glyph=caret-bottom]:before{content:'\e02d'}.oi[data-glyph=caret-left]:before{content:'\e02e'}.oi[data-glyph=caret-right]:before{content:'\e02f'}.oi[data-glyph=caret-top]:before{content:'\e030'}.oi[data-glyph=cart]:before{content:'\e031'}.oi[data-glyph=chat]:before{content:'\e032'}.oi[data-glyph=check]:before{content:'\e033'}.oi[data-glyph=chevron-bottom]:before{content:'\e034'}.oi[data-glyph=chevron-left]:before{content:'\e035'}.oi[data-glyph=chevron-right]:before{content:'\e036'}.oi[data-glyph=chevron-top]:before{content:'\e037'}.oi[data-glyph=circle-check]:before{content:'\e038'}.oi[data-glyph=circle-x]:before{content:'\e039'}.oi[data-glyph=clipboard]:before{content:'\e03a'}.oi[data-glyph=clock]:before{content:'\e03b'}.oi[data-glyph=cloud-download]:before{content:'\e03c'}.oi[data-glyph=cloud-upload]:before{content:'\e03d'}.oi[data-glyph=cloud]:before{content:'\e03e'}.oi[data-glyph=cloudy]:before{content:'\e03f'}.oi[data-glyph=code]:before{content:'\e040'}.oi[data-glyph=cog]:before{content:'\e041'}.oi[data-glyph=collapse-down]:before{content:'\e042'}.oi[data-glyph=collapse-left]:before{content:'\e043'}.oi[data-glyph=collapse-right]:before{content:'\e044'}.oi[data-glyph=collapse-up]:before{content:'\e045'}.oi[data-glyph=command]:before{content:'\e046'}.oi[data-glyph=comment-square]:before{content:'\e047'}.oi[data-glyph=compass]:before{content:'\e048'}.oi[data-glyph=contrast]:before{content:'\e049'}.oi[data-glyph=copywriting]:before{content:'\e04a'}.oi[data-glyph=credit-card]:before{content:'\e04b'}.oi[data-glyph=crop]:before{content:'\e04c'}.oi[data-glyph=dashboard]:before{content:'\e04d'}.oi[data-glyph=data-transfer-download]:before{content:'\e04e'}.oi[data-glyph=data-transfer-upload]:before{content:'\e04f'}.oi[data-glyph=delete]:before{content:'\e050'}.oi[data-glyph=dial]:before{content:'\e051'}.oi[data-glyph=document]:before{content:'\e052'}.oi[data-glyph=dollar]:before{content:'\e053'}.oi[data-glyph=double-quote-sans-left]:before{content:'\e054'}.oi[data-glyph=double-quote-sans-right]:before{content:'\e055'}.oi[data-glyph=double-quote-serif-left]:before{content:'\e056'}.oi[data-glyph=double-quote-serif-right]:before{content:'\e057'}.oi[data-glyph=droplet]:before{content:'\e058'}.oi[data-glyph=eject]:before{content:'\e059'}.oi[data-glyph=elevator]:before{content:'\e05a'}.oi[data-glyph=ellipses]:before{content:'\e05b'}.oi[data-glyph=envelope-closed]:before{content:'\e05c'}.oi[data-glyph=envelope-open]:before{content:'\e05d'}.oi[data-glyph=euro]:before{content:'\e05e'}.oi[data-glyph=excerpt]:before{content:'\e05f'}.oi[data-glyph=expand-down]:before{content:'\e060'}.oi[data-glyph=expand-left]:before{content:'\e061'}.oi[data-glyph=expand-right]:before{content:'\e062'}.oi[data-glyph=expand-up]:before{content:'\e063'}.oi[data-glyph=external-link]:before{content:'\e064'}.oi[data-glyph=eye]:before{content:'\e065'}.oi[data-glyph=eyedropper]:before{content:'\e066'}.oi[data-glyph=file]:before{content:'\e067'}.oi[data-glyph=fire]:before{content:'\e068'}.oi[data-glyph=flag]:before{content:'\e069'}.oi[data-glyph=flash]:before{content:'\e06a'}.oi[data-glyph=folder]:before{content:'\e06b'}.oi[data-glyph=fork]:before{content:'\e06c'}.oi[data-glyph=fullscreen-enter]:before{content:'\e06d'}.oi[data-glyph=fullscreen-exit]:before{content:'\e06e'}.oi[data-glyph=globe]:before{content:'\e06f'}.oi[data-glyph=graph]:before{content:'\e070'}.oi[data-glyph=grid-four-up]:before{content:'\e071'}.oi[data-glyph=grid-three-up]:before{content:'\e072'}.oi[data-glyph=grid-two-up]:before{content:'\e073'}.oi[data-glyph=hard-drive]:before{content:'\e074'}.oi[data-glyph=header]:before{content:'\e075'}.oi[data-glyph=headphones]:before{content:'\e076'}.oi[data-glyph=heart]:before{content:'\e077'}.oi[data-glyph=home]:before{content:'\e078'}.oi[data-glyph=image]:before{content:'\e079'}.oi[data-glyph=inbox]:before{content:'\e07a'}.oi[data-glyph=infinity]:before{content:'\e07b'}.oi[data-glyph=info]:before{content:'\e07c'}.oi[data-glyph=italic]:before{content:'\e07d'}.oi[data-glyph=justify-center]:before{content:'\e07e'}.oi[data-glyph=justify-left]:before{content:'\e07f'}.oi[data-glyph=justify-right]:before{content:'\e080'}.oi[data-glyph=key]:before{content:'\e081'}.oi[data-glyph=laptop]:before{content:'\e082'}.oi[data-glyph=layers]:before{content:'\e083'}.oi[data-glyph=lightbulb]:before{content:'\e084'}.oi[data-glyph=link-broken]:before{content:'\e085'}.oi[data-glyph=link-intact]:before{content:'\e086'}.oi[data-glyph=list-rich]:before{content:'\e087'}.oi[data-glyph=list]:before{content:'\e088'}.oi[data-glyph=location]:before{content:'\e089'}.oi[data-glyph=lock-locked]:before{content:'\e08a'}.oi[data-glyph=lock-unlocked]:before{content:'\e08b'}.oi[data-glyph=loop-circular]:before{content:'\e08c'}.oi[data-glyph=loop-square]:before{content:'\e08d'}.oi[data-glyph=loop]:before{content:'\e08e'}.oi[data-glyph=magnifying-glass]:before{content:'\e08f'}.oi[data-glyph=map-marker]:before{content:'\e090'}.oi[data-glyph=map]:before{content:'\e091'}.oi[data-glyph=media-pause]:before{content:'\e092'}.oi[data-glyph=media-play]:before{content:'\e093'}.oi[data-glyph=media-record]:before{content:'\e094'}.oi[data-glyph=media-skip-backward]:before{content:'\e095'}.oi[data-glyph=media-skip-forward]:before{content:'\e096'}.oi[data-glyph=media-step-backward]:before{content:'\e097'}.oi[data-glyph=media-step-forward]:before{content:'\e098'}.oi[data-glyph=media-stop]:before{content:'\e099'}.oi[data-glyph=medical-cross]:before{content:'\e09a'}.oi[data-glyph=menu]:before{content:'\e09b'}.oi[data-glyph=microphone]:before{content:'\e09c'}.oi[data-glyph=minus]:before{content:'\e09d'}.oi[data-glyph=monitor]:before{content:'\e09e'}.oi[data-glyph=moon]:before{content:'\e09f'}.oi[data-glyph=move]:before{content:'\e0a0'}.oi[data-glyph=musical-note]:before{content:'\e0a1'}.oi[data-glyph=paperclip]:before{content:'\e0a2'}.oi[data-glyph=pencil]:before{content:'\e0a3'}.oi[data-glyph=people]:before{content:'\e0a4'}.oi[data-glyph=person]:before{content:'\e0a5'}.oi[data-glyph=phone]:before{content:'\e0a6'}.oi[data-glyph=pie-chart]:before{content:'\e0a7'}.oi[data-glyph=pin]:before{content:'\e0a8'}.oi[data-glyph=play-circle]:before{content:'\e0a9'}.oi[data-glyph=plus]:before{content:'\e0aa'}.oi[data-glyph=power-standby]:before{content:'\e0ab'}.oi[data-glyph=print]:before{content:'\e0ac'}.oi[data-glyph=project]:before{content:'\e0ad'}.oi[data-glyph=pulse]:before{content:'\e0ae'}.oi[data-glyph=puzzle-piece]:before{content:'\e0af'}.oi[data-glyph=question-mark]:before{content:'\e0b0'}.oi[data-glyph=rain]:before{content:'\e0b1'}.oi[data-glyph=random]:before{content:'\e0b2'}.oi[data-glyph=reload]:before{content:'\e0b3'}.oi[data-glyph=resize-both]:before{content:'\e0b4'}.oi[data-glyph=resize-height]:before{content:'\e0b5'}.oi[data-glyph=resize-width]:before{content:'\e0b6'}.oi[data-glyph=rss-alt]:before{content:'\e0b7'}.oi[data-glyph=rss]:before{content:'\e0b8'}.oi[data-glyph=script]:before{content:'\e0b9'}.oi[data-glyph=share-boxed]:before{content:'\e0ba'}.oi[data-glyph=share]:before{content:'\e0bb'}.oi[data-glyph=shield]:before{content:'\e0bc'}.oi[data-glyph=signal]:before{content:'\e0bd'}.oi[data-glyph=signpost]:before{content:'\e0be'}.oi[data-glyph=sort-ascending]:before{content:'\e0bf'}.oi[data-glyph=sort-descending]:before{content:'\e0c0'}.oi[data-glyph=spreadsheet]:before{content:'\e0c1'}.oi[data-glyph=star]:before{content:'\e0c2'}.oi[data-glyph=sun]:before{content:'\e0c3'}.oi[data-glyph=tablet]:before{content:'\e0c4'}.oi[data-glyph=tag]:before{content:'\e0c5'}.oi[data-glyph=tags]:before{content:'\e0c6'}.oi[data-glyph=target]:before{content:'\e0c7'}.oi[data-glyph=task]:before{content:'\e0c8'}.oi[data-glyph=terminal]:before{content:'\e0c9'}.oi[data-glyph=text]:before{content:'\e0ca'}.oi[data-glyph=thumb-down]:before{content:'\e0cb'}.oi[data-glyph=thumb-up]:before{content:'\e0cc'}.oi[data-glyph=timer]:before{content:'\e0cd'}.oi[data-glyph=transfer]:before{content:'\e0ce'}.oi[data-glyph=trash]:before{content:'\e0cf'}.oi[data-glyph=underline]:before{content:'\e0d0'}.oi[data-glyph=vertical-align-bottom]:before{content:'\e0d1'}.oi[data-glyph=vertical-align-center]:before{content:'\e0d2'}.oi[data-glyph=vertical-align-top]:before{content:'\e0d3'}.oi[data-glyph=video]:before{content:'\e0d4'}.oi[data-glyph=volume-high]:before{content:'\e0d5'}.oi[data-glyph=volume-low]:before{content:'\e0d6'}.oi[data-glyph=volume-off]:before{content:'\e0d7'}.oi[data-glyph=warning]:before{content:'\e0d8'}.oi[data-glyph=wifi]:before{content:'\e0d9'}.oi[data-glyph=wrench]:before{content:'\e0da'}.oi[data-glyph=x]:before{content:'\e0db'}.oi[data-glyph=yen]:before{content:'\e0dc'}.oi[data-glyph=zoom-in]:before{content:'\e0dd'}.oi[data-glyph=zoom-out]:before{content:'\e0de'}#app main{margin-bottom:0}.app-loading{display:flex;justify-content:center;align-items:center;height:100vh;font-size:4.8rem;color:#b5b5b5}.app-loading .loader{animation:spinAround 500ms infinite linear;border:2px solid #dbdbdb;border-radius:290486px;border-right-color:transparent;border-top-color:transparent;content:"";display:block;height:1em;position:relative;width:1em}.has-navbar-fixed-bottom{padding-bottom:64px}.audio-player{left:0;position:fixed;right:0;z-index:30;bottom:0;background-color:#363636;color:#f5f5f5;min-height:64px;display:flex;align-items:center}.audio-player .idle-notification{color:inherit}.audio-player .audio-interaction{display:flex;flex-grow:1;align-items:center}.audio-player .playback-info{align-items:center;flex-grow:1;flex-basis:25%;color:inherit}.audio-player .playback-info .media-left{margin-right:.6rem}.audio-player .playback-info .artist-and-title{margin-right:.6rem}.audio-player .playback-info .artist-and-title .artist,.audio-player .playback-info .artist-and-title .song-title{display:block;white-space:nowrap;width:100%;max-width:100%;overflow:hidden;text-overflow:ellipsis}.audio-player .progress-indicators{display:none;flex-basis:75%;height:1rem}@media screen and (min-width: 769px), print{.audio-player .progress-indicators{display:flex}}.audio-player .progress-indicators .progress-info-text{color:#f5f5f5;font-size:.75rem;flex-shrink:0;flex-grow:0}.audio-player .progress-indicators svg{overflow:visible}.audio-player .progress-indicators .progress-bars{margin-left:.6rem;margin-right:.6rem;position:relative;flex-grow:1}.audio-player .progress-indicators .complete-song-bar,.audio-player .progress-indicators .buffered-part-bar,.audio-player .progress-indicators .played-back-bar{height:1rem}.audio-player .progress-indicators .complete-song-bar{width:100%}.audio-player .progress-indicators .complete-song-bar rect{fill:#5d5d5d}.audio-player .progress-indicators .buffered-part-bar rect{fill:#8f8f8f}.audio-player .progress-indicators .buffered-part-bar .click-dummy{cursor:pointer;fill:transparent}.audio-player .progress-indicators .played-back-bar{pointer-events:none}.audio-player .progress-indicators .played-back-bar circle,.audio-player .progress-indicators .played-back-bar rect{fill:#f5f5f5}.audio-player .playback-controls,.audio-player .playback-mode-controls{flex-shrink:0;padding-right:.6rem}.audio-player .playback-controls{padding-left:.6rem}.preview-card .card-content>div,.preview-card .title,.preview-card .subtitle{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.preview-card .image.is-256x256{width:auto;height:auto;max-width:256px;max-height:256px;margin:0}.image .missing-cover{display:block;max-width:100%}.image.is-48x48 .missing-cover{width:48px;height:auto}.image.is-128x128 .missing-cover{width:128px;height:auto}.image.is-256x256 .missing-cover{width:256px;height:auto}.table .grow{width:100%}.song-list .song .duration{padding-left:.5rem;color:#b5b5b5;font-weight:normal}.song-list .song.is-playing{background-color:#f5f5f5 !important;font-weight:bold}.section.is-small{padding-top:24px;padding-bottom:24px}.hero.is-small+.section{padding-top:0}.hero .media-content{align-self:center}.notifications:not(:empty){z-index:100;position:fixed;left:0;right:0;padding-top:3.2rem}@keyframes you-spin-my-head-right-round{from{transform:rotate(0deg);transform-origin:50% 46%}to{transform:rotate(359deg);transform-origin:50% 46%}}.loading-spinner .icon{animation:1s infinite you-spin-my-head-right-round}.search .content .section{padding:1.5rem 0}.search .preview-card .card-content{padding:0.375rem 0.75rem 0.75rem}.search .preview-card .missing-cover{display:inline-block}.artist.overview .alphabetical-list{column-count:2;column-gap:1.2rem}.artist.overview .alphabetical-list ol{list-style:none}@media screen and (min-width: 769px), print{.artist.overview .alphabetical-list{column-count:3}}@media screen and (min-width: 1280px){.artist.overview .alphabetical-list{column-count:4}}.artist.overview .alphabetical-list .group{margin-bottom:1.5rem}.artist.overview .alphabetical-list .group .subtitle.is-4{margin-bottom:1rem}.album.detail .collection-header{display:block}.album.detail .collection-header .media-left{margin-right:0;margin-bottom:1rem}@media screen and (min-width: 769px), print{.album.detail .collection-header{display:flex}.album.detail .collection-header .media-left{margin-right:1rem;margin-bottom:0}}.album.detail .collection-info{list-style:none}.album.detail .collection-info li{display:inline-block;margin-left:0.75rem}.album.detail .collection-info li:first-child{margin-left:0}.album.detail .song-list{counter-reset:track}.album.detail .song-list tbody tr{counter-increment:track}.album.detail .song-list tbody td:first-child>div::before{color:#b5b5b5;content:counter(track);font-weight:normal;display:inline;padding-right:0.375rem} diff --git a/docs/re-frame-10x.png b/docs/re-frame-10x.png new file mode 100644 index 0000000..e91e2e3 Binary files /dev/null and b/docs/re-frame-10x.png differ diff --git a/fonts/open-iconic.eot b/fonts/open-iconic.eot deleted file mode 100644 index f98177d..0000000 Binary files a/fonts/open-iconic.eot and /dev/null differ diff --git a/fonts/open-iconic.otf b/fonts/open-iconic.otf deleted file mode 100644 index f6bd684..0000000 Binary files a/fonts/open-iconic.otf and /dev/null differ diff --git a/fonts/open-iconic.svg b/fonts/open-iconic.svg deleted file mode 100644 index 32b2c4e..0000000 --- a/fonts/open-iconic.svg +++ /dev/null @@ -1,543 +0,0 @@ - - - - - -Created by FontForge 20120731 at Tue Jul 1 20:39:22 2014 - By P.J. Onori -Created by P.J. Onori with FontForge 2.0 (http://fontforge.sf.net) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fonts/open-iconic.ttf b/fonts/open-iconic.ttf deleted file mode 100644 index fab6048..0000000 Binary files a/fonts/open-iconic.ttf and /dev/null differ diff --git a/fonts/open-iconic.woff b/fonts/open-iconic.woff deleted file mode 100644 index f930998..0000000 Binary files a/fonts/open-iconic.woff and /dev/null differ diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..126c682 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,53 @@ +const { execSync } = require('child_process') + +module.exports = function (config) { + + let browsers = null; + if (process.env.TRAVIS || process.env.CI) { + // custom config for continuous integration + browsers = ['ChromeHeadlessCI'] + } else { + try { + // if Firefox is installed, use that as the test runner + execSync('which firefox') + browsers = ['FirefoxHeadless'] + } catch (_) { + browsers = ['ChromeHeadless'] + } + } + + const configuration = { + browsers: browsers, + // The tests are sometimes run before the tests were completely written + // to disc; this is a known problem unfortunately. This is a hack to at + // least keep the browsers connected so the tests are compiled and run + // again even if a developer isn't aware of this + autoWatchBatchDelay: 100, + browserNoActivityTimeout: 60 * 1000 * 10, + // The directory where the output file lives + basePath: 'public/test', + // The file itself + files: ['ci.js'], + frameworks: ['cljs-test'], + plugins: [ + 'karma-cljs-test', + 'karma-chrome-launcher', + 'karma-firefox-launcher', + 'karma-notify-reporter' // reporters are set in package.json + ], + colors: true, + logLevel: config.LOG_INFO, + client: { + args: ["shadow.test.karma.init"] + }, + // configure travis-ci; based on this: https://stackoverflow.com/questions/19255976/how-to-make-travis-execute-angular-tests-on-chrome-please-set-env-variable-chr#25661593 + customLaunchers: { + ChromeHeadlessCI: { + base: 'ChromeHeadless', + flags: ['--no-sandbox', '--headless', '--nogpu'] + } + } + } + + config.set(configuration) +} diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..0e89249 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,7582 @@ +{ + "name": "airsonic-ui", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "airsonic-ui", + "version": "0.0.1", + "license": "ISC", + "dependencies": { + "@hugojosefson/color-hash": "^2.0.3", + "autoprefixer": "^9.5.0", + "bulma": "^0.8.0", + "create-react-class": "^15.6.3", + "highlight.js": "10.4.1", + "open-iconic": "^1.1.1", + "postcss-cli": "^7.0.0", + "react": "^16.8.6", + "react-dom": "^16.8.6", + "react-sortable-hoc": "^1.8.3" + }, + "devDependencies": { + "gh-pages": "^3.0.0", + "karma": "^5.0.0", + "karma-chrome-launcher": "^3.0.0", + "karma-cljs-test": "^0.1.0", + "karma-firefox-launcher": "^1.2.0", + "karma-notify-reporter": "^1.1.0", + "npm-run-all": "^4.1.5", + "react-flip-move": "^3.0.3", + "react-highlight.js": "^1.0.7", + "sass": "^1.17.3", + "shadow-cljs": "^2.9.10" + } + }, + "node_modules/@babel/runtime": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.2.tgz", + "integrity": "sha512-EXxN64agfUqqIGeEjI5dL5z0Sw0ZwWo1mLTi4mQowCZ42O59b7DRpZAnTC6OqdF28wMBMFKNb/4uFGrVaigSpg==", + "dependencies": { + "regenerator-runtime": "^0.13.2" + } + }, + "node_modules/@hugojosefson/color-hash": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@hugojosefson/color-hash/-/color-hash-2.0.3.tgz", + "integrity": "sha512-ASaDCIwQmyeH6eXdG1Nf2zMOr85Ljp13/8qBSPtYkY1hAr6URRAPG+15i2ogXh/caSolZ4mGfP7MwHPLm/V2Dw==", + "dependencies": { + "string-hash": "^1.1.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz", + "integrity": "sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==", + "dependencies": { + "@nodelib/fs.stat": "2.0.3", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz", + "integrity": "sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz", + "integrity": "sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.3", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@snyk/cli-interface": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@snyk/cli-interface/-/cli-interface-2.1.0.tgz", + "integrity": "sha512-b/magC8iNQP9QhSDeV9RQDSaY3sNy57k0UH1Y/sMOSvVLHLsA7dOi/HrPWTiLouyGqcuYzwjkz7bNbu8cwmVDQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.3" + } + }, + "node_modules/@snyk/composer-lockfile-parser": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@snyk/composer-lockfile-parser/-/composer-lockfile-parser-1.0.3.tgz", + "integrity": "sha512-hb+6E7kMzWlcwfe//ILDoktBPKL2a3+RnJT/CXnzRXaiLQpsdkf5li4q2v0fmvd+4v7L3tTN8KM+//lJyviEkg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.13" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@snyk/dep-graph": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/@snyk/dep-graph/-/dep-graph-1.12.0.tgz", + "integrity": "sha512-n7+PlHn3SqznHgsCpeBRfEvU1oiQydoGkXQlnSB2+tfImiKXvY7YZbrg4wlbvYgylYiTbpCi5CpPNkJG14S+UQ==", + "dev": true, + "dependencies": { + "graphlib": "^2.1.5", + "lodash": "^4.7.14", + "object-hash": "^1.3.1", + "semver": "^6.0.0", + "source-map-support": "^0.5.11", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@snyk/dep-graph/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@snyk/gemfile": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@snyk/gemfile/-/gemfile-1.2.0.tgz", + "integrity": "sha512-nI7ELxukf7pT4/VraL4iabtNNMz8mUo7EXlqCFld8O5z6mIMLX9llps24iPpaIZOwArkY3FWA+4t+ixyvtTSIA==", + "dev": true, + "engines": { + "node": ">= 4.2.4" + } + }, + "node_modules/@types/agent-base": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@types/agent-base/-/agent-base-4.2.0.tgz", + "integrity": "sha512-8mrhPstU+ZX0Ugya8tl5DsDZ1I5ZwQzbL/8PA0z8Gj0k9nql7nkaMzmPVLj+l/nixWaliXi+EBiLA8bptw3z7Q==", + "dev": true, + "dependencies": { + "@types/events": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bunyan": { + "version": "1.8.6", + "resolved": "https://registry.npmjs.org/@types/bunyan/-/bunyan-1.8.6.tgz", + "integrity": "sha512-YiozPOOsS6bIuz31ilYqR5SlLif4TBWsousN2aCWLi5233nZSX19tFbcQUPdR7xJ8ypPyxkCGNxg0CIV5n9qxQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==" + }, + "node_modules/@types/debug": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.5.tgz", + "integrity": "sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==", + "dev": true + }, + "node_modules/@types/events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/events/-/events-3.0.0.tgz", + "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==" + }, + "node_modules/@types/glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz", + "integrity": "sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==", + "dependencies": { + "@types/events": "*", + "@types/minimatch": "*", + "@types/node": "*" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", + "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==" + }, + "node_modules/@types/node": { + "version": "12.7.8", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.8.tgz", + "integrity": "sha512-FMdVn84tJJdV+xe+53sYiZS4R5yn1mAIxfj+DVoNiQjTYz1+OYmjwEZr1ev9nU0axXwda0QDbYl06QHanRVH3A==" + }, + "node_modules/@types/restify": { + "version": "4.3.6", + "resolved": "https://registry.npmjs.org/@types/restify/-/restify-4.3.6.tgz", + "integrity": "sha512-4l4f0EXnleXQttlhRCXtTuJ8UelsKiAKIK2AAEd2epBHu41aEbM0U2z6E5tUrNwlbxz7qaNBISduGMeg+G3PaA==", + "dev": true, + "dependencies": { + "@types/bunyan": "*", + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-41qEJgBH/TWgo5NFSvBCJ1qkoi3Q6ONSF2avrHq1LVEZfYpdHmj0y9SuTK+u9ZhG1sYQKBL1AWXKyLWP4RaUoQ==", + "dev": true + }, + "node_modules/@types/xml2js": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@types/xml2js/-/xml2js-0.4.3.tgz", + "integrity": "sha512-Pv2HGRE4gWLs31In7nsyXEH4uVVsd0HNV9i2dyASvtDIlOtSTr1eczPLDpdEuyv5LWH5LT20GIXwPjkshKWI1g==", + "dev": true, + "dependencies": { + "@types/events": "*", + "@types/node": "*" + } + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "dependencies": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ansi-align": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-2.0.0.tgz", + "integrity": "sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=", + "dev": true, + "dependencies": { + "string-width": "^2.0.0" + } + }, + "node_modules/ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/ansicolors": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/ansicolors/-/ansicolors-0.3.2.tgz", + "integrity": "sha1-ZlWX3oap/+Oqm/vmyuXG6kJrSXk=", + "dev": true + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "dev": true + }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/ast-types": { + "version": "0.13.2", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.2.tgz", + "integrity": "sha512-uWMHxJxtfj/1oZClOxDEV1sQ1HCDkA4MG8Gr69KKeBjEVH0R84WlejZ0y2DcwyBlpAEMltmVYkVgqfLFb2oyiA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "node_modules/autoprefixer": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.6.1.tgz", + "integrity": "sha512-aVo5WxR3VyvyJxcJC3h4FKfwCQvQWb1tSI5VHNibddCVWrcD1NvlxEweg3TSgiPztMnWfjpy2FURKA2kvDE+Tw==", + "dependencies": { + "browserslist": "^4.6.3", + "caniuse-lite": "^1.0.30000980", + "chalk": "^2.4.2", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.17", + "postcss-value-parser": "^4.0.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "node_modules/base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "dependencies": { + "callsite": "1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "node_modules/bn.js": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.1.2.tgz", + "integrity": "sha512-40rZaf3bUNKTVYu9sIeeEGOg7g14Yvnj9kH7b50EiwX0Q7A6umbvfI5tvHaOERH0XigqKkfLkFQxzb4e6CIXnA==", + "dev": true + }, + "node_modules/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "content-type": "~1.0.4", + "debug": "2.6.9", + "depd": "~1.1.2", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "on-finished": "~2.3.0", + "qs": "6.7.0", + "raw-body": "2.4.0", + "type-is": "~1.6.17" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/boxen": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/boxen/-/boxen-1.3.0.tgz", + "integrity": "sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==", + "dev": true, + "dependencies": { + "ansi-align": "^2.0.0", + "camelcase": "^4.0.0", + "chalk": "^2.0.1", + "cli-boxes": "^1.0.0", + "string-width": "^2.0.0", + "term-size": "^1.2.0", + "widest-line": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/boxen/node_modules/camelcase": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-4.1.0.tgz", + "integrity": "sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-rsa/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/browserify-sign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.0.tgz", + "integrity": "sha512-hEZC1KEeYuoHRqhGhTy6gWrpJA3ZDjFWv0DE61643ZnOXAKJb3u7yWcrU0mMc9SwAqK1n7myPGndkp0dFG7NFA==", + "dev": true, + "dependencies": { + "bn.js": "^5.1.1", + "browserify-rsa": "^4.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.2", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.5", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.16.6", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", + "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "dependencies": { + "caniuse-lite": "^1.0.30001219", + "colorette": "^1.2.2", + "electron-to-chromium": "^1.3.723", + "escalade": "^3.1.1", + "node-releases": "^1.1.71" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist/node_modules/caniuse-lite": { + "version": "1.0.30001228", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001228.tgz", + "integrity": "sha512-QQmLOGJ3DEgokHbMSA8cj2a+geXqmnpyOFT0lhQV6P3/YOJvGDEwoedcwxEQ30gJIwIIunHIicunJ2rzK5gB2A==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + } + }, + "node_modules/browserslist/node_modules/electron-to-chromium": { + "version": "1.3.736", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.736.tgz", + "integrity": "sha512-DY8dA7gR51MSo66DqitEQoUMQ0Z+A2DSXFi7tK304bdTVqczCAfUuyQw6Wdg8hIoo5zIxkU1L24RQtUce1Ioig==" + }, + "node_modules/browserslist/node_modules/node-releases": { + "version": "1.1.72", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.72.tgz", + "integrity": "sha512-LLUo+PpH3dU6XizX3iVoubUNheF/owjXCZZ5yACDxNnPtgFuludV1ZL3ayK1kVep42Rmm0+R9/Y60NQbZ2bifw==" + }, + "node_modules/buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "node_modules/bulma": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.8.0.tgz", + "integrity": "sha512-nhf3rGyiZh/VM7FrSJ/5KeLlfaFkXz0nYcXriynfPH4vVpnxnqyEwaNGdNCVzHyyCA3cHgkQAMpdF/SFbFGZfA==" + }, + "node_modules/bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/caller-callsite": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-callsite/-/caller-callsite-2.0.0.tgz", + "integrity": "sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ=", + "dependencies": { + "callsites": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/caller-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-2.0.0.tgz", + "integrity": "sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ=", + "dependencies": { + "caller-callsite": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/callsites": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-2.0.0.tgz", + "integrity": "sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA=", + "engines": { + "node": ">=4" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30000997", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000997.tgz", + "integrity": "sha512-BQLFPIdj2ntgBNWp9Q64LGUIEmvhKkzzHhUHR3CD5A9Lb7ZKF20/+sgadhFap69lk5XmK1fTUleDclaRFvgVUA==" + }, + "node_modules/capture-stack-trace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz", + "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", + "dev": true + }, + "node_modules/chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/chokidar/node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/chokidar/node_modules/binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chokidar/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/chokidar/node_modules/readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.7" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/chokidar/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/ci-info": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-1.6.0.tgz", + "integrity": "sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==", + "dev": true + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/cli-boxes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz", + "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "dependencies": { + "restore-cursor": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cliui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cliui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/cliui/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clone-deep": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-0.3.0.tgz", + "integrity": "sha1-NIxhrpzb4O3+BT2R/0zFIdeQ7eg=", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "is-plain-object": "^2.0.1", + "kind-of": "^3.2.2", + "shallow-clone": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/clone-deep/node_modules/kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/colorette": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "node_modules/component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/configstore": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/configstore/-/configstore-3.1.2.tgz", + "integrity": "sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==", + "dev": true, + "dependencies": { + "dot-prop": "^4.1.0", + "graceful-fs": "^4.1.2", + "make-dir": "^1.0.0", + "unique-string": "^1.0.0", + "write-file-atomic": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "node_modules/content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "deprecated": "core-js@<3.23.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Some versions have web compatibility issues. Please, upgrade your dependencies to the actual version of core-js." + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/cosmiconfig": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz", + "integrity": "sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA==", + "dependencies": { + "import-fresh": "^2.0.0", + "is-directory": "^0.3.1", + "js-yaml": "^3.13.1", + "parse-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/create-error-class": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz", + "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=", + "dev": true, + "dependencies": { + "capture-stack-trace": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-react-class": { + "version": "15.6.3", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz", + "integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==", + "dependencies": { + "fbjs": "^0.8.9", + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, + "node_modules/cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/crypto-random-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-1.0.0.tgz", + "integrity": "sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "dev": true + }, + "node_modules/data-uri-to-buffer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-2.0.2.tgz", + "integrity": "sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==", + "dev": true + }, + "node_modules/date-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-2.1.0.tgz", + "integrity": "sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==", + "deprecated": "2.x is no longer supported. Please upgrade to 4.x or higher.", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/degenerator": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-1.0.4.tgz", + "integrity": "sha1-/PSQo37OJmRk2cxDGrmMWBnO0JU=", + "dev": true, + "dependencies": { + "ast-types": "0.x.x", + "escodegen": "1.x.x", + "esprima": "3.x.x" + } + }, + "node_modules/degenerator/node_modules/esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/dependency-graph": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/dependency-graph/-/dependency-graph-0.8.1.tgz", + "integrity": "sha512-g213uqF8fyk40W8SBjm079n3CZB4qSpCrA2ye1fLGzH/4HEgB6tzuW2CbLE7leb4t45/6h44Ud59Su1/ROTfqw==", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "dev": true + }, + "node_modules/diff": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz", + "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dir-glob/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/dockerfile-ast": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/dockerfile-ast/-/dockerfile-ast-0.0.16.tgz", + "integrity": "sha512-+HZToHjjiLPl46TqBrok5dMrg5oCkZFPSROMQjRmvin0zG4FxK0DJXTpV/CUPYY2zpmEvVza55XLwSHFx/xZMw==", + "dev": true, + "dependencies": { + "vscode-languageserver-types": "^3.5.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "dev": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true, + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/dot-prop": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-4.2.1.tgz", + "integrity": "sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ==", + "dev": true, + "dependencies": { + "is-obj": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dotnet-deps-parser": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/dotnet-deps-parser/-/dotnet-deps-parser-4.5.0.tgz", + "integrity": "sha512-t6rBxcWVZSDNhhWdsbq9ozaCzfPXV79FiyES1JLNEoA7nYF+zDC2VZvFZSnH8ilU3bghJXxZPH+EcKYvfw8g/g==", + "dev": true, + "dependencies": { + "@types/xml2js": "0.4.3", + "lodash": "^4.17.11", + "source-map-support": "^0.5.7", + "tslib": "^1.9.3", + "xml2js": "0.4.19" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/dotnet-deps-parser/node_modules/xml2js": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", + "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~9.0.1" + } + }, + "node_modules/duplexer3": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz", + "integrity": "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=", + "dev": true + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dev": true, + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "dev": true + }, + "node_modules/email-addresses": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-3.1.0.tgz", + "integrity": "sha512-k0/r7GrWVL32kZlGwfPNgB2Y/mMXVTq/decgLczm/j34whdaspNrZO8CnXPf1laaHxI6ptUlsnAxN+UAPw+fzg==", + "dev": true + }, + "node_modules/email-validator": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/email-validator/-/email-validator-2.0.4.tgz", + "integrity": "sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ==", + "dev": true, + "engines": { + "node": ">4.0" + } + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dependencies": { + "iconv-lite": "~0.4.13" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.2.1.tgz", + "integrity": "sha512-+VlKzHzMhaU+GsCIg4AoXF1UdDFjHHwMmMKqMJNDNLlUlejz58FCy4LBqB2YVJskHGYl06BatYWKP2TVdVXE5w==", + "dev": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "ws": "~3.3.1" + } + }, + "node_modules/engine.io-client": { + "version": "3.2.1", + "resolved": "http://registry.npmjs.org/engine.io-client/-/engine.io-client-3.2.1.tgz", + "integrity": "sha512-y5AbkytWeM4jQr7m/koQLc5AxpRKC1hEVUb/s1FUAWEJq5AzJJ4NLvzuKPuxtDi5Mq755WuDvZ6Iv2rXj4PTzw==", + "dev": true, + "dependencies": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + } + }, + "node_modules/engine.io-client/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/engine.io-client/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "dependencies": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "node_modules/engine.io/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.14.2", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.14.2.tgz", + "integrity": "sha512-DgoQmbpFNOofkjJtKwr87Ma5EW4Dc8fWhD0R+ndq7Oc456ivUfGOOP6oAZTTKl5/CcNMP+EN+e3/iUzgE0veZg==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.0.0", + "string.prototype.trimright": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "dev": true, + "dependencies": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=4.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.0.tgz", + "integrity": "sha512-qerSRB0p+UDEssxTtm6EDKcE7W4OaoisfIMl4CngyEhjpYglocpNg6UEqCvemdGhosAsg4sO2dXJOdyBifPGCg==", + "dev": true + }, + "node_modules/events": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.1.0.tgz", + "integrity": "sha512-Rv+u8MLHNOdMjTAFeT3nCjHn2aGlx435FP/sDHNaRhDEMwyI/aB22Kj2qIN8R0cw3z28psEQLYwxVKLsKrMgWg==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dev": true, + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fast-glob": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.1.1.tgz", + "integrity": "sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.0", + "merge2": "^1.3.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-glob/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/fast-glob/node_modules/micromatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.2.tgz", + "integrity": "sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.0.5" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fast-glob/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastq": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.6.0.tgz", + "integrity": "sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==", + "dependencies": { + "reusify": "^1.0.0" + } + }, + "node_modules/fbjs": { + "version": "0.8.17", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", + "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", + "dependencies": { + "core-js": "^1.0.0", + "isomorphic-fetch": "^2.1.1", + "loose-envify": "^1.0.0", + "object-assign": "^4.1.0", + "promise": "^7.1.1", + "setimmediate": "^1.0.5", + "ua-parser-js": "^0.7.18" + } + }, + "node_modules/figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true + }, + "node_modules/filename-reserved-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-1.0.0.tgz", + "integrity": "sha1-5hz4BfDeHJhFZ9A4bcXfUO5a9+Q=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/filenamify": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-1.2.1.tgz", + "integrity": "sha1-qfL/0RxQO+0wABUCknI3jx8TZaU=", + "dev": true, + "dependencies": { + "filename-reserved-regex": "^1.0.0", + "strip-outer": "^1.0.0", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/filenamify-url": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/filenamify-url/-/filenamify-url-1.0.0.tgz", + "integrity": "sha1-syvYExnvWGO3MHi+1Q9GpPeXX1A=", + "dev": true, + "dependencies": { + "filenamify": "^1.0.0", + "humanize-url": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "dev": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flatted": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", + "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.11.0.tgz", + "integrity": "sha512-KZm0V+ll8PfBrKwMzdo5D13b1bur9Iq9Zd/RMmAoQQcl2PxxFml8cxXPaaPYVbV0RjNjq1CU7zIzAOqtUPudmA==", + "dev": true, + "dependencies": { + "debug": "^3.0.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/follow-redirects/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/follow-redirects/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fs-extra": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz", + "integrity": "sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/ftp": { + "version": "0.3.10", + "resolved": "https://registry.npmjs.org/ftp/-/ftp-0.3.10.tgz", + "integrity": "sha1-kZfYYa2BQvPmPVqDv+TFn3MwiF0=", + "dev": true, + "dependencies": { + "readable-stream": "1.1.x", + "xregexp": "2.0.0" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/ftp/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/ftp/node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/ftp/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/get-stdin": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-7.0.0.tgz", + "integrity": "sha512-zRKcywvrXlXsA0v0i9Io4KDRaAw7+a1ZpjRwl9Wox8PFlVCCHra7E9c4kqXCoCM9nR5tBkaTTZRBoCm60bFqTQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/get-uri": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-2.0.3.tgz", + "integrity": "sha512-x5j6Ks7FOgLD/GlvjKwgu7wdmMR55iuRHhn8hj/+gA+eSbxQvZ+AEomq+3MgVEZj1vpi738QahGbCCSIDtXtkw==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "2", + "debug": "4", + "extend": "~3.0.2", + "file-uri-to-path": "1", + "ftp": "~0.3.10", + "readable-stream": "3" + } + }, + "node_modules/get-uri/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/get-uri/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/get-uri/node_modules/readable-stream": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz", + "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gh-pages": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-3.0.0.tgz", + "integrity": "sha512-oaOfVcrSwnqoWUgZ6cmCDM6mUuWyOSG+SHjqxGBawN0F3SKaF5NwbeYDG+w2RNXO2HJ/5Iam4o7dP5NAtoHuwQ==", + "dev": true, + "dependencies": { + "async": "^2.6.1", + "commander": "^2.18.0", + "email-addresses": "^3.0.1", + "filenamify-url": "^1.0.0", + "fs-extra": "^8.1.0", + "globby": "^6.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gh-pages/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/gh-pages/node_modules/globby": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", + "integrity": "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=", + "dev": true, + "dependencies": { + "array-union": "^1.0.1", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/git-up": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/git-up/-/git-up-4.0.1.tgz", + "integrity": "sha512-LFTZZrBlrCrGCG07/dm1aCjjpL1z9L3+5aEeI9SBhAqSc+kiA9Or1bgZhQFNppJX6h/f5McrvJt1mQXTFm6Qrw==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "parse-url": "^5.0.0" + } + }, + "node_modules/git-url-parse": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/git-url-parse/-/git-url-parse-11.1.2.tgz", + "integrity": "sha512-gZeLVGY8QVKMIkckncX+iCq2/L8PlwncvDFKiWkBn9EtCfYDbliRTTp6qzyQ1VMdITUfq7293zDzfpjdiGASSQ==", + "dev": true, + "dependencies": { + "git-up": "^4.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/global-dirs": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-0.1.1.tgz", + "integrity": "sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=", + "dev": true, + "dependencies": { + "ini": "^1.3.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.2.tgz", + "integrity": "sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg==", + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/globby/node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/got": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/got/-/got-6.7.1.tgz", + "integrity": "sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=", + "dev": true, + "dependencies": { + "create-error-class": "^3.0.0", + "duplexer3": "^0.1.4", + "get-stream": "^3.0.0", + "is-redirect": "^1.0.0", + "is-retry-allowed": "^1.0.0", + "is-stream": "^1.0.0", + "lowercase-keys": "^1.0.0", + "safe-buffer": "^5.0.1", + "timed-out": "^4.0.0", + "unzip-response": "^2.0.1", + "url-parse-lax": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/got/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.2.tgz", + "integrity": "sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==" + }, + "node_modules/graphlib": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/graphlib/-/graphlib-2.1.7.tgz", + "integrity": "sha512-TyI9jIy2J4j0qgPmOOrHTCtpPqJGN/aurBwc6ZT+bRii+di1I+Wv3obRhVrmBEXet+qkMaEX67dXrwsd3QQM6w==", + "dev": true, + "dependencies": { + "lodash": "^4.17.5" + } + }, + "node_modules/growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "dependencies": { + "isarray": "2.0.1" + } + }, + "node_modules/has-binary2/node_modules/isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "node_modules/has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "dev": true + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/highlight.js": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.4.1.tgz", + "integrity": "sha512-yR5lWvNz7c85OhVAEAeFhVCc/GV4C30Fjzc/rCP0aCWzc1UUOPUk55dK/qdwTZHBvMZo+eZ2jpk62ndX/xMFlg==", + "engines": { + "node": "*" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/http-errors": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz", + "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==", + "dev": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "dependencies": { + "agent-base": "4", + "debug": "3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/https-proxy-agent/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/https-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/humanize-url": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/humanize-url/-/humanize-url-1.0.1.tgz", + "integrity": "sha1-9KuZ4NKIF0yk4eUEB8VfuuRk7/8=", + "dev": true, + "dependencies": { + "normalize-url": "^1.0.0", + "strip-url-auth": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "node_modules/ignore": { + "version": "5.1.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", + "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=", + "dev": true + }, + "node_modules/import-cwd": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-cwd/-/import-cwd-2.1.0.tgz", + "integrity": "sha1-qmzzbnInYShcs3HsZRn1PiQ1sKk=", + "dependencies": { + "import-from": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-2.0.0.tgz", + "integrity": "sha1-2BNVwVYS04bGH53dOSLUMEgipUY=", + "dependencies": { + "caller-path": "^2.0.0", + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-from": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-from/-/import-from-2.1.0.tgz", + "integrity": "sha1-M1238qev/VOqpHHUuAId7ja387E=", + "dependencies": { + "resolve-from": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/import-lazy": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-2.1.0.tgz", + "integrity": "sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "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.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.7.tgz", + "integrity": "sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==", + "dev": true + }, + "node_modules/inquirer": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-6.5.2.tgz", + "integrity": "sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ==", + "dev": true, + "dependencies": { + "ansi-escapes": "^3.2.0", + "chalk": "^2.4.2", + "cli-cursor": "^2.1.0", + "cli-width": "^2.0.0", + "external-editor": "^3.0.3", + "figures": "^2.0.0", + "lodash": "^4.17.12", + "mute-stream": "0.0.7", + "run-async": "^2.2.0", + "rxjs": "^6.4.0", + "string-width": "^2.1.0", + "strip-ansi": "^5.1.0", + "through": "^2.3.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/inquirer/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/inquirer/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/ip": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", + "integrity": "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=", + "dev": true + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-ci": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-1.2.1.tgz", + "integrity": "sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==", + "dev": true, + "dependencies": { + "ci-info": "^1.5.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-directory": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/is-directory/-/is-directory-0.3.1.tgz", + "integrity": "sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.1.0.tgz", + "integrity": "sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=", + "dev": true, + "dependencies": { + "global-dirs": "^0.1.0", + "is-path-inside": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-npm": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz", + "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz", + "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "dependencies": { + "path-is-inside": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "node_modules/is-redirect": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz", + "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "dependencies": { + "has": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-retry-allowed": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz", + "integrity": "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-ssh": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/is-ssh/-/is-ssh-1.3.1.tgz", + "integrity": "sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg==", + "dev": true, + "dependencies": { + "protocols": "^1.1.0" + } + }, + "node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/isbinaryfile": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.6.tgz", + "integrity": "sha512-ORrEy+SNVqUhrCaal4hA4fBzhggQQ+BaLntyPOdoEiwlKZW9BZiJXjg3RMiruE4tPEI3pyVPpySHQF/dKWperg==", + "dev": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "dependencies": { + "node-fetch": "^1.0.1", + "whatwg-fetch": ">=0.10.0" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==" + }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jszip": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.7.1.tgz", + "integrity": "sha512-ghL0tz1XG9ZEmRMcEN2vt7xabrDdqHHeykgARpmZ0BiIctWxM47Vt63ZO2dnp4QYt/xJVLLy5Zv1l/xRdh2byg==", + "dev": true, + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "set-immediate-shim": "~1.0.1" + } + }, + "node_modules/karma": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/karma/-/karma-5.0.0.tgz", + "integrity": "sha512-iM0nREt/RLcF0yDvjdSLdTZ0twL/qBCJEJLbzd+BVokxPkEjtDq4HxKqRuxqlNCh8Y1jz+q54sERBEIjQBHxxA==", + "dev": true, + "dependencies": { + "body-parser": "^1.16.1", + "braces": "^3.0.2", + "chokidar": "^3.0.0", + "colors": "^1.1.0", + "connect": "^3.6.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.0", + "flatted": "^2.0.0", + "glob": "^7.1.1", + "graceful-fs": "^4.1.2", + "http-proxy": "^1.13.0", + "isbinaryfile": "^4.0.2", + "lodash": "^4.17.14", + "log4js": "^4.0.0", + "mime": "^2.3.1", + "minimatch": "^3.0.2", + "qjobs": "^1.1.4", + "range-parser": "^1.2.0", + "rimraf": "^2.6.0", + "socket.io": "2.1.1", + "source-map": "^0.6.1", + "tmp": "0.0.33", + "ua-parser-js": "0.7.21", + "yargs": "^15.3.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-chrome-launcher": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.0.tgz", + "integrity": "sha512-3dPs/n7vgz1rxxtynpzZTvb9y/GIaW8xjAwcIGttLbycqoFtI7yo1NGnQi6oFTherRE+GIhCAHZC4vEqWGhNvg==", + "dev": true, + "dependencies": { + "which": "^1.2.1" + } + }, + "node_modules/karma-cljs-test": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/karma-cljs-test/-/karma-cljs-test-0.1.0.tgz", + "integrity": "sha1-y4YF7w4R+ab20o9Wul298m84mSM=", + "dev": true + }, + "node_modules/karma-firefox-launcher": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/karma-firefox-launcher/-/karma-firefox-launcher-1.2.0.tgz", + "integrity": "sha512-j9Zp8M8+VLq1nI/5xZGfzeaEPtGQ/vk3G+Y8vpmFWLvKLNZ2TDjD6cu2dUu7lDbu1HXNgatsAX4jgCZTkR9qhQ==", + "dev": true, + "dependencies": { + "is-wsl": "^2.1.0" + } + }, + "node_modules/karma-firefox-launcher/node_modules/is-wsl": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.1.1.tgz", + "integrity": "sha512-umZHcSrwlDHo2TGMXv0DZ8dIUGunZ2Iv68YZnrmCiBPkZ4aaOhtv7pXJKeki9k3qJ3RJr0cDyitcl5wEH3AYog==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma-notify-reporter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/karma-notify-reporter/-/karma-notify-reporter-1.1.0.tgz", + "integrity": "sha512-tuyz2cKXKitDnjFtfOH9SIy+flGQqRGtn5BCTdRVsUgLFxCmSipjczfne/RZ+7yPRN+O5dTIfLu7LHJRj4Fg7Q==", + "dev": true, + "dependencies": { + "node-notifier": "^5.3.0", + "snyk": "^1.47.0" + }, + "peerDependencies": { + "karma": ">=0.9" + } + }, + "node_modules/karma/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/karma/node_modules/binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dev": true, + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/karma/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/karma/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/karma/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/karma/node_modules/glob-parent": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.1.tgz", + "integrity": "sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/karma/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/karma/node_modules/readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dev": true, + "dependencies": { + "picomatch": "^2.0.7" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/karma/node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/karma/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/karma/node_modules/ua-parser-js": { + "version": "0.7.21", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.21.tgz", + "integrity": "sha512-+O8/qh/Qj8CgC6eYBVBykMrNtp5Gebn4dlGD/kKXVkJNDwyrAwSIqwz8CDf+tsAIWVycKcku6gIXJ0qwx/ZXaQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/karma/node_modules/yargs": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz", + "integrity": "sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/latest-version": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-3.1.0.tgz", + "integrity": "sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=", + "dev": true, + "dependencies": { + "package-json": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/lazy-cache": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-0.2.7.tgz", + "integrity": "sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.assign": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz", + "integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=", + "dev": true + }, + "node_modules/lodash.assignin": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz", + "integrity": "sha1-uo31+4QesKPoBEIysOJjqNxqKKI=", + "dev": true + }, + "node_modules/lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", + "deprecated": "This package is deprecated. Use structuredClone instead.", + "dev": true + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "node_modules/lodash.flatten": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz", + "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8=", + "dev": true + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk=", + "deprecated": "This package is deprecated. Use the optional chaining (?.) operator instead.", + "dev": true + }, + "node_modules/lodash.set": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/lodash.set/-/lodash.set-4.3.2.tgz", + "integrity": "sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM=", + "dev": true + }, + "node_modules/log-symbols": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", + "integrity": "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg==", + "dependencies": { + "chalk": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/log4js": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-4.5.1.tgz", + "integrity": "sha512-EEEgFcE9bLgaYUKuozyFfytQM2wDHtXn4tAN41pkaxpNjAykv11GVdeI4tHtmPWW4Xrgh9R/2d7XYghDVjbKKw==", + "deprecated": "4.x is no longer supported. Please upgrade to 6.x or higher.", + "dev": true, + "dependencies": { + "date-format": "^2.0.0", + "debug": "^4.1.1", + "flatted": "^2.0.0", + "rfdc": "^1.1.4", + "streamroller": "^1.0.6" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/log4js/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/log4js/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/lowercase-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", + "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "dependencies": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "node_modules/macos-release": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/macos-release/-/macos-release-2.3.0.tgz", + "integrity": "sha512-OHhSbtcviqMPt7yfw5ef5aghS2jzFVKEFyCJndQt2YpSQ9qRVSEv2axSJI1paVThEu+FFGs584h/1YhxjVqajA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/make-dir": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz", + "integrity": "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/make-dir/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "http://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/merge2": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.3.0.tgz", + "integrity": "sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/mime": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.4.4.tgz", + "integrity": "sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "dev": true, + "dependencies": { + "mime-db": "1.40.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mixin-object": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mixin-object/-/mixin-object-2.0.1.tgz", + "integrity": "sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=", + "dev": true, + "dependencies": { + "for-in": "^0.1.3", + "is-extendable": "^0.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mixin-object/node_modules/for-in": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.8.tgz", + "integrity": "sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "node_modules/nconf": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/nconf/-/nconf-0.10.0.tgz", + "integrity": "sha512-fKiXMQrpP7CYWJQzKkPPx9hPgmq+YLDyxcG9N8RpiE9FoCkCbzD0NyW0YhE3xn3Aupe7nnDeIx4PFzYehpHT9Q==", + "dev": true, + "dependencies": { + "async": "^1.4.0", + "ini": "^1.3.0", + "secure-keys": "^1.0.0", + "yargs": "^3.19.0" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/nconf/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "node_modules/nconf/node_modules/camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/nconf/node_modules/invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "dependencies": { + "invert-kv": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "dependencies": { + "lcid": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nconf/node_modules/y18n": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", + "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", + "dev": true + }, + "node_modules/nconf/node_modules/yargs": { + "version": "3.32.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz", + "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=", + "dev": true, + "dependencies": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + }, + "node_modules/needle": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.4.0.tgz", + "integrity": "sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==", + "dev": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/netmask": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/netmask/-/netmask-1.0.6.tgz", + "integrity": "sha1-ICl+idhvb2QA8lDZ9Pa0wZRfzTU=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node_modules/node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dependencies": { + "encoding": "^0.1.11", + "is-stream": "^1.0.1" + } + }, + "node_modules/node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "dependencies": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + } + }, + "node_modules/node-libs-browser/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "node_modules/node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "dev": true, + "dependencies": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-url": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz", + "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=", + "dev": true, + "dependencies": { + "object-assign": "^4.0.1", + "prepend-http": "^1.0.0", + "query-string": "^4.1.0", + "sort-keys": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" + }, + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/npm-run-all/node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-all/node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "dependencies": { + "path-key": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=" + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "node_modules/object-hash": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz", + "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "dependencies": { + "mimic-fn": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/onetime/node_modules/mimic-fn": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz", + "integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/open-iconic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/open-iconic/-/open-iconic-1.1.1.tgz", + "integrity": "sha1-nc/Ix808Yc20ojaxo0eJTJetwMY=" + }, + "node_modules/opn": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.5.0.tgz", + "integrity": "sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==", + "dev": true, + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "dependencies": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/optionator/node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "node_modules/os-name": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/os-name/-/os-name-3.1.0.tgz", + "integrity": "sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg==", + "dev": true, + "dependencies": { + "macos-release": "^2.2.0", + "windows-release": "^3.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/p-limit": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", + "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pac-proxy-agent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-3.0.0.tgz", + "integrity": "sha512-AOUX9jES/EkQX2zRz0AW7lSx9jD//hQS8wFXBvcnd/J2Py9KaMJMqV/LPqJssj1tgGufotb2mmopGPR15ODv1Q==", + "dev": true, + "dependencies": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "get-uri": "^2.0.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "pac-resolver": "^3.0.0", + "raw-body": "^2.2.0", + "socks-proxy-agent": "^4.0.1" + } + }, + "node_modules/pac-proxy-agent/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/pac-proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/pac-resolver": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-3.0.0.tgz", + "integrity": "sha512-tcc38bsjuE3XZ5+4vP96OfhOugrX+JcnpUbhfuc4LuXBLQhoTthOstZeoQJBDnQUDYzYmdImKsbz0xSl1/9qeA==", + "dev": true, + "dependencies": { + "co": "^4.6.0", + "degenerator": "^1.0.4", + "ip": "^1.1.5", + "netmask": "^1.0.6", + "thunkify": "^2.1.2" + } + }, + "node_modules/package-json": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/package-json/-/package-json-4.0.1.tgz", + "integrity": "sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=", + "dev": true, + "dependencies": { + "got": "^6.7.1", + "registry-auth-token": "^3.0.1", + "registry-url": "^3.0.3", + "semver": "^5.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, + "node_modules/parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "dependencies": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/parse-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/parse-path/-/parse-path-4.0.1.tgz", + "integrity": "sha512-d7yhga0Oc+PwNXDvQ0Jv1BuWkLVPXcAoQ/WREgd6vNNoKYaW52KI+RdOFjI63wjkmps9yUE8VS4veP+AgpQ/hA==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "protocols": "^1.4.0" + } + }, + "node_modules/parse-url": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/parse-url/-/parse-url-5.0.1.tgz", + "integrity": "sha512-flNUPP27r3vJpROi0/R3/2efgKkyXqnXwyP1KQ2U0SfFRgdizOdWfvrrvJg1LuOoxs7GQhmxJlq23IpQ/BkByg==", + "dev": true, + "dependencies": { + "is-ssh": "^1.3.0", + "normalize-url": "^3.3.0", + "parse-path": "^4.0.0", + "protocols": "^1.4.0" + } + }, + "node_modules/parse-url/node_modules/normalize-url": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-3.3.0.tgz", + "integrity": "sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "dependencies": { + "better-assert": "~1.0.0" + } + }, + "node_modules/parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "dependencies": { + "better-assert": "~1.0.0" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-type/node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.0.7.tgz", + "integrity": "sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pidtree": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", + "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", + "dev": true, + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "dependencies": { + "pinkie": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/postcss": { + "version": "7.0.36", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.36.tgz", + "integrity": "sha512-BebJSIUMwJHRH0HAQoxN4u1CN86glsrwsW0q7T+/m44eXOUAxSNdHRkNZPYz5vVUbg17hFgOQDE7fZk7li3pZw==", + "dependencies": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + } + }, + "node_modules/postcss-cli": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-cli/-/postcss-cli-7.0.0.tgz", + "integrity": "sha512-dxn73RcKOennwaijmo2DjTOM3f2bcl/GSSUEqpguiHfRSfRLY3sUvbEy2vvuJ1RasuXCcJ0KvoGe9nSSA7mHQw==", + "dependencies": { + "chalk": "^3.0.0", + "chokidar": "^3.3.0", + "dependency-graph": "^0.8.0", + "fs-extra": "^8.1.0", + "get-stdin": "^7.0.0", + "globby": "^10.0.1", + "postcss": "^7.0.0", + "postcss-load-config": "^2.0.0", + "postcss-reporter": "^6.0.0", + "pretty-hrtime": "^1.0.3", + "read-cache": "^1.0.0", + "yargs": "^15.0.2" + }, + "bin": { + "postcss": "bin/postcss" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/postcss-cli/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/postcss-cli/node_modules/anymatch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.1.tgz", + "integrity": "sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/postcss-cli/node_modules/binary-extensions": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz", + "integrity": "sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow==", + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-cli/node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-cli/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-cli/node_modules/chokidar": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.3.1.tgz", + "integrity": "sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==", + "dependencies": { + "anymatch": "~3.1.1", + "braces": "~3.0.2", + "glob-parent": "~5.1.0", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.3.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/postcss-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/postcss-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/postcss-cli/node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-cli/node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/postcss-cli/node_modules/fsevents": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.2.tgz", + "integrity": "sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/postcss-cli/node_modules/glob-parent": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.0.tgz", + "integrity": "sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-cli/node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-cli/node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/postcss-cli/node_modules/readdirp": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.3.0.tgz", + "integrity": "sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==", + "dependencies": { + "picomatch": "^2.0.7" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/postcss-cli/node_modules/supports-color": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz", + "integrity": "sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/postcss-cli/node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/postcss-load-config": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-2.1.0.tgz", + "integrity": "sha512-4pV3JJVPLd5+RueiVVB+gFOAa7GWc25XQcMp86Zexzke69mKf6Nx9LRcQywdz7yZI9n1udOxmLuAwTBypypF8Q==", + "dependencies": { + "cosmiconfig": "^5.0.0", + "import-cwd": "^2.0.0" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/postcss-reporter": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-reporter/-/postcss-reporter-6.0.1.tgz", + "integrity": "sha512-LpmQjfRWyabc+fRygxZjpRxfhRf9u/fdlKf4VHG4TSPbV2XNsuISzYW1KL+1aQzx53CAppa1bKG4APIB/DOXXw==", + "dependencies": { + "chalk": "^2.4.1", + "lodash": "^4.17.11", + "log-symbols": "^2.2.0", + "postcss": "^7.0.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.0.2.tgz", + "integrity": "sha512-LmeoohTpp/K4UiyQCwuGWlONxXamGzCMtFxLq4W1nZVGIQLYvMCJx3yAF9qyyuFpflABI9yVdtJAqbihOsCsJQ==" + }, + "node_modules/postcss/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prepend-http": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz", + "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dependencies": { + "asap": "~2.0.3" + } + }, + "node_modules/prop-types": { + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.7.2.tgz", + "integrity": "sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==", + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.8.1" + } + }, + "node_modules/protocols": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/protocols/-/protocols-1.4.7.tgz", + "integrity": "sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg==", + "dev": true + }, + "node_modules/proxy-agent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-3.1.0.tgz", + "integrity": "sha512-IkbZL4ClW3wwBL/ABFD2zJ8iP84CY0uKMvBPk/OceQe/cEjrxzN1pMHsLwhbzUoRhG9QbSxYC+Z7LBkTiBNvrA==", + "dev": true, + "dependencies": { + "agent-base": "^4.2.0", + "debug": "^3.1.0", + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.1", + "lru-cache": "^4.1.2", + "pac-proxy-agent": "^3.0.0", + "proxy-from-env": "^1.0.0", + "socks-proxy-agent": "^4.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/proxy-agent/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/proxy-agent/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4=", + "dev": true + }, + "node_modules/pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.11.9", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz", + "integrity": "sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw==", + "dev": true + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "dev": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qs": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", + "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dev": true, + "dependencies": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz", + "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==", + "dev": true, + "dependencies": { + "bytes": "3.1.0", + "http-errors": "1.7.2", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/react": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz", + "integrity": "sha512-pC0uMkhLaHm11ZSJULfOBqV4tIZkx87ZLvbbQYunNixAAvjnC+snJCg0XQXn9VIsttVsbZP/H/ewzgsd5fxKXw==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "16.8.6", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.8.6.tgz", + "integrity": "sha512-1nL7PIq9LTL3fthPqwkvr2zY7phIPjYrT0jp4HjyEQrEROnw4dG41VVwi/wfoCneoleqrNX7iAD+pXebJZwrwA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.13.6" + }, + "peerDependencies": { + "react": "^16.0.0" + } + }, + "node_modules/react-flip-move": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/react-flip-move/-/react-flip-move-3.0.3.tgz", + "integrity": "sha512-gR2jvjUgIXI7ceFWJkr8owX4vKhV0IJoXIf/Dt7gESFe5OKiSz2H6d10mKTW8fN134NDI16J4HgEgq9pKqJd5A==", + "dev": true, + "peerDependencies": { + "react": ">=0.13.x <=16.x.x", + "react-dom": ">=0.13.x <=16.x.x" + } + }, + "node_modules/react-highlight.js": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/react-highlight.js/-/react-highlight.js-1.0.7.tgz", + "integrity": "sha512-OVPKnV0ZvU+V//HExwbV8M9CWy49Eo/9y9pBN2OsNWUFPN6dE4YZBLmJW/5sM2DxI5v/QQLyxOnTnSSfGCP+9Q==", + "dev": true, + "dependencies": { + "highlight.js": "^9.3.0", + "prop-types": "^15.6.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0", + "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/react-is": { + "version": "16.10.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.10.1.tgz", + "integrity": "sha512-BXUMf9sIOPXXZWqr7+c5SeOKJykyVr2u0UDzEf4LNGc6taGkQe1A9DFD07umCIXz45RLr9oAAwZbAJ0Pkknfaw==" + }, + "node_modules/react-sortable-hoc": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/react-sortable-hoc/-/react-sortable-hoc-1.10.1.tgz", + "integrity": "sha512-eVyv5rrK6qY9bG60bboRY78In7OpdRRg+hxp4QMLIjC/UJaFSU7exTYd0764GtXvBqh+b+faYGzren5/ffRYKw==", + "dependencies": { + "@babel/runtime": "^7.2.0", + "invariant": "^2.2.4", + "prop-types": "^15.5.7" + }, + "peerDependencies": { + "prop-types": "^15.5.7", + "react": "^0.14.0 || ^15.0.0 || ^16.0.0", + "react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha1-5mTvMRYRZsl1HNvo28+GtftY93Q=", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readline-sync": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", + "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.3.tgz", + "integrity": "sha512-naKIZz2GQ8JWh///G7L3X6LaQUAMp2lvb1rvwwsURe/VXwD6VMfr+/1NuNw3ag8v2kY1aQ/go5SNn79O9JU7yw==" + }, + "node_modules/registry-auth-token": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.4.0.tgz", + "integrity": "sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==", + "dev": true, + "dependencies": { + "rc": "^1.1.6", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/registry-url": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz", + "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=", + "dev": true, + "dependencies": { + "rc": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "engines": { + "node": ">=4" + } + }, + "node_modules/restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "dependencies": { + "onetime": "^2.0.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.1.4.tgz", + "integrity": "sha512-5C9HXdzK8EAqN7JDif30jqsBzavB7wLpaubisuQIGHWf2gUXSpzy6ArX/+Da8RjFpagWsCn+pIgxTMAmKw9Zug==", + "dev": true + }, + "node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "dependencies": { + "is-promise": "^2.1.0" + }, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz", + "integrity": "sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==" + }, + "node_modules/rxjs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.5.3.tgz", + "integrity": "sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sass": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.22.12.tgz", + "integrity": "sha512-u5Rxn+dKTPCW5/11kMNxtmqKsxCjcpnqj9CaJoru1NqeJ0DOa9rOM00e0HqmseTAatGkKoLY+jaNecMYevu1gg==", + "dev": true, + "dependencies": { + "chokidar": ">=2.0.0 <4.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "node_modules/scheduler": { + "version": "0.13.6", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.13.6.tgz", + "integrity": "sha512-IWnObHt413ucAYKsD9J1QShUKkbKLQQHdxRyw73sw4FN26iWr3DY/H34xGPe4nmL1DwXyWmSWmMrA9TfQbE/XQ==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/secure-keys": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/secure-keys/-/secure-keys-1.0.0.tgz", + "integrity": "sha1-8MgtmKOxOah3aogIBQuCRDEIf8o=", + "dev": true + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/semver-diff": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz", + "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=", + "dev": true, + "dependencies": { + "semver": "^5.0.3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/set-immediate-shim": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz", + "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" + }, + "node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shadow-cljs": { + "version": "2.9.10", + "resolved": "https://registry.npmjs.org/shadow-cljs/-/shadow-cljs-2.9.10.tgz", + "integrity": "sha512-LfgqHJMpYQkQey33lqdX2QW7Y6tKJGb3ye4MlYtz5Z2mHvAYEsd9WttMUXchn26bItZ1gBuESshbirUJ5gaUIA==", + "dev": true, + "dependencies": { + "node-libs-browser": "^2.0.0", + "readline-sync": "^1.4.7", + "shadow-cljs-jar": "1.3.2", + "source-map-support": "^0.4.15", + "which": "^1.3.1", + "ws": "^3.0.0" + }, + "bin": { + "shadow-cljs": "cli/runner.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/shadow-cljs-jar": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/shadow-cljs-jar/-/shadow-cljs-jar-1.3.2.tgz", + "integrity": "sha512-XmeffAZHv8z7451kzeq9oKh8fh278Ak+UIOGGrapyqrFBB773xN8vMQ3O7J7TYLnb9BUwcqadKkmgaq7q6fhZg==", + "dev": true + }, + "node_modules/shadow-cljs/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shadow-cljs/node_modules/source-map-support": { + "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", + "dev": true, + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/shallow-clone": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-0.1.2.tgz", + "integrity": "sha1-WQnodLp3EG1zrEFM/sH/yofZcGA=", + "dev": true, + "dependencies": { + "is-extendable": "^0.1.1", + "kind-of": "^2.0.1", + "lazy-cache": "^0.2.3", + "mixin-object": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shallow-clone/node_modules/kind-of": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-2.0.1.tgz", + "integrity": "sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU=", + "dev": true, + "dependencies": { + "is-buffer": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shell-quote": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", + "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", + "dev": true + }, + "node_modules/shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "node_modules/signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.0.2.tgz", + "integrity": "sha512-JDhEpTKzXusOqXZ0BUIdH+CjFdO/CR3tLlf5CN34IypI+xMmXW1uB16OOY8z3cICbJlDAVJzNbwBhNO0wt9OAw==", + "dev": true, + "engines": { + "node": ">= 4.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snyk": { + "version": "1.228.6", + "resolved": "https://registry.npmjs.org/snyk/-/snyk-1.228.6.tgz", + "integrity": "sha512-6kMyuxBKT+3Oi/dhQRnJyor/Ni/hlURjVlqC+QOpnzWjawkDCoh96V/ntxpQReJfyMrnxq7D1psgIPREjC9Biw==", + "deprecated": "A medium severity vulnerability was found in the Snyk CLI version you are using. We fixed the vulnerability in version 1.996.0. We recommend updating to the latest version. More details here: https://snyk.co/ue1NS", + "dev": true, + "dependencies": { + "@snyk/dep-graph": "1.12.0", + "@snyk/gemfile": "1.2.0", + "@types/agent-base": "^4.2.0", + "@types/restify": "^4.3.6", + "abbrev": "^1.1.1", + "ansi-escapes": "3.2.0", + "chalk": "^2.4.2", + "configstore": "^3.1.2", + "debug": "^3.1.0", + "diff": "^4.0.1", + "git-url-parse": "11.1.2", + "glob": "^7.1.3", + "inquirer": "^6.2.2", + "lodash": "^4.17.14", + "needle": "^2.2.4", + "opn": "^5.5.0", + "os-name": "^3.0.0", + "proxy-agent": "^3.1.0", + "proxy-from-env": "^1.0.0", + "semver": "^6.0.0", + "snyk-config": "^2.2.1", + "snyk-docker-plugin": "1.29.1", + "snyk-go-plugin": "1.11.0", + "snyk-gradle-plugin": "^3.0.2", + "snyk-module": "1.9.1", + "snyk-mvn-plugin": "2.4.0", + "snyk-nodejs-lockfile-parser": "1.16.0", + "snyk-nuget-plugin": "1.12.1", + "snyk-php-plugin": "1.6.4", + "snyk-policy": "1.13.5", + "snyk-python-plugin": "^1.13.2", + "snyk-resolve": "1.0.1", + "snyk-resolve-deps": "4.4.0", + "snyk-sbt-plugin": "2.8.0", + "snyk-tree": "^1.0.0", + "snyk-try-require": "1.3.1", + "source-map-support": "^0.5.11", + "strip-ansi": "^5.2.0", + "tempfile": "^2.0.0", + "then-fs": "^2.0.0", + "update-notifier": "^2.5.0", + "uuid": "^3.3.2", + "wrap-ansi": "^5.1.0" + }, + "bin": { + "snyk": "dist/cli/index.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk-config": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/snyk-config/-/snyk-config-2.2.3.tgz", + "integrity": "sha512-9NjxHVMd1U1LFw66Lya4LXgrsFUiuRiL4opxfTFo0LmMNzUoU5Bk/p0zDdg3FE5Wg61r4fP2D8w+QTl6M8CGiw==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "lodash": "^4.17.15", + "nconf": "^0.10.0" + } + }, + "node_modules/snyk-config/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-config/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-docker-plugin": { + "version": "1.29.1", + "resolved": "https://registry.npmjs.org/snyk-docker-plugin/-/snyk-docker-plugin-1.29.1.tgz", + "integrity": "sha512-Mucc1rZ7l0U8Dykr5m6HPjau8b2H8JVtVaXGbKSZD6e/47JDJhudkgrWjsS5Yt/Zdp1weE3+4SguftFiVR971A==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "dockerfile-ast": "0.0.16", + "semver": "^6.1.0", + "tslib": "^1" + } + }, + "node_modules/snyk-docker-plugin/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-docker-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-docker-plugin/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/snyk-go-parser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/snyk-go-parser/-/snyk-go-parser-1.3.1.tgz", + "integrity": "sha512-jrFRfIk6yGHFeipGD66WV9ei/A/w/lIiGqI80w1ndMbg6D6M5pVNbK7ngDTmo4GdHrZDYqx/VBGBsUm2bol3Rg==", + "dev": true, + "dependencies": { + "toml": "^3.0.0", + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/snyk-go-plugin": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/snyk-go-plugin/-/snyk-go-plugin-1.11.0.tgz", + "integrity": "sha512-9hsGgloioGuey5hbZfv+MkFEslxXHyzUlaAazcR0NsY7VLyG/b2g3f88f/ZwCwlWaKL9LMv/ERIiey3oWAB/qg==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "graphlib": "^2.1.1", + "snyk-go-parser": "1.3.1", + "tmp": "0.0.33", + "tslib": "^1.10.0" + } + }, + "node_modules/snyk-go-plugin/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-go-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-gradle-plugin": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/snyk-gradle-plugin/-/snyk-gradle-plugin-3.1.0.tgz", + "integrity": "sha512-789Rqyhv1+WYbfy1Qilgsw0FMccedSaCO5n+54CXXGVUZWMsVvqJj3T8k7+vis+9Eq+Sgbdzti8vDtApz6rWWQ==", + "dev": true, + "dependencies": { + "@snyk/cli-interface": "^2.1.0", + "@types/debug": "^4.1.4", + "chalk": "^2.4.2", + "clone-deep": "^0.3.0", + "debug": "^4.1.1", + "tmp": "0.0.33", + "tslib": "^1.9.3" + } + }, + "node_modules/snyk-gradle-plugin/node_modules/debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-gradle-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-module": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/snyk-module/-/snyk-module-1.9.1.tgz", + "integrity": "sha512-A+CCyBSa4IKok5uEhqT+hV/35RO6APFNLqk9DRRHg7xW2/j//nPX8wTSZUPF8QeRNEk/sX+6df7M1y6PBHGSHA==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "hosted-git-info": "^2.7.1" + } + }, + "node_modules/snyk-module/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-module/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-mvn-plugin": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/snyk-mvn-plugin/-/snyk-mvn-plugin-2.4.0.tgz", + "integrity": "sha512-Fmt6Mjx6zZz+4q6PnBkhuNGhEX++q/pKMI26ls4p3JPkx4KxBz89oncpkmf7P8YCkoaka8oHhtDEv/R4Z9LleQ==", + "dev": true, + "dependencies": { + "lodash": "^4.17.15", + "tslib": "1.9.3" + } + }, + "node_modules/snyk-mvn-plugin/node_modules/tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "node_modules/snyk-nodejs-lockfile-parser": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/snyk-nodejs-lockfile-parser/-/snyk-nodejs-lockfile-parser-1.16.0.tgz", + "integrity": "sha512-cf3uozRXEG88nsjOQlo+SfOJPpcLs45qpnuk2vhBBZ577IMnV+fTOJQsP2YRiikLUbdgkVlduviwUO6OVn1PhA==", + "dev": true, + "dependencies": { + "@yarnpkg/lockfile": "^1.0.2", + "graphlib": "^2.1.5", + "lodash": "^4.17.14", + "source-map-support": "^0.5.7", + "tslib": "^1.9.3", + "uuid": "^3.3.2" + }, + "bin": { + "parse-nodejs-lockfile": "bin/index.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/snyk-nuget-plugin": { + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/snyk-nuget-plugin/-/snyk-nuget-plugin-1.12.1.tgz", + "integrity": "sha512-QuANQxBjTGj3hEf2YpEQ0WuI4Yq/93boqWUs4eoSTfDyBRFgIkUP6fLkzNldrkL8fQbcagqQ2Xz8M9IEKRQtMg==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "dotnet-deps-parser": "4.5.0", + "jszip": "^3.1.5", + "lodash": "^4.17.14", + "snyk-paket-parser": "1.5.0", + "tslib": "^1.9.3", + "xml2js": "^0.4.17" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk-nuget-plugin/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-nuget-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-paket-parser": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/snyk-paket-parser/-/snyk-paket-parser-1.5.0.tgz", + "integrity": "sha512-1CYMPChJ9D9LBy3NLqHyv8TY7pR/LMISSr08LhfFw/FpfRZ+gTH8W6bbxCmybAYrOFNCqZkRprqOYDqZQFHipA==", + "dev": true, + "dependencies": { + "tslib": "^1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk-php-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/snyk-php-plugin/-/snyk-php-plugin-1.6.4.tgz", + "integrity": "sha512-FFQeimtbwq17nDUS0o0zuKgyjXSX7SpoC9iYTeKvxTXrmKf2QlxTtPvmMM4/hQxehEu1i40ow1Ozw0Ahxm8Dpw==", + "dev": true, + "dependencies": { + "@snyk/composer-lockfile-parser": "1.0.3", + "tslib": "1.9.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk-php-plugin/node_modules/tslib": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", + "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==", + "dev": true + }, + "node_modules/snyk-policy": { + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/snyk-policy/-/snyk-policy-1.13.5.tgz", + "integrity": "sha512-KI6GHt+Oj4fYKiCp7duhseUj5YhyL/zJOrrJg0u6r59Ux9w8gmkUYT92FHW27ihwuT6IPzdGNEuy06Yv2C9WaQ==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "email-validator": "^2.0.4", + "js-yaml": "^3.13.1", + "lodash.clonedeep": "^4.5.0", + "semver": "^6.0.0", + "snyk-module": "^1.9.1", + "snyk-resolve": "^1.0.1", + "snyk-try-require": "^1.3.1", + "then-fs": "^2.0.0" + } + }, + "node_modules/snyk-policy/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-policy/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-policy/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/snyk-python-plugin": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/snyk-python-plugin/-/snyk-python-plugin-1.13.2.tgz", + "integrity": "sha512-G9R1cYHw0E/VSx9tFa5nZp+653FIMXheteidrF3hjUe71jRdJELEUV/z5jxqYEWEFemcwGhMfW87De91GChVIQ==", + "dev": true, + "dependencies": { + "@snyk/cli-interface": "^2.0.2", + "tmp": "0.0.33" + } + }, + "node_modules/snyk-resolve": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/snyk-resolve/-/snyk-resolve-1.0.1.tgz", + "integrity": "sha512-7+i+LLhtBo1Pkth01xv+RYJU8a67zmJ8WFFPvSxyCjdlKIcsps4hPQFebhz+0gC5rMemlaeIV6cqwqUf9PEDpw==", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "then-fs": "^2.0.0" + } + }, + "node_modules/snyk-resolve-deps": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/snyk-resolve-deps/-/snyk-resolve-deps-4.4.0.tgz", + "integrity": "sha512-aFPtN8WLqIk4E1ulMyzvV5reY1Iksz+3oPnUVib1jKdyTHymmOIYF7z8QZ4UUr52UsgmrD9EA/dq7jpytwFoOQ==", + "dev": true, + "dependencies": { + "@types/node": "^6.14.4", + "@types/semver": "^5.5.0", + "ansicolors": "^0.3.2", + "debug": "^3.2.5", + "lodash.assign": "^4.2.0", + "lodash.assignin": "^4.2.0", + "lodash.clone": "^4.5.0", + "lodash.flatten": "^4.4.0", + "lodash.get": "^4.4.2", + "lodash.set": "^4.3.2", + "lru-cache": "^4.0.0", + "semver": "^5.5.1", + "snyk-module": "^1.6.0", + "snyk-resolve": "^1.0.0", + "snyk-tree": "^1.0.0", + "snyk-try-require": "^1.1.1", + "then-fs": "^2.0.0" + } + }, + "node_modules/snyk-resolve-deps/node_modules/@types/node": { + "version": "6.14.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-6.14.7.tgz", + "integrity": "sha512-YbPXbaynBTe0pVExPhL76TsWnxSPeFAvImIsmylpBWn/yfw+lHy+Q68aawvZHsgskT44ZAoeE67GM5f+Brekew==", + "dev": true + }, + "node_modules/snyk-resolve-deps/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-resolve-deps/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-resolve/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-resolve/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk-sbt-plugin": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/snyk-sbt-plugin/-/snyk-sbt-plugin-2.8.0.tgz", + "integrity": "sha512-ZzyBdND5CsaO0xkv05geZXu8Dd6Llvr/5oTj811U7h7UmrvljrAiABW4RGjRJPrPVuuJaDej2p633sgGtK9UsA==", + "dev": true, + "dependencies": { + "semver": "^6.1.2", + "tmp": "^0.1.0", + "tree-kill": "^1.2.1", + "tslib": "^1.10.0" + } + }, + "node_modules/snyk-sbt-plugin/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/snyk-sbt-plugin/node_modules/tmp": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.1.0.tgz", + "integrity": "sha512-J7Z2K08jbGcdA1kkQpJSqLF6T0tdQqpR2pnSUXsIchbPdTI9v3e85cLW0d6WDhwuAleOV71j2xWs8qMPfK7nKw==", + "dev": true, + "dependencies": { + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk-tree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/snyk-tree/-/snyk-tree-1.0.0.tgz", + "integrity": "sha1-D7cxdtvzLngvGRAClBYESPkRHMg=", + "dev": true, + "dependencies": { + "archy": "^1.0.0" + }, + "bin": { + "npm-tree": "lib/index.js" + } + }, + "node_modules/snyk-try-require": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/snyk-try-require/-/snyk-try-require-1.3.1.tgz", + "integrity": "sha1-bgJvkuZK9/zM6h7lPVJIQeQYohI=", + "dev": true, + "dependencies": { + "debug": "^3.1.0", + "lodash.clonedeep": "^4.3.0", + "lru-cache": "^4.0.0", + "then-fs": "^2.0.0" + } + }, + "node_modules/snyk-try-require/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk-try-require/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk/node_modules/ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/snyk/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/snyk/node_modules/semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/snyk/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/snyk/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/socket.io": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.1.1.tgz", + "integrity": "sha512-rORqq9c+7W0DAK3cleWNSyfv/qKXV99hV4tZe+gGLfBECw3XEhBy7x85F3wypA9688LKjtwO9pX9L33/xQI8yA==", + "dev": true, + "dependencies": { + "debug": "~3.1.0", + "engine.io": "~3.2.0", + "has-binary2": "~1.0.2", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.1.1", + "socket.io-parser": "~3.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", + "dev": true + }, + "node_modules/socket.io-client": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.1.1.tgz", + "integrity": "sha512-jxnFyhAuFxYfjqIgduQlhzqTcOEQSn+OHKVfAxWaNWa7ecP7xSNk2Dx/3UEsDcY7NcFafxvNvKPmmO7HTwTxGQ==", + "dev": true, + "dependencies": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "engine.io-client": "~3.2.0", + "has-binary2": "~1.0.2", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.2.0", + "to-array": "0.1.4" + } + }, + "node_modules/socket.io-client/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/socket.io-client/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "3.2.0", + "resolved": "http://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.2.0.tgz", + "integrity": "sha512-FYiBx7rc/KORMJlgsXysflWx/RIvtqZbyGLlHZvjfmPTPeuD/I8MaW7cfFrj5tRltICJdgwflhfZ3NVVbVLFQA==", + "dev": true, + "dependencies": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "isarray": "2.0.1" + } + }, + "node_modules/socket.io-parser/node_modules/component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "node_modules/socket.io-parser/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socket.io-parser/node_modules/isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "node_modules/socket.io/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/socks": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.3.2.tgz", + "integrity": "sha512-pCpjxQgOByDHLlNqlnh/mNSAxIUkyBBuwwhTcV+enZGbDaClPvHdvm6uvOwZfFJkam7cGhBNbb4JxiP8UZkRvQ==", + "dev": true, + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "4.0.2" + }, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz", + "integrity": "sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg==", + "dev": true, + "dependencies": { + "agent-base": "~4.2.1", + "socks": "~2.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.2.1.tgz", + "integrity": "sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/sort-keys": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", + "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=", + "dev": true, + "dependencies": { + "is-plain-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "dependencies": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "node_modules/streamroller": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-1.0.6.tgz", + "integrity": "sha512-3QC47Mhv3/aZNFpDDVO44qQb9gwB9QggMEE0sQmkTAwBVYdBRWISdsywlkfm5II1Q5y/pmrHflti/IgmIzdDBg==", + "deprecated": "1.x is no longer supported. Please upgrade to 3.x or higher.", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "date-format": "^2.0.0", + "debug": "^3.2.6", + "fs-extra": "^7.0.1", + "lodash": "^4.17.14" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/streamroller/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/streamroller/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-hash": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz", + "integrity": "sha1-6Kr8CsGFW0Zmkp7X3RJ1311sgRs=" + }, + "node_modules/string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "dependencies": { + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^4.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.0.0.tgz", + "integrity": "sha1-86rvfBcZ8XDF6rHDK/eA2W4h8vA=", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "es-abstract": "^1.4.3", + "function-bind": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "dependencies": { + "ansi-regex": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-url-auth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-url-auth/-/strip-url-auth-1.0.1.tgz", + "integrity": "sha1-IrD6OkE4WzO+PzMVUbu4N/oM164=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/temp-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/temp-dir/-/temp-dir-1.0.0.tgz", + "integrity": "sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tempfile": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-2.0.0.tgz", + "integrity": "sha1-awRGhWqbERTRhW/8vlCczLCXcmU=", + "dev": true, + "dependencies": { + "temp-dir": "^1.0.0", + "uuid": "^3.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/term-size/-/term-size-1.2.0.tgz", + "integrity": "sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=", + "dev": true, + "dependencies": { + "execa": "^0.7.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size/node_modules/cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "dependencies": { + "lru-cache": "^4.0.1", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "node_modules/term-size/node_modules/execa": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-0.7.0.tgz", + "integrity": "sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=", + "dev": true, + "dependencies": { + "cross-spawn": "^5.0.1", + "get-stream": "^3.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/term-size/node_modules/get-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz", + "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/then-fs": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/then-fs/-/then-fs-2.0.0.tgz", + "integrity": "sha1-cveS3Z0xcFqRrhnr/Piz+WjIHaI=", + "dev": true, + "dependencies": { + "promise": ">=3.2 <8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "node_modules/thunkify": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/thunkify/-/thunkify-2.1.2.tgz", + "integrity": "sha1-+qDp0jDFGsyVyhOjYawFyn4EVT0=", + "dev": true + }, + "node_modules/timed-out": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz", + "integrity": "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "node_modules/to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "dev": true + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha1-42RqLqTokTEr9+rObPsFOAvAHCE=", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "node_modules/tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "node_modules/type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "dependencies": { + "prelude-ls": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.20", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.20.tgz", + "integrity": "sha512-8OaIKfzL5cpx8eCMAhhvTlft8GYF8b2eQr6JkCyVdrgjcytyOmPCXrqXFcUnhonRpLlh5yxEZVohm6mzaowUOw==", + "engines": { + "node": "*" + } + }, + "node_modules/ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "node_modules/unique-string": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unique-string/-/unique-string-1.0.0.tgz", + "integrity": "sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=", + "dev": true, + "dependencies": { + "crypto-random-string": "^1.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unzip-response": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-2.0.1.tgz", + "integrity": "sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/update-notifier": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-2.5.0.tgz", + "integrity": "sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==", + "dev": true, + "dependencies": { + "boxen": "^1.2.1", + "chalk": "^2.0.1", + "configstore": "^3.0.0", + "import-lazy": "^2.1.0", + "is-ci": "^1.0.10", + "is-installed-globally": "^0.1.0", + "is-npm": "^1.0.0", + "latest-version": "^3.0.0", + "semver-diff": "^2.0.0", + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-parse-lax": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz", + "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=", + "dev": true, + "dependencies": { + "prepend-http": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + }, + "node_modules/util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "dependencies": { + "inherits": "2.0.3" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "node_modules/util/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/vscode-languageserver-types": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.14.0.tgz", + "integrity": "sha512-lTmS6AlAlMHOvPQemVwo3CezxBp0sNB95KNPkqp3Nxd5VFEnuG1ByM0zlRWos0zjO3ZWtkvhal0COgiV1xIA4A==", + "dev": true + }, + "node_modules/whatwg-fetch": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", + "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" + }, + "node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/widest-line": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-2.0.1.tgz", + "integrity": "sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==", + "dev": true, + "dependencies": { + "string-width": "^2.1.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true, + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/windows-release": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/windows-release/-/windows-release-3.2.0.tgz", + "integrity": "sha512-QTlz2hKLrdqukrsapKsINzqMgOUpQW268eJ0OaOpJN32h272waxR9fkB9VoWRtK7uKHG5EHJcTXQBD8XZVJkFA==", + "dev": true, + "dependencies": { + "execa": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "dependencies": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "dependencies": { + "number-is-nan": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "dependencies": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/write-file-atomic": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.3.tgz", + "integrity": "sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "node_modules/ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "dependencies": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "node_modules/xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/xml2js": { + "version": "0.4.22", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.22.tgz", + "integrity": "sha512-MWTbxAQqclRSTnehWWe5nMKzI3VmJ8ltiJEco8akcC6j3miOhjjfzKum5sId+CWhfxdOs/1xauYr8/ZDBtQiRw==", + "dev": true, + "dependencies": { + "sax": ">=0.6.0", + "util.promisify": "~1.0.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xml2js/node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlbuilder": { + "version": "9.0.7", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", + "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xregexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xregexp/-/xregexp-2.0.0.tgz", + "integrity": "sha1-UqY+VsoLhKfzpfPWGHLxJq16WUM=", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + }, + "node_modules/yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "node_modules/yargs": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.1.0.tgz", + "integrity": "sha512-T39FNN1b6hCW4SOIk1XyTOWxtXdcen0t+XYrysQmChzSipvhBO8Bj0nK1ozAasdk24dNWuMZvr4k24nz+8HHLg==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^16.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs-parser": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-16.1.0.tgz", + "integrity": "sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/yargs/node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/yargs/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..726675f --- /dev/null +++ b/package.json @@ -0,0 +1,54 @@ +{ + "name": "airsonic-ui", + "version": "0.0.1", + "description": "Airsonic UI written with re-frame", + "main": "index.js", + "scripts": { + "build:cljs": "shadow-cljs release app", + "build-extra:cljs-report": "shadow-cljs run shadow.cljs.build-report app public/build-report.html", + "build:sass": "sass --style compressed src/sass/app.sass | postcss -o public/app/app.css", + "build": "mkdir -p public; rm -r public/*; run-p copy:* build:*", + "copy:assets": "cp -R src/assets/* public/", + "copy:icons": "cp -R node_modules/open-iconic/font/fonts public", + "deploy": "gh-pages -d public -m \"[skip ci] Deploying $(git rev-parse --short HEAD)\"", + "dev:cljs": "shadow-cljs watch app test", + "dev:sass": "echo src/sass/app.sass | entr npm run build:sass", + "dev:test": "karma start --reporters notify,progress --auto-watch", + "dev": "rm -r public/*; npm-run-all build:sass copy:* test:compile -p dev:*", + "test": "run-s test:compile test:run", + "test:compile": "shadow-cljs compile test", + "test:run": "karma start --single-run" + }, + "author": "Arne Schlüter", + "license": "ISC", + "repository": { + "type": "git", + "url": "git://github.com/heyarne/airsonic-ui.git" + }, + "dependencies": { + "@hugojosefson/color-hash": "^2.0.3", + "autoprefixer": "^9.5.0", + "bulma": "^0.8.0", + "create-react-class": "^15.6.3", + "highlight.js": "10.4.1", + "open-iconic": "^1.1.1", + "postcss-cli": "^7.0.0", + "react": "^16.8.6", + "react-dom": "^16.8.6", + "react-sortable-hoc": "^1.8.3" + }, + "devDependencies": { + "gh-pages": "^3.0.0", + "karma": "^5.0.0", + "karma-chrome-launcher": "^3.0.0", + "karma-cljs-test": "^0.1.0", + "karma-firefox-launcher": "^1.2.0", + "karma-notify-reporter": "^1.1.0", + "sass": "^1.86.3", + "npm-run-all": "^4.1.5", + "react-flip-move": "^3.0.3", + "react-highlight.js": "^1.0.7", + "sass": "^1.17.3", + "shadow-cljs": "^2.9.10" + } +} diff --git a/postcss.config.js b/postcss.config.js new file mode 100644 index 0000000..88752c6 --- /dev/null +++ b/postcss.config.js @@ -0,0 +1,5 @@ +module.exports = { + plugins: [ + require('autoprefixer') + ] +} diff --git a/shadow-cljs.edn b/shadow-cljs.edn new file mode 100644 index 0000000..26c0850 --- /dev/null +++ b/shadow-cljs.edn @@ -0,0 +1,32 @@ +;; shadow-cljs configuration +{:source-paths + ["src/cljs", "test/cljs"] + + :dependencies + [[reagent "1.1.0"] + [re-frame "1.4.3"] + [re-pressed "0.3.1"] + [day8.re-frame/http-fx "v0.2.0"] + [akiroz.re-frame/storage "0.1.4"] + [funcool/bide "1.6.0"] + [fipp "0.6.22"] + ;; debugging + [day8.re-frame/re-frame-10x "1.10.0"] + #_[day8.re-frame/tracing "0.5.1"] + [philoskim/debux "0.5.6"]] + + :nrepl {:port 9000} + + :builds + {:app {:target :browser + :output-dir "public/app/js" + :asset-path "/app/js" + :modules {:main {:entries [airsonic-ui.core]}} + :devtools {:http-root "public" + :http-port 8080 + :after-load airsonic-ui.core/mount-root + :preloads [day8.re-frame-10x.preload]} + :dev {:closure-defines {"re_frame.trace.trace_enabled_QMARK_" true}}} + :test {:target :karma + :output-to "public/test/ci.js" + :ns-regexp "-test$"}}} diff --git a/android-chrome-192x192.png b/src/assets/android-chrome-192x192.png similarity index 100% rename from android-chrome-192x192.png rename to src/assets/android-chrome-192x192.png diff --git a/android-chrome-512x512.png b/src/assets/android-chrome-512x512.png similarity index 100% rename from android-chrome-512x512.png rename to src/assets/android-chrome-512x512.png diff --git a/apple-touch-icon.png b/src/assets/apple-touch-icon.png similarity index 100% rename from apple-touch-icon.png rename to src/assets/apple-touch-icon.png diff --git a/browserconfig.xml b/src/assets/browserconfig.xml similarity index 100% rename from browserconfig.xml rename to src/assets/browserconfig.xml diff --git a/favicon-16x16.png b/src/assets/favicon-16x16.png similarity index 100% rename from favicon-16x16.png rename to src/assets/favicon-16x16.png diff --git a/favicon-32x32.png b/src/assets/favicon-32x32.png similarity index 100% rename from favicon-32x32.png rename to src/assets/favicon-32x32.png diff --git a/favicon.ico b/src/assets/favicon.ico similarity index 100% rename from favicon.ico rename to src/assets/favicon.ico diff --git a/img/airsonic-light-350x100.png b/src/assets/img/airsonic-light-350x100.png similarity index 100% rename from img/airsonic-light-350x100.png rename to src/assets/img/airsonic-light-350x100.png diff --git a/index.html b/src/assets/index.html similarity index 94% rename from index.html rename to src/assets/index.html index b238243..940932a 100644 --- a/index.html +++ b/src/assets/index.html @@ -4,7 +4,7 @@ Airsonic - + diff --git a/mstile-144x144.png b/src/assets/mstile-144x144.png similarity index 100% rename from mstile-144x144.png rename to src/assets/mstile-144x144.png diff --git a/mstile-150x150.png b/src/assets/mstile-150x150.png similarity index 100% rename from mstile-150x150.png rename to src/assets/mstile-150x150.png diff --git a/mstile-310x150.png b/src/assets/mstile-310x150.png similarity index 100% rename from mstile-310x150.png rename to src/assets/mstile-310x150.png diff --git a/mstile-310x310.png b/src/assets/mstile-310x310.png similarity index 100% rename from mstile-310x310.png rename to src/assets/mstile-310x310.png diff --git a/mstile-70x70.png b/src/assets/mstile-70x70.png similarity index 100% rename from mstile-70x70.png rename to src/assets/mstile-70x70.png diff --git a/safari-pinned-tab.svg b/src/assets/safari-pinned-tab.svg similarity index 100% rename from safari-pinned-tab.svg rename to src/assets/safari-pinned-tab.svg diff --git a/site.webmanifest b/src/assets/site.webmanifest similarity index 100% rename from site.webmanifest rename to src/assets/site.webmanifest diff --git a/src/cljs/airsonic_ui/api/events.cljs b/src/cljs/airsonic_ui/api/events.cljs new file mode 100644 index 0000000..b99d4f0 --- /dev/null +++ b/src/cljs/airsonic_ui/api/events.cljs @@ -0,0 +1,45 @@ +(ns airsonic-ui.api.events + "This namespace contains all events relevant to API interaction. It contains + an event handler which issues requests as well as the appropriate handlers, + which dispatch :notification events in case of errors." + (:require [re-frame.core :refer [reg-event-fx]] + [ajax.core :as ajax] + [airsonic-ui.api.helpers :as api])) + +(defn- cache-path [endpoint params] [:api/responses [endpoint params]]) + +(defn api-request + "Event handler to issue API request; takes care of authorization based on our + current app state." + [{:keys [db]} [_ endpoint params]] + {:http-xhrio {:method :get + :uri (api/url (:credentials db) endpoint params) + :response-format (ajax/json-response-format {:keywords? true}) + :on-success [:api.response/ok endpoint params] + :on-failure [:api.response/failed endpoint params]} + :db (assoc-in db (conj (cache-path endpoint params) :api/is-loading?) true)}) + +(reg-event-fx :api/request api-request) + +(defn api-success + "Handles when the server responded. There could still be an error while + processing the request on the server side which we have to account for." + [{:keys [db]} [_ endpoint params response]] + (let [response-cache (cache-path endpoint params)] + (try + {:db (assoc-in db response-cache (api/unwrap-response response))} + (catch ExceptionInfo e + {:dispatch [:notification/show :error (api/error-msg e)] + :db (update-in db response-cache dissoc :api/is-loading?)})))) + +(reg-event-fx :api.response/ok api-success) + +(defn api-failure + "Handler for catastrophic failures (network errors and such things)" + [fx [ev endpoint params]] + (let [response-cache (cons :db (cache-path endpoint params))] + {:log ["API call gone bad; are CORS headers missing? check for :status 0" ev] ; <- the :log effect is registered in ../events.cljs + :dispatch [:notification/show :error "Communication with server failed. Check browser logs for details."] + :db (update-in fx response-cache dissoc :api/is-loading?)})) + +(reg-event-fx :api.response/failed api-failure) diff --git a/src/cljs/airsonic_ui/api/helpers.cljs b/src/cljs/airsonic_ui/api/helpers.cljs new file mode 100644 index 0000000..e2310d5 --- /dev/null +++ b/src/cljs/airsonic_ui/api/helpers.cljs @@ -0,0 +1,78 @@ +(ns airsonic-ui.api.helpers + (:require [clojure.string :as str] + [clojure.set :as set])) + +(def default-params {:f "json" + :c "airsonic-ui-cljs" + :v "1.15.0"}) + +(defn- unroll-variadic-params + "Turns {:id [1 2 3], :foo :bar} into [[:id 1] [:id 2] [:id 3] [:foo :bar]]" + [params] + (->> + (map (fn [[k vs]] + (if (sequential? vs) + (map (fn [v] [k v]) vs) + [k vs])) params) + (flatten) + (partition 2))) + +(def ^:private encode js/encodeURIComponent) + +(defn url + "Returns an absolute url to an API endpoint" + [credentials endpoint params] + (let [server (:server credentials) + auth (select-keys credentials [:u :p]) + query (->> (merge default-params auth params) + (unroll-variadic-params) + (map (fn [[k v]] (str (encode (name k)) "=" (encode v)))) + (str/join "&"))] + (str (str/replace server #"/+$" "") "/rest/" endpoint "?" query))) + +(defn stream-url [credentials song-or-episode] + ;; podcasts have a stream-id, normal songs just use their id + (let [params {:id (or (:streamId song-or-episode) + (:id song-or-episode))}] + (url credentials "stream" params))) + +(defn cover-url [credentials item size] + (url credentials "getCoverArt" {:id (:coverArt item) :size size})) + +(defn is-error? [response] + (= "failed" (get-in response [:subsonic-response :status]))) + +(defn- unwrap-response* [response] + (-> (:subsonic-response response) + (dissoc :status :version :type :serverVersion :openSubsonic) + vals + first)) + +(defn ->exception + "Takes an erroneous response and makes it a real exception" + [response] + (let [error (unwrap-response* response)] + (ex-info (:message response) error))) + +(defn unwrap-response + "Retrieves the actual response body" + [response] + (if (is-error? response) + (throw (->exception response)) + (unwrap-response* response))) + +(defn error-msg + [exception-info] + (let [{:keys [code message]} (ex-data exception-info)] + (str "Error " code ": " message))) + +(defn content-type + "Given some piece of data returned by the api, returns a keyword that + describes what we look at" + [data] + (keyword :content-type + (condp set/subset? (set (keys data)) + #{:path} :song + #{:artistId :name :songCount :artist} :album + #{:id :name :albumCount} :artist + :unknown))) diff --git a/src/cljs/airsonic_ui/api/subs.cljs b/src/cljs/airsonic_ui/api/subs.cljs new file mode 100644 index 0000000..1eea97c --- /dev/null +++ b/src/cljs/airsonic_ui/api/subs.cljs @@ -0,0 +1,71 @@ +(ns airsonic-ui.api.subs + (:require [clojure.string :as str] + [re-frame.core :refer [reg-sub]] + [airsonic-ui.helpers :refer [kebabify]])) + +(defn responses + "Returns the response cache" + [db _] + (:api/responses db)) + +(reg-sub :api/responses responses) + +(defn response-for + "Returns the cached response for a single endpoint, respecting passed + url pramters." + [responses [_ endpoint params]] + (get responses [endpoint params])) + +(reg-sub + :api/response-for + :<- [:api/responses] + response-for) + +(defn responses-for-endpoint + "Returns a seq of all responses for an endpoint, ignoring url parameters and + looking only at the path" + [responses [_ endpoint]] + (into {} (filter (fn [[[k _] _]] (= endpoint k)) responses))) + +(reg-sub + :api/responses-for-endpoint + :<- [:api/responses] + responses-for-endpoint) + +(defn endpoint->kw + "Given an endpoint like `getAlbumList2`, returns a cleaned keyword like + `:album-list`. + + Rules: Kebab-case everything, remove prefixes like `get`, `create`, `delete`, + `update` and strip trailing numbers." + [endpoint-str] + (-> (str/replace endpoint-str #"^(get|create|update|delete)" "") + (str/replace #"\d+$" "") + (kebabify))) + +(defn current-route-data + "Returns all responses for the current route" + [[responses current-route-events] _] + (->> (filter #(= :api/request (first %)) current-route-events) + (mapcat (fn [[_ endpoint params]] + [(endpoint->kw endpoint) (get responses [endpoint params])])) + (apply hash-map))) + +(reg-sub + :api/current-route-data + :<- [:api/responses] + :<- [:routes/events-for-current-route] + current-route-data) + +(defn content-pending? + "Tells us if any of the requests fired for the current route are + awaiting responses." + [current-route-data _] + (->> (vals current-route-data) + (map :api/is-loading?) + (some true?))) + +(reg-sub + :api/content-pending? + :<- [:api/current-route-data] + content-pending?) diff --git a/src/cljs/airsonic_ui/audio/core.cljs b/src/cljs/airsonic_ui/audio/core.cljs new file mode 100644 index 0000000..132bc2e --- /dev/null +++ b/src/cljs/airsonic_ui/audio/core.cljs @@ -0,0 +1,144 @@ +(ns airsonic-ui.audio.core + "This namespace contains some JS interop code to interact with an audio player + and receive information about the current playback status so we can use it in + our re-frame app." + (:require [re-frame.core :as rf] + [airsonic-ui.audio.playlist :as playlist] + [goog.functions :refer [throttle]])) + +(defonce audio (atom nil)) + +(defn normalize-time-ranges [time-ranges] + (if (> (.-length time-ranges) 0) + (.end time-ranges (dec (.-length time-ranges))) + 0)) + +(defn ->status + "Takes an audio object and returns a map describing its current status" + [elem] + {:ended? (.-ended elem) + :paused? (.-paused elem) + :current-src (.-currentSrc elem) + :current-time (.-currentTime elem) + :seekable (normalize-time-ranges (.-seekable elem)) + :buffered (normalize-time-ranges (.-buffered elem)) + :volume (.-volume elem)}) + + ; explanation of these events: https://developer.mozilla.org/en-US/Apps/Fundamentals/Audio_and_video_delivery/Cross-browser_audio_basics + +(defn attach-listeners! [el] + (let [emit-audio-update (throttle #(rf/dispatch [:audio/update (->status el)]) 16)] + (doseq [event ["loadstart" "progress" "play" "timeupdate" "pause" "volumechange"]] + (.addEventListener el event emit-audio-update)))) + +;; effects to be fired from event handlers + +(rf/reg-fx + :audio/play + (fn [stream-url] + (when-not @audio + (reset! audio (js/Audio.)) + (attach-listeners! @audio)) + (.pause @audio) + (set! (.-src @audio) stream-url) + (.play @audio))) + +(rf/reg-fx + :audio/pause + (fn [_] + (some-> @audio .pause))) + +(rf/reg-fx + :audio/stop + (fn [_] + (when-let [audio @audio] + (.pause audio) + (set! (.-currentTime audio) 0) + (set! (.-src audio) "")))) + +(rf/reg-fx + :audio/toggle-play-pause + (fn [_] + (if-let [a @audio] + (if (.-paused a) + (.play a) + (.pause a))))) + +(rf/reg-fx + :audio/seek + (fn [[percentage duration]] + (set! (. @audio -currentTime) + (* percentage duration)))) + +(defn- set-volume! [volume] + (set! (.-volume @audio) volume)) + +(rf/reg-fx + :audio/set-volume + (fn [percentage] + (when @audio + (set-volume! percentage)))) + +(rf/reg-fx + :audio/increase-volume + (fn [_] + (when-let [vol (some-> @audio .-volume)] + (set-volume! (min 1 (+ vol 0.05)))))) + +(rf/reg-fx + :audio/decrease-volume + (fn [_] + (when-let [vol (some-> @audio .-volume)] + (set-volume! (max 0 (- vol 0.05)))))) + +;; subscriptions + +(defn summary + "Returns all information about audio that we have" + [db _] + (:audio db)) + +(rf/reg-sub :audio/summary summary) + +(defn current-playlist + "Lists the complete current-queue" + [summary _] + (:current-playlist summary)) + +(rf/reg-sub + :audio/current-playlist + :<- [:audio/summary] + current-playlist) + +(defn current-song + "Gives us information about the currently played song as presented by + the airsonic api" + [playlist _] + (when-not (empty? playlist) + (playlist/current-song playlist))) + +(rf/reg-sub + :audio/current-song + :<- [:audio/current-playlist] + current-song) + +(defn playback-status + "Gives us information about the most recently fired html 5 audio event" + [summary _] + (:playback-status summary)) + +(rf/reg-sub + :audio/playback-status + :<- [:audio/summary] + playback-status) + +(defn is-playing? + "Predicate to tell us whether we currently have audio output or not" + [playback-status _] + (and (not (:paused? playback-status)) + (not (:ended? playback-status)))) + +(rf/reg-sub + :audio/is-playing? + :<- [:audio/playback-status] + is-playing?) diff --git a/src/cljs/airsonic_ui/audio/playlist.cljs b/src/cljs/airsonic_ui/audio/playlist.cljs new file mode 100644 index 0000000..47032ee --- /dev/null +++ b/src/cljs/airsonic_ui/audio/playlist.cljs @@ -0,0 +1,196 @@ +(ns airsonic-ui.audio.playlist + "Implements playlist queues that support different kinds of repetition and + song ordering.") + +;; Turns out we can nicely implement this by thinly wrapping a sequence of items +;; We re-use the core ClojureScript protocols internally but provide a nice and +;; explicit API to consume + +(defprotocol IPlaylist + (current-song [this]) + (next-song [this]) + (previous-song [this]) + + (set-current-song [this song-idx] + "Advances the queue to the song given by song-idx") + (set-playback-mode [this playback-mode] + "Changes the playback mode of a playlist and re-shuffles it if necessary") + (set-repeat-mode [this repeat-mode] + "Allows you to change how the next and previous song are selected") + + (enqueue-last + [this song source] + [this song] + "Registers a song to be played last, optionally remembering the source route") + (enqueue-next + [this song source] + [this song] + "Registers a song to be played next, optionally remembering the source route") + + (move-song [this from-idx to-idx] + "Allows you to move a song in a playlist") + (remove-song [this song-idx] + "Removes a song from the playlist")) + +;; helpers to manage creating playlists + +(defn- mark-original-order + "This function is used if we switch from linear to shuffled; it allows us to + restore the order of the queue when it was created." + [items] + (->> (sort-by (comp :playlist/linear-order meta) items) + (map-indexed (fn [idx item] + (vary-meta item assoc :playlist/linear-order idx))))) + +(defn- linear-queue + [items] + (->> (mark-original-order items) + (map-indexed vector) + (into (sorted-map)))) + +(defn- shuffled-queue + [items] + (let [shuffled-indices (shuffle (range (count items)))] + (->> (mark-original-order items) + (map vector shuffled-indices) + (into (sorted-map))))) + +;; the exported interface: + +(defrecord Playlist [items current-idx playback-mode repeat-mode] + cljs.core/ICounted + (-count [_] + (count items)) + + cljs.core/ISequential + cljs.core/ISeqable + (-seq [_] items) + + IPlaylist + (current-song [_] + (get items current-idx)) + + (next-song [this] + (update this :current-idx + (fn [current-idx] + (cond + (= repeat-mode :repeat-single) current-idx + + (or (= repeat-mode :repeat-all) + (< current-idx (dec (count this)))) + (mod (inc current-idx) (count this)))))) + + (previous-song [this] + (update this :current-idx + (fn [current-idx] + (cond + (= repeat-mode :repeat-single) current-idx + + (or (= repeat-mode :repeat-all) + (> current-idx 0)) + (mod (dec current-idx) (count this)) + + :else nil)))) + + (set-current-song [playlist song-idx] + (assoc playlist :current-idx song-idx)) + + (set-playback-mode [playlist playback-mode] + (let [current-song (current-song playlist) + queue-fn (case playback-mode + :shuffled shuffled-queue + :linear linear-queue) + next-playlist (-> (assoc playlist :playback-mode playback-mode) + (update :items (comp queue-fn vals))) + next-idx (first (keep (fn [[idx song]] + (when (= song current-song) + idx)) + (:items next-playlist)))] + ;; we have to find out the index of the currently playing song after the + ;; playlist was created because it might change when shuffling / unshuffling + (set-current-song next-playlist next-idx))) + + (set-repeat-mode [playlist repeat-mode] + (assoc playlist :repeat-mode repeat-mode)) + + (enqueue-last [this song source] + (let [order (inc (key (last items)))] + ;; Arguably this is a bit weird; but if you want to play something last in + ;; a shuffled playlist, you want to play it last I guess. + (assoc-in this [:items order] + (vary-meta song assoc + :playlist/linear-order order + :playlist/source source)))) + (enqueue-last [this song] (enqueue-last this song nil)) + + (enqueue-next [this song source] + ;; we slice the songs up until the currently playing one and increase the + ;; order for all the songs after + (let [songs (vec (vals items)) + reordered (-> (subvec songs 0 (inc current-idx)) + (conj (vary-meta song assoc + :playlist/linear-order (inc current-idx) + :playlist/source source)) + (concat (subvec songs (inc current-idx))))] + (assoc this :items (->> (map-indexed vector reordered) + (into (sorted-map)))))) + (enqueue-next [this song] (enqueue-next this song nil)) + + (move-song [this from-idx to-idx] + ;; we have to decide whether we move all items in-between + ;; one up or one down; this depends on whether we move our + ;; item to the front or to the back + (let [shift-fn (cond + (< from-idx to-idx) inc + (> from-idx to-idx) dec) + start (min from-idx to-idx) + end (inc (max from-idx to-idx)) + steps (range start end) + result (update this :items + (fn [items] + (-> (reduce (fn [result idx] + (assoc result idx (get items (shift-fn idx)))) + items steps) + (assoc to-idx (get items from-idx)))))] + (cond + (= from-idx current-idx) (assoc result :current-idx to-idx) + (<= to-idx current-idx from-idx) (update result :current-idx inc) + (>= to-idx current-idx from-idx) (update result :current-idx dec) + :else result))) + + (remove-song [this song-idx] + (cond-> (update this :items #(let [n-items (count %)] + (-> (reduce (fn [items idx] + (assoc items idx (get items (inc idx)))) + % (range song-idx n-items)) + (dissoc (dec n-items))))) + (= song-idx current-idx) (assoc :current-idx -1)))) + +;; constructor wrapper + +(defn set-item-source + "Can be used to attach a source route to an item" + [item source] + (vary-meta item assoc :playlist/source source)) + +(defn item-source + "Retrieve the source of an item in the playlist" + [item] + (:playlist/source (meta item))) + +(defmulti ->playlist + "Creates a new playlist that behaves according to the given playback- and + repeat-mode parameters." + (fn [_ & {:keys [playback-mode]}] playback-mode)) + +(defmethod ->playlist :linear + [items & {:keys [playback-mode repeat-mode source]}] + (->Playlist (->> (map #(set-item-source % source) items) + (linear-queue)) + 0 playback-mode repeat-mode)) + +(defmethod ->playlist :shuffled + [items & {:keys [playback-mode repeat-mode source]}] + (->Playlist (->> (map #(set-item-source % source) items) + (shuffled-queue)) + 0 playback-mode repeat-mode)) diff --git a/src/cljs/airsonic_ui/components/about/views.cljs b/src/cljs/airsonic_ui/components/about/views.cljs new file mode 100644 index 0000000..334c7d6 --- /dev/null +++ b/src/cljs/airsonic_ui/components/about/views.cljs @@ -0,0 +1,25 @@ +(ns airsonic-ui.components.about.views) + +(defn- link + "Creates an external link" + [url label] + [:a {:href url, :target "_blank"} label]) + +(defn about [] + [:section.section>div.container.content + [:h1 "About"] + [:p "This is a frontend for " [link "https://airsonic.github.io/" "Airsonic"] ", a free and open source media server. You can think of Airsonic as a Spotify that you can run out of a shoebox in your bedroom, enabling you to listen to your own music wherever you are."] + [:h2 "Motivation"] + [:p "The current frontend of airsonic has been written quite a long time ago - eons on a web development timescale, where the clocks tick a bit different. While it has many features it has unfortunately aged noticeably. It does not work well on mobile and some features, such as sharing parts of your music library, require Adobe Flash, leaving them practically unusable and insecure."] + [:p "This fronted aims to provide a focused subset. Its focus for now is on playing and sharing music. Setting up the airsonic instance has to be done via the old interface, as does podcast management."] + [:h2 "Thank you"] + [:p "This web application is built upon the work of many others. A special thank you goes out to…"] + [:ul + [:li "The authors of " [link "https://github.com/facebook/react" "React"] ", " [link "https://github.com/reagent-project/reagent" "reagent"] " and " [link "https://github.com/Day8/re-frame" "re-frame"]] + [:li "Everybody who has contributed to " [link "https://github.com/jgthms/bulma" "Bulma"]] + [:li "Everyone involved in bringing " [link "https://clojure.org/" "Clojure and ClojureScript"] " into the world, also thheller for creating " [link "https://shadow-cljs.github.io/docs/UsersGuide.html" "shadow-cljs"]] + [:li "Of course, the people behind " [link "http://www.subsonic.org/pages/index.jsp" "Sub-"] ", " [link "https://github.com/Libresonic/libresonic" "Libre-"] " and " [link "https://airsonic.github.io/" "especially Airsonic"]] + [:li "Many others that have been creating tooling or libraries that I use in some way or another."]] + [:h2 "Contact"] + [:p "The airsonic community can be found on " [link "https://riot.im/app/#/room/#airsonic:matrix.org" "Matrix"] + " and IRC (#airsonic on freenode). There is also a " [link "https://www.reddit.com/r/airsonic/" "dedicated Subreddit"] ". If you think you found a bug in the frontend, it's probably a good idea to " [link "https://github.com/heyarne/airsonic-ui/issues" "report it on github"] ". I hope you have fun with the software! If you want to say thanks or have a use case that you feel could be covered, feel free to get in touch. Just know that everybody involved does this in their free time."]]) diff --git a/src/cljs/airsonic_ui/components/artist/views.cljs b/src/cljs/airsonic_ui/components/artist/views.cljs new file mode 100644 index 0000000..ca19ea2 --- /dev/null +++ b/src/cljs/airsonic_ui/components/artist/views.cljs @@ -0,0 +1,85 @@ +(ns airsonic-ui.components.artist.views + (:require [airsonic-ui.components.collection.views :as collection] + [airsonic-ui.components.library.views :as library] + [airsonic-ui.routes :as routes] + [clojure.string :as str])) + +(defn link-button [attrs children] + [:p.control>a.button.is-small (merge attrs {:target "_blank"}) children]) + +(defn lastfm-bio + "Displays the last.fm biography without the 'Read more on Last.fm' link" + [artist-info] + (when (:biography artist-info) + (let [biography (str/replace (:biography artist-info) #"$" "")] + [:p {:dangerouslySetInnerHTML {:__html biography}}]))) + +(defn lastfm-link [artist-info] + [link-button {:href (:lastFmUrl artist-info)} "See on last.fm"]) + +(defn musicbrainz-link [artist-info] + (let [href (str "https://musicbrainz.org/artist/" (:musicBrainzId artist-info))] + [link-button {:href href} "See on musicbrainz"])) + +(defn artist-links [artist-info] + (when-not (empty? (select-keys artist-info [:lastFmUrl :musicBrainzId])) + [:div.field.is-grouped + (when (:lastFmUrl artist-info) + [lastfm-link artist-info]) + (when (:musicBrainzId artist-info) + [musicbrainz-link artist-info])])) + +(defn similar-artists + "Given an artist-info response will return a list of similar artists" + [{similar-artists :similarArtist}] + [:div.tags.are-medium.similar-artists + (for [{:keys [id name]} similar-artists] + ^{:key id} [:a.tag.is-link.is-light {:href (routes/url-for ::routes/artist.detail {:id id})} name])]) + +(defn detail + "Creates a nice artist page displaying the artist's name, bio (if available and + listing) their albums." + [{:keys [artist artist-info]}] + [:div + [:section.hero.is-small>div.hero-body>div.container + [:h1.title (:name artist)] + [:div.content + [lastfm-bio artist-info] + [artist-links artist-info]]] + [:section.section.is-small>div.container + [:h2.subtitle "Albums"] + [collection/listing (:album artist)]] + (when (:similarArtist artist-info) + [:section.section.is-small>div.container + [:h2.subtitle "Similar artists in your collection"] + [similar-artists artist-info]])]) + +(defn alphabetical-listing + [artists] + [:div.alphabetical-list + (for [group artists] + ^{:key (:name group)} + [:div.group + [:h1.subtitle.is-4 (:name group)] + [:ol.artist-links + (for [artist (:artist group)] + (let [href (routes/url-for ::routes/artist.detail (select-keys artist [:id]))] + ^{:key (:id artist)} [:li [:a {:href href} (:name artist)]]))]])]) + +(defn overview + "Displays the alphabetical listing of all artists along with some additional + information about the collection" + [current-route {:keys [artists]}] + (let [artists (:index artists) + ;; TODO: Calculations in views should be avoided + artists-count (count (mapcat :artist artists)) + album-count (->> (mapcat :artist artists) + (map :albumCount) + (reduce +))] + [:div + [library/tab-section current-route] + [:section.hero.single-line.is-small>div.hero-body + [:div.container + [:h1.title "Artists"] + [:p.subtitle.is-5.has-text-grey [:strong artists-count] " artists with " [:strong album-count] " albums"]]] + [:section.section>div.container [alphabetical-listing artists]]])) diff --git a/src/cljs/airsonic_ui/components/audio_player/events.cljs b/src/cljs/airsonic_ui/components/audio_player/events.cljs new file mode 100644 index 0000000..c476049 --- /dev/null +++ b/src/cljs/airsonic_ui/components/audio_player/events.cljs @@ -0,0 +1,113 @@ +(ns airsonic-ui.components.audio-player.events + (:require [re-frame.core :as rf] + [airsonic-ui.audio.playlist :as playlist] + [airsonic-ui.api.helpers :as api])) + +; sets up the db, starts to play a song and adds the rest to a playlist +(defn play-all-songs [{:keys [db] + :routes/keys [current-route]} [_ songs start-idx]] + (let [playlist (-> (playlist/->playlist songs :playback-mode :linear :repeat-mode :repeat-all :source current-route) + (playlist/set-current-song start-idx))] + {:audio/play (api/stream-url (:credentials db) (playlist/current-song playlist)) + :db (assoc-in db [:audio :current-playlist] playlist)})) + +(rf/reg-event-fx + :audio-player/play-all + [(rf/inject-cofx :routes/current-route)] + play-all-songs) + +(rf/reg-event-db + :audio-player/set-playback-mode + (fn [db [_ playback-mode]] + (update-in db [:audio :current-playlist] #(playlist/set-playback-mode % playback-mode)))) + +(rf/reg-event-db + :audio-player/set-repeat-mode + (fn [db [_ repeat-mode]] + (update-in db [:audio :current-playlist] #(playlist/set-repeat-mode % repeat-mode)))) + +(rf/reg-event-fx + :audio-player/next-song + (fn [{:keys [db]} _] + (let [db (update-in db [:audio :current-playlist] playlist/next-song) + next (playlist/current-song (get-in db [:audio :current-playlist]))] + {:db db + :audio/play (api/stream-url (:credentials db) next)}))) + +(rf/reg-event-fx + :audio-player/previous-song + (fn [{:keys [db]} _] + (let [db (update-in db [:audio :current-playlist] playlist/previous-song) + song (playlist/current-song (get-in db [:audio :current-playlist]))] + {:db db + :audio/play (api/stream-url (:credentials db) song)}))) + +(defn set-current-song [{:keys [db]} [_ idx]] + (let [db (update-in db [:audio :current-playlist] playlist/set-current-song idx) + song (playlist/current-song (get-in db [:audio :current-playlist]))] + {:db db + :audio/play (api/stream-url (:credentials db) song)})) + +(rf/reg-event-fx :audio-player/set-current-song set-current-song) + +(rf/reg-event-fx + :audio-player/enqueue-next + [(rf/inject-cofx :routes/current-route)] + (fn [{:keys [db] + :routes/keys [current-route]} [_ song]] + {:db (update-in db [:audio :current-playlist] #(playlist/enqueue-next % song current-route))})) + +(rf/reg-event-fx + :audio-player/enqueue-last + [(rf/inject-cofx :routes/current-route)] + (fn [{:keys [db] + :routes/keys [current-route]} [_ song]] + {:db (update-in db [:audio :current-playlist] #(playlist/enqueue-last % song current-route))})) + +(rf/reg-event-db + :audio-player/move-song + (fn [db [_ from-idx to-idx]] + (update-in db [:audio :current-playlist] #(playlist/move-song % from-idx to-idx)))) + +(rf/reg-event-fx + :audio-player/toggle-play-pause + (fn [_ _] + {:audio/toggle-play-pause nil})) + +(defn remove-song [{:keys [db]} [_ song-idx]] + (let [song-removed (update-in db [:audio :current-playlist] #(playlist/remove-song % song-idx))] + (cond-> {:db song-removed} + (nil? (playlist/current-song (get-in song-removed [:audio :current-playlist]))) + (assoc :audio/stop nil)))) + +(rf/reg-event-fx :audio-player/remove-song remove-song) + +(defn audio-update + "Reacts to audio events fired by the HTML5 audio player and plays the next + track if necessary." + [{:keys [db]} [_ status]] + (cond-> {:db (assoc-in db [:audio :playback-status] status)} + (:ended? status) (assoc :dispatch [:audio-player/next-song]))) + +(rf/reg-event-fx :audio/update audio-update) + +(rf/reg-event-fx + :audio-player/seek + (fn [{:keys [db]} [_ percentage]] + (let [duration (:duration (playlist/current-song (get-in db [:audio :current-playlist])))] + {:audio/seek [percentage duration]}))) + +(rf/reg-event-fx + :audio-player/set-volume + (fn [_ [_ percentage]] + {:audio/set-volume percentage})) + +(rf/reg-event-fx + :audio-player/increase-volume + (fn [_ _] + {:audio/increase-volume nil})) + +(rf/reg-event-fx + :audio-player/decrease-volume + (fn [_ _] + {:audio/decrease-volume nil})) diff --git a/src/cljs/airsonic_ui/components/audio_player/views.cljs b/src/cljs/airsonic_ui/components/audio_player/views.cljs new file mode 100644 index 0000000..8a35def --- /dev/null +++ b/src/cljs/airsonic_ui/components/audio_player/views.cljs @@ -0,0 +1,157 @@ +(ns airsonic-ui.components.audio-player.views + (:require [re-frame.core :refer [subscribe dispatch]] + [reagent.core :as r] + [airsonic-ui.routes :as routes] + [airsonic-ui.helpers :as h] + [airsonic-ui.views.cover :refer [cover]] + [bulma.icon :refer [icon]])) + +;; currently playing / coming next / audio controls... + +(defn seek + "Calculates the position of the click and sets current playback accordingly" + [ev] + (let [x-ratio (/ (.. ev -nativeEvent -layerX) + (.. ev -target -parentElement getBoundingClientRect -width))] + (dispatch [:audio-player/seek x-ratio]))) + +(defn- ratio->width [ratio] + (str (.toFixed (min 100 (* 100 ratio)) 2) "%")) + +(defn progress-bars [buffered-width played-width] + [:svg.progress-bars {:aria-hidden "true"} + [:svg.complete-song-bar + [:rect {:x 0, :y "50%", :width "100%", :height 1}]] + [:svg.buffered-part-bar + [:rect.click-dummy {:on-click seek + :x 0, :y 0, :width buffered-width, :height "100%"}] + [:rect {:x 0, :y "50%", :width buffered-width, :height 1}]] + [:svg.played-back-bar + [:rect {:x 0, :y "50%", :width played-width, :height 1}] + [:circle {:cx played-width, :cy "50%", :r 2.5}]]]) + +(defn progress-indicators [song status] + (let [current-time (:current-time status) + buffered (:buffered status) + duration (:duration song) + progress-text (str (h/format-duration current-time :brief? true) + " / " + (h/format-duration duration :brief? true)) + buffered-width (ratio->width (/ buffered duration)) + played-width (ratio->width (/ current-time duration))] + [:article.progress-indicators + [progress-bars buffered-width played-width] + [:div.progress-info-text.duration-text progress-text]])) + +(defn playback-info [song status] + [:a.playback-info.media + {:href (routes/url-for ::routes/current-queue) + :title "Go to current queue"} + [:div.media-left [cover song 64]] + [:div.media-content + [:div.artist-and-title + [:span.artist(:artist song)] + [:span.song-title (:title song)]]]]) + +(defn playback-controls [is-playing?] + [:div.button-controls.playback-controls + [:div.field.has-addons + (let [buttons [[:media-step-backward :audio-player/previous-song] + [(if is-playing? :media-pause :media-play) :audio-player/toggle-play-pause] + [:media-step-forward :audio-player/next-song]] + title {:media-step-backward "Previous" + :media-play "Play" + :media-pause "Pause" + :media-step-forward "Next"}] + (for [[icon-glyph event] buttons] + ^{:key icon-glyph} [:p.control [:button.button.is-light + {:on-click (h/muted-dispatch [event]) + :title (title icon-glyph)} + [icon icon-glyph]]]))]]) + +(defn- toggle-shuffle [playback-mode] + (h/muted-dispatch [:audio-player/set-playback-mode (if (= playback-mode :shuffled) + :linear :shuffled)])) + +(defn- toggle-repeat-mode [current-mode] + (let [modes (cycle '(:repeat-none :repeat-all :repeat-single)) + next-mode (->> (drop-while (partial not= current-mode) modes) + (second))] + (h/muted-dispatch [:audio-player/set-repeat-mode next-mode]))) + +(defn set-volume [ev] + (when (= 1 (.-buttons ev)) ;; only on left-click + (let [y-ratio (/ (.. ev -nativeEvent -offsetY) + (.. ev -target getBoundingClientRect -height))] + (dispatch [:audio-player/set-volume (- 1 y-ratio)])))) + +(defonce volume-slider-visible? (r/atom false)) + +(defn volume-slider [volume] + (let [y-pos (* (- 1 volume) 100)] + [:svg.volume-bar {:width "100%", :height "100%"} + ;; the translate(...) makes the 1px rects look smoother + [:g {:transform "translate(-0.5,0)"} + ;; background line + [:rect.inactive {:x "50%", :y 0, :width 1, :height "100%"}] + ;; below are the line and circle that show the current volume + [:rect.active {:x "50%", :y (str y-pos "%"), + :width 1, :height (str (- 100 y-pos) "%")}]] + [:circle.active {:cx "50%", :cy (str y-pos "%"), :r 3}] + [:rect.click-dummy {:x 0, :y 0, :width "100%", :height "100%" + :on-mouse-down set-volume + :on-mouse-up set-volume + :on-mouse-move set-volume}]])) + +(def toggle-volume-slider #(swap! volume-slider-visible? not)) +(def hide-volume-slider #(reset! volume-slider-visible? false)) + +(defn volume-controls [playback-status] + (let [volume (:volume playback-status) + volume-icon (cond + (> volume 0.66) :volume-high + (> volume 0.1) :volume-low + :else :volume-off)] + [:div.button-controls.volume-controls + (when @volume-slider-visible? + [:div.button-menu + [:div.button-menu-closer {:on-click hide-volume-slider}] + [volume-slider volume]]) + [:p.control>button.button.is-light + {:on-click toggle-volume-slider} + [icon volume-icon]]])) + +(defn playback-mode-controls [{:keys [repeat-mode playback-mode]}] + (let [button :p.control>button.button.is-light + shuffle-button (h/add-classes button (when (= playback-mode :shuffled) :is-primary)) + repeat-button (h/add-classes button (case repeat-mode + :repeat-single :is-info + :repeat-all :is-primary + nil)) + repeat-title (case repeat-mode + :repeat-all "Repeating current queue, click to repeat current track" + :repeat-single "Repeating current track, click to repeat none" + "Click to repeat current queue")] + [:div.button-controls.playback-mode-controls + [:div.button-group>div.field.has-addons + ^{:key :shuffle-button} [shuffle-button {:on-click (toggle-shuffle playback-mode) + :title "Shuffle"} [icon :random]] + ^{:key :repeat-button} [repeat-button {:on-click (toggle-repeat-mode repeat-mode) + :title repeat-title} [icon :loop]]]])) + +(defn audio-player [] + (let [current-song @(subscribe [:audio/current-song]) + current-playlist @(subscribe [:audio/current-playlist]) + playback-status @(subscribe [:audio/playback-status]) + is-playing? @(subscribe [:audio/is-playing?])] + [:nav.audio-player + (if current-song + ;; show song info, controls, progress bar, etc. + [:section.audio-interaction + [playback-info current-song playback-status] + [progress-indicators current-song playback-status] + [playback-controls is-playing?] + [volume-controls playback-status] + [playback-mode-controls current-playlist]] + ;; not playing anything + [:p.navbar-item.idle-notification "No audio playing"])])) diff --git a/src/cljs/airsonic_ui/components/bangpow/views.cljs b/src/cljs/airsonic_ui/components/bangpow/views.cljs new file mode 100644 index 0000000..374e302 --- /dev/null +++ b/src/cljs/airsonic_ui/components/bangpow/views.cljs @@ -0,0 +1,10 @@ +(ns airsonic-ui.components.bangpow.views) + +(defn not-found [] + [:section.section>div.container.content + [:h1 "Oooops..."] + [:p "That should not have happened. There are multiple things that might have gone wrong:"] + [:ul + [:li "You clicked a wrong link. Maybe you copy and pasted it and missed something."] + [:li "It's a bug in the user interface. In that case: sorry! You can report it " [:a {:href "https://github.com/heyarne/airsonic-ui/issues" + :target "_blank"} "on github"]"."]]]) diff --git a/src/cljs/airsonic_ui/components/collection/views.cljs b/src/cljs/airsonic_ui/components/collection/views.cljs new file mode 100644 index 0000000..18d98aa --- /dev/null +++ b/src/cljs/airsonic_ui/components/collection/views.cljs @@ -0,0 +1,101 @@ +(ns airsonic-ui.components.collection.views + "A collection is a list of audio files that belong together (e.g. an album or + a podcast's overview)" + (:require [re-frame.core :refer [subscribe]] + [bulma.icon :refer [icon]] + [bulma.dropdown.views :refer [dropdown]] + [airsonic-ui.helpers :as h] + [airsonic-ui.routes :as routes] + [airsonic-ui.views.cover :refer [cover card]])) + +(defn collection-info [{:keys [songCount duration year]}] + (vec (cond-> [:ul.is-smaller.collection-info + [:li [icon :audio-spectrum] (str songCount (if (= 1 songCount) + " track" " tracks"))] + [:li [icon :clock] (h/format-duration duration)]] + year (conj [:li [icon :calendar] (str "Released in " year)])))) + +;; TODO: Maybe this view belongs somewhere else? +;; Something like a collection-grid component? + +(defn album-card + "A single element in a grid of albums. Shows the cover, artist and album name." + [{:keys [artist artistId name id] :as album}] + [card album + :url-fn #(routes/url-for ::routes/album.detail {:id id}) + :content [:div + ;; link to album + [:div.title.is-5 + [:a {:href (routes/url-for ::routes/album.detail {:id id}) + :title name} name]] + ;; link to artist page + [:div.subtitle.is-6 [:a {:href (routes/url-for ::routes/artist.detail {:id artistId}) + :title artist} artist]]]]) + +(defn listing [albums] + ;; always show 5 in a row + [:div.columns.is-multiline.is-mobile + (for [[idx album] (map-indexed vector albums)] + ^{:key idx} [:div.column.is-one-fifth-desktop.is-one-quarter-tablet.is-half-mobile + [album-card album]])]) + +;; TODO: Avoid duplication +(defn artist-link [{id :artistId, artist :artist}] + (if id + [:a {:href (routes/url-for ::routes/artist.detail {:id id})} artist] + artist)) + +(defn song-link [{:keys [songs song idx]}] + [:a + {:href "#" :on-click (h/muted-dispatch [:audio-player/play-all songs idx] :sync? true)} + (:title song)]) + +(defn song-actions [song] + [dropdown {:items [{:label "Play Next" :event [:audio-player/enqueue-next song]} + {:label "Play Last" :event [:audio-player/enqueue-last song]}]}]) + +(defn default-thead [] + [:thead>tr + [:td.is-narrow] + [:td.song-artist "Artist"] + [:td.song-title "Title"] + [:td.song-duration "Duration"] + [:td.is-narrow]]) + +(defn default-tbody [{:keys [songs current-song]}] + [:tbody + (for [[idx song] (map-indexed vector songs)] + ^{:key idx} + [(if (= (:id song) (:id current-song)) :tr.is-playing :tr) + [:td.song-tracknr.is-narrow (:track song)] + [:td.song-artist [artist-link song]] + [:td.song-title [song-link {:songs songs + :song song + :idx idx}]] + [:td.song-duration (h/format-duration (:duration song) :brief? true)] + [:td.song-actions.is-narrow [song-actions song]]])]) + +(defn song-table [{:keys [songs thead tbody] + :or {thead default-thead, tbody default-tbody}}] + ;; we subscribe here instead of one level higher up to make this a more + ;; reusable component; this way we can for example get a list of all songs + ;; in a search result and easily highlight the currently playing track + (let [current-song @(subscribe [:audio/current-song])] + [:table.song-listing-table.table.is-fullwidth + [thead] + [tbody {:songs songs, :current-song current-song}]])) + +(defn detail + "Shows a detail view of a single album, listing all " + [{:keys [album]}] + [:div + [:section.hero.is-small>div.hero-body + [:div.container + [:article.collection-header.media + [:div.media-left [cover album 128]] + [:div.media-content + [:h2.title (:name album)] + [:h3.subtitle (:artist album)] + [collection-info album]]]]] + [:section.section>div.container + [song-table {:songs (:song album)}]]]) diff --git a/src/cljs/airsonic_ui/components/current_queue/subs.cljs b/src/cljs/airsonic_ui/components/current_queue/subs.cljs new file mode 100644 index 0000000..d153aac --- /dev/null +++ b/src/cljs/airsonic_ui/components/current_queue/subs.cljs @@ -0,0 +1,15 @@ +(ns airsonic-ui.components.current-queue.subs + (:require [re-frame.core :as rf])) + +(defn queue-info [playlist] + {:count (count playlist) + :duration + (reduce (fn [acc [_ item]] + (+ acc (:duration item))) 0 (:items playlist))}) + +(println "registering the sub") + +(rf/reg-sub + :current-queue/info + :<- [:audio/current-playlist] + queue-info) diff --git a/src/cljs/airsonic_ui/components/current_queue/views.cljs b/src/cljs/airsonic_ui/components/current_queue/views.cljs new file mode 100644 index 0000000..9b52ed8 --- /dev/null +++ b/src/cljs/airsonic_ui/components/current_queue/views.cljs @@ -0,0 +1,107 @@ +(ns airsonic-ui.components.current-queue.views + (:require [re-frame.core :refer [subscribe dispatch-sync]] + [reagent.core :as r] + ["react-sortable-hoc" :refer [SortableHandle]] + [bulma.icon :refer [icon]] + [bulma.dropdown.views :refer [dropdown]] + [airsonic-ui.helpers :as helpers] + [airsonic-ui.audio.playlist :as playlist] + [airsonic-ui.components.collection.views :as collection] + [airsonic-ui.components.sortable.views :as sortable] + [airsonic-ui.routes :as routes] + + ;; ↓ registers subscription handlers ↓ + [airsonic-ui.components.current-queue.subs])) + +(def SortHandle + (SortableHandle. + ;; Alternative to r/reactify-component, which doens't convert props and hiccup, + ;; is to just provide fn as component and use as-element or create-element + ;; to return React elements from the component. + (fn [] + (r/as-element [:span.is-size-7.has-text-grey-lighter + [icon :elevator]])))) + +(defn song-actions [{:keys [song idx]}] + [dropdown {:items [{:label "Remove from queue" + :event [:audio-player/remove-song idx]} + {:label "Go to source" + :event [:routes/do-navigation (playlist/item-source song)]}]}]) + +(defn artist-link [{id :artistId, artist :artist}] + (if id + [:a {:href (routes/url-for ::routes/artist.detail {:id id})} artist] + artist)) + +(defn song-link [song idx] + [:a + {:href "#" + :on-click (helpers/muted-dispatch [:audio-player/set-current-song idx])} + (:title song)]) + +(defn song-table-head [] + [:thead>tr + [:td.is-narrow] + [:td.song-artist "Artist"] + [:td.song-title "Title"] + [:td.song-duration "Duration"] + [:td.song-actions.is-narrow]]) + +(defn song-table-sortable-tbdoy [{:keys [songs current-song-idx]}] + ;; we need this closure to pass in custom arguments (current-song-idx) + (fn [] + [sortable/sortable-component + {:items songs + :container [:tbody] + :helper-class "sortable-is-moving" + + :render-item + (fn [{[idx song] :value}] + [(if (= idx current-song-idx) :tr.is-playing :tr) + [:td.sortable-handle.is-narrow [:> SortHandle]] + [:td.song-artist [artist-link song]] + [:td.song-title [song-link song idx]] + [:td.song-duration (helpers/format-duration (:duration song) :brief? true)] + [:td.song-actions.is-narrow [song-actions {:song song + :idx idx}]]]) + + :on-sort-end + (fn [{:keys [old-idx new-idx]}] + ;; if we don't dispatch-sync, the UI sometimes places the row back and + ;; resorts it a litle later + (dispatch-sync [:audio-player/move-song old-idx new-idx]))}])) + +(defn song-table [{:keys [songs current-song-idx]}] + [collection/song-table + {:songs songs + :thead song-table-head + :tbody (song-table-sortable-tbdoy {:songs songs + :current-song-idx current-song-idx})}]) + +(defn queue-info [{:keys [playlist-info]}] + [:ul.is-smaller.collection-info + [:li [icon :audio-spectrum] (str (:count playlist-info) + (if (pos? (:count playlist-info)) + " tracks" + " track"))] + [:li [icon :clock] (helpers/format-duration (:duration playlist-info))]]) + +(defn playlist [props] + [:div + [queue-info props] + [song-table {:songs (get-in props [:current-playlist :items]) + :current-song-idx (get-in props [:current-playlist :current-idx])}]]) + +(defn empty-playlist [] + [:p "You are currently not playing anything. Use the search or go to your " + [:a {:href (routes/url-for ::routes/library)} "Library"] " to start playing some music."]) + +(defn current-queue [] + (let [current-playlist @(subscribe [:audio/current-playlist]) + playlist-info @(subscribe [:current-queue/info])] + [:section.section>div.container + [:h1.title "Current Queue"] + (if (empty? current-playlist) + [empty-playlist] + [playlist {:current-playlist current-playlist + :playlist-info playlist-info}])])) diff --git a/src/cljs/airsonic_ui/components/debug/views.cljs b/src/cljs/airsonic_ui/components/debug/views.cljs new file mode 100644 index 0000000..7a8702c --- /dev/null +++ b/src/cljs/airsonic_ui/components/debug/views.cljs @@ -0,0 +1,7 @@ +(ns airsonic-ui.components.debug.views + (:require [fipp.edn :refer [pprint]])) + +(defn debug + "Returns a nicely formatted debug view of any given data structure" + [data] + [:pre (with-out-str (pprint data))]) diff --git a/src/cljs/airsonic_ui/components/highres_canvas/views.cljs b/src/cljs/airsonic_ui/components/highres_canvas/views.cljs new file mode 100644 index 0000000..bf528b0 --- /dev/null +++ b/src/cljs/airsonic_ui/components/highres_canvas/views.cljs @@ -0,0 +1,33 @@ +(ns airsonic-ui.components.highres-canvas.views + "This module provides a reusable canvas component. You can provide a drawing + function via the `:draw` attribute which will be passed a 2d rendering + context. It will automatically be drawn in high resolution on retina displays." + (:require [reagent.core :as reagent])) + +(defn redraw [this] + (let [draw (:draw (reagent/props this)) + canvas (reagent/dom-node this) + width (.-clientWidth canvas) + height (.-clientHeight canvas) + ctx (.getContext canvas "2d") + pixel-ratio (.-devicePixelRatio js/window)] + (set! (. canvas -width) width) + (set! (. canvas -height) height) + (set! (.. canvas -style -width) (str width "px")) + (set! (.. canvas -style -height) (str height "px")) + ;; retina drawing code: + ;; set up dimensions, reset the transform matrix to the identity + ;; matrix and automatically scale up + (when (> pixel-ratio 1) + (set! (. canvas -width) (* pixel-ratio width)) + (set! (. canvas -height) (* pixel-ratio height)) + (.setTransform ctx 1 0 0 1 0 0) + (.scale ctx pixel-ratio pixel-ratio)) + (draw ctx))) + +(defn canvas [attrs & _] + (reagent/create-class + {:component-did-update redraw + :component-did-mount redraw + :render (fn render [] + [:canvas.highres-canvas (dissoc attrs :draw)])})) diff --git a/src/cljs/airsonic_ui/components/keyboard_shortcuts/config.cljs b/src/cljs/airsonic_ui/components/keyboard_shortcuts/config.cljs new file mode 100644 index 0000000..5204106 --- /dev/null +++ b/src/cljs/airsonic_ui/components/keyboard_shortcuts/config.cljs @@ -0,0 +1,25 @@ +(ns airsonic-ui.components.keyboard-shortcuts.config) + +;; this keymap has the following structure: +;; [[readable-key readable-description event-vector event-keys] +;; ...] + +(def keymap + [["Space" "Toggle play / pause" + [:audio-player/toggle-play-pause] + [{:keyCode 32}]] + ["←" "Previous song" + [:audio-player/previous-song] + [{:keyCode 37}]] + ["→" "Next song" + [:audio-player/next-song] + [{:keyCode 39}]] + ["+" "Increase volume" + [:audio-player/increase-volume] + [{:keyCode 171}]] + ["-" "Decrease volume" + [:audio-player/decrease-volume] + [{:keyCode 173}]] + ["?" "Show / hide keyboard shortcut help" + [:bulma.modal.events/toggle :keyboard-shortcuts-help] + [{:keyCode 63}]]]) diff --git a/src/cljs/airsonic_ui/components/keyboard_shortcuts/events.cljs b/src/cljs/airsonic_ui/components/keyboard_shortcuts/events.cljs new file mode 100644 index 0000000..e3997ee --- /dev/null +++ b/src/cljs/airsonic_ui/components/keyboard_shortcuts/events.cljs @@ -0,0 +1,13 @@ +(ns airsonic-ui.components.keyboard-shortcuts.events + (:require [re-frame.core :as rf] + [re-pressed.core :as rp] + [airsonic-ui.components.keyboard-shortcuts.config :as config])) + +(rf/reg-event-fx + ::init-shortcuts + (fn [] + (let [event-keys (map (juxt #(nth % 2) #(nth % 3)) config/keymap) + prevent-default-keys (mapcat last event-keys)] + {:dispatch-n [[::rp/add-keyboard-event-listener "keydown"] + [::rp/set-keydown-rules {:event-keys event-keys + :prevent-default-keys prevent-default-keys}]]}))) diff --git a/src/cljs/airsonic_ui/components/keyboard_shortcuts/views.cljs b/src/cljs/airsonic_ui/components/keyboard_shortcuts/views.cljs new file mode 100644 index 0000000..9d1d95a --- /dev/null +++ b/src/cljs/airsonic_ui/components/keyboard_shortcuts/views.cljs @@ -0,0 +1,12 @@ +(ns airsonic-ui.components.keyboard-shortcuts.views + (:require [bulma.modal.views :as bulma] + [airsonic-ui.components.keyboard-shortcuts.config :as config])) + +(defn help-modal [] + [bulma/modal-card {:title "Keyboard Shortcuts" + :modal-id :keyboard-shortcuts-help} + [:table.table.is-hoverable.is-fullwidth + [:thead [:tr [:th "Key"] [:th "Function"]]] + [:tbody + (for [[idx [k desc]] (map-indexed vector config/keymap)] + ^{:key idx} [:tr [:td>code k] [:td desc]])]]]) diff --git a/src/cljs/airsonic_ui/components/library/subs.cljs b/src/cljs/airsonic_ui/components/library/subs.cljs new file mode 100644 index 0000000..1e79854 --- /dev/null +++ b/src/cljs/airsonic_ui/components/library/subs.cljs @@ -0,0 +1,41 @@ +(ns airsonic-ui.components.library.subs + (:require [re-frame.core :as rf] + [airsonic-ui.config :as conf])) + +;; first some helper functions to make the structure a bit clearer + +(defn filter-response-kind + "Takes all library responses and returns only the ones matching a specific kind" + [kind responses] + (filter (fn [[[_ params] _]] + (= kind (:type params))) responses)) + +(defn partition-responses + "Returns a map of responses, where each response is neatly mapped to the page + it show on." + [kind responses] + (->> (filter-response-kind kind responses) + (sort-by (fn [[[_ params] _]] (:offset params))) + (mapcat (fn [[[_ params] {albums :album}]] + (let [start-page (/ (:offset params) conf/albums-per-page)] + (zipmap (drop start-page (range)) + (partition-all conf/albums-per-page albums))))) + (into (sorted-map)))) + +;; `complete-library` is the subscription that is actually exported + +(defn paginated-library + "Returns a sorted map that can be used to access the library content loaded + from the server. Each key represents a page and the associated value + represents the page's content." + [responses [_ kind]] + ;; note that we "humanize" the keys, meaning page 1 is the page with offset 0 + (->> (partition-responses kind responses) + (map (fn [[k v]] [(inc k) v])) + (into (sorted-map)))) + +(rf/reg-sub + :library/paginated + :<- [:api/responses-for-endpoint "getAlbumList2"] + paginated-library) + diff --git a/src/cljs/airsonic_ui/components/library/views.cljs b/src/cljs/airsonic_ui/components/library/views.cljs new file mode 100644 index 0000000..0be8593 --- /dev/null +++ b/src/cljs/airsonic_ui/components/library/views.cljs @@ -0,0 +1,95 @@ +(ns airsonic-ui.components.library.views + (:require [re-frame.core :refer [subscribe]] + [bulma.tabs :refer [tabs]] + [airsonic-ui.routes :as routes :refer [url-for]] + [airsonic-ui.components.collection.views :as collection])) + +;; this variable determines how many pages before the first known page we should list +(def page-padding 2) + +(defn pagination-link + "One of many numbered links to a page" + [current-page page href] + (let [current-page? (= page current-page)] + [(if current-page? + :a.pagination-link.is-current + :a.pagination-link) + (cond-> {:href href, :aria-label (str "Page " page)} + current-page? (assoc :aria-current "page")) page])) + +(defn pagination + "Builds a pagination, calling `url-fn` for every rendered page link with the + page as its argument. When `max-pages` is `nil` an infinite pagination + will be rendered." + [{:keys [items current-page url-fn]}] + ;; NOTE: This is currently slightly flawed. We don't have any good way to + ;; know whether we're on the last possible page so we take the last loaded + ;; page instead + (let [num-pages (last (keys items)) + first-page? (= current-page 1) + pages (range (max 1 (- current-page page-padding)) + (min (inc (+ current-page page-padding)) (inc num-pages)))] + [:nav.pagination.is-centered {:role "pagination", :aria-label "pagination"} + ;; now we add buttons to progress one page in each direction + [:a.pagination-previous (if first-page? + {:disabled true} + {:href (url-fn (dec current-page))}) "Previous page"] + [:a.pagination-next {:href (url-fn (inc current-page))} "Next page"] + ;; and here we modify the links around our current page + [:ul.pagination-list + ;; some indication that there are previous pages + (when (> current-page (+ page-padding 2)) + [:li [pagination-link current-page 1 (url-fn 1)]]) + (when (> current-page (+ page-padding 1)) + [:li>span.pagination-ellipsis "…"]) + ;; all pagination links around our current page + (for [page pages] + ^{:key page} [:li [pagination-link current-page page (url-fn page)]]) + ;; some indication that there are more pages after + (when (< current-page (- num-pages page-padding)) + [:li>span.pagination-ellipsis "…"]) + (when (< current-page (- num-pages page-padding)) + [:li [pagination-link current-page num-pages (url-fn num-pages)]])]])) + +(defn tab-items [[current-id current-params :as current-route]] + (->> + [[[::routes/library {:kind "recent"}] "Recently Played"] + [[::routes/library {:kind "newest"}] "Newest Additions"] + [[::routes/library {:kind "starred"}] "Starred"] + [[::routes/artist.overview] "Artists"]] + (map (fn [[[id params :as route] label]] + (cond-> {:href (apply routes/url-for route) + :label label} + (and (= id current-id) + (= (:kind params) (:kind current-params))) + (assoc :active? true)))))) + +(defn tab-section [current-route] + [:section.section.ui-tab-bar.is-small>div.container + [tabs {:items (tab-items current-route)}]]) + +(defn main + "Renders the pagination and shows a list of all albums with their cover art. + The first parameter is the route that's passed in, the second one is the + content that has been fetched for that route." + [[_ {:keys [kind]} {:keys [page] :or {page 1}} :as current-route] + {:keys [scan-status]}] + (println "scan-status" scan-status) + (let [library @(subscribe [:library/paginated kind]) + page (int page) + current-items (get library page) + url-fn #(url-for ::routes/library {:kind kind} {:page %}) + pagination-links [pagination {:current-page page + :items library + :url-fn url-fn}]] + [:div + [tab-section current-route] + [:section.hero.single-line.is-small>div.hero-body>div.container + [:h2.title "Your Library"] + (if (:count scan-status) + [:p.subtitle.is-5.has-text-grey [:strong (:count scan-status)] " items"] + (when (:scanning scan-status) + [:p.subtitle.is-5.has-text-grey "Scanning…"]))] + [:section.section.is-tiny>div.container pagination-links] + [:section.section.is-tiny>div.container [collection/listing current-items]] + [:section.section.is-tiny>div.container pagination-links]])) diff --git a/src/cljs/airsonic_ui/components/podcast/events.cljs b/src/cljs/airsonic_ui/components/podcast/events.cljs new file mode 100644 index 0000000..063d6b6 --- /dev/null +++ b/src/cljs/airsonic_ui/components/podcast/events.cljs @@ -0,0 +1,13 @@ +(ns airsonic-ui.components.podcast.events) + +(defn subscribe-to-channel + [db [_ channel-url]]) + +(defn delete-podcast-channel + [db [_ channel-id]]) + +(defn download-episode + [db [_ episode-id]]) + +(defn delete-episode + [db [_ episode-id]]) diff --git a/src/cljs/airsonic_ui/components/podcast/subs.cljs b/src/cljs/airsonic_ui/components/podcast/subs.cljs new file mode 100644 index 0000000..cb9f782 --- /dev/null +++ b/src/cljs/airsonic_ui/components/podcast/subs.cljs @@ -0,0 +1,52 @@ +(ns airsonic-ui.components.podcast.subs + (:require [re-frame.core :refer [reg-sub]])) + +;; this unwraps the api response into a collection +(reg-sub + ::podcast.response + :<- [:api/response-for "getPodcasts"] + (fn [response] + (:channel response))) + +(defn podcast-channels + "Given a podcast response, returns information about the channels that have + been subscribed to." + [response _] + (when response + (map #(dissoc % :episode) response))) + +(reg-sub + ::podcast.channels + :<- [::podcast.response] + podcast-channels) + +(defn sorted-podcast-episodes + "Given a response of all podcasts, returns all episodes sorted by a given function" + [response [_ key-fn & {:keys [n reverse?] + :or {n 15 + reverse? true}}]] + ;; some podcasts have an :artist and some don't, we make sure all of them have one + (let [id->channel (into {} (map (juxt :id :title) response))] + (let [sorted (->> (mapcat :episode response) + (map (fn [episode] + (assoc episode :artist (id->channel (:channelId episode))))) + (sort-by (or key-fn identity)))] + (take n (if reverse? (reverse sorted) sorted))))) + +(reg-sub + ::podcast.all-episodes-by + :<- [::podcast.response] + sorted-podcast-episodes) + +(defn podcast-detail + "Since there's no real detail request, this function provides some abstraction + for that in providing a lense to only the podcast with a specific channel-id." + [[response [_ params _]] _] + (let [channel-id (:id params)] + (first (filter #(= channel-id (:id %)) response)))) + +(reg-sub + ::podcast.detail-from-route + :<- [::podcast.response] + :<- [:routes/current-route] + podcast-detail) diff --git a/src/cljs/airsonic_ui/components/podcast/views.cljs b/src/cljs/airsonic_ui/components/podcast/views.cljs new file mode 100644 index 0000000..85b75da --- /dev/null +++ b/src/cljs/airsonic_ui/components/podcast/views.cljs @@ -0,0 +1,85 @@ +(ns airsonic-ui.components.podcast.views + (:require [re-frame.core :refer [subscribe]] + [airsonic-ui.helpers :refer [muted-dispatch]] + [airsonic-ui.routes :as routes :refer [url-for]] + [airsonic-ui.components.podcast.subs :as subs] + [airsonic-ui.views.cover :refer [cover card]] + [bulma.icon :refer [icon]] + [airsonic-ui.components.debug.views :refer [debug]])) + +;; TODO: Implement detail pages for podcasts +;; TODO: Implement CRUD frontend for podcasts +;; TODO: Error handling for channels and episodes + +(defn channel-card + "Displays the cover of a podcast and links to the podcasts detail page" + [channel] + [card channel + :url-fn #(url-for ::routes/podcast.detail {:id (:id channel)}) + :content [:div.title.is-5 + [:a {:href (url-for ::routes/podcast.detail {:id (:id channel)}) + :title (:title channel)} (:title channel)]]]) +(defn- channel-overview [channels] + [:div.columns.is-multiline.is-mobile + (for [[idx channel] (map-indexed vector channels)] + ^{:key idx} + [:div.column.is-one-fifth-desktop.is-one-quarter-tablet.is-half-mobile + [channel-card channel]])]) + +(defn- episode-actions [episode] + (case (:status episode) + "completed" + [[:td>a {:title "Play Next" + :href "#" + :on-click (muted-dispatch [:audio-player/enqueue-next episode])} + [icon :plus]] + [:td>a {:title "Play Last" + :href "#" + :on-click (muted-dispatch [:audio-player/enqueue-last episode])} + [icon :caret-right]]] + "skipped" ;; FIXME: Show download button + [[:td] [:td]])) + +(defn- episode-list [episodes] + [:table.table.is-striped.is-hoverable.is-fullwidth>tbody + (for [[idx episode] (map-indexed vector episodes)] + ^{:key idx} + (into + [:tr + [:td.grow [:span + [:a {:href (url-for ::routes/podcast.detail {:id (:channelId episode)})} + (:artist episode)] + " - " + [:a {:title (:title episode) + :href "#" + ;; the reason for :sync? true can be found here + ;; https://github.com/heyarne/airsonic-ui/issues/33 + :on-click (muted-dispatch [:audio-player/play-all episodes idx] :sync? true)} + (:title episode)]]]] + (episode-actions episode)))]) + +(defn detail + "Detail page for a single channel" + [_] + ;; NOTE: This isn't especially pretty, but it works. The detail page can only + ;; ever be displayed for the podcast the current route points to + (let [channel @(subscribe [::subs/podcast.detail-from-route])] + [:div + [:section.section>div.hero-body + [:div.container>article.media + [:div.media-left [cover channel 128]] + [:div.media-content + [:h2.title (:title channel)] + [:p (:description channel)]]]] + [:section.section>div.container [episode-list (:episode channel)]]])) + +(defn overview + "All channels and most recently published shows" + [_] + (let [channels @(subscribe [::subs/podcast.channels]) + episodes @(subscribe [::subs/podcast.all-episodes-by :created])] + [:section.section>div.container + [:h1.title "Subscriptions"] + [channel-overview channels] + [:h1.title "Latest Episodes"] + [episode-list episodes]])) diff --git a/src/cljs/airsonic_ui/components/search/events.cljs b/src/cljs/airsonic_ui/components/search/events.cljs new file mode 100644 index 0000000..1e5fac7 --- /dev/null +++ b/src/cljs/airsonic_ui/components/search/events.cljs @@ -0,0 +1,15 @@ +(ns airsonic-ui.components.search.events + (:require [re-frame.core :refer [reg-event-fx reg-event-db]] + [airsonic-ui.routes :as routes])) + +(reg-event-db + ;; this is called on navigation and handled in routes.cljs; the reason is that + ;; when we're navigating to search?query=foo we don't have the term in our db. + :search/restore-term-from-param + (fn [db [_ term]] + (assoc-in db [:search :term] term))) + +(reg-event-fx + :search/do-search + (fn do-search [fx [_ term]] + {:dispatch [:routes/do-navigation [::routes/search {} {:query term}]]})) diff --git a/src/cljs/airsonic_ui/components/search/subs.cljs b/src/cljs/airsonic_ui/components/search/subs.cljs new file mode 100644 index 0000000..0c1293f --- /dev/null +++ b/src/cljs/airsonic_ui/components/search/subs.cljs @@ -0,0 +1,5 @@ +(ns airsonic-ui.components.search.subs + (:require [re-frame.core :refer [reg-sub subscribe]])) + +(reg-sub :search/current-term (fn current-term [db _] + (get-in db [:search :term]))) diff --git a/src/cljs/airsonic_ui/components/search/views.cljs b/src/cljs/airsonic_ui/components/search/views.cljs new file mode 100644 index 0000000..4fb1d70 --- /dev/null +++ b/src/cljs/airsonic_ui/components/search/views.cljs @@ -0,0 +1,94 @@ +(ns airsonic-ui.components.search.views + (:require [re-frame.core :refer [dispatch subscribe]] + [goog.functions :refer [debounce]] + [airsonic-ui.routes :as routes :refer [url-for]] + [airsonic-ui.helpers :as h] + [airsonic-ui.components.collection.views :as collection] + [airsonic-ui.views.cover :refer [card]])) + +(def search + (debounce #(dispatch [:search/do-search (.. % -target -value)]) 100)) + +(defn form [] + (let [search-term @(subscribe [:search/current-term])] + (fn [] + [:form {:on-submit #(.preventDefault %)} + [:div.feld>p.control + [:input.input {:on-change (fn [e] + ;; the event might be gone when we the dispatched + ;; function is fired, we need to persist it + (.persist e) + (search e)) + :default-value search-term + :placeholder "Search"}]]]))) + +(defn result-cards [items] + [:div.columns.is-multiline.is-mobile + (for [[url item] items] + ^{:key url} [:div.column.is-one-fifth-tablet.is-one-third-mobile + [card item + :url-fn (constantly url) + :content [:div>a + {:href url, :title (:name item)} + (:name item)]]])]) + +(defn- artist-url [artist] + (url-for ::routes/artist.detail (select-keys artist [:id]))) + +(defn artist-results [{:keys [artist]}] + [result-cards (map (juxt artist-url identity) artist)]) + +(defn- album-url [album] + (url-for ::routes/album.detail (select-keys album [:id]))) + +(defn album-results [{:keys [album]}] + [result-cards (map (juxt album-url identity) album)]) + +(defn song-table-thead [] + [:thead + [:td.song-artist "Artist"] + [:td.song-album "Album"] + [:td.song-title "Title"] + [:td.song-duration "Duration"] + [:td.song-actions.is-narrow]]) + +(defn album-link [{id :albumId :as song}] + [:a {:href (routes/url-for ::routes/album.detail {:id id})} (:album song)]) + +(defn song-table-tbody [{:keys [songs current-song]}] + [:tbody + (for [[idx song] (map-indexed vector songs)] + ^{:key idx} + [(if (= (:id song) (:id current-song)) :tr.is-playing :tr) + [:td.song-artist [collection/artist-link song]] + [:td.song-album [album-link song]] + [:td.song-title [collection/song-link {:songs songs + :song song + :idx idx}]] + [:td.song-duration (h/format-duration (:duration song) :brief? true)] + [:td.song-actions.is-narrow [collection/song-actions song]]])]) + +(defn song-results [{songs :song}] + [collection/song-table {:songs songs + :thead song-table-thead + :tbody song-table-tbody}]) + +(defn results [{:keys [search]}] + (let [term @(subscribe [:search/current-term])] + [:section.section>div.container + [:h2.title (str "Search results for \"" term "\"")] + (if (empty? search) + [:p "The server returned no results."] + [:div.content + (when-not (empty? (:artist search)) + [:section.section.is-small + [:h3.subtitle.is-5 "Artists"] + [artist-results search]]) + (when-not (empty? (:album search)) + [:section.section.is-small + [:h3.subtitle.is-5 "Albums"] + [album-results search]]) + (when-not (empty? (:song search)) + [:section.section.is-small + [:h3.subtitle.is-5 "Songs"] + [song-results search]])])])) diff --git a/src/cljs/airsonic_ui/components/sortable/views.cljs b/src/cljs/airsonic_ui/components/sortable/views.cljs new file mode 100644 index 0000000..0c19d4c --- /dev/null +++ b/src/cljs/airsonic_ui/components/sortable/views.cljs @@ -0,0 +1,98 @@ +(ns airsonic-ui.components.sortable.views + (:require [reagent.core :as r] + [clojure.string :as str] + ["react-sortable-hoc" :refer [SortableHandle SortableElement + SortableContainer]])) +;; this code is taken and adapted from https://github.com/reagent-project/reagent/blob/72c95257c13e5de1531e16d1a06da7686041d3f4/examples/react-sortable-hoc/src/example/core.cljs + +(defn make-wrapper [{:keys [container render-item]}] + (let [SortableItem (SortableElement. + (r/reactify-component render-item))] + (SortableContainer. + (r/reactify-component + (fn [{:keys [items]}] + (into container + (for [[idx value] (map-indexed vector items)] + (r/create-element + SortableItem + #js {:key (str "item-" idx) + :index idx + :value value})))))))) + +(defn style-map + "Returns a map representing all currently set css styles; this makes sense + so we can save a non-updating version of it." + [node] + (let [style (js/window.getComputedStyle node)] + (into {} (keep (fn [idx] + (let [property (.item style idx)] + [property (.getPropertyValue style property)])) + (range (.-length style)))))) + +(defn node-seq + "Returns a seq of all of a node's children" + [node] + (loop [waiting [node] + nodes []] + (if-let [node (first waiting)] + (if-let [children (array-seq (.-children node))] + (recur (concat (rest waiting) children) (conj nodes node)) + (recur (rest waiting) (conj nodes node))) + (rest nodes)))) + +(defn style-snapshot + "Recursively grabs the of all of a node's children" + [node] + (into [] (map style-map (node-seq node)))) + +(defn style-from-map! + "Restores the styling saved in a stylemap" + [style-map node] + (let [style (str/join ";" (map (fn [[k v]] (str k ": " v)) style-map))] + (.setAttribute node "style" style))) + +(defn restore-snapshot + "Recursively restores the styling of all of a nodes children" + [style-snapshot node] + (let [nodes (vec (node-seq node))] + (dotimes [i (count nodes)] + (style-from-map! (nth style-snapshot i) (nth nodes i))))) + +(defonce saved-snapshot (atom nil)) + +(defn sortable-component + "This function allows us to generate sortable components in a reusable way. + It takes a prop-map with several keys: + + - :container A hiccup-vector that will be used as the container + - :items A seq containing the values we want to render and sort + - :render-item Decides how we render each child; will be passed {:value value} + - :on-sort-end Will be called with a map containing :old-idx & :new-idx + - :helper-class Will be appended to the element that's sorted when it's + appended to the body" + [{:keys [container items render-item on-sort-end helper-class]}] + (let [Wrapper (make-wrapper {:container container + :render-item render-item})] + (r/create-element + Wrapper + #js {:items items + :helperClass helper-class + :axis "y" + :lockAxis "y" + + ;; save the style of all of the rows children + :updateBeforeSortStart + (fn [event] + (reset! saved-snapshot (style-snapshot (.-node event)))) + :onSortStart + (fn [_] + ;; the node we get passed as parameter is the original node unfortunately + (restore-snapshot @saved-snapshot (js/document.querySelector "body > :last-child"))) + + ;; update the state to reflect the new order + :onSortEnd + (fn [event] + (on-sort-end {:old-idx (.-oldIndex event) + :new-idx (.-newIndex event)})) + + :useDragHandle true}))) diff --git a/src/cljs/airsonic_ui/config.cljs b/src/cljs/airsonic_ui/config.cljs new file mode 100644 index 0000000..0c86287 --- /dev/null +++ b/src/cljs/airsonic_ui/config.cljs @@ -0,0 +1,8 @@ +(ns airsonic-ui.config) + +(def debug? + ^boolean goog.DEBUG) + +;; how many covers are shown per page when browsing the library +(def albums-per-page 20) +(def albums-prefetch-factor 5) diff --git a/src/cljs/airsonic_ui/core.cljs b/src/cljs/airsonic_ui/core.cljs new file mode 100644 index 0000000..7584394 --- /dev/null +++ b/src/cljs/airsonic_ui/core.cljs @@ -0,0 +1,36 @@ +(ns airsonic-ui.core + (:require [reagent.dom :as rdom] + [re-frame.core :as rf] + ;; 3rd party effects / coeffects + [day8.re-frame.http-fx] + [akiroz.re-frame.storage :as storage] + + ;; our app; namespaces that are just required but not used register + ;; event handlers, effect handlers or subscriptions + [airsonic-ui.audio.core] + [airsonic-ui.api.events] + [airsonic-ui.api.subs] + [airsonic-ui.components.audio-player.events] + [airsonic-ui.components.keyboard-shortcuts.events :as keyboard] + [airsonic-ui.components.library.subs] + [airsonic-ui.components.search.events] + [airsonic-ui.components.search.subs] + [airsonic-ui.events :as events] + [airsonic-ui.views :as views] + [airsonic-ui.config :as config])) + +(defn dev-setup [] + (when config/debug? + (enable-console-print!) + (println "dev mode"))) + +(defn mount-root [] + (rf/clear-subscription-cache!) + (rdom/render [views/main-panel] (.getElementById js/document "app"))) + +(defn ^:export init [] + (storage/reg-co-fx! :airsonic-ui {:fx :store, :cofx :store}) + (rf/dispatch-sync [::events/initialize-app]) + (rf/dispatch [::keyboard/init-shortcuts]) + (dev-setup) + (mount-root)) diff --git a/src/cljs/airsonic_ui/db.cljs b/src/cljs/airsonic_ui/db.cljs new file mode 100644 index 0000000..26d54e0 --- /dev/null +++ b/src/cljs/airsonic_ui/db.cljs @@ -0,0 +1,4 @@ +(ns airsonic-ui.db) + +(def default-db + {:notifications (sorted-map)}) diff --git a/src/cljs/airsonic_ui/events.cljs b/src/cljs/airsonic_ui/events.cljs new file mode 100644 index 0000000..905b6e9 --- /dev/null +++ b/src/cljs/airsonic_ui/events.cljs @@ -0,0 +1,170 @@ +(ns airsonic-ui.events + (:require [re-frame.core :as rf] + [ajax.core :as ajax] + [airsonic-ui.routes :as routes] + [airsonic-ui.db :as db] + [airsonic-ui.api.helpers :as api])) + +(rf/reg-fx + ;; a simple effect to keep println statements out of our event handlers + :log + (fn [params] + (apply println params))) + +(defn noop + "An event handler that can be used for clarity; doesn't do anything, but might + give a name to an event" + [cofx _] cofx) + +;; --- +;; app boot flow +;; * restoring a previous session +;; * initializing the router +;; * sending out the appropriate requests +;; --- + +(defn initialize-app + [{{:keys [credentials]} :store} _] + (let [effects {:db db/default-db + :routes/start-routing nil}] + (if (not (empty? credentials)) + (assoc effects :dispatch [:credentials/verify credentials]) + effects))) + +(rf/reg-event-fx + ::initialize-app + [(rf/inject-cofx :store)] + initialize-app) + +(defn verify-credentials + "Initializes the whole authentication chain when we have locally stored + credentials that look plausible." + [_ [_ credentials]] + ;; TODO: spec this + (if (every? string? ((juxt :u :p :server) credentials)) + {:dispatch [:credentials/send-authentication-request credentials]})) + +(rf/reg-event-fx :credentials/verify verify-credentials) + +;; --- +;; auth logic +;; --- + +(defn user-login + "Gets called after the user clicked on the login button" + [{:keys [db]} [_ user pass server]] + (let [credentials {:u user, :p pass, :server server, :verified? false}] + {:db (assoc db :credentials credentials) + :dispatch [:credentials/send-authentication-request credentials]})) + +(rf/reg-event-fx :credentials/user-login user-login) + +(defn authentication-request + "Tries to authenticate a user by requesting info about the given user, saving + the credentials when the request was successful." + [cofx [_ credentials]] + {:http-xhrio {:method :get + :uri (api/url credentials "getUser" {:username (:u credentials)}) + :response-format (ajax/json-response-format {:keywords? true}) + :on-success [:credentials/authentication-response credentials] + :on-failure [:api.response/failed]}}) ; <- we don't need endpoint and params here because the response is not cached + +(rf/reg-event-fx :credentials/send-authentication-request authentication-request) + +(defn authentication-response + "Since we don't get real status codes, we have to look into the server's + response and see whether we actually sent the correct credentials" + [_ [_ credentials response]] + {:dispatch (if (api/is-error? response) + [:credentials/authentication-failure response] + [:credentials/authentication-success credentials response])}) + +(rf/reg-event-fx :credentials/authentication-response authentication-response) + +(defn authentication-failure + "Removes all stored credentials and displays potential api errors to the user" + [{:keys [db store]} [_ response]] + {:dispatch [:notification/show :error (api/error-msg (api/->exception response))] + :store (dissoc store :credentials) + :db (dissoc db :credentials)}) + +(rf/reg-event-fx :credentials/authentication-failure authentication-failure) + +(defn authentication-success + "Gets called after the server indicates that the credentials entered by a user + are correct (see `credentials-verification-request`)" + [{:keys [db]} [_ credentials auth-response]] + {:store {:credentials credentials} + :db (-> (assoc db :credentials (assoc credentials :verified? true)) + (assoc :user (api/unwrap-response auth-response))) + :dispatch [::logged-in]}) + +(rf/reg-event-fx :credentials/authentication-success authentication-success) + +(defn logged-in + [cofx _] + (let [redirect (or (get-in cofx [:routes/from-query-param :redirect]) + [::routes/library])] + {:dispatch [:routes/do-navigation redirect]})) + +(rf/reg-event-fx + ::logged-in + [(rf/inject-cofx :routes/from-query-param :redirect)] + logged-in) + +(defn logout + "Clears all credentials and redirects the user to the login page" + [cofx [_ & args]] + (let [args (apply hash-map args)] + {:dispatch [:routes/do-navigation (if-let [redirect (:redirect-to args)] + [::routes/login {} {:redirect (routes/encode-route redirect)}] + [::routes/login])] + :store nil + :db db/default-db + :audio/stop nil})) + +(rf/reg-event-fx ::logout logout) + +;; --- +;; routing +;; --- + +(rf/reg-event-fx + :routes/did-navigate + (fn [{:keys [db]} [_ route params query]] + {:db (assoc db :routes/current-route [route params query]) + :dispatch-n (routes/route-events route params query)})) + +(rf/reg-event-fx + :routes/unauthorized + [(rf/inject-cofx :routes/current-route)] + (fn [{:routes/keys [current-route]} _] + {:dispatch [::logout :redirect-to current-route]})) + +;; --- +;; user messages +;; --- + +(def notification-duration + {:info 2500 + :error 10000}) + +(defn show-notification + "Displays an informative message to the user" + [{:keys [db]} [_ level message]] + (let [id (.now js/performance) + ;; the level argument is optional; if it's not given, it defaults to :info + level' (if (nil? message) :info level) + message' (if (nil? message) level message)] + {:db (assoc-in db [:notifications id] {:level level' + :message message'}) + :dispatch-later [{:ms (get notification-duration level) + :dispatch [:notification/hide id]}]})) + +(rf/reg-event-fx :notification/show show-notification) + +(defn hide-notification + [db [_ notification-id]] + (update db :notifications dissoc notification-id)) + +(rf/reg-event-db :notification/hide hide-notification) diff --git a/src/cljs/airsonic_ui/helpers.cljs b/src/cljs/airsonic_ui/helpers.cljs new file mode 100644 index 0000000..58f14f6 --- /dev/null +++ b/src/cljs/airsonic_ui/helpers.cljs @@ -0,0 +1,49 @@ +(ns airsonic-ui.helpers + "Assorted helper functions" + (:require [re-frame.core :as rf] + [clojure.string :as str]) + (:import [goog.string format])) + +(defn muted-dispatch + "Dispatches a re-frame event while canceling default DOM behavior; to be + called for example in `:on-click`." + [ev & {:keys [sync?]}] + (fn [e] + (.preventDefault e) + (if sync? + (rf/dispatch-sync ev) + (rf/dispatch ev)))) + +(defn add-classes + "Adds one or more classes to a hiccup keyword" + [elem & classes] + (keyword (apply str (name elem) (->> (filter identity classes) + (map #(str "." (name %))))))) + +(defn kebabify + "Turns camelCased strings and keywords into kebab-cased keywords" + [x] + (-> (if (keyword? x) (name x) x) + (str/replace #"([a-z])([A-Z])" (fn [[_ a b]] (str a "-" b))) + (str/lower-case) + (keyword))) + +(defn- brief-duration [hours minutes seconds] + (str (when (> hours 0) + (format "%02d:" hours)) + (format "%02d:%02d" minutes seconds))) + +(defn- long-duration [hours minutes seconds] + (str/trim + (cond-> "" + (> hours 0) (str hours "h ") + (> minutes 0) (str minutes "m ") + (> seconds 0) (str seconds "s")))) + +(defn format-duration [seconds & {:keys [brief?]}] + (let [hours (Math/round (quot seconds 3600)) + minutes (Math/round (quot (rem seconds 3600) 60)) + seconds (Math/round (rem seconds 60))] + (if brief? + (brief-duration hours minutes seconds) + (long-duration hours minutes seconds)))) diff --git a/src/cljs/airsonic_ui/routes.cljs b/src/cljs/airsonic_ui/routes.cljs new file mode 100644 index 0000000..21b7722 --- /dev/null +++ b/src/cljs/airsonic_ui/routes.cljs @@ -0,0 +1,188 @@ +(ns airsonic-ui.routes + (:require [bide.core :as r] + [cljs.reader :refer [read-string]] + [re-frame.core :as rf] + [airsonic-ui.config :as conf])) + +(def default-route ::login) + +(defonce router + (r/router [["/" ::login] + ["/library" ::library] + ["/library/:kind" ::library] + ["/artists" ::artist.overview] + ["/artists/:id" ::artist.detail] + ["/album/:id" ::album.detail] + ["/search" ::search] + ["/podcast" ::podcast.overview] + ["/podcast/:id" ::podcast.detail] + ["/current-queue" ::current-queue] + ["/about" ::about]])) + +;; use this in views to construct a url +(defn url-for + ([k] (url-for k {} nil)) + ([k params] (url-for k params nil)) + ([k params query] (str "#" (r/resolve router k params query)))) + +;; which routes need valid login credentials? +(def protected-routes + #{::library ::artist.overview ::artist.detail ::album.detail ::search + ::podcast.overview ::podcast.detail}) + +;; which data should be requested for which route? can either be a vector or a function returning a vector + +;; TODO: It's not so nice to have this all so close to the routing logic; +;; it would be nicer to abstract this away, so the components themselves +;; could tell what kind of events they expect + +(defmulti -route-events + "Returns the events that take care of correct data being fetched." + (fn [route-id & _] route-id)) + +(defmethod -route-events :default [route-id params query]) + +(defmethod -route-events ::library + [route-id {:keys [kind]} {:keys [page] :or {page 1}}] + (if kind + [[:api/request "getScanStatus"] + ;; we fetch more than just the albums needed for the current page so we can + ;; page through it faster + [:api/request "getAlbumList2" {:type kind + :size (* conf/albums-prefetch-factor conf/albums-per-page) + :offset (* (dec (int page)) conf/albums-per-page)}]] + [:routes/do-navigation [route-id {:kind "recent"} {:page 1}]])) + +(defmethod -route-events ::artist.overview + [route-id params query] + [:api/request "getArtists"]) + +(defmethod -route-events ::artist.detail + [route-id params query] + (let [params (select-keys params [:id])] + [[:api/request "getArtist" params] + [:api/request "getArtistInfo2" params]])) + +(defmethod -route-events ::album.detail + [route-id params query] + [:api/request "getAlbum" (select-keys params [:id])]) + +(defmethod -route-events ::search + [route-id params query] + [[:search/restore-term-from-param (:query query)] + [:api/request "search3" query]]) + +(defmethod -route-events ::podcast.overview + [route-id params query] + [[:api/request "getPodcasts"]]) + +(defmethod -route-events ::podcast.detail + [route-id params query] + ;; this is identical to ::podcast.overview on purpose + [[:api/request "getPodcasts"]]) + +;; shouldn't need to change anything below + +(defn- n-events? + "Predicate that tells us whether a vector is suitable for :dispatch-n" + [ev-vec] + (or (vector? (first ev-vec)))) + +(defn route-events + "Returns a normalized list of event vectors for a given route." + [route-id params query] + (let [ev-vec (-route-events route-id params query)] + (if (n-events? ev-vec) ev-vec [ev-vec]))) + +;; subscription returning the matched route for the current hashbang + +(rf/reg-sub :routes/current-route (fn [db _] (:routes/current-route db))) + +;; NOTE: There is some duplication here. The route events are provided as a +;; subscription but they are also invoked directly in events.cljs. It didn't +;; seem to justify pulling in a whole library and we need it in our top most view + +(rf/reg-sub + :routes/events-for-current-route + (fn [db _] (rf/subscribe [:routes/current-route])) + (fn [current-route _] (apply route-events current-route))) + +;; these are helper effects we can use to navigate; the first two manage an atom +;; holding credentials, which is necessary to restrict certain routes, and the +;; last one is used for actual navigation + +;; the event to initialize navigation is implemented so the coeffect map is +;; returned unaltered, we just need access to the current app database for +;; authentication, which we get with an interceptor + +(defonce ^:private credentials (atom nil)) + +(def do-navigation + "An interceptor which performs the navigation after looking up current + credentials in the app database" + (re-frame.core/->interceptor + :id :routes/do-navigation + :after (fn do-navigation [context] + (let [[_ & [route]] (get-in context [:coeffects :event]) + ;; because :routes/do-navigation is both an event handler and + ;; an interceptor, we know that when handling the event (see + ;; below) the credentials aren't altered anymore + credentials' (get-in context [:coeffects :db :credentials])] + #_(println "calling do-navigation with" route credentials') + (reset! credentials credentials') + (apply r/navigate! router route) + (dissoc context :event))))) + +(rf/reg-event-fx :routes/do-navigation do-navigation (fn [& _] nil)) + +(defn can-access? [route] + (or (not (protected-routes route)) + (:verified? @credentials))) + +(defn on-navigate + [route-id params query] + #_(println "calling on-navigate with" route credentials') + (if (can-access? route-id) + (rf/dispatch [:routes/did-navigate route-id params query]) + (rf/dispatch [:routes/unauthorized route-id params query]))) + +(defn encode-route + "Takes a parsed route and returns a representation that's suitable for + transportation in a uri component" + [route] + (js/encodeURIComponent (str route))) + +(defn decode-route + "Decodes and encoded route from a uri component into a parsed route" + [encoded-route] + (read-string (js/decodeURIComponent encoded-route))) + +(defn current-route + "Returns the parsed route for window.location.hash" + [] + (r/match router (subs (.. js/window -location -hash) 1))) + +;; add the current route to our coeffect map +(rf/reg-cofx + :routes/current-route + (fn [coeffects _] + (assoc coeffects :routes/current-route (current-route)))) + +;; add route into from a URL parameter to our coeffect map +(rf/reg-cofx + :routes/from-query-param + (fn [coeffects param] + ;; this allows us to encode a complete route in a url fragment; useful for + ;; doing redirects + (let [[_ _ query] (current-route) + from-param (some-> (get query param) (decode-route))] + (assoc-in coeffects [:routes/from-query-param param] from-param)))) + +(defn start-routing! + "Initializes the router and makes sure the correct events get dispatched." + ([] (r/start! router {:default default-route + :on-navigate on-navigate})) + ([_] (start-routing!))) ;; <- 1-arity is for the re-frame effect exposed below + +(rf/reg-fx + :routes/start-routing start-routing!) diff --git a/src/cljs/airsonic_ui/subs.cljs b/src/cljs/airsonic_ui/subs.cljs new file mode 100644 index 0000000..27c30e0 --- /dev/null +++ b/src/cljs/airsonic_ui/subs.cljs @@ -0,0 +1,94 @@ +(ns airsonic-ui.subs + (:require [re-frame.core :refer [reg-sub subscribe]] + [airsonic-ui.api.helpers :as api] + [airsonic-ui.helpers :refer [kebabify]] + [clojure.string :as str])) + +;; +;; app initialization +;; + +;; TODO: Computation and extaction is mixed; this could be simpler + +(defn- error-notifications [notifications] + (filter (fn [[_ n]] + (= :error (:level n))) notifications)) + +(defn- no-errors? [db] + (empty? (error-notifications (:notifications db)))) + +(defn- no-route? [db] + (empty? (:routes/current-route db))) + +(defn- no-credentials? [db] + (and (not (empty? (:credentials db))) + (not (get-in db [:credentials :verified?])))) + +(defn is-booting? + "The boot process starts with setting up routing and continues if we found + previous credentials and ends when we receive a response from the server." + [db _] + ;; so either we don't have any credentials or they are not verified + (and (no-errors? db) (or (no-route? db) (no-credentials? db)))) + +(reg-sub ::is-booting? is-booting?) + +(defn credentials [db _] (:credentials db)) +(reg-sub ::credentials credentials) + +;; --- +;; user info and roles +;; --- + +(defn user-info + "Returns the response to getUser?username=$name; this isn't cached like the + other responses because it's not retrieved via :api/request" + [db _] + (:user db)) + +(reg-sub :user/info user-info) + +(defn user-roles + "Takes only the roles out of a getUser response to make it easier to work with" + [user-info _] + (->> + (filter (fn [[k _]] (re-find #"Role$" (name k))) user-info) + (keep (fn [[role has-role?]] + (when has-role? (str/replace (name role) #"Role$" "")))) + (map kebabify) + (set))) + +(reg-sub + :user/roles + :<- [:user/info] + user-roles) + +(defn user-role + "Can be used to determine whether a user is allowed to do certain things" + [user-roles [_ role]] + (or (user-roles role) (user-roles :admin))) + +(reg-sub + :user/role + :<- [:user/roles] + user-role) + +;; --- +;; misc +;; --- + +(defn cover-url + "Provides a convenient way for views to get cover images so they don't have + to build them themselves and can live a simple and happy life." + [credentials [_ song size]] + (api/cover-url credentials song size)) + +(reg-sub + ::cover-url + :<- [::credentials] + cover-url) + +;; user notifications + +(defn notifications [db _] (:notifications db)) +(reg-sub ::notifications notifications) diff --git a/src/cljs/airsonic_ui/views.cljs b/src/cljs/airsonic_ui/views.cljs new file mode 100644 index 0000000..386dc98 --- /dev/null +++ b/src/cljs/airsonic_ui/views.cljs @@ -0,0 +1,144 @@ +(ns airsonic-ui.views + "This module contains the outmost layer of our app views. It makes sure that + the proper subscriptions are run and arranges the complete layout." + (:require [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r] + [airsonic-ui.routes :as routes :refer [url-for]] + [airsonic-ui.events :as events] + [airsonic-ui.subs :as subs] + [airsonic-ui.helpers :refer [add-classes]] + + [airsonic-ui.views.notifications :refer [notification-list]] + [airsonic-ui.views.breadcrumbs :refer [breadcrumbs]] + [airsonic-ui.views.login :refer [login-form]] + [bulma.icon :refer [icon]] + + [airsonic-ui.components.about.views :refer [about]] + [airsonic-ui.components.artist.views :as artist] + [airsonic-ui.components.audio-player.views :refer [audio-player]] + [airsonic-ui.components.bangpow.views :refer [not-found]] + [airsonic-ui.components.collection.views :as collection] + [airsonic-ui.components.current-queue.views :refer [current-queue]] + [airsonic-ui.components.keyboard-shortcuts.views :as keyboard] + [airsonic-ui.components.library.views :as library] + [airsonic-ui.components.podcast.views :as podcast] + [airsonic-ui.components.search.views :as search])) + +(def logo-url "./img/airsonic-light-350x100.png") + +;; --- +;; top navigation +;; --- + +(defonce navbar-active? (r/atom false)) +(def toggle-navbar-active! #(swap! navbar-active? not)) + +(defn navbar-item [{:keys [href]} label] + [:a.navbar-item {:href href :on-click toggle-navbar-active!} label]) + +(defn navbar-dropdown + ([label items] (navbar-dropdown label {} items)) + ([label label-opts items] + [:div.navbar-item.has-dropdown.is-hoverable + [:div.navbar-link label-opts label] + [:div.navbar-dropdown + (for [[idx [opts label]] (map-indexed vector items)] + ^{:key (str "navbar-dropdown-" idx)} + [navbar-item + (merge {:on-click toggle-navbar-active!} opts) + label])]])) + +(defn navbar-top + "Contains search, some navigational links and the logo" + [] + (let [user @(subscribe [:user/info]) + stream-role @(subscribe [:user/roles :stream]) + podcast-role @(subscribe [:user/roles :podcast]) + playlist-role @(subscribe [:user/roles :playlist]) + share-role @(subscribe [:user/roles :share]) + settings-role @(subscribe [:user/roles :settings])] + [:nav.navbar.is-fixed-top.is-dark {:role "navigation", :aria-label "search and navigation"} + ;; user is `nil` when we're not logged in, we can hide the extended navigation + [:div.navbar-brand + [:div.navbar-item + [:a {:href (url-for ::routes/library)} [:img {:src logo-url}]] + [:div.navbar-burger.burger {:on-click toggle-navbar-active!} + [:span] + [:span] + [:span]]]] + (when user + [(if @navbar-active? :div.navbar-menu.is-active :div.navbar-menu) + [:div.navbar-start + [:div.navbar-item [search/form]]] + [:div.navbar-end + [:a.navbar-item {:href (url-for ::routes/current-queue) + :title "Current queue"} [:span.heart-beat [icon :audio-spectrum]]] + (when stream-role + [navbar-dropdown "Library" + [[{:href (url-for ::routes/library {:kind "recent"})} "Recently Played"] + [{:href (url-for ::routes/library {:kind "newest"})} "Newest Additions"] + [{:href (url-for ::routes/library {:kind "starred"})} "Starred"] + [{:href (url-for ::routes/artist.overview)} "Artists"]]]) + (when podcast-role + #_(let [podcast-url (url-for ::routes/podcast.overview)] + [navbar-dropdown "Podcast" {:href podcast-url} + [[{:href podcast-url} "Overview"]]])) + (when playlist-role + #_[navbar-item {} "Playlists"]) + (when share-role + #_[navbar-item {} "Shares"]) + [:div.navbar-item.has-dropdown.is-hoverable + [:div.navbar-link "More"] + [:div.navbar-dropdown.is-right + (when settings-role + #_[navbar-item {} "Settings"]) + [:a.navbar-item {:href (url-for ::routes/about)} "About"] + [:a.navbar-item + {:on-click (fn [_] + (toggle-navbar-active!) + (dispatch [::events/logout])) + :href "#"} + (str "Logout (" (:username user) ")")]]]]])])) + +;; --- +;; this is the section the user mainly interacts with +;; --- + +(defn media-content + "Provides the complete UI to browse the media library, interact with search + results etc" + [[route-id :as route]] + (let [content @(subscribe [:api/current-route-data])] + [:div + [:section.section + [breadcrumbs route content] + (case route-id + ::routes/library [library/main route content] + ::routes/artist.overview [artist/overview route content] + ::routes/artist.detail [artist/detail content] + ::routes/album.detail [collection/detail content] + ::routes/search [search/results content] + ::routes/podcast.overview [podcast/overview content] + ::routes/podcast.detail [podcast/detail content] + ::routes/current-queue [current-queue] + ::routes/about [about] + [not-found])] + [audio-player]])) + +(defn main-panel + "The outermost wrapper; handles display of the login form if necessary, + makes the code in media-content a bit easier to follow" + [] + (let [notifications @(subscribe [::subs/notifications]) + is-booting? @(subscribe [::subs/is-booting?]) + [route-id :as route] @(subscribe [:routes/current-route])] + [(add-classes :div route-id) + [notification-list notifications] + [keyboard/help-modal] + (if is-booting? + [:div.app-loading>div.loader] + [:div + [navbar-top] + (case route-id + ::routes/login [login-form] + [media-content route])])])) diff --git a/src/cljs/airsonic_ui/views/breadcrumbs.cljs b/src/cljs/airsonic_ui/views/breadcrumbs.cljs new file mode 100644 index 0000000..30bfbef --- /dev/null +++ b/src/cljs/airsonic_ui/views/breadcrumbs.cljs @@ -0,0 +1,65 @@ +(ns airsonic-ui.views.breadcrumbs + (:require [re-frame.core :refer [subscribe]] + [airsonic-ui.routes :as routes :refer [url-for]])) + +;; Breadcrumbs are implemented in such a way that they provide a stringent +;; hierarchy no matter how you came to the url. They should allow easy +;; navigation upwards that hierarchy (e.g. album -> artist) + +(defn- bulma-breadcrumbs [& items] + (let [content-pending? @(subscribe [:api/content-pending?])] + [:div.container + [:nav.breadcrumb {:aria-label "breadcrumbs"} + [:ul + (for [[idx [href label]] (map-indexed vector (butlast items))] + [:li {:key idx} [:a {:href href} label]]) + [:li.is-active>a (last items) + (when content-pending? [:span.loader])]]]])) + +(defmulti breadcrumbs + ;; the first parameter is always the current route, the second parameter is + ;; whatever the subscriptions return as the current content (e.g. album title) + (fn dispatch-on [[route-id] _] route-id)) + +(defmethod breadcrumbs :default [_ _] + [bulma-breadcrumbs "Airsonic"]) + +(defmethod breadcrumbs ::routes/library [[_ params] _] + [bulma-breadcrumbs + [(url-for ::routes/library {:kind "recent"}) "Library"] + (case (:kind params) + "recent" "Recently Played" + "newest" "Newest Additions" + "starred" "Starred" + "…")]) + +(defmethod breadcrumbs ::routes/artist.overview [_ _] + [bulma-breadcrumbs + [(url-for ::routes/library {:kind "recent"}) "Library"] + "Artists"]) + +(defmethod breadcrumbs ::routes/artist.detail [_ {:keys [artist]}] + [bulma-breadcrumbs + [(url-for ::routes/library {:kind "recent"}) "Library"] + [(url-for ::routes/artist.overview) "Artists"] + (:name artist)]) + +(defmethod breadcrumbs ::routes/album.detail [_ {:keys [album]}] + [bulma-breadcrumbs + [(url-for ::routes/library {:kind "recent"}) "Library"] + [(url-for ::routes/artist.overview) "Artists"] + [(url-for ::routes/artist.detail {:id (:artistId album)}) (:artist album)] + (:name album)]) + +(defmethod breadcrumbs ::routes/search [_ _] + [bulma-breadcrumbs "Search"]) + +(defmethod breadcrumbs ::routes/podcast.overview [_ _] + ;; TODO: Detail view + [bulma-breadcrumbs "Podcasts"]) + +(defmethod breadcrumbs ::routes/current-queue [_ _] + [bulma-breadcrumbs "Current Queue"]) + +(defmethod breadcrumbs ::routes/about [_ _] + [bulma-breadcrumbs "About"]) diff --git a/src/cljs/airsonic_ui/views/cover.cljs b/src/cljs/airsonic_ui/views/cover.cljs new file mode 100644 index 0000000..626fc01 --- /dev/null +++ b/src/cljs/airsonic_ui/views/cover.cljs @@ -0,0 +1,48 @@ +(ns airsonic-ui.views.cover + (:require [re-frame.core :refer [subscribe]] + [airsonic-ui.subs :as subs] + ["@hugojosefson/color-hash" :as ColorHash])) + +(def color-hash (ColorHash.)) + +(defn hsl->css [h s l] + (str "hsl(" h "," (* 100 s) "%," (* 100 l) "%)")) + +(defn palette + "Generate a unique hsl palette of two colors" + [identifier] + (let [[h s l] (js->clj (.hsl color-hash identifier))] + [(hsl->css h s l) + (hsl->css (mod (+ h (* h 0.3) 10) 360) s l)])) + +(defn missing-cover + [item size] + (let [identifier (str (:artistId item) "-" (or (:albumId item) (:id item))) + [color-a color-b] (palette identifier)] + [:svg.missing-cover {:viewBox "0 0 256 256" + :xmlns "http://www.w3.org/2000/svg"} + [:defs [:linearGradient {:id (str "cover-gradient-" identifier) + :x1 0, :y1 0, + :x2 1, :y2 1} + [:stop {:offset "2%", :stop-color color-a}] + [:stop {:offset "98%", :stop-color color-b}]]] + [:rect {:x 0, :y 0, :width 256, :height 256 + :fill (str "url(#cover-gradient-" identifier ")")}]])) + +(defn has-cover? [item] + (some? (:coverArt item))) + +(defn cover + [item size] + (let [original @(subscribe [::subs/cover-url item size]) + retina @(subscribe [::subs/cover-url item (* 2 size)])] + [:figure {:class (str "image is-" size "x" size)} + (if (has-cover? item) + [:img {:src original + :srcSet (str original ", " retina " 2x")}] + [missing-cover item size])])) + +(defn card [item & {:keys [url-fn content size] :or {size 256}}] + [:article.card.preview-card + [:div.card-image [:a {:href (url-fn item)} [cover item size]]] + [:div.card-content content]]) diff --git a/src/cljs/airsonic_ui/views/login.cljs b/src/cljs/airsonic_ui/views/login.cljs new file mode 100644 index 0000000..728bfe1 --- /dev/null +++ b/src/cljs/airsonic_ui/views/login.cljs @@ -0,0 +1,42 @@ +(ns airsonic-ui.views.login + (:require [reagent.core :as r] + [re-frame.core :refer [dispatch]] + [airsonic-ui.events :as events])) + +(defn- >reset! + "Sends an event's target values to the given atom" + [atom] + #(reset! atom (.. % -target -value))) + +;; login form + +(defn login-form [] + (let [user (r/atom "") + pass (r/atom "") + server (r/atom (.. js/window -location -origin)) + submit (fn [e] + (.preventDefault e) + (dispatch [:credentials/user-login @user @pass @server]))] + (fn [] + [:section.hero.is-fullheight>div.hero-body + [:div.container.has-text-centered>div.column.is-4.is-offset-4 + [:h3.title.has-text-grey "Airsonic"] + [:p.subtitle.has-text-grey "Please login to proceed"] + [:div.box + [:form {:on-submit submit} + [:div.field>div.control + [:input.input.is-large {:type "text" + :name "user" + :placeholder "Username" + :on-change (>reset! user)}]] + [:div.field>div.control + [:input.input.is-large {:type "password" + :name "pass" + :placeholder "Password" + :on-change (>reset! pass)}]] + [:div.field>div.control + [:input.input.is-large {:type "text" + :name "server" + :on-change (>reset! server) + :value @server}]] + [:button.button.is-block.is-info.is-large.is-fullwidth {:type "submit"} "Submit"]]]]]))) diff --git a/src/cljs/airsonic_ui/views/notifications.cljs b/src/cljs/airsonic_ui/views/notifications.cljs new file mode 100644 index 0000000..f094941 --- /dev/null +++ b/src/cljs/airsonic_ui/views/notifications.cljs @@ -0,0 +1,14 @@ +(ns airsonic-ui.views.notifications + (:require [re-frame.core :refer [dispatch]])) + +;; user notifications + +(defn notification-list [notifications] + [:div.notifications + (for [[id notification] notifications] + (let [class (case (:level notification) + :error "danger" + "info")] + ^{:key id} [:div {:class (str "notification is-small is-" class)} + [:button.delete {:on-click #(dispatch [:notification/hide id])}] + (:message notification)]))]) diff --git a/src/cljs/bulma/dropdown/events.cljs b/src/cljs/bulma/dropdown/events.cljs new file mode 100644 index 0000000..7b5f0aa --- /dev/null +++ b/src/cljs/bulma/dropdown/events.cljs @@ -0,0 +1,20 @@ +(ns bulma.dropdown.events + (:require [re-frame.core :as rf])) + +(defn show-dropdown [db [_ dropdown-id]] + (assoc-in db [:bulma :visible-dropdown] dropdown-id)) + +(rf/reg-event-db ::show show-dropdown) + +(defn hide-dropdown [db _] + (update db :bulma dissoc :visible-dropdown)) + +(rf/reg-event-db ::hide hide-dropdown) + +(defn toggle-dropdown [db [_ dropdown-id]] + (let [visible-dropdown (get-in db [:bulma :visible-dropdown])] + (if (= visible-dropdown dropdown-id) + (hide-dropdown db [::hide]) + (show-dropdown db [::show dropdown-id])))) + +(rf/reg-event-db ::toggle toggle-dropdown) diff --git a/src/cljs/bulma/dropdown/subs.cljs b/src/cljs/bulma/dropdown/subs.cljs new file mode 100644 index 0000000..cdeab23 --- /dev/null +++ b/src/cljs/bulma/dropdown/subs.cljs @@ -0,0 +1,22 @@ +(ns bulma.dropdown.subs + (:require [re-frame.core :as rf])) + +;; NOTE: This is almost the same as bulma.modal.subs +;; Maybe we can provide some abstraction that covers both, but maybe we shouldn't + +(defn visible-dropdown + "Gives us the ID of the currently visible dropdown" + [db _] + (get-in db [:bulma :visible-dropdown])) + +(rf/reg-sub ::visible-dropdown visible-dropdown) + +(defn visible? + "Predicate to check the visibility of a single modal" + [visible-dropdown [_ dropdown-id]] + (= visible-dropdown dropdown-id)) + +(rf/reg-sub + ::visible? + :<- [::visible-dropdown] + visible?) diff --git a/src/cljs/bulma/dropdown/views.cljs b/src/cljs/bulma/dropdown/views.cljs new file mode 100644 index 0000000..a697350 --- /dev/null +++ b/src/cljs/bulma/dropdown/views.cljs @@ -0,0 +1,43 @@ +(ns bulma.dropdown.views + (:require [re-frame.core :refer [dispatch subscribe]] + [reagent.core :as r] + [bulma.icon :refer [icon]] + [bulma.dropdown.events :as ev] + [bulma.dropdown.subs :as sub])) + +(defn choose-action [event-vector] + (fn [e] + (.preventDefault e) + (dispatch [::ev/hide]) + (dispatch event-vector))) + +(defn generate-id [] + (str "bulma-dropdown-" (random-uuid))) + +(defn click-overlay + [] + [:div {:style {:position "fixed" + :z-index 19 ;; <- 20 is the z-index of .dropdown-menu + :top 0 + :left 0 + :bottom 0 + :right 0} + :on-click #(dispatch [::ev/hide])}]) + +(defn dropdown [{:keys [items]}] + (let [dropdown-id (generate-id)] + (fn [] + (let [visible? @(subscribe [::sub/visible? dropdown-id])] + [(if visible? :div.dropdown.is-right.is-active :div.dropdown.is-right) + (when visible? [click-overlay]) + [:div.dropdown-trigger + [:span.is-small.button {:aria-haspopup "true" + :aria-controls dropdown-id + :on-click #(dispatch [::ev/toggle dropdown-id])} + [icon :ellipses]]] + [:div.dropdown-menu {:id dropdown-id, :role "menu"} + [:div.dropdown-content + (for [[idx {:keys [label event]}] (map-indexed vector items)] + ^{:key (str dropdown-id "-" idx)} + [:a.dropdown-item {:href "#" + :on-click (choose-action event)} label])]]])))) diff --git a/src/cljs/bulma/icon.cljs b/src/cljs/bulma/icon.cljs new file mode 100644 index 0000000..caec714 --- /dev/null +++ b/src/cljs/bulma/icon.cljs @@ -0,0 +1,4 @@ +(ns bulma.icon) + +(defn icon [glyph] + [:span.icon [:span.oi {:data-glyph (name glyph)}]]) diff --git a/src/cljs/bulma/modal/events.cljs b/src/cljs/bulma/modal/events.cljs new file mode 100644 index 0000000..15cc644 --- /dev/null +++ b/src/cljs/bulma/modal/events.cljs @@ -0,0 +1,20 @@ +(ns bulma.modal.events + (:require [re-frame.core :as rf])) + +(defn show-modal [db [_ modal-id]] + (assoc-in db [:bulma :visible-modal] modal-id)) + +(rf/reg-event-db ::show show-modal) + +(defn hide-modal [db _] + (update db :bulma dissoc :visible-modal)) + +(rf/reg-event-db ::hide hide-modal) + +(defn toggle-modal [db [_ modal-id]] + (let [visible-modal (get-in db [:bulma :visible-modal])] + (if (= visible-modal modal-id) + (hide-modal db [::hide]) + (show-modal db [::show modal-id])))) + +(rf/reg-event-db ::toggle toggle-modal) diff --git a/src/cljs/bulma/modal/subs.cljs b/src/cljs/bulma/modal/subs.cljs new file mode 100644 index 0000000..291f016 --- /dev/null +++ b/src/cljs/bulma/modal/subs.cljs @@ -0,0 +1,19 @@ +(ns bulma.modal.subs + (:require [re-frame.core :as rf])) + +(defn visible-modal + "Gives us the ID of the currently visible modal" + [db _] + (get-in db [:bulma :visible-modal])) + +(rf/reg-sub ::visible-modal visible-modal) + +(defn visible? + "Predicate to check the visibility of a single modal" + [visible-modal [_ modal-id]] + (= visible-modal modal-id)) + +(rf/reg-sub + ::visible? + :<- [::visible-modal] + visible?) diff --git a/src/cljs/bulma/modal/views.cljs b/src/cljs/bulma/modal/views.cljs new file mode 100644 index 0000000..107048c --- /dev/null +++ b/src/cljs/bulma/modal/views.cljs @@ -0,0 +1,47 @@ +(ns bulma.modal.views + (:require [re-frame.core :as rf] + [bulma.modal.events :as ev] + [bulma.modal.subs :as sub])) + +(defn hide-modal [_] + (rf/dispatch [::ev/hide])) + +(defn modal + "Generic modal; arguments: + + options: + {:has-hide-button? boolean + :modal-id :some-identifier} + + & children" + [{:keys [has-hide-button? modal-id]} & children] + {:pre [(some? modal-id)]} + (let [visible? @(rf/subscribe [::sub/visible? modal-id]) + modal-tag (if visible? :div.modal.is-active :div.modal)] + [modal-tag + [:div.modal-background {:on-click hide-modal}] + (into [:div.modal-content] children) + (when has-hide-button? + [:button.modal-hide.is-large {:aria-label "hide" + :on-click hide-modal}])])) + +(defn modal-card + "A card modal that renders content on a background. Arguments: + + options: + {:title \"Title of the card\" + :foot [[:div \"An array of hiccup elements\"]] + :modal-id :some-identifier} + + & children" + [{:keys [title foot modal-id]} & children] + [modal {:has-hide-button? (not (some? title)) + :modal-id modal-id} + (when title + [:div.modal-card-head + [:p.modal-card-title title] + [:button.delete {:aria-label "hide" + :on-click hide-modal}]]) + (into [:section.modal-card-body] children) + (when foot + (into [:div.modal-card-foot] foot))]) diff --git a/src/cljs/bulma/tabs.cljs b/src/cljs/bulma/tabs.cljs new file mode 100644 index 0000000..95f36f8 --- /dev/null +++ b/src/cljs/bulma/tabs.cljs @@ -0,0 +1,8 @@ +(ns bulma.tabs) + +(defn tabs [{:keys [items]}] + [:div.tabs.is-boxed + [:ul + (for [[idx {:keys [href label active?]}] (map-indexed vector items)] + ^{:key idx} [:li (when active? {:class "is-active"}) + [:a {:href href} label]])]]) diff --git a/src/sass/app.sass b/src/sass/app.sass new file mode 100644 index 0000000..ef7660c --- /dev/null +++ b/src/sass/app.sass @@ -0,0 +1,377 @@ +@import "../../node_modules/bulma/bulma" +@import "../../node_modules/open-iconic/font/css/open-iconic.scss" + +// area holding content & side navi +#app + main + margin-bottom: 0 + +// big loading spinner +.app-loading + display: flex + justify-content: center + align-items: center + height: 100vh + font-size: 4.8rem + color: $grey-light + .loader + +loader + +// small loading indicator at top of content +.breadcrumb + .loader + margin-left: .5em + +// bottom bar +.has-navbar-fixed-bottom + padding-bottom: 64px + +.audio-player + +navbar-fixed + bottom: 0 + + // first clear some of that navigation styling + background-color: $dark + color: $dark-invert + min-height: 64px + display: flex + align-items: center + + // now off to the contents + + // when no song is playing + .idle-notification + color: inherit + + // ... or with all the bells and whistles + .audio-interaction + display: flex + flex-grow: 1 + align-items: center + + .playback-info + // shows cover and current track + align-items: center + flex-grow: 1 + flex-basis: 25% + color: inherit + + .media-left + margin-right: .6rem + + .artist-and-title + margin-right: .6rem + + .artist, + .song-title + display: block + white-space: nowrap + width: 100% + max-width: 100% + overflow: hidden + text-overflow: ellipsis + + .progress-indicators + // hide progress bar on mobile + display: none + +tablet + display: flex + + flex-basis: 75% + height: 1rem + + .progress-info-text + color: $dark-invert + font-size: $size-7 + flex-shrink: 0 + flex-grow: 0 + + svg + overflow: visible + + .progress-bars + margin-left: .6rem + margin-right: .6rem + position: relative + flex-grow: 1 + + .complete-song-bar, + .buffered-part-bar, + .played-back-bar + height: 1rem + + .complete-song-bar + width: 100% + + rect + fill: rgb(93,93,93) + + .buffered-part-bar + rect + fill: rgb(143,143,143) + + .click-dummy + cursor: pointer + fill: transparent + + .played-back-bar + pointer-events: none + + circle, + rect + fill: $dark-invert + + // buttons to control current playback and playlist behavior + .button-controls + position: relative + flex-shrink: 0 + padding-right: .6rem + + &:first-of-type + padding-left: .6rem + + .button-menu + svg.volume-bar + overflow: visible + + .inactive + fill: $background + + .active + fill: $link + + .click-dummy + cursor: pointer + fill: transparent + +.button-menu-closer + // this element is needed so we can have a "click-outside" + position: fixed + z-index: -1 + top: 0 + left: 0 + right: 0 + bottom: 0 + +.button-menu + position: absolute + z-index: 100 + width: 36px + bottom: calc(100% + .3em) + padding: $button-padding-horizontal $button-padding-horizontal / 2 + + border-radius: $radius + background: $white + color: $dark + box-shadow: 0 0 2px rgba(0,0,0,.1), 0 0 4px rgba(0,0,0,.1) + + // little arrow at the bottom + &::after + position: absolute + content: '' + display: block + width: 6px + height: 6px + background: inherit + top: 100% + left: 50% + margin-left: -3px + margin-top: -3px + transform: rotate(45deg) + box-shadow: 2px 2px 1px rgba(0,0,0,.1) + +// preview card for album or artist listings +.preview-card + .card-content > div, + .title, + .subtitle + overflow: hidden + white-space: nowrap + text-overflow: ellipsis + + .image.is-256x256 + width: auto + height: auto + max-width: 256px + max-height: 256px + margin: 0 + +.image + .missing-cover + display: block + max-width: 100% + + &.is-48x48 .missing-cover + width: 48px + height: auto + + &.is-128x128 .missing-cover + width: 128px + height: auto + + &.is-256x256 .missing-cover + width: 256px + height: auto + +// occurs in album detail view +.table + .grow + width: 100% + +// useful in general to pull elements closer together; bulma es very generous +// with whitespace +.section + // $section-padding: 3rem 1.5rem + &.is-small + padding: 1.5rem 1.5rem + + &.is-tiny + padding: 0.75rem 1.5rem + + // tab bar on top + &.ui-tab-bar + padding-bottom: 0.75rem + +// occurs on many pages at the top to show details +.hero + &.is-small + .section + padding: 1.5rem 1.5rem + + &.is-tiny + .section + padding: 0.75rem 1.5rem + + .media-content + align-self: center + + // modifies our headlines to be next to each other + +tablet + &.single-line .container + display: flex + align-items: baseline + .title + flex-grow: 1 + margin-bottom: 0 + +// floating notifications +.notifications:not(:empty) + @extend .container + z-index: 100 + position: fixed + left: 0 + right: 0 + padding-top: 3.2rem + +// route specific styling +.search + .content .section + padding: 1.5rem 0 + + .preview-card + .card-content + padding: 0.375rem 0.75rem 0.75rem + + .missing-cover + display: inline-block + +.artist.overview + .alphabetical-list + column-count: 2 + column-gap: 1.2rem + + ol + list-style: none + + +tablet + column-count: 3 + +widescreen + column-count: 4 + + .group + margin-bottom: 1.5rem + .subtitle.is-4 + margin-bottom: 1rem + +.album.detail + .collection-header + display: block + + .media-left + margin-right: 0 + margin-bottom: 1rem + + +tablet + display: flex + + .media-left + margin-right: 1rem + margin-bottom: 0 + + .song-list + counter-reset: track + + tbody + tr + counter-increment: track + + td:first-child > div::before + color: $grey-light + content: counter(track) + font-weight: normal + display: inline + padding-right: 0.375rem + +.collection-info + list-style: none + + li + display: inline-block + margin-left: 0.75rem + + &:first-child + margin-left: 0 + +.song-listing-table + tr.is-playing + background-color: $table-row-active-background-color + color: $table-row-active-color + + a, strong, td.song-duration, td.sort-handle span + color: currentColor + + span.button, div.dropdown + color: $table-color + + td + &.is-narrow + white-space: nowrap + + &.song-duration + text-align: right + + &.sortable-handle + -webkit-touch-callout: none + user-select: none + + tbody .song-duration + color: $grey-light + + tr:hover + .button + +// drag'n'drop +.sortable-handle + span + cursor: grabbing + user-select: none + +tr.sortable-is-moving.is-playing + background-color: $table-row-active-background-color + color: $table-row-active-color + + a, strong, td.song-duration, td.sort-handle span + color: currentColor + +// Navigation fixes +.navbar-brand > .navbar-item > a + display: flex + align-items: center diff --git a/test/cljs/airsonic_ui/api/events_test.cljs b/test/cljs/airsonic_ui/api/events_test.cljs new file mode 100644 index 0000000..7b053fc --- /dev/null +++ b/test/cljs/airsonic_ui/api/events_test.cljs @@ -0,0 +1,50 @@ +(ns airsonic-ui.api.events-test + (:require [cljs.test :refer-macros [deftest testing is]] + [airsonic-ui.api.events :as events] + [airsonic-ui.fixtures :as fixtures])) + +(enable-console-print!) + +(deftest api-failure-notifcations + (testing "Should show an error notification when airsonic responds with an error" + (let [fx (events/api-success {} [:api.response/ok "ping" nil (:error fixtures/responses)]) + ev (:dispatch fx)] + (is (= :notification/show (first ev))) + (is (= :error (second ev)))))) + +(deftest cached-api-requests + (letfn [(cache [fx [endpoint params]] + (get-in fx [:db :api/responses [endpoint params]]))] + (testing "Should be cached" + (testing "when the response was successful" + (let [endpoint "getScanStatus" + successful (events/api-success {} [:api.response/ok endpoint nil (:ok fixtures/responses)]) + unsuccessful (events/api-success {} [:api.response/ok endpoint nil (:error fixtures/responses)])] + (is (map? (cache successful [endpoint]))) + (is (nil? (cache unsuccessful [endpoint]))))) + (testing "in an unwrapped format" + (let [endpoint "getScanStatus" + fx (events/api-success {} [:api.response/ok endpoint nil (:ok fixtures/responses)])] + (is (= #{:count :scanning} (set (keys (cache fx [endpoint])))))))) + (testing "When being issued" + (let [endpoint "getScanStatus" + fx (events/api-request {:db {:credentials (select-keys fixtures/credentials [:server])}} + [:api/request endpoint])] + (testing "should send an http request" + (is (contains? fx :http-xhrio))) + (testing "should indicate that a request is ongoing" + (is (true? (:api/is-loading? (cache fx [endpoint]))) "for non-cached responses") + (is (true? (-> (events/api-success fx [:api.response/ok endpoint nil (:ok fixtures/responses)]) + (events/api-request [:api/request endpoint]) + (cache [endpoint]) + :api/is-loading?)) "for cached responses")) + (testing "should remove the indication that a request is ongoing when there is a response" + (is (not (:api/is-loading? (-> (events/api-success fx [:api.response/ok endpoint nil (:ok fixtures/responses)]) + (cache [endpoint])))) "for a good response") + (is (not (:api/is-loading? (-> (merge fx (events/api-success fx [:api.response/ok endpoint nil (:error fixtures/responses)])) + (cache [endpoint])))) "when an error is returned") + (is (not (:api/is-loading? (-> (merge fx (events/api-failure fx [:api.response/failed endpoint])) + (cache [endpoint])))) "when communication with the server failed")))) + (testing "Should be able to avoid the cache" + ;; FIXME: Implement this + ))) diff --git a/test/cljs/airsonic_ui/api/helpers_test.cljs b/test/cljs/airsonic_ui/api/helpers_test.cljs new file mode 100644 index 0000000..53ea60f --- /dev/null +++ b/test/cljs/airsonic_ui/api/helpers_test.cljs @@ -0,0 +1,87 @@ +(ns airsonic-ui.api.helpers-test + (:require [cljs.test :refer [deftest testing is]] + [clojure.string :as str] + [airsonic-ui.fixtures :as fixtures :refer [responses]] + [airsonic-ui.api.helpers :as api])) + +(defn- url + "Construct a url with no params" + [server endpoint] + (api/url server endpoint {})) + +(def fixtures + {:default-url (url {:server "http://localhost:8080"} "ping")}) + +(deftest general-url-construction + (testing "Handles missing slashes" + (is (true? (str/starts-with? (url {:server "http://localhost:8080"} "ping") "http://localhost:8080/rest/ping"))) + (is (true? (str/starts-with? (url {:server "http://localhost:8080/"} "ping") "http://localhost:8080/rest/ping")))) + (testing "Should set correct default parameters" + (is (string? (re-find #"f=json" (fixtures :default-url)))) + (is (string? (re-find #"v=1\.15\.0" (fixtures :default-url)))))) + +(deftest parameter-encoding + (testing "Should escape url parameters" + (let [query "äöüß" + encoded-str (js/encodeURIComponent query)] + (is (str/includes? (api/url {:server "http://localhost"} "search3" {:query query}) encoded-str))))) + +(deftest variadic-parameters + (testing "Should append list-like parameters correctly" + (is (= (count (re-seq #"id=" (api/url {:server "http://localost"} "test" {:id []}))) 0)) + (is (= (count (re-seq #"id=" (api/url {:server "http://localost"} "test" {:id [1]}))) 1)) + (is (= (count (re-seq #"id=" (api/url {:server "http://localost"} "test" {:id (range 10)}))) 10))) + (testing "Should keep the non-lists" + (let [mixed (api/url {:server "http://localost"} "test" {:id (range 5) :foo "bar"})] + (is (some? (re-find #"u=user" (api/url {:server "http://localhost"} "test" {:u "user"})))) + (is (and (some? (re-find #"foo=bar" mixed)) + (= (count (re-seq #"id=" mixed)) 5)))))) + +(deftest stream-urls + (testing "Should construct the url based on a song's id" + (let [stream-url (api/stream-url {:server "http://localhost"} fixtures/song)] + (is (str/includes? stream-url (str "id=" (:id fixtures/song)))))) + (testing "Should also work for podcasts" + (let [stream-url (api/stream-url {:server "http://localhost"} fixtures/podcast-episode)] + (is (str/includes? stream-url (str "id=" (:streamId fixtures/podcast-episode))))))) + +(deftest cover-urls + (let [album {:coverArt "cover-99999"}] + (testing "Should construct the url based on an item's cover-id" + (is (true? (str/includes? (api/cover-url {:server "http://server.tld"} album -1) (str "id=" (:coverArt album)))))) + (testing "Should scale an image to a given size" + (is (true? (str/includes? (api/cover-url {:server "http://server.tld"} album 48) "size=48")))))) + +(deftest response-handling + (testing "Should unwrap responses" + (let [response (:ok responses)] + (is (= (get-in response [:subsonic-response :scanStatus]) + (api/unwrap-response response))))) + (testing "Should detect errors" + (is (true? (api/is-error? (:error responses)))) + (is (false? (api/is-error? (:ok responses))))) + (testing "Should throw an informative error when trying to unwrap an erroneous response" + (let [error-response (:error responses)] + (is (thrown? ExceptionInfo (api/unwrap-response error-response))) + (try + (api/unwrap-response error-response) + (catch ExceptionInfo e + (is (= (get-in error-response [:subsonic-response :error]) (ex-data e)))))))) + +(deftest error-recognition + (testing "Should detect error responses" + (is (true? (api/is-error? (:error responses)))) + (is (true? (api/is-error? (:auth-failure responses))))) + (testing "Should pass on good responses" + (is (false? (api/is-error? (:ok responses)))) + (is (false? (api/is-error? (:ping-success responses)))))) + +(deftest content-type + (testing "Should detect whether the data we look at represents a song" + (is (= :content-type/song (api/content-type fixtures/song)))) + (testing "Should detect whether the data we look at represents an artist" + (is (= :content-type/artist (api/content-type fixtures/artist))) + (is (= :content-type/artist (api/content-type (dissoc fixtures/artist :coverArt))))) + (testing "Should detect whether the data we look at represents an album" + (is (= :content-type/album (api/content-type fixtures/album))) + (is (= :content-type/album (api/content-type (dissoc fixtures/album :coverArt)))))) diff --git a/test/cljs/airsonic_ui/api/subs_test.cljs b/test/cljs/airsonic_ui/api/subs_test.cljs new file mode 100644 index 0000000..43399c8 --- /dev/null +++ b/test/cljs/airsonic_ui/api/subs_test.cljs @@ -0,0 +1,61 @@ +(ns airsonic-ui.api.subs-test + (:require [cljs.test :refer-macros [deftest testing is]] + [airsonic-ui.api.subs :as sub])) + +(enable-console-print!) + +(deftest single-response + (testing "Should return the response for a specified endpoint" + (let [responses (sub/responses {:api/responses {["search2" {:query "query term"}] :result}} [:api/responses])] + (is (= :result (sub/response-for responses [:api/response-for "search2" {:query "query term"}]))) + (is (nil? (sub/response-for responses [:api/response-for "search2" {:query "another query term"}])))))) + +(deftest responses-for-endpoint + (testing "Should concatenate all responses for an endpoint" + (let [responses {["search2" {:query "query term"}] :result1 + ["something-else" nil] :ignored-result + ["search2" {:query "another query term"}] :result2}] + (is (= (dissoc responses ["something-else" nil]) + (sub/responses-for-endpoint responses [:api/responses-for-endpoint "search2"])))))) + +(deftest endpoint-keywordification + (testing "Should strip prefixes" + (is (= :artist-info (sub/endpoint->kw "getArtistInfo"))) + (is (= :jukebox-control (sub/endpoint->kw "jukeboxControl")))) + (testing "Should strip trailing numbers" + (is (= :album-list (sub/endpoint->kw "getAlbumList2"))) + (is (= :search (sub/endpoint->kw "search3"))))) + +(def responses {["getAlbumList2" {:type "recent" :size 18}] + {:album [{:genre "foo", :artistId "12345"} + {:genre "electronic", :artistId "9999"}]} + + ["getArtistInfo" {:id "128"}] + {:biography "Interesting bio" + :largeImageUrl "https://lastfm-img2.akamaized.net/i/u/300x300/fb416b59cd694587aca0b2dec8f41198.png"}}) + +(deftest responses-for-route + (testing "Should return all cached responses for a route" + (let [current-route-events [[:api/request "getAlbumList2" {:type "recent", :size 18}] + [:event/should-be-ignored] + [:api/request "getArtistInfo" {:id "128"}]]] + (is (= {:album-list (get responses ["getAlbumList2" {:type "recent" :size 18}]) + :artist-info (get responses ["getArtistInfo" {:id "128"}])} + (sub/current-route-data [responses current-route-events] + [:api/current-route-data])))))) + +(deftest content-pending + (testing "Should indicate if there are outstanding requests for the current route" + (let [current-route-events [[:api/request "getAlbumList2" {:type "recent", :size 18}] + [:event/should-be-ignored] + [:api/request "getArtistInfo" {:id "128"}]] + done responses + in-progress (assoc-in responses + [["getAlbumList2" {:type "recent" :size 18}] :api/is-loading?] + true)] + (is (true? (-> (sub/current-route-data [in-progress current-route-events] + [:api/current-route-data]) + (sub/content-pending? [:api/content-pending?])))) + (is (not (true? (-> (sub/current-route-data [done current-route-events] + [:api/current-route-data]) + (sub/content-pending? [:api/content-pending?])))))))) diff --git a/test/cljs/airsonic_ui/audio/core_test.cljs b/test/cljs/airsonic_ui/audio/core_test.cljs new file mode 100644 index 0000000..99f72fd --- /dev/null +++ b/test/cljs/airsonic_ui/audio/core_test.cljs @@ -0,0 +1,26 @@ +(ns airsonic-ui.audio.core-test + (:require [airsonic-ui.audio.core :as audio] + #_[airsonic-ui.audio.playlist-test :as p] + #_[airsonic-ui.fixtures :as fixtures] + [cljs.test :refer [deftest testing is]])) + +(enable-console-print!) + +(deftest current-song-subscription + ;; NOTE: Should the subscription be moved to the playlist.cljs? + #_(testing "Should provide information about the song" + (letfn [(current-song [db] + (-> (audio/summary db [:audio/summary]) + (audio/current-song [:audio/current-song])))] + (= fixtures/song (current-song p/fixture)))) + (testing "Should work fine when no song is playing" + (is (nil? (audio/current-song nil [:audio/current-song]))))) + +(deftest playback-status-subscription + (letfn [(is-playing? [playback-status] + (audio/is-playing? playback-status [:audio/is-playing?]))] + (testing "Should be shown as not playing when the song is paused or has ended" + (is (not (is-playing? {:paused? true, :ended? false}))) + (is (not (is-playing? {:paused? false, :ended? true})))) + (testing "Should be shown as playing when the song is not paused or finished" + (is (is-playing? {:paused? false, :ended? false}))))) diff --git a/test/cljs/airsonic_ui/audio/playlist_test.cljs b/test/cljs/airsonic_ui/audio/playlist_test.cljs new file mode 100644 index 0000000..c640d63 --- /dev/null +++ b/test/cljs/airsonic_ui/audio/playlist_test.cljs @@ -0,0 +1,341 @@ +(ns airsonic-ui.audio.playlist-test + (:require [cljs.test :refer [deftest testing is]] + [airsonic-ui.audio.playlist :as playlist] + [airsonic-ui.fixtures :as fixtures] + [airsonic-ui.test-helpers :refer [song song-queue]] + #_[debux.cs.core :refer-macros [dbg]])) + +(enable-console-print!) + +(def fixture + {:audio {:current-song fixtures/song + :playlist (song-queue 20) + :playback-status fixtures/playback-status}}) + +(defn- same-song? [a b] (= (:id a) (:id b))) + +(deftest playlist-creation + (testing "Playlist creation" + (testing "should give us the correct current song for linear playback-mode" + (let [queue (song-queue 10)] + (doseq [repeat-mode [:repeat-none :repeat-single :repeat-all]] + (is (same-song? (first queue) + (-> (playlist/->playlist queue :playback-mode :linear :repeat-mode repeat-mode) + (playlist/current-song))) + (str "repeat-mode: " repeat-mode))))) + + (testing "any current song for shuffled playback mode" + (let [queue (song-queue 10)] + (doseq [repeat-mode [:repeat-none :repeat-single :repeat-all]] + (is (some? ((set queue) + (-> (playlist/->playlist queue :playback-mode :linear :repeat-mode repeat-mode) + (playlist/current-song)))) + (str "repeat-mode: " repeat-mode))))) + + (testing "should give us a playlist with the correct number of tracks" + (let [queue (song-queue 100)] + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-single :repeat-all]] + (is (= (count queue) + (count (playlist/->playlist queue :playback-mode playback-mode :repeat-mode repeat-mode))) + (str playback-mode ", " repeat-mode))))))) + +(deftest changing-playback-mode + (testing "Changing playback mode" + (testing "from linear to shuffled" + (let [queue (song-queue 10) + linear (playlist/->playlist queue :playback-mode :linear :repeat-mode :repeat-none) + shuffled (playlist/set-playback-mode linear :shuffled)] + (testing "should indicate the new playback mode" + (is (= :linear (:playback-mode linear))) + (is (= :shuffled (:playback-mode shuffled)))) + (testing "should re-order the tracks" + (is (not= (:items shuffled) (:items linear)))) + (testing "should not change the currently playing track" + (is (same-song? (playlist/current-song linear) (playlist/current-song shuffled)))) + (testing "should not change the repeat mode" + (is (= (:repeat-mode shuffled) (:repeat-mode linear)))))) + (testing "from shuffled to linear" + (let [queue (song-queue 10) + shuffled (playlist/->playlist queue :playback-mode :shuffled :repeat-mode :repeat-none) + linear (playlist/set-playback-mode shuffled :linear)] + (testing "should indicate the new playback mode" + (is (= :linear (:playback-mode linear))) + (is (= :shuffled (:playback-mode shuffled)))) + (testing "should set the correct order for tracks" + (let [linear-order (comp :playlist/linear-order meta)] + (is (every? #(apply same-song? %) (interleave queue (vals (:items linear))))) + ;; every song should have a smaller order than its successor + (is (->> (map linear-order (vals (:items linear))) + (partition 2 1) + (every? (fn [[a b]] (< a b))))))) + (testing "should not change the currently playing track" + (is (same-song? (playlist/current-song linear) (playlist/current-song shuffled)))) + (testing "should not change the repeat mode" + (is (= (:repeat-mode shuffled) (:repeat-mode linear)))))))) + +(deftest changing-repeat-mode + (testing "Changing the repeat mode" + (testing "should not change the playback mode" + (doseq [playback-mode '(:linear :shuffled) + repeat-mode '(:repeat-none :repeat-single :repeat-all) + next-repeat-mode '(:repeat-none :repeat-single :repeat-all)] + (let [playlist (-> (playlist/->playlist (song-queue 1) :playback-mode playback-mode :repeat-mode repeat-mode) + (playlist/set-repeat-mode next-repeat-mode))] + (is (= playback-mode (:playback-mode playlist))) + (is (= next-repeat-mode (:repeat-mode playlist)) + (str "from " repeat-mode " to " next-repeat-mode))))))) + +(deftest linear-next-song + (testing "Should follow the same order as the queue used for creation" + (doseq [repeat-mode [:repeat-none :repeat-all]] + (let [queue (song-queue 5) + playlist (playlist/->playlist queue :playback-mode :linear :repeat-mode repeat-mode)] + (is (same-song? (nth queue 1) (-> (playlist/next-song playlist) + (playlist/current-song))) + (str repeat-mode ", skipped once")) + (is (same-song? (nth queue 2) (-> (playlist/next-song playlist) + (playlist/next-song) + (playlist/current-song))) + (str repeat-mode ", skipped twice"))))) + ;; TODO: Write this test + (testing "Should go back to the first song when repeat-mode is all and we played the last song") + (testing "Should always give the same track when repeat-mode is single" + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :linear :repeat-mode :repeat-single) + played-back (map playlist/current-song (iterate playlist/next-song playlist))] + (is (same-song? (first queue) (nth played-back 0))) + (is (same-song? (first queue) (nth played-back 1))) + (is (same-song? (first queue) (nth played-back 2))) + (is (same-song? (first queue) (nth played-back 3)) "wrapping around"))) + (testing "Should stop playing at the end of the queue when repeat-mode is none" + (is (nil? (-> (song-queue 1) + (playlist/->playlist :playback-mode :linear :repeat-mode :repeat-none) + (playlist/next-song) + (playlist/current-song)))))) + +(deftest shuffled-next-song + (testing "Should play every track once when called for the entire queue" + (doseq [repeat-mode '(:repeat-none :repeat-all)] + (let [length 10 + playlist (playlist/->playlist (song-queue length) :playback-mode :shuffled :repeat-mode repeat-mode) + played-tracks (->> (iterate playlist/next-song playlist) + (map playlist/current-song) + (take length))] + (is (= (count played-tracks) (count (set played-tracks))) + (str repeat-mode))))) + (testing "Should keep the song order when wrapping around and repeat-mode is all" + (let [playlist (playlist/->playlist (song-queue 100) :playback-mode :shuffled :repeat-mode :repeat-all) + next-playlist (-> (playlist/set-current-song playlist 99) + (playlist/next-song))] + (= (playlist/current-song playlist) + (playlist/current-song next-playlist)))) + + (testing "Should always give the same track when repeat-mode is single" + (let [playlist (playlist/->playlist (song-queue 10) :playback-mode :shuffled :repeat-mode :repeat-single) + played-back (map playlist/current-song (iterate playlist/next-song playlist))] + (dotimes [i 3] + (is (same-song? (nth played-back i) (nth played-back (inc i))))))) + + (testing "Should stop playing at the end of the queue when repeat-mode is none" + (is (nil? (-> (song-queue 1) + (playlist/->playlist :playback-mode :linear :repeat-mode :repeat-none) + (playlist/next-song) + (playlist/current-song)))))) + +(deftest linear-previous-song + (testing "Should always give the same track when repeat-mode is single" + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :linear :repeat-mode :repeat-single) + played-back (map playlist/current-song (iterate playlist/next-song playlist))] + (is (same-song? (first queue) (nth played-back 0))) + (is (same-song? (first queue) (nth played-back 1))) + (is (same-song? (first queue) (nth played-back 2))) + (is (same-song? (first queue) (nth played-back 3)) "wrapping around"))) + (testing "Should keep the linear order when repeat-mode is not single" + (doseq [repeat-mode '(:repeat-none :repeat-all)] + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :linear :repeat-mode repeat-mode)] + (is (same-song? (nth queue 1) (-> (playlist/next-song playlist) + (playlist/next-song) + (playlist/previous-song) + (playlist/current-song))))))) + ;; TODO: Should it? + #_(testing "Should repeatedly give the first song when repeat-mode is none" + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :linear :repeat-mode :repeat-none)] + (is (same-song? (first queue) (-> (playlist/previous-song playlist) + (playlist/current-song)))))) + (testing "Should wrap around to last song when repeat-mode is all" + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :linear :repeat-mode :repeat-all)] + (is (same-song? (last queue) (-> (playlist/previous-song playlist) + (playlist/current-song))))))) + +(deftest shuffled-previous-song + (with-redefs [shuffle reverse] + (testing "Should always give the same track when repeat-mode is single" + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :shuffled :repeat-mode :repeat-single) + played-back (map playlist/current-song (iterate playlist/next-song playlist))] + (dotimes [i 3] + (is (same-song? (nth played-back i) (nth played-back (inc i))))))) + (testing "Should keep the playing order when repeat-mode is not single" + (doseq [repeat-mode '(:repeat-none :repeat-all)] + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :shuffled :repeat-mode repeat-mode)] + (is (same-song? (playlist/current-song playlist) + (-> playlist + (playlist/next-song) + (playlist/previous-song) + (playlist/current-song))) + (str "for repeat mode " repeat-mode)) + (is (same-song? (-> (playlist/next-song playlist) + (playlist/current-song)) + (-> (playlist/next-song playlist) + (playlist/next-song) + (playlist/previous-song) + (playlist/current-song))) + (str "for repeat mode " repeat-mode))))) + (testing "Should keep the song order when repeat-mode is all and we go back to before the first track" + (let [playlist (playlist/->playlist (song-queue 10) :playback-mode :shuffled :repeat-mode :repeat-all) + next-playlist (-> (playlist/previous-song playlist) + (playlist/set-current-song 0))] + (is (= (playlist/current-song playlist) + (playlist/current-song next-playlist))))))) + +(deftest set-current-song + (testing "Should correctly set the new song" + (doseq [repeat-mode [:repeat-all :repeat-none]] + (let [queue (song-queue 3) + playlist (playlist/->playlist queue :playback-mode :shuffled :repeat-mode repeat-mode) + next-track (-> (playlist/set-current-song playlist 1) + (playlist/current-song))] + (is (not (nil? next-track))) + (is (not (same-song? (playlist/current-song playlist) + next-track))))))) + +(deftest enqueue-last + (testing "Should make sure the song is played last" + (doseq [playback-mode '(:linear :shuffled) + repeat-mode '(:repeat-none :repeat-all)] + (let [length 5, queue (song-queue length) + playlist (with-redefs [shuffle identity] + (playlist/->playlist queue :playback-mode playback-mode :repeat-mode repeat-mode)) + played-back (->> (iterate playlist/next-song playlist) + (take (dec length)) + (map #(:id (playlist/current-song %))) + (set)) + to-enqueue (song) + playlist' (playlist/enqueue-last playlist to-enqueue)] + (is (nil? (played-back (-> (->> (iterate playlist/next-song playlist') + (map playlist/current-song)) + (nth length) + (:id)))) + (str "for " playback-mode ", " repeat-mode))))) + (testing "Should not change the order of the songs already in queue" + (doseq [playback-mode '(:linear :shuffled) + repeat-mode '(:repeat-none :repeat-all)] + (let [length 5, queue (song-queue length) + playlist (playlist/->playlist queue :playback-mode playback-mode :repeat-mode repeat-mode) + played-back-songs (fn played-back-songs [playlist] + (->> (iterate playlist/next-song playlist) + (take length) + (map playlist/current-song) + (map :playlist/order))) + played-back (played-back-songs playlist) + played-back' (played-back-songs (playlist/enqueue-last playlist (song)))] + (is (= played-back played-back') + (str "for " playback-mode ", " repeat-mode)))))) + +(deftest enqueue-next + (testing "Should play the song after the currently playing song" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all]] + (let [length 5, queue (song-queue length) + playlist (playlist/->playlist queue :playback-mode playback-mode :repeat-mode repeat-mode) + next-song (song)] + (is (same-song? next-song (-> (playlist/enqueue-next playlist next-song) + (playlist/next-song) + (playlist/current-song)))))))) + +(deftest move-track + (testing "Should correctly set the new order" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all :repeat-single]] + (let [n-songs 10 + queue (song-queue n-songs) + playlist (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode)] + (is (same-song? (-> (playlist/next-song playlist) + (playlist/next-song) + (playlist/current-song)) + (-> (playlist/move-song playlist 2 1) + (playlist/next-song) + (playlist/current-song))))))) + (testing "Should update the currently playing track's index" + (testing "when inserting a track before" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all :repeat-single]] + (let [n-songs 10 + queue (song-queue n-songs) + playlist (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode)] + (is (= 4 (-> (playlist/set-current-song playlist 3) + (playlist/move-song 5 3) + :current-idx)))))) + (testing "when moving a track behind it" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all :repeat-single]] + (let [n-songs 10 + queue (song-queue n-songs) + playlist (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode)] + (is (= 2 (-> (playlist/set-current-song playlist 3) + (playlist/move-song 2 5) + :current-idx)))))) + (testing "when moving it" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all :repeat-single]] + (let [n-songs 10 + queue (song-queue n-songs) + playlist (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode)] + (is (= 7 (-> (playlist/set-current-song playlist 3) + (playlist/move-song 3 7) + :current-idx)))))) + (testing "when the current track is outside of the modified range" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all :repeat-single]] + (let [n-songs 10 + queue (song-queue n-songs) + playlist (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode)] + (is (= 3 (-> (playlist/set-current-song playlist 3) + (playlist/move-song 4 7) + :current-idx)))))))) + +(deftest remove-song + (with-redefs [shuffle identity] + (testing "Should remove a single song from the playlist" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all :repeat-single]] + (let [n-songs 10 + queue (song-queue n-songs) + playlist (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode) + first-removed (playlist/remove-song playlist 0) + middle-removed (playlist/remove-song playlist 5) + last-removed (playlist/remove-song playlist 9) + song-not-in-list? (fn [song playlist] + (every? #(not (same-song? % song)) + (vals (:items playlist))))] + (is (= 9 (count first-removed) (count middle-removed) (count last-removed))) + (is (song-not-in-list? (first queue) first-removed)) + (is (same-song? (second queue) (get (:items first-removed) 0))) + (is (song-not-in-list? (nth queue 5) middle-removed)) + (is (same-song? (nth queue 6) (get (:items middle-removed) 5))) + (is (song-not-in-list? (last queue) last-removed))))) + (testing "Should pause if the currently playing song is removed" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-all :repeat-single]] + (let [n-songs 10 + queue (song-queue n-songs)] + (is (nil? (-> (playlist/->playlist queue :repeat-mode repeat-mode :playback-mode playback-mode) + (playlist/set-current-song 5) + (playlist/remove-song 5) + (playlist/current-song))))))))) diff --git a/test/cljs/airsonic_ui/components/audio_player/events_test.cljs b/test/cljs/airsonic_ui/components/audio_player/events_test.cljs new file mode 100644 index 0000000..a4e0e20 --- /dev/null +++ b/test/cljs/airsonic_ui/components/audio_player/events_test.cljs @@ -0,0 +1,39 @@ +(ns airsonic-ui.components.audio-player.events-test + (:require [cljs.test :refer-macros [deftest testing is]] + [airsonic-ui.audio.core :as audio] + [airsonic-ui.audio.playlist :as playlist] + [airsonic-ui.fixtures :as fixtures] + [airsonic-ui.test-helpers :refer [dispatches? song-queue]] + [airsonic-ui.components.audio-player.events :as events])) + +(deftest song-has-ended + (testing "Should play the next song when current song has ended" + (is (not (dispatches? (events/audio-update {} [:audio/update {:ended? false}]) :audio-player/next-song))) + (is (dispatches? (events/audio-update {} [:audio/update {:ended? true}]) :audio-player/next-song)))) + +(deftest changing-current-song + (testing "Should correctly set the current song index" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-single :repeat-all]] + (let [n-songs 100 + next-idx (rand-int n-songs) + fixture {:db {:credentials fixtures/credentials + :audio {:current-playlist (playlist/->playlist (song-queue n-songs) :playback-mode playback-mode :repeat-mode repeat-mode)}}} + effects (events/set-current-song fixture [:audio/set-current-song next-idx])] + (is (= next-idx + (-> (:db effects) + (audio/summary [:audio/summary]) + (audio/current-playlist [:audio/current-playlist]) + (:current-idx))) + (str "for playback-mode " playback-mode " and repeat-mode " repeat-mode)) + (is (contains? effects :audio/play)))))) + +(deftest removing-currently-playing-song + (testing "Should stop all audio when removing the currently playing song" + (doseq [playback-mode [:linear :shuffled] + repeat-mode [:repeat-none :repeat-single :repeat-all]] + (let [n-songs 100 + fixture {:db {:credentials fixtures/credentials + :audio {:current-playlist (playlist/->playlist (song-queue n-songs) :playback-mode playback-mode :repeat-mode repeat-mode)}}}] + (is (contains? (events/remove-song fixture [:audio/remove-song 0]) :audio/stop)) + (is (not (contains? (events/remove-song fixture [:audio/remove-song 99]) :audio/stop))))))) diff --git a/test/cljs/airsonic_ui/components/library/fixtures.cljs b/test/cljs/airsonic_ui/components/library/fixtures.cljs new file mode 100644 index 0000000..42eccba --- /dev/null +++ b/test/cljs/airsonic_ui/components/library/fixtures.cljs @@ -0,0 +1,2834 @@ +(ns airsonic-ui.components.library.fixtures) + +;; this is straight from the response cache, copied from app db after +;; browsing through the most recently listened to tracks for the first couple +;; of pages + +(def responses + {["getAlbumList2" {:type "recent", :size 100, :offset 0}] + {:album + [{:artistId "478" + :name "The OOZ" + :songCount 19 + :created "2018-06-02T12:06:11.000Z" + :duration 3975 + :artist "King Krule" + :year 2017 + :id "857" + :coverArt "al-857"} + {:genre "hip/electronic/jaz/Alternative Hip Hop/ambient" + :artistId "644" + :name "The Unseen" + :songCount 24 + :created "2018-07-30T09:20:22.000Z" + :duration 3795 + :artist "Quasimoto" + :year 2000 + :id "1174" + :coverArt "al-1174"} + {:artistId "15" + :name "The Starkiller" + :songCount 3 + :created "2018-01-02T16:27:35.000Z" + :duration 1158 + :artist "The Starkiller" + :year 2013 + :id "29" + :coverArt "al-29"} + {:genre "Disco" + :artistId "437" + :name "Waffles 004" + :songCount 1 + :created "2018-03-08T19:18:24.000Z" + :duration 349 + :artist "Waffles" + :year 2016 + :id "771" + :coverArt "al-771"} + {:genre "Electronic" + :artistId "49" + :name "Fated" + :songCount 15 + :created "2018-03-12T08:36:57.000Z" + :duration 2017 + :artist "Nosaj Thing" + :year 2015 + :id "81" + :coverArt "al-81"} + {:genre "Electronic" + :artistId "41" + :name "Open Eye Signal (Remixes)" + :songCount 1 + :created "2017-06-28T19:11:50.000Z" + :duration 208 + :artist "Jon Hopkins" + :year 2013 + :id "68"} + {:genre "Soundtrack" + :artistId "684" + :name "Ghost in the Shell" + :songCount 11 + :created "2018-10-20T08:35:00.000Z" + :duration 2730 + :artist "Kenji Kawai" + :year 1995 + :id "1263" + :coverArt "al-1263"} + {:artistId "31" + :name "Drop Me A Line / Your Heart To Me" + :songCount 2 + :created "2017-12-30T23:40:03.000Z" + :duration 551 + :artist "Social Lovers" + :year 2017 + :id "56" + :coverArt "al-56"} + {:id "84" + :name "Unknown Album" + :artist "Nosaj Thing" + :artistId "49" + :songCount 1 + :duration 202 + :created "2017-06-28T20:08:38.000Z" + :genre "Unknown Genre"} + {:genre "Electronic" + :artistId "49" + :name "Home" + :songCount 11 + :created "2017-06-28T20:08:29.000Z" + :duration 2196 + :artist "Nosaj Thing" + :year 2013 + :id "82" + :coverArt "al-82"} + {:genre "Gothic" + :artistId "403" + :name "Three Imaginary Boys (Deluxe Edition)" + :songCount 34 + :created "2017-11-06T20:37:32.000Z" + :duration 6128 + :artist "The Cure" + :year 2005 + :id "701" + :coverArt "al-701"} + {:genre "hip" + :artistId "236" + :name "Amygdala" + :songCount 13 + :created "2018-08-14T20:23:42.000Z" + :duration 4665 + :artist "DJ Koze" + :year 2013 + :id "403" + :coverArt "al-403"} + {:genre "Downtempo" + :artistId "596" + :name "II" + :songCount 10 + :created "2017-06-28T20:15:56.000Z" + :duration 2755 + :artist "Raz Ohara and The Odd Orchestra" + :year 2009 + :id "1040"} + {:genre "Soul" + :artistId "436" + :name "Overgrown" + :songCount 11 + :created "2018-01-02T08:43:32.000Z" + :duration 2569 + :artist "James Blake" + :year 2013 + :id "770" + :coverArt "al-770"} + {:genre "Electronic" + :artistId "436" + :name "Life Round Here (feat. Chance the Rapper) - Single" + :songCount 1 + :created "2017-06-28T19:23:25.000Z" + :duration 188 + :artist "James Blake" + :year 2013 + :id "768" + :coverArt "al-768"} + {:genre "Hip Hop" + :artistId "290" + :name "C'mon! EP" + :songCount 6 + :created "2017-06-28T19:12:11.000Z" + :duration 1163 + :artist "Fatoni" + :year 2015 + :id "508" + :coverArt "al-508"} + {:genre "electronic" + :artistId "683" + :name "Das Ziel ist im Weg" + :songCount 10 + :created "2018-10-17T11:01:24.000Z" + :duration 2130 + :artist "Mine" + :year 2016 + :id "1262" + :coverArt "al-1262"} + {:genre "Downtempo" + :artistId "479" + :name "Days to Come" + :songCount 18 + :created "2017-06-28T18:47:44.000Z" + :duration 4627 + :artist "Bonobo" + :year 2006 + :id "861" + :coverArt "al-861"} + {:genre "Electronic" + :artistId "206" + :name "Andorra" + :songCount 9 + :created "2017-11-25T20:47:26.000Z" + :duration 2581 + :artist "Caribou" + :year 2007 + :id "336" + :coverArt "al-336"} + {:genre "Electronic" + :artistId "206" + :name "Melody Day" + :songCount 3 + :created "2017-11-25T20:49:51.000Z" + :duration 683 + :artist "Caribou" + :year 2007 + :id "335" + :coverArt "al-335"} + {:id "707" + :name "lassmalaura" + :artist "lassmalaura" + :artistId "406" + :songCount 2 + :duration 8241 + :created "2017-06-28T18:27:36.000Z"} + {:genre "Idm" + :artistId "597" + :name "Cerulean" + :songCount 12 + :created "2017-06-28T18:44:43.000Z" + :duration 2594 + :artist "Baths" + :year 2010 + :id "1042" + :coverArt "al-1042"} + {:genre "Electronic" + :artistId "64" + :name "Plörre" + :songCount 11 + :created "2017-06-28T19:17:41.000Z" + :duration 2495 + :artist "Frittenbude" + :year 2010 + :id "109"} + {:genre "Electronic" + :artistId "388" + :name "Rongorongo Remixed" + :songCount 11 + :created "2017-06-28T19:57:48.000Z" + :duration 3590 + :artist "Me Succeeds" + :year 2013 + :id "654" + :coverArt "al-654"} + {:genre "Hip-Hop" + :artistId "270" + :name "Über Liebe VLS" + :songCount 1 + :created "2017-06-28T18:42:12.000Z" + :duration 169 + :artist "Audio88 und Yassin" + :year 2011 + :id "469"} + {:genre "Hip-Hop" + :artistId "523" + :name "Über Liebe VLS" + :songCount 1 + :created "2017-06-28T20:21:03.000Z" + :duration 275 + :artist "Suff Daddy" + :year 2011 + :id "940"} + {:id "25" + :name "Nhar, Lee Burton" + :artist "Nhar, Lee Burton" + :artistId "13" + :songCount 1 + :duration 482 + :created "2017-06-28T18:30:39.000Z"} + {:genre "Indie Dance / Nu Disco" + :artistId "360" + :name "Salto" + :songCount 1 + :created "2018-01-02T18:55:06.000Z" + :duration 414 + :artist "Martin Heimann" + :year 2016 + :id "625" + :coverArt "al-625"} + {:id "273" + :name "[via XLR8R]" + :artist "Lianne La Havas" + :artistId "165" + :coverArt "al-273" + :songCount 1 + :duration 307 + :created "2017-06-28T19:35:28.000Z"} + {:artistId "249" + :name "Free Downloads" + :songCount 1 + :created "2017-06-28T19:10:19.000Z" + :duration 286 + :artist "Emancipator feat. Sigur Rós vs. Mobb Deep" + :year 2011 + :id "419" + :coverArt "al-419"} + {:genre "Electronic" + :artistId "64" + :name "Und täglich grüßt das Murmeltier" + :songCount 3 + :created "2017-12-31T09:03:39.000Z" + :duration 652 + :artist "Frittenbude" + :year 2010 + :id "107"} + {:genre "Electronic" + :artistId "206" + :name "Start Breaking My Heart" + :songCount 20 + :created "2017-11-25T20:47:51.000Z" + :duration 6197 + :artist "Caribou" + :year 2006 + :id "338" + :coverArt "al-338"} + {:genre "Electronic" + :artistId "206" + :name "The Milk Of Human Kindness" + :songCount 11 + :created "2017-11-25T20:41:58.000Z" + :duration 2412 + :artist "Caribou" + :year 2005 + :id "337" + :coverArt "al-337"} + {:genre "electronic" + :artistId "424" + :name "Permanent Vacation 3" + :songCount 47 + :created "2017-06-28T20:29:36.000Z" + :duration 18682 + :artist "Various Artists" + :year 2014 + :id "747" + :coverArt "al-747"} + {:genre "Electronic" + :artistId "162" + :name "Music Has the Right to Children" + :songCount 18 + :created "2017-06-28T18:46:28.000Z" + :duration 4226 + :artist "Boards of Canada" + :year 2004 + :id "270" + :coverArt "al-270"} + {:id "276" + :name "Nostalgia 77" + :artist "Nostalgia 77" + :artistId "168" + :songCount 1 + :duration 277 + :created "2017-06-28T18:31:28.000Z"} + {:genre "Electronic" + :artistId "597" + :name "Obsidian" + :songCount 10 + :created "2017-06-28T18:43:58.000Z" + :duration 2596 + :artist "Baths" + :year 2013 + :id "1041" + :coverArt "al-1041"} + {:id "954" + :name "[via XLR8R.com]" + :artist "Burial" + :artistId "530" + :coverArt "al-954" + :songCount 1 + :duration 297 + :created "2017-06-28T18:49:04.000Z"} + {:genre "Uk Garage" + :artistId "530" + :name "Kindred EP" + :songCount 3 + :created "2017-06-28T18:49:36.000Z" + :duration 1839 + :artist "Burial" + :year 2012 + :id "953" + :coverArt "al-953"} + {:genre "Unknown" + :artistId "430" + :name "Rampue" + :songCount 6 + :created "2017-06-28T18:34:00.000Z" + :duration 16433 + :artist "Rampue" + :year 2012 + :id "753" + :coverArt "al-753"} + {:artistId "96" + :name "www.soundcloud.com/rampue" + :songCount 1 + :created "2017-06-28T19:31:41.000Z" + :duration 424 + :artist "Klima" + :year 2013 + :id "166" + :coverArt "al-166"} + {:artistId "463" + :name "soundcloud.com/rampue" + :songCount 1 + :created "2017-06-28T19:35:30.000Z" + :duration 523 + :artist "Leonard Cohen" + :year 2014 + :id "831" + :coverArt "al-831"} + {:artistId "463" + :name "The Future" + :songCount 9 + :created "2018-01-16T11:14:41.000Z" + :duration 3579 + :artist "Leonard Cohen" + :year 2012 + :id "821" + :coverArt "al-821"} + {:id "1001" + :name "Lonski & Classen" + :artist "Lonski & Classen" + :artistId "566" + :coverArt "al-1001" + :songCount 1 + :duration 248 + :created "2017-06-28T20:07:24.000Z"} + {:genre "Podcast" + :artistId "199" + :name "Waterkant Souvenirs Podcast" + :songCount 1 + :created "2017-06-28T20:00:25.000Z" + :duration 5341 + :artist "Mira" + :year 2012 + :id "325"} + {:id "324" + :name "Familiar Forest Festival 2012" + :artist "Mira" + :artistId "199" + :songCount 1 + :duration 6695 + :created "2017-06-28T20:00:35.000Z" + :year 2012} + {:genre "Ambient" + :artistId "188" + :name "We're New Here" + :songCount 13 + :created "2017-06-28T19:18:06.000Z" + :duration 2135 + :artist "Gil Scott-Heron and Jamie xx" + :year 2011 + :id "310" + :coverArt "al-310"} + {:genre "Gothic" + :artistId "403" + :name "Galore : The Singles 87 - 97" + :songCount 18 + :created "2017-11-06T20:51:35.000Z" + :duration 4369 + :artist "The Cure" + :year 1997 + :id "684" + :coverArt "al-684"} + {:genre "IDM" + :artistId "333" + :name "Remixes Compiled" + :songCount 12 + :created "2017-06-28T20:22:43.000Z" + :duration 3233 + :artist "Telefon Tel Aviv" + :year 2007 + :id "723" + :coverArt "al-723"} + {:artistId "230" + :name "Ufordian Edits" + :songCount 1 + :created "2018-02-19T22:55:59.000Z" + :duration 331 + :artist "Peter Power" + :year 2015 + :id "393" + :coverArt "al-393"} + {:genre "Other" + :artistId "528" + :name "Dream Runner EP" + :songCount 6 + :created "2017-06-28T18:39:24.000Z" + :duration 899 + :artist "Annu" + :year 2009 + :id "948"} + {:genre "Techno" + :artistId "75" + :name "Unknown" + :songCount 8 + :created "2017-06-28T20:17:47.000Z" + :duration 2841 + :artist "Saschienne" + :year 2012 + :id "124" + :coverArt "al-124"} + {:genre "Nintendocore" + :artistId "306" + :name "Nach der Kippe Pogo!?" + :songCount 11 + :created "2017-06-28T18:40:09.000Z" + :duration 1508 + :artist "Antitainment" + :year 2007 + :id "532" + :coverArt "al-532"} + {:genre "Electronic" + :artistId "206" + :name "Swim" + :songCount 9 + :created "2017-11-25T20:06:58.000Z" + :duration 2596 + :artist "Caribou" + :year 2010 + :id "339" + :coverArt "al-339"} + {:genre "trance" + :artistId "117" + :name "Nymphs III" + :songCount 2 + :created "2017-06-28T20:04:17.000Z" + :duration 1080 + :artist "Nicolas Jaar" + :year 2015 + :id "201"} + {:genre "Gothic" + :artistId "403" + :name "Wish" + :songCount 12 + :created "2018-01-02T14:29:04.000Z" + :duration 3976 + :artist "The Cure" + :year 1992 + :id "685" + :coverArt "al-685"} + {:genre "Gothic" + :artistId "403" + :name "Show (Live)" + :songCount 18 + :created "2018-01-02T14:30:03.000Z" + :duration 5316 + :artist "The Cure" + :id "698" + :coverArt "al-698"} + {:genre "Gothic" + :artistId "403" + :name "Mixed Up" + :songCount 11 + :created "2018-01-02T14:29:43.000Z" + :duration 4260 + :artist "The Cure" + :year 1990 + :id "692" + :coverArt "al-692"} + {:id "1257" + :name "Saal" + :artist "Serengeti" + :artistId "678" + :songCount 13 + :duration 2437 + :created "2018-09-20T17:02:50.000Z" + :year 2013} + {:genre "Hip Hop" + :artistId "204" + :name "Leaders Of The Brew School" + :songCount 16 + :created "2017-06-28T18:45:16.000Z" + :duration 2214 + :artist "Betty Ford Boys" + :year 2013 + :id "331"} + {:id "202" + :name "Sirens" + :artist "Nicolas Jaar" + :artistId "117" + :songCount 7 + :duration 2841 + :created "2017-06-28T20:04:34.000Z" + :year 2016} + {:genre "techno" + :artistId "682" + :name "Piñata" + :songCount 21 + :created "2018-10-09T15:30:48.000Z" + :duration 3963 + :artist "Freddie Gibbs & Madlib" + :year 2014 + :id "1261" + :coverArt "al-1261"} + {:genre "electronic" + :artistId "681" + :name "We Must Become the Pitiless Censors of Ourselves" + :songCount 11 + :created "2018-10-08T17:21:47.000Z" + :duration 1916 + :artist "John Maus" + :year 2011 + :id "1260" + :coverArt "al-1260"} + {:artistId "514" + :name "Time" + :songCount 1 + :created "2017-07-24T13:19:05.000Z" + :duration 247 + :artist "Lokke" + :year 2015 + :id "923" + :coverArt "al-923"} + {:genre "jazz" + :artistId "680" + :name "These Things Take Time" + :songCount 13 + :created "2018-10-08T17:21:09.000Z" + :duration 3013 + :artist "Molly Nilsson" + :year 2008 + :id "1259" + :coverArt "al-1259"} + {:artistId "463" + :name "Songs of Love and Hate" + :songCount 4 + :created "2018-01-16T11:13:54.000Z" + :duration 1273 + :artist "Leonard Cohen" + :year 1970 + :id "829" + :coverArt "al-829"} + {:artistId "187" + :name "Vacation EP" + :songCount 7 + :created "2017-06-28T20:19:17.000Z" + :duration 1902 + :artist "Shlohmo" + :year 2012 + :id "305" + :coverArt "al-305"} + {:genre "Electronic" + :artistId "187" + :name "Vacation (Remixes)" + :songCount 6 + :created "2017-06-28T20:19:23.000Z" + :duration 3559 + :artist "Shlohmo" + :year 2012 + :id "303"} + {:genre "WeDidIt" + :artistId "302" + :name "Salvation Remixes" + :songCount 3 + :created "2017-06-28T20:14:04.000Z" + :duration 739 + :artist "Purple" + :year 2013 + :id "525" + :coverArt "al-525"} + {:genre "Alternative Rock / Indie Rock" + :artistId "16" + :name "Sleeping With Ghosts" + :songCount 22 + :created "2017-11-06T20:39:23.000Z" + :duration 5232 + :artist "Placebo" + :year 2003 + :id "38" + :coverArt "al-38"} + {:genre "Funk/Hip-Hop" + :artistId "198" + :name "Looking For the Perfect Beat" + :songCount 13 + :created "2017-06-28T18:36:47.000Z" + :duration 4521 + :artist "Afrika Bambaataa" + :year 2001 + :id "323" + :coverArt "al-323"} + {:artistId "103" + :name "edits & cuts" + :songCount 14 + :created "2017-06-28T19:37:20.000Z" + :duration 3550 + :artist "M.Rux" + :year 2014 + :id "182" + :coverArt "al-182"} + {:genre "Techno" + :artistId "117" + :name "Marks / Angles" + :songCount 3 + :created "2017-06-28T20:03:46.000Z" + :duration 1000 + :artist "Nicolas Jaar" + :year 2010 + :id "196"} + {:genre "Electronic" + :artistId "73" + :name "Don't Break My Love EP" + :songCount 2 + :created "2017-06-28T20:05:16.000Z" + :duration 673 + :artist "Nicolas Jaar & Theatre Roosevelt" + :year 2011 + :id "122" + :coverArt "al-122"} + {:genre "Electronic" + :artistId "233" + :name "Mother Earth's Plantasia" + :songCount 10 + :created "2018-05-28T21:31:55.000Z" + :duration 1837 + :artist "Mort Garson" + :year 1976 + :id "397" + :coverArt "al-397"} + {:genre "Psychedelic Rock" + :artistId "424" + :name + "Nuggets: Original Artyfacts From the First Psychedelic Era, 1965-1968" + :songCount 27 + :created "2018-02-21T12:01:38.000Z" + :duration 4614 + :artist "Various Artists" + :year 1998 + :id "743" + :coverArt "al-743"} + {:genre "Psychedelic Rock" + :artistId "37" + :name "Phluph" + :songCount 10 + :created "2018-03-05T16:31:46.000Z" + :duration 2182 + :artist "Phluph" + :year 2001 + :id "64" + :coverArt "al-64"} + {:genre "Rock" + :artistId "305" + :name "The Best of Talking Heads (Remastered)" + :songCount 18 + :created "2018-01-22T11:00:50.000Z" + :duration 4618 + :artist "Talking Heads" + :year 2004 + :id "529" + :coverArt "al-529"} + {:genre "Electronic" + :artistId "50" + :name "Divide And Exit" + :songCount 14 + :created "2018-01-21T14:47:59.000Z" + :duration 2417 + :artist "Sleaford Mods" + :year 2014 + :id "86" + :coverArt "al-86"} + {:genre "electronic" + :artistId "349" + :name "Fade to Grey: The Best of Visage" + :songCount 12 + :created "2018-08-29T13:01:26.000Z" + :duration 2757 + :artist "Visage" + :year 1993 + :id "1234"} + {:genre "electronic" + :artistId "334" + :name "Hounds of Love" + :songCount 18 + :created "2018-08-29T13:00:32.000Z" + :duration 4419 + :artist "Kate Bush" + :year 1997 + :id "1215" + :coverArt "al-1215"} + {:genre "Psychedelic" + :artistId "424" + :name + "Forge Your Own Chains: Heavy Psychedelic Ballads and Dirges 1968-1974" + :songCount 15 + :created "2018-01-27T12:23:47.000Z" + :duration 4241 + :artist "Various Artists" + :id "742" + :coverArt "al-742"} + {:genre "Live Archive" + :artistId "141" + :name "2017-08-28 Rough Trade NYC, Brooklyn, NY" + :songCount 4 + :created "2018-01-19T23:07:20.000Z" + :duration 2483 + :artist "Sunburned Hand of the Man" + :year 2017 + :id "242" + :coverArt "al-242"} + {:genre "electronic" + :artistId "236" + :name "Knock Knock" + :songCount 16 + :created "2018-06-09T23:04:20.000Z" + :duration 4710 + :artist "DJ Koze" + :year 2018 + :id "401" + :coverArt "al-401"} + {:genre "Nintendocore" + :artistId "306" + :name "Gymnasiastik mit Antitainment" + :songCount 6 + :created "2017-06-28T18:39:58.000Z" + :duration 795 + :artist "Antitainment" + :year 2004 + :id "533"} + {:genre "Electronic" + :artistId "584" + :name "Amok" + :songCount 9 + :created "2017-06-28T18:41:30.000Z" + :duration 2681 + :artist "Atoms for Peace" + :year 2013 + :id "1023" + :coverArt "al-1023"} + {:artistId "26" + :name "TamponTango I" + :songCount 3 + :created "2017-11-23T23:18:43.000Z" + :duration 851 + :artist "Diederdas" + :year 2017 + :id "51" + :coverArt "al-51"} + {:genre "electronic" + :artistId "679" + :name "Heaven and Earth" + :songCount 16 + :created "2018-09-20T22:07:23.000Z" + :duration 8672 + :artist "Kamasi Washington" + :year 2018 + :id "1258" + :coverArt "al-1258"} + {:genre "rhy" + :artistId "661" + :name "Yawn Zen" + :songCount 12 + :created "2018-08-21T21:36:43.000Z" + :duration 1883 + :artist "Mndsgn" + :year 2014 + :id "1200" + :coverArt "al-1200"} + {:genre "Rap" + :artistId "677" + :name "Elephant Eyelash" + :songCount 12 + :created "2018-09-20T17:02:08.000Z" + :duration 2478 + :artist "Why?" + :year 2005 + :id "1256"} + {:genre "Electronic" + :artistId "41" + :name "Immunity" + :songCount 8 + :created "2017-06-28T19:28:24.000Z" + :duration 3604 + :artist "Jon Hopkins" + :year 2013 + :id "104" + :coverArt "al-104"} + {:genre "IDM / Trip-Hop / Experimental" + :artistId "454" + :name "New Energy" + :songCount 14 + :created "2017-11-25T19:44:56.000Z" + :duration 3381 + :artist "Four Tet" + :year 2017 + :id "800" + :coverArt "al-800"} + {:genre "Electronic" + :artistId "633" + :name "ƒIN (Special Edition)" + :songCount 20 + :created "2017-06-28T19:26:41.000Z" + :duration 5822 + :artist "John Talabot" + :year 2012 + :id "1159"} + {:artistId "412" + :name "A Moot Point" + :songCount 2 + :created "2017-06-28T18:32:24.000Z" + :duration 857 + :artist "Pional" + :year 2010 + :id "719" + :coverArt "al-719"} + {:id "740" + :name "KR Family EP, Pt. 1" + :artist "Peter Power" + :artistId "230" + :coverArt "al-740" + :songCount 3 + :duration 1333 + :created "2017-06-28T20:31:06.000Z"} + {:genre "House" + :artistId "482" + :name "Busy Days For Fools" + :songCount 11 + :created "2017-06-28T19:35:05.000Z" + :duration 3238 + :artist "Lee Burton" + :year 2012 + :id "866" + :coverArt "al-866"} + {:id "851" + :name "Ry & Frank Wiedemann" + :artist "Ry & Frank Wiedemann" + :artistId "472" + :songCount 1 + :duration 485 + :created "2017-06-28T18:34:23.000Z"} + {:genre "Electronic" + :artistId "58" + :name "Deep Cuts" + :songCount 17 + :created "2017-12-22T08:21:19.000Z" + :duration 3321 + :artist "The Knife" + :year 2003 + :id "96" + :coverArt "al-96"} + {:artistId "125" + :name "VIA Remixes" + :songCount 1 + :created "2017-06-28T18:27:59.000Z" + :duration 362 + :artist "Andi Otto" + :year 2017 + :id "211" + :coverArt "al-211"} + {:artistId "626" + :name "Hummingbird / Milk & Honey" + :songCount 2 + :created "2017-11-23T21:27:00.000Z" + :duration 303 + :artist "Luca Nieri" + :year 2016 + :id "1150" + :coverArt "al-1150"}]} + ["getAlbumList2" {:type "recent", :size 100, :offset 20}] + {:album + [{:id "707" + :name "lassmalaura" + :artist "lassmalaura" + :artistId "406" + :songCount 2 + :duration 8241 + :created "2017-06-28T18:27:36.000Z"} + {:genre "Idm" + :artistId "597" + :name "Cerulean" + :songCount 12 + :created "2017-06-28T18:44:43.000Z" + :duration 2594 + :artist "Baths" + :year 2010 + :id "1042" + :coverArt "al-1042"} + {:genre "Electronic" + :artistId "64" + :name "Plörre" + :songCount 11 + :created "2017-06-28T19:17:41.000Z" + :duration 2495 + :artist "Frittenbude" + :year 2010 + :id "109"} + {:genre "Electronic" + :artistId "388" + :name "Rongorongo Remixed" + :songCount 11 + :created "2017-06-28T19:57:48.000Z" + :duration 3590 + :artist "Me Succeeds" + :year 2013 + :id "654" + :coverArt "al-654"} + {:genre "Hip-Hop" + :artistId "270" + :name "Über Liebe VLS" + :songCount 1 + :created "2017-06-28T18:42:12.000Z" + :duration 169 + :artist "Audio88 und Yassin" + :year 2011 + :id "469"} + {:genre "Hip-Hop" + :artistId "523" + :name "Über Liebe VLS" + :songCount 1 + :created "2017-06-28T20:21:03.000Z" + :duration 275 + :artist "Suff Daddy" + :year 2011 + :id "940"} + {:id "25" + :name "Nhar, Lee Burton" + :artist "Nhar, Lee Burton" + :artistId "13" + :songCount 1 + :duration 482 + :created "2017-06-28T18:30:39.000Z"} + {:genre "Indie Dance / Nu Disco" + :artistId "360" + :name "Salto" + :songCount 1 + :created "2018-01-02T18:55:06.000Z" + :duration 414 + :artist "Martin Heimann" + :year 2016 + :id "625" + :coverArt "al-625"} + {:id "273" + :name "[via XLR8R]" + :artist "Lianne La Havas" + :artistId "165" + :coverArt "al-273" + :songCount 1 + :duration 307 + :created "2017-06-28T19:35:28.000Z"} + {:artistId "249" + :name "Free Downloads" + :songCount 1 + :created "2017-06-28T19:10:19.000Z" + :duration 286 + :artist "Emancipator feat. Sigur Rós vs. Mobb Deep" + :year 2011 + :id "419" + :coverArt "al-419"} + {:genre "Electronic" + :artistId "64" + :name "Und täglich grüßt das Murmeltier" + :songCount 3 + :created "2017-12-31T09:03:39.000Z" + :duration 652 + :artist "Frittenbude" + :year 2010 + :id "107"} + {:genre "Electronic" + :artistId "206" + :name "Start Breaking My Heart" + :songCount 20 + :created "2017-11-25T20:47:51.000Z" + :duration 6197 + :artist "Caribou" + :year 2006 + :id "338" + :coverArt "al-338"} + {:genre "Electronic" + :artistId "206" + :name "The Milk Of Human Kindness" + :songCount 11 + :created "2017-11-25T20:41:58.000Z" + :duration 2412 + :artist "Caribou" + :year 2005 + :id "337" + :coverArt "al-337"} + {:genre "electronic" + :artistId "424" + :name "Permanent Vacation 3" + :songCount 47 + :created "2017-06-28T20:29:36.000Z" + :duration 18682 + :artist "Various Artists" + :year 2014 + :id "747" + :coverArt "al-747"} + {:genre "Electronic" + :artistId "162" + :name "Music Has the Right to Children" + :songCount 18 + :created "2017-06-28T18:46:28.000Z" + :duration 4226 + :artist "Boards of Canada" + :year 2004 + :id "270" + :coverArt "al-270"} + {:id "276" + :name "Nostalgia 77" + :artist "Nostalgia 77" + :artistId "168" + :songCount 1 + :duration 277 + :created "2017-06-28T18:31:28.000Z"} + {:genre "Electronic" + :artistId "597" + :name "Obsidian" + :songCount 10 + :created "2017-06-28T18:43:58.000Z" + :duration 2596 + :artist "Baths" + :year 2013 + :id "1041" + :coverArt "al-1041"} + {:id "954" + :name "[via XLR8R.com]" + :artist "Burial" + :artistId "530" + :coverArt "al-954" + :songCount 1 + :duration 297 + :created "2017-06-28T18:49:04.000Z"} + {:genre "Uk Garage" + :artistId "530" + :name "Kindred EP" + :songCount 3 + :created "2017-06-28T18:49:36.000Z" + :duration 1839 + :artist "Burial" + :year 2012 + :id "953" + :coverArt "al-953"} + {:genre "Unknown" + :artistId "430" + :name "Rampue" + :songCount 6 + :created "2017-06-28T18:34:00.000Z" + :duration 16433 + :artist "Rampue" + :year 2012 + :id "753" + :coverArt "al-753"} + {:artistId "96" + :name "www.soundcloud.com/rampue" + :songCount 1 + :created "2017-06-28T19:31:41.000Z" + :duration 424 + :artist "Klima" + :year 2013 + :id "166" + :coverArt "al-166"} + {:artistId "463" + :name "soundcloud.com/rampue" + :songCount 1 + :created "2017-06-28T19:35:30.000Z" + :duration 523 + :artist "Leonard Cohen" + :year 2014 + :id "831" + :coverArt "al-831"} + {:artistId "463" + :name "The Future" + :songCount 9 + :created "2018-01-16T11:14:41.000Z" + :duration 3579 + :artist "Leonard Cohen" + :year 2012 + :id "821" + :coverArt "al-821"} + {:id "1001" + :name "Lonski & Classen" + :artist "Lonski & Classen" + :artistId "566" + :coverArt "al-1001" + :songCount 1 + :duration 248 + :created "2017-06-28T20:07:24.000Z"} + {:genre "Podcast" + :artistId "199" + :name "Waterkant Souvenirs Podcast" + :songCount 1 + :created "2017-06-28T20:00:25.000Z" + :duration 5341 + :artist "Mira" + :year 2012 + :id "325"} + {:id "324" + :name "Familiar Forest Festival 2012" + :artist "Mira" + :artistId "199" + :songCount 1 + :duration 6695 + :created "2017-06-28T20:00:35.000Z" + :year 2012} + {:genre "Ambient" + :artistId "188" + :name "We're New Here" + :songCount 13 + :created "2017-06-28T19:18:06.000Z" + :duration 2135 + :artist "Gil Scott-Heron and Jamie xx" + :year 2011 + :id "310" + :coverArt "al-310"} + {:genre "Gothic" + :artistId "403" + :name "Galore : The Singles 87 - 97" + :songCount 18 + :created "2017-11-06T20:51:35.000Z" + :duration 4369 + :artist "The Cure" + :year 1997 + :id "684" + :coverArt "al-684"} + {:genre "IDM" + :artistId "333" + :name "Remixes Compiled" + :songCount 12 + :created "2017-06-28T20:22:43.000Z" + :duration 3233 + :artist "Telefon Tel Aviv" + :year 2007 + :id "723" + :coverArt "al-723"} + {:artistId "230" + :name "Ufordian Edits" + :songCount 1 + :created "2018-02-19T22:55:59.000Z" + :duration 331 + :artist "Peter Power" + :year 2015 + :id "393" + :coverArt "al-393"} + {:genre "Other" + :artistId "528" + :name "Dream Runner EP" + :songCount 6 + :created "2017-06-28T18:39:24.000Z" + :duration 899 + :artist "Annu" + :year 2009 + :id "948"} + {:genre "Techno" + :artistId "75" + :name "Unknown" + :songCount 8 + :created "2017-06-28T20:17:47.000Z" + :duration 2841 + :artist "Saschienne" + :year 2012 + :id "124" + :coverArt "al-124"} + {:genre "Nintendocore" + :artistId "306" + :name "Nach der Kippe Pogo!?" + :songCount 11 + :created "2017-06-28T18:40:09.000Z" + :duration 1508 + :artist "Antitainment" + :year 2007 + :id "532" + :coverArt "al-532"} + {:genre "Electronic" + :artistId "206" + :name "Swim" + :songCount 9 + :created "2017-11-25T20:06:58.000Z" + :duration 2596 + :artist "Caribou" + :year 2010 + :id "339" + :coverArt "al-339"} + {:genre "trance" + :artistId "117" + :name "Nymphs III" + :songCount 2 + :created "2017-06-28T20:04:17.000Z" + :duration 1080 + :artist "Nicolas Jaar" + :year 2015 + :id "201"} + {:genre "Gothic" + :artistId "403" + :name "Wish" + :songCount 12 + :created "2018-01-02T14:29:04.000Z" + :duration 3976 + :artist "The Cure" + :year 1992 + :id "685" + :coverArt "al-685"} + {:genre "Gothic" + :artistId "403" + :name "Show (Live)" + :songCount 18 + :created "2018-01-02T14:30:03.000Z" + :duration 5316 + :artist "The Cure" + :id "698" + :coverArt "al-698"} + {:genre "Gothic" + :artistId "403" + :name "Mixed Up" + :songCount 11 + :created "2018-01-02T14:29:43.000Z" + :duration 4260 + :artist "The Cure" + :year 1990 + :id "692" + :coverArt "al-692"} + {:id "1257" + :name "Saal" + :artist "Serengeti" + :artistId "678" + :songCount 13 + :duration 2437 + :created "2018-09-20T17:02:50.000Z" + :year 2013} + {:genre "Hip Hop" + :artistId "204" + :name "Leaders Of The Brew School" + :songCount 16 + :created "2017-06-28T18:45:16.000Z" + :duration 2214 + :artist "Betty Ford Boys" + :year 2013 + :id "331"} + {:id "202" + :name "Sirens" + :artist "Nicolas Jaar" + :artistId "117" + :songCount 7 + :duration 2841 + :created "2017-06-28T20:04:34.000Z" + :year 2016} + {:genre "techno" + :artistId "682" + :name "Piñata" + :songCount 21 + :created "2018-10-09T15:30:48.000Z" + :duration 3963 + :artist "Freddie Gibbs & Madlib" + :year 2014 + :id "1261" + :coverArt "al-1261"} + {:genre "electronic" + :artistId "681" + :name "We Must Become the Pitiless Censors of Ourselves" + :songCount 11 + :created "2018-10-08T17:21:47.000Z" + :duration 1916 + :artist "John Maus" + :year 2011 + :id "1260" + :coverArt "al-1260"} + {:artistId "514" + :name "Time" + :songCount 1 + :created "2017-07-24T13:19:05.000Z" + :duration 247 + :artist "Lokke" + :year 2015 + :id "923" + :coverArt "al-923"} + {:genre "jazz" + :artistId "680" + :name "These Things Take Time" + :songCount 13 + :created "2018-10-08T17:21:09.000Z" + :duration 3013 + :artist "Molly Nilsson" + :year 2008 + :id "1259" + :coverArt "al-1259"} + {:artistId "463" + :name "Songs of Love and Hate" + :songCount 4 + :created "2018-01-16T11:13:54.000Z" + :duration 1273 + :artist "Leonard Cohen" + :year 1970 + :id "829" + :coverArt "al-829"} + {:artistId "187" + :name "Vacation EP" + :songCount 7 + :created "2017-06-28T20:19:17.000Z" + :duration 1902 + :artist "Shlohmo" + :year 2012 + :id "305" + :coverArt "al-305"} + {:genre "Electronic" + :artistId "187" + :name "Vacation (Remixes)" + :songCount 6 + :created "2017-06-28T20:19:23.000Z" + :duration 3559 + :artist "Shlohmo" + :year 2012 + :id "303"} + {:genre "WeDidIt" + :artistId "302" + :name "Salvation Remixes" + :songCount 3 + :created "2017-06-28T20:14:04.000Z" + :duration 739 + :artist "Purple" + :year 2013 + :id "525" + :coverArt "al-525"} + {:genre "Alternative Rock / Indie Rock" + :artistId "16" + :name "Sleeping With Ghosts" + :songCount 22 + :created "2017-11-06T20:39:23.000Z" + :duration 5232 + :artist "Placebo" + :year 2003 + :id "38" + :coverArt "al-38"} + {:genre "Funk/Hip-Hop" + :artistId "198" + :name "Looking For the Perfect Beat" + :songCount 13 + :created "2017-06-28T18:36:47.000Z" + :duration 4521 + :artist "Afrika Bambaataa" + :year 2001 + :id "323" + :coverArt "al-323"} + {:artistId "103" + :name "edits & cuts" + :songCount 14 + :created "2017-06-28T19:37:20.000Z" + :duration 3550 + :artist "M.Rux" + :year 2014 + :id "182" + :coverArt "al-182"} + {:genre "Techno" + :artistId "117" + :name "Marks / Angles" + :songCount 3 + :created "2017-06-28T20:03:46.000Z" + :duration 1000 + :artist "Nicolas Jaar" + :year 2010 + :id "196"} + {:genre "Electronic" + :artistId "73" + :name "Don't Break My Love EP" + :songCount 2 + :created "2017-06-28T20:05:16.000Z" + :duration 673 + :artist "Nicolas Jaar & Theatre Roosevelt" + :year 2011 + :id "122" + :coverArt "al-122"} + {:genre "Electronic" + :artistId "233" + :name "Mother Earth's Plantasia" + :songCount 10 + :created "2018-05-28T21:31:55.000Z" + :duration 1837 + :artist "Mort Garson" + :year 1976 + :id "397" + :coverArt "al-397"} + {:genre "Psychedelic Rock" + :artistId "424" + :name + "Nuggets: Original Artyfacts From the First Psychedelic Era, 1965-1968" + :songCount 27 + :created "2018-02-21T12:01:38.000Z" + :duration 4614 + :artist "Various Artists" + :year 1998 + :id "743" + :coverArt "al-743"} + {:genre "Psychedelic Rock" + :artistId "37" + :name "Phluph" + :songCount 10 + :created "2018-03-05T16:31:46.000Z" + :duration 2182 + :artist "Phluph" + :year 2001 + :id "64" + :coverArt "al-64"} + {:genre "Rock" + :artistId "305" + :name "The Best of Talking Heads (Remastered)" + :songCount 18 + :created "2018-01-22T11:00:50.000Z" + :duration 4618 + :artist "Talking Heads" + :year 2004 + :id "529" + :coverArt "al-529"} + {:genre "Electronic" + :artistId "50" + :name "Divide And Exit" + :songCount 14 + :created "2018-01-21T14:47:59.000Z" + :duration 2417 + :artist "Sleaford Mods" + :year 2014 + :id "86" + :coverArt "al-86"} + {:genre "electronic" + :artistId "349" + :name "Fade to Grey: The Best of Visage" + :songCount 12 + :created "2018-08-29T13:01:26.000Z" + :duration 2757 + :artist "Visage" + :year 1993 + :id "1234"} + {:genre "electronic" + :artistId "334" + :name "Hounds of Love" + :songCount 18 + :created "2018-08-29T13:00:32.000Z" + :duration 4419 + :artist "Kate Bush" + :year 1997 + :id "1215" + :coverArt "al-1215"} + {:genre "Psychedelic" + :artistId "424" + :name + "Forge Your Own Chains: Heavy Psychedelic Ballads and Dirges 1968-1974" + :songCount 15 + :created "2018-01-27T12:23:47.000Z" + :duration 4241 + :artist "Various Artists" + :id "742" + :coverArt "al-742"} + {:genre "Live Archive" + :artistId "141" + :name "2017-08-28 Rough Trade NYC, Brooklyn, NY" + :songCount 4 + :created "2018-01-19T23:07:20.000Z" + :duration 2483 + :artist "Sunburned Hand of the Man" + :year 2017 + :id "242" + :coverArt "al-242"} + {:genre "electronic" + :artistId "236" + :name "Knock Knock" + :songCount 16 + :created "2018-06-09T23:04:20.000Z" + :duration 4710 + :artist "DJ Koze" + :year 2018 + :id "401" + :coverArt "al-401"} + {:genre "Nintendocore" + :artistId "306" + :name "Gymnasiastik mit Antitainment" + :songCount 6 + :created "2017-06-28T18:39:58.000Z" + :duration 795 + :artist "Antitainment" + :year 2004 + :id "533"} + {:genre "Electronic" + :artistId "584" + :name "Amok" + :songCount 9 + :created "2017-06-28T18:41:30.000Z" + :duration 2681 + :artist "Atoms for Peace" + :year 2013 + :id "1023" + :coverArt "al-1023"} + {:artistId "26" + :name "TamponTango I" + :songCount 3 + :created "2017-11-23T23:18:43.000Z" + :duration 851 + :artist "Diederdas" + :year 2017 + :id "51" + :coverArt "al-51"} + {:genre "electronic" + :artistId "679" + :name "Heaven and Earth" + :songCount 16 + :created "2018-09-20T22:07:23.000Z" + :duration 8672 + :artist "Kamasi Washington" + :year 2018 + :id "1258" + :coverArt "al-1258"} + {:genre "rhy" + :artistId "661" + :name "Yawn Zen" + :songCount 12 + :created "2018-08-21T21:36:43.000Z" + :duration 1883 + :artist "Mndsgn" + :year 2014 + :id "1200" + :coverArt "al-1200"} + {:genre "Rap" + :artistId "677" + :name "Elephant Eyelash" + :songCount 12 + :created "2018-09-20T17:02:08.000Z" + :duration 2478 + :artist "Why?" + :year 2005 + :id "1256"} + {:genre "Electronic" + :artistId "41" + :name "Immunity" + :songCount 8 + :created "2017-06-28T19:28:24.000Z" + :duration 3604 + :artist "Jon Hopkins" + :year 2013 + :id "104" + :coverArt "al-104"} + {:genre "IDM / Trip-Hop / Experimental" + :artistId "454" + :name "New Energy" + :songCount 14 + :created "2017-11-25T19:44:56.000Z" + :duration 3381 + :artist "Four Tet" + :year 2017 + :id "800" + :coverArt "al-800"} + {:genre "Electronic" + :artistId "633" + :name "ƒIN (Special Edition)" + :songCount 20 + :created "2017-06-28T19:26:41.000Z" + :duration 5822 + :artist "John Talabot" + :year 2012 + :id "1159"} + {:artistId "412" + :name "A Moot Point" + :songCount 2 + :created "2017-06-28T18:32:24.000Z" + :duration 857 + :artist "Pional" + :year 2010 + :id "719" + :coverArt "al-719"} + {:id "740" + :name "KR Family EP, Pt. 1" + :artist "Peter Power" + :artistId "230" + :coverArt "al-740" + :songCount 3 + :duration 1333 + :created "2017-06-28T20:31:06.000Z"} + {:genre "House" + :artistId "482" + :name "Busy Days For Fools" + :songCount 11 + :created "2017-06-28T19:35:05.000Z" + :duration 3238 + :artist "Lee Burton" + :year 2012 + :id "866" + :coverArt "al-866"} + {:id "851" + :name "Ry & Frank Wiedemann" + :artist "Ry & Frank Wiedemann" + :artistId "472" + :songCount 1 + :duration 485 + :created "2017-06-28T18:34:23.000Z"} + {:genre "Electronic" + :artistId "58" + :name "Deep Cuts" + :songCount 17 + :created "2017-12-22T08:21:19.000Z" + :duration 3321 + :artist "The Knife" + :year 2003 + :id "96" + :coverArt "al-96"} + {:artistId "125" + :name "VIA Remixes" + :songCount 1 + :created "2017-06-28T18:27:59.000Z" + :duration 362 + :artist "Andi Otto" + :year 2017 + :id "211" + :coverArt "al-211"} + {:artistId "626" + :name "Hummingbird / Milk & Honey" + :songCount 2 + :created "2017-11-23T21:27:00.000Z" + :duration 303 + :artist "Luca Nieri" + :year 2016 + :id "1150" + :coverArt "al-1150"} + {:genre "Electronic" + :artistId "434" + :name "Mercy Street" + :songCount 2 + :created "2017-12-22T08:18:55.000Z" + :duration 568 + :artist "Fever Ray" + :year 2010 + :id "762" + :coverArt "al-762"} + {:artistId "43" + :name "2012-2017" + :songCount 11 + :created "2018-03-06T15:51:42.000Z" + :duration 3998 + :artist "A.A.L." + :year 2018 + :id "73" + :coverArt "al-73"} + {:genre "New Wave Music" + :artistId "337" + :name "Liaisons dangereuses" + :songCount 10 + :created "2018-08-29T13:00:42.000Z" + :duration 2392 + :artist "Liaisons Dangereuses" + :year 1985 + :id "1216"} + {:genre "Electro" + :artistId "434" + :name "Fever Ray" + :songCount 12 + :created "2017-12-22T08:19:04.000Z" + :duration 3380 + :artist "Fever Ray" + :year 2009 + :id "765"} + {:id "621" + :name "RSS Disco" + :artist "RSS Disco" + :artistId "358" + :songCount 2 + :duration 841 + :created "2018-04-25T10:11:14.000Z"} + {:genre "House" + :artistId "358" + :name "Very" + :songCount 3 + :created "2017-06-28T20:17:12.000Z" + :duration 1339 + :artist "RSS Disco" + :year 2012 + :id "624" + :coverArt "al-624"} + {:genre "Disco" + :artistId "619" + :name "Sir John" + :songCount 1 + :created "2018-03-12T20:21:14.000Z" + :duration 419 + :artist "White Elephant" + :year 2011 + :id "1134" + :coverArt "al-1134"} + {:genre "House" + :artistId "434" + :name "Sidetracked" + :songCount 1 + :created "2017-06-28T18:20:10.000Z" + :duration 270 + :artist "Fever Ray" + :year 2012 + :id "920" + :coverArt "al-920"} + {:genre "Electronic" + :artistId "58" + :name "Hannah Med H Soundtrack" + :songCount 16 + :created "2017-12-22T08:21:33.000Z" + :duration 2307 + :artist "The Knife" + :year 2003 + :id "97" + :coverArt "al-97"} + {:genre "Alternative Rock" + :artistId "478" + :name "6 Feet Beneath the Moon" + :songCount 14 + :created "2017-09-08T17:37:16.000Z" + :duration 3136 + :artist "King Krule" + :year 2013 + :id "859" + :coverArt "al-859"} + {:artistId "103" + :name "Joga / Crazy Junker 7\"" + :songCount 2 + :created "2017-06-28T19:37:31.000Z" + :duration 442 + :artist "M.Rux" + :year 2014 + :id "177" + :coverArt "al-177"} + {:genre "House" + :artistId "267" + :name "Carat EP" + :songCount 5 + :created "2017-06-28T20:08:58.000Z" + :duration 2080 + :artist "Nu" + :year 2013 + :id "467"} + {:artistId "419" + :name "On Claws (reissue)" + :songCount 1 + :created "2017-07-24T13:48:20.000Z" + :duration 176 + :artist "I am Oak" + :year 2013 + :id "733" + :coverArt "al-733"} + {:genre "Indie Dance / Nu Disco" + :artistId "214" + :name "Thinking Allowed" + :songCount 1 + :created "2018-01-02T18:54:41.000Z" + :duration 430 + :artist "Tornado Wallace" + :year 2013 + :id "354" + :coverArt "al-354"} + {:artistId "629" + :name "V.I.C.T.O.R" + :songCount 1 + :created "2017-06-28T18:25:45.000Z" + :duration 279 + :artist "Golden Bug" + :year 2016 + :id "1153" + :coverArt "al-1153"} + {:genre "Avant-Garde" + :artistId "256" + :name "Ende Neu" + :songCount 9 + :created "2017-06-28T19:09:43.000Z" + :duration 2693 + :artist "Einstürzende Neubauten" + :year 1998 + :id "426" + :coverArt "al-426"} + {:genre "House" + :artistId "245" + :name "Visibles" + :songCount 4 + :created "2017-06-28T18:57:22.000Z" + :duration 1556 + :artist "Constantijn Lange" + :year 2014 + :id "413" + :coverArt "al-413"} + {:artistId "245" + :name "Orange Atlas" + :songCount 5 + :created "2017-06-28T18:57:08.000Z" + :duration 2171 + :artist "Constantijn Lange" + :year 2013 + :id "412" + :coverArt "al-412"} + {:artistId "146" + :name "Mapping The Futures Gone By" + :songCount 7 + :created "2017-06-28T18:57:28.000Z" + :duration 1536 + :artist "CONTACT FIELD ORCHESTRA" + :year 2015 + :id "247" + :coverArt "al-247"} + {:genre "electronic" + :artistId "253" + :name "It's Album Time" + :songCount 12 + :created "2018-09-04T14:25:00.000Z" + :duration 3555 + :artist "Todd Terje" + :year 2014 + :id "1254" + :coverArt "al-1254"}]} + ["getAlbumList2" {:type "recent", :size 100, :offset 40}] + {:album + [{:artistId "96" + :name "www.soundcloud.com/rampue" + :songCount 1 + :created "2017-06-28T19:31:41.000Z" + :duration 424 + :artist "Klima" + :year 2013 + :id "166" + :coverArt "al-166"} + {:artistId "463" + :name "soundcloud.com/rampue" + :songCount 1 + :created "2017-06-28T19:35:30.000Z" + :duration 523 + :artist "Leonard Cohen" + :year 2014 + :id "831" + :coverArt "al-831"} + {:artistId "463" + :name "The Future" + :songCount 9 + :created "2018-01-16T11:14:41.000Z" + :duration 3579 + :artist "Leonard Cohen" + :year 2012 + :id "821" + :coverArt "al-821"} + {:id "1001" + :name "Lonski & Classen" + :artist "Lonski & Classen" + :artistId "566" + :coverArt "al-1001" + :songCount 1 + :duration 248 + :created "2017-06-28T20:07:24.000Z"} + {:genre "Podcast" + :artistId "199" + :name "Waterkant Souvenirs Podcast" + :songCount 1 + :created "2017-06-28T20:00:25.000Z" + :duration 5341 + :artist "Mira" + :year 2012 + :id "325"} + {:id "324" + :name "Familiar Forest Festival 2012" + :artist "Mira" + :artistId "199" + :songCount 1 + :duration 6695 + :created "2017-06-28T20:00:35.000Z" + :year 2012} + {:genre "Ambient" + :artistId "188" + :name "We're New Here" + :songCount 13 + :created "2017-06-28T19:18:06.000Z" + :duration 2135 + :artist "Gil Scott-Heron and Jamie xx" + :year 2011 + :id "310" + :coverArt "al-310"} + {:genre "Gothic" + :artistId "403" + :name "Galore : The Singles 87 - 97" + :songCount 18 + :created "2017-11-06T20:51:35.000Z" + :duration 4369 + :artist "The Cure" + :year 1997 + :id "684" + :coverArt "al-684"} + {:genre "IDM" + :artistId "333" + :name "Remixes Compiled" + :songCount 12 + :created "2017-06-28T20:22:43.000Z" + :duration 3233 + :artist "Telefon Tel Aviv" + :year 2007 + :id "723" + :coverArt "al-723"} + {:artistId "230" + :name "Ufordian Edits" + :songCount 1 + :created "2018-02-19T22:55:59.000Z" + :duration 331 + :artist "Peter Power" + :year 2015 + :id "393" + :coverArt "al-393"} + {:genre "Other" + :artistId "528" + :name "Dream Runner EP" + :songCount 6 + :created "2017-06-28T18:39:24.000Z" + :duration 899 + :artist "Annu" + :year 2009 + :id "948"} + {:genre "Techno" + :artistId "75" + :name "Unknown" + :songCount 8 + :created "2017-06-28T20:17:47.000Z" + :duration 2841 + :artist "Saschienne" + :year 2012 + :id "124" + :coverArt "al-124"} + {:genre "Nintendocore" + :artistId "306" + :name "Nach der Kippe Pogo!?" + :songCount 11 + :created "2017-06-28T18:40:09.000Z" + :duration 1508 + :artist "Antitainment" + :year 2007 + :id "532" + :coverArt "al-532"} + {:genre "Electronic" + :artistId "206" + :name "Swim" + :songCount 9 + :created "2017-11-25T20:06:58.000Z" + :duration 2596 + :artist "Caribou" + :year 2010 + :id "339" + :coverArt "al-339"} + {:genre "trance" + :artistId "117" + :name "Nymphs III" + :songCount 2 + :created "2017-06-28T20:04:17.000Z" + :duration 1080 + :artist "Nicolas Jaar" + :year 2015 + :id "201"} + {:genre "Gothic" + :artistId "403" + :name "Wish" + :songCount 12 + :created "2018-01-02T14:29:04.000Z" + :duration 3976 + :artist "The Cure" + :year 1992 + :id "685" + :coverArt "al-685"} + {:genre "Gothic" + :artistId "403" + :name "Show (Live)" + :songCount 18 + :created "2018-01-02T14:30:03.000Z" + :duration 5316 + :artist "The Cure" + :id "698" + :coverArt "al-698"} + {:genre "Gothic" + :artistId "403" + :name "Mixed Up" + :songCount 11 + :created "2018-01-02T14:29:43.000Z" + :duration 4260 + :artist "The Cure" + :year 1990 + :id "692" + :coverArt "al-692"} + {:id "1257" + :name "Saal" + :artist "Serengeti" + :artistId "678" + :songCount 13 + :duration 2437 + :created "2018-09-20T17:02:50.000Z" + :year 2013} + {:genre "Hip Hop" + :artistId "204" + :name "Leaders Of The Brew School" + :songCount 16 + :created "2017-06-28T18:45:16.000Z" + :duration 2214 + :artist "Betty Ford Boys" + :year 2013 + :id "331"} + {:id "202" + :name "Sirens" + :artist "Nicolas Jaar" + :artistId "117" + :songCount 7 + :duration 2841 + :created "2017-06-28T20:04:34.000Z" + :year 2016} + {:genre "techno" + :artistId "682" + :name "Piñata" + :songCount 21 + :created "2018-10-09T15:30:48.000Z" + :duration 3963 + :artist "Freddie Gibbs & Madlib" + :year 2014 + :id "1261" + :coverArt "al-1261"} + {:genre "electronic" + :artistId "681" + :name "We Must Become the Pitiless Censors of Ourselves" + :songCount 11 + :created "2018-10-08T17:21:47.000Z" + :duration 1916 + :artist "John Maus" + :year 2011 + :id "1260" + :coverArt "al-1260"} + {:artistId "514" + :name "Time" + :songCount 1 + :created "2017-07-24T13:19:05.000Z" + :duration 247 + :artist "Lokke" + :year 2015 + :id "923" + :coverArt "al-923"} + {:genre "jazz" + :artistId "680" + :name "These Things Take Time" + :songCount 13 + :created "2018-10-08T17:21:09.000Z" + :duration 3013 + :artist "Molly Nilsson" + :year 2008 + :id "1259" + :coverArt "al-1259"} + {:artistId "463" + :name "Songs of Love and Hate" + :songCount 4 + :created "2018-01-16T11:13:54.000Z" + :duration 1273 + :artist "Leonard Cohen" + :year 1970 + :id "829" + :coverArt "al-829"} + {:artistId "187" + :name "Vacation EP" + :songCount 7 + :created "2017-06-28T20:19:17.000Z" + :duration 1902 + :artist "Shlohmo" + :year 2012 + :id "305" + :coverArt "al-305"} + {:genre "Electronic" + :artistId "187" + :name "Vacation (Remixes)" + :songCount 6 + :created "2017-06-28T20:19:23.000Z" + :duration 3559 + :artist "Shlohmo" + :year 2012 + :id "303"} + {:genre "WeDidIt" + :artistId "302" + :name "Salvation Remixes" + :songCount 3 + :created "2017-06-28T20:14:04.000Z" + :duration 739 + :artist "Purple" + :year 2013 + :id "525" + :coverArt "al-525"} + {:genre "Alternative Rock / Indie Rock" + :artistId "16" + :name "Sleeping With Ghosts" + :songCount 22 + :created "2017-11-06T20:39:23.000Z" + :duration 5232 + :artist "Placebo" + :year 2003 + :id "38" + :coverArt "al-38"} + {:genre "Funk/Hip-Hop" + :artistId "198" + :name "Looking For the Perfect Beat" + :songCount 13 + :created "2017-06-28T18:36:47.000Z" + :duration 4521 + :artist "Afrika Bambaataa" + :year 2001 + :id "323" + :coverArt "al-323"} + {:artistId "103" + :name "edits & cuts" + :songCount 14 + :created "2017-06-28T19:37:20.000Z" + :duration 3550 + :artist "M.Rux" + :year 2014 + :id "182" + :coverArt "al-182"} + {:genre "Techno" + :artistId "117" + :name "Marks / Angles" + :songCount 3 + :created "2017-06-28T20:03:46.000Z" + :duration 1000 + :artist "Nicolas Jaar" + :year 2010 + :id "196"} + {:genre "Electronic" + :artistId "73" + :name "Don't Break My Love EP" + :songCount 2 + :created "2017-06-28T20:05:16.000Z" + :duration 673 + :artist "Nicolas Jaar & Theatre Roosevelt" + :year 2011 + :id "122" + :coverArt "al-122"} + {:genre "Electronic" + :artistId "233" + :name "Mother Earth's Plantasia" + :songCount 10 + :created "2018-05-28T21:31:55.000Z" + :duration 1837 + :artist "Mort Garson" + :year 1976 + :id "397" + :coverArt "al-397"} + {:genre "Psychedelic Rock" + :artistId "424" + :name + "Nuggets: Original Artyfacts From the First Psychedelic Era, 1965-1968" + :songCount 27 + :created "2018-02-21T12:01:38.000Z" + :duration 4614 + :artist "Various Artists" + :year 1998 + :id "743" + :coverArt "al-743"} + {:genre "Psychedelic Rock" + :artistId "37" + :name "Phluph" + :songCount 10 + :created "2018-03-05T16:31:46.000Z" + :duration 2182 + :artist "Phluph" + :year 2001 + :id "64" + :coverArt "al-64"} + {:genre "Rock" + :artistId "305" + :name "The Best of Talking Heads (Remastered)" + :songCount 18 + :created "2018-01-22T11:00:50.000Z" + :duration 4618 + :artist "Talking Heads" + :year 2004 + :id "529" + :coverArt "al-529"} + {:genre "Electronic" + :artistId "50" + :name "Divide And Exit" + :songCount 14 + :created "2018-01-21T14:47:59.000Z" + :duration 2417 + :artist "Sleaford Mods" + :year 2014 + :id "86" + :coverArt "al-86"} + {:genre "electronic" + :artistId "349" + :name "Fade to Grey: The Best of Visage" + :songCount 12 + :created "2018-08-29T13:01:26.000Z" + :duration 2757 + :artist "Visage" + :year 1993 + :id "1234"} + {:genre "electronic" + :artistId "334" + :name "Hounds of Love" + :songCount 18 + :created "2018-08-29T13:00:32.000Z" + :duration 4419 + :artist "Kate Bush" + :year 1997 + :id "1215" + :coverArt "al-1215"} + {:genre "Psychedelic" + :artistId "424" + :name + "Forge Your Own Chains: Heavy Psychedelic Ballads and Dirges 1968-1974" + :songCount 15 + :created "2018-01-27T12:23:47.000Z" + :duration 4241 + :artist "Various Artists" + :id "742" + :coverArt "al-742"} + {:genre "Live Archive" + :artistId "141" + :name "2017-08-28 Rough Trade NYC, Brooklyn, NY" + :songCount 4 + :created "2018-01-19T23:07:20.000Z" + :duration 2483 + :artist "Sunburned Hand of the Man" + :year 2017 + :id "242" + :coverArt "al-242"} + {:genre "electronic" + :artistId "236" + :name "Knock Knock" + :songCount 16 + :created "2018-06-09T23:04:20.000Z" + :duration 4710 + :artist "DJ Koze" + :year 2018 + :id "401" + :coverArt "al-401"} + {:genre "Nintendocore" + :artistId "306" + :name "Gymnasiastik mit Antitainment" + :songCount 6 + :created "2017-06-28T18:39:58.000Z" + :duration 795 + :artist "Antitainment" + :year 2004 + :id "533"} + {:genre "Electronic" + :artistId "584" + :name "Amok" + :songCount 9 + :created "2017-06-28T18:41:30.000Z" + :duration 2681 + :artist "Atoms for Peace" + :year 2013 + :id "1023" + :coverArt "al-1023"} + {:artistId "26" + :name "TamponTango I" + :songCount 3 + :created "2017-11-23T23:18:43.000Z" + :duration 851 + :artist "Diederdas" + :year 2017 + :id "51" + :coverArt "al-51"} + {:genre "electronic" + :artistId "679" + :name "Heaven and Earth" + :songCount 16 + :created "2018-09-20T22:07:23.000Z" + :duration 8672 + :artist "Kamasi Washington" + :year 2018 + :id "1258" + :coverArt "al-1258"} + {:genre "rhy" + :artistId "661" + :name "Yawn Zen" + :songCount 12 + :created "2018-08-21T21:36:43.000Z" + :duration 1883 + :artist "Mndsgn" + :year 2014 + :id "1200" + :coverArt "al-1200"} + {:genre "Rap" + :artistId "677" + :name "Elephant Eyelash" + :songCount 12 + :created "2018-09-20T17:02:08.000Z" + :duration 2478 + :artist "Why?" + :year 2005 + :id "1256"} + {:genre "Electronic" + :artistId "41" + :name "Immunity" + :songCount 8 + :created "2017-06-28T19:28:24.000Z" + :duration 3604 + :artist "Jon Hopkins" + :year 2013 + :id "104" + :coverArt "al-104"} + {:genre "IDM / Trip-Hop / Experimental" + :artistId "454" + :name "New Energy" + :songCount 14 + :created "2017-11-25T19:44:56.000Z" + :duration 3381 + :artist "Four Tet" + :year 2017 + :id "800" + :coverArt "al-800"} + {:genre "Electronic" + :artistId "633" + :name "ƒIN (Special Edition)" + :songCount 20 + :created "2017-06-28T19:26:41.000Z" + :duration 5822 + :artist "John Talabot" + :year 2012 + :id "1159"} + {:artistId "412" + :name "A Moot Point" + :songCount 2 + :created "2017-06-28T18:32:24.000Z" + :duration 857 + :artist "Pional" + :year 2010 + :id "719" + :coverArt "al-719"} + {:id "740" + :name "KR Family EP, Pt. 1" + :artist "Peter Power" + :artistId "230" + :coverArt "al-740" + :songCount 3 + :duration 1333 + :created "2017-06-28T20:31:06.000Z"} + {:genre "House" + :artistId "482" + :name "Busy Days For Fools" + :songCount 11 + :created "2017-06-28T19:35:05.000Z" + :duration 3238 + :artist "Lee Burton" + :year 2012 + :id "866" + :coverArt "al-866"} + {:id "851" + :name "Ry & Frank Wiedemann" + :artist "Ry & Frank Wiedemann" + :artistId "472" + :songCount 1 + :duration 485 + :created "2017-06-28T18:34:23.000Z"} + {:genre "Electronic" + :artistId "58" + :name "Deep Cuts" + :songCount 17 + :created "2017-12-22T08:21:19.000Z" + :duration 3321 + :artist "The Knife" + :year 2003 + :id "96" + :coverArt "al-96"} + {:artistId "125" + :name "VIA Remixes" + :songCount 1 + :created "2017-06-28T18:27:59.000Z" + :duration 362 + :artist "Andi Otto" + :year 2017 + :id "211" + :coverArt "al-211"} + {:artistId "626" + :name "Hummingbird / Milk & Honey" + :songCount 2 + :created "2017-11-23T21:27:00.000Z" + :duration 303 + :artist "Luca Nieri" + :year 2016 + :id "1150" + :coverArt "al-1150"} + {:genre "Electronic" + :artistId "434" + :name "Mercy Street" + :songCount 2 + :created "2017-12-22T08:18:55.000Z" + :duration 568 + :artist "Fever Ray" + :year 2010 + :id "762" + :coverArt "al-762"} + {:artistId "43" + :name "2012-2017" + :songCount 11 + :created "2018-03-06T15:51:42.000Z" + :duration 3998 + :artist "A.A.L." + :year 2018 + :id "73" + :coverArt "al-73"} + {:genre "New Wave Music" + :artistId "337" + :name "Liaisons dangereuses" + :songCount 10 + :created "2018-08-29T13:00:42.000Z" + :duration 2392 + :artist "Liaisons Dangereuses" + :year 1985 + :id "1216"} + {:genre "Electro" + :artistId "434" + :name "Fever Ray" + :songCount 12 + :created "2017-12-22T08:19:04.000Z" + :duration 3380 + :artist "Fever Ray" + :year 2009 + :id "765"} + {:id "621" + :name "RSS Disco" + :artist "RSS Disco" + :artistId "358" + :songCount 2 + :duration 841 + :created "2018-04-25T10:11:14.000Z"} + {:genre "House" + :artistId "358" + :name "Very" + :songCount 3 + :created "2017-06-28T20:17:12.000Z" + :duration 1339 + :artist "RSS Disco" + :year 2012 + :id "624" + :coverArt "al-624"} + {:genre "Disco" + :artistId "619" + :name "Sir John" + :songCount 1 + :created "2018-03-12T20:21:14.000Z" + :duration 419 + :artist "White Elephant" + :year 2011 + :id "1134" + :coverArt "al-1134"} + {:genre "House" + :artistId "434" + :name "Sidetracked" + :songCount 1 + :created "2017-06-28T18:20:10.000Z" + :duration 270 + :artist "Fever Ray" + :year 2012 + :id "920" + :coverArt "al-920"} + {:genre "Electronic" + :artistId "58" + :name "Hannah Med H Soundtrack" + :songCount 16 + :created "2017-12-22T08:21:33.000Z" + :duration 2307 + :artist "The Knife" + :year 2003 + :id "97" + :coverArt "al-97"} + {:genre "Alternative Rock" + :artistId "478" + :name "6 Feet Beneath the Moon" + :songCount 14 + :created "2017-09-08T17:37:16.000Z" + :duration 3136 + :artist "King Krule" + :year 2013 + :id "859" + :coverArt "al-859"} + {:artistId "103" + :name "Joga / Crazy Junker 7\"" + :songCount 2 + :created "2017-06-28T19:37:31.000Z" + :duration 442 + :artist "M.Rux" + :year 2014 + :id "177" + :coverArt "al-177"} + {:genre "House" + :artistId "267" + :name "Carat EP" + :songCount 5 + :created "2017-06-28T20:08:58.000Z" + :duration 2080 + :artist "Nu" + :year 2013 + :id "467"} + {:artistId "419" + :name "On Claws (reissue)" + :songCount 1 + :created "2017-07-24T13:48:20.000Z" + :duration 176 + :artist "I am Oak" + :year 2013 + :id "733" + :coverArt "al-733"} + {:genre "Indie Dance / Nu Disco" + :artistId "214" + :name "Thinking Allowed" + :songCount 1 + :created "2018-01-02T18:54:41.000Z" + :duration 430 + :artist "Tornado Wallace" + :year 2013 + :id "354" + :coverArt "al-354"} + {:artistId "629" + :name "V.I.C.T.O.R" + :songCount 1 + :created "2017-06-28T18:25:45.000Z" + :duration 279 + :artist "Golden Bug" + :year 2016 + :id "1153" + :coverArt "al-1153"} + {:genre "Avant-Garde" + :artistId "256" + :name "Ende Neu" + :songCount 9 + :created "2017-06-28T19:09:43.000Z" + :duration 2693 + :artist "Einstürzende Neubauten" + :year 1998 + :id "426" + :coverArt "al-426"} + {:genre "House" + :artistId "245" + :name "Visibles" + :songCount 4 + :created "2017-06-28T18:57:22.000Z" + :duration 1556 + :artist "Constantijn Lange" + :year 2014 + :id "413" + :coverArt "al-413"} + {:artistId "245" + :name "Orange Atlas" + :songCount 5 + :created "2017-06-28T18:57:08.000Z" + :duration 2171 + :artist "Constantijn Lange" + :year 2013 + :id "412" + :coverArt "al-412"} + {:artistId "146" + :name "Mapping The Futures Gone By" + :songCount 7 + :created "2017-06-28T18:57:28.000Z" + :duration 1536 + :artist "CONTACT FIELD ORCHESTRA" + :year 2015 + :id "247" + :coverArt "al-247"} + {:genre "electronic" + :artistId "253" + :name "It's Album Time" + :songCount 12 + :created "2018-09-04T14:25:00.000Z" + :duration 3555 + :artist "Todd Terje" + :year 2014 + :id "1254" + :coverArt "al-1254"} + {:genre "electronic" + :artistId "676" + :name "The Big Cover-Up" + :songCount 8 + :created "2018-09-04T14:44:38.000Z" + :duration 3130 + :artist "Todd Terje & The Olsens" + :year 2016 + :id "1255" + :coverArt "al-1255"} + {:genre "electronic" + :artistId "424" + :name "I-Robots: Italo Electro Disco Underground Classics" + :songCount 13 + :created "2018-08-29T13:01:11.000Z" + :duration 4797 + :artist "Various Artists" + :year 2004 + :id "1217"} + {:genre "Electronic" + :artistId "497" + :name "Creature Dreams" + :songCount 7 + :created "2017-06-28T20:27:36.000Z" + :duration 1709 + :artist "TOKiMONSTA" + :year 2011 + :id "897"} + {:genre "Other" + :artistId "466" + :name "Brighton Beach (Freddie Joachim Remix)" + :songCount 1 + :created "2017-06-28T18:34:34.000Z" + :duration 187 + :artist "Télépopmusik" + :year 2011 + :id "838"} + {:genre "Hip-Hop" + :artistId "234" + :name "Viktor Vaughn - Vaudeville Villain" + :songCount 30 + :created "2017-06-28T20:45:05.000Z" + :duration 6039 + :artist "MF Doom" + :year 2012 + :id "1079" + :coverArt "al-1079"} + {:genre "Hip-Hop" + :artistId "234" + :name "King Geedorah - Take Me To Your Leader" + :songCount 13 + :created "2017-06-28T20:44:03.000Z" + :duration 2514 + :artist "MF Doom" + :year 2003 + :id "1078" + :coverArt "al-1078"} + {:genre "electronic" + :artistId "667" + :name "Solid State Survivor" + :songCount 8 + :created "2018-08-29T13:02:20.000Z" + :duration 1921 + :artist "Yellow Magic Orchestra" + :year 1979 + :id "1231"} + {:genre "electronic" + :artistId "666" + :name "Technodon" + :songCount 12 + :created "2018-08-29T13:02:40.000Z" + :duration 3806 + :artist "Y̶M̶O̶" + :year 1993 + :id "1224"} + {:genre "Alternative Hip Hop" + :artistId "669" + :name "Unicron" + :songCount 6 + :created "2018-08-29T13:45:33.000Z" + :duration 887 + :artist "MF DOOM & Trunks" + :year 2008 + :id "1235" + :coverArt "al-1235"} + {:genre "Alternative Hip Hop" + :artistId "650" + :name "Special Herbs, Volume 5 & 6" + :songCount 13 + :created "2018-08-29T13:45:33.000Z" + :duration 2760 + :artist "Metal Fingers" + :year 2004 + :id "1248" + :coverArt "al-1248"} + {:genre "Alternative Hip Hop" + :artistId "650" + :name "Special Herbs, Volume 3 & 4" + :songCount 16 + :created "2018-08-29T13:45:43.000Z" + :duration 3054 + :artist "Metal Fingers" + :year 2003 + :id "1251" + :coverArt "al-1251"} + {:genre "electronic" + :artistId "650" + :name "Special Herbs, Volume 9 & 0" + :songCount 13 + :created "2018-08-29T13:45:57.000Z" + :duration 2751 + :artist "Metal Fingers" + :year 2005 + :id "1249" + :coverArt "al-1249"} + {:genre "electronic" + :artistId "650" + :name "Special Herbs, Volume 7 & 8" + :songCount 13 + :created "2018-08-29T13:46:07.000Z" + :duration 2680 + :artist "Metal Fingers" + :year 2004 + :id "1250" + :coverArt "al-1250"} + {:genre "raphiphop" + :artistId "674" + :name "Key to the Kuffs" + :songCount 15 + :created "2018-08-29T13:46:12.000Z" + :duration 2520 + :artist "JJ DOOM" + :year 2012 + :id "1245" + :coverArt "al-1245"} + {:genre "Hip Hop Music" + :artistId "647" + :name "The Prof. Meets the Supervillain" + :songCount 5 + :created "2018-08-29T13:46:19.000Z" + :duration 829 + :artist "MF DOOM" + :year 2003 + :id "1244" + :coverArt "al-1244"} + {:genre "Hip Hop Music" + :artistId "647" + :name "Vomit" + :songCount 6 + :created "2018-08-29T13:46:24.000Z" + :duration 1254 + :artist "MF DOOM" + :year 2006 + :id "1241" + :coverArt "al-1241"} + {:genre "Hip-Hop" + :artistId "670" + :name "Victory Laps" + :songCount 6 + :created "2018-08-29T13:46:34.000Z" + :duration 1026 + :artist "DOOMSTARKS" + :year 2011 + :id "1237" + :coverArt "al-1237"} + {:genre "rock" + :artistId "672" + :name "(VV:2) Venomous Villain" + :songCount 12 + :created "2018-08-29T13:46:36.000Z" + :duration 1976 + :artist "Viktor Vaughn" + :year 2004 + :id "1242" + :coverArt "al-1242"} + {:genre "Hip Hop Music" + :artistId "671" + :name "Air" + :songCount 5 + :created "2018-08-29T13:46:39.000Z" + :duration 803 + :artist "Dabrye" + :year 2006 + :id "1238" + :coverArt "al-1238"} + {:id "984" + :name "The Wicker Man" + :artist "The Wicker Man" + :artistId "553" + :coverArt "al-984" + :songCount 1 + :duration 243 + :created "2017-06-28T20:06:58.000Z"}]}}) \ No newline at end of file diff --git a/test/cljs/airsonic_ui/components/library/subs_test.cljs b/test/cljs/airsonic_ui/components/library/subs_test.cljs new file mode 100644 index 0000000..847def2 --- /dev/null +++ b/test/cljs/airsonic_ui/components/library/subs_test.cljs @@ -0,0 +1,33 @@ +(ns airsonic-ui.components.library.subs-test + (:require [cljs.test :refer-macros [deftest testing is]] + [airsonic-ui.config :as conf] + [airsonic-ui.components.library.fixtures :as fixtures] + [airsonic-ui.components.library.subs :as sub])) + +(deftest partition-library + (testing "Should give us a map of page -> content" + (let [pages (sub/partition-responses "recent" fixtures/responses)] + (is (map? pages)) + (is (every? int? (keys pages))) + (is (every? seq? (vals pages))))) + (testing "Should map each response correctly to a page" + (let [first-response (select-keys fixtures/responses [["getAlbumList2" {:type "recent", :size 100, :offset 0}]])] + (is (= (range 5) (keys (sub/partition-responses "recent" first-response))))) + (let [first-and-third (select-keys fixtures/responses [["getAlbumList2" {:type "recent", :size 100, :offset 0}] + ["getAlbumList2" {:type "recent", :size 100, :offset 40}]])] + ;; there will be overlapping content for pages 2, 3 and 4 (with a zero-based index) + (is (= (range 7) (keys (sub/partition-responses "recent" first-and-third))))))) + +(deftest paginated-library + (testing "Should humanize page offsets" + (let [responses (select-keys fixtures/responses [["getAlbumList2" {:type "recent", :size 100, :offset 0}]]) + paginated (sub/paginated-library responses [:sub/paginated-library "recent"])] + (is (= [1 2 3 4 5] (keys paginated))))) + (testing "Should concatenate and deduplicate all album list responses" + (let [responses (select-keys fixtures/responses [["getAlbumList2" {:type "recent", :size 100, :offset 0}] + ["getAlbumList2" {:type "recent", :size 100, :offset 20}] + ["getAlbumList2" {:type "recent", :size 100, :offset 40}]]) + paginated (sub/paginated-library responses [:sub/paginated-library "recent"])] + (is (= [1 2 3 4 5 6 7] (keys paginated))) + (is (= 140 (count (mapcat val paginated)))) + (is (= 140 (count (set (mapcat val paginated)))))))) diff --git a/test/cljs/airsonic_ui/events_test.cljs b/test/cljs/airsonic_ui/events_test.cljs new file mode 100644 index 0000000..56db73e --- /dev/null +++ b/test/cljs/airsonic_ui/events_test.cljs @@ -0,0 +1,136 @@ +(ns airsonic-ui.events-test + (:require [cljs.test :refer [deftest testing is]] + [clojure.string :as str] + [airsonic-ui.test-helpers :refer [dispatches?]] + [airsonic-ui.fixtures :as fixtures] + [airsonic-ui.db :as db] + [airsonic-ui.routes :as routes] + [airsonic-ui.events :as events] + [airsonic-ui.subs :as subs] + )) + +(enable-console-print!) + +;; the event tests are actually quite nice to write: +;; because everything in re-frame is described as data, we pass on coeffects +;; to event handler after event handler and check if the final coeffect map +;; looks as expected. + +(defn no-previous-session [] (events/initialize-app {} [::events/initialize-app])) +(defn has-previous-session [] (-> {:store {:credentials fixtures/credentials}} + (events/initialize-app [::events/initialize-app]))) + +(deftest app-initialization + (testing "Should set up notifications" + (is (map? (subs/notifications (:db (no-previous-session)) + [::subs/notifications]))) + (is (map? (subs/notifications (:db (has-previous-session)) + [::subs/notifications])))) + (testing "Should set up the default database") + (testing "Should initialize credential verification" + (is (false? (dispatches? (no-previous-session) :credentials/verify))) + (is (true? (dispatches? (has-previous-session) [:credentials/verify fixtures/credentials])))) + (testing "Should initialize the router" + (is (contains? (no-previous-session) :routes/start-routing)) + (is (contains? (has-previous-session) :routes/start-routing)))) + +(deftest credential-verification + (testing "Should fail when there are no credentials" + (is (false? (dispatches? (-> (no-previous-session) + (events/verify-credentials [:credentials/verify nil])) [::subs/is-booting?])))) + (testing "Should happen server-side when we have credentials" + (let [cofx (-> (has-previous-session) + (events/verify-credentials [:credentials/verify fixtures/credentials]))] + (is (true? (dispatches? cofx :credentials/send-authentication-request))))) + (testing "Should verify the structure of credentials" + (let [empty-creds {:store {:credentials {}}}] + (is (false? (boolean (dispatches? empty-creds :credentials/send-authentication-request))))) + (let [malformed {:store {:credentials {:xyz #{12 34 56}}}}] + (is (false? (boolean (dispatches? malformed :credentials/send-authentication-request))))))) + +(deftest authentication-request + (let [event [:credentials/send-authentication-request fixtures/credentials] + fx (events/authentication-request {} event) + request (:http-xhrio fx)] + (testing "uses correct server url" + (let [uri (:uri request)] + (is (str/starts-with? uri (:server fixtures/credentials))) + (is (str/includes? uri "/getUser")) + (is (str/includes? uri (str "p=" (:p fixtures/credentials)))) + (is (str/includes? uri (str "u=" (:u fixtures/credentials)))) + (is (str/includes? uri (str "username=" (:u fixtures/credentials)))))) + (testing "invokes correct callback on server response" + (is (= [:credentials/authentication-response fixtures/credentials] (:on-success request)))) + (testing "invokes correct callback when server is not reachable" + (is (= [:api.response/failed] (:on-failure request)))))) + +(deftest authentication-response + (testing "On success" + (let [cofx (-> (has-previous-session) + (events/authentication-response [:credentials/authentication-response (:auth-success fixtures/responses)]) + (events/authentication-success [:credentials/authentication-success fixtures/credentials (:auth-success fixtures/responses)]))] + (testing "should mark the credentials as verified" + (is (true? (get-in cofx [:db :credentials :verified?])))) + (testing "should store the credentials in localstorage" + (let [stored-credentials (get-in cofx [:store :credentials])] + (is (= fixtures/credentials stored-credentials)))))) + (testing "On failure" + (let [cofx (-> (has-previous-session) + (events/authentication-response [:credentials/authentication-response (:auth-failure fixtures/responses)]) + (events/authentication-failure [:credentials/authentication-failure (:auth-failure fixtures/responses)]))] + (testing "should display a notification to the user" + (is (true? (dispatches? cofx :notification/show))))))) + +(deftest manual-login + (let [{:keys [u p server]} fixtures/credentials + credentials (assoc fixtures/credentials :verified? false) + effect (events/user-login {} [:credentials/user-login u p server])] + (testing "Should save the credentials as unverified" + + (is (= credentials (get-in effect [:db :credentials])))) + (testing "Should start the authentication request" + (is (true? (dispatches? effect [:credentials/send-authentication-request credentials])))))) + +(deftest logout + (let [fx (events/logout {} [:_])] + (testing "Should clear all stored data" + (is (nil? (:store fx)))) + (testing "Should redirect to the login screen" + (is (dispatches? fx [:routes/do-navigation [::routes/login]]))) + (testing "Should reset the app-db" + (is (= db/default-db (:db fx)))) + (testing "Should stop currently playing songs" + (is (contains? fx :audio/stop)))) + (testing "Should be able to keep a redirection parameter" + (let [redirect [:route {:with-data #{1 2 3 4 5}}] + navigation-event (:dispatch (events/logout {} [:_ :redirect-to redirect]))] + (is (= :routes/do-navigation (first navigation-event))) + (let [[route-id _ query] (second navigation-event)] + (is (= ::routes/login route-id)) + (is (contains? query :redirect)))))) + +(defn- first-notification [fx] + (-> (get-in fx [:db :notifications]) vals first)) + +(deftest user-notifications + (testing "Should be able to display a message with an assigned level" + (is (= :error (:level (first-notification (events/show-notification {} [:_ :error "foo"]))))) + (is (= :info (:level (first-notification (events/show-notification {} [:_ :info "some other message"])))))) + (testing "Should default to level :info" + (is (= :info (:level (first-notification (events/show-notification {} [:_ "and another one"])))))) + (testing "Should create a unique id for each message" + (let [state (-> + {} + (events/show-notification [:_ :info "Something something"]) + (events/show-notification [:_ :error "Something important"])) + ids (keys (:notifications state))] + (is (= (count ids) (count (set ids)))))) + (testing "Should remove a message, given it's id" + (let [state (events/show-notification {} [:_ "This is a notification"]) + id (-> (:notifications state) + keys + first)] + (is (empty? (:notifications (events/hide-notification state [:_ id])))))) + (testing "Should automatically remove a message after a while" + (let [fx (events/show-notification {} [:_ :info "This is a notification"])] + (is (= :notification/hide (-> (:dispatch-later fx) first :dispatch first)))))) diff --git a/test/cljs/airsonic_ui/fixtures.cljs b/test/cljs/airsonic_ui/fixtures.cljs new file mode 100644 index 0000000..9cc247a --- /dev/null +++ b/test/cljs/airsonic_ui/fixtures.cljs @@ -0,0 +1,115 @@ +(ns airsonic-ui.fixtures) + +(def credentials {:u "username" + :p "cleartext-password" + :server "https://demo.airsonic.io"}) + +(def responses {:error {:subsonic-response + {:error {:code 50 + :message "Incompatible Airsonic REST protocol version. Server must upgrade."} + :status "failed" + :version "1.15.0"}} + :ok {:subsonic-response + {:scanStatus {:count 10326 + :scanning false} + :status "ok" + :version "1.15.0"}} + :ping-success {:subsonic-response {:status "ok" + :version "1.15.0"}} + :auth-success {:subsonic-response + {:status "ok", + :version "1.15.0", + :user + {:videoConversionRole false, + :playlistRole true, + :shareRole true, + :podcastRole true, + :email "admin@example.com", + :streamRole true, + :folder [0], + :username "admin", + :scrobblingEnabled false, + :adminRole true, + :settingsRole true, + :commentRole true, + :jukeboxRole true, + :coverArtRole true, + :downloadRole true, + :maxBitRate 320, + :uploadRole true}}} + :auth-failure {:subsonic-response {:status "failed" + :version "1.15.0" + :error {:code 40 + :message "Wrong username or password."}}}}) + +(def artist + {:id "499", :name "Tomemitsu", :coverArt "ar-497", :albumCount 1}) + +(def album + {:artistId "258", + :name "Tocotronic", + :songCount 26, + :created "2017-12-31T08:18:45.000Z", + :duration 7383, + :artist "Tocotronic", + :year 2015, + :id "439", + :coverArt "al-439"}) + +(def song + {:artistId 42, + :path "DJ Koze/DJ Koze - Reincarnations Part 2, The Remix Chapter 2009-2014/14. Apparat - Black Water (DJ Koze Remix).mp3", + :suffix "mp3", + :isDir false, + :bitRate 320, + :parent 3556, + :albumId 382, + :type "music", + :created "2017-06-28T19:07:02.000Z", + :duration 317, + :artist "Apparat", + :isVideo false, + :size 12850290, + :title "Black Water (DJ Koze Remix)", + :playCount 0 + :year 2014, + :id 3562, + :coverArt 3556, + :contentType "audio/mpeg", + :album "Reincarnations, Pt. 2 - The Remix Chapter 2009 - 2014", + :track 14}) + +(def playback-status + {:ended? false + :loop? false + :muted? false + :paused? false + :current-src "https://londe.arnes.space/rest/stream?f=json&c=airsonic-ui-cljs&v=1.15.0&id=9574&u=arne&p=27h-%25bO%5B8-.ys%40SQ%7Bg%24-%5B5NZkX%7Dw%24NNwY%263DPATi%2CgaFoH%40e" + :current-time 3.477029}) + +(def podcast-episode + {:genre "Vocal", + :description + "Themen der Sendung: Druck auf Maaßen nach Äußerungen zu Chemnitz wächst, Köthen: 22-Jähriger stirbt nach Streit an Herzversagen, Parlamentswahl in Schweden, Russland und Syrien setzen Luftangriffe auf syrische Provinz Idlib fort, Tote und Verletzte bei Ausschreitungen im irakischem Basra, Nordkorea feiert 70. Jubiläum seiner Staatsgründung, Zahl der Toten nach Erdbeben in Japan steigt auf 39, Pläne von CDU und CSU: Fluggesellschaften sollen Auskunft über Verspätungen geben, Menschenkette in Dangast als Zeichen gegen Flüchtlingssterben im Mittelmeer, Das Wetter", + :suffix "mp3", + :isDir false, + :bitRate 64, + :parent "10409", + :channelId "4", + :type "podcast", + :created "2018-09-09T19:41:13.000Z", + :duration 965, + :artist "Tagesschau (Audio-Podcast)", + :isVideo false, + :publishDate "2018-09-09T18:00:00.000Z", + :size 7812758, + :title "09.09.2018 - tagesschau 20:00 Uhr", + :playCount 0, + :year 2018, + :streamId "11181", + :status "completed", + :id "507", + :coverArt "10409", + :contentType "audio/mpeg", + :album "tagesschau", + :track 1}) diff --git a/test/cljs/airsonic_ui/helpers_test.cljs b/test/cljs/airsonic_ui/helpers_test.cljs new file mode 100644 index 0000000..6b6023f --- /dev/null +++ b/test/cljs/airsonic_ui/helpers_test.cljs @@ -0,0 +1,34 @@ +(ns airsonic-ui.helpers-test + (:require [cljs.test :refer [deftest testing is]] + [airsonic-ui.helpers :as helpers])) + +(deftest add-classes + (testing "Should add classes to a simple hiccup keyword" + (is (= :div.foo (helpers/add-classes :div :foo))) + (is (= :div.bar.bar (helpers/add-classes :div.bar :bar))) + (is (= :div.foo.bar (helpers/add-classes :div.foo :bar)))) + (testing "Should add classes to the innermost child of a nested hiccup element" + (is (= :p>input.input (helpers/add-classes :p>input :input))) + (is (= :div.field>p>input.input.has-background-red (helpers/add-classes :div.field>p>input.input :has-background-red))))) + +(deftest kebabify + (testing "Should turn camelCased and PascalCased strings into kebab-cased keywords" + (is (= :hello-world (helpers/kebabify "HelloWorld"))) + (is (= :how-are-you (helpers/kebabify "howAreYou"))) + (is (= :foobar (helpers/kebabify "foobar")))) + (testing "Should kebab-case camelCased and PascalCased keywords" + (is (= :hello-world (helpers/kebabify :HelloWorld))) + (is (= :how-are-you (helpers/kebabify :howAreYou))) + (is (= :foobar (helpers/kebabify :foobar))))) + +(deftest format-duration + (testing "Should format hours, minutes and seconds" + (is (= "1h" (helpers/format-duration 3600))) + (is (= "59m" (helpers/format-duration (* 59 60)))) + (is (= "1m" (helpers/format-duration 60))) + (is (= "5s" (helpers/format-duration 5)))) + (testing "Should respect the :brief? option" + (is (= "01:00:00" (helpers/format-duration 3600 :brief? true))) + (is (= "59:00" (helpers/format-duration (* 59 60) :brief? true))) + (is (= "01:00" (helpers/format-duration 60 :brief? true))) + (is (= "00:05" (helpers/format-duration 5 :brief? true))))) diff --git a/test/cljs/airsonic_ui/routes_test.cljs b/test/cljs/airsonic_ui/routes_test.cljs new file mode 100644 index 0000000..055862f --- /dev/null +++ b/test/cljs/airsonic_ui/routes_test.cljs @@ -0,0 +1,23 @@ +(ns airsonic-ui.routes-test + (:require [airsonic-ui.routes :as routes] + [cljs.test :refer [deftest testing is]])) + +(def fixtures + {:default [::route {:some :data} {:some-more true}]}) + +#_(deftest permission-checking + (testing "Should succeed for unprotected routes" + (testing "without credentials") + (testing "with unverified credentials")) + (testing "Should fail for protected routes" + (testing "without credentials") + (testing "with unverified credentials")) + (testing "Should succeed for protected routes with verified credentials")) + +(deftest route-encoding + (testing "Should return a string with hash-compatible characters" + (let [encoded (routes/encode-route (:default fixtures))] + (is (string? encoded)) + (is (re-matches #"^[^#?&=]+$" encoded)))) + (testing "Should be bijective" + (is (= (:default fixtures) (routes/decode-route (routes/encode-route (:default fixtures))))))) diff --git a/test/cljs/airsonic_ui/subs_test.cljs b/test/cljs/airsonic_ui/subs_test.cljs new file mode 100644 index 0000000..9549fbf --- /dev/null +++ b/test/cljs/airsonic_ui/subs_test.cljs @@ -0,0 +1,66 @@ +(ns airsonic-ui.subs-test + (:require [cljs.test :refer [deftest testing is]] + [airsonic-ui.fixtures :as fixtures] + [airsonic-ui.api.helpers :as api] + [airsonic-ui.events :as events] + [airsonic-ui.subs :as subs])) + +(deftest booting + (let [route [:some-route nil nil] + verified-credentials (assoc fixtures/credentials :verified? true) + is-booting? (fn is-booting? [db] + (subs/is-booting? db [:subs/is-booting?]))] + (testing "Should be false when we don't have previous credentials" + (is (not (is-booting? {:routes/current-route route}))) + (is (not (is-booting? {:routes/current-route route + :credentials {}}))) ) + (testing "Should be true when we have unverified credentials" + (is (true? (is-booting? {:routes/current-route route + :credentials fixtures/credentials})))) + (testing "Should be false when we have verified credentials" + (is (not (is-booting? {:routes/current-route route + :credentials verified-credentials})))) + (testing "Should be true when routing is not yet set up" + (is (true? (is-booting? {:routes/current-route nil + :credentials verified-credentials})))) + (testing "Should be false when an error occurred" + (is (false? (is-booting? (:db (events/show-notification {} [:_ :error "Something bad happened"])))))))) + +(deftest cover-images + (let [credentials {:server "https://foo.bar" + :u "test-user" + :p "some-random-password"}] + (testing "Should give the correct path once the credentials are set" + (is (= (api/cover-url credentials fixtures/song 48) + (subs/cover-url credentials [:subs/cover-image fixtures/song 48])))))) + +(def successful-auth-db + "For the details see event_test.cljs" + (-> {:store {:credentials fixtures/credentials}} + (events/initialize-app [::events/initialize-app]) + (events/authentication-response [:credentials/authentication-response (:auth-success fixtures/responses)]) + (events/authentication-success [:credentials/authentication-success fixtures/credentials (:auth-success fixtures/responses)]) + (:db))) + +(deftest user-roles + (testing "Should be available after a successful authentication" + (let [user-roles (-> (subs/user-info successful-auth-db [:user/info]) + (subs/user-roles [:user/roles]))] + (is (set? user-roles)) + (is (every? keyword? user-roles)) + (is (not (user-roles :username)) "and contain only roles"))) + (testing "Should indicate whether a user has a given role" + (letfn [(role [role] + (-> (subs/user-info successful-auth-db [:user/info]) + (subs/user-roles [:user/roles]) + (disj :admin) ; <- makes sure we're not allowed everything + (subs/user-role [:user/role role])))] + (is (some? (role :stream))) + (is (not (some? (role :video-conversion)))))) + (testing "Should allow everything to an admin" + (letfn [(admin-role [role] + (-> (subs/user-info successful-auth-db [:user/info]) + (subs/user-roles [:user/roles]) + (subs/user-role [:user/role role])))] + (is (some? (admin-role :stream))) + (is (some? (admin-role :video-conversion)))))) diff --git a/test/cljs/airsonic_ui/test_helpers.cljs b/test/cljs/airsonic_ui/test_helpers.cljs new file mode 100644 index 0000000..a03b67e --- /dev/null +++ b/test/cljs/airsonic_ui/test_helpers.cljs @@ -0,0 +1,35 @@ +(ns airsonic-ui.test-helpers) + +(defn dispatches? + "Helper to see whether an event is dispatched in a coeffect; `ev` can either + be a whole vector or a keyword which is interpreted as the event name." + [cofx ev] + (let [all-events (conj (get cofx :dispatch-n []) (:dispatch cofx))] + (boolean (some #(= ev (if (vector? ev) % (first %))) all-events)))) + +(defn rand-str + "Generates a random string; ported from https://stackoverflow.com/a/27747377/2345852" + ([] (rand-str 40)) + ([len] + (let [arr (js/Uint8Array. (/ len 2))] + (.. js/window -crypto (getRandomValues arr)) + (.. js/Array + (from arr #(-> (str 0 (.toString % 16)) + (.substr -2))) + (join ""))))) + +(defn song [] + (hash-map :id (rand-int 9999) + :coverArt (rand-int 9999) + :year (+ 1900 (rand-int 118)) + :artist (rand-str) + :artistId (rand-int 100000) + :title (rand-str) + :album (rand-str))) + +(defn song-queue + "Generates a seq of n different songs" + [n] + (let [r-int (atom 0)] + (with-redefs [rand-int #(mod (swap! r-int inc) %1)] + (repeatedly n song)))) diff --git a/test/cljs/airsonic_ui/test_helpers_test.cljs b/test/cljs/airsonic_ui/test_helpers_test.cljs new file mode 100644 index 0000000..ec7153c --- /dev/null +++ b/test/cljs/airsonic_ui/test_helpers_test.cljs @@ -0,0 +1,24 @@ +(ns airsonic-ui.test-helpers-test + (:require [cljs.test :refer [deftest testing is]] + [airsonic-ui.test-helpers :as h])) + +(deftest dispatch-helper + (testing "Should identify singly dispatched events" + (is (false? (h/dispatches? {} :foo))) + (is (true? (h/dispatches? {:dispatch [:foo 1 2 3]} :foo))) + (is (false? (h/dispatches? {:dispatch [:foo 1 2 3]} :bar))) + (is (true? (h/dispatches? {:dispatch [:foo 1 2 3]} [:foo 1 2 3]))) + (is (false? (h/dispatches? {:dispatch [:foo 1 2 3]} [:bar 2 3])))) + (testing "Should identify an event along multiple dispatched events" + (is (false? (h/dispatches? {:dispatch-n [[:bar]]} :foo))) + (is (true? (h/dispatches? {:dispatch-n [[:foo 1 2 3]]} :foo))) + (is (false? (h/dispatches? {:dispatch-n [[:foo 1 2 3]]} :bar))) + (is (h/dispatches? {:dispatch-n [[:foo 1 2 3]]} [:foo 1 2 3])) + (is (false? (h/dispatches? {:dispatch-n [[:foo 1 2 3]]} [:bar 2 3]))))) + +(deftest rand-str + (testing "Generates strings" + (is (string? (h/rand-str))) + (is (string? (h/rand-str 20)))) + (testing "Should respect the length for even lengths" + (is (= 124 (count (h/rand-str 124)))))) diff --git a/test/cljs/bulma/dropdown_test.cljs b/test/cljs/bulma/dropdown_test.cljs new file mode 100644 index 0000000..005daa1 --- /dev/null +++ b/test/cljs/bulma/dropdown_test.cljs @@ -0,0 +1,40 @@ +(ns bulma.dropdown-test + (:require [cljs.test :refer-macros [deftest testing is]] + [bulma.dropdown.subs :as sub] + [bulma.dropdown.events :as ev])) + +;; NOTE: Here as well; this code is very much like the modal code +;; Not sure whether to explicitly duplicate it or provide some smarter +;; abstraction that's harder to understand at first sight + +(enable-console-print!) + +(deftest bulma-dropdowns + (testing "Should create a collection of dropdowns if there is none" + (let [new-db (ev/show-dropdown {} [::ev/show :some-dropdown-id])] + (is (= :some-dropdown-id (sub/visible-dropdown new-db [::sub/visible-dropdown]))))) + (testing "Should hide other dropdowns when displaying a new one" + (let [dropdown-ids [:some-id-1 :some-id-2 :some-id-3] + new-db (reduce (fn [db dropdown-id] + (ev/show-dropdown db [::ev/show dropdown-id])) + {} dropdown-ids)] + (is (= :some-id-3 (sub/visible-dropdown new-db [::sub/visible-dropdown]))))) + (testing "Should remove a dropdown from the collection when we hide it" + (let [dropdown-ids [:some-id-1 :some-id-2 :some-id-3] + new-db (-> (reduce (fn [db dropdown-id] + (ev/show-dropdown db [::ev/show dropdown-id])) + {} dropdown-ids) + (ev/hide-dropdown [::ev/hide]))] + (is (not (some? (sub/visible-dropdown new-db [::sub/visible-dropdown])))))) + (testing "Should tell us about the visibility of a dropdown with a predicate" + (is (true? (-> (ev/show-dropdown {} [::ev/show :getting-repetitive]) + (sub/visible-dropdown [::sub/visible-dropdown]) + (sub/visible? [::sub/visible? :getting-repetitive]))))) + (testing "Dropdown toggling" + (is (true? (-> (ev/toggle-dropdown {} [::ev/toggle :some-generic-dropdown]) + (sub/visible-dropdown [::sub/visible-dropdown]) + (sub/visible? [::sub/visible? :some-generic-dropdown])))) + (is (not (true? (-> (ev/toggle-dropdown {} [::ev/toggle :some-generic-dropdown]) + (ev/toggle-dropdown [::ev/toggle :some-generic-dropdown]) + (sub/visible-dropdown [::sub/visible-dropdown]) + (sub/visible? [::sub/visible? :some-generic-dropdown]))))))) diff --git a/test/cljs/bulma/modal_test.cljs b/test/cljs/bulma/modal_test.cljs new file mode 100644 index 0000000..6079a99 --- /dev/null +++ b/test/cljs/bulma/modal_test.cljs @@ -0,0 +1,36 @@ +(ns bulma.modal-test + (:require [cljs.test :refer-macros [deftest testing is]] + [bulma.modal.subs :as sub] + [bulma.modal.events :as ev])) + +(enable-console-print!) + +(deftest bulma-modals + (testing "Should create a collection of modals if there is none" + (let [new-db (ev/show-modal {} [::ev/show :some-modal-id])] + (is (= :some-modal-id (sub/visible-modal new-db [::sub/visible-modal]))))) + (testing "Should hide other modals when displaying a new one" + (let [modal-ids [:some-id-1 :some-id-2 :some-id-3] + new-db (reduce (fn [db modal-id] + (ev/show-modal db [::ev/show modal-id])) + {} modal-ids)] + (is (= :some-id-3 (sub/visible-modal new-db [::sub/visible-modal]))))) + (testing "Should remove a modal from the collection when we hide it" + (let [modal-ids [:some-id-1 :some-id-2 :some-id-3] + new-db (-> (reduce (fn [db modal-id] + (ev/show-modal db [::ev/show modal-id])) + {} modal-ids) + (ev/hide-modal [::ev/hide]))] + (is (not (some? (sub/visible-modal new-db [::sub/visible-modal])))))) + (testing "Should tell us about the visibility of a modal with a predicate" + (is (true? (-> (ev/show-modal {} [::ev/show :getting-repetitive]) + (sub/visible-modal [::sub/visible-modal]) + (sub/visible? [::sub/visible? :getting-repetitive]))))) + (testing "Modal toggling" + (is (true? (-> (ev/toggle-modal {} [::ev/toggle :some-generic-modal]) + (sub/visible-modal [::sub/visible-modal]) + (sub/visible? [::sub/visible? :some-generic-modal])))) + (is (not (true? (-> (ev/toggle-modal {} [::ev/toggle :some-generic-modal]) + (ev/toggle-modal [::ev/toggle :some-generic-modal]) + (sub/visible-modal [::sub/visible-modal]) + (sub/visible? [::sub/visible? :some-generic-modal])))))))