diff --git a/.gitignore b/.gitignore index e4510e26f8a8144c334a2482ce947d5619da9ec5..866003313d4acd651e515f7c018a81749c37ac25 100755 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ classes/ selenium/.pytest_cache selenium/.venv selenium/tests/__pycache__ +selenium/.env diff --git a/Dockerfile b/Dockerfile index 9c7a35ff737b36c51ac70f1be1835a267f76d7f4..46ace0165ba0e9bcdfeadbb731f5e6c28d60a39a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -65,8 +65,8 @@ RUN echo '<?xml version="1.0" encoding="UTF-8"?>\ <resource-root path="postgis-jdbc-${POSTGIS_VERSION}.jar"/>\ </resources>\ <dependencies>\ - <module name="javax.api"/>\ - <module name="javax.transaction.api"/>\ + <module name="jakarta.api"/>\ + <module name="jakarta.transaction.api"/>\ </dependencies>\ </module>' > ${JBOSS_HOME}/modules/org/postgresql/main/module.xml RUN cp /root/.m2/repository/org/postgresql/postgresql/${POSTGRES_VERSION}/postgresql-${POSTGRES_VERSION}.jar ${JBOSS_HOME}/modules/org/postgresql/main diff --git a/NIBIO_OPEN_SOURCE_LICENSE_1.05.txt b/NIBIO_OPEN_SOURCE_LICENSE_1.05.txt deleted file mode 100755 index 98f5ab000c55833f24e593f2a8d5f3913aa64fc3..0000000000000000000000000000000000000000 --- a/NIBIO_OPEN_SOURCE_LICENSE_1.05.txt +++ /dev/null @@ -1,618 +0,0 @@ - NIBIO OPEN SOURCE LICENSE V.1.0 (2015) - - PREAMBLE AND ADDITIONAL TERMS - - The original licensor is the Norwegian Institute for Agricultural and -Environmental Research, registered in Norway with registration number 988 983 -837, and business address NO-1430 ÅS, NORWAY, hereafter referred to as -"NIBIO". - - This NIBIO OPEN SOURCE LICENSE V.1.0 (2015), in short the NIBIO Open -Source License, is based on the GNU Affero General Public License, version 3. -All of the terms and conditions of the GNU Affero General Public License, -version 3, have been set out below, save the below mentioned additional -prevailing terms that have priority over the terms otherwise identical to the -GNU Affero General Public License, version 3, and that Section 0 ("This -License" definition changed), 13 ("version 3 of the GNU General Public License" -replaced by "this License") and 14 ("The Free Software Foundation" replaced by -"NIBIO" and "GNU Affero General Public License" replaced by "License") have -been adjusted as a consequence of this. - - ADDITONAL PREVAILING TERMS - - (a) The NIBIO Open Source License regulates the NIBIO VIPS Platform -software, an Internet based system enabling prediction of infection risk of -plant diseases, pests and weeds. The NIBIO Open Source License DOES NOT -INCLUDE the specific forecasting models, neither their algorithms nor their -implementation to be used by the NIBIO VIPS Platform. You are free to -implement any other forecasting model to be used by the NIBIO VIPS Platform, -regardless of license terms at your own responsibility. - - (b) This license is governed by Norwegian law, as far as any party or third -party purports or sets forward any claim towards NIBIO. Any claims towards -NIBIO shall be solved by the exclusive venue of Oslo City Courts, Norway. -This paragraph is not applicable for claims only between any later parties to -this license. - - (c) By entering into this agreement you also agree to indemnify NIBIO and -its employees / consultants / board, for any claims of liability related to -this license set forward by yourself or any party deviating its rights from you. - - (d) You shall include the following in the start of each source file: - - Copyright (c) <year> <name of author> - - This file is part of <application name>. <application name> is free - software: you can redistribute it and/or modify it under the terms of - the NIBIO Open Source License as published by NIBIO, either - version 1 of the License, or (at your option) any later version. - - <application name> 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with <application name>. If not, see - <http://www.nibio.no/licenses/>. - - It is also recommended that you add information on how to contact you by - electronic and paper mail. - - 1. TERMS AND CONDITIONS - - 2. 0. Definitions. - - "This License" refers to NIBIO Open Source License v.1.0 (2015). - - "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. - - 3. 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. - - 4. 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. - - 5. 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. - - 6. 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. - - 7. 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. - - 8. 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. - - 9. 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. - - 10. 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. - - 11. 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. - - 12. 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. - - 13. 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. - - 14. 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. - - 15. 13. Remote Network Interaction; Use with the GNU General Public License. - - Notwithstanding any other provision of this License, if you modify the -Program, your modified version must prominently offer all users -interacting with it remotely through a computer network (if your version -supports such interaction) an opportunity to receive the Corresponding -Source of your version by providing access to the Corresponding Source -from a network server at no charge, through some standard or customary -means of facilitating copying of software. This Corresponding Source -shall include the Corresponding Source for any work covered by This License -that is incorporated pursuant to the following paragraph. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the work with which it is combined will remain governed by version -3 of the GNU General Public License. - - 16. 14. Revised Versions of this License. - - NIBIO may publish revised and/or new versions of the 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 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 -NIBIO. If the Program does not specify a version number of the License, you -may choose any version ever published by the NIBIO. - - If the Program specifies that a proxy can decide which future -versions of the 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. - - 17. 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. - - 18. 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. - - 19. 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 diff --git a/enunciate.xml b/enunciate.xml index 982546e640b0422cbafe6a054b12f91ccbf04902..0ff5edfb027c0e1c22abf29d793072043c27a6fc 100644 --- a/enunciate.xml +++ b/enunciate.xml @@ -31,7 +31,7 @@ <exclude pattern="uk.**"/> <exclude pattern="it.**"/> <exclude pattern="antlr.**"/> - <exclude pattern="javax.**"/> + <exclude pattern="jakarta.**"/> </api-classes> <facets> <exclude name="restricted"/> diff --git a/nb-configuration.xml b/nb-configuration.xml index 94cd76d9b5f7651929f5f9bde9d8c717ecc883bc..c76af05317c2465d804973a27423254533f65abc 100755 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -27,6 +27,6 @@ Any value defined here will override the pom.xml file value but is only applicab <org-netbeans-modules-projectapi.jsf_2e_language>Facelets</org-netbeans-modules-projectapi.jsf_2e_language> <netbeans.compile.on.save>none</netbeans.compile.on.save> <org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server>WildFly</org-netbeans-modules-maven-j2ee.netbeans_2e_hint_2e_deploy_2e_server> - <netbeans.hint.jdkPlatform>JDK_11</netbeans.hint.jdkPlatform> + <netbeans.hint.jdkPlatform>JDK_18</netbeans.hint.jdkPlatform> </properties> </project-shared-configuration> diff --git a/pom.xml b/pom.xml index 8257ca22d3bee77dbc2ddaeb0b2c446bbd93737b..1ef5028de0074c245a42e1cb0ddeb2e574334c03 100755 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,16 @@ -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" - xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> - +<parent> + <groupId>no.nibio.vips</groupId> + <artifactId>vips-parent-pom</artifactId> + <version>1.1.0</version> + </parent> <groupId>no.nibio.vips.</groupId> <artifactId>VIPSLogic</artifactId> <packaging>war</packaging> - <version>2024.1</version> + <version>2025.1</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> @@ -50,9 +55,13 @@ <name>Unidata Releases</name> <url>https://artifacts.unidata.ucar.edu/content/repositories/unidata-releases/</url> </repository> + <repository> + <id>gitlab-maven</id> + <url>https://gitlab.nibio.no/api/v4/projects/401/packages/maven</url> + </repository> </repositories> <dependencies> - + <dependency> <groupId>javax.xml.bind</groupId> <artifactId>jaxb-api</artifactId> @@ -70,27 +79,45 @@ <version>11.1.0</version> </dependency> <dependency> - <groupId>javax.servlet</groupId> - <artifactId>javax.servlet-api</artifactId> - <version>4.0.1</version> + <groupId>jakarta.platform</groupId> + <artifactId>jakarta.jakartaee-api</artifactId> + <version>10.0.0</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>jakarta.persistence</groupId> + <artifactId>jakarta.persistence-api</artifactId> + <version>3.2.0</version> + <scope>provided</scope> + </dependency> + + <dependency> + <groupId>jakarta.servlet</groupId> + <artifactId>jakarta.servlet-api</artifactId> + <version>6.1.0</version> <scope>test</scope> </dependency> + <dependency> + <groupId>com.sun.mail</groupId> + <artifactId>jakarta.mail</artifactId> + <version>2.0.1</version> + </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-client</artifactId> - <version>4.7.9.Final</version> + <version>6.2.11.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-core</artifactId> - <version>4.7.9.Final</version> + <version>6.2.11.Final</version> <scope>provided</scope> </dependency> <dependency> <groupId>org.jboss.resteasy</groupId> <artifactId>resteasy-jackson2-provider</artifactId> - <version>4.7.9.Final</version> + <version>6.2.11.Final</version> <scope>provided</scope> </dependency> <dependency> @@ -105,9 +132,9 @@ <type>jar</type> </dependency> <dependency> - <groupId>org.apache.httpcomponents</groupId> - <artifactId>httpclient</artifactId> - <version>4.5.14</version> + <groupId>org.apache.httpcomponents.client5</groupId> + <artifactId>httpclient5</artifactId> + <version>5.4.1</version> <type>jar</type> <scope>provided</scope> </dependency> @@ -153,7 +180,7 @@ <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> - <version>5.6.15.Final</version> + <version>6.6.1.Final</version> <exclusions> <exclusion> <groupId>org.dom4j</groupId> @@ -162,14 +189,10 @@ </exclusions> </dependency> <dependency> - <groupId>org.hibernate</groupId> + <groupId>org.hibernate.orm</groupId> <artifactId>hibernate-spatial</artifactId> - <version>5.6.15.Final</version> + <version>6.6.1.Final</version> <exclusions> - <exclusion> - <artifactId>postgresql</artifactId> - <groupId>postgresql</groupId> - </exclusion> <exclusion> <groupId>org.dom4j</groupId> <artifactId>dom4j</artifactId> @@ -180,8 +203,23 @@ <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> - <version>42.7.1</version> - <scope>provided</scope> + <version>42.7.4</version> + </dependency> + <dependency> + <groupId>net.postgis</groupId> + <artifactId>postgis-jdbc</artifactId> + <version>2024.1.0</version> + </dependency> + <dependency> + <groupId>net.postgis</groupId> + <artifactId>postgis-geometry</artifactId> + <version>2024.1.0</version> + </dependency> + + <dependency> + <groupId>io.hypersistence</groupId> + <artifactId>hypersistence-utils-hibernate-63</artifactId> + <version>3.9.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.datatype</groupId> @@ -209,26 +247,12 @@ <dependency> <groupId>no.nibio.vips</groupId> <artifactId>VIPSCommon</artifactId> - <version>2.0.3-SNAPSHOT</version> - </dependency> - <dependency> - <groupId>javax</groupId> - <artifactId>javaee-web-api</artifactId> - <version>8.0.1</version> - <type>jar</type> - <scope>provided</scope> - </dependency> - <dependency> - <groupId>javax</groupId> - <artifactId>javaee-api</artifactId> - <version>8.0.1</version> - <type>jar</type> - <scope>provided</scope> + <version>3.0.0</version> </dependency> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> - <version>2.3.32</version> + <version>2.3.34</version> </dependency> <dependency> <groupId>it.sauronsoftware.cron4j</groupId> @@ -236,9 +260,9 @@ <version>2.2.5</version> </dependency> <dependency> - <groupId>commons-fileupload</groupId> - <artifactId>commons-fileupload</artifactId> - <version>1.5</version> + <groupId>org.apache.commons</groupId> + <artifactId>commons-fileupload2-jakarta-servlet6</artifactId> + <version>2.0.0-M2</version> </dependency> <dependency> <groupId>com.ibm.icu</groupId> @@ -253,7 +277,7 @@ <dependency> <groupId>com.webcohesion.enunciate</groupId> <artifactId>enunciate-core-annotations</artifactId> - <version>2.17.1</version> + <version>2.18.1</version> </dependency> <dependency> <groupId>com.bedatadriven</groupId> @@ -266,6 +290,21 @@ <version>2.0.11</version> <scope>provided</scope> </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi</artifactId> + <version>5.3.0</version> + </dependency> + <dependency> + <groupId>org.apache.poi</groupId> + <artifactId>poi-ooxml</artifactId> + <version>5.3.0</version> + </dependency> + <dependency> + <groupId>commons-io</groupId> + <artifactId>commons-io</artifactId> + <version>2.17.0</version> + </dependency> </dependencies> <build> @@ -327,13 +366,14 @@ <goal>docs</goal> </goals> <configuration> - <docsDir>${project.build.directory}/${project.build.finalName}/public/RESTdocs</docsDir> + <docsDir> + ${project.build.directory}/${project.build.finalName}/public/RESTdocs</docsDir> </configuration> </execution> </executions> - + </plugin> </plugins> </build> - -</project> + +</project> \ No newline at end of file diff --git a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java index a2d59c2e342bea1b638b1cd3ef8fcb1c610369f3..75ee548ed2488a772afc85f2fbe1f5babfeb9659 100755 --- a/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java +++ b/src/main/java/no/nibio/vips/logic/VIPSLogicApplication.java @@ -19,8 +19,8 @@ package no.nibio.vips.logic; import java.util.Set; -import javax.ws.rs.ApplicationPath; -import javax.ws.rs.core.Application; +import jakarta.ws.rs.ApplicationPath; +import jakarta.ws.rs.core.Application; /** * Responsible for adding REST resources @@ -55,9 +55,10 @@ public class VIPSLogicApplication extends Application resources.add(no.nibio.vips.logic.messaging.sms.SMSHandlingService.class); resources.add(no.nibio.vips.logic.modules.applefruitmoth.AppleFruitMothService.class); resources.add(no.nibio.vips.logic.service.ObservationService.class); + resources.add(no.nibio.vips.logic.service.ObservationTimeSeriesService.class); resources.add(no.nibio.vips.logic.service.ModelFormService.class); - resources.add(no.nibio.vips.logic.service.JacksonConfig.class); + resources.add(no.nibio.vips.logic.entity.helpers.KmlMessageBodyWriter.class); //resources.add(no.nibio.vips.logic.service.JSONBConfig.class); //resources.add(no.nibio.vips.coremanager.service.ManagerResourceImpl.class); } diff --git a/src/main/java/no/nibio/vips/logic/authenticate/AuthenticationFilter.java b/src/main/java/no/nibio/vips/logic/authenticate/AuthenticationFilter.java index aee204c1c02e3a3362d02c81af8724b3db8d5346..3617ff8875bd3f57daa6f8873d7405e89fd47f45 100755 --- a/src/main/java/no/nibio/vips/logic/authenticate/AuthenticationFilter.java +++ b/src/main/java/no/nibio/vips/logic/authenticate/AuthenticationFilter.java @@ -1,18 +1,16 @@ /* - * Copyright (c) 2022 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2022 NIBIO <http://www.nibio.no/>. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General + * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see + * <https://www.gnu.org/licenses/>. * */ @@ -22,11 +20,16 @@ package no.nibio.vips.logic.authenticate; import java.io.IOException; import java.net.URLEncoder; import java.util.UUID; -import javax.ejb.EJB; -import javax.servlet.*; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.VipsLogicUser; import no.nibio.vips.logic.util.Globals; @@ -34,79 +37,69 @@ import no.nibio.vips.util.ServletUtil; /** * Ensures that user accessing a restricted resource is actually logged in. Redirects to login page if not + * * @copyright 2013-2022 <a href="http://www.nibio.no">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ -public class AuthenticationFilter implements Filter{ - +public class AuthenticationFilter implements Filter { + @EJB UserBean userBean; // The URLs that do not require login private String[] unprivilegedURLs; + @Override public void init(FilterConfig filterConfig) throws ServletException { this.setUnprivilegedURLs(Globals.UNPRIVILEGED_URLS); - } + } @Override - public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { + public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) + throws IOException, ServletException { - HttpServletRequest httpRequest = (HttpServletRequest)request; + HttpServletRequest httpRequest = (HttpServletRequest) request; /* - // For debugging - BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); - String line; - while((line = reader.readLine()) != null) - { - System.out.println(line); - }*/ - if(isUnprivilegedURL(httpRequest)) - { + * // For debugging BufferedReader reader = new BufferedReader(new InputStreamReader(request.getInputStream())); + * String line; while((line = reader.readLine()) != null) { System.out.println(line); } + */ + if (isUnprivilegedURL(httpRequest)) { chain.doFilter(request, response); - //return; - } - else - { + // return; + } else { // First: Check for session variable - boolean clientAuthenticated = (httpRequest.getSession().getAttribute("user") != null && httpRequest.getSession().getAttribute("user") instanceof VipsLogicUser); + boolean clientAuthenticated = (httpRequest.getSession().getAttribute("user") != null + && httpRequest.getSession().getAttribute("user") instanceof VipsLogicUser); // Then for UUID cookie that has not expired boolean clientRemembered = false; Cookie remembered = ServletUtil.getCookie(httpRequest, "rememberedUser"); - if(remembered != null) - { + if (remembered != null) { VipsLogicUser user = userBean.findVipsLogicUser(UUID.fromString(remembered.getValue())); - if(user != null) - { + if (user != null) { httpRequest.getSession().setAttribute("user", user); clientRemembered = true; } } - - if(! clientAuthenticated && ! clientRemembered) - { + + if (!clientAuthenticated && !clientRemembered) { String nextPageDirective = ""; - if(!httpRequest.getServletPath().equals("/login")) - { + if (!httpRequest.getServletPath().equals("/login")) { String nextPage = ServletUtil.getFullRequestURI(httpRequest); - nextPageDirective= "?nextPage=" + URLEncoder.encode(nextPage, "UTF-8"); + nextPageDirective = "?nextPage=" + URLEncoder.encode(nextPage, "UTF-8"); } - ((HttpServletResponse)response).sendRedirect(Globals.PROTOCOL + "://" + ServletUtil.getServerName(httpRequest) + "/login" + nextPageDirective); - } - else - { + ((HttpServletResponse) response).sendRedirect(Globals.PROTOCOL + "://" + + ServletUtil.getServerName(httpRequest) + "/login" + nextPageDirective); + } else { chain.doFilter(request, response); } - //return; + // return; } } - + private boolean isUnprivilegedURL(HttpServletRequest request) { String path = request.getServletPath(); - for (String unprivilegedURL : this.getUnprivilegedURLs()) - { - if (path.contains(unprivilegedURL)) - { + for (String unprivilegedURL : this.getUnprivilegedURLs()) { + if (path.contains(unprivilegedURL)) { return true; } } @@ -115,12 +108,10 @@ public class AuthenticationFilter implements Filter{ @Override public void destroy() { - + } - - /** * @return the upriviligerteURLer @@ -136,6 +127,6 @@ public class AuthenticationFilter implements Filter{ this.unprivilegedURLs = unprivilegedURLs; } - - + + } diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/CropCategoryController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/CropCategoryController.java index 4d72c996355221ddf90c948b321ad8f38882dab3..388bb923f673fea89399e7acbe26d578a33e7dc8 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/CropCategoryController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/CropCategoryController.java @@ -22,11 +22,11 @@ import java.io.IOException; import java.util.HashMap; import java.util.List; import java.util.Map; -import javax.ejb.EJB; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.OrganismBean; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.CropCategory; @@ -101,7 +101,7 @@ public class CropCategoryController extends HttpServlet { Integer cropCategoryId = formValidation.getFormField("cropCategoryId").getValueAsInteger(); List<Integer> cropCategoryCropOrganismIds = FormUtil.getIdsFromMultipleSelect(formValidation.getFormField("cropCategoryCropOrganismIds").getWebValues()); CropCategory cropCategory = organismBean.getCropCategory(cropCategoryId); - cropCategory.setCropOrganismIds(cropCategoryCropOrganismIds.toArray(new Integer[cropCategoryCropOrganismIds.size()])); + cropCategory.setCropOrganismIds(cropCategoryCropOrganismIds); organismBean.storeCropCategory(cropCategory); response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append("/organism/cropcategory?messageKey=cropCategoryUpdated").toString()); diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java index b7277f97d8fac27234bf423a10618e03372d33e9..6c6a499c481c4dd8690f222fca89e73c5c6c6bd1 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/ForecastConfigurationController.java @@ -1,24 +1,21 @@ /* - * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General + * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see + * <https://www.gnu.org/licenses/>. * */ package no.nibio.vips.logic.controller.servlet; -import com.ibm.icu.util.Calendar; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; @@ -28,15 +25,19 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Map; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.ibm.icu.util.Calendar; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.OrganismBean; +import no.nibio.vips.logic.controller.session.PointOfInterestBean; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.ForecastConfiguration; import no.nibio.vips.logic.entity.ModelInformation; @@ -55,26 +56,31 @@ import no.nibio.web.forms.FormValidator; /** * Handles form configuration actions + * * @copyright 2020-2022 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ public class ForecastConfigurationController extends HttpServlet { - - @PersistenceContext(unitName="VIPSLogic-PU") + + private static final Logger LOGGER = LoggerFactory.getLogger(ForecastConfigurationController.class); + + @PersistenceContext(unitName = "VIPSLogic-PU") EntityManager em; - + @EJB ForecastBean forecastBean; - + @EJB UserBean userBean; - + @EJB OrganismBean organismBean; + @EJB + PointOfInterestBean pointOfInterestBean; + /** - * Processes requests for both HTTP <code>GET</code> and <code>POST</code> - * methods. + * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. * * @param request servlet request * @param response servlet response @@ -84,88 +90,79 @@ public class ForecastConfigurationController extends HttpServlet { protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); - + String action = request.getParameter("action"); VipsLogicUser user = (VipsLogicUser) request.getSession().getAttribute("user"); - + // Default: View list of forecast configurations // for SUPERUSERS and ORGANIZATION ADMINS - if(action == null) - { + if (action == null) { Map<String, ModelInformation> modelInformationMap = forecastBean.getIndexedBatchableModelInformation(); - if(userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { + if (userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) { // Check filtering conditions List<String> selectedModelIds; - try - { + try { selectedModelIds = Arrays.asList(request.getParameterValues("modelId")); - } - catch(NullPointerException ex) - { + } catch (NullPointerException ex) { selectedModelIds = new ArrayList(modelInformationMap.keySet()); } - + SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); - Date from,to; - try - { + Date from, to; + try { from = format.parse(request.getParameter("from")); to = format.parse(request.getParameter("to")); - } - catch(NullPointerException | ParseException ex) - { + } catch (NullPointerException | ParseException ex) { to = SystemTime.getSystemTime(); Calendar cal = Calendar.getInstance(); cal.setTime(to); cal.add(Calendar.MONTH, -2); from = cal.getTime(); } - + List<ForecastConfiguration> forecasts; - - if(user.isSuperUser()) - { + + if (user.isSuperUser()) { // Filtering of organizations List<Organization> organizations = userBean.getOrganizations(); List<Integer> selectedOrganizationIds; - try - { - selectedOrganizationIds = Arrays.asList(ArrayUtil.stringArrayToIntegerArray(request.getParameterValues("organizationId"))); + try { + selectedOrganizationIds = Arrays.asList( + ArrayUtil.stringArrayToIntegerArray(request.getParameterValues("organizationId"))); } // No filter set -> select all organizations (default) - catch(NullPointerException ex) - { + catch (NullPointerException ex) { selectedOrganizationIds = new ArrayList<>(); - for(Organization o:organizations) - { + for (Organization o : organizations) { selectedOrganizationIds.add(o.getOrganizationId()); } } - forecasts = forecastBean.getForecastConfigurations(selectedOrganizationIds, selectedModelIds, from, to); - + forecasts = + forecastBean.getForecastConfigurations(selectedOrganizationIds, selectedModelIds, from, to); + request.setAttribute("organizations", organizations); request.setAttribute("selectedOrganizationIds", selectedOrganizationIds); - + request.setAttribute("allUsers", userBean.getAllUsers()); // If super user requests private forecasts for a user - try - { + try { Integer otherUserId = Integer.valueOf(request.getParameter("otherUserId")); - List<ForecastConfiguration> privateForecastConfigurationsForOtherUser = forecastBean.getPrivateForecastConfigurationsForUser(otherUserId); - request.setAttribute("privateForecastConfigurationsForOtherUser", privateForecastConfigurationsForOtherUser); + List<ForecastConfiguration> privateForecastConfigurationsForOtherUser = + forecastBean.getPrivateForecastConfigurationsForUser(otherUserId); + request.setAttribute("privateForecastConfigurationsForOtherUser", + privateForecastConfigurationsForOtherUser); request.setAttribute("otherUserId", otherUserId); + } catch (NumberFormatException nfe) { } - catch(NumberFormatException nfe) {} - } - else - { - forecasts = forecastBean.getForecastConfigurations(user.getOrganizationId(), selectedModelIds, from, to); + } else { + forecasts = forecastBean.getForecastConfigurations(user.getOrganizationId(), selectedModelIds, from, + to); } Collections.sort(forecasts); - + + request.setAttribute("currentLanguage", SessionLocaleUtil.getCurrentLocale(request).getLanguage()); request.setAttribute("forecastConfigurations", forecasts); - + List<ForecastConfiguration> privateForecasts; privateForecasts = forecastBean.getPrivateForecastConfigurationsForUser(user.getUserId()); request.setAttribute("privateForecastConfigurations", privateForecasts); @@ -176,9 +173,7 @@ public class ForecastConfigurationController extends HttpServlet { // If this is a redirect from a controller, with a message to be passed on request.setAttribute("messageKey", request.getParameter("messageKey")); request.getRequestDispatcher("/forecastConfigurationList.ftl").forward(request, response); - } - else - { + } else { List<ForecastConfiguration> privateForecasts; privateForecasts = forecastBean.getPrivateForecastConfigurationsForUser(user.getUserId()); request.setAttribute("privateForecastConfigurations", privateForecasts); @@ -186,239 +181,265 @@ public class ForecastConfigurationController extends HttpServlet { request.setAttribute("messageKey", request.getParameter("messageKey")); request.getRequestDispatcher("/forecastConfigurationList.ftl").forward(request, response); } - + } - + // View and edit a forecast configuration - else if(action.equals("viewForecastConfiguration")) - { - if(userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - try - { + else if (action.equals("viewForecastConfiguration")) { + if (userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) { + try { Long forecastConfigurationId = Long.valueOf(request.getParameter("forecastConfigurationId")); - ForecastConfiguration forecastConfiguration = em.find(ForecastConfiguration.class, forecastConfigurationId); + ForecastConfiguration forecastConfiguration = + em.find(ForecastConfiguration.class, forecastConfigurationId); boolean multipleNew = false; // No forecastconfiguration found, assuming user want to register new - if(forecastConfiguration == null) - { + if (forecastConfiguration == null) { forecastConfiguration = new ForecastConfiguration(); - multipleNew = request.getParameter("multipleNew") != null - && request.getParameter("multipleNew").equals("true"); + multipleNew = request.getParameter("multipleNew") != null + && request.getParameter("multipleNew").equals("true"); } // Only superusers can view and edit forecasts from other organizations - if(! user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration.getVipsLogicUserId().getOrganizationId().equals(user.getOrganizationId())) - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + if (!user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null + && !forecastConfiguration.getVipsLogicUserId().getOrganizationId() + .equals(user.getOrganizationId())) { + response.sendError(403, "Access not authorized"); // HTTP Forbidden } // Only superusers can view and edit private forecasts from other users - else if(forecastConfiguration.getIsPrivate() && ! user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration.getVipsLogicUserId().getUserId().equals(user.getUserId())) - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden - } - else - { + else if (forecastConfiguration.getIsPrivate() && !user.isSuperUser() + && forecastConfiguration.getVipsLogicUserId() != null + && !forecastConfiguration.getVipsLogicUserId().getUserId().equals(user.getUserId())) { + response.sendError(403, "Access not authorized"); // HTTP Forbidden + } else { // TODO: More intelligent selection of locations, weather stations and users - if(user.isSuperUser()) - { - request.setAttribute("locationPointOfInterests", em.createNamedQuery("PointOfInterest.findAll").getResultList()); - request.setAttribute("weatherStationPointOfInterests", em.createNamedQuery("PointOfInterestWeatherStation.findAllByActivity").setParameter("active", Boolean.TRUE).getResultList()); - request.setAttribute("vipsLogicUsers", em.createNamedQuery("VipsLogicUser.findAll").getResultList()); - } - else - { - request.setAttribute("locationPointOfInterests", em.createNamedQuery("PointOfInterest.findByOrganizationId").setParameter("organizationId", user.getOrganizationId()).getResultList()); - request.setAttribute("weatherStationPointOfInterests", em.createNamedQuery("PointOfInterestWeatherStation.findByActivityAndOrganizationId").setParameter("active", Boolean.TRUE).setParameter("organizationId", user.getOrganizationId()).getResultList()); - request.setAttribute("vipsLogicUsers", em.createNamedQuery("VipsLogicUser.findByOrganizationId").setParameter("organizationId", user.getOrganizationId()).getResultList()); + if (user.isSuperUser()) { + request.setAttribute("locationPointOfInterests", + em.createNamedQuery("PointOfInterest.findAll").getResultList()); + request.setAttribute("weatherStationPointOfInterests", + em.createNamedQuery("PointOfInterestWeatherStation.findAllByActivity") + .setParameter("active", Boolean.TRUE).getResultList()); + request.setAttribute("vipsLogicUsers", + em.createNamedQuery("VipsLogicUser.findAll").getResultList()); + } else { + request.setAttribute("locationPointOfInterests", + em.createNamedQuery("PointOfInterest.findByOrganizationId") + .setParameter("organizationId", user.getOrganizationId()).getResultList()); + request.setAttribute("weatherStationPointOfInterests", + em.createNamedQuery("PointOfInterestWeatherStation.findByActivityAndOrganizationId") + .setParameter("active", Boolean.TRUE) + .setParameter("organizationId", user.getOrganizationId()).getResultList()); + request.setAttribute("vipsLogicUsers", + em.createNamedQuery("VipsLogicUser.findByOrganizationId") + .setParameter("organizationId", user.getOrganizationId()).getResultList()); } + request.setAttribute("currentLanguage", + SessionLocaleUtil.getCurrentLocale(request).getLanguage()); request.setAttribute("forecastConfiguration", forecastConfiguration); - request.setAttribute("formId", multipleNew ? "forecastConfigurationMultipleNewForm" : "forecastConfigurationForm"); + request.setAttribute("formId", + multipleNew ? "forecastConfigurationMultipleNewForm" : "forecastConfigurationForm"); request.setAttribute("multipleNew", multipleNew); request.getSession().setAttribute("availableTimeZones", SystemTime.getAvailableTimeZones()); - request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone()); + request.getSession().setAttribute("defaultTimeZoneId", + user.getOrganizationId().getDefaultTimeZone()); // All organisms used for parent organism list request.setAttribute("allCrops", em.createNamedQuery("Organism.findAllCrops").getResultList()); request.setAttribute("allPests", em.createNamedQuery("Organism.findAllPests").getResultList()); // Hierarchy categories - request.setAttribute("hierarchyCategories", organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); + request.setAttribute("hierarchyCategories", + organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); request.setAttribute("modelInformations", forecastBean.getBatchableModels()); request.setAttribute("messageKey", request.getParameter("messageKey")); request.getRequestDispatcher("/forecastConfigurationForm.ftl").forward(request, response); - + } + } catch (NullPointerException | NumberFormatException ex) { + response.sendError(500, + "Invalid forecast configurationId " + request.getParameter("forecastConfigurationId")); } - catch(NullPointerException | NumberFormatException ex) - { - response.sendError(500, "Invalid forecast configurationId " + request.getParameter("forecastConfigurationId")); - } - } - else - { + } else { Long forecastConfigurationId = Long.valueOf(request.getParameter("forecastConfigurationId")); - ForecastConfiguration forecastConfiguration = em.find(ForecastConfiguration.class, forecastConfigurationId); - if(forecastConfiguration == null || forecastConfiguration.getVipsLogicUserId().getUserId().equals(user.getUserId())) - { - if(forecastConfiguration == null) - { + ForecastConfiguration forecastConfiguration = + em.find(ForecastConfiguration.class, forecastConfigurationId); + if (forecastConfiguration == null + || forecastConfiguration.getVipsLogicUserId().getUserId().equals(user.getUserId())) { + if (forecastConfiguration == null) { forecastConfiguration = new ForecastConfiguration(); forecastConfiguration.setIsPrivate(Boolean.TRUE); } + request.setAttribute("currentLanguage", SessionLocaleUtil.getCurrentLocale(request).getLanguage()); request.setAttribute("forecastConfiguration", forecastConfiguration); - request.setAttribute("locationPointOfInterests", em.createNamedQuery("PointOfInterest.findByOrganizationId").setParameter("organizationId", user.getOrganizationId()).getResultList()); - request.setAttribute("weatherStationPointOfInterests", em.createNamedQuery("PointOfInterestWeatherStation.findByActivityAndOrganizationId").setParameter("active", Boolean.TRUE).setParameter("organizationId", user.getOrganizationId()).getResultList()); - request.setAttribute("forecastConfiguration", forecastConfiguration); - request.setAttribute("formId","forecastConfigurationForm"); + request.setAttribute("locationPointOfInterests", + em.createNamedQuery("PointOfInterest.findByOrganizationId") + .setParameter("organizationId", user.getOrganizationId()).getResultList()); + request.setAttribute("weatherStationPointOfInterests", + em.createNamedQuery("PointOfInterestWeatherStation.findByActivityAndOrganizationId") + .setParameter("active", Boolean.TRUE) + .setParameter("organizationId", user.getOrganizationId()).getResultList()); + request.setAttribute("formId", "forecastConfigurationForm"); request.getSession().setAttribute("availableTimeZones", SystemTime.getAvailableTimeZones()); - request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone()); - + request.getSession().setAttribute("defaultTimeZoneId", + user.getOrganizationId().getDefaultTimeZone()); + request.setAttribute("allCrops", em.createNamedQuery("Organism.findAllCrops").getResultList()); request.setAttribute("allPests", em.createNamedQuery("Organism.findAllPests").getResultList()); // Hierarchy categories - request.setAttribute("hierarchyCategories", organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); - request.setAttribute("modelInformations", em.createNamedQuery("ModelInformation.findAll").getResultList()); + request.setAttribute("hierarchyCategories", + organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); + request.setAttribute("modelInformations", + em.createNamedQuery("ModelInformation.findAll").getResultList()); request.setAttribute("messageKey", request.getParameter("messageKey")); + request.setAttribute("multipleNew", false); request.getRequestDispatcher("/forecastConfigurationForm.ftl").forward(request, response); - } - else - { - response.sendError(403,"Access not authorized"); + } else { + response.sendError(403, "Access not authorized"); } } } - + // Store forecast configuration(s) // Authorization: SUPERUSERS and ORGANIZATION ADMINS - else if(action.equals("forecastConfigurationFormSubmit")) - { - try - { + else if (action.equals("forecastConfigurationFormSubmit")) { + try { Long forecastConfigurationId = Long.valueOf(request.getParameter("forecastConfigurationId")); - ForecastConfiguration forecastConfiguration = em.find(ForecastConfiguration.class, forecastConfigurationId); + ForecastConfiguration forecastConfiguration = + em.find(ForecastConfiguration.class, forecastConfigurationId); // No forecastconfiguration found, assuming user want to register new - if(forecastConfiguration == null) - { + if (forecastConfiguration == null) { forecastConfiguration = new ForecastConfiguration(); } // Only superusers can view and edit forecasts from other organizations // Regular users can only edit own forecasts - if( - (! user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration.getVipsLogicUserId().getOrganizationId().equals(user.getOrganizationId())) - || (! user.isSuperUser() && ! user.isOrganizationAdmin() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration.getVipsLogicUserId().getUserId().equals(user.getUserId())) - ) - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden - } - else - { - String formId = request.getParameter("multipleNew") != null && request.getParameter("multipleNew").equals("true") ? - "forecastConfigurationMultipleNewForm" - :"forecastConfigurationForm"; - FormValidation formValidation = FormValidator.validateForm(formId,request,getServletContext()); + if ((!user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null + && !forecastConfiguration.getVipsLogicUserId().getOrganizationId() + .equals(user.getOrganizationId())) + || (!user.isSuperUser() && !user.isOrganizationAdmin() + && forecastConfiguration.getVipsLogicUserId() != null + && !forecastConfiguration.getVipsLogicUserId().getUserId().equals(user.getUserId()))) { + response.sendError(403, "Access not authorized"); // HTTP Forbidden + } else { + String formId = request.getParameter("multipleNew") != null + && request.getParameter("multipleNew").equals("true") + ? "forecastConfigurationMultipleNewForm" + : "forecastConfigurationForm"; + FormValidation formValidation = FormValidator.validateForm(formId, request, getServletContext()); + LOGGER.debug("formValidation=" + formValidation.isValid()); // Also validation the model specific fields String modelId = formValidation.getFormField("modelId").getWebValue(); - FormValidation modelFieldFormValidation = FormValidator.validateForm("models/" + modelId, request, getServletContext()); + FormValidation modelFieldFormValidation = + FormValidator.validateForm("models/" + modelId, request, getServletContext()); - if(formValidation.isValid() && modelFieldFormValidation.isValid()) - { - if(formId.equals("forecastConfigurationForm")) - { + // Additional input check: If the Grid data checkbox is not checked, a + + if (formValidation.isValid() && modelFieldFormValidation.isValid()) { + if (formId.equals("forecastConfigurationForm")) { // Ensure regular users always enter private forecasts - if(! userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { + if (!userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER)) { formValidation.getFormField("isPrivate").setWebValue("true"); } - forecastConfiguration = forecastBean.storeForecastConfiguration(forecastConfiguration, formValidation.getFormFields(), modelFieldFormValidation.getFormFields()); + forecastConfiguration = forecastBean.storeForecastConfiguration(forecastConfiguration, + formValidation.getFormFields(), modelFieldFormValidation.getFormFields()); // Store form config - //forecastBean.storeForecastModelConfigurations(forecastConfiguration, modelFieldFormValidation.getFormFields()); + // forecastBean.storeForecastModelConfigurations(forecastConfiguration, + // modelFieldFormValidation.getFormFields()); // TODO: Store model specific fields // First: Delete all o request.setAttribute("messageKey", request.getParameter("formConfigurationUpdated")); - response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append("/forecastConfiguration?action=viewForecastConfiguration&forecastConfigurationId=").append(forecastConfiguration.getForecastConfigurationId()).append("&messageKey=").append("forecastConfigurationUpdated").toString()); - } - else - { - for(String optionVal:formValidation.getFormField("weatherStationPointOfInterestIds").getWebValues()) - { + response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://") + .append(ServletUtil.getServerName(request)) + .append("/forecastConfiguration?action=viewForecastConfiguration&forecastConfigurationId=") + .append(forecastConfiguration.getForecastConfigurationId()).append("&messageKey=") + .append("forecastConfigurationUpdated").toString()); + } else { + for (String optionVal : formValidation.getFormField("weatherStationPointOfInterestIds") + .getWebValues()) { Integer weatherStationPointOfInterestId = Integer.valueOf(optionVal); - forecastBean.storeNewMultipleForecastConfiguration(weatherStationPointOfInterestId, formValidation.getFormFields(), modelFieldFormValidation.getFormFields()); + forecastBean.storeNewMultipleForecastConfiguration(weatherStationPointOfInterestId, + formValidation.getFormFields(), modelFieldFormValidation.getFormFields()); } - request.setAttribute("messageKey", request.getParameter("multipleForecastConfigurationsCreated")); - response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append("/forecastConfiguration?messageKey=").append("multipleForecastConfigurationsCreated").toString()); + request.setAttribute("messageKey", + request.getParameter("multipleForecastConfigurationsCreated")); + response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://") + .append(ServletUtil.getServerName(request)) + .append("/forecastConfiguration?messageKey=") + .append("multipleForecastConfigurationsCreated").toString()); } - } - else - { + } else { // Return to form with error messages request.setAttribute("formValidation", formValidation); // We must get date formats! - Map<String, FormField> formFields = FormValidator.getFormFields("forecastConfigurationForm",getServletContext()); + Map<String, FormField> formFields = + FormValidator.getFormFields("forecastConfigurationForm", getServletContext()); // TODO: More intelligent selection of locations, weather stations and users - request.setAttribute("locationPointOfInterests", em.createNamedQuery("PointOfInterest.findAll").getResultList()); - request.setAttribute("weatherStationPointOfInterests", em.createNamedQuery("PointOfInterestWeatherStation.findAll").getResultList()); - request.setAttribute("vipsLogicUsers", em.createNamedQuery("VipsLogicUser.findAll").getResultList()); + request.setAttribute("formId", "forecastConfigurationForm"); + request.setAttribute("allCrops", em.createNamedQuery("Organism.findAllCrops").getResultList()); + request.setAttribute("allPests", em.createNamedQuery("Organism.findAllPests").getResultList()); + request.setAttribute("locationPointOfInterests", + em.createNamedQuery("PointOfInterest.findAll").getResultList()); + request.setAttribute("weatherStationPointOfInterests", + em.createNamedQuery("PointOfInterestWeatherStation.findAll").getResultList()); + request.setAttribute("vipsLogicUsers", + em.createNamedQuery("VipsLogicUser.findAll").getResultList()); request.setAttribute("dateStart_dateFormat", formFields.get("dateStart").getDateFormat()); request.setAttribute("dateEnd_dateFormat", formFields.get("dateEnd").getDateFormat()); request.getSession().setAttribute("availableTimeZones", SystemTime.getAvailableTimeZones()); - request.getSession().setAttribute("defaultTimeZoneId", user.getOrganizationId().getDefaultTimeZone()); - request.setAttribute("modelInformations", em.createNamedQuery("ModelInformation.findAll").getResultList()); + request.getSession().setAttribute("defaultTimeZoneId", + user.getOrganizationId().getDefaultTimeZone()); + // Hierarchy categories + request.setAttribute("hierarchyCategories", + organismBean.getHierarchyCategoryNames(SessionLocaleUtil.getCurrentLocale(request))); + request.setAttribute("modelInformations", + em.createNamedQuery("ModelInformation.findAll").getResultList()); + request.setAttribute("currentLanguage", + SessionLocaleUtil.getCurrentLocale(request).getLanguage()); request.setAttribute("forecastConfiguration", forecastConfiguration); request.getRequestDispatcher("/forecastConfigurationForm.ftl").forward(request, response); } } - } - catch(NullPointerException | NumberFormatException | FormValidationException ex) - { + } catch (NullPointerException | NumberFormatException | FormValidationException ex) { ex.printStackTrace(); - if(ex instanceof NumberFormatException) - { - response.sendError(500, "Invalid forecast configurationId " + request.getParameter("forecastConfigurationId")); - } - else - { + if (ex instanceof NumberFormatException) { + response.sendError(500, + "Invalid forecast configurationId " + request.getParameter("forecastConfigurationId")); + } else { response.sendError(500, ex.getMessage()); } } } // Delete forecast configuration // Authorization: SUPERUSERS and ORGANIZATION ADMINS OR regular users owning the forecast config - else if(action.equals("deleteForecastConfiguration")) - { + else if (action.equals("deleteForecastConfiguration")) { Long forecastConfigurationId = Long.valueOf(request.getParameter("forecastConfigurationId")); ForecastConfiguration forecastConfiguration = em.find(ForecastConfiguration.class, forecastConfigurationId); - if( - userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER) - || user.getUserId().equals(forecastConfiguration.getVipsLogicUserId().getUserId()) - ) - { + if (userBean.authorizeUser(user, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER) + || user.getUserId().equals(forecastConfiguration.getVipsLogicUserId().getUserId())) { // Only superusers can delete forecasts from other organizations - if(! user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration.getVipsLogicUserId().getOrganizationId().equals(user.getOrganizationId())) - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + if (!user.isSuperUser() && forecastConfiguration.getVipsLogicUserId() != null && !forecastConfiguration + .getVipsLogicUserId().getOrganizationId().equals(user.getOrganizationId())) { + response.sendError(403, "Access not authorized"); // HTTP Forbidden return; } - try - { + try { forecastBean.deleteForecastConfiguration(forecastConfigurationId); - response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append("/forecastConfiguration?").append("&messageKey=").append("forecastConfigurationDeleted").toString()); - } - catch(NullPointerException | NumberFormatException ex) - { - response.sendError(500, "Invalid forecast configurationId " + request.getParameter("forecastConfigurationId")); + response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://") + .append(ServletUtil.getServerName(request)).append("/forecastConfiguration?") + .append("&messageKey=").append("forecastConfigurationDeleted").toString()); + } catch (NullPointerException | NumberFormatException ex) { + response.sendError(500, + "Invalid forecast configurationId " + request.getParameter("forecastConfigurationId")); } - - } - else - { - response.sendError(403,"Access not authorized"); // HTTP Forbidden + + } else { + response.sendError(403, "Access not authorized"); // HTTP Forbidden } } } - // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> + // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the + // code."> /** * Handles the HTTP <code>GET</code> method. * diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/FrontpageController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/FrontpageController.java index a0dc38573b63d1aaa0ed40717c9a418a184a87a9..b2f5756462e0969d3515edbbc6c585b6a4864366 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/FrontpageController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/FrontpageController.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.controller.servlet; import java.io.IOException; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/HttpErrorServlet.java b/src/main/java/no/nibio/vips/logic/controller/servlet/HttpErrorServlet.java index 4c76f564dd8ba0594fa52830d332cd63c2c7326a..d739be32514ade3d271898284008c0b1808859b8 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/HttpErrorServlet.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/HttpErrorServlet.java @@ -20,10 +20,10 @@ package no.nibio.vips.logic.controller.servlet; import java.io.IOException; import java.util.Enumeration; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** * @@ -44,8 +44,8 @@ public class HttpErrorServlet extends HttpServlet { throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); - request.setAttribute("message", request.getAttribute("javax.servlet.error.message")); - Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code"); + request.setAttribute("message", request.getAttribute("jakarta.servlet.error.message")); + Integer statusCode = (Integer) request.getAttribute("jakarta.servlet.error.status_code"); /** // Explore the attributes sent to error template for(Enumeration<String> e = request.getAttributeNames();e.hasMoreElements();) diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java index ba830e6cc3ad88ba3f49b845648b4cdbf4a91898..4b69de6353a3f7f463bb47b4cb7c95fc75230409 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/LoginController.java @@ -18,25 +18,24 @@ package no.nibio.vips.logic.controller.servlet; -import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; -import java.math.BigInteger; import java.net.URLDecoder; -import java.net.URLEncoder; -import java.security.SecureRandom; -import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.UUID; -import javax.ejb.EJB; -import javax.servlet.ServletException; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.Response; + +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.Response; + +import com.fasterxml.jackson.databind.ObjectMapper; + import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.UserAuthenticationType; import no.nibio.vips.logic.entity.UserUuid; @@ -47,26 +46,27 @@ import no.nibio.vips.util.ServletUtil; /** * Logs a user in or out + * * @copyright 2013-2022 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ public class LoginController extends HttpServlet { - //private static final String CLOSE_AND_RELOAD_PARENT = "close_and_reload_parent"; - + // private static final String CLOSE_AND_RELOAD_PARENT = "close_and_reload_parent"; + private static final String RETURN_UUID_PARAMETER_NAME = "returnUUID"; - + @EJB UserBean userBean; - + /** * Processes requests for both HTTP * <code>GET</code> and * <code>POST</code> methods. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { @@ -75,146 +75,124 @@ public class LoginController extends HttpServlet { request.setAttribute("nextPage", nextPage); // We remove the session attribute, so it doesn't stick request.getSession().removeAttribute("nextPage"); - + Boolean returnUUID = getReturnUUID(request); request.setAttribute(LoginController.RETURN_UUID_PARAMETER_NAME, returnUUID); // We remove the session attribute, so it doesn't stick request.getSession().removeAttribute(LoginController.RETURN_UUID_PARAMETER_NAME); - // A log out request - if(request.getServletPath().contains("logout")) - { + if (request.getServletPath().contains("logout")) { + VipsLogicUser user = request.getSession().getAttribute("user") != null ? (VipsLogicUser) request.getSession().getAttribute("user") : null; + // Make sure we delete the current user and their UUID + userBean.deleteUserUuid(user.getUserUuid()); request.getSession().removeAttribute("user"); + + // Check if we have a cookie to delete as well Cookie rememberedUser = ServletUtil.getCookie(request, "rememberedUser"); - if(rememberedUser != null) - { + if (rememberedUser != null) { rememberedUser.setMaxAge(0); response.addCookie(rememberedUser); + // This is likely duplication(?) - or are there cases where this makes sense? userBean.deleteUserUuid(UUID.fromString(rememberedUser.getValue())); } - request.setAttribute("messageKey","logoutsuccess"); + request.setAttribute("messageKey", "logoutsuccess"); request.getRequestDispatcher("/login.ftl").forward(request, response); } // A login attempt - else if(request.getServletPath().contains("loginsubmit")) - { + else if (request.getServletPath().contains("loginsubmit")) { // Which login method? Integer userAuthenticationTypeId = -1; - try - { + try { userAuthenticationTypeId = Integer.valueOf(request.getParameter("userAuthenticationTypeId")); } // No method found, redirect to form again - catch(NumberFormatException | NullPointerException ex) - { + catch (NumberFormatException | NullPointerException ex) { request.getRequestDispatcher("/login.ftl").forward(request, response); return; } - + // Standard username/password login - if(userAuthenticationTypeId.equals(UserAuthenticationType.TYPE_PASSWORD)) - { + if (userAuthenticationTypeId.equals(UserAuthenticationType.TYPE_PASSWORD)) { String username = request.getParameter("username"); String password = request.getParameter("password"); try (PrintWriter out = response.getWriter()) { - - Map<String,String> creds = new HashMap(); + + Map<String, String> creds = new HashMap<>(); creds.put("username", username); creds.put("password", password); + // Check user credentials VipsLogicUser user = userBean.authenticateUser(creds); - if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_APPROVED)) - { + if (user != null && user.getUserStatusId().equals(Globals.USER_STATUS_APPROVED)) { + UserUuid uUUID = userBean.createAndPersistUserUuid(user); + user.setUserUuid(uUUID.getUserUuidPK().getUserUuid()); request.getSession().setAttribute("user", user); - UUID uUUID = this.handleRememberUser(request, response, user, returnUUID); - if(returnUUID) - { - nextPage += (nextPage.contains("?") ? "&": "?") + "returnUUID=" + uUUID.toString(); + this.handleRememberUser(request, response, user, returnUUID); + if (returnUUID) { + nextPage += (nextPage.contains("?") ? "&" : "?") + "returnUUID=" + uUUID.getUserUuidPK().getUserUuid().toString(); } - if(nextPage.indexOf(Globals.PROTOCOL) == 0) - { - //System.out.println("nextPage=" + nextPage); + if (nextPage.indexOf(Globals.PROTOCOL) == 0) { + // System.out.println("nextPage=" + nextPage); response.sendRedirect(nextPage); - } - else - { + } else { response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append(nextPage).toString()); } - } - else if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_EMAIL_VERIFICATION)) - { + } else if (user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_EMAIL_VERIFICATION)) { request.setAttribute("errorMessageKey", "emailNotVerified"); request.getRequestDispatcher("/login.ftl").forward(request, response); - } - else if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_APPROVAL)) - { + } else if (user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_APPROVAL)) { request.setAttribute("errorMessageKey", "pleaseAwaitApproval"); request.getRequestDispatcher("/login.ftl").forward(request, response); - } - else - { + } else { request.setAttribute("errorMessageKey", "invalidcredentials"); request.getRequestDispatcher("/login.ftl").forward(request, response); } - } } // Authentication method not recognized, redirect to standard form - else - { + else { request.getRequestDispatcher("/login.ftl").forward(request, response); } } - // Login from a remote resource. Return UUID - else if(request.getServletPath().contains("remotelogin")) - { + // Login from a remote resource, e.g. an app. Return UUID + else if (request.getServletPath().contains("remotelogin")) { String username = request.getParameter("username"); String password = request.getParameter("password"); - - Map<String,String> creds = new HashMap(); + Map<String, String> creds = new HashMap<>(); creds.put("username", username); creds.put("password", password); VipsLogicUser user = userBean.authenticateUser(creds); PrintWriter out = response.getWriter(); - if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_APPROVED)) - { + if (user != null && user.getUserStatusId().equals(Globals.USER_STATUS_APPROVED)) { request.getSession().setAttribute("user", user); - UUID uUUID = this.handleRememberUser(request, response, user, returnUUID); + UserUuid uUUID = userBean.createAndPersistUserUuid(user); + user.setUserUuid(uUUID.getUserUuidPK().getUserUuid()); + this.handleRememberUser(request, response, user, returnUUID); // All is well, return object ObjectMapper mapper = new ObjectMapper(); - user.setUserUuid(uUUID); - mapper.writeValue(out,user); + mapper.writeValue(out, user); out.close(); - } - else - { + } else { response.setStatus(Response.Status.UNAUTHORIZED.getStatusCode()); - - if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_EMAIL_VERIFICATION)) - { + + if (user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_EMAIL_VERIFICATION)) { out.print(SessionLocaleUtil.getI18nText(request, "emailNotVerified")); - } - else if(user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_APPROVAL)) - { + } else if (user != null && user.getUserStatusId().equals(Globals.USER_STATUS_AWAITING_APPROVAL)) { out.print(SessionLocaleUtil.getI18nText(request, "pleaseAwaitApproval")); request.getRequestDispatcher("/login.ftl").forward(request, response); - } - else - { + } else { out.print(SessionLocaleUtil.getI18nText(request, "invalidcredentials")); } } } // No login attempt. Show form - else - { - if(request.getParameter("nextPage") != null) - { + else { + if (request.getParameter("nextPage") != null) { request.setAttribute("checkRemember", request.getParameter("nextPage").indexOf(Globals.PROTOCOL) == 0); } request.setAttribute("messageKey", request.getParameter("messageKey")); @@ -222,91 +200,81 @@ public class LoginController extends HttpServlet { request.getRequestDispatcher("/login.ftl").forward(request, response); } } - + /** * Utility method (hiding noisy code) + * * @param request * @return - * @throws UnsupportedEncodingException + * @throws UnsupportedEncodingException */ - private String getNextPage(HttpServletRequest request) throws UnsupportedEncodingException - { - String nextPage = request.getParameter("nextPage") != null ? - request.getParameter("nextPage") - : request.getSession().getAttribute("nextPage") != null ? - URLDecoder.decode((String)request.getSession().getAttribute("nextPage"),"UTF-8") - :null; - if(nextPage == null) - { - nextPage="/"; + private String getNextPage(HttpServletRequest request) throws UnsupportedEncodingException { + String nextPage = request.getParameter("nextPage") != null ? request.getParameter("nextPage") + : request.getSession().getAttribute("nextPage") != null ? URLDecoder.decode((String) request.getSession().getAttribute("nextPage"), "UTF-8") + : null; + if (nextPage == null) { + nextPage = "/"; } - + return nextPage; } - + /** * Should the generated UUID be returned to login client? + * * @param request - * @return + * @return */ - private Boolean getReturnUUID(HttpServletRequest request) - { - return request.getParameter(LoginController.RETURN_UUID_PARAMETER_NAME) != null ? - request.getParameter(LoginController.RETURN_UUID_PARAMETER_NAME).equals("true") - : request.getSession().getAttribute(LoginController.RETURN_UUID_PARAMETER_NAME) != null ? - (Boolean) request.getSession().getAttribute(LoginController.RETURN_UUID_PARAMETER_NAME) - : false; + private Boolean getReturnUUID(HttpServletRequest request) { + return request.getParameter(LoginController.RETURN_UUID_PARAMETER_NAME) != null ? request.getParameter(LoginController.RETURN_UUID_PARAMETER_NAME).equals("true") + : request.getSession().getAttribute(LoginController.RETURN_UUID_PARAMETER_NAME) != null ? (Boolean) request.getSession().getAttribute(LoginController.RETURN_UUID_PARAMETER_NAME) + : false; } - + /** * * @param request * @param response - * @param user + * @param user the VIPS user + * @param returnUUID has a UUID been requested to be returned to the client? + * @return */ - private UUID handleRememberUser(HttpServletRequest request, HttpServletResponse response, VipsLogicUser user, Boolean returnUUID) - { - - String rememberUser = request.getParameter("rememberUser") != null ? - request.getParameter("rememberUser") + private void handleRememberUser(HttpServletRequest request, HttpServletResponse response, VipsLogicUser user, Boolean returnUUID) { + // This is from the login form, the checkbox that you tick off to save your login + String rememberUser = request.getParameter("rememberUser") != null ? request.getParameter("rememberUser") : (String) request.getSession().getAttribute("rememberUser"); request.getSession().removeAttribute("rememberUser"); - if(returnUUID || (rememberUser != null && rememberUser.equals("on"))) - { - UserUuid uUUID = userBean.createAndPersistUserUuid(user); - if(rememberUser != null && rememberUser.equals("on")) - { - Cookie rememberedUser = new Cookie("rememberedUser", uUUID.getUserUuidPK().getUserUuid().toString()); + if (returnUUID || (rememberUser != null && rememberUser.equals("on"))) { + + if (rememberUser != null && rememberUser.equals("on")) { + Cookie rememberedUser = new Cookie("rememberedUser", user.getUserUuid().toString()); rememberedUser.setPath("/"); rememberedUser.setMaxAge(Globals.DEFAULT_UUID_VALIDITY_DURATION_DAYS * 24 * 60 * 60); response.addCookie(rememberedUser); } - return uUUID.getUserUuidPK().getUserUuid(); + // return uUUID.getUserUuidPK().getUserUuid(); } - else - { + // Unremember the user both server side and browser side + else { Cookie rememberedUser = ServletUtil.getCookie(request, "rememberedUser"); - if(rememberedUser != null) - { + if (rememberedUser != null) { rememberedUser.setMaxAge(0); response.addCookie(rememberedUser); userBean.deleteUserUuid(UUID.fromString(rememberedUser.getValue())); } - return null; + // return null; } } - - - + // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> /** * Handles the HTTP * <code>GET</code> method. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) @@ -318,10 +286,10 @@ public class LoginController extends HttpServlet { * Handles the HTTP * <code>POST</code> method. * - * @param request servlet request + * @param request servlet request * @param response servlet response * @throws ServletException if a servlet-specific error occurs - * @throws IOException if an I/O error occurs + * @throws IOException if an I/O error occurs */ @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java index d6e859052131dab0439e2e75330b1ab1aaa80596..80c4b2ca879c226f860092bd19d3b3fdb9711961 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/MessageController.java @@ -26,15 +26,15 @@ import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.MessageBean; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.Message; @@ -51,10 +51,10 @@ import no.nibio.web.forms.FormUtil; import no.nibio.web.forms.FormValidation; import no.nibio.web.forms.FormValidationException; import no.nibio.web.forms.FormValidator; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileUploadException; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload; /** * @copyright 2014-2022 <a href="http://www.nibio.no/">NIBIO</a> @@ -226,7 +226,11 @@ public class MessageController extends HttpServlet { request.setAttribute("allCropCategoryIds", em.createNamedQuery("CropCategory.findByOrganizationId").setParameter("organizationId",user.getOrganizationId().getOrganizationId()).getResultList()); request.getRequestDispatcher("/messageForm.ftl").forward(request, response); } - catch(NullPointerException | NumberFormatException | NoResultException ex) + catch(NoResultException ex) + { + response.sendError(404, "Message not found"); + } + catch(NullPointerException | NumberFormatException ex) { response.sendError(500, ExceptionUtil.getStackTrace(ex)); } @@ -269,18 +273,10 @@ public class MessageController extends HttpServlet { { Map<String,String[]> parameterMap; List<FileItem> items = null; - if(ServletFileUpload.isMultipartContent(request)) + if(JakartaServletFileUpload.isMultipartContent(request)) { - // Create a factory for disk-based file items - DiskFileItemFactory factory = new DiskFileItemFactory(); - - // Configure a repository (to ensure a secure temp location is used) - ServletContext servletContext = this.getServletConfig().getServletContext(); - File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir"); - factory.setRepository(repository); - // Create a new file upload handler - ServletFileUpload upload = new ServletFileUpload(factory); + JakartaServletFileUpload upload = new JakartaServletFileUpload(); // Parse the request items = upload.parseRequest(request); diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java index b93644d845a86efda90628d8f436161ee68a379c..d8cb4769f8ebd024770e4ed0a7d57e5ddf716919 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/NotificationSubscriptionController.java @@ -22,13 +22,13 @@ import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.util.List; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.OrganismBean; import no.nibio.vips.logic.controller.session.PointOfInterestBean; import no.nibio.vips.logic.controller.session.UserBean; diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java index 5c320adc975d2f694c00421c204795e95e8110af..91a147a5eddb4a5b565454990114b13d83468617 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/ObservationController.java @@ -32,14 +32,14 @@ import java.util.Map; import java.util.Set; import java.util.TimeZone; import java.util.stream.Collectors; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.ObservationBean; import no.nibio.vips.logic.controller.session.OrganismBean; import no.nibio.vips.logic.controller.session.PointOfInterestBean; @@ -65,10 +65,10 @@ import no.nibio.web.forms.FormUtil; import no.nibio.web.forms.FormValidation; import no.nibio.web.forms.FormValidationException; import no.nibio.web.forms.FormValidator; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.fileupload.FileUploadException; -import org.apache.commons.fileupload.disk.DiskFileItemFactory; -import org.apache.commons.fileupload.servlet.ServletFileUpload; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.fileupload2.core.FileUploadException; +import org.apache.commons.fileupload2.core.DiskFileItemFactory; +import org.apache.commons.fileupload2.jakarta.servlet6.JakartaServletFileUpload; /** * @copyright 2014-2022 <a href="http://www.nibio.no/">NIBIO</a> @@ -410,18 +410,11 @@ public class ObservationController extends HttpServlet { { Map<String,String[]> parameterMap; List<FileItem> items = null; - if(ServletFileUpload.isMultipartContent(request)) + if(JakartaServletFileUpload.isMultipartContent(request)) { - // Create a factory for disk-based file items - DiskFileItemFactory factory = new DiskFileItemFactory(); - - // Configure a repository (to ensure a secure temp location is used) - ServletContext servletContext = this.getServletConfig().getServletContext(); - File repository = (File) servletContext.getAttribute("javax.servlet.context.tempdir"); - factory.setRepository(repository); - + // Create a new file upload handler - ServletFileUpload upload = new ServletFileUpload(factory); + JakartaServletFileUpload upload = new JakartaServletFileUpload(); // Parse the request items = upload.parseRequest(request); diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/OrganismController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/OrganismController.java index 19e14371f1544d3c213983aa81274681f9e97bd3..2579fb867dd7538b578441c9a4715f9918d343a6 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/OrganismController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/OrganismController.java @@ -23,13 +23,13 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.OrganismBean; import no.nibio.vips.logic.entity.CropPest; import no.nibio.vips.logic.entity.Organism; @@ -377,8 +377,7 @@ public class OrganismController extends HttpServlet { { Integer cropOrganismId = formValidation.getFormField("cropOrganismId").getValueAsInteger(); boolean includeAllChildCrops = formValidation.getFormField("includeAllChildCrops").getWebValue() != null; - List<Integer> poTemp = FormUtil.getIdsFromMultipleSelect(formValidation.getFormField("pestOrganismIds").getWebValues()); - Integer[] pestOrganismIds = poTemp.toArray(new Integer[poTemp.size()]); + List<Integer> pestOrganismIds = FormUtil.getIdsFromMultipleSelect(formValidation.getFormField("pestOrganismIds").getWebValues()); CropPest cropPest = em.find(CropPest.class, cropOrganismId); if(cropPest == null) { diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationController.java index b10c713a6ce7bf20ec28db65a7ac945cc21fe658..d14421dbb84301ca6db7f019077e809521fec853 100644 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationController.java @@ -22,13 +22,14 @@ import java.io.IOException; import java.util.Collections; import java.util.List; import java.util.TimeZone; -import javax.ejb.EJB; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.gis.GISUtil; import no.nibio.vips.gis.LonLatStringFormatException; +import no.nibio.vips.logic.controller.session.PointOfInterestBean; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.Organization; import no.nibio.vips.logic.entity.VipsLogicUser; @@ -46,6 +47,9 @@ public class OrganizationController extends HttpServlet { @EJB UserBean userBean; + + @EJB + PointOfInterestBean poiBean; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. @@ -101,6 +105,7 @@ public class OrganizationController extends HttpServlet { request.setAttribute("countries", userBean.getCountries()); request.setAttribute("timeZones", TimeZone.getAvailableIDs()); request.setAttribute("organization", organization); + request.setAttribute("gridWeatherDataSources", poiBean.getGridWeatherStationDataSources()); request.getRequestDispatcher("/organizationForm.ftl").forward(request, response); } else if(action.equals("organizationFormSubmit")) @@ -142,6 +147,11 @@ public class OrganizationController extends HttpServlet { : new GISUtil().getJtsPointFromString(formValidation.getFormField("defaultMapCenter").getWebValue()) ); + organization.setDefaultGridWeatherStationDataSource( + formValidation.getFormField("defaultGridWeatherStationDataSourceId").getValueAsInteger() < 0 ? + null + : poiBean.getWeatherStationDataSource(formValidation.getFormField("defaultGridWeatherStationDataSourceId").getValueAsInteger()) + ); organization = userBean.storeOrganization(organization); response.sendRedirect( diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationGroupController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationGroupController.java index 113eca4917064c2b6646a0acd7a7687a3686a2c0..a1325ecc2c001559939b40121ba5118b79edbba2 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationGroupController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/OrganizationGroupController.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.controller.servlet; import java.io.IOException; import java.util.List; -import javax.ejb.EJB; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.Organization; import no.nibio.vips.logic.entity.OrganizationGroup; diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java index 9f2d923e257ecf34d61b674b402bedac9f633291..d8833ffdb419b1fa33e63f29217b5e614f9ef88a 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/PointOfInterestController.java @@ -27,13 +27,13 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.entity.Country; import no.nibio.vips.logic.entity.ForecastConfiguration; import no.nibio.vips.logic.entity.ModelInformation; @@ -298,6 +298,8 @@ public class PointOfInterestController extends HttpServlet { { weatherStation.setIsForecastLocation(Boolean.TRUE); } + + weatherStation.setIsPrivate(formValidation.getFormField("isPrivate").getWebValue() != null); Double altitude = 0.0; Point p2d = formValidation.getFormField("location").getValueAsPointWGS84(); @@ -657,6 +659,8 @@ public class PointOfInterestController extends HttpServlet { { poi.setIsForecastLocation(Boolean.FALSE); } + + poi.setIsPrivate(formValidation.getFormField("isPrivate").getWebValue() != null); Double altitude = 0.0; Point p2d = formValidation.getFormField("location").getValueAsPointWGS84(); diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/SchedulingController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/SchedulingController.java index 24ee6bd18ac16259cc6cdeebf59b64879866be43..1ab060eb4d1a399ed3fc571f2f30608cd457fd9f 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/SchedulingController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/SchedulingController.java @@ -27,13 +27,13 @@ import java.text.MessageFormat; import java.util.Date; import java.util.HashMap; import java.util.List; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.SchedulingBean; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.TaskHistory; diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/UserController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/UserController.java index 7fd46c594c2039e42bd93b8683919e89f56bf0fa..290ffb4f1e06e5222ff74ef29fc8df854d79121e 100755 --- a/src/main/java/no/nibio/vips/logic/controller/servlet/UserController.java +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/UserController.java @@ -31,15 +31,15 @@ import java.util.Map; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.NonUniqueResultException; -import javax.persistence.PersistenceContext; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.NonUniqueResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.i18n.LanguageUtil; import no.nibio.vips.logic.controller.session.DeleteUserException; import no.nibio.vips.logic.controller.session.UserBean; @@ -51,6 +51,8 @@ import no.nibio.vips.logic.entity.VipsLogicRole; import no.nibio.vips.logic.entity.VipsLogicUser; import no.nibio.vips.logic.entity.misc.UserResources; import no.nibio.vips.logic.i18n.SessionLocaleUtil; +import no.nibio.vips.logic.modules.barkbeetle.BarkbeetleBean; +import no.nibio.vips.logic.modules.barkbeetle.SeasonTrapsite; import no.nibio.vips.logic.util.Globals; import no.nibio.vips.util.ServletUtil; import no.nibio.web.forms.FormField; @@ -71,6 +73,9 @@ public class UserController extends HttpServlet { @EJB UserBean userBean; + + @EJB + BarkbeetleBean barkbeetleBean; /** * Processes requests for both HTTP <code>GET</code> and <code>POST</code> @@ -406,9 +411,12 @@ public class UserController extends HttpServlet { Integer userId = Integer.valueOf(request.getParameter("userId")); VipsLogicUser viewUser = em.find(VipsLogicUser.class, userId); UserResources userResources = userBean.getUserResources(viewUser); + + // Barkbeetle module dependencies + List<SeasonTrapsite> userSeasonTrapsites = barkbeetleBean.getSeasonTrapsites(viewUser); // If some resources connected, render form, otherwise, route to user delete - if(userResources.isEmpty()) + if(userResources.isEmpty() && userSeasonTrapsites.isEmpty()) { response.sendRedirect(new StringBuilder(Globals.PROTOCOL + "://").append(ServletUtil.getServerName(request)).append("/user").append("?action=deleteUser&userId=").append(userId).toString()); } @@ -423,7 +431,9 @@ public class UserController extends HttpServlet { request.setAttribute("viewUser", viewUser); request.setAttribute("userResources", userResources); + java.util.Collections.sort(users); request.setAttribute("users", users); + request.setAttribute("userBarkbeetleSeasonTrapsites", userSeasonTrapsites); request.setAttribute("errorMsg", request.getParameter("errorMsg")); request.getRequestDispatcher("/userDeleteForm.ftl").forward(request, response); } @@ -450,7 +460,9 @@ public class UserController extends HttpServlet { // Are there resources connected to this user? UserResources userResources = userBean.getUserResources(viewUser); - if(! userResources.isEmpty()) + // Barkbeetle module dependencies + List<SeasonTrapsite> userSeasonTrapsites = barkbeetleBean.getSeasonTrapsites(viewUser); + if(! userResources.isEmpty() || ! userSeasonTrapsites.isEmpty()) { boolean resourcesTransferred = false; try @@ -460,6 +472,7 @@ public class UserController extends HttpServlet { if(transferToUser != null) { userBean.transferUserResources(viewUser,transferToUser); + barkbeetleBean.transferSeasonTrapsites(viewUser,transferToUser); resourcesTransferred = true; } } diff --git a/src/main/java/no/nibio/vips/logic/controller/servlet/WeatherStationDataSourceController.java b/src/main/java/no/nibio/vips/logic/controller/servlet/WeatherStationDataSourceController.java new file mode 100644 index 0000000000000000000000000000000000000000..8848614f09bea69f8c02107d5e71fcdb9f778f14 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/controller/servlet/WeatherStationDataSourceController.java @@ -0,0 +1,231 @@ +/* + * Copyright (c) 2024 NIBIO <http://www.nibio.no/>. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ +package no.nibio.vips.logic.controller.servlet; + +import java.io.IOException; + +import java.util.List; + +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import no.nibio.vips.gis.LonLatStringFormatException; +import no.nibio.vips.logic.controller.session.PointOfInterestBean; +import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.entity.WeatherStationDataSource; +import no.nibio.vips.logic.util.Globals; +import no.nibio.vips.logic.util.SystemTime; +import no.nibio.vips.util.ServletUtil; +import no.nibio.web.forms.FormValidation; +import no.nibio.web.forms.FormValidationException; +import no.nibio.web.forms.FormValidator;; + +/** + * Handles actions regarding listing and modifying weather station data sources + * + * @copyright 2024 <a href="http://www.nibio.no/">NIBIO</a> + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ +public class WeatherStationDataSourceController extends HttpServlet{ + + private static Logger LOGGER = LoggerFactory.getLogger(WeatherStationDataSourceController.class); + + @EJB + PointOfInterestBean poiBean; + + /** + * Processes requests for both HTTP <code>GET</code> and <code>POST</code> methods. + * @param request servlet request + * @param response servlet response + * @throws ServletException if a servlet-specific error occurs + * @throws IOException if an I/O error occurs + */ + protected void processRequest(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + + response.setContentType("text/html;charset=UTF-8"); + + VipsLogicUser user = (VipsLogicUser) request.getSession().getAttribute("user"); + // Basic authorization + if(!user.isSuperUser() && ! user.isOrganizationAdmin()){ + response.sendError(403,"Access not authorized"); + return; + } + String action = request.getParameter("action"); + + if(action == null) + { + List<WeatherStationDataSource> wsDataSources = poiBean.getWeatherStationDataSources(); + request.setAttribute("messageKey", request.getParameter("messageKey") != null ? request.getParameter("messageKey") : null); + request.setAttribute("weatherStationDataSources", wsDataSources); + request.getRequestDispatcher("/weatherStationDataSourceList.ftl").forward(request, response); + } + else if(action.equals("editWeatherStationDataSource") || action.equals("newWeatherStationDataSource")) + { + WeatherStationDataSource weatherStationDataSource = null; + try + { + weatherStationDataSource = poiBean.getWeatherStationDataSource(Integer.valueOf(request.getParameter("weatherStationDataSourceId"))); + } + catch(NullPointerException | NumberFormatException ex){} + + if(weatherStationDataSource == null) + { + LOGGER.debug("Could not find weather data source with ID = " + request.getParameter("weatherStationDataSourceId")); + weatherStationDataSource = new WeatherStationDataSource(); + } + + request.setAttribute("messageKey", request.getParameter("messageKey") != null ? request.getParameter("messageKey") : null); + request.setAttribute("weatherStationDataSource", weatherStationDataSource); + request.getRequestDispatcher("/weatherStationDataSourceForm.ftl").forward(request, response); + } + else if(action.equals("weatherStationDataSourceFormSubmit")) + { + try + { + // Check that the provided id is either -1 or it already exists + Integer weatherStationDataSourceId = null; + WeatherStationDataSource weatherStationDataSource; + try + { + weatherStationDataSourceId = Integer.valueOf(request.getParameter("weatherStationDataSourceId")); + } + catch(NullPointerException | NumberFormatException ex) + { + response.sendError(400,"Wrong format of id for weather station data source"); + } + if(weatherStationDataSourceId < 0) + { + weatherStationDataSource = new WeatherStationDataSource(); + } + else + { + weatherStationDataSource = poiBean.getWeatherStationDataSource(weatherStationDataSourceId); + if(weatherStationDataSource == null) + { + response.sendError(404,"Could not find weather station data source with id=" + weatherStationDataSourceId); + } + } + FormValidation formValidation = FormValidator.validateForm("weatherStationDataSourceForm", request, getServletContext()); + if(formValidation.isValid()) + { + weatherStationDataSource.setName(formValidation.getFormField("name").getWebValue()); + weatherStationDataSource.setDefaultDescription(formValidation.getFormField("defaultDescription").getWebValue()); + weatherStationDataSource.setUri(formValidation.getFormField("uri").getWebValue()); + weatherStationDataSource.setDatafetchUriExpression(formValidation.getFormField("datafetchUriExpression").getWebValue()); + weatherStationDataSource.setInfoUriExpression(formValidation.getFormField("infoUriExpression").getWebValue()); + weatherStationDataSource.setIsGrid(formValidation.getFormField("isGrid").getWebValue() != null); + weatherStationDataSource = poiBean.storeWeatherStationDataSource(weatherStationDataSource); + + response.sendRedirect( + Globals.PROTOCOL + "://" + ServletUtil.getServerName(request) + + "/weatherstationdatasource?action=editWeatherStationDataSource&weatherStationDataSourceId=" + weatherStationDataSource.getWeatherStationDataSourceId() + + "&messageKey=weatherStationDataSourceStored" + ); + } + else + { + request.setAttribute("formValidation", formValidation); + request.setAttribute("weatherStationDataSource", weatherStationDataSource); + LOGGER.debug("Form NOT valid. Dispatching"); + request.getRequestDispatcher("/weatherStationDataSourceForm.ftl").forward(request, response); + } + } + catch(FormValidationException ex) + { + ex.printStackTrace(); + response.sendError(500, ex.getClass().toString() + ": " + ex.getMessage()); + } + } + else if(action.equals("deleteWeatherStationDataSource")) + { + + try + { + Integer weatherStationDataSourceId = Integer.valueOf(request.getParameter("weatherStationDataSourceId")); + WeatherStationDataSource weatherStationDataSource = poiBean.getWeatherStationDataSource(weatherStationDataSourceId); + if(weatherStationDataSource == null) + { + response.sendError(404,"Could not find weather station data source with id=" + weatherStationDataSourceId); + } + // Check: Can it be deleted? Not if organizations or weatherStations refer to it + if(poiBean.isweatherStationDataSourceDeleteable(weatherStationDataSource)) + { + poiBean.deleteWeatherStationDataSource(weatherStationDataSource); + // Redirect to list from which the deleted item has been removed + response.sendRedirect( + Globals.PROTOCOL + "://" + ServletUtil.getServerName(request) + + "/weatherstationdatasource?messageKey=weatherStationDataSourceDeleted" + ); + } + else + { + response.sendError(403,weatherStationDataSource.getName() + " is in use by one or more organizations, so it cannot be deleted. Hit the browser's back button return to your form."); + } + } + catch(NullPointerException | NumberFormatException ex) + { + response.sendError(400,"Wrong format of id for weather station data source"); + } + + + } + } + + // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code."> + /** + * Handles the HTTP <code>GET</code> method. + * @param request servlet request + * @param response servlet response + * @throws ServletException if a servlet-specific error occurs + * @throws IOException if an I/O error occurs + */ + @Override + protected void doGet(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response); + } + + /** + * Handles the HTTP <code>POST</code> method. + * @param request servlet request + * @param response servlet response + * @throws ServletException if a servlet-specific error occurs + * @throws IOException if an I/O error occurs + */ + @Override + protected void doPost(HttpServletRequest request, HttpServletResponse response) + throws ServletException, IOException { + processRequest(request, response); + } + + /** + * Returns a short description of the servlet. + * @return a String containing servlet description + */ + @Override + public String getServletInfo() { + return "Short description"; + }// </editor-fold> +} diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java index 29ceb7b5d4261f8cd79492d20bd8c13c50f771bc..58af01d24901d3072b5664f388a3166a6694a2e8 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/ForecastBean.java @@ -1,26 +1,51 @@ /* - * Copyright (c) 2015 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2015 NIBIO <http://www.nibio.no/>. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General + * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see + * <https://www.gnu.org/licenses/>. * */ package no.nibio.vips.logic.controller.session; -import com.fasterxml.jackson.databind.JsonNode; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.TimeZone; +import java.util.UUID; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; +import jakarta.ejb.EJB; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; +import jakarta.ws.rs.ProcessingException; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.Response; +import org.apache.commons.lang.StringUtils; +import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; +import org.slf4j.LoggerFactory; +import com.fasterxml.jackson.databind.JsonNode; import de.micromata.opengis.kml.v_2_2_0.Coordinate; import de.micromata.opengis.kml.v_2_2_0.Data; import de.micromata.opengis.kml.v_2_2_0.Document; @@ -32,30 +57,6 @@ import de.micromata.opengis.kml.v_2_2_0.Placemark; import de.micromata.opengis.kml.v_2_2_0.Point; import de.micromata.opengis.kml.v_2_2_0.Units; import de.micromata.opengis.kml.v_2_2_0.Vec2; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.ejb.EJB; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; -import javax.ws.rs.ProcessingException; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; import no.nibio.vips.coremanager.service.ManagerResource; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.ModelRunRequest; @@ -81,9 +82,6 @@ import no.nibio.vips.logic.util.RunModelException; import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.util.WeatherUtil; import no.nibio.web.forms.FormField; -import org.apache.commons.lang.StringUtils; -import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; -import org.slf4j.LoggerFactory; /** * @copyright 2013-2022 <a href="http://www.nibio.no/">NIBIO</a> @@ -94,179 +92,163 @@ public class ForecastBean { private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(ForecastBean.class); - @PersistenceContext(unitName="VIPSLogic-PU") + @PersistenceContext(unitName = "VIPSLogic-PU") EntityManager em; - + @EJB ForecastBean forecastBean; - + @EJB UserBean userBean; - + /** * Returns all forecast results. - * @return + * + * @return */ - public List<ForecastResult> getForecastResults() - { + public List<ForecastResult> getForecastResults() { return em.createNamedQuery("ForecastResult.findAll").getResultList(); } - - public List<ForecastResult> getForecastResults(Long forecastConfigurationId) - { - //ForecastConfiguration config = this.getForecastConfiguration(forecastConfigurationId); + + public List<ForecastResult> getForecastResults(Long forecastConfigurationId) { + // ForecastConfiguration config = this.getForecastConfiguration(forecastConfigurationId); Query q = em.createNamedQuery("ForecastResult.findByForecastConfigurationId"); q.setParameter("forecastConfigurationId", forecastConfigurationId); return q.getResultList(); } - + /** * * @param forecastConfiguration * @param user - * @return + * @return */ - public boolean isUserAuthorizedForForecastConfiguration(ForecastConfiguration forecastConfiguration, VipsLogicUser user) - { + public boolean isUserAuthorizedForForecastConfiguration(ForecastConfiguration forecastConfiguration, + VipsLogicUser user) { // Public forecasts are always OK for everyone to view - if(!forecastConfiguration.getIsPrivate()) - { + if (!forecastConfiguration.getIsPrivate()) { return true; } // Private forecasts are only viewable by owner or super users / orgadmins - return user != null && (user.isSuperUser() || user.isOrganizationAdmin() || user.getUserId().equals( forecastConfiguration.getVipsLogicUserId().getUserId())); + return user != null && (user.isSuperUser() || user.isOrganizationAdmin() + || user.getUserId().equals(forecastConfiguration.getVipsLogicUserId().getUserId())); } - - - public boolean isUserAuthorizedForForecastConfiguration(Long forecastConfigurationId, String userUUID) - { + + + public boolean isUserAuthorizedForForecastConfiguration(Long forecastConfigurationId, String userUUID) { // Authentication ForecastConfiguration fc = em.find(ForecastConfiguration.class, forecastConfigurationId); - if(fc == null) - { + if (fc == null) { return true; } - if(fc.getIsPrivate()) - { - if(userUUID == null) - { + if (fc.getIsPrivate()) { + if (userUUID == null) { return false; } UUID uUUID = UUID.fromString(userUUID); VipsLogicUser user = userBean.findVipsLogicUser(uUUID); - if(user == null || ! user.getUserId().equals( fc.getVipsLogicUserId().getUserId())) - { + if (user == null || !user.getUserId().equals(fc.getVipsLogicUserId().getUserId())) { return false; } } return true; } - - public List<ForecastResult> getForecastResults(Long forecastConfigurationId, Integer latestDays) - { + + public List<ForecastResult> getForecastResults(Long forecastConfigurationId, Integer latestDays) { ForecastResult mostRecentForecastResult = this.getMostRecentForecastResult(forecastConfigurationId); - if(mostRecentForecastResult == null) - { + if (mostRecentForecastResult == null) { return null; } Calendar cal = Calendar.getInstance(); cal.setTime(mostRecentForecastResult.getValidTimeStart()); cal.add(Calendar.DATE, -latestDays); Date startDate = cal.getTime(); - return this.getForecastResults(forecastConfigurationId, startDate, mostRecentForecastResult.getValidTimeStart()); - + return this.getForecastResults(forecastConfigurationId, startDate, + mostRecentForecastResult.getValidTimeStart()); + } - - public List<ForecastResult> getForecastResults(Long forecastConfigurationId, Date timeStart, Date timeEnd) - { + + public List<ForecastResult> getForecastResults(Long forecastConfigurationId, Date timeStart, Date timeEnd) { Query q = em.createNamedQuery("ForecastResult.findByForecastConfigurationIdAndPeriod"); q.setParameter("forecastConfigurationId", forecastConfigurationId); q.setParameter("timeStart", timeStart); q.setParameter("timeEnd", timeEnd); - try - { + try { return q.getResultList(); - } - catch(NoResultException ex) - { + } catch (NoResultException ex) { return null; } } - - public ForecastResult getMostRecentForecastResult(Long forecastConfigurationId) - { + + public ForecastResult getMostRecentForecastResult(Long forecastConfigurationId) { Query q = em.createNativeQuery( "SELECT * FROM forecast_result " - + "WHERE forecast_configuration_id=:forecastConfigurationId " - + "AND valid_time_start = (" + + "WHERE forecast_configuration_id=:forecastConfigurationId " + + "AND valid_time_start = (" + "SELECT MAX(valid_time_start) " + "FROM forecast_result " + "WHERE forecast_configuration_id=:forecastConfigurationId " - + ");", ForecastResult.class); - + + ");", + ForecastResult.class); + q.setParameter("forecastConfigurationId", forecastConfigurationId); - try - { + try { return (ForecastResult) q.getSingleResult(); - } - catch(NoResultException ex) - { + } catch (NoResultException ex) { return null; } } - + /** * Deletes all former results for this forecast configuration, stores the new ones + * * @param forecastConfiguration - * @param results + * @param results */ - public void storeResults(ForecastConfiguration forecastConfiguration, List<Result> results) - { - //System.out.println("forecastConfigurationId=" + forecastConfiguration.getForecastConfigurationId()); - Query q = em.createNativeQuery("DELETE FROM public.forecast_result WHERE forecast_configuration_id=:forecastConfigurationId"); + public void storeResults(ForecastConfiguration forecastConfiguration, List<Result> results) { + // System.out.println("forecastConfigurationId=" + forecastConfiguration.getForecastConfigurationId()); + Query q = em.createNativeQuery( + "DELETE FROM public.forecast_result WHERE forecast_configuration_id=:forecastConfigurationId"); q.setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()); q.executeUpdate(); - for(Result result:results) - { - ForecastResult fResult = new ForecastResult(forecastConfiguration.getForecastConfigurationId(),result); + for (Result result : results) { + ForecastResult fResult = new ForecastResult(forecastConfiguration.getForecastConfigurationId(), result); em.persist(fResult); } } - - + + /** - * Get all PUBLIC forecast configurations for one user. - * TODO: Should be season based, or possibly based on start/stop date + * Get all PUBLIC forecast configurations for one user. TODO: Should be season based, or possibly based on + * start/stop date + * * @param userId - * @return + * @return */ - public List<ForecastConfiguration> getForecastConfigurationsForUser(Integer userId) - { + public List<ForecastConfiguration> getForecastConfigurationsForUser(Integer userId) { VipsLogicUser user = em.find(VipsLogicUser.class, userId); Query q = em.createNamedQuery("ForecastConfiguration.findByVipsLogicUserId"); q.setParameter("vipsLogicUserId", user); return q.getResultList(); } - + /** - * Get all PRIVATE forecast configurations for one user. - * TODO: Should be season based, or possibly based on start/stop date + * Get all PRIVATE forecast configurations for one user. TODO: Should be season based, or possibly based on + * start/stop date + * * @param userId - * @return + * @return */ - public List<ForecastConfiguration> getPrivateForecastConfigurationsForUser(Integer userId) - { + public List<ForecastConfiguration> getPrivateForecastConfigurationsForUser(Integer userId) { VipsLogicUser user = em.find(VipsLogicUser.class, userId); Query q = em.createNamedQuery("ForecastConfiguration.findPrivateByVipsLogicUserId"); q.setParameter("vipsLogicUserId", user); return q.getResultList(); } - - - - - public List<ForecastConfiguration> getForecastConfigurationsForUserAndDate(Integer userId, Date from, Date to) - { + + + + public List<ForecastConfiguration> getForecastConfigurationsForUserAndDate(Integer userId, Date from, Date to) { VipsLogicUser user = em.find(VipsLogicUser.class, userId); Query q = em.createNamedQuery("ForecastConfiguration.findByVipsLogicUserIdAndDate"); q.setParameter("vipsLogicUserId", user); @@ -274,17 +256,18 @@ public class ForecastBean { q.setParameter("to", to); return q.getResultList(); } - - public List<ForecastConfiguration> getForecastConfigurationsForUserAndCrops(Integer userId, List<Integer> cropOrganismIds) - { + + public List<ForecastConfiguration> getForecastConfigurationsForUserAndCrops(Integer userId, + List<Integer> cropOrganismIds) { VipsLogicUser user = em.find(VipsLogicUser.class, userId); Query q = em.createNamedQuery("ForecastConfiguration.findByVipsLogicUserIdAndCropOrganismId"); q.setParameter("vipsLogicUserId", user); q.setParameter("cropOrganismIds", cropOrganismIds); return q.getResultList(); } - public List<ForecastConfiguration> getForecastConfigurationsForUserAndCropsAndDate(Integer userId, List<Integer> cropOrganismIds, Date from, Date to) - { + + public List<ForecastConfiguration> getForecastConfigurationsForUserAndCropsAndDate(Integer userId, + List<Integer> cropOrganismIds, Date from, Date to) { VipsLogicUser user = em.find(VipsLogicUser.class, userId); Query q = em.createNamedQuery("ForecastConfiguration.findByVipsLogicUserIdAndCropOrganismIdsAndDate"); q.setParameter("vipsLogicUserId", user); @@ -293,30 +276,28 @@ public class ForecastBean { q.setParameter("to", to); return q.getResultList(); } - - + + /** * Returns _ALL_ forecasts. Not for the faint hearted - * @return + * + * @return */ - public List<ForecastConfiguration> getForecastConfigurations() - { + public List<ForecastConfiguration> getForecastConfigurations() { return em.createNamedQuery("ForecastConfiguration.findAll").getResultList(); } - + /** * - * @return + * @return */ - public List<ForecastConfiguration> getForecastConfigurations(List<String> modelIds) - { + public List<ForecastConfiguration> getForecastConfigurations(List<String> modelIds) { return em.createNamedQuery("ForecastConfiguration.findByModelIds") .setParameter("modelIds", modelIds) .getResultList(); } - - public List<ForecastConfiguration> getForecastConfigurations(Organization organization) - { + + public List<ForecastConfiguration> getForecastConfigurations(Organization organization) { List<VipsLogicUser> organizationUsers = em .createNamedQuery("VipsLogicUser.findByOrganizationId") .setParameter("organizationId", organization) @@ -326,16 +307,15 @@ public class ForecastBean { .setParameter("vipsLogicUserIds", organizationUsers) .getResultList(); } - - public List<ForecastConfiguration> getForecastConfigurations(Organization organization, List<String> modelIds, Date from, Date to) - { + + public List<ForecastConfiguration> getForecastConfigurations(Organization organization, List<String> modelIds, + Date from, Date to) { List<VipsLogicUser> organizationUsers = em .createNamedQuery("VipsLogicUser.findByOrganizationId") .setParameter("organizationId", organization) .getResultList(); - - if(!organizationUsers.isEmpty()) - { + + if (!organizationUsers.isEmpty()) { return em .createNamedQuery("ForecastConfiguration.findByVipsLogicUserIdsAndModelIdsAndDate") .setParameter("vipsLogicUserIds", organizationUsers) @@ -343,22 +323,19 @@ public class ForecastBean { .setParameter("from", from) .setParameter("to", to) .getResultList(); - } - else - { + } else { return new ArrayList<>(); } } - - public List<ForecastConfiguration> getForecastConfigurations(List<Integer> organizationIds, List<String> modelIds, Date from, Date to) - { + + public List<ForecastConfiguration> getForecastConfigurations(List<Integer> organizationIds, List<String> modelIds, + Date from, Date to) { List<VipsLogicUser> organizationUsers = em .createNamedQuery("VipsLogicUser.findByOrganizationIds") .setParameter("organizationIds", organizationIds) .getResultList(); - - if(!organizationUsers.isEmpty() && ! modelIds.isEmpty()) - { + + if (!organizationUsers.isEmpty() && !modelIds.isEmpty()) { return em .createNamedQuery("ForecastConfiguration.findByVipsLogicUserIdsAndModelIdsAndDate") .setParameter("vipsLogicUserIds", organizationUsers) @@ -366,117 +343,109 @@ public class ForecastBean { .setParameter("from", from) .setParameter("to", to) .getResultList(); - } - else - { + } else { return new ArrayList<>(); } } - - public List<ForecastConfiguration> getForecastConfigurations(List<Integer> organizationIds, Date from, Date to) - { + + public List<ForecastConfiguration> getForecastConfigurations(List<Integer> organizationIds, Date from, Date to) { List<VipsLogicUser> organizationUsers = em .createNamedQuery("VipsLogicUser.findByOrganizationIds") .setParameter("organizationIds", organizationIds) .getResultList(); - - - if(!organizationUsers.isEmpty()) - { + + + if (!organizationUsers.isEmpty()) { return em .createNamedQuery("ForecastConfiguration.findByVipsLogicUserIdsAndDate") .setParameter("vipsLogicUserIds", organizationUsers) .setParameter("from", from) .setParameter("to", to) .getResultList(); - } - else - { + } else { return new ArrayList<>(); } } - - public List<ForecastConfiguration> getForecastConfigurationsByWeatherStation(PointOfInterestWeatherStation weatherStation) - { + + public List<ForecastConfiguration> getForecastConfigurationsByWeatherStation( + PointOfInterestWeatherStation weatherStation) { return em - .createNamedQuery("ForecastConfiguration.findByWeatherStationPointOfInterestId", ForecastConfiguration.class) + .createNamedQuery("ForecastConfiguration.findByWeatherStationPointOfInterestId", + ForecastConfiguration.class) .setParameter("weatherStationPointOfInterestId", weatherStation) .getResultList(); } - - public List<ForecastConfiguration> getForecastConfigurationsByLocation(PointOfInterest poi) - { + + public List<ForecastConfiguration> getForecastConfigurationsByLocation(PointOfInterest poi) { return em .createNamedQuery("ForecastConfiguration.findByLocationPointOfInterestId", ForecastConfiguration.class) .setParameter("locationPointOfInterestId", poi) .getResultList(); } - - public List<ForecastConfiguration> getForecastConfigurations(PointOfInterestWeatherStation weatherStation,Date from, Date to) - { + + public List<ForecastConfiguration> getForecastConfigurations(PointOfInterestWeatherStation weatherStation, + Date from, Date to) { return em - .createNamedQuery("ForecastConfiguration.findByWeatherStationPointOfInterestIdAndDate", ForecastConfiguration.class) + .createNamedQuery("ForecastConfiguration.findByWeatherStationPointOfInterestIdAndDate", + ForecastConfiguration.class) .setParameter("weatherStationPointOfInterestId", weatherStation) .setParameter("from", from) .setParameter("to", to) .getResultList(); } - + /** * Deletes all forecasts and results from the given weather station - * @param weatherStation + * + * @param weatherStation */ - public void deleteForecastConfigurationsForWeatherStation(PointOfInterestWeatherStation weatherStation) - { - List<ForecastConfiguration> forecastConfigurations = this.getForecastConfigurationsByWeatherStation(weatherStation); - for(ForecastConfiguration forecastConfiguration:forecastConfigurations) - { + public void deleteForecastConfigurationsForWeatherStation(PointOfInterestWeatherStation weatherStation) { + List<ForecastConfiguration> forecastConfigurations = + this.getForecastConfigurationsByWeatherStation(weatherStation); + for (ForecastConfiguration forecastConfiguration : forecastConfigurations) { em.createNativeQuery("DELETE FROM forecast_result WHERE forecast_configuration_id=:forecastConfigurationId") .setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()) .executeUpdate(); em.remove(forecastConfiguration); } } - + /** * Deletes all forecasts and results from the given location - * @param weatherStation + * + * @param weatherStation */ - public void deleteForecastConfigurationsForLocation(PointOfInterest location) - { + public void deleteForecastConfigurationsForLocation(PointOfInterest location) { List<ForecastConfiguration> forecastConfigurations = this.getForecastConfigurationsByLocation(location); - for(ForecastConfiguration forecastConfiguration:forecastConfigurations) - { + for (ForecastConfiguration forecastConfiguration : forecastConfigurations) { em.createNativeQuery("DELETE FROM forecast_result WHERE forecast_configuration_id=:forecastConfigurationId") .setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()) .executeUpdate(); em.remove(forecastConfiguration); } } - + /** * Fetches one specific forecast configuration + * * @param forecastConfigurationId - * @return + * @return */ - public ForecastConfiguration getForecastConfiguration(Long forecastConfigurationId) - { + public ForecastConfiguration getForecastConfiguration(Long forecastConfigurationId) { return em.find(ForecastConfiguration.class, forecastConfigurationId); } - + /** - * Requests all info about models currently available in VIPSCoreManager - * Stores in local db for easy access. + * Requests all info about models currently available in VIPSCoreManager Stores in local db for easy access. */ - public TaskResult updateModelInformation() - { + public TaskResult updateModelInformation() { TaskResult taskResult = new TaskResult(); String jobReport = ""; - // Iterate all the VIPSCore instances + // Iterate all the VIPSCore instances List<VipsCoreInstance> vipsCoreInstances = em.createNamedQuery("VipsCoreInstance.findAll").getResultList(); Integer instancesCompleted = 0; - for(VipsCoreInstance vipsCoreInstance:vipsCoreInstances) { - LOGGER.debug("Attempting to connect to " + vipsCoreInstance.getUri() ); + for (VipsCoreInstance vipsCoreInstance : vipsCoreInstances) { + LOGGER.debug("Attempting to connect to " + vipsCoreInstance.getUri()); try { Client client = ClientBuilder.newClient(); WebTarget target = client.target(vipsCoreInstance.getUri()); @@ -486,8 +455,9 @@ public class ForecastBean { // Get all model Ids from Core Manager Response resp = resource.printModelListJSON(); LOGGER.debug(vipsCoreInstance.getUri() + " returned status code " + String.valueOf(resp.getStatus())); - if(resp.getStatus() != 200) { - jobReport += vipsCoreInstance.getUri() + " returned status code " + String.valueOf(resp.getStatus()) + "\n"; + if (resp.getStatus() != 200) { + jobReport += vipsCoreInstance.getUri() + " returned status code " + String.valueOf(resp.getStatus()) + + "\n"; continue; } @@ -509,36 +479,34 @@ public class ForecastBean { // Retrieve and store information Response r = resource.printModelName(modelId); modelInformation.setDefaultName(r.readEntity(String.class)); - //r.close(); + // r.close(); r = resource.printModelDescription(modelId); modelInformation.setDefaultDescription(r.readEntity(String.class)); - //r.close(); + // r.close(); r = resource.printModelLicense(modelId); modelInformation.setLicense(r.readEntity(String.class)); - //r.close(); + // r.close(); r = resource.printModelCopyright(modelId); modelInformation.setCopyrightHolder(r.readEntity(String.class)); - //r.close(); + // r.close(); r = resource.printModelUsage(modelId); modelInformation.setUsage(r.readEntity(String.class)); - //r.close(); + // r.close(); r = resource.printModelSampleConfig(modelId); modelInformation.setSampleConfig(r.readEntity(String.class)); - //r.close(); + // r.close(); modelInformation.setDateLastRegistered(new Date()); } resp.close(); client.close(); instancesCompleted++; - } - catch(ProcessingException ex) - { + } catch (ProcessingException ex) { jobReport += ex.getMessage() + "\n"; } @@ -547,263 +515,261 @@ public class ForecastBean { taskResult.setMessage(jobReport); return taskResult; } - + /** * * @return All registered models accessible by ModelId as key */ - public Map<String,ModelInformation> getIndexedModelInformation() - { + public Map<String, ModelInformation> getIndexedModelInformation() { Map<String, ModelInformation> retVal = new HashMap<>(); - for(ModelInformation mi: (List<ModelInformation>) em.createNamedQuery("ModelInformation.findAll").getResultList()) - { + for (ModelInformation mi : (List<ModelInformation>) em.createNamedQuery("ModelInformation.findAll") + .getResultList()) { retVal.put(mi.getModelId(), mi); } return retVal; } - + /** * * @return All registered models that has its own preprocessor accessible by ModelId as key */ - public Map<String,ModelInformation> getIndexedBatchableModelInformation() - { + public Map<String, ModelInformation> getIndexedBatchableModelInformation() { Map<String, ModelInformation> retVal = new HashMap<>(); this.getBatchableModels().forEach((mi) -> { retVal.put(mi.getModelId(), mi); }); return retVal; } - - public ModelInformation getModelInformation(String modelId) - { - try - { - return em.createNamedQuery("ModelInformation.findByModelId", ModelInformation.class).setParameter("modelId", modelId).getSingleResult(); - } - catch(NoResultException ex) - { + + public ModelInformation getModelInformation(String modelId) { + try { + return em.createNamedQuery("ModelInformation.findByModelId", ModelInformation.class) + .setParameter("modelId", modelId).getSingleResult(); + } catch (NoResultException ex) { return null; } } - + /** * Stores a forecast configuration, including model specific form fields + * * @param forecastConfiguration * @param formFields * @param modelSpecificFormFields * @return the updated (or freshly created, with brand new Id) forecast configuration */ - public ForecastConfiguration storeForecastConfiguration(ForecastConfiguration forecastConfiguration, Map<String, FormField> formFields, Map<String, FormField> modelSpecificFormFields) - { + public ForecastConfiguration storeForecastConfiguration(ForecastConfiguration forecastConfiguration, + Map<String, FormField> formFields, Map<String, FormField> modelSpecificFormFields) { forecastConfiguration.setModelId(formFields.get("modelId").getWebValue()); - forecastConfiguration.setCropOrganismId(em.find(Organism.class, formFields.get("cropOrganismId").getValueAsInteger())); - forecastConfiguration.setPestOrganismId(em.find(Organism.class, formFields.get("pestOrganismId").getValueAsInteger())); + forecastConfiguration + .setCropOrganismId(em.find(Organism.class, formFields.get("cropOrganismId").getValueAsInteger())); + forecastConfiguration + .setPestOrganismId(em.find(Organism.class, formFields.get("pestOrganismId").getValueAsInteger())); forecastConfiguration.setIsPrivate(formFields.get("isPrivate").getWebValue() != null); - PointOfInterest locationPoi = em.find(PointOfInterest.class, formFields.get("locationPointOfInterestId").getValueAsInteger()); + forecastConfiguration.setUseGridWeatherData(formFields.get("useGridWeatherData").getWebValue() != null + && formFields.get("useGridWeatherData").getWebValue().equals("true")); + PointOfInterest locationPoi = + em.find(PointOfInterest.class, formFields.get("locationPointOfInterestId").getValueAsInteger()); forecastConfiguration.setLocationPointOfInterestId(locationPoi); - PointOfInterest weatherStationPoi = em.find(PointOfInterestWeatherStation.class, formFields.get("weatherStationPointOfInterestId").getValueAsInteger()); + PointOfInterest weatherStationPoi = em.find(PointOfInterestWeatherStation.class, + formFields.get("weatherStationPointOfInterestId").getValueAsInteger()); forecastConfiguration.setWeatherStationPointOfInterestId(weatherStationPoi); String timeZone = formFields.get("timeZone").getWebValue(); forecastConfiguration.setTimeZone(timeZone); forecastConfiguration.setDateStart(formFields.get("dateStart").getValueAsDate()); forecastConfiguration.setDateEnd(formFields.get("dateEnd").getValueAsDate()); - VipsLogicUser forecastConfigurationUser = em.find(VipsLogicUser.class, formFields.get("vipsLogicUserId").getValueAsInteger()); + VipsLogicUser forecastConfigurationUser = + em.find(VipsLogicUser.class, formFields.get("vipsLogicUserId").getValueAsInteger()); forecastConfiguration.setVipsCoreUserId(forecastConfigurationUser); - + forecastConfiguration = em.merge(forecastConfiguration); - + // Reset all model configurations, then store the new ones // As for now: We keep the old ones. // Reason: If anybody screws up by changing a form, old configurations could get lost - /*List<ForecastModelConfiguration> configsToRemove = em.createNamedQuery("ForecastModelConfiguration.findByForecastConfigurationId").setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()).getResultList(); - for(ForecastModelConfiguration configToRemove: configsToRemove) - { - em.remove(configToRemove); - } - em.flush();*/ - + /* + * List<ForecastModelConfiguration> configsToRemove = + * em.createNamedQuery("ForecastModelConfiguration.findByForecastConfigurationId").setParameter( + * "forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()).getResultList(); + * for(ForecastModelConfiguration configToRemove: configsToRemove) { em.remove(configToRemove); } em.flush(); + */ + // Store new values - for(FormField field : modelSpecificFormFields.values()) - { + for (FormField field : modelSpecificFormFields.values()) { String deCamelizedFieldName = getDeCamelizedFieldName(forecastConfiguration.getModelId(), field.getName()); - ForecastModelConfiguration forecastModelConfiguration = new ForecastModelConfiguration(forecastConfiguration.getForecastConfigurationId(), deCamelizedFieldName); + ForecastModelConfiguration forecastModelConfiguration = new ForecastModelConfiguration( + forecastConfiguration.getForecastConfigurationId(), deCamelizedFieldName); forecastModelConfiguration.setParameterValue(field.getWebValue()); em.merge(forecastModelConfiguration); } - + return forecastConfiguration; } - + /** * * @param modelId * @param camelCaseName * @return MODELID_CAMEL_CASE_NAME */ - public String getDeCamelizedFieldName(String modelId, String camelCaseName) - { + public String getDeCamelizedFieldName(String modelId, String camelCaseName) { StringBuilder deCamelizedFieldName = new StringBuilder(modelId.toUpperCase()); - for(String phrase : camelCaseName.split("(?=\\p{Lu})")) - { + for (String phrase : camelCaseName.split("(?=\\p{Lu})")) { deCamelizedFieldName.append("_").append(phrase.toUpperCase()); } - + return deCamelizedFieldName.toString(); } - - - public List<ForecastModelConfiguration> getForecastModelConfigurations(Long forecastConfigurationId) - { - return em.createNamedQuery("ForecastModelConfiguration.findByForecastConfigurationId").setParameter("forecastConfigurationId", forecastConfigurationId).getResultList(); + + + public List<ForecastModelConfiguration> getForecastModelConfigurations(Long forecastConfigurationId) { + return em.createNamedQuery("ForecastModelConfiguration.findByForecastConfigurationId") + .setParameter("forecastConfigurationId", forecastConfigurationId).getResultList(); } - + /** * Deletes a forecast configuration and all results - * @param forecastConfigurationId + * + * @param forecastConfigurationId */ - public void deleteForecastConfiguration(Long forecastConfigurationId) - { + public void deleteForecastConfiguration(Long forecastConfigurationId) { // The entity relationship between ForecastConfiguration and ForecastResult - // is not explicit in EJB model, but in the database there is a foreign key + // is not explicit in EJB model, but in the database there is a foreign key // in forecast_result (and in forecast summary) referencing the forecast_configuration // Explicit deletion of forecast_results rows is therefore necessary. ForecastConfiguration forecastConfiguration = em.find(ForecastConfiguration.class, forecastConfigurationId); - Query q = em.createNativeQuery("DELETE FROM public.forecast_result WHERE forecast_configuration_id=:forecastConfigurationId"); + Query q = em.createNativeQuery( + "DELETE FROM public.forecast_result WHERE forecast_configuration_id=:forecastConfigurationId"); q.setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()); q.executeUpdate(); - q = em.createNativeQuery("DELETE FROM public.forecast_summary WHERE forecast_configuration_id=:forecastConfigurationId"); + q = em.createNativeQuery( + "DELETE FROM public.forecast_summary WHERE forecast_configuration_id=:forecastConfigurationId"); + q.setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()); + q.executeUpdate(); + // Entries in ForecastNotificationLog referencing the ForecastConfiguration must also be deleted + q = em.createNativeQuery( + "DELETE FROM messaging.forecast_notification_log WHERE forecast_configuration_id=:forecastConfigurationId"); q.setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()); q.executeUpdate(); em.remove(forecastConfiguration); - + } - - public List<ForecastConfiguration> getForecastConfigurationsValidAtTime(Organization organization, Date time) - { + + public List<ForecastConfiguration> getForecastConfigurationsValidAtTime(Organization organization, Date time) { Query q = em.createNativeQuery( - "SELECT * FROM public.forecast_configuration " + "SELECT * FROM public.forecast_configuration " + "WHERE vips_logic_user_id IN (SELECT user_id FROM public.vips_logic_user WHERE organization_id=:organizationId) " + "AND :time BETWEEN date_start AND date_end " - + "ORDER BY weather_station_point_of_interest_id ASC " - ,ForecastConfiguration.class); + + "ORDER BY weather_station_point_of_interest_id ASC ", + ForecastConfiguration.class); q.setParameter("organizationId", organization.getOrganizationId()); q.setParameter("time", time); return q.getResultList(); } - - public void runForecast(ForecastConfiguration forecastConfiguration) throws PreprocessorException, RunModelException - { - ModelRunPreprocessor preprocessor = ModelRunPreprocessorFactory.getModelRunPreprocessor(forecastConfiguration.getModelId()); - if(preprocessor != null) - { - ModelConfiguration config = preprocessor.getModelConfiguration(forecastConfiguration); - ModelRunRequest request = new ModelRunRequest(config); - Map<String,String> loginInfo = new HashMap<>(); - - // VIPSLogic logs in on behalf of client - ModelInformation modelInformation = em.find(ModelInformation.class, config.getModelId()); - if(modelInformation.getVipsCoreInstanceId() == null) - { - throw new RunModelException("ERROR: Model " + modelInformation.getDefaultName() + "(" + config.getModelId() + ") is not connected to a VIPSCoreInstance. Please check your server configuration."); - } - loginInfo.put("username",modelInformation.getVipsCoreInstanceId().getUsername()); - //loginInfo.put("username","wrongusername"); - loginInfo.put("password",modelInformation.getVipsCoreInstanceId().getPassword()); - request.setLoginInfo(loginInfo); - // We tell which client this is (the db Id in VIPSCoreManager) - Integer VIPSCoreUserId = forecastConfiguration.getVipsLogicUserId().getVipsCoreUserIdWithFallback(); - if(VIPSCoreUserId == null) - { - throw new PreprocessorException("No user id found for forecast #" + forecastConfiguration.getForecastConfigurationId() + - ". Possible reason: The user's organization (" - + forecastConfiguration.getVipsLogicUserId().getOrganizationId().getOrganizationName() - + ") hasn't got a VIPSCoreUserId."); - } - //System.out.println("VIPSCoreUserId = " + VIPSCoreUserId + ", name=" + forecastConfiguration.getVipsLogicUserId().getLastName()); - request.setVipsCoreUserId(VIPSCoreUserId); - //System.out.println("RunModel for wsId " + forecastConfiguration.getWeatherStationPointOfInterestId()); - //System.out.println(config.toJSON()); - /* DEBUG STUFF */ - /*ObjectMapper mapper = new ObjectMapper(); - try - { - System.out.println(mapper.writeValueAsString(request)); - } - catch(JsonProcessingException ex) - { - ex.printStackTrace(); - }*/ - - Response resp = this.getManagerResource(modelInformation).runModel(config.getModelId(), request); - if(resp.getStatus() == Response.Status.OK.getStatusCode()) - { - //System.out.println(resp.readEntity(String.class)); - List<Result> results = (List<Result>) resp.readEntity(new GenericType<List<Result>>(){}); - //System.out.println("ForecastConfigId=" + forecastConfiguration.getForecastConfigurationId() + ", resultsize=" + results.size()); - // We delete all former results before we store the new ones - forecastBean.storeResults(forecastConfiguration,results); - } - else - { - throw new RunModelException(resp.readEntity(String.class)); - } - //System.out.println("Finished runModel for wsId" + forecastConfiguration.getWeatherStationPointOfInterestId()); - - } - else - { - throw new PreprocessorException("Could not find model with id=|" + forecastConfiguration.getModelId() + "|"); + + public void runForecast(ForecastConfiguration forecastConfiguration) + throws PreprocessorException, RunModelException { + ModelRunPreprocessor preprocessor = + ModelRunPreprocessorFactory.getModelRunPreprocessor(forecastConfiguration.getModelId()); + if (preprocessor != null) { + ModelConfiguration config = preprocessor.getModelConfiguration(forecastConfiguration); + ModelRunRequest request = new ModelRunRequest(config); + Map<String, String> loginInfo = new HashMap<>(); + + // VIPSLogic logs in on behalf of client + ModelInformation modelInformation = em.find(ModelInformation.class, config.getModelId()); + if (modelInformation.getVipsCoreInstanceId() == null) { + throw new RunModelException( + "ERROR: Model " + modelInformation.getDefaultName() + "(" + config.getModelId() + + ") is not connected to a VIPSCoreInstance. Please check your server configuration."); + } + loginInfo.put("username", modelInformation.getVipsCoreInstanceId().getUsername()); + // loginInfo.put("username","wrongusername"); + loginInfo.put("password", modelInformation.getVipsCoreInstanceId().getPassword()); + request.setLoginInfo(loginInfo); + // We tell which client this is (the db Id in VIPSCoreManager) + Integer VIPSCoreUserId = forecastConfiguration.getVipsLogicUserId().getVipsCoreUserIdWithFallback(); + if (VIPSCoreUserId == null) { + throw new PreprocessorException( + "No user id found for forecast #" + forecastConfiguration.getForecastConfigurationId() + + ". Possible reason: The user's organization (" + + forecastConfiguration.getVipsLogicUserId().getOrganizationId().getOrganizationName() + + ") hasn't got a VIPSCoreUserId."); + } + // System.out.println("VIPSCoreUserId = " + VIPSCoreUserId + ", name=" + + // forecastConfiguration.getVipsLogicUserId().getLastName()); + request.setVipsCoreUserId(VIPSCoreUserId); + // System.out.println("RunModel for wsId " + forecastConfiguration.getWeatherStationPointOfInterestId()); + // System.out.println(config.toJSON()); + /* DEBUG STUFF */ + /* + * ObjectMapper mapper = new ObjectMapper(); try { System.out.println(mapper.writeValueAsString(request)); } + * catch(JsonProcessingException ex) { ex.printStackTrace(); } + */ + + Response resp = this.getManagerResource(modelInformation).runModel(config.getModelId(), request); + if (resp.getStatus() == Response.Status.OK.getStatusCode()) { + // System.out.println(resp.readEntity(String.class)); + List<Result> results = (List<Result>) resp.readEntity(new GenericType<List<Result>>() {}); + // System.out.println("ForecastConfigId=" + forecastConfiguration.getForecastConfigurationId() + ", + // resultsize=" + results.size()); + // We delete all former results before we store the new ones + forecastBean.storeResults(forecastConfiguration, results); + } else { + throw new RunModelException(resp.readEntity(String.class)); + } + // System.out.println("Finished runModel for wsId" + + // forecastConfiguration.getWeatherStationPointOfInterestId()); + + } else { + throw new PreprocessorException( + "Could not find model with id=|" + forecastConfiguration.getModelId() + "|"); } } - - public List<Result> runForecast(ModelConfiguration config, Integer VIPSCoreUserId) throws RunModelException - { + + public List<Result> runForecast(ModelConfiguration config, Integer VIPSCoreUserId) throws RunModelException { ModelInformation modelInformation = em.find(ModelInformation.class, config.getModelId()); - if(modelInformation.getVipsCoreInstanceId() == null) - { - throw new RunModelException("ERROR: Model " + modelInformation.getDefaultName() + "(" + config.getModelId() + ") is not connected to a VIPSCoreInstance. Please check your server configuration."); + if (modelInformation.getVipsCoreInstanceId() == null) { + throw new RunModelException("ERROR: Model " + modelInformation.getDefaultName() + "(" + config.getModelId() + + ") is not connected to a VIPSCoreInstance. Please check your server configuration."); } ModelRunRequest request = new ModelRunRequest(config); - Map<String,String> loginInfo = new HashMap<>(); + Map<String, String> loginInfo = new HashMap<>(); // VIPSLogic logs in on behalf of client - loginInfo.put("username",modelInformation.getVipsCoreInstanceId().getUsername()); - //loginInfo.put("username","wrongusername"); - loginInfo.put("password",modelInformation.getVipsCoreInstanceId().getPassword()); + loginInfo.put("username", modelInformation.getVipsCoreInstanceId().getUsername()); + // loginInfo.put("username","wrongusername"); + loginInfo.put("password", modelInformation.getVipsCoreInstanceId().getPassword()); request.setLoginInfo(loginInfo); - //System.out.println("VIPSCoreUserId = " + VIPSCoreUserId + ", name=" + forecastConfiguration.getVipsLogicUserId().getLastName()); + // System.out.println("VIPSCoreUserId = " + VIPSCoreUserId + ", name=" + + // forecastConfiguration.getVipsLogicUserId().getLastName()); request.setVipsCoreUserId(VIPSCoreUserId); - //System.out.println("RunModel for wsId" + forecastConfiguration.getWeatherStationPointOfInterestId()); + // System.out.println("RunModel for wsId" + forecastConfiguration.getWeatherStationPointOfInterestId()); Response resp = this.getManagerResource(modelInformation).runModel(config.getModelId(), request); - if(resp.getStatus() == Response.Status.OK.getStatusCode()) - { - List<Result> results = (List<Result>) resp.readEntity(new GenericType<List<Result>>(){}); - return results; - } - else - { + if (resp.getStatus() == Response.Status.OK.getStatusCode()) { + return resp.readEntity(new GenericType<>() {}); + } else { throw new RunModelException(resp.readEntity(String.class)); } } - + /** * Get the interface for REST resources in VIPSCoreManager - * @return + * + * @return */ - private ManagerResource getManagerResource(ModelInformation modelInformation) - { + private ManagerResource getManagerResource(ModelInformation modelInformation) { Client client = ClientBuilder.newClient(); WebTarget target = client.target(modelInformation.getVipsCoreInstanceId().getUri()); ResteasyWebTarget rTarget = (ResteasyWebTarget) target; ManagerResource resource = rTarget.proxy(ManagerResource.class); return resource; } - - public Kml getForecastsAggregateKml(List<Integer> organizationIds, List<Integer> cropOrganismIds, Date theDate, String serverName, VipsLogicUser user) - { - //String iconPath = Globals.PROTOCOL + "://" + serverName + "/public/images/"; - //String iconPath = "//" + serverName + "/public/images/"; + + public Kml getForecastsAggregateKml(List<Integer> organizationIds, List<Integer> cropOrganismIds, Date theDate, + String serverName, VipsLogicUser user) { + // String iconPath = Globals.PROTOCOL + "://" + serverName + "/public/images/"; + // String iconPath = "//" + serverName + "/public/images/"; String iconPath = "https://logic.vips.nibio.no/public/images/"; // Initialization final Vec2 hotspot = new Vec2() @@ -813,66 +779,60 @@ public class ForecastBean { .withYunits(Units.FRACTION); final Kml kml = KmlFactory.createKml(); final Document document = kml.createAndSetDocument() - .withName("Forecast results - aggregates").withDescription("Worst forecasts for each POI"); + .withName("Forecast results - aggregates").withDescription("Worst forecasts for each POI"); LabelStyle noLabel = new LabelStyle().withScale(0.0); - + Calendar cal = Calendar.getInstance(); cal.setTime(SystemTime.getSystemTime()); - - for(int i=0;i<=4;i++) - { - + + for (int i = 0; i <= 4; i++) { + document.createAndAddStyle() - .withId("warning_type_" + i) - .withLabelStyle(noLabel) - .createAndSetIconStyle() + .withId("warning_type_" + i) + .withLabelStyle(noLabel) + .createAndSetIconStyle() .withScale(1) .withHotSpot(hotspot) .createAndSetIcon() - .withHref(iconPath + "station_icon_status_" + - (cal.get(Calendar.MONTH) <= 1 ? "winter" : - cal.get(Calendar.MONTH) == Calendar.DECEMBER ? "xmas" : i) - + ".png"); + .withHref(iconPath + "station_icon_status_" + + (cal.get(Calendar.MONTH) <= 1 ? "winter" + : cal.get(Calendar.MONTH) == Calendar.DECEMBER ? "xmas" : i) + + ".png"); } - - // Run through forecast configurations - //Date benchmark = new Date(); + + // Run through forecast configurations + // Date benchmark = new Date(); List<PointOfInterest> poisWithAggregate = new ArrayList<>(); - if(organizationIds.size() == 1 && organizationIds.get(0).equals(-1)) - { - em.createNamedQuery("Organization.findAll",Organization.class).getResultStream().forEach( - org-> poisWithAggregate.addAll(getPointOfInterestForecastsAggregate(org.getOrganizationId(), cropOrganismIds, theDate, user)) - ); - } - else - { + if (organizationIds.size() == 1 && organizationIds.get(0).equals(-1)) { + em.createNamedQuery("Organization.findAll", Organization.class).getResultStream().forEach( + org -> poisWithAggregate.addAll(getPointOfInterestForecastsAggregate(org.getOrganizationId(), + cropOrganismIds, theDate, user))); + } else { organizationIds.stream().forEach( - orgId-> poisWithAggregate.addAll(getPointOfInterestForecastsAggregate(orgId, cropOrganismIds, theDate, user)) - ); + orgId -> poisWithAggregate + .addAll(getPointOfInterestForecastsAggregate(orgId, cropOrganismIds, theDate, user))); } - - //System.out.println(this.getClass().getName() + " DEBUG: getPointOfInterestForecastsAggregate took " + (new Date().getTime() - benchmark.getTime()) + " ms to complete."); - + + // System.out.println(this.getClass().getName() + " DEBUG: getPointOfInterestForecastsAggregate took " + (new + // Date().getTime() - benchmark.getTime()) + " ms to complete."); + GISEntityUtil gisUtil = new GISEntityUtil(); - for(PointOfInterest poiWithAggregate:poisWithAggregate) - { + for (PointOfInterest poiWithAggregate : poisWithAggregate) { // If it's an inactive weather station, we don't produce a placemark - if(poiWithAggregate instanceof PointOfInterestWeatherStation - && ((PointOfInterestWeatherStation) poiWithAggregate).getActive().equals(Boolean.FALSE) - ) - { + if (poiWithAggregate instanceof PointOfInterestWeatherStation + && ((PointOfInterestWeatherStation) poiWithAggregate).getActive().equals(Boolean.FALSE)) { continue; } - + // Adding infoUri (direct link to weather station information) as extra attribute String infoUriValue = ""; - if(poiWithAggregate instanceof PointOfInterestWeatherStation) - { - String infoUriExpression = ((PointOfInterestWeatherStation) poiWithAggregate).getWeatherStationDataSourceId().getInfoUriExpression(); - if(!infoUriExpression.isEmpty()) - { - infoUriValue = String.format(infoUriExpression, ((PointOfInterestWeatherStation) poiWithAggregate).getWeatherStationRemoteId()); + if (poiWithAggregate instanceof PointOfInterestWeatherStation) { + String infoUriExpression = ((PointOfInterestWeatherStation) poiWithAggregate) + .getWeatherStationDataSourceId().getInfoUriExpression(); + if (!infoUriExpression.isEmpty()) { + infoUriValue = String.format(infoUriExpression, + ((PointOfInterestWeatherStation) poiWithAggregate).getWeatherStationRemoteId()); } } Data infoUri = new Data(infoUriValue); @@ -884,43 +844,44 @@ public class ForecastBean { dataList.add(stationName); ExtendedData extendedData = document.createAndSetExtendedData() .withData(dataList); - + final Placemark placemark = document.createAndAddPlacemark() - //.withName(poiWithAggregate.getName()) - .withDescription("<![CDATA[Mangler informasjon om varsler for " + poiWithAggregate.getName() + "]]>") - .withStyleUrl("#warning_type_" - + (poiWithAggregate.getProperties().get("forecastsAggregate") != null ? poiWithAggregate.getProperties().get("forecastsAggregate") : "0") - ) - .withId(poiWithAggregate.getPointOfInterestId().toString()) - .withExtendedData(extendedData); - - + // .withName(poiWithAggregate.getName()) + .withDescription( + "<![CDATA[Mangler informasjon om varsler for " + poiWithAggregate.getName() + "]]>") + .withStyleUrl("#warning_type_" + + (poiWithAggregate.getProperties().get("forecastsAggregate") != null + ? poiWithAggregate.getProperties().get("forecastsAggregate") + : "0")) + .withId(poiWithAggregate.getPointOfInterestId().toString()) + .withExtendedData(extendedData); + + final Point point = placemark.createAndSetPoint(); List<Coordinate> coord = point.createAndSetCoordinates(); - + coord.add(gisUtil.getKMLCoordinateFromJTSCoordinate(poiWithAggregate.getGisGeom().getCoordinate())); } - //System.out.println(kml.marshal()); + // System.out.println(kml.marshal()); return kml; } - + /** - * The table forecast_result_cache always should contain the forecast - * results from TODAY (The system's time, which is configurable) + * The table forecast_result_cache always should contain the forecast results from TODAY (The system's time, which + * is configurable) */ - public void updateForecastResultCacheTable() - { - // Because we might be in completely different time zones, + public void updateForecastResultCacheTable() { + // Because we might be in completely different time zones, // Today must stretch from UTC 00:00 -12h to UTC 24:00 +12h, ie 48 hours Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC")); cal.setTime(SystemTime.getSystemTime()); cal.set(Calendar.HOUR_OF_DAY, 12); - cal.set(Calendar.MINUTE,0); - cal.set(Calendar.SECOND,0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); cal.add(Calendar.DATE, -1); Date startTime = cal.getTime(); - cal.add(Calendar.DATE,2); + cal.add(Calendar.DATE, 2); Date endTime = cal.getTime(); String transactionSQL = new StringBuilder() .append("BEGIN;") @@ -936,55 +897,53 @@ public class ForecastBean { .append(" );") .append("END;") .toString(); - + Query query = em.createNativeQuery(transactionSQL); query.setParameter("startTime", startTime); query.setParameter("endTime", endTime); query.setParameter("currentDate", SystemTime.getSystemTime()); query.executeUpdate(); } - + /** - * The table forecast_summary should contain forecast summaries - * from +/- 10 days related to TODAY (The system's time, which is configurable) + * The table forecast_summary should contain forecast summaries from +/- 10 days related to TODAY (The system's + * time, which is configurable) */ - public void updateForecastSummaryTable(Date currentDate) - { - // + public void updateForecastSummaryTable(Date currentDate) { + // // Collect all forecasts that are active TODAY - // This + // This List<ForecastConfiguration> activeForecasts = em.createNamedQuery("ForecastConfiguration.findAllActiveAtDate") .setParameter("currentDate", currentDate).getResultList(); - + // Loop through them List<Long> activeForecastIds = new ArrayList<>(); Query deleteQ = em.createNativeQuery( - "DELETE FROM forecast_summary " - + "WHERE forecast_configuration_id = :forecastConfigurationId"); + "DELETE FROM forecast_summary " + + "WHERE forecast_configuration_id = :forecastConfigurationId"); Query findQ = em.createNamedQuery("ForecastResult.findByForecastConfigurationIdAndPeriod"); - for(ForecastConfiguration forecastConfiguration:activeForecasts) - { + for (ForecastConfiguration forecastConfiguration : activeForecasts) { activeForecastIds.add(forecastConfiguration.getForecastConfigurationId()); - //System.out.println("forecastConfig id=" + forecastConfiguration.getForecastConfigurationId()); + // System.out.println("forecastConfig id=" + forecastConfiguration.getForecastConfigurationId()); // Delete previous summaries for the specific forecast (one at a time, // to prevent loss of data in case of software error) - + deleteQ.setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()) - .executeUpdate(); - - // Get all results that are within +/- 10 days from TODAY (taking + .executeUpdate(); + + // Get all results that are within +/- 10 days from TODAY (taking // time zone into account) - TimeZone forecastTimeZone = forecastConfiguration.getTimeZone() != null ? - TimeZone.getTimeZone(forecastConfiguration.getTimeZone()) - : TimeZone.getTimeZone(forecastConfiguration.getVipsLogicUserId().getOrganizationId().getDefaultTimeZone()) - ; + TimeZone forecastTimeZone = forecastConfiguration.getTimeZone() != null + ? TimeZone.getTimeZone(forecastConfiguration.getTimeZone()) + : TimeZone.getTimeZone( + forecastConfiguration.getVipsLogicUserId().getOrganizationId().getDefaultTimeZone()); Calendar cal = Calendar.getInstance(forecastTimeZone); cal.setTime(currentDate); cal.add(Calendar.DATE, -10); cal.set(Calendar.HOUR_OF_DAY, 0); - cal.set(Calendar.MINUTE,0); - cal.set(Calendar.SECOND,0); - cal.set(Calendar.MILLISECOND,0); + cal.set(Calendar.MINUTE, 0); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); Date tenDaysAgo = cal.getTime(); cal.add(Calendar.DATE, 20); Date tenDaysAhead = cal.getTime(); @@ -993,174 +952,166 @@ public class ForecastBean { .setParameter("timeEnd", tenDaysAhead) .setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()) .getResultList(); - + // Loop through each day (take timezone into account!), find worst warning Collections.sort(results); SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); format.setTimeZone(forecastTimeZone); Map<String, Integer> resultDailyAggregate = new HashMap<>(); - for(ForecastResult result:results) - { + for (ForecastResult result : results) { String dayStamp = format.format(result.getValidTimeStart()); Integer currentWorstCode = resultDailyAggregate.get(dayStamp); - resultDailyAggregate.put(dayStamp, - Math.max( - currentWorstCode != null ? currentWorstCode : 0, - result.getWarningStatus() - ) - ); - + resultDailyAggregate.put(dayStamp, + Math.max( + currentWorstCode != null ? currentWorstCode : 0, + result.getWarningStatus())); + } - for(String dayStamp: resultDailyAggregate.keySet()) - { + for (String dayStamp : resultDailyAggregate.keySet()) { Date aggregateDay; try { // PostgreSQL date is a mess. Need to convert to default timezone to get it right - aggregateDay = new WeatherUtil().changeDateTimeZone(format.parse(dayStamp), forecastTimeZone, TimeZone.getDefault()); + aggregateDay = new WeatherUtil().changeDateTimeZone(format.parse(dayStamp), forecastTimeZone, + TimeZone.getDefault()); ForecastSummaryPK summaryPK = new ForecastSummaryPK( - forecastConfiguration.getForecastConfigurationId(), - aggregateDay - ); + forecastConfiguration.getForecastConfigurationId(), + aggregateDay); ForecastSummary summary = new ForecastSummary(summaryPK); summary.setSummaryCreatedTime(new Date()); summary.setWarningStatus(resultDailyAggregate.get(dayStamp)); em.persist(summary); } catch (ParseException ex) { Logger.getLogger(ForecastBean.class.getName()).log(Level.SEVERE, null, ex); - System.out.println(this.getClass().getName() + " [updateForecastSummaryTable]: Error parsing date " + dayStamp); + System.out.println(this.getClass().getName() + " [updateForecastSummaryTable]: Error parsing date " + + dayStamp); } - + } - //em.flush(); + // em.flush(); } - - if(activeForecastIds != null && ! activeForecastIds.isEmpty()) - { + + if (activeForecastIds != null && !activeForecastIds.isEmpty()) { // Delete all summaries from not active forecasts em.createNativeQuery("DELETE FROM forecast_summary " + "WHERE forecast_configuration_id NOT IN :activeForecastIds") .setParameter("activeForecastIds", activeForecastIds) .executeUpdate(); - } - else - { + } else { em.createNativeQuery("TRUNCATE forecast_summary").executeUpdate(); } } - - public List<ForecastConfiguration> getForecastConfigurationWithSummaries(List<Long> forecastConfigurationIds) - { + + public List<ForecastConfiguration> getForecastConfigurationWithSummaries(List<Long> forecastConfigurationIds) { List<ForecastConfiguration> retVal = em.createNamedQuery("ForecastConfiguration.findByForecastConfigurationIds") .setParameter("forecastConfigurationIds", forecastConfigurationIds) .getResultList(); - for(ForecastConfiguration config: retVal) - { + for (ForecastConfiguration config : retVal) { Query q = em.createNamedQuery("ForecastSummary.findByForecastConfigurationId"); config.setForecastSummaries( q.setParameter("forecastConfigurationId", config.getForecastConfigurationId()) - .getResultList() - ); + .getResultList()); } return retVal; } - + /** * Finds the forecast configuration summaries for a given organization and that this user has access to + * * @param organizationId - * @return + * @return */ - public List<ForecastConfiguration> getForecastConfigurationSummaries(Integer organizationId, VipsLogicUser user) - { + public List<ForecastConfiguration> getForecastConfigurationSummaries(Integer organizationId, VipsLogicUser user) { List<ForecastSummary> summaries = em.createNamedQuery("ForecastSummary.findByOrganizationId") .setParameter("organizationId", em.find(Organization.class, organizationId)) .getResultList(); Map<Long, List<ForecastSummary>> mappedSummaries = new HashMap<>(); summaries.forEach((s) -> { - List<ForecastSummary> summaryForForecast = mappedSummaries.get(s.getForecastSummaryPK().getForecastConfigurationId()) != null ? - mappedSummaries.get(s.getForecastSummaryPK().getForecastConfigurationId()) : - new ArrayList<>(); + List<ForecastSummary> summaryForForecast = + mappedSummaries.get(s.getForecastSummaryPK().getForecastConfigurationId()) != null + ? mappedSummaries.get(s.getForecastSummaryPK().getForecastConfigurationId()) + : new ArrayList<>(); summaryForForecast.add(s); mappedSummaries.put(s.getForecastSummaryPK().getForecastConfigurationId(), summaryForForecast); }); - if(mappedSummaries.size() > 0) - { - List<ForecastConfiguration> configurations = em.createNamedQuery("ForecastConfiguration.findByForecastConfigurationIds").setParameter("forecastConfigurationIds", mappedSummaries.keySet()).getResultList(); + if (mappedSummaries.size() > 0) { + List<ForecastConfiguration> configurations = + em.createNamedQuery("ForecastConfiguration.findByForecastConfigurationIds") + .setParameter("forecastConfigurationIds", mappedSummaries.keySet()).getResultList(); // Do some authorization. - configurations = configurations.stream().filter(fc -> this.isUserAuthorizedForForecastConfiguration(fc, user)).collect(Collectors.toList()); - + configurations = configurations.stream() + .filter(fc -> this.isUserAuthorizedForForecastConfiguration(fc, user)).collect(Collectors.toList()); + configurations.forEach((conf) -> { - + conf.setForecastSummaries(mappedSummaries.get(conf.getForecastConfigurationId())); }); return configurations; - } - else - { + } else { return new ArrayList<>(); } } /** - * Selects the "worst" (highest infection risk) warning status for forecasts - * running at the pois connected to the given organization + * Selects the "worst" (highest infection risk) warning status for forecasts running at the pois connected to the + * given organization + * * @param organizationId Filter for organization * @param cropOrganismIds Filter for crops - * @param theDate Filter for date. If theDate=systemDate, data is fetched from the caching table forecast_result_cache + * @param theDate Filter for date. If theDate=systemDate, data is fetched from the caching table + * forecast_result_cache * @param user if not null: Include private forecasts for this user - * @return + * @return */ private List<PointOfInterest> getPointOfInterestForecastsAggregate( - Integer organizationId, - List<Integer> cropOrganismIds, + Integer organizationId, + List<Integer> cropOrganismIds, Date theDate, - VipsLogicUser user - ) { + VipsLogicUser user) { // TODO: More precise gathering of POIs... List<PointOfInterest> pois; - if(organizationId != null && organizationId > 0) - { + if (organizationId != null && organizationId > 0) { pois = em.createNamedQuery("PointOfInterest.findForecastLocationsByOrganizationId") - .setParameter("organizationId", em.find(Organization.class, organizationId)) - .getResultList(); - } - else - { + .setParameter("organizationId", em.find(Organization.class, organizationId)) + .getResultList(); + } else { pois = em.createNamedQuery("PointOfInterest.findAll").getResultList(); } - + String dateFormat = "yyyy-MM-dd"; SimpleDateFormat format = new SimpleDateFormat(dateFormat); // If theDate=systemDate, data is fetched from the caching table forecast_result_cache - String tableName = (format.format(theDate).equals(format.format(SystemTime.getSystemTime()))) ? "forecast_result_cache" : "forecast_result"; - //this.updateForecastResultCacheTable(); + String tableName = + (format.format(theDate).equals(format.format(SystemTime.getSystemTime()))) ? "forecast_result_cache" + : "forecast_result"; + // this.updateForecastResultCacheTable(); Calendar cal = Calendar.getInstance(); cal.setTime(theDate); WeatherUtil wUtil = new WeatherUtil(); - for(PointOfInterest poi: pois) - { + for (PointOfInterest poi : pois) { Date midnight = wUtil.normalizeToExactDate(theDate, TimeZone.getTimeZone(poi.getTimeZone())); cal.setTime(theDate); cal.add(Calendar.DATE, 1); Date nextMidnight = cal.getTime(); - + String sql = "SELECT max(warning_status) FROM " + tableName + " \n" + - "WHERE forecast_configuration_id IN( \n" + - " SELECT forecast_configuration_id \n" + - " FROM forecast_configuration \n" + - " WHERE forecast_configuration_id > 0 \n" + - - (user == null ? - " AND is_private IS FALSE \n" - :" AND (is_private IS FALSE OR (is_private IS TRUE AND vips_logic_user_id=:vipsLogicUserId))" - ) + - " AND location_point_of_interest_id=:locationPointOfInterestId \n" + - (cropOrganismIds != null && ! cropOrganismIds.isEmpty() ? " AND crop_organism_id IN (" + StringUtils.join(cropOrganismIds, ",") + ") " : "") + - ")\n" + - "AND valid_time_start between :midnight AND :nextMidnight"; - //System.out.println(poi.getName() + " SQL=" + sql); + "WHERE forecast_configuration_id IN( \n" + + " SELECT forecast_configuration_id \n" + + " FROM forecast_configuration \n" + + " WHERE forecast_configuration_id > 0 \n" + + + (user == null ? " AND is_private IS FALSE \n" + : " AND (is_private IS FALSE OR (is_private IS TRUE AND vips_logic_user_id=:vipsLogicUserId))") + + + " AND location_point_of_interest_id=:locationPointOfInterestId \n" + + (cropOrganismIds != null && !cropOrganismIds.isEmpty() + ? " AND crop_organism_id IN (" + StringUtils.join(cropOrganismIds, ",") + ") " + : "") + + + ")\n" + + "AND valid_time_start between :midnight AND :nextMidnight"; + // System.out.println(poi.getName() + " SQL=" + sql); Query q = em.createNativeQuery(sql); - if(user != null) - { + if (user != null) { q.setParameter("vipsLogicUserId", user); } q.setParameter("locationPointOfInterestId", poi.getPointOfInterestId()); @@ -1168,152 +1119,148 @@ public class ForecastBean { q.setParameter("nextMidnight", nextMidnight); Integer result = (Integer) q.getSingleResult(); poi.getProperties().put("forecastsAggregate", result); - + } return pois; } /** * Returns the latest forecast results for given point of interest + * * @param poiId - * @return + * @return */ public Map<String, Object> getLatestForecastResultsForPoi(Integer poiId) { Map<String, Object> retVal = new HashMap<>(); - + PointOfInterest poi = em.find(PointOfInterest.class, poiId); - List<ForecastConfiguration> forecastConfigurations = - em.createNamedQuery("ForecastConfiguration.findByLocationPointOfInterestId") - .setParameter("locationPointOfInterestId", poi) - .getResultList(); - - HashMap<Long,ForecastConfiguration> mappedForecastConfigurations = new HashMap<>(); - + List<ForecastConfiguration> forecastConfigurations = + em.createNamedQuery("ForecastConfiguration.findByLocationPointOfInterestId") + .setParameter("locationPointOfInterestId", poi) + .getResultList(); + + HashMap<Long, ForecastConfiguration> mappedForecastConfigurations = new HashMap<>(); + List<ForecastResult> results = new ArrayList<>(); - for(ForecastConfiguration forecastConfiguration:forecastConfigurations) - { - if(forecastConfiguration.getIsPrivate()) - { + for (ForecastConfiguration forecastConfiguration : forecastConfigurations) { + if (forecastConfiguration.getIsPrivate()) { continue; } mappedForecastConfigurations.put(forecastConfiguration.getForecastConfigurationId(), forecastConfiguration); Query q = em.createNativeQuery( "SELECT * FROM forecast_result WHERE forecast_configuration_id = :forecastConfigurationId " - + "AND valid_time_start = (SELECT max(valid_time_start) FROM forecast_result WHERE forecast_configuration_id = :forecastConfigurationId)", - ForecastResult.class - ); + + "AND valid_time_start = (SELECT max(valid_time_start) FROM forecast_result WHERE forecast_configuration_id = :forecastConfigurationId)", + ForecastResult.class); q.setParameter("forecastConfigurationId", forecastConfiguration.getForecastConfigurationId()); - try - { - results.add((ForecastResult)q.getSingleResult()); - } - catch(NoResultException ex) - { + try { + results.add((ForecastResult) q.getSingleResult()); + } catch (NoResultException ex) { // This means that the forecast exists, but that there have not been any valid forecast results created // For example, it might be too early to start any calculation } } - + retVal.put("forecastConfigurations", mappedForecastConfigurations); retVal.put("results", results); retVal.put("pointOfInterest", poi); - + return retVal; - + } - public ForecastConfiguration storeNewMultipleForecastConfiguration(Integer weatherStationPointOfInterestId,Map<String, FormField> formFields, Map<String, FormField> modelSpecificFormFields) { + public ForecastConfiguration storeNewMultipleForecastConfiguration(Integer weatherStationPointOfInterestId, + Map<String, FormField> formFields, Map<String, FormField> modelSpecificFormFields) { ForecastConfiguration forecastConfiguration = new ForecastConfiguration(); forecastConfiguration.setModelId(formFields.get("modelId").getWebValue()); - forecastConfiguration.setCropOrganismId(em.find(Organism.class, formFields.get("cropOrganismId").getValueAsInteger())); - forecastConfiguration.setPestOrganismId(em.find(Organism.class, formFields.get("pestOrganismId").getValueAsInteger())); + forecastConfiguration + .setCropOrganismId(em.find(Organism.class, formFields.get("cropOrganismId").getValueAsInteger())); + forecastConfiguration + .setPestOrganismId(em.find(Organism.class, formFields.get("pestOrganismId").getValueAsInteger())); forecastConfiguration.setIsPrivate(formFields.get("isPrivate").getWebValue() != null); // In the multiple form, location and weatherstation is the same PointOfInterest locationPoi = em.find(PointOfInterest.class, weatherStationPointOfInterestId); forecastConfiguration.setLocationPointOfInterestId(locationPoi); - PointOfInterest weatherStationPoi = em.find(PointOfInterestWeatherStation.class, weatherStationPointOfInterestId); + PointOfInterest weatherStationPoi = + em.find(PointOfInterestWeatherStation.class, weatherStationPointOfInterestId); forecastConfiguration.setWeatherStationPointOfInterestId(weatherStationPoi); String timeZone = formFields.get("timeZone").getWebValue(); forecastConfiguration.setTimeZone(timeZone); forecastConfiguration.setDateStart(formFields.get("dateStart").getValueAsDate()); forecastConfiguration.setDateEnd(formFields.get("dateEnd").getValueAsDate()); - VipsLogicUser forecastConfigurationUser = em.find(VipsLogicUser.class, formFields.get("vipsLogicUserId").getValueAsInteger()); + VipsLogicUser forecastConfigurationUser = + em.find(VipsLogicUser.class, formFields.get("vipsLogicUserId").getValueAsInteger()); forecastConfiguration.setVipsCoreUserId(forecastConfigurationUser); - + forecastConfiguration = em.merge(forecastConfiguration); - + // Store new values - for(FormField field : modelSpecificFormFields.values()) - { + for (FormField field : modelSpecificFormFields.values()) { String deCamelizedFieldName = getDeCamelizedFieldName(forecastConfiguration.getModelId(), field.getName()); - ForecastModelConfiguration forecastModelConfiguration = new ForecastModelConfiguration(forecastConfiguration.getForecastConfigurationId(), deCamelizedFieldName); + ForecastModelConfiguration forecastModelConfiguration = new ForecastModelConfiguration( + forecastConfiguration.getForecastConfigurationId(), deCamelizedFieldName); forecastModelConfiguration.setParameterValue(field.getWebValue()); em.merge(forecastModelConfiguration); } - + return forecastConfiguration; } public List<ForecastConfiguration> getPrivateForecastConfigurationSummaries(VipsLogicUser user) { - List<ForecastConfiguration> forecastConfigurations = this.getPrivateForecastConfigurationsForUser(user.getUserId()); + List<ForecastConfiguration> forecastConfigurations = + this.getPrivateForecastConfigurationsForUser(user.getUserId()); // TODO: Filter forecastconfigurations based on criteria (activity, crops, geography etc) List<ForecastConfiguration> filteredConfigs = new ArrayList<>(); Query q = em.createNamedQuery("ForecastSummary.findByForecastConfigurationId"); - for(ForecastConfiguration config: forecastConfigurations) - { + for (ForecastConfiguration config : forecastConfigurations) { config.setForecastSummaries( - + q.setParameter("forecastConfigurationId", config.getForecastConfigurationId()) - .getResultList() - ); - if(config.getForecastSummaries() != null && !config.getForecastSummaries().isEmpty()) - { + .getResultList()); + if (config.getForecastSummaries() != null && !config.getForecastSummaries().isEmpty()) { filteredConfigs.add(config); } } return filteredConfigs; } - + /** * * @return only the models that have an existing preprocessor in VIPSLogic */ - public List<ModelInformation> getBatchableModels() - { + public List<ModelInformation> getBatchableModels() { List<ModelInformation> modelInfos = em.createNamedQuery("ModelInformation.findAll").getResultList(); return modelInfos.stream() - .filter(modelInfo -> ModelRunPreprocessorFactory.getModelRunPreprocessor(modelInfo.getModelId()) != null) + .filter(modelInfo -> ModelRunPreprocessorFactory + .getModelRunPreprocessor(modelInfo.getModelId()) != null) .collect(Collectors.toList()); } public void deleteAllPrivateForecastConfigurationsForUser(VipsLogicUser user) { - + em.createNativeQuery( "DELETE FROM public.forecast_result WHERE forecast_configuration_id IN " - + "(" - + " SELECT forecast_configuration_id " - + " FROM public.forecast_configuration " - + " WHERE is_private IS TRUE " - + " AND vips_logic_user_id = :userId " - + ")" - ) - .setParameter("userId", user.getUserId()) - .executeUpdate(); - + + "(" + + " SELECT forecast_configuration_id " + + " FROM public.forecast_configuration " + + " WHERE is_private IS TRUE " + + " AND vips_logic_user_id = :userId " + + ")") + .setParameter("userId", user.getUserId()) + .executeUpdate(); + em.createNativeQuery( "DELETE FROM public.forecast_configuration " - + " WHERE is_private IS TRUE " - + " AND vips_logic_user_id = :userId" - ) - .setParameter("userId", user.getUserId()) - .executeUpdate(); + + " WHERE is_private IS TRUE " + + " AND vips_logic_user_id = :userId") + .setParameter("userId", user.getUserId()) + .executeUpdate(); } /** * * @param modelId * @param year - * @return + * @return */ public List<ForecastConfiguration> getForecastConfigurationsForModel(String modelId, Integer year) { return em.createNamedQuery("ForecastConfiguration.findByModelIdAndYear") diff --git a/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java b/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java index 13d140ac2a770c3c9a7ccfda9554d8fae5e39402..6fe8c2e735f2e05a68c81cb49fd69973916dfec5 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/MessageBean.java @@ -26,11 +26,11 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; import no.nibio.vips.logic.entity.Message; import no.nibio.vips.logic.entity.MessageIllustration; import no.nibio.vips.logic.entity.MessageIllustrationCaptionLocale; @@ -43,7 +43,7 @@ import no.nibio.vips.logic.entity.Organization; import no.nibio.vips.logic.entity.VipsLogicUser; import no.nibio.vips.logic.util.SystemTime; import no.nibio.web.forms.FormField; -import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload2.core.FileItem; import org.apache.commons.io.FilenameUtils; /** @@ -186,7 +186,7 @@ public class MessageBean { cropCategoryIds.add(Integer.valueOf(cropCategoryId)); } } - message.setCropCategoryIds(cropCategoryIds.toArray(new Integer[cropCategoryIds.size()])); + message.setCropCategoryIds(cropCategoryIds); return message; } @@ -224,7 +224,7 @@ public class MessageBean { } // Store file - item.write(illustration); + item.write(illustration.toPath()); // Update MessageIllustrations message = em.merge(message); diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java index 212388ab9961fb819023385ac5fe2c9c947a4953..804178624ab6f309822e4e0968f85e05c9f58522 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/ObservationBean.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -18,19 +18,13 @@ package no.nibio.vips.logic.controller.session; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.node.ObjectNode; -import com.ibm.icu.util.ULocale; - import java.io.File; import java.io.IOException; import java.nio.file.Files; -import java.nio.file.Paths; import java.nio.file.Path; +import java.nio.file.Paths; import java.nio.file.StandardOpenOption; import java.util.ArrayList; -import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -39,16 +33,30 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Objects; import java.util.ResourceBundle; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; -import javax.ejb.EJB; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; -import javax.servlet.http.HttpServletRequest; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.fileupload2.core.FileItem; +import org.apache.commons.io.FilenameUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wololo.geojson.Feature; +import org.wololo.geojson.FeatureCollection; +import org.wololo.geojson.GeoJSONFactory; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.ibm.icu.util.ULocale; +import jakarta.ejb.EJB; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; +import jakarta.servlet.http.HttpServletRequest; import no.nibio.vips.logic.entity.CropCategory; import no.nibio.vips.logic.entity.Gis; import no.nibio.vips.logic.entity.Observation; @@ -56,6 +64,7 @@ import no.nibio.vips.logic.entity.ObservationFormShortcut; import no.nibio.vips.logic.entity.ObservationIllustration; import no.nibio.vips.logic.entity.ObservationIllustrationPK; import no.nibio.vips.logic.entity.ObservationStatusType; +import no.nibio.vips.logic.entity.ObservationTimeSeries; import no.nibio.vips.logic.entity.Organism; import no.nibio.vips.logic.entity.Organization; import no.nibio.vips.logic.entity.PointOfInterest; @@ -63,190 +72,168 @@ import no.nibio.vips.logic.entity.PolygonService; import no.nibio.vips.logic.entity.VipsLogicUser; import no.nibio.vips.logic.i18n.SessionLocaleUtil; import no.nibio.vips.logic.util.SystemTime; -import org.apache.commons.codec.binary.Base64; import no.nibio.vips.observationdata.ObservationDataSchema; import no.nibio.vips.observationdata.ObservationDataSchemaPK; -import org.apache.commons.fileupload.FileItem; -import org.apache.commons.io.FilenameUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.wololo.geojson.Feature; -import org.wololo.geojson.FeatureCollection; -import org.wololo.geojson.GeoJSONFactory; /** - * @copyright 2014-2020 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + * @copyright 2014-2020 <a href="http://www.nibio.no/">NIBIO</a> */ @Stateless public class ObservationBean { - @PersistenceContext(unitName="VIPSLogic-PU") + private static final Logger LOGGER = LoggerFactory.getLogger(ObservationBean.class); + @PersistenceContext(unitName = "VIPSLogic-PU") EntityManager em; - @EJB PointOfInterestBean pointOfInterestBean; @EJB UserBean userBean; - private static Logger LOGGER = LoggerFactory.getLogger(ObservationBean.class); - - public List<Observation> getObservations(Integer organizationId) - { - Organization organization = em.find(Organization.class,organizationId); + @EJB + ObservationTimeSeriesBean observationTimeSeriesBean; + + public List<Observation> getObservations(Integer organizationId) { + Organization organization = em.find(Organization.class, organizationId); List<Observation> observations = em.createNamedQuery("Observation.findByOrganizationId") .setParameter("organizationId", organization) .getResultList(); - + observations = this.getObservationsWithGeoInfo(observations); observations = this.getObservationsWithLocations(observations); observations = this.getObservationsWithObservers(observations); - - return observations; + + return observations; } - - public List<Observation> getObservations(Integer organizationId, Date periodStart, Date periodEnd) - { - Organization organization = em.find(Organization.class,organizationId); + + public List<Observation> getObservations(Integer organizationId, Date periodStart, Date periodEnd) { + Organization organization = em.find(Organization.class, organizationId); List<Observation> observations = em.createNamedQuery("Observation.findByOrganizationIdAndPeriod") .setParameter("organizationId", organization) .setParameter("start", periodStart) .setParameter("end", periodEnd) .getResultList(); - + observations = this.getObservationsWithGeoInfo(observations); observations = this.getObservationsWithLocations(observations); observations = this.getObservationsWithObservers(observations); - + return observations; } - - public List<Observation> getObservations(Integer organizationId, Integer statusTypeId) - { - Organization organization= em.find(Organization.class, organizationId); + + public List<Observation> getObservations(Integer organizationId, Integer statusTypeId) { + Organization organization = em.find(Organization.class, organizationId); /*List<VipsLogicUser> users = em.createNamedQuery("VipsLogicUser.findByOrganizationId", VipsLogicUser.class) .setParameter("organizationId", organization) .getResultList();*/ - + List<Observation> retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByOrganizationIdAndStatusTypeId") .setParameter("organizationId", organization) .setParameter("statusTypeId", statusTypeId) .getResultList()); - + return retVal; } - - public List<Observation> getObservationsForUser(VipsLogicUser user) - { + + public List<Observation> getObservationsForUser(VipsLogicUser user) { List<Observation> retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByUserId") .setParameter("userId", user.getUserId()) .getResultList()); - + retVal = this.getObservationsWithLocations(retVal); retVal = this.getObservationsWithObservers(retVal); - + return retVal; } - + public List<Observation> getObservationsLastEditedByUser(VipsLogicUser user) { List<Observation> retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByLastEditedBy") .setParameter("lastEditedBy", user.getUserId()) .getResultList()); - + retVal = this.getObservationsWithLocations(retVal); retVal = this.getObservationsWithObservers(retVal); - + return retVal; } - + public List<Observation> getObservationsStatusChangedByUser(VipsLogicUser user) { List<Observation> retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByStatusChangedByUserId") .setParameter("statusChangedByUserId", user.getUserId()) .getResultList()); - + retVal = this.getObservationsWithLocations(retVal); retVal = this.getObservationsWithObservers(retVal); - + return retVal; } - - public List<Observation> getObservationsForUser(VipsLogicUser user, Date periodStart, Date periodEnd) - { + + public List<Observation> getObservationsForUser(VipsLogicUser user, Date periodStart, Date periodEnd) { List<Observation> retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByUserIdAndPeriod") .setParameter("userId", user.getUserId()) .setParameter("start", periodStart) .setParameter("end", periodEnd) .getResultList()); - + retVal = this.getObservationsWithLocations(retVal); retVal = this.getObservationsWithObservers(retVal); - + return retVal; } - - public List<Observation> getObservationsForUser(VipsLogicUser user, Integer statusTypeId) - { + + public List<Observation> getObservationsForUser(VipsLogicUser user, Integer statusTypeId) { List<Observation> retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByUserIdAndStatusTypeId") .setParameter("userId", user.getUserId()) .setParameter("statusTypeId", statusTypeId) .getResultList()); - + return retVal; } - - public Observation getObservation(Integer observationId) - { + + public Observation getObservation(Integer observationId) { Observation retVal = em.find(Observation.class, observationId); - if(retVal != null) - { + if (retVal != null) { retVal.setGeoinfos(this.getGeoinfoForObservation(retVal)); retVal.setUser(em.find(VipsLogicUser.class, retVal.getUserId())); - if(retVal.getLastEditedBy() != null) - { + if (retVal.getLastEditedBy() != null) { retVal.setLastEditedByUser(em.find(VipsLogicUser.class, retVal.getLastEditedBy())); } } return retVal; } - - public List<Gis> getGeoinfoForObservation(Observation obs) - { + + public List<Gis> getGeoinfoForObservation(Observation obs) { List<Integer> gisIds = em.createNativeQuery("SELECT gis_id FROM public.gis_observation WHERE observation_id = :observationId") .setParameter("observationId", obs.getObservationId()) .getResultList(); - - if(gisIds != null && ! gisIds.isEmpty()) - { - return em.createNamedQuery("Gis.findByGisIds",Gis.class) + + if (gisIds != null && !gisIds.isEmpty()) { + return em.createNamedQuery("Gis.findByGisIds", Gis.class) .setParameter("gisIds", gisIds) .getResultList(); - } - else - { + } else { return null; } } - - public List<Observation> getObservationsWithGeoInfo(List<Observation> observations) - { - if(observations.isEmpty()) - { + + public List<Observation> getObservationsWithGeoInfo(List<Observation> observations) { + if (observations.isEmpty()) { return observations; } - + // Using this method as opposed to db query for each observation, we // slim the time down from 24 seconds to 270 milliseconds! DB connections are expensive.... - + // Indexing observations Map<Integer, Observation> obsBucket = new HashMap<>(); observations.stream().forEach((obs) -> { obsBucket.put(obs.getObservationId(), obs); }); - + // Getting many-to-many relations Query q = em.createNativeQuery("SELECT gis_id, observation_id FROM public.gis_observation WHERE observation_id IN :observationIds"); q.setParameter("observationIds", obsBucket.keySet()); List<Object[]> gisObservationIds = q.getResultList(); - + // Collecting and indexing geoInfo Query q2 = em.createNativeQuery("SELECT * FROM public.gis WHERE gis_id IN (SELECT gis_id FROM public.gis_observation WHERE observation_id IN :observationIds)", Gis.class); List<Gis> geoInfos = q2.setParameter("observationIds", obsBucket.keySet()).getResultList(); @@ -254,7 +241,7 @@ public class ObservationBean { geoInfos.stream().forEach((geoinfo) -> { gisBucket.put(geoinfo.getGisId(), geoinfo); }); - + // Iterating the many-to-many relations, // adding geoinfo to the correct observations gisObservationIds.stream().forEach((gisObsIds) -> { @@ -262,12 +249,11 @@ public class ObservationBean { Integer observationId = (Integer) gisObsIds[1]; obsBucket.get(observationId).addGeoInfo(gisBucket.get(gisId)); }); - + return observations; } /** - * * @param observation * @return The merged object */ @@ -283,14 +269,13 @@ public class ObservationBean { .setParameter("observationId", retVal.getObservationId()) .executeUpdate(); // Then persist the new ones - if(observation.getGeoinfos() != null && ! observation.getGeoinfos().isEmpty()) - { + if (observation.getGeoinfos() != null && !observation.getGeoinfos().isEmpty()) { observation.getGeoinfos().stream().forEach((gis) -> { em.persist(gis); }); - + Query q = em.createNativeQuery("INSERT INTO public.gis_observation(gis_id,observation_id) VALUES(:gisId,:observationId)") - .setParameter("observationId", retVal.getObservationId()); + .setParameter("observationId", retVal.getObservationId()); observation.getGeoinfos().stream().forEach((gis) -> { q.setParameter("gisId", gis.getGisId()) .executeUpdate(); @@ -304,54 +289,49 @@ public class ObservationBean { em.persist(gis); gises.add(gis); }*/ - + // The GisObservations are not included in the merged object, so we should add them retVal.setGeoinfos(this.getGeoinfoForObservation(retVal)); - + return retVal; } public void deleteObservation(Integer observationId) { Observation observation = em.find(Observation.class, observationId); - if(observation != null) - { - // Delete all current group memberships + if (observation != null) { + // Delete all current group memberships em.createNativeQuery("DELETE FROM public.organization_group_observation WHERE observation_id=:observationId") .setParameter("observationId", observation.getObservationId()) .executeUpdate(); - + // Delete all illustrations (including removing files on disk) String[] filesToDelete = observation.getObservationIllustrationSet().stream() - .map(ill->ill.getObservationIllustrationPK().getFileName()) - .collect(Collectors.toList()) - .toArray(new String[0]); + .map(ill -> ill.getObservationIllustrationPK().getFileName()) + .collect(Collectors.toList()) + .toArray(new String[0]); this.deleteObservationIllustration(observation, filesToDelete); em.remove(observation); } } /** - * * @param organizationId * @param season - * @return + * @return */ public List<Observation> getBroadcastObservations(Integer organizationId, Integer season) { - Organization organization= em.find(Organization.class, organizationId); + Organization organization = em.find(Organization.class, organizationId); /*List<VipsLogicUser> users = em.createNamedQuery("VipsLogicUser.findByOrganizationId", VipsLogicUser.class) .setParameter("organizationId", organization) .getResultList();*/ List<Observation> retVal = null; - if(season == null) - { - retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByOrganizationIdAndStatusTypeIdAndBroadcastMessage") + if (season == null) { + retVal = this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByOrganizationIdAndStatusTypeIdAndBroadcastMessage") .setParameter("organizationId", organization) .setParameter("statusTypeId", Observation.STATUS_TYPE_ID_APPROVED) .getResultList()); - } - else - { + } else { Calendar cal = Calendar.getInstance(); cal.set(season, Calendar.JANUARY, 1, 0, 0, 0); Date start = cal.getTime(); @@ -361,31 +341,29 @@ public class ObservationBean { } return retVal; } - + /** - * * @param organizationId - * @param start When period starts. Default: Jan 1st 2000 - * @param end When period ends. Default: 100 years from now - * @return + * @param start When period starts. Default: Jan 1st 2000 + * @param end When period ends. Default: 100 years from now + * @return */ public List<Observation> getBroadcastObservations(Integer organizationId, Date start, Date end) { - if(start == null || end == null) - { + if (start == null || end == null) { Calendar cal = Calendar.getInstance(); - if(start == null) // Default Jan 1st 2000 + if (start == null) // Default Jan 1st 2000 { - cal.set(2000, Calendar.JANUARY,1,0,0,0); + cal.set(2000, Calendar.JANUARY, 1, 0, 0, 0); start = cal.getTime(); } - if(end == null) // Default: Today + 100 years + if (end == null) // Default: Today + 100 years { cal.setTime(SystemTime.getSystemTime()); cal.add(Calendar.YEAR, 100); end = cal.getTime(); } } - Organization organization= em.find(Organization.class, organizationId); + Organization organization = em.find(Organization.class, organizationId); return this.getObservationsWithGeoInfo(em.createNamedQuery("Observation.findByOrganizationIdAndStatusTypeIdAndBroadcastMessageAndPeriod") .setParameter("organizationId", organization) .setParameter("statusTypeId", Observation.STATUS_TYPE_ID_APPROVED) @@ -393,45 +371,42 @@ public class ObservationBean { .setParameter("end", end) .getResultList()); } - - + + /** - * * @param observation * @return [OBSERVATION_ILLUSTRATION_PATH]/[ORGANISM_ID]/ */ - private String getFilePath(Observation observation) - { - return System.getProperty("no.nibio.vips.logic.OBSERVATION_ILLUSTRATION_PATH") + "/" - + observation.getOrganismId(); - } - - public Observation storeObservationIllustration(Observation observation, String fileName, String base64Data) - { - String[] metaAndData = base64Data.split(","); - byte[] imageData = Base64.decodeBase64(metaAndData[1]); - Path path = Paths.get(this.getFilePath(observation) + "/" + fileName); - try { - // Make sure the directory exists - File testDirectoryfile = new File(this.getFilePath(observation)); - if(!testDirectoryfile.exists()) - { - testDirectoryfile.mkdirs(); - } - Files.write(path,imageData, StandardOpenOption.CREATE); - ObservationIllustration newIllustration = new ObservationIllustration(new ObservationIllustrationPK(observation.getObservationId(), fileName)); - newIllustration = em.merge(newIllustration); - - // Add the new illustration - if(observation.getObservationIllustrationSet() == null) - { - observation.setObservationIllustrationSet(new HashSet<ObservationIllustration>()); - } - observation.getObservationIllustrationSet().add(newIllustration); - - return observation; - } - catch(IOException ex) {ex.printStackTrace(); return observation;} + private String getFilePath(Observation observation) { + return System.getProperty("no.nibio.vips.logic.OBSERVATION_ILLUSTRATION_PATH") + "/" + + observation.getOrganismId(); + } + + public Observation storeObservationIllustration(Observation observation, String fileName, String base64Data) { + String[] metaAndData = base64Data.split(","); + byte[] imageData = Base64.decodeBase64(metaAndData[1]); + Path path = Paths.get(this.getFilePath(observation) + "/" + fileName); + try { + // Make sure the directory exists + File testDirectoryfile = new File(this.getFilePath(observation)); + if (!testDirectoryfile.exists()) { + testDirectoryfile.mkdirs(); + } + Files.write(path, imageData, StandardOpenOption.CREATE); + ObservationIllustration newIllustration = new ObservationIllustration(new ObservationIllustrationPK(observation.getObservationId(), fileName)); + newIllustration = em.merge(newIllustration); + + // Add the new illustration + if (observation.getObservationIllustrationSet() == null) { + observation.setObservationIllustrationSet(new HashSet<ObservationIllustration>()); + } + observation.getObservationIllustrationSet().add(newIllustration); + + return observation; + } catch (IOException ex) { + ex.printStackTrace(); + return observation; + } } public Observation storeObservationIllustration(Observation observation, FileItem item) throws Exception { @@ -442,32 +417,29 @@ public class ObservationBean { // Check availability, and adapt filename until available Integer fileNameSuffix = 1; File illustration = new File(filePath + "/" + fileName); - while(illustration.exists()) - { + while (illustration.exists()) { fileName = observation.getObservationId() + "_illustration_" + fileNameSuffix + "." + FilenameUtils.getExtension(item.getName()); illustration = new File(filePath + "/" + fileName); fileNameSuffix++; } File testDirectoryfile = new File(filePath); // If directory does not exist, create it - if(!testDirectoryfile.exists()) - { + if (!testDirectoryfile.exists()) { testDirectoryfile.mkdirs(); } // Store file - item.write(illustration); - + item.write(illustration.toPath()); + // Update MessageIllustrations observation = em.merge(observation); // Remove the old illustration(s) - + ObservationIllustration newIllustration = new ObservationIllustration(new ObservationIllustrationPK(observation.getObservationId(), fileName)); em.persist(newIllustration); - + // Add the new illustration - if(observation.getObservationIllustrationSet() == null) - { + if (observation.getObservationIllustrationSet() == null) { observation.setObservationIllustrationSet(new HashSet<ObservationIllustration>()); } observation.getObservationIllustrationSet().add(newIllustration); @@ -476,127 +448,139 @@ public class ObservationBean { public Observation deleteObservationIllustration(Observation observation, String[] deleteIllustrations) { observation = em.merge(observation); - - Set <ObservationIllustration> formerIllustrations = observation.getObservationIllustrationSet(); - if(formerIllustrations == null) - { - return observation; + + Set<ObservationIllustration> formerIllustrations = observation.getObservationIllustrationSet(); + if (formerIllustrations == null) { + return observation; + } + + Set<ObservationIllustration> deleteThese = new HashSet<>(); + + for (String deleteIllustration : deleteIllustrations) { + for (ObservationIllustration formerIllustration : formerIllustrations) { + if (formerIllustration.getObservationIllustrationPK().getFileName() + .equals(deleteIllustration)) { + deleteThese.add(formerIllustration); + } + } + } + + for (ObservationIllustration ill : deleteThese) { + observation.getObservationIllustrationSet().remove(ill); + em.remove(ill); + // Physically remove it too + File fileToDelete = new File(this.getFilePath(observation) + "/" + ill.getObservationIllustrationPK().getFileName()); + fileToDelete.delete(); } - - Set <ObservationIllustration> deleteThese = new HashSet<>(); - - for(String deleteIllustration:deleteIllustrations) - { - for(ObservationIllustration formerIllustration:formerIllustrations) - { - if(formerIllustration.getObservationIllustrationPK().getFileName() - .equals(deleteIllustration)) - { - deleteThese.add(formerIllustration); - } - } - } - - for(ObservationIllustration ill: deleteThese) - { - observation.getObservationIllustrationSet().remove(ill); - em.remove(ill); - // Physically remove it too - File fileToDelete = new File(this.getFilePath(observation) + "/" + ill.getObservationIllustrationPK().getFileName()); - fileToDelete.delete(); - } return observation; } /** * Fetch observations of a particular organism at a particular place and period + * * @param organismId * @param pointOfInterestId * @param startDate * @param endDate - * @return + * @return */ public List<no.nibio.vips.observation.Observation> getObservations(Integer organismId, Integer pointOfInterestId, Date startDate, Date endDate) { /*System.out.println("organismId = " + organismId); System.out.println("pointOfInterestId = " + pointOfInterestId); System.out.println("period= " + startDate + "-" + endDate);*/ return em.createNativeQuery( - "SELECT * FROM public.observation " - + "WHERE organism_id = :organismId " - + "AND location_point_of_interest_id = :locationPointOfInterestId " - + "AND time_of_observation BETWEEN :startDate AND :endDate" - ,Observation.class - ) + "SELECT * FROM public.observation " + + "WHERE organism_id = :organismId " + + "AND location_point_of_interest_id = :locationPointOfInterestId " + + "AND time_of_observation BETWEEN :startDate AND :endDate" + , Observation.class + ) .setParameter("organismId", organismId) - .setParameter("locationPointOfInterestId",pointOfInterestId) + .setParameter("locationPointOfInterestId", pointOfInterestId) .setParameter("startDate", startDate) .setParameter("endDate", endDate) .getResultList(); } public List<Observation> getObservationsWithLocations(List<Observation> observations) { - Set<Integer> locationPointOfInterestIds = new HashSet<>(); - observations.stream().filter((o) -> (o.getLocationPointOfInterestId() != null)).forEach((o) -> { - locationPointOfInterestIds.add(o.getLocationPointOfInterestId()); + Set<Integer> locationPointOfInterestIds = new HashSet<>(); + observations.stream().filter((o) -> (o.getLocationPointOfInterestId() != null)).forEach((o) -> { + locationPointOfInterestIds.add(o.getLocationPointOfInterestId()); }); - // Nothing to do? - if(locationPointOfInterestIds.isEmpty()) - { + // Nothing to do? + if (locationPointOfInterestIds.isEmpty()) { return observations; } - List<PointOfInterest> pois = pointOfInterestBean.getPois(locationPointOfInterestIds); - Map<Integer, PointOfInterest> mappedPois = new HashMap<>(); - pois.stream().forEach((poi) -> { - mappedPois.put(poi.getPointOfInterestId(), poi); + List<PointOfInterest> pois = pointOfInterestBean.getPois(locationPointOfInterestIds); + Map<Integer, PointOfInterest> mappedPois = new HashMap<>(); + pois.stream().forEach((poi) -> { + mappedPois.put(poi.getPointOfInterestId(), poi); }); - observations.stream().filter((o) -> (o.getLocationPointOfInterestId() != null)).forEach((o) -> { - o.setLocation(mappedPois.get(o.getLocationPointOfInterestId())); + observations.stream().filter((o) -> (o.getLocationPointOfInterestId() != null)).forEach((o) -> { + o.setLocation(mappedPois.get(o.getLocationPointOfInterestId())); }); - return observations; + return observations; } + public List<Observation> getObservationsWithTimeSeries(List<Observation> observations) { + Set<Integer> observationTimeSeriesIds = observations.stream() + .map(Observation::getObservationTimeSeriesId) + .filter(Objects::nonNull) + .collect(Collectors.toSet()); + + if (observationTimeSeriesIds.isEmpty()) { + return observations; + } + + List<ObservationTimeSeries> timeSeriesList = observationTimeSeriesBean.getObservationTimeSeriesList(observationTimeSeriesIds); + Map<Integer, ObservationTimeSeries> timeSeriesMap = timeSeriesList.stream() + .collect(Collectors.toMap(ObservationTimeSeries::getObservationTimeSeriesId, Function.identity())); + + observations.stream() + .filter(o -> o.getObservationTimeSeriesId() != null) + .forEach(o -> o.setObservationTimeSeries(timeSeriesMap.get(o.getObservationTimeSeriesId()))); + + return observations; + } private List<Observation> getObservationsWithObservers(List<Observation> observations) { Set<Integer> userIds = new HashSet<>(); observations.stream().filter((o) -> (o.getUserId() != null)).forEach((o) -> { userIds.add(o.getUserId()); }); // Nothing to do? - if(userIds.isEmpty()) - { + if (userIds.isEmpty()) { return observations; } - List<VipsLogicUser> users = userBean.getUsers(userIds); - Map<Integer, VipsLogicUser> mappedUsers = new HashMap<>(); - users.stream().forEach((user) -> { - mappedUsers.put(user.getUserId(), user); + List<VipsLogicUser> users = userBean.getUsers(userIds); + Map<Integer, VipsLogicUser> mappedUsers = new HashMap<>(); + users.stream().forEach((user) -> { + mappedUsers.put(user.getUserId(), user); }); - observations.stream().filter((o) -> (o.getUserId() != null)).forEach((o) -> { - o.setUser(mappedUsers.get(o.getUserId())); + observations.stream().filter((o) -> (o.getUserId() != null)).forEach((o) -> { + o.setUser(mappedUsers.get(o.getUserId())); }); return observations; } - - public List<Observation> getObservationsOfPest(Integer pestOrganismId) - { - List <Observation> observations = - em.createNamedQuery("Observation.findByOrganism") - .setParameter("organism", em.find(Organism.class, pestOrganismId)) - .getResultList(); - + + public List<Observation> getObservationsOfPest(Integer pestOrganismId) { + List<Observation> observations = + em.createNamedQuery("Observation.findByOrganism") + .setParameter("organism", em.find(Organism.class, pestOrganismId)) + .getResultList(); + observations = this.getObservationsWithGeoInfo(observations); observations = this.getObservationsWithLocations(observations); observations = getObservationsWithObservers(observations); return observations; } - - public List<Observation> getObservationsOfPestForUser(VipsLogicUser user, Integer pestOrganismId) - { - List <Observation> observations = - em.createNamedQuery("Observation.findByUserIdAndOrganism") - .setParameter("userId", user.getUserId()) - .setParameter("organism", em.find(Organism.class, pestOrganismId)) - .getResultList(); - + + public List<Observation> getObservationsOfPestForUser(VipsLogicUser user, Integer pestOrganismId) { + List<Observation> observations = + em.createNamedQuery("Observation.findByUserIdAndOrganism") + .setParameter("userId", user.getUserId()) + .setParameter("organism", em.find(Organism.class, pestOrganismId)) + .getResultList(); + observations = this.getObservationsWithGeoInfo(observations); observations = this.getObservationsWithLocations(observations); observations = this.getObservationsWithObservers(observations); @@ -604,98 +588,99 @@ public class ObservationBean { } public List<Observation> getFilteredObservations( - Integer organizationId, - Integer pestId, - Integer cropId, + Integer organizationId, + Integer observationTimeSeriesId, + Integer pestId, + Integer cropId, List<Integer> cropCategoryId, - Date from, + Date from, Date to, - Boolean isPositive - ) - { + Boolean isPositive) { // The minimum SQL String sql = "SELECT * FROM public.observation \n" + - "WHERE status_type_id = :statusTypeId \n " + - "AND user_id IN (SELECT user_id FROM public.vips_logic_user WHERE organization_id = :organizationId) \n"; - + "WHERE status_type_id = :statusTypeId \n " + + "AND user_id IN (SELECT user_id FROM public.vips_logic_user WHERE organization_id = :organizationId) \n"; + Map<String, Object> parameters = new HashMap<>(); parameters.put("statusTypeId", ObservationStatusType.STATUS_APPROVED); parameters.put("organizationId", organizationId); - + + // Filter for observation time series + if (observationTimeSeriesId != null && observationTimeSeriesId > 0) { + sql += "AND observation_time_series_id = :observationTimeSeriesId \n"; + parameters.put("observationTimeSeriesId", observationTimeSeriesId); + } // Filter for pest - if(pestId != null && pestId > 0) - { + if (pestId != null && pestId > 0) { sql += "AND organism_id = :organismId \n"; parameters.put("organismId", pestId); } // Filter either for crop or cropCategoryId - if(cropId != null && cropId > 0) - { + if (cropId != null && cropId > 0) { sql += "AND crop_organism_id = :cropOrganismId \n"; parameters.put("cropOrganismId", cropId); - } - else if(cropCategoryId != null && ! cropCategoryId.isEmpty()) - { + } else if (cropCategoryId != null && !cropCategoryId.isEmpty()) { List<CropCategory> cropCategories = em.createNamedQuery("CropCategory.findByCropCategoryIds", CropCategory.class) .setParameter("cropCategoryIds", cropCategoryId) .getResultList(); - List<Integer> cropIds = new ArrayList(cropCategories.stream().flatMap(cC->Arrays.asList(cC.getCropOrganismIds()).stream()).collect(Collectors.toSet())); - + List<Integer> cropIds = new ArrayList(cropCategories.stream().flatMap(cC -> cC.getCropOrganismIds().stream()).collect(Collectors.toSet())); + sql += "AND crop_organism_id IN (:cropOrganismIds) \n"; parameters.put("cropOrganismIds", cropIds); + //parameters.put("cropOrganismIds", List.of(5)); } // Filter for dates - if(from != null) - { + if (from != null) { sql += "AND time_of_observation >= :from \n"; parameters.put("from", from); } - if(to != null) - { + if (to != null) { sql += "AND time_of_observation <= :to \n"; parameters.put("to", to); } // Filter for positive/negative registrations - if(isPositive != null) - { + if (isPositive != null) { sql += "AND is_positive = :isPositive \n"; parameters.put("isPositive", isPositive); } + sql += "ORDER BY time_of_observation DESC, observation_id DESC"; + LOGGER.debug(sql); Query q = em.createNativeQuery(sql, Observation.class); // Setting the parameters one by one parameters.keySet().stream().forEach( - (key)->{LOGGER.debug(key + ": " + parameters.get(key)); q.setParameter(key, parameters.get(key));} + (key) -> { + LOGGER.debug(key + ": " + parameters.get(key)); + q.setParameter(key, parameters.get(key)); + } ); - + //Date start = new Date(); - + List<Observation> observations = q.getResultList(); //System.out.println("Finding obs took " + (new Date().getTime() - start.getTime()) + " milliseconds"); - + //start = new Date(); observations.stream().forEach( - (observation)->observation.setUser(em.find(VipsLogicUser.class, observation.getUserId())) + (observation) -> observation.setUser(em.find(VipsLogicUser.class, observation.getUserId())) ); - + //System.out.println("Finding users took " + (new Date().getTime() - start.getTime()) + " milliseconds"); - + List<Observation> retVal = new ArrayList<>(); - if(! observations.isEmpty()) - { + if (!observations.isEmpty()) { //Date start = new Date(); retVal = this.getObservationsWithGeoInfo(observations); //System.out.println("Finding geoinfo took " + (new Date().getTime() - start.getTime()) + " milliseconds"); //start = new Date(); retVal = this.getObservationsWithLocations(retVal); //System.out.println("Finding locations took " + (new Date().getTime() - start.getTime()) + " milliseconds"); + retVal = this.getObservationsWithTimeSeries(retVal); } - return retVal; - } public List<Organism> getObservedPests(Integer organizationId) { @@ -706,9 +691,9 @@ public class ObservationBean { return em.createNamedQuery("Organism.findByOrganismIds") .setParameter("organismIds", pestIds) .getResultList(); - + } - + public List<Organism> getObservedCrops(Integer organizationId) { Query q = em.createNativeQuery("SELECT DISTINCT crop_organism_id FROM public.observation WHERE user_id IN (" + " SELECT user_id FROM vips_logic_user WHERE organization_id = :organizationId" @@ -717,7 +702,7 @@ public class ObservationBean { return em.createNamedQuery("Organism.findByOrganismIds") .setParameter("organismIds", cropIds) .getResultList(); - + } public Observation getObservationFromGeoJSON(String geoJSON) throws IOException { @@ -727,23 +712,22 @@ public class ObservationBean { Map<String, Object> properties = firstAndBest.getProperties(); Observation observation = new Observation(); Integer observationId = (Integer) properties.get("observationId"); - if(observationId > 0) - { + if (observationId > 0) { observation = em.find(Observation.class, observationId); } observation.setObservationData((String) properties.get("observationData")); ObjectMapper mapper = new ObjectMapper(); observation.setCropOrganism(mapper.convertValue(properties.get("cropOrganism"), Organism.class)); observation.setOrganism(mapper.convertValue(properties.get("organism"), Organism.class)); - observation.setObservationHeading((String)properties.get("observationHeading")); - observation.setObservationText((String)properties.get("observationText")); + observation.setObservationHeading((String) properties.get("observationHeading")); + observation.setObservationText((String) properties.get("observationText")); observation.setTimeOfObservation(new Date((Long) properties.get("timeOfObservation"))); observation.setGeoinfo(geoJSON); observation.setStatusTypeId((Integer) properties.get("statusTypeId")); observation.setStatusRemarks((String) properties.get("statusRemarks")); observation.setIsQuantified((Boolean) properties.get("isQuantified")); observation.setBroadcastMessage((Boolean) properties.get("broadcastMessage")); - return observation; + return observation; } public void deleteGisObservationByGis(Integer gisId) { @@ -759,41 +743,34 @@ public class ObservationBean { .getResultList(); } - public List<Integer> getOrganizationGroupIds(Observation observation) { - if(observation.getObservationId() != null) - { + public List<Integer> getOrganizationGroupIds(Observation observation) { + if (observation.getObservationId() != null) { return em.createNativeQuery("SELECT organization_group_id FROM public.organization_group_observation " - + "WHERE observation_id = :observationId") + + "WHERE observation_id = :observationId") .setParameter("observationId", observation.getObservationId()) .getResultList(); - } - else - { + } else { return new ArrayList<>(); } } - + public void storeOrganizationGroupObservationIds(Observation obs, String[] organizationGroupIds) { // First delete all current group memberships em.createNativeQuery("DELETE FROM public.organization_group_observation WHERE observation_id=:observationId") .setParameter("observationId", obs.getObservationId()) .executeUpdate(); - - if(organizationGroupIds != null) - { + + if (organizationGroupIds != null) { Query q = em.createNativeQuery("INSERT INTO public.organization_group_observation (organization_group_id, observation_id) " - + "VALUES(:organizationGroupId, :observationId)") + + "VALUES(:organizationGroupId, :observationId)") .setParameter("observationId", obs.getObservationId()); // Then add - for(String groupIdStr:organizationGroupIds) - { + for (String groupIdStr : organizationGroupIds) { try { Integer groupId = Integer.valueOf(groupIdStr); q.setParameter("organizationGroupId", groupId); q.executeUpdate(); - } - catch(NumberFormatException ex) - { + } catch (NumberFormatException ex) { // Continue } } @@ -802,30 +779,27 @@ public class ObservationBean { /** * Returns the first time an observation of the given pest registered in the system was made + * * @param organismId - * @return + * @return */ public Date getFirstObservationTime(Integer organismId) { - - try - { - List<Observation> obs = em.createNamedQuery("Observation.findFirstByOrganism") + + try { + List<Observation> obs = em.createNamedQuery("Observation.findFirstByOrganism") .setParameter("organism", em.find(Organism.class, organismId)) .getResultList(); return obs.get(0).getTimeOfObservation(); - } - catch(NoResultException | IndexOutOfBoundsException ex) - { + } catch (NoResultException | IndexOutOfBoundsException ex) { return null; } - + } - public PolygonService getPolygonService(Integer polygonServiceId) - { - return em.find(PolygonService.class, polygonServiceId); + public PolygonService getPolygonService(Integer polygonServiceId) { + return em.find(PolygonService.class, polygonServiceId); } - + public List<PolygonService> getPolygonServicesForOrganization(Integer organizationId) { return em.createNativeQuery("SELECT * FROM polygon_service p WHERE p.polygon_service_id IN (SELECT polygon_service_id FROM public.organization_polygon_service WHERE organization_id=:organizationId)", PolygonService.class) .setParameter("organizationId", organizationId) @@ -840,7 +814,8 @@ public class ObservationBean { /** * Part of the cleaning up dependencies procedure for when deleting a POI - * @param poi + * + * @param poi */ public void deleteObservationsForLocation(PointOfInterest poi) { em.createNamedQuery("Observation.findByLocationPointOfInterestId", Observation.class) @@ -848,99 +823,96 @@ public class ObservationBean { .getResultList().stream() .forEach(obs -> em.remove(obs)); } - + + public void deleteObservationsForObservationTimeSeries(ObservationTimeSeries observationTimeSeries) { + em.createNamedQuery("Observation.findByObservationTimeSeries", Observation.class) + .setParameter("observationTimeSeries", observationTimeSeries) + .getResultList() + .forEach(obs -> em.remove(obs)); + } + /** - * Returns the appropriate observation data schema + * Returns the appropriate observation data schema * If no existing schema, returns the standard (Requring just a number) + * * @param organizationId * @param organismId - * @param httpServletRequest - * @return + * @return */ - public ObservationDataSchema getObservationDataSchema(Integer organizationId, Integer organismId) - { - try - { + public ObservationDataSchema getObservationDataSchema(Integer organizationId, Integer organismId) { + try { return em.createNamedQuery("ObservationDataSchema.findByPK", ObservationDataSchema.class) - .setParameter("organizationId", organizationId) - .setParameter("organismId", organismId) - .getSingleResult(); - - - } - catch(NoResultException ex) - { + .setParameter("organizationId", organizationId) + .setParameter("organismId", organismId) + .getSingleResult(); + + + } catch (NoResultException ex) { //System.out.println("Could not find schema for orgId " + organizationId + " and organismId " + organismId); return this.getStandardSchema(organizationId); } } - + /** * If there exist title translations for this schema, it + * * @param schema * @param httpServletRequest - * @return + * @return */ - public ObservationDataSchema getLocalizedObservationDataSchema(ObservationDataSchema ods, HttpServletRequest httpServletRequest, ULocale locale) throws IOException - { - if(locale != null) - { - SessionLocaleUtil.setCurrentLocale(httpServletRequest, locale); + public ObservationDataSchema getLocalizedObservationDataSchema(ObservationDataSchema ods, HttpServletRequest httpServletRequest, ULocale locale) throws IOException { + if (locale != null) { + SessionLocaleUtil.setCurrentLocale(httpServletRequest, locale); } ResourceBundle bundle = SessionLocaleUtil.getI18nBundle(httpServletRequest); - - // We iterate the schema, replacing default field labels with - // translated ones - // First: Convert to Jackson JsonNode tree - ObjectMapper m = new ObjectMapper(); - JsonNode rootNode = m.readTree(ods.getDataSchema()); - // Is this the full schema or just the "properties" property? - JsonNode propertiesNode = rootNode.get("properties") == null ? rootNode : rootNode.get("properties"); - - Iterator<Entry<String, JsonNode>> nodeIterator = propertiesNode.fields(); - - String fieldKeyPrefix = "observationDataField_"; - // Loop through each field - while (nodeIterator.hasNext()) { - Map.Entry<String, JsonNode> schemaPropertyField = (Map.Entry<String, JsonNode>) nodeIterator.next(); - // Get the property field key (e.g. "counting2") - String fieldKey = schemaPropertyField.getKey(); - // Find a translation. - if(bundle.containsKey(fieldKeyPrefix + fieldKey)) - { - // If found, replace with translation - // Get the property field (e.g. {"title":"Counting 2"} ) - JsonNode schemaProperty = schemaPropertyField.getValue(); - ((ObjectNode)schemaProperty).put("title", bundle.getString(fieldKeyPrefix + fieldKey)); - ((ObjectNode)propertiesNode).replace(fieldKey, schemaProperty); - } - } - - // I repeat: Is this the full schema or just the "properties" property? - if(rootNode.get("properties") != null) - { - ((ObjectNode)rootNode).replace("properties", propertiesNode); - } - else - { - rootNode = propertiesNode; + + // We iterate the schema, replacing default field labels with + // translated ones + // First: Convert to Jackson JsonNode tree + ObjectMapper m = new ObjectMapper(); + JsonNode rootNode = m.readTree(ods.getDataSchema()); + // Is this the full schema or just the "properties" property? + JsonNode propertiesNode = rootNode.get("properties") == null ? rootNode : rootNode.get("properties"); + + Iterator<Entry<String, JsonNode>> nodeIterator = propertiesNode.fields(); + + String fieldKeyPrefix = "observationDataField_"; + // Loop through each field + while (nodeIterator.hasNext()) { + Map.Entry<String, JsonNode> schemaPropertyField = (Map.Entry<String, JsonNode>) nodeIterator.next(); + // Get the property field key (e.g. "counting2") + String fieldKey = schemaPropertyField.getKey(); + // Find a translation. + if (bundle.containsKey(fieldKeyPrefix + fieldKey)) { + // If found, replace with translation + // Get the property field (e.g. {"title":"Counting 2"} ) + JsonNode schemaProperty = schemaPropertyField.getValue(); + ((ObjectNode) schemaProperty).put("title", bundle.getString(fieldKeyPrefix + fieldKey)); + ((ObjectNode) propertiesNode).replace(fieldKey, schemaProperty); } - ods.setDataSchema(m.writeValueAsString(rootNode)); - return ods; + } + + // I repeat: Is this the full schema or just the "properties" property? + if (rootNode.get("properties") != null) { + ((ObjectNode) rootNode).replace("properties", propertiesNode); + } else { + rootNode = propertiesNode; + } + ods.setDataSchema(m.writeValueAsString(rootNode)); + return ods; } - + /** - * * @param organizationId - * @return + * @return */ - private ObservationDataSchema getStandardSchema(Integer organizationId){ + private ObservationDataSchema getStandardSchema(Integer organizationId) { ObservationDataSchema retVal = new ObservationDataSchema(); retVal.setDataSchema("{\n" - + " \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n" - + " \"type\": \"object\",\n" - + " \"title\": \"Default schema\",\n" - + " \"properties\": {" + + " \"$schema\": \"http://json-schema.org/draft-04/schema#\",\n" + + " \"type\": \"object\",\n" + + " \"title\": \"Default schema\",\n" + + " \"properties\": {" + "\"number\":{\"title\":\"Number\"}," + "\"unit\":{\"title\":\"Unit\"}" + "}" @@ -955,7 +927,6 @@ public class ObservationBean { retVal.setObservationDataSchemaPK(pk); return retVal; } - - + } diff --git a/src/main/java/no/nibio/vips/logic/controller/session/ObservationTimeSeriesBean.java b/src/main/java/no/nibio/vips/logic/controller/session/ObservationTimeSeriesBean.java new file mode 100644 index 0000000000000000000000000000000000000000..627002b9b0d6ac5e0680c346f8ed715f4c069b12 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/controller/session/ObservationTimeSeriesBean.java @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +package no.nibio.vips.logic.controller.session; + +import java.util.*; +import jakarta.ejb.EJB; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import no.nibio.vips.logic.entity.ObservationTimeSeries; +import no.nibio.vips.logic.entity.PointOfInterest; +import no.nibio.vips.logic.entity.VipsLogicUser; + +@Stateless +public class ObservationTimeSeriesBean { + + @PersistenceContext(unitName = "VIPSLogic-PU") + EntityManager em; + @EJB + PointOfInterestBean pointOfInterestBean; + @EJB + UserBean userBean; + @EJB + ObservationBean observationBean; + + public List<ObservationTimeSeries> getObservationTimeSeriesListForUser(VipsLogicUser user) { + List<ObservationTimeSeries> resultList = em.createNamedQuery("ObservationTimeSeries.findByUserId", ObservationTimeSeries.class) + .setParameter("userId", user.getUserId()) + .getResultList(); + this.enrichObservationTimeSeriesListWithPointOfInterest(resultList); + this.enrichObservationTimeSeriesListWithObservers(resultList); + return resultList; + } + + /** + * Get observation time series with given id. Enrich object with user information before returning. + * @param observationTimeSeriesId the id of the observation time series to retrieve + * @return the observation time series with the given id + */ + public ObservationTimeSeries getObservationTimeSeries(Integer observationTimeSeriesId) { + ObservationTimeSeries ots = em.find(ObservationTimeSeries.class, observationTimeSeriesId); + if (ots != null) { + ots.setUser(em.find(VipsLogicUser.class, ots.getUserId())); + if (ots.getLastModifiedBy() != null) { + ots.setLastModifiedByUser(em.find(VipsLogicUser.class, ots.getLastModifiedBy())); + } + } + return ots; + } + + public List<ObservationTimeSeries> getObservationTimeSeriesList(Set<Integer> observationTimeSeriesIds) { + return em.createNamedQuery("ObservationTimeSeries.findByObservationTimeSeriesIds") + .setParameter("observationTimeSeriesIds", observationTimeSeriesIds) + .getResultList(); + } + + /** + * @param ots the observation time series + * @return The merged object + */ + public ObservationTimeSeries storeObservationTimeSeries(ObservationTimeSeries ots) { + return em.merge(ots); + } + + public void deleteObservationTimeSeries(Integer id) { + ObservationTimeSeries observationTimeSeries = em.find(ObservationTimeSeries.class, id); + if (observationTimeSeries != null) { + // The app prevents deletion of time series with observations + observationBean.deleteObservationsForObservationTimeSeries(observationTimeSeries); + em.remove(observationTimeSeries); + } + } + + /** + * Enrich given list of observation time series with point of interest information + * + * @param otsList The list of observation time series to enrich + */ + public void enrichObservationTimeSeriesListWithPointOfInterest(List<ObservationTimeSeries> otsList) { + Set<Integer> locationPoiIds = new HashSet<>(); + otsList.stream().filter((o) -> (o.getLocationPointOfInterestId() != null)).forEach((o) -> { + locationPoiIds.add(o.getLocationPointOfInterestId()); + }); + if (locationPoiIds.isEmpty()) { + return; + } + List<PointOfInterest> pois = pointOfInterestBean.getPois(locationPoiIds); + Map<Integer, PointOfInterest> mappedPois = new HashMap<>(); + pois.stream().forEach((poi) -> { + mappedPois.put(poi.getPointOfInterestId(), poi); + }); + otsList.stream().filter((o) -> (o.getLocationPointOfInterestId() != null)).forEach((o) -> { + o.setLocationPointOfInterest(mappedPois.get(o.getLocationPointOfInterestId())); + }); + } + + /** + * Enrich given observation time series with point of interest information + * + * @param ots The observation time series to enrich + */ + public void enrichObservationTimeSeriesWithPointOfInterest(ObservationTimeSeries ots) { + if (ots == null || ots.getLocationPointOfInterestId() == null) { + return; + } + ots.setLocationPointOfInterest(pointOfInterestBean.getPointOfInterest(ots.getLocationPointOfInterestId())); + } + + /** + * Enrich given list of observation time series with user information + * + * @param otsList The list of observation time series to enrich + */ + private void enrichObservationTimeSeriesListWithObservers(List<ObservationTimeSeries> otsList) { + Set<Integer> userIds = new HashSet<>(); + otsList.stream().filter((o) -> (o.getUserId() != null)).forEach((o) -> { + userIds.add(o.getUserId()); + }); + if (userIds.isEmpty()) { + return; + } + List<VipsLogicUser> users = userBean.getUsers(userIds); + Map<Integer, VipsLogicUser> mappedUsers = new HashMap<>(); + users.stream().forEach((user) -> { + mappedUsers.put(user.getUserId(), user); + }); + otsList.stream().filter((o) -> (o.getUserId() != null)).forEach((o) -> { + o.setUser(mappedUsers.get(o.getUserId())); + }); + } +} diff --git a/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java b/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java index 44146a190e1048a5eadcc27359b160b088788fb6..52b99767e420117cbbd5819fc5e85f3c7e36273c 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/OrganismBean.java @@ -33,11 +33,11 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; import no.nibio.vips.logic.entity.CropCategory; import no.nibio.vips.logic.entity.CropPest; import no.nibio.vips.logic.entity.DbUpdate; @@ -419,7 +419,7 @@ public class OrganismBean { cropCategories.stream() .filter((cc) -> (cc.getCropOrganismIds() != null)) .forEachOrdered((cc) -> { - retVal.addAll(Arrays.asList(cc.getCropOrganismIds())); + retVal.addAll(cc.getCropOrganismIds()); }); return retVal; diff --git a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java index 7c82e925fe6a7c595ecd996b5fbbcab09b7f0182..5a4cd503af54862857e7d1f5f2dbb49173e7d6be 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/PointOfInterestBean.java @@ -33,13 +33,13 @@ import java.util.List; import java.util.ResourceBundle; import java.util.Set; import java.util.stream.Collectors; -import javax.ejb.EJB; -import javax.ejb.LocalBean; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; +import jakarta.ejb.EJB; +import jakarta.ejb.LocalBean; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; import no.nibio.vips.gis.GISUtil; import no.nibio.vips.logic.entity.ExternalResource; import no.nibio.vips.logic.entity.ExternalResourceType; @@ -263,10 +263,54 @@ public class PointOfInterestBean { return kml; } + public WeatherStationDataSource getWeatherStationDataSource(Integer weatherStationDataSourceId) + { + return em.find(WeatherStationDataSource.class, weatherStationDataSourceId); + } + public List<WeatherStationDataSource> getWeatherStationDataSources() { return em.createNamedQuery("WeatherStationDataSource.findAll").getResultList(); } + public List<WeatherStationDataSource> getGridWeatherStationDataSources() { + return em.createNamedQuery("WeatherStationDataSource.findGridSources").getResultList(); + } + + /** + * Checks if the weather station data source can be deleted from the system. Criteria: + * <ul> + * <li>Not referenced from public.point_of_interest_weather_station</li> + * <li>Not referenced from public.organization</li> + * </ul> + * @param weatherStationDataSource + * @return + */ + public Boolean isweatherStationDataSourceDeleteable(WeatherStationDataSource weatherStationDataSource) + { + Query poiRefQuery = em.createQuery("SELECT COUNT(*) FROM PointOfInterestWeatherStation poiws where poiws.weatherStationDataSourceId = :weatherStationDataSourceId"); + Long weatherStationReferences = (Long) poiRefQuery.setParameter("weatherStationDataSourceId", weatherStationDataSource).getSingleResult(); + if(weatherStationReferences > 0) + { + return false; + } + + Query orgRefQuery = em.createQuery("SELECT COUNT(*) FROM Organization o where o.defaultGridWeatherStationDataSource = :weatherStationDataSourceId"); + Long organizationReferences = (Long) orgRefQuery.setParameter("weatherStationDataSourceId", weatherStationDataSource).getSingleResult(); + return organizationReferences == 0; + } + + public void deleteWeatherStationDataSource(WeatherStationDataSource weatherStationDataSource) + { + WeatherStationDataSource sourceToDelete = em.find(WeatherStationDataSource.class, weatherStationDataSource.getWeatherStationDataSourceId()); + em.remove(sourceToDelete); + } + + public WeatherStationDataSource storeWeatherStationDataSource(WeatherStationDataSource weatherStationDataSource) + { + weatherStationDataSource = em.merge(weatherStationDataSource); + return weatherStationDataSource; + } + public PointOfInterestWeatherStation storeWeatherStation(PointOfInterestWeatherStation weatherStation) { weatherStation = em.merge(weatherStation); return weatherStation; diff --git a/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java b/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java index 5778f6c8ddb90ffeda30c8bfa10ac8563bb7e939..44f498c3a525eb55051bfc117496b6fa3ca8ea99 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/SchedulingBean.java @@ -37,16 +37,16 @@ import java.util.Set; import java.util.SortedMap; import java.util.TimeZone; import java.util.TreeMap; -import javax.ejb.EJB; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.GenericType; -import javax.ws.rs.core.Response; +import jakarta.ejb.EJB; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.GenericType; +import jakarta.ws.rs.core.Response; import no.nibio.vips.coremanager.service.ManagerResource; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.ModelRunRequest; @@ -217,9 +217,6 @@ public class SchedulingBean { sendForecastNotificationsCollector.getTasks().add(morningAndAfternoonPattern, VipsLogicTaskFactory.createVipsLogicTask(VipsLogicTaskFactory.SEND_FORECAST_EVENT_NOTIFICATIONS_TASK)); - // Run grid models - VIPSLogicTaskCollector runGridModelsCollector = new VIPSLogicTaskCollector(-1); - runGridModelsCollector.getTasks().add(morningAndAfternoonPattern, VipsLogicTaskFactory.createVipsLogicTask(VipsLogicTaskFactory.RUN_GRID_MODELS_TASK)); List<TaskCollector> definedTasks = new ArrayList<>(); definedTasks.add(modelRunCollector); @@ -227,7 +224,6 @@ public class SchedulingBean { definedTasks.add(summariesCollector); definedTasks.add(deleteAllExpiredUserUuidsCollector); definedTasks.add(sendForecastNotificationsCollector); - definedTasks.add(runGridModelsCollector); return definedTasks; } diff --git a/src/main/java/no/nibio/vips/logic/controller/session/SessionControllerGetter.java b/src/main/java/no/nibio/vips/logic/controller/session/SessionControllerGetter.java index b28098ff7f01144011fdb24b80b5a11d6246c1a4..dc399f9c705b8f310eaeb9c88b4994dcfd2a57d1 100644 --- a/src/main/java/no/nibio/vips/logic/controller/session/SessionControllerGetter.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/SessionControllerGetter.java @@ -26,7 +26,7 @@ import no.nibio.vips.logic.messaging.MessagingBean; /** * Thought this was oblivious because of @EJB, but it turns out this is necessary when invoking beans from outside managed beans! - * @copyright 2013-2022 <a href="http://www.nibio.no/">NIBIO</a> + * @copyright 2013-2025 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ @@ -34,7 +34,7 @@ public class SessionControllerGetter { // This obviously has to be changed when changing the application name in Maven // TODO: Refactor out to System properties (e.g. in standalone.xml in JBoss/WildFly) - public static final String JNDI_PATH = "java:global/VIPSLogic-2024.1/"; + public static final String JNDI_PATH = "java:global/VIPSLogic-2025.1/"; public static SchedulingBean getSchedulingBean() { diff --git a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java index c6f0a121acff084defa5cad061119032c1ee3910..d56eb126ad071ddf74b7faa54d9c84954c1783f5 100755 --- a/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java +++ b/src/main/java/no/nibio/vips/logic/controller/session/UserBean.java @@ -41,14 +41,14 @@ import java.util.Set; import java.util.UUID; import java.util.logging.Level; import java.util.logging.Logger; -import javax.ejb.EJB; -import javax.ejb.LocalBean; -import javax.ejb.Stateless; -import javax.persistence.*; -import javax.servlet.http.HttpServletRequest; -import javax.validation.ConstraintViolation; -import javax.validation.ConstraintViolationException; -import javax.ws.rs.core.HttpHeaders; +import jakarta.ejb.EJB; +import jakarta.ejb.LocalBean; +import jakarta.ejb.Stateless; +import jakarta.persistence.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.ConstraintViolationException; +import jakarta.ws.rs.core.HttpHeaders; import no.nibio.vips.logic.authenticate.PasswordValidationException; import no.nibio.vips.logic.entity.*; diff --git a/src/main/java/no/nibio/vips/logic/entity/Country.java b/src/main/java/no/nibio/vips/logic/entity/Country.java index 1f68fc8ffd8dc130d6d6cc8fe2d24b1f94c788f3..acea2f44087e0f8054bd15101cb3f24a3c4fb036 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Country.java +++ b/src/main/java/no/nibio/vips/logic/entity/Country.java @@ -21,19 +21,19 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Locale; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/CropCategory.java b/src/main/java/no/nibio/vips/logic/entity/CropCategory.java index 43cc458731c8f1194194a494ec5fe27b2659be7b..f1d249e6b7eabe376268d667c8e2d5d2817760f9 100755 --- a/src/main/java/no/nibio/vips/logic/entity/CropCategory.java +++ b/src/main/java/no/nibio/vips/logic/entity/CropCategory.java @@ -19,27 +19,28 @@ package no.nibio.vips.logic.entity; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; import java.io.Serializable; import java.util.Arrays; import java.util.HashSet; +import java.util.List; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import java.util.stream.Collectors; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; -import no.nibio.vips.logic.util.IntegerArrayUserType; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; + /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -48,7 +49,6 @@ import org.hibernate.annotations.TypeDefs; @Entity @Table(name = "crop_category") @XmlRootElement -@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) @NamedQueries({ @NamedQuery(name = "CropCategory.findAll", query = "SELECT c FROM CropCategory c"), @NamedQuery(name = "CropCategory.findByCropCategoryId", query = "SELECT c FROM CropCategory c WHERE c.cropCategoryId = :cropCategoryId"), @@ -70,9 +70,9 @@ public class CropCategory implements Serializable { private String defaultName; @OneToMany(cascade = CascadeType.ALL, mappedBy = "cropCategoryId", fetch = FetchType.EAGER) private Set<CropCategoryLocal> cropCategoryLocalSet; - @Type(type = "IntegerArray") @Column(name = "crop_organism_ids") - private Integer[] cropOrganismIds; + @Type(ListArrayType.class) + private List<Integer> cropOrganismIds; @Column(name = "organization_id") private Integer organizationId; @Column(name = "max_hierarchy_category_id") @@ -101,11 +101,11 @@ public class CropCategory implements Serializable { this.defaultName = defaultName; } - public Integer[] getCropOrganismIds() { + public List<Integer> getCropOrganismIds() { return cropOrganismIds; } - public void setCropOrganismIds(Integer[] cropOrganismIds) { + public void setCropOrganismIds(List<Integer> cropOrganismIds) { this.cropOrganismIds = cropOrganismIds; } @@ -203,18 +203,18 @@ public class CropCategory implements Serializable { } else { - cropSet = new HashSet<>(Arrays.asList(this.getCropOrganismIds())); + cropSet = new HashSet<>(this.getCropOrganismIds()); } cropSet.add(organismId); - this.setCropOrganismIds(cropSet.toArray(new Integer[cropSet.size()])); + this.setCropOrganismIds(cropSet.stream().collect(Collectors.toList())); } public void removeCropOrganismId(Integer organismId) { if(this.getCropOrganismIds() != null) { - Set<Integer> cropSet = new HashSet<>(Arrays.asList(this.getCropOrganismIds())); + Set<Integer> cropSet = new HashSet<>(this.getCropOrganismIds()); cropSet.remove(organismId); - this.setCropOrganismIds(cropSet.toArray(new Integer[cropSet.size()])); + this.setCropOrganismIds(cropSet.stream().collect(Collectors.toList())); } } diff --git a/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocal.java b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocal.java index 7521198053302f0fdb327db9f995ff76301a040f..98074bf6172b08526e05cfb69e1c3d6c3c44c486 100755 --- a/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocal.java +++ b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocal.java @@ -19,13 +19,13 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocalPK.java b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocalPK.java index b8e75cd1eae04abe22a37f976b0d0c7f7e63392e..3e0ebfa926601fe6c92b317c8122ff67f72fd477 100755 --- a/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocalPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/CropCategoryLocalPK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/CropPest.java b/src/main/java/no/nibio/vips/logic/entity/CropPest.java index 0443494be304d26850ffadbd74bc9e4a32503eb2..614352ff4ba05caa3452659eb8d4934fc64b6df2 100755 --- a/src/main/java/no/nibio/vips/logic/entity/CropPest.java +++ b/src/main/java/no/nibio/vips/logic/entity/CropPest.java @@ -19,19 +19,18 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; +import java.util.List; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import javax.xml.bind.annotation.XmlRootElement; -import no.nibio.vips.logic.util.IntegerArrayUserType; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -39,7 +38,6 @@ import org.hibernate.annotations.TypeDefs; */ @Entity @Table(name = "crop_pest") -@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) @XmlRootElement @NamedQueries({ @NamedQuery(name = "CropPest.findAll", query = "SELECT c FROM CropPest c"), @@ -55,9 +53,9 @@ public class CropPest implements Serializable { @NotNull @Column(name = "crop_organism_id") private Integer cropOrganismId; - @Type(type = "IntegerArray") + @Type(ListArrayType.class) @Column(name = "pest_organism_ids") - private Integer[] pestOrganismIds; + private List<Integer> pestOrganismIds; @Column(name = "include_all_child_crops") private Boolean includeAllChildCrops; @@ -76,11 +74,11 @@ public class CropPest implements Serializable { this.cropOrganismId = cropOrganismId; } - public Integer[] getPestOrganismIds() { + public List<Integer> getPestOrganismIds() { return pestOrganismIds; } - public void setPestOrganismIds(Integer[] pestOrganismIds) { + public void setPestOrganismIds(List<Integer> pestOrganismIds) { this.pestOrganismIds = pestOrganismIds; } diff --git a/src/main/java/no/nibio/vips/logic/entity/Currency.java b/src/main/java/no/nibio/vips/logic/entity/Currency.java index 5b2e74be654b9b884db8b714083be023fc5fa868..f7fe3adc7be7cca360870603708eb775e805549a 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Currency.java +++ b/src/main/java/no/nibio/vips/logic/entity/Currency.java @@ -20,16 +20,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Collection; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; diff --git a/src/main/java/no/nibio/vips/logic/entity/DbUpdate.java b/src/main/java/no/nibio/vips/logic/entity/DbUpdate.java index 6b74e19df6a222160cb59f8443183d2be658a449..48172b8de6c0686e7f86a112d75100d45ecc2a8d 100644 --- a/src/main/java/no/nibio/vips/logic/entity/DbUpdate.java +++ b/src/main/java/no/nibio/vips/logic/entity/DbUpdate.java @@ -20,17 +20,17 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/ExternalResource.java b/src/main/java/no/nibio/vips/logic/entity/ExternalResource.java index 19007bed6afaecd6dea8da79e47c7c04441643b8..6fe731e766a9a66e4041d0e5a9e6c924e62dfec8 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ExternalResource.java +++ b/src/main/java/no/nibio/vips/logic/entity/ExternalResource.java @@ -20,21 +20,21 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/ExternalResourceType.java b/src/main/java/no/nibio/vips/logic/entity/ExternalResourceType.java index f6076e6762d6192866082b48fa583d1f2ba74bac..6d2cdc4dc9c47918013e86b482682e39fb42f8de 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ExternalResourceType.java +++ b/src/main/java/no/nibio/vips/logic/entity/ExternalResourceType.java @@ -19,16 +19,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java index a17f2fbadaa35794dd3de13e10a6883d024776f7..dbb041d3031c109df59ef7cba5c618f33b4a6e0f 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java +++ b/src/main/java/no/nibio/vips/logic/entity/ForecastConfiguration.java @@ -20,43 +20,40 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; import java.util.List; import java.util.TimeZone; -import javax.persistence.Transient; -import no.nibio.vips.logic.util.IntegerArrayUserType; +import jakarta.persistence.Transient; import no.nibio.vips.util.WeatherUtil; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; /** - * @copyright 2014-2016 <a href="http://www.nibio.no/">NIBIO</a> + * @copyright 2014-2024 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ @Entity @Table(name = "forecast_configuration") @XmlRootElement -@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) @NamedQueries({ @NamedQuery(name = "ForecastConfiguration.findAll", query = "SELECT f FROM ForecastConfiguration f WHERE f.isPrivate = FALSE"), @NamedQuery(name = "ForecastConfiguration.findByForecastConfigurationId", query = "SELECT f FROM ForecastConfiguration f WHERE f.forecastConfigurationId = :forecastConfigurationId"), @@ -123,10 +120,20 @@ public class ForecastConfiguration implements Serializable, Comparable { private Organism pestOrganismId; @Column(name = "is_private") private Boolean isPrivate; + @Column(name = "use_grid_weather_data") + private Boolean useGridWeatherData; - @Type(type = "IntegerArray") + public Boolean getUseGridWeatherData() { + return useGridWeatherData != null ? useGridWeatherData : Boolean.FALSE; + } + + public void setUseGridWeatherData(Boolean useGridWeatherData) { + this.useGridWeatherData = useGridWeatherData; + } + + @Type(ListArrayType.class) @Column(name = "grid_weather_station_point_of_interest_ids") - private Integer[] gridWeatherStationPointOfInterestIds; + private List<Integer> gridWeatherStationPointOfInterestIds; @Transient private WeatherUtil weatherUtil; @@ -247,6 +254,29 @@ public class ForecastConfiguration implements Serializable, Comparable { * @return the weatherStationPointOfInterestId */ public PointOfInterest getWeatherStationPointOfInterestId() { + if( this.getUseGridWeatherData() && this.getVipsLogicUserId().getOrganizationId().getDefaultGridWeatherStationDataSource() != null) + { + // Create a "weather station" with coordinates from the location + // And the default grid weather data source for the current organization (get location owner's organization) + PointOfInterestWeatherStation gridStation = new PointOfInterestWeatherStation(); + gridStation.setLatitude(this.getLocationPointOfInterestId().getLatitude()); + gridStation.setLongitude(this.getLocationPointOfInterestId().getLongitude()); + gridStation.setName("GRID-punkt for " + this.getLocationPointOfInterestId().getName()); // TODO Translate!!! + gridStation.setTimeZone(this.getLocationPointOfInterestId().getTimeZone()); + gridStation.setWeatherStationDataSourceId(this.getVipsLogicUserId().getOrganizationId().getDefaultGridWeatherStationDataSource()); + gridStation.setUser(this.getVipsLogicUserId()); + gridStation.setWeatherForecastProviderId(null); + gridStation.setWeatherStationRemoteId(gridStation.getLongitude() + "_" + gridStation.getLatitude()); + gridStation.setGisGeom(this.getLocationPointOfInterestId().getGisGeom()); + gridStation.setAltitude(this.getLocationPointOfInterestId().getAltitude()); + gridStation.setCountryCode(this.getLocationPointOfInterestId().getCountryCode()); + gridStation.setIsForecastLocation(true); + gridStation.setPointOfInterestTypeId(PointOfInterestType.POINT_OF_INTEREST_TYPE_WEATHER_STATION); + gridStation.setUser(this.getVipsLogicUserId()); + gridStation.setProperties(this.getLocationPointOfInterestId().getProperties()); + return gridStation; + } + return weatherStationPointOfInterestId; } @@ -406,14 +436,14 @@ public class ForecastConfiguration implements Serializable, Comparable { /** * @return the gridWeatherStationPointOfInterestIds */ - public Integer[] getGridWeatherStationPointOfInterestIds() { + public List<Integer> getGridWeatherStationPointOfInterestIds() { return gridWeatherStationPointOfInterestIds; } /** * @param gridWeatherStationPointOfInterestIds the gridWeatherStationPointOfInterestIds to set */ - public void setGridWeatherStationPointOfInterestIds(Integer[] gridWeatherStationPointOfInterestIds) { + public void setGridWeatherStationPointOfInterestIds(List<Integer> gridWeatherStationPointOfInterestIds) { this.gridWeatherStationPointOfInterestIds = gridWeatherStationPointOfInterestIds; } } diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfiguration.java b/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfiguration.java index a37304d0f422f58d619b36bd721d162ab5ea7fb1..4a2d41e8c4450305ff0a59d7b06eefb9730b0dfa 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfiguration.java +++ b/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfiguration.java @@ -19,16 +19,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfigurationPK.java b/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfigurationPK.java index e0a82aeac9896282e23de90b5a61204841b8d321..84cf5675c038895824e5dc434eecae5f1e042d55 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfigurationPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/ForecastModelConfigurationPK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastResult.java b/src/main/java/no/nibio/vips/logic/entity/ForecastResult.java index 1b4f7e400368a478084d69480af0a80adca2473b..54a66fa806fd77e1f02580af88f53b8177ba79df 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ForecastResult.java +++ b/src/main/java/no/nibio/vips/logic/entity/ForecastResult.java @@ -26,18 +26,18 @@ import java.util.Map; import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Transient; import javax.xml.bind.annotation.XmlRootElement; import no.nibio.vips.entity.Result; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastSummary.java b/src/main/java/no/nibio/vips/logic/entity/ForecastSummary.java index 5cb3f66e0847de300c57d98bcb5da6188e363e47..88f201dc6087b7b1cad131f5007ededca5940915 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ForecastSummary.java +++ b/src/main/java/no/nibio/vips/logic/entity/ForecastSummary.java @@ -20,14 +20,14 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import javax.xml.bind.annotation.XmlRootElement; /** @@ -41,7 +41,7 @@ import javax.xml.bind.annotation.XmlRootElement; @NamedQuery(name = "ForecastSummary.findAll", query = "SELECT f FROM ForecastSummary f"), @NamedQuery(name = "ForecastSummary.findByForecastConfigurationId", query = "SELECT f FROM ForecastSummary f WHERE f.forecastSummaryPK.forecastConfigurationId = :forecastConfigurationId"), @NamedQuery(name = "ForecastSummary.findByForecastConfigurationIds", query = "SELECT f FROM ForecastSummary f WHERE f.forecastSummaryPK.forecastConfigurationId IN(:forecastConfigurationIds)"), - @NamedQuery(name = "ForecastSummary.findByOrganizationId", query = "SELECT f FROM ForecastSummary f WHERE f.forecastSummaryPK.forecastConfigurationId IN(SELECT f1.forecastConfigurationId FROM ForecastConfiguration f1 WHERE f1.vipsLogicUserId IN (SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId=:organizationId))"), + @NamedQuery(name = "ForecastSummary.findByOrganizationId", query = "SELECT f FROM ForecastSummary f WHERE f.forecastSummaryPK.forecastConfigurationId IN(SELECT f1.forecastConfigurationId FROM ForecastConfiguration f1 WHERE f1.vipsLogicUserId.userId IN (SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId))"), @NamedQuery(name = "ForecastSummary.findBySummaryForDate", query = "SELECT f FROM ForecastSummary f WHERE f.forecastSummaryPK.summaryForDate = :summaryForDate"), @NamedQuery(name = "ForecastSummary.findBySummaryCreatedTime", query = "SELECT f FROM ForecastSummary f WHERE f.summaryCreatedTime = :summaryCreatedTime"), @NamedQuery(name = "ForecastSummary.findByWarningStatus", query = "SELECT f FROM ForecastSummary f WHERE f.warningStatus = :warningStatus")}) diff --git a/src/main/java/no/nibio/vips/logic/entity/ForecastSummaryPK.java b/src/main/java/no/nibio/vips/logic/entity/ForecastSummaryPK.java index 4980278e3057d63ce00fb1cbed0c6e9e8527c7fb..1df735c7a2c8c548089cad5df09d308cd362bff0 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ForecastSummaryPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/ForecastSummaryPK.java @@ -20,12 +20,12 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.validation.constraints.NotNull; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/Gis.java b/src/main/java/no/nibio/vips/logic/entity/Gis.java index e61037ea3c04998a95f845a86e150e60c8770251..1fe5fef3da0be6c16cf385597a2e4e046782b177 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Gis.java +++ b/src/main/java/no/nibio/vips/logic/entity/Gis.java @@ -22,15 +22,15 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; import javax.xml.bind.annotation.XmlRootElement; //import org.hibernate.annotations.Type; diff --git a/src/main/java/no/nibio/vips/logic/entity/HierarchyCategory.java b/src/main/java/no/nibio/vips/logic/entity/HierarchyCategory.java index 3133b1716a60239642633e90c08e0bbb4b1a8f09..6e36162ce16df01c11cc8af6548f8dcde50a2307 100755 --- a/src/main/java/no/nibio/vips/logic/entity/HierarchyCategory.java +++ b/src/main/java/no/nibio/vips/logic/entity/HierarchyCategory.java @@ -20,18 +20,18 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocale.java b/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocale.java index e31e3744d70d00fdf3f701b2d47830615f793195..f898e378d4e6a89d821ef713a7d6be2f5854453b 100755 --- a/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocale.java +++ b/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocale.java @@ -19,15 +19,15 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocalePK.java b/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocalePK.java index d4542edf467855f4d647d02f586237fe0abe38d6..469898f2775bbfeb951c93889e0031f5eab17c61 100755 --- a/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocalePK.java +++ b/src/main/java/no/nibio/vips/logic/entity/HierarchyCategoryLocalePK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/MapLayer.java b/src/main/java/no/nibio/vips/logic/entity/MapLayer.java index f18cf17f6300c34c5d991b69b2cca7ac01921182..7fe45941d7962fa19eb81be6f471155b5da85041 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MapLayer.java +++ b/src/main/java/no/nibio/vips/logic/entity/MapLayer.java @@ -20,16 +20,16 @@ package no.nibio.vips.logic.entity; import com.fasterxml.jackson.annotation.JsonProperty; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/Message.java b/src/main/java/no/nibio/vips/logic/entity/Message.java index 1bd92c6064cc3c72c991b02744860c7170b17a8f..c58853e0fc4bd099bceb51c98bb6d11b721f4ec2 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Message.java +++ b/src/main/java/no/nibio/vips/logic/entity/Message.java @@ -24,29 +24,27 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Transient; import javax.xml.bind.annotation.XmlRootElement; -import no.nibio.vips.logic.util.IntegerArrayUserType; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> @@ -55,7 +53,6 @@ import org.hibernate.annotations.TypeDefs; @Entity @Table(name = "message") @XmlRootElement -@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) @NamedQueries({ @NamedQuery(name = "Message.findAll", query = "SELECT m FROM Message m"), @NamedQuery(name = "Message.findByMessageId", query = "SELECT m FROM Message m WHERE m.messageId = :messageId"), @@ -75,7 +72,7 @@ public class Message implements Serializable { private Set<MessageIllustration> messageIllustrationSet; private Set<MessageLocale> messageLocaleSet; private Integer organizationId; - private Integer[] cropCategoryIds; + private List<Integer> cropCategoryIds; public Message() { } @@ -276,16 +273,16 @@ public class Message implements Serializable { /** * @return the cropCategoryIds */ - @Type(type = "IntegerArray") + @Type(ListArrayType.class) @Column(name="crop_category_ids") - public Integer[] getCropCategoryIds() { + public List<Integer> getCropCategoryIds() { return cropCategoryIds; } /** * @param cropCategoryIds the cropCategoryIds to set */ - public void setCropCategoryIds(Integer[] cropCategoryIds) { + public void setCropCategoryIds(List<Integer> cropCategoryIds) { this.cropCategoryIds = cropCategoryIds; } diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageIllustration.java b/src/main/java/no/nibio/vips/logic/entity/MessageIllustration.java index c695472e1de2a68a2cf2a58570ced4e96fef1584..55b3e70c9e9cd09f0a87479984ecbd99a354ad41 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageIllustration.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageIllustration.java @@ -20,16 +20,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocale.java b/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocale.java index da38390a325fd8748b717bcca66f7df353b2975d..3a21bf652a642d5758f681a345f7112e2d1b4deb 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocale.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocale.java @@ -19,17 +19,17 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinColumns; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocalePK.java b/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocalePK.java index fe5a6c87acca4f56971f72a4e232754f9120ffa7..5cf78327bdba7b6099306baa6c875c61fd4480fc 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocalePK.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationCaptionLocalePK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationPK.java b/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationPK.java index b33858ef08c4c33bba77766d60c67e7ed4a0c9dd..b0da8810fabf47f9310b0eeb6ee3105267066bbb 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageIllustrationPK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageLocale.java b/src/main/java/no/nibio/vips/logic/entity/MessageLocale.java index e91b5fe99657e2169ea9068b17df1d6f85940136..4bf86c97026c91588a645ccae7607dea1fc4793e 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageLocale.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageLocale.java @@ -20,20 +20,20 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageLocalePK.java b/src/main/java/no/nibio/vips/logic/entity/MessageLocalePK.java index a894bcd50a007ec3ccbc33aedb19b8195a6008db..3e6960eb4d806e5fb3805d22b528f77e53d291df 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageLocalePK.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageLocalePK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageTag.java b/src/main/java/no/nibio/vips/logic/entity/MessageTag.java index 226e112987ba14845666ee3eb2f8e015c6a350df..e2c33d280f8059181562b4e418776dc12fdb0738 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageTag.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageTag.java @@ -20,20 +20,20 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageTagLocale.java b/src/main/java/no/nibio/vips/logic/entity/MessageTagLocale.java index 90e4fd9e25f3431c4d84e446cfeb52abaa86e912..0c80e15b50e88bf7ab9f88633c5d07b12273ea55 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageTagLocale.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageTagLocale.java @@ -19,16 +19,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/MessageTagLocalePK.java b/src/main/java/no/nibio/vips/logic/entity/MessageTagLocalePK.java index 3c0814ecebdb7ca37d7aff1189be7d28537bf35b..b36a727b6c4446243b86f7e545e97631029eaedd 100755 --- a/src/main/java/no/nibio/vips/logic/entity/MessageTagLocalePK.java +++ b/src/main/java/no/nibio/vips/logic/entity/MessageTagLocalePK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/ModelInformation.java b/src/main/java/no/nibio/vips/logic/entity/ModelInformation.java index ed19d2224367fa6596a6afa598346bc1e46e3ad7..9c3240d9907d05949667ab349d40598647936d05 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ModelInformation.java +++ b/src/main/java/no/nibio/vips/logic/entity/ModelInformation.java @@ -20,9 +20,9 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.*; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/Observation.java b/src/main/java/no/nibio/vips/logic/entity/Observation.java index 54fbc58b67016d2fed44542209dca50f133c3def..478e8dd610a6ebe5e9d37df9d499f097afd80445 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Observation.java +++ b/src/main/java/no/nibio/vips/logic/entity/Observation.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -19,21 +19,8 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; -import javax.validation.constraints.NotNull; +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; import javax.xml.bind.annotation.XmlRootElement; import com.fasterxml.jackson.annotation.JsonIgnore; import java.util.ArrayList; @@ -41,18 +28,14 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.FetchType; -import javax.persistence.OneToMany; -import javax.validation.constraints.Size; +import jakarta.validation.constraints.Size; import no.nibio.vips.logic.util.GISEntityUtil; import no.nibio.vips.gis.GISUtil; import no.nibio.vips.logic.entity.rest.ObservationListItem; -import no.nibio.vips.logic.util.StringJsonUserType; import no.nibio.vips.observationdata.ObservationDataSchema; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; + /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -61,22 +44,24 @@ import org.hibernate.annotations.TypeDefs; @Entity @Table(name = "observation") @XmlRootElement -@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)}) +//@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)}) + @NamedQueries({ @NamedQuery(name = "Observation.findAll", query = "SELECT o FROM Observation o"), @NamedQuery(name = "Observation.findByObservationId", query = "SELECT o FROM Observation o WHERE o.observationId = :observationId"), @NamedQuery(name = "Observation.findByUserId", query = "SELECT o FROM Observation o WHERE o.userId IN(:userId)"), @NamedQuery(name = "Observation.findByLastEditedBy", query = "SELECT o FROM Observation o WHERE o.lastEditedBy IN(:lastEditedBy)"), @NamedQuery(name = "Observation.findByLocationPointOfInterestId", query = "SELECT o FROM Observation o WHERE o.locationPointOfInterestId = :locationPointOfInterestId"), + @NamedQuery(name = "Observation.findByObservationTimeSeries", query = "SELECT o FROM Observation o WHERE o.observationTimeSeries = :observationTimeSeries"), @NamedQuery(name = "Observation.findByStatusChangedByUserId", query = "SELECT o FROM Observation o WHERE o.statusChangedByUserId IN(:statusChangedByUserId)"), @NamedQuery(name = "Observation.findByUserIdAndPeriod", query = "SELECT o FROM Observation o WHERE o.timeOfObservation BETWEEN :start AND :end AND o.userId IN(:userId)"), @NamedQuery(name = "Observation.findByUserIdAndStatusTypeId", query = "SELECT o FROM Observation o WHERE o.userId IN(:userId) AND o.statusTypeId= :statusTypeId"), @NamedQuery(name = "Observation.findByUserIdAndOrganism", query = "SELECT o FROM Observation o WHERE o.userId IN(:userId) AND o.organism = :organism"), - @NamedQuery(name = "Observation.findByOrganizationId", query = "SELECT o FROM Observation o WHERE o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))"), - @NamedQuery(name = "Observation.findByOrganizationIdAndPeriod", query = "SELECT o FROM Observation o WHERE o.timeOfObservation BETWEEN :start AND :end AND o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))"), - @NamedQuery(name = "Observation.findByOrganizationIdAndStatusTypeId", query = "SELECT o FROM Observation o WHERE o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) AND o.statusTypeId= :statusTypeId"), - @NamedQuery(name = "Observation.findByOrganizationIdAndStatusTypeIdAndBroadcastMessage", query = "SELECT o FROM Observation o WHERE o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) AND o.statusTypeId= :statusTypeId AND o.broadcastMessage IS TRUE"), - @NamedQuery(name = "Observation.findByOrganizationIdAndStatusTypeIdAndBroadcastMessageAndPeriod", query = "SELECT o FROM Observation o WHERE o.timeOfObservation BETWEEN :start AND :end AND o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) AND o.statusTypeId= :statusTypeId AND o.broadcastMessage IS TRUE"), + @NamedQuery(name = "Observation.findByOrganizationId", query = "SELECT o FROM Observation o WHERE o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId.organizationId = :organizationId OR v.organizationId.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId.organizationId = :organizationId))"), + @NamedQuery(name = "Observation.findByOrganizationIdAndPeriod", query = "SELECT o FROM Observation o WHERE o.timeOfObservation BETWEEN :start AND :end AND o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId))"), + @NamedQuery(name = "Observation.findByOrganizationIdAndStatusTypeId", query = "SELECT o FROM Observation o WHERE o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId.organizationId = :organizationId OR v.organizationId.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId.organizationId = :organizationId)) AND o.statusTypeId= :statusTypeId"), + @NamedQuery(name = "Observation.findByOrganizationIdAndStatusTypeIdAndBroadcastMessage", query = "SELECT o FROM Observation o WHERE o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) AND o.statusTypeId= :statusTypeId AND o.broadcastMessage IS TRUE"), + @NamedQuery(name = "Observation.findByOrganizationIdAndStatusTypeIdAndBroadcastMessageAndPeriod", query = "SELECT o FROM Observation o WHERE o.timeOfObservation BETWEEN :start AND :end AND o.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) AND o.statusTypeId= :statusTypeId AND o.broadcastMessage IS TRUE"), @NamedQuery(name = "Observation.findByOrganism", query = "SELECT o FROM Observation o WHERE o.organism = :organism"), @NamedQuery(name = "Observation.findFirstByOrganism", query = "SELECT o FROM Observation o WHERE o.organism = :organism AND o.timeOfObservation = (SELECT MIN(ob.timeOfObservation) FROM Observation ob WHERE ob.organism = :organism)"), @NamedQuery(name = "Observation.findByTimeOfObservation", query = "SELECT o FROM Observation o WHERE o.timeOfObservation = :timeOfObservation") @@ -91,6 +76,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse private Integer userId; private Integer lastEditedBy; private List<Gis> geoinfo; + private ObservationTimeSeries observationTimeSeries; private Integer locationPointOfInterestId; //private Double observedValue; //private Integer denominator; @@ -108,21 +94,30 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse private Boolean broadcastMessage; private Boolean locationIsPrivate; private PolygonService polygonService; - + private ObservationDataSchema observationDataSchema; - + private VipsLogicUser user; // Transient private VipsLogicUser lastEditedByUser; // private PointOfInterest location; // Transient - + private Set<ObservationIllustration> observationIllustrationSet; - + private GISEntityUtil GISEntityUtil; private GISUtil GISUtil; + // Should be defined as an enum (WEB/APP), but PostgreSQLEnumType and hibernate6 seems to be necessary + // https://stackoverflow.com/questions/50818649/hibernate-and-java-and-postgres-enumeratedvalue-enumtype-string-caused-by + private String source; + public Observation() { + this("WEB"); + } + + public Observation(String source) { this.GISEntityUtil = new GISEntityUtil(); this.GISUtil = new GISUtil(); + this.source = source; } public Observation(Integer observationId) { @@ -160,7 +155,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse this.timeOfObservation = timeOfObservation; } - + // Using PostGIS + Hibernate-spatial + Java Topology Suite to make this work /*@JsonIgnore @Type(type = "org.hibernate.spatial.GeometryType") @@ -172,12 +167,12 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse public void setLocation(Point location) { this.location = location; }*/ - + public void setGeoinfos(List<Gis> geoinfo) { this.geoinfo = geoinfo; } - + public void addGeoInfo(Gis geoinfo) { if(this.geoinfo == null) @@ -186,20 +181,20 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse } this.geoinfo.add(geoinfo); } - + @JsonIgnore @Transient public List<Gis> getGeoinfos() { return this.geoinfo; } - - + + public void setGeoinfo(String json) { this.setGeoinfos(this.GISEntityUtil.getGisFromGeoJSON(json)); } - + @Transient @Override public String getGeoinfo() @@ -272,7 +267,38 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse @Override public String toString() { - return "no.nibio.vips.logic.entity.Observation[ observationId=" + observationId + " ]"; + return "Observation{" + + "observationId=" + observationId + + ", timeOfObservation=" + timeOfObservation + + ", organism=" + organism + + ", cropOrganism=" + cropOrganism + + ", userId=" + userId + + ", lastEditedBy=" + lastEditedBy + + ", geoinfo=" + geoinfo + + ", observationTimeSeries=" + observationTimeSeries + + ", locationPointOfInterestId=" + locationPointOfInterestId + + ", observationHeading='" + observationHeading + '\'' + + ", observationText='" + observationText + '\'' + + ", statusTypeId=" + statusTypeId + + ", statusChangedByUserId=" + statusChangedByUserId + + ", statusChangedTime=" + statusChangedTime + + ", lastEditedTime=" + lastEditedTime + + ", statusRemarks='" + statusRemarks + '\'' + + ", observationData='" + observationData + '\'' + + ", isQuantified=" + isQuantified + + ", isPositive=" + isPositive + + ", broadcastMessage=" + broadcastMessage + + ", locationIsPrivate=" + locationIsPrivate + + ", polygonService=" + polygonService + + ", observationDataSchema=" + observationDataSchema + + ", user=" + user + + ", lastEditedByUser=" + lastEditedByUser + + ", location=" + location + + ", observationIllustrationSet=" + observationIllustrationSet + + ", GISEntityUtil=" + GISEntityUtil + + ", GISUtil=" + GISUtil + + ", source=" + source + + '}'; } /** @@ -311,13 +337,13 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse public void setOrganism(Organism organism) { this.organism = organism; } - + @JoinColumn(name = "polygon_service_id", referencedColumnName = "polygon_service_id") @ManyToOne public PolygonService getPolygonService(){ return this.polygonService; } - + public void setPolygonService(PolygonService polygonService) { this.polygonService = polygonService; @@ -336,7 +362,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse return this.getLocationCoordinate().x; } */ - + @Override @Transient public String getName() { @@ -440,11 +466,11 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse /** * @return the observationData */ - @Type(type = "StringJsonObject") + @JdbcTypeCode(SqlTypes.JSON) @Column(name = "observation_data") @Override public String getObservationData() { - return observationData; + return this.observationData != null && this.observationData.replaceAll("\"", "").trim().length() > 0 ? this.observationData : null; } /** @@ -453,13 +479,13 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse public void setObservationData(String observationData) { this.observationData = observationData; } - + @Transient public ObservationDataSchema getObservationDataSchema() { return this.observationDataSchema != null ? this.observationDataSchema : null; } - + public void setObservationDataSchema(ObservationDataSchema observationDataSchema) { this.observationDataSchema = observationDataSchema; @@ -495,7 +521,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse public void setCropOrganism(Organism cropOrganism) { this.cropOrganism = cropOrganism; } - + @Transient public Integer getCropOrganismId() { return this.getCropOrganism() != null ? this.getCropOrganism().getOrganismId() : null; @@ -531,6 +557,27 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse this.observationIllustrationSet = observationIllustrationSet; } + @Transient + public Integer getObservationTimeSeriesId() { + return observationTimeSeries != null ? observationTimeSeries.getObservationTimeSeriesId() : null; + } + + /** + * @return the observation time series + */ + @JoinColumn(name = "observation_time_series_id", referencedColumnName = "observation_time_series_id") + @ManyToOne + public ObservationTimeSeries getObservationTimeSeries() { + return observationTimeSeries; + } + + /** + * @param observationTimeSeries the observation time series to set + */ + public void setObservationTimeSeries(ObservationTimeSeries observationTimeSeries) { + this.observationTimeSeries = observationTimeSeries; + } + /** * @return the locationPointOfInterestId */ @@ -630,7 +677,7 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse /** * Simplifies the public JSON object * @param locale - * @return + * @return */ public ObservationListItem getListItem(String locale, ObservationDataSchema observationDataSchema) { @@ -642,34 +689,41 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse this.location.addProperty("timestamp", this.getTimeOfObservation().getTime()); } return new ObservationListItem( - this.getObservationId(), - this.getTimeOfObservation(), - this.getOrganismId(), - ! this.getOrganism().getLocalName(locale).trim().isBlank() ? this.getOrganism().getLocalName(locale) : this.getOrganism().getLatinName(), - this.getCropOrganismId(), - ! this.getCropOrganism().getLocalName(locale).trim().isBlank() ? this.getCropOrganism().getLocalName(locale) : this.getCropOrganism().getLatinName(), - // Specific geoInfo trumps location. This is to be interpreted - // as that the observation has been geographically masked by - // choice of the observer - this.location != null && this.geoinfo == null ? this.location.getGeoJSON() : this.getGeoinfo(), - this.getObservationHeading(), - this.getBroadcastMessage(), - this.getLocationIsPrivate(), - this.getIsPositive(), - this.getObservationData(), - observationDataSchema + this.getObservationId(), + this.userId, + this.user != null ? this.user.getFullName() : null, + this.getObservationTimeSeriesId(), + this.getTimeOfObservation(), + this.getOrganismId(), + ! this.getOrganism().getLocalName(locale).trim().isBlank() ? this.getOrganism().getLocalName(locale) : this.getOrganism().getLatinName(), + this.getCropOrganismId(), + ! this.getCropOrganism().getLocalName(locale).trim().isBlank() ? this.getCropOrganism().getLocalName(locale) : this.getCropOrganism().getLatinName(), + this.observationTimeSeries != null ? this.observationTimeSeries.getLabel() : null, + // Specific geoInfo trumps location. This is to be interpreted + // as that the observation has been geographically masked by + // choice of the observer + this.location != null ? this.location.getPointOfInterestId() : null, + this.location != null ? this.location.getName() : null, + this.location != null && this.geoinfo == null ? this.location.getGeoJSON() : this.getGeoinfo(), + this.getObservationHeading(), + this.getObservationText(), + this.getBroadcastMessage(), + this.getLocationIsPrivate(), + this.getIsPositive(), + this.getObservationData(), + observationDataSchema ); } @Temporal(TemporalType.TIMESTAMP) @Column(name = "last_edited_time") - public Date getLastEditedTime() { - return lastEditedTime; - } + public Date getLastEditedTime() { + return lastEditedTime; + } - public void setLastEditedTime(Date lastEditedTime) { - this.lastEditedTime = lastEditedTime; - } + public void setLastEditedTime(Date lastEditedTime) { + this.lastEditedTime = lastEditedTime; + } @Column(name = "is_positive") public Boolean getIsPositive() { @@ -679,4 +733,12 @@ public class Observation implements Serializable, no.nibio.vips.observation.Obse public void setIsPositive(Boolean positive) { isPositive = positive; } + + public String getSource() { + return source; + } + + public void setSource(String source) { + this.source = source; + } } diff --git a/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcut.java b/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcut.java index ab8bf912863a26e1ee1e9acd72d8f079358ed210..38036f496ff2a4de5784ab01242e27ddb5834948 100644 --- a/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcut.java +++ b/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcut.java @@ -20,19 +20,19 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcutLocale.java b/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcutLocale.java index 824637fc5b10319216827f490037f90ed7c07cce..f32172805424bd8e7145ef5cc65a7b2e7d80aa4d 100644 --- a/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcutLocale.java +++ b/src/main/java/no/nibio/vips/logic/entity/ObservationFormShortcutLocale.java @@ -19,16 +19,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/ObservationIllustration.java b/src/main/java/no/nibio/vips/logic/entity/ObservationIllustration.java index dcb3a55e4ffeff53060d9fc149c60ea7fbbe4a81..5e114908cab3895e54df481be7d494add28c76b9 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ObservationIllustration.java +++ b/src/main/java/no/nibio/vips/logic/entity/ObservationIllustration.java @@ -19,12 +19,12 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/ObservationIllustrationPK.java b/src/main/java/no/nibio/vips/logic/entity/ObservationIllustrationPK.java index b0eae958a4b9fdbe6080ee0846a26fd49f47f930..2868280692c4d1fc1b93b65b51ab45a25d5b9683 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ObservationIllustrationPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/ObservationIllustrationPK.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/ObservationMethod.java b/src/main/java/no/nibio/vips/logic/entity/ObservationMethod.java index f9148efafe379fe6b4718fe7ac9e0449f59a78d5..57efa06905aedc5441185aa83518196887410649 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ObservationMethod.java +++ b/src/main/java/no/nibio/vips/logic/entity/ObservationMethod.java @@ -20,16 +20,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/ObservationStatusType.java b/src/main/java/no/nibio/vips/logic/entity/ObservationStatusType.java index f00be18570b9eb9b3deced9a023eb65c96130d98..a8451fe405d1c23a12fd740113f89db8752b9caf 100755 --- a/src/main/java/no/nibio/vips/logic/entity/ObservationStatusType.java +++ b/src/main/java/no/nibio/vips/logic/entity/ObservationStatusType.java @@ -19,15 +19,15 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/ObservationTimeSeries.java b/src/main/java/no/nibio/vips/logic/entity/ObservationTimeSeries.java new file mode 100644 index 0000000000000000000000000000000000000000..24315611140e1243edc12a0d0376aa0835566a21 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/entity/ObservationTimeSeries.java @@ -0,0 +1,402 @@ +/* + * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ +package no.nibio.vips.logic.entity; + +import com.fasterxml.jackson.annotation.JsonIgnore; + +import jakarta.persistence.*; +import jakarta.validation.constraints.NotNull; +import javax.xml.bind.annotation.XmlRootElement; +import java.io.Serializable; +import java.util.Date; + +@Entity +@Table(name = "observation_time_series") +@XmlRootElement +@NamedQueries({ + @NamedQuery(name = "ObservationTimeSeries.findAll", query = "SELECT ots FROM ObservationTimeSeries ots"), + @NamedQuery(name = "ObservationTimeSeries.findByObservationTimeSeriesId", query = "SELECT ots FROM ObservationTimeSeries ots WHERE ots.observationTimeSeriesId = :id"), + @NamedQuery(name = "ObservationTimeSeries.findByObservationTimeSeriesIds", query = "SELECT ots FROM ObservationTimeSeries ots WHERE ots.observationTimeSeriesId IN :observationTimeSeriesIds"), + @NamedQuery(name = "ObservationTimeSeries.findByOrganizationId", query = "SELECT ots FROM ObservationTimeSeries ots WHERE ots.userId IN(SELECT v.userId FROM VipsLogicUser v WHERE v.organizationId.organizationId = :organizationId OR v.organizationId.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId.organizationId = :organizationId))"), + @NamedQuery(name = "ObservationTimeSeries.findByUserId", query = "SELECT ots FROM ObservationTimeSeries ots WHERE ots.userId IN(:userId)") +}) +public class ObservationTimeSeries implements Serializable { + + private static final long serialVersionUID = 1L; + private Integer observationTimeSeriesId; + private Organism cropOrganism; + private Organism organism; + private Integer year; + private String name; + private String description; + private Date created; + private Integer userId; + private VipsLogicUser user; // Transient + private String source; + private Date lastModified; + private Integer lastModifiedBy; + private VipsLogicUser lastModifiedByUser; // Transient + private Integer locationPointOfInterestId; + private PointOfInterest locationPointOfInterest; + private Boolean locationIsPrivate; + private PolygonService polygonService; + + public ObservationTimeSeries() { + } + + public ObservationTimeSeries(String source) { + this.source = source; + } + + /** + * @return the id of the observation time series + */ + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Basic(optional = false) + @Column(name = "observation_time_series_id") + public Integer getObservationTimeSeriesId() { + return observationTimeSeriesId; + } + + /** + * @param id the observation time series id to set + */ + public void setObservationTimeSeriesId(Integer id) { + this.observationTimeSeriesId = id; + } + + + /** + * @return the crop organism + */ + @JoinColumn(name = "crop_organism_id", referencedColumnName = "organism_id") + @ManyToOne + public Organism getCropOrganism() { + return cropOrganism; + } + + /** + * @param cropOrganism the crop organism to set + */ + public void setCropOrganism(Organism cropOrganism) { + this.cropOrganism = cropOrganism; + } + + /** + * @return the crop organism id + */ + @Transient + public Integer getCropOrganismId() { + return this.getCropOrganism() != null ? this.getCropOrganism().getOrganismId() : null; + } + + /** + * @return the organism + */ + @JoinColumn(name = "organism_id", referencedColumnName = "organism_id") + @ManyToOne + public Organism getOrganism() { + return organism; + } + + /** + * @param organism the organism to set + */ + public void setOrganism(Organism organism) { + this.organism = organism; + } + + /** + * @return the organism id + */ + @Transient + public Integer getOrganismId() { + return this.getOrganism() != null ? this.getOrganism().getOrganismId() : null; + } + + /** + * @return the year of the observation time series + */ + @Column(name = "year") + public Integer getYear() { + return year; + } + + /** + * @param year the observation time series year to set + */ + public void setYear(Integer year) { + this.year = year; + } + + /** + * @return the name of the observation time series + */ + @Column(name = "name") + public String getName() { + return name; + } + + /** + * @param name the observation time series name to set + */ + public void setName(String name) { + this.name = name; + } + + /** + * This logic if also implemented in the observation app, see the function timeSeriesLabel in CommonUtil.vue + * @return the first eight letters of the given name, in uppercase with spaces removed + */ + @Transient + public String getLabel() { + if (this.name == null) { + return null; + } + String timeSeriesName = this.name; + timeSeriesName = timeSeriesName.replaceAll("\\s", ""); + timeSeriesName = timeSeriesName.substring(0, Math.min(timeSeriesName.length(), 8)); + return timeSeriesName.toUpperCase(); + } + + /** + * @return the description of the observation time series + */ + @Column(name = "description") + public String getDescription() { + return description; + } + + /** + * @param description the observation time series text to set + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * @return the creation date of the observation time series + */ + @NotNull + @Basic(optional = false) + @Column(name = "created") + @Temporal(TemporalType.TIMESTAMP) + public Date getCreated() { + return created; + } + + /** + * @param created the creation date to set + */ + public void setCreated(Date created) { + this.created = created; + } + + @NotNull + @Basic(optional = false) + @Temporal(TemporalType.TIMESTAMP) + @Column(name = "last_modified") + public Date getLastModified() { + return lastModified; + } + + public void setLastModified(Date lastModified) { + this.lastModified = lastModified; + } + + /** + * @return the userId + */ + @Column(name = "user_id") + public Integer getUserId() { + return userId; + } + + /** + * @param userId the userId to set + */ + public void setUserId(Integer userId) { + this.userId = userId; + } + + /** + * @return the user + */ + @Transient + @JsonIgnore + public VipsLogicUser getUser() { + return user; + } + + /** + * @param user the user to set + */ + public void setUser(VipsLogicUser user) { + this.user = user; + } + + /** + * @return from where the observation time series originally was created, either WEB or APP + */ + @Column(name = "source") + public String getSource() { + return source; + } + + /** + * @param source From where the observation time series originally was created + */ + public void setSource(String source) { + this.source = source; + } + + @Column(name = "last_modified_by") + public Integer getLastModifiedBy() { + return lastModifiedBy; + } + + /** + * @param lastModifiedBy the lastModifiedBy to set + */ + public void setLastModifiedBy(Integer lastModifiedBy) { + this.lastModifiedBy = lastModifiedBy; + } + + /** + * @return the user who last modified the observation time series + */ + @Transient + @JsonIgnore + public VipsLogicUser getLastModifiedByUser() { + return lastModifiedByUser; + } + + /** + * @param lastModifiedByUser the lastModifiedByUser to set + */ + public void setLastModifiedByUser(VipsLogicUser lastModifiedByUser) { + this.lastModifiedByUser = lastModifiedByUser; + } + + /** + * @return the locationPointOfInterestId + */ + @Column(name = "location_point_of_interest_id") + public Integer getLocationPointOfInterestId() { + return locationPointOfInterestId; + } + + /** + * @param locationPointOfInterestId the locationPointOfInterestId to set + */ + public void setLocationPointOfInterestId(Integer locationPointOfInterestId) { + this.locationPointOfInterestId = locationPointOfInterestId; + } + + /** + * @return the location + */ + @Transient + public PointOfInterest getLocationPointOfInterest() { + return locationPointOfInterest; + } + + /** + * @param locationPointOfInterest the location to set + */ + public void setLocationPointOfInterest(PointOfInterest locationPointOfInterest) { + this.locationPointOfInterest = locationPointOfInterest; + } + + /** + * @return the locationIsPrivate + */ + @Column(name = "location_is_private") + public Boolean getLocationIsPrivate() { + return locationIsPrivate != null ? locationIsPrivate : false; + } + + /** + * @param locationIsPrivate the locationIsPrivate to set + */ + public void setLocationIsPrivate(Boolean locationIsPrivate) { + this.locationIsPrivate = locationIsPrivate; + } + + /** + * @return the polygon service + */ + @JoinColumn(name = "polygon_service_id", referencedColumnName = "polygon_service_id") + @ManyToOne + public PolygonService getPolygonService() { + return this.polygonService; + } + + /** + * @param polygonService the polygon service to set + */ + public void setPolygonService(PolygonService polygonService) { + this.polygonService = polygonService; + } + + @Override + public int hashCode() { + int hash = 0; + hash += (observationTimeSeriesId != null ? observationTimeSeriesId.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + ObservationTimeSeries that = (ObservationTimeSeries) o; + return observationTimeSeriesId.equals(that.observationTimeSeriesId); + } + + @Override + public String toString() { + return "ObservationTimeSeries{" + + "observationTimeSeriesId=" + observationTimeSeriesId + + ", cropOrganism=" + cropOrganism + + ", organism=" + organism + + ", year=" + year + + ", name='" + name + '\'' + + ", description='" + description + '\'' + + ", created=" + created + + ", userId=" + userId + + ", user=" + user + + ", source=" + source + + ", lastModified=" + lastModified + + ", lastModifiedBy=" + lastModifiedBy + + ", lastModifiedByUser=" + lastModifiedByUser + + ", locationPointOfInterestId=" + locationPointOfInterestId + + ", locationPointOfInterest=" + locationPointOfInterest + + ", locationIsPrivate=" + locationIsPrivate + + ", polygonService=" + polygonService + + '}'; + } + + public int compareTo(ObservationTimeSeries other) { + if (this.getYear() != null && other.getYear() != null) { + return other.getYear().compareTo(this.getYear()); + } + return this.getName().compareTo(other.getName()); + } +} diff --git a/src/main/java/no/nibio/vips/logic/entity/Organism.java b/src/main/java/no/nibio/vips/logic/entity/Organism.java index fa0e0c803796e47c9874318982db90434bdde491..07a86feb80fcd20b790888bc8b746bcf3b8b91e7 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Organism.java +++ b/src/main/java/no/nibio/vips/logic/entity/Organism.java @@ -23,21 +23,21 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResource.java b/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResource.java index 7c2194f05e87a7a6cb214de4f061da020013fb7a..9153293577d6597e7ba7c0aad1df156c7ea6bfc9 100755 --- a/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResource.java +++ b/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResource.java @@ -20,16 +20,16 @@ package no.nibio.vips.logic.entity; import com.fasterxml.jackson.annotation.JsonIgnore; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; diff --git a/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResourcePK.java b/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResourcePK.java index 3f55e08643430c173c82073169518b4bc11f794e..48836b1c2028f59d8b8cd6fdba1815aa8d34ac3a 100755 --- a/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResourcePK.java +++ b/src/main/java/no/nibio/vips/logic/entity/OrganismExternalResourcePK.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/OrganismLocale.java b/src/main/java/no/nibio/vips/logic/entity/OrganismLocale.java index 829e8bb4a2c39e4894e8baffcbdd07b33e76e1e7..6eeefa62592946b0f8565fec98bbcda4888b138e 100755 --- a/src/main/java/no/nibio/vips/logic/entity/OrganismLocale.java +++ b/src/main/java/no/nibio/vips/logic/entity/OrganismLocale.java @@ -19,13 +19,13 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/OrganismLocalePK.java b/src/main/java/no/nibio/vips/logic/entity/OrganismLocalePK.java index 452fb3d89b5118adf78c039be00d2c8fe9738434..a82fe9c718f1e8495cfa2d670d6df7e60cc60965 100755 --- a/src/main/java/no/nibio/vips/logic/entity/OrganismLocalePK.java +++ b/src/main/java/no/nibio/vips/logic/entity/OrganismLocalePK.java @@ -18,11 +18,11 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; /** * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/Organization.java b/src/main/java/no/nibio/vips/logic/entity/Organization.java index 4e5d1bd8be98829b6d203075f4f563e9e030607b..ae079270eabd5a98c9ed984885f84953f056fb1a 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Organization.java +++ b/src/main/java/no/nibio/vips/logic/entity/Organization.java @@ -21,24 +21,24 @@ package no.nibio.vips.logic.entity; import org.locationtech.jts.geom.Point; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; -import javax.persistence.FetchType; -import javax.persistence.OneToOne; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToOne; import org.hibernate.annotations.Type; /** @@ -111,6 +111,21 @@ public class Organization implements Serializable { @OneToOne @JsonIgnore private VipsLogicUser archiveUser; + + @JoinColumn(name = "default_grid_weather_station_data_source_id", referencedColumnName = "weather_station_data_source_id") + @ManyToOne + private WeatherStationDataSource defaultGridWeatherStationDataSource; + + public WeatherStationDataSource getDefaultGridWeatherStationDataSource() { + return defaultGridWeatherStationDataSource; + } + + public void setDefaultGridWeatherStationDataSource(WeatherStationDataSource defaultGridWeatherStationDataSource) { + this.defaultGridWeatherStationDataSource = defaultGridWeatherStationDataSource; + } + + + public Organization() { } diff --git a/src/main/java/no/nibio/vips/logic/entity/OrganizationGroup.java b/src/main/java/no/nibio/vips/logic/entity/OrganizationGroup.java index 9c62dcced809242ecb839d81505171b8452202a7..a015bf6c2f3a1eb705b725f23198e9f2c77e8e35 100755 --- a/src/main/java/no/nibio/vips/logic/entity/OrganizationGroup.java +++ b/src/main/java/no/nibio/vips/logic/entity/OrganizationGroup.java @@ -19,16 +19,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java index 425fd96c1714ce6c81c17694a4ceba28eebca450..f3faa7682359ca1ecf4a8cb5d250f825a32641c7 100755 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterest.java @@ -21,31 +21,31 @@ import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import com.fasterxml.jackson.annotation.JsonIgnore; import org.locationtech.jts.geom.Geometry; import java.util.Set; -import javax.persistence.CascadeType; -import javax.persistence.DiscriminatorType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.FetchType; -import javax.persistence.OneToMany; +import jakarta.persistence.CascadeType; +import jakarta.persistence.DiscriminatorType; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.FetchType; +import jakarta.persistence.OneToMany; import no.nibio.vips.gis.GISUtil; import org.wololo.geojson.Feature; @@ -63,9 +63,9 @@ import org.wololo.geojson.Feature; @NamedQuery(name = "PointOfInterest.findAll", query = "SELECT p FROM PointOfInterest p ORDER BY p.name ASC"), @NamedQuery(name = "PointOfInterest.findByPointOfInterestId", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestId = :pointOfInterestId"), @NamedQuery(name = "PointOfInterest.findByPointOfInterestIds", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestId IN :pointOfInterestIds"), - @NamedQuery(name = "PointOfInterest.findByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) ORDER BY p.name ASC"), - @NamedQuery(name = "PointOfInterest.findByOrganizationIdAndPoiTypes", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestTypeId in :pointOfInterestTypes AND p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) ORDER BY p.name ASC"), - @NamedQuery(name = "PointOfInterest.findForecastLocationsByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.isForecastLocation IS TRUE AND p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId OR u.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) ORDER BY p.name ASC"), + @NamedQuery(name = "PointOfInterest.findByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.user.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId = :organizationId OR u.organizationId.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) ORDER BY p.name ASC"), + @NamedQuery(name = "PointOfInterest.findByOrganizationIdAndPoiTypes", query = "SELECT p FROM PointOfInterest p WHERE p.pointOfInterestTypeId in :pointOfInterestTypes AND p.user.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId = :organizationId OR u.organizationId.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) ORDER BY p.name ASC"), + @NamedQuery(name = "PointOfInterest.findForecastLocationsByOrganizationId", query = "SELECT p FROM PointOfInterest p WHERE p.isForecastLocation IS TRUE AND p.user.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId = :organizationId OR u.organizationId.organizationId IN (SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)) ORDER BY p.name ASC"), @NamedQuery(name = "PointOfInterest.findByName", query = "SELECT p FROM PointOfInterest p WHERE p.name = :name"), @NamedQuery(name = "PointOfInterest.findByNameCaseInsensitive", query = "SELECT p FROM PointOfInterest p WHERE lower(p.name) = lower(:name)"), @NamedQuery(name = "PointOfInterest.findByUserId", query = "SELECT p FROM PointOfInterest p WHERE p.user = :userId ORDER BY p.name ASC") @@ -91,8 +91,17 @@ public class PointOfInterest implements Serializable, Comparable { private Boolean isForecastLocation; private Integer pointOfInterestTypeId; private Date lastEditedTime; + private Boolean isPrivate; - + @Column(name = "is_private") + public Boolean getIsPrivate() { + return isPrivate; + } + + public void setIsPrivate(Boolean isPrivate) { + this.isPrivate = isPrivate; + } + // For attaching ad-hoc properties // e.g. Worst warning for map private Map<String, Object> properties; @@ -132,7 +141,7 @@ public class PointOfInterest implements Serializable, Comparable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Basic(optional = false) - @Column(name = "point_of_interest_id") + @Column(name = "point_of_interest_id", insertable = false, updatable = false) public Integer getPointOfInterestId() { return pointOfInterestId; } @@ -276,6 +285,10 @@ public class PointOfInterest implements Serializable, Comparable { { this.properties.put("pointOfInterestTypeId", this.getPointOfInterestTypeId()); } + if(this.properties.get("pointOfInterestName") == null) + { + this.properties.put("pointOfInterestName", this.getName()); + } return this.properties; } diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResource.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResource.java index e3dae66c90e61ddbadc970510372b9ec74f05af5..2bff2efe2e2c4f60911556a955c1feb132e1ca88 100755 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResource.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResource.java @@ -20,17 +20,17 @@ package no.nibio.vips.logic.entity; import com.fasterxml.jackson.annotation.JsonIgnore; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResourcePK.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResourcePK.java index 627ae3c98898aa6bb9114f09a7ab0ac92e514197..979d1ac6db7dea7ab38a0d377fca6026e8a3e139 100755 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResourcePK.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestExternalResourcePK.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java index 834fd4ecba952f50bc62a2a1df34192d987b5eab..5d1f4da6ad552f7466bb6cf309e1e8965aa980ce 100755 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestType.java @@ -19,18 +19,18 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorColumn; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Inheritance; +import jakarta.persistence.InheritanceType; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** @@ -52,7 +52,7 @@ public class PointOfInterestType implements Serializable { @Id @Basic(optional = false) @NotNull - @Column(name = "point_of_interest_type_id") + @Column(name = "point_of_interest_type_id", insertable = false, updatable = false) private Integer pointOfInterestTypeId; @Size(max = 255) @Column(name = "default_name") diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java index b89fc8c0b1a09cb1e3663fd7ba5da886445d4614..c5bd42d1e2dc72b269d8867154cd704c628dc324 100644 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeApiarySite.java @@ -19,9 +19,9 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Table; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; /** * @copyright 2023 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeFarm.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeFarm.java index 377f09902a7fb318a8fc4fb071cfdde6e9ae1440..03a7df7bc1146a8151c02d91f7b06ff18079e8ec 100644 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeFarm.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeFarm.java @@ -19,9 +19,9 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Table; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; /** * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeField.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeField.java index 5e9c40c04af9d4f02432594ea10795b4b4367657..7954cee2a1b6eac35cad6cf3165a3bde7ffd6c97 100644 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeField.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeField.java @@ -19,9 +19,9 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Table; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; /** * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java index bcc4945c32ac0f8094734d65950c469abc7d9256..c67cc749f5ce43c11d9f2fa26b99e4700457c1c2 100644 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeNursery.java @@ -19,9 +19,9 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Table; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; /** * @copyright 2023 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeRegion.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeRegion.java index 42293401653e5134c28bc0c95b02b57c84ceb359..279bb5eb71a59003efc23e69e1716eac0f9e6ef8 100644 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeRegion.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeRegion.java @@ -19,9 +19,9 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Table; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; /** * @copyright 2018 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeTrap.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeTrap.java index e9a62eaa503b7a17eb2a9de9e8330a6c3db74ccc..146eaa68d9fbed5d0e9c2c633ad3cb30d22de9f2 100644 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeTrap.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestTypeTrap.java @@ -18,9 +18,9 @@ package no.nibio.vips.logic.entity; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.Table; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.Table; import java.io.Serializable; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestWeatherStation.java b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestWeatherStation.java index e4d820273d132e0056e31a0c9276d31726c2baf5..9be891c706733200239a3100a417bd5f71cbb5ba 100755 --- a/src/main/java/no/nibio/vips/logic/entity/PointOfInterestWeatherStation.java +++ b/src/main/java/no/nibio/vips/logic/entity/PointOfInterestWeatherStation.java @@ -19,19 +19,19 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.DiscriminatorValue; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.DiscriminatorValue; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import com.fasterxml.jackson.annotation.JsonIgnore; -import javax.persistence.Transient; +import jakarta.persistence.Transient; /** * Extension of {@see PointOfInterest}, with additional info for weather stations @@ -46,12 +46,12 @@ import javax.persistence.Transient; @NamedQuery(name = "PointOfInterestWeatherStation.findAll", query = "SELECT p FROM PointOfInterestWeatherStation p"), @NamedQuery(name = "PointOfInterestWeatherStation.findAllByActivity", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.active = :active"), @NamedQuery(name = "PointOfInterestWeatherStation.findByPointOfInterestId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.pointOfInterestId = :pointOfInterestId"), - @NamedQuery(name = "PointOfInterestWeatherStation.findByOrganizationId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId)"), - @NamedQuery(name = "PointOfInterestWeatherStation.findByActivityAndOrganizationId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.active = :active AND p.user IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId=:organizationId)"), + @NamedQuery(name = "PointOfInterestWeatherStation.findByOrganizationId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.user.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId.organizationId = :organizationId)"), + @NamedQuery(name = "PointOfInterestWeatherStation.findByActivityAndOrganizationId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.active = :active AND p.user.userId IN(SELECT u.userId FROM VipsLogicUser u WHERE u.organizationId = :organizationId)"), @NamedQuery(name = "PointOfInterestWeatherStation.findByUserId", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.user = :userId"), @NamedQuery(name = "PointOfInterestWeatherStation.findByNames", query = "SELECT p FROM PointOfInterestWeatherStation p WHERE p.name IN :names") }) -public class PointOfInterestWeatherStation extends PointOfInterest implements Serializable { +public class PointOfInterestWeatherStation extends PointOfInterest { @Size(max = 255) private String weatherStationRemoteId; private WeatherStationDataSource weatherStationDataSourceId; diff --git a/src/main/java/no/nibio/vips/logic/entity/PolygonService.java b/src/main/java/no/nibio/vips/logic/entity/PolygonService.java index 9097f946729c6df274f1d212775c3e6d750e35d5..1c5e06694a384708a67b57786d19002b5a10743a 100644 --- a/src/main/java/no/nibio/vips/logic/entity/PolygonService.java +++ b/src/main/java/no/nibio/vips/logic/entity/PolygonService.java @@ -19,16 +19,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/Preparation.java b/src/main/java/no/nibio/vips/logic/entity/Preparation.java index 428b7c3bd27c73abb196f7c6fa8a015681a1f429..92beeb811c2c8d15a027ac3a24266e0f1a481b90 100755 --- a/src/main/java/no/nibio/vips/logic/entity/Preparation.java +++ b/src/main/java/no/nibio/vips/logic/entity/Preparation.java @@ -20,18 +20,18 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.math.BigInteger; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/PreparationType.java b/src/main/java/no/nibio/vips/logic/entity/PreparationType.java index 48ca4c65f1c0841cd1c01b006e119de9291750f3..393444e8482303f3f450cec11c1d5cdb388db4f2 100755 --- a/src/main/java/no/nibio/vips/logic/entity/PreparationType.java +++ b/src/main/java/no/nibio/vips/logic/entity/PreparationType.java @@ -21,16 +21,16 @@ package no.nibio.vips.logic.entity; import com.fasterxml.jackson.annotation.JsonIgnore; import java.io.Serializable; import java.util.Collection; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; diff --git a/src/main/java/no/nibio/vips/logic/entity/TaskHistory.java b/src/main/java/no/nibio/vips/logic/entity/TaskHistory.java index 1fcc220c51e323d12cb37a1953dceb951c8811a0..853526d63ef15bde78e9c51198ffc3a51842b64f 100755 --- a/src/main/java/no/nibio/vips/logic/entity/TaskHistory.java +++ b/src/main/java/no/nibio/vips/logic/entity/TaskHistory.java @@ -20,20 +20,20 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/TaskHistoryStatus.java b/src/main/java/no/nibio/vips/logic/entity/TaskHistoryStatus.java index 2a81d1de8cfdf2dd396654506501c39e0c7b09b9..7d9731e69002c559240f3fbcc6dfbc100ef9e8ab 100755 --- a/src/main/java/no/nibio/vips/logic/entity/TaskHistoryStatus.java +++ b/src/main/java/no/nibio/vips/logic/entity/TaskHistoryStatus.java @@ -20,16 +20,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/UserAuthentication.java b/src/main/java/no/nibio/vips/logic/entity/UserAuthentication.java index 11632649f3c16e096da3adcabcb037927a761237..4de3cf78c90465bcfde12189aeb5d2a979ec6e6e 100755 --- a/src/main/java/no/nibio/vips/logic/entity/UserAuthentication.java +++ b/src/main/java/no/nibio/vips/logic/entity/UserAuthentication.java @@ -20,17 +20,17 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationPK.java b/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationPK.java index dd4fbbf51ba041a89371bed534bbf42f2e46939d..bffab63e2cf5bfdf49541818b6a83f5ff6f92222 100755 --- a/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationPK.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationType.java b/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationType.java index e1a66461c4ecc39d963b3e699e0e3ac942f5ce1b..2b3c981aaca5942c475e3015e01d0bf8770ae1ae 100755 --- a/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationType.java +++ b/src/main/java/no/nibio/vips/logic/entity/UserAuthenticationType.java @@ -20,17 +20,17 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; diff --git a/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterest.java b/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterest.java index 0b8a59966b3abc96fff894676a8a739cfcb91129..9e5acd71285e4a85153571de2d2b0fc56b4ee749 100755 --- a/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterest.java +++ b/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterest.java @@ -19,13 +19,13 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterestPK.java b/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterestPK.java index 6f34d94d713179943dd8cce3ea6f4a0ec01d5310..ffdc59ff1c242845b3639dc2ff3c77c4c084eeb6 100755 --- a/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterestPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/UserPointOfInterestPK.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2013 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/entity/UserUuid.java b/src/main/java/no/nibio/vips/logic/entity/UserUuid.java index 539f0c28d4bbd22b78a1f0cae191683fca2942d6..20725773ef46e22348bc1f18ad17f2b621e35413 100755 --- a/src/main/java/no/nibio/vips/logic/entity/UserUuid.java +++ b/src/main/java/no/nibio/vips/logic/entity/UserUuid.java @@ -21,14 +21,14 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Date; import java.util.UUID; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java b/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java index 9168cdfb5975ed16ce379896cea825c02d4f9430..0b08ba1cba7185a7148f965a515d1b51144f6df2 100755 --- a/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java +++ b/src/main/java/no/nibio/vips/logic/entity/UserUuidPK.java @@ -20,10 +20,12 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.UUID; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> @@ -34,7 +36,7 @@ public class UserUuidPK implements Serializable { @Basic(optional = false) @NotNull @Column(name = "user_uuid") - @org.hibernate.annotations.Type(type="pg-uuid") // Ugly implementation specific hack + @JdbcTypeCode(SqlTypes.UUID) private UUID userUuid; @Basic(optional = false) @NotNull diff --git a/src/main/java/no/nibio/vips/logic/entity/VipsCoreInstance.java b/src/main/java/no/nibio/vips/logic/entity/VipsCoreInstance.java index 81808efcf0cb1e761d57ea3892a8bff631766be4..d7ecef921fbb088c1b11e30b6bac269b3134faec 100755 --- a/src/main/java/no/nibio/vips/logic/entity/VipsCoreInstance.java +++ b/src/main/java/no/nibio/vips/logic/entity/VipsCoreInstance.java @@ -19,8 +19,8 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.*; -import javax.validation.constraints.Size; +import jakarta.persistence.*; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java b/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java index 5aaee47188e3f7de922c0cc0152be15954eef7cb..8aa56169278ea9dfd70da27c319a36c5dcce97f0 100755 --- a/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java +++ b/src/main/java/no/nibio/vips/logic/entity/VipsLogicRole.java @@ -19,15 +19,15 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** @@ -127,7 +127,9 @@ public class VipsLogicRole implements Serializable { @Override public String toString() { - return "no.nibio.vips.logic.entity.VipslogicRole[ vipslogicRoleId=" + vipsLogicRoleId + " ]"; + return "VipsLogicRole{" + + "vipsLogicRoleId=" + vipsLogicRoleId + + ", defaultTitle='" + defaultTitle + '\'' + + '}'; } - } diff --git a/src/main/java/no/nibio/vips/logic/entity/VipsLogicUser.java b/src/main/java/no/nibio/vips/logic/entity/VipsLogicUser.java index c8d96e9477c78f3cac0cb482c7168e210f084eb1..6e7c51bea32add98029d8f665cb222f5b7353027 100755 --- a/src/main/java/no/nibio/vips/logic/entity/VipsLogicUser.java +++ b/src/main/java/no/nibio/vips/logic/entity/VipsLogicUser.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2019 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2015-2019 NIBIO <http://www.nibio.no/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -19,25 +19,25 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Pattern; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.JoinTable; +import jakarta.persistence.ManyToMany; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Pattern; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import com.fasterxml.jackson.annotation.JsonIgnore; @@ -54,7 +54,7 @@ import java.util.UUID; @NamedQuery(name = "VipsLogicUser.findAll", query = "SELECT v FROM VipsLogicUser v"), @NamedQuery(name = "VipsLogicUser.findByUserId", query = "SELECT v FROM VipsLogicUser v WHERE v.userId = :userId"), @NamedQuery(name = "VipsLogicUser.findByUserIds", query = "SELECT v FROM VipsLogicUser v WHERE v.userId IN :userIds"), - @NamedQuery(name = "VipsLogicUser.findByOrganizationId", query = "SELECT v FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)"), + @NamedQuery(name = "VipsLogicUser.findByOrganizationId", query = "SELECT v FROM VipsLogicUser v WHERE v.organizationId = :organizationId OR v.organizationId.organizationId IN(SELECT o.organizationId FROM Organization o WHERE o.parentOrganizationId = :organizationId)"), @NamedQuery(name = "VipsLogicUser.findByOrganizationIds", query = "SELECT v FROM VipsLogicUser v WHERE v.organizationId.organizationId IN (:organizationIds)"), @NamedQuery(name = "VipsLogicUser.findByEmail", query = "SELECT v FROM VipsLogicUser v WHERE v.email = :email"), @NamedQuery(name = "VipsLogicUser.findByEmailVerificationCode", query = "SELECT v FROM VipsLogicUser v WHERE v.emailVerificationCode = :emailVerificationCode"), @@ -63,7 +63,7 @@ import java.util.UUID; @NamedQuery(name = "VipsLogicUser.findByCompletePhoneNumber", query = "SELECT v FROM VipsLogicUser v WHERE v.phoneCountryCode || v.phone = :completePhoneNumber") }) public class VipsLogicUser implements Serializable, Comparable{ - + private static final long serialVersionUID = 1L; private Integer userId; //if the field contains email address consider using this annotation to enforce field validation @@ -93,7 +93,7 @@ public class VipsLogicUser implements Serializable, Comparable{ private Integer vipsCoreUserId; private boolean approvesSmsBilling; private boolean freeSms; - + private UUID userUuid; public VipsLogicUser() { @@ -143,6 +143,12 @@ public class VipsLogicUser implements Serializable, Comparable{ this.lastName = lastName; } + @JsonIgnore + @Transient + public String getFullName() { + return firstName + " " + lastName; + } + @OneToMany(cascade = CascadeType.ALL, mappedBy = "vipsLogicUser", fetch=FetchType.EAGER) @XmlTransient @JsonIgnore @@ -160,7 +166,7 @@ public class VipsLogicUser implements Serializable, Comparable{ public Organization getOrganizationId() { return organizationId; } - + @Transient public Integer getOrganization_id(){ return organizationId.getOrganizationId(); @@ -249,11 +255,11 @@ public class VipsLogicUser implements Serializable, Comparable{ @ManyToMany(fetch = FetchType.EAGER) @JsonIgnore @JoinTable( - name = "user_vips_logic_role", - joinColumns = { - @JoinColumn(name = "user_id")}, - inverseJoinColumns = { - @JoinColumn(name = "vips_logic_role_id")} + name = "user_vips_logic_role", + joinColumns = { + @JoinColumn(name = "user_id")}, + inverseJoinColumns = { + @JoinColumn(name = "vips_logic_role_id")} ) public Set<VipsLogicRole> getVipsLogicRoles() { return vipsLogicRoles; @@ -287,7 +293,7 @@ public class VipsLogicUser implements Serializable, Comparable{ } return false; } - + @JsonIgnore @Transient public boolean isObservationAuthority(){ @@ -298,7 +304,7 @@ public class VipsLogicUser implements Serializable, Comparable{ } return false; } - + @JsonIgnore @Transient public boolean isOrganismEditor() { @@ -309,7 +315,7 @@ public class VipsLogicUser implements Serializable, Comparable{ } return false; } - + @JsonIgnore @Transient public boolean isAppleFruitMothAdministrator(){ @@ -320,7 +326,7 @@ public class VipsLogicUser implements Serializable, Comparable{ } return false; } - + @JsonIgnore @Transient public boolean isMessageAuthor(){ @@ -499,7 +505,7 @@ public class VipsLogicUser implements Serializable, Comparable{ public boolean isFreeSms() { return freeSms; } - + /** * @param freeSms the freeSms to set @@ -513,6 +519,6 @@ public class VipsLogicUser implements Serializable, Comparable{ VipsLogicUser other = (VipsLogicUser)o; return (this.getLastName() + ", " + this.getFirstName()).compareTo(other.getLastName() + ", " + other.getFirstName()); } - - + + } diff --git a/src/main/java/no/nibio/vips/logic/entity/WeatherForecastProvider.java b/src/main/java/no/nibio/vips/logic/entity/WeatherForecastProvider.java index f2f1ae2479a94ee6ecb5059a2ef635913b518f05..56788fa28f346e7a582741299cc7207a6bff42d4 100755 --- a/src/main/java/no/nibio/vips/logic/entity/WeatherForecastProvider.java +++ b/src/main/java/no/nibio/vips/logic/entity/WeatherForecastProvider.java @@ -19,15 +19,15 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/entity/WeatherStationDataSource.java b/src/main/java/no/nibio/vips/logic/entity/WeatherStationDataSource.java index 9fe247f205036fd792eebe65ab0e6342a2625510..54c5720f89a9dc796aef5faa0e92de41218dbf17 100755 --- a/src/main/java/no/nibio/vips/logic/entity/WeatherStationDataSource.java +++ b/src/main/java/no/nibio/vips/logic/entity/WeatherStationDataSource.java @@ -19,16 +19,16 @@ package no.nibio.vips.logic.entity; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** @@ -40,6 +40,7 @@ import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement @NamedQueries({ @NamedQuery(name = "WeatherStationDataSource.findAll", query = "SELECT w FROM WeatherStationDataSource w"), + @NamedQuery(name = "WeatherStationDataSource.findGridSources", query = "SELECT w FROM WeatherStationDataSource w WHERE w.isGrid IS TRUE"), @NamedQuery(name = "WeatherStationDataSource.findByWeatherStationDataSourceId", query = "SELECT w FROM WeatherStationDataSource w WHERE w.weatherStationDataSourceId = :weatherStationDataSourceId"), @NamedQuery(name = "WeatherStationDataSource.findByName", query = "SELECT w FROM WeatherStationDataSource w WHERE w.name = :name"), @NamedQuery(name = "WeatherStationDataSource.findByDefaultDescription", query = "SELECT w FROM WeatherStationDataSource w WHERE w.defaultDescription = :defaultDescription"), @@ -68,6 +69,18 @@ public class WeatherStationDataSource implements Serializable { @Size(max = 1024) @Column(name = "info_uri_expression") private String infoUriExpression; + @Column(name = "is_grid") + private Boolean isGrid; + + + + public Boolean getIsGrid() { + return isGrid; + } + + public void setIsGrid(Boolean isGrid) { + this.isGrid = isGrid; + } public WeatherStationDataSource() { } diff --git a/src/main/java/no/nibio/vips/logic/entity/helpers/KmlMessageBodyWriter.java b/src/main/java/no/nibio/vips/logic/entity/helpers/KmlMessageBodyWriter.java new file mode 100644 index 0000000000000000000000000000000000000000..1c94212d6aae477392ccdbb8554c866c01eea8ad --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/entity/helpers/KmlMessageBodyWriter.java @@ -0,0 +1,32 @@ +package no.nibio.vips.logic.entity.helpers; + +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.ext.Provider; +import jakarta.ws.rs.ext.MessageBodyWriter; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.MultivaluedMap; +import java.lang.annotation.Annotation; +import java.lang.reflect.Type; +import java.io.OutputStream; +import java.io.IOException; +import de.micromata.opengis.kml.v_2_2_0.Kml; + +@Provider +@Produces("application/vnd.google-earth.kml+xml") +public class KmlMessageBodyWriter implements MessageBodyWriter<Kml> { + + @Override + public boolean isWriteable(Class<?> type, Type genericType, + Annotation[] annotations, MediaType mediaType) { + return Kml.class.isAssignableFrom(type); + } + + @Override + public void writeTo(Kml kml, Class<?> type, Type genericType, Annotation[] annotations, + MediaType mediaType, MultivaluedMap<String, Object> httpHeaders, + OutputStream entityStream) throws IOException { + kml.marshal(entityStream); + } + + // Implement other MessageBodyWriter methods as needed +} diff --git a/src/main/java/no/nibio/vips/logic/entity/rest/ObservationListItem.java b/src/main/java/no/nibio/vips/logic/entity/rest/ObservationListItem.java index feda7d0be7fcecf280cb0b1f455844a7063d75d9..95d83c07dfcc4494d8fbc4022afebdff8fbb58aa 100644 --- a/src/main/java/no/nibio/vips/logic/entity/rest/ObservationListItem.java +++ b/src/main/java/no/nibio/vips/logic/entity/rest/ObservationListItem.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -26,12 +26,18 @@ import no.nibio.vips.observationdata.ObservationDataSchema; * @copyright 2018 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ -public class ObservationListItem { - private Integer observationId, organismId, cropOrganismId; +public class ObservationListItem implements Comparable{ + private Integer observationId, observationTimeSeriesId, organismId, cropOrganismId; + private Integer observerId; + private String observerName; private Date timeOfObservation; private String organismName, cropOrganismName; + private String observationTimeSeriesLabel; + private Integer locationPointOfInterestId; + private String locationPointOfInterestName; private String geoInfo; private String observationHeading; + private String observationText; private String observationData; private ObservationDataSchema observationDataSchema; private Boolean broadcastMessage; @@ -39,35 +45,59 @@ public class ObservationListItem { private Boolean isPositive; public ObservationListItem( - Integer observationId, - Date timeOfObservation, - Integer organismId, - String organismName, - Integer cropOrganismId, - String cropOrganismName, - String geoinfo, - String observationHeading, - Boolean broadcastMessage, - Boolean locationIsPrivate, - Boolean isPositive, - String observationData, - ObservationDataSchema observationDataSchema - ){ + Integer observationId, + Integer observerId, + String observerName, + Integer observationTimeSeriesId, + Date timeOfObservation, + Integer organismId, + String organismName, + Integer cropOrganismId, + String cropOrganismName, + String observationTimeSeriesLabel, + Integer poiId, + String poiName, + String geoinfo, + String observationHeading, + String observationText, + Boolean broadcastMessage, + Boolean locationIsPrivate, + Boolean isPositive, + String observationData, + ObservationDataSchema observationDataSchema){ this.observationId = observationId; + this.observerId = observerId; + this.observerName = observerName; + this.observationTimeSeriesId = observationTimeSeriesId; this.timeOfObservation = timeOfObservation; this.organismId = organismId; this.organismName = organismName; this.cropOrganismId = cropOrganismId; this.cropOrganismName = cropOrganismName; + this.observationTimeSeriesLabel = observationTimeSeriesLabel; + this.locationPointOfInterestId = poiId; + this.locationPointOfInterestName = poiName; this.geoInfo = geoinfo; this.observationHeading = observationHeading; + this.observationText = observationText; this.broadcastMessage = broadcastMessage; this.locationIsPrivate = locationIsPrivate; this.isPositive = isPositive; this.observationData = observationData; this.observationDataSchema = observationDataSchema; } - + + + @Override + public int compareTo(Object otherOne) + { + if(! (otherOne instanceof ObservationListItem)) + { + return 0; + } + return this.getTimeOfObservation().compareTo(((ObservationListItem) otherOne).getTimeOfObservation()); + } + /** * @return the observationId */ @@ -82,6 +112,48 @@ public class ObservationListItem { this.observationId = observationId; } + /** + * @return The ID of the observer + */ + public Integer getObserverId() { + return observerId; + } + + /** + * @param observerId The ID to set + */ + public void setObserverId(Integer observerId) { + this.observerId = observerId; + } + + /** + * @return The full name of the observer + */ + public String getObserverName() { + return observerName; + } + + /** + * @param observerName The observer name to set + */ + public void setObserverName(String observerName) { + this.observerName = observerName; + } + + /** + * @return the observationTimeSeriesId + */ + public Integer getObservationTimeSeriesId() { + return observationTimeSeriesId; + } + + /** + * @param observationTimeSeriesId the observationTimeSeriesId to set + */ + public void setObservationTimeSeriesId(Integer observationTimeSeriesId) { + this.observationTimeSeriesId = observationTimeSeriesId; + } + /** * @return the timeOfObservation */ @@ -124,6 +196,30 @@ public class ObservationListItem { this.cropOrganismName = cropOrganismName; } + public String getObservationTimeSeriesLabel() { + return observationTimeSeriesLabel; + } + + public void setObservationTimeSeriesLabel(String observationTimeSeriesLabel) { + this.observationTimeSeriesLabel = observationTimeSeriesLabel; + } + + public Integer getLocationPointOfInterestId() { + return locationPointOfInterestId; + } + + public void setLocationPointOfInterestId(Integer locationPointOfInterestId) { + this.locationPointOfInterestId = locationPointOfInterestId; + } + + public String getLocationPointOfInterestName() { + return locationPointOfInterestName; + } + + public void setLocationPointOfInterestName(String locationPointOfInterestName) { + this.locationPointOfInterestName = locationPointOfInterestName; + } + /** * @return the geoInfo */ @@ -152,6 +248,20 @@ public class ObservationListItem { this.observationHeading = observationHeading; } + /** + * @return the observation text + */ + public String getObservationText() { + return observationText; + } + + /** + * @param observationText The observation text to set + */ + public void setObservationText(String observationText) { + this.observationText = observationText; + } + /** * @return the organismId */ diff --git a/src/main/java/no/nibio/vips/logic/gis/GeometryEntity.java b/src/main/java/no/nibio/vips/logic/gis/GeometryEntity.java index a996188d93a37656b34c4a745ba33f626a01fde3..4ebbca82007875f308332efc0630e16222f69bf1 100755 --- a/src/main/java/no/nibio/vips/logic/gis/GeometryEntity.java +++ b/src/main/java/no/nibio/vips/logic/gis/GeometryEntity.java @@ -20,11 +20,11 @@ package no.nibio.vips.logic.gis; import org.locationtech.jts.geom.Geometry; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; import org.hibernate.annotations.Type; /** diff --git a/src/main/java/no/nibio/vips/logic/i18n/CharacterEncodingFilter.java b/src/main/java/no/nibio/vips/logic/i18n/CharacterEncodingFilter.java index ff1f0cc71914368d648141e6e038dd62c4b32c63..0d11b22209384e7f959494a994e69fc10f18f8a1 100755 --- a/src/main/java/no/nibio/vips/logic/i18n/CharacterEncodingFilter.java +++ b/src/main/java/no/nibio/vips/logic/i18n/CharacterEncodingFilter.java @@ -19,12 +19,12 @@ package no.nibio.vips.logic.i18n; import java.io.IOException; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; /** * <p> diff --git a/src/main/java/no/nibio/vips/logic/i18n/LocalizationFilter.java b/src/main/java/no/nibio/vips/logic/i18n/LocalizationFilter.java index b320d3a38e11cb88670290c1ff9b39e491590445..db56f94230ee1657b86ef11187091b2d756eded2 100755 --- a/src/main/java/no/nibio/vips/logic/i18n/LocalizationFilter.java +++ b/src/main/java/no/nibio/vips/logic/i18n/LocalizationFilter.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -20,18 +20,19 @@ package no.nibio.vips.logic.i18n; import com.ibm.icu.util.ULocale; import java.io.IOException; -import java.util.Arrays; +import java.util.HashMap; import java.util.List; -import static java.util.stream.Collectors.toList; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; +import java.util.Locale; +import java.util.Map; + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; import no.nibio.vips.i18n.LanguageUtil; -import no.nibio.vips.logic.util.SystemTime; /** * This filter checks if there are any changes in locale requests, and @@ -43,11 +44,17 @@ import no.nibio.vips.logic.util.SystemTime; public class LocalizationFilter implements Filter{ private List<ULocale> availableLocales; + private static final Map<String, String> LOCALE_MAPPING = new HashMap<>(); + static { + LOCALE_MAPPING.put("no", "nb"); + LOCALE_MAPPING.put("nn", "nb"); + } + @Override public void init(FilterConfig filterConfig) throws ServletException { - + this.availableLocales = LanguageUtil.getAvailableLocalesWithDistinctLanguage(); - + } @Override @@ -63,17 +70,17 @@ public class LocalizationFilter implements Filter{ }*/ ULocale currentLocale = SessionLocaleUtil.getCurrentLocale((HttpServletRequest)request); - ULocale browserRequestedLocale = ULocale.forLocale(((HttpServletRequest)request).getLocale()); - String userRequestedLocaleStr = ((HttpServletRequest)request).getParameter("userRequestedLocale"); + ULocale browserRequestedLocale = getBrowserRequestedLocale(request); + String userRequestedLocaleStr = request.getParameter("userRequestedLocale"); ULocale userRequestedLocale = userRequestedLocaleStr != null ? new ULocale(userRequestedLocaleStr) : null; - - /* - * If currentLocale is not set, use either userRequestedLocale (1st priority) + + /* + * If currentLocale is not set, use either userRequestedLocale (1st priority) * or browserRequestedLocale (2nd priority) or JVM's default locale (fallback) - */ + */ if(currentLocale == null) { - SessionLocaleUtil.setCurrentLocale((HttpServletRequest)request, userRequestedLocale != null ? userRequestedLocale : browserRequestedLocale != null ? browserRequestedLocale : ULocale.getDefault()); + SessionLocaleUtil.setCurrentLocale((HttpServletRequest)request, userRequestedLocale != null ? userRequestedLocale : browserRequestedLocale != null ? browserRequestedLocale : ULocale.getDefault()); } /* * If userRequestedLocale is set and differs from current, activate it @@ -100,22 +107,42 @@ public class LocalizationFilter implements Filter{ } } } - + // Set the available locales - ((HttpServletRequest)request).getSession().setAttribute("availableLocales", this.availableLocales); - + ((HttpServletRequest)request).getSession().setAttribute("availableLocales", this.availableLocales); + // We always make the system time available for FreeMarker templates //request.setAttribute("systemTime", SystemTime.getSystemTime()); - + chain.doFilter(request, response); - + + } + + /** + * Get locale from request. Map from unsupported 'no' and 'nn', to 'nb'. + * If locale or language is null or blank, null is returned. + * + * @param request The request from which to get the locale + * @return A locale which is supported by the system, or null + */ + private static ULocale getBrowserRequestedLocale(ServletRequest request) { + Locale requestLocale = request.getLocale(); + if (requestLocale == null) { + return null; + } + ULocale locale = ULocale.forLocale(requestLocale); + String language = locale.getLanguage(); + if(language == null || language.isBlank()) { + return null; + } + String mappedLanguage = LOCALE_MAPPING.getOrDefault(language, language); + return new ULocale(mappedLanguage); } - @Override public void destroy() { - + } - + } diff --git a/src/main/java/no/nibio/vips/logic/i18n/ResourceBundleJSServlet.java b/src/main/java/no/nibio/vips/logic/i18n/ResourceBundleJSServlet.java index 25108073db07c68a317ec8918765619c7430eb1e..2db6aec757ad4fc1448e35627b163a9372581317 100755 --- a/src/main/java/no/nibio/vips/logic/i18n/ResourceBundleJSServlet.java +++ b/src/main/java/no/nibio/vips/logic/i18n/ResourceBundleJSServlet.java @@ -21,10 +21,10 @@ package no.nibio.vips.logic.i18n; import java.io.IOException; import java.io.PrintWriter; import java.util.ResourceBundle; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import org.apache.commons.lang.StringEscapeUtils; /** diff --git a/src/main/java/no/nibio/vips/logic/i18n/SessionLocaleUtil.java b/src/main/java/no/nibio/vips/logic/i18n/SessionLocaleUtil.java index 9b7ea1ef44bb669058dafc7956ff7bafaa066207..2b15ec0bb74ec91b795c988c11e50ed4527bee54 100755 --- a/src/main/java/no/nibio/vips/logic/i18n/SessionLocaleUtil.java +++ b/src/main/java/no/nibio/vips/logic/i18n/SessionLocaleUtil.java @@ -20,7 +20,7 @@ package no.nibio.vips.logic.i18n; import com.ibm.icu.util.ULocale; import java.util.ResourceBundle; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletRequest; /** * Presents a uniform way of getting locale information diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java index 35b6c5326732431b657812da9f39eb3995f77174..d4400138af1918a022a997eba962fc19ab4247e0 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastEvent.java @@ -19,15 +19,15 @@ package no.nibio.vips.logic.messaging; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java index 157953ea0393c5cc3bdd972b7433c9e5ba5f1d21..7849d587f49ad94be84436ff16759302c55e08fc 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastEventNotificationSubscription.java @@ -19,15 +19,13 @@ package no.nibio.vips.logic.messaging; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import no.nibio.vips.logic.util.IntegerArrayUserType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -35,7 +33,6 @@ import org.hibernate.annotations.TypeDefs; */ @Entity @Table(name = "forecast_event_notification_subscription", schema = "messaging") -@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) public class ForecastEventNotificationSubscription { @Id @@ -46,13 +43,13 @@ public class ForecastEventNotificationSubscription { @Column(name = "universal_message_format_id") private Integer universalMessageFormatId; - @Type(type = "IntegerArray") + @Type(ListArrayType.class) @Column(name = "weather_station_ids") - private Integer[] weatherStationIds; + private List<Integer> weatherStationIds; - @Type(type = "IntegerArray") + @Type(ListArrayType.class) @Column(name = "crop_category_ids") - private Integer[] cropCategoryIds; + private List<Integer> cropCategoryIds; /** * @return the userId @@ -85,42 +82,29 @@ public class ForecastEventNotificationSubscription { /** * @return the weatherStationIds */ - public Integer[] getWeatherStationIds() { + public List<Integer> getWeatherStationIds() { return weatherStationIds; } /** * @param weatherStationIds the weatherStationIds to set */ - public void setWeatherStationIds(Integer[] weatherStationIds) { + public void setWeatherStationIds(List<Integer> weatherStationIds) { this.weatherStationIds = weatherStationIds; } - /** - * Convenience method - * @param weatherStationIds - */ - public void setWeatherStationIds(List<Integer> weatherStationIds) - { - this.weatherStationIds = weatherStationIds.toArray(new Integer[weatherStationIds.size()]); - } /** * @return the cropCategoryIds */ - public Integer[] getCropCategoryIds() { + public List<Integer> getCropCategoryIds() { return cropCategoryIds; } /** * @param cropCategoryIds the cropCategoryIds to set */ - public void setCropCategoryIds(Integer[] cropCategoryIds) { + public void setCropCategoryIds(List<Integer> cropCategoryIds) { this.cropCategoryIds = cropCategoryIds; } - - public void setCropCategoryIds(List<Integer> cropCategoryIds) - { - this.cropCategoryIds = cropCategoryIds.toArray(new Integer[cropCategoryIds.size()]); - } } diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java index dac54b75e5cda6e610bb34cd346c8327e31db433..63617d2780dac5246f85a7a6f3b4eed50bfa2f9d 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLog.java @@ -20,14 +20,14 @@ package no.nibio.vips.logic.messaging; import java.io.Serializable; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java index 083328eeb867d2344a86f3d5029633036ef53565..435c12e8de616eb8f53757918e7c70d1f5742ff0 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java +++ b/src/main/java/no/nibio/vips/logic/messaging/ForecastNotificationLogPK.java @@ -20,12 +20,12 @@ package no.nibio.vips.logic.messaging; import java.io.Serializable; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.validation.constraints.NotNull; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java index 2231f3b146004522386b65ef5450cef57efc925e..ea0adc8c8a22b51628d0e088a2c5753428dace3b 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java +++ b/src/main/java/no/nibio/vips/logic/messaging/MessageNotificationSubscription.java @@ -20,15 +20,13 @@ package no.nibio.vips.logic.messaging; import java.io.Serializable; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import no.nibio.vips.logic.util.IntegerArrayUserType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -36,7 +34,6 @@ import org.hibernate.annotations.TypeDefs; */ @Entity @Table(name = "message_notification_subscription", schema = "messaging") -@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) public class MessageNotificationSubscription implements Serializable { @Id @@ -47,13 +44,13 @@ public class MessageNotificationSubscription implements Serializable { @Column(name = "universal_message_format_id") private Integer universalMessageFormatId; - @Type(type = "IntegerArray") + @Type(ListArrayType.class) @Column(name = "message_tag_ids") - private Integer[] messageTagIds; + private List<Integer> messageTagIds; - @Type(type = "IntegerArray") + @Type(ListArrayType.class) @Column(name = "crop_category_ids") - private Integer[] cropCategoryIds; + private List<Integer> cropCategoryIds; public Integer getUserId() { return this.userId; @@ -105,43 +102,29 @@ public class MessageNotificationSubscription implements Serializable { /** * @return the messageTagIds */ - public Integer[] getMessageTagIds() { + public List<Integer> getMessageTagIds() { return messageTagIds; } /** * @param messageTagIds the messageTagIds to set */ - public void setMessageTagIds(Integer[] messageTagIds) { + public void setMessageTagIds(List<Integer> messageTagIds) { this.messageTagIds = messageTagIds; } - /** - * For your convenience - * @param messageTagIds - */ - public void setMessageTagIds(List<Integer> messageTagIds) - { - this.messageTagIds = messageTagIds.toArray(new Integer[messageTagIds.size()]); - } - /** * @return the cropCategoryIds */ - public Integer[] getCropCategoryIds() { + public List<Integer> getCropCategoryIds() { return cropCategoryIds; } /** * @param cropCategoryIds the cropCategoryIds to set */ - public void setCropCategoryIds(Integer[] cropCategoryIds) { + public void setCropCategoryIds(List<Integer> cropCategoryIds) { this.cropCategoryIds = cropCategoryIds; } - - public void setCropCategoryIds(List<Integer> cropCategoryIds) - { - this.cropCategoryIds = cropCategoryIds.toArray(new Integer[cropCategoryIds.size()]); - } } diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessageRecipient.java b/src/main/java/no/nibio/vips/logic/messaging/MessageRecipient.java index ee231e54cbd9f7cbe4a0ca457293d20d8736b0a7..c6a692d1ec34af6df9390bc56ce79f020f6565cd 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/MessageRecipient.java +++ b/src/main/java/no/nibio/vips/logic/messaging/MessageRecipient.java @@ -19,9 +19,9 @@ package no.nibio.vips.logic.messaging; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java index 8f6001b3801e67370bed6085255f936063cc5797..6b9a9b968721366c52f45ca146e7630b43f6d80a 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java +++ b/src/main/java/no/nibio/vips/logic/messaging/MessagingBean.java @@ -29,11 +29,11 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.ResourceBundle; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; import no.nibio.vips.entity.Result; import no.nibio.vips.logic.entity.ForecastConfiguration; import no.nibio.vips.logic.entity.ForecastResult; @@ -165,7 +165,7 @@ public class MessagingBean { " SELECT mns.user_id FROM messaging.message_notification_subscription mns, public.vips_logic_user u \n" + " WHERE mns.user_id = u.user_id \n" + " and u.organization_id = " + message.getOrganizationId() + - (message.getCropCategoryIds() != null && message.getCropCategoryIds().length != 0 ? " AND mns.crop_category_ids && ARRAY" + Arrays.asList(message.getCropCategoryIds()).toString() + " \n" : "") + + (message.getCropCategoryIds() != null && message.getCropCategoryIds().size() != 0 ? " AND mns.crop_category_ids && ARRAY" + Arrays.asList(message.getCropCategoryIds()).toString() + " \n" : "") + (message.getMessageTagIds() != null && !message.getMessageTagIds().isEmpty() ? " AND mns.message_tag_ids && ARRAY" + message.getMessageTagIds().toString() + " \n" : "" )+ // && is the array_overlaps operator " AND (mns.universal_message_format_id <> " + UniversalMessageFormat.FORMAT_SMS + " OR (mns.universal_message_format_id = " + UniversalMessageFormat.FORMAT_SMS + " AND u.approves_sms_billing IS TRUE))" + "); \n"; @@ -219,7 +219,7 @@ public class MessagingBean { Date in10Days = cal.getTime(); List<ForecastConfiguration> forecastConfigurations = em.createNativeQuery( "SELECT * FROM public.forecast_configuration f " - + "WHERE f.forecast_configuration_id IN (" + + "WHERE NOT f.is_private AND f.forecast_configuration_id IN (" + " SELECT forecast_configuration_id FROM forecast_result WHERE valid_time_start between :dateStart AND :dateEnd" + ")", ForecastConfiguration.class diff --git a/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java b/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java index 7df24d956a44b400a0cacbd53660cef00e7cd2fc..08c6139a10621c7a585b62df7489ed2a2eeaee8e 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java +++ b/src/main/java/no/nibio/vips/logic/messaging/ObservationNotificationSubscription.java @@ -20,15 +20,14 @@ package no.nibio.vips.logic.messaging; import java.io.Serializable; import java.util.List; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.Table; -import no.nibio.vips.logic.util.IntegerArrayUserType; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import io.hypersistence.utils.hibernate.type.array.ListArrayType; + /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -36,7 +35,6 @@ import org.hibernate.annotations.TypeDefs; */ @Entity @Table(name = "observation_notification_subscription", schema = "messaging") -@TypeDefs( {@TypeDef( name= "IntegerArray", typeClass = IntegerArrayUserType.class)}) public class ObservationNotificationSubscription implements Serializable { @Id @@ -47,9 +45,9 @@ public class ObservationNotificationSubscription implements Serializable { @Column(name = "universal_message_format_id") private Integer universalMessageFormatId; - @Type(type = "IntegerArray") + @Type(ListArrayType.class) @Column(name = "crop_category_ids") - private Integer[] cropCategoryIds; + private List<Integer> cropCategoryIds; public Integer getUserId() { return this.userId; @@ -101,20 +99,17 @@ public class ObservationNotificationSubscription implements Serializable { /** * @return the cropCategoryIds */ - public Integer[] getCropCategoryIds() { + public List<Integer> getCropCategoryIds() { return cropCategoryIds; } /** * @param cropCategoryIds the cropCategoryIds to set */ - public void setCropCategoryIds(Integer[] cropCategoryIds) { - this.cropCategoryIds = cropCategoryIds; - } public void setCropCategoryIds(List<Integer> cropCategoryIds) { - this.cropCategoryIds = cropCategoryIds.toArray(new Integer[cropCategoryIds.size()]); + this.cropCategoryIds = cropCategoryIds; } } diff --git a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java index db8020bf17a7cccac787569541a1592fd6d04065..504306acfc13d56a9cdf7893b59122329899054a 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java +++ b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessage.java @@ -31,25 +31,25 @@ import java.util.List; import java.util.ResourceBundle; import java.util.logging.Level; import java.util.logging.Logger; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Transient; import javax.xml.bind.annotation.XmlRootElement; import com.ibm.icu.util.ULocale; import no.nibio.vips.logic.util.StringJsonUserType; +import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import org.hibernate.type.SqlTypes; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -58,7 +58,6 @@ import org.hibernate.annotations.TypeDefs; @Entity @Table(name = "universal_message", schema = "messaging") @XmlRootElement -@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)}) @NamedQueries({ @NamedQuery(name = "UniversalMessage.findAll", query = "SELECT u FROM UniversalMessage u"), @NamedQuery(name = "UniversalMessage.findByUniversalMessageId", query = "SELECT u FROM UniversalMessage u WHERE u.universalMessageId = :universalMessageId"), @@ -73,14 +72,12 @@ public class UniversalMessage implements Serializable { @Column(name = "expires_at") @Temporal(TemporalType.TIMESTAMP) private Date expiresAt; - //@Column(name = "distribution_list", columnDefinition = "json") - //@Convert(converter = PostgresJSONStringConverter.class) - // Documentation on StackOverflow: http://stackoverflow.com/questions/15974474/mapping-postgresql-json-column-to-hibernate-value-type - @Type(type = "StringJsonObject") + + @JdbcTypeCode(SqlTypes.JSON) @Column(name = "distribution_list") private String distributionList; - @Type(type = "StringJsonObject") + @JdbcTypeCode(SqlTypes.JSON) @Column(name = "message_local_versions") private String messageLocalVersions; diff --git a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessageFormat.java b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessageFormat.java index 5a257076d6585b4da369f440378072ff6c3e252a..d87384d48ba5eefa225ee16ed6ecf78586a7fbfb 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessageFormat.java +++ b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessageFormat.java @@ -19,12 +19,12 @@ package no.nibio.vips.logic.messaging; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessagingServiceClient.java b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessagingServiceClient.java index f0583c3e77c793e8059a7730d62cf1f147a5d89e..3ca28aa6389793cb7919a4145b86a7407cfb38c3 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/UniversalMessagingServiceClient.java +++ b/src/main/java/no/nibio/vips/logic/messaging/UniversalMessagingServiceClient.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.messaging; import com.webcohesion.enunciate.metadata.Facet; -import javax.ws.rs.Consumes; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Response; /** * @copyright 2015 <a href="http://www.bioforsk.no/">Bioforsk</a> diff --git a/src/main/java/no/nibio/vips/logic/messaging/distribution/send/MailMsgDeliveryHandler.java b/src/main/java/no/nibio/vips/logic/messaging/distribution/send/MailMsgDeliveryHandler.java index 310eb316dcd72a4fc83bd5003be901a75d6846b0..7c8efb8d445c3fc2b06740d92ab7d8da7cbab448 100644 --- a/src/main/java/no/nibio/vips/logic/messaging/distribution/send/MailMsgDeliveryHandler.java +++ b/src/main/java/no/nibio/vips/logic/messaging/distribution/send/MailMsgDeliveryHandler.java @@ -22,14 +22,14 @@ import java.text.MessageFormat; import java.util.Date; import java.util.Properties; -import javax.mail.Message; -import javax.mail.MessagingException; -import javax.mail.Session; -import javax.mail.internet.InternetAddress; -import javax.mail.internet.MimeMessage; -import javax.mail.internet.MimeUtility; - -import com.sun.mail.smtp.SMTPTransport; +import jakarta.mail.Message; +import jakarta.mail.MessagingException; +import jakarta.mail.Session; +import jakarta.mail.internet.InternetAddress; +import jakarta.mail.internet.MimeMessage; +import jakarta.mail.internet.MimeUtility; + +import jakarta.mail.Transport; import no.nibio.vips.logic.messaging.distribution.entity.DistributionTypeEnum; import no.nibio.vips.logic.messaging.distribution.entity.MsgReceiver; import no.nibio.vips.logic.messaging.distribution.entity.MsgToSend; @@ -65,7 +65,7 @@ public class MailMsgDeliveryHandler implements IDeliveryMsgHandler { throws MessagingException, UnsupportedEncodingException { boolean result = false; - SMTPTransport t = null; + Transport t = null; String message = "Failed to send message to " + mailaddress + " using server " + mailserver; try { @@ -115,11 +115,12 @@ public class MailMsgDeliveryHandler implements IDeliveryMsgHandler { LOGGER.debug("Message ready to send : " + mailMessageBody); - t = (SMTPTransport) session.getTransport(ssl ? "smtps" : "smtp"); + t = (Transport) session.getTransport(ssl ? "smtps" : "smtp"); t.connect(); t.sendMessage(msg, msg.getAllRecipients()); - - LOGGER.debug("Mail was sent successfully. Response: " + t.getLastServerResponse()); + + // TODO: Replace with TransportListener (After upgrading to Jakarta) + //LOGGER.debug("Mail was sent successfully. Response: " + t.getLastServerResponse()); } finally { try { diff --git a/src/main/java/no/nibio/vips/logic/messaging/distribution/send/SmsMsgDeliveryHandler.java b/src/main/java/no/nibio/vips/logic/messaging/distribution/send/SmsMsgDeliveryHandler.java index 860f4514396f9c74cb7c74f6b2cb919f1373c9de..b92c123669ef5580c20a3bdd5aea911d56d65d42 100644 --- a/src/main/java/no/nibio/vips/logic/messaging/distribution/send/SmsMsgDeliveryHandler.java +++ b/src/main/java/no/nibio/vips/logic/messaging/distribution/send/SmsMsgDeliveryHandler.java @@ -27,7 +27,7 @@ import java.net.URLConnection; import java.net.URLEncoder; import java.text.MessageFormat; -import javax.mail.MessagingException; +import jakarta.mail.MessagingException; import no.nibio.vips.logic.messaging.distribution.entity.MsgReceiver; import no.nibio.vips.logic.messaging.distribution.entity.MsgToSend; import no.nibio.vips.logic.messaging.distribution.entity.VipsMessage; diff --git a/src/main/java/no/nibio/vips/logic/messaging/sms/SMSHandlingService.java b/src/main/java/no/nibio/vips/logic/messaging/sms/SMSHandlingService.java index 76ffc2829aa07745318b03359a70aefba92b8469..b07721ff2b2a9f433bb53c46478ddb3b69e729b2 100755 --- a/src/main/java/no/nibio/vips/logic/messaging/sms/SMSHandlingService.java +++ b/src/main/java/no/nibio/vips/logic/messaging/sms/SMSHandlingService.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.messaging.sms; import com.webcohesion.enunciate.metadata.Facet; -import javax.ejb.EJB; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; +import jakarta.ejb.EJB; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.VipsLogicUser; diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java index 278d8742ce56451b82b349feea1485a85203ade3..e002bd0c67a816e6be95f56573789a15d59d863a 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothBean.java @@ -32,12 +32,12 @@ import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; -import javax.ejb.LocalBean; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; +import jakarta.ejb.LocalBean; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; import no.nibio.vips.logic.util.Globals; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java index f21aeb2f9530ea09bb4bf3be00aef4311ef2b367..5916fcaa3d9d4261288254cc7cbf50d268a83ad9 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothController.java @@ -28,11 +28,11 @@ import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import javax.ejb.EJB; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.VipsLogicRole; import no.nibio.vips.logic.entity.VipsLogicUser; diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothService.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothService.java index fe21310ed23644c2d561149e4450d7117efe13ef..8c5013e8e9093e5f78c55e787bfd552bc1bb14c1 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothService.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/AppleFruitMothService.java @@ -21,15 +21,15 @@ package no.nibio.vips.logic.modules.applefruitmoth; import com.webcohesion.enunciate.metadata.Facet; import de.micromata.opengis.kml.v_2_2_0.Kml; import java.util.Calendar; -import javax.ejb.EJB; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; +import jakarta.ejb.EJB; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.util.ServletUtil; diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java index 0a380253126db6273c36952bf27ee33953980190..93c21bb6fc285297dae25ddb38f59a6bda75dd6b 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSite.java @@ -23,22 +23,22 @@ import java.io.Serializable; import java.util.Date; import java.util.HashSet; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import no.nibio.vips.logic.entity.Gis; diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePoint.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePoint.java index 64ad9e597b7f0da19dae1d1c42c1fc38362187ef..82c177d4a93b666309262095b2b7f48a47f316d9 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePoint.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePoint.java @@ -20,23 +20,23 @@ package no.nibio.vips.logic.modules.applefruitmoth; import java.io.Serializable; import java.util.Set; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import no.nibio.vips.logic.entity.Gis; diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java index 2e35f610324643c6ed68d17f3207b01b41d40035..c54d2aa69fe239e42e3301c87c9361ccf850e3e3 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonData.java @@ -21,16 +21,16 @@ package no.nibio.vips.logic.modules.applefruitmoth; import java.io.Serializable; import java.math.BigDecimal; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonDataPK.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonDataPK.java index 1f85c533303a8f5b19df7aa7d088db5a22844851..b62e6d09abfe8d6e64e01f52973ccc04b6979434 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonDataPK.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSitePointSeasonDataPK.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.modules.applefruitmoth; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java index 6635b19435d12757179e5460bda4426fb3ab8c74..33df50749be5a86326760aaba1596796dbfbc75b 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonData.java @@ -21,16 +21,16 @@ package no.nibio.vips.logic.modules.applefruitmoth; import java.io.Serializable; import java.math.BigDecimal; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonDataPK.java b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonDataPK.java index 42f89a65a522bcd48415c8330f6ce2b83bf26c39..fc3d3bb138a5561563c8f4f201cfb7155c61f089 100755 --- a/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonDataPK.java +++ b/src/main/java/no/nibio/vips/logic/modules/applefruitmoth/ObservationSiteSeasonCommonDataPK.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.modules.applefruitmoth; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleBean.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleBean.java index be9bc11cda555726f828c73e5f3e31b4c5de2a66..290cfa5e1a1ad5643f94d26e73147c137e6af52a 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleBean.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleBean.java @@ -39,14 +39,14 @@ import java.util.Locale; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import javax.ejb.EJB; +import jakarta.ejb.EJB; -import javax.ejb.LocalBean; -import javax.ejb.Stateless; +import jakarta.ejb.LocalBean; +import jakarta.ejb.Stateless; import javax.naming.InitialContext; import javax.naming.NamingException; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; import org.geotools.geometry.jts.JTS; import org.geotools.referencing.CRS; @@ -117,6 +117,30 @@ public class BarkbeetleBean { .getResultList(); } + /** + * Get all trapsites belonging to a specific user + * @param user + * @return + */ + public List<SeasonTrapsite> getSeasonTrapsites(VipsLogicUser user) + { + return em.createNamedQuery("SeasonTrapsite.findByUserId") + .setParameter("userId", user) + .getResultList(); + } + + /** + * Transferring ownership of all season trapsites for all seasons belonging to a user + * to another user + * @param fromUser the current owner of the sites + * @param toUser the new owner of the sites + */ + public void transferSeasonTrapsites(VipsLogicUser fromUser, VipsLogicUser toUser){ + em.createNativeQuery("UPDATE barkbeetle.season_trapsite SET user_id=:toUserId WHERE user_id=:fromUserId") + .setParameter("fromUserId", fromUser.getUserId()) + .setParameter("toUserId", toUser.getUserId()) + .executeUpdate(); + } /** * Get the list of trapsites for the given season * @@ -287,7 +311,9 @@ public class BarkbeetleBean { em.createNativeQuery("DELETE FROM barkbeetle.season_trapsite_bivolt WHERE season_trapsite_id = :seasonTrapsiteId") .setParameter("seasonTrapsiteId", seasonTrapsiteId) .executeUpdate(); - em.remove(stToDelete); + em.createNativeQuery("DELETE FROM barkbeetle.season_trapsite WHERE season_trapsite_id = :seasonTrapsiteId") + .setParameter("seasonTrapsiteId", seasonTrapsiteId) + .executeUpdate(); return true; } diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleController.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleController.java index 4418b800db9a1f7b1cda48deea4d1e9df7561337..0a2dcdbb90036b19ca1be6ce9e60167ede85bd52 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleController.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleController.java @@ -33,12 +33,12 @@ import java.util.List; import java.util.Locale; import java.util.Set; import java.util.stream.Collectors; -import javax.ejb.EJB; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.ws.rs.core.Response; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.ws.rs.core.Response; import no.nibio.vips.gis.GISUtil; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.VipsLogicRole; @@ -60,8 +60,8 @@ import org.locationtech.jts.geom.Point; public class BarkbeetleController extends HttpServlet { // Due to version controls of PDF files, we keep the file names globally updated here - public final static String FILENAME_INSTRUKS_REGISTRANTER = "Instruks_registranter_i_Barkbilleovervakingen_2022-04-25.pdf"; - public final static String FILENAME_INSTRUKS_BARKBILLEFYLKESKONTAKTER = "Instruks_Barkbillefylkeskontakter_2022-04-25.pdf"; + public final static String FILENAME_INSTRUKS_REGISTRANTER = "Instruks_registranter_i_Barkbilleovervakingen_2024-04-03.pdf"; + public final static String FILENAME_INSTRUKS_BARKBILLEFYLKESKONTAKTER = "Instruks_Barkbillefylkeskontakter_2024-03-04.pdf"; public final static String FILENAME_KJENN_IGJEN_ANGREP = "Kjenn_igjen_angrep_stor_granbarkbille_2022-04-25.pdf"; @EJB diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleService.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleService.java index ebcde20a98263955bfbc177cabf52ab1b5c6d585..76ddf51b3db21cab4afb58b0dd6509935a3c9afa 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleService.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/BarkbeetleService.java @@ -18,17 +18,17 @@ package no.nibio.vips.logic.modules.barkbeetle; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.PATCH; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.PATCH; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; import org.jboss.resteasy.annotations.GZIP; @@ -38,7 +38,7 @@ import com.webcohesion.enunciate.metadata.Facet; import java.text.SimpleDateFormat; import java.util.Date; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.util.ServletUtil; diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/RegistrationStatusType.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/RegistrationStatusType.java index dcf98f16832bc938a61f56aee3916a531548fc38..fe4e2e18fab3390f1186625ad98101fed1c4601e 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/RegistrationStatusType.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/RegistrationStatusType.java @@ -19,15 +19,15 @@ package no.nibio.vips.logic.modules.barkbeetle; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsite.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsite.java index 4935dbecfd73606c34850d3ff003279b9fd2eb4d..07899fda2af9ddd8327848e7a3c7a1c2053e5107 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsite.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsite.java @@ -30,27 +30,27 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.Locale; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.Lob; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.CascadeType; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.FetchType; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.Lob; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToMany; +import jakarta.persistence.OneToOne; +import jakarta.persistence.PrimaryKeyJoinColumn; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; import no.nibio.vips.logic.entity.VipsLogicUser; @@ -439,11 +439,11 @@ public class SeasonTrapsite implements Serializable, Comparable { // Thresholds for warning status @Transient - private final Integer THRESHOLD_LOW_RISK = 1000; + private final Integer THRESHOLD_LOW_RISK = 5000; @Transient - private final Integer THRESHOLD_MEDIUM_RISK = 5000; + private final Integer THRESHOLD_MEDIUM_RISK = 10000; @Transient - private final Integer THRESHOLD_HIGH_RISK = 10000; + private final Integer THRESHOLD_HIGH_RISK = 15000; @Transient public Integer getWarningStatus(){ diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsiteBivolt.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsiteBivolt.java index bc1cf21432ab5b4a1f82cf51f20411ea332685f5..98cf87086fe6bb8407403672f0df70cc35cfa0f5 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsiteBivolt.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/SeasonTrapsiteBivolt.java @@ -21,19 +21,19 @@ package no.nibio.vips.logic.modules.barkbeetle; import java.io.Serializable; import java.math.BigInteger; import java.util.Date; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.MapsId; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.OneToOne; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.MapsId; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.validation.constraints.NotNull; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistration.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistration.java index d1ec56d11c8196c737b87567df5377bf4fea7e40..19d15235437f0e8427d04fd363af0d7e5fdeddb4 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistration.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistration.java @@ -20,18 +20,18 @@ package no.nibio.vips.logic.modules.barkbeetle; import java.io.Serializable; import java.util.Date; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; -import javax.validation.constraints.Size; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.persistence.Temporal; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Transient; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistrationPK.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistrationPK.java index 398c49320392f69841d3dbb2db3ec577d8d5a099..6ca9b6a80dd0a78ed5d1730470d8cb5eb7e34f05 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistrationPK.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteRegistrationPK.java @@ -19,10 +19,10 @@ package no.nibio.vips.logic.modules.barkbeetle; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2020 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteType.java b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteType.java index 0b6d8ba524e397d5bbf9bc17f883783113bce137..867706c39f8f87a27d61c73fa360e8c3e9d5c02f 100644 --- a/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteType.java +++ b/src/main/java/no/nibio/vips/logic/modules/barkbeetle/TrapsiteType.java @@ -19,15 +19,15 @@ package no.nibio.vips.logic.modules.barkbeetle; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Size; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/BarleyNetBlotchModelService.java b/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/BarleyNetBlotchModelService.java index 58b9c26ed68b2b13de307c5f059fac87327f9f3c..0b36340b8b4cff43322937d9cf31570be42b30fa 100755 --- a/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/BarleyNetBlotchModelService.java +++ b/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/BarleyNetBlotchModelService.java @@ -19,29 +19,23 @@ package no.nibio.vips.logic.modules.barleynetblotch; import com.webcohesion.enunciate.metadata.Facet; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.TimeZone; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; + +import java.util.*; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.Result; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.controller.session.ForecastBean; -import no.nibio.vips.logic.entity.Organism; -import no.nibio.vips.logic.entity.Organization; -import no.nibio.vips.logic.entity.PointOfInterestWeatherStation; -import no.nibio.vips.logic.entity.Preparation; +import no.nibio.vips.logic.entity.*; import no.nibio.vips.logic.util.RunModelException; import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.observation.ObservationImpl; @@ -50,6 +44,7 @@ import no.nibio.vips.util.ParseRESTParamUtil; import no.nibio.vips.util.WeatherElements; import no.nibio.vips.util.weather.WeatherDataSourceException; import no.nibio.vips.util.weather.WeatherDataSourceUtil; +import org.slf4j.LoggerFactory; /** * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> @@ -58,6 +53,8 @@ import no.nibio.vips.util.weather.WeatherDataSourceUtil; @Path("rest/barleynetblotchmodel") @Facet("restricted") public class BarleyNetBlotchModelService { + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(BarleyNetBlotchModelService.class); + private final static String VIPSCOREMANAGER_URL = System.getProperty("no.nibio.vips.logic.VIPSCOREMANAGER_URL"); @PersistenceContext(unitName="VIPSLogic-PU") @@ -140,6 +137,9 @@ public class BarleyNetBlotchModelService { public Response runModel( @PathParam("organizationId") Integer organizationId, @QueryParam("timeZone") String timeZoneStr, + @QueryParam("weatherDataSourceType") String weatherDataSourceType, + @QueryParam("latitude") String latitude, + @QueryParam("longitude") String longitude, @QueryParam("weatherStationId") Integer weatherStationId, @QueryParam("sowingDate") String sowingDateStr, @QueryParam("cropId") Integer cropOrganismId, @@ -168,54 +168,74 @@ public class BarleyNetBlotchModelService { Date sprayingDate = parseUtil.parseISODate(sprayingDateStr, timeZone); Integer preparationId = parseUtil.parseInteger(preparationIdStr); Double preparationDose = parseUtil.parseDouble(preparationDoseStr); - + Double latitudeDouble = parseUtil.parseDouble(latitude); + Double longitudeDouble = parseUtil.parseDouble(longitude); + + if(weatherDataSourceType == null) { + return Response.status(Response.Status.BAD_REQUEST).entity("WeatherDataSourceType (grid or weather station) is required").build(); + } + + // Must get the VIPSCore user id for this organization + Organization org = em.find(Organization.class, organizationId); + Integer VIPSCoreUserId = org.getDefaultVipsCoreUserId(); + // Build model configuration ModelConfiguration config = new ModelConfiguration(); config.setModelId("BARLEYNETB"); - // Get weather data from weather station - PointOfInterestWeatherStation weatherStation = em.find(PointOfInterestWeatherStation.class, weatherStationId); + WeatherDataSourceUtil wsdUtil = new WeatherDataSourceUtil(); - - // End date for weather data depends on season - // We try to add 5 months to the sowing date. If thats in the future, - // We add 10 days to today - Date dateOfLastWeatherData; - Calendar cal = Calendar.getInstance(timeZone); - cal.setTime(sowingDate); - cal.add(Calendar.MONTH, 5); - Date fiveMonthsAfterSowingDate = cal.getTime(); - if(fiveMonthsAfterSowingDate.after(SystemTime.getSystemTime())) - { - cal.setTime(SystemTime.getSystemTime()); - cal.add(Calendar.DATE, 10); - dateOfLastWeatherData = cal.getTime(); - } - else - { - dateOfLastWeatherData = fiveMonthsAfterSowingDate; - } + Date endDateForWeatherData = calculateEndDateForWeatherData(timeZone, sowingDate); - List<WeatherObservation> observations; - try { - observations = wsdUtil.getWeatherObservations( + List<WeatherObservation> observations = new ArrayList<>(); + if ("weatherstation".equals(weatherDataSourceType.trim())) { + PointOfInterestWeatherStation weatherStation = + em.find(PointOfInterestWeatherStation.class, weatherStationId); + LOGGER.info("Run model with weatherdata from weatherstation {}", weatherStation.getName()); + try { + observations = wsdUtil.getWeatherObservations( weatherStation, WeatherObservation.LOG_INTERVAL_ID_1H, - new String[]{ + new String[] { WeatherElements.TEMPERATURE_MEAN, WeatherElements.PRECIPITATION }, - sowingDate, - dateOfLastWeatherData - ); - } catch (WeatherDataSourceException ex) { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); - } - - if(observations == null || observations.isEmpty()) - { - return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity("Could not find weather data for weather station with id=" + weatherStationId).build(); + sowingDate, + endDateForWeatherData + ); + } catch (WeatherDataSourceException ex) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } + if (observations == null || observations.isEmpty()) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Could not find weather data for weather station with id=" + weatherStationId).build(); + } + } else if("grid".equals(weatherDataSourceType.trim())) { + LOGGER.info("Run model with weatherdata for latitude={} and longitude={}", latitude, longitude); + String datafetchUriExpression = + org.getDefaultGridWeatherStationDataSource().getDatafetchUriExpression(); + try { + observations = wsdUtil.getWeatherObservations(String.format(datafetchUriExpression, longitude + "_" + latitude), + WeatherObservation.LOG_INTERVAL_ID_1H, + new String[] { + WeatherElements.TEMPERATURE_MEAN, + WeatherElements.PRECIPITATION + }, + sowingDate, + endDateForWeatherData, + timeZone, + Boolean.FALSE, + new HashSet<>(Collections.singletonList(WeatherObservation.LOG_INTERVAL_ID_1H)) + ); + } catch (WeatherDataSourceException ex) { + LOGGER.error("Exception while getting observations for lat={} lon={}", latitude, longitude, ex); + return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex.getMessage()).build(); + } + if (observations == null || observations.isEmpty()) { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity(String.format("Could not find weather data for lat=%s lon=%s between %s and %s", latitude, longitude, sowingDate, endDateForWeatherData)).build(); + } } - + // Mandatory parameters config.setConfigParameter("observations", observations); config.setConfigParameter("timeZone", timeZone.getID()); @@ -241,11 +261,6 @@ public class BarleyNetBlotchModelService { config.setConfigParameter("spraying", spraying); } - - // Must get the VIPSCore user id for this organization - Organization org = em.find(Organization.class, organizationId); - Integer VIPSCoreUserId = org.getDefaultVipsCoreUserId(); - List<Result> results; try { @@ -257,6 +272,32 @@ public class BarleyNetBlotchModelService { } return Response.ok().entity(results).build(); } - - + + /** + * End date for weather data depends on season. We try to add 5 months to the sowing date. + * If the resulting date is in the future, we add 10 days to today. + * + * @param timeZone The current timezone + * @param sowingDate The sowing date + * @return The end date for weather data + */ + private static Date calculateEndDateForWeatherData(TimeZone timeZone, Date sowingDate) { + Date dateOfLastWeatherData; + Calendar cal = Calendar.getInstance(timeZone); + cal.setTime(sowingDate); + cal.add(Calendar.MONTH, 5); + Date fiveMonthsAfterSowingDate = cal.getTime(); + if(fiveMonthsAfterSowingDate.after(SystemTime.getSystemTime())) + { + cal.setTime(SystemTime.getSystemTime()); + cal.add(Calendar.DATE, 10); + dateOfLastWeatherData = cal.getTime(); + } + else + { + dateOfLastWeatherData = fiveMonthsAfterSowingDate; + } + return dateOfLastWeatherData; + } + } diff --git a/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/Factors.java b/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/Factors.java index 81cb89a36a26513586f5cd6d0fb0ff61fa85eac3..db0d82756f7f4d680721ed4717812c9b907252a5 100755 --- a/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/Factors.java +++ b/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/Factors.java @@ -21,14 +21,14 @@ package no.nibio.vips.logic.modules.barleynetblotch; import java.io.Serializable; import java.math.BigDecimal; import java.math.BigInteger; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/PreparationEffectFactor.java b/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/PreparationEffectFactor.java index b79579abbb2ad41afdb5b627d936b4be5392b074..21bd0d61898ff23e96a5c7ebcc1fa87aaaa14aae 100755 --- a/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/PreparationEffectFactor.java +++ b/src/main/java/no/nibio/vips/logic/modules/barleynetblotch/PreparationEffectFactor.java @@ -20,14 +20,14 @@ package no.nibio.vips.logic.modules.barleynetblotch; import java.io.Serializable; import java.math.BigDecimal; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Entity; -import javax.persistence.Id; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; +import jakarta.validation.constraints.NotNull; import javax.xml.bind.annotation.XmlRootElement; /** diff --git a/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java b/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java index 5f08a872cda7ba7bd919cea6c25912d1111996fd..9c63267b3c37998c6e9233d1f3c025ed794d2f36 100755 --- a/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java +++ b/src/main/java/no/nibio/vips/logic/modules/roughage/RoughageService.java @@ -30,18 +30,18 @@ import java.util.List; import java.util.Map; import java.util.TimeZone; import java.util.stream.Collectors; -import javax.ejb.EJB; +import jakarta.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.PersistenceContext; -import javax.persistence.Query; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; +import jakarta.persistence.Query; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.Result; import no.nibio.vips.entity.WeatherObservation; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/TerminateSchedulerListener.java b/src/main/java/no/nibio/vips/logic/scheduling/TerminateSchedulerListener.java index 911ee8e792835b71b7e8bdd5a9b53abc1b5f679e..0a317ef6cdd427ea268247066dec4d1769df4e80 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/TerminateSchedulerListener.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/TerminateSchedulerListener.java @@ -21,7 +21,7 @@ package no.nibio.vips.logic.scheduling; import it.sauronsoftware.cron4j.Scheduler; import it.sauronsoftware.cron4j.SchedulerListener; import it.sauronsoftware.cron4j.TaskExecutor; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.controller.session.SchedulingBean; /** diff --git a/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java b/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java index 38151970bf13e2851461ebf1d1ba560f112c51a1..bf4bb80ee5e27f560c1ae23298fdc6b4385bc7c5 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/VipsLogicTaskFactory.java @@ -26,7 +26,6 @@ import no.nibio.vips.logic.scheduling.tasks.DeleteAllExpiredUserUuidsTask; import no.nibio.vips.logic.scheduling.tasks.RunAllForecastConfigurationsForOrganizationTask; import no.nibio.vips.logic.scheduling.tasks.RunAllForecastConfigurationsTask; import no.nibio.vips.logic.scheduling.tasks.RunForecastConfigurationsByIdTask; -import no.nibio.vips.logic.scheduling.tasks.RunGridModelsTask; import no.nibio.vips.logic.scheduling.tasks.SendForecastEventNotificationsTask; import no.nibio.vips.logic.scheduling.tasks.UpdateForecastResultCacheTableTask; import no.nibio.vips.logic.scheduling.tasks.UpdateForecastSummaryTableTask; @@ -46,11 +45,11 @@ public class VipsLogicTaskFactory { public static final int DELETE_ALL_EXPIRED_UUIDS_TASK = 5; public static final int SEND_FORECAST_EVENT_NOTIFICATIONS_TASK = 6; public static final int RUN_ALL_FORECAST_CONFIGURATIONS_FOR_ORGANIZATION_TASK = 7; - public static final int RUN_GRID_MODELS_TASK = 8; + //public static final int RUN_GRID_MODELS_TASK = 8; public static final int RUN_FORECAST_CONFIGURATIONS_BY_ID_TASK = 9; - private final static int[] ALL_TASK_IDS = {1,2,3,4,5,6,7,8,9}; + private final static int[] ALL_TASK_IDS = {1,2,3,4,5,6,7,9}; private final static int[] ORGANIZATION_ADMIN_TASK_IDS = {7}; @@ -89,9 +88,6 @@ public class VipsLogicTaskFactory { case RUN_ALL_FORECAST_CONFIGURATIONS_FOR_ORGANIZATION_TASK: retVal = new RunAllForecastConfigurationsForOrganizationTask(); break; - case RUN_GRID_MODELS_TASK: - retVal = new RunGridModelsTask(); - break; case RUN_FORECAST_CONFIGURATIONS_BY_ID_TASK: retVal = new RunForecastConfigurationsByIdTask(); break; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/grid/preprocessor/ZymoseptoriaSimpleRiskGridModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/grid/preprocessor/ZymoseptoriaSimpleRiskGridModelPreprocessor.java deleted file mode 100644 index 9161fc5d77bd11c0006f9e277c6298373a70622e..0000000000000000000000000000000000000000 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/grid/preprocessor/ZymoseptoriaSimpleRiskGridModelPreprocessor.java +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - */ - -package no.nibio.vips.logic.scheduling.model.grid.preprocessor; - -import java.time.ZoneId; -import java.time.ZonedDateTime; -import java.time.temporal.ChronoUnit; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.Stream; -import javax.ejb.EJB; -import no.nibio.vips.entity.ModelConfiguration; -import no.nibio.vips.entity.PointWeatherObservationList; -import no.nibio.vips.entity.WeatherObservation; -import no.nibio.vips.gis.CoordinateProxy; -import no.nibio.vips.logic.controller.session.PointOfInterestBean; -import no.nibio.vips.logic.entity.ForecastConfiguration; -import no.nibio.vips.logic.entity.PointOfInterestWeatherStation; -import no.nibio.vips.logic.scheduling.model.ModelRunPreprocessor; -import no.nibio.vips.logic.scheduling.model.PreprocessorException; -import no.nibio.vips.logic.util.SystemTime; -import no.nibio.vips.util.WeatherElements; -import no.nibio.vips.util.WeatherObservationListException; -import no.nibio.vips.util.WeatherUtil; -import no.nibio.vips.util.weather.WeatherDataSourceException; -import no.nibio.vips.util.weather.WeatherDataSourceUtil; - -/** - * @copyright 2018-2022 <a href="http://www.nibio.no/">NIBIO</a> - * @author Tor-Einar Skog <tor-einar.skog@nibio.no> - */ -public class ZymoseptoriaSimpleRiskGridModelPreprocessor extends ModelRunPreprocessor{ - - @EJB - PointOfInterestBean pointOfInterestBean; - - @Override - public ModelConfiguration getModelConfiguration(ForecastConfiguration configuration) throws PreprocessorException { - - ModelConfiguration modelConfig = new ModelConfiguration(); - // Which weather stations?? - // Ilseng and Apelsvoll to start with ;-) - List<PointOfInterestWeatherStation> stations = Stream.of(configuration.getGridWeatherStationPointOfInterestIds()).map( - stationId -> (PointOfInterestWeatherStation) pointOfInterestBean.getPointOfInterest(stationId) - ).collect(Collectors.toList()); - - List<PointWeatherObservationList> allObs = new ArrayList<>(); - WeatherUtil wUtil = new WeatherUtil(); - for(PointOfInterestWeatherStation station:stations) - { - CoordinateProxy coordinate = new CoordinateProxy(station.getPointOfInterest().getLongitude(), station.getPointOfInterest().getLatitude()); - List<WeatherObservation> stationObs = getStationObs(station, configuration); - - try - { - // We need TM, UM and RR. BT is optional - List<WeatherObservation> mandatory = wUtil.filterWeatherObservationsByParameter(stationObs, new HashSet<>(Arrays.asList("TM","UM","RR"))); - stationObs = wUtil.checkForAndFixHourlyTimeSeriesHolesMultiParameter(mandatory, 6); - } - catch(WeatherObservationListException ex) - { - //throw new PreprocessorException(); - System.out.println("Problem with station " + station.getPointOfInterest().getName() + " (#" + station.getPointOfInterestId() + "): " + ex.getMessage()); - continue; - } - // Checking for BT - try - { - List<WeatherObservation> BT = wUtil.filterWeatherObservationsByParameter(stationObs, new HashSet<>(Arrays.asList("BT"))); - stationObs.addAll(wUtil.checkForAndFixHourlyTimeSeriesHoles(BT, 6)); - } - catch(WeatherObservationListException ex) - { - System.out.println("Problem with station " + station.getPointOfInterest().getName() + " (#" + station.getPointOfInterestId() + "): " + ex.getMessage()); - } - - - // TODO: Remove this debug - /* - if(station.getPointOfInterestId().equals(345)) - { - Collections.sort(stationObs); - stationObs.forEach(obs->System.out.println(obs)); - }*/ - - - PointWeatherObservationList pointObs = new PointWeatherObservationList(coordinate, stationObs, station.getTimeZone()); - allObs.add(pointObs); - } - - modelConfig.setConfigParameter("multiPointWeatherObservations", allObs); - modelConfig.setModelId(this.getModelId()); - modelConfig.setConfigParameter("timeZone", configuration.getTimeZone()); - return modelConfig; - } - - @Override - public String getModelId() { - return "GRIDZYMOSE"; - } - - private List<WeatherObservation> getStationObs(PointOfInterestWeatherStation station, ForecastConfiguration configuration) throws PreprocessorException - { - List<WeatherObservation> stationObs;// = new ArrayList<>(); - WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); - - // We run this for max 1 week back in time to make sure it doesn't crash - ZonedDateTime aWeekAgo = ZonedDateTime.ofInstant(SystemTime.getSystemTime().toInstant(), ZoneId.of("Europe/Oslo")).minus(1, ChronoUnit.WEEKS); - ZonedDateTime aWeekAhead = ZonedDateTime.ofInstant(SystemTime.getSystemTime().toInstant(), ZoneId.of("Europe/Oslo")).plus(1, ChronoUnit.WEEKS); - try { - - stationObs = wdsUtil.getWeatherObservations( - station, - WeatherObservation.LOG_INTERVAL_ID_1H, - new String[]{ - WeatherElements.LEAF_WETNESS_DURATION, - WeatherElements.RELATIVE_HUMIDITY_MEAN, - WeatherElements.PRECIPITATION, - WeatherElements.TEMPERATURE_MEAN - }, - Date.from(aWeekAgo.toInstant()), - Date.from(aWeekAhead.toInstant()), - true, - new HashSet<>(Arrays.asList(WeatherObservation.LOG_INTERVAL_ID_1H,WeatherObservation.LOG_INTERVAL_ID_3H, WeatherObservation.LOG_INTERVAL_ID_6H)) - ); - return stationObs; - } catch (WeatherDataSourceException ex ) { - throw new PreprocessorException(ex.getMessage()); - } - } -} diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AltenariaModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AltenariaModelPreprocessor.java index 62f1a688cb0434309588ec348b2136962436371e..7b1db122c47c2f533b904110cfa0392ec6c84115 100644 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AltenariaModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AltenariaModelPreprocessor.java @@ -31,7 +31,7 @@ import java.util.List; import java.util.TimeZone; import java.util.logging.Level; import java.util.logging.Logger; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.controller.session.ForecastBean; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java index 374785eb0666c660d5b7d2800a67beb629064f17..230ffcb73ab8db055e90f5b57b72005caf1551c1 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/AppleScabModelPreprocessor.java @@ -27,6 +27,10 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.TimeZone; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.entity.ForecastConfiguration; @@ -48,17 +52,13 @@ import no.nibio.vips.util.weather.WeatherDataSourceUtil; * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ public class AppleScabModelPreprocessor extends ModelRunPreprocessor{ - - private final boolean DEBUG = false; + private static Logger LOGGER = LoggerFactory.getLogger(AppleScabModelPreprocessor.class); public final static String APPLESCABM_START_DATE_ASCOSPORE_MATURITY = "APPLESCABM_START_DATE_ASCOSPORE_MATURITY"; @Override public ModelConfiguration getModelConfiguration(ForecastConfiguration configuration) throws PreprocessorException { - if(DEBUG) - { - System.out.println("getModelConfiguration"); - } + LOGGER.debug("AppleScabModelPreprocessor.getModelConfiguration() called"); //configuration.getDateStart(); PointOfInterestWeatherStation weatherStation = (PointOfInterestWeatherStation) configuration.getWeatherStationPointOfInterestId(); // What timezone is the calculation for @@ -92,10 +92,8 @@ public class AppleScabModelPreprocessor extends ModelRunPreprocessor{ // Use Jackson to parse JSON from server // Weather data collections - if(DEBUG) - { - System.out.println("Getting weather data at " + new Date().toString()); - } + LOGGER.debug("Getting weather data at " + new Date().toString()); + WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); List<WeatherObservation> observations; try { @@ -135,22 +133,17 @@ public class AppleScabModelPreprocessor extends ModelRunPreprocessor{ // We do nothing } - - if(DEBUG) - { - System.out.println("Finished getting weather data at " + new Date().toString()); - } + LOGGER.debug("Finished getting weather data at " + new Date().toString()); + try { observations = validateAndSanitizeObservations(observations, startDateAscosporeMaturity); } catch (ConfigValidationException | WeatherObservationListException ex) { //ex.printStackTrace(); throw new PreprocessorException(ex.getMessage()); } - if(DEBUG) - { - System.out.println("Observations=" + observations.toString()); - } + //LOGGER.debug("Observations=" + observations.toString()); + // Create the complete model configuration object ModelConfiguration retVal = new ModelConfiguration(); @@ -176,11 +169,7 @@ public class AppleScabModelPreprocessor extends ModelRunPreprocessor{ * @throws WeatherObservationListException */ private List<WeatherObservation> validateAndSanitizeObservations(List<WeatherObservation> observations, Date firstTimeStamp) throws ConfigValidationException, WeatherObservationListException { - if(DEBUG) - { - System.out.println("validateAndSanitizeObservations"); - } - + WeatherUtil wUtil = new WeatherUtil(); // First we remove all duplicates @@ -241,14 +230,7 @@ public class AppleScabModelPreprocessor extends ModelRunPreprocessor{ // Problems with weather observations - // Holes in series - if(DEBUG) - { - System.out.println("checkForAndFixHourlyTimeSeriesHoles"); - //System.out.println(wUtil.dumpWeatherObservationList(RR)); - } - - + // Unequal length of lists if ( @@ -257,6 +239,7 @@ public class AppleScabModelPreprocessor extends ModelRunPreprocessor{ || RR.size() != TM.size() ) { + LOGGER.debug("Unequal lists lengt: RR=" + RR.size() + ", TM=" + TM.size() + ", BT=" + BT.size()); UM = wUtil.fixHourlyValuesForParameters( UM, new HashSet(Arrays.asList("UM")), diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java index b01ab188dbab0dadf2c007865c0638cec1b7c2a9..8e5ef8dbb5358a71f488f4c0b893838fa617acf9 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DOWNCASTModelPreprocessor.java @@ -24,6 +24,9 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; + +import com.ibm.icu.util.Calendar; + import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.entity.ForecastConfiguration; @@ -38,7 +41,7 @@ import no.nibio.vips.util.weather.WeatherDataSourceException; import no.nibio.vips.util.weather.WeatherDataSourceUtil; /** - * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> + * @copyright 2016-2024 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ public class DOWNCASTModelPreprocessor extends ModelRunPreprocessor{ @@ -49,6 +52,14 @@ public class DOWNCASTModelPreprocessor extends ModelRunPreprocessor{ PointOfInterestWeatherStation weatherStation = (PointOfInterestWeatherStation) configuration.getWeatherStationPointOfInterestId(); WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); WeatherUtil wUtil = new WeatherUtil(); + + // We use only short-time forecasts, as the model is very sensitive + Calendar cal = Calendar.getInstance(); + cal.add(Calendar.DATE,3); + if(cal.getTime().before(configuration.getDateEnd())) + { + configuration.setDateEnd(cal.getTime()); + } List<WeatherObservation> observations; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DeliaRadicumFloralisModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DeliaRadicumFloralisModelPreprocessor.java index 9d5fa878570f40d8294d212029f194f92ec197a9..6e3420a76e6f339f3b15022b7a0ad4ff78dc0294 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DeliaRadicumFloralisModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/DeliaRadicumFloralisModelPreprocessor.java @@ -24,7 +24,7 @@ import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.TimeZone; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.logic.controller.session.ObservationBean; import no.nibio.vips.logic.controller.session.OrganismBean; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/PsilaRosaeObservationModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/PsilaRosaeObservationModelPreprocessor.java index 4e9f5b7964e52452e901ecc56c0decb26803efb6..c9767cdca7c9951aad6ee6848378137bf3db3a76 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/PsilaRosaeObservationModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/PsilaRosaeObservationModelPreprocessor.java @@ -22,7 +22,7 @@ import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.TimeZone; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.logic.controller.session.ObservationBean; import no.nibio.vips.logic.controller.session.OrganismBean; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaApiicolaModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaApiicolaModelPreprocessor.java index 1cb407f2d50881816e25bfac2cf4b7db28f9e27c..322042f085dadac1f0f8f7c4b357fcc82cf14f22 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaApiicolaModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaApiicolaModelPreprocessor.java @@ -25,7 +25,7 @@ import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.stream.Collectors; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.WeatherObservation; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaHumidityModelPreprocessor.java b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaHumidityModelPreprocessor.java index 4ac0300b3f3bb36f18cfcb9d2f75325fe3ad08fa..470373f4689ca43cb89fec657d9220126c1b1b99 100644 --- a/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaHumidityModelPreprocessor.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/model/preprocessor/SeptoriaHumidityModelPreprocessor.java @@ -25,7 +25,7 @@ import java.util.Collections; import java.util.Date; import java.util.List; import java.util.TimeZone; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.controller.session.ForecastBean; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/DeleteAllExpiredUserUuidsTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/DeleteAllExpiredUserUuidsTask.java index 0ef2ce63136d40ef47196676d8eb8f67ba8ecac4..978b77a3540f69ea839a9d54cd706b83e4859ae9 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/DeleteAllExpiredUserUuidsTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/DeleteAllExpiredUserUuidsTask.java @@ -19,7 +19,7 @@ package no.nibio.vips.logic.scheduling.tasks; import it.sauronsoftware.cron4j.TaskExecutionContext; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.controller.session.SessionControllerGetter; import no.nibio.vips.logic.controller.session.UserBean; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsForOrganizationTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsForOrganizationTask.java index 84a41cc203c8e4c57e6cfe900ab189f4776af133..6b1ec30148734c75e43b6b729e00c91b6f6d0567 100644 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsForOrganizationTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsForOrganizationTask.java @@ -22,7 +22,7 @@ import it.sauronsoftware.cron4j.TaskExecutionContext; import java.util.Collections; import java.util.List; import java.util.Map; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.i18n.I18nImpl; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.PointOfInterestBean; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java index 7a5cf687a4e6fa2e3e9c1de4827fe9b4c94b3953..9bb8ae4aeac07594edbbfb760efccdb11a837ac6 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunAllForecastConfigurationsTask.java @@ -1,18 +1,16 @@ /* - * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General + * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see + * <https://www.gnu.org/licenses/>. * */ @@ -23,12 +21,13 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; -import javax.ejb.EJB; +import jakarta.ejb.EJB; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import no.nibio.vips.i18n.I18nImpl; -import no.nibio.vips.logic.controller.session.ForecastBean; -import no.nibio.vips.logic.controller.session.PointOfInterestBean; import no.nibio.vips.logic.controller.session.SessionControllerGetter; -import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.ForecastConfiguration; import no.nibio.vips.logic.entity.ModelInformation; import no.nibio.vips.logic.entity.Organization; @@ -45,32 +44,32 @@ import no.nibio.web.forms.FormField; * @copyright 2013-2022 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ -public class RunAllForecastConfigurationsTask extends VipsLogicTask{ - +public class RunAllForecastConfigurationsTask extends VipsLogicTask { + + private static Logger LOGGER = LoggerFactory.getLogger(RunAllForecastConfigurationsTask.class); + private I18nImpl i18n; - //private boolean DEBUG=true; + + // private boolean DEBUG=true; @Override public void execute(TaskExecutionContext tec) throws RuntimeException { Integer weatherStationPointOfInterestId = null; - if(this.getConfiguration() != null && this.getConfiguration().get("weatherStationPointOfInterestId") != null) - { - weatherStationPointOfInterestId = Integer.valueOf(this.getConfiguration().get("weatherStationPointOfInterestId")[0]); + if (this.getConfiguration() != null && this.getConfiguration().get("weatherStationPointOfInterestId") != null) { + weatherStationPointOfInterestId = + Integer.valueOf(this.getConfiguration().get("weatherStationPointOfInterestId")[0]); } - + // Is organization configured? In that case, pick only one. Otherwhise, pick em all // The config could come from a form - if(this.getConfiguration() != null && this.getConfiguration().get("organizationId") != null) - { - this.setOrganization(SessionControllerGetter.getUserBean().getOrganization(Integer.valueOf(this.getConfiguration().get("organizationId")[0]))); + if (this.getConfiguration() != null && this.getConfiguration().get("organizationId") != null) { + this.setOrganization(SessionControllerGetter.getUserBean() + .getOrganization(Integer.valueOf(this.getConfiguration().get("organizationId")[0]))); } - + List<Organization> organizations = new ArrayList<>(); - if(this.getOrganization() != null) - { + if (this.getOrganization() != null) { organizations.add(this.getOrganization()); - } - else - { + } else { organizations = SessionControllerGetter.getUserBean().getOrganizations(); } tec.setCompleteness(0d); @@ -79,94 +78,99 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{ StringBuilder errorMessage = new StringBuilder(); // Get all organizations, loop, get all current forecasts, loop, run models, store results boolean noForecastConfigurationsFound = true; - - Map<String, ModelInformation> modelInformationMap = SessionControllerGetter.getForecastBean().getIndexedBatchableModelInformation(); - - for(Organization organization : organizations) - { - List<ForecastConfiguration> currentForecastConfigurations = SessionControllerGetter.getForecastBean().getForecastConfigurationsValidAtTime(organization, SystemTime.getSystemTime()); - //System.out.println("Current forecasts for " + organization.getOrganizationName() + ":" + currentForecastConfigurations.size()); - if(currentForecastConfigurations != null && !currentForecastConfigurations.isEmpty()) - { + + Map<String, ModelInformation> modelInformationMap = + SessionControllerGetter.getForecastBean().getIndexedBatchableModelInformation(); + + for (Organization organization : organizations) { + List<ForecastConfiguration> currentForecastConfigurations = SessionControllerGetter.getForecastBean() + .getForecastConfigurationsValidAtTime(organization, SystemTime.getSystemTime()); + // System.out.println("Current forecasts for " + organization.getOrganizationName() + ":" + + // currentForecastConfigurations.size()); + if (currentForecastConfigurations != null && !currentForecastConfigurations.isEmpty()) { noForecastConfigurationsFound = false; - for(ForecastConfiguration forecastConfiguration:currentForecastConfigurations) - { - if( - weatherStationPointOfInterestId == null + for (ForecastConfiguration forecastConfiguration : currentForecastConfigurations) { + if (forecastConfiguration.getUseGridWeatherData() + && forecastConfiguration.getWeatherStationPointOfInterestId() == null) { + errorMessage.append( + SchedulingUtil.createSchedulingMessageHTML( + "Error with forecast #" + forecastConfiguration.getForecastConfigurationId() + + " (" + forecastConfiguration.getLocationPointOfInterestId().getName() + + " - " + + modelInformationMap.get(forecastConfiguration.getModelId()) + .getDefaultName() + + ")", + "The forecast is configured to use gridded weather data, but the organization " + + forecastConfiguration.getVipsLogicUserId().getOrganizationId() + .getOrganizationName() + + " has not set its gridded weather data source. Please contact the system administrator.", + SchedulingUtil.MESSAGE_STATUS_WARNING)); + totalNumberofForecastConfigurations++; + } else if (weatherStationPointOfInterestId == null || weatherStationPointOfInterestId <= 0 - || (forecastConfiguration.getWeatherStationPointOfInterestId() != null && forecastConfiguration.getWeatherStationPointOfInterestId().getPointOfInterestId().equals(weatherStationPointOfInterestId)) - ) + || (forecastConfiguration.getWeatherStationPointOfInterestId() != null + && forecastConfiguration.getWeatherStationPointOfInterestId() + .getPointOfInterestId() != null + && forecastConfiguration.getWeatherStationPointOfInterestId().getPointOfInterestId() + .equals(weatherStationPointOfInterestId))) + { - try - { + try { totalNumberofForecastConfigurations++; - //System.out.println("Running forecast #" + forecastConfiguration.getForecastConfigurationId()); + LOGGER.debug("Running forecast #" + forecastConfiguration.getForecastConfigurationId()); SessionControllerGetter.getForecastBean().runForecast(forecastConfiguration); - /* - if(DEBUG && totalNumberofForecastConfigurations == 2) - { - throw new RunModelException("This is a test!!!"); - }*/ numberOfCompletedForecastConfigurations++; - //System.out.println("All went well"); - } - catch (PreprocessorException | RunModelException ex) - { + } catch (PreprocessorException | RunModelException ex) { errorMessage .append( - SchedulingUtil.createSchedulingMessageHTML( - "Error with forecast #" + forecastConfiguration.getForecastConfigurationId() + " (" + forecastConfiguration.getLocationPointOfInterestId().getName() + " - " + modelInformationMap.get(forecastConfiguration.getModelId()).getDefaultName() + ")", - ex.getMessage(), - SchedulingUtil.MESSAGE_STATUS_DANGER) - ); - //System.out.println("########################### Error caught: " + errorMessage); - //System.out.println("numberOfCompletedForecastConfigurations=" + numberOfCompletedForecastConfigurations); - //System.out.println("totalNumberofForecastConfigurations=" + totalNumberofForecastConfigurations); - //continue; + SchedulingUtil.createSchedulingMessageHTML( + "Error with forecast #" + + forecastConfiguration.getForecastConfigurationId() + " (" + + forecastConfiguration.getLocationPointOfInterestId() + .getName() + + " - " + + modelInformationMap + .get(forecastConfiguration.getModelId()) + .getDefaultName() + + ")", + ex.getMessage(), + SchedulingUtil.MESSAGE_STATUS_DANGER)); } } - if(totalNumberofForecastConfigurations > 0) - { + if (totalNumberofForecastConfigurations > 0) { noForecastConfigurationsFound = false; - double completeness = (double) numberOfCompletedForecastConfigurations/totalNumberofForecastConfigurations; - tec.setCompleteness(completeness); - } - else - { + tec.setCompleteness(Double.valueOf(numberOfCompletedForecastConfigurations) + / Double.valueOf(totalNumberofForecastConfigurations)); + } else { noForecastConfigurationsFound = true; - //System.out.println("noForecastConfigurationsFound == true!!"); + } - //System.out.println("Current completeness=" + tec.getTaskExecutor().getCompleteness()); } } - + } - if(noForecastConfigurationsFound) - { - tec.setCompleteness(1.0); - tec.setStatusMessage("No current forecast configurations were found"); + + if (noForecastConfigurationsFound) { + tec.setCompleteness(1.0); + tec.setStatusMessage("No current forecast configurations were found"); } - - //System.out.println("Total completeness=" + tec.getTaskExecutor().getCompleteness()); - - if(tec.getTaskExecutor().getCompleteness() != 1.0) - { - //System.out.println("Error detected, RuntimeException thrown just after this"); + + + if (tec.getTaskExecutor().getCompleteness() != 1.0 || !errorMessage.isEmpty()) { + // System.out.println("Error detected, RuntimeException thrown just after this"); tec.setStatusMessage(errorMessage.toString()); throw new RuntimeException(); } } @Override - public boolean supportsStatusTracking() - { + public boolean supportsStatusTracking() { return true; } - + @Override - public boolean supportsCompletenessTracking() - { + public boolean supportsCompletenessTracking() { return true; } @@ -187,18 +191,19 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{ .append(" \"required\":false,") .append(" \"options\": ["); - + retVal.append(" {\"value\":\"") - .append("-1") - .append("\", \"label\":\"") - .append(this.getI18nImpl().getText("pleaseSelect", language)).append(" ").append(this.getI18nImpl().getText("weatherStationPointOfInterestId", language).toLowerCase()) - .append("\",\"selected\":") - .append("false") - .append("}\n"); - List<PointOfInterestWeatherStation> stations = SessionControllerGetter.getPointOfInterestBean().getAllWeatherStations(); + .append("-1") + .append("\", \"label\":\"") + .append(this.getI18nImpl().getText("pleaseSelect", language)).append(" ") + .append(this.getI18nImpl().getText("weatherStationPointOfInterestId", language).toLowerCase()) + .append("\",\"selected\":") + .append("false") + .append("}\n"); + List<PointOfInterestWeatherStation> stations = + SessionControllerGetter.getPointOfInterestBean().getAllWeatherStations(); Collections.sort(stations); - for(PointOfInterest station:stations) - { + for (PointOfInterest station : stations) { retVal.append(" ,{\"value\":\"") .append(station.getPointOfInterestId()) .append("\", \"label\":\"") @@ -208,9 +213,9 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{ .append("}\n"); } - retVal .append(" ]") + retVal.append(" ]") .append(" }"); - retVal .append(" ,{") + retVal.append(" ,{") .append(" \"name\":\"organizationId\",") .append(" \"dataType\":\"").append(FormField.DATA_TYPE_INTEGER).append("\",") .append(" \"fieldType\":\"").append(FormField.FIELD_TYPE_SELECT_SINGLE).append("\",") @@ -218,18 +223,18 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{ .append(" \"required\":false,") .append(" \"options\": ["); - + retVal.append(" {\"value\":\"") - .append("-1") - .append("\", \"label\":\"") - .append(this.getI18nImpl().getText("pleaseSelect", language)).append(" ").append(this.getI18nImpl().getText("organizationId", language).toLowerCase()) - .append("\",\"selected\":") - .append("false") - .append("}\n"); + .append("-1") + .append("\", \"label\":\"") + .append(this.getI18nImpl().getText("pleaseSelect", language)).append(" ") + .append(this.getI18nImpl().getText("organizationId", language).toLowerCase()) + .append("\",\"selected\":") + .append("false") + .append("}\n"); List<Organization> organizations = SessionControllerGetter.getUserBean().getOrganizations(); - //Collections.sort(organizations); - for(Organization organization:organizations) - { + // Collections.sort(organizations); + for (Organization organization : organizations) { retVal.append(" ,{\"value\":\"") .append(organization.getOrganizationId()) .append("\", \"label\":\"") @@ -239,7 +244,7 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{ .append("}\n"); } - retVal .append(" ]") + retVal.append(" ]") .append(" }") .append(" ]") .append("}"); @@ -248,13 +253,11 @@ public class RunAllForecastConfigurationsTask extends VipsLogicTask{ return retVal.toString(); } - private I18nImpl getI18nImpl() - { - if(this.i18n == null) - { + private I18nImpl getI18nImpl() { + if (this.i18n == null) { this.i18n = new I18nImpl("no.nibio.vips.logic.i18n.vipslogictexts"); } return this.i18n; } - + } diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunForecastConfigurationsByIdTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunForecastConfigurationsByIdTask.java index 040696291b7e24e51f9c5666c96492cf50c37066..907f8a2e4b957e991b8f56983a799c46ac2a0bb2 100644 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunForecastConfigurationsByIdTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunForecastConfigurationsByIdTask.java @@ -20,7 +20,7 @@ package no.nibio.vips.logic.scheduling.tasks; import it.sauronsoftware.cron4j.TaskExecutionContext; import java.util.Map; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.i18n.I18nImpl; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.SessionControllerGetter; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunGridModelsTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunGridModelsTask.java deleted file mode 100644 index 072565dfb10c5a919ccda14937fd3c5bcd6453eb..0000000000000000000000000000000000000000 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/RunGridModelsTask.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2018 NIBIO <http://www.nibio.no/>. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - */ - -package no.nibio.vips.logic.scheduling.tasks; - -import it.sauronsoftware.cron4j.TaskExecutionContext; -import javax.ejb.EJB; -import no.nibio.vips.logic.controller.session.ForecastBean; -import no.nibio.vips.logic.controller.session.SessionControllerGetter; -import no.nibio.vips.logic.entity.ForecastConfiguration; -import no.nibio.vips.logic.scheduling.SchedulingUtil; -import no.nibio.vips.logic.scheduling.VipsLogicTask; -import no.nibio.vips.logic.scheduling.model.PreprocessorException; -import no.nibio.vips.logic.util.RunModelException; - -/** - * @copyright 2018-2022 <a href="http://www.nibio.no/">NIBIO</a> - * @author Tor-Einar Skog <tor-einar.skog@nibio.no> - */ -public class RunGridModelsTask extends VipsLogicTask{ - - @Override - public String getConfigFormDefinition(String language) { - return "{\"fields\":[]}"; - } - - @Override - public void execute(TaskExecutionContext tec) throws RuntimeException { - tec.setCompleteness(0.0); - //ZymoseptoriaSimpleRiskGridModelPreprocessor pp = new ZymoseptoriaSimpleRiskGridModelPreprocessor(); - // TODO: Must find a forecast configuration id! -1000 ! - - ForecastConfiguration fConfig = SessionControllerGetter.getForecastBean().getForecastConfiguration(-1000l); - - try - { - SessionControllerGetter.getForecastBean().runForecast(fConfig); - tec.setCompleteness(1.0); - } - catch(PreprocessorException | RunModelException ex) - { - tec.setCompleteness(0.0); - tec.setStatusMessage(SchedulingUtil.createSchedulingMessageHTML( - "Error with forecast #" + fConfig.getForecastConfigurationId(), - ex.getMessage(), - SchedulingUtil.MESSAGE_STATUS_DANGER - ) - ); - - ex.printStackTrace(); - throw new RuntimeException(); - } - } - - @Override - public boolean supportsStatusTracking() - { - return true; - } - - @Override - public boolean supportsCompletenessTracking() - { - return true; - } -} diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java index 25bb6d3bada9ed28bc18025dfe26f9a93de13ebe..74a0f84114afa4b1a8fc8a70f146c4a22180c0e7 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/SendForecastEventNotificationsTask.java @@ -19,7 +19,7 @@ package no.nibio.vips.logic.scheduling.tasks; import it.sauronsoftware.cron4j.TaskExecutionContext; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.controller.session.SessionControllerGetter; import no.nibio.vips.logic.messaging.MessagingBean; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastResultCacheTableTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastResultCacheTableTask.java index 3824b616929467244f8664ff0b01c67c3aef3990..91e4acc2a0ebde40a3f984a869ccb4ef9563ba56 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastResultCacheTableTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastResultCacheTableTask.java @@ -19,7 +19,7 @@ package no.nibio.vips.logic.scheduling.tasks; import it.sauronsoftware.cron4j.TaskExecutionContext; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.SessionControllerGetter; import no.nibio.vips.logic.scheduling.VipsLogicTask; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastSummaryTableTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastSummaryTableTask.java index 8533acad16c6e46c7d38a4b314c069d953356787..4cf5d4d51a499a6ca283c934d1d2f8e58e3df4f1 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastSummaryTableTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateForecastSummaryTableTask.java @@ -19,7 +19,7 @@ package no.nibio.vips.logic.scheduling.tasks; import it.sauronsoftware.cron4j.TaskExecutionContext; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.SessionControllerGetter; import no.nibio.vips.logic.scheduling.VipsLogicTask; diff --git a/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateModelInformationTask.java b/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateModelInformationTask.java index b87173d48c85af8bdd95c7a58238a686f7efb8e1..523a9aa0206b793b4516d8e33b10be10c7b8f159 100755 --- a/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateModelInformationTask.java +++ b/src/main/java/no/nibio/vips/logic/scheduling/tasks/UpdateModelInformationTask.java @@ -19,7 +19,7 @@ package no.nibio.vips.logic.scheduling.tasks; import it.sauronsoftware.cron4j.TaskExecutionContext; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.SessionControllerGetter; import no.nibio.vips.logic.scheduling.TaskResult; diff --git a/src/main/java/no/nibio/vips/logic/service/AuthenticationService.java b/src/main/java/no/nibio/vips/logic/service/AuthenticationService.java index c2155424c0884a3c7a5b615df67453293e181424..5433ab8f73ce686d8440745e0d4b0009dcf7b0f4 100644 --- a/src/main/java/no/nibio/vips/logic/service/AuthenticationService.java +++ b/src/main/java/no/nibio/vips/logic/service/AuthenticationService.java @@ -21,24 +21,24 @@ import java.util.HashMap; import java.util.Map; import java.util.UUID; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ObjectNode; import com.webcohesion.enunciate.metadata.rs.TypeHint; -import javax.ejb.EJB; +import jakarta.ejb.EJB; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.entity.UserUuid; diff --git a/src/main/java/no/nibio/vips/logic/service/JSONBConfig.java b/src/main/java/no/nibio/vips/logic/service/JSONBConfig.java index 814f9ce13dfbd12d88fae850df396295a50a7cc8..6fef0190743b23c0ebc15a59bd8e2155c5b48102 100644 --- a/src/main/java/no/nibio/vips/logic/service/JSONBConfig.java +++ b/src/main/java/no/nibio/vips/logic/service/JSONBConfig.java @@ -18,15 +18,15 @@ package no.nibio.vips.logic.service; -import javax.json.bind.Jsonb; -import javax.json.bind.JsonbBuilder; -import javax.json.bind.JsonbConfig; -import javax.json.bind.annotation.JsonbDateFormat; -import javax.ws.rs.Consumes; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.ContextResolver; -import javax.ws.rs.ext.Provider; +import jakarta.json.bind.Jsonb; +import jakarta.json.bind.JsonbBuilder; +import jakarta.json.bind.JsonbConfig; +import jakarta.json.bind.annotation.JsonbDateFormat; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.ext.ContextResolver; +import jakarta.ws.rs.ext.Provider; import java.util.logging.Level; import java.util.logging.Logger; @@ -40,7 +40,7 @@ import java.util.logging.Logger; @Provider @Produces(MediaType.APPLICATION_JSON) //@Consumes(MediaType.APPLICATION_JSON) -public class JSONBConfig implements ContextResolver<javax.json.bind.Jsonb> +public class JSONBConfig implements ContextResolver<jakarta.json.bind.Jsonb> { //private final ObjectMapper objectMapper; private final Jsonb jsonB; diff --git a/src/main/java/no/nibio/vips/logic/service/JacksonConfig.java b/src/main/java/no/nibio/vips/logic/service/JacksonConfig.java index 78a7a337f55e22944a9e75a914bf8b98259643ca..6c64b6db345d89facbc3ac71004f445026103ac8 100755 --- a/src/main/java/no/nibio/vips/logic/service/JacksonConfig.java +++ b/src/main/java/no/nibio/vips/logic/service/JacksonConfig.java @@ -25,11 +25,11 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.text.SimpleDateFormat; -import javax.ws.rs.Consumes; -import javax.ws.rs.Produces; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.ext.ContextResolver; -import javax.ws.rs.ext.Provider; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.ext.ContextResolver; +import jakarta.ws.rs.ext.Provider; /** * Add this to no.nibio.vips.logic.VIPSLogicApplication if you want all diff --git a/src/main/java/no/nibio/vips/logic/service/LogicService.java b/src/main/java/no/nibio/vips/logic/service/LogicService.java index e4d7b5d0f7fe06aed8b1b0e81de170acda3a840d..28c15783c57823b5f38f615392ae3cf7a72fefa1 100755 --- a/src/main/java/no/nibio/vips/logic/service/LogicService.java +++ b/src/main/java/no/nibio/vips/logic/service/LogicService.java @@ -18,40 +18,75 @@ package no.nibio.vips.logic.service; -import com.fasterxml.jackson.core.JsonProcessingException; +import java.io.IOException; +import java.text.DateFormat; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.UUID; +import java.util.stream.Collectors; +import jakarta.ejb.EJB; +import jakarta.persistence.NonUniqueResultException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.Consumes; +import jakarta.ws.rs.DELETE; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.POST; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import org.apache.commons.validator.routines.EmailValidator; +import org.jboss.resteasy.annotations.GZIP; +import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; +import org.jboss.resteasy.spi.HttpRequest; import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.ibm.icu.util.ULocale; import com.webcohesion.enunciate.metadata.Facet; import com.webcohesion.enunciate.metadata.rs.TypeHint; - -import java.io.IOException; -import java.util.*; - import de.micromata.opengis.kml.v_2_2_0.Kml; -import java.text.DateFormat; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.logging.Logger; -import java.util.stream.Collectors; -import javax.ejb.EJB; -import javax.persistence.NonUniqueResultException; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; import no.nibio.vips.coremanager.service.ManagerResource; import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.logic.authenticate.PasswordValidationException; -import no.nibio.vips.logic.controller.servlet.UserController; -import no.nibio.vips.logic.controller.session.*; -import no.nibio.vips.logic.entity.*; +import no.nibio.vips.logic.controller.session.DeleteUserException; +import no.nibio.vips.logic.controller.session.ForecastBean; +import no.nibio.vips.logic.controller.session.MessageBean; +import no.nibio.vips.logic.controller.session.OrganismBean; +import no.nibio.vips.logic.controller.session.PointOfInterestBean; +import no.nibio.vips.logic.controller.session.UserBean; +import no.nibio.vips.logic.entity.CropCategory; +import no.nibio.vips.logic.entity.CropPest; +import no.nibio.vips.logic.entity.ForecastConfiguration; +import no.nibio.vips.logic.entity.ForecastModelConfiguration; +import no.nibio.vips.logic.entity.ForecastResult; +import no.nibio.vips.logic.entity.Message; +import no.nibio.vips.logic.entity.MessageTag; +import no.nibio.vips.logic.entity.ModelInformation; +import no.nibio.vips.logic.entity.Organism; +import no.nibio.vips.logic.entity.Organization; +import no.nibio.vips.logic.entity.PointOfInterest; +import no.nibio.vips.logic.entity.PointOfInterestType; +import no.nibio.vips.logic.entity.PointOfInterestWeatherStation; +import no.nibio.vips.logic.entity.UserAuthentication; +import no.nibio.vips.logic.entity.UserAuthenticationType; +import no.nibio.vips.logic.entity.VipsLogicRole; +import no.nibio.vips.logic.entity.VipsLogicUser; import no.nibio.vips.logic.i18n.SessionLocaleUtil; import no.nibio.vips.logic.util.Globals; import no.nibio.vips.logic.util.SystemTime; @@ -60,11 +95,6 @@ import no.nibio.vips.util.CSVPrintUtil; import no.nibio.vips.util.ServletUtil; import no.nibio.vips.util.SolarRadiationUtil; import no.nibio.web.forms.FormValidationException; -import org.jboss.resteasy.annotations.GZIP; -import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget; -import org.jboss.resteasy.spi.HttpRequest; - -import org.apache.commons.validator.routines.EmailValidator; /** * @copyright 2013-2023 <a href="http://www.nibio.no/">NIBIO</a> @@ -976,8 +1006,11 @@ public class LogicService { public Response getMessage(@PathParam("messageId") Integer messageId) { Message message = messageBean.getMessage(messageId); - - return Response.ok().entity(message).build(); + if(message != null) + { + return Response.ok().entity(message).build(); + } + return Response.status(Status.NOT_FOUND).build(); } /** @@ -1310,6 +1343,15 @@ public class LogicService { { return Response.ok().entity(userBean.getOrganizations()).build(); } + + @GET + @Path("organization/{organizationId}") + @Produces("application/json;charset=UTF-8") + @TypeHint(Organization[].class) + public Response getOrganizations(@PathParam("organizationId") Integer organizationId) + { + return Response.ok().entity(userBean.getOrganization(organizationId)).build(); + } @GET @Path("model/{modelId}") diff --git a/src/main/java/no/nibio/vips/logic/service/ModelFormService.java b/src/main/java/no/nibio/vips/logic/service/ModelFormService.java index c1c739baa829e0672830c473feb08357555712f5..f629605ea96e382d73fcd8a0f5466567c0b71a0d 100644 --- a/src/main/java/no/nibio/vips/logic/service/ModelFormService.java +++ b/src/main/java/no/nibio/vips/logic/service/ModelFormService.java @@ -18,23 +18,25 @@ package no.nibio.vips.logic.service; -import com.webcohesion.enunciate.metadata.rs.TypeHint; -import org.locationtech.jts.geom.Coordinate; -import com.webcohesion.enunciate.metadata.Facet; import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.TimeZone; -import javax.ejb.EJB; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Response; +import org.locationtech.jts.geom.Coordinate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.webcohesion.enunciate.metadata.Facet; +import com.webcohesion.enunciate.metadata.rs.TypeHint; +import jakarta.ejb.EJB; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; import no.nibio.vips.entity.ModelConfiguration; import no.nibio.vips.entity.Result; -import no.nibio.vips.entity.WeatherObservation; import no.nibio.vips.gis.GISUtil; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.PointOfInterestBean; @@ -44,6 +46,7 @@ import no.nibio.vips.logic.entity.ForecastModelConfiguration; import no.nibio.vips.logic.entity.ForecastModelConfigurationPK; import no.nibio.vips.logic.entity.Organization; import no.nibio.vips.logic.entity.PointOfInterestWeatherStation; +import no.nibio.vips.logic.entity.VipsLogicUser; import no.nibio.vips.logic.entity.WeatherStationDataSource; import no.nibio.vips.logic.scheduling.model.PreprocessorException; import no.nibio.vips.logic.scheduling.model.preprocessor.SeptoriaHumidityModelPreprocessor; @@ -52,7 +55,6 @@ import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.util.ParseRESTParamUtil; import no.nibio.vips.util.WeatherUtil; import no.nibio.vips.util.XDate; -import no.nibio.vips.util.weather.WeatherDataSourceUtil; /** * This is a collection of (one) service(s) for models run from forms (not as part of batch) @@ -62,7 +64,8 @@ import no.nibio.vips.util.weather.WeatherDataSourceUtil; @Path("rest/modelform") @Facet("restricted") public class ModelFormService { - + private static final Logger LOGGER = LoggerFactory.getLogger(ModelFormService.class); + @EJB UserBean userBean; @EJB @@ -100,6 +103,10 @@ public class ModelFormService { @TypeHint(Result.class) public Response runSeptoriaHumidityModel( @QueryParam("organizationId_countryCode") String organizationId_countryCode, + @QueryParam("weatherDataSourceType") String weatherDataSourceType, + @QueryParam("latitude") String latitudeStr, + @QueryParam("longitude") String longitudeStr, + @QueryParam("timezone") String timezoneStr, @QueryParam("weatherStationId") String weatherStationId, // Could be special ID from Danish system, @QueryParam("dateSpraying1") String dateSpraying1, @QueryParam("dateSpraying2") String dateSpraying2, @@ -119,7 +126,9 @@ public class ModelFormService { ){ try { + ParseRESTParamUtil pUtil = new ParseRESTParamUtil(); ForecastConfiguration fConf = new ForecastConfiguration(); + fConf.setModelId("SEPTORIAHU"); Set<ForecastModelConfiguration> fModelConf = new HashSet<>(); @@ -139,16 +148,57 @@ public class ModelFormService { fModelConf.add(this.getForecastModelConfiguration(fConf.getModelId(),"sprayingProtectionDays", String.valueOf(sprayingProtectionDays))); fModelConf.add(this.getForecastModelConfiguration(fConf.getModelId(),"leafLifeTime", String.valueOf(leafLifeTime))); fConf.setForecastModelConfigurationSet(fModelConf); - - // Data parsing - Integer organizationId = Integer.valueOf(organizationId_countryCode.split("_")[0]); - Organization organization = userBean.getOrganization(organizationId); - fConf.setTimeZone(organization.getDefaultTimeZone()); - TimeZone timeZone = TimeZone.getTimeZone(organization.getDefaultTimeZone()); - ParseRESTParamUtil pUtil = new ParseRESTParamUtil(); + PointOfInterestWeatherStation ws = null; + + // Default organization is Norway + Organization organization = userBean.getOrganization(1); + VipsLogicUser vipsLogicUser = userBean.getVipsLogicUser(organization.getDefaultVipsCoreUserId()); + String timezoneForWeatherData = organization.getDefaultTimeZone(); + + // If source of weather data is a weather station + if("weatherstation".equals(weatherDataSourceType)) { + String[] organizationIdCountryCode = organizationId_countryCode.split("_"); + organization = userBean.getOrganization(Integer.parseInt(organizationIdCountryCode[0])); + String countryCode = organizationIdCountryCode[1]; + timezoneForWeatherData = organization.getDefaultTimeZone(); + if(countryCode.equalsIgnoreCase("dk")) { + // Create a synthetic weather station to pass into the system + // Weather station id is a UTM32N coordinate, e.g. E552700N6322400 + String[] parts = weatherStationId.split("N"); + int UTM32vE = Integer.parseInt(parts[0].substring(1)); + int UTM32vN = Integer.parseInt(parts[1]); + GISUtil gisUtil = new GISUtil(); + Coordinate UTMc = new Coordinate(UTM32vE, UTM32vN); + Coordinate coordinate = gisUtil.convertCoordinate(UTMc, "EPSG:32632", "EPSG:4326"); + WeatherStationDataSource wsds = pointOfInterestBean.getWeatherStationDataSource("DMI PointWeb"); + ws = new PointOfInterestWeatherStation(); + ws.setWeatherStationDataSourceId(wsds); + ws.setWeatherStationRemoteId( + coordinate.y + "," + coordinate.x);// For some reason, The transformation switches X/Y + ws.setTimeZone(timezoneForWeatherData); + } else { + // Weather station id maps to a regular weather station + ws = (PointOfInterestWeatherStation) pointOfInterestBean.getPointOfInterest(Integer.valueOf(weatherStationId)); + } + } else if("grid".equals(weatherDataSourceType)) { + fConf.setUseGridWeatherData(true); + timezoneForWeatherData = timezoneStr; + ws = new PointOfInterestWeatherStation(); + ws.setLatitude(pUtil.parseDouble(latitudeStr)); + ws.setLongitude(pUtil.parseDouble(longitudeStr)); + ws.setTimeZone(timezoneForWeatherData); + } + else { + return Response.status(Status.BAD_REQUEST).entity("Please specify weatherDataSourceType (weatherstation|grid)").build(); + } + + fConf.setVipsCoreUserId(vipsLogicUser); + fConf.setTimeZone(timezoneForWeatherData); + + TimeZone timeZone = TimeZone.getTimeZone(timezoneForWeatherData); // Start time is gs31, easy - Date gs31 = pUtil.parseISODate(dateGs31,timeZone); + Date gs31 = pUtil.parseISODate(dateGs31, timeZone); XDate startTime = new XDate(gs31); startTime.addDays(-1); // End time is whatever comes first of the day after tomorrow or Gs75 @@ -163,47 +213,22 @@ public class ModelFormService { fConf.setDateStart(startTime); fConf.setDateEnd(endTime); - String countryCode = organizationId_countryCode.split("_")[1]; - List<WeatherObservation> observations; - WeatherDataSourceUtil wdsUtil = new WeatherDataSourceUtil(); - PointOfInterestWeatherStation ws; - if(countryCode.toLowerCase().equals("dk")){ - // Create a synthetic weather station to pass into the system - // Weather station id is a UTM32N coordinate, e.g. E552700N6322400 - String[] parts = weatherStationId.split("N"); - Integer UTM32vE = Integer.valueOf(parts[0].substring(1)); - Integer UTM32vN = Integer.valueOf(parts[1]); - GISUtil gisUtil = new GISUtil(); - Coordinate UTMc = new Coordinate(UTM32vE, UTM32vN); - Coordinate coordinate = gisUtil.convertCoordinate(UTMc, "EPSG:32632", "EPSG:4326"); - WeatherStationDataSource wsds = pointOfInterestBean.getWeatherStationDataSource("DMI PointWeb"); - ws = new PointOfInterestWeatherStation(); - ws.setWeatherStationDataSourceId(wsds); - ws.setWeatherStationRemoteId(coordinate.y + "," + coordinate.x);// For some reason, The transformation switches X/Y - ws.setTimeZone(organization.getDefaultTimeZone()); - - //observations.stream().forEach(obs->System.out.println(obs.toString())); - } - else - { - // Weather station id maps to a regular weather station - ws = (PointOfInterestWeatherStation) pointOfInterestBean.getPointOfInterest(Integer.valueOf(weatherStationId)); - } - fConf.setWeatherStationPointOfInterestId(ws); fConf.setLocationPointOfInterestId(ws); - + fConf.setWeatherStationPointOfInterestId(ws); + ModelConfiguration mConf = new SeptoriaHumidityModelPreprocessor().getModelConfiguration(fConf); Integer VIPSCoreUserId = organization.getDefaultVipsCoreUserId(); - List<Result>results = forecastBean.runForecast(mConf, VIPSCoreUserId); + List<Result> results = forecastBean.runForecast(mConf, VIPSCoreUserId); return Response.ok().entity(results).build(); } - catch(PreprocessorException |RunModelException ex) + catch(PreprocessorException | RunModelException ex) { + LOGGER.error("Exception occurred when attempting to run the septoria humidity model", ex); return Response.serverError().entity(ex.getMessage()).build(); - } + } } private ForecastModelConfiguration getForecastModelConfiguration(String modelId, String key, String value) diff --git a/src/main/java/no/nibio/vips/logic/service/ObservationService.java b/src/main/java/no/nibio/vips/logic/service/ObservationService.java index d7a51f2c35f3d974019d09990e3893ff00f58912..ec922c16830e8479ea1960de142306d362294560 100755 --- a/src/main/java/no/nibio/vips/logic/service/ObservationService.java +++ b/src/main/java/no/nibio/vips/logic/service/ObservationService.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2022 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2022 NIBIO <http://www.nibio.no/>. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by @@ -22,79 +22,71 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.ibm.icu.util.ULocale; import com.webcohesion.enunciate.metadata.rs.TypeHint; - -import java.io.IOException; -import java.net.URI; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; -import javax.ejb.EJB; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.DELETE; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.MediaType; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; +import no.nibio.vips.gis.GISUtil; import no.nibio.vips.logic.controller.session.ObservationBean; +import no.nibio.vips.logic.controller.session.ObservationTimeSeriesBean; import no.nibio.vips.logic.controller.session.OrganismBean; import no.nibio.vips.logic.controller.session.UserBean; - import no.nibio.vips.logic.entity.*; import no.nibio.vips.logic.entity.rest.ObservationListItem; import no.nibio.vips.logic.entity.rest.PointMappingResponse; import no.nibio.vips.logic.entity.rest.ReferencedPoint; import no.nibio.vips.logic.messaging.MessagingBean; +import no.nibio.vips.logic.util.ExcelFileGenerator; import no.nibio.vips.logic.util.GISEntityUtil; import no.nibio.vips.logic.util.Globals; import org.jboss.resteasy.annotations.GZIP; -import org.wololo.geojson.Feature; - +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.Point; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.wololo.geojson.FeatureCollection; +import org.wololo.geojson.Feature; import org.wololo.geojson.GeoJSON; +import jakarta.ejb.EJB; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; +import java.io.IOException; +import java.net.URI; +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; +import java.util.*; +import java.util.stream.Collectors; + /** - * @copyright 2016-2022 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + * @copyright 2016-2022 <a href="http://www.nibio.no/">NIBIO</a> */ @Path("rest/observation") public class ObservationService { - + private final static Logger LOGGER = LoggerFactory.getLogger(ObservationService.class); - - @Context - private HttpServletRequest httpServletRequest; - @EJB UserBean userBean; @EJB ObservationBean observationBean; @EJB OrganismBean organismBean; + + @EJB + ObservationTimeSeriesBean observationTimeSeriesBean; @EJB MessagingBean messagingBean; - + @Context + private HttpServletRequest httpServletRequest; + /* * PostGIS tip: * How to query for observations within a bounding box @@ -102,16 +94,15 @@ public class ObservationService { * ST_SetSRID(ST_MakeBox2D(ST_MakePoint(2.9004, 57.7511), ST_MakePoint(32.4316, 71.3851)),4326), * gis_geom); * First point is SW, last is NE (but could be anything?) - */ - + */ + /** - * * @param organizationId Database ID of the organization - * @param pestId Database ID of the pest - * @param cropId Database ID of the crop + * @param pestId Database ID of the pest + * @param cropId Database ID of the crop * @param cropCategoryId Database IDs of the crop category/categories - * @param fromStr format "yyyy-MM-dd" - * @param toStr format "yyyy-MM-dd" + * @param fromStr format "yyyy-MM-dd" + * @param toStr format "yyyy-MM-dd" * @return Observation objects with all data (full tree) */ @GET @@ -120,34 +111,35 @@ public class ObservationService { @Produces("application/json;charset=UTF-8") @TypeHint(Observation[].class) public Response getFilteredObservations( - @PathParam("organizationId") Integer organizationId, - @QueryParam("pestId") Integer pestId, - @QueryParam("cropId") Integer cropId, - @QueryParam("cropCategoryId") List<Integer> cropCategoryId, - @QueryParam("from") String fromStr, - @QueryParam("to") String toStr, - @QueryParam("isPositive") Boolean isPositive - ) - { + @PathParam("organizationId") Integer organizationId, + @QueryParam("observationTimeSeriesId") Integer observationTimeSeriesId, + @QueryParam("pestId") Integer pestId, + @QueryParam("cropId") Integer cropId, + @QueryParam("cropCategoryId") List<Integer> cropCategoryId, + @QueryParam("from") String fromStr, + @QueryParam("to") String toStr, + @QueryParam("isPositive") Boolean isPositive + ) { return Response.ok().entity(getFilteredObservationsFromBackend( - organizationId, - pestId, - cropId, - cropCategoryId, - fromStr, - toStr, - isPositive + organizationId, + observationTimeSeriesId, + pestId, + cropId, + cropCategoryId, + fromStr, + toStr, + isPositive )).build(); } - + /** - * - * @param organizationId Database ID of the organization - * @param pestId Database ID of the pest - * @param cropId Database ID of the crop - * @param cropCategoryId cropCategoryId Database IDs of the crop category/categories - * @param fromStr format "yyyy-MM-dd" - * @param toStr format "yyyy-MM-dd" + * @param organizationId Database ID of the organization + * @param observationTimeSeriesId Database ID of the observation time series + * @param pestId Database ID of the pest + * @param cropId Database ID of the crop + * @param cropCategoryId cropCategoryId Database IDs of the crop category/categories + * @param fromStr format "yyyy-MM-dd" + * @param toStr format "yyyy-MM-dd" * @return Observation objects for which the user is authorized to observe with properties relevant for lists */ @GET @@ -155,89 +147,197 @@ public class ObservationService { @GZIP @Produces("application/json;charset=UTF-8") @TypeHint(ObservationListItem.class) - public Response getFilteredObservationListItems( - @PathParam("organizationId") Integer organizationId, - @QueryParam("pestId") Integer pestId, - @QueryParam("cropId") Integer cropId, - @QueryParam("cropCategoryId") List<Integer> cropCategoryId, - @QueryParam("from") String fromStr, - @QueryParam("to") String toStr, - @QueryParam("userUUID") String userUUID, - @QueryParam("locale") String localeStr, - @QueryParam("isPositive") Boolean isPositive - ) - { - VipsLogicUser user = (VipsLogicUser) httpServletRequest.getSession().getAttribute("user"); - - if(user == null && userUUID != null) - { - user = userBean.findVipsLogicUser(UUID.fromString(userUUID)); + public Response getFilteredObservationListItemsAsJson( + @PathParam("organizationId") Integer organizationId, + @QueryParam("observationTimeSeriesId") Integer observationTimeSeriesId, + @QueryParam("pestId") Integer pestId, + @QueryParam("cropId") Integer cropId, + @QueryParam("cropCategoryId") List<Integer> cropCategoryId, + @QueryParam("from") String fromStr, + @QueryParam("to") String toStr, + @QueryParam("userUUID") String userUUID, + @QueryParam("locale") String localeStr, + @QueryParam("isPositive") Boolean isPositive + ) { + return Response.ok().entity(this.getFilteredObservationListItems(organizationId, observationTimeSeriesId, pestId, cropId, cropCategoryId, fromStr, toStr, userUUID, localeStr, isPositive)).build(); + } + + /** + * @param organizationId Database ID of the organization + * @param observationTimeSeriesId Database ID of the observation time series + * @param pestId Database ID of the pest + * @param cropId Database ID of the crop + * @param cropCategoryId cropCategoryId Database IDs of the crop category/categories + * @param fromStr format "yyyy-MM-dd" + * @param toStr format "yyyy-MM-dd" + * @return Observation objects for which the user is authorized to observe with properties relevant for lists + */ + @GET + @Path("list/filter/{organizationId}/xlsx") + @GZIP + @Produces("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") + public Response getFilteredObservationListItemsAsXlsx( + @PathParam("organizationId") Integer organizationId, + @QueryParam("observationTimeSeriesId") Integer observationTimeSeriesId, + @QueryParam("pestId") Integer pestId, + @QueryParam("cropId") Integer cropId, + @QueryParam("cropCategoryId") List<Integer> cropCategoryId, + @QueryParam("from") String fromStr, + @QueryParam("to") String toStr, + @QueryParam("userUUID") String userUUID, + @QueryParam("locale") String localeStr, + @QueryParam("isPositive") Boolean isPositive + ) { + VipsLogicUser user = getVipsLogicUser(userUUID); + ULocale locale = new ULocale(localeStr != null ? localeStr : + user != null ? user.getOrganizationId().getDefaultLocale() : + userBean.getOrganization(organizationId).getDefaultLocale()); + LOGGER.info("Generate xlsx file for observations for user {} from {} to {}", user != null ? user.getUserId() : "unregistered", fromStr, toStr); + + LocalDateTime now = LocalDateTime.now(); + DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss"); + String filenameTimestamp = now.format(formatter); + + try { + List<ObservationListItem> observations = getFilteredObservationListItems(organizationId, observationTimeSeriesId, pestId, cropId, cropCategoryId, fromStr, toStr, userUUID, localeStr, isPositive); + byte[] excelFile = ExcelFileGenerator.generateExcel(user, locale, now, fromStr, toStr, observations); + + return Response + .ok(excelFile) + .header("Content-Disposition", "attachment; filename=\"" + filenameTimestamp + "-observations.xlsx\"") + .build(); + } catch (IOException e) { + LOGGER.error(e.getMessage()); + return Response.serverError().entity("Error generating Excel file: " + e.getMessage()).build(); } - ULocale locale = new ULocale(localeStr != null ? localeStr : - user != null ? user.getOrganizationId().getDefaultLocale() : - userBean.getOrganization(organizationId).getDefaultLocale()); + } + + private List<ObservationListItem> getFilteredObservationListItems( + Integer organizationId, + Integer observationTimeSeriesId, + Integer pestId, + Integer cropId, + List<Integer> cropCategoryId, + String fromStr, + String toStr, + String userUUID, + String localeStr, + Boolean isPositive) { + VipsLogicUser user = getVipsLogicUser(userUUID); + ULocale locale = new ULocale(localeStr != null ? localeStr : + user != null ? user.getOrganizationId().getDefaultLocale() : + userBean.getOrganization(organizationId).getDefaultLocale()); + LOGGER.info("Get filtered observations for user {}", user != null ? user.getUserId() : "<no user>"); List<ObservationListItem> observations = getFilteredObservationsFromBackend( - organizationId, - pestId, - cropId, - cropCategoryId, - fromStr, - toStr, - isPositive, - user - ).stream().map(obs -> { - try { - return obs.getListItem(locale.getLanguage(), - observationBean.getLocalizedObservationDataSchema( - observationBean.getObservationDataSchema(organizationId, obs.getOrganismId()), - httpServletRequest, - locale - ) - ); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - }).collect(Collectors.toList()); + organizationId, + observationTimeSeriesId, + pestId, + cropId, + cropCategoryId, + fromStr, + toStr, + isPositive, + user + ).stream().map(obs -> { + try { + return obs.getListItem(locale.getLanguage(), + observationBean.getLocalizedObservationDataSchema( + observationBean.getObservationDataSchema(organizationId, obs.getOrganismId()), + httpServletRequest, + locale + ) + ); + } catch (IOException e) { + LOGGER.error("Exception when getting localized observation data schema for observation " + obs.getObservationId(), e); + return null; + } + }).collect(Collectors.toList()); //o.setObservationDataSchema(observationBean.getObservationDataSchema(observer.getOrganizationId().getOrganizationId(), o.getOrganismId())); - return Response.ok().entity(observations).build(); + return observations; } /** - * * @param organizationId Database ID of the organization - * @param pestId Database ID of the pest - * @param cropId Database ID of the crop + * @param pestId Database ID of the pest + * @param cropId Database ID of the crop * @param cropCategoryId cropCategoryId Database IDs of the crop category/categories - * @param fromStr format "yyyy-MM-dd" - * @param toStr format "yyyy-MM-dd" + * @param fromStr format "yyyy-MM-dd" + * @param toStr format "yyyy-MM-dd" + * @return Observation objects for which the user is authorized to observe with properties relevant for lists + */ + @GET + @Path("list/filter/{organizationId}/csv") + @GZIP + @Produces("text/csv;charset=UTF-8") + @TypeHint(ObservationListItem.class) + public Response getFilteredObservationListItemsAsCSV( + @PathParam("organizationId") Integer organizationId, + @QueryParam("observationTimeSeriesId") Integer observationTimeSeriesId, + @QueryParam("pestId") Integer pestId, + @QueryParam("cropId") Integer cropId, + @QueryParam("cropCategoryId") List<Integer> cropCategoryId, + @QueryParam("from") String fromStr, + @QueryParam("to") String toStr, + @QueryParam("userUUID") String userUUID, + @QueryParam("locale") String localeStr, + @QueryParam("isPositive") Boolean isPositive + ) { + List<ObservationListItem> observations = this.getFilteredObservationListItems(organizationId, observationTimeSeriesId, pestId, cropId, cropCategoryId, fromStr, toStr, userUUID, localeStr, isPositive); + Collections.sort(observations); + String retVal = "ObservationID;organismName;cropOrganismName;timeOfObservation;lat/lon;observationHeading;observationData"; + GISUtil gisUtil = new GISUtil(); + for (ObservationListItem obs : observations) { + // Get latlon from geoInfo + List<Geometry> geometries = gisUtil.getGeometriesFromGeoJSON(obs.getGeoInfo()); + Coordinate c = null; + if (geometries.size() == 1 && geometries.get(0) instanceof Point) { + c = ((Point) geometries.get(0)).getCoordinate(); + } + retVal += "\n" + obs.getObservationId() + + ";" + obs.getOrganismName() + + ";" + obs.getCropOrganismName() + + ";" + obs.getTimeOfObservation() + + ";" + (c != null ? c.getY() + "," + c.getX() : "") + + ";" + obs.getObservationHeading() + + ";" + obs.getObservationData(); + } + return Response.ok().entity(retVal).build(); + } + + /** + * @param organizationId Database ID of the organization + * @param observationTimeSeriesId Database ID of the observation time series + * @param pestId Database ID of the pest + * @param cropId Database ID of the crop + * @param cropCategoryId cropCategoryId Database IDs of the crop category/categories + * @param fromStr format "yyyy-MM-dd" + * @param toStr format "yyyy-MM-dd" * @return Observation objects for which the user is authorized to observe with properties relevant for lists */ private List<Observation> getFilteredObservationsFromBackend( - Integer organizationId, - Integer pestId, - Integer cropId, - List<Integer> cropCategoryId, - String fromStr, - String toStr, - Boolean isPositive - ) - { + Integer organizationId, + Integer observationTimeSeriesId, + Integer pestId, + Integer cropId, + List<Integer> cropCategoryId, + String fromStr, + String toStr, + Boolean isPositive) { SimpleDateFormat format = new SimpleDateFormat(Globals.defaultDateFormat); //TODO Set correct timeZone!!! Date from = null; Date to = null; - try - { + try { from = fromStr != null ? format.parse(fromStr) : null; to = toStr != null ? format.parse(toStr) : null; + } catch (ParseException ex) { + LOGGER.error("Error when parsing dates", ex); } - catch(ParseException ex){ System.out.println("ERROR");} - + return observationBean.getFilteredObservations( organizationId, + observationTimeSeriesId, pestId, cropId, cropCategoryId, @@ -245,11 +345,10 @@ public class ObservationService { to, isPositive ); - + } /** - * * @param organizationId * @param pestId * @param cropId @@ -257,106 +356,104 @@ public class ObservationService { * @param fromStr * @param toStr * @return - * * @responseExample application/json * { - * "type": "FeatureCollection", - * "features": [ - * { - * "type": "Feature", - * "id": 18423, - * "geometry": { - * "type": "Point", - * "coordinates": [ - * 10.782463095356452, - * 59.35794998304658, - * 0.0 - * ] - * }, - * "properties": { - * "observationId": 18446, - * "observationHeading": "NLR Øst, Huggenes: Det er funnet potettørråte i Råde", - * "organism": { - * "organismId": 14, - * "latinName": "Phytophthora infestans", - * "tradeName": "", - * "logicallyDeleted": false, - * "isPest": true, - * "isCrop": false, - * "parentOrganismId": 124, - * "hierarchyCategoryId": 120, - * "organismLocaleSet": [ - * { - * "organismLocalePK": { - * "organismId": 14, - * "locale": "nb" - * }, - * "localName": "Potettørråte" - * }, - * { - * "organismLocalePK": { - * "organismId": 14, - * "locale": "en" - * }, - * "localName": "Late blight" - * } - * ], - * "organismExternalResourceSet": [], - * "childOrganisms": null, - * "extraProperties": {}, - * "observationDataSchema": null - * }, - * "cropOrganism": { - * "organismId": 5, - * "latinName": "Solanum tuberosum", - * "tradeName": "", - * "logicallyDeleted": false, - * "isPest": false, - * "isCrop": true, - * "parentOrganismId": 4, - * "hierarchyCategoryId": 120, - * "organismLocaleSet": [ - * { - * "organismLocalePK": { - * "organismId": 5, - * "locale": "bs" - * }, - * "localName": "Potato" - * }, - * { - * "organismLocalePK": { - * "organismId": 5, - * "locale": "nb" - * }, - * "localName": "Potet" - * }, - * { - * "organismLocalePK": { - * "organismId": 5, - * "locale": "en" - * }, - * "localName": "Potato" - * }, - * { - * "organismLocalePK": { - * "organismId": 5, - * "locale": "hr" - * }, - * "localName": "Krompir" - * } - * ], - * "organismExternalResourceSet": [], - * "childOrganisms": null, - * "extraProperties": {}, - * "observationDataSchema": null - * }, - * "observationText": "Fredag 2.juli ble det gjort første funn av potettørråte i Råde. Det er noen flekker på bladene på øvre del av planten. Smitten ser ut til å ha kommet som sekundærsmitte med vinden.", - * "timeOfObservation": "2021-07-02T11:00:00+02:00" - * } - * } - * ] + * "type": "FeatureCollection", + * "features": [ + * { + * "type": "Feature", + * "id": 18423, + * "geometry": { + * "type": "Point", + * "coordinates": [ + * 10.782463095356452, + * 59.35794998304658, + * 0.0 + * ] + * }, + * "properties": { + * "observationId": 18446, + * "observationHeading": "NLR Øst, Huggenes: Det er funnet potettørråte i Råde", + * "organism": { + * "organismId": 14, + * "latinName": "Phytophthora infestans", + * "tradeName": "", + * "logicallyDeleted": false, + * "isPest": true, + * "isCrop": false, + * "parentOrganismId": 124, + * "hierarchyCategoryId": 120, + * "organismLocaleSet": [ + * { + * "organismLocalePK": { + * "organismId": 14, + * "locale": "nb" + * }, + * "localName": "Potettørråte" + * }, + * { + * "organismLocalePK": { + * "organismId": 14, + * "locale": "en" + * }, + * "localName": "Late blight" + * } + * ], + * "organismExternalResourceSet": [], + * "childOrganisms": null, + * "extraProperties": {}, + * "observationDataSchema": null + * }, + * "cropOrganism": { + * "organismId": 5, + * "latinName": "Solanum tuberosum", + * "tradeName": "", + * "logicallyDeleted": false, + * "isPest": false, + * "isCrop": true, + * "parentOrganismId": 4, + * "hierarchyCategoryId": 120, + * "organismLocaleSet": [ + * { + * "organismLocalePK": { + * "organismId": 5, + * "locale": "bs" + * }, + * "localName": "Potato" + * }, + * { + * "organismLocalePK": { + * "organismId": 5, + * "locale": "nb" + * }, + * "localName": "Potet" + * }, + * { + * "organismLocalePK": { + * "organismId": 5, + * "locale": "en" + * }, + * "localName": "Potato" + * }, + * { + * "organismLocalePK": { + * "organismId": 5, + * "locale": "hr" + * }, + * "localName": "Krompir" + * } + * ], + * "organismExternalResourceSet": [], + * "childOrganisms": null, + * "extraProperties": {}, + * "observationDataSchema": null + * }, + * "observationText": "Fredag 2.juli ble det gjort første funn av potettørråte i Råde. Det er noen flekker på bladene på øvre del av planten. Smitten ser ut til å ha kommet som sekundærsmitte med vinden.", + * "timeOfObservation": "2021-07-02T11:00:00+02:00" + * } + * } + * ] * } - * */ @GET @Path("filter/{organizationId}/geoJSON") @@ -364,44 +461,46 @@ public class ObservationService { @Produces("application/json;charset=UTF-8") @TypeHint(GeoJSON.class) public Response getFilteredObservationsAsGeoJSON( - @PathParam("organizationId") Integer organizationId, - @QueryParam("pestId") Integer pestId, - @QueryParam("cropId") Integer cropId, - @QueryParam("cropCategoryId") List<Integer> cropCategoryId, - @QueryParam("from") String fromStr, - @QueryParam("to") String toStr, - @QueryParam("to") Boolean isPositive - - ) - { + @PathParam("organizationId") Integer organizationId, + @QueryParam("observationTimeSeriesId") Integer observationTimeSeriesId, + @QueryParam("pestId") Integer pestId, + @QueryParam("cropId") Integer cropId, + @QueryParam("cropCategoryId") List<Integer> cropCategoryId, + @QueryParam("from") String fromStr, + @QueryParam("to") String toStr, + @QueryParam("isPositive") Boolean isPositive + + ) { SimpleDateFormat format = new SimpleDateFormat(Globals.defaultDateFormat); //TODO Set correct timeZone!!! Date from = null; Date to = null; - try - { + try { from = fromStr != null ? format.parse(fromStr) : null; to = toStr != null ? format.parse(toStr) : null; + } catch (ParseException ex) { + LOGGER.error("Error when parsing dates", ex); } - catch(ParseException ex){ System.out.println("ERROR");} - - List<Observation> filteredObservations = observationBean.getFilteredObservations( + + List<Observation> filteredObservations = this.getFilteredObservationsFromBackend( organizationId, + observationTimeSeriesId, pestId, cropId, cropCategoryId, - from, - to, + fromStr, + toStr, isPositive ); - + GISEntityUtil gisUtil = new GISEntityUtil(); return Response.ok().entity(gisUtil.getGeoJSONFromObservations(filteredObservations)).build(); } - + /** * Get a list of all observed pests for one organization * Practical for building effective select lists + * * @param organizationId Database ID of organization * @return list of all observed pests for one organization */ @@ -409,30 +508,29 @@ public class ObservationService { @Path("pest/{organizationId}") @Produces("application/json;charset=UTF-8") @TypeHint(Organism[].class) - public Response getObservedPests(@PathParam("organizationId") Integer organizationId) - { + public Response getObservedPests(@PathParam("organizationId") Integer organizationId) { return Response.ok().entity(observationBean.getObservedPests(organizationId)).build(); } - + /** * Get a list of all crop cultures where observations have been made for one organization * Practical for building effective select lists * TODO: Should be cached?? + * * @param organizationId Database ID of organization - * @return + * @return */ @GET @Path("crop/{organizationId}") @Produces("application/json;charset=UTF-8") @TypeHint(Organism[].class) - public Response getObservedCrops(@PathParam("organizationId") Integer organizationId) - { + public Response getObservedCrops(@PathParam("organizationId") Integer organizationId) { return Response.ok().entity(observationBean.getObservedCrops(organizationId)).build(); } - - + /** * Publicly available observations per organization + * * @param organizationId Database ID of organization * @return APPROVED observations */ @@ -441,13 +539,14 @@ public class ObservationService { @GZIP @Produces("application/json;charset=UTF-8") @TypeHint(Observation[].class) - public Response getObservations(@PathParam("organizationId") Integer organizationId){ + public Response getObservations(@PathParam("organizationId") Integer organizationId) { return Response.ok().entity(observationBean.getObservations(organizationId, Observation.STATUS_TYPE_ID_APPROVED)).build(); } - + /** * Get observations for a user * Requires a valid UUID to be provided in the Authorization header + * * @param observationIds Comma separated list of Observation Ids * @return Filtering by observation ids */ @@ -456,66 +555,60 @@ public class ObservationService { @Produces("application/json;charset=UTF-8") @TypeHint(Observation[].class) public Response getObservationsForUser( - @QueryParam("observationIds") String observationIds - ) - { - try - { - VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); - if(user != null) - { - List<Observation> allObs = observationBean.getObservationsForUser(user); - if(observationIds != null) - { - Set<Integer> observationIdSet = Arrays.asList(observationIds.split(",")).stream() - .map(s->Integer.valueOf(s)) - .collect(Collectors.toSet()); - return Response.ok().entity( - allObs.stream() - .filter(obs->observationIdSet.contains(obs.getObservationId())) - .collect(Collectors.toList()) - ) - .build(); - } - return Response.ok().entity(allObs).build(); - } - else - { - return Response.status(Status.UNAUTHORIZED).build(); - } - } - catch(Exception e) - { - return Response.serverError().entity(e.getMessage()).build(); - } + @QueryParam("observationIds") String observationIds + ) { + LOGGER.info("getObservationsForUser for observationIds={}", observationIds); + try { + VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); + if (user != null) { + LOGGER.info("Get observations for user={}", user.getUserId()); + List<Observation> allObs = observationBean.getObservationsForUser(user); + LOGGER.info("Found {} observations for user {}", allObs.size(), user.getUserId()); + if (observationIds != null) { + Set<Integer> observationIdSet = Arrays.asList(observationIds.split(",")).stream() + .map(s -> Integer.valueOf(s)) + .collect(Collectors.toSet()); + return Response.ok().entity( + allObs.stream() + .filter(obs -> observationIdSet.contains(obs.getObservationId())) + .collect(Collectors.toList()) + ) + .build(); + } + return Response.ok().entity(allObs).build(); + } else { + return Response.status(Status.UNAUTHORIZED).build(); + } + } catch (Exception e) { + LOGGER.error("Exception when getting observations for user", e); + return Response.serverError().entity(e.getMessage()).build(); + } } - + /** * Get minimized (only synchronization info) observations for a user * Used by the Observation app * Requires a valid UUID to be provided in the Authorization header + * * @return */ @GET @Path("list/minimized/user") @Produces("application/json;charset=UTF-8") @TypeHint(ObservationSyncInfo[].class) - public Response getMinimizedObservationsForUser() - { - VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); - if(user != null) - { - return Response.ok().entity(observationBean.getObservationsForUser(user).stream() - .map(obs->new ObservationSyncInfo(obs)).collect(Collectors.toList())).build(); - } - else - { - return Response.status(Status.UNAUTHORIZED).build(); - } + public Response getMinimizedObservationsForUser() { + VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); + if (user != null) { + return Response.ok().entity(observationBean.getObservationsForUser(user).stream() + .map(obs -> new ObservationSyncInfo(obs)).collect(Collectors.toList())).build(); + } else { + return Response.status(Status.UNAUTHORIZED).build(); + } } - + /** * Publicly available observations per organization + * * @param organizationId Database id of the organization * @return APPROVED observations */ @@ -525,45 +618,37 @@ public class ObservationService { @Produces("application/json;charset=UTF-8") @TypeHint(Observation[].class) public Response getBroadcastObservations( - @PathParam("organizationId") Integer organizationId, - @QueryParam("season") Integer season, - @QueryParam("timeOfObservationFrom") String timeOfObservationFrom, - @QueryParam("timeOfObservationTo") String timeOfObservationTo - ) - { - if((timeOfObservationFrom != null && ! timeOfObservationFrom.isEmpty()) - || (timeOfObservationTo != null && ! timeOfObservationTo.isEmpty())) - { + @PathParam("organizationId") Integer organizationId, + @QueryParam("season") Integer season, + @QueryParam("timeOfObservationFrom") String timeOfObservationFrom, + @QueryParam("timeOfObservationTo") String timeOfObservationTo + ) { + if ((timeOfObservationFrom != null && !timeOfObservationFrom.isEmpty()) + || (timeOfObservationTo != null && !timeOfObservationTo.isEmpty())) { Date from = null; Date to = null; - try - { + try { SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd"); - if(timeOfObservationFrom != null && ! timeOfObservationFrom.isEmpty()) - { + if (timeOfObservationFrom != null && !timeOfObservationFrom.isEmpty()) { from = format.parse(timeOfObservationFrom); } - if(timeOfObservationTo != null && ! timeOfObservationTo.isEmpty()) - { + if (timeOfObservationTo != null && !timeOfObservationTo.isEmpty()) { to = format.parse(timeOfObservationTo); } return Response.ok().entity(observationBean.getBroadcastObservations(organizationId, from, to)).build(); - } - catch(ParseException ex) - { + } catch (ParseException ex) { return Response.status(Response.Status.BAD_REQUEST).entity("Invalid date format").build(); } - } - else - { + } else { return Response.ok().entity(observationBean.getBroadcastObservations(organizationId, season)).build(); } } /** * Get one observation + * * @param observationId Database ID of the observation - * @param userUUID UUID that identifies the user (e.g. from VIPSWeb) + * @param userUUID UUID that identifies the user (e.g. from VIPSWeb) * @return */ @GET @@ -571,56 +656,51 @@ public class ObservationService { @Produces("application/json;charset=UTF-8") @TypeHint(Observation.class) public Response getObservation( - @PathParam("observationId") Integer observationId, - @QueryParam("userUUID") String userUUID - ){ + @PathParam("observationId") Integer observationId, + @QueryParam("userUUID") String userUUID + ) { // Observation needs to be masked here as well, or does it create trouble for VIPSLogic observation admin? Observation o = observationBean.getObservation(observationId); - if(o == null) - { + if (o == null) { return Response.status(Status.NOT_FOUND).build(); } // Which organization does this observation belong to? VipsLogicUser observer = userBean.getVipsLogicUser(o.getUserId()); o.setObservationDataSchema(observationBean.getObservationDataSchema(observer.getOrganizationId().getOrganizationId(), o.getOrganismId())); - + VipsLogicUser user = (VipsLogicUser) httpServletRequest.getSession().getAttribute("user"); - if(user == null && userUUID != null) - { + if (user == null && userUUID != null) { user = userBean.findVipsLogicUser(UUID.fromString(userUUID)); } // Modification of location information: // 1) If location is private, only the owner or super users/org admins may view them // slett all geoInfo - if(user == null || (! user.isSuperUser() && ! user.isOrganizationAdmin())) - { + if (user == null || (!user.isSuperUser() && !user.isOrganizationAdmin())) { // Hide completely for all users except super and orgadmin - if(o.getLocationIsPrivate() && (user == null || ! o.getUserId().equals(user.getUserId()))) - { + if (o.getLocationIsPrivate() && (user == null || !o.getUserId().equals(user.getUserId()))) { o.setGeoinfos(null); } // This means the user wants to hide the exact location, // so mask for all users except super and orgadmin - else if(o.getPolygonService() != null) - { - //System.out.println("Masking observation"); + else if (o.getPolygonService() != null) { List<Observation> intermediary = new ArrayList<>(); intermediary.add(o); - intermediary = this.maskObservations(o.getPolygonService(), - observationBean.getObservationsWithLocations( - observationBean.getObservationsWithGeoInfo(intermediary) - ) - ); + intermediary = this.maskObservations(o.getPolygonService(), + observationBean.getObservationsWithLocations( + observationBean.getObservationsWithGeoInfo(intermediary) + ) + ); o = intermediary.get(0); } } - + return Response.ok().entity(o).build(); } - + /** * Polygon services are used to mask observations (privacy concerns) * They may vary greatly between organizations (different countries) + * * @param organizationId Database id of the organization * @return A list of available polygon services for the requested organization */ @@ -629,45 +709,41 @@ public class ObservationService { @Produces("application/json;charset=UTF-8") @TypeHint(PolygonService[].class) public Response getPolygonServicesForOrganization( - @PathParam("organizationId") Integer organizationId - ) - { - return Response.ok().entity(observationBean.getPolygonServicesForOrganization(organizationId)).build(); + @PathParam("organizationId") Integer organizationId + ) { + return Response.ok().entity(observationBean.getPolygonServicesForOrganization(organizationId)).build(); } - - + /** * Deletes a gis entity and its corresponding observation + * * @param gisId Database id of the gis entity - * @return + * @return */ @DELETE @Path("gisobservation/{gisId}") - public Response deleteGisObservation(@PathParam("gisId") Integer gisId) - { + public Response deleteGisObservation(@PathParam("gisId") Integer gisId) { VipsLogicUser user = (VipsLogicUser) httpServletRequest.getSession().getAttribute("user"); // If no user, send error message back to client - if(user == null) - { + if (user == null) { return Response.status(Response.Status.UNAUTHORIZED).build(); } - if(!userBean.authorizeUser(user, - VipsLogicRole.OBSERVER, - VipsLogicRole.OBSERVATION_AUTHORITY, - VipsLogicRole.ORGANIZATION_ADMINISTRATOR, - VipsLogicRole.SUPERUSER - ) - ) - { + if (!userBean.authorizeUser(user, + VipsLogicRole.OBSERVER, + VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER + ) + ) { return Response.status(Response.Status.FORBIDDEN).build(); } observationBean.deleteGisObservationByGis(gisId); return Response.noContent().build(); } - + /** - * * Stores an observation from geoJson + * * @param geoJSON * @return the Url of the created entity (observation) */ @@ -676,26 +752,22 @@ public class ObservationService { @Path("gisobservation") @Consumes("application/json;charset=UTF-8") @Produces("application/json;charset=UTF-8") - public Response storeGisObservation(String geoJSON) - { - try - { + public Response storeGisObservation(String geoJSON) { + try { // Create the Observation Observation observation = observationBean.getObservationFromGeoJSON(geoJSON); VipsLogicUser user = (VipsLogicUser) httpServletRequest.getSession().getAttribute("user"); // If no user, send error message back to client - if(user == null) - { + if (user == null) { return Response.status(Response.Status.UNAUTHORIZED).build(); } - if(!userBean.authorizeUser(user, - VipsLogicRole.OBSERVER, - VipsLogicRole.OBSERVATION_AUTHORITY, - VipsLogicRole.ORGANIZATION_ADMINISTRATOR, - VipsLogicRole.SUPERUSER - ) + if (!userBean.authorizeUser(user, + VipsLogicRole.OBSERVER, + VipsLogicRole.OBSERVATION_AUTHORITY, + VipsLogicRole.ORGANIZATION_ADMINISTRATOR, + VipsLogicRole.SUPERUSER ) - { + ) { return Response.status(Response.Status.FORBIDDEN).build(); } observation.setUserId(user.getUserId()); @@ -704,14 +776,14 @@ public class ObservationService { observation = observationBean.storeObservation(observation); GISEntityUtil gisUtil = new GISEntityUtil(); return Response.created(URI.create("/observation/" + observation.getObservationId())).entity(gisUtil.getGeoJSONFromObservation(observation)).build(); - }catch (IOException ex) - { + } catch (IOException ex) { return Response.status(Response.Status.INTERNAL_SERVER_ERROR).entity(ex).build(); } } /** * Returns the time of the first observation in the system of the pest with given Id + * * @param organismId Database id of the given organism * @return the time of the first observation in the system of the pest with given Id */ @@ -719,16 +791,16 @@ public class ObservationService { @Path("first/{organismId}") @Produces("text/plain;charset=UTF-8") @TypeHint(Date.class) - public Response getFirstObservation(@PathParam("organismId") Integer organismId) - { + public Response getFirstObservation(@PathParam("organismId") Integer organismId) { Date firstObsTime = observationBean.getFirstObservationTime(organismId); return firstObsTime != null ? Response.ok().entity(firstObsTime).build() - : Response.status(404).entity("No observations of organism with id=" + organismId).build(); + : Response.status(404).entity("No observations of organism with id=" + organismId).build(); } - + /** * When was the last time a change was made in cropCategories or organisms? Used for sync with the Field observation * app. + * * @return last time a change was made in cropCategories or organisms * @responseExample application/json {"lastUpdated": "2021-02-08T00:00:00Z"} */ @@ -736,122 +808,119 @@ public class ObservationService { @Path("organismsystemupdated") @Produces(MediaType.APPLICATION_JSON) @TypeHint(Date.class) - public Response getDateOfLastOrganismSystemUpdate() - { - HashMap<String, Object> result = new HashMap<>(); - Instant lastUpdated = organismBean.getLatestUpdateOfOrganisms(); - result.put("lastUpdated", lastUpdated != null ? lastUpdated: "1970-01-01T00:00:00Z"); - return Response.ok().entity(result).build(); + public Response getDateOfLastOrganismSystemUpdate() { + HashMap<String, Object> result = new HashMap<>(); + Instant lastUpdated = organismBean.getLatestUpdateOfOrganisms(); + result.put("lastUpdated", lastUpdated != null ? lastUpdated : "1970-01-01T00:00:00Z"); + return Response.ok().entity(result).build(); } - /** - * - * @param organizationId Database id of the organization - * @param pestId Database id of the pest - * @param cropId Database id of the crop - * @param cropCategoryId Database ids of the crop categories - * @param fromStr format "yyyy-MM-dd" - * @param toStr format "yyyy-MM-dd" - * @param user The user that requests this (used for authorization) + * @param organizationId Database id of the organization + * @param observationTimeSeriesId Database id of the observation time series + * @param pestId Database id of the pest + * @param cropId Database id of the crop + * @param cropCategoryId Database ids of the crop categories + * @param fromStr format "yyyy-MM-dd" + * @param toStr format "yyyy-MM-dd" + * @param user The user that requests this (used for authorization) * @return A list of observations that meets the filter criteria */ private List<Observation> getFilteredObservationsFromBackend( - Integer organizationId, - Integer pestId, - Integer cropId, - List<Integer> cropCategoryId, - String fromStr, - String toStr, - Boolean isPositive, - VipsLogicUser user + Integer organizationId, + Integer observationTimeSeriesId, + Integer pestId, + Integer cropId, + List<Integer> cropCategoryId, + String fromStr, + String toStr, + Boolean isPositive, + VipsLogicUser user ) { - List<Observation> filteredObservations = this.getFilteredObservationsFromBackend(organizationId, pestId, cropId, cropCategoryId, fromStr, toStr, isPositive); - //filteredObservations.forEach(o->System.out.println(o.getObservationId())); + List<Observation> filteredObservations = this.getFilteredObservationsFromBackend(organizationId, observationTimeSeriesId, pestId, cropId, cropCategoryId, fromStr, toStr, isPositive); + // If superuser or orgadmin: Return everything, unchanged, uncensored - if(user != null && (user.isSuperUser() || user.isOrganizationAdmin())) - { - return filteredObservations; + if (user != null && (user.isSuperUser() || user.isOrganizationAdmin())) { + LOGGER.info("Return uncensored list of {} observations to {}", filteredObservations.size(), (user.isSuperUser() ? "super" : "admin") + " user"); + return sortObservationsByDateAndId(filteredObservations); } - List<Observation> retVal = filteredObservations.stream().filter(obs->obs.getBroadcastMessage() || (isPositive == null || !isPositive)).collect(Collectors.toList()); + List<Observation> retVal = filteredObservations.stream().filter(obs -> obs.getBroadcastMessage() || (isPositive == null || !isPositive)).collect(Collectors.toList()); //retVal.forEach(o->System.out.println(o.getObservationId())); retVal = this.maskObservations(retVal); //retVal.forEach(o->System.out.println(o.getObservationId())); // If user is not logged in, return only the publicly available observations - if(user == null) - { - return retVal; + if (user == null) { + LOGGER.info("Return {} masked public observations for unregistered user", retVal.size()); + return sortObservationsByDateAndId(retVal); } // Else: This is a registered user without special privileges. Show public observations + user's own - retVal.addAll(observationBean.getObservationsForUser(user)); - return retVal; + // Making sure we don't add duplicates + Set<Integer> obsIds = retVal.stream().map(o -> o.getObservationId()).collect(Collectors.toSet()); + retVal.addAll(observationBean.getObservationsForUser(user).stream().filter(o -> !obsIds.contains(o.getObservationId())).collect(Collectors.toList())); + LOGGER.info("Return {} masked public observations and user's own observations for registered user {}", retVal.size(), user.getUserId()); + return sortObservationsByDateAndId(retVal); } /** * Runs through the observations, check each to see if it should be masked * (for privacy reasons) through a polygon service + * * @param observations The list of observations to check * @return The list of observations, with the locations masked with the selected polygon service */ private List<Observation> maskObservations(List<Observation> observations) { //System.out.println("maskObservations(List<Observation> observations)"); - + // Placing all observations with a polygon service in the correct bucket. Map<PolygonService, List<Observation>> registeredPolygonServicesInObservationList = new HashMap<>(); - observations.stream().filter((obs) -> { return (!obs.getLocationIsPrivate() && obs.getPolygonService() != null);}).forEachOrdered((obs) -> { + observations.stream().filter((obs) -> { + return (!obs.getLocationIsPrivate() && obs.getPolygonService() != null); + }).forEachOrdered((obs) -> { List<Observation> obsWithPolyServ = registeredPolygonServicesInObservationList.getOrDefault(obs.getPolygonService(), new ArrayList<>()); obsWithPolyServ.add(obs); registeredPolygonServicesInObservationList.put(obs.getPolygonService(), obsWithPolyServ); }); - + // No buckets filled = No masking needed, return list unmodified - if(registeredPolygonServicesInObservationList.isEmpty()) - { - return observations; - } - else - { + if (registeredPolygonServicesInObservationList.isEmpty()) { + return observations; + } else { // Loop through, mask - Map<Integer,Observation> maskedObservations = new HashMap<>(); + Map<Integer, Observation> maskedObservations = new HashMap<>(); registeredPolygonServicesInObservationList.keySet().forEach((pService) -> { this.maskObservations(pService, registeredPolygonServicesInObservationList.get(pService)) - .forEach(o->maskedObservations.put(o.getObservationId(), o)); + .forEach(o -> maskedObservations.put(o.getObservationId(), o)); }); - + // Adding the rest of the observations (the ones that don't need masking) - observations.stream().filter(o->maskedObservations.get(o.getObservationId())==null).forEach(o->maskedObservations.put(o.getObservationId(), o)); + observations.stream().filter(o -> maskedObservations.get(o.getObservationId()) == null).forEach(o -> maskedObservations.put(o.getObservationId(), o)); return new ArrayList<>(maskedObservations.values()); } } /** - * * @param polygonService The polygon service that should be used for masking - * @param observations The list of observations to mask + * @param observations The list of observations to mask * @return The list of observations, with the locations masked with the selected polygon service */ - private List<Observation> maskObservations(PolygonService polygonService, List<Observation> observations) - { + private List<Observation> maskObservations(PolygonService polygonService, List<Observation> observations) { //observations.forEach(o->System.out.println(o.getObservationId())); Client client = ClientBuilder.newClient(); WebTarget target = client.target(polygonService.getGisSearchUrlTemplate()); List<ReferencedPoint> points = observations.stream() - .filter(obs -> (obs.getGeoinfos()!=null && !obs.getGeoinfos().isEmpty()) || obs.getLocation() != null) - .map(obs->{ - ReferencedPoint rp = new ReferencedPoint(); - rp.setId(String.valueOf(obs.getObservationId())); - if(obs.getGeoinfos() != null) - { - rp.setLon(obs.getGeoinfos().get(0).getGisGeom().getCoordinate().x); - rp.setLat(obs.getGeoinfos().get(0).getGisGeom().getCoordinate().y); - } - else - { - rp.setLon(obs.getLocation().getLongitude()); - rp.setLat(obs.getLocation().getLatitude()); - } - return rp; - }).collect(Collectors.toList()); + .filter(obs -> (obs.getGeoinfos() != null && !obs.getGeoinfos().isEmpty()) || obs.getLocation() != null) + .map(obs -> { + ReferencedPoint rp = new ReferencedPoint(); + rp.setId(String.valueOf(obs.getObservationId())); + if (obs.getGeoinfos() != null) { + rp.setLon(obs.getGeoinfos().get(0).getGisGeom().getCoordinate().x); + rp.setLat(obs.getGeoinfos().get(0).getGisGeom().getCoordinate().y); + } else { + rp.setLon(obs.getLocation().getLongitude()); + rp.setLat(obs.getLocation().getLatitude()); + } + return rp; + }).collect(Collectors.toList()); /*System.out.println("maskobservations - target.request() about to be called"); ObjectMapper oMapper = new ObjectMapper(); try { @@ -860,16 +929,14 @@ public class ObservationService { Logger.getLogger(ObservationService.class.getName()).log(Level.SEVERE, null, ex); }*/ PointMappingResponse response = target.request(MediaType.APPLICATION_JSON) - .post(Entity.entity(points.toArray(new ReferencedPoint[points.size()]), MediaType.APPLICATION_JSON), PointMappingResponse.class); + .post(Entity.entity(points.toArray(new ReferencedPoint[points.size()]), MediaType.APPLICATION_JSON), PointMappingResponse.class); // We need to loop through the observations and find corresponding featurecollections and replace those Map<Integer, Feature> indexedPolygons = new HashMap<>(); - for(Feature feature:response.getFeatureCollection().getFeatures()) - { - indexedPolygons.put((Integer)feature.getProperties().get("id"), feature); + for (Feature feature : response.getFeatureCollection().getFeatures()) { + indexedPolygons.put((Integer) feature.getProperties().get("id"), feature); } GISEntityUtil gisEntityUtil = new GISEntityUtil(); - for(Map mapping:response.getMapping()) - { + for (Map mapping : response.getMapping()) { Integer observationId = Integer.valueOf((String) mapping.get("id")); Integer borderId = (Integer) mapping.get("borderid"); observations.stream().filter((o) -> (o.getObservationId().equals(observationId))).forEachOrdered((o) -> { @@ -881,13 +948,14 @@ public class ObservationService { o.setLocationPointOfInterestId(null); }); } - + return observations; } - + /** * This service is used by the VIPS Field observation app to sync data stored locally on the smartphone with the * state of an (potentially non-existent) observation in the VIPSLogic database + * * @param observationJson Json representation of the observation(s) * @return The observation(s) in their merged state, serialized to Json */ @@ -897,144 +965,205 @@ public class ObservationService { @Produces("application/json;charset=UTF-8") @TypeHint(Observation.class) public Response syncObservationFromApp( - String observationJson - ) - { - try - { - VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); - if(user == null) - { - return Response.status(Status.UNAUTHORIZED).build(); - } - ObjectMapper oM = new ObjectMapper(); - SimpleDateFormat df = new SimpleDateFormat(Globals.defaultTimestampFormat); - try { - Map<Object,Object> mapFromApp = oM.readValue(observationJson, new TypeReference<HashMap<Object,Object>>(){}); - // Check if it is marked as deleted or not - if(mapFromApp.get("deleted") != null && ((Boolean)mapFromApp.get("deleted").equals(true))) - { - if(observationBean.getObservation((Integer)mapFromApp.get("observationId")) != null) - { - observationBean.deleteObservation((Integer)mapFromApp.get("observationId")); - return Response.ok().build(); - } - else - { - return Response.status(Status.NOT_FOUND).build(); - } - } - else - { - Observation mergeObs = ((Integer)mapFromApp.get("observationId")) > 0 ? observationBean.getObservation((Integer)mapFromApp.get("observationId")): new Observation(); - // Trying to sync a non-existing observation - if(mergeObs == null) - { - return Response.status(Status.NOT_FOUND).build(); - } - // Pest organism - mergeObs.setOrganism(organismBean.getOrganism((Integer)mapFromApp.get("organismId"))); - // Crop organism - mergeObs.setCropOrganism(organismBean.getOrganism((Integer)mapFromApp.get("cropOrganismId"))); - // Other properties - mergeObs.setTimeOfObservation(oM.convertValue(mapFromApp.get("timeOfObservation"), new TypeReference<Date>(){})); + String observationJson + ) { + LOGGER.info("In syncObservationFromApp"); + + try { + VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); + if (user == null) { + LOGGER.warn("Unable to get user from UUID"); + return Response.status(Status.UNAUTHORIZED).build(); + } + ObjectMapper oM = new ObjectMapper(); + SimpleDateFormat df = new SimpleDateFormat(Globals.defaultTimestampFormat); + try { + Map<Object, Object> mapFromApp = oM.readValue(observationJson, new TypeReference<HashMap<Object, Object>>() { + }); + LOGGER.info("Syncing for user {} with roles {}. mapFromApp.get(\"userId\")={}", user.getUserId(), user.getVipsLogicRoles(), mapFromApp.get("userId")); + + // Check if it is marked as deleted or not + if (mapFromApp.get("deleted") != null && ((Boolean) mapFromApp.get("deleted").equals(true))) { + if (observationBean.getObservation((Integer) mapFromApp.get("observationId")) != null) { + observationBean.deleteObservation((Integer) mapFromApp.get("observationId")); + return Response.ok().build(); + } else { + return Response.status(Status.NOT_FOUND).build(); + } + } else { + Integer observationId = (Integer) mapFromApp.get("observationId"); + Date now = new Date(); // For setting timestamps + + Observation mergeObs; + if (observationId > 0) { // Observation already in database + mergeObs = observationBean.getObservation(observationId); + if (mergeObs == null) { + LOGGER.warn("Observation with id {} not found", observationId); + return Response.status(Status.NOT_FOUND).build(); + } + } else { // New observation! + mergeObs = new Observation("APP"); + } + + // Observation time series + if (mapFromApp.get("observationTimeSeriesId") != null) { + Integer observationTimeSeriesId = (Integer) mapFromApp.get("observationTimeSeriesId"); + mergeObs.setObservationTimeSeries(observationTimeSeriesBean.getObservationTimeSeries(observationTimeSeriesId)); + } + // Pest organism + mergeObs.setOrganism(organismBean.getOrganism((Integer) mapFromApp.get("organismId"))); + // Crop organism + mergeObs.setCropOrganism(organismBean.getOrganism((Integer) mapFromApp.get("cropOrganismId"))); + // Other properties + mergeObs.setTimeOfObservation(oM.convertValue(mapFromApp.get("timeOfObservation"), new TypeReference<Date>() { + })); mergeObs.setIsPositive(mapFromApp.get("isPositive") != null ? (Boolean) mapFromApp.get("isPositive") : false); - mergeObs.setUserId(mapFromApp.get("userId") != null ? Integer.valueOf((Integer)mapFromApp.get("userId")): user.getUserId()); - mergeObs.setGeoinfo((String)mapFromApp.get("geoinfo")); - mergeObs.setLocationPointOfInterestId(mapFromApp.get("locationPointOfInterestId") != null ? (Integer) mapFromApp.get("locationPointOfInterestId") : null); - mergeObs.setObservationHeading(mapFromApp.get("observationHeading") != null ? (String) mapFromApp.get("observationHeading") : null); - mergeObs.setObservationText(mapFromApp.get("observationText") != null ? (String) mapFromApp.get("observationText") : null); - mergeObs.setBroadcastMessage(mapFromApp.get("broadcastMessage") != null ? (Boolean) mapFromApp.get("broadcastMessage") : false); - mergeObs.setStatusTypeId(Integer.valueOf((Integer)mapFromApp.get("statusTypeId"))); - // If the user has the role of observation approver, change to approved if set to pending - if(mergeObs.getStatusTypeId().equals(ObservationStatusType.STATUS_PENDING) && user.isObservationAuthority()) - { - mergeObs.setStatusTypeId(ObservationStatusType.STATUS_APPROVED); - } - mergeObs.setStatusChangedByUserId(mapFromApp.get("statusChangedByUserId") != null ? (Integer) mapFromApp.get("statusChangedByUserId") : null); - mergeObs.setStatusChangedTime(mapFromApp.get("timeOfObservation") != null ? oM.convertValue(mapFromApp.get("timeOfObservation"), new TypeReference<Date>(){}) : null); - mergeObs.setStatusRemarks(mapFromApp.get("statusRemarks") != null ? (String) mapFromApp.get("statusRemarks") : null); - mergeObs.setIsQuantified(mapFromApp.get("isQuantified") != null ? (Boolean) mapFromApp.get("isQuantified") : false); - mergeObs.setLocationIsPrivate(mapFromApp.get("locationIsPrivate") != null ? (Boolean) mapFromApp.get("locationIsPrivate") : false); - mergeObs.setPolygonService(mapFromApp.get("polygonService") != null && ! ((String)mapFromApp.get("polygonService")).isEmpty() ? oM.convertValue(mapFromApp.get("polygonService"), new TypeReference<PolygonService>(){}) : null); - mergeObs.setObservationDataSchema(observationBean.getObservationDataSchema(user.getOrganization_id(), mergeObs.getOrganismId())); - mergeObs.setObservationData(mapFromApp.get("observationData") != null ? mapFromApp.get("observationData").toString() : null); - mergeObs.setLastEditedBy(user.getUserId()); - mergeObs.setLastEditedTime(new Date()); - - // Input check before storing - // Location must be set - if((mergeObs.getGeoinfo() == null || mergeObs.getGeoinfo().trim().isEmpty()) && mergeObs.getLocationPointOfInterestId() == null) - { - return Response.status(Status.BAD_REQUEST).entity("The observation is missing location data.").build(); - } - - boolean sendNotification = false; - // Storing approval status - // If superusers or user with correct authorization: Set as approved and send message - if(userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER)) - { - LOGGER.debug("user properly authorized to register observations"); - LOGGER.debug("observation Id=" + mergeObs.getObservationId()); - LOGGER.debug("broadcast this message? " + mergeObs.getBroadcastMessage()); - if(mergeObs.getObservationId() == null || mergeObs.getObservationId() <= 0) - { - mergeObs.setStatusTypeId(Observation.STATUS_TYPE_ID_APPROVED); - sendNotification = mergeObs.getBroadcastMessage(); // Only send the ones intended for sending - } - } - else if(mergeObs.getObservationId() == null || mergeObs.getObservationId() <= 0) - { - mergeObs.setStatusTypeId(Observation.STATUS_TYPE_ID_PENDING); - } - - // We need to get an observation Id before storing the illustrations! - mergeObs = observationBean.storeObservation(mergeObs); - - - - // ObservationIllustrationSet - // Including data that may need to be stored - if(mapFromApp.get("observationIllustrationSet") != null) - { - List<Map<Object,Object>> illusMaps = (List<Map<Object,Object>>) mapFromApp.get("observationIllustrationSet"); - for(Map<Object,Object> illusMap:illusMaps) - { - ObservationIllustrationPK pk = oM.convertValue(illusMap.get("observationIllustrationPK"), new TypeReference<ObservationIllustrationPK>(){}); - - if(illusMap.get("deleted") != null && ((Boolean) illusMap.get("deleted")) == true) - { - observationBean.deleteObservationIllustration(mergeObs, new String[] {pk.getFileName()}); - } - else if(illusMap.get("uploaded") != null && ((Boolean) illusMap.get("uploaded")) == false && illusMap.get("imageTextData") != null) - { - mergeObs = observationBean.storeObservationIllustration(mergeObs, pk.getFileName(), (String)illusMap.get("imageTextData")); - } - } - } - LOGGER.debug("sendNotification? " + sendNotification); - - // All transactions finished, we can send notifications - // if conditions are met - if(sendNotification && ! - (System.getProperty("DISABLE_MESSAGING_SYSTEM") != null && System.getProperty("DISABLE_MESSAGING_SYSTEM").equals("true")) - ) - { - LOGGER.debug("Sending the message!"); - messagingBean.sendUniversalMessage(mergeObs); - } - - return Response.ok().entity(mergeObs).build(); - } - } catch (IOException e) { - return Response.serverError().entity(e).build(); - } - } - catch(Exception e) - { - e.printStackTrace(); - return Response.serverError().entity(e).build(); - } - + mergeObs.setUserId(mapFromApp.get("userId") != null ? (Integer) mapFromApp.get("userId") : user.getUserId()); + mergeObs.setGeoinfo((String) mapFromApp.get("geoinfo")); + mergeObs.setLocationPointOfInterestId(mapFromApp.get("locationPointOfInterestId") != null ? (Integer) mapFromApp.get("locationPointOfInterestId") : null); + + mergeObs.setObservationHeading(getStringPropertyOrNull(mapFromApp, "observationHeading")); + mergeObs.setObservationText(getStringPropertyOrNull(mapFromApp, "observationText")); + mergeObs.setBroadcastMessage(mapFromApp.get("broadcastMessage") != null ? (Boolean) mapFromApp.get("broadcastMessage") : false); + + mergeObs.setIsQuantified(mapFromApp.get("isQuantified") != null ? (Boolean) mapFromApp.get("isQuantified") : false); + mergeObs.setLocationIsPrivate(mapFromApp.get("locationIsPrivate") != null ? (Boolean) mapFromApp.get("locationIsPrivate") : false); + Object polygonServiceValue = mapFromApp.get("polygonService"); + if (polygonServiceValue != null && !polygonServiceValue.toString().isBlank()) { + PolygonService polygonService = oM.convertValue(mapFromApp.get("polygonService"), PolygonService.class); + mergeObs.setPolygonService(polygonService); + } + + mergeObs.setObservationDataSchema(observationBean.getObservationDataSchema(user.getOrganization_id(), mergeObs.getOrganismId())); + + mergeObs.setObservationData(getStringPropertyOrNull(mapFromApp, "observationData")); + mergeObs.setLastEditedBy(user.getUserId()); + mergeObs.setLastEditedTime(now); + + boolean sendNotification = false; // Notification should be sent if status is set to approved + boolean newRegistration = mergeObs.getObservationId() == null || mergeObs.getObservationId() <= 0; + boolean automaticApproval = userBean.authorizeUser(user, VipsLogicRole.OBSERVATION_AUTHORITY, VipsLogicRole.ORGANIZATION_ADMINISTRATOR, VipsLogicRole.SUPERUSER); + if (newRegistration) { + if (automaticApproval) { + LOGGER.info("Set status to approved for new observation registered by user {}", user.getUserId()); + mergeObs.setStatusChangedByUserId(user.getUserId()); + mergeObs.setStatusChangedTime(now); + mergeObs.setStatusTypeId(ObservationStatusType.STATUS_APPROVED); + sendNotification = mergeObs.getBroadcastMessage(); // Only send for approved observations + } else { + LOGGER.info("Set status to pending for new observation registered by user {}", user.getUserId()); + mergeObs.setStatusTypeId(Observation.STATUS_TYPE_ID_PENDING); + } + } else { + // Existing observation + Integer newStatusTypeId = (Integer) mapFromApp.get("statusTypeId"); + Integer originalStatusTypeId = mergeObs.getStatusTypeId(); + if (automaticApproval && ObservationStatusType.STATUS_PENDING.equals(newStatusTypeId) && ObservationStatusType.STATUS_PENDING.equals(originalStatusTypeId)) { + LOGGER.info("Set status to approved for existing observation {} and user {}", mergeObs.getObservationId(), user.getUserId()); + mergeObs.setStatusChangedByUserId(user.getUserId()); + mergeObs.setStatusChangedTime(now); + mergeObs.setStatusTypeId(ObservationStatusType.STATUS_APPROVED); + sendNotification = mergeObs.getBroadcastMessage(); // Only send for approved observations + } + // No option for changing the status in registration form in app + } + + // Input check before storing, location must be set + if ((mergeObs.getGeoinfo() == null || mergeObs.getGeoinfo().trim().isEmpty()) && mergeObs.getLocationPointOfInterestId() == null) { + LOGGER.error("The observation is missing location data, return bad request."); + return Response.status(Status.BAD_REQUEST).entity("{\"error\": \"The observation is missing location data.\"}").type(MediaType.APPLICATION_JSON).build(); + } + + // We need to get an observation Id before storing the illustrations! + mergeObs = observationBean.storeObservation(mergeObs); + + // ObservationIllustrationSet + // Including data that may need to be stored + if (mapFromApp.get("observationIllustrationSet") != null) { + List<Map<Object, Object>> illusMaps = (List<Map<Object, Object>>) mapFromApp.get("observationIllustrationSet"); + for (Map<Object, Object> illusMap : illusMaps) { + ObservationIllustrationPK pk = oM.convertValue(illusMap.get("observationIllustrationPK"), new TypeReference<ObservationIllustrationPK>() { + }); + + if (illusMap.get("deleted") != null && ((Boolean) illusMap.get("deleted")) == true) { + observationBean.deleteObservationIllustration(mergeObs, new String[]{pk.getFileName()}); + } else if (illusMap.get("uploaded") != null && ((Boolean) illusMap.get("uploaded")) == false && illusMap.get("imageTextData") != null) { + mergeObs = observationBean.storeObservationIllustration(mergeObs, pk.getFileName(), (String) illusMap.get("imageTextData")); + } + } + } + String disableMessagingSystemProperty = System.getProperty("no.nibio.vips.logic.DISABLE_MESSAGING_SYSTEM"); + boolean messagingSystemDisabled = disableMessagingSystemProperty != null && disableMessagingSystemProperty.equals("true"); + + LOGGER.info("Send notification? " + sendNotification); + LOGGER.info("Messaging system enabled? " + !messagingSystemDisabled); + + // All transactions finished, we can send notifications + // if conditions are met + if (sendNotification && !messagingSystemDisabled) { + LOGGER.info("Send message"); + messagingBean.sendUniversalMessage(mergeObs); + } + + return Response.ok().entity(mergeObs).build(); + } + } catch (IOException e) { + return Response.serverError().entity(e).build(); + } + } catch (Exception e) { + LOGGER.error("Exception occurred while syncing observations from app", e); + return Response.serverError().entity(e).build(); + } + } + + /** + * Sort observations by date in descending order, and by id in descending order if dates are identical + * + * @param observations The original list of unordered observations + * @return a sorted list of observations + */ + private List<Observation> sortObservationsByDateAndId(List<Observation> observations) { + return observations.stream() + .sorted((o1, o2) -> { + int timeCompare = o2.getTimeOfObservation().compareTo(o1.getTimeOfObservation()); + if (timeCompare != 0) { + return timeCompare; + } else { + return Integer.compare(o2.getObservationId(), o1.getObservationId()); + } + }) + .collect(Collectors.toList()); + } + + /** + * Find VipsLogic user from session or given userUUID + * + * @param userUUID the UUID of the user + * @return the corresponding VipsLogicUser + */ + private VipsLogicUser getVipsLogicUser(String userUUID) { + VipsLogicUser user = (VipsLogicUser) httpServletRequest.getSession().getAttribute("user"); + if (user == null && userUUID != null) { + user = userBean.findVipsLogicUser(UUID.fromString(userUUID)); + } + return user; } + + + /** + * Utility method for getting the string value of a given property in a given map. + * + * @param map The map from which to retrieve the value + * @param propertyName The name of the property + * @return The value of the given property, null if not existing or empty + */ + private String getStringPropertyOrNull(Map<Object, Object> map, String propertyName) { + Object mapValue = map.get(propertyName); + if (mapValue == null) { + return null; + } + String strMapValue = (String) mapValue; + return !strMapValue.isBlank() ? strMapValue : null; + } + } diff --git a/src/main/java/no/nibio/vips/logic/service/ObservationTimeSeriesService.java b/src/main/java/no/nibio/vips/logic/service/ObservationTimeSeriesService.java new file mode 100644 index 0000000000000000000000000000000000000000..600ba45032fefc4916db8fad82cfaf7528b2a297 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/service/ObservationTimeSeriesService.java @@ -0,0 +1,260 @@ +package no.nibio.vips.logic.service; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.webcohesion.enunciate.metadata.rs.TypeHint; +import no.nibio.vips.logic.controller.session.ObservationTimeSeriesBean; +import no.nibio.vips.logic.controller.session.OrganismBean; +import no.nibio.vips.logic.controller.session.UserBean; +import no.nibio.vips.logic.entity.Gis; +import no.nibio.vips.logic.entity.ObservationTimeSeries; +import no.nibio.vips.logic.entity.PolygonService; +import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.entity.rest.PointMappingResponse; +import no.nibio.vips.logic.entity.rest.ReferencedPoint; +import no.nibio.vips.logic.util.GISEntityUtil; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.wololo.geojson.Feature; + +import jakarta.ejb.EJB; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.*; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +@Path("rest/observationtimeseries") +public class ObservationTimeSeriesService { + + public static final String APPLICATION_JSON = "application/json;charset=UTF-8"; + private final static Logger LOGGER = LoggerFactory.getLogger(ObservationTimeSeriesService.class); + private static final String DELETED = "deleted"; + private static final String OBSERVATION_TIME_SERIES_ID = "observationTimeSeriesId"; + private static final String ORGANISM_ID = "organismId"; + private static final String CROP_ORGANISM_ID = "cropOrganismId"; + private static final String USER_ID = "userId"; + private static final String LOCATION_POINT_OF_INTEREST_ID = "locationPointOfInterestId"; + private static final String YEAR = "year"; + private static final String NAME = "name"; + private static final String DESCRIPTION = "description"; + private static final String LOCATION_IS_PRIVATE = "locationIsPrivate"; + private static final String POLYGON_SERVICE = "polygonService"; + @EJB + UserBean userBean; + @EJB + ObservationTimeSeriesBean observationTimeSeriesBean; + @EJB + OrganismBean organismBean; + + @Context + private HttpServletRequest httpServletRequest; + + @GET + @Path("list/user") + @Produces(APPLICATION_JSON) + @TypeHint(ObservationTimeSeries[].class) + public Response getObservationsTimeSeriesForUser(@QueryParam("observationTimeSeriesIds") String otsIds) { + LOGGER.info("In getObservationsTimeSeriesForUser observationTimeSeriesIds=" + otsIds); + try { + VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); + if (user != null) { + List<ObservationTimeSeries> allObs = observationTimeSeriesBean.getObservationTimeSeriesListForUser(user); + if (otsIds != null) { + Set<Integer> observationIdSet = Arrays.stream(otsIds.split(",")) + .map(Integer::valueOf) + .collect(Collectors.toSet()); + return Response.ok().entity( + allObs.stream() + .filter(obs -> observationIdSet.contains(obs.getObservationTimeSeriesId())) + .collect(Collectors.toList()) + ) + .build(); + } + return Response.ok().entity(allObs).build(); + } else { + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + } catch (Exception e) { + return Response.serverError().entity(e.getMessage()).build(); + } + } + + /** + * Get one observation time series + * + * @param observationTimeSeriesId Database ID of the observation time series + * @param userUUID UUID that identifies the user (e.g. from VIPSWeb) + * @return + */ + @GET + @Path("{observationTimeSeriesId}") + @Produces(APPLICATION_JSON) + @TypeHint(ObservationTimeSeries.class) + public Response getObservationTimeSeries(@PathParam("observationTimeSeriesId") Integer observationTimeSeriesId, @QueryParam("userUUID") String userUUID) { + ObservationTimeSeries ots = observationTimeSeriesBean.getObservationTimeSeries(observationTimeSeriesId); + if (ots == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } + VipsLogicUser requester = (VipsLogicUser) httpServletRequest.getSession().getAttribute("user"); + if (requester == null && userUUID != null) { + requester = userBean.findVipsLogicUser(UUID.fromString(userUUID)); + } + observationTimeSeriesBean.enrichObservationTimeSeriesWithPointOfInterest(ots); + + boolean requesterNotValidUser = requester == null; + boolean requesterRegularUser = requester != null && !requester.isSuperUser() && !requester.isOrganizationAdmin(); + boolean requesterNotCreator = requester != null && !ots.getUserId().equals(requester.getUserId()); + if (requesterNotValidUser || requesterRegularUser) { + // Mask for all users except creator, super and orgadmin + if (!(ots.getLocationIsPrivate() && (requesterNotValidUser || requesterNotCreator)) && ots.getPolygonService() != null) { + this.maskLocation(ots.getPolygonService(), ots); + } + } + return Response.ok().entity(ots).build(); + } + + /** + * The location (point of interest) of the given observation time series is masked using the provided polygon service. + * + * @param polygonService The polygon service that should be used for masking + * @param observationTimeSeries The observation time series to mask location for + * @return The observation time series, with location masked with the provided polygon service + */ + private void maskLocation(PolygonService polygonService, ObservationTimeSeries observationTimeSeries) { + Client client = ClientBuilder.newClient(); + WebTarget target = client.target(polygonService.getGisSearchUrlTemplate()); + ReferencedPoint rp = new ReferencedPoint(); + rp.setId(String.valueOf(observationTimeSeries.getObservationTimeSeriesId())); + rp.setLon(observationTimeSeries.getLocationPointOfInterest().getLongitude()); + rp.setLat(observationTimeSeries.getLocationPointOfInterest().getLatitude()); + + ReferencedPoint[] pointArray = {rp}; + PointMappingResponse response = target.request(MediaType.APPLICATION_JSON).post(Entity.entity(pointArray, MediaType.APPLICATION_JSON), PointMappingResponse.class); + // We need to loop through the observations and find corresponding featurecollections and replace those + Map<Integer, Feature> indexedPolygons = new HashMap<>(); + for (Feature feature : response.getFeatureCollection().getFeatures()) { + indexedPolygons.put((Integer) feature.getProperties().get(OBSERVATION_TIME_SERIES_ID), feature); + } + GISEntityUtil gisEntityUtil = new GISEntityUtil(); + for (Map mapping : response.getMapping()) { + Integer observationTimeSeriesId = Integer.valueOf((String) mapping.get(OBSERVATION_TIME_SERIES_ID)); + if (observationTimeSeries.getObservationTimeSeriesId().equals(observationTimeSeriesId)) { + Integer borderId = (Integer) mapping.get("borderid"); + Gis polygon = gisEntityUtil.getGisFromFeature(indexedPolygons.get(borderId)); + List<Gis> gis = new ArrayList<>(); + gis.add(polygon); + observationTimeSeries.setLocationPointOfInterest(null); + observationTimeSeries.setLocationPointOfInterestId(null); + } + } + } + + /** + * This service is used by the VIPS Field observation app to sync data stored locally on the smartphone with the + * state of a (potentially non-existent) observation time series in the VIPSLogic database + * + * @param jsonOts Json representation of the observation time series + * @return The observation time series in its merged state, serialized to Json + */ + @POST + @Path("syncfromapp") + @Consumes(APPLICATION_JSON) + @Produces(APPLICATION_JSON) + @TypeHint(ObservationTimeSeries.class) + public Response syncObservationTimeSeriesFromApp(String jsonOts) { + LOGGER.info("In syncObservationTimeSeriesFromApp"); + LOGGER.info(jsonOts); + VipsLogicUser user = userBean.getUserFromUUID(httpServletRequest); + if (user == null) { + LOGGER.warn("Unable to get user from UUID"); + return Response.status(Response.Status.UNAUTHORIZED).build(); + } + LOGGER.info("Syncing for user {} with roles {}", user.getUserId(), user.getVipsLogicRoles()); + ObjectMapper oM = new ObjectMapper(); + try { + Map<Object, Object> mapFromApp = oM.readValue(jsonOts, new TypeReference<HashMap<Object, Object>>() { + }); + + Integer otsId = (Integer) mapFromApp.get(OBSERVATION_TIME_SERIES_ID); + + // Check if the observation time series is marked as deleted + Boolean isDeleted = (Boolean) mapFromApp.getOrDefault(DELETED, false); + if (isDeleted) { + // If marked as deleted, delete the observation time series if it exists + // Observations in time series are also deleted, but the app currently prevents + // deletion of time series with content + if (observationTimeSeriesBean.getObservationTimeSeries(otsId) != null) { + observationTimeSeriesBean.deleteObservationTimeSeries(otsId); + LOGGER.info("ObservationTimeSeries with id={} deleted", otsId); + return Response.ok().build(); + } else { + LOGGER.warn("ObservationTimeSeries with id={} not found, nothing deleted", otsId); + return Response.status(Response.Status.NOT_FOUND).build(); + } + } + + Date currentDate = new Date(); + ObservationTimeSeries otsToSave; + if (otsId != null && otsId > 0) { + otsToSave = observationTimeSeriesBean.getObservationTimeSeries(otsId); + if (otsToSave == null) { + return Response.status(Response.Status.NOT_FOUND).build(); + } + } else { + otsToSave = new ObservationTimeSeries("APP"); + otsToSave.setUserId(user.getUserId()); + otsToSave.setCreated(currentDate); + } + otsToSave.setCropOrganism(organismBean.getOrganism(getValueFromMap(mapFromApp, CROP_ORGANISM_ID, Integer.class))); + otsToSave.setOrganism(organismBean.getOrganism(getValueFromMap(mapFromApp, ORGANISM_ID, Integer.class))); + otsToSave.setLocationPointOfInterestId(getValueFromMap(mapFromApp, LOCATION_POINT_OF_INTEREST_ID, Integer.class)); + otsToSave.setYear(getValueFromMap(mapFromApp, YEAR, Integer.class)); + otsToSave.setName(getValueFromMap(mapFromApp, NAME, String.class)); + otsToSave.setDescription(getValueFromMap(mapFromApp, DESCRIPTION, String.class)); + otsToSave.setLocationIsPrivate(getValueFromMap(mapFromApp, LOCATION_IS_PRIVATE, Boolean.class)); + + Object polygonServiceValue = mapFromApp.get(POLYGON_SERVICE); + if (polygonServiceValue != null && !polygonServiceValue.toString().isBlank()) { + PolygonService polygonService = oM.convertValue(polygonServiceValue, PolygonService.class); + otsToSave.setPolygonService(polygonService); + } + + otsToSave.setLastModified(currentDate); + otsToSave.setLastModifiedBy(user.getUserId()); + + // Input check before storing, location must be set + if (otsToSave.getLocationPointOfInterestId() == null) { + LOGGER.error("The observation time series is missing location data"); + return Response.status(Response.Status.BAD_REQUEST).entity("The observation time series is missing location data").build(); + } + LOGGER.info("otsToSave before storing: " + otsToSave); + otsToSave = observationTimeSeriesBean.storeObservationTimeSeries(otsToSave); + return Response.ok().entity(otsToSave).build(); + } catch (IOException e) { + LOGGER.error("IOException on save ObservationTimeSeries", e); + return Response.serverError().entity(e).build(); + } + } + + private <T> T getValueFromMap(Map<Object, Object> map, String key, Class<T> clazz) { + Object value = map.get(key); + if (clazz.isInstance(value)) { + return clazz.cast(value); + } else if (clazz == Integer.class && value instanceof String) { + try { + return clazz.cast(Integer.parseInt((String) value)); + } catch (NumberFormatException e) { + return null; + } + } + return clazz == Boolean.class ? clazz.cast(false) : null; + } +} diff --git a/src/main/java/no/nibio/vips/logic/service/POIService.java b/src/main/java/no/nibio/vips/logic/service/POIService.java index e84089cc9235d2b80849ad1e51729727e6adfaed..4ca5a1f5e26d4240cbb1a6e532001c3d41280abb 100644 --- a/src/main/java/no/nibio/vips/logic/service/POIService.java +++ b/src/main/java/no/nibio/vips/logic/service/POIService.java @@ -19,24 +19,19 @@ package no.nibio.vips.logic.service; import java.io.IOException; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.UUID; - -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.Consumes; -import javax.ws.rs.GET; -import javax.ws.rs.POST; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.HttpHeaders; -import javax.ws.rs.core.Response; -import javax.ws.rs.core.Response.Status; +import java.util.*; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.*; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.MediaType; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.core.Response.Status; + +import com.fasterxml.jackson.core.JsonProcessingException; +import no.nibio.vips.logic.controller.session.PointOfInterestBean; +import no.nibio.vips.logic.entity.helpers.PointOfInterestFactory; import org.jboss.resteasy.spi.HttpRequest; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Point; @@ -45,9 +40,8 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import com.webcohesion.enunciate.metadata.Facet; import com.webcohesion.enunciate.metadata.rs.TypeHint; -import java.util.Arrays; + import java.util.stream.Collectors; -import javax.ws.rs.QueryParam; import no.nibio.vips.gis.GISUtil; import no.nibio.vips.logic.entity.Country; @@ -55,8 +49,9 @@ import no.nibio.vips.logic.entity.Organization; import no.nibio.vips.logic.entity.PointOfInterest; import no.nibio.vips.logic.entity.PointOfInterestWeatherStation; import no.nibio.vips.logic.entity.VipsLogicUser; -import no.nibio.vips.logic.util.Globals; import no.nibio.vips.logic.controller.session.SessionControllerGetter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @copyright 2022 <a href="http://www.nibio.no/">NIBIO</a> @@ -64,6 +59,7 @@ import no.nibio.vips.logic.controller.session.SessionControllerGetter; */ @Path("rest/poi") public class POIService { + private final static Logger LOGGER = LoggerFactory.getLogger(POIService.class); @Context private HttpRequest httpRequest; @@ -99,7 +95,68 @@ public class POIService { PointOfInterest retVal = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(pointOfInterestId); return Response.ok().entity(retVal).build(); } - + + @POST + @Consumes("application/json;charset=UTF-8") + @Produces("application/json;charset=UTF-8") + public Response postPoi(String poiJson) { + ObjectMapper oM = new ObjectMapper(); + Map<Object, Object> poiMap; + try { + poiMap = oM.readValue(poiJson, new TypeReference<HashMap<Object, Object>>() {}); + } catch (JsonProcessingException e) { + LOGGER.error(e.getMessage(), e); + return Response.status(Status.BAD_REQUEST).entity("Unable to parse input").build(); + } + + VipsLogicUser user = SessionControllerGetter.getUserBean().getUserFromUUID(httpServletRequest); + if (user == null) { + LOGGER.error("No user found for UUID in Authorization"); + return Response.status(Status.UNAUTHORIZED).build(); + } + LOGGER.error("Remember to check for roles as well, if necessary!"); + + PointOfInterestBean poiBean = SessionControllerGetter.getPointOfInterestBean(); + Integer poiTypeId = poiMap.get("pointOfInterestTypeId") != null ? Integer.parseInt(poiMap.get("pointOfInterestTypeId").toString()) : null; + if(poiTypeId == null) { + return Response.status(Status.BAD_REQUEST).entity("pointOfInterestTypeId is required").build(); + } + String poiName = poiMap.get("name") != null ? poiMap.get("name").toString() : null; + Double poiLongitude = poiMap.get("longitude") != null ? Double.valueOf(poiMap.get("longitude").toString()): null; + Double poiLatitude = poiMap.get("latitude") != null ? Double.valueOf(poiMap.get("latitude").toString()): null; + Double poiAltitude = 0.0; + + PointOfInterest poiToSave = PointOfInterestFactory.getPointOfInterest(poiTypeId); + poiToSave.setName(poiName); + poiToSave.setLongitude(poiLongitude); + poiToSave.setLatitude(poiLatitude); + poiToSave.setAltitude(poiAltitude); + poiToSave.setLastEditedTime(new Date()); + poiToSave.setUser(user); + poiToSave.setCountryCode(user.getOrganizationId().getCountryCode()); + poiToSave.setTimeZone(user.getOrganizationId().getDefaultTimeZone()); + poiToSave.setIsForecastLocation(Boolean.FALSE); + poiToSave.setIsPrivate(Boolean.TRUE); + + if (poiLongitude != null && poiLatitude != null) { + GISUtil gisUtil = new GISUtil(); + Coordinate coordinate = new Coordinate(poiLongitude, poiLatitude, poiAltitude); + Point p3d = gisUtil.createPointWGS84(coordinate); + poiToSave.setGisGeom(p3d); + } + poiToSave = poiBean.storePoi(poiToSave); + + if (poiToSave != null) { + return Response.status(Response.Status.CREATED) + .entity(poiToSave) + .build(); + } else { + return Response.status(Response.Status.INTERNAL_SERVER_ERROR) + .entity("Failed to create PointOfInterest " + poiName) + .build(); + } + } + /** * @param organizationId Id of the organization in question * @param poiTypesStr Comma separated list of poiTypes @@ -121,6 +178,19 @@ public class POIService { return Response.ok().entity(SessionControllerGetter.getPointOfInterestBean().getPoisAsGeoJson(pois)).build(); } + @POST + @Path("geojson") + @Produces("application/json;charset=UTF-8") + @Consumes(MediaType.APPLICATION_JSON) + public Response getPoisGeoJson(Set<Integer> ids) { + // Retrieve POIs from data source + List<PointOfInterest> pois = SessionControllerGetter.getPointOfInterestBean().getPois(ids); + if (pois == null || pois.isEmpty()) { + return Response.noContent().build(); + } + return Response.ok(SessionControllerGetter.getPointOfInterestBean().getPoisAsGeoJson(pois)).build(); + } + /** * Find a POI (Point of interest) by name * @@ -182,22 +252,26 @@ public class POIService { return Response.status(Status.UNAUTHORIZED).build(); } ObjectMapper oM = new ObjectMapper(); - SimpleDateFormat df = new SimpleDateFormat(Globals.defaultTimestampFormat); try { Map<Object, Object> mapFromApp = oM.readValue(poiJson, new TypeReference<HashMap<Object, Object>>() { }); + Integer pointOfInterestId = (Integer) mapFromApp.get("pointOfInterestId"); + PointOfInterestBean pointOfInterestBean = SessionControllerGetter.getPointOfInterestBean(); // Check if it is marked as deleted or not - if (mapFromApp.get("deleted") != null && ((Boolean) mapFromApp.get("deleted").equals(true))) { - if (SessionControllerGetter.getPointOfInterestBean().getPointOfInterest((Integer) mapFromApp.get("pointOfInterestId")) != null) { - SessionControllerGetter.getPointOfInterestBean().deletePoi((Integer) mapFromApp.get("pointOfInterestId")); + if (mapFromApp.get("deleted") != null && (mapFromApp.get("deleted").equals(true))) { + if (pointOfInterestBean.getPointOfInterest(pointOfInterestId) != null) { + pointOfInterestBean.deletePoi(pointOfInterestId); + LOGGER.info("POI with id={} deleted", pointOfInterestId); return Response.ok().build(); } else { + LOGGER.error("POI with id={} not found, nothing deleted", pointOfInterestId); return Response.status(Status.NOT_FOUND).build(); } } else { - PointOfInterest mergePoi = ((Integer) mapFromApp.get("pointOfInterestId")) > 0 ? SessionControllerGetter.getPointOfInterestBean().getPointOfInterest((Integer) mapFromApp.get("pointOfInterestId")) : PointOfInterest.getInstance((Integer) mapFromApp.get("pointOfInterestTypeId")); + PointOfInterest mergePoi = pointOfInterestId > 0 ? pointOfInterestBean.getPointOfInterest(pointOfInterestId) : PointOfInterest.getInstance((Integer) mapFromApp.get("pointOfInterestTypeId")); // Trying to sync a non-existing POI if (mergePoi == null) { + LOGGER.error("POI with id={} not found, nothing updated", pointOfInterestId); return Response.status(Status.NOT_FOUND).build(); } @@ -228,11 +302,11 @@ public class POIService { Point p3d = gisUtil.createPointWGS84(coordinate); mergePoi.setGisGeom(p3d); - mergePoi = SessionControllerGetter.getPointOfInterestBean().getPointOfInterest(SessionControllerGetter.getPointOfInterestBean().storePoi(mergePoi).getPointOfInterestId()); - + mergePoi = pointOfInterestBean.getPointOfInterest(pointOfInterestBean.storePoi(mergePoi).getPointOfInterestId()); return Response.ok().entity(mergePoi).build(); } } catch (IOException e) { + LOGGER.error("Exception when syncing POI", e); return Response.serverError().entity(e).build(); } diff --git a/src/main/java/no/nibio/vips/logic/service/VIPSMobileService.java b/src/main/java/no/nibio/vips/logic/service/VIPSMobileService.java index 2c8c8736c20f8b841343270040a2384c5fb801c3..6fd9c7144201718309e5970080cf0aedd303b22b 100755 --- a/src/main/java/no/nibio/vips/logic/service/VIPSMobileService.java +++ b/src/main/java/no/nibio/vips/logic/service/VIPSMobileService.java @@ -30,15 +30,15 @@ import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import java.util.TimeZone; -import javax.ejb.EJB; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.QueryParam; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; +import jakarta.ejb.EJB; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.QueryParam; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; import no.nibio.vips.entity.Result; import no.nibio.vips.logic.controller.session.ForecastBean; import no.nibio.vips.logic.controller.session.MessageBean; diff --git a/src/main/java/no/nibio/vips/logic/startup/StartupListener.java b/src/main/java/no/nibio/vips/logic/startup/StartupListener.java index 6e3c8b333f7898ab6f5c47ae6f48c628459a5b87..2a7a720218f16bf19a63affb8fe95697c4f0f3c7 100755 --- a/src/main/java/no/nibio/vips/logic/startup/StartupListener.java +++ b/src/main/java/no/nibio/vips/logic/startup/StartupListener.java @@ -18,9 +18,9 @@ package no.nibio.vips.logic.startup; -import javax.annotation.Resource; -import javax.ejb.EJB; -import javax.servlet.ServletContextEvent; +import jakarta.annotation.Resource; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletContextEvent; import javax.sql.DataSource; import no.nibio.vips.logic.controller.session.SchedulingBean; import org.flywaydb.core.Flyway; @@ -32,7 +32,7 @@ import org.flywaydb.core.Flyway; * @copyright 2013-2022 {@link http://www.nibio.no NIBIO} * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ -public class StartupListener implements javax.servlet.ServletContextListener{ +public class StartupListener implements jakarta.servlet.ServletContextListener{ @Resource(lookup="java:/jboss/datasources/vipslogic") DataSource vipslogicDS; diff --git a/src/main/java/no/nibio/vips/logic/util/CorsProxyServlet.java b/src/main/java/no/nibio/vips/logic/util/CorsProxyServlet.java index e8d735e5345dd36b4dd3db89941470be9e026a4a..bf97a497757a624bcaab29ec87284cea8b62963e 100644 --- a/src/main/java/no/nibio/vips/logic/util/CorsProxyServlet.java +++ b/src/main/java/no/nibio/vips/logic/util/CorsProxyServlet.java @@ -25,10 +25,10 @@ import java.io.InputStreamReader; import java.io.PrintWriter; import java.net.HttpURLConnection; import java.net.URL; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; /** * Simple HTTP(S) proxy to avoid the CORS issues with using external web services diff --git a/src/main/java/no/nibio/vips/logic/util/ExcelFileGenerator.java b/src/main/java/no/nibio/vips/logic/util/ExcelFileGenerator.java new file mode 100644 index 0000000000000000000000000000000000000000..242306b53b1674404bb49a9f6503cc17e18e8cf0 --- /dev/null +++ b/src/main/java/no/nibio/vips/logic/util/ExcelFileGenerator.java @@ -0,0 +1,441 @@ +package no.nibio.vips.logic.util; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.ibm.icu.util.ULocale; +import no.nibio.vips.logic.entity.VipsLogicUser; +import no.nibio.vips.logic.entity.rest.ObservationListItem; +import no.nibio.vips.observationdata.ObservationDataSchema; +import org.apache.poi.common.usermodel.HyperlinkType; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import org.apache.poi.ss.usermodel.*; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.time.format.DateTimeFormatter; +import java.util.*; + +public final class ExcelFileGenerator { + + private static final Logger LOGGER = LoggerFactory.getLogger(ExcelFileGenerator.class); + private static final DateTimeFormatter DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd"); + private static final DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"); + private static final ObjectMapper objectMapper = new ObjectMapper(); + + private static final String VIPSWEB = "https://www.vips-landbruk.no"; + private static final String VIPSLOGIC = "https://logic.vips.nibio.no"; + + private enum ColumnIndex { + ID(false, 0, 0, "observationId"), + DATE(false, 1, 1, "timeOfObservation"), + POI_NAME(false, 2, 2, "location"), + OBSERVER_NAME(true, null, 3, "observer"), + OBSERVATION_TIME_SERIES_LABEL(false, 3, 4, "observationTimeSeriesLabel"), + ORGANISM(false, 4, 5, "organism"), + CROP_ORGANISM(false, 5, 6, "cropOrganismId"), + HEADING(false, 6, 7, "observationHeading"), + DESCRIPTION(false, 7, 8, "observationText"), + BROADCAST(false, 8, 9, "isBroadcast"), + POSITIVE(false, 9, 10, "isPositiveRegistration"), + INDEX_DATA(false, 10, 11, null); + + private final boolean isSensitive; + private final Integer openIndex; + private final Integer adminIndex; + private final String rbKey; + + ColumnIndex(boolean isSensitive, Integer openIndex, Integer adminIndex, String rbKey) { + this.isSensitive = isSensitive; + this.openIndex = openIndex; + this.adminIndex = adminIndex; + this.rbKey = rbKey; + } + + public static List<ColumnIndex> forUser(boolean isAdmin) { + if (!isAdmin) { + return Arrays.stream(ColumnIndex.values()).filter(columnIndex -> !columnIndex.isSensitive).toList(); + } + return Arrays.stream(ColumnIndex.values()).toList(); + } + + public String getColumnHeading(ResourceBundle rb) { + return rbKey != null && !rbKey.isBlank() ? rb.getString(rbKey) : ""; + } + + public Integer getIndex(boolean admin) { + if (admin) { + return adminIndex; + } + return openIndex; + } + } + + public static byte[] generateExcel(VipsLogicUser user, ULocale locale, LocalDateTime now, String fromStr, String toStr, List<ObservationListItem> observations) throws IOException { + ResourceBundle rb = ResourceBundle.getBundle("no.nibio.vips.logic.i18n.vipslogictexts", locale.toLocale()); + boolean isAdmin = user != null && (user.isSuperUser() || user.isOrganizationAdmin()); + LOGGER.info("Create Excel file containing {} observations for {} user", observations.size(), isAdmin ? "admin" : "regular"); + try (XSSFWorkbook workbook = new XSSFWorkbook(); + ByteArrayOutputStream out = new ByteArrayOutputStream()) { + + Font font = workbook.createFont(); + font.setBold(true); + CellStyle headerStyle = workbook.createCellStyle(); + headerStyle.setFont(font); + + // Create main sheet for all observations, with header row + Sheet mainSheet = workbook.createSheet(rb.getString("allObservations")); + createHeaderRow(isAdmin, mainSheet, headerStyle, rb); + + int mainSheetRowIndex = 1; + // Add one row for each observation in list of all observations + for (ObservationListItem item : observations) { + createItemRow(isAdmin, mainSheet, mainSheetRowIndex++, item, rb); + } + autoSizeColumns(mainSheet, 0, ColumnIndex.INDEX_DATA.getIndex(isAdmin) - 1); + + // Create meta sheet for information about the download + Sheet metaSheet = workbook.createSheet(rb.getString("downloadInfo")); + addMetaInfo(metaSheet, user, now, fromStr, toStr, observations, headerStyle, rb); + + // Prepare list of observations for each type of pest + Map<Integer, List<ObservationListItem>> pestObservations = getObservationsForEachPest(observations); + + // Create sheets for each individual pest type + for (Integer pestId : pestObservations.keySet()) { + List<ObservationListItem> observationsForPest = pestObservations.get(pestId); + ObservationListItem firstObservationForPest = observationsForPest.get(0); + String pestName = firstObservationForPest.getOrganismName(); + Sheet pestSheet = workbook.createSheet(sanitizeSheetName(pestId, pestName)); + Row headerRow = createHeaderRow(isAdmin, pestSheet, headerStyle, rb); + + // Add column titles for observation data + Map<String, String> dataColumnTitles = getObservationDataColumnTitles(firstObservationForPest.getObservationDataSchema()); + int pestSheetColIndex = ColumnIndex.INDEX_DATA.getIndex(isAdmin); + for (String key : dataColumnTitles.keySet()) { + Cell cell = headerRow.createCell(pestSheetColIndex++); + cell.setCellStyle(headerStyle); + cell.setCellValue(dataColumnTitles.get(key)); + } + + int pestSheetRowIndex = 1; + for (ObservationListItem item : observationsForPest) { + Row row = createItemRow(isAdmin, pestSheet, pestSheetRowIndex++, item, rb); + + if (item.getObservationData() != null) { + Map<String, Object> observationDataMap = objectMapper.readValue(item.getObservationData(), HashMap.class); + if (observationDataMap != null) { + pestSheetColIndex = ColumnIndex.INDEX_DATA.getIndex(isAdmin); + for (String key : dataColumnTitles.keySet()) { + pestSheetColIndex = addValueToCell(row, pestSheetColIndex, observationDataMap.get(key)); + } + } + } + } + autoSizeColumns(pestSheet, ColumnIndex.ID.getIndex(isAdmin), ColumnIndex.INDEX_DATA.getIndex(isAdmin) + dataColumnTitles.size()); + } + + workbook.write(out); + return out.toByteArray(); + } + } + + /** + * Add meta information to given sheet + * + * @param metaSheet The sheet in which to add content + * @param user The current user + * @param now The current timestamp + * @param fromStr The start of the period for which we have observations + * @param toStr The end of the period for which we have observations + * @param observations The list of observations + * @param headerStyle How to style the title cells + * @param rb Resource bundle with translations + */ + private static void addMetaInfo(Sheet metaSheet, VipsLogicUser user, LocalDateTime now, String fromStr, String toStr, List<ObservationListItem> observations, CellStyle headerStyle, ResourceBundle rb) { + Row userRow = metaSheet.createRow(0); + Cell downloadedByCell = userRow.createCell(0); + downloadedByCell.setCellStyle(headerStyle); + downloadedByCell.setCellValue(rb.getString("downloadedBy")); + userRow.createCell(1).setCellValue(user != null ? user.getFullName() : rb.getString("unregisteredUser")); + Row timeRow = metaSheet.createRow(1); + Cell downloadedTimeCell = timeRow.createCell(0); + downloadedTimeCell.setCellStyle(headerStyle); + downloadedTimeCell.setCellValue(rb.getString("downloadedTime")); + timeRow.createCell(1).setCellValue(DATE_TIME_FORMATTER.format(now)); + Row fromRow = metaSheet.createRow(2); + Cell dateFromCell = fromRow.createCell(0); + dateFromCell.setCellStyle(headerStyle); + dateFromCell.setCellValue(rb.getString("dateStart")); + fromRow.createCell(1).setCellValue(fromStr); + Row toRow = metaSheet.createRow(3); + Cell dateToCell = toRow.createCell(0); + dateToCell.setCellStyle(headerStyle); + dateToCell.setCellValue(rb.getString("dateEnd")); + toRow.createCell(1).setCellValue(toStr); + Row countRow = metaSheet.createRow(4); + Cell countCell = countRow.createCell(0); + countCell.setCellStyle(headerStyle); + countCell.setCellValue(rb.getString("observationCount")); + countRow.createCell(1).setCellValue(observations.size()); + autoSizeColumns(metaSheet, 0, 1); + } + + /** + * Create sheet name without invalid characters and within size limits + * + * @param pestId The id of the pest + * @param pestName The name of the pest + * @return a sanitized string to be used as sheet name + */ + private static String sanitizeSheetName(Integer pestId, String pestName) { + if (pestName == null || pestName.isBlank()) { + return "Id=" + pestId; + } + return pestName.replaceAll("[\\[\\]\\*/:?\\\\]", "_").substring(0, Math.min(pestName.length(), 31)); + } + + + /** + * Auto-size columns of given sheet, from startIndex to endIndex, to ensure that content fits + * + * @param sheet The sheet of which to auto-size columns + * @param startIndex The index of the first column to auto-size + * @param endIndex The index of the last column to auto-size + */ + private static void autoSizeColumns(Sheet sheet, int startIndex, int endIndex) { + for (int i = startIndex; i <= endIndex; i++) { + sheet.autoSizeColumn(i); + } + } + + /** + * Create map with data property name as key, and corresponding localized name as value + * + * @param observationDataSchema The observation data schema which contains localized names and other info + * @return result map + */ + private static Map<String, String> getObservationDataColumnTitles(ObservationDataSchema observationDataSchema) throws JsonProcessingException { + JsonNode rootNode = objectMapper.readTree(observationDataSchema.getDataSchema()); + JsonNode propertiesNode = rootNode.path("properties"); + Map<String, String> resultMap = new HashMap<>(); + Iterator<Map.Entry<String, JsonNode>> fields = propertiesNode.fields(); + while (fields.hasNext()) { + Map.Entry<String, JsonNode> field = fields.next(); + String key = field.getKey(); + String value = field.getValue().path("title").asText(); + resultMap.put(key, value); + } + return resultMap; + } + + /** + * Create map with pestId as key, and list of corresponding observations as value + * + * @param observations The original list of observations + * @return result map + */ + private static Map<Integer, List<ObservationListItem>> getObservationsForEachPest(List<ObservationListItem> observations) { + Map<Integer, List<ObservationListItem>> pestObservations = new HashMap<>(); + for (ObservationListItem observation : observations) { + Integer pestId = observation.getOrganismId(); + if (!pestObservations.containsKey(pestId)) { + List<ObservationListItem> observationList = new ArrayList<>(); + observationList.add(observation); + pestObservations.put(pestId, observationList); + } else { + pestObservations.get(pestId).add(observation); + } + } + return pestObservations; + } + + /** + * Create first row of given sheet, with column titles dependent on user privileges + * + * @param isAdmin Whether the user is a logged in admin + * @param sheet The sheet to which a row will be added + * @param headerStyle The style to be applied to each cell in the header row + * @param rb A resource bundle enabling localized messages + * @return the newly created header row + */ + public static Row createHeaderRow(boolean isAdmin, Sheet sheet, CellStyle headerStyle, ResourceBundle rb) { + Row headerRow = sheet.createRow(0); + for (ColumnIndex columnIndex : ColumnIndex.forUser(isAdmin)) { + Cell cell = headerRow.createCell(columnIndex.getIndex(isAdmin)); + cell.setCellStyle(headerStyle); + cell.setCellValue(columnIndex.getColumnHeading(rb)); + } + return headerRow; + } + + /** + * Create row with given index, for given observation list item + * + * @param isAdmin Whether the user is a logged in admin + * @param sheet The sheet to which a row will be added + * @param rowIndex The index of the row + * @param item The item of which to add data + * @return the newly created row + */ + private static Row createItemRow(boolean isAdmin, Sheet sheet, int rowIndex, ObservationListItem item, ResourceBundle rb) throws JsonProcessingException { + LocalDate localDateOfObservation = item.getTimeOfObservation().toInstant().atZone(ZoneId.systemDefault()).toLocalDate(); + Row row = sheet.createRow(rowIndex); + addObservationLink(row, ColumnIndex.ID.getIndex(isAdmin), item.getObservationId()); + addValueToCell(row, ColumnIndex.DATE.getIndex(isAdmin), localDateOfObservation.format(DATE_FORMATTER)); + + if (item.getLocationPointOfInterestId() != null) { + Integer poiNameIndex = ColumnIndex.POI_NAME.getIndex(isAdmin); + if(isAdmin) { + addPoiLink(row, poiNameIndex, item.getLocationPointOfInterestId(), item.getLocationPointOfInterestName()); + } else { + addValueToCell(row, poiNameIndex, item.getLocationPointOfInterestName()); + } + } + + if (isAdmin) { + addUserLink(row, ColumnIndex.OBSERVER_NAME.getIndex(isAdmin), item.getObserverId(), item.getObserverName()); + } + if (item.getObservationTimeSeriesId() != null) { + addTimeSeriesLink(row, ColumnIndex.OBSERVATION_TIME_SERIES_LABEL.getIndex(isAdmin), item.getObservationTimeSeriesId(), item.getObservationTimeSeriesLabel()); + } + addValueToCell(row, ColumnIndex.ORGANISM.getIndex(isAdmin), item.getOrganismName()); + addValueToCell(row, ColumnIndex.CROP_ORGANISM.getIndex(isAdmin), item.getCropOrganismName()); + addValueToCell(row, ColumnIndex.HEADING.getIndex(isAdmin), item.getObservationHeading()); + addValueToCell(row, ColumnIndex.DESCRIPTION.getIndex(isAdmin), item.getObservationText()); + + addValueToCell(row, ColumnIndex.BROADCAST.getIndex(isAdmin), getBooleanStringValue(rb, item.getBroadcastMessage())); + addValueToCell(row, ColumnIndex.POSITIVE.getIndex(isAdmin), getBooleanStringValue(rb, item.getIsPositive())); + return row; + } + + /** + * Add value to cell + * + * @param row The row to which the value should be added + * @param colIndex The index of the column to add the value to + * @param value The value + * @return The next index value + */ + private static Integer addValueToCell(Row row, Integer colIndex, Object value) { + Integer index = colIndex; + if (value == null) { + row.createCell(index++).setCellValue(""); + } else if (value instanceof Number) { + row.createCell(index++).setCellValue(((Number) value).intValue()); + } else { + try { + int intValue = Integer.parseInt(value.toString()); + row.createCell(index++).setCellValue(intValue); + } catch (NumberFormatException e) { + row.createCell(index++).setCellValue(value.toString()); + } + } + return index; + } + + /** + * Get a localized String representing either true or false + * + * @param rb The resource bundle to get the localized string from + * @param value Either true or false + * @return A localized String + */ + private static String getBooleanStringValue(ResourceBundle rb, Boolean value) { + if (value == null) { + return null; + } else if (value) { + return rb.getString("yes"); + } + return rb.getString("no"); + } + + /** + * Add link to observation details in column containing the observation Id + * + * @param row A reference to the current row + * @param colIndex The index of the column in which the link should be added + * @param observationId The id of the observation + */ + private static void addObservationLink(Row row, Integer colIndex, Integer observationId) { + Cell cell = row.createCell(colIndex); + cell.setCellValue(observationId); + + Workbook workbook = row.getSheet().getWorkbook(); + cell.setHyperlink(createHyperlink(workbook, VIPSWEB + "/observations/" + observationId)); + cell.setCellStyle(hyperlinkCellStyle(workbook)); + } + + /** + * Add link to timeseries details in column with given index + * + * @param row A reference to the current row + * @param colIndex The index of the column in which the link should be added + * @param timeSeriesId The id of the timeseries + * @param timeSeriesLabel The text which should be displayed in the cell + */ + private static void addTimeSeriesLink(Row row, Integer colIndex, Integer timeSeriesId, String timeSeriesLabel) { + Cell cell = row.createCell(colIndex); + cell.setCellValue(timeSeriesLabel); + + Workbook workbook = row.getSheet().getWorkbook(); + cell.setHyperlink(createHyperlink(workbook, VIPSWEB + "/observations/timeseries/" + timeSeriesId)); + cell.setCellStyle(hyperlinkCellStyle(workbook)); + } + + /** + * Add link to poi details in column with given index + * + * @param row A reference to the current row + * @param colIndex The index of the column in which the link should be added + * @param poiId The id of the poi + * @param poiName The text which should be displayed in the cell + */ + private static void addPoiLink(Row row, Integer colIndex, Integer poiId, String poiName) { + Cell cell = row.createCell(colIndex); + cell.setCellValue(poiName); + + Workbook workbook = row.getSheet().getWorkbook(); + cell.setHyperlink(createHyperlink(workbook, VIPSLOGIC + "/weatherStation?pointOfInterestId=" + poiId)); + cell.setCellStyle(hyperlinkCellStyle(workbook)); + } + + /** + * Add link to user details in column with given index + * + * @param row A reference to the current row + * @param colIndex The index of the column in which the link should be added + * @param userId The id of the user + * @param userName The text which should be displayed in the cell + */ + private static void addUserLink(Row row, Integer colIndex, Integer userId, String userName) { + Cell cell = row.createCell(colIndex); + cell.setCellValue(userName); + + Workbook workbook = row.getSheet().getWorkbook(); + cell.setHyperlink(createHyperlink(workbook, VIPSLOGIC + "/user?action=viewUser&userId=" + userId)); + cell.setCellStyle(hyperlinkCellStyle(workbook)); + } + + private static Hyperlink createHyperlink(Workbook workbook, String url) { + CreationHelper creationHelper = workbook.getCreationHelper(); + Hyperlink hyperlink = creationHelper.createHyperlink(HyperlinkType.URL); + hyperlink.setAddress(url); + return hyperlink; + } + + private static CellStyle hyperlinkCellStyle(Workbook workbook) { + CellStyle hyperlinkStyle = workbook.createCellStyle(); + Font hlinkFont = workbook.createFont(); + hlinkFont.setUnderline(Font.U_SINGLE); + hlinkFont.setColor(IndexedColors.BLUE.getIndex()); + hyperlinkStyle.setFont(hlinkFont); + return hyperlinkStyle; + } + +} diff --git a/src/main/java/no/nibio/vips/logic/util/HierarchyCategoryLocaleNames.java b/src/main/java/no/nibio/vips/logic/util/HierarchyCategoryLocaleNames.java index 3918f9d8f93a91c3bebe1e22e19778e5aa5b382e..9d3583ca3b2b47a8a6733f67ab485a6c00d6d788 100755 --- a/src/main/java/no/nibio/vips/logic/util/HierarchyCategoryLocaleNames.java +++ b/src/main/java/no/nibio/vips/logic/util/HierarchyCategoryLocaleNames.java @@ -33,7 +33,7 @@ public class HierarchyCategoryLocaleNames { public String getName(Integer hierarchyCategoryId) { - return this.nameMap.get(hierarchyCategoryId); + return this.nameMap.get(hierarchyCategoryId) != null ? this.nameMap.get(hierarchyCategoryId) : ""; } public List<Integer> getHierarchyCategoryIds() diff --git a/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java b/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java deleted file mode 100755 index 94ea3338fd130ee6b915935a663404cfca488ee2..0000000000000000000000000000000000000000 --- a/src/main/java/no/nibio/vips/logic/util/IntegerArrayUserType.java +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (c) 2015 NIBIO <http://www.nibio.no/>. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - */ - -package no.nibio.vips.logic.util; - -import java.io.Serializable; -import java.sql.Array; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import org.hibernate.HibernateException; -import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.usertype.UserType; - -/** - * Adapted from this: http://stackoverflow.com/questions/21940642/hibernate-postgres-array-type - * @copyright 2015-2019 <a href="http://www.nibio.no/">NIBIO</a> - * @author Tor-Einar Skog <tor-einar.skog@nibio.no> - */ - -public class IntegerArrayUserType implements UserType { - - /** - * Return the SQL type codes for the columns mapped by this type. The - * codes are defined on <tt>java.sql.Types</tt>. - * - * @return int[] the typecodes - * @see java.sql.Types - */ - @Override - public int[] sqlTypes() { - return new int[] { Types.ARRAY }; - } - - /** - * The class returned by <tt>nullSafeGet()</tt>. - * - * @return Class - */ - @Override - public Class returnedClass() { - return Integer[].class; - } - - /** - * Compare two instances of the class mapped by this type for persistence "equality". - * Equality of the persistent state. - * - * @param x - * @param y - * @return boolean - */ - @Override - public boolean equals(Object x, Object y) throws HibernateException { - - if( x== null){ - - return y== null; - } - - return x.equals( y); - } - - /** - * Get a hashcode for the instance, consistent with persistence "equality" - */ - @Override - public int hashCode(Object x) throws HibernateException { - - return x.hashCode(); - } - - /** - * Retrieve an instance of the mapped class from a JDBC resultset. Implementors - * should handle possibility of null values. - * - * @param rs a JDBC result set - * @param names the column names - * @param session - * @param owner the containing entity @return Object - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - //@Override - public Object nullSafeGet( - ResultSet rs, - String[] names, - SessionImplementor session, - Object owner) throws HibernateException, SQLException { - if (rs.wasNull()) { - return null; - } - - try - { - Integer[] array = (Integer[]) rs.getArray(names[0]).getArray(); - return array; - } - catch(NullPointerException ex) - { - return new Integer[0]; - } - } - - /** - * Write an instance of the mapped class to a prepared statement. Implementors - * should handle possibility of null values. A multi-column type should be written - * to parameters starting from <tt>index</tt>. - * - * @param st a JDBC prepared statement - * @param value the object to write - * @param index statement parameter index - * @param session - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - //@Override - public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { - if (value == null) { - st.setNull(index, Types.OTHER); - return; - } - - Integer[] castObject = (Integer[]) value; - Array array = session.connection().createArrayOf("integer", castObject); // The postgres array data type - st.setArray(index, array); - } - - /** - * Return a deep copy of the persistent state, stopping at entities and at - * collections. It is not necessary to copy immutable objects, or null - * values, in which case it is safe to simply return the argument. - * - * @param value the object to be cloned, which may be null - * @return Object a copy - */ - @Override - public Object deepCopy(Object value) throws HibernateException { - - return value; - } - - /** - * Are objects of this type mutable? - * - * @return boolean - */ - @Override - public boolean isMutable() { - return true; - } - - /** - * Transform the object into its cacheable representation. At the very least this - * method should perform a deep copy if the type is mutable. That may not be enough - * for some implementations, however; for example, associations must be cached as - * identifier values. (optional operation) - * - * @param value the object to be cached - * @return a cachable representation of the object - * @throws org.hibernate.HibernateException - * - */ - @Override - public Serializable disassemble(Object value) throws HibernateException { - return (Integer[])this.deepCopy( value); - } - - /** - * Reconstruct an object from the cacheable representation. At the very least this - * method should perform a deep copy if the type is mutable. (optional operation) - * - * @param cached the object to be cached - * @param owner the owner of the cached object - * @return a reconstructed object from the cachable representation - * @throws org.hibernate.HibernateException - * - */ - @Override - public Object assemble(Serializable cached, Object owner) throws HibernateException { - return this.deepCopy( cached); - } - - /** - * During merge, replace the existing (target) value in the entity we are merging to - * with a new (original) value from the detached entity we are merging. For immutable - * objects, or null values, it is safe to simply return the first parameter. For - * mutable objects, it is safe to return a copy of the first parameter. For objects - * with component values, it might make sense to recursively replace component values. - * - * @param original the value from the detached entity being merged - * @param target the value in the managed entity - * @return the value to be merged - */ - @Override - public Object replace(Object original, Object target, Object owner) throws HibernateException { - return original; - } - - /** - * Retrieve an instance of the mapped class from a JDBC resultset. Implementors - * should handle possibility of null values. - * - * @param rs a JDBC result set - * @param strings the column names - * @param ssci - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - @Override - public Object nullSafeGet(ResultSet rs, String[] strings, SharedSessionContractImplementor ssci, Object o) throws HibernateException, SQLException { - if (rs.wasNull()) { - return null; - } - try - { - Integer[] array = (Integer[]) rs.getArray(strings[0]).getArray(); - return array; - } - catch(NullPointerException ex) - { - return new Integer[0]; - } - } - - /** - * Write an instance of the mapped class to a prepared statement. Implementors - * should handle possibility of null values. A multi-column type should be written - * to parameters starting from <tt>index</tt>. - * - * @param ps a JDBC prepared statement - * @param o the object to write - * @param i statement parameter index - * @param ssci - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - @Override - public void nullSafeSet(PreparedStatement ps, Object o, int i, SharedSessionContractImplementor ssci) throws HibernateException, SQLException { - if (o == null) { - ps.setNull(i, Types.OTHER); - return; - } - - Integer[] castObject = (Integer[]) o; - Array array = ssci.connection().createArrayOf("integer", castObject); // The postgres array data type - ps.setArray(i, array); - } - - -} diff --git a/src/main/java/no/nibio/vips/logic/util/JsonPostgreSQLDialect.java b/src/main/java/no/nibio/vips/logic/util/JsonPostgreSQLDialect.java deleted file mode 100755 index 2e7dda6a31abe3dec1d7ec726d5e07ad6fbb52d1..0000000000000000000000000000000000000000 --- a/src/main/java/no/nibio/vips/logic/util/JsonPostgreSQLDialect.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * Copyright (c) 2015 NIBIO <http://www.nibio.no/>. - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. - * - */ - -package no.nibio.vips.logic.util; - -import java.sql.Types; -import org.hibernate.dialect.PostgreSQL9Dialect; - -/** - * @copyright 2015 <a href="http://www.nibio.no/">NIBIO</a> - * @author Tor-Einar Skog <tor-einar.skog@nibio.no> - */ -public class JsonPostgreSQLDialect extends PostgreSQL9Dialect{ - public JsonPostgreSQLDialect() { - - super(); - - this.registerColumnType(Types.JAVA_OBJECT, "json"); - } -} diff --git a/src/main/java/no/nibio/vips/logic/util/PostgresJSONStringConverter.java b/src/main/java/no/nibio/vips/logic/util/PostgresJSONStringConverter.java index d269df6fb18f0bfa4c6e6bbda6e6e8d7f35c700b..aafb201d8772df2d9bbe110bd3f9c30e48e727e7 100755 --- a/src/main/java/no/nibio/vips/logic/util/PostgresJSONStringConverter.java +++ b/src/main/java/no/nibio/vips/logic/util/PostgresJSONStringConverter.java @@ -19,8 +19,8 @@ package no.nibio.vips.logic.util; import java.sql.SQLException; -import javax.persistence.AttributeConverter; -import javax.persistence.Converter; +import jakarta.persistence.AttributeConverter; +import jakarta.persistence.Converter; import org.postgresql.util.PGobject; /** diff --git a/src/main/java/no/nibio/vips/logic/util/RESTAuthenticator.java b/src/main/java/no/nibio/vips/logic/util/RESTAuthenticator.java index c17fc1af77255b59234bd617fb832369a985d3bf..b7c20af15ca2174b1d0304b7319dc490aa686e81 100755 --- a/src/main/java/no/nibio/vips/logic/util/RESTAuthenticator.java +++ b/src/main/java/no/nibio/vips/logic/util/RESTAuthenticator.java @@ -20,9 +20,9 @@ package no.nibio.vips.logic.util; import java.io.IOException; import java.io.UnsupportedEncodingException; -import javax.ws.rs.client.ClientRequestContext; -import javax.ws.rs.client.ClientRequestFilter; -import javax.ws.rs.core.MultivaluedMap; +import jakarta.ws.rs.client.ClientRequestContext; +import jakarta.ws.rs.client.ClientRequestFilter; +import jakarta.ws.rs.core.MultivaluedMap; import javax.xml.bind.DatatypeConverter; diff --git a/src/main/java/no/nibio/vips/logic/util/SimpleMailSender.java b/src/main/java/no/nibio/vips/logic/util/SimpleMailSender.java index 682a18a10fa4557c17d396db997d18aa517cd77f..7dc0c19c122ebd138611344745e289d5155e0ecf 100755 --- a/src/main/java/no/nibio/vips/logic/util/SimpleMailSender.java +++ b/src/main/java/no/nibio/vips/logic/util/SimpleMailSender.java @@ -21,8 +21,8 @@ package no.nibio.vips.logic.util; import java.util.Iterator; import java.util.List; -import javax.mail.*; -import javax.mail.internet.*; +import jakarta.mail.*; +import jakarta.mail.internet.*; import java.util.Properties; @@ -70,8 +70,8 @@ public class SimpleMailSender { Transport.send(message); } - catch(javax.mail.internet.AddressException ae){ae.printStackTrace();} - catch(javax.mail.MessagingException me) {me.printStackTrace();} + catch(jakarta.mail.internet.AddressException ae){ae.printStackTrace();} + catch(jakarta.mail.MessagingException me) {me.printStackTrace();} } /** @@ -106,8 +106,8 @@ public class SimpleMailSender { Transport.send(message); } - catch(javax.mail.internet.AddressException ae){ae.printStackTrace();} - catch(javax.mail.MessagingException me) {me.printStackTrace();} + catch(jakarta.mail.internet.AddressException ae){ae.printStackTrace();} + catch(jakarta.mail.MessagingException me) {me.printStackTrace();} } } \ No newline at end of file diff --git a/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java b/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java index 1672d607cbfc160fe8502e5482b303e656010a70..7ecd7ec8375cf88318b4416786cb93493950bfd9 100755 --- a/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java +++ b/src/main/java/no/nibio/vips/logic/util/StringJsonUserType.java @@ -23,224 +23,74 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; -import org.hibernate.HibernateException; -import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.usertype.UserType; /** - * @copyright 2015-2019 <a href="http://www.nibio.no/">NIBIO</a> + * @copyright 2015-2025 <a href="http://www.nibio.no/">NIBIO</a> * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ -public class StringJsonUserType implements UserType { +public class StringJsonUserType implements UserType<String> { - /** - * Return the SQL type codes for the columns mapped by this type. The - * codes are defined on <tt>java.sql.Types</tt>. - * - * @return int[] the typecodes - * @see java.sql.Types - */ @Override - public int[] sqlTypes() { - return new int[] { Types.JAVA_OBJECT}; + public int getSqlType() { + return Types.OTHER; } - /** - * The class returned by <tt>nullSafeGet()</tt>. - * - * @return Class - */ @Override - public Class returnedClass() { + public Class<String> returnedClass() { return String.class; } - /** - * Compare two instances of the class mapped by this type for persistence "equality". - * Equality of the persistent state. - * - * @param x - * @param y - * @return boolean - */ @Override - public boolean equals(Object x, Object y) throws HibernateException { - - if( x== null){ - - return y== null; - } - - return x.equals( y); + public boolean equals(String x, String y) { + return x.equals(y); } - /** - * Get a hashcode for the instance, consistent with persistence "equality" - */ @Override - public int hashCode(Object x) throws HibernateException { - + public int hashCode(String x) { return x.hashCode(); } - /** - * Retrieve an instance of the mapped class from a JDBC resultset. Implementors - * should handle possibility of null values. - * - * @param rs a JDBC result set - * @param names the column names - * @param session - * @param owner the containing entity @return Object - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - //@Override - public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { - if(rs.getString(names[0]) == null){ - return null; - } - return rs.getString(names[0]); + @Override + public String nullSafeGet(ResultSet rs, int position, SharedSessionContractImplementor session, Object owner) throws SQLException { + return rs.getString(position); } - /** - * Write an instance of the mapped class to a prepared statement. Implementors - * should handle possibility of null values. A multi-column type should be written - * to parameters starting from <tt>index</tt>. - * - * @param st a JDBC prepared statement - * @param value the object to write - * @param index statement parameter index - * @param session - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - //@Override - public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { - if (value == null) { + @Override + public void nullSafeSet(PreparedStatement st, String value, int index, SharedSessionContractImplementor session) throws SQLException { + if (value != null) { + st.setObject(index, value, Types.OTHER); + } else { st.setNull(index, Types.OTHER); - return; } - - st.setObject(index, value, Types.OTHER); } - /** - * Return a deep copy of the persistent state, stopping at entities and at - * collections. It is not necessary to copy immutable objects, or null - * values, in which case it is safe to simply return the argument. - * - * @param value the object to be cloned, which may be null - * @return Object a copy - */ @Override - public Object deepCopy(Object value) throws HibernateException { - + public String deepCopy(String value) { return value; } - /** - * Are objects of this type mutable? - * - * @return boolean - */ @Override public boolean isMutable() { - return true; + return false; } - /** - * Transform the object into its cacheable representation. At the very least this - * method should perform a deep copy if the type is mutable. That may not be enough - * for some implementations, however; for example, associations must be cached as - * identifier values. (optional operation) - * - * @param value the object to be cached - * @return a cachable representation of the object - * @throws org.hibernate.HibernateException - * - */ @Override - public Serializable disassemble(Object value) throws HibernateException { - return (String)this.deepCopy( value); + public Serializable disassemble(String value) { + return value; } - /** - * Reconstruct an object from the cacheable representation. At the very least this - * method should perform a deep copy if the type is mutable. (optional operation) - * - * @param cached the object to be cached - * @param owner the owner of the cached object - * @return a reconstructed object from the cachable representation - * @throws org.hibernate.HibernateException - * - */ @Override - public Object assemble(Serializable cached, Object owner) throws HibernateException { - return this.deepCopy( cached); + public String assemble(Serializable cached, Object owner) { + return (String) cached; } - /** - * During merge, replace the existing (target) value in the entity we are merging to - * with a new (original) value from the detached entity we are merging. For immutable - * objects, or null values, it is safe to simply return the first parameter. For - * mutable objects, it is safe to return a copy of the first parameter. For objects - * with component values, it might make sense to recursively replace component values. - * - * @param original the value from the detached entity being merged - * @param target the value in the managed entity - * @return the value to be merged - */ @Override - public Object replace(Object original, Object target, Object owner) throws HibernateException { + public String replace(String original, String target, Object owner) { return original; } - - /** - * Retrieve an instance of the mapped class from a JDBC resultset. Implementors - * should handle possibility of null values. - * - * @param rs a JDBC result set - * @param strings the column names - * @param ssci - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - @Override - public Object nullSafeGet(ResultSet rs, String[] strings, SharedSessionContractImplementor ssci, Object o) throws HibernateException, SQLException { - if(rs.getString(strings[0]) == null){ - return null; - } - return rs.getString(strings[0]); - } - - /** - * Write an instance of the mapped class to a prepared statement. Implementors - * should handle possibility of null values. A multi-column type should be written - * to parameters starting from <tt>index</tt>. - * - * @param ps a JDBC prepared statement - * @param o the object to write - * @param i statement parameter index - * @param ssci - * @throws org.hibernate.HibernateException - * - * @throws java.sql.SQLException - */ - @Override - public void nullSafeSet(PreparedStatement ps, Object o, int i, SharedSessionContractImplementor ssci) throws HibernateException, SQLException { - if (o == null) { - ps.setNull(i, Types.OTHER); - return; - } - - ps.setObject(i, o, Types.OTHER); - } - } diff --git a/src/main/java/no/nibio/vips/logic/web/TemplateConfigFilter.java b/src/main/java/no/nibio/vips/logic/web/TemplateConfigFilter.java index 8de57a78a1212ee18130d3d5e3ff6078c3494314..ceb6c2578453b4f54fe897635c72c3182fe26f0e 100755 --- a/src/main/java/no/nibio/vips/logic/web/TemplateConfigFilter.java +++ b/src/main/java/no/nibio/vips/logic/web/TemplateConfigFilter.java @@ -20,13 +20,13 @@ package no.nibio.vips.logic.web; import java.io.IOException; import java.util.Date; -import javax.servlet.Filter; -import javax.servlet.FilterChain; -import javax.servlet.FilterConfig; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.HttpServletRequest; +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.FilterConfig; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.HttpServletRequest; import no.nibio.vips.logic.util.SystemTime; import no.nibio.vips.util.ServletUtil; diff --git a/src/main/java/no/nibio/vips/logic/web/js/JSEnvironment.java b/src/main/java/no/nibio/vips/logic/web/js/JSEnvironment.java index 9c0683c6bac787a30ba234ca77171dd5f21cecd0..17211ad6966de935cdd3ca7767e1150c91e8537e 100755 --- a/src/main/java/no/nibio/vips/logic/web/js/JSEnvironment.java +++ b/src/main/java/no/nibio/vips/logic/web/js/JSEnvironment.java @@ -20,10 +20,10 @@ package no.nibio.vips.logic.web.js; import java.io.IOException; import java.io.PrintWriter; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; import no.nibio.vips.logic.i18n.SessionLocaleUtil; /** diff --git a/src/main/java/no/nibio/vips/observationdata/ObservationDataBean.java b/src/main/java/no/nibio/vips/observationdata/ObservationDataBean.java index 357d5924bc150f6d263631a3db637cfcd2ea45ea..f05aee449984882d82cf0e0970297edaf1f92c6d 100644 --- a/src/main/java/no/nibio/vips/observationdata/ObservationDataBean.java +++ b/src/main/java/no/nibio/vips/observationdata/ObservationDataBean.java @@ -7,11 +7,11 @@ import java.util.Map; import java.util.ResourceBundle; import java.util.Map.Entry; -import javax.ejb.Stateless; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.servlet.http.HttpServletRequest; +import jakarta.ejb.Stateless; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.http.HttpServletRequest; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonMappingException; diff --git a/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java b/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java index 7243432516effd348cc842f2ed91040e34d919cc..6b5c4b9bc8d56876968178a56069d23c5f8ce5a7 100755 --- a/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java +++ b/src/main/java/no/nibio/vips/observationdata/ObservationDataSchema.java @@ -19,17 +19,15 @@ package no.nibio.vips.observationdata; import java.io.Serializable; -import javax.persistence.Column; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.Table; +import jakarta.persistence.Column; +import jakarta.persistence.EmbeddedId; +import jakarta.persistence.Entity; +import jakarta.persistence.NamedQueries; +import jakarta.persistence.NamedQuery; +import jakarta.persistence.Table; import javax.xml.bind.annotation.XmlRootElement; -import no.nibio.vips.logic.util.StringJsonUserType; -import org.hibernate.annotations.Type; -import org.hibernate.annotations.TypeDef; -import org.hibernate.annotations.TypeDefs; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.type.SqlTypes; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> @@ -38,7 +36,6 @@ import org.hibernate.annotations.TypeDefs; @Entity @Table(name = "observation_data_schema") @XmlRootElement -@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)}) @NamedQueries({ @NamedQuery(name = "ObservationDataSchema.findAll", query = "SELECT o FROM ObservationDataSchema o"), @NamedQuery(name = "ObservationDataSchema.findByPK", query = "SELECT o FROM ObservationDataSchema o WHERE o.observationDataSchemaPK.organizationId = :organizationId AND o.observationDataSchemaPK.organismId = :organismId"), @@ -49,10 +46,10 @@ public class ObservationDataSchema implements Serializable { private static final long serialVersionUID = 1L; @EmbeddedId protected ObservationDataSchemaPK observationDataSchemaPK; - @Type(type = "StringJsonObject") + @JdbcTypeCode(SqlTypes.JSON) @Column(name = "data_schema") private String dataSchema; - @Type(type = "StringJsonObject") + @JdbcTypeCode(SqlTypes.JSON) @Column(name = "data_model") private String dataModel; diff --git a/src/main/java/no/nibio/vips/observationdata/ObservationDataSchemaPK.java b/src/main/java/no/nibio/vips/observationdata/ObservationDataSchemaPK.java index 9fdaaa02b6b66b74fdc4becb6047df393767a91e..774e17466cc52ab5e93bf0be5a8a3407eb5c6b29 100755 --- a/src/main/java/no/nibio/vips/observationdata/ObservationDataSchemaPK.java +++ b/src/main/java/no/nibio/vips/observationdata/ObservationDataSchemaPK.java @@ -19,10 +19,10 @@ package no.nibio.vips.observationdata; import java.io.Serializable; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Embeddable; -import javax.validation.constraints.NotNull; +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Embeddable; +import jakarta.validation.constraints.NotNull; /** * @copyright 2016 <a href="http://www.nibio.no/">NIBIO</a> diff --git a/src/main/java/no/nibio/vips/observationdata/ObservationDataService.java b/src/main/java/no/nibio/vips/observationdata/ObservationDataService.java index b2143e09d2854f519c017690bae8d1a1725da42d..d2c1ce08cba1b4163c7d949cca0c1e86e81f53e2 100755 --- a/src/main/java/no/nibio/vips/observationdata/ObservationDataService.java +++ b/src/main/java/no/nibio/vips/observationdata/ObservationDataService.java @@ -21,17 +21,17 @@ package no.nibio.vips.observationdata; import com.ibm.icu.util.ULocale; import com.webcohesion.enunciate.metadata.Facet; import java.io.IOException; -import javax.ejb.EJB; -import javax.persistence.EntityManager; -import javax.persistence.NoResultException; -import javax.persistence.PersistenceContext; -import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.GET; -import javax.ws.rs.Path; -import javax.ws.rs.PathParam; -import javax.ws.rs.Produces; -import javax.ws.rs.core.Context; -import javax.ws.rs.core.Response; +import jakarta.ejb.EJB; +import jakarta.persistence.EntityManager; +import jakarta.persistence.NoResultException; +import jakarta.persistence.PersistenceContext; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.PathParam; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Context; +import jakarta.ws.rs.core.Response; import no.nibio.vips.logic.controller.session.ObservationBean; import no.nibio.vips.logic.controller.session.UserBean; diff --git a/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java b/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java index dd9eb671e3f25f4825265a19beb7154542e1467b..30b120b4e47eb54d3c0df15e9c2ddaab6794b3f0 100755 --- a/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java +++ b/src/main/java/no/nibio/vips/util/weather/WeatherDataSourceUtil.java @@ -73,6 +73,7 @@ public class WeatherDataSourceUtil { */ public List<WeatherObservation> getWeatherObservations(PointOfInterestWeatherStation station, Integer logIntervalId, String[] elementMeasurementTypes, Date startTime, Date endTime, Boolean ignoreErrors, Set<Integer> toleratedLogIntervalIds) throws WeatherDataSourceException { // Get measured (and possibly forecasted, depending on the data source) observations + LOGGER.info("Get weather observations for {} with URL {}", station.getName(), station.getDataFetchUri()); List<WeatherObservation> observations = this.getWeatherObservations(station.getDataFetchUri(), logIntervalId, elementMeasurementTypes, startTime, endTime, TimeZone.getTimeZone(station.getTimeZone()), ignoreErrors, toleratedLogIntervalIds); Collections.sort(observations); // Append forecasts, if available diff --git a/src/main/java/no/nibio/web/forms/FormUtil.java b/src/main/java/no/nibio/web/forms/FormUtil.java index 26cac47f96399f147b93bc21535cf14887760b8f..1817d7d4a91dd027df2eef023e19d2f49ac806da 100755 --- a/src/main/java/no/nibio/web/forms/FormUtil.java +++ b/src/main/java/no/nibio/web/forms/FormUtil.java @@ -18,7 +18,9 @@ package no.nibio.web.forms; +import java.io.IOException; import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -30,7 +32,7 @@ import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import no.nibio.vips.logic.util.Globals; -import org.apache.commons.fileupload.FileItem; +import org.apache.commons.fileupload2.core.FileItem; /** * @copyright 2014 <a href="http://www.nibio.no/">NIBIO</a> @@ -46,9 +48,10 @@ public class FormUtil { * @return * @throws UnsupportedEncodingException */ - public static Map<String, String[]> getParameterMap(List<FileItem> items, String encoding) throws UnsupportedEncodingException + public static Map<String, String[]> getParameterMap(List<FileItem> items, String encoding) throws UnsupportedEncodingException, IOException { Map<String, String[]> retVal = new HashMap<>(); + Charset charset = Charset.forName(encoding); for(FileItem item:items) { if(item.isFormField()) @@ -57,13 +60,13 @@ public class FormUtil { if(retVal.containsKey(item.getFieldName())) { List<String> oldValue = new ArrayList(Arrays.asList(retVal.get(item.getFieldName()))); - oldValue.add(item.getString(encoding)); + oldValue.add(item.getString(charset)); String[] newValue = new String[oldValue.size()]; retVal.put(item.getFieldName(),oldValue.toArray(newValue)); } else { - String[] value = {item.getString(encoding)}; + String[] value = {item.getString(charset)}; retVal.put(item.getFieldName(), value); } } diff --git a/src/main/java/no/nibio/web/forms/FormValidator.java b/src/main/java/no/nibio/web/forms/FormValidator.java index 65214d7edbc41e02477cbba2e8a2532528797d02..2d3659cb0b8457bce10bb0dddac267b8761bda2a 100755 --- a/src/main/java/no/nibio/web/forms/FormValidator.java +++ b/src/main/java/no/nibio/web/forms/FormValidator.java @@ -36,14 +36,15 @@ import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.ResourceBundle; -import javax.ejb.EJB; -import javax.servlet.ServletContext; -import javax.servlet.http.HttpServletRequest; +import jakarta.ejb.EJB; +import jakarta.servlet.ServletContext; +import jakarta.servlet.http.HttpServletRequest; import no.nibio.vips.logic.authenticate.PasswordValidationException; import no.nibio.vips.logic.controller.session.SessionControllerGetter; import no.nibio.vips.logic.controller.session.UserBean; import no.nibio.vips.logic.i18n.SessionLocaleUtil; import org.apache.commons.validator.routines.EmailValidator; +import org.slf4j.LoggerFactory; /** * Uses form configuration set in JSON files in [WARFILE]/formdefinitions/, or @@ -57,6 +58,8 @@ import org.apache.commons.validator.routines.EmailValidator; * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ public class FormValidator { + + private static final org.slf4j.Logger LOGGER = LoggerFactory.getLogger(FormValidator.class); @EJB UserBean userBean; @@ -340,6 +343,7 @@ public class FormValidator { { field.setValid(false); field.setValidationMessage(resourceBundle.getString("fieldIsRequired")); + LOGGER.debug(field.getName() + " with a value of " + field.getWebValue() + " is considered to be NULL"); } } diff --git a/src/main/resources/META-INF/persistence.xml b/src/main/resources/META-INF/persistence.xml index bfaf5ef4a76f98b451cbbca7fad7c0c6981c4d71..75089b795ba03b335671b88b88b109a1362605de 100755 --- a/src/main/resources/META-INF/persistence.xml +++ b/src/main/resources/META-INF/persistence.xml @@ -3,30 +3,28 @@ # # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. # - # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # - --> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="VIPSLogic-PU" transaction-type="JTA"> - <provider>org.hibernate.ejb.HibernatePersistence</provider> <jta-data-source>java:/jboss/datasources/vipslogic</jta-data-source> - <class>no.nibio.vips.logic.messaging.MessageNotificationSubscription</class> - <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> - <property name="hibernate.dialect" value="org.hibernate.spatial.dialect.postgis.PostgisDialect"/> - </properties> + <!-- Hibernate properties --> + <property name="hibernate.dialect" value="org.hibernate.spatial.dialect.postgis.PostgisPG10Dialect"/> + <property name="hibernate.show_sql" value="false"/> + <property name="hibernate.format_sql" value="true"/> + </properties> </persistence-unit> </persistence> diff --git a/src/main/resources/db/migration/V17__ObservationTimeSeries.sql b/src/main/resources/db/migration/V17__ObservationTimeSeries.sql new file mode 100644 index 0000000000000000000000000000000000000000..c278854b4599ea411fecb62c26f17911e28f94b1 --- /dev/null +++ b/src/main/resources/db/migration/V17__ObservationTimeSeries.sql @@ -0,0 +1,26 @@ +CREATE TABLE IF NOT EXISTS public.observation_time_series +( + observation_time_series_id SERIAL PRIMARY KEY, + crop_organism_id integer NOT NULL, + organism_id integer NOT NULL, + year integer NOT NULL, + name character varying(1023) NOT NULL, + description text, + source character varying(6) NOT NULL DEFAULT 'WEB', + user_id integer NOT NULL, + created timestamp with time zone NOT NULL, + last_modified_by integer, + last_modified timestamp with time zone, + location_point_of_interest_id integer NOT NULL, + location_is_private boolean DEFAULT false, + polygon_service_id integer, + CONSTRAINT observation_time_series_crop_organism_id_fkey FOREIGN KEY (crop_organism_id) REFERENCES public.organism (organism_id), + CONSTRAINT observation_time_series_organism_id_fkey FOREIGN KEY (organism_id) REFERENCES public.organism (organism_id), + CONSTRAINT observation_time_series_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.vips_logic_user (user_id), + CONSTRAINT observation_time_series_last_modified_by_fkey FOREIGN KEY (last_modified_by) REFERENCES public.vips_logic_user (user_id), + CONSTRAINT observation_time_series_location_point_of_interest_id_fkey FOREIGN KEY (location_point_of_interest_id) REFERENCES public.point_of_interest (point_of_interest_id), + CONSTRAINT observation_time_series_polygon_service_id_fkey FOREIGN KEY (polygon_service_id) REFERENCES public.polygon_service (polygon_service_id) +); + +ALTER TABLE observation ADD COLUMN source character varying(6) NOT NULL DEFAULT 'WEB'; +ALTER TABLE observation ADD COLUMN observation_time_series_id integer REFERENCES public.observation_time_series(observation_time_series_id); \ No newline at end of file diff --git a/src/main/resources/db/migration/V18__UseGridWeatherData.sql b/src/main/resources/db/migration/V18__UseGridWeatherData.sql new file mode 100644 index 0000000000000000000000000000000000000000..0775bd72877061f15cbcc5f4316a5dec35e79ef9 --- /dev/null +++ b/src/main/resources/db/migration/V18__UseGridWeatherData.sql @@ -0,0 +1,3 @@ +-- Adding this property when adding support for gridded weather datasources in VIPS +ALTER TABLE forecast_configuration +ADD COLUMN use_grid_weather_data BOOLEAN DEFAULT FALSE; \ No newline at end of file diff --git a/src/main/resources/db/migration/V19__Add_Organization_Property_Default_Grid_DataSource.sql b/src/main/resources/db/migration/V19__Add_Organization_Property_Default_Grid_DataSource.sql new file mode 100644 index 0000000000000000000000000000000000000000..b254b3e45832acef2b0e85af03c170362322435b --- /dev/null +++ b/src/main/resources/db/migration/V19__Add_Organization_Property_Default_Grid_DataSource.sql @@ -0,0 +1,3 @@ +-- Adding this property when adding support for gridded weather datasources in VIPS +ALTER TABLE organization +ADD COLUMN default_grid_weather_station_data_source_id INTEGER REFERENCES weather_station_data_source(weather_station_data_source_id) DEFAULT NULL; \ No newline at end of file diff --git a/src/main/resources/db/migration/V20__Add_Datasource_Property_IsGrid.sql b/src/main/resources/db/migration/V20__Add_Datasource_Property_IsGrid.sql new file mode 100644 index 0000000000000000000000000000000000000000..468128cbcf53a0e66d5b8373095debb8491592b7 --- /dev/null +++ b/src/main/resources/db/migration/V20__Add_Datasource_Property_IsGrid.sql @@ -0,0 +1,3 @@ +-- Adding this property when adding support for gridded weather datasources in VIPS +ALTER TABLE weather_station_data_source +ADD COLUMN is_grid BOOLEAN DEFAULT FALSE; \ No newline at end of file diff --git a/src/main/resources/db/migration/V21__Add_POI_Property_IsPrivate.sql b/src/main/resources/db/migration/V21__Add_POI_Property_IsPrivate.sql new file mode 100644 index 0000000000000000000000000000000000000000..abc442d80985e6130b570ac1d5471843d7509148 --- /dev/null +++ b/src/main/resources/db/migration/V21__Add_POI_Property_IsPrivate.sql @@ -0,0 +1,12 @@ +-- Adding this property when adding support for private POIs/weather datasources in VIPS +ALTER TABLE point_of_interest +ADD COLUMN is_private BOOLEAN DEFAULT FALSE; + +-- Set all POIS not owned by a superuser or admin to is_private = TRUE +UPDATE point_of_interest +SET is_private=TRUE +WHERE user_id NOT IN +( + SELECT DISTINCT user_id FROM user_vips_logic_role + WHERE vips_logic_role_id IN (1,2) +); \ No newline at end of file diff --git a/src/main/resources/no/nibio/vips/logic/i18n/passay.properties b/src/main/resources/no/nibio/vips/logic/i18n/passay.properties index 5d364fe65d744c84c4282e91f515509334eb7ad6..423ece4065f1d559f8168c56bb1f1bc2a68de6d5 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/passay.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/passay.properties @@ -2,18 +2,18 @@ # Copyright (c) 2016 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # # This (and and corresponding localized) property file(s) diff --git a/src/main/resources/no/nibio/vips/logic/i18n/passay_nb.properties b/src/main/resources/no/nibio/vips/logic/i18n/passay_nb.properties index 128eefb6030f3cf5a41a41857f5ac6424bf49dd1..9dc5899cb552ec70b1aaacea16ba3ef18e569df3 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/passay_nb.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/passay_nb.properties @@ -2,18 +2,18 @@ # Copyright (c) 2016 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # # This (and and corresponding localized) property file(s) diff --git a/src/main/resources/no/nibio/vips/logic/i18n/passay_zh_CN.properties b/src/main/resources/no/nibio/vips/logic/i18n/passay_zh_CN.properties index 9f1656df38a3f9a778613aacd3304c87ddbf6144..a09c9a93432e1c4e07b04308f6cdeb5a1d72c111 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/passay_zh_CN.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/passay_zh_CN.properties @@ -2,18 +2,18 @@ # Copyright (c) 2016 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # # This (and and corresponding localized) property file(s) diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties index 947d27d17a1f7e8ab711e36c5cc6eda5e01ba2a5..dd150cdced77c7dd4aaac5afb066c59a27b12336 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts.properties @@ -3,18 +3,18 @@ # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # ALTERNARIA = Alternaria Model @@ -72,7 +72,7 @@ active = Active activeWeatherStations = Active weather stations -addMultipleNew = Add multiple new +addNewForMultipleWeatherStations=Add new for multiple weather stations addNew = Add new @@ -308,6 +308,8 @@ fieldSowingDate = Field sowing date fields = Fields +traps = Traps + filter = Filter filterList = Filter list @@ -389,7 +391,9 @@ isPest = Is pest isPrivate = Is private isQuantified = Is quantified + isPositiveRegistration=Pest presence confirmed + isRequiredField = Required field language = Language @@ -554,6 +558,8 @@ observationDataField_trapCountCropInside = Number of trap counts inside the fiel observationDataField_unit = Measuring unit +allObservations = All observations + observationDeleted = Observation was deleted observationHeading = Observation heading @@ -590,7 +596,7 @@ observationSiteStored = Observation site was successfully updated observationStored = Observation was stored -observationText = Observation text +observationText = Description observations = Observations @@ -598,6 +604,8 @@ observedDateOfFirstCatch = Observed date of first catch observedValue = Observed value +observerId = Observer ID + observer = Observer older = Older @@ -710,7 +718,7 @@ reference = Reference registerNewUser = Register new user -registerNewUserExplanation = Please fill out the form to apply for a user account. +registerNewUserExplanation = Please fill out the form to apply for a user account. By registering as a user in VIPS, you accept our <a href="/public/documentation/Privacy_statement_NIBIO-VIPS.pdf" target="new">privacy statement.</a> registerNewUserReceipt = Thanks. You should receive an email requesting you to validate your email address. After following the instructions there, the organization admin will hopefully approve your application shortly. @@ -1046,3 +1054,33 @@ pointOfInterestType_5=Trap sowingDate=Sowing date pointOfInterestType_6=Apiary site pointOfInterestType_7=Nursery +privacyStatement=Privacy statement +privacyStatementFileName=Privacy_statement_NIBIO-VIPS.pdf +thresholdDSVMax=DSV threshold for high infection risk +thresholdDSVTempMin=Minimum temperature for DSV calculation +useGridWeatherData=Use grid weather data +doNotUse=Do not use +defaultGridWeatherStationDataSource=Gridded weather data source +weatherStationDataSources=Weather station data sources +newWeatherStationDataSource=New weather (station) data source +editWeatherStationDataSource=Edit weather (station) data source +datafetchUriExpression=URI template for requesting data +infoUriExpression=Template for request for station information +isGridWeatherDataSource=This is a grid based weather data source +weatherStationDataSourceStored=Weather (station) data source was successfully stored +weatherStationDataSourceDeleted=The weather (station) data source was successfully deleted +observationTimeSeriesId=Timeseries +observationTimeSeriesLabel=Timeseries label +observationId=Observation +isBroadcast=Is broadcast +yes=Yes +no=No +downloadInfo=About download +downloadedBy=Downloaded by +unregisteredUser=Unregistered user +downloadedTime=Time of download +observationCount=Observation count + +weatherDatasource=Weather datasource +useWeatherStation=Use weather station +multipleNewWarningMsg=This form is for adding the same forecast configuration to many weather stations simultaneously. diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties deleted file mode 100755 index fe09b88cbada7004a4468ee8063d3c907252ae9d..0000000000000000000000000000000000000000 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_bs.properties +++ /dev/null @@ -1,1042 +0,0 @@ -# - # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. - # - # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic 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 - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. - # -isPositiveRegistration=Pest presence confirmed -ALTERNARIA = Alternaria Model - -APPLESCABM = Apple scab model - -BARLEYNETB = Barley net blotch model - -BREMIALACT = Bremia lactucae model - -CYDIAPOMON = Cydia pomonella model - -DELIARADIC = Delia radicum model - -DELIARFOBO = Delia radicum/floralis observation model for old crops - -DELIARFOBS = Delia radicum/floralis observation model - -DELIARFOBY = Delia radicum/floralis observation model for young crops - -DOWNCASTMO = DOWNCAST model - -FINNCEREAL = Model for Pyrenophora teres, Drechslera tritici-repentis and Stagonospora nodorum - -GRASSDRYMO = Grass drying model - -LYGUSRUGUL = Lygus rugulipennis model - -MAMESTRABR = Mamestra brassicae model - -Mail = Email - -NAERSTADMO = N\u00e6rstad's model - -NEGPROGMOD = Negative prognosis model - -OATFLOWERM = Oat flowering model - -PLASMOVITI = Downy Mildew model - -PSILAROBSE = Psila rosae observation model - -PSILARTEMP = Psila rosae Temperature Model - -RAINYDAYSM = Rainy days model - -SEPAPIICOL = Septoria apiicola model - -SEPTREFHUM = Septoria reference humidity model - -Sms = SMS - -VIPSLogicTitle = VIPS administration system - -active = Active - -activeWeatherStations = Active weather stations - -addMultipleNew = Add multiple new - -addNew = Add new - -address = Address - -advisor = Advisor - -all = All - -allCategories = All categories - -allCrops = All crops - -allOrganizations = All organizations - -allPests = All pests - -allSystems = All systems - -altitude = Altitude - -appleFruitMoth = Apple fruit moth - -appleFruitMothChangeSeasonConfirm = Are you sure you want to change season? All unsaved data for the current season will be lost. - -approvalApplication = Approval application - -approvalApplicationHelp = Describe what you want to do as a registered user. E.g. write messages, register observations, etc. - -approved = Approved - -approvesSmsBilling = Approves billing for SMS messages - -approvesSmsBillingDescription = By checking this option, you confirm that you accept the billing costs for receiving SMS messages from our subscription services. This consent can be terminated at any time, either by unchecking this checkbox or by sending VIPS STOP to your country's short number. Number for Norway is 1963. - -archiveUserId = Archive user - -attachIdToExistingUser = Add this login to my existing user - -attachIdToExistingUserReceipt = The id was successfully connected to the user. You may now log in with it - -availableFor = Available for - -availableTranslations = Available translations - -back = Back - -barkbeetle = Barkbilleoverv\u00e5king - -body = Body - -broadcastMessage = Broadcast the message - -browse = Browse - -calculationEnd = Calculation end - -calculationStart = Calculation start - -cancel = Cancel - -changeDate = Change date - -children = Children - -city = City - -clearAll = Clear all - -clearOne = Clear one - -clusterStored = The cluster information was stored - -completenessAtFinish = Completeness at finish - -configureAndRunManually = Configure and run manually - -confirmCancel = Do you really want to cancel? - -confirmDelete = Do you really want to delete? - -confirmEmailFailure = Your email address was not confirmed. Please contact the system administrator. - -confirmEmailReceipt = Your email was successfully confirmed. You will be notified as soon as the organization administrator approves your application. - -confirmLeaveForm = Do you really want to leave this form? All changes are left behind. - -confirmReloadForm = Do you really want to reload this form. All unsaved changes will be lost. - -country = Country - -createPasswordResetCodeAndSendToUserBody = You have requested to reset your current password for username {0} in VIPSLogic, and create a new one. Please follow this link to proceed: {1} - -createPasswordResetCodeAndSendToUserSubject = Create new password in VIPSLogic - -cropCategoriesFor = Crop categories for - -cropCategory = Crop category - -cropCategoryIds = Crop categories - -cropCategoryUpdated = Crop category was updated - -cropOrganismId = Crop - -cropOrganismIds = Crops - -cropPestUpdated = Crop pest was updated - -cropSusceptibility = Crop susceptibility - -crops = Crops - -currentDate = Current date - -dataSource = Data source - -dataSourceMissing = Data source is missing - -dataSourceName = Data source name - -date2ndUpperLeafEmerging = Date 2nd upper leaf emerging - -date3rdUpperLeafEmerging = Date 3rd upper leaf emerging - -dateEnd = Date end - -dateGs31 = Date GS 31 - -dateGs75 = Date GS 75 - -datePub = Date published - -datePubPeriod = Period of publication - -dateSpraying1 = Spraying date 1 - -dateSpraying2 = Spraying date 2 - -dateStart = Date start - -dateUpperLeafEmerging = Date upper leaf emerging - -dateValidTo = Valid to date - -days = Days - -defaultLocale = Default language - -defaultMapCenter = Default map center - -defaultMapZoom = Default map zoom - -defaultTimeZone = Default time zone - -defaultVipsCoreUserId = Default VIPSCore user ID - -degreeOfParasitation = Degree of parasitation - -delete = Delete - -deleteIllustration = Delete illustration - -deletePoi = Delete point of interest - -deleteUser = Delete user - -deleteUserDescription = You must transfer the user's resouces to another user before deleting is possible - -deleteWeatherStation = Delete weather station - -deleteWeatherStationPreviewExplanation = The weather station that you want to delete has the resources below connected to it. When you delete the weather station, you also delete these resources. - -denominator = Denominator - -description = Description - -details = Details - -digit = Digit - -doesNotMatchDateFormat = Does not match format {0} - -doesNotMatchFormatX = Does not match format {0} - -edit = Edit - -editCropPests = Edit pests for crop - -editMessage = Edit message - -editObservation = Edit observation - -editOrganization = Edit organization - -editPoi = Edit Point Of Interest - -editWeatherStation = Edit weather station - -elementMeasurementTypes = Measurement types - -email = Email - -emailAddressIsAlreadyInUse = Email address is already in use - -emailNotRegistered = The email address is not registered - -emailNotUnique = The email address is not unique. Please contact the VIPSLogic administrator to sort this out. - -emailNotVerified = You must verify your email address before the user approval process can proceed - -endTime = End time - -exceedsMaxLengthOf = Exceeds max length of {0} - -externalForecastProviders = External forecast providers - -externalResourceIdentifier = External resource identifier - -externalResources = External resources - -factoryId = Factory id - -farmer = Farmer - -farms = Farms - -fieldIsRequired = Field is required - -fieldSowingDate = Field sowing date - -fields = Fields - -filter = Filter - -filterList = Filter list - -filterMessages = Filter messages - -firstName = First name - -forecastConfigurationDeleted = Forecast configuration was deleted - -forecastConfigurationId = Forecast configuration - -forecastConfigurationIds = Forecast configuration ids - -forecastConfigurationUpdated = Forecast configuration was updated - -forecastNotificationMessageBodyTpl_1 = This is for {0} in {1} at location {2} at date {3}. Details: {4} - -forecastNotificationMessageBodyTpl_2 = This is for {0} in {1} at location {2} at date {3}.Read more: {4} - -forecastNotificationMessageHeadingTpl_1 = Notification of high risk of infection - -forecastNotificationMessageHeadingTpl_2 = Notification of moderate infection risk - -forecastNotifications = Forecast notifications - -forecastNotificationsDescription = Forecast notifications are issued when a specific forecast (a model running for a location) changes its status to a higher risk level. E.g. green to yellow or yellow to red status. - -forecasts = Forecasts - -forgottenPassword = Forgotten password - -freeSms = Free SMS - -from = From - -general = General - -genericPlaces = Generic places - -greeting = Dobro do\u0161li u - -groupMembers = Group members - -heading = Heading - -help = Help - -helpMessageFormCropCategoryIds = No crop selection means visibility regardless of user's crop preferences - -hierarchyCategoryId = Hierarchy category - -higherThanMaximum = Higher than the maximum ({0}) - -illustration = Illustration - -inactiveWeatherStations = Inactive weather stations - -includeAllChildCrops = Include all child crops - -indexText = VIPSLogic is the common administration system for VIPS. This is where you configure users, weather stations and forecasts, and where you report observations and write messages, and more. - -informAdminOfConfirmedEmailBody = The user''s last name is {0}. The approval information is as follows: {1}. \\nFollow this link to edit this user: {2} \\n Follow this link to approve automatically: {3} - -informAdminOfConfirmedEmailSubject = New user has confirmed email and is now ready for approval - -internal = Internal - -invalidFormat = Invalid format - -invalidcredentials = Invalid username and/or password - -isCrop = Is crop - -isForecastLocation = Is forecast location - -isPest = Is pest - -isPrivate = Is private - -isQuantified = Is quantified - -isRequiredField = Required field - -language = Language - -lastEditedBy = Last edited by - -lastName = Last name - -lastUpdated = Last updated - -latinName = Latin name - -latitude = Latitude - -leadParagraph = Lead paragraph - -leafLifeTime = Leaf life time (days) - -leaveForm = Leave form - -listCrops = List all crops - -listPests = List all pests - -listSelectedCropCategoryOnTop = List crops from selected category on top - -localName = Local name - -location = Location - -locationIsPrivate = Location is private - -locationIsPublic = Location is public - -locationPointOfInterestId = Location - -logInterval = Log interval - -logInterval1d = 1 day - -logInterval1h = 1 hour - -loggedinas = Prijavi se kao - -login = Log in - -loginCredentials = Login credentials - -logout = Log out - -logoutsuccess = You are now logged out. Welcome back! - -longitude = Longitude - -lowerThanMinimum = Lower than the minimum ({0}) - -lowercase = Lower case - -mapDataIsRequired = Map data is required - -mapDrawTypeLabel = What do you want to draw - -maskObservationWith = Mask observation with - -messageDeleted = Message was deleted - -messageFormat = Message format - -messageIllustrationCaptionLocale = Caption - -messageNotifications = Message notifications - -messageNotificationsDescription = A message notification is issued when a news message is published for a specific crop group. - -messageTags = Message tags - -messageUpdated = Message was updated - -messages = Messages - -meter = Meter - -missing = Missing - -missingInDatabase = Missing in database - -missingSeparatorComma = Missing separator comma - -missingUsernameAndPassword = Missing username and password - -missingValues = Missing values - -modelId = Forecasting model - -modelName = Model name - -multipleForecastConfigurationsCreated = The forecast configurations were successfully created - -myAccount = My account - -name = Name - -nameAlreadyExists = The name already exists - -newGroup = New group - -newIllustration = New illustration - -newMessage = New message - -newObservation = New observation - -newObservationSite = New observation site - -newObservationSitePoint = New observation site point - -newOrganism = New organism - -newOrganization = New organization - -newPoi = New Point Of Interest - -newUser = New user - -newUserCredentialsHelpText = Please enter a user name for the new user. An auto generated password will be sent to the user's email address. - -newWeatherStation = New weather station - -noDescriptionFound = No description found - -noMapDataEntered = No map data entered - -noPrivateForecastsFoundForUser = No private forecasts found for user - -noResultsFoundForCriteria = No results were found for the given search criteria - -noTasksRunning = No tasks running - -noWhitespaceAllowed = No whitespace allowed - -none = None - -notificationSubscriptionDescription = You can subscribe to different kinds of notifications below. Choose the format for notification, for instance email or SMS - -notificationSubscriptions = Notification subscriptions - -notificationSubscriptionsUpdated = Notification subscriptions was successfully updated - -numberRequired = A number is required - -observationData = Observation data - -observationDataField_counting1 = Counting 1 - -observationDataField_counting2 = Counting 2 - -observationDataField_trapCountCropEdge = Number of trap counts at field's edge - -observationDataField_trapCountCropInside = Number of trap counts inside the field - -observationDeleted = Observation was deleted - -observationHeading = Observation heading - -observationMap = Observation map - -observationMethodDescription_KNOCKING = Knocking description (TODO) - -observationMethodDescription_NOT_REGISTERED = The observation method is not registered - -observationMethodId = Observation method - -observationMethodTitle_COUNTING = Counting - -observationMethodTitle_HARVESTING = Harvesting - -observationMethodTitle_KNOCKING = Knocking - -observationMethodTitle_NOT_REGISTERED = Not registered - -observationMethodTitle_VISUAL = Visual - -observationNotifications = Observation notifications - -observationNotificationsDescription = An observation notification is issued when a field observation is made of a pest or disease in a specific crop group. - -observationSiteName = Observation site name - -observationSitePointName = Observation site point name - -observationSitePoints = Observation site pointsObservasjonsstedspunkter - -observationSiteStored = Observation site was successfully updated - -observationStored = Observation was stored - -observationText = Observation text - -observations = Observations - -observedDateOfFirstCatch = Observed date of first catch - -observedValue = Observed value - -observer = Observer - -older = Older - -or = Or - -organism = Organism - -organismDeleted = Organism was deleted - -organismId = Organism id - -organismNotDeleted = Organism was not deleted - -organismRegistered = Organism was registered - -organismUpdated = Organism was updated - -organisms = Organisms - -organizationGroupDeleted = The organization group was deleted - -organizationGroupList = Organization groups - -organizationGroupStored = Organization group was stored - -organizationId = Organization - -organizationStored = Organization was stored - -organizations = Organizations - -organizationsArchiveUser = The organization's standard archive user - -other = Other - -parentOrganismId = Parent organism - -password = Password - -password2 = Repeat password - -passwordResetCodeExpired = The password reset code has expired. - -passwordResetCodeNotFound = The password reset code was not found - -passwordResetSuccess = Password was successfully created. Please log in. - -passwordsDoNotMatch = Passwords do not match - -pending = Pending - -pestOrganismId = Pest - -pestOrganismIds = Pests - -phone = Telephone - -pleaseAwaitApproval = Please await your user approval - -pleaseSelect = Please select - -pleaseSpecifyOther = If other, please specify - -pleaselogin = Please log in - -poi = Point of interest - -poiDeleted = Point of interest was deleted - -poiStored = Poi was stored - -point = point - -pointOfInterestType = Point of Interest Type - -pointOfInterestType_0 = Unspecified - -pointOfInterestType_1 = Weather station - -pointOfInterestType_2 = Farm - -pointOfInterestType_3 = Field - -pointOfInterestType_4 = Region - -pois = Points Of Interest - -polygon = Polygon - -position = Position - -postalCode = Postal code - -preferredLocale = Preferred locale - -previousCrop = Previous crop - -privateForecasts = Private forecasts - -privateForecastsForOtherUser = Private forecasts for other user - -progress = Progress - -publicForecasts = Public forecasts - -publiclyAvailable = Publicly available - -reference = Reference - -registerNewUser = Register new user - -registerNewUserExplanation = Please fill out the form to apply for a user account. - -registerNewUserReceipt = Thanks. You should receive an email requesting you to validate your email address. After following the instructions there, the organization admin will hopefully approve your application shortly. - -registrationOf = Registration of - -registrationShortcuts = Registration shortcuts - -rejected = Rejected - -remarks = Remarks - -rememberLogin = Remember login - -remoteloginfailed = Remote login failed - -replaceIllustration = Replace illustration - -researcher = Researcher - -reset = Reset - -resetPassword = Reset and create new password - -resetPasswordFormExplanation = Please enter your new password - -resetPasswordRequest = Request to reset password - -resetPasswordRequestAccepted = Your request has been accepted. An email with further instructions have been sent to the registered email address. - -resetPasswordRequestFormExplanation = An email will be sent to the address you enter here, with a link to reset your current password and enter a new one. - -runTask = Run task - -runningTasks = Running tasks - -scheduledTasks = Scheduled tasks - -scheduling = Scheduling - -schedulingOverview = Scheduling overview - -schedulingStarted = Scheduling started - -schedulingStopped = Scheduling was stopped - -schedulingStoppedExplanation = The scheduling system is stopped. None of the tasks in the list below will be run, unless scheduling is started again. - -season = Season - -seasonEnd = Season end - -seasonStart = Season start - -select = Select - -sendUserApprovalConfirmationBody = We are happy to confirm that your user account for VIPSLogic has been approved. Please log in here: {0} - -sendUserApprovalConfirmationSubject = Your user account has been approved - -sendUsernameAndPasswordToUserBody = Here is your username and password for logging in to VIPSLogic (http://{2}):\nUsername: {0}\nPassword: {1} - -sendUsernameAndPasswordToUserSubject = Username and password for VIPSLogic - -showMeWhereIAm = Show me where I Am - -signInWith = Sign in with - -slidingHoursAhead = Reference period, forwards (hours) - -slidingHoursPast = Reference period, backwards (hours) - -specificFieldsForX = Specific fields for {0} - -sprayingDate01 = Spraying Date 01 - -sprayingDate02 = Spraying Date 02 - -sprayingDate03 = Spraying Date 03 - -sprayingDate04 = Spraying Date 04 - -sprayingProtectionDays = Expected protection period (days) after spraying - -startDateAscosporeMaturity = Start date for ascospore maturation - -startDateDayDegreeAccumulation = Start date for day degree accumulation - -startDateGrowth = Start date for growth - -startScheduling = Start scheduling - -startTime = Start time - -status = Status - -statusRemarks = Status remarks - -statusTypeId = Status - -statusTypeIdTitle_1 = Pending - -statusTypeIdTitle_2 = Rejected - -statusTypeIdTitle_3 = Approved - -stopScheduling = Stop scheduling - -submit = Submit - -suggestedUserRole = Suggested user role - -surveillanceMessageInformation = If you want to create a message about an observation, please use the observation registration form - -systemTime = System time - -taskHistory = Task history - -taskHistoryDate = Date for task history - -taskHistoryDetails = Task history details - -taskHistoryStatusFailedCompletely = Failed completely - -taskHistoryStatusFailedPartly = Failed partly - -taskHistoryStatusOK = OK - -taskXWasLaunched = Task "{0}" was launched - -task_DeleteAllExpiredUserUuidsTask_description = Cleaning up the database of UUIDs, which is used for remembering client logins - -task_DeleteAllExpiredUserUuidsTask_name = Delete all expired user UUIDs - -task_RunAllForecastConfigurationsForOrganizationTask_description = Test - -task_RunAllForecastConfigurationsForOrganizationTask_name = Run all forecasts for one organization - -task_RunAllForecastConfigurationsTask_description = Runs all current forecasts for all organizations - -task_RunAllForecastConfigurationsTask_name = Run all forecast configurations - -task_RunForecastConfigurationsByIdTask_description = Run all forecast configurations corresponding to ids in a comma separated list - -task_RunForecastConfigurationsByIdTask_name = Run forecast configurations by id - -task_RunGridModelsTask_description = Test - -task_RunGridModelsTask_name = Run grid models - -task_SendForecastEventNotificationsTask_description = Checks to see if there has been changes in forecasts to YELLOW or RED status. If so, finds subscribers to such events and sends notifications - -task_SendForecastEventNotificationsTask_name = Send forecast event notifications - -task_UpdateForecastResultCacheTableTask_description = To speed up certain tasks, for instance aggregating warnings for today, the table forecast_result_cache should contain only today's forecast results. Today = SystemTime. - -task_UpdateForecastResultCacheTableTask_name = Update forecast result cache table - -task_UpdateForecastSummaryTableTask_description = This task updates the table for summaries - -task_UpdateForecastSummaryTableTask_name = Update table of forecast summaries - -task_UpdateModelInformationTask_description = Fetches information about models from VIPSCoreManager and stores in VIPSLogic - -task_UpdateModelInformationTask_name = Update model information - -tasks = Tasks - -test = Test - -thousandBerrySample = Thousand berry sample - -thresholdHumidPeriodHours = Threshold Number of consecutive humid hours - -thresholdLeafWetness = Threshold leaf wetness (min/h) - -thresholdPrecipitation = Threshold precipitation (mm) - -thresholdRelativeHumidity = Threshold relative humidty (%) - -tillageMethod = Tillage method - -timeOfObservation = Time of observation - -timeZone = Time zone - -timestamp = Timestamp - -to = To - -toTheTop = To the top - -tooManySeparatorCommas = Too many separator commas - -tradeName = Trade name - -transferAndDelete = Transfer and delete - -transferResources = Transfer resources - -type = Type - -unknownOrganismId = Unknown Organism Id - -unknownTranslationKey = Unknown translation key: {0} - -up = Up - -uppercase = Upper case - -user = User - -userAccountInformation = User account information - -userApproved = The user was approved - -userCreatedAndInformed = User was created. An email with username and password was sent to the user's email - -userDeleted = User was deleted - -userOrganizationGroupsListDescription = Organization groups can be used to share resources like points of interest - -userRegistrationEmailVerificationMessageBody = We have received a request to register a new user at VIPSLogic (http://{0}/). Please confirm your email by clicking this link: {1}\n\nThank you - -userRegistrationEmailVerificationMessageSubject = Email verification needed - -userResources = User resources - -userStatusId = Approval status - -userStatus_1 = Awaiting email validation - -userStatus_2 = Awaiting approval - -userStatus_3 = Rejected - -userStatus_4 = Approved - -userStatus_5 = Disabled - -userUpdated = User was updated - -username = User name - -usernameExists = Username {0} exists - -users = Users - -viewAllTasks = View all tasks - -viewForecastConfiguration = View forecast configuration - -viewFullScreen = Full screen view - -viewOthersObservations = View observations made by others - -vipsLogicRole_1 = Superuser - -vipsLogicRole_10 = Bark beetle administrator - -vipsLogicRole_11 = Bark beetle county admin - -vipsLogicRole_2 = Organization administrator - -vipsLogicRole_3 = Observer - -vipsLogicRole_4 = Observation authority - -vipsLogicRole_5 = Message author - -vipsLogicRole_6 = Apple Fruit Moth Administrator - -vipsLogicRole_7 = Organism editor - -vipsLogicRole_8 = Apple Fruit Moth Rowanberry Cluster Counter - -vipsLogicRole_9 = Bark beetle registrator - -vipsLogicRoles = User roles - -vipsLogicUserId = User - -vipswebUrl = VIPSWeb URL - -warningStatus = Warning status - -warningStatus_0 = No forecast available - -warningStatus_1 = Missing data - -warningStatus_2 = No risk of infection - -warningStatus_3 = Medium risk of infection - -warningStatus_4 = High risk of infection - -warning_fieldNotFoundInFormDefinition = WARNING: field {0} not found in form definition. The system does not know how to validate it. Continue anyway? - -weatherForecastProvider = Weather forecast service - -weatherStationDeleted = Weather station was deleted - -weatherStationForecastConfigurations = Forecasts connected to the weather station - -weatherStationPointOfInterestId = Weather station - -weatherStationPointOfInterestIds = Weather stations - -weatherStationRemoteId = Remote Id for weather station - -weatherStationRemoteIdMissing = Remote Id for weather station is missing - -weatherStationStored = Weather station information was stored - -weatherStations = Weather stations - -xIsNotAfterY = {0} is not after {1} - -xIsNotEqualToY = {0} is not equal to {1} - -your = Your -biofixDate=Biofix date -heatRequirements=Heat requirements -dd_lower=Day degree lower cutoffs -dd_upper=Day degree upper cutoffs -observedPhase=Observed phase at biofix date -YSTEMBTEMP=Yellow Stemborer Temperature Model -addIllustration=Add illustration -allRoles=All roles -allStatuses=All statuses -LEAFBLOTCH=Leaf blotch model -universalMessageSettingsLink_tpl=To edit your VIPS notification subscriptions, please use this link: {0} -pointOfInterestType_5=Trap -sowingDate=Sowing date -pointOfInterestType_6=Apiary site -pointOfInterestType_7=Nursery diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties deleted file mode 100755 index ebcccfcd964e5e8ef78f45865299d0021ea15439..0000000000000000000000000000000000000000 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_hr.properties +++ /dev/null @@ -1,1040 +0,0 @@ -# - # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. - # - # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic 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 - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. - # -isPositiveRegistration=Pest presence confirmed -ALTERNARIA = Alternaria Model - -APPLESCABM = Apple scab model - -BARLEYNETB = Barley net blotch model - -BREMIALACT = Bremia lactucae model - -CYDIAPOMON = Cydia pomonella model - -DELIARADIC = Delia radicum model - -DELIARFOBO = Delia radicum/floralis observation model for old crops - -DELIARFOBS = Delia radicum/floralis observation model - -DELIARFOBY = Delia radicum/floralis observation model for young crops - -DOWNCASTMO = DOWNCAST model - -FINNCEREAL = Model for Pyrenophora teres, Drechslera tritici-repentis and Stagonospora nodorum - -GRASSDRYMO = Grass drying model - -LYGUSRUGUL = Lygus rugulipennis model - -MAMESTRABR = Mamestra brassicae model - -Mail = Email - -NAERSTADMO = N\u00e6rstad's model - -NEGPROGMOD = Negative prognosis model - -OATFLOWERM = Oat flowering model - -PLASMOVITI = Downy Mildew model - -PSILAROBSE = Psila rosae observation model - -PSILARTEMP = Psila rosae Temperature Model - -RAINYDAYSM = Rainy days model - -SEPAPIICOL = Septoria apiicola model - -SEPTREFHUM = Septoria reference humidity model - -Sms = SMS - -VIPSLogicTitle = VIPS administration system - -active = Active - -activeWeatherStations = Active weather stations - -addMultipleNew = Add multiple new - -addNew = Add new - -address = Address - -advisor = Advisor - -all = All - -allCategories = All categories - -allCrops = All crops - -allOrganizations = All organizations - -allPests = All pests - -allSystems = All systems - -altitude = Altitude - -appleFruitMoth = Apple fruit moth - -appleFruitMothChangeSeasonConfirm = Are you sure you want to change season? All unsaved data for the current season will be lost. - -approvalApplication = Approval application - -approvalApplicationHelp = Describe what you want to do as a registered user. E.g. write messages, register observations, etc. - -approved = Approved - -approvesSmsBilling = Approves billing for SMS messages - -approvesSmsBillingDescription = By checking this option, you confirm that you accept the billing costs for receiving SMS messages from our subscription services. This consent can be terminated at any time, either by unchecking this checkbox or by sending VIPS STOP to your country's short number. Number for Norway is 1963. - -archiveUserId = Archive user - -attachIdToExistingUser = Add this login to my existing user - -attachIdToExistingUserReceipt = The id was successfully connected to the user. You may now log in with it - -availableFor = Available for - -availableTranslations = Available translations - -back = Back - -barkbeetle = Barkbilleoverv\u00e5king - -body = Body - -broadcastMessage = Broadcast the message - -browse = Browse - -calculationEnd = Calculation end - -calculationStart = Calculation start - -cancel = Cancel - -changeDate = Change date - -children = Children - -city = City - -clearAll = Clear all - -clearOne = Clear one - -clusterStored = The cluster information was stored - -completenessAtFinish = Completeness at finish - -configureAndRunManually = Configure and run manually - -confirmCancel = Do you really want to cancel? - -confirmDelete = Do you really want to delete? - -confirmEmailFailure = Your email address was not confirmed. Please contact the system administrator. - -confirmEmailReceipt = Your email was successfully confirmed. You will be notified as soon as the organization administrator approves your application. - -confirmLeaveForm = Do you really want to leave this form? All changes are left behind. - -confirmReloadForm = Do you really want to reload this form. All unsaved changes will be lost. - -country = Country - -createPasswordResetCodeAndSendToUserBody = You have requested to reset your current password for username {0} in VIPSLogic, and create a new one. Please follow this link to proceed: {1} - -createPasswordResetCodeAndSendToUserSubject = Create new password in VIPSLogic - -cropCategoriesFor = Crop categories for - -cropCategory = Crop category - -cropCategoryIds = Crop categories - -cropCategoryUpdated = Crop category was updated - -cropOrganismId = Crop - -cropOrganismIds = Crops - -cropPestUpdated = Crop pest was updated - -cropSusceptibility = Crop susceptibility - -crops = Crops - -currentDate = Current date - -dataSource = Data source - -dataSourceMissing = Data source is missing - -dataSourceName = Data source name - -date2ndUpperLeafEmerging = Date 2nd upper leaf emerging - -date3rdUpperLeafEmerging = Date 3rd upper leaf emerging - -dateEnd = Date end - -dateGs31 = Date GS 31 - -dateGs75 = Date GS 75 - -datePub = Date published - -datePubPeriod = Period of publication - -dateSpraying1 = Spraying date 1 - -dateSpraying2 = Spraying date 2 - -dateStart = Date start - -dateUpperLeafEmerging = Date upper leaf emerging - -dateValidTo = Valid to date - -days = Days - -defaultLocale = Default language - -defaultMapCenter = Default map center - -defaultMapZoom = Default map zoom - -defaultTimeZone = Default time zone - -defaultVipsCoreUserId = Default VIPSCore user ID - -degreeOfParasitation = Degree of parasitation - -delete = Delete - -deleteIllustration = Delete illustration - -deletePoi = Delete point of interest - -deleteUser = Delete user - -deleteUserDescription = You must transfer the user's resouces to another user before deleting is possible - -deleteWeatherStation = Delete weather station - -deleteWeatherStationPreviewExplanation = The weather station that you want to delete has the resources below connected to it. When you delete the weather station, you also delete these resources. - -denominator = Denominator - -description = Description - -details = Details - -digit = Digit - -doesNotMatchDateFormat = Does not match format {0} - -doesNotMatchFormatX = Does not match format {0} - -edit = Edit - -editCropPests = Edit pests for crop - -editMessage = Edit message - -editObservation = Edit observation - -editOrganization = Edit organization - -editPoi = Edit Point Of Interest - -editWeatherStation = Edit weather station - -elementMeasurementTypes = Measurement types - -email = Email - -emailAddressIsAlreadyInUse = Email address is already in use - -emailNotRegistered = The email address is not registered - -emailNotUnique = The email address is not unique. Please contact the VIPSLogic administrator to sort this out. - -emailNotVerified = You must verify your email address before the user approval process can proceed - -endTime = End time - -exceedsMaxLengthOf = Exceeds max length of {0} - -externalForecastProviders = External forecast providers - -externalResourceIdentifier = External resource identifier - -externalResources = External resources - -factoryId = Factory id - -farmer = Farmer - -farms = Farms - -fieldIsRequired = Field is required - -fieldSowingDate = Field sowing date - -fields = Fields - -filter = Filter - -filterList = Filter list - -filterMessages = Filter messages - -firstName = First name - -forecastConfigurationDeleted = Forecast configuration was deleted - -forecastConfigurationId = Forecast configuration - -forecastConfigurationIds = Forecast configuration ids - -forecastConfigurationUpdated = Forecast configuration was updated - -forecastNotificationMessageBodyTpl_1 = This is for {0} in {1} at location {2} at date {3}. Details: {4} - -forecastNotificationMessageBodyTpl_2 = This is for {0} in {1} at location {2} at date {3}.Read more: {4} - -forecastNotificationMessageHeadingTpl_1 = Notification of high risk of infection - -forecastNotificationMessageHeadingTpl_2 = Notification of moderate infection risk - -forecastNotifications = Forecast notifications - -forecastNotificationsDescription = Forecast notifications are issued when a specific forecast (a model running for a location) changes its status to a higher risk level. E.g. green to yellow or yellow to red status. - -forecasts = Forecasts - -forgottenPassword = Forgotten password - -freeSms = Free SMS - -from = From - -general = General - -genericPlaces = Generic places - -greeting = Dobro do\u0161li u - -groupMembers = Group members - -heading = Heading - -help = Help - -helpMessageFormCropCategoryIds = No crop selection means visibility regardless of user's crop preferences - -hierarchyCategoryId = Hierarchy category - -higherThanMaximum = Higher than the maximum ({0}) - -illustration = Illustration - -inactiveWeatherStations = Inactive weather stations - -includeAllChildCrops = Include all child crops - -indexText = VIPSLogic is the common administration system for VIPS. This is where you configure users, weather stations and forecasts, and where you report observations and write messages, and more. - -informAdminOfConfirmedEmailBody = The user''s last name is {0}. The approval information is as follows: {1}. \\nFollow this link to edit this user: {2} \\n Follow this link to approve automatically: {3} - -informAdminOfConfirmedEmailSubject = New user has confirmed email and is now ready for approval - -internal = Internal - -invalidFormat = Invalid format - -isCrop = Is crop - -isForecastLocation = Is forecast location - -isPest = Is pest - -isPrivate = Is private - -isQuantified = Is quantified - -isRequiredField = Required field - -language = Language - -lastEditedBy = Last edited by - -lastName = Last name - -lastUpdated = Last updated - -latinName = Latin name - -latitude = Latitude - -leadParagraph = Lead paragraph - -leafLifeTime = Leaf life time (days) - -leaveForm = Leave form - -listCrops = List all crops - -listPests = List all pests - -listSelectedCropCategoryOnTop = List crops from selected category on top - -localName = Local name - -location = Location - -locationIsPrivate = Location is private - -locationIsPublic = Location is public - -locationPointOfInterestId = Location - -logInterval = Log interval - -logInterval1d = 1 day - -logInterval1h = 1 hour - -loggedinas = Logged in as - -login = Log in - -loginCredentials = Login credentials - -logout = Log out - -logoutsuccess = You are now logged out. Welcome back! - -longitude = Longitude - -lowerThanMinimum = Lower than the minimum ({0}) - -lowercase = Lower case - -mapDataIsRequired = Map data is required - -mapDrawTypeLabel = What do you want to draw - -maskObservationWith = Mask observation with - -messageDeleted = Message was deleted - -messageFormat = Message format - -messageIllustrationCaptionLocale = Caption - -messageNotifications = Message notifications - -messageNotificationsDescription = A message notification is issued when a news message is published for a specific crop group. - -messageTags = Message tags - -messageUpdated = Message was updated - -messages = Messages - -meter = Meter - -missing = Missing - -missingInDatabase = Missing in database - -missingSeparatorComma = Missing separator comma - -missingUsernameAndPassword = Missing username and password - -missingValues = Missing values - -modelId = Forecasting model - -modelName = Model name - -multipleForecastConfigurationsCreated = The forecast configurations were successfully created - -myAccount = My account - -name = Name - -nameAlreadyExists = The name already exists - -newGroup = New group - -newIllustration = New illustration - -newMessage = New message - -newObservation = New observation - -newObservationSite = New observation site - -newObservationSitePoint = New observation site point - -newOrganism = New organism - -newOrganization = New organization - -newPoi = New Point Of Interest - -newUser = New user - -newUserCredentialsHelpText = Please enter a user name for the new user. An auto generated password will be sent to the user's email address. - -newWeatherStation = New weather station - -noDescriptionFound = No description found - -noMapDataEntered = No map data entered - -noPrivateForecastsFoundForUser = No private forecasts found for user - -noResultsFoundForCriteria = No results were found for the given search criteria - -noTasksRunning = No tasks running - -noWhitespaceAllowed = No whitespace allowed - -none = None - -notificationSubscriptionDescription = You can subscribe to different kinds of notifications below. Choose the format for notification, for instance email or SMS - -notificationSubscriptions = Notification subscriptions - -notificationSubscriptionsUpdated = Notification subscriptions was successfully updated - -numberRequired = A number is required - -observationData = Observation data - -observationDataField_counting1 = Counting 1 - -observationDataField_counting2 = Counting 2 - -observationDataField_trapCountCropEdge = Number of trap catches at field's edge - -observationDataField_trapCountCropInside = Number of trap catches inside the field - -observationDeleted = Observation was deleted - -observationHeading = Observation heading - -observationMap = Observation map - -observationMethodDescription_KNOCKING = Knocking description (TODO) - -observationMethodDescription_NOT_REGISTERED = The observation method is not registered - -observationMethodId = Observation method - -observationMethodTitle_COUNTING = Counting - -observationMethodTitle_HARVESTING = Harvesting - -observationMethodTitle_KNOCKING = Knocking - -observationMethodTitle_NOT_REGISTERED = Not registered - -observationMethodTitle_VISUAL = Visual - -observationNotifications = Observation notifications - -observationNotificationsDescription = An observation notification is issued when a field observation is made of a pest or disease in a specific crop group. - -observationSiteName = Observation site name - -observationSitePointName = Observation site point name - -observationSitePoints = Observation site points - -observationSiteStored = Observation site was successfully updated - -observationStored = Observation was stored - -observationText = Observation text - -observations = Observations - -observedDateOfFirstCatch = Observed date of first catch - -observedValue = Observed value - -observer = Observer - -older = Older - -or = Or - -organism = Organism - -organismDeleted = Organism was deleted - -organismId = Organism id - -organismNotDeleted = Organism was not deleted - -organismRegistered = Organism was registered - -organismUpdated = Organism was updated - -organisms = Organisms - -organizationGroupDeleted = The organization group was deleted - -organizationGroupList = Organization groups - -organizationGroupStored = Organization group was stored - -organizationId = Organization - -organizationStored = Organization was stored - -organizations = Organizations - -organizationsArchiveUser = The organization's standard archive user - -other = Other - -parentOrganismId = Parent organism - -password = Password - -password2 = Repeat password - -passwordResetCodeExpired = The password reset code has expired. - -passwordResetCodeNotFound = The password reset code was not found - -passwordResetSuccess = Password was successfully created. Please log in. - -passwordsDoNotMatch = Passwords do not match - -pending = Pending - -pestOrganismId = Pest - -pestOrganismIds = Pests - -phone = Telephone - -pleaseAwaitApproval = Please await your user approval - -pleaseSelect = Please select - -pleaseSpecifyOther = If other, please specify - -pleaselogin = Please log in - -poi = Point of interest - -poiDeleted = Point of interest was deleted - -poiStored = Poi was stored - -point = point - -pointOfInterestType = Point of Interest Type - -pointOfInterestType_0 = Unspecified - -pointOfInterestType_1 = Weather station - -pointOfInterestType_2 = Farm - -pointOfInterestType_3 = Field - -pointOfInterestType_4 = Region - -pois = Points Of Interest - -polygon = Polygon - -position = Position - -postalCode = Postal code - -preferredLocale = Preferred locale - -previousCrop = Previous crop - -privateForecasts = Private forecasts - -privateForecastsForOtherUser = Private forecasts for other user - -progress = Progress - -publicForecasts = Public forecasts - -publiclyAvailable = Publicly available - -reference = Reference - -registerNewUser = Register new user - -registerNewUserExplanation = Please fill out the form to apply for a user account. - -registerNewUserReceipt = Thanks. You should receive an email requesting you to validate your email address. After following the instructions there, the organization admin will hopefully approve your application shortly. - -registrationOf = Registration of - -registrationShortcuts = Registration shortcuts - -rejected = Rejected - -remarks = Remarks - -rememberLogin = Remember login - -remoteloginfailed = Remote login failed - -replaceIllustration = Replace illustration - -researcher = Researcher - -reset = Reset - -resetPassword = Reset and create new password - -resetPasswordFormExplanation = Please enter your new password - -resetPasswordRequest = Request to reset password - -resetPasswordRequestAccepted = Your request has been accepted. An email with further instructions have been sent to the registered email address. - -resetPasswordRequestFormExplanation = An email will be sent to the address you enter here, with a link to reset your current password and enter a new one. - -runTask = Run task - -runningTasks = Running tasks - -scheduledTasks = Scheduled tasks - -scheduling = Scheduling - -schedulingOverview = Scheduling overview - -schedulingStarted = Scheduling started - -schedulingStopped = Scheduling was stopped - -schedulingStoppedExplanation = The scheduling system is stopped. None of the tasks in the list below will be run, unless scheduling is started again. - -season = Season - -seasonEnd = Season end - -seasonStart = Season start - -select = Select - -sendUserApprovalConfirmationBody = We are happy to confirm that your user account for VIPSLogic has been approved. Please log in here: {0} - -sendUserApprovalConfirmationSubject = Your user account has been approved - -sendUsernameAndPasswordToUserBody = Here is your username and password for logging in to VIPSLogic (http://{2}):\nUsername: {0}\nPassword: {1} - -sendUsernameAndPasswordToUserSubject = Username and password for VIPSLogic - -showMeWhereIAm = Show me where I Am - -signInWith = Sign in with - -slidingHoursAhead = Reference period, forwards (hours) - -slidingHoursPast = Reference period, backwards (hours) - -specificFieldsForX = Specific fields for {0} - -sprayingDate01 = Spraying Date 01 - -sprayingDate02 = Spraying Date 02 - -sprayingDate03 = Spraying Date 03 - -sprayingDate04 = Spraying Date 04 - -sprayingProtectionDays = Expected protection period (days) after spraying - -startDateAscosporeMaturity = Start date for ascospore maturation - -startDateDayDegreeAccumulation = Start date for day degree accumulation - -startDateGrowth = Start date for growth - -startScheduling = Start scheduling - -startTime = Start time - -status = Status - -statusRemarks = Status remarks - -statusTypeId = Status - -statusTypeIdTitle_1 = Pending - -statusTypeIdTitle_2 = Rejected - -statusTypeIdTitle_3 = Approved - -stopScheduling = Stop scheduling - -submit = Submit - -suggestedUserRole = Suggested user role - -surveillanceMessageInformation = If you want to create a message about an observation, please use the observation registration form - -systemTime = System time - -taskHistory = Task history - -taskHistoryDate = Date for task history - -taskHistoryDetails = Task history details - -taskHistoryStatusFailedCompletely = Failed completely - -taskHistoryStatusFailedPartly = Failed partly - -taskHistoryStatusOK = OK - -taskXWasLaunched = Task "{0}" was launched - -task_DeleteAllExpiredUserUuidsTask_description = Cleaning up the database of UUIDs, which is used for remembering client logins - -task_DeleteAllExpiredUserUuidsTask_name = Delete all expired user UUIDs - -task_RunAllForecastConfigurationsForOrganizationTask_description = Test - -task_RunAllForecastConfigurationsForOrganizationTask_name = Run all forecasts for one organization - -task_RunAllForecastConfigurationsTask_description = Runs all current forecasts for all organizations - -task_RunAllForecastConfigurationsTask_name = Run all forecast configurations - -task_RunForecastConfigurationsByIdTask_description = Run all forecast configurations corresponding to ids in a comma separated list - -task_RunForecastConfigurationsByIdTask_name = Run forecast configurations by id - -task_RunGridModelsTask_description = Test - -task_RunGridModelsTask_name = Run grid models - -task_SendForecastEventNotificationsTask_description = Checks to see if there has been changes in forecasts to YELLOW or RED status. If so, finds subscribers to such events and sends notifications - -task_SendForecastEventNotificationsTask_name = Send forecast event notifications - -task_UpdateForecastResultCacheTableTask_description = To speed up certain tasks, for instance aggregating warnings for today, the table forecast_result_cache should contain only today's forecast results. Today = SystemTime. - -task_UpdateForecastResultCacheTableTask_name = Update forecast result cache table - -task_UpdateForecastSummaryTableTask_description = This task updates the table for summaries - -task_UpdateForecastSummaryTableTask_name = Update table of forecast summaries - -task_UpdateModelInformationTask_description = Fetches information about models from VIPSCoreManager and stores in VIPSLogic - -task_UpdateModelInformationTask_name = Update model information - -tasks = Tasks - -test = Test - -thousandBerrySample = Thousand berry sample - -thresholdHumidPeriodHours = Threshold Number of consecutive humid hours - -thresholdLeafWetness = Threshold leaf wetness (min/h) - -thresholdPrecipitation = Threshold precipitation (mm) - -thresholdRelativeHumidity = Threshold relative humidty (%) - -tillageMethod = Tillage method - -timeOfObservation = Time of observation - -timeZone = Time zone - -timestamp = Timestamp - -to = To - -toTheTop = To the top - -tooManySeparatorCommas = Too many separator commas - -tradeName = Trade name - -transferAndDelete = Transfer and delete - -transferResources = Transfer resources - -type = Type - -unknownOrganismId = Unknown Organism Id - -unknownTranslationKey = Unknown translation key: {0} - -up = Up - -uppercase = Upper case - -user = User - -userAccountInformation = User account information - -userApproved = The user was approved - -userCreatedAndInformed = User was created. An email with username and password was sent to the user's email - -userDeleted = User was deleted - -userOrganizationGroupsListDescription = Organization groups can be used to share resources like points of interest - -userRegistrationEmailVerificationMessageBody = We have received a request to register a new user at VIPSLogic (http://{0}/). Please confirm your email by clicking this link: {1}\n\nAfter confirming your email, a VIPS admin will review your registration and (hopefully) enable your account. Please contact us if this takes longer than a day or two.\n\nThank you - -userRegistrationEmailVerificationMessageSubject = Email verification needed - -userResources = User resources - -userStatusId = Approval status - -userStatus_1 = Awaiting email validation - -userStatus_2 = Awaiting approval - -userStatus_3 = Rejected - -userStatus_4 = Approved - -userStatus_5 = Disabled - -userUpdated = User was updated - -username = User name - -usernameExists = Username {0} exists - -users = Users - -viewAllTasks = View all tasks - -viewForecastConfiguration = View forecast configuration - -viewFullScreen = Full screen view - -viewOthersObservations = View observations made by others - -vipsLogicRole_1 = Superuser - -vipsLogicRole_10 = Bark beetle administrator - -vipsLogicRole_11 = Bark beetle county admin - -vipsLogicRole_2 = Organization administrator - -vipsLogicRole_3 = Observer - -vipsLogicRole_4 = Observation authority - -vipsLogicRole_5 = Message author - -vipsLogicRole_6 = Apple Fruit Moth Administrator - -vipsLogicRole_7 = Organism editor - -vipsLogicRole_8 = Apple Fruit Moth Rowanberry Cluster Counter - -vipsLogicRole_9 = Bark beetle registrator - -vipsLogicRoles = User roles - -vipsLogicUserId = User - -vipswebUrl = VIPSWeb URL - -warningStatus = Warning status - -warningStatus_0 = No forecast available - -warningStatus_1 = Missing data - -warningStatus_2 = No risk of infection - -warningStatus_3 = Medium risk of infection - -warningStatus_4 = High risk of infection - -warning_fieldNotFoundInFormDefinition = WARNING: field {0} not found in form definition. The system does not know how to validate it. Continue anyway? - -weatherForecastProvider = Weather forecast service - -weatherStationDeleted = Weather station was deleted - -weatherStationForecastConfigurations = Forecasts connected to the weather station - -weatherStationPointOfInterestId = Weather station - -weatherStationPointOfInterestIds = Weather stations - -weatherStationRemoteId = Remote Id for weather station - -weatherStationRemoteIdMissing = Remote Id for weather station is missing - -weatherStationStored = Weather station information was stored - -weatherStations = Weather stations - -xIsNotAfterY = {0} is not after {1} - -xIsNotEqualToY = {0} is not equal to {1} - -your = Your -biofixDate=Biofix date -heatRequirements=Heat requirements -dd_lower=Day degree lower cutoffs -dd_upper=Day degree upper cutoffs -observedPhase=Observed phase at biofix date -YSTEMBTEMP=Yellow Stemborer Temperature Model -addIllustration=Add illustration -allRoles=All roles -allStatuses=All statuses -LEAFBLOTCH=Leaf blotch model -universalMessageSettingsLink_tpl=To edit your notification subscriptions, please use this link: {0} -pointOfInterestType_5=Trap -sowingDate=Sowing date -pointOfInterestType_6=Apiary site -pointOfInterestType_7=Nursery diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties index 2e80c64e0c63746a4921e473ba7af674708ce032..ae2b3ac16deb47f630e9c5dee526e81916a31c36 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_nb.properties @@ -1,20 +1,20 @@ # - # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. - # - # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic 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 - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. - # +# Copyright (c) 2014 NIBIO <http://www.nibio.no/>. +# +# This file is part of VIPSLogic. +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see <https://www.gnu.org/licenses/>. +# isPositiveRegistration=Skadegj\u00f8rer p\u00e5vist ALTERNARIA = Alternariamodell @@ -70,11 +70,11 @@ VIPSLogicTitle = Administrasjonssystem active = Aktiv -activeWeatherStations = Aktive m\u00e5lestasjoner +activeWeatherStations = Aktive v\u00e6rstasjoner -addMultipleNew = Legg til nye +addNewForMultipleWeatherStations=Legg til nytt varsel for flere v\u00e6rstasjoner samtidig -addNew = Legg til ny +addNew = Legg til nytt address = Adresse @@ -244,9 +244,9 @@ deleteUser = Slett bruker deleteUserDescription = Du m\u00e5 overf\u00f8re brukerens ressurser til en annen bruker f\u00f8r brukeren kan slettes -deleteWeatherStation = Slett m\u00e5lestasjon +deleteWeatherStation = Slett v\u00e6rstasjon -deleteWeatherStationPreviewExplanation = M\u00e5lestasjonen du \u00f8nsker \u00e5 slette har knyttet til seg de ressursene som er nevnt nedenfor. N\u00e5r du sletter m\u00e5lestasjonen, vil ogs\u00e5 disse ressursene bli slettet. +deleteWeatherStationPreviewExplanation = V\u00e6rstasjonen du \u00f8nsker \u00e5 slette har knyttet til seg de ressursene som er nevnt nedenfor. N\u00e5r du sletter v\u00e6rstasjonen, vil ogs\u00e5 disse ressursene bli slettet. denominator = Denominator @@ -272,9 +272,9 @@ editOrganization = Rediger organisasjon editPoi = Rediger sted -editWeatherStation = Rediger m\u00e5lestasjon +editWeatherStation = Rediger v\u00e6rstasjon -elementMeasurementTypes = M\u00e5leparametre +elementMeasurementTypes = V\u00e6rparametre email = E-post @@ -308,6 +308,8 @@ fieldSowingDate = S\u00e5dato for felt fields = Felt +traps = Feller + filter = Filter filterList = Filtr\u00e9r lista @@ -352,7 +354,7 @@ greeting = Velkommen til groupMembers = Gruppemedlemmer -heading = Overskrift +heading = Tittel help = Hjelp @@ -364,11 +366,11 @@ higherThanMaximum = Kan ikke v\u00e6re h\u00f8yere enn {0} illustration = Illustrasjon -inactiveWeatherStations = Inaktive m\u00e5lestasjoner +inactiveWeatherStations = Inaktive v\u00e6rstasjoner includeAllChildCrops = Inkluder alle underarter, sorter og varianter -indexText = VIPSLogic er felles administrasjonssystem for VIPS. Her konfigurerer du brukere, m\u00e5lestasjoner og varsler, og her registrerer du observasjoner og skriver meldinger, med mere. Bruk menyen i toppen for \u00e5 komme i gang. +indexText = VIPSLogic er felles administrasjonssystem for VIPS. Her konfigurerer du brukere, v\u00e6rstasjoner og varsler, og her registrerer du observasjoner og skriver meldinger, med mere. Bruk menyen i toppen for \u00e5 komme i gang. informAdminOfConfirmedEmailBody = Brukerens etternavn er {0}. Oppgitt brukerinformasjon er som f\u00f8lger: {1} F\u00f8lg denne lenken for \u00e5 redigere og godkjenne: {2}. \\nF\u00f8lg denne lenken for \u00e5 godkjenne automatisk: {3} @@ -418,13 +420,13 @@ listSelectedCropCategoryOnTop = List kulturer fra valgt gruppe \u00f8verst localName = Lokalt navn -location = Plassering +location=Sted -locationIsPrivate = Lokalitet skal ikke offentliggj\u00f8res +locationIsPrivate = Sted skal ikke offentliggj\u00f8res -locationIsPublic = Lokaliteten kan vises offentlig +locationIsPublic = Sted kan vises offentlig -locationPointOfInterestId = Lokalitet +locationPointOfInterestId=Sted logInterval = M\u00e5leintervall @@ -516,7 +518,7 @@ newUser = Ny bruker newUserCredentialsHelpText = \nVennligst skriv inn et brukernavn for den nye brukeren. Et autogenerert passord sendes til brukerens epostadresse. -newWeatherStation = Ny m\u00e5lestasjon +newWeatherStation = Ny v\u00e6rstasjon noDescriptionFound = Ingen beskrivelse funnet @@ -554,9 +556,11 @@ observationDataField_trapCountCropInside = Antall insekter, fellefangst inne i f observationDataField_unit = M\u00e5leenhet +allObservations = Alle observasjoner + observationDeleted = Observasjonen ble slettet -observationHeading = Observasjons-overskrift +observationHeading = Tittel observationMap = Observasjonskart @@ -590,7 +594,7 @@ observationSiteStored = Rogneb\u00e6rm\u00f8llstasjonen ble oppdatert observationStored = Observasjonen ble lagret -observationText = Observasjonstekst +observationText = Beskrivelse observations = Observasjoner/f\u00f8rstefunn @@ -598,6 +602,8 @@ observedDateOfFirstCatch = Observert dato for f\u00f8rste fellefangst observedValue = Observert verdi +observerId = Observat\u00f8r-Id + observer = Observat\u00f8r older = Eldre @@ -676,7 +682,7 @@ pointOfInterestType = Stedstype pointOfInterestType_0 = Uspesifisert -pointOfInterestType_1 = M\u00e5lestasjon +pointOfInterestType_1 = V\u00e6rstasjon pointOfInterestType_2 = G\u00e5rd @@ -710,7 +716,7 @@ reference = Referanse registerNewUser = Registrer ny bruker -registerNewUserExplanation = Vennligst fyll ut skjemaet for \u00e5 s\u00f8ke om brukerkonto. +registerNewUserExplanation = Vennligst fyll ut skjemaet for \u00e5 s\u00f8ke om brukerkonto. Ved \u00e5 registrere deg som bruker i VIPS godtar du v\u00e5r <a href="/public/documentation/Personvernerklaering_NIBIO-VIPS.pdf" target="new">personvernerkl\u00e6ring</a> registerNewUserReceipt = Takk. En e-post med videre instruksjoner er sendt til deg. Etter at instruksjonene der er fulgt, s\u00e5 vil organisasjonens administrator forh\u00e5pentligvis godkjenne s\u00f8knaden din snarlig. Du kan ikke logge inn f\u00f8r registreringen er godkjent. @@ -892,7 +898,7 @@ thresholdRelativeHumidity = Terskelverdi relativ luftfuktighet (%) tillageMethod = Jordarbeiding -timeOfObservation = Observasjonstidspunkt +timeOfObservation = Observasjonsdato timeZone = Tidssone @@ -1010,24 +1016,25 @@ warning_fieldNotFoundInFormDefinition = Advarsel: feltet {0} ble ikke funnet i s weatherForecastProvider = V\u00e6rvarslingstjeneste -weatherStationDeleted = M\u00e5lestasjonen ble slettet +weatherStationDeleted = V\u00e6rstasjonen ble slettet -weatherStationForecastConfigurations = Varsler knyttet til m\u00e5lestasjonen +weatherStationForecastConfigurations = Varsler knyttet til v\u00e6rstasjonen -weatherStationPointOfInterestId = M\u00e5lestasjon +weatherStationPointOfInterestId = V\u00e6rstasjon -weatherStationPointOfInterestIds = M\u00e5lestasjoner +weatherStationPointOfInterestIds = V\u00e6rstasjoner -weatherStationRemoteId = Fjern-Id for m\u00e5lestasjon +weatherStationRemoteId = Fjern-Id for v\u00e6rstasjon -weatherStationRemoteIdMissing = Fjern-Id for m\u00e5lestasjon mangler +weatherStationRemoteIdMissing = Fjern-Id for v\u00e6rstasjon mangler -weatherStationStored = Informasjon om m\u00e5lestasjon ble lagret +weatherStationStored = Informasjon om v\u00e6rstasjon ble lagret -weatherStations = M\u00e5lestasjoner +weatherStations = V\u00e6rstasjoner xIsNotAfterY = {0} er ikke etter {1} + xIsNotEqualToY = {0} er ikke lik {1} your = Din @@ -1046,3 +1053,33 @@ pointOfInterestType_5=Felle sowingDate=S\u00e5dato pointOfInterestType_6=Big\u00e5rdsplass pointOfInterestType_7=Planteskole +privacyStatement=Personvernerkl\u00e6ring +privacyStatementFileName=Personvernerklaering_NIBIO-VIPS.pdf +thresholdDSVMax=DSV-terskel for h\u00f8y infeksjonsrisiko +thresholdDSVTempMin=Minimumstemperatur for beregning av DSV +useGridWeatherData=Bruk v\u00e6rdata for mitt steds posisjon +doNotUse=Ikke bruk +defaultGridWeatherStationDataSource=GRID-basert v\u00e6rdatakilde +weatherStationDataSources=V\u00e6r(stasjons)datakilder +newWeatherStationDataSource=Ny v\u00e6r(stasjons)datakilde +editWeatherStationDataSource=Rediger v\u00e6r(stasjons)datakilde +datafetchUriExpression=URI-mal for v\u00e6rdataforesp\u00f8rsel +infoUriExpression=Mal for henvendelse om stasjonsinformasjon +isGridWeatherDataSource=Er en grid-basert v\u00e6rdatakilde +weatherStationDataSourceStored=V\u00e6r(stasjons)datakilden ble lagret +weatherStationDataSourceDeleted=V\u00e6r(stasjons)datakilden ble slettet +observationTimeSeriesId=Tidsserie-Id +observationTimeSeriesLabel=Tidsserie +observationId=Observasjon-Id +isBroadcast=Er kringkastet +yes=Ja +no=Nei +downloadInfo=Om nedlastingen +downloadedBy=Lastet ned av +unregisteredUser=Uregistrert bruker +downloadedTime=Tidspunkt for nedlasting +observationCount=Antall observasjoner + +weatherDatasource=V\u00e6rdatakilde +useWeatherStation=Bruk v\u00e6rstasjon +multipleNewWarningMsg=Dette skjemaet er en snarvei for \u00e5 opprette likelydende varsel p\u00e5 flere v\u00e6rstasjoner. <a href="/forecastConfiguration?action=viewForecastConfiguration&forecastConfigurationId=-1">Klikk her</a> hvis du vil opprette bare ett varsel. diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties deleted file mode 100755 index a431e5ecf91a8274168bf9904ea0d6325f72533c..0000000000000000000000000000000000000000 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_sr.properties +++ /dev/null @@ -1,1042 +0,0 @@ -# - # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. - # - # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic 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 - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. - # -isPositiveRegistration=Pest presence confirmed -ALTERNARIA = Alternaria Model - -APPLESCABM = Apple scab model - -BARLEYNETB = Barley net blotch model - -BREMIALACT = Bremia lactucae model - -CYDIAPOMON = Cydia pomonella model - -DELIARADIC = Delia radicum model - -DELIARFOBO = Delia radicum/floralis observation model for old crops - -DELIARFOBS = Delia radicum/floralis observation model - -DELIARFOBY = Delia radicum/floralis observation model for young crops - -DOWNCASTMO = DOWNCAST model - -FINNCEREAL = Model for Pyrenophora teres, Drechslera tritici-repentis and Stagonospora nodorum - -GRASSDRYMO = Grass drying model - -LYGUSRUGUL = Lygus rugulipennis model - -MAMESTRABR = Mamestra brassicae model - -Mail = Email - -NAERSTADMO = N\u00e6rstad's model - -NEGPROGMOD = Negative prognosis model - -OATFLOWERM = Oat flowering model - -PLASMOVITI = Downy Mildew model - -PSILAROBSE = Psila rosae observation model - -PSILARTEMP = Psila rosae Temperature Model - -RAINYDAYSM = Rainy days model - -SEPAPIICOL = Septoria apiicola model - -SEPTREFHUM = Septoria reference humidity model - -Sms = SMS - -VIPSLogicTitle = VIPS administration system - -active = Active - -activeWeatherStations = Active weather stations - -addMultipleNew = Add multiple new - -addNew = Add new - -address = Address - -advisor = Advisor - -all = All - -allCategories = All categories - -allCrops = All crops - -allOrganizations = All organizations - -allPests = All pests - -allSystems = All systems - -altitude = Altitude - -appleFruitMoth = Apple fruit moth - -appleFruitMothChangeSeasonConfirm = Are you sure you want to change season? All unsaved data for the current season will be lost. - -approvalApplication = Approval application - -approvalApplicationHelp = Describe what you want to do as a registered user. E.g. write messages, register observations, etc. - -approved = Approved - -approvesSmsBilling = Approves billing for SMS messages - -approvesSmsBillingDescription = By checking this option, you confirm that you accept the billing costs for receiving SMS messages from our subscription services. This consent can be terminated at any time, either by unchecking this checkbox or by sending VIPS STOP to your country's short number. Number for Norway is 1963. - -archiveUserId = Archive user - -attachIdToExistingUser = Add this login to my existing user - -attachIdToExistingUserReceipt = The id was successfully connected to the user. You may now log in with it - -availableFor = Available for - -availableTranslations = Available translations - -back = Back - -barkbeetle = Barkbilleoverv\u00e5king - -body = Body - -broadcastMessage = Broadcast the message - -browse = Browse - -calculationEnd = Calculation end - -calculationStart = Calculation start - -cancel = Cancel - -changeDate = Change date - -children = Children - -city = City - -clearAll = Clear all - -clearOne = Clear one - -clusterStored = The cluster information was stored - -completenessAtFinish = Completeness at finish - -configureAndRunManually = Configure and run manually - -confirmCancel = Do you really want to cancel? - -confirmDelete = Do you really want to delete? - -confirmEmailFailure = Your email address was not confirmed. Please contact the system administrator. - -confirmEmailReceipt = Your email was successfully confirmed. You will be notified as soon as the organization administrator approves your application. - -confirmLeaveForm = Do you really want to leave this form? All changes are left behind. - -confirmReloadForm = Do you really want to reload this form. All unsaved changes will be lost. - -country = Country - -createPasswordResetCodeAndSendToUserBody = You have requested to reset your current password for username {0} in VIPSLogic, and create a new one. Please follow this link to proceed: {1} - -createPasswordResetCodeAndSendToUserSubject = Create new password in VIPSLogic - -cropCategoriesFor = Crop categories for - -cropCategory = Crop category - -cropCategoryIds = Crop categories - -cropCategoryUpdated = Crop category was updated - -cropOrganismId = Crop - -cropOrganismIds = Crops - -cropPestUpdated = Crop pest was updated - -cropSusceptibility = Crop susceptibility - -crops = Crops - -currentDate = Current date - -dataSource = Data source - -dataSourceMissing = Data source is missing - -dataSourceName = Data source name - -date2ndUpperLeafEmerging = Date 2nd upper leaf emerging - -date3rdUpperLeafEmerging = Date 3rd upper leaf emerging - -dateEnd = Date end - -dateGs31 = Date GS 31 - -dateGs75 = Date GS 75 - -datePub = Date published - -datePubPeriod = Period of publication - -dateSpraying1 = Spraying date 1 - -dateSpraying2 = Spraying date 2 - -dateStart = Date start - -dateUpperLeafEmerging = Date upper leaf emerging - -dateValidTo = Valid to date - -days = Days - -defaultLocale = Default language - -defaultMapCenter = Default map center - -defaultMapZoom = Default map zoom - -defaultTimeZone = Default time zone - -defaultVipsCoreUserId = Default VIPSCore user ID - -degreeOfParasitation = Degree of parasitation - -delete = Delete - -deleteIllustration = Delete illustration - -deletePoi = Delete point of interest - -deleteUser = Delete user - -deleteUserDescription = You must transfer the user's resouces to another user before deleting is possible - -deleteWeatherStation = Delete weather station - -deleteWeatherStationPreviewExplanation = The weather station that you want to delete has the resources below connected to it. When you delete the weather station, you also delete these resources. - -denominator = Denominator - -description = Description - -details = Details - -digit = Digit - -doesNotMatchDateFormat = Does not match format {0} - -doesNotMatchFormatX = Does not match format {0} - -edit = Edit - -editCropPests = Edit pests for crop - -editMessage = Edit message - -editObservation = Edit observation - -editOrganization = Edit organization - -editPoi = Edit Point Of Interest - -editWeatherStation = Edit weather station - -elementMeasurementTypes = Measurement types - -email = Email - -emailAddressIsAlreadyInUse = Email address is already in use - -emailNotRegistered = The email address is not registered - -emailNotUnique = The email address is not unique. Please contact the VIPSLogic administrator to sort this out. - -emailNotVerified = You must verify your email address before the user approval process can proceed - -endTime = End time - -exceedsMaxLengthOf = Exceeds max length of {0} - -externalForecastProviders = External forecast providers - -externalResourceIdentifier = External resource identifier - -externalResources = External resources - -factoryId = Factory id - -farmer = Farmer - -farms = Farms - -fieldIsRequired = Field is required - -fieldSowingDate = Field sowing date - -fields = Fields - -filter = Filter - -filterList = Filter list - -filterMessages = Filter messages - -firstName = First name - -forecastConfigurationDeleted = Forecast configuration was deleted - -forecastConfigurationId = Forecast configuration - -forecastConfigurationIds = Forecast configuration ids - -forecastConfigurationUpdated = Forecast configuration was updated - -forecastNotificationMessageBodyTpl_1 = This is for {0} in {1} at location {2} at date {3}. Details: {4} - -forecastNotificationMessageBodyTpl_2 = This is for {0} in {1} at location {2} at date {3}.Read more: {4} - -forecastNotificationMessageHeadingTpl_1 = Notification of high risk of infection - -forecastNotificationMessageHeadingTpl_2 = Notification of moderate infection risk - -forecastNotifications = Forecast notifications - -forecastNotificationsDescription = Forecast notifications are issued when a specific forecast (a model running for a location) changes its status to a higher risk level. E.g. green to yellow or yellow to red status. - -forecasts = Forecasts - -forgottenPassword = Forgotten password - -freeSms = Free SMS - -from = From - -general = General - -genericPlaces = Generic places - -greeting = Dobro do\u0161li u - -groupMembers = Group members - -heading = Heading - -help = Help - -helpMessageFormCropCategoryIds = No crop selection means visibility regardless of user's crop preferences - -hierarchyCategoryId = Hierarchy category - -higherThanMaximum = Higher than the maximum ({0}) - -illustration = Illustration - -inactiveWeatherStations = Inactive weather stations - -includeAllChildCrops = Include all child crops - -indexText = VIPSLogic is the common administration system for VIPS. This is where you configure users, weather stations and forecasts, and where you report observations and write messages, and more. - -informAdminOfConfirmedEmailBody = The user''s last name is {0}. The approval information is as follows: {1}. \\nFollow this link to edit this user: {2} \\n Follow this link to approve automatically: {3} - -informAdminOfConfirmedEmailSubject = New user has confirmed email and is now ready for approval - -internal = Internal - -invalidFormat = Invalid format - -invalidcredentials = Invalid username and/or password - -isCrop = Is crop - -isForecastLocation = Is forecast location - -isPest = Is pest - -isPrivate = Is private - -isQuantified = Is quantified - -isRequiredField = Required field - -language = Language - -lastEditedBy = Last edited by - -lastName = Last name - -lastUpdated = Last updated - -latinName = Latin name - -latitude = Latitude - -leadParagraph = Lead paragraph - -leafLifeTime = Leaf life time (days) - -leaveForm = Leave form - -listCrops = List all crops - -listPests = List all pests - -listSelectedCropCategoryOnTop = List crops from selected category on top - -localName = Local name - -location = Location - -locationIsPrivate = Location is private - -locationIsPublic = Location is public - -locationPointOfInterestId = Location - -logInterval = Log interval - -logInterval1d = 1 day - -logInterval1h = 1 hour - -loggedinas = Logged in as - -login = Log in - -loginCredentials = Login credentials - -logout = Log out - -logoutsuccess = You are now logged out. Welcome back! - -longitude = Longitude - -lowerThanMinimum = Lower than the minimum ({0}) - -lowercase = Lower case - -mapDataIsRequired = Map data is required - -mapDrawTypeLabel = What do you want to draw - -maskObservationWith = Mask observation with - -messageDeleted = Message was deleted - -messageFormat = Message format - -messageIllustrationCaptionLocale = Caption - -messageNotifications = Message notifications - -messageNotificationsDescription = A message notification is issued when a news message is published for a specific crop group. - -messageTags = Message tags - -messageUpdated = Message was updated - -messages = Messages - -meter = Meter - -missing = Missing - -missingInDatabase = Missing in database - -missingSeparatorComma = Missing separator comma - -missingUsernameAndPassword = Missing username and password - -missingValues = Missing values - -modelId = Forecasting model - -modelName = Model name - -multipleForecastConfigurationsCreated = The forecast configurations were successfully created - -myAccount = My account - -name = Name - -nameAlreadyExists = The name already exists - -newGroup = New group - -newIllustration = New illustration - -newMessage = New message - -newObservation = New observation - -newObservationSite = New observation site - -newObservationSitePoint = New observation site point - -newOrganism = New organism - -newOrganization = New organization - -newPoi = New Point Of Interest - -newUser = New user - -newUserCredentialsHelpText = Please enter a user name for the new user. An auto generated password will be sent to the user's email address. - -newWeatherStation = New weather station - -noDescriptionFound = No description found - -noMapDataEntered = No map data entered - -noPrivateForecastsFoundForUser = No private forecasts found for user - -noResultsFoundForCriteria = No results were found for the given search criteria - -noTasksRunning = No tasks running - -noWhitespaceAllowed = No whitespace allowed - -none = None - -notificationSubscriptionDescription = You can subscribe to different kinds of notifications below. Choose the format for notification, for instance email or SMS - -notificationSubscriptions = Notification subscriptions - -notificationSubscriptionsUpdated = Notification subscriptions was successfully updated - -numberRequired = A number is required - -observationData = Observation data - -observationDataField_counting1 = Counting 1 - -observationDataField_counting2 = Counting 2 - -observationDataField_trapCountCropEdge = Number of trap counts at field's edge - -observationDataField_trapCountCropInside = Number of trap counts inside the field - -observationDeleted = Observation was deleted - -observationHeading = Observation heading - -observationMap = Observation map - -observationMethodDescription_KNOCKING = Knocking description (TODO) - -observationMethodDescription_NOT_REGISTERED = The observation method is not registered - -observationMethodId = Observation method - -observationMethodTitle_COUNTING = Counting - -observationMethodTitle_HARVESTING = Harvesting - -observationMethodTitle_KNOCKING = Knocking - -observationMethodTitle_NOT_REGISTERED = Not registered - -observationMethodTitle_VISUAL = Visual - -observationNotifications = Observation notifications - -observationNotificationsDescription = An observation notification is issued when a field observation is made of a pest or disease in a specific crop group. - -observationSiteName = Observation site name - -observationSitePointName = Observation site point name - -observationSitePoints = Observation site points - -observationSiteStored = Observation site was successfully updated - -observationStored = Observation was stored - -observationText = Observation text - -observations = Observations - -observedDateOfFirstCatch = Observed date of first catch - -observedValue = Observed value - -observer = Observer - -older = Older - -or = Or - -organism = Organism - -organismDeleted = Organism was deleted - -organismId = Organism id - -organismNotDeleted = Organism was not deleted - -organismRegistered = Organism was registered - -organismUpdated = Organism was updated - -organisms = Organisms - -organizationGroupDeleted = The organization group was deleted - -organizationGroupList = Organization groups - -organizationGroupStored = Organization group was stored - -organizationId = Organization - -organizationStored = Organization was stored - -organizations = Organizations - -organizationsArchiveUser = The organization's standard archive user - -other = Other - -parentOrganismId = Parent organism - -password = Password - -password2 = Repeat password - -passwordResetCodeExpired = The password reset code has expired. - -passwordResetCodeNotFound = The password reset code was not found - -passwordResetSuccess = Password was successfully created. Please log in. - -passwordsDoNotMatch = Passwords do not match - -pending = Pending - -pestOrganismId = Pest - -pestOrganismIds = Pests - -phone = Telephone - -pleaseAwaitApproval = Please await your user approval - -pleaseSelect = Please select - -pleaseSpecifyOther = If other, please specify - -pleaselogin = Please log in - -poi = Point of interest - -poiDeleted = Point of interest was deleted - -poiStored = Poi was stored - -point = point - -pointOfInterestType = Point of Interest Type - -pointOfInterestType_0 = Unspecified - -pointOfInterestType_1 = Weather station - -pointOfInterestType_2 = Farm - -pointOfInterestType_3 = Field - -pointOfInterestType_4 = Region - -pois = Points Of Interest - -polygon = Polygon - -position = Position - -postalCode = Postal code - -preferredLocale = Preferred locale - -previousCrop = Previous crop - -privateForecasts = Private forecasts - -privateForecastsForOtherUser = Private forecasts for other user - -progress = Progress - -publicForecasts = Public forecasts - -publiclyAvailable = Publicly available - -reference = Reference - -registerNewUser = Register new user - -registerNewUserExplanation = Please fill out the form to apply for a user account. - -registerNewUserReceipt = Thanks. You should receive an email requesting you to validate your email address. After following the instructions there, the organization admin will hopefully approve your application shortly. - -registrationOf = Registration of - -registrationShortcuts = Registration shortcuts - -rejected = Rejected - -remarks = Remarks - -rememberLogin = Remember login - -remoteloginfailed = Remote login failed - -replaceIllustration = Replace illustration - -researcher = Researcher - -reset = Reset - -resetPassword = Reset and create new password - -resetPasswordFormExplanation = Please enter your new password - -resetPasswordRequest = Request to reset password - -resetPasswordRequestAccepted = Your request has been accepted. An email with further instructions have been sent to the registered email address. - -resetPasswordRequestFormExplanation = An email will be sent to the address you enter here, with a link to reset your current password and enter a new one. - -runTask = Run task - -runningTasks = Running tasks - -scheduledTasks = Scheduled tasks - -scheduling = Scheduling - -schedulingOverview = Scheduling overview - -schedulingStarted = Scheduling started - -schedulingStopped = Scheduling was stopped - -schedulingStoppedExplanation = The scheduling system is stopped. None of the tasks in the list below will be run, unless scheduling is started again. - -season = Season - -seasonEnd = Season end - -seasonStart = Season start - -select = Select - -sendUserApprovalConfirmationBody = We are happy to confirm that your user account for VIPSLogic has been approved. Please log in here: {0} - -sendUserApprovalConfirmationSubject = Your user account has been approved - -sendUsernameAndPasswordToUserBody = Here is your username and password for logging in to VIPSLogic (http://{2}):\nUsername: {0}\nPassword: {1} - -sendUsernameAndPasswordToUserSubject = Username and password for VIPSLogic - -showMeWhereIAm = Show me where I Am - -signInWith = Sign in with - -slidingHoursAhead = Reference period, forwards (hours) - -slidingHoursPast = Reference period, backwards (hours) - -specificFieldsForX = Specific fields for {0} - -sprayingDate01 = Spraying Date 01 - -sprayingDate02 = Spraying Date 02 - -sprayingDate03 = Spraying Date 03 - -sprayingDate04 = Spraying Date 04 - -sprayingProtectionDays = Expected protection period (days) after spraying - -startDateAscosporeMaturity = Start date for ascospore maturation - -startDateDayDegreeAccumulation = Start date for day degree accumulation - -startDateGrowth = Start date for growth - -startScheduling = Start scheduling - -startTime = Start time - -status = Status - -statusRemarks = Status remarks - -statusTypeId = Status - -statusTypeIdTitle_1 = Pending - -statusTypeIdTitle_2 = Rejected - -statusTypeIdTitle_3 = Approved - -stopScheduling = Stop scheduling - -submit = Submit - -suggestedUserRole = Suggested user role - -surveillanceMessageInformation = If you want to create a message about an observation, please use the observation registration form - -systemTime = System time - -taskHistory = Task history - -taskHistoryDate = Date for task history - -taskHistoryDetails = Task history details - -taskHistoryStatusFailedCompletely = Failed completely - -taskHistoryStatusFailedPartly = Failed partly - -taskHistoryStatusOK = OK - -taskXWasLaunched = Task "{0}" was launched - -task_DeleteAllExpiredUserUuidsTask_description = Cleaning up the database of UUIDs, which is used for remembering client logins - -task_DeleteAllExpiredUserUuidsTask_name = Delete all expired user UUIDs - -task_RunAllForecastConfigurationsForOrganizationTask_description = Test - -task_RunAllForecastConfigurationsForOrganizationTask_name = Run all forecasts for one organization - -task_RunAllForecastConfigurationsTask_description = Runs all current forecasts for all organizations - -task_RunAllForecastConfigurationsTask_name = Run all forecast configurations - -task_RunForecastConfigurationsByIdTask_description = Run all forecast configurations corresponding to ids in a comma separated list - -task_RunForecastConfigurationsByIdTask_name = Run forecast configurations by id - -task_RunGridModelsTask_description = Test - -task_RunGridModelsTask_name = Run grid models - -task_SendForecastEventNotificationsTask_description = Checks to see if there has been changes in forecasts to YELLOW or RED status. If so, finds subscribers to such events and sends notifications - -task_SendForecastEventNotificationsTask_name = Send forecast event notifications - -task_UpdateForecastResultCacheTableTask_description = To speed up certain tasks, for instance aggregating warnings for today, the table forecast_result_cache should contain only today's forecast results. Today = SystemTime. - -task_UpdateForecastResultCacheTableTask_name = Update forecast result cache table - -task_UpdateForecastSummaryTableTask_description = This task updates the table for summaries - -task_UpdateForecastSummaryTableTask_name = Update table of forecast summaries - -task_UpdateModelInformationTask_description = Fetches information about models from VIPSCoreManager and stores in VIPSLogic - -task_UpdateModelInformationTask_name = Update model information - -tasks = Tasks - -test = Test - -thousandBerrySample = Thousand berry sample - -thresholdHumidPeriodHours = Threshold Number of consecutive humid hours - -thresholdLeafWetness = Threshold leaf wetness (min/h) - -thresholdPrecipitation = Threshold precipitation (mm) - -thresholdRelativeHumidity = Threshold relative humidty (%) - -tillageMethod = Tillage method - -timeOfObservation = Time of observation - -timeZone = Time zone - -timestamp = Timestamp - -to = To - -toTheTop = To the top - -tooManySeparatorCommas = Too many separator commas - -tradeName = Trade name - -transferAndDelete = Transfer and delete - -transferResources = Transfer resources - -type = Type - -unknownOrganismId = Unknown Organism Id - -unknownTranslationKey = Unknown translation key: {0} - -up = Up - -uppercase = Upper case - -user = User - -userAccountInformation = User account information - -userApproved = The user was approved - -userCreatedAndInformed = User was created. An email with username and password was sent to the user's email - -userDeleted = User was deleted - -userOrganizationGroupsListDescription = Organization groups can be used to share resources like points of interest - -userRegistrationEmailVerificationMessageBody = We have received a request to register a new user at VIPSLogic (http://{0}/). Please confirm your email by clicking this link: {1}\n\nThank you - -userRegistrationEmailVerificationMessageSubject = Email verification needed - -userResources = User resources - -userStatusId = Approval status - -userStatus_1 = Awaiting email validation - -userStatus_2 = Awaiting approval - -userStatus_3 = Rejected - -userStatus_4 = Approved - -userStatus_5 = Disabled - -userUpdated = User was updated - -username = User name - -usernameExists = Username {0} exists - -users = Users - -viewAllTasks = View all tasks - -viewForecastConfiguration = View forecast configuration - -viewFullScreen = Full screen view - -viewOthersObservations = View observations made by others - -vipsLogicRole_1 = Superuser - -vipsLogicRole_10 = Bark beetle administrator - -vipsLogicRole_11 = Bark beetle county admin - -vipsLogicRole_2 = Organization administrator - -vipsLogicRole_3 = Observer - -vipsLogicRole_4 = Observation authority - -vipsLogicRole_5 = Message author - -vipsLogicRole_6 = Apple Fruit Moth Administrator - -vipsLogicRole_7 = Organism editor - -vipsLogicRole_8 = Apple Fruit Moth Rowanberry Cluster Counter - -vipsLogicRole_9 = Bark beetle registrator - -vipsLogicRoles = User roles - -vipsLogicUserId = User - -vipswebUrl = VIPSWeb URL - -warningStatus = Warning status - -warningStatus_0 = No forecast available - -warningStatus_1 = Missing data - -warningStatus_2 = No risk of infection - -warningStatus_3 = Medium risk of infection - -warningStatus_4 = High risk of infection - -warning_fieldNotFoundInFormDefinition = WARNING: field {0} not found in form definition. The system does not know how to validate it. Continue anyway? - -weatherForecastProvider = Weather forecast service - -weatherStationDeleted = Weather station was deleted - -weatherStationForecastConfigurations = Forecasts connected to the weather station - -weatherStationPointOfInterestId = Weather station - -weatherStationPointOfInterestIds = Weather stations - -weatherStationRemoteId = Remote Id for weather station - -weatherStationRemoteIdMissing = Remote Id for weather station is missing - -weatherStationStored = Weather station information was stored - -weatherStations = Weather stations - -xIsNotAfterY = {0} is not after {1} - -xIsNotEqualToY = {0} is not equal to {1} - -your = Your -biofixDate=Biofix date -heatRequirements=Heat requirements -dd_lower=Day degree lower cutoffs -dd_upper=Day degree upper cutoffs -observedPhase=Observed phase at biofix date -YSTEMBTEMP=Yellow Stemborer Temperature Model -addIllustration=Add illustration -allRoles=All roles -allStatuses=All statuses -LEAFBLOTCH=Leaf blotch model -universalMessageSettingsLink_tpl=To edit your notification subscriptions, please use this link: {0} -pointOfInterestType_5=Trap -sowingDate=Sowing date -pointOfInterestType_6=Apiary site -pointOfInterestType_7=Nursery diff --git a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties index 27b7151328d443f6f9e58ca5ac9fc8f9e938ba3a..2807f026bb812b2d7a917edb2e77e29a3342711f 100755 --- a/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties +++ b/src/main/resources/no/nibio/vips/logic/i18n/vipslogictexts_zh_CN.properties @@ -2,20 +2,19 @@ # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # -isPositiveRegistration=Pest presence confirmed ALTERNARIA = Alternaria Model APPLESCABM = \u82f9\u679c\u9ed1\u661f\u75c5\u6a21\u578b @@ -72,7 +71,7 @@ active = \u6709\u6548\u7684 activeWeatherStations = \u6709\u6548\u6c14\u8c61\u7ad9 -addMultipleNew = \u6dfb\u52a0\u591a\u4e2a\u65b0\u7684 +addNewForMultipleWeatherStations=\u6dfb\u52a0\u591a\u4e2a\u65b0\u7684 addNew = \u6dfb\u52a0\u65b0\u7684 @@ -174,6 +173,8 @@ cropCategory = \u4f5c\u7269\u7c7b\u578b cropCategoryIds = \u4f5c\u7269\u7c7b\u578b +cropCategoryUpdated = Crop category was updated + cropOrganismId = \u4f5c\u7269 cropOrganismIds = \u4f5c\u7269 @@ -236,6 +237,8 @@ deleteIllustration = \u5220\u9664\u56fe deletePoi = Delete point of interest +deletePoiPreviewExplanation = The point of interest that you want to delete has the resources below connected to it. When you delete the POI, you also delete these resources. + deleteUser = \u5220\u9664\u7528\u6237 deleteUserDescription = \u5728\u5220\u9664\u4e4b\u524d\u4f60\u5fc5\u987b\u5c06\u7528\u6237\u8d44\u6e90\u8f6c\u79fb\u5230\u5176\u4ed6\u7528\u6237 @@ -304,6 +307,8 @@ fieldSowingDate = Field sowing date fields = Fields +traps = Traps + filter = \u8fc7\u6ee4\u5668 filterList = Filter list @@ -378,12 +383,16 @@ invalidcredentials = \u65e0\u6548\u7528\u6237\u540d\u6216\u5bc6\u7801 isCrop = \u662f\u4f5c\u7269? +isForecastLocation = Is forecast location + isPest = \u662f\u5bb3\u866b? isPrivate = \u662f\u79c1\u4eba\u7684 isQuantified = \u662f\u5b9a\u91cf\u7684 +isPositiveRegistration=Pest presence confirmed + isRequiredField = Required field language = \u8bed\u8a00 @@ -540,14 +549,22 @@ observationDataField_counting1 = \u8ba1\u6570 1 observationDataField_counting2 = \u8ba1\u6570 2 +observationDataField_number = Number + observationDataField_trapCountCropEdge = Number of trap counts at field's edge observationDataField_trapCountCropInside = Number of trap counts inside the field +observationDataField_unit = Measuring unit + +allObservations = All observations + observationDeleted = \u89c2\u6d4b\u88ab\u5220\u9664 observationHeading = \u89c2\u6d4b\u6807\u9898 +observationMap = Observation map + observationMethodDescription_KNOCKING = \u6572\u51fb\u63cf\u8ff0 (TODO) observationMethodDescription_NOT_REGISTERED = \u89c2\u6d4b\u65b9\u6cd5\u672a\u6ce8\u518c @@ -1034,3 +1051,24 @@ pointOfInterestType_5=Trap sowingDate=Sowing date pointOfInterestType_6=Apiary site pointOfInterestType_7=Nursery +privacyStatement=Privacy statement +privacyStatementFileName=Privacy_statement_NIBIO-VIPS.pdf +thresholdDSVMax=DSV threshold for high infection risk +thresholdDSVTempMin=Minimum temperature for DSV calculation +isBroadcast=Is broadcast +yes=Yes +no=No +useGridWeatherData=Use grid weather data +doNotUse=Do not use +defaultGridWeatherStationDataSource=Gridded weather data source +weatherStationDataSources=Weather station data sources +newWeatherStationDataSource=New weather (station) data source +editWeatherStationDataSource=Edit weather (station) data source +datafetchUriExpression=URI template for requesting data +infoUriExpression=Template for request for station information +isGridWeatherDataSource=This is a grid based weather data source +weatherStationDataSourceStored=Weather (station) data source was successfully stored +weatherStationDataSourceDeleted=The weather (station) data source was successfully deleted +weatherDatasource=Weather datasource +useWeatherStation=Use weather station +multipleNewWarningMsg=This form is for adding the same forecast configuration to many weather stations simultaneously. diff --git a/src/main/resources/no/nibio/vips/util/weather/metnothredds/parametersources.properties b/src/main/resources/no/nibio/vips/util/weather/metnothredds/parametersources.properties index 5707d82869792c3b8f93bcebfc443dbe4faafc68..5269bcd13598369ce1a8dd0d5e981d9a0add674e 100644 --- a/src/main/resources/no/nibio/vips/util/weather/metnothredds/parametersources.properties +++ b/src/main/resources/no/nibio/vips/util/weather/metnothredds/parametersources.properties @@ -1,18 +1,18 @@ # Copyright (c) 2017 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. -# VIPSLogic is free software: you can redistribute it and/or modify -# it under the terms of the NIBIO Open Source License as published by -# NIBIO, either version 1 of the License, or (at your option) any -# later version. -# -# VIPSLogic 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 -# NIBIO Open Source License for more details. -# -# You should have received a copy of the NIBIO Open Source License -# along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. +# This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, + # but WITHOUT ANY WARRANTY; without even the implied warranty of + # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # TM=air_temperature_2m TX=air_temperature_max diff --git a/src/main/resources/server.properties b/src/main/resources/server.properties index 8691b9a2ca1b2493e7d865e70e4187dd6b640311..e1e68614c4735e90b71925174aa7d5c76da1389f 100755 --- a/src/main/resources/server.properties +++ b/src/main/resources/server.properties @@ -2,16 +2,16 @@ # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, +# This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # diff --git a/src/main/webapp/WEB-INF/jboss-web.xml b/src/main/webapp/WEB-INF/jboss-web.xml index 5b0877cd55bc71a7d460e77512d8405e23b378f9..e53e14728a0e23505551f8711e2b1a34803beb1e 100755 --- a/src/main/webapp/WEB-INF/jboss-web.xml +++ b/src/main/webapp/WEB-INF/jboss-web.xml @@ -3,19 +3,18 @@ # # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. # - # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # --> <jboss-web> diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index 39d9ae9147275900d44614c1ed5173d58df3d4a6..d532ad2e29b7e57402b21ae34999fefc96e3f58d 100755 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -4,18 +4,18 @@ # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. # # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # --> <web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> @@ -79,6 +79,10 @@ <servlet-name>CropCategoryController</servlet-name> <servlet-class>no.nibio.vips.logic.controller.servlet.CropCategoryController</servlet-class> </servlet> + <servlet> + <servlet-name>WeatherStationDataSourceController</servlet-name> + <servlet-class>no.nibio.vips.logic.controller.servlet.WeatherStationDataSourceController</servlet-class> + </servlet> <servlet> <servlet-name>JSEnvironment</servlet-name> <servlet-class>no.nibio.vips.logic.web.js.JSEnvironment</servlet-class> @@ -156,6 +160,10 @@ <servlet-name>CropCategoryController</servlet-name> <url-pattern>/organism/cropcategory</url-pattern> </servlet-mapping> + <servlet-mapping> + <servlet-name>WeatherStationDataSourceController</servlet-name> + <url-pattern>/weatherstationdatasource</url-pattern> + </servlet-mapping> <servlet-mapping> <servlet-name>JSEnvironment</servlet-name> <url-pattern>/js/environment.js</url-pattern> @@ -234,7 +242,7 @@ org.jboss.resteasy.plugins.server.servlet.FilterDispatcher </filter-class> <init-param> - <param-name>javax.ws.rs.Application</param-name> + <param-name>jakarta.ws.rs.Application</param-name> <param-value>no.nibio.vips.logic.VIPSLogicApplication</param-value> </init-param> </filter> @@ -245,7 +253,7 @@ <!-- FreeMarker configuration --> <servlet> <servlet-name>freemarker</servlet-name> - <servlet-class>freemarker.ext.servlet.FreemarkerServlet</servlet-class> + <servlet-class>freemarker.ext.jakarta.servlet.FreemarkerServlet</servlet-class> <!-- FreemarkerServlet settings: --> <init-param> <param-name>TemplatePath</param-name> diff --git a/src/main/webapp/css/3rdparty/leaflet.css b/src/main/webapp/css/3rdparty/leaflet.css new file mode 100644 index 0000000000000000000000000000000000000000..93477790a88403ce49993ae396495545933ebc13 --- /dev/null +++ b/src/main/webapp/css/3rdparty/leaflet.css @@ -0,0 +1,662 @@ +/* https://unpkg.com/leaflet@1.9.4/dist/leaflet.css */ +/* required styles */ + +.leaflet-pane, +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-tile-container, +.leaflet-pane > svg, +.leaflet-pane > canvas, +.leaflet-zoom-box, +.leaflet-image-layer, +.leaflet-layer { + position: absolute; + left: 0; + top: 0; + } +.leaflet-container { + overflow: hidden; + } +.leaflet-tile, +.leaflet-marker-icon, +.leaflet-marker-shadow { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + -webkit-user-drag: none; + } +/* Prevents IE11 from highlighting tiles in blue */ +.leaflet-tile::selection { + background: transparent; +} +/* Safari renders non-retina tile on retina better with this, but Chrome is worse */ +.leaflet-safari .leaflet-tile { + image-rendering: -webkit-optimize-contrast; + } +/* hack that prevents hw layers "stretching" when loading new tiles */ +.leaflet-safari .leaflet-tile-container { + width: 1600px; + height: 1600px; + -webkit-transform-origin: 0 0; + } +.leaflet-marker-icon, +.leaflet-marker-shadow { + display: block; + } +/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */ +/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */ +.leaflet-container .leaflet-overlay-pane svg { + max-width: none !important; + max-height: none !important; + } +.leaflet-container .leaflet-marker-pane img, +.leaflet-container .leaflet-shadow-pane img, +.leaflet-container .leaflet-tile-pane img, +.leaflet-container img.leaflet-image-layer, +.leaflet-container .leaflet-tile { + max-width: none !important; + max-height: none !important; + width: auto; + padding: 0; + } + +.leaflet-container img.leaflet-tile { + /* See: https://bugs.chromium.org/p/chromium/issues/detail?id=600120 */ + mix-blend-mode: plus-lighter; +} + +.leaflet-container.leaflet-touch-zoom { + -ms-touch-action: pan-x pan-y; + touch-action: pan-x pan-y; + } +.leaflet-container.leaflet-touch-drag { + -ms-touch-action: pinch-zoom; + /* Fallback for FF which doesn't support pinch-zoom */ + touch-action: none; + touch-action: pinch-zoom; +} +.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom { + -ms-touch-action: none; + touch-action: none; +} +.leaflet-container { + -webkit-tap-highlight-color: transparent; +} +.leaflet-container a { + -webkit-tap-highlight-color: rgba(51, 181, 229, 0.4); +} +.leaflet-tile { + filter: inherit; + visibility: hidden; + } +.leaflet-tile-loaded { + visibility: inherit; + } +.leaflet-zoom-box { + width: 0; + height: 0; + -moz-box-sizing: border-box; + box-sizing: border-box; + z-index: 800; + } +/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */ +.leaflet-overlay-pane svg { + -moz-user-select: none; + } + +.leaflet-pane { z-index: 400; } + +.leaflet-tile-pane { z-index: 200; } +.leaflet-overlay-pane { z-index: 400; } +.leaflet-shadow-pane { z-index: 500; } +.leaflet-marker-pane { z-index: 600; } +.leaflet-tooltip-pane { z-index: 650; } +.leaflet-popup-pane { z-index: 700; } + +.leaflet-map-pane canvas { z-index: 100; } +.leaflet-map-pane svg { z-index: 200; } + +.leaflet-vml-shape { + width: 1px; + height: 1px; + } +.lvml { + behavior: url(#default#VML); + display: inline-block; + position: absolute; + } + + +/* control positioning */ + +.leaflet-control { + position: relative; + z-index: 800; + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } +.leaflet-top, +.leaflet-bottom { + position: absolute; + z-index: 1000; + pointer-events: none; + } +.leaflet-top { + top: 0; + } +.leaflet-right { + right: 0; + } +.leaflet-bottom { + bottom: 0; + } +.leaflet-left { + left: 0; + } +.leaflet-control { + float: left; + clear: both; + } +.leaflet-right .leaflet-control { + float: right; + } +.leaflet-top .leaflet-control { + margin-top: 10px; + } +.leaflet-bottom .leaflet-control { + margin-bottom: 10px; + } +.leaflet-left .leaflet-control { + margin-left: 10px; + } +.leaflet-right .leaflet-control { + margin-right: 10px; + } + + +/* zoom and fade animations */ + +.leaflet-fade-anim .leaflet-popup { + opacity: 0; + -webkit-transition: opacity 0.2s linear; + -moz-transition: opacity 0.2s linear; + transition: opacity 0.2s linear; + } +.leaflet-fade-anim .leaflet-map-pane .leaflet-popup { + opacity: 1; + } +.leaflet-zoom-animated { + -webkit-transform-origin: 0 0; + -ms-transform-origin: 0 0; + transform-origin: 0 0; + } +svg.leaflet-zoom-animated { + will-change: transform; +} + +.leaflet-zoom-anim .leaflet-zoom-animated { + -webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1); + -moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1); + transition: transform 0.25s cubic-bezier(0,0,0.25,1); + } +.leaflet-zoom-anim .leaflet-tile, +.leaflet-pan-anim .leaflet-tile { + -webkit-transition: none; + -moz-transition: none; + transition: none; + } + +.leaflet-zoom-anim .leaflet-zoom-hide { + visibility: hidden; + } + + +/* cursors */ + +.leaflet-interactive { + cursor: pointer; + } +.leaflet-grab { + cursor: -webkit-grab; + cursor: -moz-grab; + cursor: grab; + } +.leaflet-crosshair, +.leaflet-crosshair .leaflet-interactive { + cursor: crosshair; + } +.leaflet-popup-pane, +.leaflet-control { + cursor: auto; + } +.leaflet-dragging .leaflet-grab, +.leaflet-dragging .leaflet-grab .leaflet-interactive, +.leaflet-dragging .leaflet-marker-draggable { + cursor: move; + cursor: -webkit-grabbing; + cursor: -moz-grabbing; + cursor: grabbing; + } + +/* marker & overlays interactivity */ +.leaflet-marker-icon, +.leaflet-marker-shadow, +.leaflet-image-layer, +.leaflet-pane > svg path, +.leaflet-tile-container { + pointer-events: none; + } + +.leaflet-marker-icon.leaflet-interactive, +.leaflet-image-layer.leaflet-interactive, +.leaflet-pane > svg path.leaflet-interactive, +svg.leaflet-image-layer.leaflet-interactive path { + pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */ + pointer-events: auto; + } + +/* visual tweaks */ + +.leaflet-container { + background: #ddd; + outline-offset: 1px; + } +.leaflet-container a { + color: #0078A8; + } +.leaflet-zoom-box { + border: 2px dotted #38f; + background: rgba(255,255,255,0.5); + } + + +/* general typography */ +.leaflet-container { + font-family: "Helvetica Neue", Arial, Helvetica, sans-serif; + font-size: 12px; + font-size: 0.75rem; + line-height: 1.5; + } + + +/* general toolbar styles */ + +.leaflet-bar { + box-shadow: 0 1px 5px rgba(0,0,0,0.65); + border-radius: 4px; + } +.leaflet-bar a { + background-color: #fff; + border-bottom: 1px solid #ccc; + width: 26px; + height: 26px; + line-height: 26px; + display: block; + text-align: center; + text-decoration: none; + color: black; + } +.leaflet-bar a, +.leaflet-control-layers-toggle { + background-position: 50% 50%; + background-repeat: no-repeat; + display: block; + } +.leaflet-bar a:hover, +.leaflet-bar a:focus { + background-color: #f4f4f4; + } +.leaflet-bar a:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; + } +.leaflet-bar a:last-child { + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + border-bottom: none; + } +.leaflet-bar a.leaflet-disabled { + cursor: default; + background-color: #f4f4f4; + color: #bbb; + } + +.leaflet-touch .leaflet-bar a { + width: 30px; + height: 30px; + line-height: 30px; + } +.leaflet-touch .leaflet-bar a:first-child { + border-top-left-radius: 2px; + border-top-right-radius: 2px; + } +.leaflet-touch .leaflet-bar a:last-child { + border-bottom-left-radius: 2px; + border-bottom-right-radius: 2px; + } + +/* zoom control */ + +.leaflet-control-zoom-in, +.leaflet-control-zoom-out { + font: bold 18px 'Lucida Console', Monaco, monospace; + text-indent: 1px; + } + +.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out { + font-size: 22px; + } + + +/* layers control */ + +.leaflet-control-layers { + box-shadow: 0 1px 5px rgba(0,0,0,0.4); + background: #fff; + border-radius: 5px; + } +.leaflet-control-layers-toggle { + background-image: url(images/layers.png); + width: 36px; + height: 36px; + } +.leaflet-retina .leaflet-control-layers-toggle { + background-image: url(images/layers-2x.png); + background-size: 26px 26px; + } +.leaflet-touch .leaflet-control-layers-toggle { + width: 44px; + height: 44px; + } +.leaflet-control-layers .leaflet-control-layers-list, +.leaflet-control-layers-expanded .leaflet-control-layers-toggle { + display: none; + } +.leaflet-control-layers-expanded .leaflet-control-layers-list { + display: block; + position: relative; + } +.leaflet-control-layers-expanded { + padding: 6px 10px 6px 6px; + color: #333; + background: #fff; + } +.leaflet-control-layers-scrollbar { + overflow-y: scroll; + overflow-x: hidden; + padding-right: 5px; + } +.leaflet-control-layers-selector { + margin-top: 2px; + position: relative; + top: 1px; + } +.leaflet-control-layers label { + display: block; + font-size: 13px; + font-size: 1.08333em; + } +.leaflet-control-layers-separator { + height: 0; + border-top: 1px solid #ddd; + margin: 5px -10px 5px -6px; + } + +/* Default icon URLs */ +.leaflet-default-icon-path { /* used only in path-guessing heuristic, see L.Icon.Default */ + background-image: url(images/marker-icon.png); + } + + +/* attribution and scale controls */ + +.leaflet-container .leaflet-control-attribution { + background: #fff; + background: rgba(255, 255, 255, 0.8); + margin: 0; + } +.leaflet-control-attribution, +.leaflet-control-scale-line { + padding: 0 5px; + color: #333; + line-height: 1.4; + } +.leaflet-control-attribution a { + text-decoration: none; + } +.leaflet-control-attribution a:hover, +.leaflet-control-attribution a:focus { + text-decoration: underline; + } +.leaflet-attribution-flag { + display: inline !important; + vertical-align: baseline !important; + width: 1em; + height: 0.6669em; + } +.leaflet-left .leaflet-control-scale { + margin-left: 5px; + } +.leaflet-bottom .leaflet-control-scale { + margin-bottom: 5px; + } +.leaflet-control-scale-line { + border: 2px solid #777; + border-top: none; + line-height: 1.1; + padding: 2px 5px 1px; + white-space: nowrap; + -moz-box-sizing: border-box; + box-sizing: border-box; + background: rgba(255, 255, 255, 0.8); + text-shadow: 1px 1px #fff; + } +.leaflet-control-scale-line:not(:first-child) { + border-top: 2px solid #777; + border-bottom: none; + margin-top: -2px; + } +.leaflet-control-scale-line:not(:first-child):not(:last-child) { + border-bottom: 2px solid #777; + } + +.leaflet-touch .leaflet-control-attribution, +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + box-shadow: none; + } +.leaflet-touch .leaflet-control-layers, +.leaflet-touch .leaflet-bar { + border: 2px solid rgba(0,0,0,0.2); + background-clip: padding-box; + } + + +/* popup */ + +.leaflet-popup { + position: absolute; + text-align: center; + margin-bottom: 20px; + } +.leaflet-popup-content-wrapper { + padding: 1px; + text-align: left; + border-radius: 12px; + } +.leaflet-popup-content { + margin: 13px 24px 13px 20px; + line-height: 1.3; + font-size: 13px; + font-size: 1.08333em; + min-height: 1px; + } +.leaflet-popup-content p { + margin: 17px 0; + margin: 1.3em 0; + } +.leaflet-popup-tip-container { + width: 40px; + height: 20px; + position: absolute; + left: 50%; + margin-top: -1px; + margin-left: -20px; + overflow: hidden; + pointer-events: none; + } +.leaflet-popup-tip { + width: 17px; + height: 17px; + padding: 1px; + + margin: -10px auto 0; + pointer-events: auto; + + -webkit-transform: rotate(45deg); + -moz-transform: rotate(45deg); + -ms-transform: rotate(45deg); + transform: rotate(45deg); + } +.leaflet-popup-content-wrapper, +.leaflet-popup-tip { + background: white; + color: #333; + box-shadow: 0 3px 14px rgba(0,0,0,0.4); + } +.leaflet-container a.leaflet-popup-close-button { + position: absolute; + top: 0; + right: 0; + border: none; + text-align: center; + width: 24px; + height: 24px; + font: 16px/24px Tahoma, Verdana, sans-serif; + color: #757575; + text-decoration: none; + background: transparent; + } +.leaflet-container a.leaflet-popup-close-button:hover, +.leaflet-container a.leaflet-popup-close-button:focus { + color: #585858; + } +.leaflet-popup-scrolled { + overflow: auto; + } + +.leaflet-oldie .leaflet-popup-content-wrapper { + -ms-zoom: 1; + } +.leaflet-oldie .leaflet-popup-tip { + width: 24px; + margin: 0 auto; + + -ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)"; + filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678); + } + +.leaflet-oldie .leaflet-control-zoom, +.leaflet-oldie .leaflet-control-layers, +.leaflet-oldie .leaflet-popup-content-wrapper, +.leaflet-oldie .leaflet-popup-tip { + border: 1px solid #999; + } + + +/* div icon */ + +.leaflet-div-icon { + background: #fff; + border: 1px solid #666; + } + + +/* Tooltip */ +/* Base styles for the element that has a tooltip */ +.leaflet-tooltip { + position: absolute; + padding: 6px; + background-color: #fff; + border: 1px solid #fff; + border-radius: 3px; + color: #222; + white-space: nowrap; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + pointer-events: none; + box-shadow: 0 1px 3px rgba(0,0,0,0.4); + } +.leaflet-tooltip.leaflet-interactive { + cursor: pointer; + pointer-events: auto; + } +.leaflet-tooltip-top:before, +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + position: absolute; + pointer-events: none; + border: 6px solid transparent; + background: transparent; + content: ""; + } + +/* Directions */ + +.leaflet-tooltip-bottom { + margin-top: 6px; +} +.leaflet-tooltip-top { + margin-top: -6px; +} +.leaflet-tooltip-bottom:before, +.leaflet-tooltip-top:before { + left: 50%; + margin-left: -6px; + } +.leaflet-tooltip-top:before { + bottom: 0; + margin-bottom: -12px; + border-top-color: #fff; + } +.leaflet-tooltip-bottom:before { + top: 0; + margin-top: -12px; + margin-left: -6px; + border-bottom-color: #fff; + } +.leaflet-tooltip-left { + margin-left: -6px; +} +.leaflet-tooltip-right { + margin-left: 6px; +} +.leaflet-tooltip-left:before, +.leaflet-tooltip-right:before { + top: 50%; + margin-top: -6px; + } +.leaflet-tooltip-left:before { + right: 0; + margin-right: -12px; + border-left-color: #fff; + } +.leaflet-tooltip-right:before { + left: 0; + margin-left: -12px; + border-right-color: #fff; + } + +/* Printing */ + +@media print { + /* Prevent printers from removing background-images of controls. */ + .leaflet-control { + -webkit-print-color-adjust: exact; + print-color-adjust: exact; + } + } diff --git a/src/main/webapp/css/3rdparty/ol_6_5_0.css b/src/main/webapp/css/3rdparty/ol_6_5_0.css new file mode 100644 index 0000000000000000000000000000000000000000..3984d24bb21dbe3b4ed3b108429a141ab71c277f --- /dev/null +++ b/src/main/webapp/css/3rdparty/ol_6_5_0.css @@ -0,0 +1,2 @@ +.ol-box{box-sizing:border-box;border-radius:2px;border:2px solid #00f}.ol-mouse-position{top:8px;right:8px;position:absolute}.ol-scale-line{background:rgba(0,60,136,.3);border-radius:4px;bottom:8px;left:8px;padding:2px;position:absolute}.ol-scale-line-inner{border:1px solid #eee;border-top:none;color:#eee;font-size:10px;text-align:center;margin:1px;will-change:contents,width;transition:all .25s}.ol-scale-bar{position:absolute;bottom:8px;left:8px}.ol-scale-step-marker{width:1px;height:15px;background-color:#000;float:right;z-Index:10}.ol-scale-step-text{position:absolute;bottom:-5px;font-size:12px;z-Index:11;color:#000;text-shadow:-2px 0 #fff,0 2px #fff,2px 0 #fff,0 -2px #fff}.ol-scale-text{position:absolute;font-size:14px;text-align:center;bottom:25px;color:#000;text-shadow:-2px 0 #fff,0 2px #fff,2px 0 #fff,0 -2px #fff}.ol-scale-singlebar{position:relative;height:10px;z-Index:9;box-sizing:border-box;border:1px solid #000}.ol-unsupported{display:none}.ol-unselectable,.ol-viewport{-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-tap-highlight-color:transparent}.ol-selectable{-webkit-touch-callout:default;-webkit-user-select:text;-moz-user-select:text;-ms-user-select:text;user-select:text}.ol-grabbing{cursor:-webkit-grabbing;cursor:-moz-grabbing;cursor:grabbing}.ol-grab{cursor:move;cursor:-webkit-grab;cursor:-moz-grab;cursor:grab}.ol-control{position:absolute;background-color:rgba(255,255,255,.4);border-radius:4px;padding:2px}.ol-control:hover{background-color:rgba(255,255,255,.6)}.ol-zoom{top:.5em;left:.5em}.ol-rotate{top:.5em;right:.5em;transition:opacity .25s linear,visibility 0s linear}.ol-rotate.ol-hidden{opacity:0;visibility:hidden;transition:opacity .25s linear,visibility 0s linear .25s}.ol-zoom-extent{top:4.643em;left:.5em}.ol-full-screen{right:.5em;top:.5em}.ol-control button{display:block;margin:1px;padding:0;color:#fff;font-size:1.14em;font-weight:700;text-decoration:none;text-align:center;height:1.375em;width:1.375em;line-height:.4em;background-color:rgba(0,60,136,.5);border:none;border-radius:2px}.ol-control button::-moz-focus-inner{border:none;padding:0}.ol-zoom-extent button{line-height:1.4em}.ol-compass{display:block;font-weight:400;font-size:1.2em;will-change:transform}.ol-touch .ol-control button{font-size:1.5em}.ol-touch .ol-zoom-extent{top:5.5em}.ol-control button:focus,.ol-control button:hover{text-decoration:none;background-color:rgba(0,60,136,.7)}.ol-zoom .ol-zoom-in{border-radius:2px 2px 0 0}.ol-zoom .ol-zoom-out{border-radius:0 0 2px 2px}.ol-attribution{text-align:right;bottom:.5em;right:.5em;max-width:calc(100% - 1.3em)}.ol-attribution ul{margin:0;padding:0 .5em;color:#000;text-shadow:0 0 2px #fff}.ol-attribution li{display:inline;list-style:none}.ol-attribution li:not(:last-child):after{content:" "}.ol-attribution img{max-height:2em;max-width:inherit;vertical-align:middle}.ol-attribution button,.ol-attribution ul{display:inline-block}.ol-attribution.ol-collapsed ul{display:none}.ol-attribution:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-attribution.ol-uncollapsible{bottom:0;right:0;border-radius:4px 0 0}.ol-attribution.ol-uncollapsible img{margin-top:-.2em;max-height:1.6em}.ol-attribution.ol-uncollapsible button{display:none}.ol-zoomslider{top:4.5em;left:.5em;height:200px}.ol-zoomslider button{position:relative;height:10px}.ol-touch .ol-zoomslider{top:5.5em}.ol-overviewmap{left:.5em;bottom:.5em}.ol-overviewmap.ol-uncollapsible{bottom:0;left:0;border-radius:0 4px 0 0}.ol-overviewmap .ol-overviewmap-map,.ol-overviewmap button{display:inline-block}.ol-overviewmap .ol-overviewmap-map{border:1px solid #7b98bc;height:150px;margin:2px;width:150px}.ol-overviewmap:not(.ol-collapsed) button{bottom:1px;left:2px;position:absolute}.ol-overviewmap.ol-collapsed .ol-overviewmap-map,.ol-overviewmap.ol-uncollapsible button{display:none}.ol-overviewmap:not(.ol-collapsed){background:rgba(255,255,255,.8)}.ol-overviewmap-box{border:2px dotted rgba(0,60,136,.7)}.ol-overviewmap .ol-overviewmap-box:hover{cursor:move} +/*# sourceMappingURL=ol.css.map */ \ No newline at end of file diff --git a/src/main/webapp/css/map.css b/src/main/webapp/css/map.css index 735c709a49f64c9f7da2feeae9fa99557f94699d..ab79fea3057eb20ca08c78ff2929583656a9c850 100755 --- a/src/main/webapp/css/map.css +++ b/src/main/webapp/css/map.css @@ -2,18 +2,18 @@ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ /* diff --git a/src/main/webapp/css/mapModal.css b/src/main/webapp/css/mapModal.css new file mode 100644 index 0000000000000000000000000000000000000000..40990f46c4d456ba5612050c98205438245b592d --- /dev/null +++ b/src/main/webapp/css/mapModal.css @@ -0,0 +1,78 @@ +.map-modal { + display: none; + position: fixed; + z-index: 1000; + left: 50%; + top: 50%; + width: 90%; + height: 90%; + overflow: hidden; + background-color: rgba(0, 0, 0, 0.9); + transform: translate(-50%, -50%); + border: 2px solid #fff; + box-shadow: 0 0 10px rgba(0, 0, 0, 0.5); + border-radius: 15px; +} + +.map-modal.show { + display: flex; + justify-content: center; + align-items: center; +} + +#selected-point-info-panel { + width: 160px; + background: white; + padding: 0 10px 10px 10px; + border-radius: 5px; + box-shadow: 0 0 15px rgba(0, 0, 0, 0.2); + z-index: 1100; +} + +.map-button { + font-size: 24px; +} + +.legend-item { + display: flex; + align-items: center; + margin-bottom: 5px; +} + +.legend-item i { + margin-right: 8px; + width: 18px; + height: 18px; + display: inline-block; +} + +.info.legend { + background-color: white; + padding: 10px; + font-size: 14px; + line-height: 20px; + color: #555; + border-radius: 5px; + box-shadow: 0 0 15px rgba(0,0,0,0.2); + cursor: default !important; +} + +#confirm-button { + margin-top: 10px; +} + +.leaflet-container { + cursor: default !important; + font-size: 12px; +} + +#open-map-modal-icon { + font-size: 30px; + margin-left: 15px; + cursor: pointer; +} + +#new-point-form { + z-index: 1200; + position: absolute; +} diff --git a/src/main/webapp/css/signin.css b/src/main/webapp/css/signin.css index 96a71743919ffb354618c63a123b38e3b0f84d1c..3762ccb429cfc8004a3b09c3b73ec844c5b39366 100755 --- a/src/main/webapp/css/signin.css +++ b/src/main/webapp/css/signin.css @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/css/vipslogic.css b/src/main/webapp/css/vipslogic.css index 372c43657eff0ef8909984d7edb76db293c7f1fe..d0838304e354b94d8959b630cc2695ed7378a946 100755 --- a/src/main/webapp/css/vipslogic.css +++ b/src/main/webapp/css/vipslogic.css @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ /* diff --git a/src/main/webapp/formdefinitions/appleFruitMothStationForm.json b/src/main/webapp/formdefinitions/appleFruitMothStationForm.json index cec171ad58c8eb8607190424cf90a06a34d14a2a..cf7ca381ab7f0df517617df92d4c086ac27de953 100755 --- a/src/main/webapp/formdefinitions/appleFruitMothStationForm.json +++ b/src/main/webapp/formdefinitions/appleFruitMothStationForm.json @@ -3,18 +3,18 @@ "Copyright (c) 2014-2018 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the appleFruitMothStationForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/cropCategoryCropForm.json b/src/main/webapp/formdefinitions/cropCategoryCropForm.json index 621429ac22dc34982608de0b525dea2571020511..ec641b5f2a4a8190b31b833e06b47b93d8aa1196 100755 --- a/src/main/webapp/formdefinitions/cropCategoryCropForm.json +++ b/src/main/webapp/formdefinitions/cropCategoryCropForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the organismForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/cropPestForm.json b/src/main/webapp/formdefinitions/cropPestForm.json index c2eb651c24b8ec5687993edd4d49d9cc02812a60..cc91c3cd5c8f1a26fe74ce3e0001ca9223347d85 100755 --- a/src/main/webapp/formdefinitions/cropPestForm.json +++ b/src/main/webapp/formdefinitions/cropPestForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the organismForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/forecastConfigurationForm.json b/src/main/webapp/formdefinitions/forecastConfigurationForm.json index 0273d045d5898e6c6ca56f872a46bd85f31e2dd6..ca6fd66a4cf07d58acbed4e9a62d86c9c23b3769 100755 --- a/src/main/webapp/formdefinitions/forecastConfigurationForm.json +++ b/src/main/webapp/formdefinitions/forecastConfigurationForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the forecastConfigurationForm and how to validate it", "fields": [ @@ -56,6 +57,11 @@ "dataType" : "STRING", "required" : false }, + { + "name" : "useGridWeatherData", + "dataType" : "STRING", + "required" : false + }, { "name" : "locationPointOfInterestId", "dataType" : "INTEGER", diff --git a/src/main/webapp/formdefinitions/forecastConfigurationMultipleNewForm.json b/src/main/webapp/formdefinitions/forecastConfigurationMultipleNewForm.json index a39766e81691a750c99585851bacd8d137ae1357..b3e2b1fae41777324a89ff09a0003645a21cfa7b 100755 --- a/src/main/webapp/formdefinitions/forecastConfigurationMultipleNewForm.json +++ b/src/main/webapp/formdefinitions/forecastConfigurationMultipleNewForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the forecastConfigurationMultipleNewForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/messageForm.json b/src/main/webapp/formdefinitions/messageForm.json index 5e7b86b9c16319c421fc6c160cfe44f5a391e133..cc261e337dc41ea29893538a33a81bb3f38e26d5 100755 --- a/src/main/webapp/formdefinitions/messageForm.json +++ b/src/main/webapp/formdefinitions/messageForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the organismForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/ALTERNARIA.json b/src/main/webapp/formdefinitions/models/ALTERNARIA.json index f65768d9b5b42757927f41f5d0c05012930d4c41..58d32e991cbe2e818e81fcf982ceaf3a505708c6 100644 --- a/src/main/webapp/formdefinitions/models/ALTERNARIA.json +++ b/src/main/webapp/formdefinitions/models/ALTERNARIA.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for ALTERNARIA", "fields": [ @@ -41,6 +42,18 @@ "dataType" : "DATE", "dateFormat" : "yyyy-MM-dd", "required" : false + }, + { + "name" : "thresholdDSVMax", + "dataType" : "DOUBLE", + "defaultValue" : "20.0", + "required" : false + } , + { + "name" : "thresholdDSVTempMin", + "dataType" : "DOUBLE", + "defaultValue" : "13.0", + "required" : false } ] } diff --git a/src/main/webapp/formdefinitions/models/APPLESCABM.json b/src/main/webapp/formdefinitions/models/APPLESCABM.json index c087e0cf566befbb7ed316ffc8d2f7101546e1ab..ebf0634fd8b1fe8bad0a30e7a36b9ce1e76fcf37 100755 --- a/src/main/webapp/formdefinitions/models/APPLESCABM.json +++ b/src/main/webapp/formdefinitions/models/APPLESCABM.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for APPLESCABM", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/BREMIALACT.json b/src/main/webapp/formdefinitions/models/BREMIALACT.json index e0de5760ae5667c202ab826b8dd9bd26ae9c91a9..cd24e726da0d13b4567a38b3a62a1190fb82cb40 100755 --- a/src/main/webapp/formdefinitions/models/BREMIALACT.json +++ b/src/main/webapp/formdefinitions/models/BREMIALACT.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for BREMIALACT", "fields": [] diff --git a/src/main/webapp/formdefinitions/models/CYDIAPOMON.json b/src/main/webapp/formdefinitions/models/CYDIAPOMON.json index 894f9e46adc17634b5929304cecb790aca24cd24..8287d4e5ec04542fc10a63b87e811aa06478948b 100755 --- a/src/main/webapp/formdefinitions/models/CYDIAPOMON.json +++ b/src/main/webapp/formdefinitions/models/CYDIAPOMON.json @@ -3,18 +3,19 @@ "Copyright (c) 2015 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for CYDIAPOMON (Cydia Pomonella model)", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/DELIARADIC.json b/src/main/webapp/formdefinitions/models/DELIARADIC.json index 8f0832917f2de63e67deb6b01aef2a810ad17f15..4053e2e499eb06f58640a31ada8b1e9689d7084d 100755 --- a/src/main/webapp/formdefinitions/models/DELIARADIC.json +++ b/src/main/webapp/formdefinitions/models/DELIARADIC.json @@ -3,18 +3,19 @@ "Copyright (c) 2015 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for DELIARADIC", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/DELIARFOBO.json b/src/main/webapp/formdefinitions/models/DELIARFOBO.json index 6ac4bdcb966f4340d755a6f184e6827861c6d1a9..b7c9a74c2b077047cb16e853b81ad8b36c263b16 100755 --- a/src/main/webapp/formdefinitions/models/DELIARFOBO.json +++ b/src/main/webapp/formdefinitions/models/DELIARFOBO.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for DELIARFOBS", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/DELIARFOBS.json b/src/main/webapp/formdefinitions/models/DELIARFOBS.json index 1403be2e085b3c3c87ebb7793da4360a08244587..0e2ea6e4b7f7ad8d488db73b8b43bdac049029c8 100755 --- a/src/main/webapp/formdefinitions/models/DELIARFOBS.json +++ b/src/main/webapp/formdefinitions/models/DELIARFOBS.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for DELIARFOBS", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/DELIARFOBY.json b/src/main/webapp/formdefinitions/models/DELIARFOBY.json index 6ac4bdcb966f4340d755a6f184e6827861c6d1a9..b7c9a74c2b077047cb16e853b81ad8b36c263b16 100755 --- a/src/main/webapp/formdefinitions/models/DELIARFOBY.json +++ b/src/main/webapp/formdefinitions/models/DELIARFOBY.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for DELIARFOBS", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/DOWNCASTMO.json b/src/main/webapp/formdefinitions/models/DOWNCASTMO.json index 195062a791aad3fb4be992b241f6df68d4726963..fbf19af2fe1c0992caa65a925d4d58009a673025 100755 --- a/src/main/webapp/formdefinitions/models/DOWNCASTMO.json +++ b/src/main/webapp/formdefinitions/models/DOWNCASTMO.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for DOWNCASTMO", "fields": [] diff --git a/src/main/webapp/formdefinitions/models/FINNCEREAL.json b/src/main/webapp/formdefinitions/models/FINNCEREAL.json index a8b79836ee0781bd5b0315aae32cc0c3c2e00f06..9a1e2f5f74cb07f368bf7113a4c197157c70454e 100644 --- a/src/main/webapp/formdefinitions/models/FINNCEREAL.json +++ b/src/main/webapp/formdefinitions/models/FINNCEREAL.json @@ -3,18 +3,19 @@ "Copyright (c) 2018 NIBIO <http://www.nibio.nb/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.nb/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Sowing date, previous crop, tillage method, and current crop disease susceptibility for the specific field", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/HOPLOCAMPA.json b/src/main/webapp/formdefinitions/models/HOPLOCAMPA.json index 67df9b207094f6d215c5cae64afb604f0180fe04..27fcdf690a0eda3f821191ae9a4dd86270a194c5 100755 --- a/src/main/webapp/formdefinitions/models/HOPLOCAMPA.json +++ b/src/main/webapp/formdefinitions/models/HOPLOCAMPA.json @@ -3,18 +3,19 @@ "Copyright (c) 2015 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for HOPLOCAMPA", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/LEAFBLOTCH.json b/src/main/webapp/formdefinitions/models/LEAFBLOTCH.json index 2fc42b68dc692767bb85de9973ff752460cb3daf..cfe845a0a6df641438cf6db61c115a662f542aac 100644 --- a/src/main/webapp/formdefinitions/models/LEAFBLOTCH.json +++ b/src/main/webapp/formdefinitions/models/LEAFBLOTCH.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for LEAFBLOTCH", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/LYGUSRUGUL.json b/src/main/webapp/formdefinitions/models/LYGUSRUGUL.json index 2e76ad6dc0ec77e52aa750ef4a81539a3a1e91e1..3d8857dca8931eff19255e3621ae74e853bd28de 100755 --- a/src/main/webapp/formdefinitions/models/LYGUSRUGUL.json +++ b/src/main/webapp/formdefinitions/models/LYGUSRUGUL.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for LYGUSRUGUL", "fields": [] diff --git a/src/main/webapp/formdefinitions/models/MAMESTRABR.json b/src/main/webapp/formdefinitions/models/MAMESTRABR.json index a05d85da83305946d55789957661d7d941043961..f0d24fe30dfbceec6c990cfa735d6f53aaa7adac 100755 --- a/src/main/webapp/formdefinitions/models/MAMESTRABR.json +++ b/src/main/webapp/formdefinitions/models/MAMESTRABR.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for MAMESTRABR", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/NAERSTADMO.json b/src/main/webapp/formdefinitions/models/NAERSTADMO.json index ed54bdb5c5fafe1a3d9fa0f7f8080b422c531449..b0e827d49178fee71b0054fad165ce0a9b0d58c3 100755 --- a/src/main/webapp/formdefinitions/models/NAERSTADMO.json +++ b/src/main/webapp/formdefinitions/models/NAERSTADMO.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for NAERSTADMO", "fields": [] diff --git a/src/main/webapp/formdefinitions/models/NEGPROGMOD.json b/src/main/webapp/formdefinitions/models/NEGPROGMOD.json index 4f1488884551635e5e51ff0b086dc54a92f3c746..c2be39ae49f0776c485c2f82b758b4a0d35f443c 100755 --- a/src/main/webapp/formdefinitions/models/NEGPROGMOD.json +++ b/src/main/webapp/formdefinitions/models/NEGPROGMOD.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for NEGPROGMOD", "fields": [] diff --git a/src/main/webapp/formdefinitions/models/PLASMOVITI.json b/src/main/webapp/formdefinitions/models/PLASMOVITI.json index d2c2515429dc1994d03603cef04aac7483e6acb0..82fcbe7014005568cb1818e46e158a0eccf7c366 100755 --- a/src/main/webapp/formdefinitions/models/PLASMOVITI.json +++ b/src/main/webapp/formdefinitions/models/PLASMOVITI.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for PLASMOVITI", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/PSILAROBSE.json b/src/main/webapp/formdefinitions/models/PSILAROBSE.json index 7c94af31faf124711094739e746fd73c25d14a94..2de41ab0196d077365aa537f2416b4aa6d9a0d93 100755 --- a/src/main/webapp/formdefinitions/models/PSILAROBSE.json +++ b/src/main/webapp/formdefinitions/models/PSILAROBSE.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for PSILAROBSE", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/PSILARTEMP.json b/src/main/webapp/formdefinitions/models/PSILARTEMP.json index f30421fd84021d4adc3f8dfcc2a2177a549c3684..ba30bd68b76ba0f93259d2121049815c9e05de69 100755 --- a/src/main/webapp/formdefinitions/models/PSILARTEMP.json +++ b/src/main/webapp/formdefinitions/models/PSILARTEMP.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for PSILARTEMP", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/RAINYDAYSM.json b/src/main/webapp/formdefinitions/models/RAINYDAYSM.json index 55341a1d42d704fc51e58bc907b98cb22e32c58c..35ff2bb2484e6941708f8b8691906ef39786d9ff 100644 --- a/src/main/webapp/formdefinitions/models/RAINYDAYSM.json +++ b/src/main/webapp/formdefinitions/models/RAINYDAYSM.json @@ -3,18 +3,19 @@ "Copyright (c) 2019 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for RAINYDAYSM", "fields": [{ diff --git a/src/main/webapp/formdefinitions/models/SEPAPIICOL.json b/src/main/webapp/formdefinitions/models/SEPAPIICOL.json index 684587c143bd8746b08b341ab9d8f724d4880886..0514d3de83ef9086c17fcf15d824e878a5e2fba9 100755 --- a/src/main/webapp/formdefinitions/models/SEPAPIICOL.json +++ b/src/main/webapp/formdefinitions/models/SEPAPIICOL.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for SEPAPIICOL", "fields": [] diff --git a/src/main/webapp/formdefinitions/models/SEPTORIAHU.json b/src/main/webapp/formdefinitions/models/SEPTORIAHU.json index b5c3916d653a0003accdcf5aad7d5e66c64db05c..f1917c53610820524a1ed9d65af264a33ed838cd 100644 --- a/src/main/webapp/formdefinitions/models/SEPTORIAHU.json +++ b/src/main/webapp/formdefinitions/models/SEPTORIAHU.json @@ -3,18 +3,19 @@ "Copyright (c) 2019 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for SEPTORIAHU", "fields": [ diff --git a/src/main/webapp/formdefinitions/models/SEPTREFHUM.json b/src/main/webapp/formdefinitions/models/SEPTREFHUM.json index 94cba116a03b38f57f532d5b304886b901a03afc..f7a8cbc196d6209b8dab7901bfeb60f0e4634396 100644 --- a/src/main/webapp/formdefinitions/models/SEPTREFHUM.json +++ b/src/main/webapp/formdefinitions/models/SEPTREFHUM.json @@ -3,18 +3,19 @@ "Copyright (c) 2019 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for SEPTREFHUM", "fields": [{ diff --git a/src/main/webapp/formdefinitions/models/YSTEMBTEMP.json b/src/main/webapp/formdefinitions/models/YSTEMBTEMP.json index b091e01c2b4e844ac732289f805fab1e6d2fed49..882a2bcc376257777f2bead306e5ed396d4e47a4 100644 --- a/src/main/webapp/formdefinitions/models/YSTEMBTEMP.json +++ b/src/main/webapp/formdefinitions/models/YSTEMBTEMP.json @@ -3,18 +3,19 @@ "Copyright (c) 2022 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the specific fields for YSTEMBTEMP", "fields": [ diff --git a/src/main/webapp/formdefinitions/modules/barkbeetle/seasonTrapsiteForm.json b/src/main/webapp/formdefinitions/modules/barkbeetle/seasonTrapsiteForm.json index ebd0ec05075956d066f527695bc3038e6944a1ed..57cba74120457858afce2b2dcfcc7d329e828e0a 100644 --- a/src/main/webapp/formdefinitions/modules/barkbeetle/seasonTrapsiteForm.json +++ b/src/main/webapp/formdefinitions/modules/barkbeetle/seasonTrapsiteForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2020 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the seasonTrapsiteForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/observationForm.json b/src/main/webapp/formdefinitions/observationForm.json index d559d505a6448e709b514ea2f8b1b1e4bbcd70d6..d55a16babdbfe710cefafe2e84a208b6b4657211 100755 --- a/src/main/webapp/formdefinitions/observationForm.json +++ b/src/main/webapp/formdefinitions/observationForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the observationForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/observationMapForm.json b/src/main/webapp/formdefinitions/observationMapForm.json index 77149662796904cf768c17df4098981180afe0c3..ae6027c37e60fa7ed8d0531b73e945e5c2676f98 100755 --- a/src/main/webapp/formdefinitions/observationMapForm.json +++ b/src/main/webapp/formdefinitions/observationMapForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Simplify input check for observation map", "fields": [ diff --git a/src/main/webapp/formdefinitions/organismForm.json b/src/main/webapp/formdefinitions/organismForm.json index 48c7c5bcf0603ae662e5fb5d1a42480e3a4db9c0..8395e8fc15e16a9fd4aaa0ef7821bef52cafcf10 100755 --- a/src/main/webapp/formdefinitions/organismForm.json +++ b/src/main/webapp/formdefinitions/organismForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the organismForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/organizationForm.json b/src/main/webapp/formdefinitions/organizationForm.json index cf1de2562347f7e057554f8b8bbd7d0e6fd4a35e..4ff9c999cf3cdd406e5b6db626f46b8564ebdf61 100644 --- a/src/main/webapp/formdefinitions/organizationForm.json +++ b/src/main/webapp/formdefinitions/organizationForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2019 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the organizationForm and how to validate it", "fields": [ @@ -94,6 +95,12 @@ "name" : "defaultMapCenter", "dataType" : "STRING", "required" : false + }, + { + "name": "defaultGridWeatherStationDataSourceId", + "dataType": "INTEGER", + "fieldType": "SELECT_SINGLE", + "required": false } ] diff --git a/src/main/webapp/formdefinitions/organizationGroupForm.json b/src/main/webapp/formdefinitions/organizationGroupForm.json index 3308d175b404b401de848c81d91e96d950785447..66ddb20e1b324467855cd9db593fc26248003792 100755 --- a/src/main/webapp/formdefinitions/organizationGroupForm.json +++ b/src/main/webapp/formdefinitions/organizationGroupForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the poiForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/poiForm.json b/src/main/webapp/formdefinitions/poiForm.json index fbb1808a68733ba8baf1a5cd91475f436da8881b..83a8b2f07cdc65cf3f1e72e061d7bb177ea0ab3c 100755 --- a/src/main/webapp/formdefinitions/poiForm.json +++ b/src/main/webapp/formdefinitions/poiForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2016 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the poiForm and how to validate it", "fields": [ @@ -85,6 +86,11 @@ "name" : "isForecastLocation", "dataType" : "STRING", "required" : false + }, + { + "name" : "isPrivate", + "dataType" : "STRING", + "required" : false } ] } diff --git a/src/main/webapp/formdefinitions/resetPasswordForm.json b/src/main/webapp/formdefinitions/resetPasswordForm.json index 024d351b8f5291e5cceb7b2fa13f3d9ba4f9b733..52486af534d6a4f6c4dde4675ac4ac8351cc790f 100755 --- a/src/main/webapp/formdefinitions/resetPasswordForm.json +++ b/src/main/webapp/formdefinitions/resetPasswordForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the resetPasswordForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/resetPasswordRequestForm.json b/src/main/webapp/formdefinitions/resetPasswordRequestForm.json index ded4cc3214d8b4a07e563a69da3061c6a9c4c471..ae2d963d954ad9b47949d711445a179bd17813dd 100755 --- a/src/main/webapp/formdefinitions/resetPasswordRequestForm.json +++ b/src/main/webapp/formdefinitions/resetPasswordRequestForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the resetPasswordRequestForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/taskHistoryDateForm.json b/src/main/webapp/formdefinitions/taskHistoryDateForm.json index 2f9f8ac17acd908a308d41e3ccde8a9864a94f0c..3f89913a55e81cbe0299b34225cb9bd18c8c6d4f 100755 --- a/src/main/webapp/formdefinitions/taskHistoryDateForm.json +++ b/src/main/webapp/formdefinitions/taskHistoryDateForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the taskHistoryDateForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/userForm.json b/src/main/webapp/formdefinitions/userForm.json index 93cf962af0c38bad288dfa9f8e60358b97d1c661..f727874a739c96cd94e5fa28442df8d1b16558bc 100755 --- a/src/main/webapp/formdefinitions/userForm.json +++ b/src/main/webapp/formdefinitions/userForm.json @@ -2,19 +2,19 @@ "_licenseNote": [ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", - "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the userForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/userRegistrationFormType1.json b/src/main/webapp/formdefinitions/userRegistrationFormType1.json index 04f7d313942f974f9da3604d54839e73f6599723..4ab7675ea40118d7ab5c555ada284020e7ff63ea 100755 --- a/src/main/webapp/formdefinitions/userRegistrationFormType1.json +++ b/src/main/webapp/formdefinitions/userRegistrationFormType1.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the userRegistrationForm and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/userRegistrationFormType2.json b/src/main/webapp/formdefinitions/userRegistrationFormType2.json index 2a1f9fb40a6b628f8adaea2e4fc8579329a4e888..e658e4e032bd411ed50af571a8aa71d6bb93c444 100755 --- a/src/main/webapp/formdefinitions/userRegistrationFormType2.json +++ b/src/main/webapp/formdefinitions/userRegistrationFormType2.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the userRegistrationForm for OpenId and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/userRegistrationFormType3.json b/src/main/webapp/formdefinitions/userRegistrationFormType3.json index 3b44022994b90acde404fbb5a82639094b3b506a..27c0f5ca5bfa98f48ada095177736e3a143d3be0 100755 --- a/src/main/webapp/formdefinitions/userRegistrationFormType3.json +++ b/src/main/webapp/formdefinitions/userRegistrationFormType3.json @@ -3,18 +3,19 @@ "Copyright (c) 2014 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the userRegistrationForm for GoogleId and how to validate it", "fields": [ diff --git a/src/main/webapp/formdefinitions/weatherStationDataSourceForm.json b/src/main/webapp/formdefinitions/weatherStationDataSourceForm.json new file mode 100644 index 0000000000000000000000000000000000000000..35cf480345f1f784dba1cd19c2b555b553245fbe --- /dev/null +++ b/src/main/webapp/formdefinitions/weatherStationDataSourceForm.json @@ -0,0 +1,59 @@ +{ + "_licenseNote": [ + "Copyright (c) 2024 NIBIO <http://www.nibio.no/>. ", + "", + "This file is part of VIPSLogic. ", + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." + ], + "_comment" : "Structure of the organizationForm and how to validate it", + "fields": [ + { + "name" : "weatherStationDataSourceId", + "dataType" : "INTEGER", + "required" : true + }, + { + "name" : "name", + "dataType" : "STRING", + "required" : true + }, + { + "name" : "defaultDescription", + "dataType" : "STRING", + "required" : false + }, + { + "name" : "uri", + "dataType" : "STRING", + "required" : false + }, + { + "name" : "datafetchUriExpression", + "dataType" : "STRING", + "required" : true + }, + { + "name" : "infoUriExpression", + "dataType" : "STRING", + "required" : false + }, + { + "name" : "isGrid", + "dataType" : "STRING", + "required" : false + } + + ] +} diff --git a/src/main/webapp/formdefinitions/weatherStationForm.json b/src/main/webapp/formdefinitions/weatherStationForm.json index 1bc2f92be78d4c23f1a599bada42d9b7102684ba..3b0af8f3afed9554273194d7592f241735cbd4c0 100755 --- a/src/main/webapp/formdefinitions/weatherStationForm.json +++ b/src/main/webapp/formdefinitions/weatherStationForm.json @@ -3,18 +3,19 @@ "Copyright (c) 2014-2015 NIBIO <http://www.nibio.no/>. ", "", "This file is part of VIPSLogic. ", - "VIPSLogic is free software: you can redistribute it and/or modify ", - "it under the terms of the NIBIO Open Source License as published by ", - "NIBIO, either version 1 of the License, or (at your option) any ", - "later version. ", - "", - "VIPSLogic 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 ", - "NIBIO Open Source License for more details. ", - "", - "You should have received a copy of the NIBIO Open Source License ", - "along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. " + + "This program is free software: you can redistribute it and/or modify", + "it under the terms of the GNU Affero General Public License as published by", + "the Free Software Foundation, either version 3 of the License, or", + "(at your option) any later version.", + + "This program is distributed in the hope that it will be useful,", + "but WITHOUT ANY WARRANTY; without even the implied warranty of", + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the", + "GNU Affero General Public License for more details.", + + "You should have received a copy of the GNU Affero General Public License", + "along with this program. If not, see <https://www.gnu.org/licenses/>." ], "_comment" : "Structure of the weatherStationForm and how to validate it", "fields": [ @@ -86,6 +87,11 @@ "dataType" : "STRING", "fieldType" : "MULTIPLE_MAP", "required" : false + }, + { + "name" : "isPrivate", + "dataType" : "STRING", + "required" : false } ] diff --git a/src/main/webapp/images/modules/barkbeetle/Instruks_Barkbillefylkeskontakter_2024-03-04.pdf b/src/main/webapp/images/modules/barkbeetle/Instruks_Barkbillefylkeskontakter_2024-03-04.pdf new file mode 100644 index 0000000000000000000000000000000000000000..040c7a8215a395e3a9adb18931b457fbba31edc1 Binary files /dev/null and b/src/main/webapp/images/modules/barkbeetle/Instruks_Barkbillefylkeskontakter_2024-03-04.pdf differ diff --git a/src/main/webapp/images/modules/barkbeetle/Instruks_registranter_i_Barkbilleovervakingen_2024-03-04.pdf b/src/main/webapp/images/modules/barkbeetle/Instruks_registranter_i_Barkbilleovervakingen_2024-03-04.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b2ab7a14f391155523352ea927e408bb050bfb63 Binary files /dev/null and b/src/main/webapp/images/modules/barkbeetle/Instruks_registranter_i_Barkbilleovervakingen_2024-03-04.pdf differ diff --git a/src/main/webapp/images/modules/barkbeetle/Instruks_registranter_i_Barkbilleovervakingen_2024-04-03.pdf b/src/main/webapp/images/modules/barkbeetle/Instruks_registranter_i_Barkbilleovervakingen_2024-04-03.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e8c2c65b190d05af711ac1f8f94af176201b74ff Binary files /dev/null and b/src/main/webapp/images/modules/barkbeetle/Instruks_registranter_i_Barkbilleovervakingen_2024-04-03.pdf differ diff --git a/src/main/webapp/images/modules/barkbeetle/station_icon_status_4.png b/src/main/webapp/images/modules/barkbeetle/station_icon_status_4.png index eee31a93463aeb8f12fe17e4dc902afa73e94db9..b44d305c92ba27bf57b1dbaac811a1c795d7824b 100644 Binary files a/src/main/webapp/images/modules/barkbeetle/station_icon_status_4.png and b/src/main/webapp/images/modules/barkbeetle/station_icon_status_4.png differ diff --git a/src/main/webapp/images/modules/barkbeetle/station_icon_status_5.png b/src/main/webapp/images/modules/barkbeetle/station_icon_status_5.png index d3917dde739cedaae94ba3d60dd67825eb379bee..eee31a93463aeb8f12fe17e4dc902afa73e94db9 100644 Binary files a/src/main/webapp/images/modules/barkbeetle/station_icon_status_5.png and b/src/main/webapp/images/modules/barkbeetle/station_icon_status_5.png differ diff --git a/src/main/webapp/js/3rdparty/leaflet-src.esm.js b/src/main/webapp/js/3rdparty/leaflet-src.esm.js new file mode 100644 index 0000000000000000000000000000000000000000..8f91d5ddfc78ef05576efd425aac920040a28c94 --- /dev/null +++ b/src/main/webapp/js/3rdparty/leaflet-src.esm.js @@ -0,0 +1,14419 @@ +/* @preserve + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ + +var version = "1.9.4"; + +/* + * @namespace Util + * + * Various utility functions, used by Leaflet internally. + */ + +// @function extend(dest: Object, src?: Object): Object +// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut. +function extend(dest) { + var i, j, len, src; + + for (j = 1, len = arguments.length; j < len; j++) { + src = arguments[j]; + for (i in src) { + dest[i] = src[i]; + } + } + return dest; +} + +// @function create(proto: Object, properties?: Object): Object +// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create) +var create$2 = Object.create || (function () { + function F() {} + return function (proto) { + F.prototype = proto; + return new F(); + }; +})(); + +// @function bind(fn: Function, …): Function +// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). +// Has a `L.bind()` shortcut. +function bind(fn, obj) { + var slice = Array.prototype.slice; + + if (fn.bind) { + return fn.bind.apply(fn, slice.call(arguments, 1)); + } + + var args = slice.call(arguments, 2); + + return function () { + return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments); + }; +} + +// @property lastId: Number +// Last unique ID used by [`stamp()`](#util-stamp) +var lastId = 0; + +// @function stamp(obj: Object): Number +// Returns the unique ID of an object, assigning it one if it doesn't have it. +function stamp(obj) { + if (!('_leaflet_id' in obj)) { + obj['_leaflet_id'] = ++lastId; + } + return obj._leaflet_id; +} + +// @function throttle(fn: Function, time: Number, context: Object): Function +// Returns a function which executes function `fn` with the given scope `context` +// (so that the `this` keyword refers to `context` inside `fn`'s code). The function +// `fn` will be called no more than one time per given amount of `time`. The arguments +// received by the bound function will be any arguments passed when binding the +// function, followed by any arguments passed when invoking the bound function. +// Has an `L.throttle` shortcut. +function throttle(fn, time, context) { + var lock, args, wrapperFn, later; + + later = function () { + // reset lock and call if queued + lock = false; + if (args) { + wrapperFn.apply(context, args); + args = false; + } + }; + + wrapperFn = function () { + if (lock) { + // called too soon, queue to call later + args = arguments; + + } else { + // call and lock until later + fn.apply(context, arguments); + setTimeout(later, time); + lock = true; + } + }; + + return wrapperFn; +} + +// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number +// Returns the number `num` modulo `range` in such a way so it lies within +// `range[0]` and `range[1]`. The returned value will be always smaller than +// `range[1]` unless `includeMax` is set to `true`. +function wrapNum(x, range, includeMax) { + var max = range[1], + min = range[0], + d = max - min; + return x === max && includeMax ? x : ((x - min) % d + d) % d + min; +} + +// @function falseFn(): Function +// Returns a function which always returns `false`. +function falseFn() { return false; } + +// @function formatNum(num: Number, precision?: Number|false): Number +// Returns the number `num` rounded with specified `precision`. +// The default `precision` value is 6 decimal places. +// `false` can be passed to skip any processing (can be useful to avoid round-off errors). +function formatNum(num, precision) { + if (precision === false) { return num; } + var pow = Math.pow(10, precision === undefined ? 6 : precision); + return Math.round(num * pow) / pow; +} + +// @function trim(str: String): String +// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) +function trim(str) { + return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); +} + +// @function splitWords(str: String): String[] +// Trims and splits the string on whitespace and returns the array of parts. +function splitWords(str) { + return trim(str).split(/\s+/); +} + +// @function setOptions(obj: Object, options: Object): Object +// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut. +function setOptions(obj, options) { + if (!Object.prototype.hasOwnProperty.call(obj, 'options')) { + obj.options = obj.options ? create$2(obj.options) : {}; + } + for (var i in options) { + obj.options[i] = options[i]; + } + return obj.options; +} + +// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String +// Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}` +// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will +// be appended at the end. If `uppercase` is `true`, the parameter names will +// be uppercased (e.g. `'?A=foo&B=bar'`) +function getParamString(obj, existingUrl, uppercase) { + var params = []; + for (var i in obj) { + params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); + } + return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); +} + +var templateRe = /\{ *([\w_ -]+) *\}/g; + +// @function template(str: String, data: Object): String +// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'` +// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string +// `('Hello foo, bar')`. You can also specify functions instead of strings for +// data values — they will be evaluated passing `data` as an argument. +function template(str, data) { + return str.replace(templateRe, function (str, key) { + var value = data[key]; + + if (value === undefined) { + throw new Error('No value provided for variable ' + str); + + } else if (typeof value === 'function') { + value = value(data); + } + return value; + }); +} + +// @function isArray(obj): Boolean +// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) +var isArray = Array.isArray || function (obj) { + return (Object.prototype.toString.call(obj) === '[object Array]'); +}; + +// @function indexOf(array: Array, el: Object): Number +// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) +function indexOf(array, el) { + for (var i = 0; i < array.length; i++) { + if (array[i] === el) { return i; } + } + return -1; +} + +// @property emptyImageUrl: String +// Data URI string containing a base64-encoded empty GIF image. +// Used as a hack to free memory from unused images on WebKit-powered +// mobile devices (by setting image `src` to this string). +var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + +// inspired by https://paulirish.com/2011/requestanimationframe-for-smart-animating/ + +function getPrefixed(name) { + return window['webkit' + name] || window['moz' + name] || window['ms' + name]; +} + +var lastTime = 0; + +// fallback for IE 7-8 +function timeoutDefer(fn) { + var time = +new Date(), + timeToCall = Math.max(0, 16 - (time - lastTime)); + + lastTime = time + timeToCall; + return window.setTimeout(fn, timeToCall); +} + +var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer; +var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') || + getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); }; + +// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number +// Schedules `fn` to be executed when the browser repaints. `fn` is bound to +// `context` if given. When `immediate` is set, `fn` is called immediately if +// the browser doesn't have native support for +// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame), +// otherwise it's delayed. Returns a request ID that can be used to cancel the request. +function requestAnimFrame(fn, context, immediate) { + if (immediate && requestFn === timeoutDefer) { + fn.call(context); + } else { + return requestFn.call(window, bind(fn, context)); + } +} + +// @function cancelAnimFrame(id: Number): undefined +// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame). +function cancelAnimFrame(id) { + if (id) { + cancelFn.call(window, id); + } +} + +var Util = { + __proto__: null, + extend: extend, + create: create$2, + bind: bind, + get lastId () { return lastId; }, + stamp: stamp, + throttle: throttle, + wrapNum: wrapNum, + falseFn: falseFn, + formatNum: formatNum, + trim: trim, + splitWords: splitWords, + setOptions: setOptions, + getParamString: getParamString, + template: template, + isArray: isArray, + indexOf: indexOf, + emptyImageUrl: emptyImageUrl, + requestFn: requestFn, + cancelFn: cancelFn, + requestAnimFrame: requestAnimFrame, + cancelAnimFrame: cancelAnimFrame +}; + +// @class Class +// @aka L.Class + +// @section +// @uninheritable + +// Thanks to John Resig and Dean Edwards for inspiration! + +function Class() {} + +Class.extend = function (props) { + + // @function extend(props: Object): Function + // [Extends the current class](#class-inheritance) given the properties to be included. + // Returns a Javascript function that is a class constructor (to be called with `new`). + var NewClass = function () { + + setOptions(this); + + // call the constructor + if (this.initialize) { + this.initialize.apply(this, arguments); + } + + // call all constructor hooks + this.callInitHooks(); + }; + + var parentProto = NewClass.__super__ = this.prototype; + + var proto = create$2(parentProto); + proto.constructor = NewClass; + + NewClass.prototype = proto; + + // inherit parent's statics + for (var i in this) { + if (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') { + NewClass[i] = this[i]; + } + } + + // mix static properties into the class + if (props.statics) { + extend(NewClass, props.statics); + } + + // mix includes into the prototype + if (props.includes) { + checkDeprecatedMixinEvents(props.includes); + extend.apply(null, [proto].concat(props.includes)); + } + + // mix given properties into the prototype + extend(proto, props); + delete proto.statics; + delete proto.includes; + + // merge options + if (proto.options) { + proto.options = parentProto.options ? create$2(parentProto.options) : {}; + extend(proto.options, props.options); + } + + proto._initHooks = []; + + // add method for calling all hooks + proto.callInitHooks = function () { + + if (this._initHooksCalled) { return; } + + if (parentProto.callInitHooks) { + parentProto.callInitHooks.call(this); + } + + this._initHooksCalled = true; + + for (var i = 0, len = proto._initHooks.length; i < len; i++) { + proto._initHooks[i].call(this); + } + }; + + return NewClass; +}; + + +// @function include(properties: Object): this +// [Includes a mixin](#class-includes) into the current class. +Class.include = function (props) { + var parentOptions = this.prototype.options; + extend(this.prototype, props); + if (props.options) { + this.prototype.options = parentOptions; + this.mergeOptions(props.options); + } + return this; +}; + +// @function mergeOptions(options: Object): this +// [Merges `options`](#class-options) into the defaults of the class. +Class.mergeOptions = function (options) { + extend(this.prototype.options, options); + return this; +}; + +// @function addInitHook(fn: Function): this +// Adds a [constructor hook](#class-constructor-hooks) to the class. +Class.addInitHook = function (fn) { // (Function) || (String, args...) + var args = Array.prototype.slice.call(arguments, 1); + + var init = typeof fn === 'function' ? fn : function () { + this[fn].apply(this, args); + }; + + this.prototype._initHooks = this.prototype._initHooks || []; + this.prototype._initHooks.push(init); + return this; +}; + +function checkDeprecatedMixinEvents(includes) { + /* global L: true */ + if (typeof L === 'undefined' || !L || !L.Mixin) { return; } + + includes = isArray(includes) ? includes : [includes]; + + for (var i = 0; i < includes.length; i++) { + if (includes[i] === L.Mixin.Events) { + console.warn('Deprecated include of L.Mixin.Events: ' + + 'this property will be removed in future releases, ' + + 'please inherit from L.Evented instead.', new Error().stack); + } + } +} + +/* + * @class Evented + * @aka L.Evented + * @inherits Class + * + * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event). + * + * @example + * + * ```js + * map.on('click', function(e) { + * alert(e.latlng); + * } ); + * ``` + * + * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function: + * + * ```js + * function onClick(e) { ... } + * + * map.on('click', onClick); + * map.off('click', onClick); + * ``` + */ + +var Events = { + /* @method on(type: String, fn: Function, context?: Object): this + * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`). + * + * @alternative + * @method on(eventMap: Object): this + * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` + */ + on: function (types, fn, context) { + + // types can be a map of types/handlers + if (typeof types === 'object') { + for (var type in types) { + // we don't process space-separated events here for performance; + // it's a hot path since Layer uses the on(obj) syntax + this._on(type, types[type], fn); + } + + } else { + // types can be a string of space-separated words + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + this._on(types[i], fn, context); + } + } + + return this; + }, + + /* @method off(type: String, fn?: Function, context?: Object): this + * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener. + * + * @alternative + * @method off(eventMap: Object): this + * Removes a set of type/listener pairs. + * + * @alternative + * @method off: this + * Removes all listeners to all events on the object. This includes implicitly attached events. + */ + off: function (types, fn, context) { + + if (!arguments.length) { + // clear all listeners if called without arguments + delete this._events; + + } else if (typeof types === 'object') { + for (var type in types) { + this._off(type, types[type], fn); + } + + } else { + types = splitWords(types); + + var removeAll = arguments.length === 1; + for (var i = 0, len = types.length; i < len; i++) { + if (removeAll) { + this._off(types[i]); + } else { + this._off(types[i], fn, context); + } + } + } + + return this; + }, + + // attach listener (without syntactic sugar now) + _on: function (type, fn, context, _once) { + if (typeof fn !== 'function') { + console.warn('wrong listener type: ' + typeof fn); + return; + } + + // check if fn already there + if (this._listens(type, fn, context) !== false) { + return; + } + + if (context === this) { + // Less memory footprint. + context = undefined; + } + + var newListener = {fn: fn, ctx: context}; + if (_once) { + newListener.once = true; + } + + this._events = this._events || {}; + this._events[type] = this._events[type] || []; + this._events[type].push(newListener); + }, + + _off: function (type, fn, context) { + var listeners, + i, + len; + + if (!this._events) { + return; + } + + listeners = this._events[type]; + if (!listeners) { + return; + } + + if (arguments.length === 1) { // remove all + if (this._firingCount) { + // Set all removed listeners to noop + // so they are not called if remove happens in fire + for (i = 0, len = listeners.length; i < len; i++) { + listeners[i].fn = falseFn; + } + } + // clear all listeners for a type if function isn't specified + delete this._events[type]; + return; + } + + if (typeof fn !== 'function') { + console.warn('wrong listener type: ' + typeof fn); + return; + } + + // find fn and remove it + var index = this._listens(type, fn, context); + if (index !== false) { + var listener = listeners[index]; + if (this._firingCount) { + // set the removed listener to noop so that's not called if remove happens in fire + listener.fn = falseFn; + + /* copy array in case events are being fired */ + this._events[type] = listeners = listeners.slice(); + } + listeners.splice(index, 1); + } + }, + + // @method fire(type: String, data?: Object, propagate?: Boolean): this + // Fires an event of the specified type. You can optionally provide a data + // object — the first argument of the listener function will contain its + // properties. The event can optionally be propagated to event parents. + fire: function (type, data, propagate) { + if (!this.listens(type, propagate)) { return this; } + + var event = extend({}, data, { + type: type, + target: this, + sourceTarget: data && data.sourceTarget || this + }); + + if (this._events) { + var listeners = this._events[type]; + if (listeners) { + this._firingCount = (this._firingCount + 1) || 1; + for (var i = 0, len = listeners.length; i < len; i++) { + var l = listeners[i]; + // off overwrites l.fn, so we need to copy fn to a var + var fn = l.fn; + if (l.once) { + this.off(type, fn, l.ctx); + } + fn.call(l.ctx || this, event); + } + + this._firingCount--; + } + } + + if (propagate) { + // propagate the event to parents (set with addEventParent) + this._propagateEvent(event); + } + + return this; + }, + + // @method listens(type: String, propagate?: Boolean): Boolean + // @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean + // Returns `true` if a particular event type has any listeners attached to it. + // The verification can optionally be propagated, it will return `true` if parents have the listener attached to it. + listens: function (type, fn, context, propagate) { + if (typeof type !== 'string') { + console.warn('"string" type argument expected'); + } + + // we don't overwrite the input `fn` value, because we need to use it for propagation + var _fn = fn; + if (typeof fn !== 'function') { + propagate = !!fn; + _fn = undefined; + context = undefined; + } + + var listeners = this._events && this._events[type]; + if (listeners && listeners.length) { + if (this._listens(type, _fn, context) !== false) { + return true; + } + } + + if (propagate) { + // also check parents for listeners if event propagates + for (var id in this._eventParents) { + if (this._eventParents[id].listens(type, fn, context, propagate)) { return true; } + } + } + return false; + }, + + // returns the index (number) or false + _listens: function (type, fn, context) { + if (!this._events) { + return false; + } + + var listeners = this._events[type] || []; + if (!fn) { + return !!listeners.length; + } + + if (context === this) { + // Less memory footprint. + context = undefined; + } + + for (var i = 0, len = listeners.length; i < len; i++) { + if (listeners[i].fn === fn && listeners[i].ctx === context) { + return i; + } + } + return false; + + }, + + // @method once(…): this + // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed. + once: function (types, fn, context) { + + // types can be a map of types/handlers + if (typeof types === 'object') { + for (var type in types) { + // we don't process space-separated events here for performance; + // it's a hot path since Layer uses the on(obj) syntax + this._on(type, types[type], fn, true); + } + + } else { + // types can be a string of space-separated words + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + this._on(types[i], fn, context, true); + } + } + + return this; + }, + + // @method addEventParent(obj: Evented): this + // Adds an event parent - an `Evented` that will receive propagated events + addEventParent: function (obj) { + this._eventParents = this._eventParents || {}; + this._eventParents[stamp(obj)] = obj; + return this; + }, + + // @method removeEventParent(obj: Evented): this + // Removes an event parent, so it will stop receiving propagated events + removeEventParent: function (obj) { + if (this._eventParents) { + delete this._eventParents[stamp(obj)]; + } + return this; + }, + + _propagateEvent: function (e) { + for (var id in this._eventParents) { + this._eventParents[id].fire(e.type, extend({ + layer: e.target, + propagatedFrom: e.target + }, e), true); + } + } +}; + +// aliases; we should ditch those eventually + +// @method addEventListener(…): this +// Alias to [`on(…)`](#evented-on) +Events.addEventListener = Events.on; + +// @method removeEventListener(…): this +// Alias to [`off(…)`](#evented-off) + +// @method clearAllEventListeners(…): this +// Alias to [`off()`](#evented-off) +Events.removeEventListener = Events.clearAllEventListeners = Events.off; + +// @method addOneTimeEventListener(…): this +// Alias to [`once(…)`](#evented-once) +Events.addOneTimeEventListener = Events.once; + +// @method fireEvent(…): this +// Alias to [`fire(…)`](#evented-fire) +Events.fireEvent = Events.fire; + +// @method hasEventListeners(…): Boolean +// Alias to [`listens(…)`](#evented-listens) +Events.hasEventListeners = Events.listens; + +var Evented = Class.extend(Events); + +/* + * @class Point + * @aka L.Point + * + * Represents a point with `x` and `y` coordinates in pixels. + * + * @example + * + * ```js + * var point = L.point(200, 300); + * ``` + * + * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent: + * + * ```js + * map.panBy([200, 300]); + * map.panBy(L.point(200, 300)); + * ``` + * + * Note that `Point` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function Point(x, y, round) { + // @property x: Number; The `x` coordinate of the point + this.x = (round ? Math.round(x) : x); + // @property y: Number; The `y` coordinate of the point + this.y = (round ? Math.round(y) : y); +} + +var trunc = Math.trunc || function (v) { + return v > 0 ? Math.floor(v) : Math.ceil(v); +}; + +Point.prototype = { + + // @method clone(): Point + // Returns a copy of the current point. + clone: function () { + return new Point(this.x, this.y); + }, + + // @method add(otherPoint: Point): Point + // Returns the result of addition of the current and the given points. + add: function (point) { + // non-destructive, returns a new point + return this.clone()._add(toPoint(point)); + }, + + _add: function (point) { + // destructive, used directly for performance in situations where it's safe to modify existing point + this.x += point.x; + this.y += point.y; + return this; + }, + + // @method subtract(otherPoint: Point): Point + // Returns the result of subtraction of the given point from the current. + subtract: function (point) { + return this.clone()._subtract(toPoint(point)); + }, + + _subtract: function (point) { + this.x -= point.x; + this.y -= point.y; + return this; + }, + + // @method divideBy(num: Number): Point + // Returns the result of division of the current point by the given number. + divideBy: function (num) { + return this.clone()._divideBy(num); + }, + + _divideBy: function (num) { + this.x /= num; + this.y /= num; + return this; + }, + + // @method multiplyBy(num: Number): Point + // Returns the result of multiplication of the current point by the given number. + multiplyBy: function (num) { + return this.clone()._multiplyBy(num); + }, + + _multiplyBy: function (num) { + this.x *= num; + this.y *= num; + return this; + }, + + // @method scaleBy(scale: Point): Point + // Multiply each coordinate of the current point by each coordinate of + // `scale`. In linear algebra terms, multiply the point by the + // [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation) + // defined by `scale`. + scaleBy: function (point) { + return new Point(this.x * point.x, this.y * point.y); + }, + + // @method unscaleBy(scale: Point): Point + // Inverse of `scaleBy`. Divide each coordinate of the current point by + // each coordinate of `scale`. + unscaleBy: function (point) { + return new Point(this.x / point.x, this.y / point.y); + }, + + // @method round(): Point + // Returns a copy of the current point with rounded coordinates. + round: function () { + return this.clone()._round(); + }, + + _round: function () { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + }, + + // @method floor(): Point + // Returns a copy of the current point with floored coordinates (rounded down). + floor: function () { + return this.clone()._floor(); + }, + + _floor: function () { + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + return this; + }, + + // @method ceil(): Point + // Returns a copy of the current point with ceiled coordinates (rounded up). + ceil: function () { + return this.clone()._ceil(); + }, + + _ceil: function () { + this.x = Math.ceil(this.x); + this.y = Math.ceil(this.y); + return this; + }, + + // @method trunc(): Point + // Returns a copy of the current point with truncated coordinates (rounded towards zero). + trunc: function () { + return this.clone()._trunc(); + }, + + _trunc: function () { + this.x = trunc(this.x); + this.y = trunc(this.y); + return this; + }, + + // @method distanceTo(otherPoint: Point): Number + // Returns the cartesian distance between the current and the given points. + distanceTo: function (point) { + point = toPoint(point); + + var x = point.x - this.x, + y = point.y - this.y; + + return Math.sqrt(x * x + y * y); + }, + + // @method equals(otherPoint: Point): Boolean + // Returns `true` if the given point has the same coordinates. + equals: function (point) { + point = toPoint(point); + + return point.x === this.x && + point.y === this.y; + }, + + // @method contains(otherPoint: Point): Boolean + // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values). + contains: function (point) { + point = toPoint(point); + + return Math.abs(point.x) <= Math.abs(this.x) && + Math.abs(point.y) <= Math.abs(this.y); + }, + + // @method toString(): String + // Returns a string representation of the point for debugging purposes. + toString: function () { + return 'Point(' + + formatNum(this.x) + ', ' + + formatNum(this.y) + ')'; + } +}; + +// @factory L.point(x: Number, y: Number, round?: Boolean) +// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values. + +// @alternative +// @factory L.point(coords: Number[]) +// Expects an array of the form `[x, y]` instead. + +// @alternative +// @factory L.point(coords: Object) +// Expects a plain object of the form `{x: Number, y: Number}` instead. +function toPoint(x, y, round) { + if (x instanceof Point) { + return x; + } + if (isArray(x)) { + return new Point(x[0], x[1]); + } + if (x === undefined || x === null) { + return x; + } + if (typeof x === 'object' && 'x' in x && 'y' in x) { + return new Point(x.x, x.y); + } + return new Point(x, y, round); +} + +/* + * @class Bounds + * @aka L.Bounds + * + * Represents a rectangular area in pixel coordinates. + * + * @example + * + * ```js + * var p1 = L.point(10, 10), + * p2 = L.point(40, 60), + * bounds = L.bounds(p1, p2); + * ``` + * + * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: + * + * ```js + * otherBounds.intersects([[10, 10], [40, 60]]); + * ``` + * + * Note that `Bounds` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function Bounds(a, b) { + if (!a) { return; } + + var points = b ? [a, b] : a; + + for (var i = 0, len = points.length; i < len; i++) { + this.extend(points[i]); + } +} + +Bounds.prototype = { + // @method extend(point: Point): this + // Extends the bounds to contain the given point. + + // @alternative + // @method extend(otherBounds: Bounds): this + // Extend the bounds to contain the given bounds + extend: function (obj) { + var min2, max2; + if (!obj) { return this; } + + if (obj instanceof Point || typeof obj[0] === 'number' || 'x' in obj) { + min2 = max2 = toPoint(obj); + } else { + obj = toBounds(obj); + min2 = obj.min; + max2 = obj.max; + + if (!min2 || !max2) { return this; } + } + + // @property min: Point + // The top left corner of the rectangle. + // @property max: Point + // The bottom right corner of the rectangle. + if (!this.min && !this.max) { + this.min = min2.clone(); + this.max = max2.clone(); + } else { + this.min.x = Math.min(min2.x, this.min.x); + this.max.x = Math.max(max2.x, this.max.x); + this.min.y = Math.min(min2.y, this.min.y); + this.max.y = Math.max(max2.y, this.max.y); + } + return this; + }, + + // @method getCenter(round?: Boolean): Point + // Returns the center point of the bounds. + getCenter: function (round) { + return toPoint( + (this.min.x + this.max.x) / 2, + (this.min.y + this.max.y) / 2, round); + }, + + // @method getBottomLeft(): Point + // Returns the bottom-left point of the bounds. + getBottomLeft: function () { + return toPoint(this.min.x, this.max.y); + }, + + // @method getTopRight(): Point + // Returns the top-right point of the bounds. + getTopRight: function () { // -> Point + return toPoint(this.max.x, this.min.y); + }, + + // @method getTopLeft(): Point + // Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)). + getTopLeft: function () { + return this.min; // left, top + }, + + // @method getBottomRight(): Point + // Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)). + getBottomRight: function () { + return this.max; // right, bottom + }, + + // @method getSize(): Point + // Returns the size of the given bounds + getSize: function () { + return this.max.subtract(this.min); + }, + + // @method contains(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle contains the given one. + // @alternative + // @method contains(point: Point): Boolean + // Returns `true` if the rectangle contains the given point. + contains: function (obj) { + var min, max; + + if (typeof obj[0] === 'number' || obj instanceof Point) { + obj = toPoint(obj); + } else { + obj = toBounds(obj); + } + + if (obj instanceof Bounds) { + min = obj.min; + max = obj.max; + } else { + min = max = obj; + } + + return (min.x >= this.min.x) && + (max.x <= this.max.x) && + (min.y >= this.min.y) && + (max.y <= this.max.y); + }, + + // @method intersects(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle intersects the given bounds. Two bounds + // intersect if they have at least one point in common. + intersects: function (bounds) { // (Bounds) -> Boolean + bounds = toBounds(bounds); + + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max, + xIntersects = (max2.x >= min.x) && (min2.x <= max.x), + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); + + return xIntersects && yIntersects; + }, + + // @method overlaps(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle overlaps the given bounds. Two bounds + // overlap if their intersection is an area. + overlaps: function (bounds) { // (Bounds) -> Boolean + bounds = toBounds(bounds); + + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max, + xOverlaps = (max2.x > min.x) && (min2.x < max.x), + yOverlaps = (max2.y > min.y) && (min2.y < max.y); + + return xOverlaps && yOverlaps; + }, + + // @method isValid(): Boolean + // Returns `true` if the bounds are properly initialized. + isValid: function () { + return !!(this.min && this.max); + }, + + + // @method pad(bufferRatio: Number): Bounds + // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction. + // For example, a ratio of 0.5 extends the bounds by 50% in each direction. + // Negative values will retract the bounds. + pad: function (bufferRatio) { + var min = this.min, + max = this.max, + heightBuffer = Math.abs(min.x - max.x) * bufferRatio, + widthBuffer = Math.abs(min.y - max.y) * bufferRatio; + + + return toBounds( + toPoint(min.x - heightBuffer, min.y - widthBuffer), + toPoint(max.x + heightBuffer, max.y + widthBuffer)); + }, + + + // @method equals(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle is equivalent to the given bounds. + equals: function (bounds) { + if (!bounds) { return false; } + + bounds = toBounds(bounds); + + return this.min.equals(bounds.getTopLeft()) && + this.max.equals(bounds.getBottomRight()); + }, +}; + + +// @factory L.bounds(corner1: Point, corner2: Point) +// Creates a Bounds object from two corners coordinate pairs. +// @alternative +// @factory L.bounds(points: Point[]) +// Creates a Bounds object from the given array of points. +function toBounds(a, b) { + if (!a || a instanceof Bounds) { + return a; + } + return new Bounds(a, b); +} + +/* + * @class LatLngBounds + * @aka L.LatLngBounds + * + * Represents a rectangular geographical area on a map. + * + * @example + * + * ```js + * var corner1 = L.latLng(40.712, -74.227), + * corner2 = L.latLng(40.774, -74.125), + * bounds = L.latLngBounds(corner1, corner2); + * ``` + * + * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: + * + * ```js + * map.fitBounds([ + * [40.712, -74.227], + * [40.774, -74.125] + * ]); + * ``` + * + * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range. + * + * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[]) + if (!corner1) { return; } + + var latlngs = corner2 ? [corner1, corner2] : corner1; + + for (var i = 0, len = latlngs.length; i < len; i++) { + this.extend(latlngs[i]); + } +} + +LatLngBounds.prototype = { + + // @method extend(latlng: LatLng): this + // Extend the bounds to contain the given point + + // @alternative + // @method extend(otherBounds: LatLngBounds): this + // Extend the bounds to contain the given bounds + extend: function (obj) { + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof LatLng) { + sw2 = obj; + ne2 = obj; + + } else if (obj instanceof LatLngBounds) { + sw2 = obj._southWest; + ne2 = obj._northEast; + + if (!sw2 || !ne2) { return this; } + + } else { + return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this; + } + + if (!sw && !ne) { + this._southWest = new LatLng(sw2.lat, sw2.lng); + this._northEast = new LatLng(ne2.lat, ne2.lng); + } else { + sw.lat = Math.min(sw2.lat, sw.lat); + sw.lng = Math.min(sw2.lng, sw.lng); + ne.lat = Math.max(ne2.lat, ne.lat); + ne.lng = Math.max(ne2.lng, ne.lng); + } + + return this; + }, + + // @method pad(bufferRatio: Number): LatLngBounds + // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction. + // For example, a ratio of 0.5 extends the bounds by 50% in each direction. + // Negative values will retract the bounds. + pad: function (bufferRatio) { + var sw = this._southWest, + ne = this._northEast, + heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, + widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; + + return new LatLngBounds( + new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), + new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); + }, + + // @method getCenter(): LatLng + // Returns the center point of the bounds. + getCenter: function () { + return new LatLng( + (this._southWest.lat + this._northEast.lat) / 2, + (this._southWest.lng + this._northEast.lng) / 2); + }, + + // @method getSouthWest(): LatLng + // Returns the south-west point of the bounds. + getSouthWest: function () { + return this._southWest; + }, + + // @method getNorthEast(): LatLng + // Returns the north-east point of the bounds. + getNorthEast: function () { + return this._northEast; + }, + + // @method getNorthWest(): LatLng + // Returns the north-west point of the bounds. + getNorthWest: function () { + return new LatLng(this.getNorth(), this.getWest()); + }, + + // @method getSouthEast(): LatLng + // Returns the south-east point of the bounds. + getSouthEast: function () { + return new LatLng(this.getSouth(), this.getEast()); + }, + + // @method getWest(): Number + // Returns the west longitude of the bounds + getWest: function () { + return this._southWest.lng; + }, + + // @method getSouth(): Number + // Returns the south latitude of the bounds + getSouth: function () { + return this._southWest.lat; + }, + + // @method getEast(): Number + // Returns the east longitude of the bounds + getEast: function () { + return this._northEast.lng; + }, + + // @method getNorth(): Number + // Returns the north latitude of the bounds + getNorth: function () { + return this._northEast.lat; + }, + + // @method contains(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle contains the given one. + + // @alternative + // @method contains (latlng: LatLng): Boolean + // Returns `true` if the rectangle contains the given point. + contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean + if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) { + obj = toLatLng(obj); + } else { + obj = toLatLngBounds(obj); + } + + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof LatLngBounds) { + sw2 = obj.getSouthWest(); + ne2 = obj.getNorthEast(); + } else { + sw2 = ne2 = obj; + } + + return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && + (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); + }, + + // @method intersects(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common. + intersects: function (bounds) { + bounds = toLatLngBounds(bounds); + + var sw = this._southWest, + ne = this._northEast, + sw2 = bounds.getSouthWest(), + ne2 = bounds.getNorthEast(), + + latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), + lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); + + return latIntersects && lngIntersects; + }, + + // @method overlaps(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area. + overlaps: function (bounds) { + bounds = toLatLngBounds(bounds); + + var sw = this._southWest, + ne = this._northEast, + sw2 = bounds.getSouthWest(), + ne2 = bounds.getNorthEast(), + + latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat), + lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng); + + return latOverlaps && lngOverlaps; + }, + + // @method toBBoxString(): String + // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data. + toBBoxString: function () { + return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); + }, + + // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean + // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number. + equals: function (bounds, maxMargin) { + if (!bounds) { return false; } + + bounds = toLatLngBounds(bounds); + + return this._southWest.equals(bounds.getSouthWest(), maxMargin) && + this._northEast.equals(bounds.getNorthEast(), maxMargin); + }, + + // @method isValid(): Boolean + // Returns `true` if the bounds are properly initialized. + isValid: function () { + return !!(this._southWest && this._northEast); + } +}; + +// TODO International date line? + +// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng) +// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle. + +// @alternative +// @factory L.latLngBounds(latlngs: LatLng[]) +// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds). +function toLatLngBounds(a, b) { + if (a instanceof LatLngBounds) { + return a; + } + return new LatLngBounds(a, b); +} + +/* @class LatLng + * @aka L.LatLng + * + * Represents a geographical point with a certain latitude and longitude. + * + * @example + * + * ``` + * var latlng = L.latLng(50.5, 30.5); + * ``` + * + * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent: + * + * ``` + * map.panTo([50, 30]); + * map.panTo({lon: 30, lat: 50}); + * map.panTo({lat: 50, lng: 30}); + * map.panTo(L.latLng(50, 30)); + * ``` + * + * Note that `LatLng` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function LatLng(lat, lng, alt) { + if (isNaN(lat) || isNaN(lng)) { + throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')'); + } + + // @property lat: Number + // Latitude in degrees + this.lat = +lat; + + // @property lng: Number + // Longitude in degrees + this.lng = +lng; + + // @property alt: Number + // Altitude in meters (optional) + if (alt !== undefined) { + this.alt = +alt; + } +} + +LatLng.prototype = { + // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean + // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number. + equals: function (obj, maxMargin) { + if (!obj) { return false; } + + obj = toLatLng(obj); + + var margin = Math.max( + Math.abs(this.lat - obj.lat), + Math.abs(this.lng - obj.lng)); + + return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin); + }, + + // @method toString(): String + // Returns a string representation of the point (for debugging purposes). + toString: function (precision) { + return 'LatLng(' + + formatNum(this.lat, precision) + ', ' + + formatNum(this.lng, precision) + ')'; + }, + + // @method distanceTo(otherLatLng: LatLng): Number + // Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines). + distanceTo: function (other) { + return Earth.distance(this, toLatLng(other)); + }, + + // @method wrap(): LatLng + // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees. + wrap: function () { + return Earth.wrapLatLng(this); + }, + + // @method toBounds(sizeInMeters: Number): LatLngBounds + // Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`. + toBounds: function (sizeInMeters) { + var latAccuracy = 180 * sizeInMeters / 40075017, + lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat); + + return toLatLngBounds( + [this.lat - latAccuracy, this.lng - lngAccuracy], + [this.lat + latAccuracy, this.lng + lngAccuracy]); + }, + + clone: function () { + return new LatLng(this.lat, this.lng, this.alt); + } +}; + + + +// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng +// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude). + +// @alternative +// @factory L.latLng(coords: Array): LatLng +// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead. + +// @alternative +// @factory L.latLng(coords: Object): LatLng +// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead. + +function toLatLng(a, b, c) { + if (a instanceof LatLng) { + return a; + } + if (isArray(a) && typeof a[0] !== 'object') { + if (a.length === 3) { + return new LatLng(a[0], a[1], a[2]); + } + if (a.length === 2) { + return new LatLng(a[0], a[1]); + } + return null; + } + if (a === undefined || a === null) { + return a; + } + if (typeof a === 'object' && 'lat' in a) { + return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt); + } + if (b === undefined) { + return null; + } + return new LatLng(a, b, c); +} + +/* + * @namespace CRS + * @crs L.CRS.Base + * Object that defines coordinate reference systems for projecting + * geographical points into pixel (screen) coordinates and back (and to + * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See + * [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system). + * + * Leaflet defines the most usual CRSs by default. If you want to use a + * CRS not defined by default, take a look at the + * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin. + * + * Note that the CRS instances do not inherit from Leaflet's `Class` object, + * and can't be instantiated. Also, new classes can't inherit from them, + * and methods can't be added to them with the `include` function. + */ + +var CRS = { + // @method latLngToPoint(latlng: LatLng, zoom: Number): Point + // Projects geographical coordinates into pixel coordinates for a given zoom. + latLngToPoint: function (latlng, zoom) { + var projectedPoint = this.projection.project(latlng), + scale = this.scale(zoom); + + return this.transformation._transform(projectedPoint, scale); + }, + + // @method pointToLatLng(point: Point, zoom: Number): LatLng + // The inverse of `latLngToPoint`. Projects pixel coordinates on a given + // zoom into geographical coordinates. + pointToLatLng: function (point, zoom) { + var scale = this.scale(zoom), + untransformedPoint = this.transformation.untransform(point, scale); + + return this.projection.unproject(untransformedPoint); + }, + + // @method project(latlng: LatLng): Point + // Projects geographical coordinates into coordinates in units accepted for + // this CRS (e.g. meters for EPSG:3857, for passing it to WMS services). + project: function (latlng) { + return this.projection.project(latlng); + }, + + // @method unproject(point: Point): LatLng + // Given a projected coordinate returns the corresponding LatLng. + // The inverse of `project`. + unproject: function (point) { + return this.projection.unproject(point); + }, + + // @method scale(zoom: Number): Number + // Returns the scale used when transforming projected coordinates into + // pixel coordinates for a particular zoom. For example, it returns + // `256 * 2^zoom` for Mercator-based CRS. + scale: function (zoom) { + return 256 * Math.pow(2, zoom); + }, + + // @method zoom(scale: Number): Number + // Inverse of `scale()`, returns the zoom level corresponding to a scale + // factor of `scale`. + zoom: function (scale) { + return Math.log(scale / 256) / Math.LN2; + }, + + // @method getProjectedBounds(zoom: Number): Bounds + // Returns the projection's bounds scaled and transformed for the provided `zoom`. + getProjectedBounds: function (zoom) { + if (this.infinite) { return null; } + + var b = this.projection.bounds, + s = this.scale(zoom), + min = this.transformation.transform(b.min, s), + max = this.transformation.transform(b.max, s); + + return new Bounds(min, max); + }, + + // @method distance(latlng1: LatLng, latlng2: LatLng): Number + // Returns the distance between two geographical coordinates. + + // @property code: String + // Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`) + // + // @property wrapLng: Number[] + // An array of two numbers defining whether the longitude (horizontal) coordinate + // axis wraps around a given range and how. Defaults to `[-180, 180]` in most + // geographical CRSs. If `undefined`, the longitude axis does not wrap around. + // + // @property wrapLat: Number[] + // Like `wrapLng`, but for the latitude (vertical) axis. + + // wrapLng: [min, max], + // wrapLat: [min, max], + + // @property infinite: Boolean + // If true, the coordinate space will be unbounded (infinite in both axes) + infinite: false, + + // @method wrapLatLng(latlng: LatLng): LatLng + // Returns a `LatLng` where lat and lng has been wrapped according to the + // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds. + wrapLatLng: function (latlng) { + var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng, + lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat, + alt = latlng.alt; + + return new LatLng(lat, lng, alt); + }, + + // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds + // Returns a `LatLngBounds` with the same size as the given one, ensuring + // that its center is within the CRS's bounds. + // Only accepts actual `L.LatLngBounds` instances, not arrays. + wrapLatLngBounds: function (bounds) { + var center = bounds.getCenter(), + newCenter = this.wrapLatLng(center), + latShift = center.lat - newCenter.lat, + lngShift = center.lng - newCenter.lng; + + if (latShift === 0 && lngShift === 0) { + return bounds; + } + + var sw = bounds.getSouthWest(), + ne = bounds.getNorthEast(), + newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift), + newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift); + + return new LatLngBounds(newSw, newNe); + } +}; + +/* + * @namespace CRS + * @crs L.CRS.Earth + * + * Serves as the base for CRS that are global such that they cover the earth. + * Can only be used as the base for other CRS and cannot be used directly, + * since it does not have a `code`, `projection` or `transformation`. `distance()` returns + * meters. + */ + +var Earth = extend({}, CRS, { + wrapLng: [-180, 180], + + // Mean Earth Radius, as recommended for use by + // the International Union of Geodesy and Geophysics, + // see https://rosettacode.org/wiki/Haversine_formula + R: 6371000, + + // distance between two geographical points using spherical law of cosines approximation + distance: function (latlng1, latlng2) { + var rad = Math.PI / 180, + lat1 = latlng1.lat * rad, + lat2 = latlng2.lat * rad, + sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2), + sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2), + a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon, + c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + return this.R * c; + } +}); + +/* + * @namespace Projection + * @projection L.Projection.SphericalMercator + * + * Spherical Mercator projection — the most common projection for online maps, + * used by almost all free and commercial tile providers. Assumes that Earth is + * a sphere. Used by the `EPSG:3857` CRS. + */ + +var earthRadius = 6378137; + +var SphericalMercator = { + + R: earthRadius, + MAX_LATITUDE: 85.0511287798, + + project: function (latlng) { + var d = Math.PI / 180, + max = this.MAX_LATITUDE, + lat = Math.max(Math.min(max, latlng.lat), -max), + sin = Math.sin(lat * d); + + return new Point( + this.R * latlng.lng * d, + this.R * Math.log((1 + sin) / (1 - sin)) / 2); + }, + + unproject: function (point) { + var d = 180 / Math.PI; + + return new LatLng( + (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d, + point.x * d / this.R); + }, + + bounds: (function () { + var d = earthRadius * Math.PI; + return new Bounds([-d, -d], [d, d]); + })() +}; + +/* + * @class Transformation + * @aka L.Transformation + * + * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d` + * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing + * the reverse. Used by Leaflet in its projections code. + * + * @example + * + * ```js + * var transformation = L.transformation(2, 5, -1, 10), + * p = L.point(1, 2), + * p2 = transformation.transform(p), // L.point(7, 8) + * p3 = transformation.untransform(p2); // L.point(1, 2) + * ``` + */ + + +// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number) +// Creates a `Transformation` object with the given coefficients. +function Transformation(a, b, c, d) { + if (isArray(a)) { + // use array properties + this._a = a[0]; + this._b = a[1]; + this._c = a[2]; + this._d = a[3]; + return; + } + this._a = a; + this._b = b; + this._c = c; + this._d = d; +} + +Transformation.prototype = { + // @method transform(point: Point, scale?: Number): Point + // Returns a transformed point, optionally multiplied by the given scale. + // Only accepts actual `L.Point` instances, not arrays. + transform: function (point, scale) { // (Point, Number) -> Point + return this._transform(point.clone(), scale); + }, + + // destructive transform (faster) + _transform: function (point, scale) { + scale = scale || 1; + point.x = scale * (this._a * point.x + this._b); + point.y = scale * (this._c * point.y + this._d); + return point; + }, + + // @method untransform(point: Point, scale?: Number): Point + // Returns the reverse transformation of the given point, optionally divided + // by the given scale. Only accepts actual `L.Point` instances, not arrays. + untransform: function (point, scale) { + scale = scale || 1; + return new Point( + (point.x / scale - this._b) / this._a, + (point.y / scale - this._d) / this._c); + } +}; + +// factory L.transformation(a: Number, b: Number, c: Number, d: Number) + +// @factory L.transformation(a: Number, b: Number, c: Number, d: Number) +// Instantiates a Transformation object with the given coefficients. + +// @alternative +// @factory L.transformation(coefficients: Array): Transformation +// Expects an coefficients array of the form +// `[a: Number, b: Number, c: Number, d: Number]`. + +function toTransformation(a, b, c, d) { + return new Transformation(a, b, c, d); +} + +/* + * @namespace CRS + * @crs L.CRS.EPSG3857 + * + * The most common CRS for online maps, used by almost all free and commercial + * tile providers. Uses Spherical Mercator projection. Set in by default in + * Map's `crs` option. + */ + +var EPSG3857 = extend({}, Earth, { + code: 'EPSG:3857', + projection: SphericalMercator, + + transformation: (function () { + var scale = 0.5 / (Math.PI * SphericalMercator.R); + return toTransformation(scale, 0.5, -scale, 0.5); + }()) +}); + +var EPSG900913 = extend({}, EPSG3857, { + code: 'EPSG:900913' +}); + +// @namespace SVG; @section +// There are several static functions which can be called without instantiating L.SVG: + +// @function create(name: String): SVGElement +// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement), +// corresponding to the class name passed. For example, using 'line' will return +// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement). +function svgCreate(name) { + return document.createElementNS('http://www.w3.org/2000/svg', name); +} + +// @function pointsToPath(rings: Point[], closed: Boolean): String +// Generates a SVG path string for multiple rings, with each ring turning +// into "M..L..L.." instructions +function pointsToPath(rings, closed) { + var str = '', + i, j, len, len2, points, p; + + for (i = 0, len = rings.length; i < len; i++) { + points = rings[i]; + + for (j = 0, len2 = points.length; j < len2; j++) { + p = points[j]; + str += (j ? 'L' : 'M') + p.x + ' ' + p.y; + } + + // closes the ring for polygons; "x" is VML syntax + str += closed ? (Browser.svg ? 'z' : 'x') : ''; + } + + // SVG complains about empty path strings + return str || 'M0 0'; +} + +/* + * @namespace Browser + * @aka L.Browser + * + * A namespace with static properties for browser/feature detection used by Leaflet internally. + * + * @example + * + * ```js + * if (L.Browser.ielt9) { + * alert('Upgrade your browser, dude!'); + * } + * ``` + */ + +var style = document.documentElement.style; + +// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge). +var ie = 'ActiveXObject' in window; + +// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9. +var ielt9 = ie && !document.addEventListener; + +// @property edge: Boolean; `true` for the Edge web browser. +var edge = 'msLaunchUri' in navigator && !('documentMode' in document); + +// @property webkit: Boolean; +// `true` for webkit-based browsers like Chrome and Safari (including mobile versions). +var webkit = userAgentContains('webkit'); + +// @property android: Boolean +// **Deprecated.** `true` for any browser running on an Android platform. +var android = userAgentContains('android'); + +// @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3. +var android23 = userAgentContains('android 2') || userAgentContains('android 3'); + +/* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */ +var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit +// @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome) +var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window); + +// @property opera: Boolean; `true` for the Opera browser +var opera = !!window.opera; + +// @property chrome: Boolean; `true` for the Chrome browser. +var chrome = !edge && userAgentContains('chrome'); + +// @property gecko: Boolean; `true` for gecko-based browsers like Firefox. +var gecko = userAgentContains('gecko') && !webkit && !opera && !ie; + +// @property safari: Boolean; `true` for the Safari browser. +var safari = !chrome && userAgentContains('safari'); + +var phantom = userAgentContains('phantom'); + +// @property opera12: Boolean +// `true` for the Opera browser supporting CSS transforms (version 12 or later). +var opera12 = 'OTransition' in style; + +// @property win: Boolean; `true` when the browser is running in a Windows platform +var win = navigator.platform.indexOf('Win') === 0; + +// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms. +var ie3d = ie && ('transition' in style); + +// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms. +var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23; + +// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms. +var gecko3d = 'MozPerspective' in style; + +// @property any3d: Boolean +// `true` for all browsers supporting CSS transforms. +var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom; + +// @property mobile: Boolean; `true` for all browsers running in a mobile device. +var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile'); + +// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device. +var mobileWebkit = mobile && webkit; + +// @property mobileWebkit3d: Boolean +// `true` for all webkit-based browsers in a mobile device supporting CSS transforms. +var mobileWebkit3d = mobile && webkit3d; + +// @property msPointer: Boolean +// `true` for browsers implementing the Microsoft touch events model (notably IE10). +var msPointer = !window.PointerEvent && window.MSPointerEvent; + +// @property pointer: Boolean +// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx). +var pointer = !!(window.PointerEvent || msPointer); + +// @property touchNative: Boolean +// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events). +// **This does not necessarily mean** that the browser is running in a computer with +// a touchscreen, it only means that the browser is capable of understanding +// touch events. +var touchNative = 'ontouchstart' in window || !!window.TouchEvent; + +// @property touch: Boolean +// `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events. +// Note: pointer events will be preferred (if available), and processed for all `touch*` listeners. +var touch = !window.L_NO_TOUCH && (touchNative || pointer); + +// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device. +var mobileOpera = mobile && opera; + +// @property mobileGecko: Boolean +// `true` for gecko-based browsers running in a mobile device. +var mobileGecko = mobile && gecko; + +// @property retina: Boolean +// `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%. +var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1; + +// @property passiveEvents: Boolean +// `true` for browsers that support passive events. +var passiveEvents = (function () { + var supportsPassiveOption = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { // eslint-disable-line getter-return + supportsPassiveOption = true; + } + }); + window.addEventListener('testPassiveEventSupport', falseFn, opts); + window.removeEventListener('testPassiveEventSupport', falseFn, opts); + } catch (e) { + // Errors can safely be ignored since this is only a browser support test. + } + return supportsPassiveOption; +}()); + +// @property canvas: Boolean +// `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API). +var canvas$1 = (function () { + return !!document.createElement('canvas').getContext; +}()); + +// @property svg: Boolean +// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG). +var svg$1 = !!(document.createElementNS && svgCreate('svg').createSVGRect); + +var inlineSvg = !!svg$1 && (function () { + var div = document.createElement('div'); + div.innerHTML = '<svg/>'; + return (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg'; +})(); + +// @property vml: Boolean +// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language). +var vml = !svg$1 && (function () { + try { + var div = document.createElement('div'); + div.innerHTML = '<v:shape adj="1"/>'; + + var shape = div.firstChild; + shape.style.behavior = 'url(#default#VML)'; + + return shape && (typeof shape.adj === 'object'); + + } catch (e) { + return false; + } +}()); + + +// @property mac: Boolean; `true` when the browser is running in a Mac platform +var mac = navigator.platform.indexOf('Mac') === 0; + +// @property mac: Boolean; `true` when the browser is running in a Linux platform +var linux = navigator.platform.indexOf('Linux') === 0; + +function userAgentContains(str) { + return navigator.userAgent.toLowerCase().indexOf(str) >= 0; +} + + +var Browser = { + ie: ie, + ielt9: ielt9, + edge: edge, + webkit: webkit, + android: android, + android23: android23, + androidStock: androidStock, + opera: opera, + chrome: chrome, + gecko: gecko, + safari: safari, + phantom: phantom, + opera12: opera12, + win: win, + ie3d: ie3d, + webkit3d: webkit3d, + gecko3d: gecko3d, + any3d: any3d, + mobile: mobile, + mobileWebkit: mobileWebkit, + mobileWebkit3d: mobileWebkit3d, + msPointer: msPointer, + pointer: pointer, + touch: touch, + touchNative: touchNative, + mobileOpera: mobileOpera, + mobileGecko: mobileGecko, + retina: retina, + passiveEvents: passiveEvents, + canvas: canvas$1, + svg: svg$1, + vml: vml, + inlineSvg: inlineSvg, + mac: mac, + linux: linux +}; + +/* + * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices. + */ + +var POINTER_DOWN = Browser.msPointer ? 'MSPointerDown' : 'pointerdown'; +var POINTER_MOVE = Browser.msPointer ? 'MSPointerMove' : 'pointermove'; +var POINTER_UP = Browser.msPointer ? 'MSPointerUp' : 'pointerup'; +var POINTER_CANCEL = Browser.msPointer ? 'MSPointerCancel' : 'pointercancel'; +var pEvent = { + touchstart : POINTER_DOWN, + touchmove : POINTER_MOVE, + touchend : POINTER_UP, + touchcancel : POINTER_CANCEL +}; +var handle = { + touchstart : _onPointerStart, + touchmove : _handlePointer, + touchend : _handlePointer, + touchcancel : _handlePointer +}; +var _pointers = {}; +var _pointerDocListener = false; + +// Provides a touch events wrapper for (ms)pointer events. +// ref https://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890 + +function addPointerListener(obj, type, handler) { + if (type === 'touchstart') { + _addPointerDocListener(); + } + if (!handle[type]) { + console.warn('wrong event specified:', type); + return falseFn; + } + handler = handle[type].bind(this, handler); + obj.addEventListener(pEvent[type], handler, false); + return handler; +} + +function removePointerListener(obj, type, handler) { + if (!pEvent[type]) { + console.warn('wrong event specified:', type); + return; + } + obj.removeEventListener(pEvent[type], handler, false); +} + +function _globalPointerDown(e) { + _pointers[e.pointerId] = e; +} + +function _globalPointerMove(e) { + if (_pointers[e.pointerId]) { + _pointers[e.pointerId] = e; + } +} + +function _globalPointerUp(e) { + delete _pointers[e.pointerId]; +} + +function _addPointerDocListener() { + // need to keep track of what pointers and how many are active to provide e.touches emulation + if (!_pointerDocListener) { + // we listen document as any drags that end by moving the touch off the screen get fired there + document.addEventListener(POINTER_DOWN, _globalPointerDown, true); + document.addEventListener(POINTER_MOVE, _globalPointerMove, true); + document.addEventListener(POINTER_UP, _globalPointerUp, true); + document.addEventListener(POINTER_CANCEL, _globalPointerUp, true); + + _pointerDocListener = true; + } +} + +function _handlePointer(handler, e) { + if (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; } + + e.touches = []; + for (var i in _pointers) { + e.touches.push(_pointers[i]); + } + e.changedTouches = [e]; + + handler(e); +} + +function _onPointerStart(handler, e) { + // IE10 specific: MsTouch needs preventDefault. See #2000 + if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) { + preventDefault(e); + } + _handlePointer(handler, e); +} + +/* + * Extends the event handling code with double tap support for mobile browsers. + * + * Note: currently most browsers fire native dblclick, with only a few exceptions + * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386) + */ + +function makeDblclick(event) { + // in modern browsers `type` cannot be just overridden: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only + var newEvent = {}, + prop, i; + for (i in event) { + prop = event[i]; + newEvent[i] = prop && prop.bind ? prop.bind(event) : prop; + } + event = newEvent; + newEvent.type = 'dblclick'; + newEvent.detail = 2; + newEvent.isTrusted = false; + newEvent._simulated = true; // for debug purposes + return newEvent; +} + +var delay = 200; +function addDoubleTapListener(obj, handler) { + // Most browsers handle double tap natively + obj.addEventListener('dblclick', handler); + + // On some platforms the browser doesn't fire native dblclicks for touch events. + // It seems that in all such cases `detail` property of `click` event is always `1`. + // So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed. + var last = 0, + detail; + function simDblclick(e) { + if (e.detail !== 1) { + detail = e.detail; // keep in sync to avoid false dblclick in some cases + return; + } + + if (e.pointerType === 'mouse' || + (e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) { + + return; + } + + // When clicking on an <input>, the browser generates a click on its + // <label> (and vice versa) triggering two clicks in quick succession. + // This ignores clicks on elements which are a label with a 'for' + // attribute (or children of such a label), but not children of + // a <input>. + var path = getPropagationPath(e); + if (path.some(function (el) { + return el instanceof HTMLLabelElement && el.attributes.for; + }) && + !path.some(function (el) { + return ( + el instanceof HTMLInputElement || + el instanceof HTMLSelectElement + ); + }) + ) { + return; + } + + var now = Date.now(); + if (now - last <= delay) { + detail++; + if (detail === 2) { + handler(makeDblclick(e)); + } + } else { + detail = 1; + } + last = now; + } + + obj.addEventListener('click', simDblclick); + + return { + dblclick: handler, + simDblclick: simDblclick + }; +} + +function removeDoubleTapListener(obj, handlers) { + obj.removeEventListener('dblclick', handlers.dblclick); + obj.removeEventListener('click', handlers.simDblclick); +} + +/* + * @namespace DomUtil + * + * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) + * tree, used by Leaflet internally. + * + * Most functions expecting or returning a `HTMLElement` also work for + * SVG elements. The only difference is that classes refer to CSS classes + * in HTML and SVG classes in SVG. + */ + + +// @property TRANSFORM: String +// Vendor-prefixed transform style name (e.g. `'webkitTransform'` for WebKit). +var TRANSFORM = testProp( + ['transform', 'webkitTransform', 'OTransform', 'MozTransform', 'msTransform']); + +// webkitTransition comes first because some browser versions that drop vendor prefix don't do +// the same for the transitionend event, in particular the Android 4.1 stock browser + +// @property TRANSITION: String +// Vendor-prefixed transition style name. +var TRANSITION = testProp( + ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']); + +// @property TRANSITION_END: String +// Vendor-prefixed transitionend event name. +var TRANSITION_END = + TRANSITION === 'webkitTransition' || TRANSITION === 'OTransition' ? TRANSITION + 'End' : 'transitionend'; + + +// @function get(id: String|HTMLElement): HTMLElement +// Returns an element given its DOM id, or returns the element itself +// if it was passed directly. +function get(id) { + return typeof id === 'string' ? document.getElementById(id) : id; +} + +// @function getStyle(el: HTMLElement, styleAttrib: String): String +// Returns the value for a certain style attribute on an element, +// including computed values or values set through CSS. +function getStyle(el, style) { + var value = el.style[style] || (el.currentStyle && el.currentStyle[style]); + + if ((!value || value === 'auto') && document.defaultView) { + var css = document.defaultView.getComputedStyle(el, null); + value = css ? css[style] : null; + } + return value === 'auto' ? null : value; +} + +// @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement +// Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element. +function create$1(tagName, className, container) { + var el = document.createElement(tagName); + el.className = className || ''; + + if (container) { + container.appendChild(el); + } + return el; +} + +// @function remove(el: HTMLElement) +// Removes `el` from its parent element +function remove(el) { + var parent = el.parentNode; + if (parent) { + parent.removeChild(el); + } +} + +// @function empty(el: HTMLElement) +// Removes all of `el`'s children elements from `el` +function empty(el) { + while (el.firstChild) { + el.removeChild(el.firstChild); + } +} + +// @function toFront(el: HTMLElement) +// Makes `el` the last child of its parent, so it renders in front of the other children. +function toFront(el) { + var parent = el.parentNode; + if (parent && parent.lastChild !== el) { + parent.appendChild(el); + } +} + +// @function toBack(el: HTMLElement) +// Makes `el` the first child of its parent, so it renders behind the other children. +function toBack(el) { + var parent = el.parentNode; + if (parent && parent.firstChild !== el) { + parent.insertBefore(el, parent.firstChild); + } +} + +// @function hasClass(el: HTMLElement, name: String): Boolean +// Returns `true` if the element's class attribute contains `name`. +function hasClass(el, name) { + if (el.classList !== undefined) { + return el.classList.contains(name); + } + var className = getClass(el); + return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className); +} + +// @function addClass(el: HTMLElement, name: String) +// Adds `name` to the element's class attribute. +function addClass(el, name) { + if (el.classList !== undefined) { + var classes = splitWords(name); + for (var i = 0, len = classes.length; i < len; i++) { + el.classList.add(classes[i]); + } + } else if (!hasClass(el, name)) { + var className = getClass(el); + setClass(el, (className ? className + ' ' : '') + name); + } +} + +// @function removeClass(el: HTMLElement, name: String) +// Removes `name` from the element's class attribute. +function removeClass(el, name) { + if (el.classList !== undefined) { + el.classList.remove(name); + } else { + setClass(el, trim((' ' + getClass(el) + ' ').replace(' ' + name + ' ', ' '))); + } +} + +// @function setClass(el: HTMLElement, name: String) +// Sets the element's class. +function setClass(el, name) { + if (el.className.baseVal === undefined) { + el.className = name; + } else { + // in case of SVG element + el.className.baseVal = name; + } +} + +// @function getClass(el: HTMLElement): String +// Returns the element's class. +function getClass(el) { + // Check if the element is an SVGElementInstance and use the correspondingElement instead + // (Required for linked SVG elements in IE11.) + if (el.correspondingElement) { + el = el.correspondingElement; + } + return el.className.baseVal === undefined ? el.className : el.className.baseVal; +} + +// @function setOpacity(el: HTMLElement, opacity: Number) +// Set the opacity of an element (including old IE support). +// `opacity` must be a number from `0` to `1`. +function setOpacity(el, value) { + if ('opacity' in el.style) { + el.style.opacity = value; + } else if ('filter' in el.style) { + _setOpacityIE(el, value); + } +} + +function _setOpacityIE(el, value) { + var filter = false, + filterName = 'DXImageTransform.Microsoft.Alpha'; + + // filters collection throws an error if we try to retrieve a filter that doesn't exist + try { + filter = el.filters.item(filterName); + } catch (e) { + // don't set opacity to 1 if we haven't already set an opacity, + // it isn't needed and breaks transparent pngs. + if (value === 1) { return; } + } + + value = Math.round(value * 100); + + if (filter) { + filter.Enabled = (value !== 100); + filter.Opacity = value; + } else { + el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')'; + } +} + +// @function testProp(props: String[]): String|false +// Goes through the array of style names and returns the first name +// that is a valid style name for an element. If no such name is found, +// it returns false. Useful for vendor-prefixed styles like `transform`. +function testProp(props) { + var style = document.documentElement.style; + + for (var i = 0; i < props.length; i++) { + if (props[i] in style) { + return props[i]; + } + } + return false; +} + +// @function setTransform(el: HTMLElement, offset: Point, scale?: Number) +// Resets the 3D CSS transform of `el` so it is translated by `offset` pixels +// and optionally scaled by `scale`. Does not have an effect if the +// browser doesn't support 3D CSS transforms. +function setTransform(el, offset, scale) { + var pos = offset || new Point(0, 0); + + el.style[TRANSFORM] = + (Browser.ie3d ? + 'translate(' + pos.x + 'px,' + pos.y + 'px)' : + 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') + + (scale ? ' scale(' + scale + ')' : ''); +} + +// @function setPosition(el: HTMLElement, position: Point) +// Sets the position of `el` to coordinates specified by `position`, +// using CSS translate or top/left positioning depending on the browser +// (used by Leaflet internally to position its layers). +function setPosition(el, point) { + + /*eslint-disable */ + el._leaflet_pos = point; + /* eslint-enable */ + + if (Browser.any3d) { + setTransform(el, point); + } else { + el.style.left = point.x + 'px'; + el.style.top = point.y + 'px'; + } +} + +// @function getPosition(el: HTMLElement): Point +// Returns the coordinates of an element previously positioned with setPosition. +function getPosition(el) { + // this method is only used for elements previously positioned using setPosition, + // so it's safe to cache the position for performance + + return el._leaflet_pos || new Point(0, 0); +} + +// @function disableTextSelection() +// Prevents the user from generating `selectstart` DOM events, usually generated +// when the user drags the mouse through a page with text. Used internally +// by Leaflet to override the behaviour of any click-and-drag interaction on +// the map. Affects drag interactions on the whole document. + +// @function enableTextSelection() +// Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection). +var disableTextSelection; +var enableTextSelection; +var _userSelect; +if ('onselectstart' in document) { + disableTextSelection = function () { + on(window, 'selectstart', preventDefault); + }; + enableTextSelection = function () { + off(window, 'selectstart', preventDefault); + }; +} else { + var userSelectProperty = testProp( + ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']); + + disableTextSelection = function () { + if (userSelectProperty) { + var style = document.documentElement.style; + _userSelect = style[userSelectProperty]; + style[userSelectProperty] = 'none'; + } + }; + enableTextSelection = function () { + if (userSelectProperty) { + document.documentElement.style[userSelectProperty] = _userSelect; + _userSelect = undefined; + } + }; +} + +// @function disableImageDrag() +// As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but +// for `dragstart` DOM events, usually generated when the user drags an image. +function disableImageDrag() { + on(window, 'dragstart', preventDefault); +} + +// @function enableImageDrag() +// Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection). +function enableImageDrag() { + off(window, 'dragstart', preventDefault); +} + +var _outlineElement, _outlineStyle; +// @function preventOutline(el: HTMLElement) +// Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline) +// of the element `el` invisible. Used internally by Leaflet to prevent +// focusable elements from displaying an outline when the user performs a +// drag interaction on them. +function preventOutline(element) { + while (element.tabIndex === -1) { + element = element.parentNode; + } + if (!element.style) { return; } + restoreOutline(); + _outlineElement = element; + _outlineStyle = element.style.outlineStyle; + element.style.outlineStyle = 'none'; + on(window, 'keydown', restoreOutline); +} + +// @function restoreOutline() +// Cancels the effects of a previous [`L.DomUtil.preventOutline`](). +function restoreOutline() { + if (!_outlineElement) { return; } + _outlineElement.style.outlineStyle = _outlineStyle; + _outlineElement = undefined; + _outlineStyle = undefined; + off(window, 'keydown', restoreOutline); +} + +// @function getSizedParentNode(el: HTMLElement): HTMLElement +// Finds the closest parent node which size (width and height) is not null. +function getSizedParentNode(element) { + do { + element = element.parentNode; + } while ((!element.offsetWidth || !element.offsetHeight) && element !== document.body); + return element; +} + +// @function getScale(el: HTMLElement): Object +// Computes the CSS scale currently applied on the element. +// Returns an object with `x` and `y` members as horizontal and vertical scales respectively, +// and `boundingClientRect` as the result of [`getBoundingClientRect()`](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). +function getScale(element) { + var rect = element.getBoundingClientRect(); // Read-only in old browsers. + + return { + x: rect.width / element.offsetWidth || 1, + y: rect.height / element.offsetHeight || 1, + boundingClientRect: rect + }; +} + +var DomUtil = { + __proto__: null, + TRANSFORM: TRANSFORM, + TRANSITION: TRANSITION, + TRANSITION_END: TRANSITION_END, + get: get, + getStyle: getStyle, + create: create$1, + remove: remove, + empty: empty, + toFront: toFront, + toBack: toBack, + hasClass: hasClass, + addClass: addClass, + removeClass: removeClass, + setClass: setClass, + getClass: getClass, + setOpacity: setOpacity, + testProp: testProp, + setTransform: setTransform, + setPosition: setPosition, + getPosition: getPosition, + get disableTextSelection () { return disableTextSelection; }, + get enableTextSelection () { return enableTextSelection; }, + disableImageDrag: disableImageDrag, + enableImageDrag: enableImageDrag, + preventOutline: preventOutline, + restoreOutline: restoreOutline, + getSizedParentNode: getSizedParentNode, + getScale: getScale +}; + +/* + * @namespace DomEvent + * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally. + */ + +// Inspired by John Resig, Dean Edwards and YUI addEvent implementations. + +// @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this +// Adds a listener function (`fn`) to a particular DOM event type of the +// element `el`. You can optionally specify the context of the listener +// (object the `this` keyword will point to). You can also pass several +// space-separated types (e.g. `'click dblclick'`). + +// @alternative +// @function on(el: HTMLElement, eventMap: Object, context?: Object): this +// Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` +function on(obj, types, fn, context) { + + if (types && typeof types === 'object') { + for (var type in types) { + addOne(obj, type, types[type], fn); + } + } else { + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + addOne(obj, types[i], fn, context); + } + } + + return this; +} + +var eventsKey = '_leaflet_events'; + +// @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this +// Removes a previously added listener function. +// Note that if you passed a custom context to on, you must pass the same +// context to `off` in order to remove the listener. + +// @alternative +// @function off(el: HTMLElement, eventMap: Object, context?: Object): this +// Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` + +// @alternative +// @function off(el: HTMLElement, types: String): this +// Removes all previously added listeners of given types. + +// @alternative +// @function off(el: HTMLElement): this +// Removes all previously added listeners from given HTMLElement +function off(obj, types, fn, context) { + + if (arguments.length === 1) { + batchRemove(obj); + delete obj[eventsKey]; + + } else if (types && typeof types === 'object') { + for (var type in types) { + removeOne(obj, type, types[type], fn); + } + + } else { + types = splitWords(types); + + if (arguments.length === 2) { + batchRemove(obj, function (type) { + return indexOf(types, type) !== -1; + }); + } else { + for (var i = 0, len = types.length; i < len; i++) { + removeOne(obj, types[i], fn, context); + } + } + } + + return this; +} + +function batchRemove(obj, filterFn) { + for (var id in obj[eventsKey]) { + var type = id.split(/\d/)[0]; + if (!filterFn || filterFn(type)) { + removeOne(obj, type, null, null, id); + } + } +} + +var mouseSubst = { + mouseenter: 'mouseover', + mouseleave: 'mouseout', + wheel: !('onwheel' in window) && 'mousewheel' +}; + +function addOne(obj, type, fn, context) { + var id = type + stamp(fn) + (context ? '_' + stamp(context) : ''); + + if (obj[eventsKey] && obj[eventsKey][id]) { return this; } + + var handler = function (e) { + return fn.call(context || obj, e || window.event); + }; + + var originalHandler = handler; + + if (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) { + // Needs DomEvent.Pointer.js + handler = addPointerListener(obj, type, handler); + + } else if (Browser.touch && (type === 'dblclick')) { + handler = addDoubleTapListener(obj, handler); + + } else if ('addEventListener' in obj) { + + if (type === 'touchstart' || type === 'touchmove' || type === 'wheel' || type === 'mousewheel') { + obj.addEventListener(mouseSubst[type] || type, handler, Browser.passiveEvents ? {passive: false} : false); + + } else if (type === 'mouseenter' || type === 'mouseleave') { + handler = function (e) { + e = e || window.event; + if (isExternalTarget(obj, e)) { + originalHandler(e); + } + }; + obj.addEventListener(mouseSubst[type], handler, false); + + } else { + obj.addEventListener(type, originalHandler, false); + } + + } else { + obj.attachEvent('on' + type, handler); + } + + obj[eventsKey] = obj[eventsKey] || {}; + obj[eventsKey][id] = handler; +} + +function removeOne(obj, type, fn, context, id) { + id = id || type + stamp(fn) + (context ? '_' + stamp(context) : ''); + var handler = obj[eventsKey] && obj[eventsKey][id]; + + if (!handler) { return this; } + + if (!Browser.touchNative && Browser.pointer && type.indexOf('touch') === 0) { + removePointerListener(obj, type, handler); + + } else if (Browser.touch && (type === 'dblclick')) { + removeDoubleTapListener(obj, handler); + + } else if ('removeEventListener' in obj) { + + obj.removeEventListener(mouseSubst[type] || type, handler, false); + + } else { + obj.detachEvent('on' + type, handler); + } + + obj[eventsKey][id] = null; +} + +// @function stopPropagation(ev: DOMEvent): this +// Stop the given event from propagation to parent elements. Used inside the listener functions: +// ```js +// L.DomEvent.on(div, 'click', function (ev) { +// L.DomEvent.stopPropagation(ev); +// }); +// ``` +function stopPropagation(e) { + + if (e.stopPropagation) { + e.stopPropagation(); + } else if (e.originalEvent) { // In case of Leaflet event. + e.originalEvent._stopped = true; + } else { + e.cancelBubble = true; + } + + return this; +} + +// @function disableScrollPropagation(el: HTMLElement): this +// Adds `stopPropagation` to the element's `'wheel'` events (plus browser variants). +function disableScrollPropagation(el) { + addOne(el, 'wheel', stopPropagation); + return this; +} + +// @function disableClickPropagation(el: HTMLElement): this +// Adds `stopPropagation` to the element's `'click'`, `'dblclick'`, `'contextmenu'`, +// `'mousedown'` and `'touchstart'` events (plus browser variants). +function disableClickPropagation(el) { + on(el, 'mousedown touchstart dblclick contextmenu', stopPropagation); + el['_leaflet_disable_click'] = true; + return this; +} + +// @function preventDefault(ev: DOMEvent): this +// Prevents the default action of the DOM Event `ev` from happening (such as +// following a link in the href of the a element, or doing a POST request +// with page reload when a `<form>` is submitted). +// Use it inside listener functions. +function preventDefault(e) { + if (e.preventDefault) { + e.preventDefault(); + } else { + e.returnValue = false; + } + return this; +} + +// @function stop(ev: DOMEvent): this +// Does `stopPropagation` and `preventDefault` at the same time. +function stop(e) { + preventDefault(e); + stopPropagation(e); + return this; +} + +// @function getPropagationPath(ev: DOMEvent): Array +// Compatibility polyfill for [`Event.composedPath()`](https://developer.mozilla.org/en-US/docs/Web/API/Event/composedPath). +// Returns an array containing the `HTMLElement`s that the given DOM event +// should propagate to (if not stopped). +function getPropagationPath(ev) { + if (ev.composedPath) { + return ev.composedPath(); + } + + var path = []; + var el = ev.target; + + while (el) { + path.push(el); + el = el.parentNode; + } + return path; +} + + +// @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point +// Gets normalized mouse position from a DOM event relative to the +// `container` (border excluded) or to the whole page if not specified. +function getMousePosition(e, container) { + if (!container) { + return new Point(e.clientX, e.clientY); + } + + var scale = getScale(container), + offset = scale.boundingClientRect; // left and top values are in page scale (like the event clientX/Y) + + return new Point( + // offset.left/top values are in page scale (like clientX/Y), + // whereas clientLeft/Top (border width) values are the original values (before CSS scale applies). + (e.clientX - offset.left) / scale.x - container.clientLeft, + (e.clientY - offset.top) / scale.y - container.clientTop + ); +} + + +// except , Safari and +// We need double the scroll pixels (see #7403 and #4538) for all Browsers +// except OSX (Mac) -> 3x, Chrome running on Linux 1x + +var wheelPxFactor = + (Browser.linux && Browser.chrome) ? window.devicePixelRatio : + Browser.mac ? window.devicePixelRatio * 3 : + window.devicePixelRatio > 0 ? 2 * window.devicePixelRatio : 1; +// @function getWheelDelta(ev: DOMEvent): Number +// Gets normalized wheel delta from a wheel DOM event, in vertical +// pixels scrolled (negative if scrolling down). +// Events from pointing devices without precise scrolling are mapped to +// a best guess of 60 pixels. +function getWheelDelta(e) { + return (Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta + (e.deltaY && e.deltaMode === 0) ? -e.deltaY / wheelPxFactor : // Pixels + (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines + (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages + (e.deltaX || e.deltaZ) ? 0 : // Skip horizontal/depth wheel events + e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels + (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines + e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages + 0; +} + +// check if element really left/entered the event target (for mouseenter/mouseleave) +function isExternalTarget(el, e) { + + var related = e.relatedTarget; + + if (!related) { return true; } + + try { + while (related && (related !== el)) { + related = related.parentNode; + } + } catch (err) { + return false; + } + return (related !== el); +} + +var DomEvent = { + __proto__: null, + on: on, + off: off, + stopPropagation: stopPropagation, + disableScrollPropagation: disableScrollPropagation, + disableClickPropagation: disableClickPropagation, + preventDefault: preventDefault, + stop: stop, + getPropagationPath: getPropagationPath, + getMousePosition: getMousePosition, + getWheelDelta: getWheelDelta, + isExternalTarget: isExternalTarget, + addListener: on, + removeListener: off +}; + +/* + * @class PosAnimation + * @aka L.PosAnimation + * @inherits Evented + * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9. + * + * @example + * ```js + * var myPositionMarker = L.marker([48.864716, 2.294694]).addTo(map); + * + * myPositionMarker.on("click", function() { + * var pos = map.latLngToLayerPoint(myPositionMarker.getLatLng()); + * pos.y -= 25; + * var fx = new L.PosAnimation(); + * + * fx.once('end',function() { + * pos.y += 25; + * fx.run(myPositionMarker._icon, pos, 0.8); + * }); + * + * fx.run(myPositionMarker._icon, pos, 0.3); + * }); + * + * ``` + * + * @constructor L.PosAnimation() + * Creates a `PosAnimation` object. + * + */ + +var PosAnimation = Evented.extend({ + + // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number) + // Run an animation of a given element to a new position, optionally setting + // duration in seconds (`0.25` by default) and easing linearity factor (3rd + // argument of the [cubic bezier curve](https://cubic-bezier.com/#0,0,.5,1), + // `0.5` by default). + run: function (el, newPos, duration, easeLinearity) { + this.stop(); + + this._el = el; + this._inProgress = true; + this._duration = duration || 0.25; + this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2); + + this._startPos = getPosition(el); + this._offset = newPos.subtract(this._startPos); + this._startTime = +new Date(); + + // @event start: Event + // Fired when the animation starts + this.fire('start'); + + this._animate(); + }, + + // @method stop() + // Stops the animation (if currently running). + stop: function () { + if (!this._inProgress) { return; } + + this._step(true); + this._complete(); + }, + + _animate: function () { + // animation loop + this._animId = requestAnimFrame(this._animate, this); + this._step(); + }, + + _step: function (round) { + var elapsed = (+new Date()) - this._startTime, + duration = this._duration * 1000; + + if (elapsed < duration) { + this._runFrame(this._easeOut(elapsed / duration), round); + } else { + this._runFrame(1); + this._complete(); + } + }, + + _runFrame: function (progress, round) { + var pos = this._startPos.add(this._offset.multiplyBy(progress)); + if (round) { + pos._round(); + } + setPosition(this._el, pos); + + // @event step: Event + // Fired continuously during the animation. + this.fire('step'); + }, + + _complete: function () { + cancelAnimFrame(this._animId); + + this._inProgress = false; + // @event end: Event + // Fired when the animation ends. + this.fire('end'); + }, + + _easeOut: function (t) { + return 1 - Math.pow(1 - t, this._easeOutPower); + } +}); + +/* + * @class Map + * @aka L.Map + * @inherits Evented + * + * The central class of the API — it is used to create a map on a page and manipulate it. + * + * @example + * + * ```js + * // initialize the map on the "map" div with a given center and zoom + * var map = L.map('map', { + * center: [51.505, -0.09], + * zoom: 13 + * }); + * ``` + * + */ + +var Map = Evented.extend({ + + options: { + // @section Map State Options + // @option crs: CRS = L.CRS.EPSG3857 + // The [Coordinate Reference System](#crs) to use. Don't change this if you're not + // sure what it means. + crs: EPSG3857, + + // @option center: LatLng = undefined + // Initial geographic center of the map + center: undefined, + + // @option zoom: Number = undefined + // Initial map zoom level + zoom: undefined, + + // @option minZoom: Number = * + // Minimum zoom level of the map. + // If not specified and at least one `GridLayer` or `TileLayer` is in the map, + // the lowest of their `minZoom` options will be used instead. + minZoom: undefined, + + // @option maxZoom: Number = * + // Maximum zoom level of the map. + // If not specified and at least one `GridLayer` or `TileLayer` is in the map, + // the highest of their `maxZoom` options will be used instead. + maxZoom: undefined, + + // @option layers: Layer[] = [] + // Array of layers that will be added to the map initially + layers: [], + + // @option maxBounds: LatLngBounds = null + // When this option is set, the map restricts the view to the given + // geographical bounds, bouncing the user back if the user tries to pan + // outside the view. To set the restriction dynamically, use + // [`setMaxBounds`](#map-setmaxbounds) method. + maxBounds: undefined, + + // @option renderer: Renderer = * + // The default method for drawing vector layers on the map. `L.SVG` + // or `L.Canvas` by default depending on browser support. + renderer: undefined, + + + // @section Animation Options + // @option zoomAnimation: Boolean = true + // Whether the map zoom animation is enabled. By default it's enabled + // in all browsers that support CSS3 Transitions except Android. + zoomAnimation: true, + + // @option zoomAnimationThreshold: Number = 4 + // Won't animate zoom if the zoom difference exceeds this value. + zoomAnimationThreshold: 4, + + // @option fadeAnimation: Boolean = true + // Whether the tile fade animation is enabled. By default it's enabled + // in all browsers that support CSS3 Transitions except Android. + fadeAnimation: true, + + // @option markerZoomAnimation: Boolean = true + // Whether markers animate their zoom with the zoom animation, if disabled + // they will disappear for the length of the animation. By default it's + // enabled in all browsers that support CSS3 Transitions except Android. + markerZoomAnimation: true, + + // @option transform3DLimit: Number = 2^23 + // Defines the maximum size of a CSS translation transform. The default + // value should not be changed unless a web browser positions layers in + // the wrong place after doing a large `panBy`. + transform3DLimit: 8388608, // Precision limit of a 32-bit float + + // @section Interaction Options + // @option zoomSnap: Number = 1 + // Forces the map's zoom level to always be a multiple of this, particularly + // right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom. + // By default, the zoom level snaps to the nearest integer; lower values + // (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0` + // means the zoom level will not be snapped after `fitBounds` or a pinch-zoom. + zoomSnap: 1, + + // @option zoomDelta: Number = 1 + // Controls how much the map's zoom level will change after a + // [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+` + // or `-` on the keyboard, or using the [zoom controls](#control-zoom). + // Values smaller than `1` (e.g. `0.5`) allow for greater granularity. + zoomDelta: 1, + + // @option trackResize: Boolean = true + // Whether the map automatically handles browser window resize to update itself. + trackResize: true + }, + + initialize: function (id, options) { // (HTMLElement or String, Object) + options = setOptions(this, options); + + // Make sure to assign internal flags at the beginning, + // to avoid inconsistent state in some edge cases. + this._handlers = []; + this._layers = {}; + this._zoomBoundLayers = {}; + this._sizeChanged = true; + + this._initContainer(id); + this._initLayout(); + + // hack for https://github.com/Leaflet/Leaflet/issues/1980 + this._onResize = bind(this._onResize, this); + + this._initEvents(); + + if (options.maxBounds) { + this.setMaxBounds(options.maxBounds); + } + + if (options.zoom !== undefined) { + this._zoom = this._limitZoom(options.zoom); + } + + if (options.center && options.zoom !== undefined) { + this.setView(toLatLng(options.center), options.zoom, {reset: true}); + } + + this.callInitHooks(); + + // don't animate on browsers without hardware-accelerated transitions or old Android/Opera + this._zoomAnimated = TRANSITION && Browser.any3d && !Browser.mobileOpera && + this.options.zoomAnimation; + + // zoom transitions run with the same duration for all layers, so if one of transitionend events + // happens after starting zoom animation (propagating to the map pane), we know that it ended globally + if (this._zoomAnimated) { + this._createAnimProxy(); + on(this._proxy, TRANSITION_END, this._catchTransitionEnd, this); + } + + this._addLayers(this.options.layers); + }, + + + // @section Methods for modifying map state + + // @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this + // Sets the view of the map (geographical center and zoom) with the given + // animation options. + setView: function (center, zoom, options) { + + zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom); + center = this._limitCenter(toLatLng(center), zoom, this.options.maxBounds); + options = options || {}; + + this._stop(); + + if (this._loaded && !options.reset && options !== true) { + + if (options.animate !== undefined) { + options.zoom = extend({animate: options.animate}, options.zoom); + options.pan = extend({animate: options.animate, duration: options.duration}, options.pan); + } + + // try animating pan or zoom + var moved = (this._zoom !== zoom) ? + this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) : + this._tryAnimatedPan(center, options.pan); + + if (moved) { + // prevent resize handler call, the view will refresh after animation anyway + clearTimeout(this._sizeTimer); + return this; + } + } + + // animation didn't start, just reset the map view + this._resetView(center, zoom, options.pan && options.pan.noMoveStart); + + return this; + }, + + // @method setZoom(zoom: Number, options?: Zoom/pan options): this + // Sets the zoom of the map. + setZoom: function (zoom, options) { + if (!this._loaded) { + this._zoom = zoom; + return this; + } + return this.setView(this.getCenter(), zoom, {zoom: options}); + }, + + // @method zoomIn(delta?: Number, options?: Zoom options): this + // Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default). + zoomIn: function (delta, options) { + delta = delta || (Browser.any3d ? this.options.zoomDelta : 1); + return this.setZoom(this._zoom + delta, options); + }, + + // @method zoomOut(delta?: Number, options?: Zoom options): this + // Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default). + zoomOut: function (delta, options) { + delta = delta || (Browser.any3d ? this.options.zoomDelta : 1); + return this.setZoom(this._zoom - delta, options); + }, + + // @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this + // Zooms the map while keeping a specified geographical point on the map + // stationary (e.g. used internally for scroll zoom and double-click zoom). + // @alternative + // @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this + // Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary. + setZoomAround: function (latlng, zoom, options) { + var scale = this.getZoomScale(zoom), + viewHalf = this.getSize().divideBy(2), + containerPoint = latlng instanceof Point ? latlng : this.latLngToContainerPoint(latlng), + + centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale), + newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset)); + + return this.setView(newCenter, zoom, {zoom: options}); + }, + + _getBoundsCenterZoom: function (bounds, options) { + + options = options || {}; + bounds = bounds.getBounds ? bounds.getBounds() : toLatLngBounds(bounds); + + var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]), + paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]), + + zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR)); + + zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom; + + if (zoom === Infinity) { + return { + center: bounds.getCenter(), + zoom: zoom + }; + } + + var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2), + + swPoint = this.project(bounds.getSouthWest(), zoom), + nePoint = this.project(bounds.getNorthEast(), zoom), + center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom); + + return { + center: center, + zoom: zoom + }; + }, + + // @method fitBounds(bounds: LatLngBounds, options?: fitBounds options): this + // Sets a map view that contains the given geographical bounds with the + // maximum zoom level possible. + fitBounds: function (bounds, options) { + + bounds = toLatLngBounds(bounds); + + if (!bounds.isValid()) { + throw new Error('Bounds are not valid.'); + } + + var target = this._getBoundsCenterZoom(bounds, options); + return this.setView(target.center, target.zoom, options); + }, + + // @method fitWorld(options?: fitBounds options): this + // Sets a map view that mostly contains the whole world with the maximum + // zoom level possible. + fitWorld: function (options) { + return this.fitBounds([[-90, -180], [90, 180]], options); + }, + + // @method panTo(latlng: LatLng, options?: Pan options): this + // Pans the map to a given center. + panTo: function (center, options) { // (LatLng) + return this.setView(center, this._zoom, {pan: options}); + }, + + // @method panBy(offset: Point, options?: Pan options): this + // Pans the map by a given number of pixels (animated). + panBy: function (offset, options) { + offset = toPoint(offset).round(); + options = options || {}; + + if (!offset.x && !offset.y) { + return this.fire('moveend'); + } + // If we pan too far, Chrome gets issues with tiles + // and makes them disappear or appear in the wrong place (slightly offset) #2602 + if (options.animate !== true && !this.getSize().contains(offset)) { + this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom()); + return this; + } + + if (!this._panAnim) { + this._panAnim = new PosAnimation(); + + this._panAnim.on({ + 'step': this._onPanTransitionStep, + 'end': this._onPanTransitionEnd + }, this); + } + + // don't fire movestart if animating inertia + if (!options.noMoveStart) { + this.fire('movestart'); + } + + // animate pan unless animate: false specified + if (options.animate !== false) { + addClass(this._mapPane, 'leaflet-pan-anim'); + + var newPos = this._getMapPanePos().subtract(offset).round(); + this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity); + } else { + this._rawPanBy(offset); + this.fire('move').fire('moveend'); + } + + return this; + }, + + // @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this + // Sets the view of the map (geographical center and zoom) performing a smooth + // pan-zoom animation. + flyTo: function (targetCenter, targetZoom, options) { + + options = options || {}; + if (options.animate === false || !Browser.any3d) { + return this.setView(targetCenter, targetZoom, options); + } + + this._stop(); + + var from = this.project(this.getCenter()), + to = this.project(targetCenter), + size = this.getSize(), + startZoom = this._zoom; + + targetCenter = toLatLng(targetCenter); + targetZoom = targetZoom === undefined ? startZoom : targetZoom; + + var w0 = Math.max(size.x, size.y), + w1 = w0 * this.getZoomScale(startZoom, targetZoom), + u1 = (to.distanceTo(from)) || 1, + rho = 1.42, + rho2 = rho * rho; + + function r(i) { + var s1 = i ? -1 : 1, + s2 = i ? w1 : w0, + t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1, + b1 = 2 * s2 * rho2 * u1, + b = t1 / b1, + sq = Math.sqrt(b * b + 1) - b; + + // workaround for floating point precision bug when sq = 0, log = -Infinite, + // thus triggering an infinite loop in flyTo + var log = sq < 0.000000001 ? -18 : Math.log(sq); + + return log; + } + + function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; } + function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; } + function tanh(n) { return sinh(n) / cosh(n); } + + var r0 = r(0); + + function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); } + function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; } + + function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); } + + var start = Date.now(), + S = (r(1) - r0) / rho, + duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8; + + function frame() { + var t = (Date.now() - start) / duration, + s = easeOut(t) * S; + + if (t <= 1) { + this._flyToFrame = requestAnimFrame(frame, this); + + this._move( + this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom), + this.getScaleZoom(w0 / w(s), startZoom), + {flyTo: true}); + + } else { + this + ._move(targetCenter, targetZoom) + ._moveEnd(true); + } + } + + this._moveStart(true, options.noMoveStart); + + frame.call(this); + return this; + }, + + // @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this + // Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto), + // but takes a bounds parameter like [`fitBounds`](#map-fitbounds). + flyToBounds: function (bounds, options) { + var target = this._getBoundsCenterZoom(bounds, options); + return this.flyTo(target.center, target.zoom, options); + }, + + // @method setMaxBounds(bounds: LatLngBounds): this + // Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option). + setMaxBounds: function (bounds) { + bounds = toLatLngBounds(bounds); + + if (this.listens('moveend', this._panInsideMaxBounds)) { + this.off('moveend', this._panInsideMaxBounds); + } + + if (!bounds.isValid()) { + this.options.maxBounds = null; + return this; + } + + this.options.maxBounds = bounds; + + if (this._loaded) { + this._panInsideMaxBounds(); + } + + return this.on('moveend', this._panInsideMaxBounds); + }, + + // @method setMinZoom(zoom: Number): this + // Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option). + setMinZoom: function (zoom) { + var oldZoom = this.options.minZoom; + this.options.minZoom = zoom; + + if (this._loaded && oldZoom !== zoom) { + this.fire('zoomlevelschange'); + + if (this.getZoom() < this.options.minZoom) { + return this.setZoom(zoom); + } + } + + return this; + }, + + // @method setMaxZoom(zoom: Number): this + // Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option). + setMaxZoom: function (zoom) { + var oldZoom = this.options.maxZoom; + this.options.maxZoom = zoom; + + if (this._loaded && oldZoom !== zoom) { + this.fire('zoomlevelschange'); + + if (this.getZoom() > this.options.maxZoom) { + return this.setZoom(zoom); + } + } + + return this; + }, + + // @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this + // Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any. + panInsideBounds: function (bounds, options) { + this._enforcingBounds = true; + var center = this.getCenter(), + newCenter = this._limitCenter(center, this._zoom, toLatLngBounds(bounds)); + + if (!center.equals(newCenter)) { + this.panTo(newCenter, options); + } + + this._enforcingBounds = false; + return this; + }, + + // @method panInside(latlng: LatLng, options?: padding options): this + // Pans the map the minimum amount to make the `latlng` visible. Use + // padding options to fit the display to more restricted bounds. + // If `latlng` is already within the (optionally padded) display bounds, + // the map will not be panned. + panInside: function (latlng, options) { + options = options || {}; + + var paddingTL = toPoint(options.paddingTopLeft || options.padding || [0, 0]), + paddingBR = toPoint(options.paddingBottomRight || options.padding || [0, 0]), + pixelCenter = this.project(this.getCenter()), + pixelPoint = this.project(latlng), + pixelBounds = this.getPixelBounds(), + paddedBounds = toBounds([pixelBounds.min.add(paddingTL), pixelBounds.max.subtract(paddingBR)]), + paddedSize = paddedBounds.getSize(); + + if (!paddedBounds.contains(pixelPoint)) { + this._enforcingBounds = true; + var centerOffset = pixelPoint.subtract(paddedBounds.getCenter()); + var offset = paddedBounds.extend(pixelPoint).getSize().subtract(paddedSize); + pixelCenter.x += centerOffset.x < 0 ? -offset.x : offset.x; + pixelCenter.y += centerOffset.y < 0 ? -offset.y : offset.y; + this.panTo(this.unproject(pixelCenter), options); + this._enforcingBounds = false; + } + return this; + }, + + // @method invalidateSize(options: Zoom/pan options): this + // Checks if the map container size changed and updates the map if so — + // call it after you've changed the map size dynamically, also animating + // pan by default. If `options.pan` is `false`, panning will not occur. + // If `options.debounceMoveend` is `true`, it will delay `moveend` event so + // that it doesn't happen often even if the method is called many + // times in a row. + + // @alternative + // @method invalidateSize(animate: Boolean): this + // Checks if the map container size changed and updates the map if so — + // call it after you've changed the map size dynamically, also animating + // pan by default. + invalidateSize: function (options) { + if (!this._loaded) { return this; } + + options = extend({ + animate: false, + pan: true + }, options === true ? {animate: true} : options); + + var oldSize = this.getSize(); + this._sizeChanged = true; + this._lastCenter = null; + + var newSize = this.getSize(), + oldCenter = oldSize.divideBy(2).round(), + newCenter = newSize.divideBy(2).round(), + offset = oldCenter.subtract(newCenter); + + if (!offset.x && !offset.y) { return this; } + + if (options.animate && options.pan) { + this.panBy(offset); + + } else { + if (options.pan) { + this._rawPanBy(offset); + } + + this.fire('move'); + + if (options.debounceMoveend) { + clearTimeout(this._sizeTimer); + this._sizeTimer = setTimeout(bind(this.fire, this, 'moveend'), 200); + } else { + this.fire('moveend'); + } + } + + // @section Map state change events + // @event resize: ResizeEvent + // Fired when the map is resized. + return this.fire('resize', { + oldSize: oldSize, + newSize: newSize + }); + }, + + // @section Methods for modifying map state + // @method stop(): this + // Stops the currently running `panTo` or `flyTo` animation, if any. + stop: function () { + this.setZoom(this._limitZoom(this._zoom)); + if (!this.options.zoomSnap) { + this.fire('viewreset'); + } + return this._stop(); + }, + + // @section Geolocation methods + // @method locate(options?: Locate options): this + // Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound) + // event with location data on success or a [`locationerror`](#map-locationerror) event on failure, + // and optionally sets the map view to the user's location with respect to + // detection accuracy (or to the world view if geolocation failed). + // Note that, if your page doesn't use HTTPS, this method will fail in + // modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins)) + // See `Locate options` for more details. + locate: function (options) { + + options = this._locateOptions = extend({ + timeout: 10000, + watch: false + // setView: false + // maxZoom: <Number> + // maximumAge: 0 + // enableHighAccuracy: false + }, options); + + if (!('geolocation' in navigator)) { + this._handleGeolocationError({ + code: 0, + message: 'Geolocation not supported.' + }); + return this; + } + + var onResponse = bind(this._handleGeolocationResponse, this), + onError = bind(this._handleGeolocationError, this); + + if (options.watch) { + this._locationWatchId = + navigator.geolocation.watchPosition(onResponse, onError, options); + } else { + navigator.geolocation.getCurrentPosition(onResponse, onError, options); + } + return this; + }, + + // @method stopLocate(): this + // Stops watching location previously initiated by `map.locate({watch: true})` + // and aborts resetting the map view if map.locate was called with + // `{setView: true}`. + stopLocate: function () { + if (navigator.geolocation && navigator.geolocation.clearWatch) { + navigator.geolocation.clearWatch(this._locationWatchId); + } + if (this._locateOptions) { + this._locateOptions.setView = false; + } + return this; + }, + + _handleGeolocationError: function (error) { + if (!this._container._leaflet_id) { return; } + + var c = error.code, + message = error.message || + (c === 1 ? 'permission denied' : + (c === 2 ? 'position unavailable' : 'timeout')); + + if (this._locateOptions.setView && !this._loaded) { + this.fitWorld(); + } + + // @section Location events + // @event locationerror: ErrorEvent + // Fired when geolocation (using the [`locate`](#map-locate) method) failed. + this.fire('locationerror', { + code: c, + message: 'Geolocation error: ' + message + '.' + }); + }, + + _handleGeolocationResponse: function (pos) { + if (!this._container._leaflet_id) { return; } + + var lat = pos.coords.latitude, + lng = pos.coords.longitude, + latlng = new LatLng(lat, lng), + bounds = latlng.toBounds(pos.coords.accuracy * 2), + options = this._locateOptions; + + if (options.setView) { + var zoom = this.getBoundsZoom(bounds); + this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom); + } + + var data = { + latlng: latlng, + bounds: bounds, + timestamp: pos.timestamp + }; + + for (var i in pos.coords) { + if (typeof pos.coords[i] === 'number') { + data[i] = pos.coords[i]; + } + } + + // @event locationfound: LocationEvent + // Fired when geolocation (using the [`locate`](#map-locate) method) + // went successfully. + this.fire('locationfound', data); + }, + + // TODO Appropriate docs section? + // @section Other Methods + // @method addHandler(name: String, HandlerClass: Function): this + // Adds a new `Handler` to the map, given its name and constructor function. + addHandler: function (name, HandlerClass) { + if (!HandlerClass) { return this; } + + var handler = this[name] = new HandlerClass(this); + + this._handlers.push(handler); + + if (this.options[name]) { + handler.enable(); + } + + return this; + }, + + // @method remove(): this + // Destroys the map and clears all related event listeners. + remove: function () { + + this._initEvents(true); + if (this.options.maxBounds) { this.off('moveend', this._panInsideMaxBounds); } + + if (this._containerId !== this._container._leaflet_id) { + throw new Error('Map container is being reused by another instance'); + } + + try { + // throws error in IE6-8 + delete this._container._leaflet_id; + delete this._containerId; + } catch (e) { + /*eslint-disable */ + this._container._leaflet_id = undefined; + /* eslint-enable */ + this._containerId = undefined; + } + + if (this._locationWatchId !== undefined) { + this.stopLocate(); + } + + this._stop(); + + remove(this._mapPane); + + if (this._clearControlPos) { + this._clearControlPos(); + } + if (this._resizeRequest) { + cancelAnimFrame(this._resizeRequest); + this._resizeRequest = null; + } + + this._clearHandlers(); + + if (this._loaded) { + // @section Map state change events + // @event unload: Event + // Fired when the map is destroyed with [remove](#map-remove) method. + this.fire('unload'); + } + + var i; + for (i in this._layers) { + this._layers[i].remove(); + } + for (i in this._panes) { + remove(this._panes[i]); + } + + this._layers = []; + this._panes = []; + delete this._mapPane; + delete this._renderer; + + return this; + }, + + // @section Other Methods + // @method createPane(name: String, container?: HTMLElement): HTMLElement + // Creates a new [map pane](#map-pane) with the given name if it doesn't exist already, + // then returns it. The pane is created as a child of `container`, or + // as a child of the main map pane if not set. + createPane: function (name, container) { + var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''), + pane = create$1('div', className, container || this._mapPane); + + if (name) { + this._panes[name] = pane; + } + return pane; + }, + + // @section Methods for Getting Map State + + // @method getCenter(): LatLng + // Returns the geographical center of the map view + getCenter: function () { + this._checkIfLoaded(); + + if (this._lastCenter && !this._moved()) { + return this._lastCenter.clone(); + } + return this.layerPointToLatLng(this._getCenterLayerPoint()); + }, + + // @method getZoom(): Number + // Returns the current zoom level of the map view + getZoom: function () { + return this._zoom; + }, + + // @method getBounds(): LatLngBounds + // Returns the geographical bounds visible in the current map view + getBounds: function () { + var bounds = this.getPixelBounds(), + sw = this.unproject(bounds.getBottomLeft()), + ne = this.unproject(bounds.getTopRight()); + + return new LatLngBounds(sw, ne); + }, + + // @method getMinZoom(): Number + // Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default. + getMinZoom: function () { + return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom; + }, + + // @method getMaxZoom(): Number + // Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers). + getMaxZoom: function () { + return this.options.maxZoom === undefined ? + (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) : + this.options.maxZoom; + }, + + // @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean, padding?: Point): Number + // Returns the maximum zoom level on which the given bounds fit to the map + // view in its entirety. If `inside` (optional) is set to `true`, the method + // instead returns the minimum zoom level on which the map view fits into + // the given bounds in its entirety. + getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number + bounds = toLatLngBounds(bounds); + padding = toPoint(padding || [0, 0]); + + var zoom = this.getZoom() || 0, + min = this.getMinZoom(), + max = this.getMaxZoom(), + nw = bounds.getNorthWest(), + se = bounds.getSouthEast(), + size = this.getSize().subtract(padding), + boundsSize = toBounds(this.project(se, zoom), this.project(nw, zoom)).getSize(), + snap = Browser.any3d ? this.options.zoomSnap : 1, + scalex = size.x / boundsSize.x, + scaley = size.y / boundsSize.y, + scale = inside ? Math.max(scalex, scaley) : Math.min(scalex, scaley); + + zoom = this.getScaleZoom(scale, zoom); + + if (snap) { + zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level + zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap; + } + + return Math.max(min, Math.min(max, zoom)); + }, + + // @method getSize(): Point + // Returns the current size of the map container (in pixels). + getSize: function () { + if (!this._size || this._sizeChanged) { + this._size = new Point( + this._container.clientWidth || 0, + this._container.clientHeight || 0); + + this._sizeChanged = false; + } + return this._size.clone(); + }, + + // @method getPixelBounds(): Bounds + // Returns the bounds of the current map view in projected pixel + // coordinates (sometimes useful in layer and overlay implementations). + getPixelBounds: function (center, zoom) { + var topLeftPoint = this._getTopLeftPoint(center, zoom); + return new Bounds(topLeftPoint, topLeftPoint.add(this.getSize())); + }, + + // TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to + // the map pane? "left point of the map layer" can be confusing, specially + // since there can be negative offsets. + // @method getPixelOrigin(): Point + // Returns the projected pixel coordinates of the top left point of + // the map layer (useful in custom layer and overlay implementations). + getPixelOrigin: function () { + this._checkIfLoaded(); + return this._pixelOrigin; + }, + + // @method getPixelWorldBounds(zoom?: Number): Bounds + // Returns the world's bounds in pixel coordinates for zoom level `zoom`. + // If `zoom` is omitted, the map's current zoom level is used. + getPixelWorldBounds: function (zoom) { + return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom); + }, + + // @section Other Methods + + // @method getPane(pane: String|HTMLElement): HTMLElement + // Returns a [map pane](#map-pane), given its name or its HTML element (its identity). + getPane: function (pane) { + return typeof pane === 'string' ? this._panes[pane] : pane; + }, + + // @method getPanes(): Object + // Returns a plain object containing the names of all [panes](#map-pane) as keys and + // the panes as values. + getPanes: function () { + return this._panes; + }, + + // @method getContainer: HTMLElement + // Returns the HTML element that contains the map. + getContainer: function () { + return this._container; + }, + + + // @section Conversion Methods + + // @method getZoomScale(toZoom: Number, fromZoom: Number): Number + // Returns the scale factor to be applied to a map transition from zoom level + // `fromZoom` to `toZoom`. Used internally to help with zoom animations. + getZoomScale: function (toZoom, fromZoom) { + // TODO replace with universal implementation after refactoring projections + var crs = this.options.crs; + fromZoom = fromZoom === undefined ? this._zoom : fromZoom; + return crs.scale(toZoom) / crs.scale(fromZoom); + }, + + // @method getScaleZoom(scale: Number, fromZoom: Number): Number + // Returns the zoom level that the map would end up at, if it is at `fromZoom` + // level and everything is scaled by a factor of `scale`. Inverse of + // [`getZoomScale`](#map-getZoomScale). + getScaleZoom: function (scale, fromZoom) { + var crs = this.options.crs; + fromZoom = fromZoom === undefined ? this._zoom : fromZoom; + var zoom = crs.zoom(scale * crs.scale(fromZoom)); + return isNaN(zoom) ? Infinity : zoom; + }, + + // @method project(latlng: LatLng, zoom: Number): Point + // Projects a geographical coordinate `LatLng` according to the projection + // of the map's CRS, then scales it according to `zoom` and the CRS's + // `Transformation`. The result is pixel coordinate relative to + // the CRS origin. + project: function (latlng, zoom) { + zoom = zoom === undefined ? this._zoom : zoom; + return this.options.crs.latLngToPoint(toLatLng(latlng), zoom); + }, + + // @method unproject(point: Point, zoom: Number): LatLng + // Inverse of [`project`](#map-project). + unproject: function (point, zoom) { + zoom = zoom === undefined ? this._zoom : zoom; + return this.options.crs.pointToLatLng(toPoint(point), zoom); + }, + + // @method layerPointToLatLng(point: Point): LatLng + // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin), + // returns the corresponding geographical coordinate (for the current zoom level). + layerPointToLatLng: function (point) { + var projectedPoint = toPoint(point).add(this.getPixelOrigin()); + return this.unproject(projectedPoint); + }, + + // @method latLngToLayerPoint(latlng: LatLng): Point + // Given a geographical coordinate, returns the corresponding pixel coordinate + // relative to the [origin pixel](#map-getpixelorigin). + latLngToLayerPoint: function (latlng) { + var projectedPoint = this.project(toLatLng(latlng))._round(); + return projectedPoint._subtract(this.getPixelOrigin()); + }, + + // @method wrapLatLng(latlng: LatLng): LatLng + // Returns a `LatLng` where `lat` and `lng` has been wrapped according to the + // map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the + // CRS's bounds. + // By default this means longitude is wrapped around the dateline so its + // value is between -180 and +180 degrees. + wrapLatLng: function (latlng) { + return this.options.crs.wrapLatLng(toLatLng(latlng)); + }, + + // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds + // Returns a `LatLngBounds` with the same size as the given one, ensuring that + // its center is within the CRS's bounds. + // By default this means the center longitude is wrapped around the dateline so its + // value is between -180 and +180 degrees, and the majority of the bounds + // overlaps the CRS's bounds. + wrapLatLngBounds: function (latlng) { + return this.options.crs.wrapLatLngBounds(toLatLngBounds(latlng)); + }, + + // @method distance(latlng1: LatLng, latlng2: LatLng): Number + // Returns the distance between two geographical coordinates according to + // the map's CRS. By default this measures distance in meters. + distance: function (latlng1, latlng2) { + return this.options.crs.distance(toLatLng(latlng1), toLatLng(latlng2)); + }, + + // @method containerPointToLayerPoint(point: Point): Point + // Given a pixel coordinate relative to the map container, returns the corresponding + // pixel coordinate relative to the [origin pixel](#map-getpixelorigin). + containerPointToLayerPoint: function (point) { // (Point) + return toPoint(point).subtract(this._getMapPanePos()); + }, + + // @method layerPointToContainerPoint(point: Point): Point + // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin), + // returns the corresponding pixel coordinate relative to the map container. + layerPointToContainerPoint: function (point) { // (Point) + return toPoint(point).add(this._getMapPanePos()); + }, + + // @method containerPointToLatLng(point: Point): LatLng + // Given a pixel coordinate relative to the map container, returns + // the corresponding geographical coordinate (for the current zoom level). + containerPointToLatLng: function (point) { + var layerPoint = this.containerPointToLayerPoint(toPoint(point)); + return this.layerPointToLatLng(layerPoint); + }, + + // @method latLngToContainerPoint(latlng: LatLng): Point + // Given a geographical coordinate, returns the corresponding pixel coordinate + // relative to the map container. + latLngToContainerPoint: function (latlng) { + return this.layerPointToContainerPoint(this.latLngToLayerPoint(toLatLng(latlng))); + }, + + // @method mouseEventToContainerPoint(ev: MouseEvent): Point + // Given a MouseEvent object, returns the pixel coordinate relative to the + // map container where the event took place. + mouseEventToContainerPoint: function (e) { + return getMousePosition(e, this._container); + }, + + // @method mouseEventToLayerPoint(ev: MouseEvent): Point + // Given a MouseEvent object, returns the pixel coordinate relative to + // the [origin pixel](#map-getpixelorigin) where the event took place. + mouseEventToLayerPoint: function (e) { + return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e)); + }, + + // @method mouseEventToLatLng(ev: MouseEvent): LatLng + // Given a MouseEvent object, returns geographical coordinate where the + // event took place. + mouseEventToLatLng: function (e) { // (MouseEvent) + return this.layerPointToLatLng(this.mouseEventToLayerPoint(e)); + }, + + + // map initialization methods + + _initContainer: function (id) { + var container = this._container = get(id); + + if (!container) { + throw new Error('Map container not found.'); + } else if (container._leaflet_id) { + throw new Error('Map container is already initialized.'); + } + + on(container, 'scroll', this._onScroll, this); + this._containerId = stamp(container); + }, + + _initLayout: function () { + var container = this._container; + + this._fadeAnimated = this.options.fadeAnimation && Browser.any3d; + + addClass(container, 'leaflet-container' + + (Browser.touch ? ' leaflet-touch' : '') + + (Browser.retina ? ' leaflet-retina' : '') + + (Browser.ielt9 ? ' leaflet-oldie' : '') + + (Browser.safari ? ' leaflet-safari' : '') + + (this._fadeAnimated ? ' leaflet-fade-anim' : '')); + + var position = getStyle(container, 'position'); + + if (position !== 'absolute' && position !== 'relative' && position !== 'fixed' && position !== 'sticky') { + container.style.position = 'relative'; + } + + this._initPanes(); + + if (this._initControlPos) { + this._initControlPos(); + } + }, + + _initPanes: function () { + var panes = this._panes = {}; + this._paneRenderers = {}; + + // @section + // + // Panes are DOM elements used to control the ordering of layers on the map. You + // can access panes with [`map.getPane`](#map-getpane) or + // [`map.getPanes`](#map-getpanes) methods. New panes can be created with the + // [`map.createPane`](#map-createpane) method. + // + // Every map has the following default panes that differ only in zIndex. + // + // @pane mapPane: HTMLElement = 'auto' + // Pane that contains all other map panes + + this._mapPane = this.createPane('mapPane', this._container); + setPosition(this._mapPane, new Point(0, 0)); + + // @pane tilePane: HTMLElement = 200 + // Pane for `GridLayer`s and `TileLayer`s + this.createPane('tilePane'); + // @pane overlayPane: HTMLElement = 400 + // Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s + this.createPane('overlayPane'); + // @pane shadowPane: HTMLElement = 500 + // Pane for overlay shadows (e.g. `Marker` shadows) + this.createPane('shadowPane'); + // @pane markerPane: HTMLElement = 600 + // Pane for `Icon`s of `Marker`s + this.createPane('markerPane'); + // @pane tooltipPane: HTMLElement = 650 + // Pane for `Tooltip`s. + this.createPane('tooltipPane'); + // @pane popupPane: HTMLElement = 700 + // Pane for `Popup`s. + this.createPane('popupPane'); + + if (!this.options.markerZoomAnimation) { + addClass(panes.markerPane, 'leaflet-zoom-hide'); + addClass(panes.shadowPane, 'leaflet-zoom-hide'); + } + }, + + + // private methods that modify map state + + // @section Map state change events + _resetView: function (center, zoom, noMoveStart) { + setPosition(this._mapPane, new Point(0, 0)); + + var loading = !this._loaded; + this._loaded = true; + zoom = this._limitZoom(zoom); + + this.fire('viewprereset'); + + var zoomChanged = this._zoom !== zoom; + this + ._moveStart(zoomChanged, noMoveStart) + ._move(center, zoom) + ._moveEnd(zoomChanged); + + // @event viewreset: Event + // Fired when the map needs to redraw its content (this usually happens + // on map zoom or load). Very useful for creating custom overlays. + this.fire('viewreset'); + + // @event load: Event + // Fired when the map is initialized (when its center and zoom are set + // for the first time). + if (loading) { + this.fire('load'); + } + }, + + _moveStart: function (zoomChanged, noMoveStart) { + // @event zoomstart: Event + // Fired when the map zoom is about to change (e.g. before zoom animation). + // @event movestart: Event + // Fired when the view of the map starts changing (e.g. user starts dragging the map). + if (zoomChanged) { + this.fire('zoomstart'); + } + if (!noMoveStart) { + this.fire('movestart'); + } + return this; + }, + + _move: function (center, zoom, data, supressEvent) { + if (zoom === undefined) { + zoom = this._zoom; + } + var zoomChanged = this._zoom !== zoom; + + this._zoom = zoom; + this._lastCenter = center; + this._pixelOrigin = this._getNewPixelOrigin(center); + + if (!supressEvent) { + // @event zoom: Event + // Fired repeatedly during any change in zoom level, + // including zoom and fly animations. + if (zoomChanged || (data && data.pinch)) { // Always fire 'zoom' if pinching because #3530 + this.fire('zoom', data); + } + + // @event move: Event + // Fired repeatedly during any movement of the map, + // including pan and fly animations. + this.fire('move', data); + } else if (data && data.pinch) { // Always fire 'zoom' if pinching because #3530 + this.fire('zoom', data); + } + return this; + }, + + _moveEnd: function (zoomChanged) { + // @event zoomend: Event + // Fired when the map zoom changed, after any animations. + if (zoomChanged) { + this.fire('zoomend'); + } + + // @event moveend: Event + // Fired when the center of the map stops changing + // (e.g. user stopped dragging the map or after non-centered zoom). + return this.fire('moveend'); + }, + + _stop: function () { + cancelAnimFrame(this._flyToFrame); + if (this._panAnim) { + this._panAnim.stop(); + } + return this; + }, + + _rawPanBy: function (offset) { + setPosition(this._mapPane, this._getMapPanePos().subtract(offset)); + }, + + _getZoomSpan: function () { + return this.getMaxZoom() - this.getMinZoom(); + }, + + _panInsideMaxBounds: function () { + if (!this._enforcingBounds) { + this.panInsideBounds(this.options.maxBounds); + } + }, + + _checkIfLoaded: function () { + if (!this._loaded) { + throw new Error('Set map center and zoom first.'); + } + }, + + // DOM event handling + + // @section Interaction events + _initEvents: function (remove) { + this._targets = {}; + this._targets[stamp(this._container)] = this; + + var onOff = remove ? off : on; + + // @event click: MouseEvent + // Fired when the user clicks (or taps) the map. + // @event dblclick: MouseEvent + // Fired when the user double-clicks (or double-taps) the map. + // @event mousedown: MouseEvent + // Fired when the user pushes the mouse button on the map. + // @event mouseup: MouseEvent + // Fired when the user releases the mouse button on the map. + // @event mouseover: MouseEvent + // Fired when the mouse enters the map. + // @event mouseout: MouseEvent + // Fired when the mouse leaves the map. + // @event mousemove: MouseEvent + // Fired while the mouse moves over the map. + // @event contextmenu: MouseEvent + // Fired when the user pushes the right mouse button on the map, prevents + // default browser context menu from showing if there are listeners on + // this event. Also fired on mobile when the user holds a single touch + // for a second (also called long press). + // @event keypress: KeyboardEvent + // Fired when the user presses a key from the keyboard that produces a character value while the map is focused. + // @event keydown: KeyboardEvent + // Fired when the user presses a key from the keyboard while the map is focused. Unlike the `keypress` event, + // the `keydown` event is fired for keys that produce a character value and for keys + // that do not produce a character value. + // @event keyup: KeyboardEvent + // Fired when the user releases a key from the keyboard while the map is focused. + onOff(this._container, 'click dblclick mousedown mouseup ' + + 'mouseover mouseout mousemove contextmenu keypress keydown keyup', this._handleDOMEvent, this); + + if (this.options.trackResize) { + onOff(window, 'resize', this._onResize, this); + } + + if (Browser.any3d && this.options.transform3DLimit) { + (remove ? this.off : this.on).call(this, 'moveend', this._onMoveEnd); + } + }, + + _onResize: function () { + cancelAnimFrame(this._resizeRequest); + this._resizeRequest = requestAnimFrame( + function () { this.invalidateSize({debounceMoveend: true}); }, this); + }, + + _onScroll: function () { + this._container.scrollTop = 0; + this._container.scrollLeft = 0; + }, + + _onMoveEnd: function () { + var pos = this._getMapPanePos(); + if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) { + // https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have + // a pixel offset on very high values, see: https://jsfiddle.net/dg6r5hhb/ + this._resetView(this.getCenter(), this.getZoom()); + } + }, + + _findEventTargets: function (e, type) { + var targets = [], + target, + isHover = type === 'mouseout' || type === 'mouseover', + src = e.target || e.srcElement, + dragging = false; + + while (src) { + target = this._targets[stamp(src)]; + if (target && (type === 'click' || type === 'preclick') && this._draggableMoved(target)) { + // Prevent firing click after you just dragged an object. + dragging = true; + break; + } + if (target && target.listens(type, true)) { + if (isHover && !isExternalTarget(src, e)) { break; } + targets.push(target); + if (isHover) { break; } + } + if (src === this._container) { break; } + src = src.parentNode; + } + if (!targets.length && !dragging && !isHover && this.listens(type, true)) { + targets = [this]; + } + return targets; + }, + + _isClickDisabled: function (el) { + while (el && el !== this._container) { + if (el['_leaflet_disable_click']) { return true; } + el = el.parentNode; + } + }, + + _handleDOMEvent: function (e) { + var el = (e.target || e.srcElement); + if (!this._loaded || el['_leaflet_disable_events'] || e.type === 'click' && this._isClickDisabled(el)) { + return; + } + + var type = e.type; + + if (type === 'mousedown') { + // prevents outline when clicking on keyboard-focusable element + preventOutline(el); + } + + this._fireDOMEvent(e, type); + }, + + _mouseEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu'], + + _fireDOMEvent: function (e, type, canvasTargets) { + + if (e.type === 'click') { + // Fire a synthetic 'preclick' event which propagates up (mainly for closing popups). + // @event preclick: MouseEvent + // Fired before mouse click on the map (sometimes useful when you + // want something to happen on click before any existing click + // handlers start running). + var synth = extend({}, e); + synth.type = 'preclick'; + this._fireDOMEvent(synth, synth.type, canvasTargets); + } + + // Find the layer the event is propagating from and its parents. + var targets = this._findEventTargets(e, type); + + if (canvasTargets) { + var filtered = []; // pick only targets with listeners + for (var i = 0; i < canvasTargets.length; i++) { + if (canvasTargets[i].listens(type, true)) { + filtered.push(canvasTargets[i]); + } + } + targets = filtered.concat(targets); + } + + if (!targets.length) { return; } + + if (type === 'contextmenu') { + preventDefault(e); + } + + var target = targets[0]; + var data = { + originalEvent: e + }; + + if (e.type !== 'keypress' && e.type !== 'keydown' && e.type !== 'keyup') { + var isMarker = target.getLatLng && (!target._radius || target._radius <= 10); + data.containerPoint = isMarker ? + this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e); + data.layerPoint = this.containerPointToLayerPoint(data.containerPoint); + data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint); + } + + for (i = 0; i < targets.length; i++) { + targets[i].fire(type, data, true); + if (data.originalEvent._stopped || + (targets[i].options.bubblingMouseEvents === false && indexOf(this._mouseEvents, type) !== -1)) { return; } + } + }, + + _draggableMoved: function (obj) { + obj = obj.dragging && obj.dragging.enabled() ? obj : this; + return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved()); + }, + + _clearHandlers: function () { + for (var i = 0, len = this._handlers.length; i < len; i++) { + this._handlers[i].disable(); + } + }, + + // @section Other Methods + + // @method whenReady(fn: Function, context?: Object): this + // Runs the given function `fn` when the map gets initialized with + // a view (center and zoom) and at least one layer, or immediately + // if it's already initialized, optionally passing a function context. + whenReady: function (callback, context) { + if (this._loaded) { + callback.call(context || this, {target: this}); + } else { + this.on('load', callback, context); + } + return this; + }, + + + // private methods for getting map state + + _getMapPanePos: function () { + return getPosition(this._mapPane) || new Point(0, 0); + }, + + _moved: function () { + var pos = this._getMapPanePos(); + return pos && !pos.equals([0, 0]); + }, + + _getTopLeftPoint: function (center, zoom) { + var pixelOrigin = center && zoom !== undefined ? + this._getNewPixelOrigin(center, zoom) : + this.getPixelOrigin(); + return pixelOrigin.subtract(this._getMapPanePos()); + }, + + _getNewPixelOrigin: function (center, zoom) { + var viewHalf = this.getSize()._divideBy(2); + return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round(); + }, + + _latLngToNewLayerPoint: function (latlng, zoom, center) { + var topLeft = this._getNewPixelOrigin(center, zoom); + return this.project(latlng, zoom)._subtract(topLeft); + }, + + _latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) { + var topLeft = this._getNewPixelOrigin(center, zoom); + return toBounds([ + this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft), + this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft), + this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft), + this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft) + ]); + }, + + // layer point of the current center + _getCenterLayerPoint: function () { + return this.containerPointToLayerPoint(this.getSize()._divideBy(2)); + }, + + // offset of the specified place to the current center in pixels + _getCenterOffset: function (latlng) { + return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint()); + }, + + // adjust center for view to get inside bounds + _limitCenter: function (center, zoom, bounds) { + + if (!bounds) { return center; } + + var centerPoint = this.project(center, zoom), + viewHalf = this.getSize().divideBy(2), + viewBounds = new Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)), + offset = this._getBoundsOffset(viewBounds, bounds, zoom); + + // If offset is less than a pixel, ignore. + // This prevents unstable projections from getting into + // an infinite loop of tiny offsets. + if (Math.abs(offset.x) <= 1 && Math.abs(offset.y) <= 1) { + return center; + } + + return this.unproject(centerPoint.add(offset), zoom); + }, + + // adjust offset for view to get inside bounds + _limitOffset: function (offset, bounds) { + if (!bounds) { return offset; } + + var viewBounds = this.getPixelBounds(), + newBounds = new Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset)); + + return offset.add(this._getBoundsOffset(newBounds, bounds)); + }, + + // returns offset needed for pxBounds to get inside maxBounds at a specified zoom + _getBoundsOffset: function (pxBounds, maxBounds, zoom) { + var projectedMaxBounds = toBounds( + this.project(maxBounds.getNorthEast(), zoom), + this.project(maxBounds.getSouthWest(), zoom) + ), + minOffset = projectedMaxBounds.min.subtract(pxBounds.min), + maxOffset = projectedMaxBounds.max.subtract(pxBounds.max), + + dx = this._rebound(minOffset.x, -maxOffset.x), + dy = this._rebound(minOffset.y, -maxOffset.y); + + return new Point(dx, dy); + }, + + _rebound: function (left, right) { + return left + right > 0 ? + Math.round(left - right) / 2 : + Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right)); + }, + + _limitZoom: function (zoom) { + var min = this.getMinZoom(), + max = this.getMaxZoom(), + snap = Browser.any3d ? this.options.zoomSnap : 1; + if (snap) { + zoom = Math.round(zoom / snap) * snap; + } + return Math.max(min, Math.min(max, zoom)); + }, + + _onPanTransitionStep: function () { + this.fire('move'); + }, + + _onPanTransitionEnd: function () { + removeClass(this._mapPane, 'leaflet-pan-anim'); + this.fire('moveend'); + }, + + _tryAnimatedPan: function (center, options) { + // difference between the new and current centers in pixels + var offset = this._getCenterOffset(center)._trunc(); + + // don't animate too far unless animate: true specified in options + if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; } + + this.panBy(offset, options); + + return true; + }, + + _createAnimProxy: function () { + + var proxy = this._proxy = create$1('div', 'leaflet-proxy leaflet-zoom-animated'); + this._panes.mapPane.appendChild(proxy); + + this.on('zoomanim', function (e) { + var prop = TRANSFORM, + transform = this._proxy.style[prop]; + + setTransform(this._proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1)); + + // workaround for case when transform is the same and so transitionend event is not fired + if (transform === this._proxy.style[prop] && this._animatingZoom) { + this._onZoomTransitionEnd(); + } + }, this); + + this.on('load moveend', this._animMoveEnd, this); + + this._on('unload', this._destroyAnimProxy, this); + }, + + _destroyAnimProxy: function () { + remove(this._proxy); + this.off('load moveend', this._animMoveEnd, this); + delete this._proxy; + }, + + _animMoveEnd: function () { + var c = this.getCenter(), + z = this.getZoom(); + setTransform(this._proxy, this.project(c, z), this.getZoomScale(z, 1)); + }, + + _catchTransitionEnd: function (e) { + if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) { + this._onZoomTransitionEnd(); + } + }, + + _nothingToAnimate: function () { + return !this._container.getElementsByClassName('leaflet-zoom-animated').length; + }, + + _tryAnimatedZoom: function (center, zoom, options) { + + if (this._animatingZoom) { return true; } + + options = options || {}; + + // don't animate if disabled, not supported or zoom difference is too large + if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() || + Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; } + + // offset is the pixel coords of the zoom origin relative to the current center + var scale = this.getZoomScale(zoom), + offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale); + + // don't animate if the zoom origin isn't within one screen from the current center, unless forced + if (options.animate !== true && !this.getSize().contains(offset)) { return false; } + + requestAnimFrame(function () { + this + ._moveStart(true, options.noMoveStart || false) + ._animateZoom(center, zoom, true); + }, this); + + return true; + }, + + _animateZoom: function (center, zoom, startAnim, noUpdate) { + if (!this._mapPane) { return; } + + if (startAnim) { + this._animatingZoom = true; + + // remember what center/zoom to set after animation + this._animateToCenter = center; + this._animateToZoom = zoom; + + addClass(this._mapPane, 'leaflet-zoom-anim'); + } + + // @section Other Events + // @event zoomanim: ZoomAnimEvent + // Fired at least once per zoom animation. For continuous zoom, like pinch zooming, fired once per frame during zoom. + this.fire('zoomanim', { + center: center, + zoom: zoom, + noUpdate: noUpdate + }); + + if (!this._tempFireZoomEvent) { + this._tempFireZoomEvent = this._zoom !== this._animateToZoom; + } + + this._move(this._animateToCenter, this._animateToZoom, undefined, true); + + // Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693 + setTimeout(bind(this._onZoomTransitionEnd, this), 250); + }, + + _onZoomTransitionEnd: function () { + if (!this._animatingZoom) { return; } + + if (this._mapPane) { + removeClass(this._mapPane, 'leaflet-zoom-anim'); + } + + this._animatingZoom = false; + + this._move(this._animateToCenter, this._animateToZoom, undefined, true); + + if (this._tempFireZoomEvent) { + this.fire('zoom'); + } + delete this._tempFireZoomEvent; + + this.fire('move'); + + this._moveEnd(true); + } +}); + +// @section + +// @factory L.map(id: String, options?: Map options) +// Instantiates a map object given the DOM ID of a `<div>` element +// and optionally an object literal with `Map options`. +// +// @alternative +// @factory L.map(el: HTMLElement, options?: Map options) +// Instantiates a map object given an instance of a `<div>` HTML element +// and optionally an object literal with `Map options`. +function createMap(id, options) { + return new Map(id, options); +} + +/* + * @class Control + * @aka L.Control + * @inherits Class + * + * L.Control is a base class for implementing map controls. Handles positioning. + * All other controls extend from this class. + */ + +var Control = Class.extend({ + // @section + // @aka Control Options + options: { + // @option position: String = 'topright' + // The position of the control (one of the map corners). Possible values are `'topleft'`, + // `'topright'`, `'bottomleft'` or `'bottomright'` + position: 'topright' + }, + + initialize: function (options) { + setOptions(this, options); + }, + + /* @section + * Classes extending L.Control will inherit the following methods: + * + * @method getPosition: string + * Returns the position of the control. + */ + getPosition: function () { + return this.options.position; + }, + + // @method setPosition(position: string): this + // Sets the position of the control. + setPosition: function (position) { + var map = this._map; + + if (map) { + map.removeControl(this); + } + + this.options.position = position; + + if (map) { + map.addControl(this); + } + + return this; + }, + + // @method getContainer: HTMLElement + // Returns the HTMLElement that contains the control. + getContainer: function () { + return this._container; + }, + + // @method addTo(map: Map): this + // Adds the control to the given map. + addTo: function (map) { + this.remove(); + this._map = map; + + var container = this._container = this.onAdd(map), + pos = this.getPosition(), + corner = map._controlCorners[pos]; + + addClass(container, 'leaflet-control'); + + if (pos.indexOf('bottom') !== -1) { + corner.insertBefore(container, corner.firstChild); + } else { + corner.appendChild(container); + } + + this._map.on('unload', this.remove, this); + + return this; + }, + + // @method remove: this + // Removes the control from the map it is currently active on. + remove: function () { + if (!this._map) { + return this; + } + + remove(this._container); + + if (this.onRemove) { + this.onRemove(this._map); + } + + this._map.off('unload', this.remove, this); + this._map = null; + + return this; + }, + + _refocusOnMap: function (e) { + // if map exists and event is not a keyboard event + if (this._map && e && e.screenX > 0 && e.screenY > 0) { + this._map.getContainer().focus(); + } + } +}); + +var control = function (options) { + return new Control(options); +}; + +/* @section Extension methods + * @uninheritable + * + * Every control should extend from `L.Control` and (re-)implement the following methods. + * + * @method onAdd(map: Map): HTMLElement + * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo). + * + * @method onRemove(map: Map) + * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove). + */ + +/* @namespace Map + * @section Methods for Layers and Controls + */ +Map.include({ + // @method addControl(control: Control): this + // Adds the given control to the map + addControl: function (control) { + control.addTo(this); + return this; + }, + + // @method removeControl(control: Control): this + // Removes the given control from the map + removeControl: function (control) { + control.remove(); + return this; + }, + + _initControlPos: function () { + var corners = this._controlCorners = {}, + l = 'leaflet-', + container = this._controlContainer = + create$1('div', l + 'control-container', this._container); + + function createCorner(vSide, hSide) { + var className = l + vSide + ' ' + l + hSide; + + corners[vSide + hSide] = create$1('div', className, container); + } + + createCorner('top', 'left'); + createCorner('top', 'right'); + createCorner('bottom', 'left'); + createCorner('bottom', 'right'); + }, + + _clearControlPos: function () { + for (var i in this._controlCorners) { + remove(this._controlCorners[i]); + } + remove(this._controlContainer); + delete this._controlCorners; + delete this._controlContainer; + } +}); + +/* + * @class Control.Layers + * @aka L.Control.Layers + * @inherits Control + * + * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](https://leafletjs.com/examples/layers-control/)). Extends `Control`. + * + * @example + * + * ```js + * var baseLayers = { + * "Mapbox": mapbox, + * "OpenStreetMap": osm + * }; + * + * var overlays = { + * "Marker": marker, + * "Roads": roadsLayer + * }; + * + * L.control.layers(baseLayers, overlays).addTo(map); + * ``` + * + * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values: + * + * ```js + * { + * "<someName1>": layer1, + * "<someName2>": layer2 + * } + * ``` + * + * The layer names can contain HTML, which allows you to add additional styling to the items: + * + * ```js + * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer} + * ``` + */ + +var Layers = Control.extend({ + // @section + // @aka Control.Layers options + options: { + // @option collapsed: Boolean = true + // If `true`, the control will be collapsed into an icon and expanded on mouse hover, touch, or keyboard activation. + collapsed: true, + position: 'topright', + + // @option autoZIndex: Boolean = true + // If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off. + autoZIndex: true, + + // @option hideSingleBase: Boolean = false + // If `true`, the base layers in the control will be hidden when there is only one. + hideSingleBase: false, + + // @option sortLayers: Boolean = false + // Whether to sort the layers. When `false`, layers will keep the order + // in which they were added to the control. + sortLayers: false, + + // @option sortFunction: Function = * + // A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) + // that will be used for sorting the layers, when `sortLayers` is `true`. + // The function receives both the `L.Layer` instances and their names, as in + // `sortFunction(layerA, layerB, nameA, nameB)`. + // By default, it sorts layers alphabetically by their name. + sortFunction: function (layerA, layerB, nameA, nameB) { + return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0); + } + }, + + initialize: function (baseLayers, overlays, options) { + setOptions(this, options); + + this._layerControlInputs = []; + this._layers = []; + this._lastZIndex = 0; + this._handlingClick = false; + this._preventClick = false; + + for (var i in baseLayers) { + this._addLayer(baseLayers[i], i); + } + + for (i in overlays) { + this._addLayer(overlays[i], i, true); + } + }, + + onAdd: function (map) { + this._initLayout(); + this._update(); + + this._map = map; + map.on('zoomend', this._checkDisabledLayers, this); + + for (var i = 0; i < this._layers.length; i++) { + this._layers[i].layer.on('add remove', this._onLayerChange, this); + } + + return this._container; + }, + + addTo: function (map) { + Control.prototype.addTo.call(this, map); + // Trigger expand after Layers Control has been inserted into DOM so that is now has an actual height. + return this._expandIfNotCollapsed(); + }, + + onRemove: function () { + this._map.off('zoomend', this._checkDisabledLayers, this); + + for (var i = 0; i < this._layers.length; i++) { + this._layers[i].layer.off('add remove', this._onLayerChange, this); + } + }, + + // @method addBaseLayer(layer: Layer, name: String): this + // Adds a base layer (radio button entry) with the given name to the control. + addBaseLayer: function (layer, name) { + this._addLayer(layer, name); + return (this._map) ? this._update() : this; + }, + + // @method addOverlay(layer: Layer, name: String): this + // Adds an overlay (checkbox entry) with the given name to the control. + addOverlay: function (layer, name) { + this._addLayer(layer, name, true); + return (this._map) ? this._update() : this; + }, + + // @method removeLayer(layer: Layer): this + // Remove the given layer from the control. + removeLayer: function (layer) { + layer.off('add remove', this._onLayerChange, this); + + var obj = this._getLayer(stamp(layer)); + if (obj) { + this._layers.splice(this._layers.indexOf(obj), 1); + } + return (this._map) ? this._update() : this; + }, + + // @method expand(): this + // Expand the control container if collapsed. + expand: function () { + addClass(this._container, 'leaflet-control-layers-expanded'); + this._section.style.height = null; + var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50); + if (acceptableHeight < this._section.clientHeight) { + addClass(this._section, 'leaflet-control-layers-scrollbar'); + this._section.style.height = acceptableHeight + 'px'; + } else { + removeClass(this._section, 'leaflet-control-layers-scrollbar'); + } + this._checkDisabledLayers(); + return this; + }, + + // @method collapse(): this + // Collapse the control container if expanded. + collapse: function () { + removeClass(this._container, 'leaflet-control-layers-expanded'); + return this; + }, + + _initLayout: function () { + var className = 'leaflet-control-layers', + container = this._container = create$1('div', className), + collapsed = this.options.collapsed; + + // makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released + container.setAttribute('aria-haspopup', true); + + disableClickPropagation(container); + disableScrollPropagation(container); + + var section = this._section = create$1('section', className + '-list'); + + if (collapsed) { + this._map.on('click', this.collapse, this); + + on(container, { + mouseenter: this._expandSafely, + mouseleave: this.collapse + }, this); + } + + var link = this._layersLink = create$1('a', className + '-toggle', container); + link.href = '#'; + link.title = 'Layers'; + link.setAttribute('role', 'button'); + + on(link, { + keydown: function (e) { + if (e.keyCode === 13) { + this._expandSafely(); + } + }, + // Certain screen readers intercept the key event and instead send a click event + click: function (e) { + preventDefault(e); + this._expandSafely(); + } + }, this); + + if (!collapsed) { + this.expand(); + } + + this._baseLayersList = create$1('div', className + '-base', section); + this._separator = create$1('div', className + '-separator', section); + this._overlaysList = create$1('div', className + '-overlays', section); + + container.appendChild(section); + }, + + _getLayer: function (id) { + for (var i = 0; i < this._layers.length; i++) { + + if (this._layers[i] && stamp(this._layers[i].layer) === id) { + return this._layers[i]; + } + } + }, + + _addLayer: function (layer, name, overlay) { + if (this._map) { + layer.on('add remove', this._onLayerChange, this); + } + + this._layers.push({ + layer: layer, + name: name, + overlay: overlay + }); + + if (this.options.sortLayers) { + this._layers.sort(bind(function (a, b) { + return this.options.sortFunction(a.layer, b.layer, a.name, b.name); + }, this)); + } + + if (this.options.autoZIndex && layer.setZIndex) { + this._lastZIndex++; + layer.setZIndex(this._lastZIndex); + } + + this._expandIfNotCollapsed(); + }, + + _update: function () { + if (!this._container) { return this; } + + empty(this._baseLayersList); + empty(this._overlaysList); + + this._layerControlInputs = []; + var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0; + + for (i = 0; i < this._layers.length; i++) { + obj = this._layers[i]; + this._addItem(obj); + overlaysPresent = overlaysPresent || obj.overlay; + baseLayersPresent = baseLayersPresent || !obj.overlay; + baseLayersCount += !obj.overlay ? 1 : 0; + } + + // Hide base layers section if there's only one layer. + if (this.options.hideSingleBase) { + baseLayersPresent = baseLayersPresent && baseLayersCount > 1; + this._baseLayersList.style.display = baseLayersPresent ? '' : 'none'; + } + + this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none'; + + return this; + }, + + _onLayerChange: function (e) { + if (!this._handlingClick) { + this._update(); + } + + var obj = this._getLayer(stamp(e.target)); + + // @namespace Map + // @section Layer events + // @event baselayerchange: LayersControlEvent + // Fired when the base layer is changed through the [layers control](#control-layers). + // @event overlayadd: LayersControlEvent + // Fired when an overlay is selected through the [layers control](#control-layers). + // @event overlayremove: LayersControlEvent + // Fired when an overlay is deselected through the [layers control](#control-layers). + // @namespace Control.Layers + var type = obj.overlay ? + (e.type === 'add' ? 'overlayadd' : 'overlayremove') : + (e.type === 'add' ? 'baselayerchange' : null); + + if (type) { + this._map.fire(type, obj); + } + }, + + // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see https://stackoverflow.com/a/119079) + _createRadioElement: function (name, checked) { + + var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' + + name + '"' + (checked ? ' checked="checked"' : '') + '/>'; + + var radioFragment = document.createElement('div'); + radioFragment.innerHTML = radioHtml; + + return radioFragment.firstChild; + }, + + _addItem: function (obj) { + var label = document.createElement('label'), + checked = this._map.hasLayer(obj.layer), + input; + + if (obj.overlay) { + input = document.createElement('input'); + input.type = 'checkbox'; + input.className = 'leaflet-control-layers-selector'; + input.defaultChecked = checked; + } else { + input = this._createRadioElement('leaflet-base-layers_' + stamp(this), checked); + } + + this._layerControlInputs.push(input); + input.layerId = stamp(obj.layer); + + on(input, 'click', this._onInputClick, this); + + var name = document.createElement('span'); + name.innerHTML = ' ' + obj.name; + + // Helps from preventing layer control flicker when checkboxes are disabled + // https://github.com/Leaflet/Leaflet/issues/2771 + var holder = document.createElement('span'); + + label.appendChild(holder); + holder.appendChild(input); + holder.appendChild(name); + + var container = obj.overlay ? this._overlaysList : this._baseLayersList; + container.appendChild(label); + + this._checkDisabledLayers(); + return label; + }, + + _onInputClick: function () { + // expanding the control on mobile with a click can cause adding a layer - we don't want this + if (this._preventClick) { + return; + } + + var inputs = this._layerControlInputs, + input, layer; + var addedLayers = [], + removedLayers = []; + + this._handlingClick = true; + + for (var i = inputs.length - 1; i >= 0; i--) { + input = inputs[i]; + layer = this._getLayer(input.layerId).layer; + + if (input.checked) { + addedLayers.push(layer); + } else if (!input.checked) { + removedLayers.push(layer); + } + } + + // Bugfix issue 2318: Should remove all old layers before readding new ones + for (i = 0; i < removedLayers.length; i++) { + if (this._map.hasLayer(removedLayers[i])) { + this._map.removeLayer(removedLayers[i]); + } + } + for (i = 0; i < addedLayers.length; i++) { + if (!this._map.hasLayer(addedLayers[i])) { + this._map.addLayer(addedLayers[i]); + } + } + + this._handlingClick = false; + + this._refocusOnMap(); + }, + + _checkDisabledLayers: function () { + var inputs = this._layerControlInputs, + input, + layer, + zoom = this._map.getZoom(); + + for (var i = inputs.length - 1; i >= 0; i--) { + input = inputs[i]; + layer = this._getLayer(input.layerId).layer; + input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) || + (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom); + + } + }, + + _expandIfNotCollapsed: function () { + if (this._map && !this.options.collapsed) { + this.expand(); + } + return this; + }, + + _expandSafely: function () { + var section = this._section; + this._preventClick = true; + on(section, 'click', preventDefault); + this.expand(); + var that = this; + setTimeout(function () { + off(section, 'click', preventDefault); + that._preventClick = false; + }); + } + +}); + + +// @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options) +// Creates a layers control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation. +var layers = function (baseLayers, overlays, options) { + return new Layers(baseLayers, overlays, options); +}; + +/* + * @class Control.Zoom + * @aka L.Control.Zoom + * @inherits Control + * + * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`. + */ + +var Zoom = Control.extend({ + // @section + // @aka Control.Zoom options + options: { + position: 'topleft', + + // @option zoomInText: String = '<span aria-hidden="true">+</span>' + // The text set on the 'zoom in' button. + zoomInText: '<span aria-hidden="true">+</span>', + + // @option zoomInTitle: String = 'Zoom in' + // The title set on the 'zoom in' button. + zoomInTitle: 'Zoom in', + + // @option zoomOutText: String = '<span aria-hidden="true">−</span>' + // The text set on the 'zoom out' button. + zoomOutText: '<span aria-hidden="true">−</span>', + + // @option zoomOutTitle: String = 'Zoom out' + // The title set on the 'zoom out' button. + zoomOutTitle: 'Zoom out' + }, + + onAdd: function (map) { + var zoomName = 'leaflet-control-zoom', + container = create$1('div', zoomName + ' leaflet-bar'), + options = this.options; + + this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle, + zoomName + '-in', container, this._zoomIn); + this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle, + zoomName + '-out', container, this._zoomOut); + + this._updateDisabled(); + map.on('zoomend zoomlevelschange', this._updateDisabled, this); + + return container; + }, + + onRemove: function (map) { + map.off('zoomend zoomlevelschange', this._updateDisabled, this); + }, + + disable: function () { + this._disabled = true; + this._updateDisabled(); + return this; + }, + + enable: function () { + this._disabled = false; + this._updateDisabled(); + return this; + }, + + _zoomIn: function (e) { + if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) { + this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1)); + } + }, + + _zoomOut: function (e) { + if (!this._disabled && this._map._zoom > this._map.getMinZoom()) { + this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1)); + } + }, + + _createButton: function (html, title, className, container, fn) { + var link = create$1('a', className, container); + link.innerHTML = html; + link.href = '#'; + link.title = title; + + /* + * Will force screen readers like VoiceOver to read this as "Zoom in - button" + */ + link.setAttribute('role', 'button'); + link.setAttribute('aria-label', title); + + disableClickPropagation(link); + on(link, 'click', stop); + on(link, 'click', fn, this); + on(link, 'click', this._refocusOnMap, this); + + return link; + }, + + _updateDisabled: function () { + var map = this._map, + className = 'leaflet-disabled'; + + removeClass(this._zoomInButton, className); + removeClass(this._zoomOutButton, className); + this._zoomInButton.setAttribute('aria-disabled', 'false'); + this._zoomOutButton.setAttribute('aria-disabled', 'false'); + + if (this._disabled || map._zoom === map.getMinZoom()) { + addClass(this._zoomOutButton, className); + this._zoomOutButton.setAttribute('aria-disabled', 'true'); + } + if (this._disabled || map._zoom === map.getMaxZoom()) { + addClass(this._zoomInButton, className); + this._zoomInButton.setAttribute('aria-disabled', 'true'); + } + } +}); + +// @namespace Map +// @section Control options +// @option zoomControl: Boolean = true +// Whether a [zoom control](#control-zoom) is added to the map by default. +Map.mergeOptions({ + zoomControl: true +}); + +Map.addInitHook(function () { + if (this.options.zoomControl) { + // @section Controls + // @property zoomControl: Control.Zoom + // The default zoom control (only available if the + // [`zoomControl` option](#map-zoomcontrol) was `true` when creating the map). + this.zoomControl = new Zoom(); + this.addControl(this.zoomControl); + } +}); + +// @namespace Control.Zoom +// @factory L.control.zoom(options: Control.Zoom options) +// Creates a zoom control +var zoom = function (options) { + return new Zoom(options); +}; + +/* + * @class Control.Scale + * @aka L.Control.Scale + * @inherits Control + * + * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`. + * + * @example + * + * ```js + * L.control.scale().addTo(map); + * ``` + */ + +var Scale = Control.extend({ + // @section + // @aka Control.Scale options + options: { + position: 'bottomleft', + + // @option maxWidth: Number = 100 + // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500). + maxWidth: 100, + + // @option metric: Boolean = True + // Whether to show the metric scale line (m/km). + metric: true, + + // @option imperial: Boolean = True + // Whether to show the imperial scale line (mi/ft). + imperial: true + + // @option updateWhenIdle: Boolean = false + // If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)). + }, + + onAdd: function (map) { + var className = 'leaflet-control-scale', + container = create$1('div', className), + options = this.options; + + this._addScales(options, className + '-line', container); + + map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this); + map.whenReady(this._update, this); + + return container; + }, + + onRemove: function (map) { + map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this); + }, + + _addScales: function (options, className, container) { + if (options.metric) { + this._mScale = create$1('div', className, container); + } + if (options.imperial) { + this._iScale = create$1('div', className, container); + } + }, + + _update: function () { + var map = this._map, + y = map.getSize().y / 2; + + var maxMeters = map.distance( + map.containerPointToLatLng([0, y]), + map.containerPointToLatLng([this.options.maxWidth, y])); + + this._updateScales(maxMeters); + }, + + _updateScales: function (maxMeters) { + if (this.options.metric && maxMeters) { + this._updateMetric(maxMeters); + } + if (this.options.imperial && maxMeters) { + this._updateImperial(maxMeters); + } + }, + + _updateMetric: function (maxMeters) { + var meters = this._getRoundNum(maxMeters), + label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km'; + + this._updateScale(this._mScale, label, meters / maxMeters); + }, + + _updateImperial: function (maxMeters) { + var maxFeet = maxMeters * 3.2808399, + maxMiles, miles, feet; + + if (maxFeet > 5280) { + maxMiles = maxFeet / 5280; + miles = this._getRoundNum(maxMiles); + this._updateScale(this._iScale, miles + ' mi', miles / maxMiles); + + } else { + feet = this._getRoundNum(maxFeet); + this._updateScale(this._iScale, feet + ' ft', feet / maxFeet); + } + }, + + _updateScale: function (scale, text, ratio) { + scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px'; + scale.innerHTML = text; + }, + + _getRoundNum: function (num) { + var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1), + d = num / pow10; + + d = d >= 10 ? 10 : + d >= 5 ? 5 : + d >= 3 ? 3 : + d >= 2 ? 2 : 1; + + return pow10 * d; + } +}); + + +// @factory L.control.scale(options?: Control.Scale options) +// Creates an scale control with the given options. +var scale = function (options) { + return new Scale(options); +}; + +var ukrainianFlag = '<svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" width="12" height="8" viewBox="0 0 12 8" class="leaflet-attribution-flag"><path fill="#4C7BE1" d="M0 0h12v4H0z"/><path fill="#FFD500" d="M0 4h12v3H0z"/><path fill="#E0BC00" d="M0 7h12v1H0z"/></svg>'; + + +/* + * @class Control.Attribution + * @aka L.Control.Attribution + * @inherits Control + * + * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control. + */ + +var Attribution = Control.extend({ + // @section + // @aka Control.Attribution options + options: { + position: 'bottomright', + + // @option prefix: String|false = 'Leaflet' + // The HTML text shown before the attributions. Pass `false` to disable. + prefix: '<a href="https://leafletjs.com" title="A JavaScript library for interactive maps">' + (Browser.inlineSvg ? ukrainianFlag + ' ' : '') + 'Leaflet</a>' + }, + + initialize: function (options) { + setOptions(this, options); + + this._attributions = {}; + }, + + onAdd: function (map) { + map.attributionControl = this; + this._container = create$1('div', 'leaflet-control-attribution'); + disableClickPropagation(this._container); + + // TODO ugly, refactor + for (var i in map._layers) { + if (map._layers[i].getAttribution) { + this.addAttribution(map._layers[i].getAttribution()); + } + } + + this._update(); + + map.on('layeradd', this._addAttribution, this); + + return this._container; + }, + + onRemove: function (map) { + map.off('layeradd', this._addAttribution, this); + }, + + _addAttribution: function (ev) { + if (ev.layer.getAttribution) { + this.addAttribution(ev.layer.getAttribution()); + ev.layer.once('remove', function () { + this.removeAttribution(ev.layer.getAttribution()); + }, this); + } + }, + + // @method setPrefix(prefix: String|false): this + // The HTML text shown before the attributions. Pass `false` to disable. + setPrefix: function (prefix) { + this.options.prefix = prefix; + this._update(); + return this; + }, + + // @method addAttribution(text: String): this + // Adds an attribution text (e.g. `'© OpenStreetMap contributors'`). + addAttribution: function (text) { + if (!text) { return this; } + + if (!this._attributions[text]) { + this._attributions[text] = 0; + } + this._attributions[text]++; + + this._update(); + + return this; + }, + + // @method removeAttribution(text: String): this + // Removes an attribution text. + removeAttribution: function (text) { + if (!text) { return this; } + + if (this._attributions[text]) { + this._attributions[text]--; + this._update(); + } + + return this; + }, + + _update: function () { + if (!this._map) { return; } + + var attribs = []; + + for (var i in this._attributions) { + if (this._attributions[i]) { + attribs.push(i); + } + } + + var prefixAndAttribs = []; + + if (this.options.prefix) { + prefixAndAttribs.push(this.options.prefix); + } + if (attribs.length) { + prefixAndAttribs.push(attribs.join(', ')); + } + + this._container.innerHTML = prefixAndAttribs.join(' <span aria-hidden="true">|</span> '); + } +}); + +// @namespace Map +// @section Control options +// @option attributionControl: Boolean = true +// Whether a [attribution control](#control-attribution) is added to the map by default. +Map.mergeOptions({ + attributionControl: true +}); + +Map.addInitHook(function () { + if (this.options.attributionControl) { + new Attribution().addTo(this); + } +}); + +// @namespace Control.Attribution +// @factory L.control.attribution(options: Control.Attribution options) +// Creates an attribution control. +var attribution = function (options) { + return new Attribution(options); +}; + +Control.Layers = Layers; +Control.Zoom = Zoom; +Control.Scale = Scale; +Control.Attribution = Attribution; + +control.layers = layers; +control.zoom = zoom; +control.scale = scale; +control.attribution = attribution; + +/* + L.Handler is a base class for handler classes that are used internally to inject + interaction features like dragging to classes like Map and Marker. +*/ + +// @class Handler +// @aka L.Handler +// Abstract class for map interaction handlers + +var Handler = Class.extend({ + initialize: function (map) { + this._map = map; + }, + + // @method enable(): this + // Enables the handler + enable: function () { + if (this._enabled) { return this; } + + this._enabled = true; + this.addHooks(); + return this; + }, + + // @method disable(): this + // Disables the handler + disable: function () { + if (!this._enabled) { return this; } + + this._enabled = false; + this.removeHooks(); + return this; + }, + + // @method enabled(): Boolean + // Returns `true` if the handler is enabled + enabled: function () { + return !!this._enabled; + } + + // @section Extension methods + // Classes inheriting from `Handler` must implement the two following methods: + // @method addHooks() + // Called when the handler is enabled, should add event hooks. + // @method removeHooks() + // Called when the handler is disabled, should remove the event hooks added previously. +}); + +// @section There is static function which can be called without instantiating L.Handler: +// @function addTo(map: Map, name: String): this +// Adds a new Handler to the given map with the given name. +Handler.addTo = function (map, name) { + map.addHandler(name, this); + return this; +}; + +var Mixin = {Events: Events}; + +/* + * @class Draggable + * @aka L.Draggable + * @inherits Evented + * + * A class for making DOM elements draggable (including touch support). + * Used internally for map and marker dragging. Only works for elements + * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition). + * + * @example + * ```js + * var draggable = new L.Draggable(elementToDrag); + * draggable.enable(); + * ``` + */ + +var START = Browser.touch ? 'touchstart mousedown' : 'mousedown'; + +var Draggable = Evented.extend({ + + options: { + // @section + // @aka Draggable options + // @option clickTolerance: Number = 3 + // The max number of pixels a user can shift the mouse pointer during a click + // for it to be considered a valid click (as opposed to a mouse drag). + clickTolerance: 3 + }, + + // @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline?: Boolean, options?: Draggable options) + // Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default). + initialize: function (element, dragStartTarget, preventOutline, options) { + setOptions(this, options); + + this._element = element; + this._dragStartTarget = dragStartTarget || element; + this._preventOutline = preventOutline; + }, + + // @method enable() + // Enables the dragging ability + enable: function () { + if (this._enabled) { return; } + + on(this._dragStartTarget, START, this._onDown, this); + + this._enabled = true; + }, + + // @method disable() + // Disables the dragging ability + disable: function () { + if (!this._enabled) { return; } + + // If we're currently dragging this draggable, + // disabling it counts as first ending the drag. + if (Draggable._dragging === this) { + this.finishDrag(true); + } + + off(this._dragStartTarget, START, this._onDown, this); + + this._enabled = false; + this._moved = false; + }, + + _onDown: function (e) { + // Ignore the event if disabled; this happens in IE11 + // under some circumstances, see #3666. + if (!this._enabled) { return; } + + this._moved = false; + + if (hasClass(this._element, 'leaflet-zoom-anim')) { return; } + + if (e.touches && e.touches.length !== 1) { + // Finish dragging to avoid conflict with touchZoom + if (Draggable._dragging === this) { + this.finishDrag(); + } + return; + } + + if (Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; } + Draggable._dragging = this; // Prevent dragging multiple objects at once. + + if (this._preventOutline) { + preventOutline(this._element); + } + + disableImageDrag(); + disableTextSelection(); + + if (this._moving) { return; } + + // @event down: Event + // Fired when a drag is about to start. + this.fire('down'); + + var first = e.touches ? e.touches[0] : e, + sizedParent = getSizedParentNode(this._element); + + this._startPoint = new Point(first.clientX, first.clientY); + this._startPos = getPosition(this._element); + + // Cache the scale, so that we can continuously compensate for it during drag (_onMove). + this._parentScale = getScale(sizedParent); + + var mouseevent = e.type === 'mousedown'; + on(document, mouseevent ? 'mousemove' : 'touchmove', this._onMove, this); + on(document, mouseevent ? 'mouseup' : 'touchend touchcancel', this._onUp, this); + }, + + _onMove: function (e) { + // Ignore the event if disabled; this happens in IE11 + // under some circumstances, see #3666. + if (!this._enabled) { return; } + + if (e.touches && e.touches.length > 1) { + this._moved = true; + return; + } + + var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e), + offset = new Point(first.clientX, first.clientY)._subtract(this._startPoint); + + if (!offset.x && !offset.y) { return; } + if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; } + + // We assume that the parent container's position, border and scale do not change for the duration of the drag. + // Therefore there is no need to account for the position and border (they are eliminated by the subtraction) + // and we can use the cached value for the scale. + offset.x /= this._parentScale.x; + offset.y /= this._parentScale.y; + + preventDefault(e); + + if (!this._moved) { + // @event dragstart: Event + // Fired when a drag starts + this.fire('dragstart'); + + this._moved = true; + + addClass(document.body, 'leaflet-dragging'); + + this._lastTarget = e.target || e.srcElement; + // IE and Edge do not give the <use> element, so fetch it + // if necessary + if (window.SVGElementInstance && this._lastTarget instanceof window.SVGElementInstance) { + this._lastTarget = this._lastTarget.correspondingUseElement; + } + addClass(this._lastTarget, 'leaflet-drag-target'); + } + + this._newPos = this._startPos.add(offset); + this._moving = true; + + this._lastEvent = e; + this._updatePosition(); + }, + + _updatePosition: function () { + var e = {originalEvent: this._lastEvent}; + + // @event predrag: Event + // Fired continuously during dragging *before* each corresponding + // update of the element's position. + this.fire('predrag', e); + setPosition(this._element, this._newPos); + + // @event drag: Event + // Fired continuously during dragging. + this.fire('drag', e); + }, + + _onUp: function () { + // Ignore the event if disabled; this happens in IE11 + // under some circumstances, see #3666. + if (!this._enabled) { return; } + this.finishDrag(); + }, + + finishDrag: function (noInertia) { + removeClass(document.body, 'leaflet-dragging'); + + if (this._lastTarget) { + removeClass(this._lastTarget, 'leaflet-drag-target'); + this._lastTarget = null; + } + + off(document, 'mousemove touchmove', this._onMove, this); + off(document, 'mouseup touchend touchcancel', this._onUp, this); + + enableImageDrag(); + enableTextSelection(); + + var fireDragend = this._moved && this._moving; + + this._moving = false; + Draggable._dragging = false; + + if (fireDragend) { + // @event dragend: DragEndEvent + // Fired when the drag ends. + this.fire('dragend', { + noInertia: noInertia, + distance: this._newPos.distanceTo(this._startPos) + }); + } + } + +}); + +/* + * @namespace PolyUtil + * Various utility functions for polygon geometries. + */ + +/* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[] + * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)). + * Used by Leaflet to only show polygon points that are on the screen or near, increasing + * performance. Note that polygon points needs different algorithm for clipping + * than polyline, so there's a separate method for it. + */ +function clipPolygon(points, bounds, round) { + var clippedPoints, + edges = [1, 4, 2, 8], + i, j, k, + a, b, + len, edge, p; + + for (i = 0, len = points.length; i < len; i++) { + points[i]._code = _getBitCode(points[i], bounds); + } + + // for each edge (left, bottom, right, top) + for (k = 0; k < 4; k++) { + edge = edges[k]; + clippedPoints = []; + + for (i = 0, len = points.length, j = len - 1; i < len; j = i++) { + a = points[i]; + b = points[j]; + + // if a is inside the clip window + if (!(a._code & edge)) { + // if b is outside the clip window (a->b goes out of screen) + if (b._code & edge) { + p = _getEdgeIntersection(b, a, edge, bounds, round); + p._code = _getBitCode(p, bounds); + clippedPoints.push(p); + } + clippedPoints.push(a); + + // else if b is inside the clip window (a->b enters the screen) + } else if (!(b._code & edge)) { + p = _getEdgeIntersection(b, a, edge, bounds, round); + p._code = _getBitCode(p, bounds); + clippedPoints.push(p); + } + } + points = clippedPoints; + } + + return points; +} + +/* @function polygonCenter(latlngs: LatLng[], crs: CRS): LatLng + * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polygon. + */ +function polygonCenter(latlngs, crs) { + var i, j, p1, p2, f, area, x, y, center; + + if (!latlngs || latlngs.length === 0) { + throw new Error('latlngs not passed'); + } + + if (!isFlat(latlngs)) { + console.warn('latlngs are not flat! Only the first ring will be used'); + latlngs = latlngs[0]; + } + + var centroidLatLng = toLatLng([0, 0]); + + var bounds = toLatLngBounds(latlngs); + var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest()); + // tests showed that below 1700 rounding errors are happening + if (areaBounds < 1700) { + // getting a inexact center, to move the latlngs near to [0, 0] to prevent rounding errors + centroidLatLng = centroid(latlngs); + } + + var len = latlngs.length; + var points = []; + for (i = 0; i < len; i++) { + var latlng = toLatLng(latlngs[i]); + points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng]))); + } + + area = x = y = 0; + + // polygon centroid algorithm; + for (i = 0, j = len - 1; i < len; j = i++) { + p1 = points[i]; + p2 = points[j]; + + f = p1.y * p2.x - p2.y * p1.x; + x += (p1.x + p2.x) * f; + y += (p1.y + p2.y) * f; + area += f * 3; + } + + if (area === 0) { + // Polygon is so small that all points are on same pixel. + center = points[0]; + } else { + center = [x / area, y / area]; + } + + var latlngCenter = crs.unproject(toPoint(center)); + return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]); +} + +/* @function centroid(latlngs: LatLng[]): LatLng + * Returns the 'center of mass' of the passed LatLngs. + */ +function centroid(coords) { + var latSum = 0; + var lngSum = 0; + var len = 0; + for (var i = 0; i < coords.length; i++) { + var latlng = toLatLng(coords[i]); + latSum += latlng.lat; + lngSum += latlng.lng; + len++; + } + return toLatLng([latSum / len, lngSum / len]); +} + +var PolyUtil = { + __proto__: null, + clipPolygon: clipPolygon, + polygonCenter: polygonCenter, + centroid: centroid +}; + +/* + * @namespace LineUtil + * + * Various utility functions for polyline points processing, used by Leaflet internally to make polylines lightning-fast. + */ + +// Simplify polyline with vertex reduction and Douglas-Peucker simplification. +// Improves rendering performance dramatically by lessening the number of points to draw. + +// @function simplify(points: Point[], tolerance: Number): Point[] +// Dramatically reduces the number of points in a polyline while retaining +// its shape and returns a new array of simplified points, using the +// [Ramer-Douglas-Peucker algorithm](https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm). +// Used for a huge performance boost when processing/displaying Leaflet polylines for +// each zoom level and also reducing visual noise. tolerance affects the amount of +// simplification (lesser value means higher quality but slower and with more points). +// Also released as a separated micro-library [Simplify.js](https://mourner.github.io/simplify-js/). +function simplify(points, tolerance) { + if (!tolerance || !points.length) { + return points.slice(); + } + + var sqTolerance = tolerance * tolerance; + + // stage 1: vertex reduction + points = _reducePoints(points, sqTolerance); + + // stage 2: Douglas-Peucker simplification + points = _simplifyDP(points, sqTolerance); + + return points; +} + +// @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number +// Returns the distance between point `p` and segment `p1` to `p2`. +function pointToSegmentDistance(p, p1, p2) { + return Math.sqrt(_sqClosestPointOnSegment(p, p1, p2, true)); +} + +// @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number +// Returns the closest point from a point `p` on a segment `p1` to `p2`. +function closestPointOnSegment(p, p1, p2) { + return _sqClosestPointOnSegment(p, p1, p2); +} + +// Ramer-Douglas-Peucker simplification, see https://en.wikipedia.org/wiki/Ramer-Douglas-Peucker_algorithm +function _simplifyDP(points, sqTolerance) { + + var len = points.length, + ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array, + markers = new ArrayConstructor(len); + + markers[0] = markers[len - 1] = 1; + + _simplifyDPStep(points, markers, sqTolerance, 0, len - 1); + + var i, + newPoints = []; + + for (i = 0; i < len; i++) { + if (markers[i]) { + newPoints.push(points[i]); + } + } + + return newPoints; +} + +function _simplifyDPStep(points, markers, sqTolerance, first, last) { + + var maxSqDist = 0, + index, i, sqDist; + + for (i = first + 1; i <= last - 1; i++) { + sqDist = _sqClosestPointOnSegment(points[i], points[first], points[last], true); + + if (sqDist > maxSqDist) { + index = i; + maxSqDist = sqDist; + } + } + + if (maxSqDist > sqTolerance) { + markers[index] = 1; + + _simplifyDPStep(points, markers, sqTolerance, first, index); + _simplifyDPStep(points, markers, sqTolerance, index, last); + } +} + +// reduce points that are too close to each other to a single point +function _reducePoints(points, sqTolerance) { + var reducedPoints = [points[0]]; + + for (var i = 1, prev = 0, len = points.length; i < len; i++) { + if (_sqDist(points[i], points[prev]) > sqTolerance) { + reducedPoints.push(points[i]); + prev = i; + } + } + if (prev < len - 1) { + reducedPoints.push(points[len - 1]); + } + return reducedPoints; +} + +var _lastCode; + +// @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean +// Clips the segment a to b by rectangular bounds with the +// [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm) +// (modifying the segment points directly!). Used by Leaflet to only show polyline +// points that are on the screen or near, increasing performance. +function clipSegment(a, b, bounds, useLastCode, round) { + var codeA = useLastCode ? _lastCode : _getBitCode(a, bounds), + codeB = _getBitCode(b, bounds), + + codeOut, p, newCode; + + // save 2nd code to avoid calculating it on the next segment + _lastCode = codeB; + + while (true) { + // if a,b is inside the clip window (trivial accept) + if (!(codeA | codeB)) { + return [a, b]; + } + + // if a,b is outside the clip window (trivial reject) + if (codeA & codeB) { + return false; + } + + // other cases + codeOut = codeA || codeB; + p = _getEdgeIntersection(a, b, codeOut, bounds, round); + newCode = _getBitCode(p, bounds); + + if (codeOut === codeA) { + a = p; + codeA = newCode; + } else { + b = p; + codeB = newCode; + } + } +} + +function _getEdgeIntersection(a, b, code, bounds, round) { + var dx = b.x - a.x, + dy = b.y - a.y, + min = bounds.min, + max = bounds.max, + x, y; + + if (code & 8) { // top + x = a.x + dx * (max.y - a.y) / dy; + y = max.y; + + } else if (code & 4) { // bottom + x = a.x + dx * (min.y - a.y) / dy; + y = min.y; + + } else if (code & 2) { // right + x = max.x; + y = a.y + dy * (max.x - a.x) / dx; + + } else if (code & 1) { // left + x = min.x; + y = a.y + dy * (min.x - a.x) / dx; + } + + return new Point(x, y, round); +} + +function _getBitCode(p, bounds) { + var code = 0; + + if (p.x < bounds.min.x) { // left + code |= 1; + } else if (p.x > bounds.max.x) { // right + code |= 2; + } + + if (p.y < bounds.min.y) { // bottom + code |= 4; + } else if (p.y > bounds.max.y) { // top + code |= 8; + } + + return code; +} + +// square distance (to avoid unnecessary Math.sqrt calls) +function _sqDist(p1, p2) { + var dx = p2.x - p1.x, + dy = p2.y - p1.y; + return dx * dx + dy * dy; +} + +// return closest point on segment or distance to that point +function _sqClosestPointOnSegment(p, p1, p2, sqDist) { + var x = p1.x, + y = p1.y, + dx = p2.x - x, + dy = p2.y - y, + dot = dx * dx + dy * dy, + t; + + if (dot > 0) { + t = ((p.x - x) * dx + (p.y - y) * dy) / dot; + + if (t > 1) { + x = p2.x; + y = p2.y; + } else if (t > 0) { + x += dx * t; + y += dy * t; + } + } + + dx = p.x - x; + dy = p.y - y; + + return sqDist ? dx * dx + dy * dy : new Point(x, y); +} + + +// @function isFlat(latlngs: LatLng[]): Boolean +// Returns true if `latlngs` is a flat array, false is nested. +function isFlat(latlngs) { + return !isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined'); +} + +function _flat(latlngs) { + console.warn('Deprecated use of _flat, please use L.LineUtil.isFlat instead.'); + return isFlat(latlngs); +} + +/* @function polylineCenter(latlngs: LatLng[], crs: CRS): LatLng + * Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the passed LatLngs (first ring) from a polyline. + */ +function polylineCenter(latlngs, crs) { + var i, halfDist, segDist, dist, p1, p2, ratio, center; + + if (!latlngs || latlngs.length === 0) { + throw new Error('latlngs not passed'); + } + + if (!isFlat(latlngs)) { + console.warn('latlngs are not flat! Only the first ring will be used'); + latlngs = latlngs[0]; + } + + var centroidLatLng = toLatLng([0, 0]); + + var bounds = toLatLngBounds(latlngs); + var areaBounds = bounds.getNorthWest().distanceTo(bounds.getSouthWest()) * bounds.getNorthEast().distanceTo(bounds.getNorthWest()); + // tests showed that below 1700 rounding errors are happening + if (areaBounds < 1700) { + // getting a inexact center, to move the latlngs near to [0, 0] to prevent rounding errors + centroidLatLng = centroid(latlngs); + } + + var len = latlngs.length; + var points = []; + for (i = 0; i < len; i++) { + var latlng = toLatLng(latlngs[i]); + points.push(crs.project(toLatLng([latlng.lat - centroidLatLng.lat, latlng.lng - centroidLatLng.lng]))); + } + + for (i = 0, halfDist = 0; i < len - 1; i++) { + halfDist += points[i].distanceTo(points[i + 1]) / 2; + } + + // The line is so small in the current view that all points are on the same pixel. + if (halfDist === 0) { + center = points[0]; + } else { + for (i = 0, dist = 0; i < len - 1; i++) { + p1 = points[i]; + p2 = points[i + 1]; + segDist = p1.distanceTo(p2); + dist += segDist; + + if (dist > halfDist) { + ratio = (dist - halfDist) / segDist; + center = [ + p2.x - ratio * (p2.x - p1.x), + p2.y - ratio * (p2.y - p1.y) + ]; + break; + } + } + } + + var latlngCenter = crs.unproject(toPoint(center)); + return toLatLng([latlngCenter.lat + centroidLatLng.lat, latlngCenter.lng + centroidLatLng.lng]); +} + +var LineUtil = { + __proto__: null, + simplify: simplify, + pointToSegmentDistance: pointToSegmentDistance, + closestPointOnSegment: closestPointOnSegment, + clipSegment: clipSegment, + _getEdgeIntersection: _getEdgeIntersection, + _getBitCode: _getBitCode, + _sqClosestPointOnSegment: _sqClosestPointOnSegment, + isFlat: isFlat, + _flat: _flat, + polylineCenter: polylineCenter +}; + +/* + * @namespace Projection + * @section + * Leaflet comes with a set of already defined Projections out of the box: + * + * @projection L.Projection.LonLat + * + * Equirectangular, or Plate Carree projection — the most simple projection, + * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as + * latitude. Also suitable for flat worlds, e.g. game maps. Used by the + * `EPSG:4326` and `Simple` CRS. + */ + +var LonLat = { + project: function (latlng) { + return new Point(latlng.lng, latlng.lat); + }, + + unproject: function (point) { + return new LatLng(point.y, point.x); + }, + + bounds: new Bounds([-180, -90], [180, 90]) +}; + +/* + * @namespace Projection + * @projection L.Projection.Mercator + * + * Elliptical Mercator projection — more complex than Spherical Mercator. Assumes that Earth is an ellipsoid. Used by the EPSG:3395 CRS. + */ + +var Mercator = { + R: 6378137, + R_MINOR: 6356752.314245179, + + bounds: new Bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]), + + project: function (latlng) { + var d = Math.PI / 180, + r = this.R, + y = latlng.lat * d, + tmp = this.R_MINOR / r, + e = Math.sqrt(1 - tmp * tmp), + con = e * Math.sin(y); + + var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2); + y = -r * Math.log(Math.max(ts, 1E-10)); + + return new Point(latlng.lng * d * r, y); + }, + + unproject: function (point) { + var d = 180 / Math.PI, + r = this.R, + tmp = this.R_MINOR / r, + e = Math.sqrt(1 - tmp * tmp), + ts = Math.exp(-point.y / r), + phi = Math.PI / 2 - 2 * Math.atan(ts); + + for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) { + con = e * Math.sin(phi); + con = Math.pow((1 - con) / (1 + con), e / 2); + dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi; + phi += dphi; + } + + return new LatLng(phi * d, point.x * d / r); + } +}; + +/* + * @class Projection + + * An object with methods for projecting geographical coordinates of the world onto + * a flat surface (and back). See [Map projection](https://en.wikipedia.org/wiki/Map_projection). + + * @property bounds: Bounds + * The bounds (specified in CRS units) where the projection is valid + + * @method project(latlng: LatLng): Point + * Projects geographical coordinates into a 2D point. + * Only accepts actual `L.LatLng` instances, not arrays. + + * @method unproject(point: Point): LatLng + * The inverse of `project`. Projects a 2D point into a geographical location. + * Only accepts actual `L.Point` instances, not arrays. + + * Note that the projection instances do not inherit from Leaflet's `Class` object, + * and can't be instantiated. Also, new classes can't inherit from them, + * and methods can't be added to them with the `include` function. + + */ + +var index = { + __proto__: null, + LonLat: LonLat, + Mercator: Mercator, + SphericalMercator: SphericalMercator +}; + +/* + * @namespace CRS + * @crs L.CRS.EPSG3395 + * + * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection. + */ +var EPSG3395 = extend({}, Earth, { + code: 'EPSG:3395', + projection: Mercator, + + transformation: (function () { + var scale = 0.5 / (Math.PI * Mercator.R); + return toTransformation(scale, 0.5, -scale, 0.5); + }()) +}); + +/* + * @namespace CRS + * @crs L.CRS.EPSG4326 + * + * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection. + * + * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic), + * which is a breaking change from 0.7.x behaviour. If you are using a `TileLayer` + * with this CRS, ensure that there are two 256x256 pixel tiles covering the + * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90), + * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set. + */ + +var EPSG4326 = extend({}, Earth, { + code: 'EPSG:4326', + projection: LonLat, + transformation: toTransformation(1 / 180, 1, -1 / 180, 0.5) +}); + +/* + * @namespace CRS + * @crs L.CRS.Simple + * + * A simple CRS that maps longitude and latitude into `x` and `y` directly. + * May be used for maps of flat surfaces (e.g. game maps). Note that the `y` + * axis should still be inverted (going from bottom to top). `distance()` returns + * simple euclidean distance. + */ + +var Simple = extend({}, CRS, { + projection: LonLat, + transformation: toTransformation(1, 0, -1, 0), + + scale: function (zoom) { + return Math.pow(2, zoom); + }, + + zoom: function (scale) { + return Math.log(scale) / Math.LN2; + }, + + distance: function (latlng1, latlng2) { + var dx = latlng2.lng - latlng1.lng, + dy = latlng2.lat - latlng1.lat; + + return Math.sqrt(dx * dx + dy * dy); + }, + + infinite: true +}); + +CRS.Earth = Earth; +CRS.EPSG3395 = EPSG3395; +CRS.EPSG3857 = EPSG3857; +CRS.EPSG900913 = EPSG900913; +CRS.EPSG4326 = EPSG4326; +CRS.Simple = Simple; + +/* + * @class Layer + * @inherits Evented + * @aka L.Layer + * @aka ILayer + * + * A set of methods from the Layer base class that all Leaflet layers use. + * Inherits all methods, options and events from `L.Evented`. + * + * @example + * + * ```js + * var layer = L.marker(latlng).addTo(map); + * layer.addTo(map); + * layer.remove(); + * ``` + * + * @event add: Event + * Fired after the layer is added to a map + * + * @event remove: Event + * Fired after the layer is removed from a map + */ + + +var Layer = Evented.extend({ + + // Classes extending `L.Layer` will inherit the following options: + options: { + // @option pane: String = 'overlayPane' + // By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default. + pane: 'overlayPane', + + // @option attribution: String = null + // String to be shown in the attribution control, e.g. "© OpenStreetMap contributors". It describes the layer data and is often a legal obligation towards copyright holders and tile providers. + attribution: null, + + bubblingMouseEvents: true + }, + + /* @section + * Classes extending `L.Layer` will inherit the following methods: + * + * @method addTo(map: Map|LayerGroup): this + * Adds the layer to the given map or layer group. + */ + addTo: function (map) { + map.addLayer(this); + return this; + }, + + // @method remove: this + // Removes the layer from the map it is currently active on. + remove: function () { + return this.removeFrom(this._map || this._mapToAdd); + }, + + // @method removeFrom(map: Map): this + // Removes the layer from the given map + // + // @alternative + // @method removeFrom(group: LayerGroup): this + // Removes the layer from the given `LayerGroup` + removeFrom: function (obj) { + if (obj) { + obj.removeLayer(this); + } + return this; + }, + + // @method getPane(name? : String): HTMLElement + // Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer. + getPane: function (name) { + return this._map.getPane(name ? (this.options[name] || name) : this.options.pane); + }, + + addInteractiveTarget: function (targetEl) { + this._map._targets[stamp(targetEl)] = this; + return this; + }, + + removeInteractiveTarget: function (targetEl) { + delete this._map._targets[stamp(targetEl)]; + return this; + }, + + // @method getAttribution: String + // Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution). + getAttribution: function () { + return this.options.attribution; + }, + + _layerAdd: function (e) { + var map = e.target; + + // check in case layer gets added and then removed before the map is ready + if (!map.hasLayer(this)) { return; } + + this._map = map; + this._zoomAnimated = map._zoomAnimated; + + if (this.getEvents) { + var events = this.getEvents(); + map.on(events, this); + this.once('remove', function () { + map.off(events, this); + }, this); + } + + this.onAdd(map); + + this.fire('add'); + map.fire('layeradd', {layer: this}); + } +}); + +/* @section Extension methods + * @uninheritable + * + * Every layer should extend from `L.Layer` and (re-)implement the following methods. + * + * @method onAdd(map: Map): this + * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer). + * + * @method onRemove(map: Map): this + * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer). + * + * @method getEvents(): Object + * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer. + * + * @method getAttribution(): String + * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible. + * + * @method beforeAdd(map: Map): this + * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only. + */ + + +/* @namespace Map + * @section Layer events + * + * @event layeradd: LayerEvent + * Fired when a new layer is added to the map. + * + * @event layerremove: LayerEvent + * Fired when some layer is removed from the map + * + * @section Methods for Layers and Controls + */ +Map.include({ + // @method addLayer(layer: Layer): this + // Adds the given layer to the map + addLayer: function (layer) { + if (!layer._layerAdd) { + throw new Error('The provided object is not a Layer.'); + } + + var id = stamp(layer); + if (this._layers[id]) { return this; } + this._layers[id] = layer; + + layer._mapToAdd = this; + + if (layer.beforeAdd) { + layer.beforeAdd(this); + } + + this.whenReady(layer._layerAdd, layer); + + return this; + }, + + // @method removeLayer(layer: Layer): this + // Removes the given layer from the map. + removeLayer: function (layer) { + var id = stamp(layer); + + if (!this._layers[id]) { return this; } + + if (this._loaded) { + layer.onRemove(this); + } + + delete this._layers[id]; + + if (this._loaded) { + this.fire('layerremove', {layer: layer}); + layer.fire('remove'); + } + + layer._map = layer._mapToAdd = null; + + return this; + }, + + // @method hasLayer(layer: Layer): Boolean + // Returns `true` if the given layer is currently added to the map + hasLayer: function (layer) { + return stamp(layer) in this._layers; + }, + + /* @method eachLayer(fn: Function, context?: Object): this + * Iterates over the layers of the map, optionally specifying context of the iterator function. + * ``` + * map.eachLayer(function(layer){ + * layer.bindPopup('Hello'); + * }); + * ``` + */ + eachLayer: function (method, context) { + for (var i in this._layers) { + method.call(context, this._layers[i]); + } + return this; + }, + + _addLayers: function (layers) { + layers = layers ? (isArray(layers) ? layers : [layers]) : []; + + for (var i = 0, len = layers.length; i < len; i++) { + this.addLayer(layers[i]); + } + }, + + _addZoomLimit: function (layer) { + if (!isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) { + this._zoomBoundLayers[stamp(layer)] = layer; + this._updateZoomLevels(); + } + }, + + _removeZoomLimit: function (layer) { + var id = stamp(layer); + + if (this._zoomBoundLayers[id]) { + delete this._zoomBoundLayers[id]; + this._updateZoomLevels(); + } + }, + + _updateZoomLevels: function () { + var minZoom = Infinity, + maxZoom = -Infinity, + oldZoomSpan = this._getZoomSpan(); + + for (var i in this._zoomBoundLayers) { + var options = this._zoomBoundLayers[i].options; + + minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom); + maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom); + } + + this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom; + this._layersMinZoom = minZoom === Infinity ? undefined : minZoom; + + // @section Map state change events + // @event zoomlevelschange: Event + // Fired when the number of zoomlevels on the map is changed due + // to adding or removing a layer. + if (oldZoomSpan !== this._getZoomSpan()) { + this.fire('zoomlevelschange'); + } + + if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) { + this.setZoom(this._layersMaxZoom); + } + if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) { + this.setZoom(this._layersMinZoom); + } + } +}); + +/* + * @class LayerGroup + * @aka L.LayerGroup + * @inherits Interactive layer + * + * Used to group several layers and handle them as one. If you add it to the map, + * any layers added or removed from the group will be added/removed on the map as + * well. Extends `Layer`. + * + * @example + * + * ```js + * L.layerGroup([marker1, marker2]) + * .addLayer(polyline) + * .addTo(map); + * ``` + */ + +var LayerGroup = Layer.extend({ + + initialize: function (layers, options) { + setOptions(this, options); + + this._layers = {}; + + var i, len; + + if (layers) { + for (i = 0, len = layers.length; i < len; i++) { + this.addLayer(layers[i]); + } + } + }, + + // @method addLayer(layer: Layer): this + // Adds the given layer to the group. + addLayer: function (layer) { + var id = this.getLayerId(layer); + + this._layers[id] = layer; + + if (this._map) { + this._map.addLayer(layer); + } + + return this; + }, + + // @method removeLayer(layer: Layer): this + // Removes the given layer from the group. + // @alternative + // @method removeLayer(id: Number): this + // Removes the layer with the given internal ID from the group. + removeLayer: function (layer) { + var id = layer in this._layers ? layer : this.getLayerId(layer); + + if (this._map && this._layers[id]) { + this._map.removeLayer(this._layers[id]); + } + + delete this._layers[id]; + + return this; + }, + + // @method hasLayer(layer: Layer): Boolean + // Returns `true` if the given layer is currently added to the group. + // @alternative + // @method hasLayer(id: Number): Boolean + // Returns `true` if the given internal ID is currently added to the group. + hasLayer: function (layer) { + var layerId = typeof layer === 'number' ? layer : this.getLayerId(layer); + return layerId in this._layers; + }, + + // @method clearLayers(): this + // Removes all the layers from the group. + clearLayers: function () { + return this.eachLayer(this.removeLayer, this); + }, + + // @method invoke(methodName: String, …): this + // Calls `methodName` on every layer contained in this group, passing any + // additional parameters. Has no effect if the layers contained do not + // implement `methodName`. + invoke: function (methodName) { + var args = Array.prototype.slice.call(arguments, 1), + i, layer; + + for (i in this._layers) { + layer = this._layers[i]; + + if (layer[methodName]) { + layer[methodName].apply(layer, args); + } + } + + return this; + }, + + onAdd: function (map) { + this.eachLayer(map.addLayer, map); + }, + + onRemove: function (map) { + this.eachLayer(map.removeLayer, map); + }, + + // @method eachLayer(fn: Function, context?: Object): this + // Iterates over the layers of the group, optionally specifying context of the iterator function. + // ```js + // group.eachLayer(function (layer) { + // layer.bindPopup('Hello'); + // }); + // ``` + eachLayer: function (method, context) { + for (var i in this._layers) { + method.call(context, this._layers[i]); + } + return this; + }, + + // @method getLayer(id: Number): Layer + // Returns the layer with the given internal ID. + getLayer: function (id) { + return this._layers[id]; + }, + + // @method getLayers(): Layer[] + // Returns an array of all the layers added to the group. + getLayers: function () { + var layers = []; + this.eachLayer(layers.push, layers); + return layers; + }, + + // @method setZIndex(zIndex: Number): this + // Calls `setZIndex` on every layer contained in this group, passing the z-index. + setZIndex: function (zIndex) { + return this.invoke('setZIndex', zIndex); + }, + + // @method getLayerId(layer: Layer): Number + // Returns the internal ID for a layer + getLayerId: function (layer) { + return stamp(layer); + } +}); + + +// @factory L.layerGroup(layers?: Layer[], options?: Object) +// Create a layer group, optionally given an initial set of layers and an `options` object. +var layerGroup = function (layers, options) { + return new LayerGroup(layers, options); +}; + +/* + * @class FeatureGroup + * @aka L.FeatureGroup + * @inherits LayerGroup + * + * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers: + * * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip)) + * * Events are propagated to the `FeatureGroup`, so if the group has an event + * handler, it will handle events from any of the layers. This includes mouse events + * and custom events. + * * Has `layeradd` and `layerremove` events + * + * @example + * + * ```js + * L.featureGroup([marker1, marker2, polyline]) + * .bindPopup('Hello world!') + * .on('click', function() { alert('Clicked on a member of the group!'); }) + * .addTo(map); + * ``` + */ + +var FeatureGroup = LayerGroup.extend({ + + addLayer: function (layer) { + if (this.hasLayer(layer)) { + return this; + } + + layer.addEventParent(this); + + LayerGroup.prototype.addLayer.call(this, layer); + + // @event layeradd: LayerEvent + // Fired when a layer is added to this `FeatureGroup` + return this.fire('layeradd', {layer: layer}); + }, + + removeLayer: function (layer) { + if (!this.hasLayer(layer)) { + return this; + } + if (layer in this._layers) { + layer = this._layers[layer]; + } + + layer.removeEventParent(this); + + LayerGroup.prototype.removeLayer.call(this, layer); + + // @event layerremove: LayerEvent + // Fired when a layer is removed from this `FeatureGroup` + return this.fire('layerremove', {layer: layer}); + }, + + // @method setStyle(style: Path options): this + // Sets the given path options to each layer of the group that has a `setStyle` method. + setStyle: function (style) { + return this.invoke('setStyle', style); + }, + + // @method bringToFront(): this + // Brings the layer group to the top of all other layers + bringToFront: function () { + return this.invoke('bringToFront'); + }, + + // @method bringToBack(): this + // Brings the layer group to the back of all other layers + bringToBack: function () { + return this.invoke('bringToBack'); + }, + + // @method getBounds(): LatLngBounds + // Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children). + getBounds: function () { + var bounds = new LatLngBounds(); + + for (var id in this._layers) { + var layer = this._layers[id]; + bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng()); + } + return bounds; + } +}); + +// @factory L.featureGroup(layers?: Layer[], options?: Object) +// Create a feature group, optionally given an initial set of layers and an `options` object. +var featureGroup = function (layers, options) { + return new FeatureGroup(layers, options); +}; + +/* + * @class Icon + * @aka L.Icon + * + * Represents an icon to provide when creating a marker. + * + * @example + * + * ```js + * var myIcon = L.icon({ + * iconUrl: 'my-icon.png', + * iconRetinaUrl: 'my-icon@2x.png', + * iconSize: [38, 95], + * iconAnchor: [22, 94], + * popupAnchor: [-3, -76], + * shadowUrl: 'my-icon-shadow.png', + * shadowRetinaUrl: 'my-icon-shadow@2x.png', + * shadowSize: [68, 95], + * shadowAnchor: [22, 94] + * }); + * + * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map); + * ``` + * + * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default. + * + */ + +var Icon = Class.extend({ + + /* @section + * @aka Icon options + * + * @option iconUrl: String = null + * **(required)** The URL to the icon image (absolute or relative to your script path). + * + * @option iconRetinaUrl: String = null + * The URL to a retina sized version of the icon image (absolute or relative to your + * script path). Used for Retina screen devices. + * + * @option iconSize: Point = null + * Size of the icon image in pixels. + * + * @option iconAnchor: Point = null + * The coordinates of the "tip" of the icon (relative to its top left corner). The icon + * will be aligned so that this point is at the marker's geographical location. Centered + * by default if size is specified, also can be set in CSS with negative margins. + * + * @option popupAnchor: Point = [0, 0] + * The coordinates of the point from which popups will "open", relative to the icon anchor. + * + * @option tooltipAnchor: Point = [0, 0] + * The coordinates of the point from which tooltips will "open", relative to the icon anchor. + * + * @option shadowUrl: String = null + * The URL to the icon shadow image. If not specified, no shadow image will be created. + * + * @option shadowRetinaUrl: String = null + * + * @option shadowSize: Point = null + * Size of the shadow image in pixels. + * + * @option shadowAnchor: Point = null + * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same + * as iconAnchor if not specified). + * + * @option className: String = '' + * A custom class name to assign to both icon and shadow images. Empty by default. + */ + + options: { + popupAnchor: [0, 0], + tooltipAnchor: [0, 0], + + // @option crossOrigin: Boolean|String = false + // Whether the crossOrigin attribute will be added to the tiles. + // If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. + // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values. + crossOrigin: false + }, + + initialize: function (options) { + setOptions(this, options); + }, + + // @method createIcon(oldIcon?: HTMLElement): HTMLElement + // Called internally when the icon has to be shown, returns a `<img>` HTML element + // styled according to the options. + createIcon: function (oldIcon) { + return this._createIcon('icon', oldIcon); + }, + + // @method createShadow(oldIcon?: HTMLElement): HTMLElement + // As `createIcon`, but for the shadow beneath it. + createShadow: function (oldIcon) { + return this._createIcon('shadow', oldIcon); + }, + + _createIcon: function (name, oldIcon) { + var src = this._getIconUrl(name); + + if (!src) { + if (name === 'icon') { + throw new Error('iconUrl not set in Icon options (see the docs).'); + } + return null; + } + + var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null); + this._setIconStyles(img, name); + + if (this.options.crossOrigin || this.options.crossOrigin === '') { + img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin; + } + + return img; + }, + + _setIconStyles: function (img, name) { + var options = this.options; + var sizeOption = options[name + 'Size']; + + if (typeof sizeOption === 'number') { + sizeOption = [sizeOption, sizeOption]; + } + + var size = toPoint(sizeOption), + anchor = toPoint(name === 'shadow' && options.shadowAnchor || options.iconAnchor || + size && size.divideBy(2, true)); + + img.className = 'leaflet-marker-' + name + ' ' + (options.className || ''); + + if (anchor) { + img.style.marginLeft = (-anchor.x) + 'px'; + img.style.marginTop = (-anchor.y) + 'px'; + } + + if (size) { + img.style.width = size.x + 'px'; + img.style.height = size.y + 'px'; + } + }, + + _createImg: function (src, el) { + el = el || document.createElement('img'); + el.src = src; + return el; + }, + + _getIconUrl: function (name) { + return Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url']; + } +}); + + +// @factory L.icon(options: Icon options) +// Creates an icon instance with the given options. +function icon(options) { + return new Icon(options); +} + +/* + * @miniclass Icon.Default (Icon) + * @aka L.Icon.Default + * @section + * + * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when + * no icon is specified. Points to the blue marker image distributed with Leaflet + * releases. + * + * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options` + * (which is a set of `Icon options`). + * + * If you want to _completely_ replace the default icon, override the + * `L.Marker.prototype.options.icon` with your own icon instead. + */ + +var IconDefault = Icon.extend({ + + options: { + iconUrl: 'marker-icon.png', + iconRetinaUrl: 'marker-icon-2x.png', + shadowUrl: 'marker-shadow.png', + iconSize: [25, 41], + iconAnchor: [12, 41], + popupAnchor: [1, -34], + tooltipAnchor: [16, -28], + shadowSize: [41, 41] + }, + + _getIconUrl: function (name) { + if (typeof IconDefault.imagePath !== 'string') { // Deprecated, backwards-compatibility only + IconDefault.imagePath = this._detectIconPath(); + } + + // @option imagePath: String + // `Icon.Default` will try to auto-detect the location of the + // blue icon images. If you are placing these images in a non-standard + // way, set this option to point to the right path. + return (this.options.imagePath || IconDefault.imagePath) + Icon.prototype._getIconUrl.call(this, name); + }, + + _stripUrl: function (path) { // separate function to use in tests + var strip = function (str, re, idx) { + var match = re.exec(str); + return match && match[idx]; + }; + path = strip(path, /^url\((['"])?(.+)\1\)$/, 2); + return path && strip(path, /^(.*)marker-icon\.png$/, 1); + }, + + _detectIconPath: function () { + var el = create$1('div', 'leaflet-default-icon-path', document.body); + var path = getStyle(el, 'background-image') || + getStyle(el, 'backgroundImage'); // IE8 + + document.body.removeChild(el); + path = this._stripUrl(path); + if (path) { return path; } + var link = document.querySelector('link[href$="leaflet.css"]'); + if (!link) { return ''; } + return link.href.substring(0, link.href.length - 'leaflet.css'.length - 1); + } +}); + +/* + * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable. + */ + + +/* @namespace Marker + * @section Interaction handlers + * + * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example: + * + * ```js + * marker.dragging.disable(); + * ``` + * + * @property dragging: Handler + * Marker dragging handler (by both mouse and touch). Only valid when the marker is on the map (Otherwise set [`marker.options.draggable`](#marker-draggable)). + */ + +var MarkerDrag = Handler.extend({ + initialize: function (marker) { + this._marker = marker; + }, + + addHooks: function () { + var icon = this._marker._icon; + + if (!this._draggable) { + this._draggable = new Draggable(icon, icon, true); + } + + this._draggable.on({ + dragstart: this._onDragStart, + predrag: this._onPreDrag, + drag: this._onDrag, + dragend: this._onDragEnd + }, this).enable(); + + addClass(icon, 'leaflet-marker-draggable'); + }, + + removeHooks: function () { + this._draggable.off({ + dragstart: this._onDragStart, + predrag: this._onPreDrag, + drag: this._onDrag, + dragend: this._onDragEnd + }, this).disable(); + + if (this._marker._icon) { + removeClass(this._marker._icon, 'leaflet-marker-draggable'); + } + }, + + moved: function () { + return this._draggable && this._draggable._moved; + }, + + _adjustPan: function (e) { + var marker = this._marker, + map = marker._map, + speed = this._marker.options.autoPanSpeed, + padding = this._marker.options.autoPanPadding, + iconPos = getPosition(marker._icon), + bounds = map.getPixelBounds(), + origin = map.getPixelOrigin(); + + var panBounds = toBounds( + bounds.min._subtract(origin).add(padding), + bounds.max._subtract(origin).subtract(padding) + ); + + if (!panBounds.contains(iconPos)) { + // Compute incremental movement + var movement = toPoint( + (Math.max(panBounds.max.x, iconPos.x) - panBounds.max.x) / (bounds.max.x - panBounds.max.x) - + (Math.min(panBounds.min.x, iconPos.x) - panBounds.min.x) / (bounds.min.x - panBounds.min.x), + + (Math.max(panBounds.max.y, iconPos.y) - panBounds.max.y) / (bounds.max.y - panBounds.max.y) - + (Math.min(panBounds.min.y, iconPos.y) - panBounds.min.y) / (bounds.min.y - panBounds.min.y) + ).multiplyBy(speed); + + map.panBy(movement, {animate: false}); + + this._draggable._newPos._add(movement); + this._draggable._startPos._add(movement); + + setPosition(marker._icon, this._draggable._newPos); + this._onDrag(e); + + this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e)); + } + }, + + _onDragStart: function () { + // @section Dragging events + // @event dragstart: Event + // Fired when the user starts dragging the marker. + + // @event movestart: Event + // Fired when the marker starts moving (because of dragging). + + this._oldLatLng = this._marker.getLatLng(); + + // When using ES6 imports it could not be set when `Popup` was not imported as well + this._marker.closePopup && this._marker.closePopup(); + + this._marker + .fire('movestart') + .fire('dragstart'); + }, + + _onPreDrag: function (e) { + if (this._marker.options.autoPan) { + cancelAnimFrame(this._panRequest); + this._panRequest = requestAnimFrame(this._adjustPan.bind(this, e)); + } + }, + + _onDrag: function (e) { + var marker = this._marker, + shadow = marker._shadow, + iconPos = getPosition(marker._icon), + latlng = marker._map.layerPointToLatLng(iconPos); + + // update shadow position + if (shadow) { + setPosition(shadow, iconPos); + } + + marker._latlng = latlng; + e.latlng = latlng; + e.oldLatLng = this._oldLatLng; + + // @event drag: Event + // Fired repeatedly while the user drags the marker. + marker + .fire('move', e) + .fire('drag', e); + }, + + _onDragEnd: function (e) { + // @event dragend: DragEndEvent + // Fired when the user stops dragging the marker. + + cancelAnimFrame(this._panRequest); + + // @event moveend: Event + // Fired when the marker stops moving (because of dragging). + delete this._oldLatLng; + this._marker + .fire('moveend') + .fire('dragend', e); + } +}); + +/* + * @class Marker + * @inherits Interactive layer + * @aka L.Marker + * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`. + * + * @example + * + * ```js + * L.marker([50.5, 30.5]).addTo(map); + * ``` + */ + +var Marker = Layer.extend({ + + // @section + // @aka Marker options + options: { + // @option icon: Icon = * + // Icon instance to use for rendering the marker. + // See [Icon documentation](#L.Icon) for details on how to customize the marker icon. + // If not specified, a common instance of `L.Icon.Default` is used. + icon: new IconDefault(), + + // Option inherited from "Interactive layer" abstract class + interactive: true, + + // @option keyboard: Boolean = true + // Whether the marker can be tabbed to with a keyboard and clicked by pressing enter. + keyboard: true, + + // @option title: String = '' + // Text for the browser tooltip that appear on marker hover (no tooltip by default). + // [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled). + title: '', + + // @option alt: String = 'Marker' + // Text for the `alt` attribute of the icon image. + // [Useful for accessibility](https://leafletjs.com/examples/accessibility/#markers-must-be-labelled). + alt: 'Marker', + + // @option zIndexOffset: Number = 0 + // By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively). + zIndexOffset: 0, + + // @option opacity: Number = 1.0 + // The opacity of the marker. + opacity: 1, + + // @option riseOnHover: Boolean = false + // If `true`, the marker will get on top of others when you hover the mouse over it. + riseOnHover: false, + + // @option riseOffset: Number = 250 + // The z-index offset used for the `riseOnHover` feature. + riseOffset: 250, + + // @option pane: String = 'markerPane' + // `Map pane` where the markers icon will be added. + pane: 'markerPane', + + // @option shadowPane: String = 'shadowPane' + // `Map pane` where the markers shadow will be added. + shadowPane: 'shadowPane', + + // @option bubblingMouseEvents: Boolean = false + // When `true`, a mouse event on this marker will trigger the same event on the map + // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used). + bubblingMouseEvents: false, + + // @option autoPanOnFocus: Boolean = true + // When `true`, the map will pan whenever the marker is focused (via + // e.g. pressing `tab` on the keyboard) to ensure the marker is + // visible within the map's bounds + autoPanOnFocus: true, + + // @section Draggable marker options + // @option draggable: Boolean = false + // Whether the marker is draggable with mouse/touch or not. + draggable: false, + + // @option autoPan: Boolean = false + // Whether to pan the map when dragging this marker near its edge or not. + autoPan: false, + + // @option autoPanPadding: Point = Point(50, 50) + // Distance (in pixels to the left/right and to the top/bottom) of the + // map edge to start panning the map. + autoPanPadding: [50, 50], + + // @option autoPanSpeed: Number = 10 + // Number of pixels the map should pan by. + autoPanSpeed: 10 + }, + + /* @section + * + * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods: + */ + + initialize: function (latlng, options) { + setOptions(this, options); + this._latlng = toLatLng(latlng); + }, + + onAdd: function (map) { + this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation; + + if (this._zoomAnimated) { + map.on('zoomanim', this._animateZoom, this); + } + + this._initIcon(); + this.update(); + }, + + onRemove: function (map) { + if (this.dragging && this.dragging.enabled()) { + this.options.draggable = true; + this.dragging.removeHooks(); + } + delete this.dragging; + + if (this._zoomAnimated) { + map.off('zoomanim', this._animateZoom, this); + } + + this._removeIcon(); + this._removeShadow(); + }, + + getEvents: function () { + return { + zoom: this.update, + viewreset: this.update + }; + }, + + // @method getLatLng: LatLng + // Returns the current geographical position of the marker. + getLatLng: function () { + return this._latlng; + }, + + // @method setLatLng(latlng: LatLng): this + // Changes the marker position to the given point. + setLatLng: function (latlng) { + var oldLatLng = this._latlng; + this._latlng = toLatLng(latlng); + this.update(); + + // @event move: Event + // Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`. + return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng}); + }, + + // @method setZIndexOffset(offset: Number): this + // Changes the [zIndex offset](#marker-zindexoffset) of the marker. + setZIndexOffset: function (offset) { + this.options.zIndexOffset = offset; + return this.update(); + }, + + // @method getIcon: Icon + // Returns the current icon used by the marker + getIcon: function () { + return this.options.icon; + }, + + // @method setIcon(icon: Icon): this + // Changes the marker icon. + setIcon: function (icon) { + + this.options.icon = icon; + + if (this._map) { + this._initIcon(); + this.update(); + } + + if (this._popup) { + this.bindPopup(this._popup, this._popup.options); + } + + return this; + }, + + getElement: function () { + return this._icon; + }, + + update: function () { + + if (this._icon && this._map) { + var pos = this._map.latLngToLayerPoint(this._latlng).round(); + this._setPos(pos); + } + + return this; + }, + + _initIcon: function () { + var options = this.options, + classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide'); + + var icon = options.icon.createIcon(this._icon), + addIcon = false; + + // if we're not reusing the icon, remove the old one and init new one + if (icon !== this._icon) { + if (this._icon) { + this._removeIcon(); + } + addIcon = true; + + if (options.title) { + icon.title = options.title; + } + + if (icon.tagName === 'IMG') { + icon.alt = options.alt || ''; + } + } + + addClass(icon, classToAdd); + + if (options.keyboard) { + icon.tabIndex = '0'; + icon.setAttribute('role', 'button'); + } + + this._icon = icon; + + if (options.riseOnHover) { + this.on({ + mouseover: this._bringToFront, + mouseout: this._resetZIndex + }); + } + + if (this.options.autoPanOnFocus) { + on(icon, 'focus', this._panOnFocus, this); + } + + var newShadow = options.icon.createShadow(this._shadow), + addShadow = false; + + if (newShadow !== this._shadow) { + this._removeShadow(); + addShadow = true; + } + + if (newShadow) { + addClass(newShadow, classToAdd); + newShadow.alt = ''; + } + this._shadow = newShadow; + + + if (options.opacity < 1) { + this._updateOpacity(); + } + + + if (addIcon) { + this.getPane().appendChild(this._icon); + } + this._initInteraction(); + if (newShadow && addShadow) { + this.getPane(options.shadowPane).appendChild(this._shadow); + } + }, + + _removeIcon: function () { + if (this.options.riseOnHover) { + this.off({ + mouseover: this._bringToFront, + mouseout: this._resetZIndex + }); + } + + if (this.options.autoPanOnFocus) { + off(this._icon, 'focus', this._panOnFocus, this); + } + + remove(this._icon); + this.removeInteractiveTarget(this._icon); + + this._icon = null; + }, + + _removeShadow: function () { + if (this._shadow) { + remove(this._shadow); + } + this._shadow = null; + }, + + _setPos: function (pos) { + + if (this._icon) { + setPosition(this._icon, pos); + } + + if (this._shadow) { + setPosition(this._shadow, pos); + } + + this._zIndex = pos.y + this.options.zIndexOffset; + + this._resetZIndex(); + }, + + _updateZIndex: function (offset) { + if (this._icon) { + this._icon.style.zIndex = this._zIndex + offset; + } + }, + + _animateZoom: function (opt) { + var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round(); + + this._setPos(pos); + }, + + _initInteraction: function () { + + if (!this.options.interactive) { return; } + + addClass(this._icon, 'leaflet-interactive'); + + this.addInteractiveTarget(this._icon); + + if (MarkerDrag) { + var draggable = this.options.draggable; + if (this.dragging) { + draggable = this.dragging.enabled(); + this.dragging.disable(); + } + + this.dragging = new MarkerDrag(this); + + if (draggable) { + this.dragging.enable(); + } + } + }, + + // @method setOpacity(opacity: Number): this + // Changes the opacity of the marker. + setOpacity: function (opacity) { + this.options.opacity = opacity; + if (this._map) { + this._updateOpacity(); + } + + return this; + }, + + _updateOpacity: function () { + var opacity = this.options.opacity; + + if (this._icon) { + setOpacity(this._icon, opacity); + } + + if (this._shadow) { + setOpacity(this._shadow, opacity); + } + }, + + _bringToFront: function () { + this._updateZIndex(this.options.riseOffset); + }, + + _resetZIndex: function () { + this._updateZIndex(0); + }, + + _panOnFocus: function () { + var map = this._map; + if (!map) { return; } + + var iconOpts = this.options.icon.options; + var size = iconOpts.iconSize ? toPoint(iconOpts.iconSize) : toPoint(0, 0); + var anchor = iconOpts.iconAnchor ? toPoint(iconOpts.iconAnchor) : toPoint(0, 0); + + map.panInside(this._latlng, { + paddingTopLeft: anchor, + paddingBottomRight: size.subtract(anchor) + }); + }, + + _getPopupAnchor: function () { + return this.options.icon.options.popupAnchor; + }, + + _getTooltipAnchor: function () { + return this.options.icon.options.tooltipAnchor; + } +}); + + +// factory L.marker(latlng: LatLng, options? : Marker options) + +// @factory L.marker(latlng: LatLng, options? : Marker options) +// Instantiates a Marker object given a geographical point and optionally an options object. +function marker(latlng, options) { + return new Marker(latlng, options); +} + +/* + * @class Path + * @aka L.Path + * @inherits Interactive layer + * + * An abstract class that contains options and constants shared between vector + * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`. + */ + +var Path = Layer.extend({ + + // @section + // @aka Path options + options: { + // @option stroke: Boolean = true + // Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles. + stroke: true, + + // @option color: String = '#3388ff' + // Stroke color + color: '#3388ff', + + // @option weight: Number = 3 + // Stroke width in pixels + weight: 3, + + // @option opacity: Number = 1.0 + // Stroke opacity + opacity: 1, + + // @option lineCap: String= 'round' + // A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke. + lineCap: 'round', + + // @option lineJoin: String = 'round' + // A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke. + lineJoin: 'round', + + // @option dashArray: String = null + // A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility). + dashArray: null, + + // @option dashOffset: String = null + // A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility). + dashOffset: null, + + // @option fill: Boolean = depends + // Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles. + fill: false, + + // @option fillColor: String = * + // Fill color. Defaults to the value of the [`color`](#path-color) option + fillColor: null, + + // @option fillOpacity: Number = 0.2 + // Fill opacity. + fillOpacity: 0.2, + + // @option fillRule: String = 'evenodd' + // A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined. + fillRule: 'evenodd', + + // className: '', + + // Option inherited from "Interactive layer" abstract class + interactive: true, + + // @option bubblingMouseEvents: Boolean = true + // When `true`, a mouse event on this path will trigger the same event on the map + // (unless [`L.DomEvent.stopPropagation`](#domevent-stoppropagation) is used). + bubblingMouseEvents: true + }, + + beforeAdd: function (map) { + // Renderer is set here because we need to call renderer.getEvents + // before this.getEvents. + this._renderer = map.getRenderer(this); + }, + + onAdd: function () { + this._renderer._initPath(this); + this._reset(); + this._renderer._addPath(this); + }, + + onRemove: function () { + this._renderer._removePath(this); + }, + + // @method redraw(): this + // Redraws the layer. Sometimes useful after you changed the coordinates that the path uses. + redraw: function () { + if (this._map) { + this._renderer._updatePath(this); + } + return this; + }, + + // @method setStyle(style: Path options): this + // Changes the appearance of a Path based on the options in the `Path options` object. + setStyle: function (style) { + setOptions(this, style); + if (this._renderer) { + this._renderer._updateStyle(this); + if (this.options.stroke && style && Object.prototype.hasOwnProperty.call(style, 'weight')) { + this._updateBounds(); + } + } + return this; + }, + + // @method bringToFront(): this + // Brings the layer to the top of all path layers. + bringToFront: function () { + if (this._renderer) { + this._renderer._bringToFront(this); + } + return this; + }, + + // @method bringToBack(): this + // Brings the layer to the bottom of all path layers. + bringToBack: function () { + if (this._renderer) { + this._renderer._bringToBack(this); + } + return this; + }, + + getElement: function () { + return this._path; + }, + + _reset: function () { + // defined in child classes + this._project(); + this._update(); + }, + + _clickTolerance: function () { + // used when doing hit detection for Canvas layers + return (this.options.stroke ? this.options.weight / 2 : 0) + + (this._renderer.options.tolerance || 0); + } +}); + +/* + * @class CircleMarker + * @aka L.CircleMarker + * @inherits Path + * + * A circle of a fixed size with radius specified in pixels. Extends `Path`. + */ + +var CircleMarker = Path.extend({ + + // @section + // @aka CircleMarker options + options: { + fill: true, + + // @option radius: Number = 10 + // Radius of the circle marker, in pixels + radius: 10 + }, + + initialize: function (latlng, options) { + setOptions(this, options); + this._latlng = toLatLng(latlng); + this._radius = this.options.radius; + }, + + // @method setLatLng(latLng: LatLng): this + // Sets the position of a circle marker to a new location. + setLatLng: function (latlng) { + var oldLatLng = this._latlng; + this._latlng = toLatLng(latlng); + this.redraw(); + + // @event move: Event + // Fired when the marker is moved via [`setLatLng`](#circlemarker-setlatlng). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`. + return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng}); + }, + + // @method getLatLng(): LatLng + // Returns the current geographical position of the circle marker + getLatLng: function () { + return this._latlng; + }, + + // @method setRadius(radius: Number): this + // Sets the radius of a circle marker. Units are in pixels. + setRadius: function (radius) { + this.options.radius = this._radius = radius; + return this.redraw(); + }, + + // @method getRadius(): Number + // Returns the current radius of the circle + getRadius: function () { + return this._radius; + }, + + setStyle : function (options) { + var radius = options && options.radius || this._radius; + Path.prototype.setStyle.call(this, options); + this.setRadius(radius); + return this; + }, + + _project: function () { + this._point = this._map.latLngToLayerPoint(this._latlng); + this._updateBounds(); + }, + + _updateBounds: function () { + var r = this._radius, + r2 = this._radiusY || r, + w = this._clickTolerance(), + p = [r + w, r2 + w]; + this._pxBounds = new Bounds(this._point.subtract(p), this._point.add(p)); + }, + + _update: function () { + if (this._map) { + this._updatePath(); + } + }, + + _updatePath: function () { + this._renderer._updateCircle(this); + }, + + _empty: function () { + return this._radius && !this._renderer._bounds.intersects(this._pxBounds); + }, + + // Needed by the `Canvas` renderer for interactivity + _containsPoint: function (p) { + return p.distanceTo(this._point) <= this._radius + this._clickTolerance(); + } +}); + + +// @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options) +// Instantiates a circle marker object given a geographical point, and an optional options object. +function circleMarker(latlng, options) { + return new CircleMarker(latlng, options); +} + +/* + * @class Circle + * @aka L.Circle + * @inherits CircleMarker + * + * A class for drawing circle overlays on a map. Extends `CircleMarker`. + * + * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion). + * + * @example + * + * ```js + * L.circle([50.5, 30.5], {radius: 200}).addTo(map); + * ``` + */ + +var Circle = CircleMarker.extend({ + + initialize: function (latlng, options, legacyOptions) { + if (typeof options === 'number') { + // Backwards compatibility with 0.7.x factory (latlng, radius, options?) + options = extend({}, legacyOptions, {radius: options}); + } + setOptions(this, options); + this._latlng = toLatLng(latlng); + + if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); } + + // @section + // @aka Circle options + // @option radius: Number; Radius of the circle, in meters. + this._mRadius = this.options.radius; + }, + + // @method setRadius(radius: Number): this + // Sets the radius of a circle. Units are in meters. + setRadius: function (radius) { + this._mRadius = radius; + return this.redraw(); + }, + + // @method getRadius(): Number + // Returns the current radius of a circle. Units are in meters. + getRadius: function () { + return this._mRadius; + }, + + // @method getBounds(): LatLngBounds + // Returns the `LatLngBounds` of the path. + getBounds: function () { + var half = [this._radius, this._radiusY || this._radius]; + + return new LatLngBounds( + this._map.layerPointToLatLng(this._point.subtract(half)), + this._map.layerPointToLatLng(this._point.add(half))); + }, + + setStyle: Path.prototype.setStyle, + + _project: function () { + + var lng = this._latlng.lng, + lat = this._latlng.lat, + map = this._map, + crs = map.options.crs; + + if (crs.distance === Earth.distance) { + var d = Math.PI / 180, + latR = (this._mRadius / Earth.R) / d, + top = map.project([lat + latR, lng]), + bottom = map.project([lat - latR, lng]), + p = top.add(bottom).divideBy(2), + lat2 = map.unproject(p).lat, + lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) / + (Math.cos(lat * d) * Math.cos(lat2 * d))) / d; + + if (isNaN(lngR) || lngR === 0) { + lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425 + } + + this._point = p.subtract(map.getPixelOrigin()); + this._radius = isNaN(lngR) ? 0 : p.x - map.project([lat2, lng - lngR]).x; + this._radiusY = p.y - top.y; + + } else { + var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0])); + + this._point = map.latLngToLayerPoint(this._latlng); + this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x; + } + + this._updateBounds(); + } +}); + +// @factory L.circle(latlng: LatLng, options?: Circle options) +// Instantiates a circle object given a geographical point, and an options object +// which contains the circle radius. +// @alternative +// @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options) +// Obsolete way of instantiating a circle, for compatibility with 0.7.x code. +// Do not use in new applications or plugins. +function circle(latlng, options, legacyOptions) { + return new Circle(latlng, options, legacyOptions); +} + +/* + * @class Polyline + * @aka L.Polyline + * @inherits Path + * + * A class for drawing polyline overlays on a map. Extends `Path`. + * + * @example + * + * ```js + * // create a red polyline from an array of LatLng points + * var latlngs = [ + * [45.51, -122.68], + * [37.77, -122.43], + * [34.04, -118.2] + * ]; + * + * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map); + * + * // zoom the map to the polyline + * map.fitBounds(polyline.getBounds()); + * ``` + * + * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape: + * + * ```js + * // create a red polyline from an array of arrays of LatLng points + * var latlngs = [ + * [[45.51, -122.68], + * [37.77, -122.43], + * [34.04, -118.2]], + * [[40.78, -73.91], + * [41.83, -87.62], + * [32.76, -96.72]] + * ]; + * ``` + */ + + +var Polyline = Path.extend({ + + // @section + // @aka Polyline options + options: { + // @option smoothFactor: Number = 1.0 + // How much to simplify the polyline on each zoom level. More means + // better performance and smoother look, and less means more accurate representation. + smoothFactor: 1.0, + + // @option noClip: Boolean = false + // Disable polyline clipping. + noClip: false + }, + + initialize: function (latlngs, options) { + setOptions(this, options); + this._setLatLngs(latlngs); + }, + + // @method getLatLngs(): LatLng[] + // Returns an array of the points in the path, or nested arrays of points in case of multi-polyline. + getLatLngs: function () { + return this._latlngs; + }, + + // @method setLatLngs(latlngs: LatLng[]): this + // Replaces all the points in the polyline with the given array of geographical points. + setLatLngs: function (latlngs) { + this._setLatLngs(latlngs); + return this.redraw(); + }, + + // @method isEmpty(): Boolean + // Returns `true` if the Polyline has no LatLngs. + isEmpty: function () { + return !this._latlngs.length; + }, + + // @method closestLayerPoint(p: Point): Point + // Returns the point closest to `p` on the Polyline. + closestLayerPoint: function (p) { + var minDistance = Infinity, + minPoint = null, + closest = _sqClosestPointOnSegment, + p1, p2; + + for (var j = 0, jLen = this._parts.length; j < jLen; j++) { + var points = this._parts[j]; + + for (var i = 1, len = points.length; i < len; i++) { + p1 = points[i - 1]; + p2 = points[i]; + + var sqDist = closest(p, p1, p2, true); + + if (sqDist < minDistance) { + minDistance = sqDist; + minPoint = closest(p, p1, p2); + } + } + } + if (minPoint) { + minPoint.distance = Math.sqrt(minDistance); + } + return minPoint; + }, + + // @method getCenter(): LatLng + // Returns the center ([centroid](https://en.wikipedia.org/wiki/Centroid)) of the polyline. + getCenter: function () { + // throws error when not yet added to map as this center calculation requires projected coordinates + if (!this._map) { + throw new Error('Must add layer to map before using getCenter()'); + } + return polylineCenter(this._defaultShape(), this._map.options.crs); + }, + + // @method getBounds(): LatLngBounds + // Returns the `LatLngBounds` of the path. + getBounds: function () { + return this._bounds; + }, + + // @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this + // Adds a given point to the polyline. By default, adds to the first ring of + // the polyline in case of a multi-polyline, but can be overridden by passing + // a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)). + addLatLng: function (latlng, latlngs) { + latlngs = latlngs || this._defaultShape(); + latlng = toLatLng(latlng); + latlngs.push(latlng); + this._bounds.extend(latlng); + return this.redraw(); + }, + + _setLatLngs: function (latlngs) { + this._bounds = new LatLngBounds(); + this._latlngs = this._convertLatLngs(latlngs); + }, + + _defaultShape: function () { + return isFlat(this._latlngs) ? this._latlngs : this._latlngs[0]; + }, + + // recursively convert latlngs input into actual LatLng instances; calculate bounds along the way + _convertLatLngs: function (latlngs) { + var result = [], + flat = isFlat(latlngs); + + for (var i = 0, len = latlngs.length; i < len; i++) { + if (flat) { + result[i] = toLatLng(latlngs[i]); + this._bounds.extend(result[i]); + } else { + result[i] = this._convertLatLngs(latlngs[i]); + } + } + + return result; + }, + + _project: function () { + var pxBounds = new Bounds(); + this._rings = []; + this._projectLatlngs(this._latlngs, this._rings, pxBounds); + + if (this._bounds.isValid() && pxBounds.isValid()) { + this._rawPxBounds = pxBounds; + this._updateBounds(); + } + }, + + _updateBounds: function () { + var w = this._clickTolerance(), + p = new Point(w, w); + + if (!this._rawPxBounds) { + return; + } + + this._pxBounds = new Bounds([ + this._rawPxBounds.min.subtract(p), + this._rawPxBounds.max.add(p) + ]); + }, + + // recursively turns latlngs into a set of rings with projected coordinates + _projectLatlngs: function (latlngs, result, projectedBounds) { + var flat = latlngs[0] instanceof LatLng, + len = latlngs.length, + i, ring; + + if (flat) { + ring = []; + for (i = 0; i < len; i++) { + ring[i] = this._map.latLngToLayerPoint(latlngs[i]); + projectedBounds.extend(ring[i]); + } + result.push(ring); + } else { + for (i = 0; i < len; i++) { + this._projectLatlngs(latlngs[i], result, projectedBounds); + } + } + }, + + // clip polyline by renderer bounds so that we have less to render for performance + _clipPoints: function () { + var bounds = this._renderer._bounds; + + this._parts = []; + if (!this._pxBounds || !this._pxBounds.intersects(bounds)) { + return; + } + + if (this.options.noClip) { + this._parts = this._rings; + return; + } + + var parts = this._parts, + i, j, k, len, len2, segment, points; + + for (i = 0, k = 0, len = this._rings.length; i < len; i++) { + points = this._rings[i]; + + for (j = 0, len2 = points.length; j < len2 - 1; j++) { + segment = clipSegment(points[j], points[j + 1], bounds, j, true); + + if (!segment) { continue; } + + parts[k] = parts[k] || []; + parts[k].push(segment[0]); + + // if segment goes out of screen, or it's the last one, it's the end of the line part + if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) { + parts[k].push(segment[1]); + k++; + } + } + } + }, + + // simplify each clipped part of the polyline for performance + _simplifyPoints: function () { + var parts = this._parts, + tolerance = this.options.smoothFactor; + + for (var i = 0, len = parts.length; i < len; i++) { + parts[i] = simplify(parts[i], tolerance); + } + }, + + _update: function () { + if (!this._map) { return; } + + this._clipPoints(); + this._simplifyPoints(); + this._updatePath(); + }, + + _updatePath: function () { + this._renderer._updatePoly(this); + }, + + // Needed by the `Canvas` renderer for interactivity + _containsPoint: function (p, closed) { + var i, j, k, len, len2, part, + w = this._clickTolerance(); + + if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; } + + // hit detection for polylines + for (i = 0, len = this._parts.length; i < len; i++) { + part = this._parts[i]; + + for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { + if (!closed && (j === 0)) { continue; } + + if (pointToSegmentDistance(p, part[k], part[j]) <= w) { + return true; + } + } + } + return false; + } +}); + +// @factory L.polyline(latlngs: LatLng[], options?: Polyline options) +// Instantiates a polyline object given an array of geographical points and +// optionally an options object. You can create a `Polyline` object with +// multiple separate lines (`MultiPolyline`) by passing an array of arrays +// of geographic points. +function polyline(latlngs, options) { + return new Polyline(latlngs, options); +} + +// Retrocompat. Allow plugins to support Leaflet versions before and after 1.1. +Polyline._flat = _flat; + +/* + * @class Polygon + * @aka L.Polygon + * @inherits Polyline + * + * A class for drawing polygon overlays on a map. Extends `Polyline`. + * + * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points. + * + * + * @example + * + * ```js + * // create a red polygon from an array of LatLng points + * var latlngs = [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]]; + * + * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map); + * + * // zoom the map to the polygon + * map.fitBounds(polygon.getBounds()); + * ``` + * + * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape: + * + * ```js + * var latlngs = [ + * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring + * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole + * ]; + * ``` + * + * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape. + * + * ```js + * var latlngs = [ + * [ // first polygon + * [[37, -109.05],[41, -109.03],[41, -102.05],[37, -102.04]], // outer ring + * [[37.29, -108.58],[40.71, -108.58],[40.71, -102.50],[37.29, -102.50]] // hole + * ], + * [ // second polygon + * [[41, -111.03],[45, -111.04],[45, -104.05],[41, -104.05]] + * ] + * ]; + * ``` + */ + +var Polygon = Polyline.extend({ + + options: { + fill: true + }, + + isEmpty: function () { + return !this._latlngs.length || !this._latlngs[0].length; + }, + + // @method getCenter(): LatLng + // Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the Polygon. + getCenter: function () { + // throws error when not yet added to map as this center calculation requires projected coordinates + if (!this._map) { + throw new Error('Must add layer to map before using getCenter()'); + } + return polygonCenter(this._defaultShape(), this._map.options.crs); + }, + + _convertLatLngs: function (latlngs) { + var result = Polyline.prototype._convertLatLngs.call(this, latlngs), + len = result.length; + + // remove last point if it equals first one + if (len >= 2 && result[0] instanceof LatLng && result[0].equals(result[len - 1])) { + result.pop(); + } + return result; + }, + + _setLatLngs: function (latlngs) { + Polyline.prototype._setLatLngs.call(this, latlngs); + if (isFlat(this._latlngs)) { + this._latlngs = [this._latlngs]; + } + }, + + _defaultShape: function () { + return isFlat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0]; + }, + + _clipPoints: function () { + // polygons need a different clipping algorithm so we redefine that + + var bounds = this._renderer._bounds, + w = this.options.weight, + p = new Point(w, w); + + // increase clip padding by stroke width to avoid stroke on clip edges + bounds = new Bounds(bounds.min.subtract(p), bounds.max.add(p)); + + this._parts = []; + if (!this._pxBounds || !this._pxBounds.intersects(bounds)) { + return; + } + + if (this.options.noClip) { + this._parts = this._rings; + return; + } + + for (var i = 0, len = this._rings.length, clipped; i < len; i++) { + clipped = clipPolygon(this._rings[i], bounds, true); + if (clipped.length) { + this._parts.push(clipped); + } + } + }, + + _updatePath: function () { + this._renderer._updatePoly(this, true); + }, + + // Needed by the `Canvas` renderer for interactivity + _containsPoint: function (p) { + var inside = false, + part, p1, p2, i, j, k, len, len2; + + if (!this._pxBounds || !this._pxBounds.contains(p)) { return false; } + + // ray casting algorithm for detecting if point is in polygon + for (i = 0, len = this._parts.length; i < len; i++) { + part = this._parts[i]; + + for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) { + p1 = part[j]; + p2 = part[k]; + + if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) { + inside = !inside; + } + } + } + + // also check if it's on polygon stroke + return inside || Polyline.prototype._containsPoint.call(this, p, true); + } + +}); + + +// @factory L.polygon(latlngs: LatLng[], options?: Polyline options) +function polygon(latlngs, options) { + return new Polygon(latlngs, options); +} + +/* + * @class GeoJSON + * @aka L.GeoJSON + * @inherits FeatureGroup + * + * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse + * GeoJSON data and display it on the map. Extends `FeatureGroup`. + * + * @example + * + * ```js + * L.geoJSON(data, { + * style: function (feature) { + * return {color: feature.properties.color}; + * } + * }).bindPopup(function (layer) { + * return layer.feature.properties.description; + * }).addTo(map); + * ``` + */ + +var GeoJSON = FeatureGroup.extend({ + + /* @section + * @aka GeoJSON options + * + * @option pointToLayer: Function = * + * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally + * called when data is added, passing the GeoJSON point feature and its `LatLng`. + * The default is to spawn a default `Marker`: + * ```js + * function(geoJsonPoint, latlng) { + * return L.marker(latlng); + * } + * ``` + * + * @option style: Function = * + * A `Function` defining the `Path options` for styling GeoJSON lines and polygons, + * called internally when data is added. + * The default value is to not override any defaults: + * ```js + * function (geoJsonFeature) { + * return {} + * } + * ``` + * + * @option onEachFeature: Function = * + * A `Function` that will be called once for each created `Feature`, after it has + * been created and styled. Useful for attaching events and popups to features. + * The default is to do nothing with the newly created layers: + * ```js + * function (feature, layer) {} + * ``` + * + * @option filter: Function = * + * A `Function` that will be used to decide whether to include a feature or not. + * The default is to include all features: + * ```js + * function (geoJsonFeature) { + * return true; + * } + * ``` + * Note: dynamically changing the `filter` option will have effect only on newly + * added data. It will _not_ re-evaluate already included features. + * + * @option coordsToLatLng: Function = * + * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s. + * The default is the `coordsToLatLng` static method. + * + * @option markersInheritOptions: Boolean = false + * Whether default Markers for "Point" type Features inherit from group options. + */ + + initialize: function (geojson, options) { + setOptions(this, options); + + this._layers = {}; + + if (geojson) { + this.addData(geojson); + } + }, + + // @method addData( <GeoJSON> data ): this + // Adds a GeoJSON object to the layer. + addData: function (geojson) { + var features = isArray(geojson) ? geojson : geojson.features, + i, len, feature; + + if (features) { + for (i = 0, len = features.length; i < len; i++) { + // only add this if geometry or geometries are set and not null + feature = features[i]; + if (feature.geometries || feature.geometry || feature.features || feature.coordinates) { + this.addData(feature); + } + } + return this; + } + + var options = this.options; + + if (options.filter && !options.filter(geojson)) { return this; } + + var layer = geometryToLayer(geojson, options); + if (!layer) { + return this; + } + layer.feature = asFeature(geojson); + + layer.defaultOptions = layer.options; + this.resetStyle(layer); + + if (options.onEachFeature) { + options.onEachFeature(geojson, layer); + } + + return this.addLayer(layer); + }, + + // @method resetStyle( <Path> layer? ): this + // Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events. + // If `layer` is omitted, the style of all features in the current layer is reset. + resetStyle: function (layer) { + if (layer === undefined) { + return this.eachLayer(this.resetStyle, this); + } + // reset any custom styles + layer.options = extend({}, layer.defaultOptions); + this._setLayerStyle(layer, this.options.style); + return this; + }, + + // @method setStyle( <Function> style ): this + // Changes styles of GeoJSON vector layers with the given style function. + setStyle: function (style) { + return this.eachLayer(function (layer) { + this._setLayerStyle(layer, style); + }, this); + }, + + _setLayerStyle: function (layer, style) { + if (layer.setStyle) { + if (typeof style === 'function') { + style = style(layer.feature); + } + layer.setStyle(style); + } + } +}); + +// @section +// There are several static functions which can be called without instantiating L.GeoJSON: + +// @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer +// Creates a `Layer` from a given GeoJSON feature. Can use a custom +// [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng) +// functions if provided as options. +function geometryToLayer(geojson, options) { + + var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson, + coords = geometry ? geometry.coordinates : null, + layers = [], + pointToLayer = options && options.pointToLayer, + _coordsToLatLng = options && options.coordsToLatLng || coordsToLatLng, + latlng, latlngs, i, len; + + if (!coords && !geometry) { + return null; + } + + switch (geometry.type) { + case 'Point': + latlng = _coordsToLatLng(coords); + return _pointToLayer(pointToLayer, geojson, latlng, options); + + case 'MultiPoint': + for (i = 0, len = coords.length; i < len; i++) { + latlng = _coordsToLatLng(coords[i]); + layers.push(_pointToLayer(pointToLayer, geojson, latlng, options)); + } + return new FeatureGroup(layers); + + case 'LineString': + case 'MultiLineString': + latlngs = coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, _coordsToLatLng); + return new Polyline(latlngs, options); + + case 'Polygon': + case 'MultiPolygon': + latlngs = coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, _coordsToLatLng); + return new Polygon(latlngs, options); + + case 'GeometryCollection': + for (i = 0, len = geometry.geometries.length; i < len; i++) { + var geoLayer = geometryToLayer({ + geometry: geometry.geometries[i], + type: 'Feature', + properties: geojson.properties + }, options); + + if (geoLayer) { + layers.push(geoLayer); + } + } + return new FeatureGroup(layers); + + case 'FeatureCollection': + for (i = 0, len = geometry.features.length; i < len; i++) { + var featureLayer = geometryToLayer(geometry.features[i], options); + + if (featureLayer) { + layers.push(featureLayer); + } + } + return new FeatureGroup(layers); + + default: + throw new Error('Invalid GeoJSON object.'); + } +} + +function _pointToLayer(pointToLayerFn, geojson, latlng, options) { + return pointToLayerFn ? + pointToLayerFn(geojson, latlng) : + new Marker(latlng, options && options.markersInheritOptions && options); +} + +// @function coordsToLatLng(coords: Array): LatLng +// Creates a `LatLng` object from an array of 2 numbers (longitude, latitude) +// or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points. +function coordsToLatLng(coords) { + return new LatLng(coords[1], coords[0], coords[2]); +} + +// @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array +// Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array. +// `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default). +// Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function. +function coordsToLatLngs(coords, levelsDeep, _coordsToLatLng) { + var latlngs = []; + + for (var i = 0, len = coords.length, latlng; i < len; i++) { + latlng = levelsDeep ? + coordsToLatLngs(coords[i], levelsDeep - 1, _coordsToLatLng) : + (_coordsToLatLng || coordsToLatLng)(coords[i]); + + latlngs.push(latlng); + } + + return latlngs; +} + +// @function latLngToCoords(latlng: LatLng, precision?: Number|false): Array +// Reverse of [`coordsToLatLng`](#geojson-coordstolatlng) +// Coordinates values are rounded with [`formatNum`](#util-formatnum) function. +function latLngToCoords(latlng, precision) { + latlng = toLatLng(latlng); + return latlng.alt !== undefined ? + [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision), formatNum(latlng.alt, precision)] : + [formatNum(latlng.lng, precision), formatNum(latlng.lat, precision)]; +} + +// @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean, precision?: Number|false): Array +// Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs) +// `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default. +// Coordinates values are rounded with [`formatNum`](#util-formatnum) function. +function latLngsToCoords(latlngs, levelsDeep, closed, precision) { + var coords = []; + + for (var i = 0, len = latlngs.length; i < len; i++) { + // Check for flat arrays required to ensure unbalanced arrays are correctly converted in recursion + coords.push(levelsDeep ? + latLngsToCoords(latlngs[i], isFlat(latlngs[i]) ? 0 : levelsDeep - 1, closed, precision) : + latLngToCoords(latlngs[i], precision)); + } + + if (!levelsDeep && closed && coords.length > 0) { + coords.push(coords[0].slice()); + } + + return coords; +} + +function getFeature(layer, newGeometry) { + return layer.feature ? + extend({}, layer.feature, {geometry: newGeometry}) : + asFeature(newGeometry); +} + +// @function asFeature(geojson: Object): Object +// Normalize GeoJSON geometries/features into GeoJSON features. +function asFeature(geojson) { + if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') { + return geojson; + } + + return { + type: 'Feature', + properties: {}, + geometry: geojson + }; +} + +var PointToGeoJSON = { + toGeoJSON: function (precision) { + return getFeature(this, { + type: 'Point', + coordinates: latLngToCoords(this.getLatLng(), precision) + }); + } +}; + +// @namespace Marker +// @section Other methods +// @method toGeoJSON(precision?: Number|false): Object +// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`. +// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature). +Marker.include(PointToGeoJSON); + +// @namespace CircleMarker +// @method toGeoJSON(precision?: Number|false): Object +// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`. +// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature). +Circle.include(PointToGeoJSON); +CircleMarker.include(PointToGeoJSON); + + +// @namespace Polyline +// @method toGeoJSON(precision?: Number|false): Object +// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`. +// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature). +Polyline.include({ + toGeoJSON: function (precision) { + var multi = !isFlat(this._latlngs); + + var coords = latLngsToCoords(this._latlngs, multi ? 1 : 0, false, precision); + + return getFeature(this, { + type: (multi ? 'Multi' : '') + 'LineString', + coordinates: coords + }); + } +}); + +// @namespace Polygon +// @method toGeoJSON(precision?: Number|false): Object +// Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`. +// Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature). +Polygon.include({ + toGeoJSON: function (precision) { + var holes = !isFlat(this._latlngs), + multi = holes && !isFlat(this._latlngs[0]); + + var coords = latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true, precision); + + if (!holes) { + coords = [coords]; + } + + return getFeature(this, { + type: (multi ? 'Multi' : '') + 'Polygon', + coordinates: coords + }); + } +}); + + +// @namespace LayerGroup +LayerGroup.include({ + toMultiPoint: function (precision) { + var coords = []; + + this.eachLayer(function (layer) { + coords.push(layer.toGeoJSON(precision).geometry.coordinates); + }); + + return getFeature(this, { + type: 'MultiPoint', + coordinates: coords + }); + }, + + // @method toGeoJSON(precision?: Number|false): Object + // Coordinates values are rounded with [`formatNum`](#util-formatnum) function with given `precision`. + // Returns a [`GeoJSON`](https://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `FeatureCollection`, `GeometryCollection`, or `MultiPoint`). + toGeoJSON: function (precision) { + + var type = this.feature && this.feature.geometry && this.feature.geometry.type; + + if (type === 'MultiPoint') { + return this.toMultiPoint(precision); + } + + var isGeometryCollection = type === 'GeometryCollection', + jsons = []; + + this.eachLayer(function (layer) { + if (layer.toGeoJSON) { + var json = layer.toGeoJSON(precision); + if (isGeometryCollection) { + jsons.push(json.geometry); + } else { + var feature = asFeature(json); + // Squash nested feature collections + if (feature.type === 'FeatureCollection') { + jsons.push.apply(jsons, feature.features); + } else { + jsons.push(feature); + } + } + } + }); + + if (isGeometryCollection) { + return getFeature(this, { + geometries: jsons, + type: 'GeometryCollection' + }); + } + + return { + type: 'FeatureCollection', + features: jsons + }; + } +}); + +// @namespace GeoJSON +// @factory L.geoJSON(geojson?: Object, options?: GeoJSON options) +// Creates a GeoJSON layer. Optionally accepts an object in +// [GeoJSON format](https://tools.ietf.org/html/rfc7946) to display on the map +// (you can alternatively add it later with `addData` method) and an `options` object. +function geoJSON(geojson, options) { + return new GeoJSON(geojson, options); +} + +// Backward compatibility. +var geoJson = geoJSON; + +/* + * @class ImageOverlay + * @aka L.ImageOverlay + * @inherits Interactive layer + * + * Used to load and display a single image over specific bounds of the map. Extends `Layer`. + * + * @example + * + * ```js + * var imageUrl = 'https://maps.lib.utexas.edu/maps/historical/newark_nj_1922.jpg', + * imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]]; + * L.imageOverlay(imageUrl, imageBounds).addTo(map); + * ``` + */ + +var ImageOverlay = Layer.extend({ + + // @section + // @aka ImageOverlay options + options: { + // @option opacity: Number = 1.0 + // The opacity of the image overlay. + opacity: 1, + + // @option alt: String = '' + // Text for the `alt` attribute of the image (useful for accessibility). + alt: '', + + // @option interactive: Boolean = false + // If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered. + interactive: false, + + // @option crossOrigin: Boolean|String = false + // Whether the crossOrigin attribute will be added to the image. + // If a String is provided, the image will have its crossOrigin attribute set to the String provided. This is needed if you want to access image pixel data. + // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values. + crossOrigin: false, + + // @option errorOverlayUrl: String = '' + // URL to the overlay image to show in place of the overlay that failed to load. + errorOverlayUrl: '', + + // @option zIndex: Number = 1 + // The explicit [zIndex](https://developer.mozilla.org/docs/Web/CSS/CSS_Positioning/Understanding_z_index) of the overlay layer. + zIndex: 1, + + // @option className: String = '' + // A custom class name to assign to the image. Empty by default. + className: '' + }, + + initialize: function (url, bounds, options) { // (String, LatLngBounds, Object) + this._url = url; + this._bounds = toLatLngBounds(bounds); + + setOptions(this, options); + }, + + onAdd: function () { + if (!this._image) { + this._initImage(); + + if (this.options.opacity < 1) { + this._updateOpacity(); + } + } + + if (this.options.interactive) { + addClass(this._image, 'leaflet-interactive'); + this.addInteractiveTarget(this._image); + } + + this.getPane().appendChild(this._image); + this._reset(); + }, + + onRemove: function () { + remove(this._image); + if (this.options.interactive) { + this.removeInteractiveTarget(this._image); + } + }, + + // @method setOpacity(opacity: Number): this + // Sets the opacity of the overlay. + setOpacity: function (opacity) { + this.options.opacity = opacity; + + if (this._image) { + this._updateOpacity(); + } + return this; + }, + + setStyle: function (styleOpts) { + if (styleOpts.opacity) { + this.setOpacity(styleOpts.opacity); + } + return this; + }, + + // @method bringToFront(): this + // Brings the layer to the top of all overlays. + bringToFront: function () { + if (this._map) { + toFront(this._image); + } + return this; + }, + + // @method bringToBack(): this + // Brings the layer to the bottom of all overlays. + bringToBack: function () { + if (this._map) { + toBack(this._image); + } + return this; + }, + + // @method setUrl(url: String): this + // Changes the URL of the image. + setUrl: function (url) { + this._url = url; + + if (this._image) { + this._image.src = url; + } + return this; + }, + + // @method setBounds(bounds: LatLngBounds): this + // Update the bounds that this ImageOverlay covers + setBounds: function (bounds) { + this._bounds = toLatLngBounds(bounds); + + if (this._map) { + this._reset(); + } + return this; + }, + + getEvents: function () { + var events = { + zoom: this._reset, + viewreset: this._reset + }; + + if (this._zoomAnimated) { + events.zoomanim = this._animateZoom; + } + + return events; + }, + + // @method setZIndex(value: Number): this + // Changes the [zIndex](#imageoverlay-zindex) of the image overlay. + setZIndex: function (value) { + this.options.zIndex = value; + this._updateZIndex(); + return this; + }, + + // @method getBounds(): LatLngBounds + // Get the bounds that this ImageOverlay covers + getBounds: function () { + return this._bounds; + }, + + // @method getElement(): HTMLElement + // Returns the instance of [`HTMLImageElement`](https://developer.mozilla.org/docs/Web/API/HTMLImageElement) + // used by this overlay. + getElement: function () { + return this._image; + }, + + _initImage: function () { + var wasElementSupplied = this._url.tagName === 'IMG'; + var img = this._image = wasElementSupplied ? this._url : create$1('img'); + + addClass(img, 'leaflet-image-layer'); + if (this._zoomAnimated) { addClass(img, 'leaflet-zoom-animated'); } + if (this.options.className) { addClass(img, this.options.className); } + + img.onselectstart = falseFn; + img.onmousemove = falseFn; + + // @event load: Event + // Fired when the ImageOverlay layer has loaded its image + img.onload = bind(this.fire, this, 'load'); + img.onerror = bind(this._overlayOnError, this, 'error'); + + if (this.options.crossOrigin || this.options.crossOrigin === '') { + img.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin; + } + + if (this.options.zIndex) { + this._updateZIndex(); + } + + if (wasElementSupplied) { + this._url = img.src; + return; + } + + img.src = this._url; + img.alt = this.options.alt; + }, + + _animateZoom: function (e) { + var scale = this._map.getZoomScale(e.zoom), + offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min; + + setTransform(this._image, offset, scale); + }, + + _reset: function () { + var image = this._image, + bounds = new Bounds( + this._map.latLngToLayerPoint(this._bounds.getNorthWest()), + this._map.latLngToLayerPoint(this._bounds.getSouthEast())), + size = bounds.getSize(); + + setPosition(image, bounds.min); + + image.style.width = size.x + 'px'; + image.style.height = size.y + 'px'; + }, + + _updateOpacity: function () { + setOpacity(this._image, this.options.opacity); + }, + + _updateZIndex: function () { + if (this._image && this.options.zIndex !== undefined && this.options.zIndex !== null) { + this._image.style.zIndex = this.options.zIndex; + } + }, + + _overlayOnError: function () { + // @event error: Event + // Fired when the ImageOverlay layer fails to load its image + this.fire('error'); + + var errorUrl = this.options.errorOverlayUrl; + if (errorUrl && this._url !== errorUrl) { + this._url = errorUrl; + this._image.src = errorUrl; + } + }, + + // @method getCenter(): LatLng + // Returns the center of the ImageOverlay. + getCenter: function () { + return this._bounds.getCenter(); + } +}); + +// @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options) +// Instantiates an image overlay object given the URL of the image and the +// geographical bounds it is tied to. +var imageOverlay = function (url, bounds, options) { + return new ImageOverlay(url, bounds, options); +}; + +/* + * @class VideoOverlay + * @aka L.VideoOverlay + * @inherits ImageOverlay + * + * Used to load and display a video player over specific bounds of the map. Extends `ImageOverlay`. + * + * A video overlay uses the [`<video>`](https://developer.mozilla.org/docs/Web/HTML/Element/video) + * HTML5 element. + * + * @example + * + * ```js + * var videoUrl = 'https://www.mapbox.com/bites/00188/patricia_nasa.webm', + * videoBounds = [[ 32, -130], [ 13, -100]]; + * L.videoOverlay(videoUrl, videoBounds ).addTo(map); + * ``` + */ + +var VideoOverlay = ImageOverlay.extend({ + + // @section + // @aka VideoOverlay options + options: { + // @option autoplay: Boolean = true + // Whether the video starts playing automatically when loaded. + // On some browsers autoplay will only work with `muted: true` + autoplay: true, + + // @option loop: Boolean = true + // Whether the video will loop back to the beginning when played. + loop: true, + + // @option keepAspectRatio: Boolean = true + // Whether the video will save aspect ratio after the projection. + // Relevant for supported browsers. See [browser compatibility](https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit) + keepAspectRatio: true, + + // @option muted: Boolean = false + // Whether the video starts on mute when loaded. + muted: false, + + // @option playsInline: Boolean = true + // Mobile browsers will play the video right where it is instead of open it up in fullscreen mode. + playsInline: true + }, + + _initImage: function () { + var wasElementSupplied = this._url.tagName === 'VIDEO'; + var vid = this._image = wasElementSupplied ? this._url : create$1('video'); + + addClass(vid, 'leaflet-image-layer'); + if (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated'); } + if (this.options.className) { addClass(vid, this.options.className); } + + vid.onselectstart = falseFn; + vid.onmousemove = falseFn; + + // @event load: Event + // Fired when the video has finished loading the first frame + vid.onloadeddata = bind(this.fire, this, 'load'); + + if (wasElementSupplied) { + var sourceElements = vid.getElementsByTagName('source'); + var sources = []; + for (var j = 0; j < sourceElements.length; j++) { + sources.push(sourceElements[j].src); + } + + this._url = (sourceElements.length > 0) ? sources : [vid.src]; + return; + } + + if (!isArray(this._url)) { this._url = [this._url]; } + + if (!this.options.keepAspectRatio && Object.prototype.hasOwnProperty.call(vid.style, 'objectFit')) { + vid.style['objectFit'] = 'fill'; + } + vid.autoplay = !!this.options.autoplay; + vid.loop = !!this.options.loop; + vid.muted = !!this.options.muted; + vid.playsInline = !!this.options.playsInline; + for (var i = 0; i < this._url.length; i++) { + var source = create$1('source'); + source.src = this._url[i]; + vid.appendChild(source); + } + } + + // @method getElement(): HTMLVideoElement + // Returns the instance of [`HTMLVideoElement`](https://developer.mozilla.org/docs/Web/API/HTMLVideoElement) + // used by this overlay. +}); + + +// @factory L.videoOverlay(video: String|Array|HTMLVideoElement, bounds: LatLngBounds, options?: VideoOverlay options) +// Instantiates an image overlay object given the URL of the video (or array of URLs, or even a video element) and the +// geographical bounds it is tied to. + +function videoOverlay(video, bounds, options) { + return new VideoOverlay(video, bounds, options); +} + +/* + * @class SVGOverlay + * @aka L.SVGOverlay + * @inherits ImageOverlay + * + * Used to load, display and provide DOM access to an SVG file over specific bounds of the map. Extends `ImageOverlay`. + * + * An SVG overlay uses the [`<svg>`](https://developer.mozilla.org/docs/Web/SVG/Element/svg) element. + * + * @example + * + * ```js + * var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + * svgElement.setAttribute('xmlns', "http://www.w3.org/2000/svg"); + * svgElement.setAttribute('viewBox', "0 0 200 200"); + * svgElement.innerHTML = '<rect width="200" height="200"/><rect x="75" y="23" width="50" height="50" style="fill:red"/><rect x="75" y="123" width="50" height="50" style="fill:#0013ff"/>'; + * var svgElementBounds = [ [ 32, -130 ], [ 13, -100 ] ]; + * L.svgOverlay(svgElement, svgElementBounds).addTo(map); + * ``` + */ + +var SVGOverlay = ImageOverlay.extend({ + _initImage: function () { + var el = this._image = this._url; + + addClass(el, 'leaflet-image-layer'); + if (this._zoomAnimated) { addClass(el, 'leaflet-zoom-animated'); } + if (this.options.className) { addClass(el, this.options.className); } + + el.onselectstart = falseFn; + el.onmousemove = falseFn; + } + + // @method getElement(): SVGElement + // Returns the instance of [`SVGElement`](https://developer.mozilla.org/docs/Web/API/SVGElement) + // used by this overlay. +}); + + +// @factory L.svgOverlay(svg: String|SVGElement, bounds: LatLngBounds, options?: SVGOverlay options) +// Instantiates an image overlay object given an SVG element and the geographical bounds it is tied to. +// A viewBox attribute is required on the SVG element to zoom in and out properly. + +function svgOverlay(el, bounds, options) { + return new SVGOverlay(el, bounds, options); +} + +/* + * @class DivOverlay + * @inherits Interactive layer + * @aka L.DivOverlay + * Base model for L.Popup and L.Tooltip. Inherit from it for custom overlays like plugins. + */ + +// @namespace DivOverlay +var DivOverlay = Layer.extend({ + + // @section + // @aka DivOverlay options + options: { + // @option interactive: Boolean = false + // If true, the popup/tooltip will listen to the mouse events. + interactive: false, + + // @option offset: Point = Point(0, 0) + // The offset of the overlay position. + offset: [0, 0], + + // @option className: String = '' + // A custom CSS class name to assign to the overlay. + className: '', + + // @option pane: String = undefined + // `Map pane` where the overlay will be added. + pane: undefined, + + // @option content: String|HTMLElement|Function = '' + // Sets the HTML content of the overlay while initializing. If a function is passed the source layer will be + // passed to the function. The function should return a `String` or `HTMLElement` to be used in the overlay. + content: '' + }, + + initialize: function (options, source) { + if (options && (options instanceof LatLng || isArray(options))) { + this._latlng = toLatLng(options); + setOptions(this, source); + } else { + setOptions(this, options); + this._source = source; + } + if (this.options.content) { + this._content = this.options.content; + } + }, + + // @method openOn(map: Map): this + // Adds the overlay to the map. + // Alternative to `map.openPopup(popup)`/`.openTooltip(tooltip)`. + openOn: function (map) { + map = arguments.length ? map : this._source._map; // experimental, not the part of public api + if (!map.hasLayer(this)) { + map.addLayer(this); + } + return this; + }, + + // @method close(): this + // Closes the overlay. + // Alternative to `map.closePopup(popup)`/`.closeTooltip(tooltip)` + // and `layer.closePopup()`/`.closeTooltip()`. + close: function () { + if (this._map) { + this._map.removeLayer(this); + } + return this; + }, + + // @method toggle(layer?: Layer): this + // Opens or closes the overlay bound to layer depending on its current state. + // Argument may be omitted only for overlay bound to layer. + // Alternative to `layer.togglePopup()`/`.toggleTooltip()`. + toggle: function (layer) { + if (this._map) { + this.close(); + } else { + if (arguments.length) { + this._source = layer; + } else { + layer = this._source; + } + this._prepareOpen(); + + // open the overlay on the map + this.openOn(layer._map); + } + return this; + }, + + onAdd: function (map) { + this._zoomAnimated = map._zoomAnimated; + + if (!this._container) { + this._initLayout(); + } + + if (map._fadeAnimated) { + setOpacity(this._container, 0); + } + + clearTimeout(this._removeTimeout); + this.getPane().appendChild(this._container); + this.update(); + + if (map._fadeAnimated) { + setOpacity(this._container, 1); + } + + this.bringToFront(); + + if (this.options.interactive) { + addClass(this._container, 'leaflet-interactive'); + this.addInteractiveTarget(this._container); + } + }, + + onRemove: function (map) { + if (map._fadeAnimated) { + setOpacity(this._container, 0); + this._removeTimeout = setTimeout(bind(remove, undefined, this._container), 200); + } else { + remove(this._container); + } + + if (this.options.interactive) { + removeClass(this._container, 'leaflet-interactive'); + this.removeInteractiveTarget(this._container); + } + }, + + // @namespace DivOverlay + // @method getLatLng: LatLng + // Returns the geographical point of the overlay. + getLatLng: function () { + return this._latlng; + }, + + // @method setLatLng(latlng: LatLng): this + // Sets the geographical point where the overlay will open. + setLatLng: function (latlng) { + this._latlng = toLatLng(latlng); + if (this._map) { + this._updatePosition(); + this._adjustPan(); + } + return this; + }, + + // @method getContent: String|HTMLElement + // Returns the content of the overlay. + getContent: function () { + return this._content; + }, + + // @method setContent(htmlContent: String|HTMLElement|Function): this + // Sets the HTML content of the overlay. If a function is passed the source layer will be passed to the function. + // The function should return a `String` or `HTMLElement` to be used in the overlay. + setContent: function (content) { + this._content = content; + this.update(); + return this; + }, + + // @method getElement: String|HTMLElement + // Returns the HTML container of the overlay. + getElement: function () { + return this._container; + }, + + // @method update: null + // Updates the overlay content, layout and position. Useful for updating the overlay after something inside changed, e.g. image loaded. + update: function () { + if (!this._map) { return; } + + this._container.style.visibility = 'hidden'; + + this._updateContent(); + this._updateLayout(); + this._updatePosition(); + + this._container.style.visibility = ''; + + this._adjustPan(); + }, + + getEvents: function () { + var events = { + zoom: this._updatePosition, + viewreset: this._updatePosition + }; + + if (this._zoomAnimated) { + events.zoomanim = this._animateZoom; + } + return events; + }, + + // @method isOpen: Boolean + // Returns `true` when the overlay is visible on the map. + isOpen: function () { + return !!this._map && this._map.hasLayer(this); + }, + + // @method bringToFront: this + // Brings this overlay in front of other overlays (in the same map pane). + bringToFront: function () { + if (this._map) { + toFront(this._container); + } + return this; + }, + + // @method bringToBack: this + // Brings this overlay to the back of other overlays (in the same map pane). + bringToBack: function () { + if (this._map) { + toBack(this._container); + } + return this; + }, + + // prepare bound overlay to open: update latlng pos / content source (for FeatureGroup) + _prepareOpen: function (latlng) { + var source = this._source; + if (!source._map) { return false; } + + if (source instanceof FeatureGroup) { + source = null; + var layers = this._source._layers; + for (var id in layers) { + if (layers[id]._map) { + source = layers[id]; + break; + } + } + if (!source) { return false; } // Unable to get source layer. + + // set overlay source to this layer + this._source = source; + } + + if (!latlng) { + if (source.getCenter) { + latlng = source.getCenter(); + } else if (source.getLatLng) { + latlng = source.getLatLng(); + } else if (source.getBounds) { + latlng = source.getBounds().getCenter(); + } else { + throw new Error('Unable to get source layer LatLng.'); + } + } + this.setLatLng(latlng); + + if (this._map) { + // update the overlay (content, layout, etc...) + this.update(); + } + + return true; + }, + + _updateContent: function () { + if (!this._content) { return; } + + var node = this._contentNode; + var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content; + + if (typeof content === 'string') { + node.innerHTML = content; + } else { + while (node.hasChildNodes()) { + node.removeChild(node.firstChild); + } + node.appendChild(content); + } + + // @namespace DivOverlay + // @section DivOverlay events + // @event contentupdate: Event + // Fired when the content of the overlay is updated + this.fire('contentupdate'); + }, + + _updatePosition: function () { + if (!this._map) { return; } + + var pos = this._map.latLngToLayerPoint(this._latlng), + offset = toPoint(this.options.offset), + anchor = this._getAnchor(); + + if (this._zoomAnimated) { + setPosition(this._container, pos.add(anchor)); + } else { + offset = offset.add(pos).add(anchor); + } + + var bottom = this._containerBottom = -offset.y, + left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x; + + // bottom position the overlay in case the height of the overlay changes (images loading etc) + this._container.style.bottom = bottom + 'px'; + this._container.style.left = left + 'px'; + }, + + _getAnchor: function () { + return [0, 0]; + } + +}); + +Map.include({ + _initOverlay: function (OverlayClass, content, latlng, options) { + var overlay = content; + if (!(overlay instanceof OverlayClass)) { + overlay = new OverlayClass(options).setContent(content); + } + if (latlng) { + overlay.setLatLng(latlng); + } + return overlay; + } +}); + + +Layer.include({ + _initOverlay: function (OverlayClass, old, content, options) { + var overlay = content; + if (overlay instanceof OverlayClass) { + setOptions(overlay, options); + overlay._source = this; + } else { + overlay = (old && !options) ? old : new OverlayClass(options, this); + overlay.setContent(content); + } + return overlay; + } +}); + +/* + * @class Popup + * @inherits DivOverlay + * @aka L.Popup + * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to + * open popups while making sure that only one popup is open at one time + * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want. + * + * @example + * + * If you want to just bind a popup to marker click and then open it, it's really easy: + * + * ```js + * marker.bindPopup(popupContent).openPopup(); + * ``` + * Path overlays like polylines also have a `bindPopup` method. + * + * A popup can be also standalone: + * + * ```js + * var popup = L.popup() + * .setLatLng(latlng) + * .setContent('<p>Hello world!<br />This is a nice popup.</p>') + * .openOn(map); + * ``` + * or + * ```js + * var popup = L.popup(latlng, {content: '<p>Hello world!<br />This is a nice popup.</p>') + * .openOn(map); + * ``` + */ + + +// @namespace Popup +var Popup = DivOverlay.extend({ + + // @section + // @aka Popup options + options: { + // @option pane: String = 'popupPane' + // `Map pane` where the popup will be added. + pane: 'popupPane', + + // @option offset: Point = Point(0, 7) + // The offset of the popup position. + offset: [0, 7], + + // @option maxWidth: Number = 300 + // Max width of the popup, in pixels. + maxWidth: 300, + + // @option minWidth: Number = 50 + // Min width of the popup, in pixels. + minWidth: 50, + + // @option maxHeight: Number = null + // If set, creates a scrollable container of the given height + // inside a popup if its content exceeds it. + // The scrollable container can be styled using the + // `leaflet-popup-scrolled` CSS class selector. + maxHeight: null, + + // @option autoPan: Boolean = true + // Set it to `false` if you don't want the map to do panning animation + // to fit the opened popup. + autoPan: true, + + // @option autoPanPaddingTopLeft: Point = null + // The margin between the popup and the top left corner of the map + // view after autopanning was performed. + autoPanPaddingTopLeft: null, + + // @option autoPanPaddingBottomRight: Point = null + // The margin between the popup and the bottom right corner of the map + // view after autopanning was performed. + autoPanPaddingBottomRight: null, + + // @option autoPanPadding: Point = Point(5, 5) + // Equivalent of setting both top left and bottom right autopan padding to the same value. + autoPanPadding: [5, 5], + + // @option keepInView: Boolean = false + // Set it to `true` if you want to prevent users from panning the popup + // off of the screen while it is open. + keepInView: false, + + // @option closeButton: Boolean = true + // Controls the presence of a close button in the popup. + closeButton: true, + + // @option autoClose: Boolean = true + // Set it to `false` if you want to override the default behavior of + // the popup closing when another popup is opened. + autoClose: true, + + // @option closeOnEscapeKey: Boolean = true + // Set it to `false` if you want to override the default behavior of + // the ESC key for closing of the popup. + closeOnEscapeKey: true, + + // @option closeOnClick: Boolean = * + // Set it if you want to override the default behavior of the popup closing when user clicks + // on the map. Defaults to the map's [`closePopupOnClick`](#map-closepopuponclick) option. + + // @option className: String = '' + // A custom CSS class name to assign to the popup. + className: '' + }, + + // @namespace Popup + // @method openOn(map: Map): this + // Alternative to `map.openPopup(popup)`. + // Adds the popup to the map and closes the previous one. + openOn: function (map) { + map = arguments.length ? map : this._source._map; // experimental, not the part of public api + + if (!map.hasLayer(this) && map._popup && map._popup.options.autoClose) { + map.removeLayer(map._popup); + } + map._popup = this; + + return DivOverlay.prototype.openOn.call(this, map); + }, + + onAdd: function (map) { + DivOverlay.prototype.onAdd.call(this, map); + + // @namespace Map + // @section Popup events + // @event popupopen: PopupEvent + // Fired when a popup is opened in the map + map.fire('popupopen', {popup: this}); + + if (this._source) { + // @namespace Layer + // @section Popup events + // @event popupopen: PopupEvent + // Fired when a popup bound to this layer is opened + this._source.fire('popupopen', {popup: this}, true); + // For non-path layers, we toggle the popup when clicking + // again the layer, so prevent the map to reopen it. + if (!(this._source instanceof Path)) { + this._source.on('preclick', stopPropagation); + } + } + }, + + onRemove: function (map) { + DivOverlay.prototype.onRemove.call(this, map); + + // @namespace Map + // @section Popup events + // @event popupclose: PopupEvent + // Fired when a popup in the map is closed + map.fire('popupclose', {popup: this}); + + if (this._source) { + // @namespace Layer + // @section Popup events + // @event popupclose: PopupEvent + // Fired when a popup bound to this layer is closed + this._source.fire('popupclose', {popup: this}, true); + if (!(this._source instanceof Path)) { + this._source.off('preclick', stopPropagation); + } + } + }, + + getEvents: function () { + var events = DivOverlay.prototype.getEvents.call(this); + + if (this.options.closeOnClick !== undefined ? this.options.closeOnClick : this._map.options.closePopupOnClick) { + events.preclick = this.close; + } + + if (this.options.keepInView) { + events.moveend = this._adjustPan; + } + + return events; + }, + + _initLayout: function () { + var prefix = 'leaflet-popup', + container = this._container = create$1('div', + prefix + ' ' + (this.options.className || '') + + ' leaflet-zoom-animated'); + + var wrapper = this._wrapper = create$1('div', prefix + '-content-wrapper', container); + this._contentNode = create$1('div', prefix + '-content', wrapper); + + disableClickPropagation(container); + disableScrollPropagation(this._contentNode); + on(container, 'contextmenu', stopPropagation); + + this._tipContainer = create$1('div', prefix + '-tip-container', container); + this._tip = create$1('div', prefix + '-tip', this._tipContainer); + + if (this.options.closeButton) { + var closeButton = this._closeButton = create$1('a', prefix + '-close-button', container); + closeButton.setAttribute('role', 'button'); // overrides the implicit role=link of <a> elements #7399 + closeButton.setAttribute('aria-label', 'Close popup'); + closeButton.href = '#close'; + closeButton.innerHTML = '<span aria-hidden="true">×</span>'; + + on(closeButton, 'click', function (ev) { + preventDefault(ev); + this.close(); + }, this); + } + }, + + _updateLayout: function () { + var container = this._contentNode, + style = container.style; + + style.width = ''; + style.whiteSpace = 'nowrap'; + + var width = container.offsetWidth; + width = Math.min(width, this.options.maxWidth); + width = Math.max(width, this.options.minWidth); + + style.width = (width + 1) + 'px'; + style.whiteSpace = ''; + + style.height = ''; + + var height = container.offsetHeight, + maxHeight = this.options.maxHeight, + scrolledClass = 'leaflet-popup-scrolled'; + + if (maxHeight && height > maxHeight) { + style.height = maxHeight + 'px'; + addClass(container, scrolledClass); + } else { + removeClass(container, scrolledClass); + } + + this._containerWidth = this._container.offsetWidth; + }, + + _animateZoom: function (e) { + var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center), + anchor = this._getAnchor(); + setPosition(this._container, pos.add(anchor)); + }, + + _adjustPan: function () { + if (!this.options.autoPan) { return; } + if (this._map._panAnim) { this._map._panAnim.stop(); } + + // We can endlessly recurse if keepInView is set and the view resets. + // Let's guard against that by exiting early if we're responding to our own autopan. + if (this._autopanning) { + this._autopanning = false; + return; + } + + var map = this._map, + marginBottom = parseInt(getStyle(this._container, 'marginBottom'), 10) || 0, + containerHeight = this._container.offsetHeight + marginBottom, + containerWidth = this._containerWidth, + layerPos = new Point(this._containerLeft, -containerHeight - this._containerBottom); + + layerPos._add(getPosition(this._container)); + + var containerPos = map.layerPointToContainerPoint(layerPos), + padding = toPoint(this.options.autoPanPadding), + paddingTL = toPoint(this.options.autoPanPaddingTopLeft || padding), + paddingBR = toPoint(this.options.autoPanPaddingBottomRight || padding), + size = map.getSize(), + dx = 0, + dy = 0; + + if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right + dx = containerPos.x + containerWidth - size.x + paddingBR.x; + } + if (containerPos.x - dx - paddingTL.x < 0) { // left + dx = containerPos.x - paddingTL.x; + } + if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom + dy = containerPos.y + containerHeight - size.y + paddingBR.y; + } + if (containerPos.y - dy - paddingTL.y < 0) { // top + dy = containerPos.y - paddingTL.y; + } + + // @namespace Map + // @section Popup events + // @event autopanstart: Event + // Fired when the map starts autopanning when opening a popup. + if (dx || dy) { + // Track that we're autopanning, as this function will be re-ran on moveend + if (this.options.keepInView) { + this._autopanning = true; + } + + map + .fire('autopanstart') + .panBy([dx, dy]); + } + }, + + _getAnchor: function () { + // Where should we anchor the popup on the source layer? + return toPoint(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]); + } + +}); + +// @namespace Popup +// @factory L.popup(options?: Popup options, source?: Layer) +// Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers. +// @alternative +// @factory L.popup(latlng: LatLng, options?: Popup options) +// Instantiates a `Popup` object given `latlng` where the popup will open and an optional `options` object that describes its appearance and location. +var popup = function (options, source) { + return new Popup(options, source); +}; + + +/* @namespace Map + * @section Interaction Options + * @option closePopupOnClick: Boolean = true + * Set it to `false` if you don't want popups to close when user clicks the map. + */ +Map.mergeOptions({ + closePopupOnClick: true +}); + + +// @namespace Map +// @section Methods for Layers and Controls +Map.include({ + // @method openPopup(popup: Popup): this + // Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability). + // @alternative + // @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this + // Creates a popup with the specified content and options and opens it in the given point on a map. + openPopup: function (popup, latlng, options) { + this._initOverlay(Popup, popup, latlng, options) + .openOn(this); + + return this; + }, + + // @method closePopup(popup?: Popup): this + // Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one). + closePopup: function (popup) { + popup = arguments.length ? popup : this._popup; + if (popup) { + popup.close(); + } + return this; + } +}); + +/* + * @namespace Layer + * @section Popup methods example + * + * All layers share a set of methods convenient for binding popups to it. + * + * ```js + * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map); + * layer.openPopup(); + * layer.closePopup(); + * ``` + * + * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened. + */ + +// @section Popup methods +Layer.include({ + + // @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this + // Binds a popup to the layer with the passed `content` and sets up the + // necessary event listeners. If a `Function` is passed it will receive + // the layer as the first argument and should return a `String` or `HTMLElement`. + bindPopup: function (content, options) { + this._popup = this._initOverlay(Popup, this._popup, content, options); + if (!this._popupHandlersAdded) { + this.on({ + click: this._openPopup, + keypress: this._onKeyPress, + remove: this.closePopup, + move: this._movePopup + }); + this._popupHandlersAdded = true; + } + + return this; + }, + + // @method unbindPopup(): this + // Removes the popup previously bound with `bindPopup`. + unbindPopup: function () { + if (this._popup) { + this.off({ + click: this._openPopup, + keypress: this._onKeyPress, + remove: this.closePopup, + move: this._movePopup + }); + this._popupHandlersAdded = false; + this._popup = null; + } + return this; + }, + + // @method openPopup(latlng?: LatLng): this + // Opens the bound popup at the specified `latlng` or at the default popup anchor if no `latlng` is passed. + openPopup: function (latlng) { + if (this._popup) { + if (!(this instanceof FeatureGroup)) { + this._popup._source = this; + } + if (this._popup._prepareOpen(latlng || this._latlng)) { + // open the popup on the map + this._popup.openOn(this._map); + } + } + return this; + }, + + // @method closePopup(): this + // Closes the popup bound to this layer if it is open. + closePopup: function () { + if (this._popup) { + this._popup.close(); + } + return this; + }, + + // @method togglePopup(): this + // Opens or closes the popup bound to this layer depending on its current state. + togglePopup: function () { + if (this._popup) { + this._popup.toggle(this); + } + return this; + }, + + // @method isPopupOpen(): boolean + // Returns `true` if the popup bound to this layer is currently open. + isPopupOpen: function () { + return (this._popup ? this._popup.isOpen() : false); + }, + + // @method setPopupContent(content: String|HTMLElement|Popup): this + // Sets the content of the popup bound to this layer. + setPopupContent: function (content) { + if (this._popup) { + this._popup.setContent(content); + } + return this; + }, + + // @method getPopup(): Popup + // Returns the popup bound to this layer. + getPopup: function () { + return this._popup; + }, + + _openPopup: function (e) { + if (!this._popup || !this._map) { + return; + } + // prevent map click + stop(e); + + var target = e.layer || e.target; + if (this._popup._source === target && !(target instanceof Path)) { + // treat it like a marker and figure out + // if we should toggle it open/closed + if (this._map.hasLayer(this._popup)) { + this.closePopup(); + } else { + this.openPopup(e.latlng); + } + return; + } + this._popup._source = target; + this.openPopup(e.latlng); + }, + + _movePopup: function (e) { + this._popup.setLatLng(e.latlng); + }, + + _onKeyPress: function (e) { + if (e.originalEvent.keyCode === 13) { + this._openPopup(e); + } + } +}); + +/* + * @class Tooltip + * @inherits DivOverlay + * @aka L.Tooltip + * Used to display small texts on top of map layers. + * + * @example + * If you want to just bind a tooltip to marker: + * + * ```js + * marker.bindTooltip("my tooltip text").openTooltip(); + * ``` + * Path overlays like polylines also have a `bindTooltip` method. + * + * A tooltip can be also standalone: + * + * ```js + * var tooltip = L.tooltip() + * .setLatLng(latlng) + * .setContent('Hello world!<br />This is a nice tooltip.') + * .addTo(map); + * ``` + * or + * ```js + * var tooltip = L.tooltip(latlng, {content: 'Hello world!<br />This is a nice tooltip.'}) + * .addTo(map); + * ``` + * + * + * Note about tooltip offset. Leaflet takes two options in consideration + * for computing tooltip offsetting: + * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip. + * Add a positive x offset to move the tooltip to the right, and a positive y offset to + * move it to the bottom. Negatives will move to the left and top. + * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You + * should adapt this value if you use a custom icon. + */ + + +// @namespace Tooltip +var Tooltip = DivOverlay.extend({ + + // @section + // @aka Tooltip options + options: { + // @option pane: String = 'tooltipPane' + // `Map pane` where the tooltip will be added. + pane: 'tooltipPane', + + // @option offset: Point = Point(0, 0) + // Optional offset of the tooltip position. + offset: [0, 0], + + // @option direction: String = 'auto' + // Direction where to open the tooltip. Possible values are: `right`, `left`, + // `top`, `bottom`, `center`, `auto`. + // `auto` will dynamically switch between `right` and `left` according to the tooltip + // position on the map. + direction: 'auto', + + // @option permanent: Boolean = false + // Whether to open the tooltip permanently or only on mouseover. + permanent: false, + + // @option sticky: Boolean = false + // If true, the tooltip will follow the mouse instead of being fixed at the feature center. + sticky: false, + + // @option opacity: Number = 0.9 + // Tooltip container opacity. + opacity: 0.9 + }, + + onAdd: function (map) { + DivOverlay.prototype.onAdd.call(this, map); + this.setOpacity(this.options.opacity); + + // @namespace Map + // @section Tooltip events + // @event tooltipopen: TooltipEvent + // Fired when a tooltip is opened in the map. + map.fire('tooltipopen', {tooltip: this}); + + if (this._source) { + this.addEventParent(this._source); + + // @namespace Layer + // @section Tooltip events + // @event tooltipopen: TooltipEvent + // Fired when a tooltip bound to this layer is opened. + this._source.fire('tooltipopen', {tooltip: this}, true); + } + }, + + onRemove: function (map) { + DivOverlay.prototype.onRemove.call(this, map); + + // @namespace Map + // @section Tooltip events + // @event tooltipclose: TooltipEvent + // Fired when a tooltip in the map is closed. + map.fire('tooltipclose', {tooltip: this}); + + if (this._source) { + this.removeEventParent(this._source); + + // @namespace Layer + // @section Tooltip events + // @event tooltipclose: TooltipEvent + // Fired when a tooltip bound to this layer is closed. + this._source.fire('tooltipclose', {tooltip: this}, true); + } + }, + + getEvents: function () { + var events = DivOverlay.prototype.getEvents.call(this); + + if (!this.options.permanent) { + events.preclick = this.close; + } + + return events; + }, + + _initLayout: function () { + var prefix = 'leaflet-tooltip', + className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide'); + + this._contentNode = this._container = create$1('div', className); + + this._container.setAttribute('role', 'tooltip'); + this._container.setAttribute('id', 'leaflet-tooltip-' + stamp(this)); + }, + + _updateLayout: function () {}, + + _adjustPan: function () {}, + + _setPosition: function (pos) { + var subX, subY, + map = this._map, + container = this._container, + centerPoint = map.latLngToContainerPoint(map.getCenter()), + tooltipPoint = map.layerPointToContainerPoint(pos), + direction = this.options.direction, + tooltipWidth = container.offsetWidth, + tooltipHeight = container.offsetHeight, + offset = toPoint(this.options.offset), + anchor = this._getAnchor(); + + if (direction === 'top') { + subX = tooltipWidth / 2; + subY = tooltipHeight; + } else if (direction === 'bottom') { + subX = tooltipWidth / 2; + subY = 0; + } else if (direction === 'center') { + subX = tooltipWidth / 2; + subY = tooltipHeight / 2; + } else if (direction === 'right') { + subX = 0; + subY = tooltipHeight / 2; + } else if (direction === 'left') { + subX = tooltipWidth; + subY = tooltipHeight / 2; + } else if (tooltipPoint.x < centerPoint.x) { + direction = 'right'; + subX = 0; + subY = tooltipHeight / 2; + } else { + direction = 'left'; + subX = tooltipWidth + (offset.x + anchor.x) * 2; + subY = tooltipHeight / 2; + } + + pos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor); + + removeClass(container, 'leaflet-tooltip-right'); + removeClass(container, 'leaflet-tooltip-left'); + removeClass(container, 'leaflet-tooltip-top'); + removeClass(container, 'leaflet-tooltip-bottom'); + addClass(container, 'leaflet-tooltip-' + direction); + setPosition(container, pos); + }, + + _updatePosition: function () { + var pos = this._map.latLngToLayerPoint(this._latlng); + this._setPosition(pos); + }, + + setOpacity: function (opacity) { + this.options.opacity = opacity; + + if (this._container) { + setOpacity(this._container, opacity); + } + }, + + _animateZoom: function (e) { + var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center); + this._setPosition(pos); + }, + + _getAnchor: function () { + // Where should we anchor the tooltip on the source layer? + return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]); + } + +}); + +// @namespace Tooltip +// @factory L.tooltip(options?: Tooltip options, source?: Layer) +// Instantiates a `Tooltip` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers. +// @alternative +// @factory L.tooltip(latlng: LatLng, options?: Tooltip options) +// Instantiates a `Tooltip` object given `latlng` where the tooltip will open and an optional `options` object that describes its appearance and location. +var tooltip = function (options, source) { + return new Tooltip(options, source); +}; + +// @namespace Map +// @section Methods for Layers and Controls +Map.include({ + + // @method openTooltip(tooltip: Tooltip): this + // Opens the specified tooltip. + // @alternative + // @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this + // Creates a tooltip with the specified content and options and open it. + openTooltip: function (tooltip, latlng, options) { + this._initOverlay(Tooltip, tooltip, latlng, options) + .openOn(this); + + return this; + }, + + // @method closeTooltip(tooltip: Tooltip): this + // Closes the tooltip given as parameter. + closeTooltip: function (tooltip) { + tooltip.close(); + return this; + } + +}); + +/* + * @namespace Layer + * @section Tooltip methods example + * + * All layers share a set of methods convenient for binding tooltips to it. + * + * ```js + * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map); + * layer.openTooltip(); + * layer.closeTooltip(); + * ``` + */ + +// @section Tooltip methods +Layer.include({ + + // @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this + // Binds a tooltip to the layer with the passed `content` and sets up the + // necessary event listeners. If a `Function` is passed it will receive + // the layer as the first argument and should return a `String` or `HTMLElement`. + bindTooltip: function (content, options) { + + if (this._tooltip && this.isTooltipOpen()) { + this.unbindTooltip(); + } + + this._tooltip = this._initOverlay(Tooltip, this._tooltip, content, options); + this._initTooltipInteractions(); + + if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) { + this.openTooltip(); + } + + return this; + }, + + // @method unbindTooltip(): this + // Removes the tooltip previously bound with `bindTooltip`. + unbindTooltip: function () { + if (this._tooltip) { + this._initTooltipInteractions(true); + this.closeTooltip(); + this._tooltip = null; + } + return this; + }, + + _initTooltipInteractions: function (remove) { + if (!remove && this._tooltipHandlersAdded) { return; } + var onOff = remove ? 'off' : 'on', + events = { + remove: this.closeTooltip, + move: this._moveTooltip + }; + if (!this._tooltip.options.permanent) { + events.mouseover = this._openTooltip; + events.mouseout = this.closeTooltip; + events.click = this._openTooltip; + if (this._map) { + this._addFocusListeners(); + } else { + events.add = this._addFocusListeners; + } + } else { + events.add = this._openTooltip; + } + if (this._tooltip.options.sticky) { + events.mousemove = this._moveTooltip; + } + this[onOff](events); + this._tooltipHandlersAdded = !remove; + }, + + // @method openTooltip(latlng?: LatLng): this + // Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed. + openTooltip: function (latlng) { + if (this._tooltip) { + if (!(this instanceof FeatureGroup)) { + this._tooltip._source = this; + } + if (this._tooltip._prepareOpen(latlng)) { + // open the tooltip on the map + this._tooltip.openOn(this._map); + + if (this.getElement) { + this._setAriaDescribedByOnLayer(this); + } else if (this.eachLayer) { + this.eachLayer(this._setAriaDescribedByOnLayer, this); + } + } + } + return this; + }, + + // @method closeTooltip(): this + // Closes the tooltip bound to this layer if it is open. + closeTooltip: function () { + if (this._tooltip) { + return this._tooltip.close(); + } + }, + + // @method toggleTooltip(): this + // Opens or closes the tooltip bound to this layer depending on its current state. + toggleTooltip: function () { + if (this._tooltip) { + this._tooltip.toggle(this); + } + return this; + }, + + // @method isTooltipOpen(): boolean + // Returns `true` if the tooltip bound to this layer is currently open. + isTooltipOpen: function () { + return this._tooltip.isOpen(); + }, + + // @method setTooltipContent(content: String|HTMLElement|Tooltip): this + // Sets the content of the tooltip bound to this layer. + setTooltipContent: function (content) { + if (this._tooltip) { + this._tooltip.setContent(content); + } + return this; + }, + + // @method getTooltip(): Tooltip + // Returns the tooltip bound to this layer. + getTooltip: function () { + return this._tooltip; + }, + + _addFocusListeners: function () { + if (this.getElement) { + this._addFocusListenersOnLayer(this); + } else if (this.eachLayer) { + this.eachLayer(this._addFocusListenersOnLayer, this); + } + }, + + _addFocusListenersOnLayer: function (layer) { + var el = typeof layer.getElement === 'function' && layer.getElement(); + if (el) { + on(el, 'focus', function () { + this._tooltip._source = layer; + this.openTooltip(); + }, this); + on(el, 'blur', this.closeTooltip, this); + } + }, + + _setAriaDescribedByOnLayer: function (layer) { + var el = typeof layer.getElement === 'function' && layer.getElement(); + if (el) { + el.setAttribute('aria-describedby', this._tooltip._container.id); + } + }, + + + _openTooltip: function (e) { + if (!this._tooltip || !this._map) { + return; + } + + // If the map is moving, we will show the tooltip after it's done. + if (this._map.dragging && this._map.dragging.moving() && !this._openOnceFlag) { + this._openOnceFlag = true; + var that = this; + this._map.once('moveend', function () { + that._openOnceFlag = false; + that._openTooltip(e); + }); + return; + } + + this._tooltip._source = e.layer || e.target; + + this.openTooltip(this._tooltip.options.sticky ? e.latlng : undefined); + }, + + _moveTooltip: function (e) { + var latlng = e.latlng, containerPoint, layerPoint; + if (this._tooltip.options.sticky && e.originalEvent) { + containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent); + layerPoint = this._map.containerPointToLayerPoint(containerPoint); + latlng = this._map.layerPointToLatLng(layerPoint); + } + this._tooltip.setLatLng(latlng); + } +}); + +/* + * @class DivIcon + * @aka L.DivIcon + * @inherits Icon + * + * Represents a lightweight icon for markers that uses a simple `<div>` + * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options. + * + * @example + * ```js + * var myIcon = L.divIcon({className: 'my-div-icon'}); + * // you can set .my-div-icon styles in CSS + * + * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map); + * ``` + * + * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow. + */ + +var DivIcon = Icon.extend({ + options: { + // @section + // @aka DivIcon options + iconSize: [12, 12], // also can be set through CSS + + // iconAnchor: (Point), + // popupAnchor: (Point), + + // @option html: String|HTMLElement = '' + // Custom HTML code to put inside the div element, empty by default. Alternatively, + // an instance of `HTMLElement`. + html: false, + + // @option bgPos: Point = [0, 0] + // Optional relative position of the background, in pixels + bgPos: null, + + className: 'leaflet-div-icon' + }, + + createIcon: function (oldIcon) { + var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'), + options = this.options; + + if (options.html instanceof Element) { + empty(div); + div.appendChild(options.html); + } else { + div.innerHTML = options.html !== false ? options.html : ''; + } + + if (options.bgPos) { + var bgPos = toPoint(options.bgPos); + div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px'; + } + this._setIconStyles(div, 'icon'); + + return div; + }, + + createShadow: function () { + return null; + } +}); + +// @factory L.divIcon(options: DivIcon options) +// Creates a `DivIcon` instance with the given options. +function divIcon(options) { + return new DivIcon(options); +} + +Icon.Default = IconDefault; + +/* + * @class GridLayer + * @inherits Layer + * @aka L.GridLayer + * + * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`. + * GridLayer can be extended to create a tiled grid of HTML elements like `<canvas>`, `<img>` or `<div>`. GridLayer will handle creating and animating these DOM elements for you. + * + * + * @section Synchronous usage + * @example + * + * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile. + * + * ```js + * var CanvasLayer = L.GridLayer.extend({ + * createTile: function(coords){ + * // create a <canvas> element for drawing + * var tile = L.DomUtil.create('canvas', 'leaflet-tile'); + * + * // setup tile width and height according to the options + * var size = this.getTileSize(); + * tile.width = size.x; + * tile.height = size.y; + * + * // get a canvas context and draw something on it using coords.x, coords.y and coords.z + * var ctx = tile.getContext('2d'); + * + * // return the tile so it can be rendered on screen + * return tile; + * } + * }); + * ``` + * + * @section Asynchronous usage + * @example + * + * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. Once the tile is finished drawing it can be passed to the `done()` callback. + * + * ```js + * var CanvasLayer = L.GridLayer.extend({ + * createTile: function(coords, done){ + * var error; + * + * // create a <canvas> element for drawing + * var tile = L.DomUtil.create('canvas', 'leaflet-tile'); + * + * // setup tile width and height according to the options + * var size = this.getTileSize(); + * tile.width = size.x; + * tile.height = size.y; + * + * // draw something asynchronously and pass the tile to the done() callback + * setTimeout(function() { + * done(error, tile); + * }, 1000); + * + * return tile; + * } + * }); + * ``` + * + * @section + */ + + +var GridLayer = Layer.extend({ + + // @section + // @aka GridLayer options + options: { + // @option tileSize: Number|Point = 256 + // Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise. + tileSize: 256, + + // @option opacity: Number = 1.0 + // Opacity of the tiles. Can be used in the `createTile()` function. + opacity: 1, + + // @option updateWhenIdle: Boolean = (depends) + // Load new tiles only when panning ends. + // `true` by default on mobile browsers, in order to avoid too many requests and keep smooth navigation. + // `false` otherwise in order to display new tiles _during_ panning, since it is easy to pan outside the + // [`keepBuffer`](#gridlayer-keepbuffer) option in desktop browsers. + updateWhenIdle: Browser.mobile, + + // @option updateWhenZooming: Boolean = true + // By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends. + updateWhenZooming: true, + + // @option updateInterval: Number = 200 + // Tiles will not update more than once every `updateInterval` milliseconds when panning. + updateInterval: 200, + + // @option zIndex: Number = 1 + // The explicit zIndex of the tile layer. + zIndex: 1, + + // @option bounds: LatLngBounds = undefined + // If set, tiles will only be loaded inside the set `LatLngBounds`. + bounds: null, + + // @option minZoom: Number = 0 + // The minimum zoom level down to which this layer will be displayed (inclusive). + minZoom: 0, + + // @option maxZoom: Number = undefined + // The maximum zoom level up to which this layer will be displayed (inclusive). + maxZoom: undefined, + + // @option maxNativeZoom: Number = undefined + // Maximum zoom number the tile source has available. If it is specified, + // the tiles on all zoom levels higher than `maxNativeZoom` will be loaded + // from `maxNativeZoom` level and auto-scaled. + maxNativeZoom: undefined, + + // @option minNativeZoom: Number = undefined + // Minimum zoom number the tile source has available. If it is specified, + // the tiles on all zoom levels lower than `minNativeZoom` will be loaded + // from `minNativeZoom` level and auto-scaled. + minNativeZoom: undefined, + + // @option noWrap: Boolean = false + // Whether the layer is wrapped around the antimeridian. If `true`, the + // GridLayer will only be displayed once at low zoom levels. Has no + // effect when the [map CRS](#map-crs) doesn't wrap around. Can be used + // in combination with [`bounds`](#gridlayer-bounds) to prevent requesting + // tiles outside the CRS limits. + noWrap: false, + + // @option pane: String = 'tilePane' + // `Map pane` where the grid layer will be added. + pane: 'tilePane', + + // @option className: String = '' + // A custom class name to assign to the tile layer. Empty by default. + className: '', + + // @option keepBuffer: Number = 2 + // When panning the map, keep this many rows and columns of tiles before unloading them. + keepBuffer: 2 + }, + + initialize: function (options) { + setOptions(this, options); + }, + + onAdd: function () { + this._initContainer(); + + this._levels = {}; + this._tiles = {}; + + this._resetView(); // implicit _update() call + }, + + beforeAdd: function (map) { + map._addZoomLimit(this); + }, + + onRemove: function (map) { + this._removeAllTiles(); + remove(this._container); + map._removeZoomLimit(this); + this._container = null; + this._tileZoom = undefined; + }, + + // @method bringToFront: this + // Brings the tile layer to the top of all tile layers. + bringToFront: function () { + if (this._map) { + toFront(this._container); + this._setAutoZIndex(Math.max); + } + return this; + }, + + // @method bringToBack: this + // Brings the tile layer to the bottom of all tile layers. + bringToBack: function () { + if (this._map) { + toBack(this._container); + this._setAutoZIndex(Math.min); + } + return this; + }, + + // @method getContainer: HTMLElement + // Returns the HTML element that contains the tiles for this layer. + getContainer: function () { + return this._container; + }, + + // @method setOpacity(opacity: Number): this + // Changes the [opacity](#gridlayer-opacity) of the grid layer. + setOpacity: function (opacity) { + this.options.opacity = opacity; + this._updateOpacity(); + return this; + }, + + // @method setZIndex(zIndex: Number): this + // Changes the [zIndex](#gridlayer-zindex) of the grid layer. + setZIndex: function (zIndex) { + this.options.zIndex = zIndex; + this._updateZIndex(); + + return this; + }, + + // @method isLoading: Boolean + // Returns `true` if any tile in the grid layer has not finished loading. + isLoading: function () { + return this._loading; + }, + + // @method redraw: this + // Causes the layer to clear all the tiles and request them again. + redraw: function () { + if (this._map) { + this._removeAllTiles(); + var tileZoom = this._clampZoom(this._map.getZoom()); + if (tileZoom !== this._tileZoom) { + this._tileZoom = tileZoom; + this._updateLevels(); + } + this._update(); + } + return this; + }, + + getEvents: function () { + var events = { + viewprereset: this._invalidateAll, + viewreset: this._resetView, + zoom: this._resetView, + moveend: this._onMoveEnd + }; + + if (!this.options.updateWhenIdle) { + // update tiles on move, but not more often than once per given interval + if (!this._onMove) { + this._onMove = throttle(this._onMoveEnd, this.options.updateInterval, this); + } + + events.move = this._onMove; + } + + if (this._zoomAnimated) { + events.zoomanim = this._animateZoom; + } + + return events; + }, + + // @section Extension methods + // Layers extending `GridLayer` shall reimplement the following method. + // @method createTile(coords: Object, done?: Function): HTMLElement + // Called only internally, must be overridden by classes extending `GridLayer`. + // Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback + // is specified, it must be called when the tile has finished loading and drawing. + createTile: function () { + return document.createElement('div'); + }, + + // @section + // @method getTileSize: Point + // Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method. + getTileSize: function () { + var s = this.options.tileSize; + return s instanceof Point ? s : new Point(s, s); + }, + + _updateZIndex: function () { + if (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) { + this._container.style.zIndex = this.options.zIndex; + } + }, + + _setAutoZIndex: function (compare) { + // go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back) + + var layers = this.getPane().children, + edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min + + for (var i = 0, len = layers.length, zIndex; i < len; i++) { + + zIndex = layers[i].style.zIndex; + + if (layers[i] !== this._container && zIndex) { + edgeZIndex = compare(edgeZIndex, +zIndex); + } + } + + if (isFinite(edgeZIndex)) { + this.options.zIndex = edgeZIndex + compare(-1, 1); + this._updateZIndex(); + } + }, + + _updateOpacity: function () { + if (!this._map) { return; } + + // IE doesn't inherit filter opacity properly, so we're forced to set it on tiles + if (Browser.ielt9) { return; } + + setOpacity(this._container, this.options.opacity); + + var now = +new Date(), + nextFrame = false, + willPrune = false; + + for (var key in this._tiles) { + var tile = this._tiles[key]; + if (!tile.current || !tile.loaded) { continue; } + + var fade = Math.min(1, (now - tile.loaded) / 200); + + setOpacity(tile.el, fade); + if (fade < 1) { + nextFrame = true; + } else { + if (tile.active) { + willPrune = true; + } else { + this._onOpaqueTile(tile); + } + tile.active = true; + } + } + + if (willPrune && !this._noPrune) { this._pruneTiles(); } + + if (nextFrame) { + cancelAnimFrame(this._fadeFrame); + this._fadeFrame = requestAnimFrame(this._updateOpacity, this); + } + }, + + _onOpaqueTile: falseFn, + + _initContainer: function () { + if (this._container) { return; } + + this._container = create$1('div', 'leaflet-layer ' + (this.options.className || '')); + this._updateZIndex(); + + if (this.options.opacity < 1) { + this._updateOpacity(); + } + + this.getPane().appendChild(this._container); + }, + + _updateLevels: function () { + + var zoom = this._tileZoom, + maxZoom = this.options.maxZoom; + + if (zoom === undefined) { return undefined; } + + for (var z in this._levels) { + z = Number(z); + if (this._levels[z].el.children.length || z === zoom) { + this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z); + this._onUpdateLevel(z); + } else { + remove(this._levels[z].el); + this._removeTilesAtZoom(z); + this._onRemoveLevel(z); + delete this._levels[z]; + } + } + + var level = this._levels[zoom], + map = this._map; + + if (!level) { + level = this._levels[zoom] = {}; + + level.el = create$1('div', 'leaflet-tile-container leaflet-zoom-animated', this._container); + level.el.style.zIndex = maxZoom; + + level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round(); + level.zoom = zoom; + + this._setZoomTransform(level, map.getCenter(), map.getZoom()); + + // force the browser to consider the newly added element for transition + falseFn(level.el.offsetWidth); + + this._onCreateLevel(level); + } + + this._level = level; + + return level; + }, + + _onUpdateLevel: falseFn, + + _onRemoveLevel: falseFn, + + _onCreateLevel: falseFn, + + _pruneTiles: function () { + if (!this._map) { + return; + } + + var key, tile; + + var zoom = this._map.getZoom(); + if (zoom > this.options.maxZoom || + zoom < this.options.minZoom) { + this._removeAllTiles(); + return; + } + + for (key in this._tiles) { + tile = this._tiles[key]; + tile.retain = tile.current; + } + + for (key in this._tiles) { + tile = this._tiles[key]; + if (tile.current && !tile.active) { + var coords = tile.coords; + if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) { + this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2); + } + } + } + + for (key in this._tiles) { + if (!this._tiles[key].retain) { + this._removeTile(key); + } + } + }, + + _removeTilesAtZoom: function (zoom) { + for (var key in this._tiles) { + if (this._tiles[key].coords.z !== zoom) { + continue; + } + this._removeTile(key); + } + }, + + _removeAllTiles: function () { + for (var key in this._tiles) { + this._removeTile(key); + } + }, + + _invalidateAll: function () { + for (var z in this._levels) { + remove(this._levels[z].el); + this._onRemoveLevel(Number(z)); + delete this._levels[z]; + } + this._removeAllTiles(); + + this._tileZoom = undefined; + }, + + _retainParent: function (x, y, z, minZoom) { + var x2 = Math.floor(x / 2), + y2 = Math.floor(y / 2), + z2 = z - 1, + coords2 = new Point(+x2, +y2); + coords2.z = +z2; + + var key = this._tileCoordsToKey(coords2), + tile = this._tiles[key]; + + if (tile && tile.active) { + tile.retain = true; + return true; + + } else if (tile && tile.loaded) { + tile.retain = true; + } + + if (z2 > minZoom) { + return this._retainParent(x2, y2, z2, minZoom); + } + + return false; + }, + + _retainChildren: function (x, y, z, maxZoom) { + + for (var i = 2 * x; i < 2 * x + 2; i++) { + for (var j = 2 * y; j < 2 * y + 2; j++) { + + var coords = new Point(i, j); + coords.z = z + 1; + + var key = this._tileCoordsToKey(coords), + tile = this._tiles[key]; + + if (tile && tile.active) { + tile.retain = true; + continue; + + } else if (tile && tile.loaded) { + tile.retain = true; + } + + if (z + 1 < maxZoom) { + this._retainChildren(i, j, z + 1, maxZoom); + } + } + } + }, + + _resetView: function (e) { + var animating = e && (e.pinch || e.flyTo); + this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating); + }, + + _animateZoom: function (e) { + this._setView(e.center, e.zoom, true, e.noUpdate); + }, + + _clampZoom: function (zoom) { + var options = this.options; + + if (undefined !== options.minNativeZoom && zoom < options.minNativeZoom) { + return options.minNativeZoom; + } + + if (undefined !== options.maxNativeZoom && options.maxNativeZoom < zoom) { + return options.maxNativeZoom; + } + + return zoom; + }, + + _setView: function (center, zoom, noPrune, noUpdate) { + var tileZoom = Math.round(zoom); + if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) || + (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) { + tileZoom = undefined; + } else { + tileZoom = this._clampZoom(tileZoom); + } + + var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom); + + if (!noUpdate || tileZoomChanged) { + + this._tileZoom = tileZoom; + + if (this._abortLoading) { + this._abortLoading(); + } + + this._updateLevels(); + this._resetGrid(); + + if (tileZoom !== undefined) { + this._update(center); + } + + if (!noPrune) { + this._pruneTiles(); + } + + // Flag to prevent _updateOpacity from pruning tiles during + // a zoom anim or a pinch gesture + this._noPrune = !!noPrune; + } + + this._setZoomTransforms(center, zoom); + }, + + _setZoomTransforms: function (center, zoom) { + for (var i in this._levels) { + this._setZoomTransform(this._levels[i], center, zoom); + } + }, + + _setZoomTransform: function (level, center, zoom) { + var scale = this._map.getZoomScale(zoom, level.zoom), + translate = level.origin.multiplyBy(scale) + .subtract(this._map._getNewPixelOrigin(center, zoom)).round(); + + if (Browser.any3d) { + setTransform(level.el, translate, scale); + } else { + setPosition(level.el, translate); + } + }, + + _resetGrid: function () { + var map = this._map, + crs = map.options.crs, + tileSize = this._tileSize = this.getTileSize(), + tileZoom = this._tileZoom; + + var bounds = this._map.getPixelWorldBounds(this._tileZoom); + if (bounds) { + this._globalTileRange = this._pxBoundsToTileRange(bounds); + } + + this._wrapX = crs.wrapLng && !this.options.noWrap && [ + Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x), + Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y) + ]; + this._wrapY = crs.wrapLat && !this.options.noWrap && [ + Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x), + Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y) + ]; + }, + + _onMoveEnd: function () { + if (!this._map || this._map._animatingZoom) { return; } + + this._update(); + }, + + _getTiledPixelBounds: function (center) { + var map = this._map, + mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(), + scale = map.getZoomScale(mapZoom, this._tileZoom), + pixelCenter = map.project(center, this._tileZoom).floor(), + halfSize = map.getSize().divideBy(scale * 2); + + return new Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize)); + }, + + // Private method to load tiles in the grid's active zoom level according to map bounds + _update: function (center) { + var map = this._map; + if (!map) { return; } + var zoom = this._clampZoom(map.getZoom()); + + if (center === undefined) { center = map.getCenter(); } + if (this._tileZoom === undefined) { return; } // if out of minzoom/maxzoom + + var pixelBounds = this._getTiledPixelBounds(center), + tileRange = this._pxBoundsToTileRange(pixelBounds), + tileCenter = tileRange.getCenter(), + queue = [], + margin = this.options.keepBuffer, + noPruneRange = new Bounds(tileRange.getBottomLeft().subtract([margin, -margin]), + tileRange.getTopRight().add([margin, -margin])); + + // Sanity check: panic if the tile range contains Infinity somewhere. + if (!(isFinite(tileRange.min.x) && + isFinite(tileRange.min.y) && + isFinite(tileRange.max.x) && + isFinite(tileRange.max.y))) { throw new Error('Attempted to load an infinite number of tiles'); } + + for (var key in this._tiles) { + var c = this._tiles[key].coords; + if (c.z !== this._tileZoom || !noPruneRange.contains(new Point(c.x, c.y))) { + this._tiles[key].current = false; + } + } + + // _update just loads more tiles. If the tile zoom level differs too much + // from the map's, let _setView reset levels and prune old tiles. + if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; } + + // create a queue of coordinates to load tiles from + for (var j = tileRange.min.y; j <= tileRange.max.y; j++) { + for (var i = tileRange.min.x; i <= tileRange.max.x; i++) { + var coords = new Point(i, j); + coords.z = this._tileZoom; + + if (!this._isValidTile(coords)) { continue; } + + var tile = this._tiles[this._tileCoordsToKey(coords)]; + if (tile) { + tile.current = true; + } else { + queue.push(coords); + } + } + } + + // sort tile queue to load tiles in order of their distance to center + queue.sort(function (a, b) { + return a.distanceTo(tileCenter) - b.distanceTo(tileCenter); + }); + + if (queue.length !== 0) { + // if it's the first batch of tiles to load + if (!this._loading) { + this._loading = true; + // @event loading: Event + // Fired when the grid layer starts loading tiles. + this.fire('loading'); + } + + // create DOM fragment to append tiles in one batch + var fragment = document.createDocumentFragment(); + + for (i = 0; i < queue.length; i++) { + this._addTile(queue[i], fragment); + } + + this._level.el.appendChild(fragment); + } + }, + + _isValidTile: function (coords) { + var crs = this._map.options.crs; + + if (!crs.infinite) { + // don't load tile if it's out of bounds and not wrapped + var bounds = this._globalTileRange; + if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) || + (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; } + } + + if (!this.options.bounds) { return true; } + + // don't load tile if it doesn't intersect the bounds in options + var tileBounds = this._tileCoordsToBounds(coords); + return toLatLngBounds(this.options.bounds).overlaps(tileBounds); + }, + + _keyToBounds: function (key) { + return this._tileCoordsToBounds(this._keyToTileCoords(key)); + }, + + _tileCoordsToNwSe: function (coords) { + var map = this._map, + tileSize = this.getTileSize(), + nwPoint = coords.scaleBy(tileSize), + sePoint = nwPoint.add(tileSize), + nw = map.unproject(nwPoint, coords.z), + se = map.unproject(sePoint, coords.z); + return [nw, se]; + }, + + // converts tile coordinates to its geographical bounds + _tileCoordsToBounds: function (coords) { + var bp = this._tileCoordsToNwSe(coords), + bounds = new LatLngBounds(bp[0], bp[1]); + + if (!this.options.noWrap) { + bounds = this._map.wrapLatLngBounds(bounds); + } + return bounds; + }, + // converts tile coordinates to key for the tile cache + _tileCoordsToKey: function (coords) { + return coords.x + ':' + coords.y + ':' + coords.z; + }, + + // converts tile cache key to coordinates + _keyToTileCoords: function (key) { + var k = key.split(':'), + coords = new Point(+k[0], +k[1]); + coords.z = +k[2]; + return coords; + }, + + _removeTile: function (key) { + var tile = this._tiles[key]; + if (!tile) { return; } + + remove(tile.el); + + delete this._tiles[key]; + + // @event tileunload: TileEvent + // Fired when a tile is removed (e.g. when a tile goes off the screen). + this.fire('tileunload', { + tile: tile.el, + coords: this._keyToTileCoords(key) + }); + }, + + _initTile: function (tile) { + addClass(tile, 'leaflet-tile'); + + var tileSize = this.getTileSize(); + tile.style.width = tileSize.x + 'px'; + tile.style.height = tileSize.y + 'px'; + + tile.onselectstart = falseFn; + tile.onmousemove = falseFn; + + // update opacity on tiles in IE7-8 because of filter inheritance problems + if (Browser.ielt9 && this.options.opacity < 1) { + setOpacity(tile, this.options.opacity); + } + }, + + _addTile: function (coords, container) { + var tilePos = this._getTilePos(coords), + key = this._tileCoordsToKey(coords); + + var tile = this.createTile(this._wrapCoords(coords), bind(this._tileReady, this, coords)); + + this._initTile(tile); + + // if createTile is defined with a second argument ("done" callback), + // we know that tile is async and will be ready later; otherwise + if (this.createTile.length < 2) { + // mark tile as ready, but delay one frame for opacity animation to happen + requestAnimFrame(bind(this._tileReady, this, coords, null, tile)); + } + + setPosition(tile, tilePos); + + // save tile in cache + this._tiles[key] = { + el: tile, + coords: coords, + current: true + }; + + container.appendChild(tile); + // @event tileloadstart: TileEvent + // Fired when a tile is requested and starts loading. + this.fire('tileloadstart', { + tile: tile, + coords: coords + }); + }, + + _tileReady: function (coords, err, tile) { + if (err) { + // @event tileerror: TileErrorEvent + // Fired when there is an error loading a tile. + this.fire('tileerror', { + error: err, + tile: tile, + coords: coords + }); + } + + var key = this._tileCoordsToKey(coords); + + tile = this._tiles[key]; + if (!tile) { return; } + + tile.loaded = +new Date(); + if (this._map._fadeAnimated) { + setOpacity(tile.el, 0); + cancelAnimFrame(this._fadeFrame); + this._fadeFrame = requestAnimFrame(this._updateOpacity, this); + } else { + tile.active = true; + this._pruneTiles(); + } + + if (!err) { + addClass(tile.el, 'leaflet-tile-loaded'); + + // @event tileload: TileEvent + // Fired when a tile loads. + this.fire('tileload', { + tile: tile.el, + coords: coords + }); + } + + if (this._noTilesToLoad()) { + this._loading = false; + // @event load: Event + // Fired when the grid layer loaded all visible tiles. + this.fire('load'); + + if (Browser.ielt9 || !this._map._fadeAnimated) { + requestAnimFrame(this._pruneTiles, this); + } else { + // Wait a bit more than 0.2 secs (the duration of the tile fade-in) + // to trigger a pruning. + setTimeout(bind(this._pruneTiles, this), 250); + } + } + }, + + _getTilePos: function (coords) { + return coords.scaleBy(this.getTileSize()).subtract(this._level.origin); + }, + + _wrapCoords: function (coords) { + var newCoords = new Point( + this._wrapX ? wrapNum(coords.x, this._wrapX) : coords.x, + this._wrapY ? wrapNum(coords.y, this._wrapY) : coords.y); + newCoords.z = coords.z; + return newCoords; + }, + + _pxBoundsToTileRange: function (bounds) { + var tileSize = this.getTileSize(); + return new Bounds( + bounds.min.unscaleBy(tileSize).floor(), + bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1])); + }, + + _noTilesToLoad: function () { + for (var key in this._tiles) { + if (!this._tiles[key].loaded) { return false; } + } + return true; + } +}); + +// @factory L.gridLayer(options?: GridLayer options) +// Creates a new instance of GridLayer with the supplied options. +function gridLayer(options) { + return new GridLayer(options); +} + +/* + * @class TileLayer + * @inherits GridLayer + * @aka L.TileLayer + * Used to load and display tile layers on the map. Note that most tile servers require attribution, which you can set under `Layer`. Extends `GridLayer`. + * + * @example + * + * ```js + * L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar', attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'}).addTo(map); + * ``` + * + * @section URL template + * @example + * + * A string of the following form: + * + * ``` + * 'https://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png' + * ``` + * + * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add "@2x" to the URL to load retina tiles. + * + * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this: + * + * ``` + * L.tileLayer('https://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'}); + * ``` + */ + + +var TileLayer = GridLayer.extend({ + + // @section + // @aka TileLayer options + options: { + // @option minZoom: Number = 0 + // The minimum zoom level down to which this layer will be displayed (inclusive). + minZoom: 0, + + // @option maxZoom: Number = 18 + // The maximum zoom level up to which this layer will be displayed (inclusive). + maxZoom: 18, + + // @option subdomains: String|String[] = 'abc' + // Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings. + subdomains: 'abc', + + // @option errorTileUrl: String = '' + // URL to the tile image to show in place of the tile that failed to load. + errorTileUrl: '', + + // @option zoomOffset: Number = 0 + // The zoom number used in tile URLs will be offset with this value. + zoomOffset: 0, + + // @option tms: Boolean = false + // If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services). + tms: false, + + // @option zoomReverse: Boolean = false + // If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`) + zoomReverse: false, + + // @option detectRetina: Boolean = false + // If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution. + detectRetina: false, + + // @option crossOrigin: Boolean|String = false + // Whether the crossOrigin attribute will be added to the tiles. + // If a String is provided, all tiles will have their crossOrigin attribute set to the String provided. This is needed if you want to access tile pixel data. + // Refer to [CORS Settings](https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes) for valid String values. + crossOrigin: false, + + // @option referrerPolicy: Boolean|String = false + // Whether the referrerPolicy attribute will be added to the tiles. + // If a String is provided, all tiles will have their referrerPolicy attribute set to the String provided. + // This may be needed if your map's rendering context has a strict default but your tile provider expects a valid referrer + // (e.g. to validate an API token). + // Refer to [HTMLImageElement.referrerPolicy](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/referrerPolicy) for valid String values. + referrerPolicy: false + }, + + initialize: function (url, options) { + + this._url = url; + + options = setOptions(this, options); + + // detecting retina displays, adjusting tileSize and zoom levels + if (options.detectRetina && Browser.retina && options.maxZoom > 0) { + + options.tileSize = Math.floor(options.tileSize / 2); + + if (!options.zoomReverse) { + options.zoomOffset++; + options.maxZoom = Math.max(options.minZoom, options.maxZoom - 1); + } else { + options.zoomOffset--; + options.minZoom = Math.min(options.maxZoom, options.minZoom + 1); + } + + options.minZoom = Math.max(0, options.minZoom); + } else if (!options.zoomReverse) { + // make sure maxZoom is gte minZoom + options.maxZoom = Math.max(options.minZoom, options.maxZoom); + } else { + // make sure minZoom is lte maxZoom + options.minZoom = Math.min(options.maxZoom, options.minZoom); + } + + if (typeof options.subdomains === 'string') { + options.subdomains = options.subdomains.split(''); + } + + this.on('tileunload', this._onTileRemove); + }, + + // @method setUrl(url: String, noRedraw?: Boolean): this + // Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`). + // If the URL does not change, the layer will not be redrawn unless + // the noRedraw parameter is set to false. + setUrl: function (url, noRedraw) { + if (this._url === url && noRedraw === undefined) { + noRedraw = true; + } + + this._url = url; + + if (!noRedraw) { + this.redraw(); + } + return this; + }, + + // @method createTile(coords: Object, done?: Function): HTMLElement + // Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile) + // to return an `<img>` HTML element with the appropriate image URL given `coords`. The `done` + // callback is called when the tile has been loaded. + createTile: function (coords, done) { + var tile = document.createElement('img'); + + on(tile, 'load', bind(this._tileOnLoad, this, done, tile)); + on(tile, 'error', bind(this._tileOnError, this, done, tile)); + + if (this.options.crossOrigin || this.options.crossOrigin === '') { + tile.crossOrigin = this.options.crossOrigin === true ? '' : this.options.crossOrigin; + } + + // for this new option we follow the documented behavior + // more closely by only setting the property when string + if (typeof this.options.referrerPolicy === 'string') { + tile.referrerPolicy = this.options.referrerPolicy; + } + + // The alt attribute is set to the empty string, + // allowing screen readers to ignore the decorative image tiles. + // https://www.w3.org/WAI/tutorials/images/decorative/ + // https://www.w3.org/TR/html-aria/#el-img-empty-alt + tile.alt = ''; + + tile.src = this.getTileUrl(coords); + + return tile; + }, + + // @section Extension methods + // @uninheritable + // Layers extending `TileLayer` might reimplement the following method. + // @method getTileUrl(coords: Object): String + // Called only internally, returns the URL for a tile given its coordinates. + // Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes. + getTileUrl: function (coords) { + var data = { + r: Browser.retina ? '@2x' : '', + s: this._getSubdomain(coords), + x: coords.x, + y: coords.y, + z: this._getZoomForUrl() + }; + if (this._map && !this._map.options.crs.infinite) { + var invertedY = this._globalTileRange.max.y - coords.y; + if (this.options.tms) { + data['y'] = invertedY; + } + data['-y'] = invertedY; + } + + return template(this._url, extend(data, this.options)); + }, + + _tileOnLoad: function (done, tile) { + // For https://github.com/Leaflet/Leaflet/issues/3332 + if (Browser.ielt9) { + setTimeout(bind(done, this, null, tile), 0); + } else { + done(null, tile); + } + }, + + _tileOnError: function (done, tile, e) { + var errorUrl = this.options.errorTileUrl; + if (errorUrl && tile.getAttribute('src') !== errorUrl) { + tile.src = errorUrl; + } + done(e, tile); + }, + + _onTileRemove: function (e) { + e.tile.onload = null; + }, + + _getZoomForUrl: function () { + var zoom = this._tileZoom, + maxZoom = this.options.maxZoom, + zoomReverse = this.options.zoomReverse, + zoomOffset = this.options.zoomOffset; + + if (zoomReverse) { + zoom = maxZoom - zoom; + } + + return zoom + zoomOffset; + }, + + _getSubdomain: function (tilePoint) { + var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length; + return this.options.subdomains[index]; + }, + + // stops loading all tiles in the background layer + _abortLoading: function () { + var i, tile; + for (i in this._tiles) { + if (this._tiles[i].coords.z !== this._tileZoom) { + tile = this._tiles[i].el; + + tile.onload = falseFn; + tile.onerror = falseFn; + + if (!tile.complete) { + tile.src = emptyImageUrl; + var coords = this._tiles[i].coords; + remove(tile); + delete this._tiles[i]; + // @event tileabort: TileEvent + // Fired when a tile was loading but is now not wanted. + this.fire('tileabort', { + tile: tile, + coords: coords + }); + } + } + } + }, + + _removeTile: function (key) { + var tile = this._tiles[key]; + if (!tile) { return; } + + // Cancels any pending http requests associated with the tile + tile.el.setAttribute('src', emptyImageUrl); + + return GridLayer.prototype._removeTile.call(this, key); + }, + + _tileReady: function (coords, err, tile) { + if (!this._map || (tile && tile.getAttribute('src') === emptyImageUrl)) { + return; + } + + return GridLayer.prototype._tileReady.call(this, coords, err, tile); + } +}); + + +// @factory L.tilelayer(urlTemplate: String, options?: TileLayer options) +// Instantiates a tile layer object given a `URL template` and optionally an options object. + +function tileLayer(url, options) { + return new TileLayer(url, options); +} + +/* + * @class TileLayer.WMS + * @inherits TileLayer + * @aka L.TileLayer.WMS + * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`. + * + * @example + * + * ```js + * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", { + * layers: 'nexrad-n0r-900913', + * format: 'image/png', + * transparent: true, + * attribution: "Weather data © 2012 IEM Nexrad" + * }); + * ``` + */ + +var TileLayerWMS = TileLayer.extend({ + + // @section + // @aka TileLayer.WMS options + // If any custom options not documented here are used, they will be sent to the + // WMS server as extra parameters in each request URL. This can be useful for + // [non-standard vendor WMS parameters](https://docs.geoserver.org/stable/en/user/services/wms/vendor.html). + defaultWmsParams: { + service: 'WMS', + request: 'GetMap', + + // @option layers: String = '' + // **(required)** Comma-separated list of WMS layers to show. + layers: '', + + // @option styles: String = '' + // Comma-separated list of WMS styles. + styles: '', + + // @option format: String = 'image/jpeg' + // WMS image format (use `'image/png'` for layers with transparency). + format: 'image/jpeg', + + // @option transparent: Boolean = false + // If `true`, the WMS service will return images with transparency. + transparent: false, + + // @option version: String = '1.1.1' + // Version of the WMS service to use + version: '1.1.1' + }, + + options: { + // @option crs: CRS = null + // Coordinate Reference System to use for the WMS requests, defaults to + // map CRS. Don't change this if you're not sure what it means. + crs: null, + + // @option uppercase: Boolean = false + // If `true`, WMS request parameter keys will be uppercase. + uppercase: false + }, + + initialize: function (url, options) { + + this._url = url; + + var wmsParams = extend({}, this.defaultWmsParams); + + // all keys that are not TileLayer options go to WMS params + for (var i in options) { + if (!(i in this.options)) { + wmsParams[i] = options[i]; + } + } + + options = setOptions(this, options); + + var realRetina = options.detectRetina && Browser.retina ? 2 : 1; + var tileSize = this.getTileSize(); + wmsParams.width = tileSize.x * realRetina; + wmsParams.height = tileSize.y * realRetina; + + this.wmsParams = wmsParams; + }, + + onAdd: function (map) { + + this._crs = this.options.crs || map.options.crs; + this._wmsVersion = parseFloat(this.wmsParams.version); + + var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs'; + this.wmsParams[projectionKey] = this._crs.code; + + TileLayer.prototype.onAdd.call(this, map); + }, + + getTileUrl: function (coords) { + + var tileBounds = this._tileCoordsToNwSe(coords), + crs = this._crs, + bounds = toBounds(crs.project(tileBounds[0]), crs.project(tileBounds[1])), + min = bounds.min, + max = bounds.max, + bbox = (this._wmsVersion >= 1.3 && this._crs === EPSG4326 ? + [min.y, min.x, max.y, max.x] : + [min.x, min.y, max.x, max.y]).join(','), + url = TileLayer.prototype.getTileUrl.call(this, coords); + return url + + getParamString(this.wmsParams, url, this.options.uppercase) + + (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox; + }, + + // @method setParams(params: Object, noRedraw?: Boolean): this + // Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true). + setParams: function (params, noRedraw) { + + extend(this.wmsParams, params); + + if (!noRedraw) { + this.redraw(); + } + + return this; + } +}); + + +// @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options) +// Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object. +function tileLayerWMS(url, options) { + return new TileLayerWMS(url, options); +} + +TileLayer.WMS = TileLayerWMS; +tileLayer.wms = tileLayerWMS; + +/* + * @class Renderer + * @inherits Layer + * @aka L.Renderer + * + * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the + * DOM container of the renderer, its bounds, and its zoom animation. + * + * A `Renderer` works as an implicit layer group for all `Path`s - the renderer + * itself can be added or removed to the map. All paths use a renderer, which can + * be implicit (the map will decide the type of renderer and use it automatically) + * or explicit (using the [`renderer`](#path-renderer) option of the path). + * + * Do not use this class directly, use `SVG` and `Canvas` instead. + * + * @event update: Event + * Fired when the renderer updates its bounds, center and zoom, for example when + * its map has moved + */ + +var Renderer = Layer.extend({ + + // @section + // @aka Renderer options + options: { + // @option padding: Number = 0.1 + // How much to extend the clip area around the map view (relative to its size) + // e.g. 0.1 would be 10% of map view in each direction + padding: 0.1 + }, + + initialize: function (options) { + setOptions(this, options); + stamp(this); + this._layers = this._layers || {}; + }, + + onAdd: function () { + if (!this._container) { + this._initContainer(); // defined by renderer implementations + + // always keep transform-origin as 0 0 + addClass(this._container, 'leaflet-zoom-animated'); + } + + this.getPane().appendChild(this._container); + this._update(); + this.on('update', this._updatePaths, this); + }, + + onRemove: function () { + this.off('update', this._updatePaths, this); + this._destroyContainer(); + }, + + getEvents: function () { + var events = { + viewreset: this._reset, + zoom: this._onZoom, + moveend: this._update, + zoomend: this._onZoomEnd + }; + if (this._zoomAnimated) { + events.zoomanim = this._onAnimZoom; + } + return events; + }, + + _onAnimZoom: function (ev) { + this._updateTransform(ev.center, ev.zoom); + }, + + _onZoom: function () { + this._updateTransform(this._map.getCenter(), this._map.getZoom()); + }, + + _updateTransform: function (center, zoom) { + var scale = this._map.getZoomScale(zoom, this._zoom), + viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding), + currentCenterPoint = this._map.project(this._center, zoom), + + topLeftOffset = viewHalf.multiplyBy(-scale).add(currentCenterPoint) + .subtract(this._map._getNewPixelOrigin(center, zoom)); + + if (Browser.any3d) { + setTransform(this._container, topLeftOffset, scale); + } else { + setPosition(this._container, topLeftOffset); + } + }, + + _reset: function () { + this._update(); + this._updateTransform(this._center, this._zoom); + + for (var id in this._layers) { + this._layers[id]._reset(); + } + }, + + _onZoomEnd: function () { + for (var id in this._layers) { + this._layers[id]._project(); + } + }, + + _updatePaths: function () { + for (var id in this._layers) { + this._layers[id]._update(); + } + }, + + _update: function () { + // Update pixel bounds of renderer container (for positioning/sizing/clipping later) + // Subclasses are responsible of firing the 'update' event. + var p = this.options.padding, + size = this._map.getSize(), + min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round(); + + this._bounds = new Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round()); + + this._center = this._map.getCenter(); + this._zoom = this._map.getZoom(); + } +}); + +/* + * @class Canvas + * @inherits Renderer + * @aka L.Canvas + * + * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API). + * Inherits `Renderer`. + * + * Due to [technical limitations](https://caniuse.com/canvas), Canvas is not + * available in all web browsers, notably IE8, and overlapping geometries might + * not display properly in some edge cases. + * + * @example + * + * Use Canvas by default for all paths in the map: + * + * ```js + * var map = L.map('map', { + * renderer: L.canvas() + * }); + * ``` + * + * Use a Canvas renderer with extra padding for specific vector geometries: + * + * ```js + * var map = L.map('map'); + * var myRenderer = L.canvas({ padding: 0.5 }); + * var line = L.polyline( coordinates, { renderer: myRenderer } ); + * var circle = L.circle( center, { renderer: myRenderer } ); + * ``` + */ + +var Canvas = Renderer.extend({ + + // @section + // @aka Canvas options + options: { + // @option tolerance: Number = 0 + // How much to extend the click tolerance around a path/object on the map. + tolerance: 0 + }, + + getEvents: function () { + var events = Renderer.prototype.getEvents.call(this); + events.viewprereset = this._onViewPreReset; + return events; + }, + + _onViewPreReset: function () { + // Set a flag so that a viewprereset+moveend+viewreset only updates&redraws once + this._postponeUpdatePaths = true; + }, + + onAdd: function () { + Renderer.prototype.onAdd.call(this); + + // Redraw vectors since canvas is cleared upon removal, + // in case of removing the renderer itself from the map. + this._draw(); + }, + + _initContainer: function () { + var container = this._container = document.createElement('canvas'); + + on(container, 'mousemove', this._onMouseMove, this); + on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this); + on(container, 'mouseout', this._handleMouseOut, this); + container['_leaflet_disable_events'] = true; + + this._ctx = container.getContext('2d'); + }, + + _destroyContainer: function () { + cancelAnimFrame(this._redrawRequest); + delete this._ctx; + remove(this._container); + off(this._container); + delete this._container; + }, + + _updatePaths: function () { + if (this._postponeUpdatePaths) { return; } + + var layer; + this._redrawBounds = null; + for (var id in this._layers) { + layer = this._layers[id]; + layer._update(); + } + this._redraw(); + }, + + _update: function () { + if (this._map._animatingZoom && this._bounds) { return; } + + Renderer.prototype._update.call(this); + + var b = this._bounds, + container = this._container, + size = b.getSize(), + m = Browser.retina ? 2 : 1; + + setPosition(container, b.min); + + // set canvas size (also clearing it); use double size on retina + container.width = m * size.x; + container.height = m * size.y; + container.style.width = size.x + 'px'; + container.style.height = size.y + 'px'; + + if (Browser.retina) { + this._ctx.scale(2, 2); + } + + // translate so we use the same path coordinates after canvas element moves + this._ctx.translate(-b.min.x, -b.min.y); + + // Tell paths to redraw themselves + this.fire('update'); + }, + + _reset: function () { + Renderer.prototype._reset.call(this); + + if (this._postponeUpdatePaths) { + this._postponeUpdatePaths = false; + this._updatePaths(); + } + }, + + _initPath: function (layer) { + this._updateDashArray(layer); + this._layers[stamp(layer)] = layer; + + var order = layer._order = { + layer: layer, + prev: this._drawLast, + next: null + }; + if (this._drawLast) { this._drawLast.next = order; } + this._drawLast = order; + this._drawFirst = this._drawFirst || this._drawLast; + }, + + _addPath: function (layer) { + this._requestRedraw(layer); + }, + + _removePath: function (layer) { + var order = layer._order; + var next = order.next; + var prev = order.prev; + + if (next) { + next.prev = prev; + } else { + this._drawLast = prev; + } + if (prev) { + prev.next = next; + } else { + this._drawFirst = next; + } + + delete layer._order; + + delete this._layers[stamp(layer)]; + + this._requestRedraw(layer); + }, + + _updatePath: function (layer) { + // Redraw the union of the layer's old pixel + // bounds and the new pixel bounds. + this._extendRedrawBounds(layer); + layer._project(); + layer._update(); + // The redraw will extend the redraw bounds + // with the new pixel bounds. + this._requestRedraw(layer); + }, + + _updateStyle: function (layer) { + this._updateDashArray(layer); + this._requestRedraw(layer); + }, + + _updateDashArray: function (layer) { + if (typeof layer.options.dashArray === 'string') { + var parts = layer.options.dashArray.split(/[, ]+/), + dashArray = [], + dashValue, + i; + for (i = 0; i < parts.length; i++) { + dashValue = Number(parts[i]); + // Ignore dash array containing invalid lengths + if (isNaN(dashValue)) { return; } + dashArray.push(dashValue); + } + layer.options._dashArray = dashArray; + } else { + layer.options._dashArray = layer.options.dashArray; + } + }, + + _requestRedraw: function (layer) { + if (!this._map) { return; } + + this._extendRedrawBounds(layer); + this._redrawRequest = this._redrawRequest || requestAnimFrame(this._redraw, this); + }, + + _extendRedrawBounds: function (layer) { + if (layer._pxBounds) { + var padding = (layer.options.weight || 0) + 1; + this._redrawBounds = this._redrawBounds || new Bounds(); + this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding])); + this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding])); + } + }, + + _redraw: function () { + this._redrawRequest = null; + + if (this._redrawBounds) { + this._redrawBounds.min._floor(); + this._redrawBounds.max._ceil(); + } + + this._clear(); // clear layers in redraw bounds + this._draw(); // draw layers + + this._redrawBounds = null; + }, + + _clear: function () { + var bounds = this._redrawBounds; + if (bounds) { + var size = bounds.getSize(); + this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y); + } else { + this._ctx.save(); + this._ctx.setTransform(1, 0, 0, 1, 0, 0); + this._ctx.clearRect(0, 0, this._container.width, this._container.height); + this._ctx.restore(); + } + }, + + _draw: function () { + var layer, bounds = this._redrawBounds; + this._ctx.save(); + if (bounds) { + var size = bounds.getSize(); + this._ctx.beginPath(); + this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y); + this._ctx.clip(); + } + + this._drawing = true; + + for (var order = this._drawFirst; order; order = order.next) { + layer = order.layer; + if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) { + layer._updatePath(); + } + } + + this._drawing = false; + + this._ctx.restore(); // Restore state before clipping. + }, + + _updatePoly: function (layer, closed) { + if (!this._drawing) { return; } + + var i, j, len2, p, + parts = layer._parts, + len = parts.length, + ctx = this._ctx; + + if (!len) { return; } + + ctx.beginPath(); + + for (i = 0; i < len; i++) { + for (j = 0, len2 = parts[i].length; j < len2; j++) { + p = parts[i][j]; + ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y); + } + if (closed) { + ctx.closePath(); + } + } + + this._fillStroke(ctx, layer); + + // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature + }, + + _updateCircle: function (layer) { + + if (!this._drawing || layer._empty()) { return; } + + var p = layer._point, + ctx = this._ctx, + r = Math.max(Math.round(layer._radius), 1), + s = (Math.max(Math.round(layer._radiusY), 1) || r) / r; + + if (s !== 1) { + ctx.save(); + ctx.scale(1, s); + } + + ctx.beginPath(); + ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false); + + if (s !== 1) { + ctx.restore(); + } + + this._fillStroke(ctx, layer); + }, + + _fillStroke: function (ctx, layer) { + var options = layer.options; + + if (options.fill) { + ctx.globalAlpha = options.fillOpacity; + ctx.fillStyle = options.fillColor || options.color; + ctx.fill(options.fillRule || 'evenodd'); + } + + if (options.stroke && options.weight !== 0) { + if (ctx.setLineDash) { + ctx.setLineDash(layer.options && layer.options._dashArray || []); + } + ctx.globalAlpha = options.opacity; + ctx.lineWidth = options.weight; + ctx.strokeStyle = options.color; + ctx.lineCap = options.lineCap; + ctx.lineJoin = options.lineJoin; + ctx.stroke(); + } + }, + + // Canvas obviously doesn't have mouse events for individual drawn objects, + // so we emulate that by calculating what's under the mouse on mousemove/click manually + + _onClick: function (e) { + var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer; + + for (var order = this._drawFirst; order; order = order.next) { + layer = order.layer; + if (layer.options.interactive && layer._containsPoint(point)) { + if (!(e.type === 'click' || e.type === 'preclick') || !this._map._draggableMoved(layer)) { + clickedLayer = layer; + } + } + } + this._fireEvent(clickedLayer ? [clickedLayer] : false, e); + }, + + _onMouseMove: function (e) { + if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; } + + var point = this._map.mouseEventToLayerPoint(e); + this._handleMouseHover(e, point); + }, + + + _handleMouseOut: function (e) { + var layer = this._hoveredLayer; + if (layer) { + // if we're leaving the layer, fire mouseout + removeClass(this._container, 'leaflet-interactive'); + this._fireEvent([layer], e, 'mouseout'); + this._hoveredLayer = null; + this._mouseHoverThrottled = false; + } + }, + + _handleMouseHover: function (e, point) { + if (this._mouseHoverThrottled) { + return; + } + + var layer, candidateHoveredLayer; + + for (var order = this._drawFirst; order; order = order.next) { + layer = order.layer; + if (layer.options.interactive && layer._containsPoint(point)) { + candidateHoveredLayer = layer; + } + } + + if (candidateHoveredLayer !== this._hoveredLayer) { + this._handleMouseOut(e); + + if (candidateHoveredLayer) { + addClass(this._container, 'leaflet-interactive'); // change cursor + this._fireEvent([candidateHoveredLayer], e, 'mouseover'); + this._hoveredLayer = candidateHoveredLayer; + } + } + + this._fireEvent(this._hoveredLayer ? [this._hoveredLayer] : false, e); + + this._mouseHoverThrottled = true; + setTimeout(bind(function () { + this._mouseHoverThrottled = false; + }, this), 32); + }, + + _fireEvent: function (layers, e, type) { + this._map._fireDOMEvent(e, type || e.type, layers); + }, + + _bringToFront: function (layer) { + var order = layer._order; + + if (!order) { return; } + + var next = order.next; + var prev = order.prev; + + if (next) { + next.prev = prev; + } else { + // Already last + return; + } + if (prev) { + prev.next = next; + } else if (next) { + // Update first entry unless this is the + // single entry + this._drawFirst = next; + } + + order.prev = this._drawLast; + this._drawLast.next = order; + + order.next = null; + this._drawLast = order; + + this._requestRedraw(layer); + }, + + _bringToBack: function (layer) { + var order = layer._order; + + if (!order) { return; } + + var next = order.next; + var prev = order.prev; + + if (prev) { + prev.next = next; + } else { + // Already first + return; + } + if (next) { + next.prev = prev; + } else if (prev) { + // Update last entry unless this is the + // single entry + this._drawLast = prev; + } + + order.prev = null; + + order.next = this._drawFirst; + this._drawFirst.prev = order; + this._drawFirst = order; + + this._requestRedraw(layer); + } +}); + +// @factory L.canvas(options?: Renderer options) +// Creates a Canvas renderer with the given options. +function canvas(options) { + return Browser.canvas ? new Canvas(options) : null; +} + +/* + * Thanks to Dmitry Baranovsky and his Raphael library for inspiration! + */ + + +var vmlCreate = (function () { + try { + document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml'); + return function (name) { + return document.createElement('<lvml:' + name + ' class="lvml">'); + }; + } catch (e) { + // Do not return fn from catch block so `e` can be garbage collected + // See https://github.com/Leaflet/Leaflet/pull/7279 + } + return function (name) { + return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">'); + }; +})(); + + +/* + * @class SVG + * + * + * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility + * with old versions of Internet Explorer. + */ + +// mixin to redefine some SVG methods to handle VML syntax which is similar but with some differences +var vmlMixin = { + + _initContainer: function () { + this._container = create$1('div', 'leaflet-vml-container'); + }, + + _update: function () { + if (this._map._animatingZoom) { return; } + Renderer.prototype._update.call(this); + this.fire('update'); + }, + + _initPath: function (layer) { + var container = layer._container = vmlCreate('shape'); + + addClass(container, 'leaflet-vml-shape ' + (this.options.className || '')); + + container.coordsize = '1 1'; + + layer._path = vmlCreate('path'); + container.appendChild(layer._path); + + this._updateStyle(layer); + this._layers[stamp(layer)] = layer; + }, + + _addPath: function (layer) { + var container = layer._container; + this._container.appendChild(container); + + if (layer.options.interactive) { + layer.addInteractiveTarget(container); + } + }, + + _removePath: function (layer) { + var container = layer._container; + remove(container); + layer.removeInteractiveTarget(container); + delete this._layers[stamp(layer)]; + }, + + _updateStyle: function (layer) { + var stroke = layer._stroke, + fill = layer._fill, + options = layer.options, + container = layer._container; + + container.stroked = !!options.stroke; + container.filled = !!options.fill; + + if (options.stroke) { + if (!stroke) { + stroke = layer._stroke = vmlCreate('stroke'); + } + container.appendChild(stroke); + stroke.weight = options.weight + 'px'; + stroke.color = options.color; + stroke.opacity = options.opacity; + + if (options.dashArray) { + stroke.dashStyle = isArray(options.dashArray) ? + options.dashArray.join(' ') : + options.dashArray.replace(/( *, *)/g, ' '); + } else { + stroke.dashStyle = ''; + } + stroke.endcap = options.lineCap.replace('butt', 'flat'); + stroke.joinstyle = options.lineJoin; + + } else if (stroke) { + container.removeChild(stroke); + layer._stroke = null; + } + + if (options.fill) { + if (!fill) { + fill = layer._fill = vmlCreate('fill'); + } + container.appendChild(fill); + fill.color = options.fillColor || options.color; + fill.opacity = options.fillOpacity; + + } else if (fill) { + container.removeChild(fill); + layer._fill = null; + } + }, + + _updateCircle: function (layer) { + var p = layer._point.round(), + r = Math.round(layer._radius), + r2 = Math.round(layer._radiusY || r); + + this._setPath(layer, layer._empty() ? 'M0 0' : + 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360)); + }, + + _setPath: function (layer, path) { + layer._path.v = path; + }, + + _bringToFront: function (layer) { + toFront(layer._container); + }, + + _bringToBack: function (layer) { + toBack(layer._container); + } +}; + +var create = Browser.vml ? vmlCreate : svgCreate; + +/* + * @class SVG + * @inherits Renderer + * @aka L.SVG + * + * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG). + * Inherits `Renderer`. + * + * Due to [technical limitations](https://caniuse.com/svg), SVG is not + * available in all web browsers, notably Android 2.x and 3.x. + * + * Although SVG is not available on IE7 and IE8, these browsers support + * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language) + * (a now deprecated technology), and the SVG renderer will fall back to VML in + * this case. + * + * @example + * + * Use SVG by default for all paths in the map: + * + * ```js + * var map = L.map('map', { + * renderer: L.svg() + * }); + * ``` + * + * Use a SVG renderer with extra padding for specific vector geometries: + * + * ```js + * var map = L.map('map'); + * var myRenderer = L.svg({ padding: 0.5 }); + * var line = L.polyline( coordinates, { renderer: myRenderer } ); + * var circle = L.circle( center, { renderer: myRenderer } ); + * ``` + */ + +var SVG = Renderer.extend({ + + _initContainer: function () { + this._container = create('svg'); + + // makes it possible to click through svg root; we'll reset it back in individual paths + this._container.setAttribute('pointer-events', 'none'); + + this._rootGroup = create('g'); + this._container.appendChild(this._rootGroup); + }, + + _destroyContainer: function () { + remove(this._container); + off(this._container); + delete this._container; + delete this._rootGroup; + delete this._svgSize; + }, + + _update: function () { + if (this._map._animatingZoom && this._bounds) { return; } + + Renderer.prototype._update.call(this); + + var b = this._bounds, + size = b.getSize(), + container = this._container; + + // set size of svg-container if changed + if (!this._svgSize || !this._svgSize.equals(size)) { + this._svgSize = size; + container.setAttribute('width', size.x); + container.setAttribute('height', size.y); + } + + // movement: update container viewBox so that we don't have to change coordinates of individual layers + setPosition(container, b.min); + container.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' ')); + + this.fire('update'); + }, + + // methods below are called by vector layers implementations + + _initPath: function (layer) { + var path = layer._path = create('path'); + + // @namespace Path + // @option className: String = null + // Custom class name set on an element. Only for SVG renderer. + if (layer.options.className) { + addClass(path, layer.options.className); + } + + if (layer.options.interactive) { + addClass(path, 'leaflet-interactive'); + } + + this._updateStyle(layer); + this._layers[stamp(layer)] = layer; + }, + + _addPath: function (layer) { + if (!this._rootGroup) { this._initContainer(); } + this._rootGroup.appendChild(layer._path); + layer.addInteractiveTarget(layer._path); + }, + + _removePath: function (layer) { + remove(layer._path); + layer.removeInteractiveTarget(layer._path); + delete this._layers[stamp(layer)]; + }, + + _updatePath: function (layer) { + layer._project(); + layer._update(); + }, + + _updateStyle: function (layer) { + var path = layer._path, + options = layer.options; + + if (!path) { return; } + + if (options.stroke) { + path.setAttribute('stroke', options.color); + path.setAttribute('stroke-opacity', options.opacity); + path.setAttribute('stroke-width', options.weight); + path.setAttribute('stroke-linecap', options.lineCap); + path.setAttribute('stroke-linejoin', options.lineJoin); + + if (options.dashArray) { + path.setAttribute('stroke-dasharray', options.dashArray); + } else { + path.removeAttribute('stroke-dasharray'); + } + + if (options.dashOffset) { + path.setAttribute('stroke-dashoffset', options.dashOffset); + } else { + path.removeAttribute('stroke-dashoffset'); + } + } else { + path.setAttribute('stroke', 'none'); + } + + if (options.fill) { + path.setAttribute('fill', options.fillColor || options.color); + path.setAttribute('fill-opacity', options.fillOpacity); + path.setAttribute('fill-rule', options.fillRule || 'evenodd'); + } else { + path.setAttribute('fill', 'none'); + } + }, + + _updatePoly: function (layer, closed) { + this._setPath(layer, pointsToPath(layer._parts, closed)); + }, + + _updateCircle: function (layer) { + var p = layer._point, + r = Math.max(Math.round(layer._radius), 1), + r2 = Math.max(Math.round(layer._radiusY), 1) || r, + arc = 'a' + r + ',' + r2 + ' 0 1,0 '; + + // drawing a circle with two half-arcs + var d = layer._empty() ? 'M0 0' : + 'M' + (p.x - r) + ',' + p.y + + arc + (r * 2) + ',0 ' + + arc + (-r * 2) + ',0 '; + + this._setPath(layer, d); + }, + + _setPath: function (layer, path) { + layer._path.setAttribute('d', path); + }, + + // SVG does not have the concept of zIndex so we resort to changing the DOM order of elements + _bringToFront: function (layer) { + toFront(layer._path); + }, + + _bringToBack: function (layer) { + toBack(layer._path); + } +}); + +if (Browser.vml) { + SVG.include(vmlMixin); +} + +// @namespace SVG +// @factory L.svg(options?: Renderer options) +// Creates a SVG renderer with the given options. +function svg(options) { + return Browser.svg || Browser.vml ? new SVG(options) : null; +} + +Map.include({ + // @namespace Map; @method getRenderer(layer: Path): Renderer + // Returns the instance of `Renderer` that should be used to render the given + // `Path`. It will ensure that the `renderer` options of the map and paths + // are respected, and that the renderers do exist on the map. + getRenderer: function (layer) { + // @namespace Path; @option renderer: Renderer + // Use this specific instance of `Renderer` for this path. Takes + // precedence over the map's [default renderer](#map-renderer). + var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer; + + if (!renderer) { + renderer = this._renderer = this._createRenderer(); + } + + if (!this.hasLayer(renderer)) { + this.addLayer(renderer); + } + return renderer; + }, + + _getPaneRenderer: function (name) { + if (name === 'overlayPane' || name === undefined) { + return false; + } + + var renderer = this._paneRenderers[name]; + if (renderer === undefined) { + renderer = this._createRenderer({pane: name}); + this._paneRenderers[name] = renderer; + } + return renderer; + }, + + _createRenderer: function (options) { + // @namespace Map; @option preferCanvas: Boolean = false + // Whether `Path`s should be rendered on a `Canvas` renderer. + // By default, all `Path`s are rendered in a `SVG` renderer. + return (this.options.preferCanvas && canvas(options)) || svg(options); + } +}); + +/* + * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object. + */ + +/* + * @class Rectangle + * @aka L.Rectangle + * @inherits Polygon + * + * A class for drawing rectangle overlays on a map. Extends `Polygon`. + * + * @example + * + * ```js + * // define rectangle geographical bounds + * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]]; + * + * // create an orange rectangle + * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map); + * + * // zoom the map to the rectangle bounds + * map.fitBounds(bounds); + * ``` + * + */ + + +var Rectangle = Polygon.extend({ + initialize: function (latLngBounds, options) { + Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options); + }, + + // @method setBounds(latLngBounds: LatLngBounds): this + // Redraws the rectangle with the passed bounds. + setBounds: function (latLngBounds) { + return this.setLatLngs(this._boundsToLatLngs(latLngBounds)); + }, + + _boundsToLatLngs: function (latLngBounds) { + latLngBounds = toLatLngBounds(latLngBounds); + return [ + latLngBounds.getSouthWest(), + latLngBounds.getNorthWest(), + latLngBounds.getNorthEast(), + latLngBounds.getSouthEast() + ]; + } +}); + + +// @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options) +function rectangle(latLngBounds, options) { + return new Rectangle(latLngBounds, options); +} + +SVG.create = create; +SVG.pointsToPath = pointsToPath; + +GeoJSON.geometryToLayer = geometryToLayer; +GeoJSON.coordsToLatLng = coordsToLatLng; +GeoJSON.coordsToLatLngs = coordsToLatLngs; +GeoJSON.latLngToCoords = latLngToCoords; +GeoJSON.latLngsToCoords = latLngsToCoords; +GeoJSON.getFeature = getFeature; +GeoJSON.asFeature = asFeature; + +/* + * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map + * (zoom to a selected bounding box), enabled by default. + */ + +// @namespace Map +// @section Interaction Options +Map.mergeOptions({ + // @option boxZoom: Boolean = true + // Whether the map can be zoomed to a rectangular area specified by + // dragging the mouse while pressing the shift key. + boxZoom: true +}); + +var BoxZoom = Handler.extend({ + initialize: function (map) { + this._map = map; + this._container = map._container; + this._pane = map._panes.overlayPane; + this._resetStateTimeout = 0; + map.on('unload', this._destroy, this); + }, + + addHooks: function () { + on(this._container, 'mousedown', this._onMouseDown, this); + }, + + removeHooks: function () { + off(this._container, 'mousedown', this._onMouseDown, this); + }, + + moved: function () { + return this._moved; + }, + + _destroy: function () { + remove(this._pane); + delete this._pane; + }, + + _resetState: function () { + this._resetStateTimeout = 0; + this._moved = false; + }, + + _clearDeferredResetState: function () { + if (this._resetStateTimeout !== 0) { + clearTimeout(this._resetStateTimeout); + this._resetStateTimeout = 0; + } + }, + + _onMouseDown: function (e) { + if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; } + + // Clear the deferred resetState if it hasn't executed yet, otherwise it + // will interrupt the interaction and orphan a box element in the container. + this._clearDeferredResetState(); + this._resetState(); + + disableTextSelection(); + disableImageDrag(); + + this._startPoint = this._map.mouseEventToContainerPoint(e); + + on(document, { + contextmenu: stop, + mousemove: this._onMouseMove, + mouseup: this._onMouseUp, + keydown: this._onKeyDown + }, this); + }, + + _onMouseMove: function (e) { + if (!this._moved) { + this._moved = true; + + this._box = create$1('div', 'leaflet-zoom-box', this._container); + addClass(this._container, 'leaflet-crosshair'); + + this._map.fire('boxzoomstart'); + } + + this._point = this._map.mouseEventToContainerPoint(e); + + var bounds = new Bounds(this._point, this._startPoint), + size = bounds.getSize(); + + setPosition(this._box, bounds.min); + + this._box.style.width = size.x + 'px'; + this._box.style.height = size.y + 'px'; + }, + + _finish: function () { + if (this._moved) { + remove(this._box); + removeClass(this._container, 'leaflet-crosshair'); + } + + enableTextSelection(); + enableImageDrag(); + + off(document, { + contextmenu: stop, + mousemove: this._onMouseMove, + mouseup: this._onMouseUp, + keydown: this._onKeyDown + }, this); + }, + + _onMouseUp: function (e) { + if ((e.which !== 1) && (e.button !== 1)) { return; } + + this._finish(); + + if (!this._moved) { return; } + // Postpone to next JS tick so internal click event handling + // still see it as "moved". + this._clearDeferredResetState(); + this._resetStateTimeout = setTimeout(bind(this._resetState, this), 0); + + var bounds = new LatLngBounds( + this._map.containerPointToLatLng(this._startPoint), + this._map.containerPointToLatLng(this._point)); + + this._map + .fitBounds(bounds) + .fire('boxzoomend', {boxZoomBounds: bounds}); + }, + + _onKeyDown: function (e) { + if (e.keyCode === 27) { + this._finish(); + this._clearDeferredResetState(); + this._resetState(); + } + } +}); + +// @section Handlers +// @property boxZoom: Handler +// Box (shift-drag with mouse) zoom handler. +Map.addInitHook('addHandler', 'boxZoom', BoxZoom); + +/* + * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default. + */ + +// @namespace Map +// @section Interaction Options + +Map.mergeOptions({ + // @option doubleClickZoom: Boolean|String = true + // Whether the map can be zoomed in by double clicking on it and + // zoomed out by double clicking while holding shift. If passed + // `'center'`, double-click zoom will zoom to the center of the + // view regardless of where the mouse was. + doubleClickZoom: true +}); + +var DoubleClickZoom = Handler.extend({ + addHooks: function () { + this._map.on('dblclick', this._onDoubleClick, this); + }, + + removeHooks: function () { + this._map.off('dblclick', this._onDoubleClick, this); + }, + + _onDoubleClick: function (e) { + var map = this._map, + oldZoom = map.getZoom(), + delta = map.options.zoomDelta, + zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta; + + if (map.options.doubleClickZoom === 'center') { + map.setZoom(zoom); + } else { + map.setZoomAround(e.containerPoint, zoom); + } + } +}); + +// @section Handlers +// +// Map properties include interaction handlers that allow you to control +// interaction behavior in runtime, enabling or disabling certain features such +// as dragging or touch zoom (see `Handler` methods). For example: +// +// ```js +// map.doubleClickZoom.disable(); +// ``` +// +// @property doubleClickZoom: Handler +// Double click zoom handler. +Map.addInitHook('addHandler', 'doubleClickZoom', DoubleClickZoom); + +/* + * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default. + */ + +// @namespace Map +// @section Interaction Options +Map.mergeOptions({ + // @option dragging: Boolean = true + // Whether the map is draggable with mouse/touch or not. + dragging: true, + + // @section Panning Inertia Options + // @option inertia: Boolean = * + // If enabled, panning of the map will have an inertia effect where + // the map builds momentum while dragging and continues moving in + // the same direction for some time. Feels especially nice on touch + // devices. Enabled by default. + inertia: true, + + // @option inertiaDeceleration: Number = 3000 + // The rate with which the inertial movement slows down, in pixels/second². + inertiaDeceleration: 3400, // px/s^2 + + // @option inertiaMaxSpeed: Number = Infinity + // Max speed of the inertial movement, in pixels/second. + inertiaMaxSpeed: Infinity, // px/s + + // @option easeLinearity: Number = 0.2 + easeLinearity: 0.2, + + // TODO refactor, move to CRS + // @option worldCopyJump: Boolean = false + // With this option enabled, the map tracks when you pan to another "copy" + // of the world and seamlessly jumps to the original one so that all overlays + // like markers and vector layers are still visible. + worldCopyJump: false, + + // @option maxBoundsViscosity: Number = 0.0 + // If `maxBounds` is set, this option will control how solid the bounds + // are when dragging the map around. The default value of `0.0` allows the + // user to drag outside the bounds at normal speed, higher values will + // slow down map dragging outside bounds, and `1.0` makes the bounds fully + // solid, preventing the user from dragging outside the bounds. + maxBoundsViscosity: 0.0 +}); + +var Drag = Handler.extend({ + addHooks: function () { + if (!this._draggable) { + var map = this._map; + + this._draggable = new Draggable(map._mapPane, map._container); + + this._draggable.on({ + dragstart: this._onDragStart, + drag: this._onDrag, + dragend: this._onDragEnd + }, this); + + this._draggable.on('predrag', this._onPreDragLimit, this); + if (map.options.worldCopyJump) { + this._draggable.on('predrag', this._onPreDragWrap, this); + map.on('zoomend', this._onZoomEnd, this); + + map.whenReady(this._onZoomEnd, this); + } + } + addClass(this._map._container, 'leaflet-grab leaflet-touch-drag'); + this._draggable.enable(); + this._positions = []; + this._times = []; + }, + + removeHooks: function () { + removeClass(this._map._container, 'leaflet-grab'); + removeClass(this._map._container, 'leaflet-touch-drag'); + this._draggable.disable(); + }, + + moved: function () { + return this._draggable && this._draggable._moved; + }, + + moving: function () { + return this._draggable && this._draggable._moving; + }, + + _onDragStart: function () { + var map = this._map; + + map._stop(); + if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) { + var bounds = toLatLngBounds(this._map.options.maxBounds); + + this._offsetLimit = toBounds( + this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1), + this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1) + .add(this._map.getSize())); + + this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity)); + } else { + this._offsetLimit = null; + } + + map + .fire('movestart') + .fire('dragstart'); + + if (map.options.inertia) { + this._positions = []; + this._times = []; + } + }, + + _onDrag: function (e) { + if (this._map.options.inertia) { + var time = this._lastTime = +new Date(), + pos = this._lastPos = this._draggable._absPos || this._draggable._newPos; + + this._positions.push(pos); + this._times.push(time); + + this._prunePositions(time); + } + + this._map + .fire('move', e) + .fire('drag', e); + }, + + _prunePositions: function (time) { + while (this._positions.length > 1 && time - this._times[0] > 50) { + this._positions.shift(); + this._times.shift(); + } + }, + + _onZoomEnd: function () { + var pxCenter = this._map.getSize().divideBy(2), + pxWorldCenter = this._map.latLngToLayerPoint([0, 0]); + + this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x; + this._worldWidth = this._map.getPixelWorldBounds().getSize().x; + }, + + _viscousLimit: function (value, threshold) { + return value - (value - threshold) * this._viscosity; + }, + + _onPreDragLimit: function () { + if (!this._viscosity || !this._offsetLimit) { return; } + + var offset = this._draggable._newPos.subtract(this._draggable._startPos); + + var limit = this._offsetLimit; + if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); } + if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); } + if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); } + if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); } + + this._draggable._newPos = this._draggable._startPos.add(offset); + }, + + _onPreDragWrap: function () { + // TODO refactor to be able to adjust map pane position after zoom + var worldWidth = this._worldWidth, + halfWidth = Math.round(worldWidth / 2), + dx = this._initialWorldOffset, + x = this._draggable._newPos.x, + newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx, + newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx, + newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2; + + this._draggable._absPos = this._draggable._newPos.clone(); + this._draggable._newPos.x = newX; + }, + + _onDragEnd: function (e) { + var map = this._map, + options = map.options, + + noInertia = !options.inertia || e.noInertia || this._times.length < 2; + + map.fire('dragend', e); + + if (noInertia) { + map.fire('moveend'); + + } else { + this._prunePositions(+new Date()); + + var direction = this._lastPos.subtract(this._positions[0]), + duration = (this._lastTime - this._times[0]) / 1000, + ease = options.easeLinearity, + + speedVector = direction.multiplyBy(ease / duration), + speed = speedVector.distanceTo([0, 0]), + + limitedSpeed = Math.min(options.inertiaMaxSpeed, speed), + limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed), + + decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease), + offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round(); + + if (!offset.x && !offset.y) { + map.fire('moveend'); + + } else { + offset = map._limitOffset(offset, map.options.maxBounds); + + requestAnimFrame(function () { + map.panBy(offset, { + duration: decelerationDuration, + easeLinearity: ease, + noMoveStart: true, + animate: true + }); + }); + } + } + } +}); + +// @section Handlers +// @property dragging: Handler +// Map dragging handler (by both mouse and touch). +Map.addInitHook('addHandler', 'dragging', Drag); + +/* + * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default. + */ + +// @namespace Map +// @section Keyboard Navigation Options +Map.mergeOptions({ + // @option keyboard: Boolean = true + // Makes the map focusable and allows users to navigate the map with keyboard + // arrows and `+`/`-` keys. + keyboard: true, + + // @option keyboardPanDelta: Number = 80 + // Amount of pixels to pan when pressing an arrow key. + keyboardPanDelta: 80 +}); + +var Keyboard = Handler.extend({ + + keyCodes: { + left: [37], + right: [39], + down: [40], + up: [38], + zoomIn: [187, 107, 61, 171], + zoomOut: [189, 109, 54, 173] + }, + + initialize: function (map) { + this._map = map; + + this._setPanDelta(map.options.keyboardPanDelta); + this._setZoomDelta(map.options.zoomDelta); + }, + + addHooks: function () { + var container = this._map._container; + + // make the container focusable by tabbing + if (container.tabIndex <= 0) { + container.tabIndex = '0'; + } + + on(container, { + focus: this._onFocus, + blur: this._onBlur, + mousedown: this._onMouseDown + }, this); + + this._map.on({ + focus: this._addHooks, + blur: this._removeHooks + }, this); + }, + + removeHooks: function () { + this._removeHooks(); + + off(this._map._container, { + focus: this._onFocus, + blur: this._onBlur, + mousedown: this._onMouseDown + }, this); + + this._map.off({ + focus: this._addHooks, + blur: this._removeHooks + }, this); + }, + + _onMouseDown: function () { + if (this._focused) { return; } + + var body = document.body, + docEl = document.documentElement, + top = body.scrollTop || docEl.scrollTop, + left = body.scrollLeft || docEl.scrollLeft; + + this._map._container.focus(); + + window.scrollTo(left, top); + }, + + _onFocus: function () { + this._focused = true; + this._map.fire('focus'); + }, + + _onBlur: function () { + this._focused = false; + this._map.fire('blur'); + }, + + _setPanDelta: function (panDelta) { + var keys = this._panKeys = {}, + codes = this.keyCodes, + i, len; + + for (i = 0, len = codes.left.length; i < len; i++) { + keys[codes.left[i]] = [-1 * panDelta, 0]; + } + for (i = 0, len = codes.right.length; i < len; i++) { + keys[codes.right[i]] = [panDelta, 0]; + } + for (i = 0, len = codes.down.length; i < len; i++) { + keys[codes.down[i]] = [0, panDelta]; + } + for (i = 0, len = codes.up.length; i < len; i++) { + keys[codes.up[i]] = [0, -1 * panDelta]; + } + }, + + _setZoomDelta: function (zoomDelta) { + var keys = this._zoomKeys = {}, + codes = this.keyCodes, + i, len; + + for (i = 0, len = codes.zoomIn.length; i < len; i++) { + keys[codes.zoomIn[i]] = zoomDelta; + } + for (i = 0, len = codes.zoomOut.length; i < len; i++) { + keys[codes.zoomOut[i]] = -zoomDelta; + } + }, + + _addHooks: function () { + on(document, 'keydown', this._onKeyDown, this); + }, + + _removeHooks: function () { + off(document, 'keydown', this._onKeyDown, this); + }, + + _onKeyDown: function (e) { + if (e.altKey || e.ctrlKey || e.metaKey) { return; } + + var key = e.keyCode, + map = this._map, + offset; + + if (key in this._panKeys) { + if (!map._panAnim || !map._panAnim._inProgress) { + offset = this._panKeys[key]; + if (e.shiftKey) { + offset = toPoint(offset).multiplyBy(3); + } + + if (map.options.maxBounds) { + offset = map._limitOffset(toPoint(offset), map.options.maxBounds); + } + + if (map.options.worldCopyJump) { + var newLatLng = map.wrapLatLng(map.unproject(map.project(map.getCenter()).add(offset))); + map.panTo(newLatLng); + } else { + map.panBy(offset); + } + } + } else if (key in this._zoomKeys) { + map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]); + + } else if (key === 27 && map._popup && map._popup.options.closeOnEscapeKey) { + map.closePopup(); + + } else { + return; + } + + stop(e); + } +}); + +// @section Handlers +// @section Handlers +// @property keyboard: Handler +// Keyboard navigation handler. +Map.addInitHook('addHandler', 'keyboard', Keyboard); + +/* + * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map. + */ + +// @namespace Map +// @section Interaction Options +Map.mergeOptions({ + // @section Mouse wheel options + // @option scrollWheelZoom: Boolean|String = true + // Whether the map can be zoomed by using the mouse wheel. If passed `'center'`, + // it will zoom to the center of the view regardless of where the mouse was. + scrollWheelZoom: true, + + // @option wheelDebounceTime: Number = 40 + // Limits the rate at which a wheel can fire (in milliseconds). By default + // user can't zoom via wheel more often than once per 40 ms. + wheelDebounceTime: 40, + + // @option wheelPxPerZoomLevel: Number = 60 + // How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta)) + // mean a change of one full zoom level. Smaller values will make wheel-zooming + // faster (and vice versa). + wheelPxPerZoomLevel: 60 +}); + +var ScrollWheelZoom = Handler.extend({ + addHooks: function () { + on(this._map._container, 'wheel', this._onWheelScroll, this); + + this._delta = 0; + }, + + removeHooks: function () { + off(this._map._container, 'wheel', this._onWheelScroll, this); + }, + + _onWheelScroll: function (e) { + var delta = getWheelDelta(e); + + var debounce = this._map.options.wheelDebounceTime; + + this._delta += delta; + this._lastMousePos = this._map.mouseEventToContainerPoint(e); + + if (!this._startTime) { + this._startTime = +new Date(); + } + + var left = Math.max(debounce - (+new Date() - this._startTime), 0); + + clearTimeout(this._timer); + this._timer = setTimeout(bind(this._performZoom, this), left); + + stop(e); + }, + + _performZoom: function () { + var map = this._map, + zoom = map.getZoom(), + snap = this._map.options.zoomSnap || 0; + + map._stop(); // stop panning and fly animations if any + + // map the delta with a sigmoid function to -4..4 range leaning on -1..1 + var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4), + d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2, + d4 = snap ? Math.ceil(d3 / snap) * snap : d3, + delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom; + + this._delta = 0; + this._startTime = null; + + if (!delta) { return; } + + if (map.options.scrollWheelZoom === 'center') { + map.setZoom(zoom + delta); + } else { + map.setZoomAround(this._lastMousePos, zoom + delta); + } + } +}); + +// @section Handlers +// @property scrollWheelZoom: Handler +// Scroll wheel zoom handler. +Map.addInitHook('addHandler', 'scrollWheelZoom', ScrollWheelZoom); + +/* + * L.Map.TapHold is used to simulate `contextmenu` event on long hold, + * which otherwise is not fired by mobile Safari. + */ + +var tapHoldDelay = 600; + +// @namespace Map +// @section Interaction Options +Map.mergeOptions({ + // @section Touch interaction options + // @option tapHold: Boolean + // Enables simulation of `contextmenu` event, default is `true` for mobile Safari. + tapHold: Browser.touchNative && Browser.safari && Browser.mobile, + + // @option tapTolerance: Number = 15 + // The max number of pixels a user can shift his finger during touch + // for it to be considered a valid tap. + tapTolerance: 15 +}); + +var TapHold = Handler.extend({ + addHooks: function () { + on(this._map._container, 'touchstart', this._onDown, this); + }, + + removeHooks: function () { + off(this._map._container, 'touchstart', this._onDown, this); + }, + + _onDown: function (e) { + clearTimeout(this._holdTimeout); + if (e.touches.length !== 1) { return; } + + var first = e.touches[0]; + this._startPos = this._newPos = new Point(first.clientX, first.clientY); + + this._holdTimeout = setTimeout(bind(function () { + this._cancel(); + if (!this._isTapValid()) { return; } + + // prevent simulated mouse events https://w3c.github.io/touch-events/#mouse-events + on(document, 'touchend', preventDefault); + on(document, 'touchend touchcancel', this._cancelClickPrevent); + this._simulateEvent('contextmenu', first); + }, this), tapHoldDelay); + + on(document, 'touchend touchcancel contextmenu', this._cancel, this); + on(document, 'touchmove', this._onMove, this); + }, + + _cancelClickPrevent: function cancelClickPrevent() { + off(document, 'touchend', preventDefault); + off(document, 'touchend touchcancel', cancelClickPrevent); + }, + + _cancel: function () { + clearTimeout(this._holdTimeout); + off(document, 'touchend touchcancel contextmenu', this._cancel, this); + off(document, 'touchmove', this._onMove, this); + }, + + _onMove: function (e) { + var first = e.touches[0]; + this._newPos = new Point(first.clientX, first.clientY); + }, + + _isTapValid: function () { + return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance; + }, + + _simulateEvent: function (type, e) { + var simulatedEvent = new MouseEvent(type, { + bubbles: true, + cancelable: true, + view: window, + // detail: 1, + screenX: e.screenX, + screenY: e.screenY, + clientX: e.clientX, + clientY: e.clientY, + // button: 2, + // buttons: 2 + }); + + simulatedEvent._simulated = true; + + e.target.dispatchEvent(simulatedEvent); + } +}); + +// @section Handlers +// @property tapHold: Handler +// Long tap handler to simulate `contextmenu` event (useful in mobile Safari). +Map.addInitHook('addHandler', 'tapHold', TapHold); + +/* + * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers. + */ + +// @namespace Map +// @section Interaction Options +Map.mergeOptions({ + // @section Touch interaction options + // @option touchZoom: Boolean|String = * + // Whether the map can be zoomed by touch-dragging with two fingers. If + // passed `'center'`, it will zoom to the center of the view regardless of + // where the touch events (fingers) were. Enabled for touch-capable web + // browsers. + touchZoom: Browser.touch, + + // @option bounceAtZoomLimits: Boolean = true + // Set it to false if you don't want the map to zoom beyond min/max zoom + // and then bounce back when pinch-zooming. + bounceAtZoomLimits: true +}); + +var TouchZoom = Handler.extend({ + addHooks: function () { + addClass(this._map._container, 'leaflet-touch-zoom'); + on(this._map._container, 'touchstart', this._onTouchStart, this); + }, + + removeHooks: function () { + removeClass(this._map._container, 'leaflet-touch-zoom'); + off(this._map._container, 'touchstart', this._onTouchStart, this); + }, + + _onTouchStart: function (e) { + var map = this._map; + if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; } + + var p1 = map.mouseEventToContainerPoint(e.touches[0]), + p2 = map.mouseEventToContainerPoint(e.touches[1]); + + this._centerPoint = map.getSize()._divideBy(2); + this._startLatLng = map.containerPointToLatLng(this._centerPoint); + if (map.options.touchZoom !== 'center') { + this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2)); + } + + this._startDist = p1.distanceTo(p2); + this._startZoom = map.getZoom(); + + this._moved = false; + this._zooming = true; + + map._stop(); + + on(document, 'touchmove', this._onTouchMove, this); + on(document, 'touchend touchcancel', this._onTouchEnd, this); + + preventDefault(e); + }, + + _onTouchMove: function (e) { + if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; } + + var map = this._map, + p1 = map.mouseEventToContainerPoint(e.touches[0]), + p2 = map.mouseEventToContainerPoint(e.touches[1]), + scale = p1.distanceTo(p2) / this._startDist; + + this._zoom = map.getScaleZoom(scale, this._startZoom); + + if (!map.options.bounceAtZoomLimits && ( + (this._zoom < map.getMinZoom() && scale < 1) || + (this._zoom > map.getMaxZoom() && scale > 1))) { + this._zoom = map._limitZoom(this._zoom); + } + + if (map.options.touchZoom === 'center') { + this._center = this._startLatLng; + if (scale === 1) { return; } + } else { + // Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng + var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint); + if (scale === 1 && delta.x === 0 && delta.y === 0) { return; } + this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom); + } + + if (!this._moved) { + map._moveStart(true, false); + this._moved = true; + } + + cancelAnimFrame(this._animRequest); + + var moveFn = bind(map._move, map, this._center, this._zoom, {pinch: true, round: false}, undefined); + this._animRequest = requestAnimFrame(moveFn, this, true); + + preventDefault(e); + }, + + _onTouchEnd: function () { + if (!this._moved || !this._zooming) { + this._zooming = false; + return; + } + + this._zooming = false; + cancelAnimFrame(this._animRequest); + + off(document, 'touchmove', this._onTouchMove, this); + off(document, 'touchend touchcancel', this._onTouchEnd, this); + + // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate. + if (this._map.options.zoomAnimation) { + this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap); + } else { + this._map._resetView(this._center, this._map._limitZoom(this._zoom)); + } + } +}); + +// @section Handlers +// @property touchZoom: Handler +// Touch zoom handler. +Map.addInitHook('addHandler', 'touchZoom', TouchZoom); + +Map.BoxZoom = BoxZoom; +Map.DoubleClickZoom = DoubleClickZoom; +Map.Drag = Drag; +Map.Keyboard = Keyboard; +Map.ScrollWheelZoom = ScrollWheelZoom; +Map.TapHold = TapHold; +Map.TouchZoom = TouchZoom; + +export { Bounds, Browser, CRS, Canvas, Circle, CircleMarker, Class, Control, DivIcon, DivOverlay, DomEvent, DomUtil, Draggable, Evented, FeatureGroup, GeoJSON, GridLayer, Handler, Icon, ImageOverlay, LatLng, LatLngBounds, Layer, LayerGroup, LineUtil, Map, Marker, Mixin, Path, Point, PolyUtil, Polygon, Polyline, Popup, PosAnimation, index as Projection, Rectangle, Renderer, SVG, SVGOverlay, TileLayer, Tooltip, Transformation, Util, VideoOverlay, bind, toBounds as bounds, canvas, circle, circleMarker, control, divIcon, extend, featureGroup, geoJSON, geoJson, gridLayer, icon, imageOverlay, toLatLng as latLng, toLatLngBounds as latLngBounds, layerGroup, createMap as map, marker, toPoint as point, polygon, polyline, popup, rectangle, setOptions, stamp, svg, svgOverlay, tileLayer, tooltip, toTransformation as transformation, version, videoOverlay }; +//# sourceMappingURL=leaflet-src.esm.js.map diff --git a/src/main/webapp/js/3rdparty/ol_6_5_0.js b/src/main/webapp/js/3rdparty/ol_6_5_0.js new file mode 100644 index 0000000000000000000000000000000000000000..f1f1fb351e8b1d053447811bf01136222e86493a --- /dev/null +++ b/src/main/webapp/js/3rdparty/ol_6_5_0.js @@ -0,0 +1,9 @@ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ol=e():t.ol=e()}(window,(function(){return function(t){var e={};function r(n){if(e[n])return e[n].exports;var i=e[n]={i:n,l:!1,exports:{}};return t[n].call(i.exports,i,i.exports,r),i.l=!0,i.exports}return r.m=t,r.c=e,r.d=function(t,e,n){r.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:n})},r.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},r.t=function(t,e){if(1&e&&(t=r(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)r.d(n,i,function(e){return t[e]}.bind(null,i));return n},r.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return r.d(e,"a",e),e},r.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},r.p="",r(r.s=10)}([function(t,e,r){"use strict";(function(t,n){r.d(e,"a",(function(){return J})),r.d(e,"b",(function(){return br})),r.d(e,"c",(function(){return $r})),r.d(e,"d",(function(){return hr})),r.d(e,"e",(function(){return Jr})),r.d(e,"f",(function(){return i}));var i={$version:8,$root:{version:{required:!0,type:"enum",values:[8],doc:"Style specification version number. Must be 8.",example:8},name:{type:"string",doc:"A human-readable name for the style.",example:"Bright"},metadata:{type:"*",doc:"Arbitrary properties useful to track with the stylesheet, but do not influence rendering. Properties should be prefixed to avoid collisions, like 'mapbox:'."},center:{type:"array",value:"number",doc:"Default map center in longitude and latitude. The style center will be used only if the map has not been positioned by other means (e.g. map options or user interaction).",example:[-73.9749,40.7736]},zoom:{type:"number",doc:"Default zoom level. The style zoom will be used only if the map has not been positioned by other means (e.g. map options or user interaction).",example:12.5},bearing:{type:"number",default:0,period:360,units:"degrees",doc:'Default bearing, in degrees. The bearing is the compass direction that is "up"; for example, a bearing of 90° orients the map so that east is up. This value will be used only if the map has not been positioned by other means (e.g. map options or user interaction).',example:29},pitch:{type:"number",default:0,units:"degrees",doc:"Default pitch, in degrees. Zero is perpendicular to the surface, for a look straight down at the map, while a greater value like 60 looks ahead towards the horizon. The style pitch will be used only if the map has not been positioned by other means (e.g. map options or user interaction).",example:50},light:{type:"light",doc:"The global light source.",example:{anchor:"viewport",color:"white",intensity:.4}},terrain:{type:"terrain",doc:"A global modifier that elevates layers and markers based on a DEM data source."},sources:{required:!0,type:"sources",doc:"Data source specifications.",example:{"mapbox-streets":{type:"vector",url:"mapbox://mapbox.mapbox-streets-v6"}}},sprite:{type:"string",doc:"A base URL for retrieving the sprite image and metadata. The extensions `.png`, `.json` and scale factor `@2x.png` will be automatically appended. This property is required if any layer uses the `background-pattern`, `fill-pattern`, `line-pattern`, `fill-extrusion-pattern`, or `icon-image` properties. The URL must be absolute, containing the [scheme, authority and path components](https://en.wikipedia.org/wiki/URL#Syntax).",example:"mapbox://sprites/mapbox/bright-v8"},glyphs:{type:"string",doc:"A URL template for loading signed-distance-field glyph sets in PBF format. The URL must include `{fontstack}` and `{range}` tokens. This property is required if any layer uses the `text-field` layout property. The URL must be absolute, containing the [scheme, authority and path components](https://en.wikipedia.org/wiki/URL#Syntax).",example:"mapbox://fonts/mapbox/{fontstack}/{range}.pbf"},transition:{type:"transition",doc:"A global transition definition to use as a default across properties, to be used for timing transitions between one value and the next when no property-specific transition is set. Collision-based symbol fading is controlled independently of the style's `transition` property.",example:{duration:300,delay:0}},layers:{required:!0,type:"array",value:"layer",doc:"Layers will be drawn in the order of this array.",example:[{id:"water",source:"mapbox-streets","source-layer":"water",type:"fill",paint:{"fill-color":"#00ffff"}}]}},sources:{"*":{type:"source",doc:"Specification of a data source. For vector and raster sources, either TileJSON or a URL to a TileJSON must be provided. For image and video sources, a URL must be provided. For GeoJSON sources, a URL or inline GeoJSON must be provided."}},source:["source_vector","source_raster","source_raster_dem","source_geojson","source_video","source_image"],source_vector:{type:{required:!0,type:"enum",values:{vector:{doc:"A vector tile source."}},doc:"The type of the source."},url:{type:"string",doc:"A URL to a TileJSON resource. Supported protocols are `http:`, `https:`, and `mapbox://<Tileset ID>`."},tiles:{type:"array",value:"string",doc:"An array of one or more tile source URLs, as in the TileJSON spec."},bounds:{type:"array",value:"number",length:4,default:[-180,-85.051129,180,85.051129],doc:"An array containing the longitude and latitude of the southwest and northeast corners of the source's bounding box in the following order: `[sw.lng, sw.lat, ne.lng, ne.lat]`. When this property is included in a source, no tiles outside of the given bounds are requested by Mapbox GL."},scheme:{type:"enum",values:{xyz:{doc:"Slippy map tilenames scheme."},tms:{doc:"OSGeo spec scheme."}},default:"xyz",doc:"Influences the y direction of the tile coordinates. The global-mercator (aka Spherical Mercator) profile is assumed."},minzoom:{type:"number",default:0,doc:"Minimum zoom level for which tiles are available, as in the TileJSON spec."},maxzoom:{type:"number",default:22,doc:"Maximum zoom level for which tiles are available, as in the TileJSON spec. Data from tiles at the maxzoom are used when displaying the map at higher zoom levels."},attribution:{type:"string",doc:"Contains an attribution to be displayed when the map is shown to a user."},promoteId:{type:"promoteId",doc:"A property to use as a feature id (for feature state). Either a property name, or an object of the form `{<sourceLayer>: <propertyName>}`. If specified as a string for a vector tile source, the same property is used across all its source layers."},volatile:{type:"boolean",default:!1,doc:"A setting to determine whether a source's tiles are cached locally.","sdk-support":{"basic functionality":{android:"9.3.0",ios:"5.10.0"}}},"*":{type:"*",doc:"Other keys to configure the data source."}},source_raster:{type:{required:!0,type:"enum",values:{raster:{doc:"A raster tile source."}},doc:"The type of the source."},url:{type:"string",doc:"A URL to a TileJSON resource. Supported protocols are `http:`, `https:`, and `mapbox://<Tileset ID>`."},tiles:{type:"array",value:"string",doc:"An array of one or more tile source URLs, as in the TileJSON spec."},bounds:{type:"array",value:"number",length:4,default:[-180,-85.051129,180,85.051129],doc:"An array containing the longitude and latitude of the southwest and northeast corners of the source's bounding box in the following order: `[sw.lng, sw.lat, ne.lng, ne.lat]`. When this property is included in a source, no tiles outside of the given bounds are requested by Mapbox GL."},minzoom:{type:"number",default:0,doc:"Minimum zoom level for which tiles are available, as in the TileJSON spec."},maxzoom:{type:"number",default:22,doc:"Maximum zoom level for which tiles are available, as in the TileJSON spec. Data from tiles at the maxzoom are used when displaying the map at higher zoom levels."},tileSize:{type:"number",default:512,units:"pixels",doc:"The minimum visual size to display tiles for this layer. Only configurable for raster layers."},scheme:{type:"enum",values:{xyz:{doc:"Slippy map tilenames scheme."},tms:{doc:"OSGeo spec scheme."}},default:"xyz",doc:"Influences the y direction of the tile coordinates. The global-mercator (aka Spherical Mercator) profile is assumed."},attribution:{type:"string",doc:"Contains an attribution to be displayed when the map is shown to a user."},volatile:{type:"boolean",default:!1,doc:"A setting to determine whether a source's tiles are cached locally.","sdk-support":{"basic functionality":{android:"9.3.0",ios:"5.10.0"}}},"*":{type:"*",doc:"Other keys to configure the data source."}},source_raster_dem:{type:{required:!0,type:"enum",values:{"raster-dem":{doc:"A RGB-encoded raster DEM source"}},doc:"The type of the source."},url:{type:"string",doc:"A URL to a TileJSON resource. Supported protocols are `http:`, `https:`, and `mapbox://<Tileset ID>`."},tiles:{type:"array",value:"string",doc:"An array of one or more tile source URLs, as in the TileJSON spec."},bounds:{type:"array",value:"number",length:4,default:[-180,-85.051129,180,85.051129],doc:"An array containing the longitude and latitude of the southwest and northeast corners of the source's bounding box in the following order: `[sw.lng, sw.lat, ne.lng, ne.lat]`. When this property is included in a source, no tiles outside of the given bounds are requested by Mapbox GL."},minzoom:{type:"number",default:0,doc:"Minimum zoom level for which tiles are available, as in the TileJSON spec."},maxzoom:{type:"number",default:22,doc:"Maximum zoom level for which tiles are available, as in the TileJSON spec. Data from tiles at the maxzoom are used when displaying the map at higher zoom levels."},tileSize:{type:"number",default:512,units:"pixels",doc:"The minimum visual size to display tiles for this layer. Only configurable for raster layers."},attribution:{type:"string",doc:"Contains an attribution to be displayed when the map is shown to a user."},encoding:{type:"enum",values:{terrarium:{doc:"Terrarium format PNG tiles. See https://aws.amazon.com/es/public-datasets/terrain/ for more info."},mapbox:{doc:"Mapbox Terrain RGB tiles. See https://www.mapbox.com/help/access-elevation-data/#mapbox-terrain-rgb for more info."}},default:"mapbox",doc:"The encoding used by this source. Mapbox Terrain RGB is used by default"},volatile:{type:"boolean",default:!1,doc:"A setting to determine whether a source's tiles are cached locally.","sdk-support":{"basic functionality":{android:"9.3.0",ios:"5.10.0"}}},"*":{type:"*",doc:"Other keys to configure the data source."}},source_geojson:{type:{required:!0,type:"enum",values:{geojson:{doc:"A GeoJSON data source."}},doc:"The data type of the GeoJSON source."},data:{type:"*",doc:"A URL to a GeoJSON file, or inline GeoJSON."},maxzoom:{type:"number",default:18,doc:"Maximum zoom level at which to create vector tiles (higher means greater detail at high zoom levels)."},attribution:{type:"string",doc:"Contains an attribution to be displayed when the map is shown to a user."},buffer:{type:"number",default:128,maximum:512,minimum:0,doc:"Size of the tile buffer on each side. A value of 0 produces no buffer. A value of 512 produces a buffer as wide as the tile itself. Larger values produce fewer rendering artifacts near tile edges and slower performance."},filter:{type:"*",doc:"An expression for filtering features prior to processing them for rendering."},tolerance:{type:"number",default:.375,doc:"Douglas-Peucker simplification tolerance (higher means simpler geometries and faster performance)."},cluster:{type:"boolean",default:!1,doc:"If the data is a collection of point features, setting this to true clusters the points by radius into groups. Cluster groups become new `Point` features in the source with additional properties:\n * `cluster` Is `true` if the point is a cluster \n * `cluster_id` A unqiue id for the cluster to be used in conjunction with the [cluster inspection methods](https://www.mapbox.com/mapbox-gl-js/api/#geojsonsource#getclusterexpansionzoom)\n * `point_count` Number of original points grouped into this cluster\n * `point_count_abbreviated` An abbreviated point count"},clusterRadius:{type:"number",default:50,minimum:0,doc:"Radius of each cluster if clustering is enabled. A value of 512 indicates a radius equal to the width of a tile."},clusterMaxZoom:{type:"number",doc:"Max zoom on which to cluster points if clustering is enabled. Defaults to one zoom less than maxzoom (so that last zoom features are not clustered). Clusters are re-evaluated at integer zoom levels so setting clusterMaxZoom to 14 means the clusters will be displayed until z15."},clusterMinPoints:{type:"number",doc:"Minimum number of points necessary to form a cluster if clustering is enabled. Defaults to `2`."},clusterProperties:{type:"*",doc:'An object defining custom properties on the generated clusters if clustering is enabled, aggregating values from clustered points. Has the form `{"property_name": [operator, map_expression]}`. `operator` is any expression function that accepts at least 2 operands (e.g. `"+"` or `"max"`) — it accumulates the property value from clusters/points the cluster contains; `map_expression` produces the value of a single point.\n\nExample: `{"sum": ["+", ["get", "scalerank"]]}`.\n\nFor more advanced use cases, in place of `operator`, you can use a custom reduce expression that references a special `["accumulated"]` value, e.g.:\n`{"sum": [["+", ["accumulated"], ["get", "sum"]], ["get", "scalerank"]]}`'},lineMetrics:{type:"boolean",default:!1,doc:"Whether to calculate line distance metrics. This is required for line layers that specify `line-gradient` values."},generateId:{type:"boolean",default:!1,doc:"Whether to generate ids for the geojson features. When enabled, the `feature.id` property will be auto assigned based on its index in the `features` array, over-writing any previous values."},promoteId:{type:"promoteId",doc:"A property to use as a feature id (for feature state). Either a property name, or an object of the form `{<sourceLayer>: <propertyName>}`."}},source_video:{type:{required:!0,type:"enum",values:{video:{doc:"A video data source."}},doc:"The data type of the video source."},urls:{required:!0,type:"array",value:"string",doc:"URLs to video content in order of preferred format."},coordinates:{required:!0,doc:"Corners of video specified in longitude, latitude pairs.",type:"array",length:4,value:{type:"array",length:2,value:"number",doc:"A single longitude, latitude pair."}}},source_image:{type:{required:!0,type:"enum",values:{image:{doc:"An image data source."}},doc:"The data type of the image source."},url:{required:!0,type:"string",doc:"URL that points to an image."},coordinates:{required:!0,doc:"Corners of image specified in longitude, latitude pairs.",type:"array",length:4,value:{type:"array",length:2,value:"number",doc:"A single longitude, latitude pair."}}},layer:{id:{type:"string",doc:"Unique layer name.",required:!0},type:{type:"enum",values:{fill:{doc:"A filled polygon with an optional stroked border.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}}},line:{doc:"A stroked line.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}}},symbol:{doc:"An icon or a text label.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}}},circle:{doc:"A filled circle.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}}},heatmap:{doc:"A heatmap.","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"fill-extrusion":{doc:"An extruded (3D) polygon.","sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}}},raster:{doc:"Raster map textures such as satellite imagery.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}}},hillshade:{doc:"Client-side hillshading visualization based on DEM data. Currently, the implementation only supports Mapbox Terrain RGB and Mapzen Terrarium tiles.","sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},background:{doc:"The background color or pattern of the map.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}}},sky:{doc:"A spherical dome around the map that is always rendered behind all other layers.","sdk-support":{"basic functionality":{js:"2.0.0"}}}},doc:"Rendering type of this layer.",required:!0},metadata:{type:"*",doc:"Arbitrary properties useful to track with the layer, but do not influence rendering. Properties should be prefixed to avoid collisions, like 'mapbox:'."},source:{type:"string",doc:"Name of a source description to be used for this layer. Required for all layer types except `background`."},"source-layer":{type:"string",doc:"Layer to use from a vector tile source. Required for vector tile sources; prohibited for all other source types, including GeoJSON sources."},minzoom:{type:"number",minimum:0,maximum:24,doc:"The minimum zoom level for the layer. At zoom levels less than the minzoom, the layer will be hidden."},maxzoom:{type:"number",minimum:0,maximum:24,doc:"The maximum zoom level for the layer. At zoom levels equal to or greater than the maxzoom, the layer will be hidden."},filter:{type:"filter",doc:"A expression specifying conditions on source features. Only features that match the filter are displayed. Zoom expressions in filters are only evaluated at integer zoom levels. The `feature-state` expression is not supported in filter expressions."},layout:{type:"layout",doc:"Layout properties for the layer."},paint:{type:"paint",doc:"Default paint properties for this layer."}},layout:["layout_fill","layout_line","layout_circle","layout_heatmap","layout_fill-extrusion","layout_symbol","layout_raster","layout_hillshade","layout_background","layout_sky"],layout_background:{visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},"property-type":"constant"}},layout_sky:{visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"2.0.0"}},"property-type":"constant"}},layout_fill:{"fill-sort-key":{type:"number",doc:"Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key.","sdk-support":{"basic functionality":{js:"1.2.0",android:"9.1.0",ios:"5.8.0",macos:"0.15.0"},"data-driven styling":{js:"1.2.0",android:"9.1.0",ios:"5.8.0",macos:"0.15.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},"property-type":"constant"}},layout_circle:{"circle-sort-key":{type:"number",doc:"Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key.","sdk-support":{"basic functionality":{js:"1.2.0",android:"9.2.0",ios:"5.9.0",macos:"0.16.0"},"data-driven styling":{js:"1.2.0",android:"9.2.0",ios:"5.9.0",macos:"0.16.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},"property-type":"constant"}},layout_heatmap:{visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},"property-type":"constant"}},"layout_fill-extrusion":{visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},"property-type":"constant"}},layout_line:{"line-cap":{type:"enum",values:{butt:{doc:"A cap with a squared-off end which is drawn to the exact endpoint of the line."},round:{doc:"A cap with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line."},square:{doc:"A cap with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width."}},default:"butt",doc:"The display of line endings.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"line-join":{type:"enum",values:{bevel:{doc:"A join with a squared-off end which is drawn beyond the endpoint of the line at a distance of one-half of the line's width."},round:{doc:"A join with a rounded end which is drawn beyond the endpoint of the line at a radius of one-half of the line's width and centered on the endpoint of the line."},miter:{doc:"A join with a sharp, angled corner which is drawn with the outer sides beyond the endpoint of the path until they meet."}},default:"miter",doc:"The display of lines when joining.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.40.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"line-miter-limit":{type:"number",default:2,doc:"Used to automatically convert miter joins to bevel joins for sharp angles.",requires:[{"line-join":"miter"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"line-round-limit":{type:"number",default:1.05,doc:"Used to automatically convert round joins to miter joins for shallow angles.",requires:[{"line-join":"round"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"line-sort-key":{type:"number",doc:"Sorts features in ascending order based on this value. Features with a higher sort key will appear above features with a lower sort key.","sdk-support":{"basic functionality":{js:"1.2.0",android:"9.1.0",ios:"5.8.0",macos:"0.15.0"},"data-driven styling":{js:"1.2.0",android:"9.1.0",ios:"5.8.0",macos:"0.15.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},"property-type":"constant"}},layout_symbol:{"symbol-placement":{type:"enum",values:{point:{doc:"The label is placed at the point where the geometry is located."},line:{doc:"The label is placed along the line of the geometry. Can only be used on `LineString` and `Polygon` geometries."},"line-center":{doc:"The label is placed at the center of the line of the geometry. Can only be used on `LineString` and `Polygon` geometries. Note that a single feature in a vector tile may contain multiple line geometries."}},default:"point",doc:"Label placement relative to its geometry.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"`line-center` value":{js:"0.47.0",android:"6.4.0",ios:"4.3.0",macos:"0.10.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"symbol-spacing":{type:"number",default:250,minimum:1,units:"pixels",doc:"Distance between two symbol anchors.",requires:[{"symbol-placement":"line"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"symbol-avoid-edges":{type:"boolean",default:!1,doc:"If true, the symbols will not cross tile edges to avoid mutual collisions. Recommended in layers that don't have enough padding in the vector tile to prevent collisions, or if it is a point symbol layer placed after a line symbol layer. When using a client that supports global collision detection, like Mapbox GL JS version 0.42.0 or greater, enabling this property is not needed to prevent clipped labels at tile boundaries.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"symbol-sort-key":{type:"number",doc:"Sorts features in ascending order based on this value. Features with lower sort keys are drawn and placed first. When `icon-allow-overlap` or `text-allow-overlap` is `false`, features with a lower sort key will have priority during placement. When `icon-allow-overlap` or `text-allow-overlap` is set to `true`, features with a higher sort key will overlap over features with a lower sort key.","sdk-support":{"basic functionality":{js:"0.53.0",android:"7.4.0",ios:"4.11.0",macos:"0.14.0"},"data-driven styling":{js:"0.53.0",android:"7.4.0",ios:"4.11.0",macos:"0.14.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"symbol-z-order":{type:"enum",values:{auto:{doc:"Sorts symbols by `symbol-sort-key` if set. Otherwise, sorts symbols by their y-position relative to the viewport if `icon-allow-overlap` or `text-allow-overlap` is set to `true` or `icon-ignore-placement` or `text-ignore-placement` is `false`."},"viewport-y":{doc:"Sorts symbols by their y-position relative to the viewport if `icon-allow-overlap` or `text-allow-overlap` is set to `true` or `icon-ignore-placement` or `text-ignore-placement` is `false`."},source:{doc:"Sorts symbols by `symbol-sort-key` if set. Otherwise, no sorting is applied; symbols are rendered in the same order as the source data."}},default:"auto",doc:"Determines whether overlapping symbols in the same layer are rendered in the order that they appear in the data source or by their y-position relative to the viewport. To control the order and prioritization of symbols otherwise, use `symbol-sort-key`.","sdk-support":{"basic functionality":{js:"0.49.0",android:"6.6.0",ios:"4.5.0",macos:"0.12.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"icon-allow-overlap":{type:"boolean",default:!1,doc:"If true, the icon will be visible even if it collides with other previously drawn symbols.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"icon-ignore-placement":{type:"boolean",default:!1,doc:"If true, other symbols can be visible even if they collide with the icon.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"icon-optional":{type:"boolean",default:!1,doc:"If true, text will display without their corresponding icons when the icon collides with other symbols and the text does not.",requires:["icon-image","text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"icon-rotation-alignment":{type:"enum",values:{map:{doc:"When `symbol-placement` is set to `point`, aligns icons east-west. When `symbol-placement` is set to `line` or `line-center`, aligns icon x-axes with the line."},viewport:{doc:"Produces icons whose x-axes are aligned with the x-axis of the viewport, regardless of the value of `symbol-placement`."},auto:{doc:"When `symbol-placement` is set to `point`, this is equivalent to `viewport`. When `symbol-placement` is set to `line` or `line-center`, this is equivalent to `map`."}},default:"auto",doc:"In combination with `symbol-placement`, determines the rotation behavior of icons.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"`auto` value":{js:"0.25.0",android:"4.2.0",ios:"3.4.0",macos:"0.3.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"icon-size":{type:"number",default:1,minimum:0,units:"factor of the original icon size",doc:"Scales the original size of the icon by the provided factor. The new pixel size of the image will be the original pixel size multiplied by `icon-size`. 1 is the original size; 3 triples the size of the image.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.35.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"icon-text-fit":{type:"enum",values:{none:{doc:"The icon is displayed at its intrinsic aspect ratio."},width:{doc:"The icon is scaled in the x-dimension to fit the width of the text."},height:{doc:"The icon is scaled in the y-dimension to fit the height of the text."},both:{doc:"The icon is scaled in both x- and y-dimensions."}},default:"none",doc:"Scales the icon to fit around the associated text.",requires:["icon-image","text-field"],"sdk-support":{"basic functionality":{js:"0.21.0",android:"4.2.0",ios:"3.4.0",macos:"0.2.1"},"stretchable icons":{js:"1.6.0",android:"9.2.0",ios:"5.8.0",macos:"0.15.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"icon-text-fit-padding":{type:"array",value:"number",length:4,default:[0,0,0,0],units:"pixels",doc:"Size of the additional area added to dimensions determined by `icon-text-fit`, in clockwise order: top, right, bottom, left.",requires:["icon-image","text-field",{"icon-text-fit":["both","width","height"]}],"sdk-support":{"basic functionality":{js:"0.21.0",android:"4.2.0",ios:"3.4.0",macos:"0.2.1"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"icon-image":{type:"resolvedImage",doc:"Name of image in sprite to use for drawing an image background.",tokens:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.35.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"icon-rotate":{type:"number",default:0,period:360,units:"degrees",doc:"Rotates the icon clockwise.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.21.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"icon-padding":{type:"number",default:2,minimum:0,units:"pixels",doc:"Size of the additional area around the icon bounding box used for detecting symbol collisions.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"icon-keep-upright":{type:"boolean",default:!1,doc:"If true, the icon may be flipped to prevent it from being rendered upside-down.",requires:["icon-image",{"icon-rotation-alignment":"map"},{"symbol-placement":["line","line-center"]}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"icon-offset":{type:"array",value:"number",length:2,default:[0,0],doc:"Offset distance of icon from its anchor. Positive values indicate right and down, while negative values indicate left and up. Each component is multiplied by the value of `icon-size` to obtain the final offset in pixels. When combined with `icon-rotate` the offset will be as if the rotated direction was up.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"icon-anchor":{type:"enum",values:{center:{doc:"The center of the icon is placed closest to the anchor."},left:{doc:"The left side of the icon is placed closest to the anchor."},right:{doc:"The right side of the icon is placed closest to the anchor."},top:{doc:"The top of the icon is placed closest to the anchor."},bottom:{doc:"The bottom of the icon is placed closest to the anchor."},"top-left":{doc:"The top left corner of the icon is placed closest to the anchor."},"top-right":{doc:"The top right corner of the icon is placed closest to the anchor."},"bottom-left":{doc:"The bottom left corner of the icon is placed closest to the anchor."},"bottom-right":{doc:"The bottom right corner of the icon is placed closest to the anchor."}},default:"center",doc:"Part of the icon placed closest to the anchor.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.40.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"},"data-driven styling":{js:"0.40.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"icon-pitch-alignment":{type:"enum",values:{map:{doc:"The icon is aligned to the plane of the map."},viewport:{doc:"The icon is aligned to the plane of the viewport."},auto:{doc:"Automatically matches the value of `icon-rotation-alignment`."}},default:"auto",doc:"Orientation of icon when map is pitched.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.39.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-pitch-alignment":{type:"enum",values:{map:{doc:"The text is aligned to the plane of the map."},viewport:{doc:"The text is aligned to the plane of the viewport."},auto:{doc:"Automatically matches the value of `text-rotation-alignment`."}},default:"auto",doc:"Orientation of text when map is pitched.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.21.0",android:"4.2.0",ios:"3.4.0",macos:"0.2.1"},"`auto` value":{js:"0.25.0",android:"4.2.0",ios:"3.4.0",macos:"0.3.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-rotation-alignment":{type:"enum",values:{map:{doc:"When `symbol-placement` is set to `point`, aligns text east-west. When `symbol-placement` is set to `line` or `line-center`, aligns text x-axes with the line."},viewport:{doc:"Produces glyphs whose x-axes are aligned with the x-axis of the viewport, regardless of the value of `symbol-placement`."},auto:{doc:"When `symbol-placement` is set to `point`, this is equivalent to `viewport`. When `symbol-placement` is set to `line` or `line-center`, this is equivalent to `map`."}},default:"auto",doc:"In combination with `symbol-placement`, determines the rotation behavior of the individual glyphs forming the text.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"`auto` value":{js:"0.25.0",android:"4.2.0",ios:"3.4.0",macos:"0.3.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-field":{type:"formatted",default:"",tokens:!0,doc:"Value to use for a text label. If a plain `string` is provided, it will be treated as a `formatted` with default/inherited formatting options.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-font":{type:"array",value:"string",default:["Open Sans Regular","Arial Unicode MS Regular"],doc:"Font stack to use for displaying text.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-size":{type:"number",default:16,minimum:0,units:"pixels",doc:"Font size.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.35.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-max-width":{type:"number",default:10,minimum:0,units:"ems",doc:"The maximum line width for text wrapping.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.40.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-line-height":{type:"number",default:1.2,units:"ems",doc:"Text leading value for multi-line text.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"text-letter-spacing":{type:"number",default:0,units:"ems",doc:"Text tracking amount.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.40.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-justify":{type:"enum",values:{auto:{doc:"The text is aligned towards the anchor position."},left:{doc:"The text is aligned to the left."},center:{doc:"The text is centered."},right:{doc:"The text is aligned to the right."}},default:"center",doc:"Text justification options.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.39.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"},auto:{js:"0.54.0",android:"7.4.0",ios:"4.10.0",macos:"0.14.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-radial-offset":{type:"number",units:"ems",default:0,doc:"Radial offset of text, in the direction of the symbol's anchor. Useful in combination with `text-variable-anchor`, which defaults to using the two-dimensional `text-offset` if present.","sdk-support":{"basic functionality":{js:"0.54.0",android:"7.4.0",ios:"4.10.0",macos:"0.14.0"},"data-driven styling":{js:"0.54.0",android:"7.4.0",ios:"4.10.0",macos:"0.14.0"}},requires:["text-field"],"property-type":"data-driven",expression:{interpolated:!0,parameters:["zoom","feature"]}},"text-variable-anchor":{type:"array",value:"enum",values:{center:{doc:"The center of the text is placed closest to the anchor."},left:{doc:"The left side of the text is placed closest to the anchor."},right:{doc:"The right side of the text is placed closest to the anchor."},top:{doc:"The top of the text is placed closest to the anchor."},bottom:{doc:"The bottom of the text is placed closest to the anchor."},"top-left":{doc:"The top left corner of the text is placed closest to the anchor."},"top-right":{doc:"The top right corner of the text is placed closest to the anchor."},"bottom-left":{doc:"The bottom left corner of the text is placed closest to the anchor."},"bottom-right":{doc:"The bottom right corner of the text is placed closest to the anchor."}},requires:["text-field",{"symbol-placement":["point"]}],doc:"To increase the chance of placing high-priority labels on the map, you can provide an array of `text-anchor` locations: the renderer will attempt to place the label at each location, in order, before moving onto the next label. Use `text-justify: auto` to choose justification based on anchor position. To apply an offset, use the `text-radial-offset` or the two-dimensional `text-offset`.","sdk-support":{"basic functionality":{js:"0.54.0",android:"7.4.0",ios:"4.10.0",macos:"0.14.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-anchor":{type:"enum",values:{center:{doc:"The center of the text is placed closest to the anchor."},left:{doc:"The left side of the text is placed closest to the anchor."},right:{doc:"The right side of the text is placed closest to the anchor."},top:{doc:"The top of the text is placed closest to the anchor."},bottom:{doc:"The bottom of the text is placed closest to the anchor."},"top-left":{doc:"The top left corner of the text is placed closest to the anchor."},"top-right":{doc:"The top right corner of the text is placed closest to the anchor."},"bottom-left":{doc:"The bottom left corner of the text is placed closest to the anchor."},"bottom-right":{doc:"The bottom right corner of the text is placed closest to the anchor."}},default:"center",doc:"Part of the text placed closest to the anchor.",requires:["text-field",{"!":"text-variable-anchor"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.39.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-max-angle":{type:"number",default:45,units:"degrees",doc:"Maximum angle change between adjacent characters.",requires:["text-field",{"symbol-placement":["line","line-center"]}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"text-writing-mode":{type:"array",value:"enum",values:{horizontal:{doc:"If a text's language supports horizontal writing mode, symbols with point placement would be laid out horizontally."},vertical:{doc:"If a text's language supports vertical writing mode, symbols with point placement would be laid out vertically."}},doc:"The property allows control over a symbol's orientation. Note that the property values act as a hint, so that a symbol whose language doesn’t support the provided orientation will be laid out in its natural orientation. Example: English point symbol will be rendered horizontally even if array value contains single 'vertical' enum value. The order of elements in an array define priority order for the placement of an orientation variant.",requires:["text-field",{"symbol-placement":["point"]}],"sdk-support":{"basic functionality":{js:"1.3.0",android:"8.3.0",ios:"5.3.0",macos:"0.15.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-rotate":{type:"number",default:0,period:360,units:"degrees",doc:"Rotates the text clockwise.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.35.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-padding":{type:"number",default:2,minimum:0,units:"pixels",doc:"Size of the additional area around the text bounding box used for detecting symbol collisions.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"text-keep-upright":{type:"boolean",default:!0,doc:"If true, the text may be flipped vertically to prevent it from being rendered upside-down.",requires:["text-field",{"text-rotation-alignment":"map"},{"symbol-placement":["line","line-center"]}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-transform":{type:"enum",values:{none:{doc:"The text is not altered."},uppercase:{doc:"Forces all letters to be displayed in uppercase."},lowercase:{doc:"Forces all letters to be displayed in lowercase."}},default:"none",doc:"Specifies how to capitalize text, similar to the CSS `text-transform` property.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-offset":{type:"array",doc:"Offset distance of text from its anchor. Positive values indicate right and down, while negative values indicate left and up. If used with text-variable-anchor, input values will be taken as absolute values. Offsets along the x- and y-axis will be applied automatically based on the anchor position.",value:"number",units:"ems",length:2,default:[0,0],requires:["text-field",{"!":"text-radial-offset"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.35.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom","feature"]},"property-type":"data-driven"},"text-allow-overlap":{type:"boolean",default:!1,doc:"If true, the text will be visible even if it collides with other previously drawn symbols.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-ignore-placement":{type:"boolean",default:!1,doc:"If true, other symbols can be visible even if they collide with the text.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-optional":{type:"boolean",default:!1,doc:"If true, icons will display without their corresponding text when the text collides with other symbols and the icon does not.",requires:["text-field","icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},"property-type":"constant"}},layout_raster:{visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},"property-type":"constant"}},layout_hillshade:{visibility:{type:"enum",values:{visible:{doc:"The layer is shown."},none:{doc:"The layer is not shown."}},default:"visible",doc:"Whether this layer is displayed.","sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},"property-type":"constant"}},filter:{type:"array",value:"*",doc:"A filter selects specific features from a layer."},filter_operator:{type:"enum",values:{"==":{doc:'`["==", key, value]` equality: `feature[key] = value`'},"!=":{doc:'`["!=", key, value]` inequality: `feature[key] ≠ value`'},">":{doc:'`[">", key, value]` greater than: `feature[key] > value`'},">=":{doc:'`[">=", key, value]` greater than or equal: `feature[key] ≥ value`'},"<":{doc:'`["<", key, value]` less than: `feature[key] < value`'},"<=":{doc:'`["<=", key, value]` less than or equal: `feature[key] ≤ value`'},in:{doc:'`["in", key, v0, ..., vn]` set inclusion: `feature[key] ∈ {v0, ..., vn}`'},"!in":{doc:'`["!in", key, v0, ..., vn]` set exclusion: `feature[key] ∉ {v0, ..., vn}`'},all:{doc:'`["all", f0, ..., fn]` logical `AND`: `f0 ∧ ... ∧ fn`'},any:{doc:'`["any", f0, ..., fn]` logical `OR`: `f0 ∨ ... ∨ fn`'},none:{doc:'`["none", f0, ..., fn]` logical `NOR`: `¬f0 ∧ ... ∧ ¬fn`'},has:{doc:'`["has", key]` `feature[key]` exists'},"!has":{doc:'`["!has", key]` `feature[key]` does not exist'},within:{doc:'`["within", object]` feature geometry is within object geometry'}},doc:"The filter operator."},geometry_type:{type:"enum",values:{Point:{doc:"Filter to point geometries."},LineString:{doc:"Filter to line geometries."},Polygon:{doc:"Filter to polygon geometries."}},doc:"The geometry type for the filter to select."},function:{expression:{type:"expression",doc:"An expression."},stops:{type:"array",doc:"An array of stops.",value:"function_stop"},base:{type:"number",default:1,minimum:0,doc:"The exponential base of the interpolation curve. It controls the rate at which the result increases. Higher values make the result increase more towards the high end of the range. With `1` the stops are interpolated linearly."},property:{type:"string",doc:"The name of a feature property to use as the function input.",default:"$zoom"},type:{type:"enum",values:{identity:{doc:"Return the input value as the output value."},exponential:{doc:"Generate an output by interpolating between stops just less than and just greater than the function input."},interval:{doc:"Return the output value of the stop just less than the function input."},categorical:{doc:"Return the output value of the stop equal to the function input."}},doc:"The interpolation strategy to use in function evaluation.",default:"exponential"},colorSpace:{type:"enum",values:{rgb:{doc:"Use the RGB color space to interpolate color values"},lab:{doc:"Use the LAB color space to interpolate color values."},hcl:{doc:"Use the HCL color space to interpolate color values, interpolating the Hue, Chroma, and Luminance channels individually."}},doc:"The color space in which colors interpolated. Interpolating colors in perceptual color spaces like LAB and HCL tend to produce color ramps that look more consistent and produce colors that can be differentiated more easily than those interpolated in RGB space.",default:"rgb"},default:{type:"*",required:!1,doc:"A value to serve as a fallback function result when a value isn't otherwise available. It is used in the following circumstances:\n* In categorical functions, when the feature value does not match any of the stop domain values.\n* In property and zoom-and-property functions, when a feature does not contain a value for the specified property.\n* In identity functions, when the feature value is not valid for the style property (for example, if the function is being used for a `circle-color` property but the feature property value is not a string or not a valid color).\n* In interval or exponential property and zoom-and-property functions, when the feature value is not numeric.\nIf no default is provided, the style property's default is used in these circumstances."}},function_stop:{type:"array",minimum:0,maximum:24,value:["number","color"],length:2,doc:"Zoom level and value pair."},expression:{type:"array",value:"*",minimum:1,doc:"An expression defines a function that can be used for data-driven style properties or feature filters."},expression_name:{doc:"",type:"enum",values:{let:{doc:'Binds expressions to named variables, which can then be referenced in the result expression using ["var", "variable_name"].',group:"Variable binding","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},var:{doc:'References variable bound using "let".',group:"Variable binding","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},literal:{doc:"Provides a literal array or object value.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},array:{doc:"Asserts that the input is an array (optionally with a specific item type and length). If, when the input expression is evaluated, it is not of the asserted type, then this assertion will cause the whole expression to be aborted.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},at:{doc:"Retrieves an item from an array.",group:"Lookup","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},in:{doc:"Determines whether an item exists in an array or a substring exists in a string.",group:"Lookup","sdk-support":{"basic functionality":{js:"1.6.0",android:"9.1.0",ios:"5.8.0",macos:"0.15.0"}}},"index-of":{doc:"Returns the first position at which an item can be found in an array or a substring can be found in a string, or `-1` if the input cannot be found. Accepts an optional index from where to begin the search.",group:"Lookup","sdk-support":{"basic functionality":{js:"1.10.0"}}},slice:{doc:"Returns an item from an array or a substring from a string from a specified start index, or between a start index and an end index if set. The return value is inclusive of the start index but not of the end index.",group:"Lookup","sdk-support":{"basic functionality":{js:"1.10.0"}}},case:{doc:"Selects the first output whose corresponding test condition evaluates to true, or the fallback value otherwise.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},match:{doc:'Selects the output whose label value matches the input value, or the fallback value if no match is found. The input can be any expression (e.g. `["get", "building_type"]`). Each label must be either:\n - a single literal value; or\n - an array of literal values, whose values must be all strings or all numbers (e.g. `[100, 101]` or `["c", "b"]`). The input matches if any of the values in the array matches, similar to the `"in"` operator.\nEach label must be unique. If the input type does not match the type of the labels, the result will be the fallback value.',group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},coalesce:{doc:"Evaluates each expression in turn until the first non-null value is obtained, and returns that value.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},step:{doc:'Produces discrete, stepped results by evaluating a piecewise-constant function defined by pairs of input and output values ("stops"). The `input` may be any numeric expression (e.g., `["get", "population"]`). Stop inputs must be numeric literals in strictly ascending order. Returns the output value of the stop just less than the input, or the first output if the input is less than the first stop.',group:"Ramps, scales, curves","sdk-support":{"basic functionality":{js:"0.42.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},interpolate:{doc:'Produces continuous, smooth results by interpolating between pairs of input and output values ("stops"). The `input` may be any numeric expression (e.g., `["get", "population"]`). Stop inputs must be numeric literals in strictly ascending order. The output type must be `number`, `array<number>`, or `color`.\n\nInterpolation types:\n- `["linear"]`: Interpolates linearly between the pair of stops just less than and just greater than the input.\n- `["exponential", base]`: Interpolates exponentially between the stops just less than and just greater than the input. `base` controls the rate at which the output increases: higher values make the output increase more towards the high end of the range. With values close to 1 the output increases linearly.\n- `["cubic-bezier", x1, y1, x2, y2]`: Interpolates using the cubic bezier curve defined by the given control points.',group:"Ramps, scales, curves","sdk-support":{"basic functionality":{js:"0.42.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"interpolate-hcl":{doc:'Produces continuous, smooth results by interpolating between pairs of input and output values ("stops"). Works like `interpolate`, but the output type must be `color`, and the interpolation is performed in the Hue-Chroma-Luminance color space.',group:"Ramps, scales, curves","sdk-support":{"basic functionality":{js:"0.49.0"}}},"interpolate-lab":{doc:'Produces continuous, smooth results by interpolating between pairs of input and output values ("stops"). Works like `interpolate`, but the output type must be `color`, and the interpolation is performed in the CIELAB color space.',group:"Ramps, scales, curves","sdk-support":{"basic functionality":{js:"0.49.0"}}},ln2:{doc:"Returns mathematical constant ln(2).",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},pi:{doc:"Returns the mathematical constant pi.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},e:{doc:"Returns the mathematical constant e.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},typeof:{doc:"Returns a string describing the type of the given value.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},string:{doc:"Asserts that the input value is a string. If multiple values are provided, each one is evaluated in order until a string is obtained. If none of the inputs are strings, the expression is an error.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},number:{doc:"Asserts that the input value is a number. If multiple values are provided, each one is evaluated in order until a number is obtained. If none of the inputs are numbers, the expression is an error.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},boolean:{doc:"Asserts that the input value is a boolean. If multiple values are provided, each one is evaluated in order until a boolean is obtained. If none of the inputs are booleans, the expression is an error.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},object:{doc:"Asserts that the input value is an object. If multiple values are provided, each one is evaluated in order until an object is obtained. If none of the inputs are objects, the expression is an error.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},collator:{doc:"Returns a `collator` for use in locale-dependent comparison operations. The `case-sensitive` and `diacritic-sensitive` options default to `false`. The `locale` argument specifies the IETF language tag of the locale to use. If none is provided, the default locale is used. If the requested locale is not available, the `collator` will use a system-defined fallback locale. Use `resolved-locale` to test the results of locale fallback behavior.",group:"Types","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}},format:{doc:'Returns a `formatted` string for displaying mixed-format text in the `text-field` property. The input may contain a string literal or expression, including an [`\'image\'`](#types-image) expression. Strings may be followed by a style override object that supports the following properties:\n- `"text-font"`: Overrides the font stack specified by the root layout property.\n- `"text-color"`: Overrides the color specified by the root paint property.\n- `"font-scale"`: Applies a scaling factor on `text-size` as specified by the root layout property.',group:"Types","sdk-support":{"basic functionality":{js:"0.48.0",android:"6.7.0",ios:"4.6.0",macos:"0.12.0"},"text-font":{js:"0.48.0",android:"6.7.0",ios:"4.6.0",macos:"0.12.0"},"font-scale":{js:"0.48.0",android:"6.7.0",ios:"4.6.0",macos:"0.12.0"},"text-color":{js:"1.3.0",android:"7.3.0",ios:"4.10.0",macos:"0.14.0"},image:{js:"1.6.0",android:"8.6.0",ios:"5.7.0",macos:"0.15.0"}}},image:{doc:"Returns an `image` type for use in `icon-image`, `*-pattern` entries and as a section in the `format` expression. If set, the `image` argument will check that the requested image exists in the style and will return either the resolved image name or `null`, depending on whether or not the image is currently in the style. This validation process is synchronous and requires the image to have been added to the style before requesting it in the `image` argument.",group:"Types","sdk-support":{"basic functionality":{js:"1.4.0",android:"8.6.0",ios:"5.7.0",macos:"0.15.0"}}},"number-format":{doc:"Converts the input number into a string representation using the providing formatting rules. If set, the `locale` argument specifies the locale to use, as a BCP 47 language tag. If set, the `currency` argument specifies an ISO 4217 code to use for currency-style formatting. If set, the `min-fraction-digits` and `max-fraction-digits` arguments specify the minimum and maximum number of fractional digits to include.",group:"Types","sdk-support":{"basic functionality":{js:"0.54.0"}}},"to-string":{doc:'Converts the input value to a string. If the input is `null`, the result is `""`. If the input is a boolean, the result is `"true"` or `"false"`. If the input is a number, it is converted to a string as specified by the ["NumberToString" algorithm](https://tc39.github.io/ecma262/#sec-tostring-applied-to-the-number-type) of the ECMAScript Language Specification. If the input is a color, it is converted to a string of the form `"rgba(r,g,b,a)"`, where `r`, `g`, and `b` are numerals ranging from 0 to 255, and `a` ranges from 0 to 1. Otherwise, the input is converted to a string in the format specified by the [`JSON.stringify`](https://tc39.github.io/ecma262/#sec-json.stringify) function of the ECMAScript Language Specification.',group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"to-number":{doc:'Converts the input value to a number, if possible. If the input is `null` or `false`, the result is 0. If the input is `true`, the result is 1. If the input is a string, it is converted to a number as specified by the ["ToNumber Applied to the String Type" algorithm](https://tc39.github.io/ecma262/#sec-tonumber-applied-to-the-string-type) of the ECMAScript Language Specification. If multiple values are provided, each one is evaluated in order until the first successful conversion is obtained. If none of the inputs can be converted, the expression is an error.',group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"to-boolean":{doc:"Converts the input value to a boolean. The result is `false` when then input is an empty string, 0, `false`, `null`, or `NaN`; otherwise it is `true`.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"to-rgba":{doc:"Returns a four-element array containing the input color's red, green, blue, and alpha components, in that order.",group:"Color","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"to-color":{doc:"Converts the input value to a color. If multiple values are provided, each one is evaluated in order until the first successful conversion is obtained. If none of the inputs can be converted, the expression is an error.",group:"Types","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},rgb:{doc:"Creates a color value from red, green, and blue components, which must range between 0 and 255, and an alpha component of 1. If any component is out of range, the expression is an error.",group:"Color","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},rgba:{doc:"Creates a color value from red, green, blue components, which must range between 0 and 255, and an alpha component which must range between 0 and 1. If any component is out of range, the expression is an error.",group:"Color","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},get:{doc:"Retrieves a property value from the current feature's properties, or from another object if a second argument is provided. Returns null if the requested property is missing.",group:"Lookup","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},has:{doc:"Tests for the presence of an property value in the current feature's properties, or from another object if a second argument is provided.",group:"Lookup","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},length:{doc:"Gets the length of an array or string.",group:"Lookup","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},properties:{doc:'Gets the feature properties object. Note that in some cases, it may be more efficient to use ["get", "property_name"] directly.',group:"Feature data","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"feature-state":{doc:"Retrieves a property value from the current feature's state. Returns null if the requested property is not present on the feature's state. A feature's state is not part of the GeoJSON or vector tile data, and must be set programmatically on each feature. Features are identified by their `id` attribute, which must be an integer or a string that can be cast to an integer. Note that [\"feature-state\"] can only be used with paint properties that support data-driven styling.",group:"Feature data","sdk-support":{"basic functionality":{js:"0.46.0"}}},"geometry-type":{doc:"Gets the feature's geometry type: `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`.",group:"Feature data","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},id:{doc:"Gets the feature's id, if it has one.",group:"Feature data","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},zoom:{doc:'Gets the current zoom level. Note that in style layout and paint properties, ["zoom"] may only appear as the input to a top-level "step" or "interpolate" expression.',group:"Zoom","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"heatmap-density":{doc:"Gets the kernel density estimation of a pixel in a heatmap layer, which is a relative measure of how many data points are crowded around a particular pixel. Can only be used in the `heatmap-color` property.",group:"Heatmap","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"line-progress":{doc:"Gets the progress along a gradient line. Can only be used in the `line-gradient` property.",group:"Feature data","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.5.0",ios:"4.6.0",macos:"0.12.0"}}},"sky-radial-progress":{doc:"Gets the distance of a point on the sky from the sun position. Returns 0 at sun position and 1 when the distance reaches `sky-gradient-radius`. Can only be used in the `sky-gradient` property.",group:"sky","sdk-support":{"basic functionality":{js:"2.0.0"}}},accumulated:{doc:"Gets the value of a cluster property accumulated so far. Can only be used in the `clusterProperties` option of a clustered GeoJSON source.",group:"Feature data","sdk-support":{"basic functionality":{js:"0.53.0"}}},"+":{doc:"Returns the sum of the inputs.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"*":{doc:"Returns the product of the inputs.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"-":{doc:"For two inputs, returns the result of subtracting the second input from the first. For a single input, returns the result of subtracting it from 0.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"/":{doc:"Returns the result of floating point division of the first input by the second.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"%":{doc:"Returns the remainder after integer division of the first input by the second.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"^":{doc:"Returns the result of raising the first input to the power specified by the second.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},sqrt:{doc:"Returns the square root of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.42.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},log10:{doc:"Returns the base-ten logarithm of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},ln:{doc:"Returns the natural logarithm of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},log2:{doc:"Returns the base-two logarithm of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},sin:{doc:"Returns the sine of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},cos:{doc:"Returns the cosine of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},tan:{doc:"Returns the tangent of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},asin:{doc:"Returns the arcsine of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},acos:{doc:"Returns the arccosine of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},atan:{doc:"Returns the arctangent of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},min:{doc:"Returns the minimum value of the inputs.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},max:{doc:"Returns the maximum value of the inputs.",group:"Math","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},round:{doc:'Rounds the input to the nearest integer. Halfway values are rounded away from zero. For example, `["round", -1.5]` evaluates to -2.',group:"Math","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},abs:{doc:"Returns the absolute value of the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},ceil:{doc:"Returns the smallest integer that is greater than or equal to the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},floor:{doc:"Returns the largest integer that is less than or equal to the input.",group:"Math","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},distance:{doc:"Returns the shortest distance in meters between the evaluated feature and the input geometry. The input value can be a valid GeoJSON of type `Point`, `MultiPoint`, `LineString`, `MultiLineString`, `Polygon`, `MultiPolygon`, `Feature`, or `FeatureCollection`. Distance values returned may vary in precision due to loss in precision from encoding geometries, particularly below zoom level 13.",group:"Math","sdk-support":{"basic functionality":{android:"9.2.0",ios:"5.9.0",macos:"0.16.0"}}},"==":{doc:"Returns `true` if the input values are equal, `false` otherwise. The comparison is strictly typed: values of different runtime types are always considered unequal. Cases where the types are known to be different at parse time are considered invalid and will produce a parse error. Accepts an optional `collator` argument to control locale-dependent string comparisons.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},collator:{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}},"!=":{doc:"Returns `true` if the input values are not equal, `false` otherwise. The comparison is strictly typed: values of different runtime types are always considered unequal. Cases where the types are known to be different at parse time are considered invalid and will produce a parse error. Accepts an optional `collator` argument to control locale-dependent string comparisons.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},collator:{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}},">":{doc:"Returns `true` if the first input is strictly greater than the second, `false` otherwise. The arguments are required to be either both strings or both numbers; if during evaluation they are not, expression evaluation produces an error. Cases where this constraint is known not to hold at parse time are considered in valid and will produce a parse error. Accepts an optional `collator` argument to control locale-dependent string comparisons.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},collator:{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}},"<":{doc:"Returns `true` if the first input is strictly less than the second, `false` otherwise. The arguments are required to be either both strings or both numbers; if during evaluation they are not, expression evaluation produces an error. Cases where this constraint is known not to hold at parse time are considered in valid and will produce a parse error. Accepts an optional `collator` argument to control locale-dependent string comparisons.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},collator:{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}},">=":{doc:"Returns `true` if the first input is greater than or equal to the second, `false` otherwise. The arguments are required to be either both strings or both numbers; if during evaluation they are not, expression evaluation produces an error. Cases where this constraint is known not to hold at parse time are considered in valid and will produce a parse error. Accepts an optional `collator` argument to control locale-dependent string comparisons.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},collator:{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}},"<=":{doc:"Returns `true` if the first input is less than or equal to the second, `false` otherwise. The arguments are required to be either both strings or both numbers; if during evaluation they are not, expression evaluation produces an error. Cases where this constraint is known not to hold at parse time are considered in valid and will produce a parse error. Accepts an optional `collator` argument to control locale-dependent string comparisons.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},collator:{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}},all:{doc:"Returns `true` if all the inputs are `true`, `false` otherwise. The inputs are evaluated in order, and evaluation is short-circuiting: once an input expression evaluates to `false`, the result is `false` and no further input expressions are evaluated.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},any:{doc:"Returns `true` if any of the inputs are `true`, `false` otherwise. The inputs are evaluated in order, and evaluation is short-circuiting: once an input expression evaluates to `true`, the result is `true` and no further input expressions are evaluated.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"!":{doc:"Logical negation. Returns `true` if the input is `false`, and `false` if the input is `true`.",group:"Decision","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},within:{doc:"Returns `true` if the evaluated feature is fully contained inside a boundary of the input geometry, `false` otherwise. The input value can be a valid GeoJSON of type `Polygon`, `MultiPolygon`, `Feature`, or `FeatureCollection`. Supported features for evaluation:\n- `Point`: Returns `false` if a point is on the boundary or falls outside the boundary.\n- `LineString`: Returns `false` if any part of a line falls outside the boundary, the line intersects the boundary, or a line's endpoint is on the boundary.",group:"Decision","sdk-support":{"basic functionality":{js:"1.9.0",android:"9.1.0",ios:"5.8.0",macos:"0.15.0"}}},"is-supported-script":{doc:"Returns `true` if the input string is expected to render legibly. Returns `false` if the input string contains sections that cannot be rendered without potential loss of meaning (e.g. Indic scripts that require complex text shaping, or right-to-left scripts if the the `mapbox-gl-rtl-text` plugin is not in use in Mapbox GL JS).",group:"String","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.6.0"}}},upcase:{doc:"Returns the input string converted to uppercase. Follows the Unicode Default Case Conversion algorithm and the locale-insensitive case mappings in the Unicode Character Database.",group:"String","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},downcase:{doc:"Returns the input string converted to lowercase. Follows the Unicode Default Case Conversion algorithm and the locale-insensitive case mappings in the Unicode Character Database.",group:"String","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},concat:{doc:"Returns a `string` consisting of the concatenation of the inputs. Each input is converted to a string as if by `to-string`.",group:"String","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}}},"resolved-locale":{doc:"Returns the IETF language tag of the locale being used by the provided `collator`. This can be used to determine the default system locale, or to determine if a requested locale was successfully loaded.",group:"String","sdk-support":{"basic functionality":{js:"0.45.0",android:"6.5.0",ios:"4.2.0",macos:"0.9.0"}}}}},light:{anchor:{type:"enum",default:"viewport",values:{map:{doc:"The position of the light source is aligned to the rotation of the map."},viewport:{doc:"The position of the light source is aligned to the rotation of the viewport."}},"property-type":"data-constant",transition:!1,expression:{interpolated:!1,parameters:["zoom"]},doc:"Whether extruded geometries are lit relative to the map or viewport.",example:"map","sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}}},position:{type:"array",default:[1.15,210,30],length:3,value:"number","property-type":"data-constant",transition:!0,expression:{interpolated:!0,parameters:["zoom"]},doc:"Position of the light source relative to lit (extruded) geometries, in [r radial coordinate, a azimuthal angle, p polar angle] where r indicates the distance from the center of the base of an object to its light, a indicates the position of the light relative to 0° (0° when `light.anchor` is set to `viewport` corresponds to the top of the viewport, or 0° when `light.anchor` is set to `map` corresponds to due north, and degrees proceed clockwise), and p indicates the height of the light (from 0°, directly above, to 180°, directly below).",example:[1.5,90,80],"sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}}},color:{type:"color","property-type":"data-constant",default:"#ffffff",expression:{interpolated:!0,parameters:["zoom"]},transition:!0,doc:"Color tint for lighting extruded geometries.","sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}}},intensity:{type:"number","property-type":"data-constant",default:.5,minimum:0,maximum:1,expression:{interpolated:!0,parameters:["zoom"]},transition:!0,doc:"Intensity of lighting (on a scale from 0 to 1). Higher numbers will present as more extreme contrast.","sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}}}},terrain:{source:{type:"string",doc:"Name of a source of `raster_dem` type to be used for terrain elevation.",required:!0},exaggeration:{type:"number","property-type":"data-constant",default:1,minimum:0,maximum:1e3,expression:{interpolated:!0,parameters:["zoom"]},transition:!0,doc:"Exaggerates the elevation of the terrain by multiplying the data from the DEM with this value.","sdk-support":{"basic functionality":{js:"2.0.0"}}}},paint:["paint_fill","paint_line","paint_circle","paint_heatmap","paint_fill-extrusion","paint_symbol","paint_raster","paint_hillshade","paint_background","paint_sky"],paint_fill:{"fill-antialias":{type:"boolean",default:!0,doc:"Whether or not the fill should be antialiased.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"fill-opacity":{type:"number",default:1,minimum:0,maximum:1,doc:"The opacity of the entire fill layer. In contrast to the `fill-color`, this value will also affect the 1px stroke around the fill, if the stroke is used.",transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.21.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-color":{type:"color",default:"#000000",doc:"The color of the filled part of this layer. This color can be specified as `rgba` with an alpha component and the color's opacity will not affect the opacity of the 1px stroke, if it is used.",transition:!0,requires:[{"!":"fill-pattern"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.19.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-outline-color":{type:"color",doc:"The outline color of the fill. Matches the value of `fill-color` if unspecified.",transition:!0,requires:[{"!":"fill-pattern"},{"fill-antialias":!0}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.19.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-translate":{type:"array",value:"number",length:2,default:[0,0],transition:!0,units:"pixels",doc:"The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"fill-translate-anchor":{type:"enum",values:{map:{doc:"The fill is translated relative to the map."},viewport:{doc:"The fill is translated relative to the viewport."}},doc:"Controls the frame of reference for `fill-translate`.",default:"map",requires:["fill-translate"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"fill-pattern":{type:"resolvedImage",transition:!0,doc:"Name of image in sprite to use for drawing image fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.49.0",android:"6.5.0",macos:"0.11.0",ios:"4.4.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"cross-faded-data-driven"}},"paint_fill-extrusion":{"fill-extrusion-opacity":{type:"number",default:1,minimum:0,maximum:1,doc:"The opacity of the entire fill extrusion layer. This is rendered on a per-layer, not per-feature, basis, and data-driven styling is not available.",transition:!0,"sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"fill-extrusion-color":{type:"color",default:"#000000",doc:"The base color of the extruded fill. The extrusion's surfaces will be shaded differently based on this color in combination with the root `light` settings. If this color is specified as `rgba` with an alpha component, the alpha component will be ignored; use `fill-extrusion-opacity` to set layer opacity.",transition:!0,requires:[{"!":"fill-extrusion-pattern"}],"sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"},"data-driven styling":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-translate":{type:"array",value:"number",length:2,default:[0,0],transition:!0,units:"pixels",doc:"The geometry's offset. Values are [x, y] where negatives indicate left and up (on the flat plane), respectively.","sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"fill-extrusion-translate-anchor":{type:"enum",values:{map:{doc:"The fill extrusion is translated relative to the map."},viewport:{doc:"The fill extrusion is translated relative to the viewport."}},doc:"Controls the frame of reference for `fill-extrusion-translate`.",default:"map",requires:["fill-extrusion-translate"],"sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"fill-extrusion-pattern":{type:"resolvedImage",transition:!0,doc:"Name of image in sprite to use for drawing images on extruded fills. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.","sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"},"data-driven styling":{js:"0.49.0",android:"6.5.0",macos:"0.11.0",ios:"4.4.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"cross-faded-data-driven"},"fill-extrusion-height":{type:"number",default:0,minimum:0,units:"meters",doc:"The height with which to extrude this layer.",transition:!0,"sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"},"data-driven styling":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-base":{type:"number",default:0,minimum:0,units:"meters",doc:"The height with which to extrude the base of this layer. Must be less than or equal to `fill-extrusion-height`.",transition:!0,requires:["fill-extrusion-height"],"sdk-support":{"basic functionality":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"},"data-driven styling":{js:"0.27.0",android:"5.1.0",ios:"3.6.0",macos:"0.5.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"fill-extrusion-vertical-gradient":{type:"boolean",default:!0,doc:"Whether to apply a vertical gradient to the sides of a fill-extrusion layer. If true, sides will be shaded slightly darker farther down.",transition:!1,"sdk-support":{"basic functionality":{js:"0.50.0",ios:"4.7.0",macos:"0.13.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"}},paint_line:{"line-opacity":{type:"number",doc:"The opacity at which the line will be drawn.",default:1,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-color":{type:"color",doc:"The color with which the line will be drawn.",default:"#000000",transition:!0,requires:[{"!":"line-pattern"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.23.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-translate":{type:"array",value:"number",length:2,default:[0,0],transition:!0,units:"pixels",doc:"The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"line-translate-anchor":{type:"enum",values:{map:{doc:"The line is translated relative to the map."},viewport:{doc:"The line is translated relative to the viewport."}},doc:"Controls the frame of reference for `line-translate`.",default:"map",requires:["line-translate"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"line-width":{type:"number",default:1,minimum:0,transition:!0,units:"pixels",doc:"Stroke thickness.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.39.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-gap-width":{type:"number",default:0,minimum:0,doc:"Draws a line casing outside of a line's actual path. Value indicates the width of the inner gap.",transition:!0,units:"pixels","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-offset":{type:"number",default:0,doc:"The line's offset. For linear features, a positive value offsets the line to the right, relative to the direction of the line, and a negative value to the left. For polygon features, a positive value results in an inset, and a negative value results in an outset.",transition:!0,units:"pixels","sdk-support":{"basic functionality":{js:"0.12.1",android:"3.0.0",ios:"3.1.0",macos:"0.1.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-blur":{type:"number",default:0,minimum:0,transition:!0,units:"pixels",doc:"Blur applied to the line, in pixels.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"line-dasharray":{type:"array",value:"number",doc:"Specifies the lengths of the alternating dashes and gaps that form the dash pattern. The lengths are later scaled by the line width. To convert a dash length to pixels, multiply the length by the current line width. Note that GeoJSON sources with `lineMetrics: true` specified won't render dashed lines to the expected scale. Also note that zoom-dependent expressions will be evaluated only at integer zoom levels.",minimum:0,transition:!0,units:"line widths",requires:[{"!":"line-pattern"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"cross-faded"},"line-pattern":{type:"resolvedImage",transition:!0,doc:"Name of image in sprite to use for drawing image lines. For seamless patterns, image width must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.49.0",android:"6.5.0",macos:"0.11.0",ios:"4.4.0"}},expression:{interpolated:!1,parameters:["zoom","feature"]},"property-type":"cross-faded-data-driven"},"line-gradient":{type:"color",doc:'Defines a gradient with which to color a line feature. Can only be used with GeoJSON sources that specify `"lineMetrics": true`.',transition:!1,requires:[{"!":"line-dasharray"},{"!":"line-pattern"},{source:"geojson",has:{lineMetrics:!0}}],"sdk-support":{"basic functionality":{js:"0.45.0",android:"6.5.0",ios:"4.4.0",macos:"0.11.0"},"data-driven styling":{}},expression:{interpolated:!0,parameters:["line-progress"]},"property-type":"color-ramp"}},paint_circle:{"circle-radius":{type:"number",default:5,minimum:0,transition:!0,units:"pixels",doc:"Circle radius.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.18.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-color":{type:"color",default:"#000000",doc:"The fill color of the circle.",transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.18.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-blur":{type:"number",default:0,doc:"Amount to blur the circle. 1 blurs the circle such that only the centerpoint is full opacity.",transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.20.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-opacity":{type:"number",doc:"The opacity at which the circle will be drawn.",default:1,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.20.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-translate":{type:"array",value:"number",length:2,default:[0,0],transition:!0,units:"pixels",doc:"The geometry's offset. Values are [x, y] where negatives indicate left and up, respectively.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"circle-translate-anchor":{type:"enum",values:{map:{doc:"The circle is translated relative to the map."},viewport:{doc:"The circle is translated relative to the viewport."}},doc:"Controls the frame of reference for `circle-translate`.",default:"map",requires:["circle-translate"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"circle-pitch-scale":{type:"enum",values:{map:{doc:"Circles are scaled according to their apparent distance to the camera."},viewport:{doc:"Circles are not scaled."}},default:"map",doc:"Controls the scaling behavior of the circle when the map is pitched.","sdk-support":{"basic functionality":{js:"0.21.0",android:"4.2.0",ios:"3.4.0",macos:"0.2.1"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"circle-pitch-alignment":{type:"enum",values:{map:{doc:"The circle is aligned to the plane of the map."},viewport:{doc:"The circle is aligned to the plane of the viewport."}},default:"viewport",doc:"Orientation of circle when map is pitched.","sdk-support":{"basic functionality":{js:"0.39.0",android:"5.2.0",ios:"3.7.0",macos:"0.6.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"circle-stroke-width":{type:"number",default:0,minimum:0,transition:!0,units:"pixels",doc:"The width of the circle's stroke. Strokes are placed outside of the `circle-radius`.","sdk-support":{"basic functionality":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-stroke-color":{type:"color",default:"#000000",doc:"The stroke color of the circle.",transition:!0,"sdk-support":{"basic functionality":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"circle-stroke-opacity":{type:"number",doc:"The opacity of the circle's stroke.",default:1,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"},"data-driven styling":{js:"0.29.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"}},paint_heatmap:{"heatmap-radius":{type:"number",default:30,minimum:1,transition:!0,units:"pixels",doc:"Radius of influence of one heatmap point in pixels. Increasing the value makes the heatmap smoother, but less detailed.","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},"data-driven styling":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"heatmap-weight":{type:"number",default:1,minimum:0,transition:!1,doc:"A measure of how much an individual point contributes to the heatmap. A value of 10 would be equivalent to having 10 points of weight 1 in the same spot. Especially useful when combined with clustering.","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},"data-driven styling":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"heatmap-intensity":{type:"number",default:1,minimum:0,transition:!0,doc:"Similar to `heatmap-weight` but controls the intensity of the heatmap globally. Primarily used for adjusting the heatmap based on zoom level.","sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"heatmap-color":{type:"color",default:["interpolate",["linear"],["heatmap-density"],0,"rgba(0, 0, 255, 0)",.1,"royalblue",.3,"cyan",.5,"lime",.7,"yellow",1,"red"],doc:'Defines the color of each pixel based on its density value in a heatmap. Should be an expression that uses `["heatmap-density"]` as input.',transition:!1,"sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"},"data-driven styling":{}},expression:{interpolated:!0,parameters:["heatmap-density"]},"property-type":"color-ramp"},"heatmap-opacity":{type:"number",doc:"The global opacity at which the heatmap layer will be drawn.",default:1,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.41.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"}},paint_symbol:{"icon-opacity":{doc:"The opacity at which the icon will be drawn.",type:"number",default:1,minimum:0,maximum:1,transition:!0,requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-color":{type:"color",default:"#000000",transition:!0,doc:"The color of the icon. This can only be used with sdf icons.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-color":{type:"color",default:"rgba(0, 0, 0, 0)",transition:!0,doc:"The color of the icon's halo. Icon halos can only be used with SDF icons.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-width":{type:"number",default:0,minimum:0,transition:!0,units:"pixels",doc:"Distance of halo to the icon outline.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-halo-blur":{type:"number",default:0,minimum:0,transition:!0,units:"pixels",doc:"Fade out the halo towards the outside.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"icon-translate":{type:"array",value:"number",length:2,default:[0,0],transition:!0,units:"pixels",doc:"Distance that the icon's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.",requires:["icon-image"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"icon-translate-anchor":{type:"enum",values:{map:{doc:"Icons are translated relative to the map."},viewport:{doc:"Icons are translated relative to the viewport."}},doc:"Controls the frame of reference for `icon-translate`.",default:"map",requires:["icon-image","icon-translate"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"text-opacity":{type:"number",doc:"The opacity at which the text will be drawn.",default:1,minimum:0,maximum:1,transition:!0,requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-color":{type:"color",doc:"The color with which the text will be drawn.",default:"#000000",transition:!0,overridable:!0,requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-color":{type:"color",default:"rgba(0, 0, 0, 0)",transition:!0,doc:"The color of the text's halo, which helps it stand out from backgrounds.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-width":{type:"number",default:0,minimum:0,transition:!0,units:"pixels",doc:"Distance of halo to the font outline. Max text halo width is 1/4 of the font-size.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-halo-blur":{type:"number",default:0,minimum:0,transition:!0,units:"pixels",doc:"The halo's fadeout distance towards the outside.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{js:"0.33.0",android:"5.0.0",ios:"3.5.0",macos:"0.4.0"}},expression:{interpolated:!0,parameters:["zoom","feature","feature-state"]},"property-type":"data-driven"},"text-translate":{type:"array",value:"number",length:2,default:[0,0],transition:!0,units:"pixels",doc:"Distance that the text's anchor is moved from its original placement. Positive values indicate right and down, while negative values indicate left and up.",requires:["text-field"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"text-translate-anchor":{type:"enum",values:{map:{doc:"The text is translated relative to the map."},viewport:{doc:"The text is translated relative to the viewport."}},doc:"Controls the frame of reference for `text-translate`.",default:"map",requires:["text-field","text-translate"],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"}},paint_raster:{"raster-opacity":{type:"number",doc:"The opacity at which the image will be drawn.",default:1,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"raster-hue-rotate":{type:"number",default:0,period:360,transition:!0,units:"degrees",doc:"Rotates hues around the color wheel.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"raster-brightness-min":{type:"number",doc:"Increase or reduce the brightness of the image. The value is the minimum brightness.",default:0,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"raster-brightness-max":{type:"number",doc:"Increase or reduce the brightness of the image. The value is the maximum brightness.",default:1,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"raster-saturation":{type:"number",doc:"Increase or reduce the saturation of the image.",default:0,minimum:-1,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"raster-contrast":{type:"number",doc:"Increase or reduce the contrast of the image.",default:0,minimum:-1,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"raster-resampling":{type:"enum",doc:"The resampling/interpolation method to use for overscaling, also known as texture magnification filter",values:{linear:{doc:"(Bi)linear filtering interpolates pixel values using the weighted average of the four closest original source pixels creating a smooth but blurry look when overscaled"},nearest:{doc:"Nearest neighbor filtering interpolates pixel values using the nearest original source pixel creating a sharp but pixelated look when overscaled"}},default:"linear","sdk-support":{"basic functionality":{js:"0.47.0",android:"6.3.0",ios:"4.2.0",macos:"0.9.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"raster-fade-duration":{type:"number",default:300,minimum:0,transition:!1,units:"milliseconds",doc:"Fade duration when a new tile is added.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"}},paint_hillshade:{"hillshade-illumination-direction":{type:"number",default:335,minimum:0,maximum:359,doc:"The direction of the light source used to generate the hillshading with 0 as the top of the viewport if `hillshade-illumination-anchor` is set to `viewport` and due north if `hillshade-illumination-anchor` is set to `map`.",transition:!1,"sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"hillshade-illumination-anchor":{type:"enum",values:{map:{doc:"The hillshade illumination is relative to the north direction."},viewport:{doc:"The hillshade illumination is relative to the top of the viewport."}},default:"viewport",doc:"Direction of light source when map is rotated.","sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"hillshade-exaggeration":{type:"number",doc:"Intensity of the hillshade",default:.5,minimum:0,maximum:1,transition:!0,"sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"hillshade-shadow-color":{type:"color",default:"#000000",doc:"The shading color of areas that face away from the light source.",transition:!0,"sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"hillshade-highlight-color":{type:"color",default:"#FFFFFF",doc:"The shading color of areas that faces towards the light source.",transition:!0,"sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"hillshade-accent-color":{type:"color",default:"#000000",doc:"The shading color used to accentuate rugged terrain like sharp cliffs and gorges.",transition:!0,"sdk-support":{"basic functionality":{js:"0.43.0",android:"6.0.0",ios:"4.0.0",macos:"0.7.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"}},paint_background:{"background-color":{type:"color",default:"#000000",doc:"The color with which the background will be drawn.",transition:!0,requires:[{"!":"background-pattern"}],"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"},"background-pattern":{type:"resolvedImage",transition:!0,doc:"Name of image in sprite to use for drawing an image background. For seamless patterns, image width and height must be a factor of two (2, 4, 8, ..., 512). Note that zoom-dependent expressions will be evaluated only at integer zoom levels.","sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"},"data-driven styling":{}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"cross-faded"},"background-opacity":{type:"number",default:1,minimum:0,maximum:1,doc:"The opacity at which the background will be drawn.",transition:!0,"sdk-support":{"basic functionality":{js:"0.10.0",android:"2.0.1",ios:"2.0.0",macos:"0.1.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"}},paint_sky:{"sky-type":{type:"enum",values:{gradient:{doc:"Renders the sky with a gradient that can be configured with `sky-gradient-radius` and `sky-gradient`."},atmosphere:{doc:"Renders the sky with a simulated atmospheric scattering algorithm, the sun direction can be attached to the light position or explicitly set through `sky-atmosphere-sun`."}},default:"atmosphere",doc:"The type of the sky","sdk-support":{"basic functionality":{js:"2.0.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"sky-atmosphere-sun":{type:"array",value:"number",length:2,transition:!1,doc:"Position of the sun center [a azimuthal angle, p polar angle]. The azimuthal angle indicates the position of the sun relative to 0° north, where degrees proceed clockwise. The polar angle indicates the height of the sun, where 0° is directly above, at zenith, and 90° at the horizon. When this property is ommitted, the sun center is directly inherited from the light position.","sdk-support":{"basic functionality":{js:"2.0.0"}},requires:[{"sky-type":"atmosphere"}],expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"sky-atmosphere-sun-intensity":{type:"number",requires:[{"sky-type":"atmosphere"}],default:10,minimum:0,maximum:100,transition:!1,doc:"Intensity of the sun as a light source in the atmosphere (on a scale from 0 to a 100). Setting higher values will brighten up the sky.","sdk-support":{"basic functionality":{js:"2.0.0"}},"property-type":"data-constant"},"sky-gradient-center":{type:"array",requires:[{"sky-type":"gradient"}],value:"number",default:[0,0],length:2,transition:!1,doc:"Position of the gradient center [a azimuthal angle, p polar angle]. The azimuthal angle indicates the position of the gradient center relative to 0° north, where degrees proceed clockwise. The polar angle indicates the height of the gradient center, where 0° is directly above, at zenith, and 90° at the horizon.","sdk-support":{"basic functionality":{js:"2.0.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"sky-gradient-radius":{type:"number",requires:[{"sky-type":"gradient"}],default:90,minimum:0,maximum:180,transition:!1,doc:"The angular distance (measured in degrees) from `sky-gradient-center` up to which the gradient extends. A value of 180 causes the gradient to wrap around to the opposite direction from `sky-gradient-center`.","sdk-support":{"basic functionality":{js:"2.0.0"}},expression:{interpolated:!1,parameters:["zoom"]},"property-type":"data-constant"},"sky-gradient":{type:"color",default:["interpolate",["linear"],["sky-radial-progress"],.8,"#87ceeb",1,"white"],doc:"Defines a radial color gradient with which to color the sky. The color values can be interpolated with an expression using `sky-radial-progress`. The range [0, 1] for the interpolant covers a radial distance (in degrees) of [0, `sky-gradient-radius`] centered at the position specified by `sky-gradient-center`.",transition:!1,requires:[{"sky-type":"gradient"}],"sdk-support":{"basic functionality":{js:"2.0.0"},"data-driven styling":{}},expression:{interpolated:!0,parameters:["sky-radial-progress"]},"property-type":"color-ramp"},"sky-atmosphere-halo-color":{type:"color",default:"white",doc:"A color applied to the atmosphere sun halo. The alpha channel describes how strongly the sun halo is represented in an atmosphere sky layer.",transition:!1,requires:[{"sky-type":"atmosphere"}],"sdk-support":{"basic functionality":{js:"2.0.0"}},"property-type":"data-constant"},"sky-atmosphere-color":{type:"color",default:"white",doc:"A color used to tweak the main atmospheric scattering coefficients. Using white applies the default coefficients giving the natural blue color to the atmosphere. This color affects how heavily the corresponding wavelength is represented during scattering. The alpha channel describes the density of the atmosphere, with 1 maximum density and 0 no density.",transition:!1,requires:[{"sky-type":"atmosphere"}],"sdk-support":{"basic functionality":{js:"2.0.0"}},"property-type":"data-constant"},"sky-opacity":{type:"number",default:1,minimum:0,maximum:1,doc:"The opacity of the entire sky layer.",transition:!0,"sdk-support":{"basic functionality":{js:"2.0.0"}},expression:{interpolated:!0,parameters:["zoom"]},"property-type":"data-constant"}},transition:{duration:{type:"number",default:300,minimum:0,units:"milliseconds",doc:"Time allotted for transitions to complete."},delay:{type:"number",default:0,minimum:0,units:"milliseconds",doc:"Length of time before a transition begins."}},"property-type":{"data-driven":{type:"property-type",doc:"Property is interpolable and can be represented using a property expression."},"cross-faded":{type:"property-type",doc:"Property is non-interpolable; rather, its values will be cross-faded to smoothly transition between integer zooms."},"cross-faded-data-driven":{type:"property-type",doc:"Property is non-interpolable; rather, its values will be cross-faded to smoothly transition between integer zooms. It can be represented using a property expression."},"color-ramp":{type:"property-type",doc:"Property should be specified using a color ramp from which the output color can be sampled based on a property calculation."},"data-constant":{type:"property-type",doc:"Property is interpolable but cannot be represented using a property expression."},constant:{type:"property-type",doc:"Property is constant across all zoom levels and property values."}},promoteId:{"*":{type:"string",doc:"A name of a feature property to use as ID for feature state."}}};var o="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:void 0!==t?t:"undefined"!=typeof self?self:{};function a(){throw new Error("Dynamic requires are not currently supported by rollup-plugin-commonjs")}function s(t,e){return t(e={exports:{}},e.exports),e.exports}var l=s((function(t,e){!function(r){var n=e&&!e.nodeType&&e,i=t&&!t.nodeType&&t,a="object"==typeof o&&o;a.global!==a&&a.window!==a&&a.self!==a||(r=a);var s,l,u=2147483647,c=/^xn--/,h=/[^\x20-\x7E]/,p=/[\x2E\u3002\uFF0E\uFF61]/g,f={overflow:"Overflow: input needs wider integers to process","not-basic":"Illegal input >= 0x80 (not a basic code point)","invalid-input":"Invalid input"},d=Math.floor,g=String.fromCharCode;function y(t){throw RangeError(f[t])}function m(t,e){for(var r=t.length,n=[];r--;)n[r]=e(t[r]);return n}function v(t,e){var r=t.split("@"),n="";return r.length>1&&(n=r[0]+"@",t=r[1]),n+m((t=t.replace(p,".")).split("."),e).join(".")}function _(t){for(var e,r,n=[],i=0,o=t.length;i<o;)(e=t.charCodeAt(i++))>=55296&&e<=56319&&i<o?56320==(64512&(r=t.charCodeAt(i++)))?n.push(((1023&e)<<10)+(1023&r)+65536):(n.push(e),i--):n.push(e);return n}function b(t){return m(t,(function(t){var e="";return t>65535&&(e+=g((t-=65536)>>>10&1023|55296),t=56320|1023&t),e+=g(t)})).join("")}function x(t,e){return t+22+75*(t<26)-((0!=e)<<5)}function w(t,e,r){var n=0;for(t=r?d(t/700):t>>1,t+=d(t/e);t>455;n+=36)t=d(t/35);return d(n+36*t/(t+38))}function S(t){var e,r,n,i,o,a,s,l,c,h,p,f=[],g=t.length,m=0,v=128,_=72;for((r=t.lastIndexOf("-"))<0&&(r=0),n=0;n<r;++n)t.charCodeAt(n)>=128&&y("not-basic"),f.push(t.charCodeAt(n));for(i=r>0?r+1:0;i<g;){for(o=m,a=1,s=36;i>=g&&y("invalid-input"),((l=(p=t.charCodeAt(i++))-48<10?p-22:p-65<26?p-65:p-97<26?p-97:36)>=36||l>d((u-m)/a))&&y("overflow"),m+=l*a,!(l<(c=s<=_?1:s>=_+26?26:s-_));s+=36)a>d(u/(h=36-c))&&y("overflow"),a*=h;_=w(m-o,e=f.length+1,0==o),d(m/e)>u-v&&y("overflow"),v+=d(m/e),m%=e,f.splice(m++,0,v)}return b(f)}function E(t){var e,r,n,i,o,a,s,l,c,h,p,f,m,v,b,S=[];for(f=(t=_(t)).length,e=128,r=0,o=72,a=0;a<f;++a)(p=t[a])<128&&S.push(g(p));for(n=i=S.length,i&&S.push("-");n<f;){for(s=u,a=0;a<f;++a)(p=t[a])>=e&&p<s&&(s=p);for(s-e>d((u-r)/(m=n+1))&&y("overflow"),r+=(s-e)*m,e=s,a=0;a<f;++a)if((p=t[a])<e&&++r>u&&y("overflow"),p==e){for(l=r,c=36;!(l<(h=c<=o?1:c>=o+26?26:c-o));c+=36)b=l-h,v=36-h,S.push(g(x(h+b%v,0))),l=d(b/v);S.push(g(x(l,0))),o=w(r,m,n==i),r=0,++n}++r,++e}return S.join("")}if(s={version:"1.3.2",ucs2:{decode:_,encode:b},decode:S,encode:E,toASCII:function(t){return v(t,(function(t){return h.test(t)?"xn--"+E(t):t}))},toUnicode:function(t){return v(t,(function(t){return c.test(t)?S(t.slice(4).toLowerCase()):t}))}},n&&i)if(t.exports==n)i.exports=s;else for(l in s)s.hasOwnProperty(l)&&(n[l]=s[l]);else r.punycode=s}(o)})),u=function(t){return"string"==typeof t},c=function(t){return"object"==typeof t&&null!==t},h=function(t){return null===t},p=function(t){return null==t};function f(t,e){return Object.prototype.hasOwnProperty.call(t,e)}var d=function(t,e,r,n){e=e||"&",r=r||"=";var i={};if("string"!=typeof t||0===t.length)return i;var o=/\+/g;t=t.split(e);var a=1e3;n&&"number"==typeof n.maxKeys&&(a=n.maxKeys);var s=t.length;a>0&&s>a&&(s=a);for(var l=0;l<s;++l){var u,c,h,p,d=t[l].replace(o,"%20"),g=d.indexOf(r);g>=0?(u=d.substr(0,g),c=d.substr(g+1)):(u=d,c=""),h=decodeURIComponent(u),p=decodeURIComponent(c),f(i,h)?Array.isArray(i[h])?i[h].push(p):i[h]=[i[h],p]:i[h]=p}return i},g=function(t){switch(typeof t){case"string":return t;case"boolean":return t?"true":"false";case"number":return isFinite(t)?t:"";default:return""}},y=function(t,e,r,n){return e=e||"&",r=r||"=",null===t&&(t=void 0),"object"==typeof t?Object.keys(t).map((function(n){var i=encodeURIComponent(g(n))+r;return Array.isArray(t[n])?t[n].map((function(t){return i+encodeURIComponent(g(t))})).join(e):i+encodeURIComponent(g(t[n]))})).join(e):n?encodeURIComponent(g(n))+r+encodeURIComponent(g(t)):""},m=s((function(t,e){e.decode=e.parse=d,e.encode=e.stringify=y}));m.decode,m.parse,m.encode,m.stringify;function v(){this.protocol=null,this.slashes=null,this.auth=null,this.host=null,this.port=null,this.hostname=null,this.hash=null,this.search=null,this.query=null,this.pathname=null,this.path=null,this.href=null}var _=/^([a-z0-9.+-]+:)/i,b=/:[0-9]*$/,x=/^(\/\/?(?!\/)[^\?\s]*)(\?[^\s]*)?$/,w=["{","}","|","\\","^","`"].concat(["<",">",'"',"`"," ","\r","\n","\t"]),S=["'"].concat(w),E=["%","/","?",";","#"].concat(S),T=["/","?","#"],C=/^[+a-z0-9A-Z_-]{0,63}$/,O=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,P={javascript:!0,"javascript:":!0},R={javascript:!0,"javascript:":!0},I={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0};function L(t,e,r){if(t&&c(t)&&t instanceof v)return t;var n=new v;return n.parse(t,e,r),n}v.prototype.parse=function(t,e,r){if(!u(t))throw new TypeError("Parameter 'url' must be a string, not "+typeof t);var n=t.indexOf("?"),i=-1!==n&&n<t.indexOf("#")?"?":"#",o=t.split(i);o[0]=o[0].replace(/\\/g,"/");var a=t=o.join(i);if(a=a.trim(),!r&&1===t.split("#").length){var s=x.exec(a);if(s)return this.path=a,this.href=a,this.pathname=s[1],s[2]?(this.search=s[2],this.query=e?m.parse(this.search.substr(1)):this.search.substr(1)):e&&(this.search="",this.query={}),this}var c=_.exec(a);if(c){var h=(c=c[0]).toLowerCase();this.protocol=h,a=a.substr(c.length)}if(r||c||a.match(/^\/\/[^@\/]+@[^@\/]+/)){var p="//"===a.substr(0,2);!p||c&&R[c]||(a=a.substr(2),this.slashes=!0)}if(!R[c]&&(p||c&&!I[c])){for(var f,d,g=-1,y=0;y<T.length;y++){-1!==(v=a.indexOf(T[y]))&&(-1===g||v<g)&&(g=v)}-1!==(d=-1===g?a.lastIndexOf("@"):a.lastIndexOf("@",g))&&(f=a.slice(0,d),a=a.slice(d+1),this.auth=decodeURIComponent(f)),g=-1;for(y=0;y<E.length;y++){var v;-1!==(v=a.indexOf(E[y]))&&(-1===g||v<g)&&(g=v)}-1===g&&(g=a.length),this.host=a.slice(0,g),a=a.slice(g),this.parseHost(),this.hostname=this.hostname||"";var b="["===this.hostname[0]&&"]"===this.hostname[this.hostname.length-1];if(!b)for(var w=this.hostname.split(/\./),L=(y=0,w.length);y<L;y++){var M=w[y];if(M&&!M.match(C)){for(var F="",A=0,k=M.length;A<k;A++)M.charCodeAt(A)>127?F+="x":F+=M[A];if(!F.match(C)){var j=w.slice(0,y),N=w.slice(y+1),D=M.match(O);D&&(j.push(D[1]),N.unshift(D[2])),N.length&&(a="/"+N.join(".")+a),this.hostname=j.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),b||(this.hostname=l.toASCII(this.hostname));var G=this.port?":"+this.port:"",z=this.hostname||"";this.host=z+G,this.href+=this.host,b&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==a[0]&&(a="/"+a))}if(!P[h])for(y=0,L=S.length;y<L;y++){var U=S[y];if(-1!==a.indexOf(U)){var B=encodeURIComponent(U);B===U&&(B=escape(U)),a=a.split(U).join(B)}}var V=a.indexOf("#");-1!==V&&(this.hash=a.substr(V),a=a.slice(0,V));var Y=a.indexOf("?");if(-1!==Y?(this.search=a.substr(Y),this.query=a.substr(Y+1),e&&(this.query=m.parse(this.query)),a=a.slice(0,Y)):e&&(this.search="",this.query={}),a&&(this.pathname=a),I[h]&&this.hostname&&!this.pathname&&(this.pathname="/"),this.pathname||this.search){G=this.pathname||"";var W=this.search||"";this.path=G+W}return this.href=this.format(),this},v.prototype.format=function(){var t=this.auth||"";t&&(t=(t=encodeURIComponent(t)).replace(/%3A/i,":"),t+="@");var e=this.protocol||"",r=this.pathname||"",n=this.hash||"",i=!1,o="";this.host?i=t+this.host:this.hostname&&(i=t+(-1===this.hostname.indexOf(":")?this.hostname:"["+this.hostname+"]"),this.port&&(i+=":"+this.port)),this.query&&c(this.query)&&Object.keys(this.query).length&&(o=m.stringify(this.query));var a=this.search||o&&"?"+o||"";return e&&":"!==e.substr(-1)&&(e+=":"),this.slashes||(!e||I[e])&&!1!==i?(i="//"+(i||""),r&&"/"!==r.charAt(0)&&(r="/"+r)):i||(i=""),n&&"#"!==n.charAt(0)&&(n="#"+n),a&&"?"!==a.charAt(0)&&(a="?"+a),e+i+(r=r.replace(/[?#]/g,(function(t){return encodeURIComponent(t)})))+(a=a.replace("#","%23"))+n},v.prototype.resolve=function(t){return this.resolveObject(L(t,!1,!0)).format()},v.prototype.resolveObject=function(t){if(u(t)){var e=new v;e.parse(t,!1,!0),t=e}for(var r=new v,n=Object.keys(this),i=0;i<n.length;i++){var o=n[i];r[o]=this[o]}if(r.hash=t.hash,""===t.href)return r.href=r.format(),r;if(t.slashes&&!t.protocol){for(var a=Object.keys(t),s=0;s<a.length;s++){var l=a[s];"protocol"!==l&&(r[l]=t[l])}return I[r.protocol]&&r.hostname&&!r.pathname&&(r.path=r.pathname="/"),r.href=r.format(),r}if(t.protocol&&t.protocol!==r.protocol){if(!I[t.protocol]){for(var c=Object.keys(t),f=0;f<c.length;f++){var d=c[f];r[d]=t[d]}return r.href=r.format(),r}if(r.protocol=t.protocol,t.host||R[t.protocol])r.pathname=t.pathname;else{for(var g=(t.pathname||"").split("/");g.length&&!(t.host=g.shift()););t.host||(t.host=""),t.hostname||(t.hostname=""),""!==g[0]&&g.unshift(""),g.length<2&&g.unshift(""),r.pathname=g.join("/")}if(r.search=t.search,r.query=t.query,r.host=t.host||"",r.auth=t.auth,r.hostname=t.hostname||t.host,r.port=t.port,r.pathname||r.search){var y=r.pathname||"",m=r.search||"";r.path=y+m}return r.slashes=r.slashes||t.slashes,r.href=r.format(),r}var _=r.pathname&&"/"===r.pathname.charAt(0),b=t.host||t.pathname&&"/"===t.pathname.charAt(0),x=b||_||r.host&&t.pathname,w=x,S=r.pathname&&r.pathname.split("/")||[],E=(g=t.pathname&&t.pathname.split("/")||[],r.protocol&&!I[r.protocol]);if(E&&(r.hostname="",r.port=null,r.host&&(""===S[0]?S[0]=r.host:S.unshift(r.host)),r.host="",t.protocol&&(t.hostname=null,t.port=null,t.host&&(""===g[0]?g[0]=t.host:g.unshift(t.host)),t.host=null),x=x&&(""===g[0]||""===S[0])),b)r.host=t.host||""===t.host?t.host:r.host,r.hostname=t.hostname||""===t.hostname?t.hostname:r.hostname,r.search=t.search,r.query=t.query,S=g;else if(g.length)S||(S=[]),S.pop(),S=S.concat(g),r.search=t.search,r.query=t.query;else if(!p(t.search)){if(E)r.hostname=r.host=S.shift(),(L=!!(r.host&&r.host.indexOf("@")>0)&&r.host.split("@"))&&(r.auth=L.shift(),r.host=r.hostname=L.shift());return r.search=t.search,r.query=t.query,h(r.pathname)&&h(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.href=r.format(),r}if(!S.length)return r.pathname=null,r.search?r.path="/"+r.search:r.path=null,r.href=r.format(),r;for(var T=S.slice(-1)[0],C=(r.host||t.host||S.length>1)&&("."===T||".."===T)||""===T,O=0,P=S.length;P>=0;P--)"."===(T=S[P])?S.splice(P,1):".."===T?(S.splice(P,1),O++):O&&(S.splice(P,1),O--);if(!x&&!w)for(;O--;O)S.unshift("..");!x||""===S[0]||S[0]&&"/"===S[0].charAt(0)||S.unshift(""),C&&"/"!==S.join("/").substr(-1)&&S.push("");var L,M=""===S[0]||S[0]&&"/"===S[0].charAt(0);E&&(r.hostname=r.host=M?"":S.length?S.shift():"",(L=!!(r.host&&r.host.indexOf("@")>0)&&r.host.split("@"))&&(r.auth=L.shift(),r.host=r.hostname=L.shift()));return(x=x||r.host&&S.length)&&!M&&S.unshift(""),S.length?r.pathname=S.join("/"):(r.pathname=null,r.path=null),h(r.pathname)&&h(r.search)||(r.path=(r.pathname?r.pathname:"")+(r.search?r.search:"")),r.auth=t.auth||r.auth,r.slashes=r.slashes||t.slashes,r.href=r.format(),r},v.prototype.parseHost=function(){var t=this.host,e=b.exec(t);e&&(":"!==(e=e[0])&&(this.port=e.substr(1)),t=t.substr(0,t.length-e.length)),t&&(this.hostname=t)};function M(t,...e){for(const r of e)for(const e in r)t[e]=r[e];return t}class F extends Error{constructor(t,e){super(e),this.message=e,this.key=t}}class A{constructor(t,e=[]){this.parent=t,this.bindings={};for(const[t,r]of e)this.bindings[t]=r}concat(t){return new A(this,t)}get(t){if(this.bindings[t])return this.bindings[t];if(this.parent)return this.parent.get(t);throw new Error(t+" not found in scope.")}has(t){return!!this.bindings[t]||!!this.parent&&this.parent.has(t)}}const k={kind:"null"},j={kind:"number"},N={kind:"string"},D={kind:"boolean"},G={kind:"color"},z={kind:"object"},U={kind:"value"},B={kind:"collator"},V={kind:"formatted"},Y={kind:"resolvedImage"};function W(t,e){return{kind:"array",itemType:t,N:e}}function q(t){if("array"===t.kind){const e=q(t.itemType);return"number"==typeof t.N?`array<${e}, ${t.N}>`:"value"===t.itemType.kind?"array":`array<${e}>`}return t.kind}const X=[k,j,N,D,G,V,z,W(U),Y];function Z(t,e){if("error"===e.kind)return null;if("array"===t.kind){if("array"===e.kind&&(0===e.N&&"value"===e.itemType.kind||!Z(t.itemType,e.itemType))&&("number"!=typeof t.N||t.N===e.N))return null}else{if(t.kind===e.kind)return null;if("value"===t.kind)for(const t of X)if(!Z(t,e))return null}return`Expected ${q(t)} but found ${q(e)} instead.`}function K(t,e){return e.some(e=>e.kind===t.kind)}function H(t,e){return e.some(e=>"null"===e?null===t:"array"===e?Array.isArray(t):"object"===e?t&&!Array.isArray(t)&&"object"==typeof t:e===typeof t)}var $=s((function(t,e){var r={transparent:[0,0,0,0],aliceblue:[240,248,255,1],antiquewhite:[250,235,215,1],aqua:[0,255,255,1],aquamarine:[127,255,212,1],azure:[240,255,255,1],beige:[245,245,220,1],bisque:[255,228,196,1],black:[0,0,0,1],blanchedalmond:[255,235,205,1],blue:[0,0,255,1],blueviolet:[138,43,226,1],brown:[165,42,42,1],burlywood:[222,184,135,1],cadetblue:[95,158,160,1],chartreuse:[127,255,0,1],chocolate:[210,105,30,1],coral:[255,127,80,1],cornflowerblue:[100,149,237,1],cornsilk:[255,248,220,1],crimson:[220,20,60,1],cyan:[0,255,255,1],darkblue:[0,0,139,1],darkcyan:[0,139,139,1],darkgoldenrod:[184,134,11,1],darkgray:[169,169,169,1],darkgreen:[0,100,0,1],darkgrey:[169,169,169,1],darkkhaki:[189,183,107,1],darkmagenta:[139,0,139,1],darkolivegreen:[85,107,47,1],darkorange:[255,140,0,1],darkorchid:[153,50,204,1],darkred:[139,0,0,1],darksalmon:[233,150,122,1],darkseagreen:[143,188,143,1],darkslateblue:[72,61,139,1],darkslategray:[47,79,79,1],darkslategrey:[47,79,79,1],darkturquoise:[0,206,209,1],darkviolet:[148,0,211,1],deeppink:[255,20,147,1],deepskyblue:[0,191,255,1],dimgray:[105,105,105,1],dimgrey:[105,105,105,1],dodgerblue:[30,144,255,1],firebrick:[178,34,34,1],floralwhite:[255,250,240,1],forestgreen:[34,139,34,1],fuchsia:[255,0,255,1],gainsboro:[220,220,220,1],ghostwhite:[248,248,255,1],gold:[255,215,0,1],goldenrod:[218,165,32,1],gray:[128,128,128,1],green:[0,128,0,1],greenyellow:[173,255,47,1],grey:[128,128,128,1],honeydew:[240,255,240,1],hotpink:[255,105,180,1],indianred:[205,92,92,1],indigo:[75,0,130,1],ivory:[255,255,240,1],khaki:[240,230,140,1],lavender:[230,230,250,1],lavenderblush:[255,240,245,1],lawngreen:[124,252,0,1],lemonchiffon:[255,250,205,1],lightblue:[173,216,230,1],lightcoral:[240,128,128,1],lightcyan:[224,255,255,1],lightgoldenrodyellow:[250,250,210,1],lightgray:[211,211,211,1],lightgreen:[144,238,144,1],lightgrey:[211,211,211,1],lightpink:[255,182,193,1],lightsalmon:[255,160,122,1],lightseagreen:[32,178,170,1],lightskyblue:[135,206,250,1],lightslategray:[119,136,153,1],lightslategrey:[119,136,153,1],lightsteelblue:[176,196,222,1],lightyellow:[255,255,224,1],lime:[0,255,0,1],limegreen:[50,205,50,1],linen:[250,240,230,1],magenta:[255,0,255,1],maroon:[128,0,0,1],mediumaquamarine:[102,205,170,1],mediumblue:[0,0,205,1],mediumorchid:[186,85,211,1],mediumpurple:[147,112,219,1],mediumseagreen:[60,179,113,1],mediumslateblue:[123,104,238,1],mediumspringgreen:[0,250,154,1],mediumturquoise:[72,209,204,1],mediumvioletred:[199,21,133,1],midnightblue:[25,25,112,1],mintcream:[245,255,250,1],mistyrose:[255,228,225,1],moccasin:[255,228,181,1],navajowhite:[255,222,173,1],navy:[0,0,128,1],oldlace:[253,245,230,1],olive:[128,128,0,1],olivedrab:[107,142,35,1],orange:[255,165,0,1],orangered:[255,69,0,1],orchid:[218,112,214,1],palegoldenrod:[238,232,170,1],palegreen:[152,251,152,1],paleturquoise:[175,238,238,1],palevioletred:[219,112,147,1],papayawhip:[255,239,213,1],peachpuff:[255,218,185,1],peru:[205,133,63,1],pink:[255,192,203,1],plum:[221,160,221,1],powderblue:[176,224,230,1],purple:[128,0,128,1],rebeccapurple:[102,51,153,1],red:[255,0,0,1],rosybrown:[188,143,143,1],royalblue:[65,105,225,1],saddlebrown:[139,69,19,1],salmon:[250,128,114,1],sandybrown:[244,164,96,1],seagreen:[46,139,87,1],seashell:[255,245,238,1],sienna:[160,82,45,1],silver:[192,192,192,1],skyblue:[135,206,235,1],slateblue:[106,90,205,1],slategray:[112,128,144,1],slategrey:[112,128,144,1],snow:[255,250,250,1],springgreen:[0,255,127,1],steelblue:[70,130,180,1],tan:[210,180,140,1],teal:[0,128,128,1],thistle:[216,191,216,1],tomato:[255,99,71,1],turquoise:[64,224,208,1],violet:[238,130,238,1],wheat:[245,222,179,1],white:[255,255,255,1],whitesmoke:[245,245,245,1],yellow:[255,255,0,1],yellowgreen:[154,205,50,1]};function n(t){return(t=Math.round(t))<0?0:t>255?255:t}function i(t){return t<0?0:t>1?1:t}function o(t){return"%"===t[t.length-1]?n(parseFloat(t)/100*255):n(parseInt(t))}function a(t){return"%"===t[t.length-1]?i(parseFloat(t)/100):i(parseFloat(t))}function s(t,e,r){return r<0?r+=1:r>1&&(r-=1),6*r<1?t+(e-t)*r*6:2*r<1?e:3*r<2?t+(e-t)*(2/3-r)*6:t}try{e.parseCSSColor=function(t){var e,i=t.replace(/ /g,"").toLowerCase();if(i in r)return r[i].slice();if("#"===i[0])return 4===i.length?(e=parseInt(i.substr(1),16))>=0&&e<=4095?[(3840&e)>>4|(3840&e)>>8,240&e|(240&e)>>4,15&e|(15&e)<<4,1]:null:7===i.length&&(e=parseInt(i.substr(1),16))>=0&&e<=16777215?[(16711680&e)>>16,(65280&e)>>8,255&e,1]:null;var l=i.indexOf("("),u=i.indexOf(")");if(-1!==l&&u+1===i.length){var c=i.substr(0,l),h=i.substr(l+1,u-(l+1)).split(","),p=1;switch(c){case"rgba":if(4!==h.length)return null;p=a(h.pop());case"rgb":return 3!==h.length?null:[o(h[0]),o(h[1]),o(h[2]),p];case"hsla":if(4!==h.length)return null;p=a(h.pop());case"hsl":if(3!==h.length)return null;var f=(parseFloat(h[0])%360+360)%360/360,d=a(h[1]),g=a(h[2]),y=g<=.5?g*(d+1):g+d-g*d,m=2*g-y;return[n(255*s(m,y,f+1/3)),n(255*s(m,y,f)),n(255*s(m,y,f-1/3)),p];default:return null}}return null}}catch(t){}})).parseCSSColor;class J{constructor(t,e,r,n=1){this.r=t,this.g=e,this.b=r,this.a=n}static parse(t){if(!t)return;if(t instanceof J)return t;if("string"!=typeof t)return;const e=$(t);return e?new J(e[0]/255*e[3],e[1]/255*e[3],e[2]/255*e[3],e[3]):void 0}toString(){const[t,e,r,n]=this.toArray();return`rgba(${Math.round(t)},${Math.round(e)},${Math.round(r)},${n})`}toArray(){const{r:t,g:e,b:r,a:n}=this;return 0===n?[0,0,0,0]:[255*t/n,255*e/n,255*r/n,n]}}J.black=new J(0,0,0,1),J.white=new J(1,1,1,1),J.transparent=new J(0,0,0,0),J.red=new J(1,0,0,1),J.blue=new J(0,0,1,1);class Q{constructor(t,e,r){this.sensitivity=t?e?"variant":"case":e?"accent":"base",this.locale=r,this.collator=new Intl.Collator(this.locale?this.locale:[],{sensitivity:this.sensitivity,usage:"search"})}compare(t,e){return this.collator.compare(t,e)}resolvedLocale(){return new Intl.Collator(this.locale?this.locale:[]).resolvedOptions().locale}}class tt{constructor(t,e,r,n,i){this.text=t,this.image=e,this.scale=r,this.fontStack=n,this.textColor=i}}class et{constructor(t){this.sections=t}static fromString(t){return new et([new tt(t,null,null,null,null)])}isEmpty(){return 0===this.sections.length||!this.sections.some(t=>0!==t.text.length||t.image&&0!==t.image.name.length)}static factory(t){return t instanceof et?t:et.fromString(t)}toString(){return 0===this.sections.length?"":this.sections.map(t=>t.text).join("")}serialize(){const t=["format"];for(const e of this.sections){if(e.image){t.push(["image",e.image.name]);continue}t.push(e.text);const r={};e.fontStack&&(r["text-font"]=["literal",e.fontStack.split(",")]),e.scale&&(r["font-scale"]=e.scale),e.textColor&&(r["text-color"]=["rgba"].concat(e.textColor.toArray())),t.push(r)}return t}}class rt{constructor(t){this.name=t.name,this.available=t.available}toString(){return this.name}static fromString(t){return t?new rt({name:t,available:!1}):null}serialize(){return["image",this.name]}}function nt(t,e,r,n){if(!("number"==typeof t&&t>=0&&t<=255&&"number"==typeof e&&e>=0&&e<=255&&"number"==typeof r&&r>=0&&r<=255)){return`Invalid rgba value [${("number"==typeof n?[t,e,r,n]:[t,e,r]).join(", ")}]: 'r', 'g', and 'b' must be between 0 and 255.`}return void 0===n||"number"==typeof n&&n>=0&&n<=1?null:`Invalid rgba value [${[t,e,r,n].join(", ")}]: 'a' must be between 0 and 1.`}function it(t){if(null===t)return!0;if("string"==typeof t)return!0;if("boolean"==typeof t)return!0;if("number"==typeof t)return!0;if(t instanceof J)return!0;if(t instanceof Q)return!0;if(t instanceof et)return!0;if(t instanceof rt)return!0;if(Array.isArray(t)){for(const e of t)if(!it(e))return!1;return!0}if("object"==typeof t){for(const e in t)if(!it(t[e]))return!1;return!0}return!1}function ot(t){if(null===t)return k;if("string"==typeof t)return N;if("boolean"==typeof t)return D;if("number"==typeof t)return j;if(t instanceof J)return G;if(t instanceof Q)return B;if(t instanceof et)return V;if(t instanceof rt)return Y;if(Array.isArray(t)){const e=t.length;let r;for(const e of t){const t=ot(e);if(r){if(r===t)continue;r=U;break}r=t}return W(r||U,e)}return z}function at(t){const e=typeof t;return null===t?"":"string"===e||"number"===e||"boolean"===e?String(t):t instanceof J||t instanceof et||t instanceof rt?t.toString():JSON.stringify(t)}class st{constructor(t,e){this.type=t,this.value=e}static parse(t,e){if(2!==t.length)return e.error(`'literal' expression requires exactly one argument, but found ${t.length-1} instead.`);if(!it(t[1]))return e.error("invalid value");const r=t[1];let n=ot(r);const i=e.expectedType;return"array"!==n.kind||0!==n.N||!i||"array"!==i.kind||"number"==typeof i.N&&0!==i.N||(n=i),new st(n,r)}evaluate(){return this.value}eachChild(){}outputDefined(){return!0}serialize(){return"array"===this.type.kind||"object"===this.type.kind?["literal",this.value]:this.value instanceof J?["rgba"].concat(this.value.toArray()):this.value instanceof et?this.value.serialize():this.value}}class lt{constructor(t){this.name="ExpressionEvaluationError",this.message=t}toJSON(){return this.message}}const ut={string:N,number:j,boolean:D,object:z};class ct{constructor(t,e){this.type=t,this.args=e}static parse(t,e){if(t.length<2)return e.error("Expected at least one argument.");let r,n=1;const i=t[0];if("array"===i){let i,o;if(t.length>2){const r=t[1];if("string"!=typeof r||!(r in ut)||"object"===r)return e.error('The item type argument of "array" must be one of string, number, boolean',1);i=ut[r],n++}else i=U;if(t.length>3){if(null!==t[2]&&("number"!=typeof t[2]||t[2]<0||t[2]!==Math.floor(t[2])))return e.error('The length argument to "array" must be a positive integer literal',2);o=t[2],n++}r=W(i,o)}else r=ut[i];const o=[];for(;n<t.length;n++){const r=e.parse(t[n],n,U);if(!r)return null;o.push(r)}return new ct(r,o)}evaluate(t){for(let e=0;e<this.args.length;e++){const r=this.args[e].evaluate(t);if(!Z(this.type,ot(r)))return r;if(e===this.args.length-1)throw new lt(`Expected value to be of type ${q(this.type)}, but found ${q(ot(r))} instead.`)}return null}eachChild(t){this.args.forEach(t)}outputDefined(){return this.args.every(t=>t.outputDefined())}serialize(){const t=this.type,e=[t.kind];if("array"===t.kind){const r=t.itemType;if("string"===r.kind||"number"===r.kind||"boolean"===r.kind){e.push(r.kind);const n=t.N;("number"==typeof n||this.args.length>1)&&e.push(n)}}return e.concat(this.args.map(t=>t.serialize()))}}class ht{constructor(t){this.type=V,this.sections=t}static parse(t,e){if(t.length<2)return e.error("Expected at least one argument.");const r=t[1];if(!Array.isArray(r)&&"object"==typeof r)return e.error("First argument must be an image or text section.");const n=[];let i=!1;for(let r=1;r<=t.length-1;++r){const o=t[r];if(i&&"object"==typeof o&&!Array.isArray(o)){i=!1;let t=null;if(o["font-scale"]&&(t=e.parse(o["font-scale"],1,j),!t))return null;let r=null;if(o["text-font"]&&(r=e.parse(o["text-font"],1,W(N)),!r))return null;let a=null;if(o["text-color"]&&(a=e.parse(o["text-color"],1,G),!a))return null;const s=n[n.length-1];s.scale=t,s.font=r,s.textColor=a}else{const o=e.parse(t[r],1,U);if(!o)return null;const a=o.type.kind;if("string"!==a&&"value"!==a&&"null"!==a&&"resolvedImage"!==a)return e.error("Formatted text type must be 'string', 'value', 'image' or 'null'.");i=!0,n.push({content:o,scale:null,font:null,textColor:null})}}return new ht(n)}evaluate(t){return new et(this.sections.map(e=>{const r=e.content.evaluate(t);return ot(r)===Y?new tt("",r,null,null,null):new tt(at(r),null,e.scale?e.scale.evaluate(t):null,e.font?e.font.evaluate(t).join(","):null,e.textColor?e.textColor.evaluate(t):null)}))}eachChild(t){for(const e of this.sections)t(e.content),e.scale&&t(e.scale),e.font&&t(e.font),e.textColor&&t(e.textColor)}outputDefined(){return!1}serialize(){const t=["format"];for(const e of this.sections){t.push(e.content.serialize());const r={};e.scale&&(r["font-scale"]=e.scale.serialize()),e.font&&(r["text-font"]=e.font.serialize()),e.textColor&&(r["text-color"]=e.textColor.serialize()),t.push(r)}return t}}class pt{constructor(t){this.type=Y,this.input=t}static parse(t,e){if(2!==t.length)return e.error("Expected two arguments.");const r=e.parse(t[1],1,N);return r?new pt(r):e.error("No image name provided.")}evaluate(t){const e=this.input.evaluate(t),r=rt.fromString(e);return r&&t.availableImages&&(r.available=t.availableImages.indexOf(e)>-1),r}eachChild(t){t(this.input)}outputDefined(){return!1}serialize(){return["image",this.input.serialize()]}}const ft={"to-boolean":D,"to-color":G,"to-number":j,"to-string":N};class dt{constructor(t,e){this.type=t,this.args=e}static parse(t,e){if(t.length<2)return e.error("Expected at least one argument.");const r=t[0];if(("to-boolean"===r||"to-string"===r)&&2!==t.length)return e.error("Expected one argument.");const n=ft[r],i=[];for(let r=1;r<t.length;r++){const n=e.parse(t[r],r,U);if(!n)return null;i.push(n)}return new dt(n,i)}evaluate(t){if("boolean"===this.type.kind)return Boolean(this.args[0].evaluate(t));if("color"===this.type.kind){let e,r;for(const n of this.args){if(e=n.evaluate(t),r=null,e instanceof J)return e;if("string"==typeof e){const r=t.parseColor(e);if(r)return r}else if(Array.isArray(e)&&(r=e.length<3||e.length>4?`Invalid rbga value ${JSON.stringify(e)}: expected an array containing either three or four numeric values.`:nt(e[0],e[1],e[2],e[3]),!r))return new J(e[0]/255,e[1]/255,e[2]/255,e[3])}throw new lt(r||`Could not parse color from value '${"string"==typeof e?e:String(JSON.stringify(e))}'`)}if("number"===this.type.kind){let e=null;for(const r of this.args){if(e=r.evaluate(t),null===e)return 0;const n=Number(e);if(!isNaN(n))return n}throw new lt(`Could not convert ${JSON.stringify(e)} to number.`)}return"formatted"===this.type.kind?et.fromString(at(this.args[0].evaluate(t))):"resolvedImage"===this.type.kind?rt.fromString(at(this.args[0].evaluate(t))):at(this.args[0].evaluate(t))}eachChild(t){this.args.forEach(t)}outputDefined(){return this.args.every(t=>t.outputDefined())}serialize(){if("formatted"===this.type.kind)return new ht([{content:this.args[0],scale:null,font:null,textColor:null}]).serialize();if("resolvedImage"===this.type.kind)return new pt(this.args[0]).serialize();const t=["to-"+this.type.kind];return this.eachChild(e=>{t.push(e.serialize())}),t}}const gt=["Unknown","Point","LineString","Polygon"];class yt{constructor(){this.globals=null,this.feature=null,this.featureState=null,this.formattedSection=null,this._parseColorCache={},this.availableImages=null,this.canonical=null}id(){return this.feature&&"id"in this.feature?this.feature.id:null}geometryType(){return this.feature?"number"==typeof this.feature.type?gt[this.feature.type]:this.feature.type:null}geometry(){return this.feature&&"geometry"in this.feature?this.feature.geometry:null}canonicalID(){return this.canonical}properties(){return this.feature&&this.feature.properties||{}}parseColor(t){let e=this._parseColorCache[t];return e||(e=this._parseColorCache[t]=J.parse(t)),e}}class mt{constructor(t,e,r,n){this.name=t,this.type=e,this._evaluate=r,this.args=n}evaluate(t){return this._evaluate(t,this.args)}eachChild(t){this.args.forEach(t)}outputDefined(){return!1}serialize(){return[this.name].concat(this.args.map(t=>t.serialize()))}static parse(t,e){const r=t[0],n=mt.definitions[r];if(!n)return e.error(`Unknown expression "${r}". If you wanted a literal array, use ["literal", [...]].`,0);const i=Array.isArray(n)?n[0]:n.type,o=Array.isArray(n)?[[n[1],n[2]]]:n.overloads,a=o.filter(([e])=>!Array.isArray(e)||e.length===t.length-1);let s=null;for(const[n,o]of a){s=new zt(e.registry,e.path,null,e.scope);const a=[];let l=!1;for(let e=1;e<t.length;e++){const r=t[e],i=Array.isArray(n)?n[e-1]:n.type,o=s.parse(r,1+a.length,i);if(!o){l=!0;break}a.push(o)}if(!l)if(Array.isArray(n)&&n.length!==a.length)s.error(`Expected ${n.length} arguments, but found ${a.length} instead.`);else{for(let t=0;t<a.length;t++){const e=Array.isArray(n)?n[t]:n.type,r=a[t];s.concat(t+1).checkSubtype(e,r.type)}if(0===s.errors.length)return new mt(r,i,o,a)}}if(1===a.length)e.errors.push(...s.errors);else{const r=(a.length?a:o).map(([t])=>{return e=t,Array.isArray(e)?`(${e.map(q).join(", ")})`:`(${q(e.type)}...)`;var e}).join(" | "),n=[];for(let r=1;r<t.length;r++){const i=e.parse(t[r],1+n.length);if(!i)return null;n.push(q(i.type))}e.error(`Expected arguments of type ${r}, but found (${n.join(", ")}) instead.`)}return null}static register(t,e){mt.definitions=e;for(const r in e)t[r]=mt}}class vt{constructor(t,e,r){this.type=B,this.locale=r,this.caseSensitive=t,this.diacriticSensitive=e}static parse(t,e){if(2!==t.length)return e.error("Expected one argument.");const r=t[1];if("object"!=typeof r||Array.isArray(r))return e.error("Collator options argument must be an object.");const n=e.parse(void 0!==r["case-sensitive"]&&r["case-sensitive"],1,D);if(!n)return null;const i=e.parse(void 0!==r["diacritic-sensitive"]&&r["diacritic-sensitive"],1,D);if(!i)return null;let o=null;return r.locale&&(o=e.parse(r.locale,1,N),!o)?null:new vt(n,i,o)}evaluate(t){return new Q(this.caseSensitive.evaluate(t),this.diacriticSensitive.evaluate(t),this.locale?this.locale.evaluate(t):null)}eachChild(t){t(this.caseSensitive),t(this.diacriticSensitive),this.locale&&t(this.locale)}outputDefined(){return!1}serialize(){const t={};return t["case-sensitive"]=this.caseSensitive.serialize(),t["diacritic-sensitive"]=this.diacriticSensitive.serialize(),this.locale&&(t.locale=this.locale.serialize()),["collator",t]}}function _t(t,e){t[0]=Math.min(t[0],e[0]),t[1]=Math.min(t[1],e[1]),t[2]=Math.max(t[2],e[0]),t[3]=Math.max(t[3],e[1])}function bt(t,e){return!(t[0]<=e[0])&&(!(t[2]>=e[2])&&(!(t[1]<=e[1])&&!(t[3]>=e[3])))}function xt(t,e){const r=(180+t[0])/360;const n=(i=t[1],(180-180/Math.PI*Math.log(Math.tan(Math.PI/4+i*Math.PI/360)))/360);var i;const o=Math.pow(2,e.z);return[Math.round(r*o*8192),Math.round(n*o*8192)]}function wt(t,e,r){const n=t[0]-e[0],i=t[1]-e[1],o=t[0]-r[0],a=t[1]-r[1];return n*a-o*i==0&&n*o<=0&&i*a<=0}function St(t,e){let r=!1;for(let a=0,s=e.length;a<s;a++){const s=e[a];for(let e=0,a=s.length;e<a-1;e++){if(wt(t,s[e],s[e+1]))return!1;n=t,i=s[e],o=s[e+1],i[1]>n[1]!=o[1]>n[1]&&n[0]<(o[0]-i[0])*(n[1]-i[1])/(o[1]-i[1])+i[0]&&(r=!r)}}var n,i,o;return r}function Et(t,e){for(let r=0;r<e.length;r++)if(St(t,e[r]))return!0;return!1}function Tt(t,e,r,n){const i=t[0]-r[0],o=t[1]-r[1],a=e[0]-r[0],s=e[1]-r[1],l=n[0]-r[0],u=n[1]-r[1],c=i*u-l*o,h=a*u-l*s;return c>0&&h<0||c<0&&h>0}function Ct(t,e,r,n){const i=[e[0]-t[0],e[1]-t[1]],o=[n[0]-r[0],n[1]-r[1]];return 0!=(a=o)[0]*(s=i)[1]-a[1]*s[0]&&!(!Tt(t,e,r,n)||!Tt(r,n,t,e));var a,s}function Ot(t,e,r){for(const n of r)for(let r=0;r<n.length-1;++r)if(Ct(t,e,n[r],n[r+1]))return!0;return!1}function Pt(t,e){for(let r=0;r<t.length;++r)if(!St(t[r],e))return!1;for(let r=0;r<t.length-1;++r)if(Ot(t[r],t[r+1],e))return!1;return!0}function Rt(t,e){for(let r=0;r<e.length;r++)if(Pt(t,e[r]))return!0;return!1}function It(t,e,r){const n=[];for(let i=0;i<t.length;i++){const o=[];for(let n=0;n<t[i].length;n++){const a=xt(t[i][n],r);_t(e,a),o.push(a)}n.push(o)}return n}function Lt(t,e,r){const n=[];for(let i=0;i<t.length;i++){const o=It(t[i],e,r);n.push(o)}return n}function Mt(t,e,r,n){if(t[0]<r[0]||t[0]>r[2]){const e=.5*n;let i=t[0]-r[0]>e?-n:r[0]-t[0]>e?n:0;0===i&&(i=t[0]-r[2]>e?-n:r[2]-t[0]>e?n:0),t[0]+=i}_t(e,t)}function Ft(t,e,r,n){const i=8192*Math.pow(2,n.z),o=[8192*n.x,8192*n.y],a=[];for(const n of t)for(const t of n){const n=[t.x+o[0],t.y+o[1]];Mt(n,e,r,i),a.push(n)}return a}function At(t,e,r,n){const i=8192*Math.pow(2,n.z),o=[8192*n.x,8192*n.y],a=[];for(const r of t){const t=[];for(const n of r){const r=[n.x+o[0],n.y+o[1]];_t(e,r),t.push(r)}a.push(t)}if(e[2]-e[0]<=i/2){(s=e)[0]=s[1]=1/0,s[2]=s[3]=-1/0;for(const t of a)for(const n of t)Mt(n,e,r,i)}var s;return a}class kt{constructor(t,e){this.type=D,this.geojson=t,this.geometries=e}static parse(t,e){if(2!==t.length)return e.error(`'within' expression requires exactly one argument, but found ${t.length-1} instead.`);if(it(t[1])){const e=t[1];if("FeatureCollection"===e.type)for(let t=0;t<e.features.length;++t){const r=e.features[t].geometry.type;if("Polygon"===r||"MultiPolygon"===r)return new kt(e,e.features[t].geometry)}else if("Feature"===e.type){const t=e.geometry.type;if("Polygon"===t||"MultiPolygon"===t)return new kt(e,e.geometry)}else if("Polygon"===e.type||"MultiPolygon"===e.type)return new kt(e,e)}return e.error("'within' expression requires valid geojson object that contains polygon geometry type.")}evaluate(t){if(null!=t.geometry()&&null!=t.canonicalID()){if("Point"===t.geometryType())return function(t,e){const r=[1/0,1/0,-1/0,-1/0],n=[1/0,1/0,-1/0,-1/0],i=t.canonicalID();if("Polygon"===e.type){const o=It(e.coordinates,n,i),a=Ft(t.geometry(),r,n,i);if(!bt(r,n))return!1;for(const t of a)if(!St(t,o))return!1}if("MultiPolygon"===e.type){const o=Lt(e.coordinates,n,i),a=Ft(t.geometry(),r,n,i);if(!bt(r,n))return!1;for(const t of a)if(!Et(t,o))return!1}return!0}(t,this.geometries);if("LineString"===t.geometryType())return function(t,e){const r=[1/0,1/0,-1/0,-1/0],n=[1/0,1/0,-1/0,-1/0],i=t.canonicalID();if("Polygon"===e.type){const o=It(e.coordinates,n,i),a=At(t.geometry(),r,n,i);if(!bt(r,n))return!1;for(const t of a)if(!Pt(t,o))return!1}if("MultiPolygon"===e.type){const o=Lt(e.coordinates,n,i),a=At(t.geometry(),r,n,i);if(!bt(r,n))return!1;for(const t of a)if(!Rt(t,o))return!1}return!0}(t,this.geometries)}return!1}eachChild(){}outputDefined(){return!0}serialize(){return["within",this.geojson]}}function jt(t){if(t instanceof mt){if("get"===t.name&&1===t.args.length)return!1;if("feature-state"===t.name)return!1;if("has"===t.name&&1===t.args.length)return!1;if("properties"===t.name||"geometry-type"===t.name||"id"===t.name)return!1;if(/^filter-/.test(t.name))return!1}if(t instanceof kt)return!1;let e=!0;return t.eachChild(t=>{e&&!jt(t)&&(e=!1)}),e}function Nt(t){if(t instanceof mt&&"feature-state"===t.name)return!1;let e=!0;return t.eachChild(t=>{e&&!Nt(t)&&(e=!1)}),e}function Dt(t,e){if(t instanceof mt&&e.indexOf(t.name)>=0)return!1;let r=!0;return t.eachChild(t=>{r&&!Dt(t,e)&&(r=!1)}),r}class Gt{constructor(t,e){this.type=e.type,this.name=t,this.boundExpression=e}static parse(t,e){if(2!==t.length||"string"!=typeof t[1])return e.error("'var' expression requires exactly one string literal argument.");const r=t[1];return e.scope.has(r)?new Gt(r,e.scope.get(r)):e.error(`Unknown variable "${r}". Make sure "${r}" has been bound in an enclosing "let" expression before using it.`,1)}evaluate(t){return this.boundExpression.evaluate(t)}eachChild(){}outputDefined(){return!1}serialize(){return["var",this.name]}}class zt{constructor(t,e=[],r,n=new A,i=[]){this.registry=t,this.path=e,this.key=e.map(t=>`[${t}]`).join(""),this.scope=n,this.errors=i,this.expectedType=r}parse(t,e,r,n,i={}){return e?this.concat(e,r,n)._parse(t,i):this._parse(t,i)}_parse(t,e){function r(t,e,r){return"assert"===r?new ct(e,[t]):"coerce"===r?new dt(e,[t]):t}if(null!==t&&"string"!=typeof t&&"boolean"!=typeof t&&"number"!=typeof t||(t=["literal",t]),Array.isArray(t)){if(0===t.length)return this.error('Expected an array with at least one element. If you wanted a literal array, use ["literal", []].');const n=t[0];if("string"!=typeof n)return this.error(`Expression name must be a string, but found ${typeof n} instead. If you wanted a literal array, use ["literal", [...]].`,0),null;const i=this.registry[n];if(i){let n=i.parse(t,this);if(!n)return null;if(this.expectedType){const t=this.expectedType,i=n.type;if("string"!==t.kind&&"number"!==t.kind&&"boolean"!==t.kind&&"object"!==t.kind&&"array"!==t.kind||"value"!==i.kind)if("color"!==t.kind&&"formatted"!==t.kind&&"resolvedImage"!==t.kind||"value"!==i.kind&&"string"!==i.kind){if(this.checkSubtype(t,i))return null}else n=r(n,t,e.typeAnnotation||"coerce");else n=r(n,t,e.typeAnnotation||"assert")}if(!(n instanceof st)&&"resolvedImage"!==n.type.kind&&function t(e){if(e instanceof Gt)return t(e.boundExpression);if(e instanceof mt&&"error"===e.name)return!1;if(e instanceof vt)return!1;if(e instanceof kt)return!1;const r=e instanceof dt||e instanceof ct;let n=!0;if(e.eachChild(e=>{n=r?n&&t(e):n&&e instanceof st}),!n)return!1;return jt(e)&&Dt(e,["zoom","heatmap-density","line-progress","sky-radial-progress","accumulated","is-supported-script"])}(n)){const t=new yt;try{n=new st(n.type,n.evaluate(t))}catch(t){return this.error(t.message),null}}return n}return this.error(`Unknown expression "${n}". If you wanted a literal array, use ["literal", [...]].`,0)}return void 0===t?this.error("'undefined' value invalid. Use null instead."):"object"==typeof t?this.error('Bare objects invalid. Use ["literal", {...}] instead.'):this.error(`Expected an array, but found ${typeof t} instead.`)}concat(t,e,r){const n="number"==typeof t?this.path.concat(t):this.path,i=r?this.scope.concat(r):this.scope;return new zt(this.registry,n,e||null,i,this.errors)}error(t,...e){const r=`${this.key}${e.map(t=>`[${t}]`).join("")}`;this.errors.push(new F(r,t))}checkSubtype(t,e){const r=Z(t,e);return r&&this.error(r),r}}function Ut(t,e){const r=t.length-1;let n,i,o=0,a=r,s=0;for(;o<=a;)if(s=Math.floor((o+a)/2),n=t[s],i=t[s+1],n<=e){if(s===r||e<i)return s;o=s+1}else{if(!(n>e))throw new lt("Input is not a number.");a=s-1}return 0}class Bt{constructor(t,e,r){this.type=t,this.input=e,this.labels=[],this.outputs=[];for(const[t,e]of r)this.labels.push(t),this.outputs.push(e)}static parse(t,e){if(t.length-1<4)return e.error(`Expected at least 4 arguments, but found only ${t.length-1}.`);if((t.length-1)%2!=0)return e.error("Expected an even number of arguments.");const r=e.parse(t[1],1,j);if(!r)return null;const n=[];let i=null;e.expectedType&&"value"!==e.expectedType.kind&&(i=e.expectedType);for(let r=1;r<t.length;r+=2){const o=1===r?-1/0:t[r],a=t[r+1],s=r,l=r+1;if("number"!=typeof o)return e.error('Input/output pairs for "step" expressions must be defined using literal numeric values (not computed expressions) for the input values.',s);if(n.length&&n[n.length-1][0]>=o)return e.error('Input/output pairs for "step" expressions must be arranged with input values in strictly ascending order.',s);const u=e.parse(a,l,i);if(!u)return null;i=i||u.type,n.push([o,u])}return new Bt(i,r,n)}evaluate(t){const e=this.labels,r=this.outputs;if(1===e.length)return r[0].evaluate(t);const n=this.input.evaluate(t);if(n<=e[0])return r[0].evaluate(t);const i=e.length;if(n>=e[i-1])return r[i-1].evaluate(t);return r[Ut(e,n)].evaluate(t)}eachChild(t){t(this.input);for(const e of this.outputs)t(e)}outputDefined(){return this.outputs.every(t=>t.outputDefined())}serialize(){const t=["step",this.input.serialize()];for(let e=0;e<this.labels.length;e++)e>0&&t.push(this.labels[e]),t.push(this.outputs[e].serialize());return t}}var Vt=Yt;function Yt(t,e,r,n){this.cx=3*t,this.bx=3*(r-t)-this.cx,this.ax=1-this.cx-this.bx,this.cy=3*e,this.by=3*(n-e)-this.cy,this.ay=1-this.cy-this.by,this.p1x=t,this.p1y=n,this.p2x=r,this.p2y=n}function Wt(t,e,r){return t*(1-r)+e*r}Yt.prototype.sampleCurveX=function(t){return((this.ax*t+this.bx)*t+this.cx)*t},Yt.prototype.sampleCurveY=function(t){return((this.ay*t+this.by)*t+this.cy)*t},Yt.prototype.sampleCurveDerivativeX=function(t){return(3*this.ax*t+2*this.bx)*t+this.cx},Yt.prototype.solveCurveX=function(t,e){var r,n,i,o,a;for(void 0===e&&(e=1e-6),i=t,a=0;a<8;a++){if(o=this.sampleCurveX(i)-t,Math.abs(o)<e)return i;var s=this.sampleCurveDerivativeX(i);if(Math.abs(s)<1e-6)break;i-=o/s}if((i=t)<(r=0))return r;if(i>(n=1))return n;for(;r<n;){if(o=this.sampleCurveX(i),Math.abs(o-t)<e)return i;t>o?r=i:n=i,i=.5*(n-r)+r}return i},Yt.prototype.solve=function(t,e){return this.sampleCurveY(this.solveCurveX(t,e))};var qt=Object.freeze({__proto__:null,number:Wt,color:function(t,e,r){return new J(Wt(t.r,e.r,r),Wt(t.g,e.g,r),Wt(t.b,e.b,r),Wt(t.a,e.a,r))},array:function(t,e,r){return t.map((t,n)=>Wt(t,e[n],r))}});const Xt=6/29,Zt=3*Xt*Xt,Kt=Math.PI/180,Ht=180/Math.PI;function $t(t){return t>.008856451679035631?Math.pow(t,1/3):t/Zt+4/29}function Jt(t){return t>Xt?t*t*t:Zt*(t-4/29)}function Qt(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function te(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function ee(t){const e=te(t.r),r=te(t.g),n=te(t.b),i=$t((.4124564*e+.3575761*r+.1804375*n)/.95047),o=$t((.2126729*e+.7151522*r+.072175*n)/1);return{l:116*o-16,a:500*(i-o),b:200*(o-$t((.0193339*e+.119192*r+.9503041*n)/1.08883)),alpha:t.a}}function re(t){let e=(t.l+16)/116,r=isNaN(t.a)?e:e+t.a/500,n=isNaN(t.b)?e:e-t.b/200;return e=1*Jt(e),r=.95047*Jt(r),n=1.08883*Jt(n),new J(Qt(3.2404542*r-1.5371385*e-.4985314*n),Qt(-.969266*r+1.8760108*e+.041556*n),Qt(.0556434*r-.2040259*e+1.0572252*n),t.alpha)}function ne(t,e,r){const n=e-t;return t+r*(n>180||n<-180?n-360*Math.round(n/360):n)}const ie={forward:ee,reverse:re,interpolate:function(t,e,r){return{l:Wt(t.l,e.l,r),a:Wt(t.a,e.a,r),b:Wt(t.b,e.b,r),alpha:Wt(t.alpha,e.alpha,r)}}},oe={forward:function(t){const{l:e,a:r,b:n}=ee(t),i=Math.atan2(n,r)*Ht;return{h:i<0?i+360:i,c:Math.sqrt(r*r+n*n),l:e,alpha:t.a}},reverse:function(t){const e=t.h*Kt,r=t.c;return re({l:t.l,a:Math.cos(e)*r,b:Math.sin(e)*r,alpha:t.alpha})},interpolate:function(t,e,r){return{h:ne(t.h,e.h,r),c:Wt(t.c,e.c,r),l:Wt(t.l,e.l,r),alpha:Wt(t.alpha,e.alpha,r)}}};var ae=Object.freeze({__proto__:null,lab:ie,hcl:oe});class se{constructor(t,e,r,n,i){this.type=t,this.operator=e,this.interpolation=r,this.input=n,this.labels=[],this.outputs=[];for(const[t,e]of i)this.labels.push(t),this.outputs.push(e)}static interpolationFactor(t,e,r,n){let i=0;if("exponential"===t.name)i=le(e,t.base,r,n);else if("linear"===t.name)i=le(e,1,r,n);else if("cubic-bezier"===t.name){const o=t.controlPoints;i=new Vt(o[0],o[1],o[2],o[3]).solve(le(e,1,r,n))}return i}static parse(t,e){let[r,n,i,...o]=t;if(!Array.isArray(n)||0===n.length)return e.error("Expected an interpolation type expression.",1);if("linear"===n[0])n={name:"linear"};else if("exponential"===n[0]){const t=n[1];if("number"!=typeof t)return e.error("Exponential interpolation requires a numeric base.",1,1);n={name:"exponential",base:t}}else{if("cubic-bezier"!==n[0])return e.error("Unknown interpolation type "+String(n[0]),1,0);{const t=n.slice(1);if(4!==t.length||t.some(t=>"number"!=typeof t||t<0||t>1))return e.error("Cubic bezier interpolation requires four numeric arguments with values between 0 and 1.",1);n={name:"cubic-bezier",controlPoints:t}}}if(t.length-1<4)return e.error(`Expected at least 4 arguments, but found only ${t.length-1}.`);if((t.length-1)%2!=0)return e.error("Expected an even number of arguments.");if(i=e.parse(i,2,j),!i)return null;const a=[];let s=null;"interpolate-hcl"===r||"interpolate-lab"===r?s=G:e.expectedType&&"value"!==e.expectedType.kind&&(s=e.expectedType);for(let t=0;t<o.length;t+=2){const r=o[t],n=o[t+1],i=t+3,l=t+4;if("number"!=typeof r)return e.error('Input/output pairs for "interpolate" expressions must be defined using literal numeric values (not computed expressions) for the input values.',i);if(a.length&&a[a.length-1][0]>=r)return e.error('Input/output pairs for "interpolate" expressions must be arranged with input values in strictly ascending order.',i);const u=e.parse(n,l,s);if(!u)return null;s=s||u.type,a.push([r,u])}return"number"===s.kind||"color"===s.kind||"array"===s.kind&&"number"===s.itemType.kind&&"number"==typeof s.N?new se(s,r,n,i,a):e.error(`Type ${q(s)} is not interpolatable.`)}evaluate(t){const e=this.labels,r=this.outputs;if(1===e.length)return r[0].evaluate(t);const n=this.input.evaluate(t);if(n<=e[0])return r[0].evaluate(t);const i=e.length;if(n>=e[i-1])return r[i-1].evaluate(t);const o=Ut(e,n),a=e[o],s=e[o+1],l=se.interpolationFactor(this.interpolation,n,a,s),u=r[o].evaluate(t),c=r[o+1].evaluate(t);return"interpolate"===this.operator?qt[this.type.kind.toLowerCase()](u,c,l):"interpolate-hcl"===this.operator?oe.reverse(oe.interpolate(oe.forward(u),oe.forward(c),l)):ie.reverse(ie.interpolate(ie.forward(u),ie.forward(c),l))}eachChild(t){t(this.input);for(const e of this.outputs)t(e)}outputDefined(){return this.outputs.every(t=>t.outputDefined())}serialize(){let t;t="linear"===this.interpolation.name?["linear"]:"exponential"===this.interpolation.name?1===this.interpolation.base?["linear"]:["exponential",this.interpolation.base]:["cubic-bezier"].concat(this.interpolation.controlPoints);const e=[this.operator,t,this.input.serialize()];for(let t=0;t<this.labels.length;t++)e.push(this.labels[t],this.outputs[t].serialize());return e}}function le(t,e,r,n){const i=n-r,o=t-r;return 0===i?0:1===e?o/i:(Math.pow(e,o)-1)/(Math.pow(e,i)-1)}class ue{constructor(t,e){this.type=t,this.args=e}static parse(t,e){if(t.length<2)return e.error("Expectected at least one argument.");let r=null;const n=e.expectedType;n&&"value"!==n.kind&&(r=n);const i=[];for(const n of t.slice(1)){const t=e.parse(n,1+i.length,r,void 0,{typeAnnotation:"omit"});if(!t)return null;r=r||t.type,i.push(t)}const o=n&&i.some(t=>Z(n,t.type));return new ue(o?U:r,i)}evaluate(t){let e,r=null,n=0;for(const i of this.args)if(n++,r=i.evaluate(t),r&&r instanceof rt&&!r.available&&(e||(e=r.name),r=null,n===this.args.length&&(r=e)),null!==r)break;return r}eachChild(t){this.args.forEach(t)}outputDefined(){return this.args.every(t=>t.outputDefined())}serialize(){const t=["coalesce"];return this.eachChild(e=>{t.push(e.serialize())}),t}}class ce{constructor(t,e){this.type=e.type,this.bindings=[].concat(t),this.result=e}evaluate(t){return this.result.evaluate(t)}eachChild(t){for(const e of this.bindings)t(e[1]);t(this.result)}static parse(t,e){if(t.length<4)return e.error(`Expected at least 3 arguments, but found ${t.length-1} instead.`);const r=[];for(let n=1;n<t.length-1;n+=2){const i=t[n];if("string"!=typeof i)return e.error(`Expected string, but found ${typeof i} instead.`,n);if(/[^a-zA-Z0-9_]/.test(i))return e.error("Variable names must contain only alphanumeric characters or '_'.",n);const o=e.parse(t[n+1],n+1);if(!o)return null;r.push([i,o])}const n=e.parse(t[t.length-1],t.length-1,e.expectedType,r);return n?new ce(r,n):null}outputDefined(){return this.result.outputDefined()}serialize(){const t=["let"];for(const[e,r]of this.bindings)t.push(e,r.serialize());return t.push(this.result.serialize()),t}}class he{constructor(t,e,r){this.type=t,this.index=e,this.input=r}static parse(t,e){if(3!==t.length)return e.error(`Expected 2 arguments, but found ${t.length-1} instead.`);const r=e.parse(t[1],1,j),n=e.parse(t[2],2,W(e.expectedType||U));if(!r||!n)return null;const i=n.type;return new he(i.itemType,r,n)}evaluate(t){const e=this.index.evaluate(t),r=this.input.evaluate(t);if(e<0)throw new lt(`Array index out of bounds: ${e} < 0.`);if(e>=r.length)throw new lt(`Array index out of bounds: ${e} > ${r.length-1}.`);if(e!==Math.floor(e))throw new lt(`Array index must be an integer, but found ${e} instead.`);return r[e]}eachChild(t){t(this.index),t(this.input)}outputDefined(){return!1}serialize(){return["at",this.index.serialize(),this.input.serialize()]}}class pe{constructor(t,e){this.type=D,this.needle=t,this.haystack=e}static parse(t,e){if(3!==t.length)return e.error(`Expected 2 arguments, but found ${t.length-1} instead.`);const r=e.parse(t[1],1,U),n=e.parse(t[2],2,U);return r&&n?K(r.type,[D,N,j,k,U])?new pe(r,n):e.error(`Expected first argument to be of type boolean, string, number or null, but found ${q(r.type)} instead`):null}evaluate(t){const e=this.needle.evaluate(t),r=this.haystack.evaluate(t);if(!r)return!1;if(!H(e,["boolean","string","number","null"]))throw new lt(`Expected first argument to be of type boolean, string, number or null, but found ${q(ot(e))} instead.`);if(!H(r,["string","array"]))throw new lt(`Expected second argument to be of type array or string, but found ${q(ot(r))} instead.`);return r.indexOf(e)>=0}eachChild(t){t(this.needle),t(this.haystack)}outputDefined(){return!0}serialize(){return["in",this.needle.serialize(),this.haystack.serialize()]}}class fe{constructor(t,e,r){this.type=j,this.needle=t,this.haystack=e,this.fromIndex=r}static parse(t,e){if(t.length<=2||t.length>=5)return e.error(`Expected 3 or 4 arguments, but found ${t.length-1} instead.`);const r=e.parse(t[1],1,U),n=e.parse(t[2],2,U);if(!r||!n)return null;if(!K(r.type,[D,N,j,k,U]))return e.error(`Expected first argument to be of type boolean, string, number or null, but found ${q(r.type)} instead`);if(4===t.length){const i=e.parse(t[3],3,j);return i?new fe(r,n,i):null}return new fe(r,n)}evaluate(t){const e=this.needle.evaluate(t),r=this.haystack.evaluate(t);if(!H(e,["boolean","string","number","null"]))throw new lt(`Expected first argument to be of type boolean, string, number or null, but found ${q(ot(e))} instead.`);if(!H(r,["string","array"]))throw new lt(`Expected second argument to be of type array or string, but found ${q(ot(r))} instead.`);if(this.fromIndex){const n=this.fromIndex.evaluate(t);return r.indexOf(e,n)}return r.indexOf(e)}eachChild(t){t(this.needle),t(this.haystack),this.fromIndex&&t(this.fromIndex)}outputDefined(){return!1}serialize(){if(null!=this.fromIndex&&void 0!==this.fromIndex){const t=this.fromIndex.serialize();return["index-of",this.needle.serialize(),this.haystack.serialize(),t]}return["index-of",this.needle.serialize(),this.haystack.serialize()]}}class de{constructor(t,e,r,n,i,o){this.inputType=t,this.type=e,this.input=r,this.cases=n,this.outputs=i,this.otherwise=o}static parse(t,e){if(t.length<5)return e.error(`Expected at least 4 arguments, but found only ${t.length-1}.`);if(t.length%2!=1)return e.error("Expected an even number of arguments.");let r,n;e.expectedType&&"value"!==e.expectedType.kind&&(n=e.expectedType);const i={},o=[];for(let a=2;a<t.length-1;a+=2){let s=t[a];const l=t[a+1];Array.isArray(s)||(s=[s]);const u=e.concat(a);if(0===s.length)return u.error("Expected at least one branch label.");for(const t of s){if("number"!=typeof t&&"string"!=typeof t)return u.error("Branch labels must be numbers or strings.");if("number"==typeof t&&Math.abs(t)>Number.MAX_SAFE_INTEGER)return u.error(`Branch labels must be integers no larger than ${Number.MAX_SAFE_INTEGER}.`);if("number"==typeof t&&Math.floor(t)!==t)return u.error("Numeric branch labels must be integer values.");if(r){if(u.checkSubtype(r,ot(t)))return null}else r=ot(t);if(void 0!==i[String(t)])return u.error("Branch labels must be unique.");i[String(t)]=o.length}const c=e.parse(l,a,n);if(!c)return null;n=n||c.type,o.push(c)}const a=e.parse(t[1],1,U);if(!a)return null;const s=e.parse(t[t.length-1],t.length-1,n);return s?"value"!==a.type.kind&&e.concat(1).checkSubtype(r,a.type)?null:new de(r,n,a,i,o,s):null}evaluate(t){const e=this.input.evaluate(t);return(ot(e)===this.inputType&&this.outputs[this.cases[e]]||this.otherwise).evaluate(t)}eachChild(t){t(this.input),this.outputs.forEach(t),t(this.otherwise)}outputDefined(){return this.outputs.every(t=>t.outputDefined())&&this.otherwise.outputDefined()}serialize(){const t=["match",this.input.serialize()],e=Object.keys(this.cases).sort(),r=[],n={};for(const t of e){const e=n[this.cases[t]];void 0===e?(n[this.cases[t]]=r.length,r.push([this.cases[t],[t]])):r[e][1].push(t)}const i=t=>"number"===this.inputType.kind?Number(t):t;for(const[e,n]of r)1===n.length?t.push(i(n[0])):t.push(n.map(i)),t.push(this.outputs[e].serialize());return t.push(this.otherwise.serialize()),t}}class ge{constructor(t,e,r){this.type=t,this.branches=e,this.otherwise=r}static parse(t,e){if(t.length<4)return e.error(`Expected at least 3 arguments, but found only ${t.length-1}.`);if(t.length%2!=0)return e.error("Expected an odd number of arguments.");let r;e.expectedType&&"value"!==e.expectedType.kind&&(r=e.expectedType);const n=[];for(let i=1;i<t.length-1;i+=2){const o=e.parse(t[i],i,D);if(!o)return null;const a=e.parse(t[i+1],i+1,r);if(!a)return null;n.push([o,a]),r=r||a.type}const i=e.parse(t[t.length-1],t.length-1,r);return i?new ge(r,n,i):null}evaluate(t){for(const[e,r]of this.branches)if(e.evaluate(t))return r.evaluate(t);return this.otherwise.evaluate(t)}eachChild(t){for(const[e,r]of this.branches)t(e),t(r);t(this.otherwise)}outputDefined(){return this.branches.every(([t,e])=>e.outputDefined())&&this.otherwise.outputDefined()}serialize(){const t=["case"];return this.eachChild(e=>{t.push(e.serialize())}),t}}class ye{constructor(t,e,r,n){this.type=t,this.input=e,this.beginIndex=r,this.endIndex=n}static parse(t,e){if(t.length<=2||t.length>=5)return e.error(`Expected 3 or 4 arguments, but found ${t.length-1} instead.`);const r=e.parse(t[1],1,U),n=e.parse(t[2],2,j);if(!r||!n)return null;if(!K(r.type,[W(U),N,U]))return e.error(`Expected first argument to be of type array or string, but found ${q(r.type)} instead`);if(4===t.length){const i=e.parse(t[3],3,j);return i?new ye(r.type,r,n,i):null}return new ye(r.type,r,n)}evaluate(t){const e=this.input.evaluate(t),r=this.beginIndex.evaluate(t);if(!H(e,["string","array"]))throw new lt(`Expected first argument to be of type array or string, but found ${q(ot(e))} instead.`);if(this.endIndex){const n=this.endIndex.evaluate(t);return e.slice(r,n)}return e.slice(r)}eachChild(t){t(this.input),t(this.beginIndex),this.endIndex&&t(this.endIndex)}outputDefined(){return!1}serialize(){if(null!=this.endIndex&&void 0!==this.endIndex){const t=this.endIndex.serialize();return["slice",this.input.serialize(),this.beginIndex.serialize(),t]}return["slice",this.input.serialize(),this.beginIndex.serialize()]}}function me(t,e){return"=="===t||"!="===t?"boolean"===e.kind||"string"===e.kind||"number"===e.kind||"null"===e.kind||"value"===e.kind:"string"===e.kind||"number"===e.kind||"value"===e.kind}function ve(t,e,r,n){return 0===n.compare(e,r)}function _e(t,e,r){const n="=="!==t&&"!="!==t;return class i{constructor(t,e,r){this.type=D,this.lhs=t,this.rhs=e,this.collator=r,this.hasUntypedArgument="value"===t.type.kind||"value"===e.type.kind}static parse(t,e){if(3!==t.length&&4!==t.length)return e.error("Expected two or three arguments.");const r=t[0];let o=e.parse(t[1],1,U);if(!o)return null;if(!me(r,o.type))return e.concat(1).error(`"${r}" comparisons are not supported for type '${q(o.type)}'.`);let a=e.parse(t[2],2,U);if(!a)return null;if(!me(r,a.type))return e.concat(2).error(`"${r}" comparisons are not supported for type '${q(a.type)}'.`);if(o.type.kind!==a.type.kind&&"value"!==o.type.kind&&"value"!==a.type.kind)return e.error(`Cannot compare types '${q(o.type)}' and '${q(a.type)}'.`);n&&("value"===o.type.kind&&"value"!==a.type.kind?o=new ct(a.type,[o]):"value"!==o.type.kind&&"value"===a.type.kind&&(a=new ct(o.type,[a])));let s=null;if(4===t.length){if("string"!==o.type.kind&&"string"!==a.type.kind&&"value"!==o.type.kind&&"value"!==a.type.kind)return e.error("Cannot use collator to compare non-string types.");if(s=e.parse(t[3],3,B),!s)return null}return new i(o,a,s)}evaluate(i){const o=this.lhs.evaluate(i),a=this.rhs.evaluate(i);if(n&&this.hasUntypedArgument){const e=ot(o),r=ot(a);if(e.kind!==r.kind||"string"!==e.kind&&"number"!==e.kind)throw new lt(`Expected arguments for "${t}" to be (string, string) or (number, number), but found (${e.kind}, ${r.kind}) instead.`)}if(this.collator&&!n&&this.hasUntypedArgument){const t=ot(o),r=ot(a);if("string"!==t.kind||"string"!==r.kind)return e(i,o,a)}return this.collator?r(i,o,a,this.collator.evaluate(i)):e(i,o,a)}eachChild(t){t(this.lhs),t(this.rhs),this.collator&&t(this.collator)}outputDefined(){return!0}serialize(){const e=[t];return this.eachChild(t=>{e.push(t.serialize())}),e}}}const be=_e("==",(function(t,e,r){return e===r}),ve),xe=_e("!=",(function(t,e,r){return e!==r}),(function(t,e,r,n){return!ve(0,e,r,n)})),we=_e("<",(function(t,e,r){return e<r}),(function(t,e,r,n){return n.compare(e,r)<0})),Se=_e(">",(function(t,e,r){return e>r}),(function(t,e,r,n){return n.compare(e,r)>0})),Ee=_e("<=",(function(t,e,r){return e<=r}),(function(t,e,r,n){return n.compare(e,r)<=0})),Te=_e(">=",(function(t,e,r){return e>=r}),(function(t,e,r,n){return n.compare(e,r)>=0}));class Ce{constructor(t,e,r,n,i){this.type=N,this.number=t,this.locale=e,this.currency=r,this.minFractionDigits=n,this.maxFractionDigits=i}static parse(t,e){if(3!==t.length)return e.error("Expected two arguments.");const r=e.parse(t[1],1,j);if(!r)return null;const n=t[2];if("object"!=typeof n||Array.isArray(n))return e.error("NumberFormat options argument must be an object.");let i=null;if(n.locale&&(i=e.parse(n.locale,1,N),!i))return null;let o=null;if(n.currency&&(o=e.parse(n.currency,1,N),!o))return null;let a=null;if(n["min-fraction-digits"]&&(a=e.parse(n["min-fraction-digits"],1,j),!a))return null;let s=null;return n["max-fraction-digits"]&&(s=e.parse(n["max-fraction-digits"],1,j),!s)?null:new Ce(r,i,o,a,s)}evaluate(t){return new Intl.NumberFormat(this.locale?this.locale.evaluate(t):[],{style:this.currency?"currency":"decimal",currency:this.currency?this.currency.evaluate(t):void 0,minimumFractionDigits:this.minFractionDigits?this.minFractionDigits.evaluate(t):void 0,maximumFractionDigits:this.maxFractionDigits?this.maxFractionDigits.evaluate(t):void 0}).format(this.number.evaluate(t))}eachChild(t){t(this.number),this.locale&&t(this.locale),this.currency&&t(this.currency),this.minFractionDigits&&t(this.minFractionDigits),this.maxFractionDigits&&t(this.maxFractionDigits)}outputDefined(){return!1}serialize(){const t={};return this.locale&&(t.locale=this.locale.serialize()),this.currency&&(t.currency=this.currency.serialize()),this.minFractionDigits&&(t["min-fraction-digits"]=this.minFractionDigits.serialize()),this.maxFractionDigits&&(t["max-fraction-digits"]=this.maxFractionDigits.serialize()),["number-format",this.number.serialize(),t]}}class Oe{constructor(t){this.type=j,this.input=t}static parse(t,e){if(2!==t.length)return e.error(`Expected 1 argument, but found ${t.length-1} instead.`);const r=e.parse(t[1],1);return r?"array"!==r.type.kind&&"string"!==r.type.kind&&"value"!==r.type.kind?e.error(`Expected argument of type string or array, but found ${q(r.type)} instead.`):new Oe(r):null}evaluate(t){const e=this.input.evaluate(t);if("string"==typeof e)return e.length;if(Array.isArray(e))return e.length;throw new lt(`Expected value to be of type string or array, but found ${q(ot(e))} instead.`)}eachChild(t){t(this.input)}outputDefined(){return!1}serialize(){const t=["length"];return this.eachChild(e=>{t.push(e.serialize())}),t}}const Pe={"==":be,"!=":xe,">":Se,"<":we,">=":Te,"<=":Ee,array:ct,at:he,boolean:ct,case:ge,coalesce:ue,collator:vt,format:ht,image:pt,in:pe,"index-of":fe,interpolate:se,"interpolate-hcl":se,"interpolate-lab":se,length:Oe,let:ce,literal:st,match:de,number:ct,"number-format":Ce,object:ct,slice:ye,step:Bt,string:ct,"to-boolean":dt,"to-color":dt,"to-number":dt,"to-string":dt,var:Gt,within:kt};function Re(t,[e,r,n,i]){e=e.evaluate(t),r=r.evaluate(t),n=n.evaluate(t);const o=i?i.evaluate(t):1,a=nt(e,r,n,o);if(a)throw new lt(a);return new J(e/255*o,r/255*o,n/255*o,o)}function Ie(t,e){return t in e}function Le(t,e){const r=e[t];return void 0===r?null:r}function Me(t){return{type:t}}function Fe(t){return{result:"success",value:t}}function Ae(t){return{result:"error",value:t}}function ke(t){return"data-driven"===t["property-type"]||"cross-faded-data-driven"===t["property-type"]}function je(t){return!!t.expression&&t.expression.parameters.indexOf("zoom")>-1}function Ne(t){return!!t.expression&&t.expression.interpolated}function De(t){return t instanceof Number?"number":t instanceof String?"string":t instanceof Boolean?"boolean":Array.isArray(t)?"array":null===t?"null":typeof t}function Ge(t){return"object"==typeof t&&null!==t&&!Array.isArray(t)}function ze(t){return t}function Ue(t,e){const r="color"===e.type,n=t.stops&&"object"==typeof t.stops[0][0],i=n||void 0!==t.property,o=n||!i,a=t.type||(Ne(e)?"exponential":"interval");if(r&&((t=M({},t)).stops&&(t.stops=t.stops.map(t=>[t[0],J.parse(t[1])])),t.default?t.default=J.parse(t.default):t.default=J.parse(e.default)),t.colorSpace&&"rgb"!==t.colorSpace&&!ae[t.colorSpace])throw new Error("Unknown color space: "+t.colorSpace);let s,l,u;if("exponential"===a)s=We;else if("interval"===a)s=Ye;else if("categorical"===a){s=Ve,l=Object.create(null);for(const e of t.stops)l[e[0]]=e[1];u=typeof t.stops[0][0]}else{if("identity"!==a)throw new Error(`Unknown function type "${a}"`);s=qe}if(n){const r={},n=[];for(let e=0;e<t.stops.length;e++){const i=t.stops[e],o=i[0].zoom;void 0===r[o]&&(r[o]={zoom:o,type:t.type,property:t.property,default:t.default,stops:[]},n.push(o)),r[o].stops.push([i[0].value,i[1]])}const i=[];for(const t of n)i.push([r[t].zoom,Ue(r[t],e)]);const o={name:"linear"};return{kind:"composite",interpolationType:o,interpolationFactor:se.interpolationFactor.bind(void 0,o),zoomStops:i.map(t=>t[0]),evaluate:({zoom:r},n)=>We({stops:i,base:t.base},e,r).evaluate(r,n)}}if(o){const r="exponential"===a?{name:"exponential",base:void 0!==t.base?t.base:1}:null;return{kind:"camera",interpolationType:r,interpolationFactor:se.interpolationFactor.bind(void 0,r),zoomStops:t.stops.map(t=>t[0]),evaluate:({zoom:r})=>s(t,e,r,l,u)}}return{kind:"source",evaluate(r,n){const i=n&&n.properties?n.properties[t.property]:void 0;return void 0===i?Be(t.default,e.default):s(t,e,i,l,u)}}}function Be(t,e,r){return void 0!==t?t:void 0!==e?e:void 0!==r?r:void 0}function Ve(t,e,r,n,i){return Be(typeof r===i?n[r]:void 0,t.default,e.default)}function Ye(t,e,r){if("number"!==De(r))return Be(t.default,e.default);const n=t.stops.length;if(1===n)return t.stops[0][1];if(r<=t.stops[0][0])return t.stops[0][1];if(r>=t.stops[n-1][0])return t.stops[n-1][1];const i=Ut(t.stops.map(t=>t[0]),r);return t.stops[i][1]}function We(t,e,r){const n=void 0!==t.base?t.base:1;if("number"!==De(r))return Be(t.default,e.default);const i=t.stops.length;if(1===i)return t.stops[0][1];if(r<=t.stops[0][0])return t.stops[0][1];if(r>=t.stops[i-1][0])return t.stops[i-1][1];const o=Ut(t.stops.map(t=>t[0]),r),a=function(t,e,r,n){const i=n-r,o=t-r;return 0===i?0:1===e?o/i:(Math.pow(e,o)-1)/(Math.pow(e,i)-1)}(r,n,t.stops[o][0],t.stops[o+1][0]),s=t.stops[o][1],l=t.stops[o+1][1];let u=qt[e.type]||ze;if(t.colorSpace&&"rgb"!==t.colorSpace){const e=ae[t.colorSpace];u=(t,r)=>e.reverse(e.interpolate(e.forward(t),e.forward(r),a))}return"function"==typeof s.evaluate?{evaluate(...t){const e=s.evaluate.apply(void 0,t),r=l.evaluate.apply(void 0,t);if(void 0!==e&&void 0!==r)return u(e,r,a)}}:u(s,l,a)}function qe(t,e,r){return"color"===e.type?r=J.parse(r):"formatted"===e.type?r=et.fromString(r.toString()):"resolvedImage"===e.type?r=rt.fromString(r.toString()):De(r)===e.type||"enum"===e.type&&e.values[r]||(r=void 0),Be(r,t.default,e.default)}mt.register(Pe,{error:[{kind:"error"},[N],(t,[e])=>{throw new lt(e.evaluate(t))}],typeof:[N,[U],(t,[e])=>q(ot(e.evaluate(t)))],"to-rgba":[W(j,4),[G],(t,[e])=>e.evaluate(t).toArray()],rgb:[G,[j,j,j],Re],rgba:[G,[j,j,j,j],Re],has:{type:D,overloads:[[[N],(t,[e])=>Ie(e.evaluate(t),t.properties())],[[N,z],(t,[e,r])=>Ie(e.evaluate(t),r.evaluate(t))]]},get:{type:U,overloads:[[[N],(t,[e])=>Le(e.evaluate(t),t.properties())],[[N,z],(t,[e,r])=>Le(e.evaluate(t),r.evaluate(t))]]},"feature-state":[U,[N],(t,[e])=>Le(e.evaluate(t),t.featureState||{})],properties:[z,[],t=>t.properties()],"geometry-type":[N,[],t=>t.geometryType()],id:[U,[],t=>t.id()],zoom:[j,[],t=>t.globals.zoom],"heatmap-density":[j,[],t=>t.globals.heatmapDensity||0],"line-progress":[j,[],t=>t.globals.lineProgress||0],"sky-radial-progress":[j,[],t=>t.globals.skyRadialProgress||0],accumulated:[U,[],t=>void 0===t.globals.accumulated?null:t.globals.accumulated],"+":[j,Me(j),(t,e)=>{let r=0;for(const n of e)r+=n.evaluate(t);return r}],"*":[j,Me(j),(t,e)=>{let r=1;for(const n of e)r*=n.evaluate(t);return r}],"-":{type:j,overloads:[[[j,j],(t,[e,r])=>e.evaluate(t)-r.evaluate(t)],[[j],(t,[e])=>-e.evaluate(t)]]},"/":[j,[j,j],(t,[e,r])=>e.evaluate(t)/r.evaluate(t)],"%":[j,[j,j],(t,[e,r])=>e.evaluate(t)%r.evaluate(t)],ln2:[j,[],()=>Math.LN2],pi:[j,[],()=>Math.PI],e:[j,[],()=>Math.E],"^":[j,[j,j],(t,[e,r])=>Math.pow(e.evaluate(t),r.evaluate(t))],sqrt:[j,[j],(t,[e])=>Math.sqrt(e.evaluate(t))],log10:[j,[j],(t,[e])=>Math.log(e.evaluate(t))/Math.LN10],ln:[j,[j],(t,[e])=>Math.log(e.evaluate(t))],log2:[j,[j],(t,[e])=>Math.log(e.evaluate(t))/Math.LN2],sin:[j,[j],(t,[e])=>Math.sin(e.evaluate(t))],cos:[j,[j],(t,[e])=>Math.cos(e.evaluate(t))],tan:[j,[j],(t,[e])=>Math.tan(e.evaluate(t))],asin:[j,[j],(t,[e])=>Math.asin(e.evaluate(t))],acos:[j,[j],(t,[e])=>Math.acos(e.evaluate(t))],atan:[j,[j],(t,[e])=>Math.atan(e.evaluate(t))],min:[j,Me(j),(t,e)=>Math.min(...e.map(e=>e.evaluate(t)))],max:[j,Me(j),(t,e)=>Math.max(...e.map(e=>e.evaluate(t)))],abs:[j,[j],(t,[e])=>Math.abs(e.evaluate(t))],round:[j,[j],(t,[e])=>{const r=e.evaluate(t);return r<0?-Math.round(-r):Math.round(r)}],floor:[j,[j],(t,[e])=>Math.floor(e.evaluate(t))],ceil:[j,[j],(t,[e])=>Math.ceil(e.evaluate(t))],"filter-==":[D,[N,U],(t,[e,r])=>t.properties()[e.value]===r.value],"filter-id-==":[D,[U],(t,[e])=>t.id()===e.value],"filter-type-==":[D,[N],(t,[e])=>t.geometryType()===e.value],"filter-<":[D,[N,U],(t,[e,r])=>{const n=t.properties()[e.value],i=r.value;return typeof n==typeof i&&n<i}],"filter-id-<":[D,[U],(t,[e])=>{const r=t.id(),n=e.value;return typeof r==typeof n&&r<n}],"filter->":[D,[N,U],(t,[e,r])=>{const n=t.properties()[e.value],i=r.value;return typeof n==typeof i&&n>i}],"filter-id->":[D,[U],(t,[e])=>{const r=t.id(),n=e.value;return typeof r==typeof n&&r>n}],"filter-<=":[D,[N,U],(t,[e,r])=>{const n=t.properties()[e.value],i=r.value;return typeof n==typeof i&&n<=i}],"filter-id-<=":[D,[U],(t,[e])=>{const r=t.id(),n=e.value;return typeof r==typeof n&&r<=n}],"filter->=":[D,[N,U],(t,[e,r])=>{const n=t.properties()[e.value],i=r.value;return typeof n==typeof i&&n>=i}],"filter-id->=":[D,[U],(t,[e])=>{const r=t.id(),n=e.value;return typeof r==typeof n&&r>=n}],"filter-has":[D,[U],(t,[e])=>e.value in t.properties()],"filter-has-id":[D,[],t=>null!==t.id()&&void 0!==t.id()],"filter-type-in":[D,[W(N)],(t,[e])=>e.value.indexOf(t.geometryType())>=0],"filter-id-in":[D,[W(U)],(t,[e])=>e.value.indexOf(t.id())>=0],"filter-in-small":[D,[N,W(U)],(t,[e,r])=>r.value.indexOf(t.properties()[e.value])>=0],"filter-in-large":[D,[N,W(U)],(t,[e,r])=>function(t,e,r,n){for(;r<=n;){const i=r+n>>1;if(e[i]===t)return!0;e[i]>t?n=i-1:r=i+1}return!1}(t.properties()[e.value],r.value,0,r.value.length-1)],all:{type:D,overloads:[[[D,D],(t,[e,r])=>e.evaluate(t)&&r.evaluate(t)],[Me(D),(t,e)=>{for(const r of e)if(!r.evaluate(t))return!1;return!0}]]},any:{type:D,overloads:[[[D,D],(t,[e,r])=>e.evaluate(t)||r.evaluate(t)],[Me(D),(t,e)=>{for(const r of e)if(r.evaluate(t))return!0;return!1}]]},"!":[D,[D],(t,[e])=>!e.evaluate(t)],"is-supported-script":[D,[N],(t,[e])=>{const r=t.globals&&t.globals.isSupportedScript;return!r||r(e.evaluate(t))}],upcase:[N,[N],(t,[e])=>e.evaluate(t).toUpperCase()],downcase:[N,[N],(t,[e])=>e.evaluate(t).toLowerCase()],concat:[N,Me(U),(t,e)=>e.map(e=>at(e.evaluate(t))).join("")],"resolved-locale":[N,[B],(t,[e])=>e.evaluate(t).resolvedLocale()]});class Xe{constructor(t,e){var r;this.expression=t,this._warningHistory={},this._evaluator=new yt,this._defaultValue=e?"color"===(r=e).type&&Ge(r.default)?new J(0,0,0,0):"color"===r.type?J.parse(r.default)||null:void 0===r.default?null:r.default:null,this._enumValues=e&&"enum"===e.type?e.values:null}evaluateWithoutErrorHandling(t,e,r,n,i,o){return this._evaluator.globals=t,this._evaluator.feature=e,this._evaluator.featureState=r,this._evaluator.canonical=n,this._evaluator.availableImages=i||null,this._evaluator.formattedSection=o,this.expression.evaluate(this._evaluator)}evaluate(t,e,r,n,i,o){this._evaluator.globals=t,this._evaluator.feature=e||null,this._evaluator.featureState=r||null,this._evaluator.canonical=n,this._evaluator.availableImages=i||null,this._evaluator.formattedSection=o||null;try{const t=this.expression.evaluate(this._evaluator);if(null==t||"number"==typeof t&&t!=t)return this._defaultValue;if(this._enumValues&&!(t in this._enumValues))throw new lt(`Expected value to be one of ${Object.keys(this._enumValues).map(t=>JSON.stringify(t)).join(", ")}, but found ${JSON.stringify(t)} instead.`);return t}catch(t){return this._warningHistory[t.message]||(this._warningHistory[t.message]=!0,"undefined"!=typeof console&&console.warn(t.message)),this._defaultValue}}}function Ze(t){return Array.isArray(t)&&t.length>0&&"string"==typeof t[0]&&t[0]in Pe}function Ke(t,e){const r=new zt(Pe,[],e?function(t){const e={color:G,string:N,number:j,enum:N,boolean:D,formatted:V,resolvedImage:Y};if("array"===t.type)return W(e[t.value]||U,t.length);return e[t.type]}(e):void 0),n=r.parse(t,void 0,void 0,void 0,e&&"string"===e.type?{typeAnnotation:"coerce"}:void 0);return n?Fe(new Xe(n,e)):Ae(r.errors)}class He{constructor(t,e){this.kind=t,this._styleExpression=e,this.isStateDependent="constant"!==t&&!Nt(e.expression)}evaluateWithoutErrorHandling(t,e,r,n,i,o){return this._styleExpression.evaluateWithoutErrorHandling(t,e,r,n,i,o)}evaluate(t,e,r,n,i,o){return this._styleExpression.evaluate(t,e,r,n,i,o)}}class $e{constructor(t,e,r,n){this.kind=t,this.zoomStops=r,this._styleExpression=e,this.isStateDependent="camera"!==t&&!Nt(e.expression),this.interpolationType=n}evaluateWithoutErrorHandling(t,e,r,n,i,o){return this._styleExpression.evaluateWithoutErrorHandling(t,e,r,n,i,o)}evaluate(t,e,r,n,i,o){return this._styleExpression.evaluate(t,e,r,n,i,o)}interpolationFactor(t,e,r){return this.interpolationType?se.interpolationFactor(this.interpolationType,t,e,r):0}}function Je(t,e){if("error"===(t=Ke(t,e)).result)return t;const r=t.value.expression,n=jt(r);if(!n&&!ke(e))return Ae([new F("","data expressions not supported")]);const i=Dt(r,["zoom"]);if(!i&&!je(e))return Ae([new F("","zoom expressions not supported")]);const o=function t(e){let r=null;if(e instanceof ce)r=t(e.result);else if(e instanceof ue){for(const n of e.args)if(r=t(n),r)break}else(e instanceof Bt||e instanceof se)&&e.input instanceof mt&&"zoom"===e.input.name&&(r=e);if(r instanceof F)return r;return e.eachChild(e=>{const n=t(e);n instanceof F?r=n:!r&&n?r=new F("",'"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.'):r&&n&&r!==n&&(r=new F("",'Only one zoom-based "step" or "interpolate" subexpression may be used in an expression.'))}),r}(r);if(!o&&!i)return Ae([new F("",'"zoom" expression may only be used as input to a top-level "step" or "interpolate" expression.')]);if(o instanceof F)return Ae([o]);if(o instanceof se&&!Ne(e))return Ae([new F("",'"interpolate" expressions cannot be used with this property')]);if(!o)return Fe(new He(n?"constant":"source",t.value));const a=o instanceof se?o.interpolation:void 0;return Fe(new $e(n?"camera":"composite",t.value,o.labels,a))}class Qe{constructor(t,e){this._parameters=t,this._specification=e,M(this,Ue(this._parameters,this._specification))}static deserialize(t){return new Qe(t._parameters,t._specification)}static serialize(t){return{_parameters:t._parameters,_specification:t._specification}}}function tr(t){return"object"==typeof t?["literal",t]:t}function er(t,e){let r=t.stops;if(!r)return function(t,e){const r=["get",t.property];if(void 0===t.default)return"string"===e.type?["string",r]:r;if("enum"===e.type)return["match",r,Object.keys(e.values),r,t.default];{const n=["color"===e.type?"to-color":e.type,r,tr(t.default)];return"array"===e.type&&n.splice(1,0,e.value,e.length||null),n}}(t,e);const n=r&&"object"==typeof r[0][0],i=n||void 0!==t.property,o=n||!i;return r=r.map(t=>!i&&e.tokens&&"string"==typeof t[1]?[t[0],lr(t[1])]:[t[0],tr(t[1])]),n?function(t,e,r){const n={},i={},o=[];for(let e=0;e<r.length;e++){const a=r[e],s=a[0].zoom;void 0===n[s]&&(n[s]={zoom:s,type:t.type,property:t.property,default:t.default},i[s]=[],o.push(s)),i[s].push([a[0].value,a[1]])}if("exponential"===sr({},e)){const r=[rr(t),["linear"],["zoom"]];for(const t of o){const o=ir(n[t],e,i[t]);ar(r,t,o,!1)}return r}{const t=["step",["zoom"]];for(const r of o){const o=ir(n[r],e,i[r]);ar(t,r,o,!0)}return or(t),t}}(t,e,r):o?function(t,e,r,n=["zoom"]){const i=sr(t,e);let o,a=!1;if("interval"===i)o=["step",n],a=!0;else{if("exponential"!==i)throw new Error(`Unknown zoom function type "${i}"`);{const e=void 0!==t.base?t.base:1;o=[rr(t),1===e?["linear"]:["exponential",e],n]}}for(const t of r)ar(o,t[0],t[1],a);return or(o),o}(t,e,r):ir(t,e,r)}function rr(t){switch(t.colorSpace){case"hcl":return"interpolate-hcl";case"lab":return"interpolate-lab";default:return"interpolate"}}function nr(t,e){const r=tr((n=t.default,i=e.default,void 0!==n?n:void 0!==i?i:void 0));var n,i;return void 0===r&&"resolvedImage"===e.type?"":r}function ir(t,e,r){const n=sr(t,e),i=["get",t.property];if("categorical"===n&&"boolean"==typeof r[0][0]){const n=["case"];for(const t of r)n.push(["==",i,t[0]],t[1]);return n.push(nr(t,e)),n}if("categorical"===n){const n=["match",i];for(const t of r)ar(n,t[0],t[1],!1);return n.push(nr(t,e)),n}if("interval"===n){const e=["step",["number",i]];for(const t of r)ar(e,t[0],t[1],!0);return or(e),void 0===t.default?e:["case",["==",["typeof",i],"number"],e,tr(t.default)]}if("exponential"===n){const e=void 0!==t.base?t.base:1,n=[rr(t),1===e?["linear"]:["exponential",e],["number",i]];for(const t of r)ar(n,t[0],t[1],!1);return void 0===t.default?n:["case",["==",["typeof",i],"number"],n,tr(t.default)]}throw new Error("Unknown property function type "+n)}function or(t){"step"===t[0]&&3===t.length&&(t.push(0),t.push(t[3]))}function ar(t,e,r,n){t.length>3&&e===t[t.length-2]||(n&&2===t.length||t.push(e),t.push(r))}function sr(t,e){return t.type?t.type:e.expression.interpolated?"exponential":"interval"}function lr(t){const e=["concat"],r=/{([^{}]+)}/g;let n=0;for(let i=r.exec(t);null!==i;i=r.exec(t)){const o=t.slice(n,r.lastIndex-i[0].length);n=r.lastIndex,o.length>0&&e.push(o),e.push(["get",i[1]])}if(1===e.length)return t;if(n<t.length)e.push(t.slice(n));else if(2===e.length)return["to-string",e[1]];return e}function ur(t){if(!0===t||!1===t)return!0;if(!Array.isArray(t)||0===t.length)return!1;switch(t[0]){case"has":return t.length>=2&&"$id"!==t[1]&&"$type"!==t[1];case"in":return t.length>=3&&("string"!=typeof t[1]||Array.isArray(t[2]));case"!in":case"!has":case"none":return!1;case"==":case"!=":case">":case">=":case"<":case"<=":return 3!==t.length||Array.isArray(t[1])||Array.isArray(t[2]);case"any":case"all":for(const e of t.slice(1))if(!ur(e)&&"boolean"!=typeof e)return!1;return!0;default:return!0}}const cr={type:"boolean",default:!1,transition:!1,"property-type":"data-driven",expression:{interpolated:!1,parameters:["zoom","feature"]}};function hr(t){if(null==t)return{filter:()=>!0,needGeometry:!1};ur(t)||(t=fr(t));const e=Ke(t,cr);if("error"===e.result)throw new Error(e.value.map(t=>`${t.key}: ${t.message}`).join(", "));return{filter:(t,r,n)=>e.value.evaluate(t,r,{},n),needGeometry:function t(e){if(!Array.isArray(e))return!1;if("within"===e[0])return!0;for(let r=1;r<e.length;r++)if(t(e[r]))return!0;return!1}(t)}}function pr(t,e){return t<e?-1:t>e?1:0}function fr(t){if(!t)return!0;const e=t[0];if(t.length<=1)return"any"!==e;var r;return"=="===e?dr(t[1],t[2],"=="):"!="===e?mr(dr(t[1],t[2],"==")):"<"===e||">"===e||"<="===e||">="===e?dr(t[1],t[2],e):"any"===e?(r=t.slice(1),["any"].concat(r.map(fr))):"all"===e?["all"].concat(t.slice(1).map(fr)):"none"===e?["all"].concat(t.slice(1).map(fr).map(mr)):"in"===e?gr(t[1],t.slice(2)):"!in"===e?mr(gr(t[1],t.slice(2))):"has"===e?yr(t[1]):"!has"===e?mr(yr(t[1])):"within"!==e||t}function dr(t,e,r){switch(t){case"$type":return["filter-type-"+r,e];case"$id":return["filter-id-"+r,e];default:return["filter-"+r,t,e]}}function gr(t,e){if(0===e.length)return!1;switch(t){case"$type":return["filter-type-in",["literal",e]];case"$id":return["filter-id-in",["literal",e]];default:return e.length>200&&!e.some(t=>typeof t!=typeof e[0])?["filter-in-large",t,["literal",e.sort(pr)]]:["filter-in-small",t,["literal",e]]}}function yr(t){switch(t){case"$type":return!0;case"$id":return["filter-has-id"];default:return["filter-has",t]}}function mr(t){return["!",t]}var vr=["type","source","source-layer","minzoom","maxzoom","filter","layout"];function _r(t,e){const r={};for(const e in t)"ref"!==e&&(r[e]=t[e]);return vr.forEach(t=>{t in e&&(r[t]=e[t])}),r}function br(t){t=t.slice();const e=Object.create(null);for(let r=0;r<t.length;r++)e[t[r].id]=t[r];for(let r=0;r<t.length;r++)"ref"in t[r]&&(t[r]=_r(t[r],e[t[r].ref]));return t}class xr{constructor(t,e,r,n){this.message=(t?t+": ":"")+r,n&&(this.identifier=n),null!=e&&e.__line__&&(this.line=e.__line__)}}class wr{constructor(t){this.error=t,this.message=t.message;const e=t.message.match(/line (\d+)/);this.line=e?parseInt(e[1],10):0}}function Sr(t){const e=t.key,r=t.value;return r?[new xr(e,r,"constants have been deprecated as of v8")]:[]}function Er(t){return t instanceof Number||t instanceof String||t instanceof Boolean?t.valueOf():t}function Tr(t){if(Array.isArray(t))return t.map(Tr);if(t instanceof Object&&!(t instanceof Number||t instanceof String||t instanceof Boolean)){const e={};for(const r in t)e[r]=Tr(t[r]);return e}return Er(t)}function Cr(t){const e=t.key,r=t.value,n=t.valueSpec||{},i=t.objectElementValidators||{},o=t.style,a=t.styleSpec;let s=[];const l=De(r);if("object"!==l)return[new xr(e,r,`object expected, ${l} found`)];for(const t in r){const l=t.split(".")[0],u=n[l]||n["*"];let c;if(i[l])c=i[l];else if(n[l])c=Vr;else if(i["*"])c=i["*"];else{if(!n["*"]){s.push(new xr(e,r[t],`unknown property "${t}"`));continue}c=Vr}s=s.concat(c({key:(e?e+".":e)+t,value:r[t],valueSpec:u,style:o,styleSpec:a,object:r,objectKey:t},r))}for(const t in n)i[t]||n[t].required&&void 0===n[t].default&&void 0===r[t]&&s.push(new xr(e,r,`missing required property "${t}"`));return s}function Or(t){const e=t.value,r=t.valueSpec,n=t.style,i=t.styleSpec,o=t.key,a=t.arrayElementValidator||Vr;if("array"!==De(e))return[new xr(o,e,`array expected, ${De(e)} found`)];if(r.length&&e.length!==r.length)return[new xr(o,e,`array length ${r.length} expected, length ${e.length} found`)];if(r["min-length"]&&e.length<r["min-length"])return[new xr(o,e,`array length at least ${r["min-length"]} expected, length ${e.length} found`)];let s={type:r.value,values:r.values};i.$version<7&&(s.function=r.function),"object"===De(r.value)&&(s=r.value);let l=[];for(let t=0;t<e.length;t++)l=l.concat(a({array:e,arrayIndex:t,value:e[t],valueSpec:s,style:n,styleSpec:i,key:`${o}[${t}]`}));return l}function Pr(t){const e=t.key,r=t.value,n=t.valueSpec;let i=De(r);return"number"===i&&r!=r&&(i="NaN"),"number"!==i?[new xr(e,r,`number expected, ${i} found`)]:"minimum"in n&&r<n.minimum?[new xr(e,r,`${r} is less than the minimum value ${n.minimum}`)]:"maximum"in n&&r>n.maximum?[new xr(e,r,`${r} is greater than the maximum value ${n.maximum}`)]:[]}function Rr(t){const e=t.valueSpec,r=Er(t.value.type);let n,i,o,a={};const s="categorical"!==r&&void 0===t.value.property,l=!s,u="array"===De(t.value.stops)&&"array"===De(t.value.stops[0])&&"object"===De(t.value.stops[0][0]),c=Cr({key:t.key,value:t.value,valueSpec:t.styleSpec.function,style:t.style,styleSpec:t.styleSpec,objectElementValidators:{stops:function(t){if("identity"===r)return[new xr(t.key,t.value,'identity function may not have a "stops" property')];let e=[];const n=t.value;e=e.concat(Or({key:t.key,value:n,valueSpec:t.valueSpec,style:t.style,styleSpec:t.styleSpec,arrayElementValidator:h})),"array"===De(n)&&0===n.length&&e.push(new xr(t.key,n,"array must have at least one stop"));return e},default:function(t){return Vr({key:t.key,value:t.value,valueSpec:e,style:t.style,styleSpec:t.styleSpec})}}});return"identity"===r&&s&&c.push(new xr(t.key,t.value,'missing required property "property"')),"identity"===r||t.value.stops||c.push(new xr(t.key,t.value,'missing required property "stops"')),"exponential"===r&&t.valueSpec.expression&&!Ne(t.valueSpec)&&c.push(new xr(t.key,t.value,"exponential functions not supported")),t.styleSpec.$version>=8&&(l&&!ke(t.valueSpec)?c.push(new xr(t.key,t.value,"property functions not supported")):s&&!je(t.valueSpec)&&c.push(new xr(t.key,t.value,"zoom functions not supported"))),"categorical"!==r&&!u||void 0!==t.value.property||c.push(new xr(t.key,t.value,'"property" property is required')),c;function h(t){let r=[];const n=t.value,s=t.key;if("array"!==De(n))return[new xr(s,n,`array expected, ${De(n)} found`)];if(2!==n.length)return[new xr(s,n,`array length 2 expected, length ${n.length} found`)];if(u){if("object"!==De(n[0]))return[new xr(s,n,`object expected, ${De(n[0])} found`)];if(void 0===n[0].zoom)return[new xr(s,n,"object stop key must have zoom")];if(void 0===n[0].value)return[new xr(s,n,"object stop key must have value")];if(o&&o>Er(n[0].zoom))return[new xr(s,n[0].zoom,"stop zoom values must appear in ascending order")];Er(n[0].zoom)!==o&&(o=Er(n[0].zoom),i=void 0,a={}),r=r.concat(Cr({key:s+"[0]",value:n[0],valueSpec:{zoom:{}},style:t.style,styleSpec:t.styleSpec,objectElementValidators:{zoom:Pr,value:p}}))}else r=r.concat(p({key:s+"[0]",value:n[0],valueSpec:{},style:t.style,styleSpec:t.styleSpec},n));return Ze(Tr(n[1]))?r.concat([new xr(s+"[1]",n[1],"expressions are not allowed in function stops.")]):r.concat(Vr({key:s+"[1]",value:n[1],valueSpec:e,style:t.style,styleSpec:t.styleSpec}))}function p(t,o){const s=De(t.value),l=Er(t.value),u=null!==t.value?t.value:o;if(n){if(s!==n)return[new xr(t.key,u,`${s} stop domain type must match previous stop domain type ${n}`)]}else n=s;if("number"!==s&&"string"!==s&&"boolean"!==s)return[new xr(t.key,u,"stop domain value must be a number, string, or boolean")];if("number"!==s&&"categorical"!==r){let n=`number expected, ${s} found`;return ke(e)&&void 0===r&&(n+='\nIf you intended to use a categorical function, specify `"type": "categorical"`.'),[new xr(t.key,u,n)]}return"categorical"!==r||"number"!==s||isFinite(l)&&Math.floor(l)===l?"categorical"!==r&&"number"===s&&void 0!==i&&l<i?[new xr(t.key,u,"stop domain values must appear in ascending order")]:(i=l,"categorical"===r&&l in a?[new xr(t.key,u,"stop domain values must be unique")]:(a[l]=!0,[])):[new xr(t.key,u,"integer expected, found "+l)]}}function Ir(t){const e=("property"===t.expressionContext?Je:Ke)(Tr(t.value),t.valueSpec);if("error"===e.result)return e.value.map(e=>new xr(`${t.key}${e.key}`,t.value,e.message));const r=e.value.expression||e.value._styleExpression.expression;if("property"===t.expressionContext&&"text-font"===t.propertyKey&&!r.outputDefined())return[new xr(t.key,t.value,`Invalid data expression for "${t.propertyKey}". Output values must be contained as literals within the expression.`)];if("property"===t.expressionContext&&"layout"===t.propertyType&&!Nt(r))return[new xr(t.key,t.value,'"feature-state" data expressions are not supported with layout properties.')];if("filter"===t.expressionContext&&!Nt(r))return[new xr(t.key,t.value,'"feature-state" data expressions are not supported with filters.')];if(t.expressionContext&&0===t.expressionContext.indexOf("cluster")){if(!Dt(r,["zoom","feature-state"]))return[new xr(t.key,t.value,'"zoom" and "feature-state" expressions are not supported with cluster properties.')];if("cluster-initial"===t.expressionContext&&!jt(r))return[new xr(t.key,t.value,"Feature data expressions are not supported with initial expression part of cluster properties.")]}return[]}function Lr(t){const e=t.key,r=t.value,n=t.valueSpec,i=[];return Array.isArray(n.values)?-1===n.values.indexOf(Er(r))&&i.push(new xr(e,r,`expected one of [${n.values.join(", ")}], ${JSON.stringify(r)} found`)):-1===Object.keys(n.values).indexOf(Er(r))&&i.push(new xr(e,r,`expected one of [${Object.keys(n.values).join(", ")}], ${JSON.stringify(r)} found`)),i}function Mr(t){return ur(Tr(t.value))?Ir(M({},t,{expressionContext:"filter",valueSpec:{value:"boolean"}})):function t(e){const r=e.value,n=e.key;if("array"!==De(r))return[new xr(n,r,`array expected, ${De(r)} found`)];const i=e.styleSpec;let o,a=[];if(r.length<1)return[new xr(n,r,"filter array must have at least 1 element")];switch(a=a.concat(Lr({key:n+"[0]",value:r[0],valueSpec:i.filter_operator,style:e.style,styleSpec:e.styleSpec})),Er(r[0])){case"<":case"<=":case">":case">=":r.length>=2&&"$type"===Er(r[1])&&a.push(new xr(n,r,`"$type" cannot be use with operator "${r[0]}"`));case"==":case"!=":3!==r.length&&a.push(new xr(n,r,`filter array for operator "${r[0]}" must have 3 elements`));case"in":case"!in":r.length>=2&&(o=De(r[1]),"string"!==o&&a.push(new xr(n+"[1]",r[1],`string expected, ${o} found`)));for(let t=2;t<r.length;t++)o=De(r[t]),"$type"===Er(r[1])?a=a.concat(Lr({key:`${n}[${t}]`,value:r[t],valueSpec:i.geometry_type,style:e.style,styleSpec:e.styleSpec})):"string"!==o&&"number"!==o&&"boolean"!==o&&a.push(new xr(`${n}[${t}]`,r[t],`string, number, or boolean expected, ${o} found`));break;case"any":case"all":case"none":for(let i=1;i<r.length;i++)a=a.concat(t({key:`${n}[${i}]`,value:r[i],style:e.style,styleSpec:e.styleSpec}));break;case"has":case"!has":o=De(r[1]),2!==r.length?a.push(new xr(n,r,`filter array for "${r[0]}" operator must have 2 elements`)):"string"!==o&&a.push(new xr(n+"[1]",r[1],`string expected, ${o} found`));break;case"within":o=De(r[1]),2!==r.length?a.push(new xr(n,r,`filter array for "${r[0]}" operator must have 2 elements`)):"object"!==o&&a.push(new xr(n+"[1]",r[1],`object expected, ${o} found`))}return a}(t)}function Fr(t,e){const r=t.key,n=t.style,i=t.styleSpec,o=t.value,a=t.objectKey,s=i[`${e}_${t.layerType}`];if(!s)return[];const l=a.match(/^(.*)-transition$/);if("paint"===e&&l&&s[l[1]]&&s[l[1]].transition)return Vr({key:r,value:o,valueSpec:i.transition,style:n,styleSpec:i});const u=t.valueSpec||s[a];if(!u)return[new xr(r,o,`unknown property "${a}"`)];let c;if("string"===De(o)&&ke(u)&&!u.tokens&&(c=/^{([^}]+)}$/.exec(o)))return[new xr(r,o,`"${a}" does not support interpolation syntax\nUse an identity property function instead: \`{ "type": "identity", "property": ${JSON.stringify(c[1])} }\`.`)];const h=[];return"symbol"===t.layerType&&("text-field"===a&&n&&!n.glyphs&&h.push(new xr(r,o,'use of "text-field" requires a style "glyphs" property')),"text-font"===a&&Ge(Tr(o))&&"identity"===Er(o.type)&&h.push(new xr(r,o,'"text-font" does not support identity functions'))),h.concat(Vr({key:t.key,value:o,valueSpec:u,style:n,styleSpec:i,expressionContext:"property",propertyType:e,propertyKey:a}))}function Ar(t){return Fr(t,"paint")}function kr(t){return Fr(t,"layout")}function jr(t){let e=[];const r=t.value,n=t.key,i=t.style,o=t.styleSpec;r.type||r.ref||e.push(new xr(n,r,'either "type" or "ref" is required'));let a=Er(r.type);const s=Er(r.ref);if(r.id){const o=Er(r.id);for(let a=0;a<t.arrayIndex;a++){const t=i.layers[a];Er(t.id)===o&&e.push(new xr(n,r.id,`duplicate layer id "${r.id}", previously used at line ${t.id.__line__}`))}}if("ref"in r){let t;["type","source","source-layer","filter","layout"].forEach(t=>{t in r&&e.push(new xr(n,r[t],`"${t}" is prohibited for ref layers`))}),i.layers.forEach(e=>{Er(e.id)===s&&(t=e)}),t?t.ref?e.push(new xr(n,r.ref,"ref cannot reference another ref layer")):a=Er(t.type):e.push(new xr(n,r.ref,`ref layer "${s}" not found`))}else if("background"!==a&&"sky"!==a)if(r.source){const t=i.sources&&i.sources[r.source],o=t&&Er(t.type);t?"vector"===o&&"raster"===a?e.push(new xr(n,r.source,`layer "${r.id}" requires a raster source`)):"raster"===o&&"raster"!==a?e.push(new xr(n,r.source,`layer "${r.id}" requires a vector source`)):"vector"!==o||r["source-layer"]?"raster-dem"===o&&"hillshade"!==a?e.push(new xr(n,r.source,"raster-dem source can only be used with layer type 'hillshade'.")):"line"!==a||!r.paint||!r.paint["line-gradient"]||"geojson"===o&&t.lineMetrics||e.push(new xr(n,r,`layer "${r.id}" specifies a line-gradient, which requires a GeoJSON source with \`lineMetrics\` enabled.`)):e.push(new xr(n,r,`layer "${r.id}" must specify a "source-layer"`)):e.push(new xr(n,r.source,`source "${r.source}" not found`))}else e.push(new xr(n,r,'missing required property "source"'));return e=e.concat(Cr({key:n,value:r,valueSpec:o.layer,style:t.style,styleSpec:t.styleSpec,objectElementValidators:{"*":()=>[],type:()=>Vr({key:n+".type",value:r.type,valueSpec:o.layer.type,style:t.style,styleSpec:t.styleSpec,object:r,objectKey:"type"}),filter:Mr,layout:t=>Cr({layer:r,key:t.key,value:t.value,style:t.style,styleSpec:t.styleSpec,objectElementValidators:{"*":t=>kr(M({layerType:a},t))}}),paint:t=>Cr({layer:r,key:t.key,value:t.value,style:t.style,styleSpec:t.styleSpec,objectElementValidators:{"*":t=>Ar(M({layerType:a},t))}})}})),e}function Nr(t){const e=t.value,r=t.key,n=De(e);return"string"!==n?[new xr(r,e,`string expected, ${n} found`)]:[]}const Dr={promoteId:function({key:t,value:e}){if("string"===De(e))return Nr({key:t,value:e});{const r=[];for(const n in e)r.push(...Nr({key:`${t}.${n}`,value:e[n]}));return r}}};function Gr(t){const e=t.value,r=t.key,n=t.styleSpec,i=t.style;if(!e.type)return[new xr(r,e,'"type" is required')];const o=Er(e.type);let a;switch(o){case"vector":case"raster":case"raster-dem":return a=Cr({key:r,value:e,valueSpec:n["source_"+o.replace("-","_")],style:t.style,styleSpec:n,objectElementValidators:Dr}),a;case"geojson":if(a=Cr({key:r,value:e,valueSpec:n.source_geojson,style:i,styleSpec:n,objectElementValidators:Dr}),e.cluster)for(const t in e.clusterProperties){const[n,i]=e.clusterProperties[t],o="string"==typeof n?[n,["accumulated"],["get",t]]:n;a.push(...Ir({key:`${r}.${t}.map`,value:i,expressionContext:"cluster-map"})),a.push(...Ir({key:`${r}.${t}.reduce`,value:o,expressionContext:"cluster-reduce"}))}return a;case"video":return Cr({key:r,value:e,valueSpec:n.source_video,style:i,styleSpec:n});case"image":return Cr({key:r,value:e,valueSpec:n.source_image,style:i,styleSpec:n});case"canvas":return[new xr(r,null,"Please use runtime APIs to add canvas sources, rather than including them in stylesheets.","source.canvas")];default:return Lr({key:r+".type",value:e.type,valueSpec:{values:["vector","raster","raster-dem","geojson","video","image"]},style:i,styleSpec:n})}}function zr(t){const e=t.value,r=t.styleSpec,n=r.light,i=t.style;let o=[];const a=De(e);if(void 0===e)return o;if("object"!==a)return o=o.concat([new xr("light",e,`object expected, ${a} found`)]),o;for(const t in e){const a=t.match(/^(.*)-transition$/);o=a&&n[a[1]]&&n[a[1]].transition?o.concat(Vr({key:t,value:e[t],valueSpec:r.transition,style:i,styleSpec:r})):n[t]?o.concat(Vr({key:t,value:e[t],valueSpec:n[t],style:i,styleSpec:r})):o.concat([new xr(t,e[t],`unknown property "${t}"`)])}return o}function Ur(t){const e=t.value,r=t.key,n=t.style,i=t.styleSpec,o=i.terrain;let a=[];const s=De(e);if(void 0===e)return a;if("object"!==s)return a=a.concat([new xr("terrain",e,`object expected, ${s} found`)]),a;for(const t in e){const r=t.match(/^(.*)-transition$/);a=r&&o[r[1]]&&o[r[1]].transition?a.concat(Vr({key:t,value:e[t],valueSpec:i.transition,style:n,styleSpec:i})):o[t]?a.concat(Vr({key:t,value:e[t],valueSpec:o[t],style:n,styleSpec:i})):a.concat([new xr(t,e[t],`unknown property "${t}"`)])}if(e.source){const t=n.sources&&n.sources[e.source],i=t&&Er(t.type);t?"raster-dem"!==i&&a.push(new xr(r,e.source,`terrain cannot be used with a source of type ${i}, it only be used with a "raster-dem" source type`)):a.push(new xr(r,e.source,`source "${e.source}" not found`))}else a.push(new xr(r,e,'terrain is missing required property "source"'));return a}const Br={"*":()=>[],array:Or,boolean:function(t){const e=t.value,r=t.key,n=De(e);return"boolean"!==n?[new xr(r,e,`boolean expected, ${n} found`)]:[]},number:Pr,color:function(t){const e=t.key,r=t.value,n=De(r);return"string"!==n?[new xr(e,r,`color expected, ${n} found`)]:null===$(r)?[new xr(e,r,`color expected, "${r}" found`)]:[]},constants:Sr,enum:Lr,filter:Mr,function:Rr,layer:jr,object:Cr,source:Gr,light:zr,terrain:Ur,string:Nr,formatted:function(t){return 0===Nr(t).length?[]:Ir(t)},resolvedImage:function(t){return 0===Nr(t).length?[]:Ir(t)}};function Vr(t){const e=t.value,r=t.valueSpec,n=t.styleSpec;if(r.expression&&Ge(Er(e)))return Rr(t);if(r.expression&&Ze(Tr(e)))return Ir(t);if(r.type&&Br[r.type])return Br[r.type](t);return Cr(M({},t,{valueSpec:r.type?n[r.type]:r}))}function Yr(t){const e=t.value,r=t.key,n=Nr(t);return n.length||(-1===e.indexOf("{fontstack}")&&n.push(new xr(r,e,'"glyphs" url must include a "{fontstack}" token')),-1===e.indexOf("{range}")&&n.push(new xr(r,e,'"glyphs" url must include a "{range}" token'))),n}function Wr(t,e=i){let r=[];return r=r.concat(Vr({key:"",value:t,valueSpec:e.$root,styleSpec:e,style:t,objectElementValidators:{glyphs:Yr,"*":()=>[]}})),t.constants&&(r=r.concat(Sr({key:"constants",value:t.constants,style:t,styleSpec:e}))),qr(r)}function qr(t){return[].concat(t).sort((t,e)=>t.line-e.line)}function Xr(t){return function(...e){return qr(t.apply(this,e))}}Wr.source=Xr(Gr),Wr.light=Xr(zr),Wr.terrain=Xr(Ur),Wr.layer=Xr(jr),Wr.filter=Xr(Mr),Wr.paintProperty=Xr(Ar),Wr.layoutProperty=Xr(kr);var Zr=s((function(t,e){var r=function(){var t=function(t,e,r,n){for(r=r||{},n=t.length;n--;r[t[n]]=e);return r},e=[1,12],r=[1,13],n=[1,9],i=[1,10],o=[1,11],a=[1,14],s=[1,15],l=[14,18,22,24],u=[18,22],c=[22,24],h={trace:function(){},yy:{},symbols_:{error:2,JSONString:3,STRING:4,JSONNumber:5,NUMBER:6,JSONNullLiteral:7,NULL:8,JSONBooleanLiteral:9,TRUE:10,FALSE:11,JSONText:12,JSONValue:13,EOF:14,JSONObject:15,JSONArray:16,"{":17,"}":18,JSONMemberList:19,JSONMember:20,":":21,",":22,"[":23,"]":24,JSONElementList:25,$accept:0,$end:1},terminals_:{2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"},productions_:[0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]],performAction:function(t,e,r,n,i,o,a){var s=o.length-1;switch(i){case 1:this.$=new String(t.replace(/\\(\\|")/g,"$1").replace(/\\n/g,"\n").replace(/\\r/g,"\r").replace(/\\t/g,"\t").replace(/\\v/g,"\v").replace(/\\f/g,"\f").replace(/\\b/g,"\b")),this.$.__line__=this._$.first_line;break;case 2:this.$=new Number(t),this.$.__line__=this._$.first_line;break;case 3:this.$=null;break;case 4:this.$=new Boolean(!0),this.$.__line__=this._$.first_line;break;case 5:this.$=new Boolean(!1),this.$.__line__=this._$.first_line;break;case 6:return this.$=o[s-1];case 13:this.$={},Object.defineProperty(this.$,"__line__",{value:this._$.first_line,enumerable:!1});break;case 14:case 19:this.$=o[s-1],Object.defineProperty(this.$,"__line__",{value:this._$.first_line,enumerable:!1});break;case 15:this.$=[o[s-2],o[s]];break;case 16:this.$={},this.$[o[s][0]]=o[s][1];break;case 17:this.$=o[s-2],o[s-2][o[s][0]]=o[s][1];break;case 18:this.$=[],Object.defineProperty(this.$,"__line__",{value:this._$.first_line,enumerable:!1});break;case 20:this.$=[o[s]];break;case 21:this.$=o[s-2],o[s-2].push(o[s])}},table:[{3:5,4:e,5:6,6:r,7:3,8:n,9:4,10:i,11:o,12:1,13:2,15:7,16:8,17:a,23:s},{1:[3]},{14:[1,16]},t(l,[2,7]),t(l,[2,8]),t(l,[2,9]),t(l,[2,10]),t(l,[2,11]),t(l,[2,12]),t(l,[2,3]),t(l,[2,4]),t(l,[2,5]),t([14,18,21,22,24],[2,1]),t(l,[2,2]),{3:20,4:e,18:[1,17],19:18,20:19},{3:5,4:e,5:6,6:r,7:3,8:n,9:4,10:i,11:o,13:23,15:7,16:8,17:a,23:s,24:[1,21],25:22},{1:[2,6]},t(l,[2,13]),{18:[1,24],22:[1,25]},t(u,[2,16]),{21:[1,26]},t(l,[2,18]),{22:[1,28],24:[1,27]},t(c,[2,20]),t(l,[2,14]),{3:20,4:e,20:29},{3:5,4:e,5:6,6:r,7:3,8:n,9:4,10:i,11:o,13:30,15:7,16:8,17:a,23:s},t(l,[2,19]),{3:5,4:e,5:6,6:r,7:3,8:n,9:4,10:i,11:o,13:31,15:7,16:8,17:a,23:s},t(u,[2,17]),t(u,[2,15]),t(c,[2,21])],defaultActions:{16:[2,6]},parseError:function(t,e){if(!e.recoverable)throw new Error(t);this.trace(t)},parse:function(t){var e=this,r=[0],n=[null],i=[],o=this.table,a="",s=0,l=0,u=2,c=1,h=i.slice.call(arguments,1),p=Object.create(this.lexer),f={yy:{}};for(var d in this.yy)Object.prototype.hasOwnProperty.call(this.yy,d)&&(f.yy[d]=this.yy[d]);p.setInput(t,f.yy),f.yy.lexer=p,f.yy.parser=this,void 0===p.yylloc&&(p.yylloc={});var g=p.yylloc;i.push(g);var y=p.options&&p.options.ranges;function m(){var t;return"number"!=typeof(t=p.lex()||c)&&(t=e.symbols_[t]||t),t}"function"==typeof f.yy.parseError?this.parseError=f.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;for(var v,_,b,x,w,S,E,T,C={};;){if(_=r[r.length-1],this.defaultActions[_]?b=this.defaultActions[_]:(null==v&&(v=m()),b=o[_]&&o[_][v]),void 0===b||!b.length||!b[0]){var O="";for(w in T=[],o[_])this.terminals_[w]&&w>u&&T.push("'"+this.terminals_[w]+"'");O=p.showPosition?"Parse error on line "+(s+1)+":\n"+p.showPosition()+"\nExpecting "+T.join(", ")+", got '"+(this.terminals_[v]||v)+"'":"Parse error on line "+(s+1)+": Unexpected "+(v==c?"end of input":"'"+(this.terminals_[v]||v)+"'"),this.parseError(O,{text:p.match,token:this.terminals_[v]||v,line:p.yylineno,loc:g,expected:T})}if(b[0]instanceof Array&&b.length>1)throw new Error("Parse Error: multiple actions possible at state: "+_+", token: "+v);switch(b[0]){case 1:r.push(v),n.push(p.yytext),i.push(p.yylloc),r.push(b[1]),v=null,l=p.yyleng,a=p.yytext,s=p.yylineno,g=p.yylloc;break;case 2:if(S=this.productions_[b[1]][1],C.$=n[n.length-S],C._$={first_line:i[i.length-(S||1)].first_line,last_line:i[i.length-1].last_line,first_column:i[i.length-(S||1)].first_column,last_column:i[i.length-1].last_column},y&&(C._$.range=[i[i.length-(S||1)].range[0],i[i.length-1].range[1]]),void 0!==(x=this.performAction.apply(C,[a,l,s,f.yy,b[1],n,i].concat(h))))return x;S&&(r=r.slice(0,-1*S*2),n=n.slice(0,-1*S),i=i.slice(0,-1*S)),r.push(this.productions_[b[1]][0]),n.push(C.$),i.push(C._$),E=o[r[r.length-2]][r[r.length-1]],r.push(E);break;case 3:return!0}}return!0}},p={EOF:1,parseError:function(t,e){if(!this.yy.parser)throw new Error(t);this.yy.parser.parseError(t,e)},setInput:function(t,e){return this.yy=e||this.yy||{},this._input=t,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},input:function(){var t=this._input[0];return this.yytext+=t,this.yyleng++,this.offset++,this.match+=t,this.matched+=t,t.match(/(?:\r\n?|\n).*/g)?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),t},unput:function(t){var e=t.length,r=t.split(/(?:\r\n?|\n)/g);this._input=t+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-e),this.offset-=e;var n=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),r.length-1&&(this.yylineno-=r.length-1);var i=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:r?(r.length===n.length?this.yylloc.first_column:0)+n[n.length-r.length].length-r[0].length:this.yylloc.first_column-e},this.options.ranges&&(this.yylloc.range=[i[0],i[0]+this.yyleng-e]),this.yyleng=this.yytext.length,this},more:function(){return this._more=!0,this},reject:function(){return this.options.backtrack_lexer?(this._backtrack=!0,this):this.parseError("Lexical error on line "+(this.yylineno+1)+". You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},less:function(t){this.unput(this.match.slice(t))},pastInput:function(){var t=this.matched.substr(0,this.matched.length-this.match.length);return(t.length>20?"...":"")+t.substr(-20).replace(/\n/g,"")},upcomingInput:function(){var t=this.match;return t.length<20&&(t+=this._input.substr(0,20-t.length)),(t.substr(0,20)+(t.length>20?"...":"")).replace(/\n/g,"")},showPosition:function(){var t=this.pastInput(),e=new Array(t.length+1).join("-");return t+this.upcomingInput()+"\n"+e+"^"},test_match:function(t,e){var r,n,i;if(this.options.backtrack_lexer&&(i={yylineno:this.yylineno,yylloc:{first_line:this.yylloc.first_line,last_line:this.last_line,first_column:this.yylloc.first_column,last_column:this.yylloc.last_column},yytext:this.yytext,match:this.match,matches:this.matches,matched:this.matched,yyleng:this.yyleng,offset:this.offset,_more:this._more,_input:this._input,yy:this.yy,conditionStack:this.conditionStack.slice(0),done:this.done},this.options.ranges&&(i.yylloc.range=this.yylloc.range.slice(0))),(n=t[0].match(/(?:\r\n?|\n).*/g))&&(this.yylineno+=n.length),this.yylloc={first_line:this.yylloc.last_line,last_line:this.yylineno+1,first_column:this.yylloc.last_column,last_column:n?n[n.length-1].length-n[n.length-1].match(/\r?\n?/)[0].length:this.yylloc.last_column+t[0].length},this.yytext+=t[0],this.match+=t[0],this.matches=t,this.yyleng=this.yytext.length,this.options.ranges&&(this.yylloc.range=[this.offset,this.offset+=this.yyleng]),this._more=!1,this._backtrack=!1,this._input=this._input.slice(t[0].length),this.matched+=t[0],r=this.performAction.call(this,this.yy,this,e,this.conditionStack[this.conditionStack.length-1]),this.done&&this._input&&(this.done=!1),r)return r;if(this._backtrack){for(var o in i)this[o]=i[o];return!1}return!1},next:function(){if(this.done)return this.EOF;var t,e,r,n;this._input||(this.done=!0),this._more||(this.yytext="",this.match="");for(var i=this._currentRules(),o=0;o<i.length;o++)if((r=this._input.match(this.rules[i[o]]))&&(!e||r[0].length>e[0].length)){if(e=r,n=o,this.options.backtrack_lexer){if(!1!==(t=this.test_match(r,i[o])))return t;if(this._backtrack){e=!1;continue}return!1}if(!this.options.flex)break}return e?!1!==(t=this.test_match(e,i[n]))&&t:""===this._input?this.EOF:this.parseError("Lexical error on line "+(this.yylineno+1)+". Unrecognized text.\n"+this.showPosition(),{text:"",token:null,line:this.yylineno})},lex:function(){var t=this.next();return t||this.lex()},begin:function(t){this.conditionStack.push(t)},popState:function(){return this.conditionStack.length-1>0?this.conditionStack.pop():this.conditionStack[0]},_currentRules:function(){return this.conditionStack.length&&this.conditionStack[this.conditionStack.length-1]?this.conditions[this.conditionStack[this.conditionStack.length-1]].rules:this.conditions.INITIAL.rules},topState:function(t){return(t=this.conditionStack.length-1-Math.abs(t||0))>=0?this.conditionStack[t]:"INITIAL"},pushState:function(t){this.begin(t)},stateStackSize:function(){return this.conditionStack.length},options:{},performAction:function(t,e,r,n){switch(r){case 0:break;case 1:return 6;case 2:return e.yytext=e.yytext.substr(1,e.yyleng-2),4;case 3:return 17;case 4:return 18;case 5:return 23;case 6:return 24;case 7:return 22;case 8:return 21;case 9:return 10;case 10:return 11;case 11:return 8;case 12:return 14;case 13:return"INVALID"}},rules:[/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/],conditions:{INITIAL:{rules:[0,1,2,3,4,5,6,7,8,9,10,11,12,13],inclusive:!0}}};function f(){this.yy={}}return h.lexer=p,f.prototype=h,h.Parser=f,new f}();void 0!==a&&(e.parser=r,e.Parser=r.Parser,e.parse=function(){return r.parse.apply(r,arguments)})}));Zr.parser,Zr.Parser,Zr.parse;function Kr(t){if(t instanceof String||"string"==typeof t||t instanceof n)try{return Zr.parse(t.toString())}catch(t){throw new wr(t)}return t}function Hr(t,e=i){let r=t;try{r=Kr(r)}catch(t){return[t]}return Wr(r,e)}const $r={StyleExpression:Xe,isExpression:Ze,isExpressionFilter:ur,createExpression:Ke,createPropertyExpression:Je,normalizePropertyExpression:function(t,e){if(Ge(t))return new Qe(t,e);if(Ze(t)){const r=Je(t,e);if("error"===r.result)throw new Error(r.value.map(t=>`${t.key}: ${t.message}`).join(", "));return r.value}{let r=t;return"string"==typeof t&&"color"===e.type&&(r=J.parse(t)),{kind:"constant",evaluate:()=>r}}},ZoomConstantExpression:He,ZoomDependentExpression:$e,StylePropertyFunction:Qe},Jr={convertFunction:er,createFunction:Ue,isFunction:Ge};Hr.parsed=Hr,Hr.latest=Hr}).call(this,r(4),r(7).Buffer)},function(t,e,r){t.exports=function(){"use strict";function t(t,n,i,o,a){!function t(r,n,i,o,a){for(;o>i;){if(o-i>600){var s=o-i+1,l=n-i+1,u=Math.log(s),c=.5*Math.exp(2*u/3),h=.5*Math.sqrt(u*c*(s-c)/s)*(l-s/2<0?-1:1);t(r,n,Math.max(i,Math.floor(n-l*c/s+h)),Math.min(o,Math.floor(n+(s-l)*c/s+h)),a)}var p=r[n],f=i,d=o;for(e(r,i,n),a(r[o],p)>0&&e(r,i,o);f<d;){for(e(r,f,d),f++,d--;a(r[f],p)<0;)f++;for(;a(r[d],p)>0;)d--}0===a(r[i],p)?e(r,i,d):e(r,++d,o),d<=n&&(i=d+1),n<=d&&(o=d-1)}}(t,n,i||0,o||t.length-1,a||r)}function e(t,e,r){var n=t[e];t[e]=t[r],t[r]=n}function r(t,e){return t<e?-1:t>e?1:0}var n=function(t){void 0===t&&(t=9),this._maxEntries=Math.max(4,t),this._minEntries=Math.max(2,Math.ceil(.4*this._maxEntries)),this.clear()};function i(t,e,r){if(!r)return e.indexOf(t);for(var n=0;n<e.length;n++)if(r(t,e[n]))return n;return-1}function o(t,e){a(t,0,t.children.length,e,t)}function a(t,e,r,n,i){i||(i=d(null)),i.minX=1/0,i.minY=1/0,i.maxX=-1/0,i.maxY=-1/0;for(var o=e;o<r;o++){var a=t.children[o];s(i,t.leaf?n(a):a)}return i}function s(t,e){return t.minX=Math.min(t.minX,e.minX),t.minY=Math.min(t.minY,e.minY),t.maxX=Math.max(t.maxX,e.maxX),t.maxY=Math.max(t.maxY,e.maxY),t}function l(t,e){return t.minX-e.minX}function u(t,e){return t.minY-e.minY}function c(t){return(t.maxX-t.minX)*(t.maxY-t.minY)}function h(t){return t.maxX-t.minX+(t.maxY-t.minY)}function p(t,e){return t.minX<=e.minX&&t.minY<=e.minY&&e.maxX<=t.maxX&&e.maxY<=t.maxY}function f(t,e){return e.minX<=t.maxX&&e.minY<=t.maxY&&e.maxX>=t.minX&&e.maxY>=t.minY}function d(t){return{children:t,height:1,leaf:!0,minX:1/0,minY:1/0,maxX:-1/0,maxY:-1/0}}function g(e,r,n,i,o){for(var a=[r,n];a.length;)if(!((n=a.pop())-(r=a.pop())<=i)){var s=r+Math.ceil((n-r)/i/2)*i;t(e,s,r,n,o),a.push(r,s,s,n)}}return n.prototype.all=function(){return this._all(this.data,[])},n.prototype.search=function(t){var e=this.data,r=[];if(!f(t,e))return r;for(var n=this.toBBox,i=[];e;){for(var o=0;o<e.children.length;o++){var a=e.children[o],s=e.leaf?n(a):a;f(t,s)&&(e.leaf?r.push(a):p(t,s)?this._all(a,r):i.push(a))}e=i.pop()}return r},n.prototype.collides=function(t){var e=this.data;if(!f(t,e))return!1;for(var r=[];e;){for(var n=0;n<e.children.length;n++){var i=e.children[n],o=e.leaf?this.toBBox(i):i;if(f(t,o)){if(e.leaf||p(t,o))return!0;r.push(i)}}e=r.pop()}return!1},n.prototype.load=function(t){if(!t||!t.length)return this;if(t.length<this._minEntries){for(var e=0;e<t.length;e++)this.insert(t[e]);return this}var r=this._build(t.slice(),0,t.length-1,0);if(this.data.children.length)if(this.data.height===r.height)this._splitRoot(this.data,r);else{if(this.data.height<r.height){var n=this.data;this.data=r,r=n}this._insert(r,this.data.height-r.height-1,!0)}else this.data=r;return this},n.prototype.insert=function(t){return t&&this._insert(t,this.data.height-1),this},n.prototype.clear=function(){return this.data=d([]),this},n.prototype.remove=function(t,e){if(!t)return this;for(var r,n,o,a=this.data,s=this.toBBox(t),l=[],u=[];a||l.length;){if(a||(a=l.pop(),n=l[l.length-1],r=u.pop(),o=!0),a.leaf){var c=i(t,a.children,e);if(-1!==c)return a.children.splice(c,1),l.push(a),this._condense(l),this}o||a.leaf||!p(a,s)?n?(r++,a=n.children[r],o=!1):a=null:(l.push(a),u.push(r),r=0,n=a,a=a.children[0])}return this},n.prototype.toBBox=function(t){return t},n.prototype.compareMinX=function(t,e){return t.minX-e.minX},n.prototype.compareMinY=function(t,e){return t.minY-e.minY},n.prototype.toJSON=function(){return this.data},n.prototype.fromJSON=function(t){return this.data=t,this},n.prototype._all=function(t,e){for(var r=[];t;)t.leaf?e.push.apply(e,t.children):r.push.apply(r,t.children),t=r.pop();return e},n.prototype._build=function(t,e,r,n){var i,a=r-e+1,s=this._maxEntries;if(a<=s)return o(i=d(t.slice(e,r+1)),this.toBBox),i;n||(n=Math.ceil(Math.log(a)/Math.log(s)),s=Math.ceil(a/Math.pow(s,n-1))),(i=d([])).leaf=!1,i.height=n;var l=Math.ceil(a/s),u=l*Math.ceil(Math.sqrt(s));g(t,e,r,u,this.compareMinX);for(var c=e;c<=r;c+=u){var h=Math.min(c+u-1,r);g(t,c,h,l,this.compareMinY);for(var p=c;p<=h;p+=l){var f=Math.min(p+l-1,h);i.children.push(this._build(t,p,f,n-1))}}return o(i,this.toBBox),i},n.prototype._chooseSubtree=function(t,e,r,n){for(;n.push(e),!e.leaf&&n.length-1!==r;){for(var i=1/0,o=1/0,a=void 0,s=0;s<e.children.length;s++){var l=e.children[s],u=c(l),h=(p=t,f=l,(Math.max(f.maxX,p.maxX)-Math.min(f.minX,p.minX))*(Math.max(f.maxY,p.maxY)-Math.min(f.minY,p.minY))-u);h<o?(o=h,i=u<i?u:i,a=l):h===o&&u<i&&(i=u,a=l)}e=a||e.children[0]}var p,f;return e},n.prototype._insert=function(t,e,r){var n=r?t:this.toBBox(t),i=[],o=this._chooseSubtree(n,this.data,e,i);for(o.children.push(t),s(o,n);e>=0&&i[e].children.length>this._maxEntries;)this._split(i,e),e--;this._adjustParentBBoxes(n,i,e)},n.prototype._split=function(t,e){var r=t[e],n=r.children.length,i=this._minEntries;this._chooseSplitAxis(r,i,n);var a=this._chooseSplitIndex(r,i,n),s=d(r.children.splice(a,r.children.length-a));s.height=r.height,s.leaf=r.leaf,o(r,this.toBBox),o(s,this.toBBox),e?t[e-1].children.push(s):this._splitRoot(r,s)},n.prototype._splitRoot=function(t,e){this.data=d([t,e]),this.data.height=t.height+1,this.data.leaf=!1,o(this.data,this.toBBox)},n.prototype._chooseSplitIndex=function(t,e,r){for(var n,i,o,s,l,u,h,p=1/0,f=1/0,d=e;d<=r-e;d++){var g=a(t,0,d,this.toBBox),y=a(t,d,r,this.toBBox),m=(i=g,o=y,s=Math.max(i.minX,o.minX),l=Math.max(i.minY,o.minY),u=Math.min(i.maxX,o.maxX),h=Math.min(i.maxY,o.maxY),Math.max(0,u-s)*Math.max(0,h-l)),v=c(g)+c(y);m<p?(p=m,n=d,f=v<f?v:f):m===p&&v<f&&(f=v,n=d)}return n||r-e},n.prototype._chooseSplitAxis=function(t,e,r){var n=t.leaf?this.compareMinX:l,i=t.leaf?this.compareMinY:u;this._allDistMargin(t,e,r,n)<this._allDistMargin(t,e,r,i)&&t.children.sort(n)},n.prototype._allDistMargin=function(t,e,r,n){t.children.sort(n);for(var i=this.toBBox,o=a(t,0,e,i),l=a(t,r-e,r,i),u=h(o)+h(l),c=e;c<r-e;c++){var p=t.children[c];s(o,t.leaf?i(p):p),u+=h(o)}for(var f=r-e-1;f>=e;f--){var d=t.children[f];s(l,t.leaf?i(d):d),u+=h(l)}return u},n.prototype._adjustParentBBoxes=function(t,e,r){for(var n=r;n>=0;n--)s(e[n],t)},n.prototype._condense=function(t){for(var e=t.length-1,r=void 0;e>=0;e--)0===t[e].children.length?e>0?(r=t[e-1].children).splice(r.indexOf(t[e]),1):this.clear():o(t[e],this.toBBox)},n}()},function(t,e){var r={thin:100,hairline:100,"ultra-light":100,"extra-light":100,light:200,book:300,regular:400,normal:400,plain:400,roman:400,standard:400,medium:500,"semi-bold":600,"demi-bold":600,bold:700,heavy:800,black:800,"extra-bold":800,"ultra-black":900,"extra-black":900,"ultra-bold":900,"heavy-black":900,fat:900,poster:900},n=/(italic|oblique)$/i,i={};t.exports=function(t,e,o){var a=i[t];if(!a){Array.isArray(t)||(t=[t]);for(var s=400,l="normal",u=[],c=0,h=t.length;c<h;++c){var p=t[c].split(" "),f=p[p.length-1].toLowerCase();for(var d in"normal"==f||"italic"==f||"oblique"==f?(l=f,p.pop(),f=p[p.length-1].toLowerCase()):n.test(f)&&(f=f.replace(n,""),l=p[p.length-1].replace(f,"")),r)if(f==d||f==d.replace("-","")||f==d.replace("-"," ")){s=r[d],p.pop();break}"number"==typeof f&&(s=f);var g=p.join(" ").replace("Klokantech Noto Sans","Noto Sans");-1!==g.indexOf(" ")&&(g='"'+g+'"'),u.push(g)}a=i[t]=[l,s,u]}return a[0]+" "+a[1]+" "+e+"px"+(o?"/"+o:"")+" "+a[2]}},function(t,e){e.read=function(t,e,r,n,i){var o,a,s=8*i-n-1,l=(1<<s)-1,u=l>>1,c=-7,h=r?i-1:0,p=r?-1:1,f=t[e+h];for(h+=p,o=f&(1<<-c)-1,f>>=-c,c+=s;c>0;o=256*o+t[e+h],h+=p,c-=8);for(a=o&(1<<-c)-1,o>>=-c,c+=n;c>0;a=256*a+t[e+h],h+=p,c-=8);if(0===o)o=1-u;else{if(o===l)return a?NaN:1/0*(f?-1:1);a+=Math.pow(2,n),o-=u}return(f?-1:1)*a*Math.pow(2,o-n)},e.write=function(t,e,r,n,i,o){var a,s,l,u=8*o-i-1,c=(1<<u)-1,h=c>>1,p=23===i?Math.pow(2,-24)-Math.pow(2,-77):0,f=n?0:o-1,d=n?1:-1,g=e<0||0===e&&1/e<0?1:0;for(e=Math.abs(e),isNaN(e)||e===1/0?(s=isNaN(e)?1:0,a=c):(a=Math.floor(Math.log(e)/Math.LN2),e*(l=Math.pow(2,-a))<1&&(a--,l*=2),(e+=a+h>=1?p/l:p*Math.pow(2,1-h))*l>=2&&(a++,l/=2),a+h>=c?(s=0,a=c):a+h>=1?(s=(e*l-1)*Math.pow(2,i),a+=h):(s=e*Math.pow(2,h-1)*Math.pow(2,i),a=0));i>=8;t[r+f]=255&s,f+=d,s/=256,i-=8);for(a=a<<i|s,u+=i;u>0;t[r+f]=255&a,f+=d,a/=256,u-=8);t[r+f-d]|=128*g}},function(t,e){var r;r=function(){return this}();try{r=r||new Function("return this")()}catch(t){"object"==typeof window&&(r=window)}t.exports=r},function(t,e,r){"use strict";t.exports=i;var n=r(3);function i(t){this.buf=ArrayBuffer.isView&&ArrayBuffer.isView(t)?t:new Uint8Array(t||0),this.pos=0,this.type=0,this.length=this.buf.length}i.Varint=0,i.Fixed64=1,i.Bytes=2,i.Fixed32=5;var o="undefined"==typeof TextDecoder?null:new TextDecoder("utf8");function a(t){return t.type===i.Bytes?t.readVarint()+t.pos:t.pos+1}function s(t,e,r){return r?4294967296*e+(t>>>0):4294967296*(e>>>0)+(t>>>0)}function l(t,e,r){var n=e<=16383?1:e<=2097151?2:e<=268435455?3:Math.floor(Math.log(e)/(7*Math.LN2));r.realloc(n);for(var i=r.pos-1;i>=t;i--)r.buf[i+n]=r.buf[i]}function u(t,e){for(var r=0;r<t.length;r++)e.writeVarint(t[r])}function c(t,e){for(var r=0;r<t.length;r++)e.writeSVarint(t[r])}function h(t,e){for(var r=0;r<t.length;r++)e.writeFloat(t[r])}function p(t,e){for(var r=0;r<t.length;r++)e.writeDouble(t[r])}function f(t,e){for(var r=0;r<t.length;r++)e.writeBoolean(t[r])}function d(t,e){for(var r=0;r<t.length;r++)e.writeFixed32(t[r])}function g(t,e){for(var r=0;r<t.length;r++)e.writeSFixed32(t[r])}function y(t,e){for(var r=0;r<t.length;r++)e.writeFixed64(t[r])}function m(t,e){for(var r=0;r<t.length;r++)e.writeSFixed64(t[r])}function v(t,e){return(t[e]|t[e+1]<<8|t[e+2]<<16)+16777216*t[e+3]}function _(t,e,r){t[r]=e,t[r+1]=e>>>8,t[r+2]=e>>>16,t[r+3]=e>>>24}function b(t,e){return(t[e]|t[e+1]<<8|t[e+2]<<16)+(t[e+3]<<24)}i.prototype={destroy:function(){this.buf=null},readFields:function(t,e,r){for(r=r||this.length;this.pos<r;){var n=this.readVarint(),i=n>>3,o=this.pos;this.type=7&n,t(i,e,this),this.pos===o&&this.skip(n)}return e},readMessage:function(t,e){return this.readFields(t,e,this.readVarint()+this.pos)},readFixed32:function(){var t=v(this.buf,this.pos);return this.pos+=4,t},readSFixed32:function(){var t=b(this.buf,this.pos);return this.pos+=4,t},readFixed64:function(){var t=v(this.buf,this.pos)+4294967296*v(this.buf,this.pos+4);return this.pos+=8,t},readSFixed64:function(){var t=v(this.buf,this.pos)+4294967296*b(this.buf,this.pos+4);return this.pos+=8,t},readFloat:function(){var t=n.read(this.buf,this.pos,!0,23,4);return this.pos+=4,t},readDouble:function(){var t=n.read(this.buf,this.pos,!0,52,8);return this.pos+=8,t},readVarint:function(t){var e,r,n=this.buf;return e=127&(r=n[this.pos++]),r<128?e:(e|=(127&(r=n[this.pos++]))<<7,r<128?e:(e|=(127&(r=n[this.pos++]))<<14,r<128?e:(e|=(127&(r=n[this.pos++]))<<21,r<128?e:function(t,e,r){var n,i,o=r.buf;if(i=o[r.pos++],n=(112&i)>>4,i<128)return s(t,n,e);if(i=o[r.pos++],n|=(127&i)<<3,i<128)return s(t,n,e);if(i=o[r.pos++],n|=(127&i)<<10,i<128)return s(t,n,e);if(i=o[r.pos++],n|=(127&i)<<17,i<128)return s(t,n,e);if(i=o[r.pos++],n|=(127&i)<<24,i<128)return s(t,n,e);if(i=o[r.pos++],n|=(1&i)<<31,i<128)return s(t,n,e);throw new Error("Expected varint not more than 10 bytes")}(e|=(15&(r=n[this.pos]))<<28,t,this))))},readVarint64:function(){return this.readVarint(!0)},readSVarint:function(){var t=this.readVarint();return t%2==1?(t+1)/-2:t/2},readBoolean:function(){return Boolean(this.readVarint())},readString:function(){var t=this.readVarint()+this.pos,e=this.pos;return this.pos=t,t-e>=12&&o?function(t,e,r){return o.decode(t.subarray(e,r))}(this.buf,e,t):function(t,e,r){var n="",i=e;for(;i<r;){var o,a,s,l=t[i],u=null,c=l>239?4:l>223?3:l>191?2:1;if(i+c>r)break;1===c?l<128&&(u=l):2===c?128==(192&(o=t[i+1]))&&(u=(31&l)<<6|63&o)<=127&&(u=null):3===c?(o=t[i+1],a=t[i+2],128==(192&o)&&128==(192&a)&&((u=(15&l)<<12|(63&o)<<6|63&a)<=2047||u>=55296&&u<=57343)&&(u=null)):4===c&&(o=t[i+1],a=t[i+2],s=t[i+3],128==(192&o)&&128==(192&a)&&128==(192&s)&&((u=(15&l)<<18|(63&o)<<12|(63&a)<<6|63&s)<=65535||u>=1114112)&&(u=null)),null===u?(u=65533,c=1):u>65535&&(u-=65536,n+=String.fromCharCode(u>>>10&1023|55296),u=56320|1023&u),n+=String.fromCharCode(u),i+=c}return n}(this.buf,e,t)},readBytes:function(){var t=this.readVarint()+this.pos,e=this.buf.subarray(this.pos,t);return this.pos=t,e},readPackedVarint:function(t,e){if(this.type!==i.Bytes)return t.push(this.readVarint(e));var r=a(this);for(t=t||[];this.pos<r;)t.push(this.readVarint(e));return t},readPackedSVarint:function(t){if(this.type!==i.Bytes)return t.push(this.readSVarint());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readSVarint());return t},readPackedBoolean:function(t){if(this.type!==i.Bytes)return t.push(this.readBoolean());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readBoolean());return t},readPackedFloat:function(t){if(this.type!==i.Bytes)return t.push(this.readFloat());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readFloat());return t},readPackedDouble:function(t){if(this.type!==i.Bytes)return t.push(this.readDouble());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readDouble());return t},readPackedFixed32:function(t){if(this.type!==i.Bytes)return t.push(this.readFixed32());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readFixed32());return t},readPackedSFixed32:function(t){if(this.type!==i.Bytes)return t.push(this.readSFixed32());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readSFixed32());return t},readPackedFixed64:function(t){if(this.type!==i.Bytes)return t.push(this.readFixed64());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readFixed64());return t},readPackedSFixed64:function(t){if(this.type!==i.Bytes)return t.push(this.readSFixed64());var e=a(this);for(t=t||[];this.pos<e;)t.push(this.readSFixed64());return t},skip:function(t){var e=7&t;if(e===i.Varint)for(;this.buf[this.pos++]>127;);else if(e===i.Bytes)this.pos=this.readVarint()+this.pos;else if(e===i.Fixed32)this.pos+=4;else{if(e!==i.Fixed64)throw new Error("Unimplemented type: "+e);this.pos+=8}},writeTag:function(t,e){this.writeVarint(t<<3|e)},realloc:function(t){for(var e=this.length||16;e<this.pos+t;)e*=2;if(e!==this.length){var r=new Uint8Array(e);r.set(this.buf),this.buf=r,this.length=e}},finish:function(){return this.length=this.pos,this.pos=0,this.buf.subarray(0,this.length)},writeFixed32:function(t){this.realloc(4),_(this.buf,t,this.pos),this.pos+=4},writeSFixed32:function(t){this.realloc(4),_(this.buf,t,this.pos),this.pos+=4},writeFixed64:function(t){this.realloc(8),_(this.buf,-1&t,this.pos),_(this.buf,Math.floor(t*(1/4294967296)),this.pos+4),this.pos+=8},writeSFixed64:function(t){this.realloc(8),_(this.buf,-1&t,this.pos),_(this.buf,Math.floor(t*(1/4294967296)),this.pos+4),this.pos+=8},writeVarint:function(t){(t=+t||0)>268435455||t<0?function(t,e){var r,n;t>=0?(r=t%4294967296|0,n=t/4294967296|0):(n=~(-t/4294967296),4294967295^(r=~(-t%4294967296))?r=r+1|0:(r=0,n=n+1|0));if(t>=0x10000000000000000||t<-0x10000000000000000)throw new Error("Given varint doesn't fit into 10 bytes");e.realloc(10),function(t,e,r){r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos++]=127&t|128,t>>>=7,r.buf[r.pos]=127&t}(r,0,e),function(t,e){var r=(7&t)<<4;if(e.buf[e.pos++]|=r|((t>>>=3)?128:0),!t)return;if(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),!t)return;if(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),!t)return;if(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),!t)return;if(e.buf[e.pos++]=127&t|((t>>>=7)?128:0),!t)return;e.buf[e.pos++]=127&t}(n,e)}(t,this):(this.realloc(4),this.buf[this.pos++]=127&t|(t>127?128:0),t<=127||(this.buf[this.pos++]=127&(t>>>=7)|(t>127?128:0),t<=127||(this.buf[this.pos++]=127&(t>>>=7)|(t>127?128:0),t<=127||(this.buf[this.pos++]=t>>>7&127))))},writeSVarint:function(t){this.writeVarint(t<0?2*-t-1:2*t)},writeBoolean:function(t){this.writeVarint(Boolean(t))},writeString:function(t){t=String(t),this.realloc(4*t.length),this.pos++;var e=this.pos;this.pos=function(t,e,r){for(var n,i,o=0;o<e.length;o++){if((n=e.charCodeAt(o))>55295&&n<57344){if(!i){n>56319||o+1===e.length?(t[r++]=239,t[r++]=191,t[r++]=189):i=n;continue}if(n<56320){t[r++]=239,t[r++]=191,t[r++]=189,i=n;continue}n=i-55296<<10|n-56320|65536,i=null}else i&&(t[r++]=239,t[r++]=191,t[r++]=189,i=null);n<128?t[r++]=n:(n<2048?t[r++]=n>>6|192:(n<65536?t[r++]=n>>12|224:(t[r++]=n>>18|240,t[r++]=n>>12&63|128),t[r++]=n>>6&63|128),t[r++]=63&n|128)}return r}(this.buf,t,this.pos);var r=this.pos-e;r>=128&&l(e,r,this),this.pos=e-1,this.writeVarint(r),this.pos+=r},writeFloat:function(t){this.realloc(4),n.write(this.buf,t,this.pos,!0,23,4),this.pos+=4},writeDouble:function(t){this.realloc(8),n.write(this.buf,t,this.pos,!0,52,8),this.pos+=8},writeBytes:function(t){var e=t.length;this.writeVarint(e),this.realloc(e);for(var r=0;r<e;r++)this.buf[this.pos++]=t[r]},writeRawMessage:function(t,e){this.pos++;var r=this.pos;t(e,this);var n=this.pos-r;n>=128&&l(r,n,this),this.pos=r-1,this.writeVarint(n),this.pos+=n},writeMessage:function(t,e,r){this.writeTag(t,i.Bytes),this.writeRawMessage(e,r)},writePackedVarint:function(t,e){e.length&&this.writeMessage(t,u,e)},writePackedSVarint:function(t,e){e.length&&this.writeMessage(t,c,e)},writePackedBoolean:function(t,e){e.length&&this.writeMessage(t,f,e)},writePackedFloat:function(t,e){e.length&&this.writeMessage(t,h,e)},writePackedDouble:function(t,e){e.length&&this.writeMessage(t,p,e)},writePackedFixed32:function(t,e){e.length&&this.writeMessage(t,d,e)},writePackedSFixed32:function(t,e){e.length&&this.writeMessage(t,g,e)},writePackedFixed64:function(t,e){e.length&&this.writeMessage(t,y,e)},writePackedSFixed64:function(t,e){e.length&&this.writeMessage(t,m,e)},writeBytesField:function(t,e){this.writeTag(t,i.Bytes),this.writeBytes(e)},writeFixed32Field:function(t,e){this.writeTag(t,i.Fixed32),this.writeFixed32(e)},writeSFixed32Field:function(t,e){this.writeTag(t,i.Fixed32),this.writeSFixed32(e)},writeFixed64Field:function(t,e){this.writeTag(t,i.Fixed64),this.writeFixed64(e)},writeSFixed64Field:function(t,e){this.writeTag(t,i.Fixed64),this.writeSFixed64(e)},writeVarintField:function(t,e){this.writeTag(t,i.Varint),this.writeVarint(e)},writeSVarintField:function(t,e){this.writeTag(t,i.Varint),this.writeSVarint(e)},writeStringField:function(t,e){this.writeTag(t,i.Bytes),this.writeString(e)},writeFloatField:function(t,e){this.writeTag(t,i.Fixed32),this.writeFloat(e)},writeDoubleField:function(t,e){this.writeTag(t,i.Fixed64),this.writeDouble(e)},writeBooleanField:function(t,e){this.writeVarintField(t,Boolean(e))}}},function(t,e){(function(){var e;t.exports={icon:"icons/google.svg",name:"google",title:"Google Fonts",link:"google.com/fonts",getNames:function(){return e},getLink:function(t){return"https://fonts.google.com/specimen/"+t.replace(/( )/g,"+")},normalizeName:function(t){return t}},e=["ABeeZee","Abel","Abril Fatface","Aclonica","Acme","Actor","Adamina","Advent Pro","Aguafina Script","Akronim","Aladin","Aldrich","Alef","Alegreya","Alegreya SC","Alegreya Sans","Alegreya Sans SC","Alex Brush","Alfa Slab One","Alice","Alike","Alike Angular","Allan","Allerta","Allerta Stencil","Allura","Almendra","Almendra Display","Almendra SC","Amarante","Amaranth","Amatic SC","Amethysta","Amiri","Amita","Anaheim","Andada","Andika","Angkor","Annie Use Your Telescope","Anonymous Pro","Antic","Antic Didone","Antic Slab","Anton","Arapey","Arbutus","Arbutus Slab","Architects Daughter","Archivo Black","Archivo Narrow","Arimo","Arizonia","Armata","Artifika","Arvo","Arya","Asap","Asar","Asset","Astloch","Asul","Atomic Age","Aubrey","Audiowide","Autour One","Average","Average Sans","Averia Gruesa Libre","Averia Libre","Averia Sans Libre","Averia Serif Libre","Bad Script","Balthazar","Bangers","Basic","Battambang","Baumans","Bayon","Belgrano","Belleza","BenchNine","Bentham","Berkshire Swash","Bevan","Bigelow Rules","Bigshot One","Bilbo","Bilbo Swash Caps","Biryani","Bitter","Black Ops One","Bokor","Bonbon","Boogaloo","Bowlby One","Bowlby One SC","Brawler","Bree Serif","Bubblegum Sans","Bubbler One","Buda","Buenard","Butcherman","Butterfly Kids","Cabin","Cabin Condensed","Cabin Sketch","Caesar Dressing","Cagliostro","Calligraffitti","Cambay","Cambo","Candal","Cantarell","Cantata One","Cantora One","Capriola","Cardo","Carme","Carrois Gothic","Carrois Gothic SC","Carter One","Catamaran","Caudex","Caveat","Caveat Brush","Cedarville Cursive","Ceviche One","Changa One","Chango","Chau Philomene One","Chela One","Chelsea Market","Chenla","Cherry Cream Soda","Cherry Swash","Chewy","Chicle","Chivo","Chonburi","Cinzel","Cinzel Decorative","Clicker Script","Coda","Coda Caption","Codystar","Combo","Comfortaa","Coming Soon","Concert One","Condiment","Content","Contrail One","Convergence","Cookie","Copse","Corben","Courgette","Cousine","Coustard","Covered By Your Grace","Crafty Girls","Creepster","Crete Round","Crimson Text","Croissant One","Crushed","Cuprum","Cutive","Cutive Mono","Damion","Dancing Script","Dangrek","Dawning of a New Day","Days One","Dekko","Delius","Delius Swash Caps","Delius Unicase","Della Respira","Denk One","Devonshire","Dhurjati","Didact Gothic","Diplomata","Diplomata SC","Domine","Donegal One","Doppio One","Dorsa","Dosis","Dr Sugiyama","Droid Sans","Droid Sans Mono","Droid Serif","Duru Sans","Dynalight","EB Garamond","Eagle Lake","Eater","Economica","Eczar","Ek Mukta","Electrolize","Elsie","Elsie Swash Caps","Emblema One","Emilys Candy","Engagement","Englebert","Enriqueta","Erica One","Esteban","Euphoria Script","Ewert","Exo","Exo 2","Expletus Sans","Fanwood Text","Fascinate","Fascinate Inline","Faster One","Fasthand","Fauna One","Federant","Federo","Felipa","Fenix","Finger Paint","Fira Mono","Fira Sans","Fjalla One","Fjord One","Flamenco","Flavors","Fondamento","Fontdiner Swanky","Forum","Francois One","Freckle Face","Fredericka the Great","Fredoka One","Freehand","Fresca","Frijole","Fruktur","Fugaz One","GFS Didot","GFS Neohellenic","Gabriela","Gafata","Galdeano","Galindo","Gentium Basic","Gentium Book Basic","Geo","Geostar","Geostar Fill","Germania One","Gidugu","Gilda Display","Give You Glory","Glass Antiqua","Glegoo","Gloria Hallelujah","Goblin One","Gochi Hand","Gorditas","Goudy Bookletter 1911","Graduate","Grand Hotel","Gravitas One","Great Vibes","Griffy","Gruppo","Gudea","Gurajada","Habibi","Halant","Hammersmith One","Hanalei","Hanalei Fill","Handlee","Hanuman","Happy Monkey","Headland One","Henny Penny","Herr Von Muellerhoff","Hind","Hind Siliguri","Hind Vadodara","Holtwood One SC","Homemade Apple","Homenaje","IM Fell DW Pica","IM Fell DW Pica SC","IM Fell Double Pica","IM Fell Double Pica SC","IM Fell English","IM Fell English SC","IM Fell French Canon","IM Fell French Canon SC","IM Fell Great Primer","IM Fell Great Primer SC","Iceberg","Iceland","Imprima","Inconsolata","Inder","Indie Flower","Inika","Inknut Antiqua","Irish Grover","Istok Web","Italiana","Italianno","Itim","Jacques Francois","Jacques Francois Shadow","Jaldi","Jim Nightshade","Jockey One","Jolly Lodger","Josefin Sans","Josefin Slab","Joti One","Judson","Julee","Julius Sans One","Junge","Jura","Just Another Hand","Just Me Again Down Here","Kadwa","Kalam","Kameron","Kantumruy","Karla","Karma","Kaushan Script","Kavoon","Kdam Thmor","Keania One","Kelly Slab","Kenia","Khand","Khmer","Khula","Kite One","Knewave","Kotta One","Koulen","Kranky","Kreon","Kristi","Krona One","Kurale","La Belle Aurore","Laila","Lakki Reddy","Lancelot","Lateef","Lato","League Script","Leckerli One","Ledger","Lekton","Lemon","Libre Baskerville","Life Savers","Lilita One","Lily Script One","Limelight","Linden Hill","Lobster","Lobster Two","Londrina Outline","Londrina Shadow","Londrina Sketch","Londrina Solid","Lora","Love Ya Like A Sister","Loved by the King","Lovers Quarrel","Luckiest Guy","Lusitana","Lustria","Macondo","Macondo Swash Caps","Magra","Maiden Orange","Mako","Mallanna","Mandali","Marcellus","Marcellus SC","Marck Script","Margarine","Marko One","Marmelad","Martel","Martel Sans","Marvel","Mate","Mate SC","Maven Pro","McLaren","Meddon","MedievalSharp","Medula One","Megrim","Meie Script","Merienda","Merienda One","Merriweather","Merriweather Sans","Metal","Metal Mania","Metamorphous","Metrophobic","Michroma","Milonga","Miltonian","Miltonian Tattoo","Miniver","Miss Fajardose","Modak","Modern Antiqua","Molengo","Molle","Monda","Monofett","Monoton","Monsieur La Doulaise","Montaga","Montez","Montserrat","Montserrat Alternates","Montserrat Subrayada","Moul","Moulpali","Mountains of Christmas","Mouse Memoirs","Mr Bedfort","Mr Dafoe","Mr De Haviland","Mrs Saint Delafield","Mrs Sheppards","Muli","Mystery Quest","NTR","Neucha","Neuton","New Rocker","News Cycle","Niconne","Nixie One","Nobile","Nokora","Norican","Nosifer","Nothing You Could Do","Noticia Text","Noto Sans","Noto Serif","Nova Cut","Nova Flat","Nova Mono","Nova Oval","Nova Round","Nova Script","Nova Slim","Nova Square","Numans","Nunito","Odor Mean Chey","Offside","Old Standard TT","Oldenburg","Oleo Script","Oleo Script Swash Caps","Open Sans","Open Sans Condensed","Oranienbaum","Orbitron","Oregano","Orienta","Original Surfer","Oswald","Over the Rainbow","Overlock","Overlock SC","Ovo","Oxygen","Oxygen Mono","PT Mono","PT Sans","PT Sans Caption","PT Sans Narrow","PT Serif","PT Serif Caption","Pacifico","Palanquin","Palanquin Dark","Paprika","Parisienne","Passero One","Passion One","Pathway Gothic One","Patrick Hand","Patrick Hand SC","Patua One","Paytone One","Peddana","Peralta","Permanent Marker","Petit Formal Script","Petrona","Philosopher","Piedra","Pinyon Script","Pirata One","Plaster","Play","Playball","Playfair Display","Playfair Display SC","Podkova","Poiret One","Poller One","Poly","Pompiere","Pontano Sans","Poppins","Port Lligat Sans","Port Lligat Slab","Pragati Narrow","Prata","Preahvihear","Press Start 2P","Princess Sofia","Prociono","Prosto One","Puritan","Purple Purse","Quando","Quantico","Quattrocento","Quattrocento Sans","Questrial","Quicksand","Quintessential","Qwigley","Racing Sans One","Radley","Rajdhani","Raleway","Raleway Dots","Ramabhadra","Ramaraja","Rambla","Rammetto One","Ranchers","Rancho","Ranga","Rationale","Ravi Prakash","Redressed","Reenie Beanie","Revalia","Rhodium Libre","Ribeye","Ribeye Marrow","Righteous","Risque","Roboto","Roboto Condensed","Roboto Mono","Roboto Slab","Rochester","Rock Salt","Rokkitt","Romanesco","Ropa Sans","Rosario","Rosarivo","Rouge Script","Rozha One","Rubik","Rubik Mono One","Rubik One","Ruda","Rufina","Ruge Boogie","Ruluko","Rum Raisin","Ruslan Display","Russo One","Ruthie","Rye","Sacramento","Sahitya","Sail","Salsa","Sanchez","Sancreek","Sansita One","Sarala","Sarina","Sarpanch","Satisfy","Scada","Scheherazade","Schoolbell","Seaweed Script","Sevillana","Seymour One","Shadows Into Light","Shadows Into Light Two","Shanti","Share","Share Tech","Share Tech Mono","Shojumaru","Short Stack","Siemreap","Sigmar One","Signika","Signika Negative","Simonetta","Sintony","Sirin Stencil","Six Caps","Skranji","Slabo 13px","Slabo 27px","Slackey","Smokum","Smythe","Sniglet","Snippet","Snowburst One","Sofadi One","Sofia","Sonsie One","Sorts Mill Goudy","Source Code Pro","Source Sans Pro","Source Serif Pro","Special Elite","Spicy Rice","Spinnaker","Spirax","Squada One","Sree Krushnadevaraya","Stalemate","Stalinist One","Stardos Stencil","Stint Ultra Condensed","Stint Ultra Expanded","Stoke","Strait","Sue Ellen Francisco","Sumana","Sunshiney","Supermercado One","Sura","Suranna","Suravaram","Suwannaphum","Swanky and Moo Moo","Syncopate","Tangerine","Taprom","Tauri","Teko","Telex","Tenali Ramakrishna","Tenor Sans","Text Me One","The Girl Next Door","Tienne","Tillana","Timmana","Tinos","Titan One","Titillium Web","Trade Winds","Trocchi","Trochut","Trykker","Tulpen One","Ubuntu","Ubuntu Condensed","Ubuntu Mono","Ultra","Uncial Antiqua","Underdog","Unica One","UnifrakturCook","UnifrakturMaguntia","Unkempt","Unlock","Unna","VT323","Vampiro One","Varela","Varela Round","Vast Shadow","Vesper Libre","Vibur","Vidaloka","Viga","Voces","Volkhov","Vollkorn","Voltaire","Waiting for the Sunrise","Wallpoet","Walter Turncoat","Warnes","Wellfleet","Wendy One","Wire One","Work Sans","Yanone Kaffeesatz","Yantramanav","Yellowtail","Yeseva One","Yesteryear","Zeyada"]}).call(this)},function(t,e,r){"use strict";(function(t){ +/*! + * The buffer module from node.js, for the browser. + * + * @author Feross Aboukhadijeh <http://feross.org> + * @license MIT + */ +var n=r(8),i=r(3),o=r(9);function a(){return l.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(t,e){if(a()<e)throw new RangeError("Invalid typed array length");return l.TYPED_ARRAY_SUPPORT?(t=new Uint8Array(e)).__proto__=l.prototype:(null===t&&(t=new l(e)),t.length=e),t}function l(t,e,r){if(!(l.TYPED_ARRAY_SUPPORT||this instanceof l))return new l(t,e,r);if("number"==typeof t){if("string"==typeof e)throw new Error("If encoding is specified then the first argument must be a string");return h(this,t)}return u(this,t,e,r)}function u(t,e,r,n){if("number"==typeof e)throw new TypeError('"value" argument must not be a number');return"undefined"!=typeof ArrayBuffer&&e instanceof ArrayBuffer?function(t,e,r,n){if(e.byteLength,r<0||e.byteLength<r)throw new RangeError("'offset' is out of bounds");if(e.byteLength<r+(n||0))throw new RangeError("'length' is out of bounds");e=void 0===r&&void 0===n?new Uint8Array(e):void 0===n?new Uint8Array(e,r):new Uint8Array(e,r,n);l.TYPED_ARRAY_SUPPORT?(t=e).__proto__=l.prototype:t=p(t,e);return t}(t,e,r,n):"string"==typeof e?function(t,e,r){"string"==typeof r&&""!==r||(r="utf8");if(!l.isEncoding(r))throw new TypeError('"encoding" must be a valid string encoding');var n=0|d(e,r),i=(t=s(t,n)).write(e,r);i!==n&&(t=t.slice(0,i));return t}(t,e,r):function(t,e){if(l.isBuffer(e)){var r=0|f(e.length);return 0===(t=s(t,r)).length||e.copy(t,0,0,r),t}if(e){if("undefined"!=typeof ArrayBuffer&&e.buffer instanceof ArrayBuffer||"length"in e)return"number"!=typeof e.length||(n=e.length)!=n?s(t,0):p(t,e);if("Buffer"===e.type&&o(e.data))return p(t,e.data)}var n;throw new TypeError("First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.")}(t,e)}function c(t){if("number"!=typeof t)throw new TypeError('"size" argument must be a number');if(t<0)throw new RangeError('"size" argument must not be negative')}function h(t,e){if(c(e),t=s(t,e<0?0:0|f(e)),!l.TYPED_ARRAY_SUPPORT)for(var r=0;r<e;++r)t[r]=0;return t}function p(t,e){var r=e.length<0?0:0|f(e.length);t=s(t,r);for(var n=0;n<r;n+=1)t[n]=255&e[n];return t}function f(t){if(t>=a())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+a().toString(16)+" bytes");return 0|t}function d(t,e){if(l.isBuffer(t))return t.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(t)||t instanceof ArrayBuffer))return t.byteLength;"string"!=typeof t&&(t=""+t);var r=t.length;if(0===r)return 0;for(var n=!1;;)switch(e){case"ascii":case"latin1":case"binary":return r;case"utf8":case"utf-8":case void 0:return z(t).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*r;case"hex":return r>>>1;case"base64":return U(t).length;default:if(n)return z(t).length;e=(""+e).toLowerCase(),n=!0}}function g(t,e,r){var n=!1;if((void 0===e||e<0)&&(e=0),e>this.length)return"";if((void 0===r||r>this.length)&&(r=this.length),r<=0)return"";if((r>>>=0)<=(e>>>=0))return"";for(t||(t="utf8");;)switch(t){case"hex":return R(this,e,r);case"utf8":case"utf-8":return C(this,e,r);case"ascii":return O(this,e,r);case"latin1":case"binary":return P(this,e,r);case"base64":return T(this,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,e,r);default:if(n)throw new TypeError("Unknown encoding: "+t);t=(t+"").toLowerCase(),n=!0}}function y(t,e,r){var n=t[e];t[e]=t[r],t[r]=n}function m(t,e,r,n,i){if(0===t.length)return-1;if("string"==typeof r?(n=r,r=0):r>2147483647?r=2147483647:r<-2147483648&&(r=-2147483648),r=+r,isNaN(r)&&(r=i?0:t.length-1),r<0&&(r=t.length+r),r>=t.length){if(i)return-1;r=t.length-1}else if(r<0){if(!i)return-1;r=0}if("string"==typeof e&&(e=l.from(e,n)),l.isBuffer(e))return 0===e.length?-1:v(t,e,r,n,i);if("number"==typeof e)return e&=255,l.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?i?Uint8Array.prototype.indexOf.call(t,e,r):Uint8Array.prototype.lastIndexOf.call(t,e,r):v(t,[e],r,n,i);throw new TypeError("val must be string, number or Buffer")}function v(t,e,r,n,i){var o,a=1,s=t.length,l=e.length;if(void 0!==n&&("ucs2"===(n=String(n).toLowerCase())||"ucs-2"===n||"utf16le"===n||"utf-16le"===n)){if(t.length<2||e.length<2)return-1;a=2,s/=2,l/=2,r/=2}function u(t,e){return 1===a?t[e]:t.readUInt16BE(e*a)}if(i){var c=-1;for(o=r;o<s;o++)if(u(t,o)===u(e,-1===c?0:o-c)){if(-1===c&&(c=o),o-c+1===l)return c*a}else-1!==c&&(o-=o-c),c=-1}else for(r+l>s&&(r=s-l),o=r;o>=0;o--){for(var h=!0,p=0;p<l;p++)if(u(t,o+p)!==u(e,p)){h=!1;break}if(h)return o}return-1}function _(t,e,r,n){r=Number(r)||0;var i=t.length-r;n?(n=Number(n))>i&&(n=i):n=i;var o=e.length;if(o%2!=0)throw new TypeError("Invalid hex string");n>o/2&&(n=o/2);for(var a=0;a<n;++a){var s=parseInt(e.substr(2*a,2),16);if(isNaN(s))return a;t[r+a]=s}return a}function b(t,e,r,n){return B(z(e,t.length-r),t,r,n)}function x(t,e,r,n){return B(function(t){for(var e=[],r=0;r<t.length;++r)e.push(255&t.charCodeAt(r));return e}(e),t,r,n)}function w(t,e,r,n){return x(t,e,r,n)}function S(t,e,r,n){return B(U(e),t,r,n)}function E(t,e,r,n){return B(function(t,e){for(var r,n,i,o=[],a=0;a<t.length&&!((e-=2)<0);++a)r=t.charCodeAt(a),n=r>>8,i=r%256,o.push(i),o.push(n);return o}(e,t.length-r),t,r,n)}function T(t,e,r){return 0===e&&r===t.length?n.fromByteArray(t):n.fromByteArray(t.slice(e,r))}function C(t,e,r){r=Math.min(t.length,r);for(var n=[],i=e;i<r;){var o,a,s,l,u=t[i],c=null,h=u>239?4:u>223?3:u>191?2:1;if(i+h<=r)switch(h){case 1:u<128&&(c=u);break;case 2:128==(192&(o=t[i+1]))&&(l=(31&u)<<6|63&o)>127&&(c=l);break;case 3:o=t[i+1],a=t[i+2],128==(192&o)&&128==(192&a)&&(l=(15&u)<<12|(63&o)<<6|63&a)>2047&&(l<55296||l>57343)&&(c=l);break;case 4:o=t[i+1],a=t[i+2],s=t[i+3],128==(192&o)&&128==(192&a)&&128==(192&s)&&(l=(15&u)<<18|(63&o)<<12|(63&a)<<6|63&s)>65535&&l<1114112&&(c=l)}null===c?(c=65533,h=1):c>65535&&(c-=65536,n.push(c>>>10&1023|55296),c=56320|1023&c),n.push(c),i+=h}return function(t){var e=t.length;if(e<=4096)return String.fromCharCode.apply(String,t);var r="",n=0;for(;n<e;)r+=String.fromCharCode.apply(String,t.slice(n,n+=4096));return r}(n)}e.Buffer=l,e.SlowBuffer=function(t){+t!=t&&(t=0);return l.alloc(+t)},e.INSPECT_MAX_BYTES=50,l.TYPED_ARRAY_SUPPORT=void 0!==t.TYPED_ARRAY_SUPPORT?t.TYPED_ARRAY_SUPPORT:function(){try{var t=new Uint8Array(1);return t.__proto__={__proto__:Uint8Array.prototype,foo:function(){return 42}},42===t.foo()&&"function"==typeof t.subarray&&0===t.subarray(1,1).byteLength}catch(t){return!1}}(),e.kMaxLength=a(),l.poolSize=8192,l._augment=function(t){return t.__proto__=l.prototype,t},l.from=function(t,e,r){return u(null,t,e,r)},l.TYPED_ARRAY_SUPPORT&&(l.prototype.__proto__=Uint8Array.prototype,l.__proto__=Uint8Array,"undefined"!=typeof Symbol&&Symbol.species&&l[Symbol.species]===l&&Object.defineProperty(l,Symbol.species,{value:null,configurable:!0})),l.alloc=function(t,e,r){return function(t,e,r,n){return c(e),e<=0?s(t,e):void 0!==r?"string"==typeof n?s(t,e).fill(r,n):s(t,e).fill(r):s(t,e)}(null,t,e,r)},l.allocUnsafe=function(t){return h(null,t)},l.allocUnsafeSlow=function(t){return h(null,t)},l.isBuffer=function(t){return!(null==t||!t._isBuffer)},l.compare=function(t,e){if(!l.isBuffer(t)||!l.isBuffer(e))throw new TypeError("Arguments must be Buffers");if(t===e)return 0;for(var r=t.length,n=e.length,i=0,o=Math.min(r,n);i<o;++i)if(t[i]!==e[i]){r=t[i],n=e[i];break}return r<n?-1:n<r?1:0},l.isEncoding=function(t){switch(String(t).toLowerCase()){case"hex":case"utf8":case"utf-8":case"ascii":case"latin1":case"binary":case"base64":case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return!0;default:return!1}},l.concat=function(t,e){if(!o(t))throw new TypeError('"list" argument must be an Array of Buffers');if(0===t.length)return l.alloc(0);var r;if(void 0===e)for(e=0,r=0;r<t.length;++r)e+=t[r].length;var n=l.allocUnsafe(e),i=0;for(r=0;r<t.length;++r){var a=t[r];if(!l.isBuffer(a))throw new TypeError('"list" argument must be an Array of Buffers');a.copy(n,i),i+=a.length}return n},l.byteLength=d,l.prototype._isBuffer=!0,l.prototype.swap16=function(){var t=this.length;if(t%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(var e=0;e<t;e+=2)y(this,e,e+1);return this},l.prototype.swap32=function(){var t=this.length;if(t%4!=0)throw new RangeError("Buffer size must be a multiple of 32-bits");for(var e=0;e<t;e+=4)y(this,e,e+3),y(this,e+1,e+2);return this},l.prototype.swap64=function(){var t=this.length;if(t%8!=0)throw new RangeError("Buffer size must be a multiple of 64-bits");for(var e=0;e<t;e+=8)y(this,e,e+7),y(this,e+1,e+6),y(this,e+2,e+5),y(this,e+3,e+4);return this},l.prototype.toString=function(){var t=0|this.length;return 0===t?"":0===arguments.length?C(this,0,t):g.apply(this,arguments)},l.prototype.equals=function(t){if(!l.isBuffer(t))throw new TypeError("Argument must be a Buffer");return this===t||0===l.compare(this,t)},l.prototype.inspect=function(){var t="",r=e.INSPECT_MAX_BYTES;return this.length>0&&(t=this.toString("hex",0,r).match(/.{2}/g).join(" "),this.length>r&&(t+=" ... ")),"<Buffer "+t+">"},l.prototype.compare=function(t,e,r,n,i){if(!l.isBuffer(t))throw new TypeError("Argument must be a Buffer");if(void 0===e&&(e=0),void 0===r&&(r=t?t.length:0),void 0===n&&(n=0),void 0===i&&(i=this.length),e<0||r>t.length||n<0||i>this.length)throw new RangeError("out of range index");if(n>=i&&e>=r)return 0;if(n>=i)return-1;if(e>=r)return 1;if(this===t)return 0;for(var o=(i>>>=0)-(n>>>=0),a=(r>>>=0)-(e>>>=0),s=Math.min(o,a),u=this.slice(n,i),c=t.slice(e,r),h=0;h<s;++h)if(u[h]!==c[h]){o=u[h],a=c[h];break}return o<a?-1:a<o?1:0},l.prototype.includes=function(t,e,r){return-1!==this.indexOf(t,e,r)},l.prototype.indexOf=function(t,e,r){return m(this,t,e,r,!0)},l.prototype.lastIndexOf=function(t,e,r){return m(this,t,e,r,!1)},l.prototype.write=function(t,e,r,n){if(void 0===e)n="utf8",r=this.length,e=0;else if(void 0===r&&"string"==typeof e)n=e,r=this.length,e=0;else{if(!isFinite(e))throw new Error("Buffer.write(string, encoding, offset[, length]) is no longer supported");e|=0,isFinite(r)?(r|=0,void 0===n&&(n="utf8")):(n=r,r=void 0)}var i=this.length-e;if((void 0===r||r>i)&&(r=i),t.length>0&&(r<0||e<0)||e>this.length)throw new RangeError("Attempt to write outside buffer bounds");n||(n="utf8");for(var o=!1;;)switch(n){case"hex":return _(this,t,e,r);case"utf8":case"utf-8":return b(this,t,e,r);case"ascii":return x(this,t,e,r);case"latin1":case"binary":return w(this,t,e,r);case"base64":return S(this,t,e,r);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return E(this,t,e,r);default:if(o)throw new TypeError("Unknown encoding: "+n);n=(""+n).toLowerCase(),o=!0}},l.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};function O(t,e,r){var n="";r=Math.min(t.length,r);for(var i=e;i<r;++i)n+=String.fromCharCode(127&t[i]);return n}function P(t,e,r){var n="";r=Math.min(t.length,r);for(var i=e;i<r;++i)n+=String.fromCharCode(t[i]);return n}function R(t,e,r){var n=t.length;(!e||e<0)&&(e=0),(!r||r<0||r>n)&&(r=n);for(var i="",o=e;o<r;++o)i+=G(t[o]);return i}function I(t,e,r){for(var n=t.slice(e,r),i="",o=0;o<n.length;o+=2)i+=String.fromCharCode(n[o]+256*n[o+1]);return i}function L(t,e,r){if(t%1!=0||t<0)throw new RangeError("offset is not uint");if(t+e>r)throw new RangeError("Trying to access beyond buffer length")}function M(t,e,r,n,i,o){if(!l.isBuffer(t))throw new TypeError('"buffer" argument must be a Buffer instance');if(e>i||e<o)throw new RangeError('"value" argument is out of bounds');if(r+n>t.length)throw new RangeError("Index out of range")}function F(t,e,r,n){e<0&&(e=65535+e+1);for(var i=0,o=Math.min(t.length-r,2);i<o;++i)t[r+i]=(e&255<<8*(n?i:1-i))>>>8*(n?i:1-i)}function A(t,e,r,n){e<0&&(e=4294967295+e+1);for(var i=0,o=Math.min(t.length-r,4);i<o;++i)t[r+i]=e>>>8*(n?i:3-i)&255}function k(t,e,r,n,i,o){if(r+n>t.length)throw new RangeError("Index out of range");if(r<0)throw new RangeError("Index out of range")}function j(t,e,r,n,o){return o||k(t,0,r,4),i.write(t,e,r,n,23,4),r+4}function N(t,e,r,n,o){return o||k(t,0,r,8),i.write(t,e,r,n,52,8),r+8}l.prototype.slice=function(t,e){var r,n=this.length;if((t=~~t)<0?(t+=n)<0&&(t=0):t>n&&(t=n),(e=void 0===e?n:~~e)<0?(e+=n)<0&&(e=0):e>n&&(e=n),e<t&&(e=t),l.TYPED_ARRAY_SUPPORT)(r=this.subarray(t,e)).__proto__=l.prototype;else{var i=e-t;r=new l(i,void 0);for(var o=0;o<i;++o)r[o]=this[o+t]}return r},l.prototype.readUIntLE=function(t,e,r){t|=0,e|=0,r||L(t,e,this.length);for(var n=this[t],i=1,o=0;++o<e&&(i*=256);)n+=this[t+o]*i;return n},l.prototype.readUIntBE=function(t,e,r){t|=0,e|=0,r||L(t,e,this.length);for(var n=this[t+--e],i=1;e>0&&(i*=256);)n+=this[t+--e]*i;return n},l.prototype.readUInt8=function(t,e){return e||L(t,1,this.length),this[t]},l.prototype.readUInt16LE=function(t,e){return e||L(t,2,this.length),this[t]|this[t+1]<<8},l.prototype.readUInt16BE=function(t,e){return e||L(t,2,this.length),this[t]<<8|this[t+1]},l.prototype.readUInt32LE=function(t,e){return e||L(t,4,this.length),(this[t]|this[t+1]<<8|this[t+2]<<16)+16777216*this[t+3]},l.prototype.readUInt32BE=function(t,e){return e||L(t,4,this.length),16777216*this[t]+(this[t+1]<<16|this[t+2]<<8|this[t+3])},l.prototype.readIntLE=function(t,e,r){t|=0,e|=0,r||L(t,e,this.length);for(var n=this[t],i=1,o=0;++o<e&&(i*=256);)n+=this[t+o]*i;return n>=(i*=128)&&(n-=Math.pow(2,8*e)),n},l.prototype.readIntBE=function(t,e,r){t|=0,e|=0,r||L(t,e,this.length);for(var n=e,i=1,o=this[t+--n];n>0&&(i*=256);)o+=this[t+--n]*i;return o>=(i*=128)&&(o-=Math.pow(2,8*e)),o},l.prototype.readInt8=function(t,e){return e||L(t,1,this.length),128&this[t]?-1*(255-this[t]+1):this[t]},l.prototype.readInt16LE=function(t,e){e||L(t,2,this.length);var r=this[t]|this[t+1]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt16BE=function(t,e){e||L(t,2,this.length);var r=this[t+1]|this[t]<<8;return 32768&r?4294901760|r:r},l.prototype.readInt32LE=function(t,e){return e||L(t,4,this.length),this[t]|this[t+1]<<8|this[t+2]<<16|this[t+3]<<24},l.prototype.readInt32BE=function(t,e){return e||L(t,4,this.length),this[t]<<24|this[t+1]<<16|this[t+2]<<8|this[t+3]},l.prototype.readFloatLE=function(t,e){return e||L(t,4,this.length),i.read(this,t,!0,23,4)},l.prototype.readFloatBE=function(t,e){return e||L(t,4,this.length),i.read(this,t,!1,23,4)},l.prototype.readDoubleLE=function(t,e){return e||L(t,8,this.length),i.read(this,t,!0,52,8)},l.prototype.readDoubleBE=function(t,e){return e||L(t,8,this.length),i.read(this,t,!1,52,8)},l.prototype.writeUIntLE=function(t,e,r,n){(t=+t,e|=0,r|=0,n)||M(this,t,e,r,Math.pow(2,8*r)-1,0);var i=1,o=0;for(this[e]=255&t;++o<r&&(i*=256);)this[e+o]=t/i&255;return e+r},l.prototype.writeUIntBE=function(t,e,r,n){(t=+t,e|=0,r|=0,n)||M(this,t,e,r,Math.pow(2,8*r)-1,0);var i=r-1,o=1;for(this[e+i]=255&t;--i>=0&&(o*=256);)this[e+i]=t/o&255;return e+r},l.prototype.writeUInt8=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,1,255,0),l.TYPED_ARRAY_SUPPORT||(t=Math.floor(t)),this[e]=255&t,e+1},l.prototype.writeUInt16LE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,2,65535,0),l.TYPED_ARRAY_SUPPORT?(this[e]=255&t,this[e+1]=t>>>8):F(this,t,e,!0),e+2},l.prototype.writeUInt16BE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,2,65535,0),l.TYPED_ARRAY_SUPPORT?(this[e]=t>>>8,this[e+1]=255&t):F(this,t,e,!1),e+2},l.prototype.writeUInt32LE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,4,4294967295,0),l.TYPED_ARRAY_SUPPORT?(this[e+3]=t>>>24,this[e+2]=t>>>16,this[e+1]=t>>>8,this[e]=255&t):A(this,t,e,!0),e+4},l.prototype.writeUInt32BE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,4,4294967295,0),l.TYPED_ARRAY_SUPPORT?(this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t):A(this,t,e,!1),e+4},l.prototype.writeIntLE=function(t,e,r,n){if(t=+t,e|=0,!n){var i=Math.pow(2,8*r-1);M(this,t,e,r,i-1,-i)}var o=0,a=1,s=0;for(this[e]=255&t;++o<r&&(a*=256);)t<0&&0===s&&0!==this[e+o-1]&&(s=1),this[e+o]=(t/a>>0)-s&255;return e+r},l.prototype.writeIntBE=function(t,e,r,n){if(t=+t,e|=0,!n){var i=Math.pow(2,8*r-1);M(this,t,e,r,i-1,-i)}var o=r-1,a=1,s=0;for(this[e+o]=255&t;--o>=0&&(a*=256);)t<0&&0===s&&0!==this[e+o+1]&&(s=1),this[e+o]=(t/a>>0)-s&255;return e+r},l.prototype.writeInt8=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,1,127,-128),l.TYPED_ARRAY_SUPPORT||(t=Math.floor(t)),t<0&&(t=255+t+1),this[e]=255&t,e+1},l.prototype.writeInt16LE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,2,32767,-32768),l.TYPED_ARRAY_SUPPORT?(this[e]=255&t,this[e+1]=t>>>8):F(this,t,e,!0),e+2},l.prototype.writeInt16BE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,2,32767,-32768),l.TYPED_ARRAY_SUPPORT?(this[e]=t>>>8,this[e+1]=255&t):F(this,t,e,!1),e+2},l.prototype.writeInt32LE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,4,2147483647,-2147483648),l.TYPED_ARRAY_SUPPORT?(this[e]=255&t,this[e+1]=t>>>8,this[e+2]=t>>>16,this[e+3]=t>>>24):A(this,t,e,!0),e+4},l.prototype.writeInt32BE=function(t,e,r){return t=+t,e|=0,r||M(this,t,e,4,2147483647,-2147483648),t<0&&(t=4294967295+t+1),l.TYPED_ARRAY_SUPPORT?(this[e]=t>>>24,this[e+1]=t>>>16,this[e+2]=t>>>8,this[e+3]=255&t):A(this,t,e,!1),e+4},l.prototype.writeFloatLE=function(t,e,r){return j(this,t,e,!0,r)},l.prototype.writeFloatBE=function(t,e,r){return j(this,t,e,!1,r)},l.prototype.writeDoubleLE=function(t,e,r){return N(this,t,e,!0,r)},l.prototype.writeDoubleBE=function(t,e,r){return N(this,t,e,!1,r)},l.prototype.copy=function(t,e,r,n){if(r||(r=0),n||0===n||(n=this.length),e>=t.length&&(e=t.length),e||(e=0),n>0&&n<r&&(n=r),n===r)return 0;if(0===t.length||0===this.length)return 0;if(e<0)throw new RangeError("targetStart out of bounds");if(r<0||r>=this.length)throw new RangeError("sourceStart out of bounds");if(n<0)throw new RangeError("sourceEnd out of bounds");n>this.length&&(n=this.length),t.length-e<n-r&&(n=t.length-e+r);var i,o=n-r;if(this===t&&r<e&&e<n)for(i=o-1;i>=0;--i)t[i+e]=this[i+r];else if(o<1e3||!l.TYPED_ARRAY_SUPPORT)for(i=0;i<o;++i)t[i+e]=this[i+r];else Uint8Array.prototype.set.call(t,this.subarray(r,r+o),e);return o},l.prototype.fill=function(t,e,r,n){if("string"==typeof t){if("string"==typeof e?(n=e,e=0,r=this.length):"string"==typeof r&&(n=r,r=this.length),1===t.length){var i=t.charCodeAt(0);i<256&&(t=i)}if(void 0!==n&&"string"!=typeof n)throw new TypeError("encoding must be a string");if("string"==typeof n&&!l.isEncoding(n))throw new TypeError("Unknown encoding: "+n)}else"number"==typeof t&&(t&=255);if(e<0||this.length<e||this.length<r)throw new RangeError("Out of range index");if(r<=e)return this;var o;if(e>>>=0,r=void 0===r?this.length:r>>>0,t||(t=0),"number"==typeof t)for(o=e;o<r;++o)this[o]=t;else{var a=l.isBuffer(t)?t:z(new l(t,n).toString()),s=a.length;for(o=0;o<r-e;++o)this[o+e]=a[o%s]}return this};var D=/[^+\/0-9A-Za-z-_]/g;function G(t){return t<16?"0"+t.toString(16):t.toString(16)}function z(t,e){var r;e=e||1/0;for(var n=t.length,i=null,o=[],a=0;a<n;++a){if((r=t.charCodeAt(a))>55295&&r<57344){if(!i){if(r>56319){(e-=3)>-1&&o.push(239,191,189);continue}if(a+1===n){(e-=3)>-1&&o.push(239,191,189);continue}i=r;continue}if(r<56320){(e-=3)>-1&&o.push(239,191,189),i=r;continue}r=65536+(i-55296<<10|r-56320)}else i&&(e-=3)>-1&&o.push(239,191,189);if(i=null,r<128){if((e-=1)<0)break;o.push(r)}else if(r<2048){if((e-=2)<0)break;o.push(r>>6|192,63&r|128)}else if(r<65536){if((e-=3)<0)break;o.push(r>>12|224,r>>6&63|128,63&r|128)}else{if(!(r<1114112))throw new Error("Invalid code point");if((e-=4)<0)break;o.push(r>>18|240,r>>12&63|128,r>>6&63|128,63&r|128)}}return o}function U(t){return n.toByteArray(function(t){if((t=function(t){return t.trim?t.trim():t.replace(/^\s+|\s+$/g,"")}(t).replace(D,"")).length<2)return"";for(;t.length%4!=0;)t+="=";return t}(t))}function B(t,e,r,n){for(var i=0;i<n&&!(i+r>=e.length||i>=t.length);++i)e[i+r]=t[i];return i}}).call(this,r(4))},function(t,e,r){"use strict";e.byteLength=function(t){var e=u(t),r=e[0],n=e[1];return 3*(r+n)/4-n},e.toByteArray=function(t){var e,r,n=u(t),a=n[0],s=n[1],l=new o(function(t,e,r){return 3*(e+r)/4-r}(0,a,s)),c=0,h=s>0?a-4:a;for(r=0;r<h;r+=4)e=i[t.charCodeAt(r)]<<18|i[t.charCodeAt(r+1)]<<12|i[t.charCodeAt(r+2)]<<6|i[t.charCodeAt(r+3)],l[c++]=e>>16&255,l[c++]=e>>8&255,l[c++]=255&e;2===s&&(e=i[t.charCodeAt(r)]<<2|i[t.charCodeAt(r+1)]>>4,l[c++]=255&e);1===s&&(e=i[t.charCodeAt(r)]<<10|i[t.charCodeAt(r+1)]<<4|i[t.charCodeAt(r+2)]>>2,l[c++]=e>>8&255,l[c++]=255&e);return l},e.fromByteArray=function(t){for(var e,r=t.length,i=r%3,o=[],a=0,s=r-i;a<s;a+=16383)o.push(c(t,a,a+16383>s?s:a+16383));1===i?(e=t[r-1],o.push(n[e>>2]+n[e<<4&63]+"==")):2===i&&(e=(t[r-2]<<8)+t[r-1],o.push(n[e>>10]+n[e>>4&63]+n[e<<2&63]+"="));return o.join("")};for(var n=[],i=[],o="undefined"!=typeof Uint8Array?Uint8Array:Array,a="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",s=0,l=a.length;s<l;++s)n[s]=a[s],i[a.charCodeAt(s)]=s;function u(t){var e=t.length;if(e%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var r=t.indexOf("=");return-1===r&&(r=e),[r,r===e?0:4-r%4]}function c(t,e,r){for(var i,o,a=[],s=e;s<r;s+=3)i=(t[s]<<16&16711680)+(t[s+1]<<8&65280)+(255&t[s+2]),a.push(n[(o=i)>>18&63]+n[o>>12&63]+n[o>>6&63]+n[63&o]);return a.join("")}i["-".charCodeAt(0)]=62,i["_".charCodeAt(0)]=63},function(t,e){var r={}.toString;t.exports=Array.isArray||function(t){return"[object Array]"==r.call(t)}},function(t,e,r){"use strict";function n(){return function(){throw new Error("Unimplemented abstract method.")}()}r.r(e);var i=0;function o(t){return t.ol_uid||(t.ol_uid=String(++i))}var a,s=(a=function(t,e){return(a=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(t,e)},function(t,e){function r(){this.constructor=t}a(t,e),t.prototype=null===e?Object.create(e):(r.prototype=e.prototype,new r)}),l=function(t){function e(e){var r=this,n="Assertion failed. See https://openlayers.org/en/"+("v"+"6.5.0".split("-")[0])+"/doc/errors/#"+e+" for details.";return(r=t.call(this,n)||this).code=e,r.name="AssertionError",r.message=n,r}return s(e,t),e}(Error);function u(t){t.stopPropagation()}var c=function(){function t(t){this.propagationStopped,this.type=t,this.target=null}return t.prototype.preventDefault=function(){this.propagationStopped=!0},t.prototype.stopPropagation=function(){this.propagationStopped=!0},t}(),h="propertychange",p=function(){function t(){this.disposed=!1}return t.prototype.dispose=function(){this.disposed||(this.disposed=!0,this.disposeInternal())},t.prototype.disposeInternal=function(){},t}();function f(t,e,r){for(var n,i,o=r||d,a=0,s=t.length,l=!1;a<s;)(i=+o(t[n=a+(s-a>>1)],e))<0?a=n+1:(s=n,l=!i);return l?a:~a}function d(t,e){return t>e?1:t<e?-1:0}function g(t,e){return t.indexOf(e)>=0}function y(t,e,r){var n=t.length;if(t[0]<=e)return 0;if(e<=t[n-1])return n-1;var i=void 0;if(r>0){for(i=1;i<n;++i)if(t[i]<e)return i-1}else if(r<0){for(i=1;i<n;++i)if(t[i]<=e)return i}else for(i=1;i<n;++i){if(t[i]==e)return i;if(t[i]<e)return t[i-1]-e<e-t[i]?i-1:i}return n-1}function m(t,e,r){for(;e<r;){var n=t[e];t[e]=t[r],t[r]=n,++e,--r}}function v(t,e){for(var r=Array.isArray(e)?e:[e],n=r.length,i=0;i<n;i++)t[t.length]=r[i]}function _(t,e){for(var r,n=t.length>>>0,i=0;i<n;i++)if(e(r=t[i],i,t))return r;return null}function b(t,e){var r=t.length;if(r!==e.length)return!1;for(var n=0;n<r;n++)if(t[n]!==e[n])return!1;return!0}function x(t,e){var r;return!t.every((function(n,i){return r=i,!e(n,i,t)}))?r:-1}function w(t,e,r){var n=e||d;return t.every((function(e,i){if(0===i)return!0;var o=n(t[i-1],e);return!(o>0||r&&0===o)}))}function S(){return!0}function E(){return!1}function T(){}function C(t){var e,r,n,i=!1;return function(){var o=Array.prototype.slice.call(arguments);return i&&this===n&&b(o,r)||(i=!0,n=this,r=o,e=t.apply(this,arguments)),e}}var O="function"==typeof Object.assign?Object.assign:function(t,e){if(null==t)throw new TypeError("Cannot convert undefined or null to object");for(var r=Object(t),n=1,i=arguments.length;n<i;++n){var o=arguments[n];if(null!=o)for(var a in o)o.hasOwnProperty(a)&&(r[a]=o[a])}return r};function P(t){for(var e in t)delete t[e]}var R="function"==typeof Object.values?Object.values:function(t){var e=[];for(var r in t)e.push(t[r]);return e};function I(t){var e;for(e in t)return!1;return!e}var L=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),M=function(t){function e(e){var r=t.call(this)||this;return r.eventTarget_=e,r.pendingRemovals_=null,r.dispatching_=null,r.listeners_=null,r}return L(e,t),e.prototype.addEventListener=function(t,e){if(t&&e){var r=this.listeners_||(this.listeners_={}),n=r[t]||(r[t]=[]);-1===n.indexOf(e)&&n.push(e)}},e.prototype.dispatchEvent=function(t){var e="string"==typeof t?new c(t):t,r=e.type;e.target||(e.target=this.eventTarget_||this);var n,i=this.listeners_&&this.listeners_[r];if(i){var o=this.dispatching_||(this.dispatching_={}),a=this.pendingRemovals_||(this.pendingRemovals_={});r in o||(o[r]=0,a[r]=0),++o[r];for(var s=0,l=i.length;s<l;++s)if(!1===(n="handleEvent"in i[s]?i[s].handleEvent(e):i[s].call(this,e))||e.propagationStopped){n=!1;break}if(--o[r],0===o[r]){var u=a[r];for(delete a[r];u--;)this.removeEventListener(r,T);delete o[r]}return n}},e.prototype.disposeInternal=function(){this.listeners_&&P(this.listeners_)},e.prototype.getListeners=function(t){return this.listeners_&&this.listeners_[t]||void 0},e.prototype.hasListener=function(t){return!!this.listeners_&&(t?t in this.listeners_:Object.keys(this.listeners_).length>0)},e.prototype.removeEventListener=function(t,e){var r=this.listeners_&&this.listeners_[t];if(r){var n=r.indexOf(e);-1!==n&&(this.pendingRemovals_&&t in this.pendingRemovals_?(r[n]=T,++this.pendingRemovals_[t]):(r.splice(n,1),0===r.length&&delete this.listeners_[t]))}},e}(p),F="change",A="error",k="clear",j="contextmenu",N="click",D="dblclick",G="dragenter",z="dragover",U="drop",B="keydown",V="keypress",Y="load",W="resize",q="touchmove",X="wheel";function Z(t,e,r,n,i){if(n&&n!==t&&(r=r.bind(n)),i){var o=r;r=function(){t.removeEventListener(e,r),o.apply(this,arguments)}}var a={target:t,type:e,listener:r};return t.addEventListener(e,r),a}function K(t,e,r,n){return Z(t,e,r,n,!0)}function H(t){t&&t.target&&(t.target.removeEventListener(t.type,t.listener),P(t))}var $=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function J(t){if(Array.isArray(t))for(var e=0,r=t.length;e<r;++e)H(t[e]);else H(t)}var Q=function(t){function e(){var e=t.call(this)||this;return e.revision_=0,e}return $(e,t),e.prototype.changed=function(){++this.revision_,this.dispatchEvent(F)},e.prototype.getRevision=function(){return this.revision_},e.prototype.on=function(t,e){if(Array.isArray(t)){for(var r=t.length,n=new Array(r),i=0;i<r;++i)n[i]=Z(this,t[i],e);return n}return Z(this,t,e)},e.prototype.once=function(t,e){var r;if(Array.isArray(t)){var n=t.length;r=new Array(n);for(var i=0;i<n;++i)r[i]=K(this,t[i],e)}else r=K(this,t,e);return e.ol_key=r,r},e.prototype.un=function(t,e){var r=e.ol_key;if(r)J(r);else if(Array.isArray(t))for(var n=0,i=t.length;n<i;++n)this.removeEventListener(t[n],e);else this.removeEventListener(t,e)},e}(M),tt=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),et=function(t){function e(e,r,n){var i=t.call(this,e)||this;return i.key=r,i.oldValue=n,i}return tt(e,t),e}(c),rt=function(t){function e(e){var r=t.call(this)||this;return o(r),r.values_=null,void 0!==e&&r.setProperties(e),r}return tt(e,t),e.prototype.get=function(t){var e;return this.values_&&this.values_.hasOwnProperty(t)&&(e=this.values_[t]),e},e.prototype.getKeys=function(){return this.values_&&Object.keys(this.values_)||[]},e.prototype.getProperties=function(){return this.values_&&O({},this.values_)||{}},e.prototype.hasProperties=function(){return!!this.values_},e.prototype.notify=function(t,e){var r;r=it(t),this.dispatchEvent(new et(r,t,e)),r=h,this.dispatchEvent(new et(r,t,e))},e.prototype.set=function(t,e,r){var n=this.values_||(this.values_={});if(r)n[t]=e;else{var i=n[t];n[t]=e,i!==e&&this.notify(t,i)}},e.prototype.setProperties=function(t,e){for(var r in t)this.set(r,t[r],e)},e.prototype.applyProperties=function(t){t.values_&&O(this.values_||(this.values_={}),t.values_)},e.prototype.unset=function(t,e){if(this.values_&&t in this.values_){var r=this.values_[t];delete this.values_[t],I(this.values_)&&(this.values_=null),e||this.notify(t,r)}},e}(Q),nt={};function it(t){return nt.hasOwnProperty(t)?nt[t]:nt[t]="change:"+t}var ot=rt,at="add",st="remove",lt=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ut="length",ct=function(t){function e(e,r,n){var i=t.call(this,e)||this;return i.element=r,i.index=n,i}return lt(e,t),e}(c),ht=function(t){function e(e,r){var n=t.call(this)||this,i=r||{};if(n.unique_=!!i.unique,n.array_=e||[],n.unique_)for(var o=0,a=n.array_.length;o<a;++o)n.assertUnique_(n.array_[o],o);return n.updateLength_(),n}return lt(e,t),e.prototype.clear=function(){for(;this.getLength()>0;)this.pop()},e.prototype.extend=function(t){for(var e=0,r=t.length;e<r;++e)this.push(t[e]);return this},e.prototype.forEach=function(t){for(var e=this.array_,r=0,n=e.length;r<n;++r)t(e[r],r,e)},e.prototype.getArray=function(){return this.array_},e.prototype.item=function(t){return this.array_[t]},e.prototype.getLength=function(){return this.get(ut)},e.prototype.insertAt=function(t,e){this.unique_&&this.assertUnique_(e),this.array_.splice(t,0,e),this.updateLength_(),this.dispatchEvent(new ct(at,e,t))},e.prototype.pop=function(){return this.removeAt(this.getLength()-1)},e.prototype.push=function(t){this.unique_&&this.assertUnique_(t);var e=this.getLength();return this.insertAt(e,t),this.getLength()},e.prototype.remove=function(t){for(var e=this.array_,r=0,n=e.length;r<n;++r)if(e[r]===t)return this.removeAt(r)},e.prototype.removeAt=function(t){var e=this.array_[t];return this.array_.splice(t,1),this.updateLength_(),this.dispatchEvent(new ct(st,e,t)),e},e.prototype.setAt=function(t,e){var r=this.getLength();if(t<r){this.unique_&&this.assertUnique_(e,t);var n=this.array_[t];this.array_[t]=e,this.dispatchEvent(new ct(st,n,t)),this.dispatchEvent(new ct(at,e,t))}else{for(var i=r;i<t;++i)this.insertAt(i,void 0);this.insertAt(t,e)}},e.prototype.updateLength_=function(){this.set(ut,this.array_.length)},e.prototype.assertUnique_=function(t,e){for(var r=0,n=this.array_.length;r<n;++r)if(this.array_[r]===t&&r!==e)throw new l(58)},e}(ot);function pt(t,e){if(!t)throw new l(e)}var ft=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function dt(t){return"function"==typeof t?t:(Array.isArray(t)?e=t:(pt("function"==typeof t.getZIndex,41),e=[t]),function(){return e});var e}var gt=function(t){function e(e){var r=t.call(this)||this;if(r.id_=void 0,r.geometryName_="geometry",r.style_=null,r.styleFunction_=void 0,r.geometryChangeKey_=null,r.addEventListener(it(r.geometryName_),r.handleGeometryChanged_),e)if("function"==typeof e.getSimplifiedGeometry){var n=e;r.setGeometry(n)}else{var i=e;r.setProperties(i)}return r}return ft(e,t),e.prototype.clone=function(){var t=new e(this.hasProperties()?this.getProperties():null);t.setGeometryName(this.getGeometryName());var r=this.getGeometry();r&&t.setGeometry(r.clone());var n=this.getStyle();return n&&t.setStyle(n),t},e.prototype.getGeometry=function(){return this.get(this.geometryName_)},e.prototype.getId=function(){return this.id_},e.prototype.getGeometryName=function(){return this.geometryName_},e.prototype.getStyle=function(){return this.style_},e.prototype.getStyleFunction=function(){return this.styleFunction_},e.prototype.handleGeometryChange_=function(){this.changed()},e.prototype.handleGeometryChanged_=function(){this.geometryChangeKey_&&(H(this.geometryChangeKey_),this.geometryChangeKey_=null);var t=this.getGeometry();t&&(this.geometryChangeKey_=Z(t,F,this.handleGeometryChange_,this)),this.changed()},e.prototype.setGeometry=function(t){this.set(this.geometryName_,t)},e.prototype.setStyle=function(t){this.style_=t,this.styleFunction_=t?dt(t):void 0,this.changed()},e.prototype.setId=function(t){this.id_=t,this.changed()},e.prototype.setGeometryName=function(t){this.removeEventListener(it(this.geometryName_),this.handleGeometryChanged_),this.geometryName_=t,this.addEventListener(it(this.geometryName_),this.handleGeometryChanged_),this.handleGeometryChanged_()},e}(ot),yt="XY",mt="XYZ",vt="XYM",_t="XYZM",bt={POINT:"Point",LINE_STRING:"LineString",LINEAR_RING:"LinearRing",POLYGON:"Polygon",MULTI_POINT:"MultiPoint",MULTI_LINE_STRING:"MultiLineString",MULTI_POLYGON:"MultiPolygon",GEOMETRY_COLLECTION:"GeometryCollection",CIRCLE:"Circle"},xt={DEGREES:"degrees",FEET:"ft",METERS:"m",PIXELS:"pixels",TILE_PIXELS:"tile-pixels",USFEET:"us-ft"},wt={};wt[xt.DEGREES]=2*Math.PI*6370997/360,wt[xt.FEET]=.3048,wt[xt.METERS]=1,wt[xt.USFEET]=1200/3937;var St=xt,Et=new Array(6);function Tt(){return[1,0,0,1,0,0]}function Ct(t){return Pt(t,1,0,0,1,0,0)}function Ot(t,e){var r=t[0],n=t[1],i=t[2],o=t[3],a=t[4],s=t[5],l=e[0],u=e[1],c=e[2],h=e[3],p=e[4],f=e[5];return t[0]=r*l+i*u,t[1]=n*l+o*u,t[2]=r*c+i*h,t[3]=n*c+o*h,t[4]=r*p+i*f+a,t[5]=n*p+o*f+s,t}function Pt(t,e,r,n,i,o,a){return t[0]=e,t[1]=r,t[2]=n,t[3]=i,t[4]=o,t[5]=a,t}function Rt(t,e){return t[0]=e[0],t[1]=e[1],t[2]=e[2],t[3]=e[3],t[4]=e[4],t[5]=e[5],t}function It(t,e){var r=e[0],n=e[1];return e[0]=t[0]*r+t[2]*n+t[4],e[1]=t[1]*r+t[3]*n+t[5],e}function Lt(t,e){var r=Math.cos(e),n=Math.sin(e);return Ot(t,Pt(Et,r,n,-n,r,0,0))}function Mt(t,e,r){return Ot(t,Pt(Et,e,0,0,r,0,0))}function Ft(t,e,r){return Pt(t,e,0,0,r,0,0)}function At(t,e,r){return Ot(t,Pt(Et,1,0,0,1,e,r))}function kt(t,e,r,n,i,o,a,s){var l=Math.sin(o),u=Math.cos(o);return t[0]=n*u,t[1]=i*l,t[2]=-n*l,t[3]=i*u,t[4]=a*n*u-s*n*l+e,t[5]=a*i*l+s*i*u+r,t}function jt(t,e){var r=Nt(e);pt(0!==r,32);var n=e[0],i=e[1],o=e[2],a=e[3],s=e[4],l=e[5];return t[0]=a/r,t[1]=-i/r,t[2]=-o/r,t[3]=n/r,t[4]=(o*l-a*s)/r,t[5]=-(n*l-i*s)/r,t}function Nt(t){return t[0]*t[3]-t[1]*t[2]}function Dt(t){return"matrix("+t.join(", ")+")"}var Gt="bottom-left",zt="bottom-right",Ut="top-left",Bt="top-right",Vt=0,Yt=1,Wt=2,qt=4,Xt=8,Zt=16;function Kt(t){for(var e=ne(),r=0,n=t.length;r<n;++r)pe(e,t[r]);return e}function Ht(t,e,r){return r?(r[0]=t[0]-e,r[1]=t[1]-e,r[2]=t[2]+e,r[3]=t[3]+e,r):[t[0]-e,t[1]-e,t[2]+e,t[3]+e]}function $t(t,e){return e?(e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e):t.slice()}function Jt(t,e,r){var n,i;return(n=e<t[0]?t[0]-e:t[2]<e?e-t[2]:0)*n+(i=r<t[1]?t[1]-r:t[3]<r?r-t[3]:0)*i}function Qt(t,e){return ee(t,e[0],e[1])}function te(t,e){return t[0]<=e[0]&&e[2]<=t[2]&&t[1]<=e[1]&&e[3]<=t[3]}function ee(t,e,r){return t[0]<=e&&e<=t[2]&&t[1]<=r&&r<=t[3]}function re(t,e){var r=t[0],n=t[1],i=t[2],o=t[3],a=e[0],s=e[1],l=Vt;return a<r?l|=Zt:a>i&&(l|=qt),s<n?l|=Xt:s>o&&(l|=Wt),l===Vt&&(l=Yt),l}function ne(){return[1/0,1/0,-1/0,-1/0]}function ie(t,e,r,n,i){return i?(i[0]=t,i[1]=e,i[2]=r,i[3]=n,i):[t,e,r,n]}function oe(t){return ie(1/0,1/0,-1/0,-1/0,t)}function ae(t,e){var r=t[0],n=t[1];return ie(r,n,r,n,e)}function se(t,e){return fe(oe(e),t)}function le(t,e,r,n,i){return de(oe(i),t,e,r,n)}function ue(t,e){return t[0]==e[0]&&t[2]==e[2]&&t[1]==e[1]&&t[3]==e[3]}function ce(t,e,r){return Math.abs(t[0]-e[0])<r&&Math.abs(t[2]-e[2])<r&&Math.abs(t[1]-e[1])<r&&Math.abs(t[3]-e[3])<r}function he(t,e){return e[0]<t[0]&&(t[0]=e[0]),e[2]>t[2]&&(t[2]=e[2]),e[1]<t[1]&&(t[1]=e[1]),e[3]>t[3]&&(t[3]=e[3]),t}function pe(t,e){e[0]<t[0]&&(t[0]=e[0]),e[0]>t[2]&&(t[2]=e[0]),e[1]<t[1]&&(t[1]=e[1]),e[1]>t[3]&&(t[3]=e[1])}function fe(t,e){for(var r=0,n=e.length;r<n;++r)pe(t,e[r]);return t}function de(t,e,r,n,i){for(;r<n;r+=i)ye(t,e[r],e[r+1]);return t}function ge(t,e){for(var r=0,n=e.length;r<n;++r)fe(t,e[r]);return t}function ye(t,e,r){t[0]=Math.min(t[0],e),t[1]=Math.min(t[1],r),t[2]=Math.max(t[2],e),t[3]=Math.max(t[3],r)}function me(t,e){var r;return(r=e(_e(t)))||(r=e(be(t)))||(r=e(Oe(t)))?r:(r=e(Ce(t)))||!1}function ve(t){var e=0;return Ie(t)||(e=Pe(t)*Ee(t)),e}function _e(t){return[t[0],t[1]]}function be(t){return[t[2],t[1]]}function xe(t){return[(t[0]+t[2])/2,(t[1]+t[3])/2]}function we(t,e){var r;return e===Gt?r=_e(t):e===zt?r=be(t):e===Ut?r=Ce(t):e===Bt?r=Oe(t):pt(!1,13),r}function Se(t,e,r,n,i){var o=e*n[0]/2,a=e*n[1]/2,s=Math.cos(r),l=Math.sin(r),u=o*s,c=o*l,h=a*s,p=a*l,f=t[0],d=t[1],g=f-u+p,y=f-u-p,m=f+u-p,v=f+u+p,_=d-c-h,b=d-c+h,x=d+c+h,w=d+c-h;return ie(Math.min(g,y,m,v),Math.min(_,b,x,w),Math.max(g,y,m,v),Math.max(_,b,x,w),i)}function Ee(t){return t[3]-t[1]}function Te(t,e,r){var n=r||[1/0,1/0,-1/0,-1/0];return Re(t,e)?(t[0]>e[0]?n[0]=t[0]:n[0]=e[0],t[1]>e[1]?n[1]=t[1]:n[1]=e[1],t[2]<e[2]?n[2]=t[2]:n[2]=e[2],t[3]<e[3]?n[3]=t[3]:n[3]=e[3]):oe(n),n}function Ce(t){return[t[0],t[3]]}function Oe(t){return[t[2],t[3]]}function Pe(t){return t[2]-t[0]}function Re(t,e){return t[0]<=e[2]&&t[2]>=e[0]&&t[1]<=e[3]&&t[3]>=e[1]}function Ie(t){return t[2]<t[0]||t[3]<t[1]}function Le(t,e){return e?(e[0]=t[0],e[1]=t[1],e[2]=t[2],e[3]=t[3],e):t}function Me(t,e){var r=(t[2]-t[0])/2*(e-1),n=(t[3]-t[1])/2*(e-1);t[0]-=r,t[2]+=r,t[1]-=n,t[3]+=n}function Fe(t,e,r){var n=!1,i=re(t,e),o=re(t,r);if(i===Yt||o===Yt)n=!0;else{var a=t[0],s=t[1],l=t[2],u=t[3],c=e[0],h=e[1],p=r[0],f=r[1],d=(f-h)/(p-c),g=void 0,y=void 0;o&Wt&&!(i&Wt)&&(n=(g=p-(f-u)/d)>=a&&g<=l),n||!(o&qt)||i&qt||(n=(y=f-(p-l)*d)>=s&&y<=u),n||!(o&Xt)||i&Xt||(n=(g=p-(f-s)/d)>=a&&g<=l),n||!(o&Zt)||i&Zt||(n=(y=f-(p-a)*d)>=s&&y<=u)}return n}function Ae(t,e,r,n){var i=[];if(n>1)for(var o=t[2]-t[0],a=t[3]-t[1],s=0;s<n;++s)i.push(t[0]+o*s/n,t[1],t[2],t[1]+a*s/n,t[2]-o*s/n,t[3],t[0],t[3]-a*s/n);else i=[t[0],t[1],t[2],t[1],t[2],t[3],t[0],t[3]];e(i,i,2);for(var l=[],u=[],c=(s=0,i.length);s<c;s+=2)l.push(i[s]),u.push(i[s+1]);return function(t,e,r){return ie(Math.min.apply(null,t),Math.min.apply(null,e),Math.max.apply(null,t),Math.max.apply(null,e),r)}(l,u,r)}function ke(t,e){var r=e.getExtent(),n=xe(t);if(e.canWrapX()&&(n[0]<r[0]||n[0]>=r[2])){var i=Pe(r),o=Math.floor((n[0]-r[0])/i)*i;t[0]-=o,t[2]-=o}return t}var je=function(){function t(t){this.code_=t.code,this.units_=t.units,this.extent_=void 0!==t.extent?t.extent:null,this.worldExtent_=void 0!==t.worldExtent?t.worldExtent:null,this.axisOrientation_=void 0!==t.axisOrientation?t.axisOrientation:"enu",this.global_=void 0!==t.global&&t.global,this.canWrapX_=!(!this.global_||!this.extent_),this.getPointResolutionFunc_=t.getPointResolution,this.defaultTileGrid_=null,this.metersPerUnit_=t.metersPerUnit}return t.prototype.canWrapX=function(){return this.canWrapX_},t.prototype.getCode=function(){return this.code_},t.prototype.getExtent=function(){return this.extent_},t.prototype.getUnits=function(){return this.units_},t.prototype.getMetersPerUnit=function(){return this.metersPerUnit_||wt[this.units_]},t.prototype.getWorldExtent=function(){return this.worldExtent_},t.prototype.getAxisOrientation=function(){return this.axisOrientation_},t.prototype.isGlobal=function(){return this.global_},t.prototype.setGlobal=function(t){this.global_=t,this.canWrapX_=!(!t||!this.extent_)},t.prototype.getDefaultTileGrid=function(){return this.defaultTileGrid_},t.prototype.setDefaultTileGrid=function(t){this.defaultTileGrid_=t},t.prototype.setExtent=function(t){this.extent_=t,this.canWrapX_=!(!this.global_||!t)},t.prototype.setWorldExtent=function(t){this.worldExtent_=t},t.prototype.setGetPointResolution=function(t){this.getPointResolutionFunc_=t},t.prototype.getPointResolutionFunc=function(){return this.getPointResolutionFunc_},t}();function Ne(t,e,r){return Math.min(Math.max(t,e),r)}var De="cosh"in Math?Math.cosh:function(t){var e=Math.exp(t);return(e+1/e)/2},Ge="log2"in Math?Math.log2:function(t){return Math.log(t)*Math.LOG2E};function ze(t,e,r,n,i,o){var a=i-r,s=o-n;if(0!==a||0!==s){var l=((t-r)*a+(e-n)*s)/(a*a+s*s);l>1?(r=i,n=o):l>0&&(r+=a*l,n+=s*l)}return Ue(t,e,r,n)}function Ue(t,e,r,n){var i=r-t,o=n-e;return i*i+o*o}function Be(t){for(var e=t.length,r=0;r<e;r++){for(var n=r,i=Math.abs(t[r][r]),o=r+1;o<e;o++){var a=Math.abs(t[o][r]);a>i&&(i=a,n=o)}if(0===i)return null;var s=t[n];t[n]=t[r],t[r]=s;for(var l=r+1;l<e;l++)for(var u=-t[l][r]/t[r][r],c=r;c<e+1;c++)r==c?t[l][c]=0:t[l][c]+=u*t[r][c]}for(var h=new Array(e),p=e-1;p>=0;p--){h[p]=t[p][e]/t[p][p];for(var f=p-1;f>=0;f--)t[f][e]-=t[f][p]*h[p]}return h}function Ve(t){return 180*t/Math.PI}function Ye(t){return t*Math.PI/180}function We(t,e){var r=t%e;return r*e<0?r+e:r}function qe(t,e,r){return t+r*(e-t)}var Xe=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Ze=6378137*Math.PI,Ke=[-Ze,-Ze,Ze,Ze],He=[-180,-85,180,85],$e=6378137*Math.log(Math.tan(Math.PI/2)),Je=function(t){function e(e){return t.call(this,{code:e,units:St.METERS,extent:Ke,global:!0,worldExtent:He,getPointResolution:function(t,e){return t/De(e[1]/6378137)}})||this}return Xe(e,t),e}(je),Qe=[new Je("EPSG:3857"),new Je("EPSG:102100"),new Je("EPSG:102113"),new Je("EPSG:900913"),new Je("http://www.opengis.net/gml/srs/epsg.xml#3857")];function tr(t,e,r){var n=t.length,i=r>1?r:2,o=e;void 0===o&&(o=i>2?t.slice():new Array(n));for(var a=0;a<n;a+=i){o[a]=Ze*t[a]/180;var s=6378137*Math.log(Math.tan(Math.PI*(+t[a+1]+90)/360));s>$e?s=$e:s<-$e&&(s=-$e),o[a+1]=s}return o}function er(t,e,r){var n=t.length,i=r>1?r:2,o=e;void 0===o&&(o=i>2?t.slice():new Array(n));for(var a=0;a<n;a+=i)o[a]=180*t[a]/Ze,o[a+1]=360*Math.atan(Math.exp(t[a+1]/6378137))/Math.PI-90;return o}var rr=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),nr=[-180,-90,180,90],ir=6378137*Math.PI/180,or=function(t){function e(e,r){return t.call(this,{code:e,units:St.DEGREES,extent:nr,axisOrientation:r,global:!0,metersPerUnit:ir,worldExtent:nr})||this}return rr(e,t),e}(je),ar=[new or("CRS:84"),new or("EPSG:4326","neu"),new or("urn:ogc:def:crs:OGC:1.3:CRS84"),new or("urn:ogc:def:crs:OGC:2:84"),new or("http://www.opengis.net/gml/srs/epsg.xml#4326","neu")],sr={};function lr(){sr={}}function ur(t){return sr[t]||sr[t.replace(/urn:(x-)?ogc:def:crs:EPSG:(.*:)?(\w+)$/,"EPSG:$3")]||null}function cr(t,e){sr[t]=e}var hr={};function pr(){hr={}}function fr(t,e,r){var n=t.getCode(),i=e.getCode();n in hr||(hr[n]={}),hr[n][i]=r}function dr(t,e){var r;return t in hr&&e in hr[t]&&(r=hr[t][e]),r}function gr(t,e,r){var n=r||6371008.8,i=Ye(t[1]),o=Ye(e[1]),a=(o-i)/2,s=Ye(e[0]-t[0])/2,l=Math.sin(a)*Math.sin(a)+Math.sin(s)*Math.sin(s)*Math.cos(i)*Math.cos(o);return 2*n*Math.atan2(Math.sqrt(l),Math.sqrt(1-l))}function yr(t,e){for(var r=0,n=0,i=t.length;n<i-1;++n)r+=gr(t[n],t[n+1],e);return r}function mr(t,e){for(var r=0,n=t.length,i=t[n-1][0],o=t[n-1][1],a=0;a<n;a++){var s=t[a][0],l=t[a][1];r+=Ye(s-i)*(2+Math.sin(Ye(o))+Math.sin(Ye(l))),i=s,o=l}return r*e*e/2}function vr(t,e,r,n){var i=n||6371008.8,o=Ye(t[1]),a=Ye(t[0]),s=e/i,l=Math.asin(Math.sin(o)*Math.cos(s)+Math.cos(o)*Math.sin(s)*Math.cos(r));return[Ve(a+Math.atan2(Math.sin(r)*Math.sin(s)*Math.cos(o),Math.cos(s)-Math.sin(o)*Math.sin(l))),Ve(l)]}function _r(t,e,r){var n=void 0!==r?t.toFixed(r):""+t,i=n.indexOf(".");return(i=-1===i?n.length:i)>e?n:new Array(1+e-i).join("0")+n}function br(t,e){for(var r=(""+t).split("."),n=(""+e).split("."),i=0;i<Math.max(r.length,n.length);i++){var o=parseInt(r[i]||"0",10),a=parseInt(n[i]||"0",10);if(o>a)return 1;if(a>o)return-1}return 0}function xr(t,e){return t[0]+=+e[0],t[1]+=+e[1],t}function wr(t,e){var r=e.getRadius(),n=e.getCenter(),i=n[0],o=n[1],a=t[0]-i,s=t[1]-o;0===a&&0===s&&(a=1);var l=Math.sqrt(a*a+s*s);return[i+r*a/l,o+r*s/l]}function Sr(t,e){var r,n,i=t[0],o=t[1],a=e[0],s=e[1],l=a[0],u=a[1],c=s[0],h=s[1],p=c-l,f=h-u,d=0===p&&0===f?0:(p*(i-l)+f*(o-u))/(p*p+f*f||0);return d<=0?(r=l,n=u):d>=1?(r=c,n=h):(r=l+d*p,n=u+d*f),[r,n]}function Er(t,e,r){var n=We(e+180,360)-180,i=Math.abs(3600*n),o=r||0,a=Math.pow(10,o),s=Math.floor(i/3600),l=Math.floor((i-3600*s)/60),u=i-3600*s-60*l;return(u=Math.ceil(u*a)/a)>=60&&(u=0,l+=1),l>=60&&(l=0,s+=1),s+"° "+_r(l,2)+"′ "+_r(u,2,o)+"″"+(0==n?"":" "+t.charAt(n<0?1:0))}function Tr(t,e,r){return t?e.replace("{x}",t[0].toFixed(r)).replace("{y}",t[1].toFixed(r)):""}function Cr(t,e){for(var r=!0,n=t.length-1;n>=0;--n)if(t[n]!=e[n]){r=!1;break}return r}function Or(t,e){var r=Math.cos(e),n=Math.sin(e),i=t[0]*r-t[1]*n,o=t[1]*r+t[0]*n;return t[0]=i,t[1]=o,t}function Pr(t,e){return t[0]*=e,t[1]*=e,t}function Rr(t,e){var r=t[0]-e[0],n=t[1]-e[1];return r*r+n*n}function Ir(t,e){return Math.sqrt(Rr(t,e))}function Lr(t,e){return Rr(t,Sr(t,e))}function Mr(t,e){return Tr(t,"{x}, {y}",e)}function Fr(t,e){if(e.canWrapX()){var r=Pe(e.getExtent()),n=Ar(t,e,r);n&&(t[0]-=n*r)}return t}function Ar(t,e,r){var n=e.getExtent(),i=0;if(e.canWrapX()&&(t[0]<n[0]||t[0]>n[2])){var o=r||Pe(n);i=Math.floor((t[0]-n[0])/o)}return i}function kr(t,e,r){var n;if(void 0!==e){for(var i=0,o=t.length;i<o;++i)e[i]=t[i];n=e}else n=t.slice();return n}function jr(t,e,r){if(void 0!==e&&t!==e){for(var n=0,i=t.length;n<i;++n)e[n]=t[n];t=e}return t}function Nr(t){cr(t.getCode(),t),fr(t,t,kr)}function Dr(t){t.forEach(Nr)}function Gr(t){return"string"==typeof t?ur(t):t||null}function zr(t,e,r,n){var i,o=(t=Gr(t)).getPointResolutionFunc();if(o){if(i=o(e,r),n&&n!==t.getUnits())(s=t.getMetersPerUnit())&&(i=i*s/wt[n])}else{var a=t.getUnits();if(a==St.DEGREES&&!n||n==St.DEGREES)i=e;else{var s,l=Zr(t,Gr("EPSG:4326"));if(l===jr&&a!==St.DEGREES)i=e*t.getMetersPerUnit();else{var u=[r[0]-e/2,r[1],r[0]+e/2,r[1],r[0],r[1]-e/2,r[0],r[1]+e/2];i=(gr((u=l(u,u,2)).slice(0,2),u.slice(2,4))+gr(u.slice(4,6),u.slice(6,8)))/2}void 0!==(s=n?wt[n]:t.getMetersPerUnit())&&(i/=s)}}return i}function Ur(t){Dr(t),t.forEach((function(e){t.forEach((function(t){e!==t&&fr(e,t,kr)}))}))}function Br(t,e,r,n){t.forEach((function(t){e.forEach((function(e){fr(t,e,r),fr(e,t,n)}))}))}function Vr(t,e){return t?"string"==typeof t?Gr(t):t:Gr(e)}function Yr(t){return function(e,r,n){for(var i=e.length,o=void 0!==n?n:2,a=void 0!==r?r:new Array(i),s=0;s<i;s+=o){var l=t([e[s],e[s+1]]);a[s]=l[0],a[s+1]=l[1];for(var u=o-1;u>=2;--u)a[s+u]=e[s+u]}return a}}function Wr(t,e,r,n){var i=Gr(t),o=Gr(e);fr(i,o,Yr(r)),fr(o,i,Yr(n))}function qr(t,e){return Hr(t,"EPSG:4326",void 0!==e?e:"EPSG:3857")}function Xr(t,e){if(t===e)return!0;var r=t.getUnits()===e.getUnits();return(t.getCode()===e.getCode()||Zr(t,e)===kr)&&r}function Zr(t,e){var r=dr(t.getCode(),e.getCode());return r||(r=jr),r}function Kr(t,e){return Zr(Gr(t),Gr(e))}function Hr(t,e,r){return Kr(e,r)(t,void 0,t.length)}function $r(t,e,r,n){return Ae(t,Kr(e,r),void 0,n)}var Jr=null;function Qr(t){Jr=Gr(t)}function tn(){return Jr}function en(t,e){return Jr?Hr(t,e,Jr):t}function rn(t,e){return Jr?Hr(t,Jr,e):t}function nn(t,e){return Jr?$r(t,e,Jr):t}function on(t,e){return Jr?$r(t,Jr,e):t}function an(t,e,r){return function(n){var i,o,a=n[0],s=n[1];if(t.canWrapX()){var l=t.getExtent(),u=Pe(l);(o=Ar(n,t,u))&&(a-=o*u),a=Ne(a,l[0],l[2]),s=Ne(s,l[1],l[3]),i=r([a,s])}else i=r(n);return o&&e.canWrapX()&&(i[0]+=o*Pe(e.getExtent())),i}}function sn(){Ur(Qe),Ur(ar),Br(ar,Qe,tr,er)}function ln(t,e,r,n,i,o){for(var a=o||[],s=0,l=e;l<r;l+=n){var u=t[l],c=t[l+1];a[s++]=i[0]*u+i[2]*c+i[4],a[s++]=i[1]*u+i[3]*c+i[5]}return o&&a.length!=s&&(a.length=s),a}function un(t,e,r,n,i,o,a){for(var s=a||[],l=Math.cos(i),u=Math.sin(i),c=o[0],h=o[1],p=0,f=e;f<r;f+=n){var d=t[f]-c,g=t[f+1]-h;s[p++]=c+d*l-g*u,s[p++]=h+d*u+g*l;for(var y=f+2;y<f+n;++y)s[p++]=t[y]}return a&&s.length!=p&&(s.length=p),s}function cn(t,e,r,n,i,o,a,s){for(var l=s||[],u=a[0],c=a[1],h=0,p=e;p<r;p+=n){var f=t[p]-u,d=t[p+1]-c;l[h++]=u+i*f,l[h++]=c+o*d;for(var g=p+2;g<p+n;++g)l[h++]=t[g]}return s&&l.length!=h&&(l.length=h),l}function hn(t,e,r,n,i,o,a){for(var s=a||[],l=0,u=e;u<r;u+=n){s[l++]=t[u]+i,s[l++]=t[u+1]+o;for(var c=u+2;c<u+n;++c)s[l++]=t[c]}return a&&s.length!=l&&(s.length=l),s}sn();var pn=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),fn=[1,0,0,1,0,0],dn=function(t){function e(){var e=t.call(this)||this;return e.extent_=[1/0,1/0,-1/0,-1/0],e.extentRevision_=-1,e.simplifiedGeometryMaxMinSquaredTolerance=0,e.simplifiedGeometryRevision=0,e.simplifyTransformedInternal=C((function(t,e,r){if(!r)return this.getSimplifiedGeometry(e);var n=this.clone();return n.applyTransform(r),n.getSimplifiedGeometry(e)})),e}return pn(e,t),e.prototype.simplifyTransformed=function(t,e){return this.simplifyTransformedInternal(this.getRevision(),t,e)},e.prototype.clone=function(){return n()},e.prototype.closestPointXY=function(t,e,r,i){return n()},e.prototype.containsXY=function(t,e){var r=this.getClosestPoint([t,e]);return r[0]===t&&r[1]===e},e.prototype.getClosestPoint=function(t,e){var r=e||[NaN,NaN];return this.closestPointXY(t[0],t[1],r,1/0),r},e.prototype.intersectsCoordinate=function(t){return this.containsXY(t[0],t[1])},e.prototype.computeExtent=function(t){return n()},e.prototype.getExtent=function(t){if(this.extentRevision_!=this.getRevision()){var e=this.computeExtent(this.extent_);(isNaN(e[0])||isNaN(e[1]))&&oe(e),this.extentRevision_=this.getRevision()}return Le(this.extent_,t)},e.prototype.rotate=function(t,e){n()},e.prototype.scale=function(t,e,r){n()},e.prototype.simplify=function(t){return this.getSimplifiedGeometry(t*t)},e.prototype.getSimplifiedGeometry=function(t){return n()},e.prototype.getType=function(){return n()},e.prototype.applyTransform=function(t){n()},e.prototype.intersectsExtent=function(t){return n()},e.prototype.translate=function(t,e){n()},e.prototype.transform=function(t,e){var r=Gr(t),n=r.getUnits()==St.TILE_PIXELS?function(t,n,i){var o=r.getExtent(),a=r.getWorldExtent(),s=Ee(a)/Ee(o);return kt(fn,a[0],a[3],s,-s,0,0,0),ln(t,0,t.length,i,fn,n),Kr(r,e)(t,n,i)}:Kr(r,e);return this.applyTransform(n),this},e}(ot),gn=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function yn(t){var e;return t==yt?e=2:t==mt||t==vt?e=3:t==_t&&(e=4),e}function mn(t,e,r){var n=t.getFlatCoordinates();if(n){var i=t.getStride();return ln(n,0,n.length,i,e,r)}return null}var vn=function(t){function e(){var e=t.call(this)||this;return e.layout=yt,e.stride=2,e.flatCoordinates=null,e}return gn(e,t),e.prototype.computeExtent=function(t){return le(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t)},e.prototype.getCoordinates=function(){return n()},e.prototype.getFirstCoordinate=function(){return this.flatCoordinates.slice(0,this.stride)},e.prototype.getFlatCoordinates=function(){return this.flatCoordinates},e.prototype.getLastCoordinate=function(){return this.flatCoordinates.slice(this.flatCoordinates.length-this.stride)},e.prototype.getLayout=function(){return this.layout},e.prototype.getSimplifiedGeometry=function(t){if(this.simplifiedGeometryRevision!==this.getRevision()&&(this.simplifiedGeometryMaxMinSquaredTolerance=0,this.simplifiedGeometryRevision=this.getRevision()),t<0||0!==this.simplifiedGeometryMaxMinSquaredTolerance&&t<=this.simplifiedGeometryMaxMinSquaredTolerance)return this;var e=this.getSimplifiedGeometryInternal(t);return e.getFlatCoordinates().length<this.flatCoordinates.length?e:(this.simplifiedGeometryMaxMinSquaredTolerance=t,this)},e.prototype.getSimplifiedGeometryInternal=function(t){return this},e.prototype.getStride=function(){return this.stride},e.prototype.setFlatCoordinates=function(t,e){this.stride=yn(t),this.layout=t,this.flatCoordinates=e},e.prototype.setCoordinates=function(t,e){n()},e.prototype.setLayout=function(t,e,r){var n;if(t)n=yn(t);else{for(var i=0;i<r;++i){if(0===e.length)return this.layout=yt,void(this.stride=2);e=e[0]}t=function(t){var e;2==t?e=yt:3==t?e=mt:4==t&&(e=_t);return e}(n=e.length)}this.layout=t,this.stride=n},e.prototype.applyTransform=function(t){this.flatCoordinates&&(t(this.flatCoordinates,this.flatCoordinates,this.stride),this.changed())},e.prototype.rotate=function(t,e){var r=this.getFlatCoordinates();if(r){var n=this.getStride();un(r,0,r.length,n,t,e,r),this.changed()}},e.prototype.scale=function(t,e,r){var n=e;void 0===n&&(n=t);var i=r;i||(i=xe(this.getExtent()));var o=this.getFlatCoordinates();if(o){var a=this.getStride();cn(o,0,o.length,a,t,n,i,o),this.changed()}},e.prototype.translate=function(t,e){var r=this.getFlatCoordinates();if(r){var n=this.getStride();hn(r,0,r.length,n,t,e,r),this.changed()}},e}(dn);function _n(t,e,r,n,i,o,a){var s,l=t[e],u=t[e+1],c=t[r]-l,h=t[r+1]-u;if(0===c&&0===h)s=e;else{var p=((i-l)*c+(o-u)*h)/(c*c+h*h);if(p>1)s=r;else{if(p>0){for(var f=0;f<n;++f)a[f]=qe(t[e+f],t[r+f],p);return void(a.length=n)}s=e}}for(f=0;f<n;++f)a[f]=t[s+f];a.length=n}function bn(t,e,r,n,i){var o=t[e],a=t[e+1];for(e+=n;e<r;e+=n){var s=t[e],l=t[e+1],u=Ue(o,a,s,l);u>i&&(i=u),o=s,a=l}return i}function xn(t,e,r,n,i){for(var o=0,a=r.length;o<a;++o){var s=r[o];i=bn(t,e,s,n,i),e=s}return i}function wn(t,e,r,n,i){for(var o=0,a=r.length;o<a;++o){var s=r[o];i=xn(t,e,s,n,i),e=s[s.length-1]}return i}function Sn(t,e,r,n,i,o,a,s,l,u,c){if(e==r)return u;var h,p;if(0===i){if((p=Ue(a,s,t[e],t[e+1]))<u){for(h=0;h<n;++h)l[h]=t[e+h];return l.length=n,p}return u}for(var f=c||[NaN,NaN],d=e+n;d<r;)if(_n(t,d-n,d,n,a,s,f),(p=Ue(a,s,f[0],f[1]))<u){for(u=p,h=0;h<n;++h)l[h]=f[h];l.length=n,d+=n}else d+=n*Math.max((Math.sqrt(p)-Math.sqrt(u))/i|0,1);if(o&&(_n(t,r-n,e,n,a,s,f),(p=Ue(a,s,f[0],f[1]))<u)){for(u=p,h=0;h<n;++h)l[h]=f[h];l.length=n}return u}function En(t,e,r,n,i,o,a,s,l,u,c){for(var h=c||[NaN,NaN],p=0,f=r.length;p<f;++p){var d=r[p];u=Sn(t,e,d,n,i,o,a,s,l,u,h),e=d}return u}function Tn(t,e,r,n,i,o,a,s,l,u,c){for(var h=c||[NaN,NaN],p=0,f=r.length;p<f;++p){var d=r[p];u=En(t,e,d,n,i,o,a,s,l,u,h),e=d[d.length-1]}return u}function Cn(t,e,r,n){for(var i=0,o=r.length;i<o;++i)t[e++]=r[i];return e}function On(t,e,r,n){for(var i=0,o=r.length;i<o;++i)for(var a=r[i],s=0;s<n;++s)t[e++]=a[s];return e}function Pn(t,e,r,n,i){for(var o=i||[],a=0,s=0,l=r.length;s<l;++s){var u=On(t,e,r[s],n);o[a++]=u,e=u}return o.length=a,o}function Rn(t,e,r,n,i){for(var o=i||[],a=0,s=0,l=r.length;s<l;++s){var u=Pn(t,e,r[s],n,o[a]);o[a++]=u,e=u[u.length-1]}return o.length=a,o}function In(t,e,r,n,i,o,a){var s=(r-e)/n;if(s<3){for(;e<r;e+=n)o[a++]=t[e],o[a++]=t[e+1];return a}var l=new Array(s);l[0]=1,l[s-1]=1;for(var u=[e,r-n],c=0;u.length>0;){for(var h=u.pop(),p=u.pop(),f=0,d=t[p],g=t[p+1],y=t[h],m=t[h+1],v=p+n;v<h;v+=n){var _=ze(t[v],t[v+1],d,g,y,m);_>f&&(c=v,f=_)}f>i&&(l[(c-e)/n]=1,p+n<c&&u.push(p,c),c+n<h&&u.push(c,h))}for(v=0;v<s;++v)l[v]&&(o[a++]=t[e+v*n],o[a++]=t[e+v*n+1]);return a}function Ln(t,e,r,n,i,o,a,s){for(var l=0,u=r.length;l<u;++l){var c=r[l];a=In(t,e,c,n,i,o,a),s.push(a),e=c}return a}function Mn(t,e,r,n,i,o,a){if(r<=e+n){for(;e<r;e+=n)o[a++]=t[e],o[a++]=t[e+1];return a}var s=t[e],l=t[e+1];o[a++]=s,o[a++]=l;var u=s,c=l;for(e+=n;e<r;e+=n)Ue(s,l,u=t[e],c=t[e+1])>i&&(o[a++]=u,o[a++]=c,s=u,l=c);return u==s&&c==l||(o[a++]=u,o[a++]=c),a}function Fn(t,e){return e*Math.round(t/e)}function An(t,e,r,n,i,o,a){if(e==r)return a;var s,l,u=Fn(t[e],i),c=Fn(t[e+1],i);e+=n,o[a++]=u,o[a++]=c;do{if(s=Fn(t[e],i),l=Fn(t[e+1],i),(e+=n)==r)return o[a++]=s,o[a++]=l,a}while(s==u&&l==c);for(;e<r;){var h=Fn(t[e],i),p=Fn(t[e+1],i);if(e+=n,h!=s||p!=l){var f=s-u,d=l-c,g=h-u,y=p-c;f*y==d*g&&(f<0&&g<f||f==g||f>0&&g>f)&&(d<0&&y<d||d==y||d>0&&y>d)?(s=h,l=p):(o[a++]=s,o[a++]=l,u=s,c=l,s=h,l=p)}}return o[a++]=s,o[a++]=l,a}function kn(t,e,r,n,i,o,a,s){for(var l=0,u=r.length;l<u;++l){var c=r[l];a=An(t,e,c,n,i,o,a),s.push(a),e=c}return a}function jn(t,e,r,n,i,o,a,s){for(var l=0,u=r.length;l<u;++l){var c=r[l],h=[];a=kn(t,e,c,n,i,o,a,h),s.push(h),e=c[c.length-1]}return a}function Nn(t,e,r,n,i){for(var o=void 0!==i?i:[],a=0,s=e;s<r;s+=n)o[a++]=t.slice(s,s+n);return o.length=a,o}function Dn(t,e,r,n,i){for(var o=void 0!==i?i:[],a=0,s=0,l=r.length;s<l;++s){var u=r[s];o[a++]=Nn(t,e,u,n,o[a]),e=u}return o.length=a,o}function Gn(t,e,r,n,i){for(var o=void 0!==i?i:[],a=0,s=0,l=r.length;s<l;++s){var u=r[s];o[a++]=Dn(t,e,u,n,o[a]),e=u[u.length-1]}return o.length=a,o}function zn(t,e,r,n){for(var i=0,o=t[r-n],a=t[r-n+1];e<r;e+=n){var s=t[e],l=t[e+1];i+=a*s-o*l,o=s,a=l}return i/2}function Un(t,e,r,n){for(var i=0,o=0,a=r.length;o<a;++o){var s=r[o];i+=zn(t,e,s,n),e=s}return i}function Bn(t,e,r,n){for(var i=0,o=0,a=r.length;o<a;++o){var s=r[o];i+=Un(t,e,s,n),e=s[s.length-1]}return i}var Vn=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Yn=function(t){function e(e,r){var n=t.call(this)||this;return n.maxDelta_=-1,n.maxDeltaRevision_=-1,void 0===r||Array.isArray(e[0])?n.setCoordinates(e,r):n.setFlatCoordinates(r,e),n}return Vn(e,t),e.prototype.clone=function(){return new e(this.flatCoordinates.slice(),this.layout)},e.prototype.closestPointXY=function(t,e,r,n){return n<Jt(this.getExtent(),t,e)?n:(this.maxDeltaRevision_!=this.getRevision()&&(this.maxDelta_=Math.sqrt(bn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,0)),this.maxDeltaRevision_=this.getRevision()),Sn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,this.maxDelta_,!0,t,e,r,n))},e.prototype.getArea=function(){return zn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)},e.prototype.getCoordinates=function(){return Nn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)},e.prototype.getSimplifiedGeometryInternal=function(t){var r=[];return r.length=In(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,r,0),new e(r,yt)},e.prototype.getType=function(){return bt.LINEAR_RING},e.prototype.intersectsExtent=function(t){return!1},e.prototype.setCoordinates=function(t,e){this.setLayout(e,t,1),this.flatCoordinates||(this.flatCoordinates=[]),this.flatCoordinates.length=On(this.flatCoordinates,0,t,this.stride),this.changed()},e}(vn),Wn=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),qn=function(t){function e(e,r){var n=t.call(this)||this;return n.setCoordinates(e,r),n}return Wn(e,t),e.prototype.clone=function(){var t=new e(this.flatCoordinates.slice(),this.layout);return t.applyProperties(this),t},e.prototype.closestPointXY=function(t,e,r,n){var i=this.flatCoordinates,o=Ue(t,e,i[0],i[1]);if(o<n){for(var a=this.stride,s=0;s<a;++s)r[s]=i[s];return r.length=a,o}return n},e.prototype.getCoordinates=function(){return this.flatCoordinates?this.flatCoordinates.slice():[]},e.prototype.computeExtent=function(t){return ae(this.flatCoordinates,t)},e.prototype.getType=function(){return bt.POINT},e.prototype.intersectsExtent=function(t){return ee(t,this.flatCoordinates[0],this.flatCoordinates[1])},e.prototype.setCoordinates=function(t,e){this.setLayout(e,t,0),this.flatCoordinates||(this.flatCoordinates=[]),this.flatCoordinates.length=Cn(this.flatCoordinates,0,t,this.stride),this.changed()},e}(vn);function Xn(t,e,r,n,i){return!me(i,(function(i){return!Zn(t,e,r,n,i[0],i[1])}))}function Zn(t,e,r,n,i,o){for(var a=0,s=t[r-n],l=t[r-n+1];e<r;e+=n){var u=t[e],c=t[e+1];l<=o?c>o&&(u-s)*(o-l)-(i-s)*(c-l)>0&&a++:c<=o&&(u-s)*(o-l)-(i-s)*(c-l)<0&&a--,s=u,l=c}return 0!==a}function Kn(t,e,r,n,i,o){if(0===r.length)return!1;if(!Zn(t,e,r[0],n,i,o))return!1;for(var a=1,s=r.length;a<s;++a)if(Zn(t,r[a-1],r[a],n,i,o))return!1;return!0}function Hn(t,e,r,n,i,o){if(0===r.length)return!1;for(var a=0,s=r.length;a<s;++a){var l=r[a];if(Kn(t,e,l,n,i,o))return!0;e=l[l.length-1]}return!1}function $n(t,e,r,n,i,o,a){for(var s,l,u,c,h,p,f,g=i[o+1],y=[],m=0,v=r.length;m<v;++m){var _=r[m];for(c=t[_-n],p=t[_-n+1],s=e;s<_;s+=n)h=t[s],f=t[s+1],(g<=p&&f<=g||p<=g&&g<=f)&&(u=(g-p)/(f-p)*(h-c)+c,y.push(u)),c=h,p=f}var b=NaN,x=-1/0;for(y.sort(d),c=y[0],s=1,l=y.length;s<l;++s){h=y[s];var w=Math.abs(h-c);w>x&&Kn(t,e,r,n,u=(c+h)/2,g)&&(b=u,x=w),c=h}return isNaN(b)&&(b=i[o]),a?(a.push(b,g,x),a):[b,g,x]}function Jn(t,e,r,n,i){for(var o=[],a=0,s=r.length;a<s;++a){var l=r[a];o=$n(t,e,l,n,i,2*a,o),e=l[l.length-1]}return o}function Qn(t,e,r,n,i){for(var o,a=[t[e],t[e+1]],s=[];e+n<r;e+=n){if(s[0]=t[e+n],s[1]=t[e+n+1],o=i(a,s))return o;a[0]=s[0],a[1]=s[1]}return!1}function ti(t,e,r,n,i){var o=de([1/0,1/0,-1/0,-1/0],t,e,r,n);return!!Re(i,o)&&(!!te(i,o)||(o[0]>=i[0]&&o[2]<=i[2]||(o[1]>=i[1]&&o[3]<=i[3]||Qn(t,e,r,n,(function(t,e){return Fe(i,t,e)})))))}function ei(t,e,r,n,i){for(var o=0,a=r.length;o<a;++o){if(ti(t,e,r[o],n,i))return!0;e=r[o]}return!1}function ri(t,e,r,n,i){return!!ti(t,e,r,n,i)||(!!Zn(t,e,r,n,i[0],i[1])||(!!Zn(t,e,r,n,i[0],i[3])||(!!Zn(t,e,r,n,i[2],i[1])||!!Zn(t,e,r,n,i[2],i[3]))))}function ni(t,e,r,n,i){if(!ri(t,e,r[0],n,i))return!1;if(1===r.length)return!0;for(var o=1,a=r.length;o<a;++o)if(Xn(t,r[o-1],r[o],n,i)&&!ti(t,r[o-1],r[o],n,i))return!1;return!0}function ii(t,e,r,n,i){for(var o=0,a=r.length;o<a;++o){var s=r[o];if(ni(t,e,s,n,i))return!0;e=s[s.length-1]}return!1}function oi(t,e,r,n){for(;e<r-n;){for(var i=0;i<n;++i){var o=t[e+i];t[e+i]=t[r-n+i],t[r-n+i]=o}e+=n,r-=n}}function ai(t,e,r,n){for(var i=0,o=t[r-n],a=t[r-n+1];e<r;e+=n){var s=t[e],l=t[e+1];i+=(s-o)*(l+a),o=s,a=l}return 0===i?void 0:i>0}function si(t,e,r,n,i){for(var o=void 0!==i&&i,a=0,s=r.length;a<s;++a){var l=r[a],u=ai(t,e,l,n);if(0===a){if(o&&u||!o&&!u)return!1}else if(o&&!u||!o&&u)return!1;e=l}return!0}function li(t,e,r,n,i){for(var o=0,a=r.length;o<a;++o){var s=r[o];if(!si(t,e,s,n,i))return!1;s.length&&(e=s[s.length-1])}return!0}function ui(t,e,r,n,i){for(var o=void 0!==i&&i,a=0,s=r.length;a<s;++a){var l=r[a],u=ai(t,e,l,n);(0===a?o&&u||!o&&!u:o&&!u||!o&&u)&&oi(t,e,l,n),e=l}return e}function ci(t,e,r,n,i){for(var o=0,a=r.length;o<a;++o)e=ui(t,e,r[o],n,i);return e}var hi=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),pi=function(t){function e(e,r,n){var i=t.call(this)||this;return i.ends_=[],i.flatInteriorPointRevision_=-1,i.flatInteriorPoint_=null,i.maxDelta_=-1,i.maxDeltaRevision_=-1,i.orientedRevision_=-1,i.orientedFlatCoordinates_=null,void 0!==r&&n?(i.setFlatCoordinates(r,e),i.ends_=n):i.setCoordinates(e,r),i}return hi(e,t),e.prototype.appendLinearRing=function(t){this.flatCoordinates?v(this.flatCoordinates,t.getFlatCoordinates()):this.flatCoordinates=t.getFlatCoordinates().slice(),this.ends_.push(this.flatCoordinates.length),this.changed()},e.prototype.clone=function(){var t=new e(this.flatCoordinates.slice(),this.layout,this.ends_.slice());return t.applyProperties(this),t},e.prototype.closestPointXY=function(t,e,r,n){return n<Jt(this.getExtent(),t,e)?n:(this.maxDeltaRevision_!=this.getRevision()&&(this.maxDelta_=Math.sqrt(xn(this.flatCoordinates,0,this.ends_,this.stride,0)),this.maxDeltaRevision_=this.getRevision()),En(this.flatCoordinates,0,this.ends_,this.stride,this.maxDelta_,!0,t,e,r,n))},e.prototype.containsXY=function(t,e){return Kn(this.getOrientedFlatCoordinates(),0,this.ends_,this.stride,t,e)},e.prototype.getArea=function(){return Un(this.getOrientedFlatCoordinates(),0,this.ends_,this.stride)},e.prototype.getCoordinates=function(t){var e;return void 0!==t?ui(e=this.getOrientedFlatCoordinates().slice(),0,this.ends_,this.stride,t):e=this.flatCoordinates,Dn(e,0,this.ends_,this.stride)},e.prototype.getEnds=function(){return this.ends_},e.prototype.getFlatInteriorPoint=function(){if(this.flatInteriorPointRevision_!=this.getRevision()){var t=xe(this.getExtent());this.flatInteriorPoint_=$n(this.getOrientedFlatCoordinates(),0,this.ends_,this.stride,t,0),this.flatInteriorPointRevision_=this.getRevision()}return this.flatInteriorPoint_},e.prototype.getInteriorPoint=function(){return new qn(this.getFlatInteriorPoint(),vt)},e.prototype.getLinearRingCount=function(){return this.ends_.length},e.prototype.getLinearRing=function(t){return t<0||this.ends_.length<=t?null:new Yn(this.flatCoordinates.slice(0===t?0:this.ends_[t-1],this.ends_[t]),this.layout)},e.prototype.getLinearRings=function(){for(var t=this.layout,e=this.flatCoordinates,r=this.ends_,n=[],i=0,o=0,a=r.length;o<a;++o){var s=r[o],l=new Yn(e.slice(i,s),t);n.push(l),i=s}return n},e.prototype.getOrientedFlatCoordinates=function(){if(this.orientedRevision_!=this.getRevision()){var t=this.flatCoordinates;si(t,0,this.ends_,this.stride)?this.orientedFlatCoordinates_=t:(this.orientedFlatCoordinates_=t.slice(),this.orientedFlatCoordinates_.length=ui(this.orientedFlatCoordinates_,0,this.ends_,this.stride)),this.orientedRevision_=this.getRevision()}return this.orientedFlatCoordinates_},e.prototype.getSimplifiedGeometryInternal=function(t){var r=[],n=[];return r.length=kn(this.flatCoordinates,0,this.ends_,this.stride,Math.sqrt(t),r,0,n),new e(r,yt,n)},e.prototype.getType=function(){return bt.POLYGON},e.prototype.intersectsExtent=function(t){return ni(this.getOrientedFlatCoordinates(),0,this.ends_,this.stride,t)},e.prototype.setCoordinates=function(t,e){this.setLayout(e,t,2),this.flatCoordinates||(this.flatCoordinates=[]);var r=Pn(this.flatCoordinates,0,t,this.stride,this.ends_);this.flatCoordinates.length=0===r.length?0:r[r.length-1],this.changed()},e}(vn),fi=pi;function di(t,e,r,n){for(var i=r||32,o=[],a=0;a<i;++a)v(o,vr(t,e,2*Math.PI*a/i,n));return o.push(o[0],o[1]),new pi(o,yt,[o.length])}function gi(t){var e=t[0],r=t[1],n=t[2],i=t[3],o=[e,r,e,i,n,i,n,r,e,r];return new pi(o,yt,[o.length])}function yi(t,e,r){for(var n=e||32,i=t.getStride(),o=t.getLayout(),a=t.getCenter(),s=i*(n+1),l=new Array(s),u=0;u<s;u+=i){l[u]=0,l[u+1]=0;for(var c=2;c<i;c++)l[u+c]=a[c]}var h=[l.length],p=new pi(l,o,h);return mi(p,a,t.getRadius(),r),p}function mi(t,e,r,n){for(var i=t.getFlatCoordinates(),o=t.getStride(),a=i.length/o-1,s=n||0,l=0;l<=a;++l){var u=l*o,c=s+2*We(l,a)*Math.PI/a;i[u]=e[0]+r*Math.cos(c),i[u+1]=e[1]+r*Math.sin(c)}t.changed()}var vi=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),_i="accuracy",bi="accuracyGeometry",xi="altitude",wi="altitudeAccuracy",Si="heading",Ei="position",Ti="projection",Ci="speed",Oi="tracking",Pi="trackingOptions",Ri=function(t){function e(e){var r=t.call(this,A)||this;return r.code=e.code,r.message=e.message,r}return vi(e,t),e}(c),Ii=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.position_=null,r.transform_=jr,r.watchId_=void 0,r.addEventListener(it(Ti),r.handleProjectionChanged_),r.addEventListener(it(Oi),r.handleTrackingChanged_),void 0!==n.projection&&r.setProjection(n.projection),void 0!==n.trackingOptions&&r.setTrackingOptions(n.trackingOptions),r.setTracking(void 0!==n.tracking&&n.tracking),r}return vi(e,t),e.prototype.disposeInternal=function(){this.setTracking(!1),t.prototype.disposeInternal.call(this)},e.prototype.handleProjectionChanged_=function(){var t=this.getProjection();t&&(this.transform_=Zr(Gr("EPSG:4326"),t),this.position_&&this.set(Ei,this.transform_(this.position_)))},e.prototype.handleTrackingChanged_=function(){if("geolocation"in navigator){var t=this.getTracking();t&&void 0===this.watchId_?this.watchId_=navigator.geolocation.watchPosition(this.positionChange_.bind(this),this.positionError_.bind(this),this.getTrackingOptions()):t||void 0===this.watchId_||(navigator.geolocation.clearWatch(this.watchId_),this.watchId_=void 0)}},e.prototype.positionChange_=function(t){var e=t.coords;this.set(_i,e.accuracy),this.set(xi,null===e.altitude?void 0:e.altitude),this.set(wi,null===e.altitudeAccuracy?void 0:e.altitudeAccuracy),this.set(Si,null===e.heading?void 0:Ye(e.heading)),this.position_?(this.position_[0]=e.longitude,this.position_[1]=e.latitude):this.position_=[e.longitude,e.latitude];var r=this.transform_(this.position_);this.set(Ei,r),this.set(Ci,null===e.speed?void 0:e.speed);var n=di(this.position_,e.accuracy);n.applyTransform(this.transform_),this.set(bi,n),this.changed()},e.prototype.positionError_=function(t){this.dispatchEvent(new Ri(t))},e.prototype.getAccuracy=function(){return this.get(_i)},e.prototype.getAccuracyGeometry=function(){return this.get(bi)||null},e.prototype.getAltitude=function(){return this.get(xi)},e.prototype.getAltitudeAccuracy=function(){return this.get(wi)},e.prototype.getHeading=function(){return this.get(Si)},e.prototype.getPosition=function(){return this.get(Ei)},e.prototype.getProjection=function(){return this.get(Ti)},e.prototype.getSpeed=function(){return this.get(Ci)},e.prototype.getTracking=function(){return this.get(Oi)},e.prototype.getTrackingOptions=function(){return this.get(Pi)},e.prototype.setProjection=function(t){this.set(Ti,Gr(t))},e.prototype.setTracking=function(t){this.set(Oi,t)},e.prototype.setTrackingOptions=function(t){this.set(Pi,t)},e}(ot),Li=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Mi=function(t){function e(e,r,n,i){var o=t.call(this)||this;return o.extent=e,o.pixelRatio_=n,o.resolution=r,o.state=i,o}return Li(e,t),e.prototype.changed=function(){this.dispatchEvent(F)},e.prototype.getExtent=function(){return this.extent},e.prototype.getImage=function(){return n()},e.prototype.getPixelRatio=function(){return this.pixelRatio_},e.prototype.getResolution=function(){return this.resolution},e.prototype.getState=function(){return this.state},e.prototype.load=function(){n()},e}(M),Fi=0,Ai=1,ki=2,ji=3,Ni=4,Di="undefined"!=typeof navigator&&void 0!==navigator.userAgent?navigator.userAgent.toLowerCase():"",Gi=-1!==Di.indexOf("firefox"),zi=-1!==Di.indexOf("safari")&&-1==Di.indexOf("chrom"),Ui=-1!==Di.indexOf("webkit")&&-1==Di.indexOf("edge"),Bi=-1!==Di.indexOf("macintosh"),Vi="undefined"!=typeof devicePixelRatio?devicePixelRatio:1,Yi="undefined"!=typeof WorkerGlobalScope&&"undefined"!=typeof OffscreenCanvas&&self instanceof WorkerGlobalScope,Wi="undefined"!=typeof Image&&Image.prototype.decode,qi=function(){var t=!1;try{var e=Object.defineProperty({},"passive",{get:function(){t=!0}});window.addEventListener("_",null,e),window.removeEventListener("_",null,e)}catch(t){}return t}(),Xi=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Zi(t,e,r){var n=t;if(n.src&&Wi){var i=n.decode(),o=!0;return i.then((function(){o&&e()})).catch((function(t){o&&("EncodingError"===t.name&&"Invalid image type."===t.message?e():r())})),function(){o=!1}}var a=[K(n,Y,e),K(n,A,r)];return function(){a.forEach(H)}}var Ki=function(t){function e(e,r,n,i,o,a){var s=t.call(this,e,r,n,Fi)||this;return s.src_=i,s.image_=new Image,null!==o&&(s.image_.crossOrigin=o),s.unlisten_=null,s.state=Fi,s.imageLoadFunction_=a,s}return Xi(e,t),e.prototype.getImage=function(){return this.image_},e.prototype.handleImageError_=function(){this.state=ji,this.unlistenImage_(),this.changed()},e.prototype.handleImageLoad_=function(){void 0===this.resolution&&(this.resolution=Ee(this.extent)/this.image_.height),this.state=ki,this.unlistenImage_(),this.changed()},e.prototype.load=function(){this.state!=Fi&&this.state!=ji||(this.state=Ai,this.changed(),this.imageLoadFunction_(this,this.src_),this.unlisten_=Zi(this.image_,this.handleImageLoad_.bind(this),this.handleImageError_.bind(this)))},e.prototype.setImage=function(t){this.image_=t},e.prototype.unlistenImage_=function(){this.unlisten_&&(this.unlisten_(),this.unlisten_=null)},e}(Mi),Hi=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),$i=function(t){function e(e,r,n,i,o){var a=this,s=void 0!==o?Fi:ki;return(a=t.call(this,e,r,n,s)||this).loader_=void 0!==o?o:null,a.canvas_=i,a.error_=null,a}return Hi(e,t),e.prototype.getError=function(){return this.error_},e.prototype.handleLoad_=function(t){t?(this.error_=t,this.state=ji):this.state=ki,this.changed()},e.prototype.load=function(){this.state==Fi&&(this.state=Ai,this.changed(),this.loader_(this.handleLoad_.bind(this)))},e.prototype.getImage=function(){return this.canvas_},e}(Mi),Ji=0,Qi=1,to=2,eo=3,ro=4;function no(t){return Math.pow(t,3)}function io(t){return 1-no(1-t)}function oo(t){return 3*t*t-2*t*t*t}function ao(t){return t}var so=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),lo=function(t){function e(e,r,n){var i=t.call(this)||this,o=n||{};return i.tileCoord=e,i.state=r,i.interimTile=null,i.hifi=!0,i.key="",i.transition_=void 0===o.transition?250:o.transition,i.transitionStarts_={},i}return so(e,t),e.prototype.changed=function(){this.dispatchEvent(F)},e.prototype.release=function(){},e.prototype.getKey=function(){return this.key+"/"+this.tileCoord},e.prototype.getInterimTile=function(){if(!this.interimTile)return this;var t=this.interimTile;do{if(t.getState()==to)return this.transition_=0,t;t=t.interimTile}while(t);return this},e.prototype.refreshInterimChain=function(){if(this.interimTile){var t=this.interimTile,e=this;do{if(t.getState()==to){t.interimTile=null;break}t.getState()==Qi?e=t:t.getState()==Ji?e.interimTile=t.interimTile:e=t,t=e.interimTile}while(t)}},e.prototype.getTileCoord=function(){return this.tileCoord},e.prototype.getState=function(){return this.state},e.prototype.setState=function(t){if(this.state!==eo&&this.state>t)throw new Error("Tile load sequence violation");this.state=t,this.changed()},e.prototype.load=function(){n()},e.prototype.getAlpha=function(t,e){if(!this.transition_)return 1;var r=this.transitionStarts_[t];if(r){if(-1===r)return 1}else r=e,this.transitionStarts_[t]=r;var n=e-r+1e3/60;return n>=this.transition_?1:no(n/this.transition_)},e.prototype.inTransition=function(t){return!!this.transition_&&-1!==this.transitionStarts_[t]},e.prototype.endTransition=function(t){this.transition_&&(this.transitionStarts_[t]=-1)},e}(M);function uo(t,e,r){var n=r&&r.length?r.shift():Yi?new OffscreenCanvas(t||300,e||300):document.createElement("canvas");return t&&(n.width=t),e&&(n.height=e),n.getContext("2d")}function co(t){var e=t.offsetWidth,r=getComputedStyle(t);return e+=parseInt(r.marginLeft,10)+parseInt(r.marginRight,10)}function ho(t){var e=t.offsetHeight,r=getComputedStyle(t);return e+=parseInt(r.marginTop,10)+parseInt(r.marginBottom,10)}function po(t,e){var r=e.parentNode;r&&r.replaceChild(t,e)}function fo(t){return t&&t.parentNode?t.parentNode.removeChild(t):null}function go(t){for(;t.lastChild;)t.removeChild(t.lastChild)}function yo(t,e){for(var r=t.childNodes,n=0;;++n){var i=r[n],o=e[n];if(!i&&!o)break;i!==o&&(i?o?t.insertBefore(o,i):(t.removeChild(i),--n):t.appendChild(o))}}var mo=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();var vo=function(t){function e(e,r,n,i,o,a){var s=t.call(this,e,r,a)||this;return s.crossOrigin_=i,s.src_=n,s.key=n,s.image_=new Image,null!==i&&(s.image_.crossOrigin=i),s.unlisten_=null,s.tileLoadFunction_=o,s}return mo(e,t),e.prototype.getImage=function(){return this.image_},e.prototype.handleImageError_=function(){var t;this.state=eo,this.unlistenImage_(),this.image_=((t=uo(1,1)).fillStyle="rgba(0,0,0,0)",t.fillRect(0,0,1,1),t.canvas),this.changed()},e.prototype.handleImageLoad_=function(){var t=this.image_;t.naturalWidth&&t.naturalHeight?this.state=to:this.state=ro,this.unlistenImage_(),this.changed()},e.prototype.load=function(){this.state==eo&&(this.state=Ji,this.image_=new Image,null!==this.crossOrigin_&&(this.image_.crossOrigin=this.crossOrigin_)),this.state==Ji&&(this.state=Qi,this.changed(),this.tileLoadFunction_(this,this.src_),this.unlisten_=Zi(this.image_,this.handleImageLoad_.bind(this),this.handleImageError_.bind(this)))},e.prototype.unlistenImage_=function(){this.unlisten_&&(this.unlisten_(),this.unlisten_=null)},e}(lo),_o=function(){function t(t,e,r){this.decay_=t,this.minVelocity_=e,this.delay_=r,this.points_=[],this.angle_=0,this.initialVelocity_=0}return t.prototype.begin=function(){this.points_.length=0,this.angle_=0,this.initialVelocity_=0},t.prototype.update=function(t,e){this.points_.push(t,e,Date.now())},t.prototype.end=function(){if(this.points_.length<6)return!1;var t=Date.now()-this.delay_,e=this.points_.length-3;if(this.points_[e+2]<t)return!1;for(var r=e-3;r>0&&this.points_[r+2]>t;)r-=3;var n=this.points_[e+2]-this.points_[r+2];if(n<1e3/60)return!1;var i=this.points_[e]-this.points_[r],o=this.points_[e+1]-this.points_[r+1];return this.angle_=Math.atan2(o,i),this.initialVelocity_=Math.sqrt(i*i+o*o)/n,this.initialVelocity_>this.minVelocity_},t.prototype.getDistance=function(){return(this.minVelocity_-this.initialVelocity_)/this.decay_},t.prototype.getAngle=function(){return this.angle_},t}(),bo=/^#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})$/i,xo=/^([a-z]*)$|^hsla?\(.*\)$/i;function wo(t){return"string"==typeof t?t:Ro(t)}function So(t){var e=document.createElement("div");if(e.style.color=t,""!==e.style.color){document.body.appendChild(e);var r=getComputedStyle(e).color;return document.body.removeChild(e),r}return""}var Eo,To,Co=(Eo={},To=0,function(t){var e;if(Eo.hasOwnProperty(t))e=Eo[t];else{if(To>=1024){var r=0;for(var n in Eo)0==(3&r++)&&(delete Eo[n],--To)}e=function(t){var e,r,n,i,o;if(xo.exec(t)&&(t=So(t)),bo.exec(t)){var a=t.length-1,s=void 0;s=a<=4?1:2;var l=4===a||8===a;e=parseInt(t.substr(1+0*s,s),16),r=parseInt(t.substr(1+1*s,s),16),n=parseInt(t.substr(1+2*s,s),16),i=l?parseInt(t.substr(1+3*s,s),16):255,1==s&&(e=(e<<4)+e,r=(r<<4)+r,n=(n<<4)+n,l&&(i=(i<<4)+i)),o=[e,r,n,i/255]}else 0==t.indexOf("rgba(")?Po(o=t.slice(5,-1).split(",").map(Number)):0==t.indexOf("rgb(")?((o=t.slice(4,-1).split(",").map(Number)).push(1),Po(o)):pt(!1,14);return o}(t),Eo[t]=e,++To}return e});function Oo(t){return Array.isArray(t)?t:Co(t)}function Po(t){return t[0]=Ne(t[0]+.5|0,0,255),t[1]=Ne(t[1]+.5|0,0,255),t[2]=Ne(t[2]+.5|0,0,255),t[3]=Ne(t[3],0,1),t}function Ro(t){var e=t[0];e!=(0|e)&&(e=e+.5|0);var r=t[1];r!=(0|r)&&(r=r+.5|0);var n=t[2];return n!=(0|n)&&(n=n+.5|0),"rgba("+e+","+r+","+n+","+(void 0===t[3]?1:t[3])+")"}function Io(t){return xo.test(t)&&(t=So(t)),bo.test(t)||0===t.indexOf("rgba(")||0===t.indexOf("rgb(")}var Lo=function(){function t(){this.cache_={},this.cacheSize_=0,this.maxCacheSize_=32}return t.prototype.clear=function(){this.cache_={},this.cacheSize_=0},t.prototype.canExpireCache=function(){return this.cacheSize_>this.maxCacheSize_},t.prototype.expire=function(){if(this.canExpireCache()){var t=0;for(var e in this.cache_){var r=this.cache_[e];0!=(3&t++)||r.hasListener()||(delete this.cache_[e],--this.cacheSize_)}}},t.prototype.get=function(t,e,r){var n=Mo(t,e,r);return n in this.cache_?this.cache_[n]:null},t.prototype.set=function(t,e,r,n){var i=Mo(t,e,r);this.cache_[i]=n,++this.cacheSize_},t.prototype.setSize=function(t){this.maxCacheSize_=t,this.expire()},t}();function Mo(t,e,r){return e+":"+t+":"+(r?wo(r):"null")}var Fo=Lo,Ao=new Lo,ko="opacity",jo="visible",No="extent",Do="zIndex",Go="maxResolution",zo="minResolution",Uo="maxZoom",Bo="minZoom",Vo="source",Yo=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Wo=function(t){function e(e){var r=t.call(this)||this,n=O({},e);return n[ko]=void 0!==e.opacity?e.opacity:1,pt("number"==typeof n[ko],64),n[jo]=void 0===e.visible||e.visible,n[Do]=e.zIndex,n[Go]=void 0!==e.maxResolution?e.maxResolution:1/0,n[zo]=void 0!==e.minResolution?e.minResolution:0,n[Bo]=void 0!==e.minZoom?e.minZoom:-1/0,n[Uo]=void 0!==e.maxZoom?e.maxZoom:1/0,r.className_=void 0!==n.className?e.className:"ol-layer",delete n.className,r.setProperties(n),r.state_=null,r}return Yo(e,t),e.prototype.getClassName=function(){return this.className_},e.prototype.getLayerState=function(t){var e=this.state_||{layer:this,managed:void 0===t||t},r=this.getZIndex();return e.opacity=Ne(Math.round(100*this.getOpacity())/100,0,1),e.sourceState=this.getSourceState(),e.visible=this.getVisible(),e.extent=this.getExtent(),e.zIndex=void 0!==r?r:!1===e.managed?1/0:0,e.maxResolution=this.getMaxResolution(),e.minResolution=Math.max(this.getMinResolution(),0),e.minZoom=this.getMinZoom(),e.maxZoom=this.getMaxZoom(),this.state_=e,e},e.prototype.getLayersArray=function(t){return n()},e.prototype.getLayerStatesArray=function(t){return n()},e.prototype.getExtent=function(){return this.get(No)},e.prototype.getMaxResolution=function(){return this.get(Go)},e.prototype.getMinResolution=function(){return this.get(zo)},e.prototype.getMinZoom=function(){return this.get(Bo)},e.prototype.getMaxZoom=function(){return this.get(Uo)},e.prototype.getOpacity=function(){return this.get(ko)},e.prototype.getSourceState=function(){return n()},e.prototype.getVisible=function(){return this.get(jo)},e.prototype.getZIndex=function(){return this.get(Do)},e.prototype.setExtent=function(t){this.set(No,t)},e.prototype.setMaxResolution=function(t){this.set(Go,t)},e.prototype.setMinResolution=function(t){this.set(zo,t)},e.prototype.setMaxZoom=function(t){this.set(Uo,t)},e.prototype.setMinZoom=function(t){this.set(Bo,t)},e.prototype.setOpacity=function(t){pt("number"==typeof t,64),this.set(ko,t)},e.prototype.setVisible=function(t){this.set(jo,t)},e.prototype.setZIndex=function(t){this.set(Do,t)},e.prototype.disposeInternal=function(){this.state_&&(this.state_.layer=null,this.state_=null),t.prototype.disposeInternal.call(this)},e}(ot),qo="prerender",Xo="postrender",Zo="precompose",Ko="postcompose",Ho="rendercomplete",$o="undefined",Jo="loading",Qo="ready",ta="error",ea=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function ra(t,e){if(!t.visible)return!1;var r=e.resolution;if(r<t.minResolution||r>=t.maxResolution)return!1;var n=e.zoom;return n>t.minZoom&&n<=t.maxZoom}var na=function(t){function e(e){var r=this,n=O({},e);delete n.source,(r=t.call(this,n)||this).mapPrecomposeKey_=null,r.mapRenderKey_=null,r.sourceChangeKey_=null,r.renderer_=null,e.render&&(r.render=e.render),e.map&&r.setMap(e.map),r.addEventListener(it(Vo),r.handleSourcePropertyChange_);var i=e.source?e.source:null;return r.setSource(i),r}return ea(e,t),e.prototype.getLayersArray=function(t){var e=t||[];return e.push(this),e},e.prototype.getLayerStatesArray=function(t){var e=t||[];return e.push(this.getLayerState()),e},e.prototype.getSource=function(){return this.get(Vo)||null},e.prototype.getSourceState=function(){var t=this.getSource();return t?t.getState():$o},e.prototype.handleSourceChange_=function(){this.changed()},e.prototype.handleSourcePropertyChange_=function(){this.sourceChangeKey_&&(H(this.sourceChangeKey_),this.sourceChangeKey_=null);var t=this.getSource();t&&(this.sourceChangeKey_=Z(t,F,this.handleSourceChange_,this)),this.changed()},e.prototype.getFeatures=function(t){return this.renderer_.getFeatures(t)},e.prototype.render=function(t,e){var r=this.getRenderer();if(r.prepareFrame(t))return r.renderFrame(t,e)},e.prototype.setMap=function(t){this.mapPrecomposeKey_&&(H(this.mapPrecomposeKey_),this.mapPrecomposeKey_=null),t||this.changed(),this.mapRenderKey_&&(H(this.mapRenderKey_),this.mapRenderKey_=null),t&&(this.mapPrecomposeKey_=Z(t,Zo,(function(t){var e=t.frameState.layerStatesArray,r=this.getLayerState(!1);pt(!e.some((function(t){return t.layer===r.layer})),67),e.push(r)}),this),this.mapRenderKey_=Z(this,F,t.render,t),this.changed())},e.prototype.setSource=function(t){this.set(Vo,t)},e.prototype.getRenderer=function(){return this.renderer_||(this.renderer_=this.createRenderer()),this.renderer_},e.prototype.hasRenderer=function(){return!!this.renderer_},e.prototype.createRenderer=function(){return null},e.prototype.disposeInternal=function(){this.setSource(null),t.prototype.disposeInternal.call(this)},e}(Wo),ia=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function oa(t,e){Ao.expire()}var aa=function(t){function e(e){var r=t.call(this)||this;return r.map_=e,r}return ia(e,t),e.prototype.dispatchRenderEvent=function(t,e){n()},e.prototype.calculateMatrices2D=function(t){var e=t.viewState,r=t.coordinateToPixelTransform,n=t.pixelToCoordinateTransform;kt(r,t.size[0]/2,t.size[1]/2,1/e.resolution,-1/e.resolution,-e.rotation,-e.center[0],-e.center[1]),jt(n,r)},e.prototype.forEachFeatureAtCoordinate=function(t,e,r,n,i,o,a,s){var l,u=e.viewState;function c(t,e,r,n){return i.call(o,e,t?r:null,n)}var h=u.projection,p=Fr(t.slice(),h),f=[[0,0]];if(h.canWrapX()&&n){var d=Pe(h.getExtent());f.push([-d,0],[d,0])}for(var g=e.layerStatesArray,y=g.length,m=[],v=[],_=0;_<f.length;_++)for(var b=y-1;b>=0;--b){var x=g[b],w=x.layer;if(w.hasRenderer()&&ra(x,u)&&a.call(s,w)){var S=w.getRenderer(),E=w.getSource();if(S&&E){var T=E.getWrapX()?p:t,C=c.bind(null,x.managed);v[0]=T[0]+f[_][0],v[1]=T[1]+f[_][1],l=S.forEachFeatureAtCoordinate(v,e,r,C,m)}if(l)return l}}if(0!==m.length){var O=1/m.length;return m.forEach((function(t,e){return t.distanceSq+=e*O})),m.sort((function(t,e){return t.distanceSq-e.distanceSq})),m.some((function(t){return l=t.callback(t.feature,t.layer,t.geometry)})),l}},e.prototype.forEachLayerAtPixel=function(t,e,r,i,o){return n()},e.prototype.hasFeatureAtCoordinate=function(t,e,r,n,i,o){return void 0!==this.forEachFeatureAtCoordinate(t,e,r,n,S,this,i,o)},e.prototype.getMap=function(){return this.map_},e.prototype.renderFrame=function(t){n()},e.prototype.scheduleExpireIconCache=function(t){Ao.canExpireCache()&&t.postRenderFunctions.push(oa)},e}(p),sa=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),la=function(t){function e(e,r,n,i){var o=t.call(this,e)||this;return o.inversePixelTransform=r,o.frameState=n,o.context=i,o}return sa(e,t),e}(c),ua=new RegExp(["^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)","(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)","(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)","(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?","(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))","(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))","?\\s*([-,\\\"\\'\\sa-z]+?)\\s*$"].join(""),"i"),ca=["style","variant","weight","size","lineHeight","family"],ha=function(t){var e=t.match(ua);if(!e)return null;for(var r={lineHeight:"normal",size:"1.2em",style:"normal",weight:"normal",variant:"normal"},n=0,i=ca.length;n<i;++n){var o=e[n+1];void 0!==o&&(r[ca[n]]=o)}return r.families=r.family.split(/,\s?/),r},pa=[],fa=[0,0,0,0],da=new ot,ga=new M;ga.setSize=function(){console.warn("labelCache is deprecated.")};var ya,ma,va=null,_a={},ba=function(){var t,e,r=["monospace","serif"],n=r.length,i="wmytzilWMYTZIL@#/&?$%10";function o(t,o,a){for(var s=!0,l=0;l<n;++l){var u=r[l];if(e=Sa(t+" "+o+" 32px "+u,i),a!=u){var c=Sa(t+" "+o+" 32px "+a+","+u,i);s=s&&c!=e}}return!!s}function a(){for(var e=!0,r=da.getKeys(),n=0,i=r.length;n<i;++n){var a=r[n];da.get(a)<100&&(o.apply(this,a.split("\n"))?(P(_a),va=null,ya=void 0,da.set(a,100)):(da.set(a,da.get(a)+1,!0),e=!1))}e&&(clearInterval(t),t=void 0)}return function(e){var r=ha(e);if(r)for(var n=r.families,i=0,s=n.length;i<s;++i){var l=n[i],u=r.style+"\n"+r.weight+"\n"+l;void 0===da.get(u)&&(da.set(u,100,!0),o(r.style,r.weight,l)||(da.set(u,0,!0),void 0===t&&(t=setInterval(a,32))))}}}(),xa=function(t){var e=_a[t];if(null==e){if(Yi){var r=ha(t),n=wa(t,"Žg");e=(isNaN(Number(r.lineHeight))?1.2:Number(r.lineHeight))*(n.actualBoundingBoxAscent+n.actualBoundingBoxDescent)}else ma||((ma=document.createElement("div")).innerHTML="M",ma.style.margin="0 !important",ma.style.padding="0 !important",ma.style.position="absolute !important",ma.style.left="-99999px !important"),ma.style.font=t,document.body.appendChild(ma),e=ma.offsetHeight,document.body.removeChild(ma);_a[t]=e}return e};function wa(t,e){return va||(va=uo(1,1)),t!=ya&&(va.font=t,ya=va.font),va.measureText(e)}function Sa(t,e){return wa(t,e).width}function Ea(t,e,r){if(e in r)return r[e];var n=Sa(t,e);return r[e]=n,n}function Ta(t,e,r){for(var n=e.length,i=0,o=0;o<n;++o){var a=Sa(t,e[o]);i=Math.max(i,a),r.push(a)}return i}function Ca(t,e,r,n){0!==e&&(t.translate(r,n),t.rotate(e),t.translate(-r,-n))}function Oa(t,e,r,n,i,o,a,s,l,u,c){t.save(),1!==r&&(t.globalAlpha*=r),e&&t.setTransform.apply(t,e),n.contextInstructions?(t.translate(l,u),t.scale(c[0],c[1]),function(t,e){for(var r=t.contextInstructions,n=0,i=r.length;n<i;n+=2)Array.isArray(r[n+1])?e[r[n]].apply(e,r[n+1]):e[r[n]]=r[n+1]}(n,t)):c[0]<0||c[1]<0?(t.translate(l,u),t.scale(c[0],c[1]),t.drawImage(n,i,o,a,s,0,0,a,s)):t.drawImage(n,i,o,a,s,l,u,a*c[0],s*c[1]),t.restore()}var Pa=null;function Ra(t){return Yi?Dt(t):(Pa||(Pa=uo(1,1).canvas),Pa.style.transform=Dt(t),Pa.style.transform)}var Ia=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),La=function(t){function e(e){var r=t.call(this,e)||this;r.fontChangeListenerKey_=Z(da,h,e.redrawText.bind(e)),r.element_=document.createElement("div");var n=r.element_.style;n.position="absolute",n.width="100%",n.height="100%",n.zIndex="0",r.element_.className="ol-unselectable ol-layers";var i=e.getViewport();return i.insertBefore(r.element_,i.firstChild||null),r.children_=[],r.renderedVisible_=!0,r}return Ia(e,t),e.prototype.dispatchRenderEvent=function(t,e){var r=this.getMap();if(r.hasListener(t)){var n=new la(t,void 0,e);r.dispatchEvent(n)}},e.prototype.disposeInternal=function(){H(this.fontChangeListenerKey_),this.element_.parentNode.removeChild(this.element_),t.prototype.disposeInternal.call(this)},e.prototype.renderFrame=function(t){if(t){this.calculateMatrices2D(t),this.dispatchRenderEvent(Zo,t);var e=t.layerStatesArray.sort((function(t,e){return t.zIndex-e.zIndex})),r=t.viewState;this.children_.length=0;for(var n=[],i=null,o=0,a=e.length;o<a;++o){var s=e[o];if(t.layerIndex=o,ra(s,r)&&(s.sourceState==Qo||s.sourceState==$o)){var l=s.layer,u=l.render(t,i);u&&(u!==i&&(this.children_.push(u),i=u),"getDeclutter"in l&&n.push(l))}}for(o=n.length-1;o>=0;--o)n[o].renderDeclutter(t);yo(this.element_,this.children_),this.dispatchRenderEvent(Ko,t),this.renderedVisible_||(this.element_.style.display="",this.renderedVisible_=!0),this.scheduleExpireIconCache(t)}else this.renderedVisible_&&(this.element_.style.display="none",this.renderedVisible_=!1)},e.prototype.forEachLayerAtPixel=function(t,e,r,n,i){for(var o=e.viewState,a=e.layerStatesArray,s=a.length-1;s>=0;--s){var l=a[s],u=l.layer;if(u.hasRenderer()&&ra(l,o)&&i(u)){var c=u.getRenderer().getDataAtPixel(t,e,r);if(c){var h=n(u,c);if(h)return h}}}},e}(aa),Ma=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Fa="layers",Aa=function(t){function e(e){var r=this,n=e||{},i=O({},n);delete i.layers;var o=n.layers;return(r=t.call(this,i)||this).layersListenerKeys_=[],r.listenerKeys_={},r.addEventListener(it(Fa),r.handleLayersChanged_),o?Array.isArray(o)?o=new ht(o.slice(),{unique:!0}):pt("function"==typeof o.getArray,43):o=new ht(void 0,{unique:!0}),r.setLayers(o),r}return Ma(e,t),e.prototype.handleLayerChange_=function(){this.changed()},e.prototype.handleLayersChanged_=function(){this.layersListenerKeys_.forEach(H),this.layersListenerKeys_.length=0;var t=this.getLayers();for(var e in this.layersListenerKeys_.push(Z(t,at,this.handleLayersAdd_,this),Z(t,st,this.handleLayersRemove_,this)),this.listenerKeys_)this.listenerKeys_[e].forEach(H);P(this.listenerKeys_);for(var r=t.getArray(),n=0,i=r.length;n<i;n++){var a=r[n];this.listenerKeys_[o(a)]=[Z(a,h,this.handleLayerChange_,this),Z(a,F,this.handleLayerChange_,this)]}this.changed()},e.prototype.handleLayersAdd_=function(t){var e=t.element;this.listenerKeys_[o(e)]=[Z(e,h,this.handleLayerChange_,this),Z(e,F,this.handleLayerChange_,this)],this.changed()},e.prototype.handleLayersRemove_=function(t){var e=o(t.element);this.listenerKeys_[e].forEach(H),delete this.listenerKeys_[e],this.changed()},e.prototype.getLayers=function(){return this.get(Fa)},e.prototype.setLayers=function(t){this.set(Fa,t)},e.prototype.getLayersArray=function(t){var e=void 0!==t?t:[];return this.getLayers().forEach((function(t){t.getLayersArray(e)})),e},e.prototype.getLayerStatesArray=function(t){var e=void 0!==t?t:[],r=e.length;this.getLayers().forEach((function(t){t.getLayerStatesArray(e)}));for(var n=this.getLayerState(),i=r,o=e.length;i<o;i++){var a=e[i];a.opacity*=n.opacity,a.visible=a.visible&&n.visible,a.maxResolution=Math.min(a.maxResolution,n.maxResolution),a.minResolution=Math.max(a.minResolution,n.minResolution),a.minZoom=Math.max(a.minZoom,n.minZoom),a.maxZoom=Math.min(a.maxZoom,n.maxZoom),void 0!==n.extent&&(void 0!==a.extent?a.extent=Te(a.extent,n.extent):a.extent=n.extent)}return e},e.prototype.getSourceState=function(){return Qo},e}(Wo),ka=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ja=function(t){function e(e,r,n){var i=t.call(this,e)||this;return i.map=r,i.frameState=void 0!==n?n:null,i}return ka(e,t),e}(c),Na=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Da=function(t){function e(e,r,n,i,o){var a=t.call(this,e,r,o)||this;return a.originalEvent=n,a.pixel_=null,a.coordinate_=null,a.dragging=void 0!==i&&i,a}return Na(e,t),Object.defineProperty(e.prototype,"pixel",{get:function(){return this.pixel_||(this.pixel_=this.map.getEventPixel(this.originalEvent)),this.pixel_},set:function(t){this.pixel_=t},enumerable:!1,configurable:!0}),Object.defineProperty(e.prototype,"coordinate",{get:function(){return this.coordinate_||(this.coordinate_=this.map.getCoordinateFromPixel(this.pixel)),this.coordinate_},set:function(t){this.coordinate_=t},enumerable:!1,configurable:!0}),e.prototype.preventDefault=function(){t.prototype.preventDefault.call(this),this.originalEvent.preventDefault()},e.prototype.stopPropagation=function(){t.prototype.stopPropagation.call(this),this.originalEvent.stopPropagation()},e}(ja),Ga={SINGLECLICK:"singleclick",CLICK:N,DBLCLICK:D,POINTERDRAG:"pointerdrag",POINTERMOVE:"pointermove",POINTERDOWN:"pointerdown",POINTERUP:"pointerup",POINTEROVER:"pointerover",POINTEROUT:"pointerout",POINTERENTER:"pointerenter",POINTERLEAVE:"pointerleave",POINTERCANCEL:"pointercancel"},za="pointermove",Ua="pointerdown",Ba="pointerup",Va="pointerout",Ya=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Wa=function(t){function e(e,r){var n=t.call(this,e)||this;n.map_=e,n.clickTimeoutId_,n.emulateClicks_=!1,n.dragging_=!1,n.dragListenerKeys_=[],n.moveTolerance_=r?r*Vi:Vi,n.down_=null;var i=n.map_.getViewport();return n.activePointers_=0,n.trackedTouches_={},n.element_=i,n.pointerdownListenerKey_=Z(i,Ua,n.handlePointerDown_,n),n.originalPointerMoveEvent_,n.relayedListenerKey_=Z(i,za,n.relayEvent_,n),n.boundHandleTouchMove_=n.handleTouchMove_.bind(n),n.element_.addEventListener(q,n.boundHandleTouchMove_,!!qi&&{passive:!1}),n}return Ya(e,t),e.prototype.emulateClick_=function(t){var e=new Da(Ga.CLICK,this.map_,t);this.dispatchEvent(e),void 0!==this.clickTimeoutId_?(clearTimeout(this.clickTimeoutId_),this.clickTimeoutId_=void 0,e=new Da(Ga.DBLCLICK,this.map_,t),this.dispatchEvent(e)):this.clickTimeoutId_=setTimeout(function(){this.clickTimeoutId_=void 0;var e=new Da(Ga.SINGLECLICK,this.map_,t);this.dispatchEvent(e)}.bind(this),250)},e.prototype.updateActivePointers_=function(t){var e=t;e.type==Ga.POINTERUP||e.type==Ga.POINTERCANCEL?delete this.trackedTouches_[e.pointerId]:e.type==Ga.POINTERDOWN&&(this.trackedTouches_[e.pointerId]=!0),this.activePointers_=Object.keys(this.trackedTouches_).length},e.prototype.handlePointerUp_=function(t){this.updateActivePointers_(t);var e=new Da(Ga.POINTERUP,this.map_,t);this.dispatchEvent(e),this.emulateClicks_&&!e.propagationStopped&&!this.dragging_&&this.isMouseActionButton_(t)&&this.emulateClick_(this.down_),0===this.activePointers_&&(this.dragListenerKeys_.forEach(H),this.dragListenerKeys_.length=0,this.dragging_=!1,this.down_=null)},e.prototype.isMouseActionButton_=function(t){return 0===t.button},e.prototype.handlePointerDown_=function(t){this.emulateClicks_=0===this.activePointers_,this.updateActivePointers_(t);var e=new Da(Ga.POINTERDOWN,this.map_,t);if(this.dispatchEvent(e),this.down_=t,0===this.dragListenerKeys_.length){var r=this.map_.getOwnerDocument();this.dragListenerKeys_.push(Z(r,Ga.POINTERMOVE,this.handlePointerMove_,this),Z(r,Ga.POINTERUP,this.handlePointerUp_,this),Z(this.element_,Ga.POINTERCANCEL,this.handlePointerUp_,this)),this.element_.getRootNode&&this.element_.getRootNode()!==r&&this.dragListenerKeys_.push(Z(this.element_.getRootNode(),Ga.POINTERUP,this.handlePointerUp_,this))}},e.prototype.handlePointerMove_=function(t){if(this.isMoving_(t)){this.dragging_=!0;var e=new Da(Ga.POINTERDRAG,this.map_,t,this.dragging_);this.dispatchEvent(e)}},e.prototype.relayEvent_=function(t){this.originalPointerMoveEvent_=t;var e=!(!this.down_||!this.isMoving_(t));this.dispatchEvent(new Da(t.type,this.map_,t,e))},e.prototype.handleTouchMove_=function(t){this.originalPointerMoveEvent_&&!this.originalPointerMoveEvent_.defaultPrevented||t.preventDefault()},e.prototype.isMoving_=function(t){return this.dragging_||Math.abs(t.clientX-this.down_.clientX)>this.moveTolerance_||Math.abs(t.clientY-this.down_.clientY)>this.moveTolerance_},e.prototype.disposeInternal=function(){this.relayedListenerKey_&&(H(this.relayedListenerKey_),this.relayedListenerKey_=null),this.element_.removeEventListener(q,this.boundHandleTouchMove_),this.pointerdownListenerKey_&&(H(this.pointerdownListenerKey_),this.pointerdownListenerKey_=null),this.dragListenerKeys_.forEach(H),this.dragListenerKeys_.length=0,this.element_=null,t.prototype.disposeInternal.call(this)},e}(M),qa="postrender",Xa="movestart",Za="moveend",Ka="layergroup",Ha="size",$a="target",Ja="view",Qa=function(){function t(t,e){this.priorityFunction_=t,this.keyFunction_=e,this.elements_=[],this.priorities_=[],this.queuedElements_={}}return t.prototype.clear=function(){this.elements_.length=0,this.priorities_.length=0,P(this.queuedElements_)},t.prototype.dequeue=function(){var t=this.elements_,e=this.priorities_,r=t[0];1==t.length?(t.length=0,e.length=0):(t[0]=t.pop(),e[0]=e.pop(),this.siftUp_(0));var n=this.keyFunction_(r);return delete this.queuedElements_[n],r},t.prototype.enqueue=function(t){pt(!(this.keyFunction_(t)in this.queuedElements_),31);var e=this.priorityFunction_(t);return e!=1/0&&(this.elements_.push(t),this.priorities_.push(e),this.queuedElements_[this.keyFunction_(t)]=!0,this.siftDown_(0,this.elements_.length-1),!0)},t.prototype.getCount=function(){return this.elements_.length},t.prototype.getLeftChildIndex_=function(t){return 2*t+1},t.prototype.getRightChildIndex_=function(t){return 2*t+2},t.prototype.getParentIndex_=function(t){return t-1>>1},t.prototype.heapify_=function(){var t;for(t=(this.elements_.length>>1)-1;t>=0;t--)this.siftUp_(t)},t.prototype.isEmpty=function(){return 0===this.elements_.length},t.prototype.isKeyQueued=function(t){return t in this.queuedElements_},t.prototype.isQueued=function(t){return this.isKeyQueued(this.keyFunction_(t))},t.prototype.siftUp_=function(t){for(var e=this.elements_,r=this.priorities_,n=e.length,i=e[t],o=r[t],a=t;t<n>>1;){var s=this.getLeftChildIndex_(t),l=this.getRightChildIndex_(t),u=l<n&&r[l]<r[s]?l:s;e[t]=e[u],r[t]=r[u],t=u}e[t]=i,r[t]=o,this.siftDown_(a,t)},t.prototype.siftDown_=function(t,e){for(var r=this.elements_,n=this.priorities_,i=r[e],o=n[e];e>t;){var a=this.getParentIndex_(e);if(!(n[a]>o))break;r[e]=r[a],n[e]=n[a],e=a}r[e]=i,n[e]=o},t.prototype.reprioritize=function(){var t,e,r,n=this.priorityFunction_,i=this.elements_,o=this.priorities_,a=0,s=i.length;for(e=0;e<s;++e)(r=n(t=i[e]))==1/0?delete this.queuedElements_[this.keyFunction_(t)]:(o[a]=r,i[a++]=t);i.length=a,o.length=a,this.heapify_()},t}(),ts=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),es=function(t){function e(e,r){var n=t.call(this,(function(t){return e.apply(null,t)}),(function(t){return t[0].getKey()}))||this;return n.boundHandleTileChange_=n.handleTileChange.bind(n),n.tileChangeCallback_=r,n.tilesLoading_=0,n.tilesLoadingKeys_={},n}return ts(e,t),e.prototype.enqueue=function(e){var r=t.prototype.enqueue.call(this,e);r&&e[0].addEventListener(F,this.boundHandleTileChange_);return r},e.prototype.getTilesLoading=function(){return this.tilesLoading_},e.prototype.handleTileChange=function(t){var e=t.target,r=e.getState();if(e.hifi&&r===to||r===eo||r===ro){e.removeEventListener(F,this.boundHandleTileChange_);var n=e.getKey();n in this.tilesLoadingKeys_&&(delete this.tilesLoadingKeys_[n],--this.tilesLoading_),this.tileChangeCallback_()}},e.prototype.loadMoreTiles=function(t,e){for(var r,n,i=0;this.tilesLoading_<t&&i<e&&this.getCount()>0;)n=(r=this.dequeue()[0]).getKey(),r.getState()!==Ji||n in this.tilesLoadingKeys_||(this.tilesLoadingKeys_[n]=!0,++this.tilesLoading_,++i,r.load())},e}(Qa);function rs(t,e,r,n,i){if(!t||!(r in t.wantedTiles))return 1/0;if(!t.wantedTiles[r][e.getKey()])return 1/0;var o=t.viewState.center,a=n[0]-o[0],s=n[1]-o[1];return 65536*Math.log(i)+Math.sqrt(a*a+s*s)/i}var ns=0,is=1,os="center",as="resolution",ss="rotation";function ls(t,e,r){return function(n,i,o,a,s){if(n){var l=e?0:o[0]*i,u=e?0:o[1]*i,c=s?s[0]:0,h=s?s[1]:0,p=t[0]+l/2+c,f=t[2]-l/2+c,d=t[1]+u/2+h,g=t[3]-u/2+h;p>f&&(f=p=(f+p)/2),d>g&&(g=d=(g+d)/2);var y=Ne(n[0],p,f),m=Ne(n[1],d,g),v=30*i;return a&&r&&(y+=-v*Math.log(1+Math.max(0,p-n[0])/v)+v*Math.log(1+Math.max(0,n[0]-f)/v),m+=-v*Math.log(1+Math.max(0,d-n[1])/v)+v*Math.log(1+Math.max(0,n[1]-g)/v)),[y,m]}}}function us(t){return t}function cs(t,e,r,n){var i=Pe(e)/r[0],o=Ee(e)/r[1];return n?Math.min(t,Math.max(i,o)):Math.min(t,Math.min(i,o))}function hs(t,e,r){var n=Math.min(t,e);return n*=Math.log(1+50*Math.max(0,t/e-1))/50+1,r&&(n=Math.max(n,r),n/=Math.log(1+50*Math.max(0,r/t-1))/50+1),Ne(n,r/2,2*e)}function ps(t,e,r,n){return function(i,o,a,s){if(void 0!==i){var l=t[0],u=t[t.length-1],c=r?cs(l,r,a,n):l;if(s)return void 0===e||e?hs(i,c,u):Ne(i,u,c);var h=Math.min(c,i),p=Math.floor(y(t,h,o));return t[p]>c&&p<t.length-1?t[p+1]:t[p]}}}function fs(t,e,r,n,i,o){return function(a,s,l,u){if(void 0!==a){var c=i?cs(e,i,l,o):e,h=void 0!==r?r:0;if(u)return void 0===n||n?hs(a,c,h):Ne(a,h,c);var p=Math.ceil(Math.log(e/c)/Math.log(t)-1e-9),f=-s*(.5-1e-9)+.5,d=Math.min(c,a),g=Math.floor(Math.log(e/d)/Math.log(t)+f),y=Math.max(p,g);return Ne(e/Math.pow(t,y),h,c)}}}function ds(t,e,r,n,i){return function(o,a,s,l){if(void 0!==o){var u=n?cs(t,n,s,i):t;return(void 0===r||r)&&l?hs(o,u,e):Ne(o,e,u)}}}function gs(t){return void 0!==t?0:void 0}function ys(t){return void 0!==t?t:void 0}function ms(t){var e=2*Math.PI/t;return function(t,r){return r?t:void 0!==t?t=Math.floor(t/e+.5)*e:void 0}}function vs(t){var e=t||Ye(5);return function(t,r){return r?t:void 0!==t?Math.abs(t)<=e?0:t:void 0}}var _s=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function bs(t,e){setTimeout((function(){t(e)}),0)}function xs(t){if(void 0!==t.extent){var e=void 0===t.smoothExtentConstraint||t.smoothExtentConstraint;return ls(t.extent,t.constrainOnlyCenter,e)}var r=Vr(t.projection,"EPSG:3857");if(!0!==t.multiWorld&&r.isGlobal()){var n=r.getExtent().slice();return n[0]=-1/0,n[2]=1/0,ls(n,!1,!1)}return us}function ws(t){var e,r,n,i=void 0!==t.minZoom?t.minZoom:0,o=void 0!==t.maxZoom?t.maxZoom:28,a=void 0!==t.zoomFactor?t.zoomFactor:2,s=void 0!==t.multiWorld&&t.multiWorld,l=void 0===t.smoothResolutionConstraint||t.smoothResolutionConstraint,u=void 0!==t.showFullExtent&&t.showFullExtent,c=Vr(t.projection,"EPSG:3857"),h=c.getExtent(),p=t.constrainOnlyCenter,f=t.extent;if(s||f||!c.isGlobal()||(p=!1,f=h),void 0!==t.resolutions){var d=t.resolutions;r=d[i],n=void 0!==d[o]?d[o]:d[d.length-1],e=t.constrainResolution?ps(d,l,!p&&f,u):ds(r,n,l,!p&&f,u)}else{var g=(h?Math.max(Pe(h),Ee(h)):360*wt[St.DEGREES]/c.getMetersPerUnit())/256/Math.pow(2,0),y=g/Math.pow(2,28);void 0!==(r=t.maxResolution)?i=0:r=g/Math.pow(a,i),void 0===(n=t.minResolution)&&(n=void 0!==t.maxZoom?void 0!==t.maxResolution?r/Math.pow(a,o):g/Math.pow(a,o):y),o=i+Math.floor(Math.log(r/n)/Math.log(a)),n=r/Math.pow(a,o-i),e=t.constrainResolution?fs(a,r,n,l,!p&&f,u):ds(r,n,l,!p&&f,u)}return{constraint:e,maxResolution:r,minResolution:n,minZoom:i,zoomFactor:a}}function Ss(t){if(void 0===t.enableRotation||t.enableRotation){var e=t.constrainRotation;return void 0===e||!0===e?vs():!1===e?ys:"number"==typeof e?ms(e):ys}return gs}function Es(t){return!(t.sourceCenter&&t.targetCenter&&!Cr(t.sourceCenter,t.targetCenter))&&(t.sourceResolution===t.targetResolution&&t.sourceRotation===t.targetRotation)}function Ts(t,e,r,n,i){var o=Math.cos(-i),a=Math.sin(-i),s=t[0]*o-t[1]*a,l=t[1]*o+t[0]*a;return[(s+=(e[0]/2-r[0])*n)*o-(l+=(r[1]-e[1]/2)*n)*(a=-a),l*o+s*a]}var Cs=function(t){function e(e){var r=t.call(this)||this,n=O({},e);return r.hints_=[0,0],r.animations_=[],r.updateAnimationKey_,r.projection_=Vr(n.projection,"EPSG:3857"),r.viewportSize_=[100,100],r.targetCenter_=null,r.targetResolution_,r.targetRotation_,r.cancelAnchor_=void 0,n.center&&(n.center=rn(n.center,r.projection_)),n.extent&&(n.extent=on(n.extent,r.projection_)),r.applyOptions_(n),r}return _s(e,t),e.prototype.applyOptions_=function(t){var e=ws(t);this.maxResolution_=e.maxResolution,this.minResolution_=e.minResolution,this.zoomFactor_=e.zoomFactor,this.resolutions_=t.resolutions,this.padding=t.padding,this.minZoom_=e.minZoom;var r=xs(t),n=e.constraint,i=Ss(t);this.constraints_={center:r,resolution:n,rotation:i},this.setRotation(void 0!==t.rotation?t.rotation:0),this.setCenterInternal(void 0!==t.center?t.center:null),void 0!==t.resolution?this.setResolution(t.resolution):void 0!==t.zoom&&this.setZoom(t.zoom),this.setProperties({}),this.options_=t},e.prototype.getUpdatedOptions_=function(t){var e=O({},this.options_);return void 0!==e.resolution?e.resolution=this.getResolution():e.zoom=this.getZoom(),e.center=this.getCenterInternal(),e.rotation=this.getRotation(),O({},e,t)},e.prototype.animate=function(t){this.isDef()&&!this.getAnimating()&&this.resolveConstraints(0);for(var e=new Array(arguments.length),r=0;r<e.length;++r){var n=arguments[r];n.center&&((n=O({},n)).center=rn(n.center,this.getProjection())),n.anchor&&((n=O({},n)).anchor=rn(n.anchor,this.getProjection())),e[r]=n}this.animateInternal.apply(this,e)},e.prototype.animateInternal=function(t){var e,r=arguments.length;if(r>1&&"function"==typeof arguments[r-1]&&(e=arguments[r-1],--r),!this.isDef()){var n=arguments[r-1];return n.center&&this.setCenterInternal(n.center),void 0!==n.zoom&&this.setZoom(n.zoom),void 0!==n.rotation&&this.setRotation(n.rotation),void(e&&bs(e,!0))}for(var i=Date.now(),o=this.targetCenter_.slice(),a=this.targetResolution_,s=this.targetRotation_,l=[],u=0;u<r;++u){var c=arguments[u],h={start:i,complete:!1,anchor:c.anchor,duration:void 0!==c.duration?c.duration:1e3,easing:c.easing||oo,callback:e};if(c.center&&(h.sourceCenter=o,h.targetCenter=c.center.slice(),o=h.targetCenter),void 0!==c.zoom?(h.sourceResolution=a,h.targetResolution=this.getResolutionForZoom(c.zoom),a=h.targetResolution):c.resolution&&(h.sourceResolution=a,h.targetResolution=c.resolution,a=h.targetResolution),void 0!==c.rotation){h.sourceRotation=s;var p=We(c.rotation-s+Math.PI,2*Math.PI)-Math.PI;h.targetRotation=s+p,s=h.targetRotation}Es(h)?h.complete=!0:i+=h.duration,l.push(h)}this.animations_.push(l),this.setHint(ns,1),this.updateAnimations_()},e.prototype.getAnimating=function(){return this.hints_[ns]>0},e.prototype.getInteracting=function(){return this.hints_[is]>0},e.prototype.cancelAnimations=function(){var t;this.setHint(ns,-this.hints_[ns]);for(var e=0,r=this.animations_.length;e<r;++e){var n=this.animations_[e];if(n[0].callback&&bs(n[0].callback,!1),!t)for(var i=0,o=n.length;i<o;++i){var a=n[i];if(!a.complete){t=a.anchor;break}}}this.animations_.length=0,this.cancelAnchor_=t},e.prototype.updateAnimations_=function(){if(void 0!==this.updateAnimationKey_&&(cancelAnimationFrame(this.updateAnimationKey_),this.updateAnimationKey_=void 0),this.getAnimating()){for(var t=Date.now(),e=!1,r=this.animations_.length-1;r>=0;--r){for(var n=this.animations_[r],i=!0,o=0,a=n.length;o<a;++o){var s=n[o];if(!s.complete){var l=t-s.start,u=s.duration>0?l/s.duration:1;u>=1?(s.complete=!0,u=1):i=!1;var c=s.easing(u);if(s.sourceCenter){var h=s.sourceCenter[0],p=s.sourceCenter[1],f=h+c*(s.targetCenter[0]-h),d=p+c*(s.targetCenter[1]-p);this.targetCenter_=[f,d]}if(s.sourceResolution&&s.targetResolution){var g=1===c?s.targetResolution:s.sourceResolution+c*(s.targetResolution-s.sourceResolution);if(s.anchor){var y=this.getViewportSize_(this.getRotation()),m=this.constraints_.resolution(g,0,y,!0);this.targetCenter_=this.calculateCenterZoom(m,s.anchor)}this.targetResolution_=g,this.applyTargetState_(!0)}if(void 0!==s.sourceRotation&&void 0!==s.targetRotation){var v=1===c?We(s.targetRotation+Math.PI,2*Math.PI)-Math.PI:s.sourceRotation+c*(s.targetRotation-s.sourceRotation);if(s.anchor){var _=this.constraints_.rotation(v,!0);this.targetCenter_=this.calculateCenterRotate(_,s.anchor)}this.targetRotation_=v}if(this.applyTargetState_(!0),e=!0,!s.complete)break}}if(i){this.animations_[r]=null,this.setHint(ns,-1);var b=n[0].callback;b&&bs(b,!0)}}this.animations_=this.animations_.filter(Boolean),e&&void 0===this.updateAnimationKey_&&(this.updateAnimationKey_=requestAnimationFrame(this.updateAnimations_.bind(this)))}},e.prototype.calculateCenterRotate=function(t,e){var r,n=this.getCenterInternal();return void 0!==n&&(Or(r=[n[0]-e[0],n[1]-e[1]],t-this.getRotation()),xr(r,e)),r},e.prototype.calculateCenterZoom=function(t,e){var r,n=this.getCenterInternal(),i=this.getResolution();void 0!==n&&void 0!==i&&(r=[e[0]-t*(e[0]-n[0])/i,e[1]-t*(e[1]-n[1])/i]);return r},e.prototype.getViewportSize_=function(t){var e=this.viewportSize_;if(t){var r=e[0],n=e[1];return[Math.abs(r*Math.cos(t))+Math.abs(n*Math.sin(t)),Math.abs(r*Math.sin(t))+Math.abs(n*Math.cos(t))]}return e},e.prototype.setViewportSize=function(t){this.viewportSize_=Array.isArray(t)?t.slice():[100,100],this.getAnimating()||this.resolveConstraints(0)},e.prototype.getCenter=function(){var t=this.getCenterInternal();return t?en(t,this.getProjection()):t},e.prototype.getCenterInternal=function(){return this.get(os)},e.prototype.getConstraints=function(){return this.constraints_},e.prototype.getConstrainResolution=function(){return this.options_.constrainResolution},e.prototype.getHints=function(t){return void 0!==t?(t[0]=this.hints_[0],t[1]=this.hints_[1],t):this.hints_.slice()},e.prototype.calculateExtent=function(t){return nn(this.calculateExtentInternal(t),this.getProjection())},e.prototype.calculateExtentInternal=function(t){var e=t||this.getViewportSize_(),r=this.getCenterInternal();pt(r,1);var n=this.getResolution();pt(void 0!==n,2);var i=this.getRotation();return pt(void 0!==i,3),Se(r,n,i,e)},e.prototype.getMaxResolution=function(){return this.maxResolution_},e.prototype.getMinResolution=function(){return this.minResolution_},e.prototype.getMaxZoom=function(){return this.getZoomForResolution(this.minResolution_)},e.prototype.setMaxZoom=function(t){this.applyOptions_(this.getUpdatedOptions_({maxZoom:t}))},e.prototype.getMinZoom=function(){return this.getZoomForResolution(this.maxResolution_)},e.prototype.setMinZoom=function(t){this.applyOptions_(this.getUpdatedOptions_({minZoom:t}))},e.prototype.setConstrainResolution=function(t){this.applyOptions_(this.getUpdatedOptions_({constrainResolution:t}))},e.prototype.getProjection=function(){return this.projection_},e.prototype.getResolution=function(){return this.get(as)},e.prototype.getResolutions=function(){return this.resolutions_},e.prototype.getResolutionForExtent=function(t,e){return this.getResolutionForExtentInternal(on(t,this.getProjection()),e)},e.prototype.getResolutionForExtentInternal=function(t,e){var r=e||this.getViewportSize_(),n=Pe(t)/r[0],i=Ee(t)/r[1];return Math.max(n,i)},e.prototype.getResolutionForValueFunction=function(t){var e=t||2,r=this.getConstrainedResolution(this.maxResolution_),n=this.minResolution_,i=Math.log(r/n)/Math.log(e);return function(t){return r/Math.pow(e,t*i)}},e.prototype.getRotation=function(){return this.get(ss)},e.prototype.getValueForResolutionFunction=function(t){var e=Math.log(t||2),r=this.getConstrainedResolution(this.maxResolution_),n=this.minResolution_,i=Math.log(r/n)/e;return function(t){return Math.log(r/t)/e/i}},e.prototype.getViewportSizeMinusPadding_=function(t){var e=this.getViewportSize_(t),r=this.padding;return r&&(e=[e[0]-r[1]-r[3],e[1]-r[0]-r[2]]),e},e.prototype.getState=function(){var t=this.getProjection(),e=this.getResolution(),r=this.getRotation(),n=this.getCenterInternal(),i=this.padding;if(i){var o=this.getViewportSizeMinusPadding_();n=Ts(n,this.getViewportSize_(),[o[0]/2+i[3],o[1]/2+i[0]],e,r)}return{center:n.slice(0),projection:void 0!==t?t:null,resolution:e,rotation:r,zoom:this.getZoom()}},e.prototype.getZoom=function(){var t,e=this.getResolution();return void 0!==e&&(t=this.getZoomForResolution(e)),t},e.prototype.getZoomForResolution=function(t){var e,r,n=this.minZoom_||0;if(this.resolutions_){var i=y(this.resolutions_,t,1);n=i,e=this.resolutions_[i],r=i==this.resolutions_.length-1?2:e/this.resolutions_[i+1]}else e=this.maxResolution_,r=this.zoomFactor_;return n+Math.log(e/t)/Math.log(r)},e.prototype.getResolutionForZoom=function(t){if(this.resolutions_){if(this.resolutions_.length<=1)return 0;var e=Ne(Math.floor(t),0,this.resolutions_.length-2),r=this.resolutions_[e]/this.resolutions_[e+1];return this.resolutions_[e]/Math.pow(r,Ne(t-e,0,1))}return this.maxResolution_/Math.pow(this.zoomFactor_,t-this.minZoom_)},e.prototype.fit=function(t,e){var r;if(pt(Array.isArray(t)||"function"==typeof t.getSimplifiedGeometry,24),Array.isArray(t))pt(!Ie(t),25),r=gi(n=on(t,this.getProjection()));else if(t.getType()===bt.CIRCLE){var n;(r=gi(n=on(t.getExtent(),this.getProjection()))).rotate(this.getRotation(),xe(n))}else{var i=tn();r=i?t.clone().transform(i,this.getProjection()):t}this.fitInternal(r,e)},e.prototype.fitInternal=function(t,e){var r=e||{},n=r.size;n||(n=this.getViewportSizeMinusPadding_());var i,o=void 0!==r.padding?r.padding:[0,0,0,0],a=void 0!==r.nearest&&r.nearest;i=void 0!==r.minResolution?r.minResolution:void 0!==r.maxZoom?this.getResolutionForZoom(r.maxZoom):0;for(var s=t.getFlatCoordinates(),l=this.getRotation(),u=Math.cos(-l),c=Math.sin(-l),h=1/0,p=1/0,f=-1/0,d=-1/0,g=t.getStride(),y=0,m=s.length;y<m;y+=g){var v=s[y]*u-s[y+1]*c,_=s[y]*c+s[y+1]*u;h=Math.min(h,v),p=Math.min(p,_),f=Math.max(f,v),d=Math.max(d,_)}var b=this.getResolutionForExtentInternal([h,p,f,d],[n[0]-o[1]-o[3],n[1]-o[0]-o[2]]);b=isNaN(b)?i:Math.max(b,i),b=this.getConstrainedResolution(b,a?0:1),c=-c;var x=(h+f)/2,w=(p+d)/2,S=(x+=(o[1]-o[3])/2*b)*u-(w+=(o[0]-o[2])/2*b)*c,E=w*u+x*c,C=this.getConstrainedCenter([S,E],b),O=r.callback?r.callback:T;void 0!==r.duration?this.animateInternal({resolution:b,center:C,duration:r.duration,easing:r.easing},O):(this.targetResolution_=b,this.targetCenter_=C,this.applyTargetState_(!1,!0),bs(O,!0))},e.prototype.centerOn=function(t,e,r){this.centerOnInternal(rn(t,this.getProjection()),e,r)},e.prototype.centerOnInternal=function(t,e,r){this.setCenterInternal(Ts(t,e,r,this.getResolution(),this.getRotation()))},e.prototype.calculateCenterShift=function(t,e,r,n){var i,o=this.padding;if(o&&t){var a=this.getViewportSizeMinusPadding_(-r),s=Ts(t,n,[a[0]/2+o[3],a[1]/2+o[0]],e,r);i=[t[0]-s[0],t[1]-s[1]]}return i},e.prototype.isDef=function(){return!!this.getCenterInternal()&&void 0!==this.getResolution()},e.prototype.adjustCenter=function(t){var e=en(this.targetCenter_,this.getProjection());this.setCenter([e[0]+t[0],e[1]+t[1]])},e.prototype.adjustCenterInternal=function(t){var e=this.targetCenter_;this.setCenterInternal([e[0]+t[0],e[1]+t[1]])},e.prototype.adjustResolution=function(t,e){var r=e&&rn(e,this.getProjection());this.adjustResolutionInternal(t,r)},e.prototype.adjustResolutionInternal=function(t,e){var r=this.getAnimating()||this.getInteracting(),n=this.getViewportSize_(this.getRotation()),i=this.constraints_.resolution(this.targetResolution_*t,0,n,r);e&&(this.targetCenter_=this.calculateCenterZoom(i,e)),this.targetResolution_*=t,this.applyTargetState_()},e.prototype.adjustZoom=function(t,e){this.adjustResolution(Math.pow(this.zoomFactor_,-t),e)},e.prototype.adjustRotation=function(t,e){e&&(e=rn(e,this.getProjection())),this.adjustRotationInternal(t,e)},e.prototype.adjustRotationInternal=function(t,e){var r=this.getAnimating()||this.getInteracting(),n=this.constraints_.rotation(this.targetRotation_+t,r);e&&(this.targetCenter_=this.calculateCenterRotate(n,e)),this.targetRotation_+=t,this.applyTargetState_()},e.prototype.setCenter=function(t){this.setCenterInternal(rn(t,this.getProjection()))},e.prototype.setCenterInternal=function(t){this.targetCenter_=t,this.applyTargetState_()},e.prototype.setHint=function(t,e){return this.hints_[t]+=e,this.changed(),this.hints_[t]},e.prototype.setResolution=function(t){this.targetResolution_=t,this.applyTargetState_()},e.prototype.setRotation=function(t){this.targetRotation_=t,this.applyTargetState_()},e.prototype.setZoom=function(t){this.setResolution(this.getResolutionForZoom(t))},e.prototype.applyTargetState_=function(t,e){var r=this.getAnimating()||this.getInteracting()||e,n=this.constraints_.rotation(this.targetRotation_,r),i=this.getViewportSize_(n),o=this.constraints_.resolution(this.targetResolution_,0,i,r),a=this.constraints_.center(this.targetCenter_,o,i,r,this.calculateCenterShift(this.targetCenter_,o,n,i));this.get(ss)!==n&&this.set(ss,n),this.get(as)!==o&&this.set(as,o),this.get(os)&&Cr(this.get(os),a)||this.set(os,a),this.getAnimating()&&!t&&this.cancelAnimations(),this.cancelAnchor_=void 0},e.prototype.resolveConstraints=function(t,e,r){var n=void 0!==t?t:200,i=e||0,o=this.constraints_.rotation(this.targetRotation_),a=this.getViewportSize_(o),s=this.constraints_.resolution(this.targetResolution_,i,a),l=this.constraints_.center(this.targetCenter_,s,a,!1,this.calculateCenterShift(this.targetCenter_,s,o,a));if(0===n&&!this.cancelAnchor_)return this.targetResolution_=s,this.targetRotation_=o,this.targetCenter_=l,void this.applyTargetState_();var u=r||(0===n?this.cancelAnchor_:void 0);this.cancelAnchor_=void 0,this.getResolution()===s&&this.getRotation()===o&&this.getCenterInternal()&&Cr(this.getCenterInternal(),l)||(this.getAnimating()&&this.cancelAnimations(),this.animateInternal({rotation:o,center:l,resolution:s,duration:n,easing:io,anchor:u}))},e.prototype.beginInteraction=function(){this.resolveConstraints(0),this.setHint(is,1)},e.prototype.endInteraction=function(t,e,r){var n=r&&rn(r,this.getProjection());this.endInteractionInternal(t,e,n)},e.prototype.endInteractionInternal=function(t,e,r){this.setHint(is,-1),this.resolveConstraints(t,e,r)},e.prototype.getConstrainedCenter=function(t,e){var r=this.getViewportSize_(this.getRotation());return this.constraints_.center(t,e||this.getResolution(),r)},e.prototype.getConstrainedZoom=function(t,e){var r=this.getResolutionForZoom(t);return this.getZoomForResolution(this.getConstrainedResolution(r,e))},e.prototype.getConstrainedResolution=function(t,e){var r=e||0,n=this.getViewportSize_(this.getRotation());return this.constraints_.resolution(t,r,n)},e}(ot);function Os(t,e,r){return void 0===r&&(r=[0,0]),r[0]=t[0]+2*e,r[1]=t[1]+2*e,r}function Ps(t){return t[0]>0&&t[1]>0}function Rs(t,e,r){return void 0===r&&(r=[0,0]),r[0]=t[0]*e+.5|0,r[1]=t[1]*e+.5|0,r}function Is(t,e){return Array.isArray(t)?t:(void 0===e?e=[t,t]:(e[0]=t,e[1]=t),e)}var Ls=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();var Ms=function(t){function e(e){var r=t.call(this)||this,n=function(t){var e=null;void 0!==t.keyboardEventTarget&&(e="string"==typeof t.keyboardEventTarget?document.getElementById(t.keyboardEventTarget):t.keyboardEventTarget);var r,n,i,o={},a=t.layers&&"function"==typeof t.layers.getLayers?t.layers:new Aa({layers:t.layers});o[Ka]=a,o[$a]=t.target,o[Ja]=void 0!==t.view?t.view:new Cs,void 0!==t.controls&&(Array.isArray(t.controls)?r=new ht(t.controls.slice()):(pt("function"==typeof t.controls.getArray,47),r=t.controls));void 0!==t.interactions&&(Array.isArray(t.interactions)?n=new ht(t.interactions.slice()):(pt("function"==typeof t.interactions.getArray,48),n=t.interactions));void 0!==t.overlays?Array.isArray(t.overlays)?i=new ht(t.overlays.slice()):(pt("function"==typeof t.overlays.getArray,49),i=t.overlays):i=new ht;return{controls:r,interactions:n,keyboardEventTarget:e,overlays:i,values:o}}(e);return r.boundHandleBrowserEvent_=r.handleBrowserEvent.bind(r),r.maxTilesLoading_=void 0!==e.maxTilesLoading?e.maxTilesLoading:16,r.pixelRatio_=void 0!==e.pixelRatio?e.pixelRatio:Vi,r.postRenderTimeoutHandle_,r.animationDelayKey_,r.animationDelay_=function(){this.animationDelayKey_=void 0,this.renderFrame_(Date.now())}.bind(r),r.coordinateToPixelTransform_=[1,0,0,1,0,0],r.pixelToCoordinateTransform_=[1,0,0,1,0,0],r.frameIndex_=0,r.frameState_=null,r.previousExtent_=null,r.viewPropertyListenerKey_=null,r.viewChangeListenerKey_=null,r.layerGroupPropertyListenerKeys_=null,r.viewport_=document.createElement("div"),r.viewport_.className="ol-viewport"+("ontouchstart"in window?" ol-touch":""),r.viewport_.style.position="relative",r.viewport_.style.overflow="hidden",r.viewport_.style.width="100%",r.viewport_.style.height="100%",r.overlayContainer_=document.createElement("div"),r.overlayContainer_.style.position="absolute",r.overlayContainer_.style.zIndex="0",r.overlayContainer_.style.width="100%",r.overlayContainer_.style.height="100%",r.overlayContainer_.style.pointerEvents="none",r.overlayContainer_.className="ol-overlaycontainer",r.viewport_.appendChild(r.overlayContainer_),r.overlayContainerStopEvent_=document.createElement("div"),r.overlayContainerStopEvent_.style.position="absolute",r.overlayContainerStopEvent_.style.zIndex="0",r.overlayContainerStopEvent_.style.width="100%",r.overlayContainerStopEvent_.style.height="100%",r.overlayContainerStopEvent_.style.pointerEvents="none",r.overlayContainerStopEvent_.className="ol-overlaycontainer-stopevent",r.viewport_.appendChild(r.overlayContainerStopEvent_),r.mapBrowserEventHandler_=null,r.moveTolerance_=e.moveTolerance,r.keyboardEventTarget_=n.keyboardEventTarget,r.keyHandlerKeys_=null,r.controls=n.controls||new ht,r.interactions=n.interactions||new ht,r.overlays_=n.overlays,r.overlayIdIndex_={},r.renderer_=null,r.handleResize_,r.postRenderFunctions_=[],r.tileQueue_=new es(r.getTilePriority.bind(r),r.handleTileChange_.bind(r)),r.addEventListener(it(Ka),r.handleLayerGroupChanged_),r.addEventListener(it(Ja),r.handleViewChanged_),r.addEventListener(it(Ha),r.handleSizeChanged_),r.addEventListener(it($a),r.handleTargetChanged_),r.setProperties(n.values),r.controls.forEach(function(t){t.setMap(this)}.bind(r)),r.controls.addEventListener(at,function(t){t.element.setMap(this)}.bind(r)),r.controls.addEventListener(st,function(t){t.element.setMap(null)}.bind(r)),r.interactions.forEach(function(t){t.setMap(this)}.bind(r)),r.interactions.addEventListener(at,function(t){t.element.setMap(this)}.bind(r)),r.interactions.addEventListener(st,function(t){t.element.setMap(null)}.bind(r)),r.overlays_.forEach(r.addOverlayInternal_.bind(r)),r.overlays_.addEventListener(at,function(t){this.addOverlayInternal_(t.element)}.bind(r)),r.overlays_.addEventListener(st,function(t){var e=t.element.getId();void 0!==e&&delete this.overlayIdIndex_[e.toString()],t.element.setMap(null)}.bind(r)),r}return Ls(e,t),e.prototype.createRenderer=function(){throw new Error("Use a map type that has a createRenderer method")},e.prototype.addControl=function(t){this.getControls().push(t)},e.prototype.addInteraction=function(t){this.getInteractions().push(t)},e.prototype.addLayer=function(t){this.getLayerGroup().getLayers().push(t)},e.prototype.addOverlay=function(t){this.getOverlays().push(t)},e.prototype.addOverlayInternal_=function(t){var e=t.getId();void 0!==e&&(this.overlayIdIndex_[e.toString()]=t),t.setMap(this)},e.prototype.disposeInternal=function(){this.setTarget(null),t.prototype.disposeInternal.call(this)},e.prototype.forEachFeatureAtPixel=function(t,e,r){if(this.frameState_){var n=this.getCoordinateFromPixelInternal(t),i=void 0!==(r=void 0!==r?r:{}).hitTolerance?r.hitTolerance:0,o=void 0!==r.layerFilter?r.layerFilter:S,a=!1!==r.checkWrapped;return this.renderer_.forEachFeatureAtCoordinate(n,this.frameState_,i,a,e,null,o,null)}},e.prototype.getFeaturesAtPixel=function(t,e){var r=[];return this.forEachFeatureAtPixel(t,(function(t){r.push(t)}),e),r},e.prototype.forEachLayerAtPixel=function(t,e,r){if(this.frameState_){var n=r||{},i=void 0!==n.hitTolerance?n.hitTolerance:0,o=n.layerFilter||S;return this.renderer_.forEachLayerAtPixel(t,this.frameState_,i,e,o)}},e.prototype.hasFeatureAtPixel=function(t,e){if(!this.frameState_)return!1;var r=this.getCoordinateFromPixelInternal(t),n=void 0!==(e=void 0!==e?e:{}).layerFilter?e.layerFilter:S,i=void 0!==e.hitTolerance?e.hitTolerance:0,o=!1!==e.checkWrapped;return this.renderer_.hasFeatureAtCoordinate(r,this.frameState_,i,o,n,null)},e.prototype.getEventCoordinate=function(t){return this.getCoordinateFromPixel(this.getEventPixel(t))},e.prototype.getEventCoordinateInternal=function(t){return this.getCoordinateFromPixelInternal(this.getEventPixel(t))},e.prototype.getEventPixel=function(t){var e=this.viewport_.getBoundingClientRect(),r="changedTouches"in t?t.changedTouches[0]:t;return[r.clientX-e.left,r.clientY-e.top]},e.prototype.getTarget=function(){return this.get($a)},e.prototype.getTargetElement=function(){var t=this.getTarget();return void 0!==t?"string"==typeof t?document.getElementById(t):t:null},e.prototype.getCoordinateFromPixel=function(t){return en(this.getCoordinateFromPixelInternal(t),this.getView().getProjection())},e.prototype.getCoordinateFromPixelInternal=function(t){var e=this.frameState_;return e?It(e.pixelToCoordinateTransform,t.slice()):null},e.prototype.getControls=function(){return this.controls},e.prototype.getOverlays=function(){return this.overlays_},e.prototype.getOverlayById=function(t){var e=this.overlayIdIndex_[t.toString()];return void 0!==e?e:null},e.prototype.getInteractions=function(){return this.interactions},e.prototype.getLayerGroup=function(){return this.get(Ka)},e.prototype.getLayers=function(){return this.getLayerGroup().getLayers()},e.prototype.getLoading=function(){for(var t=this.getLayerGroup().getLayerStatesArray(),e=0,r=t.length;e<r;++e){var n=t[e].layer.getSource();if(n&&n.loading)return!0}return!1},e.prototype.getPixelFromCoordinate=function(t){var e=rn(t,this.getView().getProjection());return this.getPixelFromCoordinateInternal(e)},e.prototype.getPixelFromCoordinateInternal=function(t){var e=this.frameState_;return e?It(e.coordinateToPixelTransform,t.slice(0,2)):null},e.prototype.getRenderer=function(){return this.renderer_},e.prototype.getSize=function(){return this.get(Ha)},e.prototype.getView=function(){return this.get(Ja)},e.prototype.getViewport=function(){return this.viewport_},e.prototype.getOverlayContainer=function(){return this.overlayContainer_},e.prototype.getOverlayContainerStopEvent=function(){return this.overlayContainerStopEvent_},e.prototype.getOwnerDocument=function(){return this.getTargetElement()?this.getTargetElement().ownerDocument:document},e.prototype.getTilePriority=function(t,e,r,n){return rs(this.frameState_,t,e,r,n)},e.prototype.handleBrowserEvent=function(t,e){var r=e||t.type,n=new Da(r,this,t);this.handleMapBrowserEvent(n)},e.prototype.handleMapBrowserEvent=function(t){if(this.frameState_){var e=t.originalEvent,r=e.type;if(r===Ua||r===X||r===B){var n=this.getOwnerDocument(),i=this.viewport_.getRootNode?this.viewport_.getRootNode():n,o="host"in i?i.elementFromPoint(e.clientX,e.clientY):e.target;if(this.overlayContainerStopEvent_.contains(o)||!(i===n?n.documentElement:i).contains(o))return}if(t.frameState=this.frameState_,!1!==this.dispatchEvent(t))for(var a=this.getInteractions().getArray().slice(),s=a.length-1;s>=0;s--){var l=a[s];if(l.getMap()===this&&l.getActive()&&this.getTargetElement())if(!l.handleEvent(t)||t.propagationStopped)break}}},e.prototype.handlePostRender=function(){var t=this.frameState_,e=this.tileQueue_;if(!e.isEmpty()){var r=this.maxTilesLoading_,n=r;if(t){var i=t.viewHints;if(i[ns]||i[is]){var o=!Wi&&Date.now()-t.time>8;r=o?0:8,n=o?0:2}}e.getTilesLoading()<r&&(e.reprioritize(),e.loadMoreTiles(r,n))}!t||!this.hasListener(Ho)||t.animate||this.tileQueue_.getTilesLoading()||this.getLoading()||this.renderer_.dispatchRenderEvent(Ho,t);for(var a=this.postRenderFunctions_,s=0,l=a.length;s<l;++s)a[s](this,t);a.length=0},e.prototype.handleSizeChanged_=function(){this.getView()&&!this.getView().getAnimating()&&this.getView().resolveConstraints(0),this.render()},e.prototype.handleTargetChanged_=function(){var t;if(this.getTarget()&&(t=this.getTargetElement()),this.mapBrowserEventHandler_){for(var e=0,r=this.keyHandlerKeys_.length;e<r;++e)H(this.keyHandlerKeys_[e]);this.keyHandlerKeys_=null,this.viewport_.removeEventListener(j,this.boundHandleBrowserEvent_),this.viewport_.removeEventListener(X,this.boundHandleBrowserEvent_),void 0!==this.handleResize_&&(removeEventListener(W,this.handleResize_,!1),this.handleResize_=void 0),this.mapBrowserEventHandler_.dispose(),this.mapBrowserEventHandler_=null,fo(this.viewport_)}if(t){for(var n in t.appendChild(this.viewport_),this.renderer_||(this.renderer_=this.createRenderer()),this.mapBrowserEventHandler_=new Wa(this,this.moveTolerance_),Ga)this.mapBrowserEventHandler_.addEventListener(Ga[n],this.handleMapBrowserEvent.bind(this));this.viewport_.addEventListener(j,this.boundHandleBrowserEvent_,!1),this.viewport_.addEventListener(X,this.boundHandleBrowserEvent_,!!qi&&{passive:!1});var i=this.keyboardEventTarget_?this.keyboardEventTarget_:t;this.keyHandlerKeys_=[Z(i,B,this.handleBrowserEvent,this),Z(i,V,this.handleBrowserEvent,this)],this.handleResize_||(this.handleResize_=this.updateSize.bind(this),window.addEventListener(W,this.handleResize_,!1))}else this.renderer_&&(clearTimeout(this.postRenderTimeoutHandle_),this.postRenderTimeoutHandle_=void 0,this.postRenderFunctions_.length=0,this.renderer_.dispose(),this.renderer_=null),this.animationDelayKey_&&(cancelAnimationFrame(this.animationDelayKey_),this.animationDelayKey_=void 0);this.updateSize()},e.prototype.handleTileChange_=function(){this.render()},e.prototype.handleViewPropertyChanged_=function(){this.render()},e.prototype.handleViewChanged_=function(){this.viewPropertyListenerKey_&&(H(this.viewPropertyListenerKey_),this.viewPropertyListenerKey_=null),this.viewChangeListenerKey_&&(H(this.viewChangeListenerKey_),this.viewChangeListenerKey_=null);var t=this.getView();t&&(this.updateViewportSize_(),this.viewPropertyListenerKey_=Z(t,h,this.handleViewPropertyChanged_,this),this.viewChangeListenerKey_=Z(t,F,this.handleViewPropertyChanged_,this),t.resolveConstraints(0)),this.render()},e.prototype.handleLayerGroupChanged_=function(){this.layerGroupPropertyListenerKeys_&&(this.layerGroupPropertyListenerKeys_.forEach(H),this.layerGroupPropertyListenerKeys_=null);var t=this.getLayerGroup();t&&(this.layerGroupPropertyListenerKeys_=[Z(t,h,this.render,this),Z(t,F,this.render,this)]),this.render()},e.prototype.isRendered=function(){return!!this.frameState_},e.prototype.renderSync=function(){this.animationDelayKey_&&cancelAnimationFrame(this.animationDelayKey_),this.animationDelay_()},e.prototype.redrawText=function(){for(var t=this.getLayerGroup().getLayerStatesArray(),e=0,r=t.length;e<r;++e){var n=t[e].layer;n.hasRenderer()&&n.getRenderer().handleFontsChanged()}},e.prototype.render=function(){this.renderer_&&void 0===this.animationDelayKey_&&(this.animationDelayKey_=requestAnimationFrame(this.animationDelay_))},e.prototype.removeControl=function(t){return this.getControls().remove(t)},e.prototype.removeInteraction=function(t){return this.getInteractions().remove(t)},e.prototype.removeLayer=function(t){return this.getLayerGroup().getLayers().remove(t)},e.prototype.removeOverlay=function(t){return this.getOverlays().remove(t)},e.prototype.renderFrame_=function(t){var e=this,r=this.getSize(),n=this.getView(),i=this.frameState_,o=null;if(void 0!==r&&Ps(r)&&n&&n.isDef()){var a=n.getHints(this.frameState_?this.frameState_.viewHints:void 0),s=n.getState();o={animate:!1,coordinateToPixelTransform:this.coordinateToPixelTransform_,declutterTree:null,extent:Se(s.center,s.resolution,s.rotation,r),index:this.frameIndex_++,layerIndex:0,layerStatesArray:this.getLayerGroup().getLayerStatesArray(),pixelRatio:this.pixelRatio_,pixelToCoordinateTransform:this.pixelToCoordinateTransform_,postRenderFunctions:[],size:r,tileQueue:this.tileQueue_,time:t,usedTiles:{},viewState:s,viewHints:a,wantedTiles:{}}}if(this.frameState_=o,this.renderer_.renderFrame(o),o){if(o.animate&&this.render(),Array.prototype.push.apply(this.postRenderFunctions_,o.postRenderFunctions),i)(!this.previousExtent_||!Ie(this.previousExtent_)&&!ue(o.extent,this.previousExtent_))&&(this.dispatchEvent(new ja(Xa,this,i)),this.previousExtent_=oe(this.previousExtent_));this.previousExtent_&&!o.viewHints[ns]&&!o.viewHints[is]&&!ue(o.extent,this.previousExtent_)&&(this.dispatchEvent(new ja(Za,this,o)),$t(o.extent,this.previousExtent_))}this.dispatchEvent(new ja(qa,this,o)),this.postRenderTimeoutHandle_||(this.postRenderTimeoutHandle_=setTimeout((function(){e.postRenderTimeoutHandle_=void 0,e.handlePostRender()}),0))},e.prototype.setLayerGroup=function(t){this.set(Ka,t)},e.prototype.setSize=function(t){this.set(Ha,t)},e.prototype.setTarget=function(t){this.set($a,t)},e.prototype.setView=function(t){this.set(Ja,t)},e.prototype.updateSize=function(){var t=this.getTargetElement();if(t){var e=getComputedStyle(t);this.setSize([t.offsetWidth-parseFloat(e.borderLeftWidth)-parseFloat(e.paddingLeft)-parseFloat(e.paddingRight)-parseFloat(e.borderRightWidth),t.offsetHeight-parseFloat(e.borderTopWidth)-parseFloat(e.paddingTop)-parseFloat(e.paddingBottom)-parseFloat(e.borderBottomWidth)])}else this.setSize(void 0);this.updateViewportSize_()},e.prototype.updateViewportSize_=function(){var t=this.getView();if(t){var e=void 0,r=getComputedStyle(this.viewport_);r.width&&r.height&&(e=[parseInt(r.width,10),parseInt(r.height,10)]),t.setViewportSize(e)}},e}(ot),Fs=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),As=function(t){function e(e){var r=t.call(this)||this,n=e.element;return!n||e.target||n.style.pointerEvents||(n.style.pointerEvents="auto"),r.element=n||null,r.target_=null,r.map_=null,r.listenerKeys=[],e.render&&(r.render=e.render),e.target&&r.setTarget(e.target),r}return Fs(e,t),e.prototype.disposeInternal=function(){fo(this.element),t.prototype.disposeInternal.call(this)},e.prototype.getMap=function(){return this.map_},e.prototype.setMap=function(t){this.map_&&fo(this.element);for(var e=0,r=this.listenerKeys.length;e<r;++e)H(this.listenerKeys[e]);(this.listenerKeys.length=0,this.map_=t,this.map_)&&((this.target_?this.target_:t.getOverlayContainerStopEvent()).appendChild(this.element),this.render!==T&&this.listenerKeys.push(Z(t,qa,this.render,this)),t.render())},e.prototype.render=function(t){},e.prototype.setTarget=function(t){this.target_="string"==typeof t?document.getElementById(t):t},e}(ot),ks=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),js=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,{element:document.createElement("div"),render:n.render,target:n.target})||this).ulElement_=document.createElement("ul"),r.collapsed_=void 0===n.collapsed||n.collapsed,r.userCollapsed_=r.collapsed_,r.overrideCollapsible_=void 0!==n.collapsible,r.collapsible_=void 0===n.collapsible||n.collapsible,r.collapsible_||(r.collapsed_=!1);var i=void 0!==n.className?n.className:"ol-attribution",o=void 0!==n.tipLabel?n.tipLabel:"Attributions",a=void 0!==n.expandClassName?n.expandClassName:i+"-expand",s=void 0!==n.collapseLabel?n.collapseLabel:"»",l=void 0!==n.collapseClassName?n.collapseClassName:i+"-collpase";"string"==typeof s?(r.collapseLabel_=document.createElement("span"),r.collapseLabel_.textContent=s,r.collapseLabel_.className=l):r.collapseLabel_=s;var u=void 0!==n.label?n.label:"i";"string"==typeof u?(r.label_=document.createElement("span"),r.label_.textContent=u,r.label_.className=a):r.label_=u;var c=r.collapsible_&&!r.collapsed_?r.collapseLabel_:r.label_,h=document.createElement("button");h.setAttribute("type","button"),h.title=o,h.appendChild(c),h.addEventListener(N,r.handleClick_.bind(r),!1);var p=i+" ol-unselectable ol-control"+(r.collapsed_&&r.collapsible_?" ol-collapsed":"")+(r.collapsible_?"":" ol-uncollapsible"),f=r.element;return f.className=p,f.appendChild(r.ulElement_),f.appendChild(h),r.renderedAttributions_=[],r.renderedVisible_=!0,r}return ks(e,t),e.prototype.collectSourceAttributions_=function(t){for(var e={},r=[],n=!0,i=t.layerStatesArray,o=0,a=i.length;o<a;++o){var s=i[o];if(ra(s,t.viewState)){var l=s.layer.getSource();if(l){var u=l.getAttributions();if(u){var c=u(t);if(c)if(n=n&&!1!==l.getAttributionsCollapsible(),Array.isArray(c))for(var h=0,p=c.length;h<p;++h)c[h]in e||(r.push(c[h]),e[c[h]]=!0);else c in e||(r.push(c),e[c]=!0)}}}}return this.overrideCollapsible_||this.setCollapsible(n),r},e.prototype.updateElement_=function(t){if(t){var e=this.collectSourceAttributions_(t),r=e.length>0;if(this.renderedVisible_!=r&&(this.element.style.display=r?"":"none",this.renderedVisible_=r),!b(e,this.renderedAttributions_)){go(this.ulElement_);for(var n=0,i=e.length;n<i;++n){var o=document.createElement("li");o.innerHTML=e[n],this.ulElement_.appendChild(o)}this.renderedAttributions_=e}}else this.renderedVisible_&&(this.element.style.display="none",this.renderedVisible_=!1)},e.prototype.handleClick_=function(t){t.preventDefault(),this.handleToggle_(),this.userCollapsed_=this.collapsed_},e.prototype.handleToggle_=function(){this.element.classList.toggle("ol-collapsed"),this.collapsed_?po(this.collapseLabel_,this.label_):po(this.label_,this.collapseLabel_),this.collapsed_=!this.collapsed_},e.prototype.getCollapsible=function(){return this.collapsible_},e.prototype.setCollapsible=function(t){this.collapsible_!==t&&(this.collapsible_=t,this.element.classList.toggle("ol-uncollapsible"),this.userCollapsed_&&this.handleToggle_())},e.prototype.setCollapsed=function(t){this.userCollapsed_=t,this.collapsible_&&this.collapsed_!==t&&this.handleToggle_()},e.prototype.getCollapsed=function(){return this.collapsed_},e.prototype.render=function(t){this.updateElement_(t.frameState)},e}(As),Ns=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Ds=function(t){function e(e){var r=this,n=e||{};r=t.call(this,{element:document.createElement("div"),render:n.render,target:n.target})||this;var i=void 0!==n.className?n.className:"ol-rotate",o=void 0!==n.label?n.label:"⇧",a=void 0!==n.compassClassName?n.compassClassName:"ol-compass";r.label_=null,"string"==typeof o?(r.label_=document.createElement("span"),r.label_.className=a,r.label_.textContent=o):(r.label_=o,r.label_.classList.add(a));var s=n.tipLabel?n.tipLabel:"Reset rotation",l=document.createElement("button");l.className=i+"-reset",l.setAttribute("type","button"),l.title=s,l.appendChild(r.label_),l.addEventListener(N,r.handleClick_.bind(r),!1);var u=i+" ol-unselectable ol-control",c=r.element;return c.className=u,c.appendChild(l),r.callResetNorth_=n.resetNorth?n.resetNorth:void 0,r.duration_=void 0!==n.duration?n.duration:250,r.autoHide_=void 0===n.autoHide||n.autoHide,r.rotation_=void 0,r.autoHide_&&r.element.classList.add("ol-hidden"),r}return Ns(e,t),e.prototype.handleClick_=function(t){t.preventDefault(),void 0!==this.callResetNorth_?this.callResetNorth_():this.resetNorth_()},e.prototype.resetNorth_=function(){var t=this.getMap().getView();if(t){var e=t.getRotation();void 0!==e&&(this.duration_>0&&e%(2*Math.PI)!=0?t.animate({rotation:0,duration:this.duration_,easing:io}):t.setRotation(0))}},e.prototype.render=function(t){var e=t.frameState;if(e){var r=e.viewState.rotation;if(r!=this.rotation_){var n="rotate("+r+"rad)";if(this.autoHide_){var i=this.element.classList.contains("ol-hidden");i||0!==r?i&&0!==r&&this.element.classList.remove("ol-hidden"):this.element.classList.add("ol-hidden")}this.label_.style.transform=n}this.rotation_=r}},e}(As),Gs=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),zs=function(t){function e(e){var r=this,n=e||{};r=t.call(this,{element:document.createElement("div"),target:n.target})||this;var i=void 0!==n.className?n.className:"ol-zoom",o=void 0!==n.delta?n.delta:1,a=void 0!==n.zoomInClassName?n.zoomInClassName:i+"-in",s=void 0!==n.zoomOutClassName?n.zoomOutClassName:i+"-out",l=void 0!==n.zoomInLabel?n.zoomInLabel:"+",u=void 0!==n.zoomOutLabel?n.zoomOutLabel:"−",c=void 0!==n.zoomInTipLabel?n.zoomInTipLabel:"Zoom in",h=void 0!==n.zoomOutTipLabel?n.zoomOutTipLabel:"Zoom out",p=document.createElement("button");p.className=a,p.setAttribute("type","button"),p.title=c,p.appendChild("string"==typeof l?document.createTextNode(l):l),p.addEventListener(N,r.handleClick_.bind(r,o),!1);var f=document.createElement("button");f.className=s,f.setAttribute("type","button"),f.title=h,f.appendChild("string"==typeof u?document.createTextNode(u):u),f.addEventListener(N,r.handleClick_.bind(r,-o),!1);var d=i+" ol-unselectable ol-control",g=r.element;return g.className=d,g.appendChild(p),g.appendChild(f),r.duration_=void 0!==n.duration?n.duration:250,r}return Gs(e,t),e.prototype.handleClick_=function(t,e){e.preventDefault(),this.zoomByDelta_(t)},e.prototype.zoomByDelta_=function(t){var e=this.getMap().getView();if(e){var r=e.getZoom();if(void 0!==r){var n=e.getConstrainedZoom(r+t);this.duration_>0?(e.getAnimating()&&e.cancelAnimations(),e.animate({zoom:n,duration:this.duration_,easing:io})):e.setZoom(n)}}},e}(As);function Us(t){var e=t||{},r=new ht;return(void 0===e.zoom||e.zoom)&&r.push(new zs(e.zoomOptions)),(void 0===e.rotate||e.rotate)&&r.push(new Ds(e.rotateOptions)),(void 0===e.attribution||e.attribution)&&r.push(new js(e.attributionOptions)),r}var Bs="active",Vs=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Ys(t,e,r){var n=t.getCenterInternal();if(n){var i=[n[0]+e[0],n[1]+e[1]];t.animateInternal({duration:void 0!==r?r:250,easing:ao,center:t.getConstrainedCenter(i)})}}function Ws(t,e,r,n){var i=t.getZoom();if(void 0!==i){var o=t.getConstrainedZoom(i+e),a=t.getResolutionForZoom(o);t.getAnimating()&&t.cancelAnimations(),t.animate({resolution:a,anchor:r,duration:void 0!==n?n:250,easing:io})}}var qs=function(t){function e(e){var r=t.call(this)||this;return e&&e.handleEvent&&(r.handleEvent=e.handleEvent),r.map_=null,r.setActive(!0),r}return Vs(e,t),e.prototype.getActive=function(){return this.get(Bs)},e.prototype.getMap=function(){return this.map_},e.prototype.handleEvent=function(t){return!0},e.prototype.setActive=function(t){this.set(Bs,t)},e.prototype.setMap=function(t){this.map_=t},e}(ot),Xs=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Zs=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.delta_=n.delta?n.delta:1,r.duration_=void 0!==n.duration?n.duration:250,r}return Xs(e,t),e.prototype.handleEvent=function(t){var e=!1;if(t.type==Ga.DBLCLICK){var r=t.originalEvent,n=t.map,i=t.coordinate,o=r.shiftKey?-this.delta_:this.delta_;Ws(n.getView(),o,i,this.duration_),r.preventDefault(),e=!0}return!e},e}(qs),Ks=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Hs(t){for(var e=t.length,r=0,n=0,i=0;i<e;i++)r+=t[i].clientX,n+=t[i].clientY;return[r/e,n/e]}var $s=function(t){function e(e){var r=this,n=e||{};return r=t.call(this,n)||this,n.handleDownEvent&&(r.handleDownEvent=n.handleDownEvent),n.handleDragEvent&&(r.handleDragEvent=n.handleDragEvent),n.handleMoveEvent&&(r.handleMoveEvent=n.handleMoveEvent),n.handleUpEvent&&(r.handleUpEvent=n.handleUpEvent),n.stopDown&&(r.stopDown=n.stopDown),r.handlingDownUpSequence=!1,r.trackedPointers_={},r.targetPointers=[],r}return Ks(e,t),e.prototype.getPointerCount=function(){return this.targetPointers.length},e.prototype.handleDownEvent=function(t){return!1},e.prototype.handleDragEvent=function(t){},e.prototype.handleEvent=function(t){if(!t.originalEvent)return!0;var e=!1;if(this.updateTrackedPointers_(t),this.handlingDownUpSequence){if(t.type==Ga.POINTERDRAG)this.handleDragEvent(t),t.originalEvent.preventDefault();else if(t.type==Ga.POINTERUP){var r=this.handleUpEvent(t);this.handlingDownUpSequence=r&&this.targetPointers.length>0}}else if(t.type==Ga.POINTERDOWN){var n=this.handleDownEvent(t);this.handlingDownUpSequence=n,e=this.stopDown(n)}else t.type==Ga.POINTERMOVE&&this.handleMoveEvent(t);return!e},e.prototype.handleMoveEvent=function(t){},e.prototype.handleUpEvent=function(t){return!1},e.prototype.stopDown=function(t){return t},e.prototype.updateTrackedPointers_=function(t){if(function(t){var e=t.type;return e===Ga.POINTERDOWN||e===Ga.POINTERDRAG||e===Ga.POINTERUP}(t)){var e=t.originalEvent,r=e.pointerId.toString();t.type==Ga.POINTERUP?delete this.trackedPointers_[r]:(t.type==Ga.POINTERDOWN||r in this.trackedPointers_)&&(this.trackedPointers_[r]=e),this.targetPointers=R(this.trackedPointers_)}},e}(qs);function Js(t){var e=arguments;return function(t){for(var r=!0,n=0,i=e.length;n<i&&(r=r&&e[n](t));++n);return r}}var Qs=function(t){var e=t.originalEvent;return e.altKey&&!(e.metaKey||e.ctrlKey)&&!e.shiftKey},tl=function(t){var e=t.originalEvent;return e.altKey&&!(e.metaKey||e.ctrlKey)&&e.shiftKey},el=function(t){return t.target.getTargetElement().contains(document.activeElement)},rl=function(t){return!t.map.getTargetElement().hasAttribute("tabindex")||el(t)},nl=S,il=function(t){var e=t.originalEvent;return 0==e.button&&!(Ui&&Bi&&e.ctrlKey)},ol=E,al=function(t){return t.type==Ga.SINGLECLICK},sl=function(t){var e=t.originalEvent;return!e.altKey&&!(e.metaKey||e.ctrlKey)&&!e.shiftKey},ll=function(t){var e=t.originalEvent;return!e.altKey&&!(e.metaKey||e.ctrlKey)&&e.shiftKey},ul=function(t){var e=t.originalEvent.target.tagName;return"INPUT"!==e&&"SELECT"!==e&&"TEXTAREA"!==e},cl=function(t){var e=t.originalEvent;return pt(void 0!==e,56),"mouse"==e.pointerType},hl=function(t){var e=t.originalEvent;return pt(void 0!==e,56),e.isPrimary&&0===e.button},pl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),fl=function(t){function e(e){var r=t.call(this,{stopDown:E})||this,n=e||{};r.kinetic_=n.kinetic,r.lastCentroid=null,r.lastPointersCount_,r.panning_=!1;var i=n.condition?n.condition:Js(sl,hl);return r.condition_=n.onFocusOnly?Js(rl,i):i,r.noKinetic_=!1,r}return pl(e,t),e.prototype.handleDragEvent=function(t){this.panning_||(this.panning_=!0,this.getMap().getView().beginInteraction());var e=this.targetPointers,r=Hs(e);if(e.length==this.lastPointersCount_){if(this.kinetic_&&this.kinetic_.update(r[0],r[1]),this.lastCentroid){var n=[this.lastCentroid[0]-r[0],r[1]-this.lastCentroid[1]],i=t.map.getView();Pr(n,i.getResolution()),Or(n,i.getRotation()),i.adjustCenterInternal(n)}}else this.kinetic_&&this.kinetic_.begin();this.lastCentroid=r,this.lastPointersCount_=e.length,t.originalEvent.preventDefault()},e.prototype.handleUpEvent=function(t){var e=t.map,r=e.getView();if(0===this.targetPointers.length){if(!this.noKinetic_&&this.kinetic_&&this.kinetic_.end()){var n=this.kinetic_.getDistance(),i=this.kinetic_.getAngle(),o=r.getCenterInternal(),a=e.getPixelFromCoordinateInternal(o),s=e.getCoordinateFromPixelInternal([a[0]-n*Math.cos(i),a[1]-n*Math.sin(i)]);r.animateInternal({center:r.getConstrainedCenter(s),duration:500,easing:io})}return this.panning_&&(this.panning_=!1,r.endInteraction()),!1}return this.kinetic_&&this.kinetic_.begin(),this.lastCentroid=null,!0},e.prototype.handleDownEvent=function(t){if(this.targetPointers.length>0&&this.condition_(t)){var e=t.map.getView();return this.lastCentroid=null,e.getAnimating()&&e.cancelAnimations(),this.kinetic_&&this.kinetic_.begin(),this.noKinetic_=this.targetPointers.length>1,!0}return!1},e}($s),dl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),gl=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,{stopDown:E})||this).condition_=n.condition?n.condition:tl,r.lastAngle_=void 0,r.duration_=void 0!==n.duration?n.duration:250,r}return dl(e,t),e.prototype.handleDragEvent=function(t){if(cl(t)){var e=t.map,r=e.getView();if(r.getConstraints().rotation!==gs){var n=e.getSize(),i=t.pixel,o=Math.atan2(n[1]/2-i[1],i[0]-n[0]/2);if(void 0!==this.lastAngle_){var a=o-this.lastAngle_;r.adjustRotationInternal(-a)}this.lastAngle_=o}}},e.prototype.handleUpEvent=function(t){return!cl(t)||(t.map.getView().endInteraction(this.duration_),!1)},e.prototype.handleDownEvent=function(t){return!!cl(t)&&(!(!il(t)||!this.condition_(t))&&(t.map.getView().beginInteraction(),this.lastAngle_=void 0,!0))},e}($s),yl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ml=function(t){function e(e){var r=t.call(this)||this;return r.geometry_=null,r.element_=document.createElement("div"),r.element_.style.position="absolute",r.element_.style.pointerEvents="auto",r.element_.className="ol-box "+e,r.map_=null,r.startPixel_=null,r.endPixel_=null,r}return yl(e,t),e.prototype.disposeInternal=function(){this.setMap(null)},e.prototype.render_=function(){var t=this.startPixel_,e=this.endPixel_,r=this.element_.style;r.left=Math.min(t[0],e[0])+"px",r.top=Math.min(t[1],e[1])+"px",r.width=Math.abs(e[0]-t[0])+"px",r.height=Math.abs(e[1]-t[1])+"px"},e.prototype.setMap=function(t){if(this.map_){this.map_.getOverlayContainer().removeChild(this.element_);var e=this.element_.style;e.left="inherit",e.top="inherit",e.width="inherit",e.height="inherit"}this.map_=t,this.map_&&this.map_.getOverlayContainer().appendChild(this.element_)},e.prototype.setPixels=function(t,e){this.startPixel_=t,this.endPixel_=e,this.createOrUpdateGeometry(),this.render_()},e.prototype.createOrUpdateGeometry=function(){var t=this.startPixel_,e=this.endPixel_,r=[t,[t[0],e[1]],e,[e[0],t[1]]].map(this.map_.getCoordinateFromPixelInternal,this.map_);r[4]=r[0].slice(),this.geometry_?this.geometry_.setCoordinates([r]):this.geometry_=new fi([r])},e.prototype.getGeometry=function(){return this.geometry_},e}(p),vl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),_l="boxstart",bl="boxdrag",xl="boxend",wl="boxcancel",Sl=function(t){function e(e,r,n){var i=t.call(this,e)||this;return i.coordinate=r,i.mapBrowserEvent=n,i}return vl(e,t),e}(c),El=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.box_=new ml(n.className||"ol-dragbox"),r.minArea_=void 0!==n.minArea?n.minArea:64,n.onBoxEnd&&(r.onBoxEnd=n.onBoxEnd),r.startPixel_=null,r.condition_=n.condition?n.condition:il,r.boxEndCondition_=n.boxEndCondition?n.boxEndCondition:r.defaultBoxEndCondition,r}return vl(e,t),e.prototype.defaultBoxEndCondition=function(t,e,r){var n=r[0]-e[0],i=r[1]-e[1];return n*n+i*i>=this.minArea_},e.prototype.getGeometry=function(){return this.box_.getGeometry()},e.prototype.handleDragEvent=function(t){this.box_.setPixels(this.startPixel_,t.pixel),this.dispatchEvent(new Sl(bl,t.coordinate,t))},e.prototype.handleUpEvent=function(t){this.box_.setMap(null);var e=this.boxEndCondition_(t,this.startPixel_,t.pixel);return e&&this.onBoxEnd(t),this.dispatchEvent(new Sl(e?xl:wl,t.coordinate,t)),!1},e.prototype.handleDownEvent=function(t){return!!this.condition_(t)&&(this.startPixel_=t.pixel,this.box_.setMap(t.map),this.box_.setPixels(this.startPixel_,this.startPixel_),this.dispatchEvent(new Sl(_l,t.coordinate,t)),!0)},e.prototype.onBoxEnd=function(t){},e}($s),Tl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Cl=function(t){function e(e){var r=this,n=e||{},i=n.condition?n.condition:ll;return(r=t.call(this,{condition:i,className:n.className||"ol-dragzoom",minArea:n.minArea})||this).duration_=void 0!==n.duration?n.duration:200,r.out_=void 0!==n.out&&n.out,r}return Tl(e,t),e.prototype.onBoxEnd=function(t){var e=this.getMap(),r=e.getView(),n=e.getSize(),i=this.getGeometry().getExtent();if(this.out_){var o=r.calculateExtentInternal(n),a=se([e.getPixelFromCoordinateInternal(_e(i)),e.getPixelFromCoordinateInternal(Oe(i))]);Me(o,1/r.getResolutionForExtentInternal(a,n)),i=o}var s=r.getConstrainedResolution(r.getResolutionForExtentInternal(i,n)),l=r.getConstrainedCenter(xe(i),s);r.animateInternal({resolution:s,center:l,duration:this.duration_,easing:io})},e}(El),Ol=37,Pl=38,Rl=39,Il=40,Ll=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Ml=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.defaultCondition_=function(t){return sl(t)&&ul(t)},r.condition_=void 0!==n.condition?n.condition:r.defaultCondition_,r.duration_=void 0!==n.duration?n.duration:100,r.pixelDelta_=void 0!==n.pixelDelta?n.pixelDelta:128,r}return Ll(e,t),e.prototype.handleEvent=function(t){var e=!1;if(t.type==B){var r=t.originalEvent,n=r.keyCode;if(this.condition_(t)&&(n==Il||n==Ol||n==Rl||n==Pl)){var i=t.map.getView(),o=i.getResolution()*this.pixelDelta_,a=0,s=0;n==Il?s=-o:n==Ol?a=-o:n==Rl?a=o:s=o;var l=[a,s];Or(l,i.getRotation()),Ys(i,l,this.duration_),r.preventDefault(),e=!0}}return!e},e}(qs),Fl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Al=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.condition_=n.condition?n.condition:ul,r.delta_=n.delta?n.delta:1,r.duration_=void 0!==n.duration?n.duration:100,r}return Fl(e,t),e.prototype.handleEvent=function(t){var e=!1;if(t.type==B||t.type==V){var r=t.originalEvent,n=r.charCode;if(this.condition_(t)&&(n=="+".charCodeAt(0)||n=="-".charCodeAt(0))){var i=t.map,o=n=="+".charCodeAt(0)?this.delta_:-this.delta_;Ws(i.getView(),o,void 0,this.duration_),r.preventDefault(),e=!0}}return!e},e}(qs),kl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),jl="trackpad",Nl="wheel",Dl=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,n)||this).totalDelta_=0,r.lastDelta_=0,r.maxDelta_=void 0!==n.maxDelta?n.maxDelta:1,r.duration_=void 0!==n.duration?n.duration:250,r.timeout_=void 0!==n.timeout?n.timeout:80,r.useAnchor_=void 0===n.useAnchor||n.useAnchor,r.constrainResolution_=void 0!==n.constrainResolution&&n.constrainResolution;var i=n.condition?n.condition:nl;return r.condition_=n.onFocusOnly?Js(rl,i):i,r.lastAnchor_=null,r.startTime_=void 0,r.timeoutId_,r.mode_=void 0,r.trackpadEventGap_=400,r.trackpadTimeoutId_,r.deltaPerZoom_=300,r}return kl(e,t),e.prototype.endInteraction_=function(){this.trackpadTimeoutId_=void 0,this.getMap().getView().endInteraction(void 0,this.lastDelta_?this.lastDelta_>0?1:-1:0,this.lastAnchor_)},e.prototype.handleEvent=function(t){if(!this.condition_(t))return!0;if(t.type!==X)return!0;var e,r=t.map,n=t.originalEvent;if(n.preventDefault(),this.useAnchor_&&(this.lastAnchor_=t.coordinate),t.type==X&&(e=n.deltaY,Gi&&n.deltaMode===WheelEvent.DOM_DELTA_PIXEL&&(e/=Vi),n.deltaMode===WheelEvent.DOM_DELTA_LINE&&(e*=40)),0===e)return!1;this.lastDelta_=e;var i=Date.now();void 0===this.startTime_&&(this.startTime_=i),(!this.mode_||i-this.startTime_>this.trackpadEventGap_)&&(this.mode_=Math.abs(e)<4?jl:Nl);var o=r.getView();if(this.mode_===jl&&!o.getConstrainResolution()&&!this.constrainResolution_)return this.trackpadTimeoutId_?clearTimeout(this.trackpadTimeoutId_):(o.getAnimating()&&o.cancelAnimations(),o.beginInteraction()),this.trackpadTimeoutId_=setTimeout(this.endInteraction_.bind(this),this.timeout_),o.adjustZoom(-e/this.deltaPerZoom_,this.lastAnchor_),this.startTime_=i,!1;this.totalDelta_+=e;var a=Math.max(this.timeout_-(i-this.startTime_),0);return clearTimeout(this.timeoutId_),this.timeoutId_=setTimeout(this.handleWheelZoom_.bind(this,r),a),!1},e.prototype.handleWheelZoom_=function(t){var e=t.getView();e.getAnimating()&&e.cancelAnimations();var r=-Ne(this.totalDelta_,-this.maxDelta_*this.deltaPerZoom_,this.maxDelta_*this.deltaPerZoom_)/this.deltaPerZoom_;(e.getConstrainResolution()||this.constrainResolution_)&&(r=r?r>0?1:-1:0),Ws(e,r,this.lastAnchor_,this.duration_),this.mode_=void 0,this.totalDelta_=0,this.lastAnchor_=null,this.startTime_=void 0,this.timeoutId_=void 0},e.prototype.setMouseAnchor=function(t){this.useAnchor_=t,t||(this.lastAnchor_=null)},e}(qs),Gl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),zl=function(t){function e(e){var r=this,n=e||{},i=n;return i.stopDown||(i.stopDown=E),(r=t.call(this,i)||this).anchor_=null,r.lastAngle_=void 0,r.rotating_=!1,r.rotationDelta_=0,r.threshold_=void 0!==n.threshold?n.threshold:.3,r.duration_=void 0!==n.duration?n.duration:250,r}return Gl(e,t),e.prototype.handleDragEvent=function(t){var e=0,r=this.targetPointers[0],n=this.targetPointers[1],i=Math.atan2(n.clientY-r.clientY,n.clientX-r.clientX);if(void 0!==this.lastAngle_){var o=i-this.lastAngle_;this.rotationDelta_+=o,!this.rotating_&&Math.abs(this.rotationDelta_)>this.threshold_&&(this.rotating_=!0),e=o}this.lastAngle_=i;var a=t.map,s=a.getView();if(s.getConstraints().rotation!==gs){var l=a.getViewport().getBoundingClientRect(),u=Hs(this.targetPointers);u[0]-=l.left,u[1]-=l.top,this.anchor_=a.getCoordinateFromPixelInternal(u),this.rotating_&&(a.render(),s.adjustRotationInternal(e,this.anchor_))}},e.prototype.handleUpEvent=function(t){return!(this.targetPointers.length<2)||(t.map.getView().endInteraction(this.duration_),!1)},e.prototype.handleDownEvent=function(t){if(this.targetPointers.length>=2){var e=t.map;return this.anchor_=null,this.lastAngle_=void 0,this.rotating_=!1,this.rotationDelta_=0,this.handlingDownUpSequence||e.getView().beginInteraction(),!0}return!1},e}($s),Ul=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Bl=function(t){function e(e){var r=this,n=e||{},i=n;return i.stopDown||(i.stopDown=E),(r=t.call(this,i)||this).anchor_=null,r.duration_=void 0!==n.duration?n.duration:400,r.lastDistance_=void 0,r.lastScaleDelta_=1,r}return Ul(e,t),e.prototype.handleDragEvent=function(t){var e=1,r=this.targetPointers[0],n=this.targetPointers[1],i=r.clientX-n.clientX,o=r.clientY-n.clientY,a=Math.sqrt(i*i+o*o);void 0!==this.lastDistance_&&(e=this.lastDistance_/a),this.lastDistance_=a;var s=t.map,l=s.getView();1!=e&&(this.lastScaleDelta_=e);var u=s.getViewport().getBoundingClientRect(),c=Hs(this.targetPointers);c[0]-=u.left,c[1]-=u.top,this.anchor_=s.getCoordinateFromPixelInternal(c),s.render(),l.adjustResolutionInternal(e,this.anchor_)},e.prototype.handleUpEvent=function(t){if(this.targetPointers.length<2){var e=t.map.getView(),r=this.lastScaleDelta_>1?1:-1;return e.endInteraction(this.duration_,r),!1}return!0},e.prototype.handleDownEvent=function(t){if(this.targetPointers.length>=2){var e=t.map;return this.anchor_=null,this.lastDistance_=void 0,this.lastScaleDelta_=1,this.handlingDownUpSequence||e.getView().beginInteraction(),!0}return!1},e}($s);function Vl(t){var e=t||{},r=new ht,n=new _o(-.005,.05,100);return(void 0===e.altShiftDragRotate||e.altShiftDragRotate)&&r.push(new gl),(void 0===e.doubleClickZoom||e.doubleClickZoom)&&r.push(new Zs({delta:e.zoomDelta,duration:e.zoomDuration})),(void 0===e.dragPan||e.dragPan)&&r.push(new fl({onFocusOnly:e.onFocusOnly,kinetic:n})),(void 0===e.pinchRotate||e.pinchRotate)&&r.push(new zl),(void 0===e.pinchZoom||e.pinchZoom)&&r.push(new Bl({duration:e.zoomDuration})),(void 0===e.keyboard||e.keyboard)&&(r.push(new Ml),r.push(new Al({delta:e.zoomDelta,duration:e.zoomDuration}))),(void 0===e.mouseWheelZoom||e.mouseWheelZoom)&&r.push(new Dl({onFocusOnly:e.onFocusOnly,duration:e.zoomDuration})),(void 0===e.shiftDragZoom||e.shiftDragZoom)&&r.push(new Cl({duration:e.zoomDuration})),r}var Yl=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Wl=function(t){function e(e){return(e=O({},e)).controls||(e.controls=Us()),e.interactions||(e.interactions=Vl({onFocusOnly:!0})),t.call(this,e)||this}return Yl(e,t),e.prototype.createRenderer=function(){return new La(this)},e}(Ms),ql="bottom-left",Xl="bottom-center",Zl="bottom-right",Kl="center-left",Hl="center-center",$l="center-right",Jl="top-left",Ql="top-center",tu="top-right",eu=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ru="element",nu="map",iu="offset",ou="position",au="positioning",su=function(t){function e(e){var r=t.call(this)||this;r.options=e,r.id=e.id,r.insertFirst=void 0===e.insertFirst||e.insertFirst,r.stopEvent=void 0===e.stopEvent||e.stopEvent,r.element=document.createElement("div"),r.element.className=void 0!==e.className?e.className:"ol-overlay-container ol-selectable",r.element.style.position="absolute",r.element.style.pointerEvents="auto";var n=e.autoPan;return n&&"object"!=typeof n&&(n={animation:e.autoPanAnimation,margin:e.autoPanMargin}),r.autoPan=n||!1,r.rendered={transform_:"",visible:!0},r.mapPostrenderListenerKey=null,r.addEventListener(it(ru),r.handleElementChanged),r.addEventListener(it(nu),r.handleMapChanged),r.addEventListener(it(iu),r.handleOffsetChanged),r.addEventListener(it(ou),r.handlePositionChanged),r.addEventListener(it(au),r.handlePositioningChanged),void 0!==e.element&&r.setElement(e.element),r.setOffset(void 0!==e.offset?e.offset:[0,0]),r.setPositioning(void 0!==e.positioning?e.positioning:Jl),void 0!==e.position&&r.setPosition(e.position),r}return eu(e,t),e.prototype.getElement=function(){return this.get(ru)},e.prototype.getId=function(){return this.id},e.prototype.getMap=function(){return this.get(nu)},e.prototype.getOffset=function(){return this.get(iu)},e.prototype.getPosition=function(){return this.get(ou)},e.prototype.getPositioning=function(){return this.get(au)},e.prototype.handleElementChanged=function(){go(this.element);var t=this.getElement();t&&this.element.appendChild(t)},e.prototype.handleMapChanged=function(){this.mapPostrenderListenerKey&&(fo(this.element),H(this.mapPostrenderListenerKey),this.mapPostrenderListenerKey=null);var t=this.getMap();if(t){this.mapPostrenderListenerKey=Z(t,qa,this.render,this),this.updatePixelPosition();var e=this.stopEvent?t.getOverlayContainerStopEvent():t.getOverlayContainer();this.insertFirst?e.insertBefore(this.element,e.childNodes[0]||null):e.appendChild(this.element),this.performAutoPan()}},e.prototype.render=function(){this.updatePixelPosition()},e.prototype.handleOffsetChanged=function(){this.updatePixelPosition()},e.prototype.handlePositionChanged=function(){this.updatePixelPosition(),this.performAutoPan()},e.prototype.handlePositioningChanged=function(){this.updatePixelPosition()},e.prototype.setElement=function(t){this.set(ru,t)},e.prototype.setMap=function(t){this.set(nu,t)},e.prototype.setOffset=function(t){this.set(iu,t)},e.prototype.setPosition=function(t){this.set(ou,t)},e.prototype.performAutoPan=function(){this.autoPan&&this.panIntoView(this.autoPan)},e.prototype.panIntoView=function(t){var e=this.getMap();if(e&&e.getTargetElement()&&this.get(ou)){var r=this.getRect(e.getTargetElement(),e.getSize()),n=this.getElement(),i=this.getRect(n,[co(n),ho(n)]),o=t||{},a=void 0===o.margin?20:o.margin;if(!te(r,i)){var s=i[0]-r[0],l=r[2]-i[2],u=i[1]-r[1],c=r[3]-i[3],h=[0,0];if(s<0?h[0]=s-a:l<0&&(h[0]=Math.abs(l)+a),u<0?h[1]=u-a:c<0&&(h[1]=Math.abs(c)+a),0!==h[0]||0!==h[1]){var p=e.getView().getCenterInternal(),f=e.getPixelFromCoordinateInternal(p);if(!f)return;var d=[f[0]+h[0],f[1]+h[1]],g=o.animation||{};e.getView().animateInternal({center:e.getCoordinateFromPixelInternal(d),duration:g.duration,easing:g.easing})}}}},e.prototype.getRect=function(t,e){var r=t.getBoundingClientRect(),n=r.left+window.pageXOffset,i=r.top+window.pageYOffset;return[n,i,n+e[0],i+e[1]]},e.prototype.setPositioning=function(t){this.set(au,t)},e.prototype.setVisible=function(t){this.rendered.visible!==t&&(this.element.style.display=t?"":"none",this.rendered.visible=t)},e.prototype.updatePixelPosition=function(){var t=this.getMap(),e=this.getPosition();if(t&&t.isRendered()&&e){var r=t.getPixelFromCoordinate(e),n=t.getSize();this.updateRenderedPosition(r,n)}else this.setVisible(!1)},e.prototype.updateRenderedPosition=function(t,e){var r=this.element.style,n=this.getOffset(),i=this.getPositioning();this.setVisible(!0);var o=Math.round(t[0]+n[0])+"px",a=Math.round(t[1]+n[1])+"px",s="0%",l="0%";i==Zl||i==$l||i==tu?s="-100%":i!=Xl&&i!=Hl&&i!=Ql||(s="-50%"),i==ql||i==Xl||i==Zl?l="-100%":i!=Kl&&i!=Hl&&i!=$l||(l="-50%");var u="translate("+s+", "+l+") translate("+o+", "+a+")";this.rendered.transform_!=u&&(this.rendered.transform_=u,r.transform=u,r.msTransform=u)},e.prototype.getOptions=function(){return this.options},e}(ot),lu=function(){function t(t){this.highWaterMark=void 0!==t?t:2048,this.count_=0,this.entries_={},this.oldest_=null,this.newest_=null}return t.prototype.canExpireCache=function(){return this.highWaterMark>0&&this.getCount()>this.highWaterMark},t.prototype.clear=function(){this.count_=0,this.entries_={},this.oldest_=null,this.newest_=null},t.prototype.containsKey=function(t){return this.entries_.hasOwnProperty(t)},t.prototype.forEach=function(t){for(var e=this.oldest_;e;)t(e.value_,e.key_,this),e=e.newer},t.prototype.get=function(t,e){var r=this.entries_[t];return pt(void 0!==r,15),r===this.newest_||(r===this.oldest_?(this.oldest_=this.oldest_.newer,this.oldest_.older=null):(r.newer.older=r.older,r.older.newer=r.newer),r.newer=null,r.older=this.newest_,this.newest_.newer=r,this.newest_=r),r.value_},t.prototype.remove=function(t){var e=this.entries_[t];return pt(void 0!==e,15),e===this.newest_?(this.newest_=e.older,this.newest_&&(this.newest_.newer=null)):e===this.oldest_?(this.oldest_=e.newer,this.oldest_&&(this.oldest_.older=null)):(e.newer.older=e.older,e.older.newer=e.newer),delete this.entries_[t],--this.count_,e.value_},t.prototype.getCount=function(){return this.count_},t.prototype.getKeys=function(){var t,e=new Array(this.count_),r=0;for(t=this.newest_;t;t=t.older)e[r++]=t.key_;return e},t.prototype.getValues=function(){var t,e=new Array(this.count_),r=0;for(t=this.newest_;t;t=t.older)e[r++]=t.value_;return e},t.prototype.peekLast=function(){return this.oldest_.value_},t.prototype.peekLastKey=function(){return this.oldest_.key_},t.prototype.peekFirstKey=function(){return this.newest_.key_},t.prototype.pop=function(){var t=this.oldest_;return delete this.entries_[t.key_],t.newer&&(t.newer.older=null),this.oldest_=t.newer,this.oldest_||(this.newest_=null),--this.count_,t.value_},t.prototype.replace=function(t,e){this.get(t),this.entries_[t].value_=e},t.prototype.set=function(t,e){pt(!(t in this.entries_),16);var r={key_:t,newer:null,older:this.newest_,value_:e};this.newest_?this.newest_.newer=r:this.oldest_=r,this.newest_=r,this.entries_[t]=r,++this.count_},t.prototype.setSize=function(t){this.highWaterMark=t},t}();function uu(t,e,r,n){return void 0!==n?(n[0]=t,n[1]=e,n[2]=r,n):[t,e,r]}function cu(t,e,r){return t+"/"+e+"/"+r}function hu(t){return cu(t[0],t[1],t[2])}function pu(t){return t.split("/").map(Number)}function fu(t){return(t[1]<<t[0])+t[2]}function du(t,e){var r=t[0],n=t[1],i=t[2];if(e.getMinZoom()>r||r>e.getMaxZoom())return!1;var o=e.getFullTileRange(r);return!o||o.containsXY(n,i)}var gu=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),yu=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return gu(e,t),e.prototype.expireCache=function(t){for(;this.canExpireCache();){if(this.peekLast().getKey()in t)break;this.pop().release()}},e.prototype.pruneExceptNewestZ=function(){if(0!==this.getCount()){var t=pu(this.peekFirstKey())[0];this.forEach(function(e){e.tileCoord[0]!==t&&(this.remove(hu(e.tileCoord)),e.release())}.bind(this))}},e}(lu),mu=function(){function t(t,e,r,n){this.minX=t,this.maxX=e,this.minY=r,this.maxY=n}return t.prototype.contains=function(t){return this.containsXY(t[1],t[2])},t.prototype.containsTileRange=function(t){return this.minX<=t.minX&&t.maxX<=this.maxX&&this.minY<=t.minY&&t.maxY<=this.maxY},t.prototype.containsXY=function(t,e){return this.minX<=t&&t<=this.maxX&&this.minY<=e&&e<=this.maxY},t.prototype.equals=function(t){return this.minX==t.minX&&this.minY==t.minY&&this.maxX==t.maxX&&this.maxY==t.maxY},t.prototype.extend=function(t){t.minX<this.minX&&(this.minX=t.minX),t.maxX>this.maxX&&(this.maxX=t.maxX),t.minY<this.minY&&(this.minY=t.minY),t.maxY>this.maxY&&(this.maxY=t.maxY)},t.prototype.getHeight=function(){return this.maxY-this.minY+1},t.prototype.getSize=function(){return[this.getWidth(),this.getHeight()]},t.prototype.getWidth=function(){return this.maxX-this.minX+1},t.prototype.intersects=function(t){return this.minX<=t.maxX&&this.maxX>=t.minX&&this.minY<=t.maxY&&this.maxY>=t.minY},t}();function vu(t,e,r,n,i){return void 0!==i?(i.minX=t,i.maxX=e,i.minY=r,i.maxY=n,i):new mu(t,e,r,n)}var _u=mu,bu=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),xu=[],wu=function(t){function e(e,r,n,i){var o=t.call(this,e,r,{transition:0})||this;return o.context_={},o.executorGroups={},o.declutterExecutorGroups={},o.loadingSourceTiles=0,o.errorSourceTileKeys={},o.hitDetectionImageData={},o.replayState_={},o.sourceTiles=null,o.wantedResolution,o.getSourceTiles=i.bind(void 0,o),o.sourceZ=-1,o.hifi=!1,o.wrappedTileCoord=n,o}return bu(e,t),e.prototype.getContext=function(t){var e=o(t);return e in this.context_||(this.context_[e]=uo(1,1,xu)),this.context_[e]},e.prototype.hasContext=function(t){return o(t)in this.context_},e.prototype.getImage=function(t){return this.hasContext(t)?this.getContext(t).canvas:null},e.prototype.getReplayState=function(t){var e=o(t);return e in this.replayState_||(this.replayState_[e]={dirty:!1,renderedRenderOrder:null,renderedResolution:NaN,renderedRevision:-1,renderedTileResolution:NaN,renderedTileRevision:-1,renderedZ:-1,renderedTileZ:-1}),this.replayState_[e]},e.prototype.load=function(){this.getSourceTiles()},e.prototype.release=function(){for(var e in this.context_)xu.push(this.context_[e].canvas),delete this.context_[e];t.prototype.release.call(this)},e}(lo),Su=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Eu=function(t){function e(e,r,n,i,o,a){var s=t.call(this,e,r,a)||this;return s.extent=null,s.format_=i,s.features_=null,s.loader_,s.projection=null,s.resolution,s.tileLoadFunction_=o,s.url_=n,s.key=n,s}return Su(e,t),e.prototype.getFormat=function(){return this.format_},e.prototype.getFeatures=function(){return this.features_},e.prototype.load=function(){this.state==Ji&&(this.setState(Qi),this.tileLoadFunction_(this,this.url_),this.loader_&&this.loader_(this.extent,this.resolution,this.projection))},e.prototype.onLoad=function(t,e){this.setFeatures(t)},e.prototype.onError=function(){this.setState(eo)},e.prototype.setFeatures=function(t){this.features_=t,this.setState(to)},e.prototype.setLoader=function(t){this.loader_=t},e}(lo);function Tu(t){return Array.isArray(t)?Ro(t):t}var Cu="arraybuffer",Ou="json",Pu="text",Ru="xml",Iu=!1;function Lu(t,e,r,n,i,o,a){var s=new XMLHttpRequest;s.open("GET","function"==typeof t?t(r,n,i):t,!0),e.getType()==Cu&&(s.responseType="arraybuffer"),s.withCredentials=Iu,s.onload=function(t){if(!s.status||s.status>=200&&s.status<300){var n=e.getType(),l=void 0;n==Ou||n==Pu?l=s.responseText:n==Ru?(l=s.responseXML)||(l=(new DOMParser).parseFromString(s.responseText,"application/xml")):n==Cu&&(l=s.response),l?o(e.readFeatures(l,{extent:r,featureProjection:i}),e.readProjection(l)):a()}else a()},s.onerror=a,s.send()}function Mu(t,e){return function(r,n,i,o,a){var s=this;Lu(t,e,r,n,i,(function(t,e){void 0!==o&&o(t),s.addFeatures(t)}),a||T)}}function Fu(t,e){return[[-1/0,-1/0,1/0,1/0]]}function Au(t,e,r,n){var i=document.createElement("script"),a="olc_"+o(e);function s(){delete window[a],i.parentNode.removeChild(i)}i.async=!0,i.src=t+(-1==t.indexOf("?")?"?":"&")+(n||"callback")+"="+a;var l=setTimeout((function(){s(),r&&r()}),1e4);window[a]=function(t){clearTimeout(l),s(),e(t)},document.getElementsByTagName("head")[0].appendChild(i)}var ku=function(){function t(){}return t.prototype.drawCustom=function(t,e,r){},t.prototype.drawGeometry=function(t){},t.prototype.setStyle=function(t){},t.prototype.drawCircle=function(t,e){},t.prototype.drawFeature=function(t,e){},t.prototype.drawGeometryCollection=function(t,e){},t.prototype.drawLineString=function(t,e){},t.prototype.drawMultiLineString=function(t,e){},t.prototype.drawMultiPoint=function(t,e){},t.prototype.drawMultiPolygon=function(t,e){},t.prototype.drawPoint=function(t,e){},t.prototype.drawPolygon=function(t,e){},t.prototype.drawText=function(t,e){},t.prototype.setFillStrokeStyle=function(t,e){},t.prototype.setImageStyle=function(t,e){},t.prototype.setTextStyle=function(t,e){},t}(),ju=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Nu=function(t){function e(e,r,n,i,o,a,s){var l=t.call(this)||this;return l.context_=e,l.pixelRatio_=r,l.extent_=n,l.transform_=i,l.viewRotation_=o,l.squaredTolerance_=a,l.userTransform_=s,l.contextFillState_=null,l.contextStrokeState_=null,l.contextTextState_=null,l.fillState_=null,l.strokeState_=null,l.image_=null,l.imageAnchorX_=0,l.imageAnchorY_=0,l.imageHeight_=0,l.imageOpacity_=0,l.imageOriginX_=0,l.imageOriginY_=0,l.imageRotateWithView_=!1,l.imageRotation_=0,l.imageScale_=[0,0],l.imageWidth_=0,l.text_="",l.textOffsetX_=0,l.textOffsetY_=0,l.textRotateWithView_=!1,l.textRotation_=0,l.textScale_=[0,0],l.textFillState_=null,l.textStrokeState_=null,l.textState_=null,l.pixelCoordinates_=[],l.tmpLocalTransform_=[1,0,0,1,0,0],l}return ju(e,t),e.prototype.drawImages_=function(t,e,r,n){if(this.image_){var i=ln(t,e,r,2,this.transform_,this.pixelCoordinates_),o=this.context_,a=this.tmpLocalTransform_,s=o.globalAlpha;1!=this.imageOpacity_&&(o.globalAlpha=s*this.imageOpacity_);var l=this.imageRotation_;this.imageRotateWithView_&&(l+=this.viewRotation_);for(var u=0,c=i.length;u<c;u+=2){var h=i[u]-this.imageAnchorX_,p=i[u+1]-this.imageAnchorY_;if(0!==l||1!=this.imageScale_[0]||1!=this.imageScale_[1]){var f=h+this.imageAnchorX_,d=p+this.imageAnchorY_;kt(a,f,d,1,1,l,-f,-d),o.setTransform.apply(o,a),o.translate(f,d),o.scale(this.imageScale_[0],this.imageScale_[1]),o.drawImage(this.image_,this.imageOriginX_,this.imageOriginY_,this.imageWidth_,this.imageHeight_,-this.imageAnchorX_,-this.imageAnchorY_,this.imageWidth_,this.imageHeight_),o.setTransform(1,0,0,1,0,0)}else o.drawImage(this.image_,this.imageOriginX_,this.imageOriginY_,this.imageWidth_,this.imageHeight_,h,p,this.imageWidth_,this.imageHeight_)}1!=this.imageOpacity_&&(o.globalAlpha=s)}},e.prototype.drawText_=function(t,e,r,n){if(this.textState_&&""!==this.text_){this.textFillState_&&this.setContextFillState_(this.textFillState_),this.textStrokeState_&&this.setContextStrokeState_(this.textStrokeState_),this.setContextTextState_(this.textState_);var i=ln(t,e,r,n,this.transform_,this.pixelCoordinates_),o=this.context_,a=this.textRotation_;for(this.textRotateWithView_&&(a+=this.viewRotation_);e<r;e+=n){var s=i[e]+this.textOffsetX_,l=i[e+1]+this.textOffsetY_;if(0!==a||1!=this.textScale_[0]||1!=this.textScale_[1]){var u=kt(this.tmpLocalTransform_,s,l,1,1,a,-s,-l);o.setTransform.apply(o,u),o.translate(s,l),o.scale(this.textScale_[0],this.textScale_[1]),this.textStrokeState_&&o.strokeText(this.text_,0,0),this.textFillState_&&o.fillText(this.text_,0,0),o.setTransform(1,0,0,1,0,0)}else this.textStrokeState_&&o.strokeText(this.text_,s,l),this.textFillState_&&o.fillText(this.text_,s,l)}}},e.prototype.moveToLineTo_=function(t,e,r,n,i){var o=this.context_,a=ln(t,e,r,n,this.transform_,this.pixelCoordinates_);o.moveTo(a[0],a[1]);var s=a.length;i&&(s-=2);for(var l=2;l<s;l+=2)o.lineTo(a[l],a[l+1]);return i&&o.closePath(),r},e.prototype.drawRings_=function(t,e,r,n){for(var i=0,o=r.length;i<o;++i)e=this.moveToLineTo_(t,e,r[i],n,!0);return e},e.prototype.drawCircle=function(t){if(Re(this.extent_,t.getExtent())){if(this.fillState_||this.strokeState_){this.fillState_&&this.setContextFillState_(this.fillState_),this.strokeState_&&this.setContextStrokeState_(this.strokeState_);var e=mn(t,this.transform_,this.pixelCoordinates_),r=e[2]-e[0],n=e[3]-e[1],i=Math.sqrt(r*r+n*n),o=this.context_;o.beginPath(),o.arc(e[0],e[1],i,0,2*Math.PI),this.fillState_&&o.fill(),this.strokeState_&&o.stroke()}""!==this.text_&&this.drawText_(t.getCenter(),0,2,2)}},e.prototype.setStyle=function(t){this.setFillStrokeStyle(t.getFill(),t.getStroke()),this.setImageStyle(t.getImage()),this.setTextStyle(t.getText())},e.prototype.setTransform=function(t){this.transform_=t},e.prototype.drawGeometry=function(t){switch(t.getType()){case bt.POINT:this.drawPoint(t);break;case bt.LINE_STRING:this.drawLineString(t);break;case bt.POLYGON:this.drawPolygon(t);break;case bt.MULTI_POINT:this.drawMultiPoint(t);break;case bt.MULTI_LINE_STRING:this.drawMultiLineString(t);break;case bt.MULTI_POLYGON:this.drawMultiPolygon(t);break;case bt.GEOMETRY_COLLECTION:this.drawGeometryCollection(t);break;case bt.CIRCLE:this.drawCircle(t)}},e.prototype.drawFeature=function(t,e){var r=e.getGeometryFunction()(t);r&&Re(this.extent_,r.getExtent())&&(this.setStyle(e),this.drawGeometry(r))},e.prototype.drawGeometryCollection=function(t){for(var e=t.getGeometriesArray(),r=0,n=e.length;r<n;++r)this.drawGeometry(e[r])},e.prototype.drawPoint=function(t){this.squaredTolerance_&&(t=t.simplifyTransformed(this.squaredTolerance_,this.userTransform_));var e=t.getFlatCoordinates(),r=t.getStride();this.image_&&this.drawImages_(e,0,e.length,r),""!==this.text_&&this.drawText_(e,0,e.length,r)},e.prototype.drawMultiPoint=function(t){this.squaredTolerance_&&(t=t.simplifyTransformed(this.squaredTolerance_,this.userTransform_));var e=t.getFlatCoordinates(),r=t.getStride();this.image_&&this.drawImages_(e,0,e.length,r),""!==this.text_&&this.drawText_(e,0,e.length,r)},e.prototype.drawLineString=function(t){if(this.squaredTolerance_&&(t=t.simplifyTransformed(this.squaredTolerance_,this.userTransform_)),Re(this.extent_,t.getExtent())){if(this.strokeState_){this.setContextStrokeState_(this.strokeState_);var e=this.context_,r=t.getFlatCoordinates();e.beginPath(),this.moveToLineTo_(r,0,r.length,t.getStride(),!1),e.stroke()}if(""!==this.text_){var n=t.getFlatMidpoint();this.drawText_(n,0,2,2)}}},e.prototype.drawMultiLineString=function(t){this.squaredTolerance_&&(t=t.simplifyTransformed(this.squaredTolerance_,this.userTransform_));var e=t.getExtent();if(Re(this.extent_,e)){if(this.strokeState_){this.setContextStrokeState_(this.strokeState_);var r=this.context_,n=t.getFlatCoordinates(),i=0,o=t.getEnds(),a=t.getStride();r.beginPath();for(var s=0,l=o.length;s<l;++s)i=this.moveToLineTo_(n,i,o[s],a,!1);r.stroke()}if(""!==this.text_){var u=t.getFlatMidpoints();this.drawText_(u,0,u.length,2)}}},e.prototype.drawPolygon=function(t){if(this.squaredTolerance_&&(t=t.simplifyTransformed(this.squaredTolerance_,this.userTransform_)),Re(this.extent_,t.getExtent())){if(this.strokeState_||this.fillState_){this.fillState_&&this.setContextFillState_(this.fillState_),this.strokeState_&&this.setContextStrokeState_(this.strokeState_);var e=this.context_;e.beginPath(),this.drawRings_(t.getOrientedFlatCoordinates(),0,t.getEnds(),t.getStride()),this.fillState_&&e.fill(),this.strokeState_&&e.stroke()}if(""!==this.text_){var r=t.getFlatInteriorPoint();this.drawText_(r,0,2,2)}}},e.prototype.drawMultiPolygon=function(t){if(this.squaredTolerance_&&(t=t.simplifyTransformed(this.squaredTolerance_,this.userTransform_)),Re(this.extent_,t.getExtent())){if(this.strokeState_||this.fillState_){this.fillState_&&this.setContextFillState_(this.fillState_),this.strokeState_&&this.setContextStrokeState_(this.strokeState_);var e=this.context_,r=t.getOrientedFlatCoordinates(),n=0,i=t.getEndss(),o=t.getStride();e.beginPath();for(var a=0,s=i.length;a<s;++a){var l=i[a];n=this.drawRings_(r,n,l,o)}this.fillState_&&e.fill(),this.strokeState_&&e.stroke()}if(""!==this.text_){var u=t.getFlatInteriorPoints();this.drawText_(u,0,u.length,2)}}},e.prototype.setContextFillState_=function(t){var e=this.context_,r=this.contextFillState_;r?r.fillStyle!=t.fillStyle&&(r.fillStyle=t.fillStyle,e.fillStyle=t.fillStyle):(e.fillStyle=t.fillStyle,this.contextFillState_={fillStyle:t.fillStyle})},e.prototype.setContextStrokeState_=function(t){var e=this.context_,r=this.contextStrokeState_;r?(r.lineCap!=t.lineCap&&(r.lineCap=t.lineCap,e.lineCap=t.lineCap),e.setLineDash&&(b(r.lineDash,t.lineDash)||e.setLineDash(r.lineDash=t.lineDash),r.lineDashOffset!=t.lineDashOffset&&(r.lineDashOffset=t.lineDashOffset,e.lineDashOffset=t.lineDashOffset)),r.lineJoin!=t.lineJoin&&(r.lineJoin=t.lineJoin,e.lineJoin=t.lineJoin),r.lineWidth!=t.lineWidth&&(r.lineWidth=t.lineWidth,e.lineWidth=t.lineWidth),r.miterLimit!=t.miterLimit&&(r.miterLimit=t.miterLimit,e.miterLimit=t.miterLimit),r.strokeStyle!=t.strokeStyle&&(r.strokeStyle=t.strokeStyle,e.strokeStyle=t.strokeStyle)):(e.lineCap=t.lineCap,e.setLineDash&&(e.setLineDash(t.lineDash),e.lineDashOffset=t.lineDashOffset),e.lineJoin=t.lineJoin,e.lineWidth=t.lineWidth,e.miterLimit=t.miterLimit,e.strokeStyle=t.strokeStyle,this.contextStrokeState_={lineCap:t.lineCap,lineDash:t.lineDash,lineDashOffset:t.lineDashOffset,lineJoin:t.lineJoin,lineWidth:t.lineWidth,miterLimit:t.miterLimit,strokeStyle:t.strokeStyle})},e.prototype.setContextTextState_=function(t){var e=this.context_,r=this.contextTextState_,n=t.textAlign?t.textAlign:"center";r?(r.font!=t.font&&(r.font=t.font,e.font=t.font),r.textAlign!=n&&(r.textAlign=n,e.textAlign=n),r.textBaseline!=t.textBaseline&&(r.textBaseline=t.textBaseline,e.textBaseline=t.textBaseline)):(e.font=t.font,e.textAlign=n,e.textBaseline=t.textBaseline,this.contextTextState_={font:t.font,textAlign:n,textBaseline:t.textBaseline})},e.prototype.setFillStrokeStyle=function(t,e){if(t){var r=t.getColor();this.fillState_={fillStyle:Tu(r||"#000")}}else this.fillState_=null;if(e){var n=e.getColor(),i=e.getLineCap(),o=e.getLineDash(),a=e.getLineDashOffset(),s=e.getLineJoin(),l=e.getWidth(),u=e.getMiterLimit();this.strokeState_={lineCap:void 0!==i?i:"round",lineDash:o||pa,lineDashOffset:a||0,lineJoin:void 0!==s?s:"round",lineWidth:this.pixelRatio_*(void 0!==l?l:1),miterLimit:void 0!==u?u:10,strokeStyle:Tu(n||"#000")}}else this.strokeState_=null},e.prototype.setImageStyle=function(t){if(t){var e=t.getSize();if(e){var r=t.getAnchor(),n=t.getImage(1),i=t.getOrigin(),o=t.getScaleArray();this.imageAnchorX_=r[0],this.imageAnchorY_=r[1],this.imageHeight_=e[1],this.image_=n,this.imageOpacity_=t.getOpacity(),this.imageOriginX_=i[0],this.imageOriginY_=i[1],this.imageRotateWithView_=t.getRotateWithView(),this.imageRotation_=t.getRotation(),this.imageScale_=[this.pixelRatio_*o[0],this.pixelRatio_*o[1]],this.imageWidth_=e[0]}else this.image_=null}else this.image_=null},e.prototype.setTextStyle=function(t){if(t){var e=t.getFill();if(e){var r=e.getColor();this.textFillState_={fillStyle:Tu(r||"#000")}}else this.textFillState_=null;var n=t.getStroke();if(n){var i=n.getColor(),o=n.getLineCap(),a=n.getLineDash(),s=n.getLineDashOffset(),l=n.getLineJoin(),u=n.getWidth(),c=n.getMiterLimit();this.textStrokeState_={lineCap:void 0!==o?o:"round",lineDash:a||pa,lineDashOffset:s||0,lineJoin:void 0!==l?l:"round",lineWidth:void 0!==u?u:1,miterLimit:void 0!==c?c:10,strokeStyle:Tu(i||"#000")}}else this.textStrokeState_=null;var h=t.getFont(),p=t.getOffsetX(),f=t.getOffsetY(),d=t.getRotateWithView(),g=t.getRotation(),y=t.getScaleArray(),m=t.getText(),v=t.getTextAlign(),_=t.getTextBaseline();this.textState_={font:void 0!==h?h:"10px sans-serif",textAlign:void 0!==v?v:"center",textBaseline:void 0!==_?_:"middle"},this.text_=void 0!==m?m:"",this.textOffsetX_=void 0!==p?this.pixelRatio_*p:0,this.textOffsetY_=void 0!==f?this.pixelRatio_*f:0,this.textRotateWithView_=void 0!==d&&d,this.textRotation_=void 0!==g?g:0,this.textScale_=[this.pixelRatio_*y[0],this.pixelRatio_*y[1]]}else this.text_=""},e}(ku),Du="Circle",Gu="Default",zu="Image",Uu="LineString",Bu="Polygon",Vu="Text",Yu={Point:function(t,e,r,n,i){var o,a=r.getImage(),s=r.getText();i&&(t=i,o=a&&s&&s.getText()?{}:void 0);if(a){if(a.getImageState()!=ki)return;var l=t.getBuilder(r.getZIndex(),zu);l.setImageStyle(a,o),l.drawPoint(e,n)}if(s&&s.getText()){var u=t.getBuilder(r.getZIndex(),Vu);u.setTextStyle(s,o),u.drawText(e,n)}},LineString:function(t,e,r,n,i){var o=r.getStroke();if(o){var a=t.getBuilder(r.getZIndex(),Uu);a.setFillStrokeStyle(null,o),a.drawLineString(e,n)}var s=r.getText();if(s&&s.getText()){var l=(i||t).getBuilder(r.getZIndex(),Vu);l.setTextStyle(s),l.drawText(e,n)}},Polygon:function(t,e,r,n,i){var o=r.getFill(),a=r.getStroke();if(o||a){var s=t.getBuilder(r.getZIndex(),Bu);s.setFillStrokeStyle(o,a),s.drawPolygon(e,n)}var l=r.getText();if(l&&l.getText()){var u=(i||t).getBuilder(r.getZIndex(),Vu);u.setTextStyle(l),u.drawText(e,n)}},MultiPoint:function(t,e,r,n,i){var o,a=r.getImage(),s=r.getText();i&&(t=i,o=a&&s&&s.getText()?{}:void 0);if(a){if(a.getImageState()!=ki)return;var l=t.getBuilder(r.getZIndex(),zu);l.setImageStyle(a,o),l.drawMultiPoint(e,n)}if(s&&s.getText()){var u=(i||t).getBuilder(r.getZIndex(),Vu);u.setTextStyle(s,o),u.drawText(e,n)}},MultiLineString:function(t,e,r,n,i){var o=r.getStroke();if(o){var a=t.getBuilder(r.getZIndex(),Uu);a.setFillStrokeStyle(null,o),a.drawMultiLineString(e,n)}var s=r.getText();if(s&&s.getText()){var l=(i||t).getBuilder(r.getZIndex(),Vu);l.setTextStyle(s),l.drawText(e,n)}},MultiPolygon:function(t,e,r,n,i){var o=r.getFill(),a=r.getStroke();if(a||o){var s=t.getBuilder(r.getZIndex(),Bu);s.setFillStrokeStyle(o,a),s.drawMultiPolygon(e,n)}var l=r.getText();if(l&&l.getText()){var u=(i||t).getBuilder(r.getZIndex(),Vu);u.setTextStyle(l),u.drawText(e,n)}},GeometryCollection:function(t,e,r,n,i){var o,a,s=e.getGeometriesArray();for(o=0,a=s.length;o<a;++o){(0,Yu[s[o].getType()])(t,s[o],r,n,i)}},Circle:function(t,e,r,n,i){var o=r.getFill(),a=r.getStroke();if(o||a){var s=t.getBuilder(r.getZIndex(),Du);s.setFillStrokeStyle(o,a),s.drawCircle(e,n)}var l=r.getText();if(l&&l.getText()){var u=(i||t).getBuilder(r.getZIndex(),Vu);u.setTextStyle(l),u.drawText(e,n)}}};function Wu(t,e){return parseInt(o(t),10)-parseInt(o(e),10)}function qu(t,e){var r=Xu(t,e);return r*r}function Xu(t,e){return.5*t/e}function Zu(t,e,r,n,i,o,a){var s=!1,l=r.getImage();if(l){var u=l.getImageState();u==ki||u==ji?l.unlistenImageChange(i):(u==Fi&&l.load(),u=l.getImageState(),l.listenImageChange(i),s=!0)}return function(t,e,r,n,i,o){var a=r.getGeometryFunction()(e);if(!a)return;var s=a.simplifyTransformed(n,i);if(r.getRenderer())!function t(e,r,n,i){if(r.getType()==bt.GEOMETRY_COLLECTION){for(var o=r.getGeometries(),a=0,s=o.length;a<s;++a)t(e,o[a],n,i);return}e.getBuilder(n.getZIndex(),Gu).drawCustom(r,i,n.getRenderer())}(t,s,r,e);else{(0,Yu[s.getType()])(t,s,r,e,o)}}(t,e,r,n,o,a),s}function Ku(t){var e,r=t.frameState,n=Ot(t.inversePixelTransform.slice(),r.coordinateToPixelTransform),i=qu(r.viewState.resolution,r.pixelRatio),o=tn();return o&&(e=Zr(o,r.viewState.projection)),new Nu(t.context,r.pixelRatio,r.extent,n,r.viewState.rotation,i,e)}var Hu,$u={imageSmoothingEnabled:!1,msImageSmoothingEnabled:!1};function Ju(t,e,r,n,i){t.beginPath(),t.moveTo(0,0),t.lineTo(e,r),t.lineTo(n,i),t.closePath(),t.save(),t.clip(),t.fillRect(0,0,Math.max(e,n)+1,Math.max(r,i)),t.restore()}function Qu(t,e){return Math.abs(t[4*e]-210)>2||Math.abs(t[4*e+3]-191.25)>2}function tc(t,e,r,n){var i=Hr(r,e,t),o=zr(e,n,r),a=e.getMetersPerUnit();void 0!==a&&(o*=a);var s=t.getMetersPerUnit();void 0!==s&&(o/=s);var l=t.getExtent();if(!l||Qt(l,i)){var u=zr(t,o,i)/o;isFinite(u)&&u>0&&(o/=u)}return o}function ec(t,e,r,n){var i=xe(r),o=tc(t,e,i,n);return(!isFinite(o)||o<=0)&&me(r,(function(r){return o=tc(t,e,r,n),isFinite(o)&&o>0})),o}function rc(t,e,r,n,i,o,a,s,l,u,c,h){var p=uo(Math.round(r*t),Math.round(r*e));if(O(p,h),0===l.length)return p.canvas;function f(t){return Math.round(t*r)/r}p.scale(r,r),p.globalCompositeOperation="lighter";var d=[1/0,1/0,-1/0,-1/0];l.forEach((function(t,e,r){he(d,t.extent)}));var g=Pe(d),y=Ee(d),m=uo(Math.round(r*g/n),Math.round(r*y/n));O(m,h);var v=r/n;l.forEach((function(t,e,r){var n=t.extent[0]-d[0],i=-(t.extent[3]-d[3]),o=Pe(t.extent),a=Ee(t.extent);t.image.width>0&&t.image.height>0&&m.drawImage(t.image,u,u,t.image.width-2*u,t.image.height-2*u,n*v,i*v,o*v,a*v)}));var _=Ce(a);return s.getTriangles().forEach((function(t,e,i){var a=t.source,s=t.target,l=a[0][0],u=a[0][1],c=a[1][0],g=a[1][1],y=a[2][0],v=a[2][1],b=f((s[0][0]-_[0])/o),x=f(-(s[0][1]-_[1])/o),w=f((s[1][0]-_[0])/o),S=f(-(s[1][1]-_[1])/o),E=f((s[2][0]-_[0])/o),T=f(-(s[2][1]-_[1])/o),C=l,O=u;l=0,u=0;var P=Be([[c-=C,g-=O,0,0,w-b],[y-=C,v-=O,0,0,E-b],[0,0,c,g,S-x],[0,0,y,v,T-x]]);if(P){if(p.save(),p.beginPath(),function(){if(void 0===Hu){var t=document.createElement("canvas").getContext("2d");t.globalCompositeOperation="lighter",t.fillStyle="rgba(210, 0, 0, 0.75)",Ju(t,4,5,4,0),Ju(t,4,5,0,5);var e=t.getImageData(0,0,3,3).data;Hu=Qu(e,0)||Qu(e,4)||Qu(e,8)}return Hu}()||h===$u){p.moveTo(w,S);for(var R=b-w,I=x-S,L=0;L<4;L++)p.lineTo(w+f((L+1)*R/4),S+f(L*I/3)),3!=L&&p.lineTo(w+f((L+1)*R/4),S+f((L+1)*I/3));p.lineTo(E,T)}else p.moveTo(w,S),p.lineTo(b,x),p.lineTo(E,T);p.clip(),p.transform(P[0],P[2],P[1],P[3],b,x),p.translate(d[0]-C,d[3]-O),p.scale(n/r,-n/r),p.drawImage(m.canvas,0,0),p.restore()}})),c&&(p.save(),p.globalCompositeOperation="source-over",p.strokeStyle="black",p.lineWidth=1,s.getTriangles().forEach((function(t,e,r){var n=t.target,i=(n[0][0]-_[0])/o,a=-(n[0][1]-_[1])/o,s=(n[1][0]-_[0])/o,l=-(n[1][1]-_[1])/o,u=(n[2][0]-_[0])/o,c=-(n[2][1]-_[1])/o;p.beginPath(),p.moveTo(s,l),p.lineTo(i,a),p.lineTo(u,c),p.closePath(),p.stroke()})),p.restore()),p.canvas}var nc=[0,0,0],ic=function(){function t(t){var e;if(this.minZoom=void 0!==t.minZoom?t.minZoom:0,this.resolutions_=t.resolutions,pt(w(this.resolutions_,(function(t,e){return e-t}),!0),17),!t.origins)for(var r=0,n=this.resolutions_.length-1;r<n;++r)if(e){if(this.resolutions_[r]/this.resolutions_[r+1]!==e){e=void 0;break}}else e=this.resolutions_[r]/this.resolutions_[r+1];this.zoomFactor_=e,this.maxZoom=this.resolutions_.length-1,this.origin_=void 0!==t.origin?t.origin:null,this.origins_=null,void 0!==t.origins&&(this.origins_=t.origins,pt(this.origins_.length==this.resolutions_.length,20));var i=t.extent;void 0===i||this.origin_||this.origins_||(this.origin_=Ce(i)),pt(!this.origin_&&this.origins_||this.origin_&&!this.origins_,18),this.tileSizes_=null,void 0!==t.tileSizes&&(this.tileSizes_=t.tileSizes,pt(this.tileSizes_.length==this.resolutions_.length,19)),this.tileSize_=void 0!==t.tileSize?t.tileSize:this.tileSizes_?null:256,pt(!this.tileSize_&&this.tileSizes_||this.tileSize_&&!this.tileSizes_,22),this.extent_=void 0!==i?i:null,this.fullTileRanges_=null,this.tmpSize_=[0,0],void 0!==t.sizes?this.fullTileRanges_=t.sizes.map((function(t,e){var r=new _u(Math.min(0,t[0]),Math.max(t[0]-1,-1),Math.min(0,t[1]),Math.max(t[1]-1,-1));if(i){var n=this.getTileRangeForExtentAndZ(i,e);r.minX=Math.max(n.minX,r.minX),r.maxX=Math.min(n.maxX,r.maxX),r.minY=Math.max(n.minY,r.minY),r.maxY=Math.min(n.maxY,r.maxY)}return r}),this):i&&this.calculateTileRanges_(i)}return t.prototype.forEachTileCoord=function(t,e,r){for(var n=this.getTileRangeForExtentAndZ(t,e),i=n.minX,o=n.maxX;i<=o;++i)for(var a=n.minY,s=n.maxY;a<=s;++a)r([e,i,a])},t.prototype.forEachTileCoordParentTileRange=function(t,e,r,n){var i,o,a=null,s=t[0]-1;for(2===this.zoomFactor_?(i=t[1],o=t[2]):a=this.getTileCoordExtent(t,n);s>=this.minZoom;){if(e(s,2===this.zoomFactor_?vu(i=Math.floor(i/2),i,o=Math.floor(o/2),o,r):this.getTileRangeForExtentAndZ(a,s,r)))return!0;--s}return!1},t.prototype.getExtent=function(){return this.extent_},t.prototype.getMaxZoom=function(){return this.maxZoom},t.prototype.getMinZoom=function(){return this.minZoom},t.prototype.getOrigin=function(t){return this.origin_?this.origin_:this.origins_[t]},t.prototype.getResolution=function(t){return this.resolutions_[t]},t.prototype.getResolutions=function(){return this.resolutions_},t.prototype.getTileCoordChildTileRange=function(t,e,r){if(t[0]<this.maxZoom){if(2===this.zoomFactor_){var n=2*t[1],i=2*t[2];return vu(n,n+1,i,i+1,e)}var o=this.getTileCoordExtent(t,r);return this.getTileRangeForExtentAndZ(o,t[0]+1,e)}return null},t.prototype.getTileRangeExtent=function(t,e,r){var n=this.getOrigin(t),i=this.getResolution(t),o=Is(this.getTileSize(t),this.tmpSize_),a=n[0]+e.minX*o[0]*i,s=n[0]+(e.maxX+1)*o[0]*i;return ie(a,n[1]+e.minY*o[1]*i,s,n[1]+(e.maxY+1)*o[1]*i,r)},t.prototype.getTileRangeForExtentAndZ=function(t,e,r){var n=nc;this.getTileCoordForXYAndZ_(t[0],t[3],e,!1,n);var i=n[1],o=n[2];return this.getTileCoordForXYAndZ_(t[2],t[1],e,!0,n),vu(i,n[1],o,n[2],r)},t.prototype.getTileCoordCenter=function(t){var e=this.getOrigin(t[0]),r=this.getResolution(t[0]),n=Is(this.getTileSize(t[0]),this.tmpSize_);return[e[0]+(t[1]+.5)*n[0]*r,e[1]-(t[2]+.5)*n[1]*r]},t.prototype.getTileCoordExtent=function(t,e){var r=this.getOrigin(t[0]),n=this.getResolution(t[0]),i=Is(this.getTileSize(t[0]),this.tmpSize_),o=r[0]+t[1]*i[0]*n,a=r[1]-(t[2]+1)*i[1]*n;return ie(o,a,o+i[0]*n,a+i[1]*n,e)},t.prototype.getTileCoordForCoordAndResolution=function(t,e,r){return this.getTileCoordForXYAndResolution_(t[0],t[1],e,!1,r)},t.prototype.getTileCoordForXYAndResolution_=function(t,e,r,n,i){var o=this.getZForResolution(r),a=r/this.getResolution(o),s=this.getOrigin(o),l=Is(this.getTileSize(o),this.tmpSize_),u=n?.5:0,c=n?.5:0,h=Math.floor((t-s[0])/r+u),p=Math.floor((s[1]-e)/r+c),f=a*h/l[0],d=a*p/l[1];return n?(f=Math.ceil(f)-1,d=Math.ceil(d)-1):(f=Math.floor(f),d=Math.floor(d)),uu(o,f,d,i)},t.prototype.getTileCoordForXYAndZ_=function(t,e,r,n,i){var o=this.getOrigin(r),a=this.getResolution(r),s=Is(this.getTileSize(r),this.tmpSize_),l=n?.5:0,u=n?.5:0,c=Math.floor((t-o[0])/a+l),h=Math.floor((o[1]-e)/a+u),p=c/s[0],f=h/s[1];return n?(p=Math.ceil(p)-1,f=Math.ceil(f)-1):(p=Math.floor(p),f=Math.floor(f)),uu(r,p,f,i)},t.prototype.getTileCoordForCoordAndZ=function(t,e,r){return this.getTileCoordForXYAndZ_(t[0],t[1],e,!1,r)},t.prototype.getTileCoordResolution=function(t){return this.resolutions_[t[0]]},t.prototype.getTileSize=function(t){return this.tileSize_?this.tileSize_:this.tileSizes_[t]},t.prototype.getFullTileRange=function(t){return this.fullTileRanges_?this.fullTileRanges_[t]:this.extent_?this.getTileRangeForExtentAndZ(this.extent_,t):null},t.prototype.getZForResolution=function(t,e){return Ne(y(this.resolutions_,t,e||0),this.minZoom,this.maxZoom)},t.prototype.calculateTileRanges_=function(t){for(var e=this.resolutions_.length,r=new Array(e),n=this.minZoom;n<e;++n)r[n]=this.getTileRangeForExtentAndZ(t,n);this.fullTileRanges_=r},t}();function oc(t){var e=t.getDefaultTileGrid();return e||(e=cc(t),t.setDefaultTileGrid(e)),e}function ac(t,e,r){var n=e[0],i=t.getTileCoordCenter(e),o=hc(r);if(Qt(o,i))return e;var a=Pe(o),s=Math.ceil((o[0]-i[0])/a);return i[0]+=a*s,t.getTileCoordForCoordAndZ(i,n)}function sc(t,e,r,n){var i=void 0!==n?n:Ut,o=uc(t,e,r);return new ic({extent:t,origin:we(t,i),resolutions:o,tileSize:r})}function lc(t){var e=t||{},r=e.extent||Gr("EPSG:3857").getExtent(),n={extent:r,minZoom:e.minZoom,tileSize:e.tileSize,resolutions:uc(r,e.maxZoom,e.tileSize,e.maxResolution)};return new ic(n)}function uc(t,e,r,n){for(var i=void 0!==e?e:42,o=Ee(t),a=Pe(t),s=Is(void 0!==r?r:256),l=n>0?n:Math.max(a/s[0],o/s[1]),u=i+1,c=new Array(u),h=0;h<u;++h)c[h]=l/Math.pow(2,h);return c}function cc(t,e,r,n){return sc(hc(t),e,r,n)}function hc(t){var e=(t=Gr(t)).getExtent();if(!e){var r=180*wt[St.DEGREES]/t.getMetersPerUnit();e=ie(-r,-r,r,r)}return e}function pc(t,e){var r=/\{z\}/g,n=/\{x\}/g,i=/\{y\}/g,o=/\{-y\}/g;return function(a,s,l){return a?t.replace(r,a[0].toString()).replace(n,a[1].toString()).replace(i,a[2].toString()).replace(o,(function(){var t=a[0],r=e.getFullTileRange(t);return pt(r,55),(r.getHeight()-a[2]-1).toString()})):void 0}}function fc(t,e){for(var r=t.length,n=new Array(r),i=0;i<r;++i)n[i]=pc(t[i],e);return dc(n)}function dc(t){return 1===t.length?t[0]:function(e,r,n){if(e){var i=We(fu(e),t.length);return t[i](e,r,n)}}}function gc(t,e,r){}function yc(t){var e=[],r=/\{([a-z])-([a-z])\}/.exec(t);if(r){var n=r[1].charCodeAt(0),i=r[2].charCodeAt(0),o=void 0;for(o=n;o<=i;++o)e.push(t.replace(r[0],String.fromCharCode(o)));return e}if(r=/\{(\d+)-(\d+)\}/.exec(t)){for(var a=parseInt(r[2],10),s=parseInt(r[1],10);s<=a;s++)e.push(t.replace(r[0],s.toString()));return e}return e.push(t),e}function mc(t,e){var r=[];Object.keys(e).forEach((function(t){null!==e[t]&&void 0!==e[t]&&r.push(t+"="+encodeURIComponent(e[t]))}));var n=r.join("&");return(t=-1===(t=t.replace(/[?&]$/,"")).indexOf("?")?t+"?":t+"&")+n}var vc,_c=["experimental-webgl","webgl","webkit-3d","moz-webgl"];function bc(t,e){for(var r=_c.length,n=0;n<r;++n)try{var i=t.getContext(_c[n],e);if(i)return i}catch(t){}return null}function xc(){if(!vc){var t=bc(document.createElement("canvas"));t&&(vc=t.getSupportedExtensions())}return vc}var wc="http://www.w3.org/2001/XMLSchema-instance";function Sc(t,e){return Xc().createElementNS(t,e)}function Ec(t,e){return Tc(t,e,[]).join("")}function Tc(t,e,r){if(t.nodeType==Node.CDATA_SECTION_NODE||t.nodeType==Node.TEXT_NODE)e?r.push(String(t.nodeValue).replace(/(\r\n|\r|\n)/g,"")):r.push(t.nodeValue);else{var n=void 0;for(n=t.firstChild;n;n=n.nextSibling)Tc(n,e,r)}return r}function Cc(t){return"documentElement"in t}function Oc(t,e,r){return t.getAttributeNS(e,r)||""}function Pc(t){return(new DOMParser).parseFromString(t,"application/xml")}function Rc(t,e){return function(r,n){var i=t.call(void 0!==e?e:this,r,n);void 0!==i&&v(n[n.length-1],i)}}function Ic(t,e){return function(r,n){var i=t.call(void 0!==e?e:this,r,n);void 0!==i&&n[n.length-1].push(i)}}function Lc(t,e){return function(r,n){var i=t.call(void 0!==e?e:this,r,n);void 0!==i&&(n[n.length-1]=i)}}function Mc(t,e,r){return function(n,i){var o=t.call(void 0!==r?r:this,n,i);if(void 0!==o){var a=i[i.length-1],s=void 0!==e?e:n.localName,l=void 0;s in a?l=a[s]:(l=[],a[s]=l),l.push(o)}}}function Fc(t,e,r){return function(n,i){var o=t.call(void 0!==r?r:this,n,i);void 0!==o&&(i[i.length-1][void 0!==e?e:n.localName]=o)}}function Ac(t,e){return function(r,n,i){t.call(void 0!==e?e:this,r,n,i),i[i.length-1].node.appendChild(r)}}function kc(t,e){var r,n;return function(e,i,o){if(void 0===r){r={};var a={};a[e.localName]=t,r[e.namespaceURI]=a,n=jc(e.localName)}Bc(r,n,i,o)}}function jc(t,e){var r=t;return function(t,n,i){var o=n[n.length-1].node,a=r;return void 0===a&&(a=i),Sc(void 0!==e?e:o.namespaceURI,a)}}var Nc=jc();function Dc(t,e){for(var r=e.length,n=new Array(r),i=0;i<r;++i)n[i]=t[e[i]];return n}function Gc(t,e,r){var n,i,o=void 0!==r?r:{};for(n=0,i=t.length;n<i;++n)o[t[n]]=e;return o}function zc(t,e,r,n){var i;for(i=e.firstElementChild;i;i=i.nextElementSibling){var o=t[i.namespaceURI];if(void 0!==o){var a=o[i.localName];void 0!==a&&a.call(n,i,r)}}}function Uc(t,e,r,n,i){return n.push(t),zc(e,r,n,i),n.pop()}function Bc(t,e,r,n,i,o){for(var a,s,l=(void 0!==i?i:r).length,u=0;u<l;++u)void 0!==(a=r[u])&&void 0!==(s=e.call(void 0!==o?o:this,a,n,void 0!==i?i[u]:void 0))&&t[s.namespaceURI][s.localName].call(o,s,a,n)}function Vc(t,e,r,n,i,o,a){return i.push(t),Bc(e,r,n,i,o,a),i.pop()}var Yc=void 0;function Wc(){return void 0===Yc&&"undefined"!=typeof XMLSerializer&&(Yc=new XMLSerializer),Yc}var qc=void 0;function Xc(){return void 0===qc&&"undefined"!=typeof document&&(qc=document.implementation.createDocument("","",null)),qc}var Zc=new Blob(['var e=self;e.onmessage=function(s){console.log("version worker received message:",s.data),e.postMessage("version: ".concat("latest"))};'],{type:"application/javascript"});URL.createObjectURL(Zc);var Kc=new Blob(['var e="function"==typeof Object.assign?Object.assign:function(e,n){if(null==e)throw new TypeError("Cannot convert undefined or null to object");for(var t=Object(e),r=1,o=arguments.length;r<o;++r){var i=arguments[r];if(null!=i)for(var f in i)i.hasOwnProperty(f)&&(t[f]=i[f])}return t},n="GENERATE_BUFFERS",t=[],r={vertexPosition:0,indexPosition:0};function o(e,n,t,r,o){e[n+0]=t,e[n+1]=r,e[n+2]=o}function i(e,n,i,f,s,u){var a=3+s,l=e[n+0],v=e[n+1],c=t;c.length=s;for(var g=0;g<c.length;g++)c[g]=e[n+2+g];var b=u?u.vertexPosition:0,h=u?u.indexPosition:0,d=b/a;return o(i,b,l,v,0),c.length&&i.set(c,b+3),o(i,b+=a,l,v,1),c.length&&i.set(c,b+3),o(i,b+=a,l,v,2),c.length&&i.set(c,b+3),o(i,b+=a,l,v,3),c.length&&i.set(c,b+3),b+=a,f[h++]=d,f[h++]=d+1,f[h++]=d+3,f[h++]=d+1,f[h++]=d+2,f[h++]=d+3,r.vertexPosition=b,r.indexPosition=h,r}var f=self;f.onmessage=function(t){var r=t.data;if(r.type===n){for(var o=r.customAttributesCount,s=2+o,u=new Float32Array(r.renderInstructions),a=u.length/s,l=4*a*(o+3),v=new Uint32Array(6*a),c=new Float32Array(l),g=null,b=0;b<u.length;b+=s)g=i(u,b,c,v,o,g);var h=e({vertexBuffer:c.buffer,indexBuffer:v.buffer,renderInstructions:u.buffer},r);f.postMessage(h,[c.buffer,v.buffer,u.buffer])}};'],{type:"application/javascript"}),Hc=URL.createObjectURL(Kc);var $c=35044;function Jc(t){switch(t){case 34962:return Float32Array;case 34963:return Uint32Array;default:return Float32Array}}var Qc=function(){function t(t,e){this.array=null,this.type=t,pt(34962===t||34963===t,62),this.usage=void 0!==e?e:$c}return t.prototype.ofSize=function(t){this.array=new(Jc(this.type))(t)},t.prototype.fromArray=function(t){this.array=Jc(this.type).from(t)},t.prototype.fromArrayBuffer=function(t){this.array=new(Jc(this.type))(t)},t.prototype.getType=function(){return this.type},t.prototype.getArray=function(){return this.array},t.prototype.getUsage=function(){return this.usage},t.prototype.getSize=function(){return this.array?this.array.length:0},t}(),th="webglcontextlost",eh="webglcontextrestored",rh=function(){function t(t){this.gl_=t.webGlContext;var e=this.gl_;this.scaleRatio_=t.scaleRatio||1,this.renderTargetTexture_=e.createTexture(),this.renderTargetTextureSize_=null,this.frameBuffer_=e.createFramebuffer();var r=e.createShader(e.VERTEX_SHADER);e.shaderSource(r,t.vertexShader||"\n precision mediump float;\n \n attribute vec2 a_position;\n varying vec2 v_texCoord;\n varying vec2 v_screenCoord;\n \n uniform vec2 u_screenSize;\n \n void main() {\n v_texCoord = a_position * 0.5 + 0.5;\n v_screenCoord = v_texCoord * u_screenSize;\n gl_Position = vec4(a_position, 0.0, 1.0);\n }\n"),e.compileShader(r);var n=e.createShader(e.FRAGMENT_SHADER);e.shaderSource(n,t.fragmentShader||"\n precision mediump float;\n \n uniform sampler2D u_image;\n \n varying vec2 v_texCoord;\n \n void main() {\n gl_FragColor = texture2D(u_image, v_texCoord);\n }\n"),e.compileShader(n),this.renderTargetProgram_=e.createProgram(),e.attachShader(this.renderTargetProgram_,r),e.attachShader(this.renderTargetProgram_,n),e.linkProgram(this.renderTargetProgram_),this.renderTargetVerticesBuffer_=e.createBuffer();e.bindBuffer(e.ARRAY_BUFFER,this.renderTargetVerticesBuffer_),e.bufferData(e.ARRAY_BUFFER,new Float32Array([-1,-1,1,-1,-1,1,1,-1,1,1,-1,1]),e.STATIC_DRAW),this.renderTargetAttribLocation_=e.getAttribLocation(this.renderTargetProgram_,"a_position"),this.renderTargetUniformLocation_=e.getUniformLocation(this.renderTargetProgram_,"u_screenSize"),this.renderTargetTextureLocation_=e.getUniformLocation(this.renderTargetProgram_,"u_image"),this.uniforms_=[],t.uniforms&&Object.keys(t.uniforms).forEach(function(r){this.uniforms_.push({value:t.uniforms[r],location:e.getUniformLocation(this.renderTargetProgram_,r)})}.bind(this))}return t.prototype.getGL=function(){return this.gl_},t.prototype.init=function(t){var e=this.getGL(),r=[e.drawingBufferWidth*this.scaleRatio_,e.drawingBufferHeight*this.scaleRatio_];if(e.bindFramebuffer(e.FRAMEBUFFER,this.getFrameBuffer()),e.viewport(0,0,r[0],r[1]),!this.renderTargetTextureSize_||this.renderTargetTextureSize_[0]!==r[0]||this.renderTargetTextureSize_[1]!==r[1]){this.renderTargetTextureSize_=r;var n=e.RGBA,i=e.RGBA,o=e.UNSIGNED_BYTE;e.bindTexture(e.TEXTURE_2D,this.renderTargetTexture_),e.texImage2D(e.TEXTURE_2D,0,n,r[0],r[1],0,i,o,null),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_MIN_FILTER,e.LINEAR),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_S,e.CLAMP_TO_EDGE),e.texParameteri(e.TEXTURE_2D,e.TEXTURE_WRAP_T,e.CLAMP_TO_EDGE),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.renderTargetTexture_,0)}},t.prototype.apply=function(t,e){var r=this.getGL(),n=t.size;r.bindFramebuffer(r.FRAMEBUFFER,e?e.getFrameBuffer():null),r.activeTexture(r.TEXTURE0),r.bindTexture(r.TEXTURE_2D,this.renderTargetTexture_),r.clearColor(0,0,0,0),r.clear(r.COLOR_BUFFER_BIT),r.enable(r.BLEND),r.blendFunc(r.ONE,r.ONE_MINUS_SRC_ALPHA),r.viewport(0,0,r.drawingBufferWidth,r.drawingBufferHeight),r.bindBuffer(r.ARRAY_BUFFER,this.renderTargetVerticesBuffer_),r.useProgram(this.renderTargetProgram_),r.enableVertexAttribArray(this.renderTargetAttribLocation_),r.vertexAttribPointer(this.renderTargetAttribLocation_,2,r.FLOAT,!1,0,0),r.uniform2f(this.renderTargetUniformLocation_,n[0],n[1]),r.uniform1i(this.renderTargetTextureLocation_,0),this.applyUniforms(t),r.drawArrays(r.TRIANGLES,0,6)},t.prototype.getFrameBuffer=function(){return this.frameBuffer_},t.prototype.applyUniforms=function(t){var e,r=this.getGL(),n=1;this.uniforms_.forEach((function(i){if((e="function"==typeof i.value?i.value(t):i.value)instanceof HTMLCanvasElement||e instanceof ImageData)i.texture||(i.texture=r.createTexture()),r.activeTexture(r["TEXTURE"+n]),r.bindTexture(r.TEXTURE_2D,i.texture),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),e instanceof ImageData?r.texImage2D(r.TEXTURE_2D,0,r.RGBA,r.RGBA,e.width,e.height,0,r.UNSIGNED_BYTE,new Uint8Array(e.data)):r.texImage2D(r.TEXTURE_2D,0,r.RGBA,r.RGBA,r.UNSIGNED_BYTE,e),r.uniform1i(i.location,n++);else if(Array.isArray(e))switch(e.length){case 2:return void r.uniform2f(i.location,e[0],e[1]);case 3:return void r.uniform3f(i.location,e[0],e[1],e[2]);case 4:return void r.uniform4f(i.location,e[0],e[1],e[2],e[3]);default:return}else"number"==typeof e&&r.uniform1f(i.location,e)}))},t}();function nh(){return[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1]}function ih(t,e){return t[0]=e[0],t[1]=e[1],t[4]=e[2],t[5]=e[3],t[12]=e[4],t[13]=e[5],t}var oh=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ah="u_projectionMatrix",sh="u_offsetScaleMatrix",lh="u_offsetRotateMatrix",uh="u_time",ch="u_zoom",hh="u_resolution",ph={UNSIGNED_BYTE:5121,UNSIGNED_SHORT:5123,UNSIGNED_INT:5125,FLOAT:5126};function fh(t){for(var e=0,r=0;r<t.length;r++){var n=t[r];e+=n.size*dh(n.type)}return e}function dh(t){switch(t){case ph.UNSIGNED_BYTE:return Uint8Array.BYTES_PER_ELEMENT;case ph.UNSIGNED_SHORT:return Uint16Array.BYTES_PER_ELEMENT;case ph.UNSIGNED_INT:return Uint32Array.BYTES_PER_ELEMENT;case ph.FLOAT:default:return Float32Array.BYTES_PER_ELEMENT}}var gh=function(t){function e(e){var r=t.call(this)||this,n=e||{};r.boundHandleWebGLContextLost_=r.handleWebGLContextLost.bind(r),r.boundHandleWebGLContextRestored_=r.handleWebGLContextRestored.bind(r),r.canvas_=document.createElement("canvas"),r.canvas_.style.position="absolute",r.canvas_.style.left="0",r.gl_=bc(r.canvas_);var i=r.getGL();if(r.bufferCache_={},r.currentProgram_=null,pt(g(xc(),"OES_element_index_uint"),63),i.getExtension("OES_element_index_uint"),r.canvas_.addEventListener(th,r.boundHandleWebGLContextLost_),r.canvas_.addEventListener(eh,r.boundHandleWebGLContextRestored_),r.offsetRotateMatrix_=[1,0,0,1,0,0],r.offsetScaleMatrix_=[1,0,0,1,0,0],r.tmpMat4_=[1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1],r.uniformLocations_={},r.attribLocations_={},r.uniforms_=[],n.uniforms)for(var o in n.uniforms)r.uniforms_.push({name:o,value:n.uniforms[o]});return r.postProcessPasses_=n.postProcesses?n.postProcesses.map((function(t){return new rh({webGlContext:i,scaleRatio:t.scaleRatio,vertexShader:t.vertexShader,fragmentShader:t.fragmentShader,uniforms:t.uniforms})})):[new rh({webGlContext:i})],r.shaderCompileErrors_=null,r.startTime_=Date.now(),r}return oh(e,t),e.prototype.bindBuffer=function(t){var e=this.getGL(),r=o(t),n=this.bufferCache_[r];n||(n={buffer:t,webGlBuffer:e.createBuffer()},this.bufferCache_[r]=n);e.bindBuffer(t.getType(),n.webGlBuffer)},e.prototype.flushBufferData=function(t){var e=this.getGL();this.bindBuffer(t),e.bufferData(t.getType(),t.getArray(),t.getUsage())},e.prototype.deleteBuffer=function(t){var e=this.getGL(),r=o(t),n=this.bufferCache_[r];e.isContextLost()||e.deleteBuffer(n.buffer),delete this.bufferCache_[r]},e.prototype.disposeInternal=function(){this.canvas_.removeEventListener(th,this.boundHandleWebGLContextLost_),this.canvas_.removeEventListener(eh,this.boundHandleWebGLContextRestored_)},e.prototype.prepareDraw=function(t){var e=this.getGL(),r=this.getCanvas(),n=t.size,i=t.pixelRatio;r.width=n[0]*i,r.height=n[1]*i,r.style.width=n[0]+"px",r.style.height=n[1]+"px",e.useProgram(this.currentProgram_);for(var o=this.postProcessPasses_.length-1;o>=0;o--)this.postProcessPasses_[o].init(t);e.bindTexture(e.TEXTURE_2D,null),e.clearColor(0,0,0,0),e.clear(e.COLOR_BUFFER_BIT),e.enable(e.BLEND),e.blendFunc(e.ONE,e.ONE_MINUS_SRC_ALPHA),e.useProgram(this.currentProgram_),this.applyFrameState(t),this.applyUniforms(t)},e.prototype.prepareDrawToRenderTarget=function(t,e,r){var n=this.getGL(),i=e.getSize();n.bindFramebuffer(n.FRAMEBUFFER,e.getFramebuffer()),n.viewport(0,0,i[0],i[1]),n.bindTexture(n.TEXTURE_2D,e.getTexture()),n.clearColor(0,0,0,0),n.clear(n.COLOR_BUFFER_BIT),n.enable(n.BLEND),n.blendFunc(n.ONE,r?n.ZERO:n.ONE_MINUS_SRC_ALPHA),n.useProgram(this.currentProgram_),this.applyFrameState(t),this.applyUniforms(t)},e.prototype.drawElements=function(t,e){var r=this.getGL(),n=r.UNSIGNED_INT,i=e-t,o=4*t;r.drawElements(r.TRIANGLES,i,n,o)},e.prototype.finalizeDraw=function(t){for(var e=0;e<this.postProcessPasses_.length;e++)this.postProcessPasses_[e].apply(t,this.postProcessPasses_[e+1]||null)},e.prototype.getCanvas=function(){return this.canvas_},e.prototype.getGL=function(){return this.gl_},e.prototype.applyFrameState=function(t){var e=t.size,r=t.viewState.rotation,n=Ct(this.offsetScaleMatrix_);Mt(n,2/e[0],2/e[1]);var i=Ct(this.offsetRotateMatrix_);0!==r&&Lt(i,-r),this.setUniformMatrixValue(sh,ih(this.tmpMat4_,n)),this.setUniformMatrixValue(lh,ih(this.tmpMat4_,i)),this.setUniformFloatValue(uh,.001*(Date.now()-this.startTime_)),this.setUniformFloatValue(ch,t.viewState.zoom),this.setUniformFloatValue(hh,t.viewState.resolution)},e.prototype.applyUniforms=function(t){var e,r=this.getGL(),n=0;this.uniforms_.forEach(function(i){if((e="function"==typeof i.value?i.value(t):i.value)instanceof HTMLCanvasElement||e instanceof HTMLImageElement||e instanceof ImageData)i.texture||(i.prevValue=void 0,i.texture=r.createTexture()),r.activeTexture(r["TEXTURE"+n]),r.bindTexture(r.TEXTURE_2D,i.texture),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_MIN_FILTER,r.LINEAR),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_S,r.CLAMP_TO_EDGE),r.texParameteri(r.TEXTURE_2D,r.TEXTURE_WRAP_T,r.CLAMP_TO_EDGE),(!(e instanceof HTMLImageElement)||e.complete)&&i.prevValue!==e&&(i.prevValue=e,r.texImage2D(r.TEXTURE_2D,0,r.RGBA,r.RGBA,r.UNSIGNED_BYTE,e)),r.uniform1i(this.getUniformLocation(i.name),n++);else if(Array.isArray(e)&&6===e.length)this.setUniformMatrixValue(i.name,ih(this.tmpMat4_,e));else if(Array.isArray(e)&&e.length<=4)switch(e.length){case 2:return void r.uniform2f(this.getUniformLocation(i.name),e[0],e[1]);case 3:return void r.uniform3f(this.getUniformLocation(i.name),e[0],e[1],e[2]);case 4:return void r.uniform4f(this.getUniformLocation(i.name),e[0],e[1],e[2],e[3]);default:return}else"number"==typeof e&&r.uniform1f(this.getUniformLocation(i.name),e)}.bind(this))},e.prototype.useProgram=function(t){return t!=this.currentProgram_&&(this.getGL().useProgram(t),this.currentProgram_=t,this.uniformLocations_={},this.attribLocations_={},!0)},e.prototype.compileShader=function(t,e){var r=this.getGL(),n=r.createShader(e);return r.shaderSource(n,t),r.compileShader(n),n},e.prototype.getProgram=function(t,e){var r=this.getGL(),n=this.compileShader(t,r.FRAGMENT_SHADER),i=this.compileShader(e,r.VERTEX_SHADER);this.shaderCompileErrors_=null,r.getShaderInfoLog(n)&&(this.shaderCompileErrors_="Fragment shader compilation failed:\n"+r.getShaderInfoLog(n)),r.getShaderInfoLog(i)&&(this.shaderCompileErrors_=(this.shaderCompileErrors_||"")+"Vertex shader compilation failed:\n"+r.getShaderInfoLog(i));var o=r.createProgram();return r.attachShader(o,n),r.attachShader(o,i),r.linkProgram(o),o},e.prototype.getShaderCompileErrors=function(){return this.shaderCompileErrors_},e.prototype.getUniformLocation=function(t){return void 0===this.uniformLocations_[t]&&(this.uniformLocations_[t]=this.getGL().getUniformLocation(this.currentProgram_,t)),this.uniformLocations_[t]},e.prototype.getAttributeLocation=function(t){return void 0===this.attribLocations_[t]&&(this.attribLocations_[t]=this.getGL().getAttribLocation(this.currentProgram_,t)),this.attribLocations_[t]},e.prototype.makeProjectionTransform=function(t,e){var r=t.size,n=t.viewState.rotation,i=t.viewState.resolution,o=t.viewState.center;return Ct(e),kt(e,0,0,2/(i*r[0]),2/(i*r[1]),-n,-o[0],-o[1]),e},e.prototype.setUniformFloatValue=function(t,e){this.getGL().uniform1f(this.getUniformLocation(t),e)},e.prototype.setUniformMatrixValue=function(t,e){this.getGL().uniformMatrix4fv(this.getUniformLocation(t),!1,e)},e.prototype.enableAttributeArray_=function(t,e,r,n,i){var o=this.getAttributeLocation(t);o<0||(this.getGL().enableVertexAttribArray(o),this.getGL().vertexAttribPointer(o,e,r,!1,n,i))},e.prototype.enableAttributes=function(t){for(var e=fh(t),r=0,n=0;n<t.length;n++){var i=t[n];this.enableAttributeArray_(i.name,i.size,i.type||5126,e,r),r+=i.size*dh(i.type)}},e.prototype.handleWebGLContextLost=function(){P(this.bufferCache_),this.currentProgram_=null},e.prototype.handleWebGLContextRestored=function(){},e.prototype.createTexture=function(t,e,r){var n=this.getGL(),i=r||n.createTexture(),o=n.RGBA,a=n.RGBA,s=n.UNSIGNED_BYTE;return n.bindTexture(n.TEXTURE_2D,i),e?n.texImage2D(n.TEXTURE_2D,0,o,a,s,e):n.texImage2D(n.TEXTURE_2D,0,o,t[0],t[1],0,a,s,null),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_MIN_FILTER,n.LINEAR),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_S,n.CLAMP_TO_EDGE),n.texParameteri(n.TEXTURE_2D,n.TEXTURE_WRAP_T,n.CLAMP_TO_EDGE),i},e}(p),yh=new Uint8Array(4),mh=function(){function t(t,e){this.helper_=t;var r=t.getGL();this.texture_=r.createTexture(),this.framebuffer_=r.createFramebuffer(),this.size_=e||[1,1],this.data_=new Uint8Array(0),this.dataCacheDirty_=!0,this.updateSize_()}return t.prototype.setSize=function(t){b(t,this.size_)||(this.size_[0]=t[0],this.size_[1]=t[1],this.updateSize_())},t.prototype.getSize=function(){return this.size_},t.prototype.clearCachedData=function(){this.dataCacheDirty_=!0},t.prototype.readAll=function(){if(this.dataCacheDirty_){var t=this.size_,e=this.helper_.getGL();e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer_),e.readPixels(0,0,t[0],t[1],e.RGBA,e.UNSIGNED_BYTE,this.data_),this.dataCacheDirty_=!1}return this.data_},t.prototype.readPixel=function(t,e){if(t<0||e<0||t>this.size_[0]||e>=this.size_[1])return yh[0]=0,yh[1]=0,yh[2]=0,yh[3]=0,yh;this.readAll();var r=Math.floor(t)+(this.size_[1]-Math.floor(e)-1)*this.size_[0];return yh[0]=this.data_[4*r],yh[1]=this.data_[4*r+1],yh[2]=this.data_[4*r+2],yh[3]=this.data_[4*r+3],yh},t.prototype.getTexture=function(){return this.texture_},t.prototype.getFramebuffer=function(){return this.framebuffer_},t.prototype.updateSize_=function(){var t=this.size_,e=this.helper_.getGL();this.texture_=this.helper_.createTexture(t,null,this.texture_),e.bindFramebuffer(e.FRAMEBUFFER,this.framebuffer_),e.viewport(0,0,t[0],t[1]),e.framebufferTexture2D(e.FRAMEBUFFER,e.COLOR_ATTACHMENT0,e.TEXTURE_2D,this.texture_,0),this.data_=new Uint8Array(t[0]*t[1]*4)},t}(),vh=1,_h=2,bh=4,xh=8,wh=16,Sh=31,Eh={};function Th(t){if("number"==typeof t)return vh;if("boolean"==typeof t)return xh;if("string"==typeof t)return Io(t)?bh|_h:_h;if(!Array.isArray(t))throw new Error("Unhandled value type: "+JSON.stringify(t));var e=t;if(e.every((function(t){return"number"==typeof t})))return 3===e.length||4===e.length?bh|wh:wh;if("string"!=typeof e[0])throw new Error("Expected an expression operator but received: "+JSON.stringify(e));var r=Eh[e[0]];if(void 0===r)throw new Error("Unrecognized expression operator: "+JSON.stringify(e));return r.getReturnType(e.slice(1))}function Ch(t){return Math.log2(t)%1==0}function Oh(t){var e=t.toString();return-1===e.indexOf(".")?e+".0":e}function Ph(t){if(t.length<2||t.length>4)throw new Error("`formatArray` can only output `vec2`, `vec3` or `vec4` arrays.");return"vec"+t.length+"("+t.map(Oh).join(", ")+")"}function Rh(t){var e=Oo(t).slice();return e.length<4&&e.push(1),Ph(e.map((function(t,e){return e<3?t/255:t})))}function Ih(t,e){return void 0===t.stringLiteralsMap[e]&&(t.stringLiteralsMap[e]=Object.keys(t.stringLiteralsMap).length),t.stringLiteralsMap[e]}function Lh(t,e){return Oh(Ih(t,e))}function Mh(t,e,r){if(Array.isArray(e)&&"string"==typeof e[0]){var n=Eh[e[0]];if(void 0===n)throw new Error("Unrecognized expression operator: "+JSON.stringify(e));return n.toGlsl(t,e.slice(1),r)}var i=Th(e);return(i&vh)>0?Oh(e):(i&xh)>0?e.toString():(i&_h)>0&&(void 0===r||r==_h)?Lh(t,e.toString()):(i&bh)>0&&(void 0===r||r==bh)?Rh(e):(i&wh)>0?Ph(e):void 0}function Fh(t){if(!(Th(t)&vh))throw new Error("A numeric value was expected, got "+JSON.stringify(t)+" instead")}function Ah(t){for(var e=0;e<t.length;e++)Fh(t[e])}function kh(t){if(!(Th(t)&_h))throw new Error("A string value was expected, got "+JSON.stringify(t)+" instead")}function jh(t){if(!(Th(t)&xh))throw new Error("A boolean value was expected, got "+JSON.stringify(t)+" instead")}function Nh(t,e){if(t.length!==e)throw new Error("Exactly "+e+" arguments were expected, got "+t.length+" instead")}function Dh(t,e){if(t.length<e)throw new Error("At least "+e+" arguments were expected, got "+t.length+" instead")}function Gh(t,e){if(t.length>e)throw new Error("At most "+e+" arguments were expected, got "+t.length+" instead")}function zh(t){if(t.length%2!=0)throw new Error("An even amount of arguments was expected, got "+t+" instead")}function Uh(t,e){if(!Ch(e))throw new Error("Could not infer only one type from the following expression: "+JSON.stringify(t))}function Bh(t){return{getReturnType:function(t){return xh},toGlsl:function(e,r){Nh(r,2);for(var n=Sh,i=0;i<r.length;i++)n&=Th(r[i]);if(0===n)throw new Error("All arguments should be of compatible type, got "+JSON.stringify(r)+" instead");return"("+Mh(e,r[0],n)+" "+t+" "+Mh(e,r[1],n)+")"}}}function Vh(t){return{getReturnType:function(t){return xh},toGlsl:function(e,r){Dh(r,2);for(var n=0;n<r.length;n++)jh(r[n]);return"("+r.map((function(t){return Mh(e,t)})).join(" "+t+" ")+")"}}}Eh.get={getReturnType:function(t){return Sh},toGlsl:function(t,e){Nh(e,1),kh(e[0]);var r=e[0].toString();return-1===t.attributes.indexOf(r)&&t.attributes.push(r),(t.inFragmentShader?"v_":"a_")+r}},Eh.var={getReturnType:function(t){return Sh},toGlsl:function(t,e){Nh(e,1),kh(e[0]);var r=e[0].toString();return-1===t.variables.indexOf(r)&&t.variables.push(r),"u_"+r}},Eh.time={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,0),"u_time"}},Eh.zoom={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,0),"u_zoom"}},Eh.resolution={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,0),"u_resolution"}},Eh["*"]={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" * "+Mh(t,e[1])+")"}},Eh["/"]={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" / "+Mh(t,e[1])+")"}},Eh["+"]={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" + "+Mh(t,e[1])+")"}},Eh["-"]={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" - "+Mh(t,e[1])+")"}},Eh.clamp={getReturnType:function(t){return vh},toGlsl:function(t,e){Nh(e,3),Ah(e);var r=Mh(t,e[1]),n=Mh(t,e[2]);return"clamp("+Mh(t,e[0])+", "+r+", "+n+")"}},Eh["%"]={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"mod("+Mh(t,e[0])+", "+Mh(t,e[1])+")"}},Eh["^"]={getReturnType:function(t){return vh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"pow("+Mh(t,e[0])+", "+Mh(t,e[1])+")"}},Eh[">"]={getReturnType:function(t){return xh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" > "+Mh(t,e[1])+")"}},Eh[">="]={getReturnType:function(t){return xh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" >= "+Mh(t,e[1])+")"}},Eh["<"]={getReturnType:function(t){return xh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" < "+Mh(t,e[1])+")"}},Eh["<="]={getReturnType:function(t){return xh},toGlsl:function(t,e){return Nh(e,2),Ah(e),"("+Mh(t,e[0])+" <= "+Mh(t,e[1])+")"}},Eh["=="]=Bh("=="),Eh["!="]=Bh("!="),Eh["!"]={getReturnType:function(t){return xh},toGlsl:function(t,e){return Nh(e,1),jh(e[0]),"(!"+Mh(t,e[0])+")"}},Eh.all=Vh("&&"),Eh.any=Vh("||"),Eh.between={getReturnType:function(t){return xh},toGlsl:function(t,e){Nh(e,3),Ah(e);var r=Mh(t,e[1]),n=Mh(t,e[2]),i=Mh(t,e[0]);return"("+i+" >= "+r+" && "+i+" <= "+n+")"}},Eh.array={getReturnType:function(t){return wh},toGlsl:function(t,e){Dh(e,2),Gh(e,4),Ah(e);var r=e.map((function(e){return Mh(t,e,vh)}));return"vec"+e.length+"("+r.join(", ")+")"}},Eh.color={getReturnType:function(t){return bh},toGlsl:function(t,e){Dh(e,3),Gh(e,4),Ah(e);var r=e;3===e.length&&r.push(1);var n=e.map((function(e,r){return Mh(t,e,vh)+(r<3?" / 255.0":"")}));return"vec"+e.length+"("+n.join(", ")+")"}},Eh.interpolate={getReturnType:function(t){for(var e=bh|vh,r=3;r<t.length;r+=2)e&=Th(t[r]);return e},toGlsl:function(t,e,r){zh(e),Dh(e,6);var n,i=e[0];switch(i[0]){case"linear":n=1;break;case"exponential":n=i[1];break;default:n=null}if(!n)throw new Error('Invalid interpolation type for "interpolate" operator, received: '+JSON.stringify(i));var o=void 0!==r?r:Sh,a=Eh.interpolate.getReturnType(e)&o;Uh(e,a);for(var s=Mh(t,e[1]),l=null,u=2;u<e.length-2;u+=2){var c=Mh(t,e[u]),h=Mh(t,e[u+1],a),p=Mh(t,e[u+2]);l="mix("+(l||h)+", "+Mh(t,e[u+3],a)+", pow(clamp(("+s+" - "+c+") / ("+p+" - "+c+"), 0.0, 1.0), "+Oh(n)+"))"}return l}},Eh.match={getReturnType:function(t){for(var e=Sh,r=2;r<t.length;r+=2)e&=Th(t[r]);return e&=Th(t[t.length-1])},toGlsl:function(t,e,r){zh(e),Dh(e,4);var n=void 0!==r?r:Sh,i=Eh.match.getReturnType(e)&n;Uh(e,i);for(var o=Mh(t,e[0]),a=Mh(t,e[e.length-1],i),s=null,l=e.length-3;l>=1;l-=2){s="("+o+" == "+Mh(t,e[l])+" ? "+Mh(t,e[l+1],i)+" : "+(s||a)+")"}return s}},Eh.case={getReturnType:function(t){for(var e=Sh,r=1;r<t.length;r+=2)e&=Th(t[r]);return e&=Th(t[t.length-1])},toGlsl:function(t,e,r){!function(t){if(t.length%2==0)throw new Error("An odd amount of arguments was expected, got "+t+" instead")}(e),Dh(e,3);var n=void 0!==r?r:Sh,i=Eh.case.getReturnType(e)&n;Uh(e,i);for(var o=0;o<e.length-1;o+=2)jh(e[o]);var a=Mh(t,e[e.length-1],i),s=null;for(o=e.length-3;o>=0;o-=2){s="("+Mh(t,e[o])+" ? "+Mh(t,e[o+1],i)+" : "+(s||a)+")"}return s}};var Yh=function(){function t(){this.uniforms=[],this.attributes=[],this.varyings=[],this.sizeExpression="vec2(1.0)",this.rotationExpression="0.0",this.offsetExpression="vec2(0.0)",this.colorExpression="vec4(1.0)",this.texCoordExpression="vec4(0.0, 0.0, 1.0, 1.0)",this.discardExpression="false",this.rotateWithView=!1}return t.prototype.addUniform=function(t){return this.uniforms.push(t),this},t.prototype.addAttribute=function(t){return this.attributes.push(t),this},t.prototype.addVarying=function(t,e,r){return this.varyings.push({name:t,type:e,expression:r}),this},t.prototype.setSizeExpression=function(t){return this.sizeExpression=t,this},t.prototype.setRotationExpression=function(t){return this.rotationExpression=t,this},t.prototype.setSymbolOffsetExpression=function(t){return this.offsetExpression=t,this},t.prototype.setColorExpression=function(t){return this.colorExpression=t,this},t.prototype.setTextureCoordinateExpression=function(t){return this.texCoordExpression=t,this},t.prototype.setFragmentDiscardExpression=function(t){return this.discardExpression=t,this},t.prototype.setSymbolRotateWithView=function(t){return this.rotateWithView=t,this},t.prototype.getSizeExpression=function(){return this.sizeExpression},t.prototype.getOffsetExpression=function(){return this.offsetExpression},t.prototype.getColorExpression=function(){return this.colorExpression},t.prototype.getTextureCoordinateExpression=function(){return this.texCoordExpression},t.prototype.getFragmentDiscardExpression=function(){return this.discardExpression},t.prototype.getSymbolVertexShader=function(t){var e=this.rotateWithView?"u_offsetScaleMatrix * u_offsetRotateMatrix":"u_offsetScaleMatrix",r=this.attributes,n=this.varyings;return t&&(r=r.concat("vec4 a_hitColor"),n=n.concat({name:"v_hitColor",type:"vec4",expression:"a_hitColor"})),"precision mediump float;\nuniform mat4 u_projectionMatrix;\nuniform mat4 u_offsetScaleMatrix;\nuniform mat4 u_offsetRotateMatrix;\nuniform float u_time;\nuniform float u_zoom;\nuniform float u_resolution;\n"+this.uniforms.map((function(t){return"uniform "+t+";"})).join("\n")+"\nattribute vec2 a_position;\nattribute float a_index;\n"+r.map((function(t){return"attribute "+t+";"})).join("\n")+"\nvarying vec2 v_texCoord;\nvarying vec2 v_quadCoord;\n"+n.map((function(t){return"varying "+t.type+" "+t.name+";"})).join("\n")+"\nvoid main(void) {\n mat4 offsetMatrix = "+e+";\n vec2 halfSize = "+this.sizeExpression+" * 0.5;\n vec2 offset = "+this.offsetExpression+";\n float angle = "+this.rotationExpression+";\n float offsetX;\n float offsetY;\n if (a_index == 0.0) {\n offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);\n offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);\n } else if (a_index == 1.0) {\n offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y - halfSize.y) * sin(angle);\n offsetY = (offset.y - halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);\n } else if (a_index == 2.0) {\n offsetX = (offset.x + halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);\n offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x + halfSize.x) * sin(angle);\n } else {\n offsetX = (offset.x - halfSize.x) * cos(angle) + (offset.y + halfSize.y) * sin(angle);\n offsetY = (offset.y + halfSize.y) * cos(angle) - (offset.x - halfSize.x) * sin(angle);\n }\n vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);\n gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;\n vec4 texCoord = "+this.texCoordExpression+";\n float u = a_index == 0.0 || a_index == 3.0 ? texCoord.s : texCoord.p;\n float v = a_index == 2.0 || a_index == 3.0 ? texCoord.t : texCoord.q;\n v_texCoord = vec2(u, v);\n u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;\n v = a_index == 2.0 || a_index == 3.0 ? 0.0 : 1.0;\n v_quadCoord = vec2(u, v);\n"+n.map((function(t){return" "+t.name+" = "+t.expression+";"})).join("\n")+"\n}"},t.prototype.getSymbolFragmentShader=function(t){var e=t?" if (gl_FragColor.a < 0.1) { discard; } gl_FragColor = v_hitColor;":"",r=this.varyings;return t&&(r=r.concat({name:"v_hitColor",type:"vec4",expression:"a_hitColor"})),"precision mediump float;\nuniform float u_time;\nuniform float u_zoom;\nuniform float u_resolution;\n"+this.uniforms.map((function(t){return"uniform "+t+";"})).join("\n")+"\nvarying vec2 v_texCoord;\nvarying vec2 v_quadCoord;\n"+r.map((function(t){return"varying "+t.type+" "+t.name+";"})).join("\n")+"\nvoid main(void) {\n if ("+this.discardExpression+") { discard; }\n gl_FragColor = "+this.colorExpression+";\n gl_FragColor.rgb *= gl_FragColor.a;\n"+e+"\n}"},t}();function Wh(t){var e=t.symbol,r=void 0!==e.size?e.size:1,n=e.color||"white",i=e.textureCoord||[0,0,1,1],o=e.offset||[0,0],a=void 0!==e.opacity?e.opacity:1,s=void 0!==e.rotation?e.rotation:0,l={inFragmentShader:!1,variables:[],attributes:[],stringLiteralsMap:{}},u=Mh(l,r,wh|vh),c=Mh(l,o,wh),h=Mh(l,i,wh),p=Mh(l,s,vh),f={inFragmentShader:!0,variables:l.variables,attributes:[],stringLiteralsMap:l.stringLiteralsMap},d=Mh(f,n,bh),g=Mh(f,a,vh),y="1.0",m="vec2("+Mh(f,r,wh|vh)+").x";switch(e.symbolType){case"square":case"image":break;case"circle":y="(1.0-smoothstep(1.-4./"+m+",1.,dot(v_quadCoord-.5,v_quadCoord-.5)*4.))";break;case"triangle":var v="(v_quadCoord*2.-1.)",_="(atan("+v+".x,"+v+".y))";y="(1.0-smoothstep(.5-3./"+m+",.5,cos(floor(.5+"+_+"/2.094395102)*2.094395102-"+_+")*length("+v+")))";break;default:throw new Error("Unexpected symbol type: "+e.symbolType)}var b=(new Yh).setSizeExpression("vec2("+u+")").setRotationExpression(p).setSymbolOffsetExpression(c).setTextureCoordinateExpression(h).setSymbolRotateWithView(!!e.rotateWithView).setColorExpression("vec4("+d+".rgb, "+d+".a * "+g+" * "+y+")");if(t.filter){var x=Mh(f,t.filter,xh);b.setFragmentDiscardExpression("!"+x)}var w={};if(f.variables.forEach((function(e){b.addUniform("float u_"+e),w["u_"+e]=function(){if(!t.variables||void 0===t.variables[e])throw new Error("The following variable is missing from the style: "+e);var r=t.variables[e];return"string"==typeof r&&(r=Ih(l,r)),void 0!==r?r:-9999999}})),"image"===e.symbolType&&e.src){var S=new Image;S.src=e.src,b.addUniform("sampler2D u_texture").setColorExpression(b.getColorExpression()+" * texture2D(u_texture, v_texCoord)"),w.u_texture=S}return f.attributes.forEach((function(t){-1===l.attributes.indexOf(t)&&l.attributes.push(t),b.addVarying("v_"+t,"float","a_"+t)})),l.attributes.forEach((function(t){b.addAttribute("float a_"+t)})),{builder:b,attributes:l.attributes.map((function(t){return{name:t,callback:function(e,r){var n=r[t];return"string"==typeof n&&(n=Ih(l,n)),void 0!==n?n:-9999999}}})),uniforms:w}}var qh=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Xh=function(t){function e(e){var r=t.call(this,{extent:e.extent,origin:e.origin,origins:e.origins,resolutions:e.resolutions,tileSize:e.tileSize,tileSizes:e.tileSizes,sizes:e.sizes})||this;return r.matrixIds_=e.matrixIds,r}return qh(e,t),e.prototype.getMatrixId=function(t){return this.matrixIds_[t]},e.prototype.getMatrixIds=function(){return this.matrixIds_},e}(ic),Zh=Xh;function Kh(t,e,r){var n=[],i=[],o=[],a=[],s=[],l=void 0!==r?r:[],u=Gr(t.SupportedCRS),c=u.getMetersPerUnit(),h="ne"==u.getAxisOrientation().substr(0,2);return t.TileMatrix.sort((function(t,e){return e.ScaleDenominator-t.ScaleDenominator})),t.TileMatrix.forEach((function(e){if(!(l.length>0)||_(l,(function(r){return e.Identifier==r.TileMatrix||-1===e.Identifier.indexOf(":")&&t.Identifier+":"+e.Identifier===r.TileMatrix}))){i.push(e.Identifier);var r=28e-5*e.ScaleDenominator/c,u=e.TileWidth,p=e.TileHeight;h?o.push([e.TopLeftCorner[1],e.TopLeftCorner[0]]):o.push(e.TopLeftCorner),n.push(r),a.push(u==p?u:[u,p]),s.push([e.MatrixWidth,e.MatrixHeight])}})),new Xh({extent:e,origins:o,resolutions:n,matrixIds:i,tileSizes:a,sizes:s})}var Hh=function(){function t(t){this.opacity_=t.opacity,this.rotateWithView_=t.rotateWithView,this.rotation_=t.rotation,this.scale_=t.scale,this.scaleArray_=Is(t.scale),this.displacement_=t.displacement}return t.prototype.clone=function(){var e=this.getScale();return new t({opacity:this.getOpacity(),scale:Array.isArray(e)?e.slice():e,rotation:this.getRotation(),rotateWithView:this.getRotateWithView(),displacement:this.getDisplacement().slice()})},t.prototype.getOpacity=function(){return this.opacity_},t.prototype.getRotateWithView=function(){return this.rotateWithView_},t.prototype.getRotation=function(){return this.rotation_},t.prototype.getScale=function(){return this.scale_},t.prototype.getScaleArray=function(){return this.scaleArray_},t.prototype.getDisplacement=function(){return this.displacement_},t.prototype.getAnchor=function(){return n()},t.prototype.getImage=function(t){return n()},t.prototype.getHitDetectionImage=function(){return n()},t.prototype.getPixelRatio=function(t){return 1},t.prototype.getImageState=function(){return n()},t.prototype.getImageSize=function(){return n()},t.prototype.getHitDetectionImageSize=function(){return n()},t.prototype.getOrigin=function(){return n()},t.prototype.getSize=function(){return n()},t.prototype.setOpacity=function(t){this.opacity_=t},t.prototype.setRotateWithView=function(t){this.rotateWithView_=t},t.prototype.setRotation=function(t){this.rotation_=t},t.prototype.setScale=function(t){this.scale_=t,this.scaleArray_=Is(t)},t.prototype.listenImageChange=function(t){n()},t.prototype.load=function(){n()},t.prototype.unlistenImageChange=function(t){n()},t}(),$h=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Jh=function(t){function e(e){var r=this,n=void 0!==e.rotateWithView&&e.rotateWithView;return(r=t.call(this,{opacity:1,rotateWithView:n,rotation:void 0!==e.rotation?e.rotation:0,scale:void 0!==e.scale?e.scale:1,displacement:void 0!==e.displacement?e.displacement:[0,0]})||this).canvas_={},r.hitDetectionCanvas_=null,r.fill_=void 0!==e.fill?e.fill:null,r.origin_=[0,0],r.points_=e.points,r.radius_=void 0!==e.radius?e.radius:e.radius1,r.radius2_=e.radius2,r.angle_=void 0!==e.angle?e.angle:0,r.stroke_=void 0!==e.stroke?e.stroke:null,r.anchor_=null,r.size_=null,r.imageSize_=null,r.hitDetectionImageSize_=null,r.render(),r}return $h(e,t),e.prototype.clone=function(){var t=this.getScale(),r=new e({fill:this.getFill()?this.getFill().clone():void 0,points:this.getPoints(),radius:this.getRadius(),radius2:this.getRadius2(),angle:this.getAngle(),stroke:this.getStroke()?this.getStroke().clone():void 0,rotation:this.getRotation(),rotateWithView:this.getRotateWithView(),scale:Array.isArray(t)?t.slice():t,displacement:this.getDisplacement().slice()});return r.setOpacity(this.getOpacity()),r},e.prototype.getAnchor=function(){return this.anchor_},e.prototype.getAngle=function(){return this.angle_},e.prototype.getFill=function(){return this.fill_},e.prototype.getHitDetectionImage=function(){if(!this.hitDetectionCanvas_){var t=this.createRenderOptions();this.createHitDetectionCanvas_(t)}return this.hitDetectionCanvas_},e.prototype.getImage=function(t){if(!this.canvas_[t||1]){var e=this.createRenderOptions(),r=uo(e.size*t||1,e.size*t||1);this.draw_(e,r,0,0,t||1),this.canvas_[t||1]=r.canvas}return this.canvas_[t||1]},e.prototype.getPixelRatio=function(t){return t},e.prototype.getImageSize=function(){return this.imageSize_},e.prototype.getHitDetectionImageSize=function(){return this.hitDetectionImageSize_},e.prototype.getImageState=function(){return ki},e.prototype.getOrigin=function(){return this.origin_},e.prototype.getPoints=function(){return this.points_},e.prototype.getRadius=function(){return this.radius_},e.prototype.getRadius2=function(){return this.radius2_},e.prototype.getSize=function(){return this.size_},e.prototype.getStroke=function(){return this.stroke_},e.prototype.listenImageChange=function(t){},e.prototype.load=function(){},e.prototype.unlistenImageChange=function(t){},e.prototype.createRenderOptions=function(){var t,e="round",r="round",n=0,i=null,o=0,a=0;return this.stroke_&&(null===(t=this.stroke_.getColor())&&(t="#000"),t=Tu(t),void 0===(a=this.stroke_.getWidth())&&(a=1),i=this.stroke_.getLineDash(),o=this.stroke_.getLineDashOffset(),void 0===(r=this.stroke_.getLineJoin())&&(r="round"),void 0===(e=this.stroke_.getLineCap())&&(e="round"),void 0===(n=this.stroke_.getMiterLimit())&&(n=10)),{strokeStyle:t,strokeWidth:a,size:2*(this.radius_+a)+1,lineCap:e,lineDash:i,lineDashOffset:o,lineJoin:r,miterLimit:n}},e.prototype.render=function(){var t=this.createRenderOptions(),e=uo(t.size,t.size);this.draw_(t,e,0,0,1),this.canvas_={},this.canvas_[1]=e.canvas;var r=e.canvas.width,n=r,i=this.getDisplacement();this.hitDetectionImageSize_=[t.size,t.size],this.createHitDetectionCanvas_(t),this.anchor_=[r/2-i[0],r/2+i[1]],this.size_=[r,r],this.imageSize_=[n,n]},e.prototype.draw_=function(t,e,r,n,i){var o,a,s;e.setTransform(i,0,0,i,0,0),e.translate(r,n),e.beginPath();var l=this.points_;if(l===1/0)e.arc(t.size/2,t.size/2,this.radius_,0,2*Math.PI,!0);else{var u=void 0!==this.radius2_?this.radius2_:this.radius_;for(u!==this.radius_&&(l*=2),o=0;o<=l;o++)a=2*o*Math.PI/l-Math.PI/2+this.angle_,s=o%2==0?this.radius_:u,e.lineTo(t.size/2+s*Math.cos(a),t.size/2+s*Math.sin(a))}if(this.fill_){var c=this.fill_.getColor();null===c&&(c="#000"),e.fillStyle=Tu(c),e.fill()}this.stroke_&&(e.strokeStyle=t.strokeStyle,e.lineWidth=t.strokeWidth,e.setLineDash&&t.lineDash&&(e.setLineDash(t.lineDash),e.lineDashOffset=t.lineDashOffset),e.lineCap=t.lineCap,e.lineJoin=t.lineJoin,e.miterLimit=t.miterLimit,e.stroke()),e.closePath()},e.prototype.createHitDetectionCanvas_=function(t){if(this.hitDetectionCanvas_=this.getImage(1),this.fill_){var e=this.fill_.getColor(),r=0;if("string"==typeof e&&(e=Oo(e)),null===e?r=1:Array.isArray(e)&&(r=4===e.length?e[3]:1),0===r){var n=uo(t.size,t.size);this.hitDetectionCanvas_=n.canvas,this.drawHitDetectionCanvas_(t,n,0,0)}}},e.prototype.drawHitDetectionCanvas_=function(t,e,r,n){e.translate(r,n),e.beginPath();var i=this.points_;if(i===1/0)e.arc(t.size/2,t.size/2,this.radius_,0,2*Math.PI,!0);else{var o=void 0!==this.radius2_?this.radius2_:this.radius_;o!==this.radius_&&(i*=2);var a=void 0,s=void 0,l=void 0;for(a=0;a<=i;a++)l=2*a*Math.PI/i-Math.PI/2+this.angle_,s=a%2==0?this.radius_:o,e.lineTo(t.size/2+s*Math.cos(l),t.size/2+s*Math.sin(l))}e.fillStyle="#000",e.fill(),this.stroke_&&(e.strokeStyle=t.strokeStyle,e.lineWidth=t.strokeWidth,t.lineDash&&(e.setLineDash(t.lineDash),e.lineDashOffset=t.lineDashOffset),e.stroke()),e.closePath()},e}(Hh),Qh=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),tp=function(t){function e(e){var r=e||{};return t.call(this,{points:1/0,fill:r.fill,radius:r.radius,stroke:r.stroke,scale:void 0!==r.scale?r.scale:1,rotation:void 0!==r.rotation?r.rotation:0,rotateWithView:void 0!==r.rotateWithView&&r.rotateWithView,displacement:void 0!==r.displacement?r.displacement:[0,0]})||this}return Qh(e,t),e.prototype.clone=function(){var t=this.getScale(),r=new e({fill:this.getFill()?this.getFill().clone():void 0,stroke:this.getStroke()?this.getStroke().clone():void 0,radius:this.getRadius(),scale:Array.isArray(t)?t.slice():t,rotation:this.getRotation(),rotateWithView:this.getRotateWithView(),displacement:this.getDisplacement().slice()});return r.setOpacity(this.getOpacity()),r},e.prototype.setRadius=function(t){this.radius_=t,this.render()},e}(Jh),ep=function(){function t(t){var e=t||{};this.color_=void 0!==e.color?e.color:null}return t.prototype.clone=function(){var e=this.getColor();return new t({color:Array.isArray(e)?e.slice():e||void 0})},t.prototype.getColor=function(){return this.color_},t.prototype.setColor=function(t){this.color_=t},t}(),rp="fraction",np="pixels",ip="bottom-left",op="bottom-right",ap="top-left",sp="top-right",lp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),up=null,cp=function(t){function e(e,r,n,i,o,a){var s=t.call(this)||this;return s.hitDetectionImage_=null,s.image_=e||new Image,null!==i&&(s.image_.crossOrigin=i),s.canvas_={},s.color_=a,s.unlisten_=null,s.imageState_=o,s.size_=n,s.src_=r,s.tainted_,s}return lp(e,t),e.prototype.isTainted_=function(){if(void 0===this.tainted_&&this.imageState_===ki){up||(up=uo(1,1)),up.drawImage(this.image_,0,0);try{up.getImageData(0,0,1,1),this.tainted_=!1}catch(t){up=null,this.tainted_=!0}}return!0===this.tainted_},e.prototype.dispatchChangeEvent_=function(){this.dispatchEvent(F)},e.prototype.handleImageError_=function(){this.imageState_=ji,this.unlistenImage_(),this.dispatchChangeEvent_()},e.prototype.handleImageLoad_=function(){this.imageState_=ki,this.size_?(this.image_.width=this.size_[0],this.image_.height=this.size_[1]):this.size_=[this.image_.width,this.image_.height],this.unlistenImage_(),this.dispatchChangeEvent_()},e.prototype.getImage=function(t){return this.replaceColor_(t),this.canvas_[t]?this.canvas_[t]:this.image_},e.prototype.getPixelRatio=function(t){return this.replaceColor_(t),this.canvas_[t]?t:1},e.prototype.getImageState=function(){return this.imageState_},e.prototype.getHitDetectionImage=function(){if(!this.hitDetectionImage_)if(this.isTainted_()){var t=this.size_[0],e=this.size_[1],r=uo(t,e);r.fillRect(0,0,t,e),this.hitDetectionImage_=r.canvas}else this.hitDetectionImage_=this.image_;return this.hitDetectionImage_},e.prototype.getSize=function(){return this.size_},e.prototype.getSrc=function(){return this.src_},e.prototype.load=function(){if(this.imageState_==Fi){this.imageState_=Ai;try{this.image_.src=this.src_}catch(t){this.handleImageError_()}this.unlisten_=Zi(this.image_,this.handleImageLoad_.bind(this),this.handleImageError_.bind(this))}},e.prototype.replaceColor_=function(t){if(this.color_&&!this.canvas_[t]){var e=document.createElement("canvas");this.canvas_[t]=e,e.width=Math.ceil(this.image_.width*t),e.height=Math.ceil(this.image_.height*t);var r=e.getContext("2d");if(r.scale(t,t),r.drawImage(this.image_,0,0),r.globalCompositeOperation="multiply","multiply"===r.globalCompositeOperation||this.isTainted_())r.fillStyle=wo(this.color_),r.fillRect(0,0,e.width,e.height),r.globalCompositeOperation="destination-in",r.drawImage(this.image_,0,0);else{for(var n=r.getImageData(0,0,e.width,e.height),i=n.data,o=this.color_[0]/255,a=this.color_[1]/255,s=this.color_[2]/255,l=this.color_[3],u=0,c=i.length;u<c;u+=4)i[u]*=o,i[u+1]*=a,i[u+2]*=s,i[u+3]*=l;r.putImageData(n,0,0)}}},e.prototype.unlistenImage_=function(){this.unlisten_&&(this.unlisten_(),this.unlisten_=null)},e}(M);function hp(t,e,r,n,i,o){var a=Ao.get(e,n,o);return a||(a=new cp(t,e,r,n,i,o),Ao.set(e,n,o,a)),a}var pp=cp,fp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),dp=function(t){function e(e){var r=this,n=e||{},i=void 0!==n.opacity?n.opacity:1,a=void 0!==n.rotation?n.rotation:0,s=void 0!==n.scale?n.scale:1,l=void 0!==n.rotateWithView&&n.rotateWithView;(r=t.call(this,{opacity:i,rotation:a,scale:s,displacement:void 0!==n.displacement?n.displacement:[0,0],rotateWithView:l})||this).anchor_=void 0!==n.anchor?n.anchor:[.5,.5],r.normalizedAnchor_=null,r.anchorOrigin_=void 0!==n.anchorOrigin?n.anchorOrigin:ap,r.anchorXUnits_=void 0!==n.anchorXUnits?n.anchorXUnits:rp,r.anchorYUnits_=void 0!==n.anchorYUnits?n.anchorYUnits:rp,r.crossOrigin_=void 0!==n.crossOrigin?n.crossOrigin:null;var u=void 0!==n.img?n.img:null,c=void 0!==n.imgSize?n.imgSize:null,h=n.src;pt(!(void 0!==h&&u),4),pt(!u||u&&c,5),void 0!==h&&0!==h.length||!u||(h=u.src||o(u)),pt(void 0!==h&&h.length>0,6);var p=void 0!==n.src?Fi:ki;return r.color_=void 0!==n.color?Oo(n.color):null,r.iconImage_=hp(u,h,c,r.crossOrigin_,p,r.color_),r.offset_=void 0!==n.offset?n.offset:[0,0],r.offsetOrigin_=void 0!==n.offsetOrigin?n.offsetOrigin:ap,r.origin_=null,r.size_=void 0!==n.size?n.size:null,r}return fp(e,t),e.prototype.clone=function(){var t=this.getScale();return new e({anchor:this.anchor_.slice(),anchorOrigin:this.anchorOrigin_,anchorXUnits:this.anchorXUnits_,anchorYUnits:this.anchorYUnits_,crossOrigin:this.crossOrigin_,color:this.color_&&this.color_.slice?this.color_.slice():this.color_||void 0,src:this.getSrc(),offset:this.offset_.slice(),offsetOrigin:this.offsetOrigin_,size:null!==this.size_?this.size_.slice():void 0,opacity:this.getOpacity(),scale:Array.isArray(t)?t.slice():t,rotation:this.getRotation(),rotateWithView:this.getRotateWithView()})},e.prototype.getAnchor=function(){if(this.normalizedAnchor_)return this.normalizedAnchor_;var t=this.anchor_,e=this.getSize();if(this.anchorXUnits_==rp||this.anchorYUnits_==rp){if(!e)return null;t=this.anchor_.slice(),this.anchorXUnits_==rp&&(t[0]*=e[0]),this.anchorYUnits_==rp&&(t[1]*=e[1])}if(this.anchorOrigin_!=ap){if(!e)return null;t===this.anchor_&&(t=this.anchor_.slice()),this.anchorOrigin_!=sp&&this.anchorOrigin_!=op||(t[0]=-t[0]+e[0]),this.anchorOrigin_!=ip&&this.anchorOrigin_!=op||(t[1]=-t[1]+e[1])}return this.normalizedAnchor_=t,this.normalizedAnchor_},e.prototype.setAnchor=function(t){this.anchor_=t,this.normalizedAnchor_=null},e.prototype.getColor=function(){return this.color_},e.prototype.getImage=function(t){return this.iconImage_.getImage(t)},e.prototype.getPixelRatio=function(t){return this.iconImage_.getPixelRatio(t)},e.prototype.getImageSize=function(){return this.iconImage_.getSize()},e.prototype.getHitDetectionImageSize=function(){return this.getImageSize()},e.prototype.getImageState=function(){return this.iconImage_.getImageState()},e.prototype.getHitDetectionImage=function(){return this.iconImage_.getHitDetectionImage()},e.prototype.getOrigin=function(){if(this.origin_)return this.origin_;var t=this.offset_,e=this.getDisplacement();if(this.offsetOrigin_!=ap){var r=this.getSize(),n=this.iconImage_.getSize();if(!r||!n)return null;t=t.slice(),this.offsetOrigin_!=sp&&this.offsetOrigin_!=op||(t[0]=n[0]-r[0]-t[0]),this.offsetOrigin_!=ip&&this.offsetOrigin_!=op||(t[1]=n[1]-r[1]-t[1])}return t[0]+=e[0],t[1]+=e[1],this.origin_=t,this.origin_},e.prototype.getSrc=function(){return this.iconImage_.getSrc()},e.prototype.getSize=function(){return this.size_?this.size_:this.iconImage_.getSize()},e.prototype.listenImageChange=function(t){this.iconImage_.addEventListener(F,t)},e.prototype.load=function(){this.iconImage_.load()},e.prototype.unlistenImageChange=function(t){this.iconImage_.removeEventListener(F,t)},e}(Hh),gp=function(){function t(t){var e=t||{};this.color_=void 0!==e.color?e.color:null,this.lineCap_=e.lineCap,this.lineDash_=void 0!==e.lineDash?e.lineDash:null,this.lineDashOffset_=e.lineDashOffset,this.lineJoin_=e.lineJoin,this.miterLimit_=e.miterLimit,this.width_=e.width}return t.prototype.clone=function(){var e=this.getColor();return new t({color:Array.isArray(e)?e.slice():e||void 0,lineCap:this.getLineCap(),lineDash:this.getLineDash()?this.getLineDash().slice():void 0,lineDashOffset:this.getLineDashOffset(),lineJoin:this.getLineJoin(),miterLimit:this.getMiterLimit(),width:this.getWidth()})},t.prototype.getColor=function(){return this.color_},t.prototype.getLineCap=function(){return this.lineCap_},t.prototype.getLineDash=function(){return this.lineDash_},t.prototype.getLineDashOffset=function(){return this.lineDashOffset_},t.prototype.getLineJoin=function(){return this.lineJoin_},t.prototype.getMiterLimit=function(){return this.miterLimit_},t.prototype.getWidth=function(){return this.width_},t.prototype.setColor=function(t){this.color_=t},t.prototype.setLineCap=function(t){this.lineCap_=t},t.prototype.setLineDash=function(t){this.lineDash_=t},t.prototype.setLineDashOffset=function(t){this.lineDashOffset_=t},t.prototype.setLineJoin=function(t){this.lineJoin_=t},t.prototype.setMiterLimit=function(t){this.miterLimit_=t},t.prototype.setWidth=function(t){this.width_=t},t}(),yp=function(){function t(t){var e=t||{};this.geometry_=null,this.geometryFunction_=xp,void 0!==e.geometry&&this.setGeometry(e.geometry),this.fill_=void 0!==e.fill?e.fill:null,this.image_=void 0!==e.image?e.image:null,this.renderer_=void 0!==e.renderer?e.renderer:null,this.stroke_=void 0!==e.stroke?e.stroke:null,this.text_=void 0!==e.text?e.text:null,this.zIndex_=e.zIndex}return t.prototype.clone=function(){var e=this.getGeometry();return e&&"object"==typeof e&&(e=e.clone()),new t({geometry:e,fill:this.getFill()?this.getFill().clone():void 0,image:this.getImage()?this.getImage().clone():void 0,stroke:this.getStroke()?this.getStroke().clone():void 0,text:this.getText()?this.getText().clone():void 0,zIndex:this.getZIndex()})},t.prototype.getRenderer=function(){return this.renderer_},t.prototype.setRenderer=function(t){this.renderer_=t},t.prototype.getGeometry=function(){return this.geometry_},t.prototype.getGeometryFunction=function(){return this.geometryFunction_},t.prototype.getFill=function(){return this.fill_},t.prototype.setFill=function(t){this.fill_=t},t.prototype.getImage=function(){return this.image_},t.prototype.setImage=function(t){this.image_=t},t.prototype.getStroke=function(){return this.stroke_},t.prototype.setStroke=function(t){this.stroke_=t},t.prototype.getText=function(){return this.text_},t.prototype.setText=function(t){this.text_=t},t.prototype.getZIndex=function(){return this.zIndex_},t.prototype.setGeometry=function(t){"function"==typeof t?this.geometryFunction_=t:"string"==typeof t?this.geometryFunction_=function(e){return e.get(t)}:t?void 0!==t&&(this.geometryFunction_=function(){return t}):this.geometryFunction_=xp,this.geometry_=t},t.prototype.setZIndex=function(t){this.zIndex_=t},t}();function mp(t){var e;if("function"==typeof t)e=t;else{var r;if(Array.isArray(t))r=t;else pt("function"==typeof t.getZIndex,41),r=[t];e=function(){return r}}return e}var vp=null;function _p(t,e){if(!vp){var r=new ep({color:"rgba(255,255,255,0.4)"}),n=new gp({color:"#3399CC",width:1.25});vp=[new yp({image:new tp({fill:r,stroke:n,radius:5}),fill:r,stroke:n})]}return vp}function bp(){var t={},e=[255,255,255,1],r=[0,153,255,1];return t[bt.POLYGON]=[new yp({fill:new ep({color:[255,255,255,.5]})})],t[bt.MULTI_POLYGON]=t[bt.POLYGON],t[bt.LINE_STRING]=[new yp({stroke:new gp({color:e,width:5})}),new yp({stroke:new gp({color:r,width:3})})],t[bt.MULTI_LINE_STRING]=t[bt.LINE_STRING],t[bt.CIRCLE]=t[bt.POLYGON].concat(t[bt.LINE_STRING]),t[bt.POINT]=[new yp({image:new tp({radius:6,fill:new ep({color:r}),stroke:new gp({color:e,width:1.5})}),zIndex:1/0})],t[bt.MULTI_POINT]=t[bt.POINT],t[bt.GEOMETRY_COLLECTION]=t[bt.POLYGON].concat(t[bt.LINE_STRING],t[bt.POINT]),t}function xp(t){return t.getGeometry()}var wp=yp,Sp="point",Ep="line",Tp=function(){function t(t){var e=t||{};this.font_=e.font,this.rotation_=e.rotation,this.rotateWithView_=e.rotateWithView,this.scale_=e.scale,this.scaleArray_=Is(void 0!==e.scale?e.scale:1),this.text_=e.text,this.textAlign_=e.textAlign,this.textBaseline_=e.textBaseline,this.fill_=void 0!==e.fill?e.fill:new ep({color:"#333"}),this.maxAngle_=void 0!==e.maxAngle?e.maxAngle:Math.PI/4,this.placement_=void 0!==e.placement?e.placement:Sp,this.overflow_=!!e.overflow,this.stroke_=void 0!==e.stroke?e.stroke:null,this.offsetX_=void 0!==e.offsetX?e.offsetX:0,this.offsetY_=void 0!==e.offsetY?e.offsetY:0,this.backgroundFill_=e.backgroundFill?e.backgroundFill:null,this.backgroundStroke_=e.backgroundStroke?e.backgroundStroke:null,this.padding_=void 0===e.padding?null:e.padding}return t.prototype.clone=function(){var e=this.getScale();return new t({font:this.getFont(),placement:this.getPlacement(),maxAngle:this.getMaxAngle(),overflow:this.getOverflow(),rotation:this.getRotation(),rotateWithView:this.getRotateWithView(),scale:Array.isArray(e)?e.slice():e,text:this.getText(),textAlign:this.getTextAlign(),textBaseline:this.getTextBaseline(),fill:this.getFill()?this.getFill().clone():void 0,stroke:this.getStroke()?this.getStroke().clone():void 0,offsetX:this.getOffsetX(),offsetY:this.getOffsetY(),backgroundFill:this.getBackgroundFill()?this.getBackgroundFill().clone():void 0,backgroundStroke:this.getBackgroundStroke()?this.getBackgroundStroke().clone():void 0,padding:this.getPadding()})},t.prototype.getOverflow=function(){return this.overflow_},t.prototype.getFont=function(){return this.font_},t.prototype.getMaxAngle=function(){return this.maxAngle_},t.prototype.getPlacement=function(){return this.placement_},t.prototype.getOffsetX=function(){return this.offsetX_},t.prototype.getOffsetY=function(){return this.offsetY_},t.prototype.getFill=function(){return this.fill_},t.prototype.getRotateWithView=function(){return this.rotateWithView_},t.prototype.getRotation=function(){return this.rotation_},t.prototype.getScale=function(){return this.scale_},t.prototype.getScaleArray=function(){return this.scaleArray_},t.prototype.getStroke=function(){return this.stroke_},t.prototype.getText=function(){return this.text_},t.prototype.getTextAlign=function(){return this.textAlign_},t.prototype.getTextBaseline=function(){return this.textBaseline_},t.prototype.getBackgroundFill=function(){return this.backgroundFill_},t.prototype.getBackgroundStroke=function(){return this.backgroundStroke_},t.prototype.getPadding=function(){return this.padding_},t.prototype.setOverflow=function(t){this.overflow_=t},t.prototype.setFont=function(t){this.font_=t},t.prototype.setMaxAngle=function(t){this.maxAngle_=t},t.prototype.setOffsetX=function(t){this.offsetX_=t},t.prototype.setOffsetY=function(t){this.offsetY_=t},t.prototype.setPlacement=function(t){this.placement_=t},t.prototype.setRotateWithView=function(t){this.rotateWithView_=t},t.prototype.setFill=function(t){this.fill_=t},t.prototype.setRotation=function(t){this.rotation_=t},t.prototype.setScale=function(t){this.scale_=t,this.scaleArray_=Is(void 0!==t?t:1)},t.prototype.setStroke=function(t){this.stroke_=t},t.prototype.setText=function(t){this.text_=t},t.prototype.setTextAlign=function(t){this.textAlign_=t},t.prototype.setTextBaseline=function(t){this.textBaseline_=t},t.prototype.setBackgroundFill=function(t){this.backgroundFill_=t},t.prototype.setBackgroundStroke=function(t){this.backgroundStroke_=t},t.prototype.setPadding=function(t){this.padding_=t},t}(),Cp=function(){function t(t){this.first_,this.last_,this.head_,this.circular_=void 0===t||t,this.length_=0}return t.prototype.insertItem=function(t){var e={prev:void 0,next:void 0,data:t},r=this.head_;if(r){var n=r.next;e.prev=r,e.next=n,r.next=e,n&&(n.prev=e),r===this.last_&&(this.last_=e)}else this.first_=e,this.last_=e,this.circular_&&(e.next=e,e.prev=e);this.head_=e,this.length_++},t.prototype.removeItem=function(){var t=this.head_;if(t){var e=t.next,r=t.prev;e&&(e.prev=r),r&&(r.next=e),this.head_=e||r,this.first_===this.last_?(this.head_=void 0,this.first_=void 0,this.last_=void 0):this.first_===t?this.first_=this.head_:this.last_===t&&(this.last_=r?this.head_.prev:this.head_),this.length_--}},t.prototype.firstItem=function(){if(this.head_=this.first_,this.head_)return this.head_.data},t.prototype.lastItem=function(){if(this.head_=this.last_,this.head_)return this.head_.data},t.prototype.nextItem=function(){if(this.head_&&this.head_.next)return this.head_=this.head_.next,this.head_.data},t.prototype.getNextItem=function(){if(this.head_&&this.head_.next)return this.head_.next.data},t.prototype.prevItem=function(){if(this.head_&&this.head_.prev)return this.head_=this.head_.prev,this.head_.data},t.prototype.getPrevItem=function(){if(this.head_&&this.head_.prev)return this.head_.prev.data},t.prototype.getCurrItem=function(){if(this.head_)return this.head_.data},t.prototype.setFirstItem=function(){this.circular_&&this.head_&&(this.first_=this.head_,this.last_=this.head_.prev)},t.prototype.concat=function(t){if(t.head_){if(this.head_){var e=this.head_.next;this.head_.next=t.first_,t.first_.prev=this.head_,e.prev=t.last_,t.last_.next=e,this.length_+=t.length_}else this.head_=t.head_,this.first_=t.first_,this.last_=t.last_,this.length_=t.length_;t.head_=void 0,t.first_=void 0,t.last_=void 0,t.length_=0}},t.prototype.getLength=function(){return this.length_},t}(),Op=r(1),Pp=r.n(Op),Rp=function(){function t(t){this.rbush_=new Pp.a(t),this.items_={}}return t.prototype.insert=function(t,e){var r={minX:t[0],minY:t[1],maxX:t[2],maxY:t[3],value:e};this.rbush_.insert(r),this.items_[o(e)]=r},t.prototype.load=function(t,e){for(var r=new Array(e.length),n=0,i=e.length;n<i;n++){var a=t[n],s=e[n],l={minX:a[0],minY:a[1],maxX:a[2],maxY:a[3],value:s};r[n]=l,this.items_[o(s)]=l}this.rbush_.load(r)},t.prototype.remove=function(t){var e=o(t),r=this.items_[e];return delete this.items_[e],null!==this.rbush_.remove(r)},t.prototype.update=function(t,e){var r=this.items_[o(e)];ue([r.minX,r.minY,r.maxX,r.maxY],t)||(this.remove(e),this.insert(t,e))},t.prototype.getAll=function(){return this.rbush_.all().map((function(t){return t.value}))},t.prototype.getInExtent=function(t){var e={minX:t[0],minY:t[1],maxX:t[2],maxY:t[3]};return this.rbush_.search(e).map((function(t){return t.value}))},t.prototype.forEach=function(t){return this.forEach_(this.getAll(),t)},t.prototype.forEachInExtent=function(t,e){return this.forEach_(this.getInExtent(t),e)},t.prototype.forEach_=function(t,e){for(var r,n=0,i=t.length;n<i;n++)if(r=e(t[n]))return r;return r},t.prototype.isEmpty=function(){return I(this.items_)},t.prototype.clear=function(){this.rbush_.clear(),this.items_={}},t.prototype.getExtent=function(t){var e=this.rbush_.toJSON();return ie(e.minX,e.minY,e.maxX,e.maxY,t)},t.prototype.concat=function(t){for(var e in this.rbush_.load(t.rbush_.all()),t.items_)this.items_[e]=t.items_[e]},t}(),Ip=function(){function t(t,e,r,n,i,o){this.sourceProj_=t,this.targetProj_=e;var a={},s=Kr(this.targetProj_,this.sourceProj_);this.transformInv_=function(t){var e=t[0]+"/"+t[1];return a[e]||(a[e]=s(t)),a[e]},this.maxSourceExtent_=n,this.errorThresholdSquared_=i*i,this.triangles_=[],this.wrapsXInSource_=!1,this.canWrapXInSource_=this.sourceProj_.canWrapX()&&!!n&&!!this.sourceProj_.getExtent()&&Pe(n)==Pe(this.sourceProj_.getExtent()),this.sourceWorldWidth_=this.sourceProj_.getExtent()?Pe(this.sourceProj_.getExtent()):null,this.targetWorldWidth_=this.targetProj_.getExtent()?Pe(this.targetProj_.getExtent()):null;var l=Ce(r),u=Oe(r),c=be(r),h=_e(r),p=this.transformInv_(l),f=this.transformInv_(u),d=this.transformInv_(c),g=this.transformInv_(h),y=10+(o?Math.max(0,Math.ceil(Ge(ve(r)/(o*o*256*256)))):0);if(this.addQuad_(l,u,c,h,p,f,d,g,y),this.wrapsXInSource_){var m=1/0;this.triangles_.forEach((function(t,e,r){m=Math.min(m,t.source[0][0],t.source[1][0],t.source[2][0])})),this.triangles_.forEach(function(t){if(Math.max(t.source[0][0],t.source[1][0],t.source[2][0])-m>this.sourceWorldWidth_/2){var e=[[t.source[0][0],t.source[0][1]],[t.source[1][0],t.source[1][1]],[t.source[2][0],t.source[2][1]]];e[0][0]-m>this.sourceWorldWidth_/2&&(e[0][0]-=this.sourceWorldWidth_),e[1][0]-m>this.sourceWorldWidth_/2&&(e[1][0]-=this.sourceWorldWidth_),e[2][0]-m>this.sourceWorldWidth_/2&&(e[2][0]-=this.sourceWorldWidth_);var r=Math.min(e[0][0],e[1][0],e[2][0]);Math.max(e[0][0],e[1][0],e[2][0])-r<this.sourceWorldWidth_/2&&(t.source=e)}}.bind(this))}a={}}return t.prototype.addTriangle_=function(t,e,r,n,i,o){this.triangles_.push({source:[n,i,o],target:[t,e,r]})},t.prototype.addQuad_=function(t,e,r,n,i,o,a,s,l){var u=Kt([i,o,a,s]),c=this.sourceWorldWidth_?Pe(u)/this.sourceWorldWidth_:null,h=this.sourceWorldWidth_,p=this.sourceProj_.canWrapX()&&c>.5&&c<1,f=!1;if(l>0){if(this.targetProj_.isGlobal()&&this.targetWorldWidth_)f=Pe(Kt([t,e,r,n]))/this.targetWorldWidth_>.25||f;!p&&this.sourceProj_.isGlobal()&&c&&(f=c>.25||f)}if(!(!f&&this.maxSourceExtent_&&isFinite(u[0])&&isFinite(u[1])&&isFinite(u[2])&&isFinite(u[3]))||Re(u,this.maxSourceExtent_)){var d=0;if(!(f||isFinite(i[0])&&isFinite(i[1])&&isFinite(o[0])&&isFinite(o[1])&&isFinite(a[0])&&isFinite(a[1])&&isFinite(s[0])&&isFinite(s[1])))if(l>0)f=!0;else if(1!=(d=(isFinite(i[0])&&isFinite(i[1])?0:8)+(isFinite(o[0])&&isFinite(o[1])?0:4)+(isFinite(a[0])&&isFinite(a[1])?0:2)+(isFinite(s[0])&&isFinite(s[1])?0:1))&&2!=d&&4!=d&&8!=d)return;if(l>0){if(!f){var g=[(t[0]+r[0])/2,(t[1]+r[1])/2],y=this.transformInv_(g),m=void 0;if(p)m=(We(i[0],h)+We(a[0],h))/2-We(y[0],h);else m=(i[0]+a[0])/2-y[0];var v=(i[1]+a[1])/2-y[1];f=m*m+v*v>this.errorThresholdSquared_}if(f){if(Math.abs(t[0]-r[0])<=Math.abs(t[1]-r[1])){var _=[(e[0]+r[0])/2,(e[1]+r[1])/2],b=this.transformInv_(_),x=[(n[0]+t[0])/2,(n[1]+t[1])/2],w=this.transformInv_(x);this.addQuad_(t,e,_,x,i,o,b,w,l-1),this.addQuad_(x,_,r,n,w,b,a,s,l-1)}else{var S=[(t[0]+e[0])/2,(t[1]+e[1])/2],E=this.transformInv_(S),T=[(r[0]+n[0])/2,(r[1]+n[1])/2],C=this.transformInv_(T);this.addQuad_(t,S,T,n,i,E,C,s,l-1),this.addQuad_(S,e,r,T,E,o,a,C,l-1)}return}}if(p){if(!this.canWrapXInSource_)return;this.wrapsXInSource_=!0}0==(11&d)&&this.addTriangle_(t,r,n,i,a,s),0==(14&d)&&this.addTriangle_(t,r,e,i,a,o),d&&(0==(13&d)&&this.addTriangle_(e,n,t,o,s,i),0==(7&d)&&this.addTriangle_(e,n,r,o,s,a))}},t.prototype.calculateSourceExtent=function(){var t=[1/0,1/0,-1/0,-1/0];return this.triangles_.forEach((function(e,r,n){var i=e.source;pe(t,i[0]),pe(t,i[1]),pe(t,i[2])})),t},t.prototype.getTriangles=function(){return this.triangles_},t}(),Lp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Mp=function(t){function e(e,r,n,i,o,a,s,l,u,c,h,p){var f=t.call(this,o,Ji)||this;f.renderEdges_=void 0!==h&&h,f.contextOptions_=p,f.pixelRatio_=s,f.gutter_=l,f.canvas_=null,f.sourceTileGrid_=r,f.targetTileGrid_=i,f.wrappedTileCoord_=a||o,f.sourceTiles_=[],f.sourcesListenerKeys_=null,f.sourceZ_=0;var d=i.getTileCoordExtent(f.wrappedTileCoord_),g=f.targetTileGrid_.getExtent(),y=f.sourceTileGrid_.getExtent(),m=g?Te(d,g):d;if(0===ve(m))return f.state=ro,f;var v=e.getExtent();v&&(y=y?Te(y,v):v);var _=i.getResolution(f.wrappedTileCoord_[0]),b=ec(e,n,m,_);if(!isFinite(b)||b<=0)return f.state=ro,f;var x=void 0!==c?c:.5;if(f.triangulation_=new Ip(e,n,m,y,b*x,_),0===f.triangulation_.getTriangles().length)return f.state=ro,f;f.sourceZ_=r.getZForResolution(b);var w=f.triangulation_.calculateSourceExtent();if(y&&(e.canWrapX()?(w[1]=Ne(w[1],y[1],y[3]),w[3]=Ne(w[3],y[1],y[3])):w=Te(w,y)),ve(w)){for(var S=r.getTileRangeForExtentAndZ(w,f.sourceZ_),E=S.minX;E<=S.maxX;E++)for(var T=S.minY;T<=S.maxY;T++){var C=u(f.sourceZ_,E,T,s);C&&f.sourceTiles_.push(C)}0===f.sourceTiles_.length&&(f.state=ro)}else f.state=ro;return f}return Lp(e,t),e.prototype.getImage=function(){return this.canvas_},e.prototype.reproject_=function(){var t=[];if(this.sourceTiles_.forEach(function(e,r,n){e&&e.getState()==to&&t.push({extent:this.sourceTileGrid_.getTileCoordExtent(e.tileCoord),image:e.getImage()})}.bind(this)),this.sourceTiles_.length=0,0===t.length)this.state=eo;else{var e=this.wrappedTileCoord_[0],r=this.targetTileGrid_.getTileSize(e),n="number"==typeof r?r:r[0],i="number"==typeof r?r:r[1],o=this.targetTileGrid_.getResolution(e),a=this.sourceTileGrid_.getResolution(this.sourceZ_),s=this.targetTileGrid_.getTileCoordExtent(this.wrappedTileCoord_);this.canvas_=rc(n,i,this.pixelRatio_,a,this.sourceTileGrid_.getExtent(),o,s,this.triangulation_,t,this.gutter_,this.renderEdges_,this.contextOptions_),this.state=to}this.changed()},e.prototype.load=function(){if(this.state==Ji){this.state=Qi,this.changed();var t=0;this.sourcesListenerKeys_=[],this.sourceTiles_.forEach(function(e,r,n){var i=e.getState();if(i==Ji||i==Qi){t++;var o=Z(e,F,(function(r){var n=e.getState();n!=to&&n!=eo&&n!=ro||(H(o),0===--t&&(this.unlistenSources_(),this.reproject_()))}),this);this.sourcesListenerKeys_.push(o)}}.bind(this)),this.sourceTiles_.forEach((function(t,e,r){t.getState()==Ji&&t.load()})),0===t&&setTimeout(this.reproject_.bind(this),0)}},e.prototype.unlistenSources_=function(){this.sourcesListenerKeys_.forEach(H),this.sourcesListenerKeys_=null},e}(lo),Fp="tileloadstart",Ap="tileloadend",kp="tileloaderror",jp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Np(t){return t?Array.isArray(t)?function(e){return t}:"function"==typeof t?t:function(e){return[t]}:null}var Dp=function(t){function e(e){var r=t.call(this)||this;return r.projection_=Gr(e.projection),r.attributions_=Np(e.attributions),r.attributionsCollapsible_=void 0===e.attributionsCollapsible||e.attributionsCollapsible,r.loading=!1,r.state_=void 0!==e.state?e.state:Qo,r.wrapX_=void 0!==e.wrapX&&e.wrapX,r}return jp(e,t),e.prototype.getAttributions=function(){return this.attributions_},e.prototype.getAttributionsCollapsible=function(){return this.attributionsCollapsible_},e.prototype.getProjection=function(){return this.projection_},e.prototype.getResolutions=function(){return n()},e.prototype.getState=function(){return this.state_},e.prototype.getWrapX=function(){return this.wrapX_},e.prototype.getContextOptions=function(){},e.prototype.refresh=function(){this.changed()},e.prototype.setAttributions=function(t){this.attributions_=Np(t),this.changed()},e.prototype.setState=function(t){this.state_=t,this.changed()},e}(ot),Gp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),zp=function(t){function e(e){var r=t.call(this,{attributions:e.attributions,attributionsCollapsible:e.attributionsCollapsible,projection:e.projection,state:e.state,wrapX:e.wrapX})||this;r.opaque_=void 0!==e.opaque&&e.opaque,r.tilePixelRatio_=void 0!==e.tilePixelRatio?e.tilePixelRatio:1,r.tileGrid=void 0!==e.tileGrid?e.tileGrid:null;var n=e.tileGrid;return n&&Is(n.getTileSize(n.getMinZoom()),[256,256]),r.tileCache=new yu(e.cacheSize||0),r.tmpSize=[0,0],r.key_=e.key||"",r.tileOptions={transition:e.transition},r.zDirection=e.zDirection?e.zDirection:0,r}return Gp(e,t),e.prototype.canExpireCache=function(){return this.tileCache.canExpireCache()},e.prototype.expireCache=function(t,e){var r=this.getTileCacheForProjection(t);r&&r.expireCache(e)},e.prototype.forEachLoadedTile=function(t,e,r,n){var i=this.getTileCacheForProjection(t);if(!i)return!1;for(var o,a,s,l=!0,u=r.minX;u<=r.maxX;++u)for(var c=r.minY;c<=r.maxY;++c)a=cu(e,u,c),s=!1,i.containsKey(a)&&(s=(o=i.get(a)).getState()===to)&&(s=!1!==n(o)),s||(l=!1);return l},e.prototype.getGutterForProjection=function(t){return 0},e.prototype.getKey=function(){return this.key_},e.prototype.setKey=function(t){this.key_!==t&&(this.key_=t,this.changed())},e.prototype.getOpaque=function(t){return this.opaque_},e.prototype.getResolutions=function(){return this.tileGrid.getResolutions()},e.prototype.getTile=function(t,e,r,i,o){return n()},e.prototype.getTileGrid=function(){return this.tileGrid},e.prototype.getTileGridForProjection=function(t){return this.tileGrid?this.tileGrid:oc(t)},e.prototype.getTileCacheForProjection=function(t){return pt(Xr(this.getProjection(),t),68),this.tileCache},e.prototype.getTilePixelRatio=function(t){return this.tilePixelRatio_},e.prototype.getTilePixelSize=function(t,e,r){var n=this.getTileGridForProjection(r),i=this.getTilePixelRatio(e),o=Is(n.getTileSize(t),this.tmpSize);return 1==i?o:Rs(o,i,this.tmpSize)},e.prototype.getTileCoordForTileUrlFunction=function(t,e){var r=void 0!==e?e:this.getProjection(),n=this.getTileGridForProjection(r);return this.getWrapX()&&r.isGlobal()&&(t=ac(n,t,r)),du(t,n)?t:null},e.prototype.clear=function(){this.tileCache.clear()},e.prototype.refresh=function(){this.clear(),t.prototype.refresh.call(this)},e.prototype.updateCacheSize=function(t,e){var r=this.getTileCacheForProjection(e);t>r.highWaterMark&&(r.highWaterMark=t)},e.prototype.useTile=function(t,e,r,n){},e}(Dp),Up=function(t){function e(e,r){var n=t.call(this,e)||this;return n.tile=r,n}return Gp(e,t),e}(c),Bp=zp,Vp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Yp=function(t){function e(r){var n=t.call(this,{attributions:r.attributions,cacheSize:r.cacheSize,opaque:r.opaque,projection:r.projection,state:r.state,tileGrid:r.tileGrid,tilePixelRatio:r.tilePixelRatio,wrapX:r.wrapX,transition:r.transition,key:r.key,attributionsCollapsible:r.attributionsCollapsible,zDirection:r.zDirection})||this;return n.generateTileUrlFunction_=n.tileUrlFunction===e.prototype.tileUrlFunction,n.tileLoadFunction=r.tileLoadFunction,r.tileUrlFunction&&(n.tileUrlFunction=r.tileUrlFunction),n.urls=null,r.urls?n.setUrls(r.urls):r.url&&n.setUrl(r.url),n.tileLoadingKeys_={},n}return Vp(e,t),e.prototype.getTileLoadFunction=function(){return this.tileLoadFunction},e.prototype.getTileUrlFunction=function(){return Object.getPrototypeOf(this).tileUrlFunction===this.tileUrlFunction?this.tileUrlFunction.bind(this):this.tileUrlFunction},e.prototype.getUrls=function(){return this.urls},e.prototype.handleTileChange=function(t){var e,r=t.target,n=o(r),i=r.getState();i==Qi?(this.tileLoadingKeys_[n]=!0,e=Fp):n in this.tileLoadingKeys_&&(delete this.tileLoadingKeys_[n],e=i==eo?kp:i==to?Ap:void 0),null!=e&&this.dispatchEvent(new Up(e,r))},e.prototype.setTileLoadFunction=function(t){this.tileCache.clear(),this.tileLoadFunction=t,this.changed()},e.prototype.setTileUrlFunction=function(t,e){this.tileUrlFunction=t,this.tileCache.pruneExceptNewestZ(),void 0!==e?this.setKey(e):this.changed()},e.prototype.setUrl=function(t){var e=yc(t);this.urls=e,this.setUrls(e)},e.prototype.setUrls=function(t){this.urls=t;var e=t.join("\n");this.generateTileUrlFunction_?this.setTileUrlFunction(fc(t,this.tileGrid),e):this.setKey(e)},e.prototype.tileUrlFunction=function(t,e,r){},e.prototype.useTile=function(t,e,r){var n=cu(t,e,r);this.tileCache.containsKey(n)&&this.tileCache.get(n)},e}(Bp),Wp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function qp(t,e){t.getImage().src=e}var Xp=function(t){function e(e){var r=t.call(this,{attributions:e.attributions,cacheSize:e.cacheSize,opaque:e.opaque,projection:e.projection,state:e.state,tileGrid:e.tileGrid,tileLoadFunction:e.tileLoadFunction?e.tileLoadFunction:qp,tilePixelRatio:e.tilePixelRatio,tileUrlFunction:e.tileUrlFunction,url:e.url,urls:e.urls,wrapX:e.wrapX,transition:e.transition,key:e.key,attributionsCollapsible:e.attributionsCollapsible,zDirection:e.zDirection})||this;return r.crossOrigin=void 0!==e.crossOrigin?e.crossOrigin:null,r.tileClass=void 0!==e.tileClass?e.tileClass:vo,r.tileCacheForProjection={},r.tileGridForProjection={},r.reprojectionErrorThreshold_=e.reprojectionErrorThreshold,r.contextOptions_=!1===e.imageSmoothing?$u:void 0,r.renderReprojectionEdges_=!1,r}return Wp(e,t),e.prototype.canExpireCache=function(){if(this.tileCache.canExpireCache())return!0;for(var t in this.tileCacheForProjection)if(this.tileCacheForProjection[t].canExpireCache())return!0;return!1},e.prototype.expireCache=function(t,e){var r=this.getTileCacheForProjection(t);for(var n in this.tileCache.expireCache(this.tileCache==r?e:{}),this.tileCacheForProjection){var i=this.tileCacheForProjection[n];i.expireCache(i==r?e:{})}},e.prototype.getContextOptions=function(){return this.contextOptions_},e.prototype.getGutterForProjection=function(t){return this.getProjection()&&t&&!Xr(this.getProjection(),t)?0:this.getGutter()},e.prototype.getGutter=function(){return 0},e.prototype.getKey=function(){return t.prototype.getKey.call(this)+(this.contextOptions_?"\n"+JSON.stringify(this.contextOptions_):"")},e.prototype.getOpaque=function(e){return!(this.getProjection()&&e&&!Xr(this.getProjection(),e))&&t.prototype.getOpaque.call(this,e)},e.prototype.getTileGridForProjection=function(t){var e=this.getProjection();if(!this.tileGrid||e&&!Xr(e,t)){var r=o(t);return r in this.tileGridForProjection||(this.tileGridForProjection[r]=oc(t)),this.tileGridForProjection[r]}return this.tileGrid},e.prototype.getTileCacheForProjection=function(t){var e=this.getProjection();if(!e||Xr(e,t))return this.tileCache;var r=o(t);return r in this.tileCacheForProjection||(this.tileCacheForProjection[r]=new yu(this.tileCache.highWaterMark)),this.tileCacheForProjection[r]},e.prototype.createTile_=function(t,e,r,n,i,o){var a=[t,e,r],s=this.getTileCoordForTileUrlFunction(a,i),l=s?this.tileUrlFunction(s,n,i):void 0,u=new this.tileClass(a,void 0!==l?Ji:ro,void 0!==l?l:"",this.crossOrigin,this.tileLoadFunction,this.tileOptions);return u.key=o,u.addEventListener(F,this.handleTileChange.bind(this)),u},e.prototype.getTile=function(t,e,r,n,i){var o=this.getProjection();if(o&&i&&!Xr(o,i)){var a=this.getTileCacheForProjection(i),s=[t,e,r],l=void 0,u=hu(s);a.containsKey(u)&&(l=a.get(u));var c=this.getKey();if(l&&l.key==c)return l;var h=this.getTileGridForProjection(o),p=this.getTileGridForProjection(i),f=this.getTileCoordForTileUrlFunction(s,i),d=new Mp(o,h,i,p,s,f,this.getTilePixelRatio(n),this.getGutter(),function(t,e,r,n){return this.getTileInternal(t,e,r,n,o)}.bind(this),this.reprojectionErrorThreshold_,this.renderReprojectionEdges_,this.contextOptions_);return d.key=c,l?(d.interimTile=l,d.refreshInterimChain(),a.replace(u,d)):a.set(u,d),d}return this.getTileInternal(t,e,r,n,o||i)},e.prototype.getTileInternal=function(t,e,r,n,i){var o=null,a=cu(t,e,r),s=this.getKey();if(this.tileCache.containsKey(a)){if((o=this.tileCache.get(a)).key!=s){var l=o;o=this.createTile_(t,e,r,n,i,s),l.getState()==Ji?o.interimTile=l.interimTile:o.interimTile=l,o.refreshInterimChain(),this.tileCache.replace(a,o)}}else o=this.createTile_(t,e,r,n,i,s),this.tileCache.set(a,o);return o},e.prototype.setRenderReprojectionEdges=function(t){if(this.renderReprojectionEdges_!=t){for(var e in this.renderReprojectionEdges_=t,this.tileCacheForProjection)this.tileCacheForProjection[e].clear();this.changed()}},e.prototype.setTileGridForProjection=function(t,e){var r=Gr(t);if(r){var n=o(r);n in this.tileGridForProjection||(this.tileGridForProjection[n]=e)}},e}(Yp),Zp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Kp(t){var e,r,n=t[0],i=new Array(n),o=1<<n-1;for(e=0;e<n;++e)r=48,t[1]&o&&(r+=1),t[2]&o&&(r+=2),i[e]=String.fromCharCode(r),o>>=1;return i.join("")}var Hp=function(t){function e(e){var r=this,n=void 0!==e.hidpi&&e.hidpi;return(r=t.call(this,{cacheSize:e.cacheSize,crossOrigin:"anonymous",imageSmoothing:e.imageSmoothing,opaque:!0,projection:Gr("EPSG:3857"),reprojectionErrorThreshold:e.reprojectionErrorThreshold,state:Jo,tileLoadFunction:e.tileLoadFunction,tilePixelRatio:n?2:1,wrapX:void 0===e.wrapX||e.wrapX,transition:e.transition})||this).hidpi_=n,r.culture_=void 0!==e.culture?e.culture:"en-us",r.maxZoom_=void 0!==e.maxZoom?e.maxZoom:-1,r.apiKey_=e.key,r.imagerySet_=e.imagerySet,Au("https://dev.virtualearth.net/REST/v1/Imagery/Metadata/"+r.imagerySet_+"?uriScheme=https&include=ImageryProviders&key="+r.apiKey_+"&c="+r.culture_,r.handleImageryMetadataResponse.bind(r),void 0,"jsonp"),r}return Zp(e,t),e.prototype.getApiKey=function(){return this.apiKey_},e.prototype.getImagerySet=function(){return this.imagerySet_},e.prototype.handleImageryMetadataResponse=function(t){if(200==t.statusCode&&"OK"==t.statusDescription&&"ValidCredentials"==t.authenticationResultCode&&1==t.resourceSets.length&&1==t.resourceSets[0].resources.length){var e=t.resourceSets[0].resources[0],r=-1==this.maxZoom_?e.zoomMax:this.maxZoom_,n=hc(this.getProjection()),i=this.hidpi_?2:1,o=e.imageWidth==e.imageHeight?e.imageWidth/i:[e.imageWidth/i,e.imageHeight/i],a=lc({extent:n,minZoom:e.zoomMin,maxZoom:r,tileSize:o});this.tileGrid=a;var s=this.culture_,l=this.hidpi_;if(this.tileUrlFunction=dc(e.imageUrlSubdomains.map((function(t){var r=[0,0,0],n=e.imageUrl.replace("{subdomain}",t).replace("{culture}",s);return function(t,e,i){if(t){uu(t[0],t[1],t[2],r);var o=n;return l&&(o+="&dpi=d1&device=mobile"),o.replace("{quadkey}",Kp(r))}}}))),e.imageryProviders){var u=Zr(Gr("EPSG:4326"),this.getProjection());this.setAttributions(function(t){var r=[],n=t.viewState,i=this.getTileGrid(),o=i.getZForResolution(n.resolution,this.zDirection),a=i.getTileCoordForCoordAndZ(n.center,o)[0];return e.imageryProviders.map((function(e){for(var n=!1,i=e.coverageAreas,o=0,s=i.length;o<s;++o){var l=i[o];if(a>=l.zoomMin&&a<=l.zoomMax){var c=l.bbox;if(Re(Ae([c[1],c[0],c[3],c[2]],u),t.extent)){n=!0;break}}}n&&r.push(e.attribution)})),r.push('<a class="ol-attribution-bing-tos" href="https://www.microsoft.com/maps/product/terms.html" target="_blank">Terms of Use</a>'),r}.bind(this))}this.setState(Qo)}else this.setState(ta)},e}(Xp),$p=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Jp=function(t){function e(e){var r=e||{},n=void 0!==r.projection?r.projection:"EPSG:3857",i=void 0!==r.tileGrid?r.tileGrid:lc({extent:hc(n),maxResolution:r.maxResolution,maxZoom:r.maxZoom,minZoom:r.minZoom,tileSize:r.tileSize});return t.call(this,{attributions:r.attributions,cacheSize:r.cacheSize,crossOrigin:r.crossOrigin,imageSmoothing:r.imageSmoothing,opaque:r.opaque,projection:n,reprojectionErrorThreshold:r.reprojectionErrorThreshold,tileGrid:i,tileLoadFunction:r.tileLoadFunction,tilePixelRatio:r.tilePixelRatio,tileUrlFunction:r.tileUrlFunction,url:r.url,urls:r.urls,wrapX:void 0===r.wrapX||r.wrapX,transition:r.transition,attributionsCollapsible:r.attributionsCollapsible,zDirection:r.zDirection})||this}return $p(e,t),e}(Xp),Qp=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),tf=function(t){function e(e){var r=t.call(this,{attributions:e.attributions,cacheSize:e.cacheSize,crossOrigin:e.crossOrigin,maxZoom:void 0!==e.maxZoom?e.maxZoom:18,minZoom:e.minZoom,projection:e.projection,transition:e.transition,wrapX:e.wrapX})||this;return r.account_=e.account,r.mapId_=e.map||"",r.config_=e.config||{},r.templateCache_={},r.initializeMap_(),r}return Qp(e,t),e.prototype.getConfig=function(){return this.config_},e.prototype.updateConfig=function(t){O(this.config_,t),this.initializeMap_()},e.prototype.setConfig=function(t){this.config_=t||{},this.initializeMap_()},e.prototype.initializeMap_=function(){var t=JSON.stringify(this.config_);if(this.templateCache_[t])this.applyTemplate_(this.templateCache_[t]);else{var e="https://"+this.account_+".carto.com/api/v1/map";this.mapId_&&(e+="/named/"+this.mapId_);var r=new XMLHttpRequest;r.addEventListener("load",this.handleInitResponse_.bind(this,t)),r.addEventListener("error",this.handleInitError_.bind(this)),r.open("POST",e),r.setRequestHeader("Content-type","application/json"),r.send(JSON.stringify(this.config_))}},e.prototype.handleInitResponse_=function(t,e){var r=e.target;if(!r.status||r.status>=200&&r.status<300){var n=void 0;try{n=JSON.parse(r.responseText)}catch(t){return void this.setState(ta)}this.applyTemplate_(n),this.templateCache_[t]=n,this.setState(Qo)}else this.setState(ta)},e.prototype.handleInitError_=function(t){this.setState(ta)},e.prototype.applyTemplate_=function(t){var e="https://"+t.cdn_url.https+"/"+this.account_+"/api/v1/map/"+t.layergroupid+"/{z}/{x}/{y}.png";this.setUrl(e)},e}(Jp),ef="addfeature",rf="changefeature",nf="clear",of="removefeature",af="featuresloadstart",sf="featuresloadend",lf="featuresloaderror",uf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),cf=function(t){function e(e,r,n){var i=t.call(this,e)||this;return i.feature=r,i.features=n,i}return uf(e,t),e}(c),hf=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,{attributions:n.attributions,projection:void 0,state:Qo,wrapX:void 0===n.wrapX||n.wrapX})||this).loader_=T,r.format_=n.format,r.overlaps_=void 0===n.overlaps||n.overlaps,r.url_=n.url,void 0!==n.loader?r.loader_=n.loader:void 0!==r.url_&&(pt(r.format_,7),r.loader_=Mu(r.url_,r.format_)),r.strategy_=void 0!==n.strategy?n.strategy:Fu;var i,o,a=void 0===n.useSpatialIndex||n.useSpatialIndex;return r.featuresRtree_=a?new Rp:null,r.loadedExtentsRtree_=new Rp,r.nullGeometryFeatures_={},r.idIndex_={},r.uidIndex_={},r.featureChangeKeys_={},r.featuresCollection_=null,Array.isArray(n.features)?o=n.features:n.features&&(o=(i=n.features).getArray()),a||void 0!==i||(i=new ht(o)),void 0!==o&&r.addFeaturesInternal(o),void 0!==i&&r.bindFeaturesCollection_(i),r}return uf(e,t),e.prototype.addFeature=function(t){this.addFeatureInternal(t),this.changed()},e.prototype.addFeatureInternal=function(t){var e=o(t);if(this.addToIndex_(e,t)){this.setupChangeEvents_(e,t);var r=t.getGeometry();if(r){var n=r.getExtent();this.featuresRtree_&&this.featuresRtree_.insert(n,t)}else this.nullGeometryFeatures_[e]=t;this.dispatchEvent(new cf(ef,t))}else this.featuresCollection_&&this.featuresCollection_.remove(t)},e.prototype.setupChangeEvents_=function(t,e){this.featureChangeKeys_[t]=[Z(e,F,this.handleFeatureChange_,this),Z(e,h,this.handleFeatureChange_,this)]},e.prototype.addToIndex_=function(t,e){var r=!0,n=e.getId();return void 0!==n&&(n.toString()in this.idIndex_?r=!1:this.idIndex_[n.toString()]=e),r&&(pt(!(t in this.uidIndex_),30),this.uidIndex_[t]=e),r},e.prototype.addFeatures=function(t){this.addFeaturesInternal(t),this.changed()},e.prototype.addFeaturesInternal=function(t){for(var e=[],r=[],n=[],i=0,a=t.length;i<a;i++){var s=o(u=t[i]);this.addToIndex_(s,u)&&r.push(u)}i=0;for(var l=r.length;i<l;i++){var u;s=o(u=r[i]);this.setupChangeEvents_(s,u);var c=u.getGeometry();if(c){var h=c.getExtent();e.push(h),n.push(u)}else this.nullGeometryFeatures_[s]=u}this.featuresRtree_&&this.featuresRtree_.load(e,n);i=0;for(var p=r.length;i<p;i++)this.dispatchEvent(new cf(ef,r[i]))},e.prototype.bindFeaturesCollection_=function(t){var e=!1;this.addEventListener(ef,(function(r){e||(e=!0,t.push(r.feature),e=!1)})),this.addEventListener(of,(function(r){e||(e=!0,t.remove(r.feature),e=!1)})),t.addEventListener(at,function(t){e||(e=!0,this.addFeature(t.element),e=!1)}.bind(this)),t.addEventListener(st,function(t){e||(e=!0,this.removeFeature(t.element),e=!1)}.bind(this)),this.featuresCollection_=t},e.prototype.clear=function(t){if(t){for(var e in this.featureChangeKeys_){this.featureChangeKeys_[e].forEach(H)}this.featuresCollection_||(this.featureChangeKeys_={},this.idIndex_={},this.uidIndex_={})}else if(this.featuresRtree_)for(var r in this.featuresRtree_.forEach(this.removeFeatureInternal.bind(this)),this.nullGeometryFeatures_)this.removeFeatureInternal(this.nullGeometryFeatures_[r]);this.featuresCollection_&&this.featuresCollection_.clear(),this.featuresRtree_&&this.featuresRtree_.clear(),this.nullGeometryFeatures_={};var n=new cf(nf);this.dispatchEvent(n),this.changed()},e.prototype.forEachFeature=function(t){if(this.featuresRtree_)return this.featuresRtree_.forEach(t);this.featuresCollection_&&this.featuresCollection_.forEach(t)},e.prototype.forEachFeatureAtCoordinateDirect=function(t,e){var r=[t[0],t[1],t[0],t[1]];return this.forEachFeatureInExtent(r,(function(r){return r.getGeometry().intersectsCoordinate(t)?e(r):void 0}))},e.prototype.forEachFeatureInExtent=function(t,e){if(this.featuresRtree_)return this.featuresRtree_.forEachInExtent(t,e);this.featuresCollection_&&this.featuresCollection_.forEach(e)},e.prototype.forEachFeatureIntersectingExtent=function(t,e){return this.forEachFeatureInExtent(t,(function(r){if(r.getGeometry().intersectsExtent(t)){var n=e(r);if(n)return n}}))},e.prototype.getFeaturesCollection=function(){return this.featuresCollection_},e.prototype.getFeatures=function(){var t;return this.featuresCollection_?t=this.featuresCollection_.getArray():this.featuresRtree_&&(t=this.featuresRtree_.getAll(),I(this.nullGeometryFeatures_)||v(t,R(this.nullGeometryFeatures_))),t},e.prototype.getFeaturesAtCoordinate=function(t){var e=[];return this.forEachFeatureAtCoordinateDirect(t,(function(t){e.push(t)})),e},e.prototype.getFeaturesInExtent=function(t){return this.featuresRtree_?this.featuresRtree_.getInExtent(t):this.featuresCollection_?this.featuresCollection_.getArray():[]},e.prototype.getClosestFeatureToCoordinate=function(t,e){var r=t[0],n=t[1],i=null,o=[NaN,NaN],a=1/0,s=[-1/0,-1/0,1/0,1/0],l=e||S;return this.featuresRtree_.forEachInExtent(s,(function(t){if(l(t)){var e=t.getGeometry(),u=a;if((a=e.closestPointXY(r,n,o,a))<u){i=t;var c=Math.sqrt(a);s[0]=r-c,s[1]=n-c,s[2]=r+c,s[3]=n+c}}})),i},e.prototype.getExtent=function(t){return this.featuresRtree_.getExtent(t)},e.prototype.getFeatureById=function(t){var e=this.idIndex_[t.toString()];return void 0!==e?e:null},e.prototype.getFeatureByUid=function(t){var e=this.uidIndex_[t];return void 0!==e?e:null},e.prototype.getFormat=function(){return this.format_},e.prototype.getOverlaps=function(){return this.overlaps_},e.prototype.getUrl=function(){return this.url_},e.prototype.handleFeatureChange_=function(t){var e=t.target,r=o(e),n=e.getGeometry();if(n){var i=n.getExtent();r in this.nullGeometryFeatures_?(delete this.nullGeometryFeatures_[r],this.featuresRtree_&&this.featuresRtree_.insert(i,e)):this.featuresRtree_&&this.featuresRtree_.update(i,e)}else r in this.nullGeometryFeatures_||(this.featuresRtree_&&this.featuresRtree_.remove(e),this.nullGeometryFeatures_[r]=e);var a=e.getId();if(void 0!==a){var s=a.toString();this.idIndex_[s]!==e&&(this.removeFromIdIndex_(e),this.idIndex_[s]=e)}else this.removeFromIdIndex_(e),this.uidIndex_[r]=e;this.changed(),this.dispatchEvent(new cf(rf,e))},e.prototype.hasFeature=function(t){var e=t.getId();return void 0!==e?e in this.idIndex_:o(t)in this.uidIndex_},e.prototype.isEmpty=function(){return this.featuresRtree_.isEmpty()&&I(this.nullGeometryFeatures_)},e.prototype.loadFeatures=function(t,e,r){var n=this.loadedExtentsRtree_,i=this.strategy_(t,e);this.loading=!1;for(var o=function(t,o){var s=i[t];n.forEachInExtent(s,(function(t){return te(t.extent,s)}))||(a.dispatchEvent(new cf(af)),a.loader_.call(a,s,e,r,function(t){this.dispatchEvent(new cf(sf,void 0,t))}.bind(a),function(){this.dispatchEvent(new cf(lf))}.bind(a)),n.insert(s,{extent:s.slice()}),a.loading=a.loader_!==T)},a=this,s=0,l=i.length;s<l;++s)o(s)},e.prototype.refresh=function(){this.clear(!0),this.loadedExtentsRtree_.clear(),t.prototype.refresh.call(this)},e.prototype.removeLoadedExtent=function(t){var e,r=this.loadedExtentsRtree_;r.forEachInExtent(t,(function(r){if(ue(r.extent,t))return e=r,!0})),e&&r.remove(e)},e.prototype.removeFeature=function(t){var e=o(t);e in this.nullGeometryFeatures_?delete this.nullGeometryFeatures_[e]:this.featuresRtree_&&this.featuresRtree_.remove(t),this.removeFeatureInternal(t),this.changed()},e.prototype.removeFeatureInternal=function(t){var e=o(t);this.featureChangeKeys_[e].forEach(H),delete this.featureChangeKeys_[e];var r=t.getId();void 0!==r&&delete this.idIndex_[r.toString()],delete this.uidIndex_[e],this.dispatchEvent(new cf(of,t))},e.prototype.removeFromIdIndex_=function(t){var e=!1;for(var r in this.idIndex_)if(this.idIndex_[r]===t){delete this.idIndex_[r],e=!0;break}return e},e.prototype.setLoader=function(t){this.loader_=t},e.prototype.setUrl=function(t){pt(this.format_,7),this.setLoader(Mu(t,this.format_))},e}(Dp),pf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ff=function(t){function e(e){var r=t.call(this,{attributions:e.attributions,wrapX:e.wrapX})||this;return r.resolution=void 0,r.distance=void 0!==e.distance?e.distance:20,r.features=[],r.geometryFunction=e.geometryFunction||function(t){var e=t.getGeometry();return pt(e.getType()==bt.POINT,10),e},r.boundRefresh_=r.refresh.bind(r),r.setSource(e.source||null),r}return pf(e,t),e.prototype.clear=function(e){this.features.length=0,t.prototype.clear.call(this,e)},e.prototype.getDistance=function(){return this.distance},e.prototype.getSource=function(){return this.source},e.prototype.loadFeatures=function(t,e,r){this.source.loadFeatures(t,e,r),e!==this.resolution&&(this.clear(),this.resolution=e,this.cluster(),this.addFeatures(this.features))},e.prototype.setDistance=function(t){this.distance=t,this.refresh()},e.prototype.setSource=function(t){this.source&&this.source.removeEventListener(F,this.boundRefresh_),this.source=t,t&&t.addEventListener(F,this.boundRefresh_),this.refresh()},e.prototype.refresh=function(){this.clear(),this.cluster(),this.addFeatures(this.features)},e.prototype.cluster=function(){if(void 0!==this.resolution&&this.source)for(var t=[1/0,1/0,-1/0,-1/0],e=this.distance*this.resolution,r=this.source.getFeatures(),n={},i=0,a=r.length;i<a;i++){var s=r[i];if(!(o(s)in n)){var l=this.geometryFunction(s);if(l){ae(l.getCoordinates(),t),Ht(t,e,t);var u=this.source.getFeaturesInExtent(t);u=u.filter((function(t){var e=o(t);return!(e in n)&&(n[e]=!0,!0)})),this.features.push(this.createCluster(u))}}}},e.prototype.createCluster=function(t){for(var e=[0,0],r=t.length-1;r>=0;--r){var n=this.geometryFunction(t[r]);n?xr(e,n.getCoordinates()):t.splice(r,1)}Pr(e,1/t.length);var i=new gt(new qn(e));return i.set("features",t),i},e}(hf),df=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),gf="default",yf="truncated",mf=function(t){function e(e,r,n,i,o,a,s){var l=t.call(this,r,n,i,o,a,s)||this;return l.zoomifyImage_=null,l.tileSize_=e,l}return df(e,t),e.prototype.getImage=function(){if(this.zoomifyImage_)return this.zoomifyImage_;var e=t.prototype.getImage.call(this);if(this.state==to){var r=this.tileSize_;if(e.width==r[0]&&e.height==r[1])return this.zoomifyImage_=e,e;var n=uo(r[0],r[1]);return n.drawImage(e,0,0),this.zoomifyImage_=n.canvas,n.canvas}return e},e}(vo),vf=function(t){function e(e){var r=this,n=e,i=n.size,o=void 0!==n.tierSizeCalculation?n.tierSizeCalculation:gf,a=n.tilePixelRatio||1,s=i[0],l=i[1],u=[],c=n.tileSize||256,h=c*a;switch(o){case gf:for(;s>h||l>h;)u.push([Math.ceil(s/h),Math.ceil(l/h)]),h+=h;break;case yf:for(var p=s,f=l;p>h||f>h;)u.push([Math.ceil(p/h),Math.ceil(f/h)]),p>>=1,f>>=1;break;default:pt(!1,53)}u.push([1,1]),u.reverse();for(var d=[a],g=[0],y=1,m=u.length;y<m;y++)d.push(a<<y),g.push(u[y-1][0]*u[y-1][1]+g[y-1]);d.reverse();var v=new ic({tileSize:c,extent:n.extent||[0,-l,s,0],resolutions:d}),_=n.url;_&&-1==_.indexOf("{TileGroup}")&&-1==_.indexOf("{tileIndex}")&&(_+="{TileGroup}/{z}-{x}-{y}.jpg");var b=yc(_),x=c*a;var w=dc(b.map((function(t){return function(e,r,n){if(e){var i=e[0],o=e[1],a=e[2],s=o+a*u[i][0],l={z:i,x:o,y:a,tileIndex:s,TileGroup:"TileGroup"+((s+g[i])/x|0)};return t.replace(/\{(\w+?)\}/g,(function(t,e){return l[e]}))}}}))),S=mf.bind(null,Is(c*a));(r=t.call(this,{attributions:n.attributions,cacheSize:n.cacheSize,crossOrigin:n.crossOrigin,imageSmoothing:n.imageSmoothing,projection:n.projection,tilePixelRatio:a,reprojectionErrorThreshold:n.reprojectionErrorThreshold,tileClass:S,tileGrid:v,tileUrlFunction:w,transition:n.transition})||this).zDirection=n.zDirection;var E=w(v.getTileCoordForCoordAndResolution(xe(v.getExtent()),d[d.length-1]),1,null),T=new Image;return T.addEventListener("error",function(){x=c,this.changed()}.bind(r)),T.src=E,r}return df(e,t),e}(Xp),_f=function(){for(var t=0,e=0,r=arguments.length;e<r;e++)t+=arguments[e].length;var n=Array(t),i=0;for(e=0;e<r;e++)for(var o=arguments[e],a=0,s=o.length;a<s;a++,i++)n[i]=o[a];return n},bf="version1",xf="version2",wf="version3",Sf={};Sf[bf]={level0:{supports:[],formats:[],qualities:["native"]},level1:{supports:["regionByPx","sizeByW","sizeByH","sizeByPct"],formats:["jpg"],qualities:["native"]},level2:{supports:["regionByPx","regionByPct","sizeByW","sizeByH","sizeByPct","sizeByConfinedWh","sizeByWh"],formats:["jpg","png"],qualities:["native","color","grey","bitonal"]}},Sf[xf]={level0:{supports:[],formats:["jpg"],qualities:["default"]},level1:{supports:["regionByPx","sizeByW","sizeByH","sizeByPct"],formats:["jpg"],qualities:["default"]},level2:{supports:["regionByPx","regionByPct","sizeByW","sizeByH","sizeByPct","sizeByConfinedWh","sizeByDistortedWh","sizeByWh"],formats:["jpg","png"],qualities:["default","bitonal"]}},Sf[wf]={level0:{supports:[],formats:["jpg"],qualities:["default"]},level1:{supports:["regionByPx","regionSquare","sizeByW","sizeByH","sizeByWh"],formats:["jpg"],qualities:["default"]},level2:{supports:["regionByPx","regionSquare","regionByPct","sizeByW","sizeByH","sizeByPct","sizeByConfinedWh","sizeByWh"],formats:["jpg","png"],qualities:["default"]}},Sf.none={none:{supports:[],formats:[],qualities:[]}};var Ef=/^https?:\/\/library\.stanford\.edu\/iiif\/image-api\/(?:1\.1\/)?compliance\.html#level[0-2]$/,Tf=/^https?:\/\/iiif\.io\/api\/image\/2\/level[0-2](?:\.json)?$/,Cf=/(^https?:\/\/iiif\.io\/api\/image\/3\/level[0-2](?:\.json)?$)|(^level[0-2]$)/;var Of={};Of[bf]=function(t){var e=t.getComplianceLevelSupportedFeatures();return void 0===e&&(e=Sf[bf].level0),{url:void 0===t.imageInfo["@id"]?void 0:t.imageInfo["@id"].replace(/\/?(?:info\.json)?$/g,""),supports:e.supports,formats:_f(e.formats,[void 0===t.imageInfo.formats?[]:t.imageInfo.formats]),qualities:_f(e.qualities,[void 0===t.imageInfo.qualities?[]:t.imageInfo.qualities]),resolutions:t.imageInfo.scale_factors,tileSize:void 0!==t.imageInfo.tile_width?void 0!==t.imageInfo.tile_height?[t.imageInfo.tile_width,t.imageInfo.tile_height]:[t.imageInfo.tile_width,t.imageInfo.tile_width]:null!=t.imageInfo.tile_height?[t.imageInfo.tile_height,t.imageInfo.tile_height]:void 0}},Of[xf]=function(t){var e=t.getComplianceLevelSupportedFeatures(),r=Array.isArray(t.imageInfo.profile)&&t.imageInfo.profile.length>1,n=r&&t.imageInfo.profile[1].supports?t.imageInfo.profile[1].supports:[],i=r&&t.imageInfo.profile[1].formats?t.imageInfo.profile[1].formats:[],o=r&&t.imageInfo.profile[1].qualities?t.imageInfo.profile[1].qualities:[];return{url:t.imageInfo["@id"].replace(/\/?(?:info\.json)?$/g,""),sizes:void 0===t.imageInfo.sizes?void 0:t.imageInfo.sizes.map((function(t){return[t.width,t.height]})),tileSize:void 0===t.imageInfo.tiles?void 0:[t.imageInfo.tiles.map((function(t){return t.width}))[0],t.imageInfo.tiles.map((function(t){return void 0===t.height?t.width:t.height}))[0]],resolutions:void 0===t.imageInfo.tiles?void 0:t.imageInfo.tiles.map((function(t){return t.scaleFactors}))[0],supports:_f(e.supports,n),formats:_f(e.formats,i),qualities:_f(e.qualities,o)}},Of[wf]=function(t){var e=t.getComplianceLevelSupportedFeatures(),r=void 0===t.imageInfo.extraFormats?e.formats:_f(e.formats,t.imageInfo.extraFormats),n=void 0!==t.imageInfo.preferredFormats&&Array.isArray(t.imageInfo.preferredFormats)&&t.imageInfo.preferredFormats.length>0?t.imageInfo.preferredFormats.filter((function(t){return["jpg","png","gif"].includes(t)})).reduce((function(t,e){return void 0===t&&r.includes(e)?e:t}),void 0):void 0;return{url:t.imageInfo.id,sizes:void 0===t.imageInfo.sizes?void 0:t.imageInfo.sizes.map((function(t){return[t.width,t.height]})),tileSize:void 0===t.imageInfo.tiles?void 0:[t.imageInfo.tiles.map((function(t){return t.width}))[0],t.imageInfo.tiles.map((function(t){return t.height}))[0]],resolutions:void 0===t.imageInfo.tiles?void 0:t.imageInfo.tiles.map((function(t){return t.scaleFactors}))[0],supports:void 0===t.imageInfo.extraFeatures?e.supports:_f(e.supports,t.imageInfo.extraFeatures),formats:r,qualities:void 0===t.imageInfo.extraQualities?e.qualities:_f(e.qualities,t.imageInfo.extraQualities),preferredFormat:n}};var Pf=function(){function t(t){this.setImageInfo(t)}return t.prototype.setImageInfo=function(t){this.imageInfo="string"==typeof t?JSON.parse(t):t},t.prototype.getImageApiVersion=function(){if(void 0!==this.imageInfo){var t=this.imageInfo["@context"]||"ol-no-context";"string"==typeof t&&(t=[t]);for(var e=0;e<t.length;e++)switch(t[e]){case"http://library.stanford.edu/iiif/image-api/1.1/context.json":case"http://iiif.io/api/image/1/context.json":return bf;case"http://iiif.io/api/image/2/context.json":return xf;case"http://iiif.io/api/image/3/context.json":return wf;case"ol-no-context":if(this.getComplianceLevelEntryFromProfile(bf)&&this.imageInfo.identifier)return bf}pt(!1,61)}},t.prototype.getComplianceLevelEntryFromProfile=function(t){if(void 0!==this.imageInfo&&void 0!==this.imageInfo.profile)switch(void 0===t&&(t=this.getImageApiVersion()),t){case bf:if(Ef.test(this.imageInfo.profile))return this.imageInfo.profile;break;case wf:if(Cf.test(this.imageInfo.profile))return this.imageInfo.profile;break;case xf:if("string"==typeof this.imageInfo.profile&&Tf.test(this.imageInfo.profile))return this.imageInfo.profile;if(Array.isArray(this.imageInfo.profile)&&this.imageInfo.profile.length>0&&"string"==typeof this.imageInfo.profile[0]&&Tf.test(this.imageInfo.profile[0]))return this.imageInfo.profile[0]}},t.prototype.getComplianceLevelFromProfile=function(t){var e=this.getComplianceLevelEntryFromProfile(t);if(void 0!==e){var r=e.match(/level[0-2](?:\.json)?$/g);return Array.isArray(r)?r[0].replace(".json",""):void 0}},t.prototype.getComplianceLevelSupportedFeatures=function(){if(void 0!==this.imageInfo){var t=this.getImageApiVersion(),e=this.getComplianceLevelFromProfile(t);return void 0===e?Sf.none.none:Sf[t][e]}},t.prototype.getTileSourceOptions=function(t){var e=t||{},r=this.getImageApiVersion();if(void 0!==r){var n=void 0===r?void 0:Of[r](this);if(void 0!==n)return{url:n.url,version:r,size:[this.imageInfo.width,this.imageInfo.height],sizes:n.sizes,format:void 0!==e.format&&n.formats.includes(e.format)?e.format:void 0!==n.preferredFormat?n.preferredFormat:"jpg",supports:n.supports,quality:e.quality&&n.qualities.includes(e.quality)?e.quality:n.qualities.includes("native")?"native":"default",resolutions:Array.isArray(n.resolutions)?n.resolutions.sort((function(t,e){return e-t})):void 0,tileSize:n.tileSize}}},t}(),Rf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function If(t){return t.toLocaleString("en",{maximumFractionDigits:10})}var Lf=function(t){function e(e){var r=this,n=e||{},i=n.url||"";i+=i.lastIndexOf("/")===i.length-1||""===i?"":"/";var o=n.version||xf,a=n.sizes||[],s=n.size;pt(null!=s&&Array.isArray(s)&&2==s.length&&!isNaN(s[0])&&s[0]>0&&!isNaN(s[1])&&s[1]>0,60);var l,u,c,h=s[0],p=s[1],f=n.tileSize,d=n.tilePixelRatio||1,g=n.format||"jpg",y=n.quality||(n.version==bf?"native":"default"),m=n.resolutions||[],v=n.supports||[],_=n.extent||[0,-p,h,0],b=null!=a&&Array.isArray(a)&&a.length>0,x=void 0!==f&&("number"==typeof f&&Number.isInteger(f)&&f>0||Array.isArray(f)&&f.length>0),w=null!=v&&Array.isArray(v)&&(v.includes("regionByPx")||v.includes("regionByPct"))&&(v.includes("sizeByWh")||v.includes("sizeByH")||v.includes("sizeByW")||v.includes("sizeByPct"));if(m.sort((function(t,e){return e-t})),x||w)if(null!=f&&("number"==typeof f&&Number.isInteger(f)&&f>0?(l=f,u=f):Array.isArray(f)&&f.length>0&&((1==f.length||null==f[1]&&Number.isInteger(f[0]))&&(l=f[0],u=f[0]),2==f.length&&(Number.isInteger(f[0])&&Number.isInteger(f[1])?(l=f[0],u=f[1]):null==f[0]&&Number.isInteger(f[1])&&(l=f[1],u=f[1])))),void 0!==l&&void 0!==u||(l=256,u=256),0==m.length)for(var S=c=Math.max(Math.ceil(Math.log(h/l)/Math.LN2),Math.ceil(Math.log(p/u)/Math.LN2));S>=0;S--)m.push(Math.pow(2,S));else{var E=Math.max.apply(Math,m);c=Math.round(Math.log(E)/Math.LN2)}else if(l=h,u=p,m=[],b){a.sort((function(t,e){return t[0]-e[0]})),c=-1;var T=[];for(S=0;S<a.length;S++){var C=h/a[S][0];m.length>0&&m[m.length-1]==C?T.push(S):(m.push(C),c++)}if(T.length>0)for(S=0;S<T.length;S++)a.splice(T[S]-S,1)}else m.push(1),a.push([h,p]),c=0;var O=new ic({tileSize:[l,u],extent:_,origin:Ce(_),resolutions:m}),P=mf.bind(null,Is(f||256).map((function(t){return t*d})));return(r=t.call(this,{attributions:n.attributions,attributionsCollapsible:n.attributionsCollapsible,cacheSize:n.cacheSize,crossOrigin:n.crossOrigin,imageSmoothing:n.imageSmoothing,projection:n.projection,reprojectionErrorThreshold:n.reprojectionErrorThreshold,state:n.state,tileClass:P,tileGrid:O,tilePixelRatio:n.tilePixelRatio,tileUrlFunction:function(t,e,r){var n,s,f=t[0];if(!(f>c)){var d=t[1],_=t[2],S=m[f];if(!(void 0===d||void 0===_||void 0===S||d<0||Math.ceil(h/S/l)<=d||_<0||Math.ceil(p/S/u)<=_)){if(w||x){var E=d*l*S,T=_*u*S,C=l*S,O=u*S,P=l,R=u;if(E+C>h&&(C=h-E),T+O>p&&(O=p-T),E+l*S>h&&(P=Math.floor((h-E+S-1)/S)),T+u*S>p&&(R=Math.floor((p-T+S-1)/S)),0==E&&C==h&&0==T&&O==p)n="full";else if(!w||v.includes("regionByPx"))n=E+","+T+","+C+","+O;else if(v.includes("regionByPct")){n="pct:"+If(E/h*100)+","+If(T/p*100)+","+If(C/h*100)+","+If(O/p*100)}o!=wf||w&&!v.includes("sizeByWh")?!w||v.includes("sizeByW")?s=P+",":v.includes("sizeByH")?s=","+R:v.includes("sizeByWh")?s=P+","+R:v.includes("sizeByPct")&&(s="pct:"+If(100/S)):s=P+","+R}else if(n="full",b){var I=a[f][0],L=a[f][1];s=o==wf?I==h&&L==p?"max":I+","+L:I==h?"full":I+","}else s=o==wf?"max":"full";return i+n+"/"+s+"/0/"+y+"."+g}}},transition:n.transition})||this).zDirection=n.zDirection,r}return Rf(e,t),e}(Xp),Mf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Ff=function(t){function e(e,r,n,i,o,a,s){var l=this,u=e.getExtent(),c=r.getExtent(),h=c?Te(n,c):n,p=tc(e,r,xe(h),i),f=new Ip(e,r,h,u,.5*p,i),d=a(f.calculateSourceExtent(),p,o),g=d?Fi:Ni,y=d?d.getPixelRatio():1;return(l=t.call(this,n,i,y,g)||this).targetProj_=r,l.maxSourceExtent_=u,l.triangulation_=f,l.targetResolution_=i,l.targetExtent_=n,l.sourceImage_=d,l.sourcePixelRatio_=y,l.contextOptions_=s,l.canvas_=null,l.sourceListenerKey_=null,l}return Mf(e,t),e.prototype.disposeInternal=function(){this.state==Ai&&this.unlistenSource_(),t.prototype.disposeInternal.call(this)},e.prototype.getImage=function(){return this.canvas_},e.prototype.getProjection=function(){return this.targetProj_},e.prototype.reproject_=function(){var t=this.sourceImage_.getState();if(t==ki){var e=Pe(this.targetExtent_)/this.targetResolution_,r=Ee(this.targetExtent_)/this.targetResolution_;this.canvas_=rc(e,r,this.sourcePixelRatio_,this.sourceImage_.getResolution(),this.maxSourceExtent_,this.targetResolution_,this.targetExtent_,this.triangulation_,[{extent:this.sourceImage_.getExtent(),image:this.sourceImage_.getImage()}],0,void 0,this.contextOptions_)}this.state=t,this.changed()},e.prototype.load=function(){if(this.state==Fi){this.state=Ai,this.changed();var t=this.sourceImage_.getState();t==ki||t==ji?this.reproject_():(this.sourceListenerKey_=Z(this.sourceImage_,F,(function(t){var e=this.sourceImage_.getState();e!=ki&&e!=ji||(this.unlistenSource_(),this.reproject_())}),this),this.sourceImage_.load())}},e.prototype.unlistenSource_=function(){H(this.sourceListenerKey_),this.sourceListenerKey_=null},e}(Mi),Af=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),kf="imageloadstart",jf="imageloadend",Nf="imageloaderror",Df=function(t){function e(e,r){var n=t.call(this,e)||this;return n.image=r,n}return Af(e,t),e}(c);function Gf(t,e){t.getImage().src=e}var zf=function(t){function e(e){var r=t.call(this,{attributions:e.attributions,projection:e.projection,state:e.state})||this;return r.resolutions_=void 0!==e.resolutions?e.resolutions:null,r.reprojectedImage_=null,r.reprojectedRevision_=0,r.contextOptions_=!1===e.imageSmoothing?$u:void 0,r}return Af(e,t),e.prototype.getResolutions=function(){return this.resolutions_},e.prototype.getContextOptions=function(){return this.contextOptions_},e.prototype.findNearestResolution=function(t){if(this.resolutions_){var e=y(this.resolutions_,t,0);t=this.resolutions_[e]}return t},e.prototype.getImage=function(t,e,r,n){var i=this.getProjection();if(i&&n&&!Xr(i,n)){if(this.reprojectedImage_){if(this.reprojectedRevision_==this.getRevision()&&Xr(this.reprojectedImage_.getProjection(),n)&&this.reprojectedImage_.getResolution()==e&&ue(this.reprojectedImage_.getExtent(),t))return this.reprojectedImage_;this.reprojectedImage_.dispose(),this.reprojectedImage_=null}return this.reprojectedImage_=new Ff(i,n,t,e,r,function(t,e,r){return this.getImageInternal(t,e,r,i)}.bind(this),this.contextOptions_),this.reprojectedRevision_=this.getRevision(),this.reprojectedImage_}return i&&(n=i),this.getImageInternal(t,e,r,n)},e.prototype.getImageInternal=function(t,e,r,i){return n()},e.prototype.handleImageChange=function(t){var e=t.target;switch(e.getState()){case Ai:this.loading=!0,this.dispatchEvent(new Df(kf,e));break;case ki:this.loading=!1,this.dispatchEvent(new Df(jf,e));break;case ji:this.loading=!1,this.dispatchEvent(new Df(Nf,e))}},e}(Dp),Uf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Bf=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,{attributions:n.attributions,imageSmoothing:n.imageSmoothing,projection:n.projection,resolutions:n.resolutions})||this).crossOrigin_=void 0!==n.crossOrigin?n.crossOrigin:null,r.hidpi_=void 0===n.hidpi||n.hidpi,r.url_=n.url,r.imageLoadFunction_=void 0!==n.imageLoadFunction?n.imageLoadFunction:Gf,r.params_=n.params||{},r.image_=null,r.imageSize_=[0,0],r.renderedRevision_=0,r.ratio_=void 0!==n.ratio?n.ratio:1.5,r}return Uf(e,t),e.prototype.getParams=function(){return this.params_},e.prototype.getImageInternal=function(t,e,r,n){if(void 0===this.url_)return null;e=this.findNearestResolution(e),r=this.hidpi_?r:1;var i=this.image_;if(i&&this.renderedRevision_==this.getRevision()&&i.getResolution()==e&&i.getPixelRatio()==r&&te(i.getExtent(),t))return i;var o={F:"image",FORMAT:"PNG32",TRANSPARENT:!0};O(o,this.params_);var a=((t=t.slice())[0]+t[2])/2,s=(t[1]+t[3])/2;if(1!=this.ratio_){var l=this.ratio_*Pe(t)/2,u=this.ratio_*Ee(t)/2;t[0]=a-l,t[1]=s-u,t[2]=a+l,t[3]=s+u}var c=e/r,h=Math.ceil(Pe(t)/c),p=Math.ceil(Ee(t)/c);t[0]=a-c*h/2,t[2]=a+c*h/2,t[1]=s-c*p/2,t[3]=s+c*p/2,this.imageSize_[0]=h,this.imageSize_[1]=p;var f=this.getRequestUrl_(t,this.imageSize_,r,n,o);return this.image_=new Ki(t,e,r,f,this.crossOrigin_,this.imageLoadFunction_),this.renderedRevision_=this.getRevision(),this.image_.addEventListener(F,this.handleImageChange.bind(this)),this.image_},e.prototype.getImageLoadFunction=function(){return this.imageLoadFunction_},e.prototype.getRequestUrl_=function(t,e,r,n,i){var o=n.getCode().split(":").pop();i.SIZE=e[0]+","+e[1],i.BBOX=t.join(","),i.BBOXSR=o,i.IMAGESR=o,i.DPI=Math.round(90*r);var a=this.url_,s=a.replace(/MapServer\/?$/,"MapServer/export").replace(/ImageServer\/?$/,"ImageServer/exportImage");return s==a&&pt(!1,50),mc(s,i)},e.prototype.getUrl=function(){return this.url_},e.prototype.setImageLoadFunction=function(t){this.image_=null,this.imageLoadFunction_=t,this.changed()},e.prototype.setUrl=function(t){t!=this.url_&&(this.url_=t,this.image_=null,this.changed())},e.prototype.updateParams=function(t){O(this.params_,t),this.image_=null,this.changed()},e}(zf),Vf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Yf=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,{attributions:n.attributions,imageSmoothing:n.imageSmoothing,projection:n.projection,resolutions:n.resolutions,state:n.state})||this).canvasFunction_=n.canvasFunction,r.canvas_=null,r.renderedRevision_=0,r.ratio_=void 0!==n.ratio?n.ratio:1.5,r}return Vf(e,t),e.prototype.getImageInternal=function(t,e,r,n){e=this.findNearestResolution(e);var i=this.canvas_;if(i&&this.renderedRevision_==this.getRevision()&&i.getResolution()==e&&i.getPixelRatio()==r&&te(i.getExtent(),t))return i;Me(t=t.slice(),this.ratio_);var o=[Pe(t)/e*r,Ee(t)/e*r],a=this.canvasFunction_.call(this,t,e,r,o,n);return a&&(i=new $i(t,e,r,a)),this.canvas_=i,this.renderedRevision_=this.getRevision(),i},e}(zf),Wf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();var qf=function(t){function e(e){var r=t.call(this,{imageSmoothing:e.imageSmoothing,projection:e.projection,resolutions:e.resolutions})||this;return r.crossOrigin_=void 0!==e.crossOrigin?e.crossOrigin:null,r.displayDpi_=void 0!==e.displayDpi?e.displayDpi:96,r.params_=e.params||{},r.url_=e.url,r.imageLoadFunction_=void 0!==e.imageLoadFunction?e.imageLoadFunction:Gf,r.hidpi_=void 0===e.hidpi||e.hidpi,r.metersPerUnit_=void 0!==e.metersPerUnit?e.metersPerUnit:1,r.ratio_=void 0!==e.ratio?e.ratio:1,r.useOverlay_=void 0!==e.useOverlay&&e.useOverlay,r.image_=null,r.renderedRevision_=0,r}return Wf(e,t),e.prototype.getParams=function(){return this.params_},e.prototype.getImageInternal=function(t,e,r,n){e=this.findNearestResolution(e),r=this.hidpi_?r:1;var i=this.image_;if(i&&this.renderedRevision_==this.getRevision()&&i.getResolution()==e&&i.getPixelRatio()==r&&te(i.getExtent(),t))return i;1!=this.ratio_&&Me(t=t.slice(),this.ratio_);var o=[Pe(t)/e*r,Ee(t)/e*r];if(void 0!==this.url_){var a=this.getUrl(this.url_,this.params_,t,o,n);(i=new Ki(t,e,r,a,this.crossOrigin_,this.imageLoadFunction_)).addEventListener(F,this.handleImageChange.bind(this))}else i=null;return this.image_=i,this.renderedRevision_=this.getRevision(),i},e.prototype.getImageLoadFunction=function(){return this.imageLoadFunction_},e.prototype.updateParams=function(t){O(this.params_,t),this.changed()},e.prototype.getUrl=function(t,e,r,n,i){var o=function(t,e,r,n){var i=Pe(t),o=Ee(t),a=e[0],s=e[1],l=.0254/n;return s*i>a*o?i*r/(a*l):o*r/(s*l)}(r,n,this.metersPerUnit_,this.displayDpi_),a=xe(r),s={OPERATION:this.useOverlay_?"GETDYNAMICMAPOVERLAYIMAGE":"GETMAPIMAGE",VERSION:"2.0.0",LOCALE:"en",CLIENTAGENT:"ol/source/ImageMapGuide source",CLIP:"1",SETDISPLAYDPI:this.displayDpi_,SETDISPLAYWIDTH:Math.round(n[0]),SETDISPLAYHEIGHT:Math.round(n[1]),SETVIEWSCALE:o,SETVIEWCENTERX:a[0],SETVIEWCENTERY:a[1]};return O(s,e),mc(t,s)},e.prototype.setImageLoadFunction=function(t){this.image_=null,this.imageLoadFunction_=t,this.changed()},e}(zf),Xf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Zf=function(t){function e(e){var r=this,n=void 0!==e.crossOrigin?e.crossOrigin:null,i=void 0!==e.imageLoadFunction?e.imageLoadFunction:Gf;return(r=t.call(this,{attributions:e.attributions,imageSmoothing:e.imageSmoothing,projection:Gr(e.projection)})||this).url_=e.url,r.imageExtent_=e.imageExtent,r.image_=new Ki(r.imageExtent_,void 0,1,r.url_,n,i),r.imageSize_=e.imageSize?e.imageSize:null,r.image_.addEventListener(F,r.handleImageChange.bind(r)),r}return Xf(e,t),e.prototype.getImageExtent=function(){return this.imageExtent_},e.prototype.getImageInternal=function(t,e,r,n){return Re(t,this.image_.getExtent())?this.image_:null},e.prototype.getUrl=function(){return this.url_},e.prototype.handleImageChange=function(e){if(this.image_.getState()==ki){var r=this.image_.getExtent(),n=this.image_.getImage(),i=void 0,o=void 0;this.imageSize_?(i=this.imageSize_[0],o=this.imageSize_[1]):(i=n.width,o=n.height);var a=Ee(r)/o,s=Math.ceil(Pe(r)/a);if(s!=i){var l=uo(s,o);O(l,this.getContextOptions());var u=l.canvas;l.drawImage(n,0,0,i,o,0,0,u.width,u.height),this.image_.setImage(u)}}t.prototype.handleImageChange.call(this,e)},e}(zf),Kf="carmentaserver",Hf="geoserver",$f="mapserver",Jf="qgis",Qf=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),td=[101,101],ed=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,{attributions:n.attributions,imageSmoothing:n.imageSmoothing,projection:n.projection,resolutions:n.resolutions})||this).crossOrigin_=void 0!==n.crossOrigin?n.crossOrigin:null,r.url_=n.url,r.imageLoadFunction_=void 0!==n.imageLoadFunction?n.imageLoadFunction:Gf,r.params_=n.params||{},r.v13_=!0,r.updateV13_(),r.serverType_=n.serverType,r.hidpi_=void 0===n.hidpi||n.hidpi,r.image_=null,r.imageSize_=[0,0],r.renderedRevision_=0,r.ratio_=void 0!==n.ratio?n.ratio:1.5,r}return Qf(e,t),e.prototype.getFeatureInfoUrl=function(t,e,r,n){if(void 0!==this.url_){var i=Gr(r),o=this.getProjection();o&&o!==i&&(e=tc(o,i,t,e),t=Hr(t,i,o));var a=Se(t,e,0,td),s={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.params_.LAYERS};O(s,this.params_,n);var l=Math.floor((t[0]-a[0])/e),u=Math.floor((a[3]-t[1])/e);return s[this.v13_?"I":"X"]=l,s[this.v13_?"J":"Y"]=u,this.getRequestUrl_(a,td,1,o||i,s)}},e.prototype.getLegendUrl=function(t,e){if(void 0!==this.url_){var r={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetLegendGraphic",FORMAT:"image/png"};if(void 0===e||void 0===e.LAYER){var n=this.params_.LAYERS;if(!(!Array.isArray(n)||1===n.length))return;r.LAYER=n}if(void 0!==t){var i=this.getProjection()?this.getProjection().getMetersPerUnit():1;r.SCALE=t*i/28e-5}return O(r,e),mc(this.url_,r)}},e.prototype.getParams=function(){return this.params_},e.prototype.getImageInternal=function(t,e,r,n){if(void 0===this.url_)return null;e=this.findNearestResolution(e),1==r||this.hidpi_&&void 0!==this.serverType_||(r=1);var i=e/r,o=xe(t),a=Se(o,i,0,[Math.ceil(Pe(t)/i),Math.ceil(Ee(t)/i)]),s=Se(o,i,0,[Math.ceil(this.ratio_*Pe(t)/i),Math.ceil(this.ratio_*Ee(t)/i)]),l=this.image_;if(l&&this.renderedRevision_==this.getRevision()&&l.getResolution()==e&&l.getPixelRatio()==r&&te(l.getExtent(),a))return l;var u={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};O(u,this.params_),this.imageSize_[0]=Math.round(Pe(s)/i),this.imageSize_[1]=Math.round(Ee(s)/i);var c=this.getRequestUrl_(s,this.imageSize_,r,n,u);return this.image_=new Ki(s,e,r,c,this.crossOrigin_,this.imageLoadFunction_),this.renderedRevision_=this.getRevision(),this.image_.addEventListener(F,this.handleImageChange.bind(this)),this.image_},e.prototype.getImageLoadFunction=function(){return this.imageLoadFunction_},e.prototype.getRequestUrl_=function(t,e,r,n,i){if(pt(void 0!==this.url_,9),i[this.v13_?"CRS":"SRS"]=n.getCode(),"STYLES"in this.params_||(i.STYLES=""),1!=r)switch(this.serverType_){case Hf:var o=90*r+.5|0;"FORMAT_OPTIONS"in i?i.FORMAT_OPTIONS+=";dpi:"+o:i.FORMAT_OPTIONS="dpi:"+o;break;case $f:i.MAP_RESOLUTION=90*r;break;case Kf:case Jf:i.DPI=90*r;break;default:pt(!1,8)}i.WIDTH=e[0],i.HEIGHT=e[1];var a,s=n.getAxisOrientation();return a=this.v13_&&"ne"==s.substr(0,2)?[t[1],t[0],t[3],t[2]]:t,i.BBOX=a.join(","),mc(this.url_,i)},e.prototype.getUrl=function(){return this.url_},e.prototype.setImageLoadFunction=function(t){this.image_=null,this.imageLoadFunction_=t,this.changed()},e.prototype.setUrl=function(t){t!=this.url_&&(this.url_=t,this.image_=null,this.changed())},e.prototype.updateParams=function(t){O(this.params_,t),this.updateV13_(),this.image_=null,this.changed()},e.prototype.updateV13_=function(){var t=this.params_.VERSION||"1.3.0";this.v13_=br(t,"1.3")>=0},e}(zf),rd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),nd='© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors.',id=function(t){function e(e){var r,n=e||{};r=void 0!==n.attributions?n.attributions:[nd];var i=void 0!==n.crossOrigin?n.crossOrigin:"anonymous",o=void 0!==n.url?n.url:"https://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png";return t.call(this,{attributions:r,attributionsCollapsible:!1,cacheSize:n.cacheSize,crossOrigin:i,imageSmoothing:n.imageSmoothing,maxZoom:void 0!==n.maxZoom?n.maxZoom:19,opaque:void 0===n.opaque||n.opaque,reprojectionErrorThreshold:n.reprojectionErrorThreshold,tileLoadFunction:n.tileLoadFunction,transition:n.transition,url:o,wrapX:n.wrapX})||this}return rd(e,t),e}(Jp),od=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ad=function(t){function e(e){var r=e||{};return t.call(this,r)||this}return od(e,t),e}(na),sd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ld=function(t){function e(e){var r=t.call(this)||this;return r.boundHandleImageChange_=r.handleImageChange_.bind(r),r.layer_=e,r.declutterExecutorGroup=null,r}return sd(e,t),e.prototype.getFeatures=function(t){return n()},e.prototype.prepareFrame=function(t){return n()},e.prototype.renderFrame=function(t,e){return n()},e.prototype.loadedTileCallback=function(t,e,r){t[e]||(t[e]={}),t[e][r.tileCoord.toString()]=r},e.prototype.createLoadedTileFinder=function(t,e,r){return function(n,i){var o=this.loadedTileCallback.bind(this,r,n);return t.forEachLoadedTile(e,n,i,o)}.bind(this)},e.prototype.forEachFeatureAtCoordinate=function(t,e,r,n,i){},e.prototype.getDataAtPixel=function(t,e,r){return n()},e.prototype.getLayer=function(){return this.layer_},e.prototype.handleFontsChanged=function(){},e.prototype.handleImageChange_=function(t){t.target.getState()===ki&&this.renderIfReadyAndVisible()},e.prototype.loadImage=function(t){var e=t.getState();return e!=ki&&e!=ji&&t.addEventListener(F,this.boundHandleImageChange_),e==Fi&&(t.load(),e=t.getState()),e==ki},e.prototype.renderIfReadyAndVisible=function(){var t=this.getLayer();t.getVisible()&&t.getSourceState()==Qo&&t.changed()},e}(Q),ud=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),cd=function(t){function e(e){var r=t.call(this,e)||this;return r.container=null,r.renderedResolution,r.tempTransform=[1,0,0,1,0,0],r.pixelTransform=[1,0,0,1,0,0],r.inversePixelTransform=[1,0,0,1,0,0],r.context=null,r.containerReused=!1,r}return ud(e,t),e.prototype.useContainer=function(t,e,r){var n,i,o=this.getLayer().getClassName();t&&""===t.style.opacity&&t.className===o&&((s=t.firstElementChild)instanceof HTMLCanvasElement&&(i=s.getContext("2d")));if(!i||0!==i.canvas.width&&i.canvas.style.transform!==e?this.containerReused&&(this.container=null,this.context=null,this.containerReused=!1):(this.container=t,this.context=i,this.containerReused=!0),!this.container){(n=document.createElement("div")).className=o;var a=n.style;a.position="absolute",a.width="100%",a.height="100%";var s=(i=uo()).canvas;n.appendChild(s),(a=s.style).position="absolute",a.left="0",a.transformOrigin="top left",this.container=n,this.context=i}},e.prototype.clip=function(t,e,r){var n=e.pixelRatio,i=e.size[0]*n/2,o=e.size[1]*n/2,a=e.viewState.rotation,s=Ce(r),l=Oe(r),u=be(r),c=_e(r);It(e.coordinateToPixelTransform,s),It(e.coordinateToPixelTransform,l),It(e.coordinateToPixelTransform,u),It(e.coordinateToPixelTransform,c),t.save(),Ca(t,-a,i,o),t.beginPath(),t.moveTo(s[0]*n,s[1]*n),t.lineTo(l[0]*n,l[1]*n),t.lineTo(u[0]*n,u[1]*n),t.lineTo(c[0]*n,c[1]*n),t.clip(),Ca(t,a,i,o)},e.prototype.clipUnrotated=function(t,e,r){var n=Ce(r),i=Oe(r),o=be(r),a=_e(r);It(e.coordinateToPixelTransform,n),It(e.coordinateToPixelTransform,i),It(e.coordinateToPixelTransform,o),It(e.coordinateToPixelTransform,a);var s=this.inversePixelTransform;It(s,n),It(s,i),It(s,o),It(s,a),t.save(),t.beginPath(),t.moveTo(Math.round(n[0]),Math.round(n[1])),t.lineTo(Math.round(i[0]),Math.round(i[1])),t.lineTo(Math.round(o[0]),Math.round(o[1])),t.lineTo(Math.round(a[0]),Math.round(a[1])),t.clip()},e.prototype.dispatchRenderEvent_=function(t,e,r){var n=this.getLayer();if(n.hasListener(t)){var i=new la(t,this.inversePixelTransform,r,e);n.dispatchEvent(i)}},e.prototype.preRender=function(t,e){this.dispatchRenderEvent_(qo,t,e)},e.prototype.postRender=function(t,e){this.dispatchRenderEvent_(Xo,t,e)},e.prototype.getRenderTransform=function(t,e,r,n,i,o,a){var s=i/2,l=o/2,u=n/e,c=-u,h=-t[0]+a,p=-t[1];return kt(this.tempTransform,s,l,u,c,-r,h,p)},e.prototype.getDataAtPixel=function(t,e,r){var n,i=It(this.inversePixelTransform,t.slice()),o=this.context,a=this.getLayer().getExtent();if(a&&!Qt(a,It(e.pixelToCoordinateTransform,t.slice())))return null;try{var s=Math.round(i[0]),l=Math.round(i[1]),u=document.createElement("canvas"),c=u.getContext("2d");u.width=1,u.height=1,c.clearRect(0,0,1,1),c.drawImage(o.canvas,s,l,1,1,0,0,1,1),n=c.getImageData(0,0,1,1).data}catch(t){return"SecurityError"===t.name?new Uint8Array:n}return 0===n[3]?null:n},e}(ld),hd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),pd=function(t){function e(e){var r=t.call(this,e)||this;return r.image_=null,r}return hd(e,t),e.prototype.getImage=function(){return this.image_?this.image_.getImage():null},e.prototype.prepareFrame=function(t){var e=t.layerStatesArray[t.layerIndex],r=t.pixelRatio,n=t.viewState,i=n.resolution,o=this.getLayer().getSource(),a=t.viewHints,s=t.extent;if(void 0!==e.extent&&(s=Te(s,on(e.extent,n.projection))),!a[ns]&&!a[is]&&!Ie(s))if(o){var l=n.projection,u=o.getImage(s,i,r,l);u&&this.loadImage(u)&&(this.image_=u)}else this.image_=null;return!!this.image_},e.prototype.renderFrame=function(t,e){var r=this.image_,n=r.getExtent(),i=r.getResolution(),o=r.getPixelRatio(),a=t.layerStatesArray[t.layerIndex],s=t.pixelRatio,l=t.viewState,u=l.center,c=l.resolution,h=t.size,p=s*i/(c*o),f=Math.round(h[0]*s),d=Math.round(h[1]*s),g=l.rotation;if(g){var y=Math.round(Math.sqrt(f*f+d*d));f=y,d=y}kt(this.pixelTransform,t.size[0]/2,t.size[1]/2,1/s,1/s,g,-f/2,-d/2),jt(this.inversePixelTransform,this.pixelTransform);var m=Ra(this.pixelTransform);this.useContainer(e,m,a.opacity);var v=this.context,_=v.canvas;_.width!=f||_.height!=d?(_.width=f,_.height=d):this.containerReused||v.clearRect(0,0,f,d);var b=!1;if(a.extent){var x=on(a.extent,l.projection);(b=!te(x,t.extent)&&Re(x,t.extent))&&this.clipUnrotated(v,t,x)}var w=r.getImage(),S=kt(this.tempTransform,f/2,d/2,p,p,0,o*(n[0]-u[0])/i,o*(u[1]-n[3])/i);this.renderedResolution=i*s/o;var E=S[4],T=S[5],C=w.width*S[0],P=w.height*S[3];if(O(v,this.getLayer().getSource().getContextOptions()),this.preRender(v,t),C>=.5&&P>=.5){var R=a.opacity,I=void 0;1!==R&&(I=this.context.globalAlpha,this.context.globalAlpha=R),this.context.drawImage(w,0,0,+w.width,+w.height,Math.round(E),Math.round(T),Math.round(C),Math.round(P)),1!==R&&(this.context.globalAlpha=I)}return this.postRender(v,t),b&&v.restore(),m!==_.style.transform&&(_.style.transform=m),this.container},e}(cd),fd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),dd=function(t){function e(e){return t.call(this,e)||this}return fd(e,t),e.prototype.createRenderer=function(){return new pd(this)},e}(ad),gd="preload",yd="useInterimTilesOnError",md=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),vd=function(t){function e(e){var r=this,n=e||{},i=O({},n);return delete i.preload,delete i.useInterimTilesOnError,(r=t.call(this,i)||this).setPreload(void 0!==n.preload?n.preload:0),r.setUseInterimTilesOnError(void 0===n.useInterimTilesOnError||n.useInterimTilesOnError),r}return md(e,t),e.prototype.getPreload=function(){return this.get(gd)},e.prototype.setPreload=function(t){this.set(gd,t)},e.prototype.getUseInterimTilesOnError=function(){return this.get(yd)},e.prototype.setUseInterimTilesOnError=function(t){this.set(yd,t)},e}(na),_d=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),bd=function(t){function e(e){var r=t.call(this,e)||this;return r.extentChanged=!0,r.renderedExtent_=null,r.renderedPixelRatio,r.renderedProjection=null,r.renderedRevision,r.renderedTiles=[],r.newTiles_=!1,r.tmpExtent=[1/0,1/0,-1/0,-1/0],r.tmpTileRange_=new _u(0,0,0,0),r}return _d(e,t),e.prototype.isDrawableTile=function(t){var e=this.getLayer(),r=t.getState(),n=e.getUseInterimTilesOnError();return r==to||r==ro||r==eo&&!n},e.prototype.getTile=function(t,e,r,n){var i=n.pixelRatio,o=n.viewState.projection,a=this.getLayer(),s=a.getSource().getTile(t,e,r,i,o);return s.getState()==eo&&(a.getUseInterimTilesOnError()?a.getPreload()>0&&(this.newTiles_=!0):s.setState(to)),this.isDrawableTile(s)||(s=s.getInterimTile()),s},e.prototype.loadedTileCallback=function(e,r,n){return!!this.isDrawableTile(n)&&t.prototype.loadedTileCallback.call(this,e,r,n)},e.prototype.prepareFrame=function(t){return!!this.getLayer().getSource()},e.prototype.renderFrame=function(t,e){var r=t.layerStatesArray[t.layerIndex],n=t.viewState,i=n.projection,a=n.resolution,s=n.center,l=n.rotation,u=t.pixelRatio,c=this.getLayer(),h=c.getSource(),p=h.getRevision(),f=h.getTileGridForProjection(i),g=f.getZForResolution(a,h.zDirection),y=f.getResolution(g),m=t.extent,v=r.extent&&on(r.extent,i);v&&(m=Te(m,on(r.extent,i)));var _=h.getTilePixelRatio(u),b=Math.round(t.size[0]*_),x=Math.round(t.size[1]*_);if(l){var w=Math.round(Math.sqrt(b*b+x*x));b=w,x=w}var S=y*b/2/_,E=y*x/2/_,T=[s[0]-S,s[1]-E,s[0]+S,s[1]+E],C=f.getTileRangeForExtentAndZ(m,g),P={};P[g]={};var R=this.createLoadedTileFinder(h,i,P),I=this.tmpExtent,L=this.tmpTileRange_;this.newTiles_=!1;for(var M=C.minX;M<=C.maxX;++M)for(var F=C.minY;F<=C.maxY;++F){var A=this.getTile(g,M,F,t);if(this.isDrawableTile(A)){var k=o(this);if(A.getState()==to){P[g][A.tileCoord.toString()]=A;var j=A.inTransition(k);this.newTiles_||!j&&-1!==this.renderedTiles.indexOf(A)||(this.newTiles_=!0)}if(1===A.getAlpha(k,t.time))continue}var N=f.getTileCoordChildTileRange(A.tileCoord,L,I),D=!1;N&&(D=R(g+1,N)),D||f.forEachTileCoordParentTileRange(A.tileCoord,R,L,I)}var G=y/a;kt(this.pixelTransform,t.size[0]/2,t.size[1]/2,1/_,1/_,l,-b/2,-x/2);var z=Ra(this.pixelTransform);this.useContainer(e,z,r.opacity);var U=this.context,B=U.canvas;jt(this.inversePixelTransform,this.pixelTransform),kt(this.tempTransform,b/2,x/2,G,G,0,-b/2,-x/2),B.width!=b||B.height!=x?(B.width=b,B.height=x):this.containerReused||U.clearRect(0,0,b,x),v&&this.clipUnrotated(U,t,v),O(U,h.getContextOptions()),this.preRender(U,t),this.renderedTiles.length=0;var V,Y,W,q=Object.keys(P).map(Number);q.sort(d),1!==r.opacity||this.containerReused&&!h.getOpaque(t.viewState.projection)?(V=[],Y=[]):q=q.reverse();for(var X=q.length-1;X>=0;--X){var Z=q[X],K=h.getTilePixelSize(Z,u,i),H=f.getResolution(Z)/y,$=K[0]*H*G,J=K[1]*H*G,Q=f.getTileCoordForCoordAndZ(Ce(T),Z),tt=f.getTileCoordExtent(Q),et=It(this.tempTransform,[_*(tt[0]-T[0])/y,_*(T[3]-tt[3])/y]),rt=_*h.getGutterForProjection(i),nt=P[Z];for(var it in nt){var ot=(A=nt[it]).tileCoord,at=et[0]-(Q[1]-ot[1])*$,st=Math.round(at+$),lt=et[1]-(Q[2]-ot[2])*J,ut=Math.round(lt+J),ct=st-(M=Math.round(at)),ht=ut-(F=Math.round(lt)),pt=g===Z;if(!(j=pt&&1!==A.getAlpha(o(this),t.time)))if(V){U.save(),W=[M,F,M+ct,F,M+ct,F+ht,M,F+ht];for(var ft=0,dt=V.length;ft<dt;++ft)if(g!==Z&&Z<Y[ft]){var gt=V[ft];U.beginPath(),U.moveTo(W[0],W[1]),U.lineTo(W[2],W[3]),U.lineTo(W[4],W[5]),U.lineTo(W[6],W[7]),U.moveTo(gt[6],gt[7]),U.lineTo(gt[4],gt[5]),U.lineTo(gt[2],gt[3]),U.lineTo(gt[0],gt[1]),U.clip()}V.push(W),Y.push(Z)}else U.clearRect(M,F,ct,ht);this.drawTileImage(A,t,M,F,ct,ht,rt,pt,r.opacity),V&&!j&&U.restore(),this.renderedTiles.push(A),this.updateUsedTiles(t.usedTiles,h,A)}}return this.renderedRevision=p,this.renderedResolution=y,this.extentChanged=!this.renderedExtent_||!ue(this.renderedExtent_,T),this.renderedExtent_=T,this.renderedPixelRatio=u,this.renderedProjection=i,this.manageTilePyramid(t,h,f,u,i,m,g,c.getPreload()),this.scheduleExpireCache(t,h),this.postRender(U,t),r.extent&&U.restore(),z!==B.style.transform&&(B.style.transform=z),this.container},e.prototype.drawTileImage=function(t,e,r,n,i,a,s,l,u){var c=this.getTileImage(t);if(c){var h=o(this),p=l?t.getAlpha(h,e.time):1,f=u*p,d=f!==this.context.globalAlpha;d&&(this.context.save(),this.context.globalAlpha=f),this.context.drawImage(c,s,s,c.width-2*s,c.height-2*s,r,n,i,a),d&&this.context.restore(),1!==p?e.animate=!0:l&&t.endTransition(h)}},e.prototype.getImage=function(){var t=this.context;return t?t.canvas:null},e.prototype.getTileImage=function(t){return t.getImage()},e.prototype.scheduleExpireCache=function(t,e){if(e.canExpireCache()){var r=function(t,e,r){var n=o(t);n in r.usedTiles&&t.expireCache(r.viewState.projection,r.usedTiles[n])}.bind(null,e);t.postRenderFunctions.push(r)}},e.prototype.updateUsedTiles=function(t,e,r){var n=o(e);n in t||(t[n]={}),t[n][r.getKey()]=!0},e.prototype.manageTilePyramid=function(t,e,r,n,i,a,s,l,u){var c=o(e);c in t.wantedTiles||(t.wantedTiles[c]={});var h,p,f,d,g,y,m=t.wantedTiles[c],v=t.tileQueue,_=0;for(y=r.getMinZoom();y<=s;++y)for(p=r.getTileRangeForExtentAndZ(a,y,p),f=r.getResolution(y),d=p.minX;d<=p.maxX;++d)for(g=p.minY;g<=p.maxY;++g)s-y<=l?(++_,(h=e.getTile(y,d,g,n,i)).getState()==Ji&&(m[h.getKey()]=!0,v.isKeyQueued(h.getKey())||v.enqueue([h,c,r.getTileCoordCenter(h.tileCoord),f])),void 0!==u&&u(h)):e.useTile(y,d,g,i);e.updateCacheSize(_,i)},e}(cd);bd.prototype.getLayer;var xd=bd,wd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Sd=function(t){function e(e){return t.call(this,e)||this}return wd(e,t),e.prototype.createRenderer=function(){return new xd(this)},e}(vd),Ed=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Td=!0;try{new ImageData(10,10)}catch(t){Td=!1}var Cd=document.createElement("canvas").getContext("2d");function Od(t,e,r){if(Td)return new ImageData(t,e,r);var n=Cd.createImageData(e,r);return n.data.set(t),n}function Pd(t){var e=!0;try{new ImageData(10,10)}catch(t){e=!1}function r(t,r,n){return e?new ImageData(t,r,n):{data:t,width:r,height:n}}return function(e){var n,i,o=e.buffers,a=e.meta,s=e.imageOps,l=e.width,u=e.height,c=o.length,h=o[0].byteLength;if(s){var p=new Array(c);for(i=0;i<c;++i)p[i]=r(new Uint8ClampedArray(o[i]),l,u);n=t(p,a).data}else{n=new Uint8ClampedArray(h);var f=new Array(c),d=new Array(c);for(i=0;i<c;++i)f[i]=new Uint8ClampedArray(o[i]),d[i]=[0,0,0,0];for(var g=0;g<h;g+=4){for(var y=0;y<c;++y){var m=f[y];d[y][0]=m[g],d[y][1]=m[g+1],d[y][2]=m[g+2],d[y][3]=m[g+3]}var v=t(d,a);n[g]=v[0],n[g+1]=v[1],n[g+2]=v[2],n[g+3]=v[3]}}return n.buffer}}function Rd(t,e){var r=Object.keys(t.lib||{}).map((function(e){return"var "+e+" = "+t.lib[e].toString()+";"})).concat(["var __minion__ = ("+Pd.toString()+")(",t.operation.toString(),");",'self.addEventListener("message", function(event) {'," var buffer = __minion__(event.data);"," self.postMessage({buffer: buffer, meta: event.data.meta}, [buffer]);","});"]),n=new Blob(r,{type:"text/javascript"}),i=URL.createObjectURL(n),o=new Worker(i);return o.addEventListener("message",e),o}var Id=function(t){function e(e){var r,n=t.call(this)||this;n._imageOps=!!e.imageOps;var i=[];if(r=0===e.threads?0:n._imageOps?1:e.threads||1)for(var o=0;o<r;++o)i[o]=Rd(e,n._onWorkerMessage.bind(n,o));else i[0]=function(t,e){var r=Pd(t.operation),n=!1;return{postMessage:function(t){setTimeout((function(){n||e({data:{buffer:r(t),meta:t.meta}})}),0)},terminate:function(){n=!0}}}(e,n._onWorkerMessage.bind(n,0));return n._workers=i,n._queue=[],n._maxQueueLength=e.queue||1/0,n._running=0,n._dataLookup={},n._job=null,n}return Ed(e,t),e.prototype.process=function(t,e,r){this._enqueue({inputs:t,meta:e,callback:r}),this._dispatch()},e.prototype._enqueue=function(t){for(this._queue.push(t);this._queue.length>this._maxQueueLength;)this._queue.shift().callback(null,null)},e.prototype._dispatch=function(){if(0===this._running&&this._queue.length>0){var t=this._queue.shift();this._job=t;var e=t.inputs[0].width,r=t.inputs[0].height,n=t.inputs.map((function(t){return t.data.buffer})),i=this._workers.length;if(this._running=i,1===i)this._workers[0].postMessage({buffers:n,meta:t.meta,imageOps:this._imageOps,width:e,height:r},n);else for(var o=t.inputs[0].data.length,a=4*Math.ceil(o/4/i),s=0;s<i;++s){for(var l=s*a,u=[],c=0,h=n.length;c<h;++c)u.push(n[c].slice(l,l+a));this._workers[s].postMessage({buffers:u,meta:t.meta,imageOps:this._imageOps,width:e,height:r},u)}}},e.prototype._onWorkerMessage=function(t,e){this.disposed||(this._dataLookup[t]=e.data,--this._running,0===this._running&&this._resolveJob())},e.prototype._resolveJob=function(){var t,e,r=this._job,n=this._workers.length;if(1===n)t=new Uint8ClampedArray(this._dataLookup[0].buffer),e=this._dataLookup[0].meta;else{var i=r.inputs[0].data.length;t=new Uint8ClampedArray(i),e=new Array(i);for(var o=4*Math.ceil(i/4/n),a=0;a<n;++a){var s=this._dataLookup[a].buffer,l=a*o;t.set(new Uint8ClampedArray(s),l),e[a]=this._dataLookup[a].meta}}this._job=null,this._dataLookup={},r.callback(null,Od(t,r.inputs[0].width,r.inputs[0].height),e),this._dispatch()},e.prototype.disposeInternal=function(){for(var t=0;t<this._workers.length;++t)this._workers[t].terminate();this._workers.length=0},e}(p),Ld="beforeoperations",Md="afteroperations",Fd="pixel",Ad="image",kd=function(t){function e(e,r,n){var i=t.call(this,e)||this;return i.extent=r.extent,i.resolution=r.viewState.resolution/r.pixelRatio,i.data=n,i}return Ed(e,t),e}(c),jd=function(t){function e(e){var r=t.call(this,{projection:null})||this;r.processor_=null,r.operationType_=void 0!==e.operationType?e.operationType:Fd,r.threads_=void 0!==e.threads?e.threads:1,r.layers_=function(t){for(var e=t.length,r=new Array(e),n=0;n<e;++n)r[n]=Gd(t[n]);return r}(e.sources);for(var n,i=r.changed.bind(r),o=0,a=r.layers_.length;o<a;++o)r.layers_[o].addEventListener(F,i);return r.tileQueue_=new es((function(){return 1}),r.changed.bind(r)),r.requestedFrameState_,r.renderedImageCanvas_=null,r.renderedRevision_,r.frameState_={animate:!1,coordinateToPixelTransform:[1,0,0,1,0,0],declutterTree:null,extent:null,index:0,layerIndex:0,layerStatesArray:(n=r.layers_,n.map((function(t){return t.getLayerState()}))),pixelRatio:1,pixelToCoordinateTransform:[1,0,0,1,0,0],postRenderFunctions:[],size:[0,0],tileQueue:r.tileQueue_,time:Date.now(),usedTiles:{},viewState:{rotation:0},viewHints:[],wantedTiles:{}},r.setAttributions((function(t){for(var r=[],n=0,i=e.sources.length;n<i;++n){var o=e.sources[n],a=(o instanceof Dp?o:o.getSource()).getAttributions();if("function"==typeof a){var s=a(t);r.push.apply(r,s)}}return 0!==r.length?r:null})),void 0!==e.operation&&r.setOperation(e.operation,e.lib),r}return Ed(e,t),e.prototype.setOperation=function(t,e){this.processor_&&this.processor_.dispose(),this.processor_=new Id({operation:t,imageOps:this.operationType_===Ad,queue:1,lib:e,threads:this.threads_}),this.changed()},e.prototype.updateFrameState_=function(t,e,r){var n=O({},this.frameState_);n.viewState=O({},n.viewState);var i=xe(t);n.extent=t.slice(),n.size[0]=Math.round(Pe(t)/e),n.size[1]=Math.round(Ee(t)/e),n.time=1/0;var o=n.viewState;return o.center=i,o.projection=r,o.resolution=e,n},e.prototype.allSourcesReady_=function(){for(var t=!0,e=0,r=this.layers_.length;e<r;++e)if(this.layers_[e].getSource().getState()!==Qo){t=!1;break}return t},e.prototype.getImage=function(t,e,r,n){if(!this.allSourcesReady_())return null;var i=this.updateFrameState_(t,e,n);if(this.requestedFrameState_=i,this.renderedImageCanvas_){var o=this.renderedImageCanvas_.getResolution(),a=this.renderedImageCanvas_.getExtent();e===o&&ue(t,a)||(this.renderedImageCanvas_=null)}return this.renderedImageCanvas_&&this.getRevision()===this.renderedRevision_||this.processSources_(),i.tileQueue.loadMoreTiles(16,16),i.animate&&requestAnimationFrame(this.changed.bind(this)),this.renderedImageCanvas_},e.prototype.processSources_=function(){for(var t=this.requestedFrameState_,e=this.layers_.length,r=new Array(e),n=0;n<e;++n){t.layerIndex=n;var i=Dd(this.layers_[n],t);if(!i)return;r[n]=i}var o={};this.dispatchEvent(new kd(Ld,t,o)),this.processor_.process(r,o,this.onWorkerComplete_.bind(this,t))},e.prototype.onWorkerComplete_=function(t,e,r,n){if(!e&&r){var i=t.extent,o=t.viewState.resolution;if(o===this.requestedFrameState_.viewState.resolution&&ue(i,this.requestedFrameState_.extent)){var a;if(this.renderedImageCanvas_)a=this.renderedImageCanvas_.getImage().getContext("2d");else a=uo(Math.round(Pe(i)/o),Math.round(Ee(i)/o)),this.renderedImageCanvas_=new $i(i,o,1,a.canvas);a.putImageData(r,0,0),this.changed(),this.renderedRevision_=this.getRevision(),this.dispatchEvent(new kd(Md,t,n))}}},e.prototype.getImageInternal=function(){return null},e.prototype.disposeInternal=function(){this.processor_&&this.processor_.dispose(),t.prototype.disposeInternal.call(this)},e}(zf);jd.prototype.dispose;var Nd=null;function Dd(t,e){var r=t.getRenderer();if(!r)throw new Error("Unsupported layer type: "+t);if(!r.prepareFrame(e))return null;var n=e.size[0],i=e.size[1];if(0===n||0===i)return null;var o,a=r.renderFrame(e,null);if(a&&(o=a.firstElementChild),!(o instanceof HTMLCanvasElement))throw new Error("Unsupported rendered element: "+o);if(o.width===n&&o.height===i)return o.getContext("2d").getImageData(0,0,n,i);if(Nd){var s=Nd.canvas;s.width!==n||s.height!==i?Nd=uo(n,i):Nd.clearRect(0,0,n,i)}else Nd=uo(n,i);return Nd.drawImage(o,0,0,n,i),Nd.getImageData(0,0,n,i)}function Gd(t){var e;return t instanceof Dp?t instanceof Bp?e=new Sd({source:t}):t instanceof zf&&(e=new dd({source:t})):e=t,e}var zd=jd,Ud=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Bd=['Map tiles by <a href="https://stamen.com/" target="_blank">Stamen Design</a>, under <a href="https://creativecommons.org/licenses/by/3.0/" target="_blank">CC BY 3.0</a>.',nd],Vd={terrain:{extension:"jpg",opaque:!0},"terrain-background":{extension:"jpg",opaque:!0},"terrain-labels":{extension:"png",opaque:!1},"terrain-lines":{extension:"png",opaque:!1},"toner-background":{extension:"png",opaque:!0},toner:{extension:"png",opaque:!0},"toner-hybrid":{extension:"png",opaque:!1},"toner-labels":{extension:"png",opaque:!1},"toner-lines":{extension:"png",opaque:!1},"toner-lite":{extension:"png",opaque:!0},watercolor:{extension:"jpg",opaque:!0}},Yd={terrain:{minZoom:0,maxZoom:18},toner:{minZoom:0,maxZoom:20},watercolor:{minZoom:0,maxZoom:18}},Wd=function(t){function e(e){var r=e.layer.indexOf("-"),n=-1==r?e.layer:e.layer.slice(0,r),i=Yd[n],o=Vd[e.layer],a=void 0!==e.url?e.url:"https://stamen-tiles-{a-d}.a.ssl.fastly.net/"+e.layer+"/{z}/{x}/{y}."+o.extension;return t.call(this,{attributions:Bd,cacheSize:e.cacheSize,crossOrigin:"anonymous",imageSmoothing:e.imageSmoothing,maxZoom:null!=e.maxZoom?e.maxZoom:i.maxZoom,minZoom:null!=e.minZoom?e.minZoom:i.minZoom,opaque:o.opaque,reprojectionErrorThreshold:e.reprojectionErrorThreshold,tileLoadFunction:e.tileLoadFunction,transition:e.transition,url:a,wrapX:e.wrapX})||this}return Ud(e,t),e}(Jp),qd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Xd=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,{attributions:n.attributions,cacheSize:n.cacheSize,crossOrigin:n.crossOrigin,imageSmoothing:n.imageSmoothing,projection:n.projection,reprojectionErrorThreshold:n.reprojectionErrorThreshold,tileGrid:n.tileGrid,tileLoadFunction:n.tileLoadFunction,url:n.url,urls:n.urls,wrapX:void 0===n.wrapX||n.wrapX,transition:n.transition})||this).params_=n.params||{},r.hidpi_=void 0===n.hidpi||n.hidpi,r.tmpExtent_=[1/0,1/0,-1/0,-1/0],r.setKey(r.getKeyForParams_()),r}return qd(e,t),e.prototype.getKeyForParams_=function(){var t=0,e=[];for(var r in this.params_)e[t++]=r+"-"+this.params_[r];return e.join("/")},e.prototype.getParams=function(){return this.params_},e.prototype.getRequestUrl_=function(t,e,r,n,i,o){var a=this.urls;if(a){var s,l=i.getCode().split(":").pop();if(o.SIZE=e[0]+","+e[1],o.BBOX=r.join(","),o.BBOXSR=l,o.IMAGESR=l,o.DPI=Math.round(o.DPI?o.DPI*n:90*n),1==a.length)s=a[0];else s=a[We(fu(t),a.length)];return mc(s.replace(/MapServer\/?$/,"MapServer/export").replace(/ImageServer\/?$/,"ImageServer/exportImage"),o)}},e.prototype.getTilePixelRatio=function(t){return this.hidpi_?t:1},e.prototype.updateParams=function(t){O(this.params_,t),this.setKey(this.getKeyForParams_())},e.prototype.tileUrlFunction=function(t,e,r){var n=this.getTileGrid();if(n||(n=this.getTileGridForProjection(r)),!(n.getResolutions().length<=t[0])){1==e||this.hidpi_||(e=1);var i=n.getTileCoordExtent(t,this.tmpExtent_),o=Is(n.getTileSize(t[0]),this.tmpSize);1!=e&&(o=Rs(o,e,this.tmpSize));var a={F:"image",FORMAT:"PNG32",TRANSPARENT:!0};return O(a,this.params_),this.getRequestUrl_(t,o,i,e,r,a)}},e}(Xp),Zd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Kd=function(t){function e(e,r,n){var i=t.call(this,e,to)||this;return i.tileSize_=r,i.text_=n,i.canvas_=null,i}return Zd(e,t),e.prototype.getImage=function(){if(this.canvas_)return this.canvas_;var t=this.tileSize_,e=uo(t[0],t[1]);return e.strokeStyle="grey",e.strokeRect(.5,.5,t[0]+.5,t[1]+.5),e.fillStyle="grey",e.strokeStyle="white",e.textAlign="center",e.textBaseline="middle",e.font="24px sans-serif",e.lineWidth=4,e.strokeText(this.text_,t[0]/2,t[1]/2,t[0]),e.fillText(this.text_,t[0]/2,t[1]/2,t[0]),this.canvas_=e.canvas,e.canvas},e.prototype.load=function(){},e}(lo),Hd=function(t){function e(e){var r=e||{};return t.call(this,{opaque:!1,projection:r.projection,tileGrid:r.tileGrid,wrapX:void 0===r.wrapX||r.wrapX,zDirection:r.zDirection})||this}return Zd(e,t),e.prototype.getTile=function(t,e,r){var n=cu(t,e,r);if(this.tileCache.containsKey(n))return this.tileCache.get(n);var i=Is(this.tileGrid.getTileSize(t)),o=[t,e,r],a=this.getTileCoordForTileUrlFunction(o),s=void 0;s=a?"z:"+a[0]+" x:"+a[1]+" y:"+a[2]:"none";var l=new Kd(o,i,s);return this.tileCache.set(n,l),l},e}(Jp),$d=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Jd=function(t){function e(e){var r=t.call(this,{attributions:e.attributions,cacheSize:e.cacheSize,crossOrigin:e.crossOrigin,imageSmoothing:e.imageSmoothing,projection:Gr("EPSG:3857"),reprojectionErrorThreshold:e.reprojectionErrorThreshold,state:Jo,tileLoadFunction:e.tileLoadFunction,wrapX:void 0===e.wrapX||e.wrapX,transition:e.transition})||this;if(r.tileJSON_=null,r.tileSize_=e.tileSize,e.url)if(e.jsonp)Au(e.url,r.handleTileJSONResponse.bind(r),r.handleTileJSONError.bind(r));else{var n=new XMLHttpRequest;n.addEventListener("load",r.onXHRLoad_.bind(r)),n.addEventListener("error",r.onXHRError_.bind(r)),n.open("GET",e.url),n.send()}else e.tileJSON?r.handleTileJSONResponse(e.tileJSON):pt(!1,51);return r}return $d(e,t),e.prototype.onXHRLoad_=function(t){var e=t.target;if(!e.status||e.status>=200&&e.status<300){var r=void 0;try{r=JSON.parse(e.responseText)}catch(t){return void this.handleTileJSONError()}this.handleTileJSONResponse(r)}else this.handleTileJSONError()},e.prototype.onXHRError_=function(t){this.handleTileJSONError()},e.prototype.getTileJSON=function(){return this.tileJSON_},e.prototype.handleTileJSONResponse=function(t){var e,r=Gr("EPSG:4326"),n=this.getProjection();if(void 0!==t.bounds){var i=Zr(r,n);e=Ae(t.bounds,i)}var o=t.minzoom||0,a=t.maxzoom||22,s=lc({extent:hc(n),maxZoom:a,minZoom:o,tileSize:this.tileSize_});if(this.tileGrid=s,this.tileUrlFunction=fc(t.tiles,s),void 0!==t.attribution&&!this.getAttributions()){var l=void 0!==e?e:r.getExtent();this.setAttributions((function(e){return Re(l,e.extent)?[t.attribution]:null}))}this.tileJSON_=t,this.setState(Qo)},e.prototype.handleTileJSONError=function(){this.setState(ta)},e}(Xp),Qd=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),tg=function(t){function e(e){var r=this,n=e||{},i=n.params||{},o=!("TRANSPARENT"in i)||i.TRANSPARENT;return(r=t.call(this,{attributions:n.attributions,cacheSize:n.cacheSize,crossOrigin:n.crossOrigin,imageSmoothing:n.imageSmoothing,opaque:!o,projection:n.projection,reprojectionErrorThreshold:n.reprojectionErrorThreshold,tileClass:n.tileClass,tileGrid:n.tileGrid,tileLoadFunction:n.tileLoadFunction,url:n.url,urls:n.urls,wrapX:void 0===n.wrapX||n.wrapX,transition:n.transition})||this).gutter_=void 0!==n.gutter?n.gutter:0,r.params_=i,r.v13_=!0,r.serverType_=n.serverType,r.hidpi_=void 0===n.hidpi||n.hidpi,r.tmpExtent_=[1/0,1/0,-1/0,-1/0],r.updateV13_(),r.setKey(r.getKeyForParams_()),r}return Qd(e,t),e.prototype.getFeatureInfoUrl=function(t,e,r,n){var i=Gr(r),o=this.getProjection(),a=this.getTileGrid();a||(a=this.getTileGridForProjection(i));var s=a.getZForResolution(e,this.zDirection),l=a.getTileCoordForCoordAndZ(t,s);if(!(a.getResolutions().length<=l[0])){var u=a.getResolution(l[0]),c=a.getTileCoordExtent(l,this.tmpExtent_),h=Is(a.getTileSize(l[0]),this.tmpSize),p=this.gutter_;0!==p&&(h=Os(h,p,this.tmpSize),c=Ht(c,u*p,c)),o&&o!==i&&(u=tc(o,i,t,u),c=$r(c,i,o),t=Hr(t,i,o));var f={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetFeatureInfo",FORMAT:"image/png",TRANSPARENT:!0,QUERY_LAYERS:this.params_.LAYERS};O(f,this.params_,n);var d=Math.floor((t[0]-c[0])/u),g=Math.floor((c[3]-t[1])/u);return f[this.v13_?"I":"X"]=d,f[this.v13_?"J":"Y"]=g,this.getRequestUrl_(l,h,c,1,o||i,f)}},e.prototype.getLegendUrl=function(t,e){if(void 0!==this.urls[0]){var r={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetLegendGraphic",FORMAT:"image/png"};if(void 0===e||void 0===e.LAYER){var n=this.params_.LAYERS;if(!(!Array.isArray(n)||1===n.length))return;r.LAYER=n}if(void 0!==t){var i=this.getProjection()?this.getProjection().getMetersPerUnit():1;r.SCALE=t*i/28e-5}return O(r,e),mc(this.urls[0],r)}},e.prototype.getGutter=function(){return this.gutter_},e.prototype.getParams=function(){return this.params_},e.prototype.getRequestUrl_=function(t,e,r,n,i,o){var a=this.urls;if(a){if(o.WIDTH=e[0],o.HEIGHT=e[1],o[this.v13_?"CRS":"SRS"]=i.getCode(),"STYLES"in this.params_||(o.STYLES=""),1!=n)switch(this.serverType_){case Hf:var s=90*n+.5|0;"FORMAT_OPTIONS"in o?o.FORMAT_OPTIONS+=";dpi:"+s:o.FORMAT_OPTIONS="dpi:"+s;break;case $f:o.MAP_RESOLUTION=90*n;break;case Kf:case Jf:o.DPI=90*n;break;default:pt(!1,52)}var l,u=i.getAxisOrientation(),c=r;if(this.v13_&&"ne"==u.substr(0,2)){var h=void 0;h=r[0],c[0]=r[1],c[1]=h,h=r[2],c[2]=r[3],c[3]=h}if(o.BBOX=c.join(","),1==a.length)l=a[0];else l=a[We(fu(t),a.length)];return mc(l,o)}},e.prototype.getTilePixelRatio=function(t){return this.hidpi_&&void 0!==this.serverType_?t:1},e.prototype.getKeyForParams_=function(){var t=0,e=[];for(var r in this.params_)e[t++]=r+"-"+this.params_[r];return e.join("/")},e.prototype.updateParams=function(t){O(this.params_,t),this.updateV13_(),this.setKey(this.getKeyForParams_())},e.prototype.updateV13_=function(){var t=this.params_.VERSION||"1.3.0";this.v13_=br(t,"1.3")>=0},e.prototype.tileUrlFunction=function(t,e,r){var n=this.getTileGrid();if(n||(n=this.getTileGridForProjection(r)),!(n.getResolutions().length<=t[0])){1==e||this.hidpi_&&void 0!==this.serverType_||(e=1);var i=n.getResolution(t[0]),o=n.getTileCoordExtent(t,this.tmpExtent_),a=Is(n.getTileSize(t[0]),this.tmpSize),s=this.gutter_;0!==s&&(a=Os(a,s,this.tmpSize),o=Ht(o,i*s,o)),1!=e&&(a=Rs(a,e,this.tmpSize));var l={SERVICE:"WMS",VERSION:"1.3.0",REQUEST:"GetMap",FORMAT:"image/png",TRANSPARENT:!0};return O(l,this.params_),this.getRequestUrl_(t,a,o,e,r,l)}},e}(Xp),eg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),rg=function(t){function e(e,r,n,i,o,a){var s=t.call(this,e,r)||this;return s.src_=n,s.extent_=i,s.preemptive_=o,s.grid_=null,s.keys_=null,s.data_=null,s.jsonp_=a,s}return eg(e,t),e.prototype.getImage=function(){return null},e.prototype.getData=function(t){if(!this.grid_||!this.keys_)return null;var e=(t[0]-this.extent_[0])/(this.extent_[2]-this.extent_[0]),r=(t[1]-this.extent_[1])/(this.extent_[3]-this.extent_[1]),n=this.grid_[Math.floor((1-r)*this.grid_.length)];if("string"!=typeof n)return null;var i=n.charCodeAt(Math.floor(e*n.length));i>=93&&i--,i>=35&&i--;var o=null;if((i-=32)in this.keys_){var a=this.keys_[i];o=this.data_&&a in this.data_?this.data_[a]:a}return o},e.prototype.forDataAtCoordinate=function(t,e,r){this.state==ro&&!0===r?(this.state=Ji,K(this,F,(function(r){e(this.getData(t))}),this),this.loadInternal_()):!0===r?setTimeout(function(){e(this.getData(t))}.bind(this),0):e(this.getData(t))},e.prototype.getKey=function(){return this.src_},e.prototype.handleError_=function(){this.state=eo,this.changed()},e.prototype.handleLoad_=function(t){this.grid_=t.grid,this.keys_=t.keys,this.data_=t.data,this.state=to,this.changed()},e.prototype.loadInternal_=function(){if(this.state==Ji)if(this.state=Qi,this.jsonp_)Au(this.src_,this.handleLoad_.bind(this),this.handleError_.bind(this));else{var t=new XMLHttpRequest;t.addEventListener("load",this.onXHRLoad_.bind(this)),t.addEventListener("error",this.onXHRError_.bind(this)),t.open("GET",this.src_),t.send()}},e.prototype.onXHRLoad_=function(t){var e=t.target;if(!e.status||e.status>=200&&e.status<300){var r=void 0;try{r=JSON.parse(e.responseText)}catch(t){return void this.handleError_()}this.handleLoad_(r)}else this.handleError_()},e.prototype.onXHRError_=function(t){this.handleError_()},e.prototype.load=function(){this.preemptive_?this.loadInternal_():this.setState(ro)},e}(lo),ng=function(t){function e(e){var r=t.call(this,{projection:Gr("EPSG:3857"),state:Jo})||this;if(r.preemptive_=void 0===e.preemptive||e.preemptive,r.tileUrlFunction_=gc,r.template_=void 0,r.jsonp_=e.jsonp||!1,e.url)if(r.jsonp_)Au(e.url,r.handleTileJSONResponse.bind(r),r.handleTileJSONError.bind(r));else{var n=new XMLHttpRequest;n.addEventListener("load",r.onXHRLoad_.bind(r)),n.addEventListener("error",r.onXHRError_.bind(r)),n.open("GET",e.url),n.send()}else e.tileJSON?r.handleTileJSONResponse(e.tileJSON):pt(!1,51);return r}return eg(e,t),e.prototype.onXHRLoad_=function(t){var e=t.target;if(!e.status||e.status>=200&&e.status<300){var r=void 0;try{r=JSON.parse(e.responseText)}catch(t){return void this.handleTileJSONError()}this.handleTileJSONResponse(r)}else this.handleTileJSONError()},e.prototype.onXHRError_=function(t){this.handleTileJSONError()},e.prototype.getTemplate=function(){return this.template_},e.prototype.forDataAtCoordinateAndResolution=function(t,e,r,n){if(this.tileGrid){var i=this.tileGrid.getZForResolution(e,this.zDirection),o=this.tileGrid.getTileCoordForCoordAndZ(t,i);this.getTile(o[0],o[1],o[2],1,this.getProjection()).forDataAtCoordinate(t,r,n)}else!0===n?setTimeout((function(){r(null)}),0):r(null)},e.prototype.handleTileJSONError=function(){this.setState(ta)},e.prototype.handleTileJSONResponse=function(t){var e,r=Gr("EPSG:4326"),n=this.getProjection();if(void 0!==t.bounds){var i=Zr(r,n);e=Ae(t.bounds,i)}var o=t.minzoom||0,a=t.maxzoom||22,s=lc({extent:hc(n),maxZoom:a,minZoom:o});this.tileGrid=s,this.template_=t.template;var l=t.grids;if(l){if(this.tileUrlFunction_=fc(l,s),void 0!==t.attribution){var u=void 0!==e?e:r.getExtent();this.setAttributions((function(e){return Re(u,e.extent)?[t.attribution]:null}))}this.setState(Qo)}else this.setState(ta)},e.prototype.getTile=function(t,e,r,n,i){var o=cu(t,e,r);if(this.tileCache.containsKey(o))return this.tileCache.get(o);var a=[t,e,r],s=this.getTileCoordForTileUrlFunction(a,i),l=this.tileUrlFunction_(s,n,i),u=new rg(a,void 0!==l?Ji:ro,void 0!==l?l:"",this.tileGrid.getTileCoordExtent(a),this.preemptive_,this.jsonp_);return this.tileCache.set(o,u),u},e.prototype.useTile=function(t,e,r){var n=cu(t,e,r);this.tileCache.containsKey(n)&&this.tileCache.get(n)},e}(Bp),ig=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),og=function(t){function e(e){var r=this,n=e.projection||"EPSG:3857",i=e.extent||hc(n),o=e.tileGrid||lc({extent:i,maxResolution:e.maxResolution,maxZoom:void 0!==e.maxZoom?e.maxZoom:22,minZoom:e.minZoom,tileSize:e.tileSize||512});return(r=t.call(this,{attributions:e.attributions,attributionsCollapsible:e.attributionsCollapsible,cacheSize:e.cacheSize,opaque:!1,projection:n,state:e.state,tileGrid:o,tileLoadFunction:e.tileLoadFunction?e.tileLoadFunction:ag,tileUrlFunction:e.tileUrlFunction,url:e.url,urls:e.urls,wrapX:void 0===e.wrapX||e.wrapX,transition:e.transition,zDirection:void 0===e.zDirection?1:e.zDirection})||this).format_=e.format?e.format:null,r.loadingTiles_={},r.sourceTileCache=new yu(r.tileCache.highWaterMark),r.overlaps_=null==e.overlaps||e.overlaps,r.tileClass=e.tileClass?e.tileClass:Eu,r.tileGrids_={},r}return ig(e,t),e.prototype.getFeaturesInExtent=function(t){var e=[],r=this.tileCache;if(0===r.getCount())return e;var n=pu(r.peekFirstKey())[0],i=this.tileGrid;return r.forEach((function(r){if(r.tileCoord[0]===n&&r.getState()===to)for(var o=r.getSourceTiles(),a=0,s=o.length;a<s;++a){var l=o[a],u=l.tileCoord;if(Re(t,i.getTileCoordExtent(u))){var c=l.getFeatures();if(c)for(var h=0,p=c.length;h<p;++h){var f=c[h],d=f.getGeometry();Re(t,d.getExtent())&&e.push(f)}}}})),e},e.prototype.getOverlaps=function(){return this.overlaps_},e.prototype.clear=function(){this.tileCache.clear(),this.sourceTileCache.clear()},e.prototype.expireCache=function(e,r){t.prototype.expireCache.call(this,e,r),this.sourceTileCache.expireCache({})},e.prototype.getSourceTiles=function(t,e,r){var n=r.wrappedTileCoord,i=this.getTileGridForProjection(e),o=i.getTileCoordExtent(n),a=n[0],s=i.getResolution(a);Ht(o,-s,o);var l=this.tileGrid,u=l.getExtent();u&&Te(o,u,o);var c,h,p,f=l.getZForResolution(s,1),d=l.getMinZoom(),g=r.sourceTiles;if(g&&g.length>0&&g[0].tileCoord[0]===f)c=g,h=!0,p=f;else{c=[],p=f+1;do{--p,h=!0,l.forEachTileCoord(o,p,function(n){var i,o=this.tileUrlFunction(n,t,e);if(void 0!==o)if(this.sourceTileCache.containsKey(o)){var a=(i=this.sourceTileCache.get(o)).getState();if(a===to||a===eo||a===ro)return void c.push(i)}else p===f&&((i=new this.tileClass(n,Ji,o,this.format_,this.tileLoadFunction)).extent=l.getTileCoordExtent(n),i.projection=e,i.resolution=l.getResolution(n[0]),this.sourceTileCache.set(o,i),i.addEventListener(F,this.handleTileChange.bind(this)),i.load());h=h&&i&&i.getState()===to,i&&i.getState()!==ro&&r.getState()===Ji&&(r.loadingSourceTiles++,i.addEventListener(F,(function t(){var e=i.getState(),n=i.getKey();if(e===to||e===eo){e===to?(i.removeEventListener(F,t),r.loadingSourceTiles--,delete r.errorSourceTileKeys[n]):e===eo&&(r.errorSourceTileKeys[n]=!0);var o=Object.keys(r.errorSourceTileKeys).length;r.loadingSourceTiles-o==0&&(r.hifi=0===o,r.sourceZ=f,r.setState(to))}})))}.bind(this)),h||(c.length=0)}while(!h&&p>d)}return r.getState()===Ji&&r.setState(Qi),h&&(r.hifi=f===p,r.sourceZ=p,r.getState()<to?r.setState(to):g&&b(c,g)||(r.sourceTiles=c)),c},e.prototype.getTile=function(t,e,r,n,i){var o,a=cu(t,e,r),s=this.getKey();if(this.tileCache.containsKey(a)&&(o=this.tileCache.get(a)).key===s)return o;var l=[t,e,r],u=this.getTileCoordForTileUrlFunction(l,i),c=this.getTileGrid().getExtent(),h=this.getTileGridForProjection(i);if(u&&c){var p=h.getTileCoordExtent(u);Ht(p,-h.getResolution(t),p),Re(c,p)||(u=null)}var f=!0;if(null!==u){var d=this.tileGrid,g=h.getResolution(t),y=d.getZForResolution(g,1),m=h.getTileCoordExtent(u);Ht(m,-g,m),d.forEachTileCoord(m,y,function(t){f=f&&!this.tileUrlFunction(t,n,i)}.bind(this))}var v=new wu(l,f?ro:Ji,u,this.getSourceTiles.bind(this,n,i));return v.key=s,o?(v.interimTile=o,v.refreshInterimChain(),this.tileCache.replace(a,v)):this.tileCache.set(a,v),v},e.prototype.getTileGridForProjection=function(t){var e=t.getCode(),r=this.tileGrids_[e];if(!r){var n=this.tileGrid;r=cc(t,void 0,n?n.getTileSize(n.getMinZoom()):void 0),this.tileGrids_[e]=r}return r},e.prototype.getTilePixelRatio=function(t){return t},e.prototype.getTilePixelSize=function(t,e,r){var n=Is(this.getTileGridForProjection(r).getTileSize(t),this.tmpSize);return[Math.round(n[0]*e),Math.round(n[1]*e)]},e.prototype.updateCacheSize=function(e,r){t.prototype.updateCacheSize.call(this,2*e,r)},e}(Yp);function ag(t,e){t.setLoader((function(r,n,i){Lu(e,t.getFormat(),r,n,i,t.onLoad.bind(t),t.onError.bind(t))}))}var sg="KVP",lg="REST",ug=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),cg=function(t){function e(e){var r=this,n=void 0!==e.requestEncoding?e.requestEncoding:sg,i=e.tileGrid,o=e.urls;return void 0===o&&void 0!==e.url&&(o=yc(e.url)),(r=t.call(this,{attributions:e.attributions,cacheSize:e.cacheSize,crossOrigin:e.crossOrigin,imageSmoothing:e.imageSmoothing,projection:e.projection,reprojectionErrorThreshold:e.reprojectionErrorThreshold,tileClass:e.tileClass,tileGrid:i,tileLoadFunction:e.tileLoadFunction,tilePixelRatio:e.tilePixelRatio,urls:o,wrapX:void 0!==e.wrapX&&e.wrapX,transition:e.transition})||this).version_=void 0!==e.version?e.version:"1.0.0",r.format_=void 0!==e.format?e.format:"image/jpeg",r.dimensions_=void 0!==e.dimensions?e.dimensions:{},r.layer_=e.layer,r.matrixSet_=e.matrixSet,r.style_=e.style,r.requestEncoding_=n,r.setKey(r.getKeyForDimensions_()),o&&o.length>0&&(r.tileUrlFunction=dc(o.map(r.createFromWMTSTemplate.bind(r)))),r}return ug(e,t),e.prototype.setUrls=function(t){this.urls=t;var e=t.join("\n");this.setTileUrlFunction(dc(t.map(this.createFromWMTSTemplate.bind(this))),e)},e.prototype.getDimensions=function(){return this.dimensions_},e.prototype.getFormat=function(){return this.format_},e.prototype.getLayer=function(){return this.layer_},e.prototype.getMatrixSet=function(){return this.matrixSet_},e.prototype.getRequestEncoding=function(){return this.requestEncoding_},e.prototype.getStyle=function(){return this.style_},e.prototype.getVersion=function(){return this.version_},e.prototype.getKeyForDimensions_=function(){var t=0,e=[];for(var r in this.dimensions_)e[t++]=r+"-"+this.dimensions_[r];return e.join("/")},e.prototype.updateDimensions=function(t){O(this.dimensions_,t),this.setKey(this.getKeyForDimensions_())},e.prototype.createFromWMTSTemplate=function(t){var e=this.requestEncoding_,r={layer:this.layer_,style:this.style_,tilematrixset:this.matrixSet_};e==sg&&O(r,{Service:"WMTS",Request:"GetTile",Version:this.version_,Format:this.format_}),t=e==sg?mc(t,r):t.replace(/\{(\w+?)\}/g,(function(t,e){return e.toLowerCase()in r?r[e.toLowerCase()]:t}));var n=this.tileGrid,i=this.dimensions_;return function(r,o,a){if(r){var s={TileMatrix:n.getMatrixId(r[0]),TileCol:r[1],TileRow:r[2]};O(s,i);var l=t;return l=e==sg?mc(l,s):l.replace(/\{(\w+?)\}/g,(function(t,e){return s[e]}))}}},e}(Xp);var hg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),pg="GENERATE_BUFFERS",fg=function(t){function e(e,r){var n=t.call(this,e)||this,i=r||{};return n.helper=new gh({postProcesses:i.postProcesses,uniforms:i.uniforms}),void 0!==i.className&&(n.helper.getCanvas().className=i.className),n}return hg(e,t),e.prototype.disposeInternal=function(){this.helper.dispose(),t.prototype.disposeInternal.call(this)},e.prototype.getShaderCompileErrors=function(){return this.helper.getShaderCompileErrors()},e.prototype.dispatchRenderEvent_=function(t,e){var r=this.getLayer();if(r.hasListener(t)){var n=new la(t,null,e,null);r.dispatchEvent(n)}},e.prototype.preRender=function(t){this.dispatchRenderEvent_(qo,t)},e.prototype.postRender=function(t){this.dispatchRenderEvent_(Xo,t)},e}(ld),dg=[],gg={vertexPosition:0,indexPosition:0};function yg(t,e,r,n,i){t[e+0]=r,t[e+1]=n,t[e+2]=i}function mg(t,e){var r=e||[];return r[0]=Math.floor(t/256/256/256)/255,r[1]=Math.floor(t/256/256)%256/255,r[2]=Math.floor(t/256)%256/255,r[3]=t%256/255,r}function vg(t){var e=0;return e+=Math.round(256*t[0]*256*256*255),e+=Math.round(256*t[1]*256*255),e+=Math.round(256*t[2]*255),e+=Math.round(255*t[3])}var _g=fg,bg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),xg="renderOrder",wg=function(t){function e(e){var r=this,n=e||{},i=O({},n);return delete i.style,delete i.renderBuffer,delete i.updateWhileAnimating,delete i.updateWhileInteracting,(r=t.call(this,i)||this).declutter_=void 0!==n.declutter&&n.declutter,r.renderBuffer_=void 0!==n.renderBuffer?n.renderBuffer:100,r.style_=null,r.styleFunction_=void 0,r.setStyle(n.style),r.updateWhileAnimating_=void 0!==n.updateWhileAnimating&&n.updateWhileAnimating,r.updateWhileInteracting_=void 0!==n.updateWhileInteracting&&n.updateWhileInteracting,r}return bg(e,t),e.prototype.getDeclutter=function(){return this.declutter_},e.prototype.getFeatures=function(e){return t.prototype.getFeatures.call(this,e)},e.prototype.getRenderBuffer=function(){return this.renderBuffer_},e.prototype.getRenderOrder=function(){return this.get(xg)},e.prototype.getStyle=function(){return this.style_},e.prototype.getStyleFunction=function(){return this.styleFunction_},e.prototype.getUpdateWhileAnimating=function(){return this.updateWhileAnimating_},e.prototype.getUpdateWhileInteracting=function(){return this.updateWhileInteracting_},e.prototype.renderDeclutter=function(t){t.declutterTree||(t.declutterTree=new Pp.a(9)),this.getRenderer().renderDeclutter(t)},e.prototype.setRenderOrder=function(t){this.set(xg,t)},e.prototype.setStyle=function(t){this.style_=void 0!==t?t:_p,this.styleFunction_=null===t?void 0:mp(this.style_),this.changed()},e}(na),Sg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Eg=function(t){function e(e,r){var n=this,i=r.uniforms||{},a=[1,0,0,1,0,0];i[ah]=a,(n=t.call(this,e,{className:r.className,uniforms:i,postProcesses:r.postProcesses})||this).sourceRevision_=-1,n.verticesBuffer_=new Qc(34962,35048),n.hitVerticesBuffer_=new Qc(34962,35048),n.indicesBuffer_=new Qc(34963,35048),n.program_=n.helper.getProgram(r.fragmentShader,r.vertexShader),n.hitDetectionEnabled_=!(!r.hitFragmentShader||!r.hitVertexShader),n.hitProgram_=n.hitDetectionEnabled_&&n.helper.getProgram(r.hitFragmentShader,r.hitVertexShader);var s=r.attributes?r.attributes.map((function(t){return{name:"a_"+t.name,size:1,type:ph.FLOAT}})):[];n.attributes=[{name:"a_position",size:2,type:ph.FLOAT},{name:"a_index",size:1,type:ph.FLOAT}].concat(s),n.hitDetectionAttributes=[{name:"a_position",size:2,type:ph.FLOAT},{name:"a_index",size:1,type:ph.FLOAT},{name:"a_hitColor",size:4,type:ph.FLOAT},{name:"a_featureUid",size:1,type:ph.FLOAT}].concat(s),n.customAttributes=r.attributes?r.attributes:[],n.previousExtent_=[1/0,1/0,-1/0,-1/0],n.currentTransform_=a,n.renderTransform_=[1,0,0,1,0,0],n.invertRenderTransform_=[1,0,0,1,0,0],n.renderInstructions_=new Float32Array(0),n.hitRenderInstructions_=new Float32Array(0),n.hitRenderTarget_=n.hitDetectionEnabled_&&new mh(n.helper),n.worker_=new Worker(Hc),n.worker_.addEventListener("message",function(t){var e=t.data;if(e.type===pg){var r=e.projectionTransform;e.hitDetection?(this.hitVerticesBuffer_.fromArrayBuffer(e.vertexBuffer),this.helper.flushBufferData(this.hitVerticesBuffer_)):(this.verticesBuffer_.fromArrayBuffer(e.vertexBuffer),this.helper.flushBufferData(this.verticesBuffer_)),this.indicesBuffer_.fromArrayBuffer(e.indexBuffer),this.helper.flushBufferData(this.indicesBuffer_),this.renderTransform_=r,jt(this.invertRenderTransform_,this.renderTransform_),e.hitDetection?this.hitRenderInstructions_=new Float32Array(t.data.renderInstructions):this.renderInstructions_=new Float32Array(t.data.renderInstructions),this.getLayer().changed()}}.bind(n)),n.featureCache_={},n.featureCount_=0;var l=n.getLayer().getSource();return n.sourceListenKeys_=[Z(l,ef,n.handleSourceFeatureAdded_,n),Z(l,rf,n.handleSourceFeatureChanged_,n),Z(l,of,n.handleSourceFeatureDelete_,n),Z(l,nf,n.handleSourceFeatureClear_,n)],l.forEachFeature(function(t){this.featureCache_[o(t)]={feature:t,properties:t.getProperties(),geometry:t.getGeometry()},this.featureCount_++}.bind(n)),n}return Sg(e,t),e.prototype.handleSourceFeatureAdded_=function(t){var e=t.feature;this.featureCache_[o(e)]={feature:e,properties:e.getProperties(),geometry:e.getGeometry()},this.featureCount_++},e.prototype.handleSourceFeatureChanged_=function(t){var e=t.feature;this.featureCache_[o(e)]={feature:e,properties:e.getProperties(),geometry:e.getGeometry()}},e.prototype.handleSourceFeatureDelete_=function(t){var e=t.feature;delete this.featureCache_[o(e)],this.featureCount_--},e.prototype.handleSourceFeatureClear_=function(){this.featureCache_={},this.featureCount_=0},e.prototype.renderFrame=function(t){this.preRender(t);var e=this.indicesBuffer_.getSize();this.helper.drawElements(0,e),this.helper.finalizeDraw(t);var r=this.helper.getCanvas(),n=t.layerStatesArray[t.layerIndex].opacity;return n!==parseFloat(r.style.opacity)&&(r.style.opacity=String(n)),this.hitDetectionEnabled_&&(this.renderHitDetection(t),this.hitRenderTarget_.clearCachedData()),this.postRender(t),r},e.prototype.prepareFrame=function(t){var e=this.getLayer(),r=e.getSource(),n=t.viewState,i=!t.viewHints[ns]&&!t.viewHints[is],o=!ue(this.previousExtent_,t.extent),a=this.sourceRevision_<r.getRevision();if(a&&(this.sourceRevision_=r.getRevision()),i&&(o||a)){var s=n.projection,l=n.resolution,u=e instanceof wg?e.getRenderBuffer():0,c=Ht(t.extent,u*l);r.loadFeatures(c,l,s),this.rebuildBuffers_(t),this.previousExtent_=t.extent.slice()}return this.helper.makeProjectionTransform(t,this.currentTransform_),Ot(this.currentTransform_,this.invertRenderTransform_),this.helper.useProgram(this.program_),this.helper.prepareDraw(t),this.helper.bindBuffer(this.verticesBuffer_),this.helper.bindBuffer(this.indicesBuffer_),this.helper.enableAttributes(this.attributes),!0},e.prototype.rebuildBuffers_=function(t){var e=[1,0,0,1,0,0];this.helper.makeProjectionTransform(t,e);var r,n,i=(2+this.customAttributes.length)*this.featureCount_;if(this.renderInstructions_&&this.renderInstructions_.length===i||(this.renderInstructions_=new Float32Array(i)),this.hitDetectionEnabled_){var o=(7+this.customAttributes.length)*this.featureCount_;this.hitRenderInstructions_&&this.hitRenderInstructions_.length===o||(this.hitRenderInstructions_=new Float32Array(o))}var a,s=[],l=[],u=0,c=0;for(var h in this.featureCache_)if((n=(r=this.featureCache_[h]).geometry)&&n.getType()===bt.POINT){s[0]=n.getFlatCoordinates()[0],s[1]=n.getFlatCoordinates()[1],It(e,s),a=mg(c+6,l),this.renderInstructions_[u++]=s[0],this.renderInstructions_[u++]=s[1],this.hitDetectionEnabled_&&(this.hitRenderInstructions_[c++]=s[0],this.hitRenderInstructions_[c++]=s[1],this.hitRenderInstructions_[c++]=a[0],this.hitRenderInstructions_[c++]=a[1],this.hitRenderInstructions_[c++]=a[2],this.hitRenderInstructions_[c++]=a[3],this.hitRenderInstructions_[c++]=Number(h));for(var p=void 0,f=0;f<this.customAttributes.length;f++)p=this.customAttributes[f].callback(r.feature,r.properties),this.renderInstructions_[u++]=p,this.hitDetectionEnabled_&&(this.hitRenderInstructions_[c++]=p)}var d={type:pg,renderInstructions:this.renderInstructions_.buffer,customAttributesCount:this.customAttributes.length};if(d.projectionTransform=e,this.worker_.postMessage(d,[this.renderInstructions_.buffer]),this.renderInstructions_=null,this.hitDetectionEnabled_){var g={type:pg,renderInstructions:this.hitRenderInstructions_.buffer,customAttributesCount:5+this.customAttributes.length};g.projectionTransform=e,g.hitDetection=!0,this.worker_.postMessage(g,[this.hitRenderInstructions_.buffer]),this.hitRenderInstructions_=null}},e.prototype.forEachFeatureAtCoordinate=function(t,e,r,n,i){if(pt(this.hitDetectionEnabled_,66),this.hitRenderInstructions_){var o=It(e.coordinateToPixelTransform,t.slice()),a=this.hitRenderTarget_.readPixel(o[0]/2,o[1]/2),s=vg([a[0]/255,a[1]/255,a[2]/255,a[3]/255]),l=this.hitRenderInstructions_[s],u=Math.floor(l).toString(),c=this.getLayer().getSource().getFeatureByUid(u);return c?n(c,this.getLayer(),null):void 0}},e.prototype.renderHitDetection=function(t){if(this.hitVerticesBuffer_.getSize()){this.hitRenderTarget_.setSize([Math.floor(t.size[0]/2),Math.floor(t.size[1]/2)]),this.helper.useProgram(this.hitProgram_),this.helper.prepareDrawToRenderTarget(t,this.hitRenderTarget_,!0),this.helper.bindBuffer(this.hitVerticesBuffer_),this.helper.bindBuffer(this.indicesBuffer_),this.helper.enableAttributes(this.hitDetectionAttributes);var e=this.indicesBuffer_.getSize();this.helper.drawElements(0,e)}},e.prototype.disposeInternal=function(){this.worker_.terminate(),this.layer_=null,this.sourceListenKeys_.forEach((function(t){H(t)})),this.sourceListenKeys_=null,t.prototype.disposeInternal.call(this)},e}(_g),Tg={BEGIN_GEOMETRY:0,BEGIN_PATH:1,CIRCLE:2,CLOSE_PATH:3,CUSTOM:4,DRAW_CHARS:5,DRAW_IMAGE:6,END_GEOMETRY:7,FILL:8,MOVE_TO_LINE_TO:9,SET_FILL_STYLE:10,SET_STROKE_STYLE:11,STROKE:12},Cg=[Tg.FILL],Og=[Tg.STROKE],Pg=[Tg.BEGIN_PATH],Rg=[Tg.CLOSE_PATH],Ig=Tg,Lg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Mg=function(t){function e(e,r,n,i){var o=t.call(this)||this;return o.tolerance=e,o.maxExtent=r,o.pixelRatio=i,o.maxLineWidth=0,o.resolution=n,o.beginGeometryInstruction1_=null,o.beginGeometryInstruction2_=null,o.bufferedMaxExtent_=null,o.instructions=[],o.coordinates=[],o.tmpCoordinate_=[],o.hitDetectionInstructions=[],o.state={},o}return Lg(e,t),e.prototype.applyPixelRatio=function(t){var e=this.pixelRatio;return 1==e?t:t.map((function(t){return t*e}))},e.prototype.appendFlatPointCoordinates=function(t,e){for(var r=this.getBufferedMaxExtent(),n=this.tmpCoordinate_,i=this.coordinates,o=i.length,a=0,s=t.length;a<s;a+=e)n[0]=t[a],n[1]=t[a+1],Qt(r,n)&&(i[o++]=n[0],i[o++]=n[1]);return o},e.prototype.appendFlatLineCoordinates=function(t,e,r,n,i,o){var a=this.coordinates,s=a.length,l=this.getBufferedMaxExtent();o&&(e+=n);var u,c,h,p=t[e],f=t[e+1],d=this.tmpCoordinate_,g=!0;for(u=e+n;u<r;u+=n)d[0]=t[u],d[1]=t[u+1],(h=re(l,d))!==c?(g&&(a[s++]=p,a[s++]=f,g=!1),a[s++]=d[0],a[s++]=d[1]):h===Yt?(a[s++]=d[0],a[s++]=d[1],g=!1):g=!0,p=d[0],f=d[1],c=h;return(i&&g||u===e+n)&&(a[s++]=p,a[s++]=f),s},e.prototype.drawCustomCoordinates_=function(t,e,r,n,i){for(var o=0,a=r.length;o<a;++o){var s=r[o],l=this.appendFlatLineCoordinates(t,e,s,n,!1,!1);i.push(l),e=s}return e},e.prototype.drawCustom=function(t,e,r){this.beginGeometry(t,e);var n,i,o,a,s,l=t.getType(),u=t.getStride(),c=this.coordinates.length;if(l==bt.MULTI_POLYGON){n=t.getOrientedFlatCoordinates(),a=[];var h=t.getEndss();s=0;for(var p=0,f=h.length;p<f;++p){var d=[];s=this.drawCustomCoordinates_(n,s,h[p],u,d),a.push(d)}this.instructions.push([Ig.CUSTOM,c,a,t,r,Gn])}else l==bt.POLYGON||l==bt.MULTI_LINE_STRING?(o=[],n=l==bt.POLYGON?t.getOrientedFlatCoordinates():t.getFlatCoordinates(),s=this.drawCustomCoordinates_(n,0,t.getEnds(),u,o),this.instructions.push([Ig.CUSTOM,c,o,t,r,Dn])):l==bt.LINE_STRING||l==bt.CIRCLE?(n=t.getFlatCoordinates(),i=this.appendFlatLineCoordinates(n,0,n.length,u,!1,!1),this.instructions.push([Ig.CUSTOM,c,i,t,r,Nn])):l==bt.MULTI_POINT?(n=t.getFlatCoordinates(),(i=this.appendFlatPointCoordinates(n,u))>c&&this.instructions.push([Ig.CUSTOM,c,i,t,r,Nn])):l==bt.POINT&&(n=t.getFlatCoordinates(),this.coordinates.push(n[0],n[1]),i=this.coordinates.length,this.instructions.push([Ig.CUSTOM,c,i,t,r]));this.endGeometry(e)},e.prototype.beginGeometry=function(t,e){this.beginGeometryInstruction1_=[Ig.BEGIN_GEOMETRY,e,0,t],this.instructions.push(this.beginGeometryInstruction1_),this.beginGeometryInstruction2_=[Ig.BEGIN_GEOMETRY,e,0,t],this.hitDetectionInstructions.push(this.beginGeometryInstruction2_)},e.prototype.finish=function(){return{instructions:this.instructions,hitDetectionInstructions:this.hitDetectionInstructions,coordinates:this.coordinates}},e.prototype.reverseHitDetectionInstructions=function(){var t,e=this.hitDetectionInstructions;e.reverse();var r,n,i=e.length,o=-1;for(t=0;t<i;++t)(n=(r=e[t])[0])==Ig.END_GEOMETRY?o=t:n==Ig.BEGIN_GEOMETRY&&(r[2]=t,m(this.hitDetectionInstructions,o,t),o=-1)},e.prototype.setFillStrokeStyle=function(t,e){var r=this.state;if(t){var n=t.getColor();r.fillStyle=Tu(n||"#000")}else r.fillStyle=void 0;if(e){var i=e.getColor();r.strokeStyle=Tu(i||"#000");var o=e.getLineCap();r.lineCap=void 0!==o?o:"round";var a=e.getLineDash();r.lineDash=a?a.slice():pa;var s=e.getLineDashOffset();r.lineDashOffset=s||0;var l=e.getLineJoin();r.lineJoin=void 0!==l?l:"round";var u=e.getWidth();r.lineWidth=void 0!==u?u:1;var c=e.getMiterLimit();r.miterLimit=void 0!==c?c:10,r.lineWidth>this.maxLineWidth&&(this.maxLineWidth=r.lineWidth,this.bufferedMaxExtent_=null)}else r.strokeStyle=void 0,r.lineCap=void 0,r.lineDash=null,r.lineDashOffset=void 0,r.lineJoin=void 0,r.lineWidth=void 0,r.miterLimit=void 0},e.prototype.createFill=function(t){var e=t.fillStyle,r=[Ig.SET_FILL_STYLE,e];return"string"!=typeof e&&r.push(!0),r},e.prototype.applyStroke=function(t){this.instructions.push(this.createStroke(t))},e.prototype.createStroke=function(t){return[Ig.SET_STROKE_STYLE,t.strokeStyle,t.lineWidth*this.pixelRatio,t.lineCap,t.lineJoin,t.miterLimit,this.applyPixelRatio(t.lineDash),t.lineDashOffset*this.pixelRatio]},e.prototype.updateFillStyle=function(t,e){var r=t.fillStyle;"string"==typeof r&&t.currentFillStyle==r||(void 0!==r&&this.instructions.push(e.call(this,t)),t.currentFillStyle=r)},e.prototype.updateStrokeStyle=function(t,e){var r=t.strokeStyle,n=t.lineCap,i=t.lineDash,o=t.lineDashOffset,a=t.lineJoin,s=t.lineWidth,l=t.miterLimit;(t.currentStrokeStyle!=r||t.currentLineCap!=n||i!=t.currentLineDash&&!b(t.currentLineDash,i)||t.currentLineDashOffset!=o||t.currentLineJoin!=a||t.currentLineWidth!=s||t.currentMiterLimit!=l)&&(void 0!==r&&e.call(this,t),t.currentStrokeStyle=r,t.currentLineCap=n,t.currentLineDash=i,t.currentLineDashOffset=o,t.currentLineJoin=a,t.currentLineWidth=s,t.currentMiterLimit=l)},e.prototype.endGeometry=function(t){this.beginGeometryInstruction1_[2]=this.instructions.length,this.beginGeometryInstruction1_=null,this.beginGeometryInstruction2_[2]=this.hitDetectionInstructions.length,this.beginGeometryInstruction2_=null;var e=[Ig.END_GEOMETRY,t];this.instructions.push(e),this.hitDetectionInstructions.push(e)},e.prototype.getBufferedMaxExtent=function(){if(!this.bufferedMaxExtent_&&(this.bufferedMaxExtent_=$t(this.maxExtent),this.maxLineWidth>0)){var t=this.resolution*(this.maxLineWidth+1)/2;Ht(this.bufferedMaxExtent_,t,this.bufferedMaxExtent_)}return this.bufferedMaxExtent_},e}(ku),Fg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Ag=function(t){function e(e,r,n,i){var o=t.call(this,e,r,n,i)||this;return o.hitDetectionImage_=null,o.image_=null,o.imagePixelRatio_=void 0,o.anchorX_=void 0,o.anchorY_=void 0,o.height_=void 0,o.opacity_=void 0,o.originX_=void 0,o.originY_=void 0,o.rotateWithView_=void 0,o.rotation_=void 0,o.scale_=void 0,o.width_=void 0,o.declutterImageWithText_=void 0,o}return Fg(e,t),e.prototype.drawPoint=function(t,e){if(this.image_){this.beginGeometry(t,e);var r=t.getFlatCoordinates(),n=t.getStride(),i=this.coordinates.length,o=this.appendFlatPointCoordinates(r,n);this.instructions.push([Ig.DRAW_IMAGE,i,o,this.image_,this.anchorX_*this.imagePixelRatio_,this.anchorY_*this.imagePixelRatio_,Math.ceil(this.height_*this.imagePixelRatio_),this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,[this.scale_[0]*this.pixelRatio/this.imagePixelRatio_,this.scale_[1]*this.pixelRatio/this.imagePixelRatio_],Math.ceil(this.width_*this.imagePixelRatio_),this.declutterImageWithText_]),this.hitDetectionInstructions.push([Ig.DRAW_IMAGE,i,o,this.hitDetectionImage_,this.anchorX_,this.anchorY_,this.height_,this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,this.scale_,this.width_,this.declutterImageWithText_]),this.endGeometry(e)}},e.prototype.drawMultiPoint=function(t,e){if(this.image_){this.beginGeometry(t,e);var r=t.getFlatCoordinates(),n=t.getStride(),i=this.coordinates.length,o=this.appendFlatPointCoordinates(r,n);this.instructions.push([Ig.DRAW_IMAGE,i,o,this.image_,this.anchorX_*this.imagePixelRatio_,this.anchorY_*this.imagePixelRatio_,Math.ceil(this.height_*this.imagePixelRatio_),this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,[this.scale_[0]*this.pixelRatio/this.imagePixelRatio_,this.scale_[1]*this.pixelRatio/this.imagePixelRatio_],Math.ceil(this.width_*this.imagePixelRatio_),this.declutterImageWithText_]),this.hitDetectionInstructions.push([Ig.DRAW_IMAGE,i,o,this.hitDetectionImage_,this.anchorX_,this.anchorY_,this.height_,this.opacity_,this.originX_,this.originY_,this.rotateWithView_,this.rotation_,this.scale_,this.width_,this.declutterImageWithText_]),this.endGeometry(e)}},e.prototype.finish=function(){return this.reverseHitDetectionInstructions(),this.anchorX_=void 0,this.anchorY_=void 0,this.hitDetectionImage_=null,this.image_=null,this.imagePixelRatio_=void 0,this.height_=void 0,this.scale_=void 0,this.opacity_=void 0,this.originX_=void 0,this.originY_=void 0,this.rotateWithView_=void 0,this.rotation_=void 0,this.width_=void 0,t.prototype.finish.call(this)},e.prototype.setImageStyle=function(t,e){var r=t.getAnchor(),n=t.getSize(),i=t.getHitDetectionImage(),o=t.getImage(this.pixelRatio),a=t.getOrigin();this.imagePixelRatio_=t.getPixelRatio(this.pixelRatio),this.anchorX_=r[0],this.anchorY_=r[1],this.hitDetectionImage_=i,this.image_=o,this.height_=n[1],this.opacity_=t.getOpacity(),this.originX_=a[0],this.originY_=a[1],this.rotateWithView_=t.getRotateWithView(),this.rotation_=t.getRotation(),this.scale_=t.getScaleArray(),this.width_=n[0],this.declutterImageWithText_=e},e}(Mg),kg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),jg=function(t){function e(e,r,n,i){return t.call(this,e,r,n,i)||this}return kg(e,t),e.prototype.drawFlatCoordinates_=function(t,e,r,n){var i=this.coordinates.length,o=this.appendFlatLineCoordinates(t,e,r,n,!1,!1),a=[Ig.MOVE_TO_LINE_TO,i,o];return this.instructions.push(a),this.hitDetectionInstructions.push(a),r},e.prototype.drawLineString=function(t,e){var r=this.state,n=r.strokeStyle,i=r.lineWidth;if(void 0!==n&&void 0!==i){this.updateStrokeStyle(r,this.applyStroke),this.beginGeometry(t,e),this.hitDetectionInstructions.push([Ig.SET_STROKE_STYLE,r.strokeStyle,r.lineWidth,r.lineCap,r.lineJoin,r.miterLimit,r.lineDash,r.lineDashOffset],Pg);var o=t.getFlatCoordinates(),a=t.getStride();this.drawFlatCoordinates_(o,0,o.length,a),this.hitDetectionInstructions.push(Og),this.endGeometry(e)}},e.prototype.drawMultiLineString=function(t,e){var r=this.state,n=r.strokeStyle,i=r.lineWidth;if(void 0!==n&&void 0!==i){this.updateStrokeStyle(r,this.applyStroke),this.beginGeometry(t,e),this.hitDetectionInstructions.push([Ig.SET_STROKE_STYLE,r.strokeStyle,r.lineWidth,r.lineCap,r.lineJoin,r.miterLimit,r.lineDash,r.lineDashOffset],Pg);for(var o=t.getEnds(),a=t.getFlatCoordinates(),s=t.getStride(),l=0,u=0,c=o.length;u<c;++u)l=this.drawFlatCoordinates_(a,l,o[u],s);this.hitDetectionInstructions.push(Og),this.endGeometry(e)}},e.prototype.finish=function(){var e=this.state;return null!=e.lastStroke&&e.lastStroke!=this.coordinates.length&&this.instructions.push(Og),this.reverseHitDetectionInstructions(),this.state=null,t.prototype.finish.call(this)},e.prototype.applyStroke=function(e){null!=e.lastStroke&&e.lastStroke!=this.coordinates.length&&(this.instructions.push(Og),e.lastStroke=this.coordinates.length),e.lastStroke=0,t.prototype.applyStroke.call(this,e),this.instructions.push(Pg)},e}(Mg),Ng=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Dg=function(t){function e(e,r,n,i){return t.call(this,e,r,n,i)||this}return Ng(e,t),e.prototype.drawFlatCoordinatess_=function(t,e,r,n){var i=this.state,o=void 0!==i.fillStyle,a=void 0!==i.strokeStyle,s=r.length;this.instructions.push(Pg),this.hitDetectionInstructions.push(Pg);for(var l=0;l<s;++l){var u=r[l],c=this.coordinates.length,h=this.appendFlatLineCoordinates(t,e,u,n,!0,!a),p=[Ig.MOVE_TO_LINE_TO,c,h];this.instructions.push(p),this.hitDetectionInstructions.push(p),a&&(this.instructions.push(Rg),this.hitDetectionInstructions.push(Rg)),e=u}return o&&(this.instructions.push(Cg),this.hitDetectionInstructions.push(Cg)),a&&(this.instructions.push(Og),this.hitDetectionInstructions.push(Og)),e},e.prototype.drawCircle=function(t,e){var r=this.state,n=r.fillStyle,i=r.strokeStyle;if(void 0!==n||void 0!==i){this.setFillStrokeStyles_(),this.beginGeometry(t,e),void 0!==r.fillStyle&&this.hitDetectionInstructions.push([Ig.SET_FILL_STYLE,"#000"]),void 0!==r.strokeStyle&&this.hitDetectionInstructions.push([Ig.SET_STROKE_STYLE,r.strokeStyle,r.lineWidth,r.lineCap,r.lineJoin,r.miterLimit,r.lineDash,r.lineDashOffset]);var o=t.getFlatCoordinates(),a=t.getStride(),s=this.coordinates.length;this.appendFlatLineCoordinates(o,0,o.length,a,!1,!1);var l=[Ig.CIRCLE,s];this.instructions.push(Pg,l),this.hitDetectionInstructions.push(Pg,l),void 0!==r.fillStyle&&(this.instructions.push(Cg),this.hitDetectionInstructions.push(Cg)),void 0!==r.strokeStyle&&(this.instructions.push(Og),this.hitDetectionInstructions.push(Og)),this.endGeometry(e)}},e.prototype.drawPolygon=function(t,e){var r=this.state,n=r.fillStyle,i=r.strokeStyle;if(void 0!==n||void 0!==i){this.setFillStrokeStyles_(),this.beginGeometry(t,e),void 0!==r.fillStyle&&this.hitDetectionInstructions.push([Ig.SET_FILL_STYLE,"#000"]),void 0!==r.strokeStyle&&this.hitDetectionInstructions.push([Ig.SET_STROKE_STYLE,r.strokeStyle,r.lineWidth,r.lineCap,r.lineJoin,r.miterLimit,r.lineDash,r.lineDashOffset]);var o=t.getEnds(),a=t.getOrientedFlatCoordinates(),s=t.getStride();this.drawFlatCoordinatess_(a,0,o,s),this.endGeometry(e)}},e.prototype.drawMultiPolygon=function(t,e){var r=this.state,n=r.fillStyle,i=r.strokeStyle;if(void 0!==n||void 0!==i){this.setFillStrokeStyles_(),this.beginGeometry(t,e),void 0!==r.fillStyle&&this.hitDetectionInstructions.push([Ig.SET_FILL_STYLE,"#000"]),void 0!==r.strokeStyle&&this.hitDetectionInstructions.push([Ig.SET_STROKE_STYLE,r.strokeStyle,r.lineWidth,r.lineCap,r.lineJoin,r.miterLimit,r.lineDash,r.lineDashOffset]);for(var o=t.getEndss(),a=t.getOrientedFlatCoordinates(),s=t.getStride(),l=0,u=0,c=o.length;u<c;++u)l=this.drawFlatCoordinatess_(a,l,o[u],s);this.endGeometry(e)}},e.prototype.finish=function(){this.reverseHitDetectionInstructions(),this.state=null;var e=this.tolerance;if(0!==e)for(var r=this.coordinates,n=0,i=r.length;n<i;++n)r[n]=Fn(r[n],e);return t.prototype.finish.call(this)},e.prototype.setFillStrokeStyles_=function(){var t=this.state;void 0!==t.fillStyle&&this.updateFillStyle(t,this.createFill),void 0!==t.strokeStyle&&this.updateStrokeStyle(t,this.applyStroke)},e}(Mg);function Gg(t,e,r,n,i){var o,a,s,l,u,c,h,p,f,d=r,g=r,y=0,m=0,v=r;for(o=r;o<n;o+=i){var _=e[o],b=e[o+1];void 0!==l&&(p=_-l,f=b-u,s=Math.sqrt(p*p+f*f),void 0!==c&&(m+=a,Math.acos((c*p+h*f)/(a*s))>t&&(m>y&&(y=m,d=v,g=o),m=0,v=o-i)),a=s,c=p,h=f),l=_,u=b}return(m+=s)>y?[v,o]:[d,g]}var zg=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Ug={left:0,end:0,center:.5,right:1,start:1,top:0,middle:.5,hanging:.2,alphabetic:.8,ideographic:.8,bottom:1},Bg=function(t){function e(e,r,n,i){var o=t.call(this,e,r,n,i)||this;return o.labels_=null,o.text_="",o.textOffsetX_=0,o.textOffsetY_=0,o.textRotateWithView_=void 0,o.textRotation_=0,o.textFillState_=null,o.fillStates={},o.textStrokeState_=null,o.strokeStates={},o.textState_={},o.textStates={},o.textKey_="",o.fillKey_="",o.strokeKey_="",o.declutterImageWithText_=void 0,o}return zg(e,t),e.prototype.finish=function(){var e=t.prototype.finish.call(this);return e.textStates=this.textStates,e.fillStates=this.fillStates,e.strokeStates=this.strokeStates,e},e.prototype.drawText=function(t,e){var r=this.textFillState_,n=this.textStrokeState_,i=this.textState_;if(""!==this.text_&&i&&(r||n)){var o=this.coordinates,a=o.length,s=t.getType(),l=null,u=t.getStride();if(i.placement!==Ep||s!=bt.LINE_STRING&&s!=bt.MULTI_LINE_STRING&&s!=bt.POLYGON&&s!=bt.MULTI_POLYGON){var c=i.overflow?null:[];switch(s){case bt.POINT:case bt.MULTI_POINT:l=t.getFlatCoordinates();break;case bt.LINE_STRING:l=t.getFlatMidpoint();break;case bt.CIRCLE:l=t.getCenter();break;case bt.MULTI_LINE_STRING:l=t.getFlatMidpoints(),u=2;break;case bt.POLYGON:l=t.getFlatInteriorPoint(),i.overflow||c.push(l[2]/this.resolution),u=3;break;case bt.MULTI_POLYGON:var h=t.getFlatInteriorPoints();l=[];for(x=0,w=h.length;x<w;x+=3)i.overflow||c.push(h[x+2]/this.resolution),l.push(h[x],h[x+1]);if(0===l.length)return;u=2}if((R=this.appendFlatPointCoordinates(l,u))===a)return;this.saveTextStates_(),(i.backgroundFill||i.backgroundStroke)&&(this.setFillStrokeStyle(i.backgroundFill,i.backgroundStroke),i.backgroundFill&&(this.updateFillStyle(this.state,this.createFill),this.hitDetectionInstructions.push(this.createFill(this.state))),i.backgroundStroke&&(this.updateStrokeStyle(this.state,this.applyStroke),this.hitDetectionInstructions.push(this.createStroke(this.state)))),this.beginGeometry(t,e);var p=i.padding;if(p!=fa&&(i.scale[0]<0||i.scale[1]<0)){var f=i.padding[0],d=i.padding[1],g=i.padding[2],y=i.padding[3];i.scale[0]<0&&(d=-d,y=-y),i.scale[1]<0&&(f=-f,g=-g),p=[f,d,g,y]}var m=this.pixelRatio;this.instructions.push([Ig.DRAW_IMAGE,a,R,null,NaN,NaN,NaN,1,0,0,this.textRotateWithView_,this.textRotation_,[1,1],NaN,this.declutterImageWithText_,p==fa?fa:p.map((function(t){return t*m})),!!i.backgroundFill,!!i.backgroundStroke,this.text_,this.textKey_,this.strokeKey_,this.fillKey_,this.textOffsetX_,this.textOffsetY_,c]);var v=1/m;this.hitDetectionInstructions.push([Ig.DRAW_IMAGE,a,R,null,NaN,NaN,NaN,1,0,0,this.textRotateWithView_,this.textRotation_,[v,v],NaN,this.declutterImageWithText_,p,!!i.backgroundFill,!!i.backgroundStroke,this.text_,this.textKey_,this.strokeKey_,this.fillKey_,this.textOffsetX_,this.textOffsetY_,c]),this.endGeometry(e)}else{if(!Re(this.getBufferedMaxExtent(),t.getExtent()))return;var _=void 0;if(l=t.getFlatCoordinates(),s==bt.LINE_STRING)_=[l.length];else if(s==bt.MULTI_LINE_STRING)_=t.getEnds();else if(s==bt.POLYGON)_=t.getEnds().slice(0,1);else if(s==bt.MULTI_POLYGON){var b=t.getEndss();_=[];for(var x=0,w=b.length;x<w;++x)_.push(b[x][0])}this.beginGeometry(t,e);for(var S=i.textAlign,E=0,T=void 0,C=0,O=_.length;C<O;++C){if(null==S){var P=Gg(i.maxAngle,l,E,_[C],u);E=P[0],T=P[1]}else T=_[C];for(var x=E;x<T;x+=u)o.push(l[x],l[x+1]);var R=o.length;E=_[C],this.drawChars_(a,R),a=R}this.endGeometry(e)}}},e.prototype.saveTextStates_=function(){var t=this.textStrokeState_,e=this.textState_,r=this.textFillState_,n=this.strokeKey_;t&&(n in this.strokeStates||(this.strokeStates[n]={strokeStyle:t.strokeStyle,lineCap:t.lineCap,lineDashOffset:t.lineDashOffset,lineWidth:t.lineWidth,lineJoin:t.lineJoin,miterLimit:t.miterLimit,lineDash:t.lineDash}));var i=this.textKey_;i in this.textStates||(this.textStates[i]={font:e.font,textAlign:e.textAlign||"center",textBaseline:e.textBaseline||"middle",scale:e.scale});var o=this.fillKey_;r&&(o in this.fillStates||(this.fillStates[o]={fillStyle:r.fillStyle}))},e.prototype.drawChars_=function(t,e){var r=this.textStrokeState_,n=this.textState_,i=this.strokeKey_,o=this.textKey_,a=this.fillKey_;this.saveTextStates_();var s=this.pixelRatio,l=Ug[n.textBaseline],u=this.textOffsetY_*s,c=this.text_,h=r?r.lineWidth*Math.abs(n.scale[0])/2:0;this.instructions.push([Ig.DRAW_CHARS,t,e,l,n.overflow,a,n.maxAngle,s,u,i,h*s,c,o,1]),this.hitDetectionInstructions.push([Ig.DRAW_CHARS,t,e,l,n.overflow,a,n.maxAngle,1,u,i,h,c,o,1/s])},e.prototype.setTextStyle=function(t,e){var r,n,i;if(t){var a=t.getFill();a?((n=this.textFillState_)||(n={},this.textFillState_=n),n.fillStyle=Tu(a.getColor()||"#000")):(n=null,this.textFillState_=n);var s=t.getStroke();if(s){(i=this.textStrokeState_)||(i={},this.textStrokeState_=i);var l=s.getLineDash(),u=s.getLineDashOffset(),c=s.getWidth(),h=s.getMiterLimit();i.lineCap=s.getLineCap()||"round",i.lineDash=l?l.slice():pa,i.lineDashOffset=void 0===u?0:u,i.lineJoin=s.getLineJoin()||"round",i.lineWidth=void 0===c?1:c,i.miterLimit=void 0===h?10:h,i.strokeStyle=Tu(s.getColor()||"#000")}else i=null,this.textStrokeState_=i;r=this.textState_;var p=t.getFont()||"10px sans-serif";ba(p);var f=t.getScaleArray();r.overflow=t.getOverflow(),r.font=p,r.maxAngle=t.getMaxAngle(),r.placement=t.getPlacement(),r.textAlign=t.getTextAlign(),r.textBaseline=t.getTextBaseline()||"middle",r.backgroundFill=t.getBackgroundFill(),r.backgroundStroke=t.getBackgroundStroke(),r.padding=t.getPadding()||fa,r.scale=void 0===f?[1,1]:f;var d=t.getOffsetX(),g=t.getOffsetY(),y=t.getRotateWithView(),m=t.getRotation();this.text_=t.getText()||"",this.textOffsetX_=void 0===d?0:d,this.textOffsetY_=void 0===g?0:g,this.textRotateWithView_=void 0!==y&&y,this.textRotation_=void 0===m?0:m,this.strokeKey_=i?("string"==typeof i.strokeStyle?i.strokeStyle:o(i.strokeStyle))+i.lineCap+i.lineDashOffset+"|"+i.lineWidth+i.lineJoin+i.miterLimit+"["+i.lineDash.join()+"]":"",this.textKey_=r.font+r.scale+(r.textAlign||"?")+(r.textBaseline||"?"),this.fillKey_=n?"string"==typeof n.fillStyle?n.fillStyle:"|"+o(n.fillStyle):""}else this.text_="";this.declutterImageWithText_=e},e}(Mg),Vg={Circle:Dg,Default:Mg,Image:Ag,LineString:jg,Polygon:Dg,Text:Bg},Yg=function(){function t(t,e,r,n){this.tolerance_=t,this.maxExtent_=e,this.pixelRatio_=n,this.resolution_=r,this.buildersByZIndex_={}}return t.prototype.finish=function(){var t={};for(var e in this.buildersByZIndex_){t[e]=t[e]||{};var r=this.buildersByZIndex_[e];for(var n in r){var i=r[n].finish();t[e][n]=i}}return t},t.prototype.getBuilder=function(t,e){var r=void 0!==t?t.toString():"0",n=this.buildersByZIndex_[r];void 0===n&&(n={},this.buildersByZIndex_[r]=n);var i=n[e];void 0===i&&(i=new(0,Vg[e])(this.tolerance_,this.maxExtent_,this.resolution_,this.pixelRatio_),n[e]=i);return i},t}();function Wg(t,e,r,n,i,o,a,s,l,u,c,h){var p=t[e],f=t[e+1],d=0,g=0,y=0,m=0;function v(){d=p,g=f,p=t[e+=n],f=t[e+1],m+=y,y=Math.sqrt((p-d)*(p-d)+(f-g)*(f-g))}do{v()}while(e<r-n&&m+y<o);for(var _=(o-m)/y,b=qe(d,p,_),x=qe(g,f,_),w=e-n,S=m,E=o+s*l(u,i,c);e<r-n&&m+y<E;)v();var T,C=qe(d,p,_=(E-m)/y),O=qe(g,f,_);if(h){var P=[b,x,C,O];un(P,0,4,2,h,P,P),T=P[0]>P[2]}else T=b>C;var R,I=Math.PI,L=[],M=w+n===e;if(y=0,m=S,p=t[e=w],f=t[e+1],M){v();var F=Math.atan2(f-g,p-d);T&&(F+=F>0?-I:I);var A=(C+b)/2,k=(O+x)/2;return L[0]=[A,k,(E-o)/2,F,i],L}for(var j=0,N=i.length;j<N;){v();var D=Math.atan2(f-g,p-d);if(T&&(D+=D>0?-I:I),void 0!==R){var G=D-R;if(G+=G>I?-2*I:G<-I?2*I:0,Math.abs(G)>a)return null}R=D;for(var z=j,U=0;j<N;++j){var B=s*l(u,i[T?N-j-1:j],c);if(e+n<r&&m+y<o+U+B/2)break;U+=B}if(j!==z){var V=T?i.substring(N-z,N-j):i.substring(z,j);A=qe(d,p,_=(o+U/2-m)/y),k=qe(g,f,_);L.push([A,k,U/2,D,V]),o+=U}}return L}function qg(t,e,r,n){for(var i=t[e],o=t[e+1],a=0,s=e+n;s<r;s+=n){var l=t[s],u=t[s+1];a+=Math.sqrt((l-i)*(l-i)+(u-o)*(u-o)),i=l,o=u}return a}var Xg=[1/0,1/0,-1/0,-1/0],Zg=[],Kg=[],Hg=[],$g=[];function Jg(t){return t[3].declutterBox}var Qg=new RegExp("["+String.fromCharCode(1425)+"-"+String.fromCharCode(2303)+String.fromCharCode(64285)+"-"+String.fromCharCode(65023)+String.fromCharCode(65136)+"-"+String.fromCharCode(65276)+String.fromCharCode(67584)+"-"+String.fromCharCode(69631)+String.fromCharCode(124928)+"-"+String.fromCharCode(126975)+"]");function ty(t,e){return"start"!==e&&"end"!==e||Qg.test(t)||(e="start"===e?"left":"right"),Ug[e]}var ey=function(){function t(t,e,r,n,i){this.overlaps=r,this.pixelRatio=e,this.resolution=t,this.alignFill_,this.instructions=n.instructions,this.coordinates=n.coordinates,this.coordinateCache_={},this.renderBuffer_=i,this.renderedTransform_=[1,0,0,1,0,0],this.hitDetectionInstructions=n.hitDetectionInstructions,this.pixelCoordinates_=null,this.viewRotation_=0,this.fillStates=n.fillStates||{},this.strokeStates=n.strokeStates||{},this.textStates=n.textStates||{},this.widths_={},this.labels_={}}return t.prototype.createLabel=function(t,e,r,n){var i=t+e+r+n;if(this.labels_[i])return this.labels_[i];var o=n?this.strokeStates[n]:null,a=r?this.fillStates[r]:null,s=this.textStates[e],l=this.pixelRatio,u=[s.scale[0]*l,s.scale[1]*l],c=ty(t,s.textAlign||"center"),h=n&&o.lineWidth?o.lineWidth:0,p=t.split("\n"),f=p.length,d=[],g=Ta(s.font,p,d),y=xa(s.font),m=g+h,v=[],_=(m+2)*u[0],b=(y*f+h)*u[1],x={width:_<0?Math.floor(_):Math.ceil(_),height:b<0?Math.floor(b):Math.ceil(b),contextInstructions:v};(1==u[0]&&1==u[1]||v.push("scale",u),v.push("font",s.font),n)&&(v.push("strokeStyle",o.strokeStyle),v.push("lineWidth",h),v.push("lineCap",o.lineCap),v.push("lineJoin",o.lineJoin),v.push("miterLimit",o.miterLimit),(Yi?OffscreenCanvasRenderingContext2D:CanvasRenderingContext2D).prototype.setLineDash&&(v.push("setLineDash",[o.lineDash]),v.push("lineDashOffset",o.lineDashOffset)));r&&v.push("fillStyle",a.fillStyle),v.push("textBaseline","middle"),v.push("textAlign","center");var w,S=.5-c,E=c*m+S*h;if(n)for(w=0;w<f;++w)v.push("strokeText",[p[w],E+S*d[w],.5*(h+y)+w*y]);if(r)for(w=0;w<f;++w)v.push("fillText",[p[w],E+S*d[w],.5*(h+y)+w*y]);return this.labels_[i]=x,x},t.prototype.replayTextBackground_=function(t,e,r,n,i,o,a){t.beginPath(),t.moveTo.apply(t,e),t.lineTo.apply(t,r),t.lineTo.apply(t,n),t.lineTo.apply(t,i),t.lineTo.apply(t,e),o&&(this.alignFill_=o[2],this.fill_(t)),a&&(this.setStrokeStyle_(t,a),t.stroke())},t.prototype.calculateImageOrLabelDimensions_=function(t,e,r,n,i,o,a,s,l,u,c,h,p,f,d,g){var y,m=r-(a*=h[0]),v=n-(s*=h[1]),_=i+l>t?t-l:i,b=o+u>e?e-u:o,x=f[3]+_*h[0]+f[1],w=f[0]+b*h[1]+f[2],S=m-f[3],E=v-f[0];return(d||0!==c)&&(Zg[0]=S,$g[0]=S,Zg[1]=E,Kg[1]=E,Kg[0]=S+x,Hg[0]=Kg[0],Hg[1]=E+w,$g[1]=Hg[1]),0!==c?(It(y=kt([1,0,0,1,0,0],r,n,1,1,c,-r,-n),Zg),It(y,Kg),It(y,Hg),It(y,$g),ie(Math.min(Zg[0],Kg[0],Hg[0],$g[0]),Math.min(Zg[1],Kg[1],Hg[1],$g[1]),Math.max(Zg[0],Kg[0],Hg[0],$g[0]),Math.max(Zg[1],Kg[1],Hg[1],$g[1]),Xg)):ie(Math.min(S,S+x),Math.min(E,E+w),Math.max(S,S+x),Math.max(E,E+w),Xg),p&&(m=Math.round(m),v=Math.round(v)),{drawImageX:m,drawImageY:v,drawImageW:_,drawImageH:b,originX:l,originY:u,declutterBox:{minX:Xg[0],minY:Xg[1],maxX:Xg[2],maxY:Xg[3],value:g},canvasTransform:y,scale:h}},t.prototype.replayImageOrLabel_=function(t,e,r,n,i,o,a){var s=!(!o&&!a),l=n.declutterBox,u=t.canvas,c=a?a[2]*n.scale[0]/2:0;return l.minX-c<=u.width/e&&l.maxX+c>=0&&l.minY-c<=u.height/e&&l.maxY+c>=0&&(s&&this.replayTextBackground_(t,Zg,Kg,Hg,$g,o,a),Oa(t,n.canvasTransform,i,r,n.originX,n.originY,n.drawImageW,n.drawImageH,n.drawImageX,n.drawImageY,n.scale)),!0},t.prototype.fill_=function(t){if(this.alignFill_){var e=It(this.renderedTransform_,[0,0]),r=512*this.pixelRatio;t.save(),t.translate(e[0]%r,e[1]%r),t.rotate(this.viewRotation_)}t.fill(),this.alignFill_&&t.restore()},t.prototype.setStrokeStyle_=function(t,e){t.strokeStyle=e[1],t.lineWidth=e[2],t.lineCap=e[3],t.lineJoin=e[4],t.miterLimit=e[5],t.setLineDash&&(t.lineDashOffset=e[7],t.setLineDash(e[6]))},t.prototype.drawLabelWithPointPlacement_=function(t,e,r,n){var i=this.textStates[e],o=this.createLabel(t,e,n,r),a=this.strokeStates[r],s=this.pixelRatio,l=ty(t,i.textAlign||"center"),u=Ug[i.textBaseline||"middle"],c=a&&a.lineWidth?a.lineWidth:0;return{label:o,anchorX:l*(o.width/s-2*i.scale[0])+2*(.5-l)*c,anchorY:u*o.height/s+2*(.5-u)*c}},t.prototype.execute_=function(t,e,r,n,i,o,a,s){var l;this.pixelCoordinates_&&b(r,this.renderedTransform_)?l=this.pixelCoordinates_:(this.pixelCoordinates_||(this.pixelCoordinates_=[]),l=ln(this.coordinates,0,this.coordinates.length,2,r,this.pixelCoordinates_),Rt(this.renderedTransform_,r));for(var u,c,h,p,f,d,g,y,m,v,_,x,w,S,E,T,C=0,O=n.length,P=0,R=0,I=0,L=null,M=null,F=this.coordinateCache_,A=this.viewRotation_,k=Math.round(1e12*Math.atan2(-r[1],r[0]))/1e12,j={context:t,pixelRatio:this.pixelRatio,resolution:this.resolution,rotation:A},N=this.instructions!=n||this.overlaps?0:200;C<O;){var D=n[C];switch(D[0]){case Ig.BEGIN_GEOMETRY:w=D[1],T=D[3],w.getGeometry()?void 0===a||Re(a,T.getExtent())?++C:C=D[2]+1:C=D[2];break;case Ig.BEGIN_PATH:R>N&&(this.fill_(t),R=0),I>N&&(t.stroke(),I=0),R||I||(t.beginPath(),p=NaN,f=NaN),++C;break;case Ig.CIRCLE:var G=l[P=D[1]],z=l[P+1],U=l[P+2]-G,B=l[P+3]-z,V=Math.sqrt(U*U+B*B);t.moveTo(G+V,z),t.arc(G,z,V,0,2*Math.PI,!0),++C;break;case Ig.CLOSE_PATH:t.closePath(),++C;break;case Ig.CUSTOM:P=D[1],u=D[2];var Y=D[3],W=D[4],q=6==D.length?D[5]:void 0;j.geometry=Y,j.feature=w,C in F||(F[C]=[]);var X=F[C];q?q(l,P,u,2,X):(X[0]=l[P],X[1]=l[P+1],X.length=2),W(X,j),++C;break;case Ig.DRAW_IMAGE:P=D[1],u=D[2],y=D[3],c=D[4],h=D[5];var Z=D[6],K=D[7],H=D[8],$=D[9],J=D[10],Q=D[11],tt=D[12],et=D[13],rt=D[14];if(!y&&D.length>=19){m=D[18],v=D[19],_=D[20],x=D[21];var nt=this.drawLabelWithPointPlacement_(m,v,_,x);y=nt.label,D[3]=y;var it=D[22];c=(nt.anchorX-it)*this.pixelRatio,D[4]=c;var ot=D[23];h=(nt.anchorY-ot)*this.pixelRatio,D[5]=h,Z=y.height,D[6]=Z,et=y.width,D[13]=et}var at=void 0;D.length>24&&(at=D[24]);var st=void 0,lt=void 0,ut=void 0;D.length>16?(st=D[15],lt=D[16],ut=D[17]):(st=fa,lt=!1,ut=!1),J&&k?Q+=A:J||k||(Q-=A);for(var ct=0;P<u;P+=2)if(!(at&&at[ct++]<et/this.pixelRatio)){var ht=[t,e,y,Dt=this.calculateImageOrLabelDimensions_(y.width,y.height,l[P],l[P+1],et,Z,c,h,H,$,Q,tt,i,st,lt||ut,w),K,lt?L:null,ut?M:null],pt=void 0,ft=void 0;if(s&&rt){if(!rt[P]){rt[P]=ht;continue}if(pt=rt[P],delete rt[P],ft=Jg(pt),s.collides(ft))continue}s&&s.collides(Dt.declutterBox)||(pt&&(s&&s.insert(ft),this.replayImageOrLabel_.apply(this,pt)),s&&s.insert(Dt.declutterBox),this.replayImageOrLabel_.apply(this,ht))}++C;break;case Ig.DRAW_CHARS:var dt=D[1],gt=D[2],yt=D[3],mt=D[4];x=D[5];var vt=D[6],_t=D[7],bt=D[8];_=D[9];var xt=D[10];m=D[11],v=D[12];var wt=[D[13],D[13]],St=this.textStates[v],Et=St.font,Tt=[St.scale[0]*_t,St.scale[1]*_t],Ct=void 0;Et in this.widths_?Ct=this.widths_[Et]:(Ct={},this.widths_[Et]=Ct);var Ot=qg(l,dt,gt,2),Pt=Math.abs(Tt[0])*Ea(Et,m,Ct);if(mt||Pt<=Ot){var It=this.textStates[v].textAlign,Lt=Wg(l,dt,gt,2,m,(Ot-Pt)*Ug[It],vt,Math.abs(Tt[0]),Ea,Et,Ct,k?0:this.viewRotation_);t:if(Lt){var Mt=[],Ft=void 0,At=void 0,kt=void 0,jt=void 0,Nt=void 0;if(_)for(Ft=0,At=Lt.length;Ft<At;++Ft){kt=(Nt=Lt[Ft])[4],jt=this.createLabel(kt,v,"",_),c=Nt[2]+(Tt[0]<0?-xt:xt),h=yt*jt.height+2*(.5-yt)*xt*Tt[1]/Tt[0]-bt;var Dt=this.calculateImageOrLabelDimensions_(jt.width,jt.height,Nt[0],Nt[1],jt.width,jt.height,c,h,0,0,Nt[3],wt,!1,fa,!1,w);if(s&&s.collides(Dt.declutterBox))break t;Mt.push([t,e,jt,Dt,1,null,null])}if(x)for(Ft=0,At=Lt.length;Ft<At;++Ft){kt=(Nt=Lt[Ft])[4],jt=this.createLabel(kt,v,x,""),c=Nt[2],h=yt*jt.height-bt;Dt=this.calculateImageOrLabelDimensions_(jt.width,jt.height,Nt[0],Nt[1],jt.width,jt.height,c,h,0,0,Nt[3],wt,!1,fa,!1,w);if(s&&s.collides(Dt.declutterBox))break t;Mt.push([t,e,jt,Dt,1,null,null])}s&&s.load(Mt.map(Jg));for(var Gt=0,zt=Mt.length;Gt<zt;++Gt)this.replayImageOrLabel_.apply(this,Mt[Gt])}}++C;break;case Ig.END_GEOMETRY:if(void 0!==o){var Ut=o(w=D[1],T);if(Ut)return Ut}++C;break;case Ig.FILL:N?R++:this.fill_(t),++C;break;case Ig.MOVE_TO_LINE_TO:for(P=D[1],u=D[2],S=l[P],g=(E=l[P+1])+.5|0,(d=S+.5|0)===p&&g===f||(t.moveTo(S,E),p=d,f=g),P+=2;P<u;P+=2)d=(S=l[P])+.5|0,g=(E=l[P+1])+.5|0,P!=u-2&&d===p&&g===f||(t.lineTo(S,E),p=d,f=g);++C;break;case Ig.SET_FILL_STYLE:L=D,this.alignFill_=D[2],R&&(this.fill_(t),R=0,I&&(t.stroke(),I=0)),t.fillStyle=D[1],++C;break;case Ig.SET_STROKE_STYLE:M=D,I&&(t.stroke(),I=0),this.setStrokeStyle_(t,D),++C;break;case Ig.STROKE:N?I++:t.stroke(),++C;break;default:++C}}R&&this.fill_(t),I&&t.stroke()},t.prototype.execute=function(t,e,r,n,i,o){this.viewRotation_=n,this.execute_(t,e,r,this.instructions,i,void 0,void 0,o)},t.prototype.executeHitDetection=function(t,e,r,n,i){return this.viewRotation_=r,this.execute_(t,1,e,this.hitDetectionInstructions,!0,n,i)},t}(),ry=[Bu,Du,Uu,zu,Vu,Gu],ny=function(){function t(t,e,r,n,i,o){this.maxExtent_=t,this.overlaps_=n,this.pixelRatio_=r,this.resolution_=e,this.renderBuffer_=o,this.executorsByZIndex_={},this.hitDetectionContext_=null,this.hitDetectionTransform_=[1,0,0,1,0,0],this.createExecutors_(i)}return t.prototype.clip=function(t,e){var r=this.getClipCoords(e);t.beginPath(),t.moveTo(r[0],r[1]),t.lineTo(r[2],r[3]),t.lineTo(r[4],r[5]),t.lineTo(r[6],r[7]),t.clip()},t.prototype.createExecutors_=function(t){for(var e in t){var r=this.executorsByZIndex_[e];void 0===r&&(r={},this.executorsByZIndex_[e]=r);var n=t[e],i=[this.renderBuffer_||0,this.renderBuffer_||0];for(var o in n){var a=n[o];r[o]=new ey(this.resolution_,this.pixelRatio_,this.overlaps_,a,i)}}},t.prototype.hasExecutors=function(t){for(var e in this.executorsByZIndex_)for(var r=this.executorsByZIndex_[e],n=0,i=t.length;n<i;++n)if(t[n]in r)return!0;return!1},t.prototype.forEachFeatureAtCoordinate=function(t,e,r,n,i,o){var a=2*(n=Math.round(n))+1,s=kt(this.hitDetectionTransform_,n+.5,n+.5,1/e,-1/e,-r,-t[0],-t[1]),l=!this.hitDetectionContext_;l&&(this.hitDetectionContext_=uo(a,a));var u,c=this.hitDetectionContext_;c.canvas.width!==a||c.canvas.height!==a?(c.canvas.width=a,c.canvas.height=a):l||c.clearRect(0,0,a,a),void 0!==this.renderBuffer_&&(pe(u=[1/0,1/0,-1/0,-1/0],t),Ht(u,e*(this.renderBuffer_+n),u));var h,p=oy(n);function f(t,e){for(var r=c.getImageData(0,0,a,a).data,s=0,l=p.length;s<l;s++)if(r[p[s]]>0){if(!o||h!==zu&&h!==Vu||-1!==o.indexOf(t)){var u=(p[s]-3)/4,f=n-u%a,d=n-(u/a|0),g=i(t,e,f*f+d*d);if(g)return g}c.clearRect(0,0,a,a);break}}var g,y,m,v,_,b=Object.keys(this.executorsByZIndex_).map(Number);for(b.sort(d),g=b.length-1;g>=0;--g){var x=b[g].toString();for(m=this.executorsByZIndex_[x],y=ry.length-1;y>=0;--y)if(void 0!==(v=m[h=ry[y]])&&(_=v.executeHitDetection(c,s,r,f,u)))return _}},t.prototype.getClipCoords=function(t){var e=this.maxExtent_;if(!e)return null;var r=e[0],n=e[1],i=e[2],o=e[3],a=[r,n,r,o,i,o,i,n];return ln(a,0,8,2,t,a),a},t.prototype.isEmpty=function(){return I(this.executorsByZIndex_)},t.prototype.execute=function(t,e,r,n,i,o,a){var s=Object.keys(this.executorsByZIndex_).map(Number);s.sort(d),this.maxExtent_&&(t.save(),this.clip(t,r));var l,u,c,h,p,f,g=o||ry;for(a&&s.reverse(),l=0,u=s.length;l<u;++l){var y=s[l].toString();for(p=this.executorsByZIndex_[y],c=0,h=g.length;c<h;++c){void 0!==(f=p[g[c]])&&f.execute(t,e,r,n,i,a)}}this.maxExtent_&&t.restore()},t}(),iy={};function oy(t){if(void 0!==iy[t])return iy[t];for(var e=2*t+1,r=t*t,n=new Array(r+1),i=0;i<=t;++i)for(var o=0;o<=t;++o){var a=i*i+o*o;if(a>r)break;var s=n[a];s||(s=[],n[a]=s),s.push(4*((t+i)*e+(t+o))+3),i>0&&s.push(4*((t-i)*e+(t+o))+3),o>0&&(s.push(4*((t+i)*e+(t-o))+3),i>0&&s.push(4*((t-i)*e+(t-o))+3))}for(var l=[],u=(i=0,n.length);i<u;++i)n[i]&&l.push.apply(l,n[i]);return iy[t]=l,l}var ay=ny;function sy(t,e,r,n,i,o,a){var s=uo(t[0]/2,t[1]/2);s.imageSmoothingEnabled=!1;for(var l=s.canvas,u=new Nu(s,.5,i,null,a),c=r.length,h=Math.floor(16777215/c),p={},f=1;f<=c;++f){var g=r[f-1],y=g.getStyleFunction()||n;if(n){var m=y(g,o);if(m){Array.isArray(m)||(m=[m]);for(var v="#"+("000000"+(f*h).toString(16)).slice(-6),_=0,b=m.length;_<b;++_){var x=m[_],w=x.clone(),S=w.getFill();S&&S.setColor(v);var E=w.getStroke();E&&E.setColor(v),w.setText(void 0);var T=x.getImage();if(T){var C=T.getImageSize();if(!C)continue;var O=document.createElement("canvas");O.width=C[0],O.height=C[1];var P=O.getContext("2d",{alpha:!1});P.fillStyle=v;var R=P.canvas;P.fillRect(0,0,R.width,R.height),uo(C?C[0]:R.width,C?C[1]:R.height).drawImage(R,0,0),w.setImage(new dp({img:R,imgSize:C,anchor:T.getAnchor(),anchorXUnits:np,anchorYUnits:np,offset:T.getOrigin(),size:T.getSize(),opacity:T.getOpacity(),scale:T.getScale(),rotation:T.getRotation(),rotateWithView:T.getRotateWithView()}))}var I=Number(w.getZIndex());(A=p[I])||(A={},p[I]=A,A[bt.POLYGON]=[],A[bt.CIRCLE]=[],A[bt.LINE_STRING]=[],A[bt.POINT]=[]);var L=w.getGeometryFunction()(g);L&&Re(i,L.getExtent())&&A[L.getType().replace("Multi","")].push(L,w)}}}}for(var M=Object.keys(p).map(Number).sort(d),F=(f=0,M.length);f<F;++f){var A=p[M[f]];for(var k in A){var j=A[k];for(_=0,b=j.length;_<b;_+=2){u.setStyle(j[_+1]);for(var N=0,D=e.length;N<D;++N)u.setTransform(e[N]),u.drawGeometry(j[_])}}}return s.getImageData(0,0,l.width,l.height)}function ly(t,e,r){var n=[];if(r){var i=4*(Math.round(t[0]/2)+Math.round(t[1]/2)*r.width),o=r.data[i],a=r.data[i+1],s=r.data[i+2]+256*(a+256*o),l=Math.floor(16777215/e.length);s&&s%l==0&&n.push(e[s/l-1])}return n}var uy=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),cy=function(t){function e(e){var r=t.call(this,e)||this;return r.boundHandleStyleImageChange_=r.handleStyleImageChange_.bind(r),r.animatingOrInteracting_,r.dirty_=!1,r.hitDetectionImageData_=null,r.renderedFeatures_=null,r.renderedRevision_=-1,r.renderedResolution_=NaN,r.renderedExtent_=[1/0,1/0,-1/0,-1/0],r.renderedRotation_,r.renderedCenter_=null,r.renderedProjection_=null,r.renderedRenderOrder_=null,r.replayGroup_=null,r.replayGroupChanged=!0,r.declutterExecutorGroup=null,r.clipping=!0,r}return uy(e,t),e.prototype.useContainer=function(e,r,n){n<1&&(e=null),t.prototype.useContainer.call(this,e,r,n)},e.prototype.renderWorlds=function(t,e,r){var n=e.extent,i=e.viewState,o=i.center,a=i.resolution,s=i.projection,l=i.rotation,u=s.getExtent(),c=this.getLayer().getSource(),h=e.pixelRatio,p=e.viewHints,f=!(p[ns]||p[is]),d=this.context,g=Math.round(e.size[0]*h),y=Math.round(e.size[1]*h),m=c.getWrapX()&&s.canWrapX(),v=m?Pe(u):null,_=m?Math.ceil((n[2]-u[2])/v)+1:1,b=m?Math.floor((n[0]-u[0])/v):0;do{var x=this.getRenderTransform(o,a,l,h,g,y,b*v);t.execute(d,1,x,l,f,void 0,r)}while(++b<_)},e.prototype.renderDeclutter=function(t){this.declutterExecutorGroup&&this.renderWorlds(this.declutterExecutorGroup,t,t.declutterTree)},e.prototype.renderFrame=function(t,e){var r=t.pixelRatio,n=t.layerStatesArray[t.layerIndex];Ft(this.pixelTransform,1/r,1/r),jt(this.inversePixelTransform,this.pixelTransform);var i=Dt(this.pixelTransform);this.useContainer(e,i,n.opacity);var o=this.context,a=o.canvas,s=this.replayGroup_,l=this.declutterExecutorGroup;if((!s||s.isEmpty())&&(!l||l.isEmpty()))return!this.containerReused&&a.width>0&&(a.width=0),this.container;var u=Math.round(t.size[0]*r),c=Math.round(t.size[1]*r);a.width!=u||a.height!=c?(a.width=u,a.height=c,a.style.transform!==i&&(a.style.transform=i)):this.containerReused||o.clearRect(0,0,u,c),this.preRender(o,t);var h=t.viewState,p=h.projection,f=!1;if(n.extent&&this.clipping){var d=on(n.extent,p);(f=!te(d,t.extent)&&Re(d,t.extent))&&this.clipUnrotated(o,t,d)}this.renderWorlds(s,t),f&&o.restore(),this.postRender(o,t);var g=n.opacity,y=this.container;return g!==parseFloat(y.style.opacity)&&(y.style.opacity=1===g?"":String(g)),this.renderedRotation_!==h.rotation&&(this.renderedRotation_=h.rotation,this.hitDetectionImageData_=null),this.container},e.prototype.getFeatures=function(t){return new Promise(function(e){if(!this.hitDetectionImageData_&&!this.animatingOrInteracting_){var r=[this.context.canvas.width,this.context.canvas.height];It(this.pixelTransform,r);var n=this.renderedCenter_,i=this.renderedResolution_,o=this.renderedRotation_,a=this.renderedProjection_,s=this.renderedExtent_,l=this.getLayer(),u=[],c=r[0]/2,h=r[1]/2;u.push(this.getRenderTransform(n,i,o,.5,c,h,0).slice());var p=l.getSource(),f=a.getExtent();if(p.getWrapX()&&a.canWrapX()&&!te(f,s)){for(var d=s[0],g=Pe(f),y=0,m=void 0;d<f[0];)m=g*--y,u.push(this.getRenderTransform(n,i,o,.5,c,h,m).slice()),d+=g;for(y=0,d=s[2];d>f[2];)m=g*++y,u.push(this.getRenderTransform(n,i,o,.5,c,h,m).slice()),d-=g}this.hitDetectionImageData_=sy(r,u,this.renderedFeatures_,l.getStyleFunction(),s,i,o)}e(ly(t,this.renderedFeatures_,this.hitDetectionImageData_))}.bind(this))},e.prototype.forEachFeatureAtCoordinate=function(t,e,r,n,i){var a=this;if(this.replayGroup_){var s,l=e.viewState.resolution,u=e.viewState.rotation,c=this.getLayer(),h={},p=function(t,e,r){var a=o(t),s=h[a];if(s){if(!0!==s&&r<s.distanceSq){if(0===r)return h[a]=!0,i.splice(i.lastIndexOf(s),1),n(t,c,e);s.geometry=e,s.distanceSq=r}}else{if(0===r)return h[a]=!0,n(t,c,e);i.push(h[a]={feature:t,layer:c,geometry:e,distanceSq:r,callback:n})}},f=[this.replayGroup_];return this.declutterExecutorGroup&&f.push(this.declutterExecutorGroup),f.some((function(n){return s=n.forEachFeatureAtCoordinate(t,l,u,r,p,n===a.declutterExecutorGroup?e.declutterTree.all().map((function(t){return t.value})):null)})),s}},e.prototype.handleFontsChanged=function(){var t=this.getLayer();t.getVisible()&&this.replayGroup_&&t.changed()},e.prototype.handleStyleImageChange_=function(t){this.renderIfReadyAndVisible()},e.prototype.prepareFrame=function(t){var e=this.getLayer(),r=e.getSource();if(!r)return!1;var n=t.viewHints[ns],i=t.viewHints[is],o=e.getUpdateWhileAnimating(),a=e.getUpdateWhileInteracting();if(!this.dirty_&&!o&&n||!a&&i)return this.animatingOrInteracting_=!0,!0;this.animatingOrInteracting_=!1;var s=t.extent,l=t.viewState,u=l.projection,c=l.resolution,h=t.pixelRatio,p=e.getRevision(),f=e.getRenderBuffer(),d=e.getRenderOrder();void 0===d&&(d=Wu);var g=l.center.slice(),y=Ht(s,f*c),m=[y.slice()],v=u.getExtent();if(r.getWrapX()&&u.canWrapX()&&!te(v,t.extent)){var _=Pe(v),b=Math.max(Pe(y)/2,_);y[0]=v[0]-b,y[2]=v[2]+b,Fr(g,u);var x=ke(m[0],u);x[0]<v[0]&&x[2]<v[2]?m.push([x[0]+_,x[1],x[2]+_,x[3]]):x[0]>v[0]&&x[2]>v[2]&&m.push([x[0]-_,x[1],x[2]-_,x[3]])}if(!this.dirty_&&this.renderedResolution_==c&&this.renderedRevision_==p&&this.renderedRenderOrder_==d&&te(this.renderedExtent_,y))return this.replayGroupChanged=!1,!0;this.replayGroup_=null,this.dirty_=!1;var w,S=new Yg(Xu(c,h),y,c,h);this.getLayer().getDeclutter()&&(w=new Yg(Xu(c,h),y,c,h));var E,T=tn();if(T){for(var C=0,O=m.length;C<O;++C)r.loadFeatures(nn(m[C],u),c,T);E=Zr(T,u)}else for(C=0,O=m.length;C<O;++C)r.loadFeatures(m[C],c,u);var P=qu(c,h),R=function(t){var r,n=t.getStyleFunction()||e.getStyleFunction();if(n&&(r=n(t,c)),r){var i=this.renderFeature(t,P,r,S,E,w);this.dirty_=this.dirty_||i}}.bind(this),I=nn(y,u),L=r.getFeaturesInExtent(I);d&&L.sort(d);for(C=0,O=L.length;C<O;++C)R(L[C]);this.renderedFeatures_=L;var M=S.finish(),F=new ay(y,c,h,r.getOverlaps(),M,e.getRenderBuffer());return w&&(this.declutterExecutorGroup=new ay(y,c,h,r.getOverlaps(),w.finish(),e.getRenderBuffer())),this.renderedResolution_=c,this.renderedRevision_=p,this.renderedRenderOrder_=d,this.renderedExtent_=y,this.renderedCenter_=g,this.renderedProjection_=u,this.replayGroup_=F,this.hitDetectionImageData_=null,this.replayGroupChanged=!0,!0},e.prototype.renderFeature=function(t,e,r,n,i,o){if(!r)return!1;var a=!1;if(Array.isArray(r))for(var s=0,l=r.length;s<l;++s)a=Zu(n,t,r[s],e,this.boundHandleStyleImageChange_,i,o)||a;else a=Zu(n,t,r,e,this.boundHandleStyleImageChange_,i,o);return a},e}(cd),hy=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),py=function(t){function e(e){var r=t.call(this,e)||this;return r.vectorRenderer_=new cy(e),r.layerImageRatio_=e.getImageRatio(),r.coordinateToVectorPixelTransform_=[1,0,0,1,0,0],r.renderedPixelToCoordinateTransform_=null,r}return hy(e,t),e.prototype.disposeInternal=function(){this.vectorRenderer_.dispose(),t.prototype.disposeInternal.call(this)},e.prototype.getFeatures=function(t){if(this.vectorRenderer_){var e=It(this.coordinateToVectorPixelTransform_,It(this.renderedPixelToCoordinateTransform_,t.slice()));return this.vectorRenderer_.getFeatures(e)}return new Promise((function(t,e){t([])}))},e.prototype.handleFontsChanged=function(){this.vectorRenderer_.handleFontsChanged()},e.prototype.prepareFrame=function(t){var e=t.pixelRatio,r=t.viewState,n=r.resolution,i=t.viewHints,o=this.vectorRenderer_,a=t.extent;1!==this.layerImageRatio_&&Me(a=a.slice(0),this.layerImageRatio_);var s=Pe(a)/n,l=Ee(a)/n;if(!i[ns]&&!i[is]&&!Ie(a)){o.useContainer(null,null,1);var u=o.context,c=O({},t,{declutterTree:new Pp.a(9),extent:a,size:[s,l],viewState:O({},t.viewState,{rotation:0})}),h=new $i(a,n,e,u.canvas,(function(t){o.prepareFrame(c)&&o.replayGroupChanged&&(o.clipping=!1,o.renderFrame(c,null),o.renderDeclutter(c),t())}));h.addEventListener(F,function(){if(h.getState()===ki){this.image_=h;var t=h.getResolution(),n=h.getPixelRatio(),i=t*e/n;this.renderedResolution=i,this.coordinateToVectorPixelTransform_=kt(this.coordinateToVectorPixelTransform_,s/2,l/2,1/i,-1/i,0,-r.center[0],-r.center[1])}}.bind(this)),h.load()}return this.image_&&(this.renderedPixelToCoordinateTransform_=t.pixelToCoordinateTransform.slice()),!!this.image_},e.prototype.preRender=function(){},e.prototype.postRender=function(){},e.prototype.renderDeclutter=function(){},e.prototype.forEachFeatureAtCoordinate=function(e,r,n,i,o){return this.vectorRenderer_?this.vectorRenderer_.forEachFeatureAtCoordinate(e,r,n,i,o):t.prototype.forEachFeatureAtCoordinate.call(this,e,r,n,i,o)},e}(pd),fy="image",dy="hybrid",gy="vector",yy=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),my={image:[Bu,Du,Uu,zu,Vu],hybrid:[Bu,Uu],vector:[]},vy={image:[Gu],hybrid:[zu,Vu,Gu],vector:[Bu,Du,Uu,zu,Vu,Gu]},_y=function(t){function e(e){var r=t.call(this,e)||this;return r.boundHandleStyleImageChange_=r.handleStyleImageChange_.bind(r),r.dirty_=!1,r.renderedLayerRevision_,r.renderedPixelToCoordinateTransform_=null,r.renderedRotation_,r.renderTileImageQueue_={},r.tileListenerKeys_={},r.tmpTransform_=[1,0,0,1,0,0],r}return yy(e,t),e.prototype.prepareTile=function(t,e,r,n){var i,a=o(t),s=t.getState();return(s===to&&t.hifi||s===eo)&&a in this.tileListenerKeys_&&(H(this.tileListenerKeys_[a]),delete this.tileListenerKeys_[a]),s!==to&&s!==eo||(this.updateExecutorGroup_(t,e,r),this.tileImageNeedsRender_(t,e,r)&&(i=!0,n&&(this.renderTileImageQueue_[a]=t))),i},e.prototype.getTile=function(e,r,n,i){var a=i.pixelRatio,s=i.viewState,l=s.resolution,u=s.projection,c=this.getLayer(),h=c.getSource().getTile(e,r,n,a,u);if(h.getState()<to){h.wantedResolution=l;var p=o(h);if(!(p in this.tileListenerKeys_)){var f=Z(h,F,this.prepareTile.bind(this,h,a,u,!0));this.tileListenerKeys_[p]=f}}else{var d=i.viewHints;!!(d[ns]||d[is])&&h.wantedResolution||(h.wantedResolution=l),this.prepareTile(h,a,u,!1)&&c.getRenderMode()!==gy&&this.renderTileImage_(h,i)}return t.prototype.getTile.call(this,e,r,n,i)},e.prototype.isDrawableTile=function(e){var r=this.getLayer();return t.prototype.isDrawableTile.call(this,e)&&(r.getRenderMode()===gy?o(r)in e.executorGroups:e.hasContext(r))},e.prototype.getTileImage=function(t){return t.getImage(this.getLayer())},e.prototype.prepareFrame=function(e){var r=this.getLayer().getRevision();return this.renderedLayerRevision_!=r&&(this.renderedTiles.length=0),this.renderedLayerRevision_=r,t.prototype.prepareFrame.call(this,e)},e.prototype.updateExecutorGroup_=function(t,e,r){var n=this.getLayer(),i=n.getRevision(),a=n.getRenderOrder()||null,s=t.wantedResolution,l=t.getReplayState(n);if(l.dirty||l.renderedResolution!==s||l.renderedRevision!=i||l.renderedRenderOrder!=a||l.renderedZ!==t.sourceZ){var u=n.getSource(),c=n.getDeclutter(),h=u.getTileGrid(),p=u.getTileGridForProjection(r).getTileCoordExtent(t.wrappedTileCoord),f=u.getSourceTiles(e,r,t),d=o(n);delete t.hitDetectionImageData[d],t.executorGroups[d]=[],c&&(t.declutterExecutorGroups[d]=[]);for(var g=function(r,i){var o=f[r];if(o.getState()!=to)return"continue";var g=o.tileCoord,m=h.getTileCoordExtent(g),v=Te(p,m),_=ue(m,v)?null:Ht(v,n.getRenderBuffer()*s,y.tmpExtent);l.dirty=!1;var b=new Yg(0,v,s,e),x=c?new Yg(0,v,s,e):void 0,w=qu(s,e),S=function(t){var e,r=t.getStyleFunction()||n.getStyleFunction();if(r&&(e=r(t,s)),e){var i=this.renderFeature(t,w,e,b,x);this.dirty_=this.dirty_||i,l.dirty=l.dirty||i}},E=o.getFeatures();a&&a!==l.renderedRenderOrder&&E.sort(a);for(var T=0,C=E.length;T<C;++T){var O=E[T];_&&!Re(_,O.getGeometry().getExtent())||S.call(y,O)}var P=b.finish(),R=n.getRenderMode()!==gy&&c&&1===f.length?null:v,I=new ay(R,s,e,u.getOverlaps(),P,n.getRenderBuffer());if(t.executorGroups[d].push(I),x){var L=new ay(R,s,e,u.getOverlaps(),x.finish(),n.getRenderBuffer());t.declutterExecutorGroups[d].push(L)}},y=this,m=0,v=f.length;m<v;++m)g(m);l.renderedRevision=i,l.renderedZ=t.sourceZ,l.renderedRenderOrder=a,l.renderedResolution=s}},e.prototype.forEachFeatureAtCoordinate=function(t,e,r,n,i){var a=e.viewState.resolution,s=e.viewState.rotation;r=null==r?0:r;var l=this.getLayer(),u=l.getSource().getTileGridForProjection(e.viewState.projection),c=Kt([t]);Ht(c,a*r,c);for(var h,p={},f=function(t,e,r){var a=t.getId();void 0===a&&(a=o(t));var s=p[a];if(s){if(!0!==s&&r<s.distanceSq){if(0===r)return p[a]=!0,i.splice(i.lastIndexOf(s),1),n(t,l,e);s.geometry=e,s.distanceSq=r}}else{if(0===r)return p[a]=!0,n(t,l,e);i.push(p[a]={feature:t,layer:l,geometry:e,distanceSq:r,callback:n})}},d=this.renderedTiles,g=function(n,i){var p=d[n];if(!Re(u.getTileCoordExtent(p.wrappedTileCoord),c))return"continue";var g=o(l),y=[p.executorGroups[g]],m=p.declutterExecutorGroups[g];m&&y.push(m),y.some((function(n){for(var i=n===m?e.declutterTree.all().map((function(t){return t.value})):null,o=0,l=n.length;o<l;++o){var u=n[o];if(h=u.forEachFeatureAtCoordinate(t,a,s,r,f,i))return!0}}))},y=0,m=d.length;!h&&y<m;++y)g(y);return h},e.prototype.getFeatures=function(t){return new Promise(function(e,r){for(var n,i=this.getLayer(),a=o(i),s=i.getSource(),l=this.renderedProjection,u=l.getExtent(),c=this.renderedResolution,h=s.getTileGridForProjection(l),p=It(this.renderedPixelToCoordinateTransform_,t.slice()),f=h.getTileCoordForCoordAndResolution(p,c),d=0,g=this.renderedTiles.length;d<g;++d)if(f.toString()===this.renderedTiles[d].tileCoord.toString()){if((n=this.renderedTiles[d]).getState()===to&&n.hifi){var y=h.getTileCoordExtent(n.tileCoord);s.getWrapX()&&l.canWrapX()&&!te(u,y)&&Fr(p,l);break}n=void 0}if(!n||n.loadingSourceTiles>0)e([]);else{var m=Ce(h.getTileCoordExtent(n.wrappedTileCoord)),v=[(p[0]-m[0])/c,(m[1]-p[1])/c],_=n.getSourceTiles().reduce((function(t,e){return t.concat(e.getFeatures())}),[]),b=n.hitDetectionImageData[a];if(!b&&!this.animatingOrInteracting_){var x=Is(h.getTileSize(h.getZForResolution(c))),w=[x[0]/2,x[1]/2],S=this.renderedRotation_;b=sy(x,[this.getRenderTransform(h.getTileCoordCenter(n.wrappedTileCoord),c,0,.5,w[0],w[1],0)],_,i.getStyleFunction(),h.getTileCoordExtent(n.wrappedTileCoord),n.getReplayState(i).renderedResolution,S),n.hitDetectionImageData[a]=b}e(ly(v,_,b))}}.bind(this))},e.prototype.handleFontsChanged=function(){P(this.renderTileImageQueue_);var t=this.getLayer();t.getVisible()&&void 0!==this.renderedLayerRevision_&&t.changed()},e.prototype.handleStyleImageChange_=function(t){this.renderIfReadyAndVisible()},e.prototype.renderDeclutter=function(t){for(var e=t.viewHints,r=!(e[ns]||e[is]),n=this.renderedTiles,i=0,a=n.length;i<a;++i){var s=n[i],l=s.declutterExecutorGroups[o(this.getLayer())];if(l)for(var u=l.length-1;u>=0;--u)l[u].execute(this.context,1,this.getTileRenderTransform(s,t),t.viewState.rotation,r,void 0,t.declutterTree)}},e.prototype.getTileRenderTransform=function(t,e){var r=e.pixelRatio,n=e.viewState,i=n.center,o=n.resolution,a=n.rotation,s=e.size,l=Math.round(s[0]*r),u=Math.round(s[1]*r),c=this.getLayer().getSource().getTileGridForProjection(e.viewState.projection),h=t.tileCoord,p=c.getTileCoordExtent(t.wrappedTileCoord),f=c.getTileCoordExtent(h,this.tmpExtent)[0]-p[0];return Ot(Mt(this.inversePixelTransform.slice(),1/r,1/r),this.getRenderTransform(i,o,a,r,l,u,f))},e.prototype.renderFrame=function(e,r){var n=e.viewHints,i=!(n[ns]||n[is]);this.renderQueuedTileImages_(i,e),t.prototype.renderFrame.call(this,e,r),this.renderedPixelToCoordinateTransform_=e.pixelToCoordinateTransform.slice(),this.renderedRotation_=e.viewState.rotation;var a=this.getLayer(),s=a.getRenderMode();if(s===fy)return this.container;var l=a.getSource(),u=e.usedTiles[o(l)];for(var c in this.renderTileImageQueue_)u&&c in u||delete this.renderTileImageQueue_[c];for(var h=this.context,p=vy[s],f=e.viewState.rotation,d=this.renderedTiles,g=[],y=[],m=d.length-1;m>=0;--m)for(var v=d[m],_=this.getTileRenderTransform(v,e),b=v.executorGroups[o(a)],x=!1,w=0,S=b.length;w<S;++w){var E=b[w];if(E.hasExecutors(p)){var T=v.tileCoord[0],C=void 0;if(!x&&(C=E.getClipCoords(_))){h.save();for(var O=0,P=g.length;O<P;++O){var R=g[O];T<y[O]&&(h.beginPath(),h.moveTo(C[0],C[1]),h.lineTo(C[2],C[3]),h.lineTo(C[4],C[5]),h.lineTo(C[6],C[7]),h.moveTo(R[6],R[7]),h.lineTo(R[4],R[5]),h.lineTo(R[2],R[3]),h.lineTo(R[0],R[1]),h.clip())}}E.execute(h,1,_,f,i,p),!x&&C&&(h.restore(),g.push(C),y.push(T),x=!0)}}return this.container},e.prototype.renderQueuedTileImages_=function(t,e){for(var r in this.renderTileImageQueue_){if(!t&&Date.now()-e.time>8){e.animate=!0;break}var n=this.renderTileImageQueue_[r];delete this.renderTileImageQueue_[r],this.renderTileImage_(n,e)}},e.prototype.renderFeature=function(t,e,r,n,i){if(!r)return!1;var o=!1;if(Array.isArray(r))for(var a=0,s=r.length;a<s;++a)o=Zu(n,t,r[a],e,this.boundHandleStyleImageChange_,void 0,i)||o;else o=Zu(n,t,r,e,this.boundHandleStyleImageChange_,void 0,i);return o},e.prototype.tileImageNeedsRender_=function(t,e,r){var n=this.getLayer(),i=t.getReplayState(n),o=n.getRevision(),a=t.sourceZ,s=t.wantedResolution;return i.renderedTileResolution!==s||i.renderedTileRevision!==o||i.renderedTileZ!==a},e.prototype.renderTileImage_=function(t,e){var r=this.getLayer(),n=t.getReplayState(r),i=r.getRevision(),a=t.executorGroups[o(r)];n.renderedTileRevision=i,n.renderedTileZ=t.sourceZ;var s=t.wrappedTileCoord,l=s[0],u=r.getSource(),c=e.pixelRatio,h=e.viewState.projection,p=u.getTileGridForProjection(h),f=p.getResolution(t.tileCoord[0]),d=e.pixelRatio/t.wantedResolution*f,g=p.getResolution(l),y=t.getContext(r);c=Math.round(Math.max(c,d/c));var m=u.getTilePixelSize(l,c,h);y.canvas.width=m[0],y.canvas.height=m[1];var v=c/d;if(1!==v){var _=Ct(this.tmpTransform_);Mt(_,v,v),y.setTransform.apply(y,_)}var b=p.getTileCoordExtent(s,this.tmpExtent),x=d/g,w=Ct(this.tmpTransform_);Mt(w,x,-x),At(w,-b[0],-b[3]);for(var S=0,E=a.length;S<E;++S){a[S].execute(y,v,w,0,!0,my[r.getRenderMode()])}n.renderedTileResolution=t.wantedResolution},e}(xd);function by(t,e,r,n,i,o,a){var s,l,u=(r-e)/n;if(1===u)s=e;else if(2===u)s=e,l=i;else if(0!==u){for(var c=t[e],h=t[e+1],p=0,d=[0],g=e+n;g<r;g+=n){var y=t[g],m=t[g+1];p+=Math.sqrt((y-c)*(y-c)+(m-h)*(m-h)),d.push(p),c=y,h=m}var v=i*p,_=f(d,v);_<0?(l=(v-d[-_-2])/(d[-_-1]-d[-_-2]),s=e+(-_-2)*n):s=e+_*n}var b=a>1?a:2,x=o||new Array(b);for(g=0;g<b;++g)x[g]=void 0===s?NaN:void 0===l?t[s+g]:qe(t[s+g],t[s+n+g],l);return x}function xy(t,e,r,n,i,o){if(r==e)return null;var a;if(i<t[e+n-1])return o?((a=t.slice(e,e+n))[n-1]=i,a):null;if(t[r-1]<i)return o?((a=t.slice(r-n,r))[n-1]=i,a):null;if(i==t[e+n-1])return t.slice(e,e+n);for(var s=e/n,l=r/n;s<l;){var u=s+l>>1;i<t[(u+1)*n-1]?l=u:s=u+1}var c=t[s*n-1];if(i==c)return t.slice((s-1)*n,(s-1)*n+n);var h=(i-c)/(t[(s+1)*n-1]-c);a=[];for(var p=0;p<n-1;++p)a.push(qe(t[(s-1)*n+p],t[s*n+p],h));return a.push(i),a}function wy(t,e,r,n,i,o,a){if(a)return xy(t,e,r[r.length-1],n,i,o);var s;if(i<t[n-1])return o?((s=t.slice(0,n))[n-1]=i,s):null;if(t[t.length-1]<i)return o?((s=t.slice(t.length-n))[n-1]=i,s):null;for(var l=0,u=r.length;l<u;++l){var c=r[l];if(e!=c){if(i<t[e+n-1])return null;if(i<=t[c-1])return xy(t,e,c,n,i,!1);e=c}}return null}function Sy(t,e,r,n){for(var i=[],o=[1/0,1/0,-1/0,-1/0],a=0,s=r.length;a<s;++a){var l=r[a];o=le(t,e,l[0],n),i.push((o[0]+o[2])/2,(o[1]+o[3])/2),e=l[l.length-1]}return i}var Ey=[1,0,0,1,0,0],Ty=function(){function t(t,e,r,n,i){this.extent_,this.id_=i,this.type_=t,this.flatCoordinates_=e,this.flatInteriorPoints_=null,this.flatMidpoints_=null,this.ends_=r,this.properties_=n}return t.prototype.get=function(t){return this.properties_[t]},t.prototype.getExtent=function(){return this.extent_||(this.extent_=this.type_===bt.POINT?ae(this.flatCoordinates_):le(this.flatCoordinates_,0,this.flatCoordinates_.length,2)),this.extent_},t.prototype.getFlatInteriorPoint=function(){if(!this.flatInteriorPoints_){var t=xe(this.getExtent());this.flatInteriorPoints_=$n(this.flatCoordinates_,0,this.ends_,2,t,0)}return this.flatInteriorPoints_},t.prototype.getFlatInteriorPoints=function(){if(!this.flatInteriorPoints_){var t=Sy(this.flatCoordinates_,0,this.ends_,2);this.flatInteriorPoints_=Jn(this.flatCoordinates_,0,this.ends_,2,t)}return this.flatInteriorPoints_},t.prototype.getFlatMidpoint=function(){return this.flatMidpoints_||(this.flatMidpoints_=by(this.flatCoordinates_,0,this.flatCoordinates_.length,2,.5)),this.flatMidpoints_},t.prototype.getFlatMidpoints=function(){if(!this.flatMidpoints_){this.flatMidpoints_=[];for(var t=this.flatCoordinates_,e=0,r=this.ends_,n=0,i=r.length;n<i;++n){var o=r[n],a=by(t,e,o,2,.5);v(this.flatMidpoints_,a),e=o}}return this.flatMidpoints_},t.prototype.getId=function(){return this.id_},t.prototype.getOrientedFlatCoordinates=function(){return this.flatCoordinates_},t.prototype.getGeometry=function(){return this},t.prototype.getSimplifiedGeometry=function(t){return this},t.prototype.simplifyTransformed=function(t,e){return this},t.prototype.getProperties=function(){return this.properties_},t.prototype.getStride=function(){return 2},t.prototype.getStyleFunction=function(){},t.prototype.getType=function(){return this.type_},t.prototype.transform=function(t){var e=(t=Gr(t)).getExtent(),r=t.getWorldExtent();if(e&&r){var n=Ee(r)/Ee(e);kt(Ey,r[0],r[3],n,-n,0,0,0),ln(this.flatCoordinates_,0,this.flatCoordinates_.length,2,Ey,this.flatCoordinates_)}},t.prototype.getEnds=function(){return this.ends_},t}();Ty.prototype.getEndss=Ty.prototype.getEnds,Ty.prototype.getFlatCoordinates=Ty.prototype.getOrientedFlatCoordinates;var Cy=Ty;var Oy=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Py=function(t){function e(e,r){var n=t.call(this)||this;return n.flatMidpoint_=null,n.flatMidpointRevision_=-1,n.maxDelta_=-1,n.maxDeltaRevision_=-1,void 0===r||Array.isArray(e[0])?n.setCoordinates(e,r):n.setFlatCoordinates(r,e),n}return Oy(e,t),e.prototype.appendCoordinate=function(t){this.flatCoordinates?v(this.flatCoordinates,t):this.flatCoordinates=t.slice(),this.changed()},e.prototype.clone=function(){var t=new e(this.flatCoordinates.slice(),this.layout);return t.applyProperties(this),t},e.prototype.closestPointXY=function(t,e,r,n){return n<Jt(this.getExtent(),t,e)?n:(this.maxDeltaRevision_!=this.getRevision()&&(this.maxDelta_=Math.sqrt(bn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,0)),this.maxDeltaRevision_=this.getRevision()),Sn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,this.maxDelta_,!1,t,e,r,n))},e.prototype.forEachSegment=function(t){return Qn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t)},e.prototype.getCoordinateAtM=function(t,e){if(this.layout!=vt&&this.layout!=_t)return null;var r=void 0!==e&&e;return xy(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,r)},e.prototype.getCoordinates=function(){return Nn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)},e.prototype.getCoordinateAt=function(t,e){return by(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,e,this.stride)},e.prototype.getLength=function(){return qg(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)},e.prototype.getFlatMidpoint=function(){return this.flatMidpointRevision_!=this.getRevision()&&(this.flatMidpoint_=this.getCoordinateAt(.5,this.flatMidpoint_),this.flatMidpointRevision_=this.getRevision()),this.flatMidpoint_},e.prototype.getSimplifiedGeometryInternal=function(t){var r=[];return r.length=In(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t,r,0),new e(r,yt)},e.prototype.getType=function(){return bt.LINE_STRING},e.prototype.intersectsExtent=function(t){return ti(this.flatCoordinates,0,this.flatCoordinates.length,this.stride,t)},e.prototype.setCoordinates=function(t,e){this.setLayout(e,t,1),this.flatCoordinates||(this.flatCoordinates=[]),this.flatCoordinates.length=On(this.flatCoordinates,0,t,this.stride),this.changed()},e}(vn),Ry=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Iy=function(t){function e(e){return t.call(this,e)||this}return Ry(e,t),e.prototype.createRenderer=function(){return new cy(this)},e}(wg);function Ly(t,e,r){for(var n,i,o,a,s,l,u=[],c=t(0),h=t(1),p=e(c),f=e(h),d=[h,c],g=[f,p],y=[1,0],m={},v=1e5;--v>0&&y.length>0;)o=y.pop(),c=d.pop(),p=g.pop(),(l=o.toString())in m||(u.push(p[0],p[1]),m[l]=!0),a=y.pop(),h=d.pop(),f=g.pop(),ze((i=e(n=t(s=(o+a)/2)))[0],i[1],p[0],p[1],f[0],f[1])<r?(u.push(f[0],f[1]),m[l=a.toString()]=!0):(y.push(a,s,s,o),g.push(f,i,i,p),d.push(h,n,n,c));return u}function My(t,e,r,n,i){return Ly((function(n){return[t,e+(r-e)*n]}),Kr(Gr("EPSG:4326"),n),i)}function Fy(t,e,r,n,i){return Ly((function(n){return[e+(r-e)*n,t]}),Kr(Gr("EPSG:4326"),n),i)}var Ay=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ky=new gp({color:"rgba(0,0,0,0.2)"}),jy=[90,45,30,20,10,5,2,1,.5,.2,.1,.05,.01,.005,.002,.001],Ny=function(t){function e(e){var r=this,n=e||{},i=O({updateWhileAnimating:!0,updateWhileInteracting:!0,renderBuffer:0},n);return delete i.maxLines,delete i.strokeStyle,delete i.targetSize,delete i.showLabels,delete i.lonLabelFormatter,delete i.latLabelFormatter,delete i.lonLabelPosition,delete i.latLabelPosition,delete i.lonLabelStyle,delete i.latLabelStyle,delete i.intervals,(r=t.call(this,i)||this).projection_=null,r.maxLat_=1/0,r.maxLon_=1/0,r.minLat_=-1/0,r.minLon_=-1/0,r.maxX_=1/0,r.maxY_=1/0,r.minX_=-1/0,r.minY_=-1/0,r.targetSize_=void 0!==n.targetSize?n.targetSize:100,r.maxLines_=void 0!==n.maxLines?n.maxLines:100,r.meridians_=[],r.parallels_=[],r.strokeStyle_=void 0!==n.strokeStyle?n.strokeStyle:ky,r.fromLonLatTransform_=void 0,r.toLonLatTransform_=void 0,r.projectionCenterLonLat_=null,r.bottomLeft_=null,r.bottomRight_=null,r.topLeft_=null,r.topRight_=null,r.meridiansLabels_=null,r.parallelsLabels_=null,n.showLabels&&(r.lonLabelFormatter_=null==n.lonLabelFormatter?Er.bind(r,"EW"):n.lonLabelFormatter,r.latLabelFormatter_=null==n.latLabelFormatter?Er.bind(r,"NS"):n.latLabelFormatter,r.lonLabelPosition_=null==n.lonLabelPosition?0:n.lonLabelPosition,r.latLabelPosition_=null==n.latLabelPosition?1:n.latLabelPosition,r.lonLabelStyleBase_=new wp({text:void 0!==n.lonLabelStyle?n.lonLabelStyle.clone():new Tp({font:"12px Calibri,sans-serif",textBaseline:"bottom",fill:new ep({color:"rgba(0,0,0,1)"}),stroke:new gp({color:"rgba(255,255,255,1)",width:3})})}),r.lonLabelStyle_=function(t){var e=t.get("graticule_label");return this.lonLabelStyleBase_.getText().setText(e),this.lonLabelStyleBase_}.bind(r),r.latLabelStyleBase_=new wp({text:void 0!==n.latLabelStyle?n.latLabelStyle.clone():new Tp({font:"12px Calibri,sans-serif",textAlign:"right",fill:new ep({color:"rgba(0,0,0,1)"}),stroke:new gp({color:"rgba(255,255,255,1)",width:3})})}),r.latLabelStyle_=function(t){var e=t.get("graticule_label");return this.latLabelStyleBase_.getText().setText(e),this.latLabelStyleBase_}.bind(r),r.meridiansLabels_=[],r.parallelsLabels_=[],r.addEventListener(Xo,r.drawLabels_.bind(r))),r.intervals_=void 0!==n.intervals?n.intervals:jy,r.setSource(new hf({loader:r.loaderFunction.bind(r),strategy:r.strategyFunction.bind(r),features:new ht,overlaps:!1,useSpatialIndex:!1,wrapX:n.wrapX})),r.featurePool_=[],r.lineStyle_=new wp({stroke:r.strokeStyle_}),r.loadedExtent_=null,r.renderedExtent_=null,r.setRenderOrder(null),r}return Ay(e,t),e.prototype.strategyFunction=function(t,e){var r=t.slice();return this.projection_&&this.getSource().getWrapX()&&ke(r,this.projection_),this.loadedExtent_&&(ce(this.loadedExtent_,r,e)?r=this.loadedExtent_.slice():this.getSource().removeLoadedExtent(this.loadedExtent_)),[r]},e.prototype.loaderFunction=function(t,e,r){this.loadedExtent_=t;var n=this.getSource(),i=Te(this.getExtent()||[-1/0,-1/0,1/0,1/0],t);if(!(this.renderedExtent_&&ue(this.renderedExtent_,i)||(this.renderedExtent_=i,Ie(i)))){var o=xe(i),a=e*e/4;(!this.projection_||!Xr(this.projection_,r))&&this.updateProjectionInfo_(r),this.createGraticule_(i,o,e,a);var s,l=this.meridians_.length+this.parallels_.length;for(this.meridiansLabels_&&(l+=this.meridians_.length),this.parallelsLabels_&&(l+=this.parallels_.length);l>this.featurePool_.length;)s=new gt,this.featurePool_.push(s);var u=n.getFeaturesCollection();u.clear();var c,h,p=0;for(c=0,h=this.meridians_.length;c<h;++c)(s=this.featurePool_[p++]).setGeometry(this.meridians_[c]),s.setStyle(this.lineStyle_),u.push(s);for(c=0,h=this.parallels_.length;c<h;++c)(s=this.featurePool_[p++]).setGeometry(this.parallels_[c]),s.setStyle(this.lineStyle_),u.push(s)}},e.prototype.addMeridian_=function(t,e,r,n,i,o){var a=this.getMeridian_(t,e,r,n,o);if(Re(a.getExtent(),i)){if(this.meridiansLabels_){var s=this.lonLabelFormatter_(t);o in this.meridiansLabels_?this.meridiansLabels_[o].text=s:this.meridiansLabels_[o]={geom:new qn([]),text:s}}this.meridians_[o++]=a}return o},e.prototype.addParallel_=function(t,e,r,n,i,o){var a=this.getParallel_(t,e,r,n,o);if(Re(a.getExtent(),i)){if(this.parallelsLabels_){var s=this.latLabelFormatter_(t);o in this.parallelsLabels_?this.parallelsLabels_[o].text=s:this.parallelsLabels_[o]={geom:new qn([]),text:s}}this.parallels_[o++]=a}return o},e.prototype.drawLabels_=function(t){var e=t.frameState.viewState.rotation,r=t.frameState.extent,n=xe(r),i=r;if(e){var o=Pe(r),a=Ee(r),s=Math.abs(Math.cos(e)),l=Math.abs(Math.sin(e)),u=(l*a-s*o)/(l*l-s*s),c=(l*o-s*a)/(l*l-s*s);i=[n[0]-u/2,n[1]-c/2,n[0]+u/2,n[1]+c/2]}var h=0,p=0,f=this.latLabelPosition_<.5,d=this.projection_.getExtent(),g=Pe(d);this.getSource().getWrapX()&&this.projection_.canWrapX()&&!te(d,r)&&(h=Math.floor((r[0]-d[0])/g),p=Math.ceil((r[2]-d[2])/g),f=f!==Math.abs(e)>Math.PI/2);for(var y=Ku(t),m=h;m<=p;++m){var v=this.meridians_.length+this.parallels_.length,_=void 0,b=void 0,x=void 0,w=void 0;if(this.meridiansLabels_)for(b=0,x=this.meridiansLabels_.length;b<x;++b){var S=this.meridians_[b];if(e||0!==m)(E=S.clone()).translate(m*g,0),E.rotate(-e,n),(w=this.getMeridianPoint_(E,i,b)).rotate(e,n);else w=this.getMeridianPoint_(S,r,b);(_=this.featurePool_[v++]).setGeometry(w),_.set("graticule_label",this.meridiansLabels_[b].text),y.drawFeature(_,this.lonLabelStyle_(_))}if(this.parallelsLabels_&&(m===h&&f||m===p&&!f))for(b=0,x=this.parallels_.length;b<x;++b){var E;S=this.parallels_[b];if(e||0!==m)(E=S.clone()).translate(m*g,0),E.rotate(-e,n),(w=this.getParallelPoint_(E,i,b)).rotate(e,n);else w=this.getParallelPoint_(S,r,b);(_=this.featurePool_[v++]).setGeometry(w),_.set("graticule_label",this.parallelsLabels_[b].text),y.drawFeature(_,this.latLabelStyle_(_))}}},e.prototype.createGraticule_=function(t,e,r,n){var i=this.getInterval_(r);if(-1==i)return this.meridians_.length=0,this.parallels_.length=0,this.meridiansLabels_&&(this.meridiansLabels_.length=0),void(this.parallelsLabels_&&(this.parallelsLabels_.length=0));var o=!1,a=this.projection_.getExtent(),s=Pe(a);this.getSource().getWrapX()&&this.projection_.canWrapX()&&!te(a,t)&&(Pe(t)>=s?(t[0]=a[0],t[2]=a[2]):o=!0);var l=[Ne(e[0],this.minX_,this.maxX_),Ne(e[1],this.minY_,this.maxY_)],u=this.toLonLatTransform_(l);isNaN(u[1])&&(u[1]=Math.abs(this.maxLat_)>=Math.abs(this.minLat_)?this.maxLat_:this.minLat_);var c,h,p,f,d=Ne(u[0],this.minLon_,this.maxLon_),g=Ne(u[1],this.minLat_,this.maxLat_),y=this.maxLines_,m=t;o||(m=[Ne(t[0],this.minX_,this.maxX_),Ne(t[1],this.minY_,this.maxY_),Ne(t[2],this.minX_,this.maxX_),Ne(t[3],this.minY_,this.maxY_)]);var v=Ae(m,this.toLonLatTransform_,void 0,8),_=v[3],b=v[2],x=v[1],w=v[0];if(o||(Qt(m,this.bottomLeft_)&&(w=this.minLon_,x=this.minLat_),Qt(m,this.bottomRight_)&&(b=this.maxLon_,x=this.minLat_),Qt(m,this.topLeft_)&&(w=this.minLon_,_=this.maxLat_),Qt(m,this.topRight_)&&(b=this.maxLon_,_=this.maxLat_),_=Ne(_,g,this.maxLat_),b=Ne(b,d,this.maxLon_),x=Ne(x,this.minLat_,g),w=Ne(w,this.minLon_,d)),f=Ne(d=Math.floor(d/i)*i,this.minLon_,this.maxLon_),h=this.addMeridian_(f,x,_,n,t,0),c=0,o)for(;(f-=i)>=w&&c++<y;)h=this.addMeridian_(f,x,_,n,t,h);else for(;f!=this.minLon_&&c++<y;)f=Math.max(f-i,this.minLon_),h=this.addMeridian_(f,x,_,n,t,h);if(f=Ne(d,this.minLon_,this.maxLon_),c=0,o)for(;(f+=i)<=b&&c++<y;)h=this.addMeridian_(f,x,_,n,t,h);else for(;f!=this.maxLon_&&c++<y;)f=Math.min(f+i,this.maxLon_),h=this.addMeridian_(f,x,_,n,t,h);for(this.meridians_.length=h,this.meridiansLabels_&&(this.meridiansLabels_.length=h),p=Ne(g=Math.floor(g/i)*i,this.minLat_,this.maxLat_),h=this.addParallel_(p,w,b,n,t,0),c=0;p!=this.minLat_&&c++<y;)p=Math.max(p-i,this.minLat_),h=this.addParallel_(p,w,b,n,t,h);for(p=Ne(g,this.minLat_,this.maxLat_),c=0;p!=this.maxLat_&&c++<y;)p=Math.min(p+i,this.maxLat_),h=this.addParallel_(p,w,b,n,t,h);this.parallels_.length=h,this.parallelsLabels_&&(this.parallelsLabels_.length=h)},e.prototype.getInterval_=function(t){for(var e=this.projectionCenterLonLat_[0],r=this.projectionCenterLonLat_[1],n=-1,i=Math.pow(this.targetSize_*t,2),o=[],a=[],s=0,l=this.intervals_.length;s<l;++s){var u=Ne(this.intervals_[s]/2,0,90),c=Ne(r,-90+u,90-u);if(o[0]=e-u,o[1]=c-u,a[0]=e+u,a[1]=c+u,this.fromLonLatTransform_(o,o),this.fromLonLatTransform_(a,a),Math.pow(a[0]-o[0],2)+Math.pow(a[1]-o[1],2)<=i)break;n=this.intervals_[s]}return n},e.prototype.getMeridian_=function(t,e,r,n,i){var o=My(t,e,r,this.projection_,n),a=this.meridians_[i];return a?(a.setFlatCoordinates(yt,o),a.changed()):(a=new Py(o,yt),this.meridians_[i]=a),a},e.prototype.getMeridianPoint_=function(t,e,r){var n=t.getFlatCoordinates(),i=1,o=n.length-1;n[i]>n[o]&&(i=o,o=1);var a=Math.max(e[1],n[i]),s=Math.min(e[3],n[o]),l=Ne(e[1]+Math.abs(e[1]-e[3])*this.lonLabelPosition_,a,s),u=[n[i-1]+(n[o-1]-n[i-1])*(l-n[i])/(n[o]-n[i]),l],c=this.meridiansLabels_[r].geom;return c.setCoordinates(u),c},e.prototype.getMeridians=function(){return this.meridians_},e.prototype.getParallel_=function(t,e,r,n,i){var o=Fy(t,e,r,this.projection_,n),a=this.parallels_[i];return a?(a.setFlatCoordinates(yt,o),a.changed()):a=new Py(o,yt),a},e.prototype.getParallelPoint_=function(t,e,r){var n=t.getFlatCoordinates(),i=0,o=n.length-2;n[i]>n[o]&&(i=o,o=0);var a=Math.max(e[0],n[i]),s=Math.min(e[2],n[o]),l=Ne(e[0]+Math.abs(e[0]-e[2])*this.latLabelPosition_,a,s),u=[l,n[i+1]+(n[o+1]-n[i+1])*(l-n[i])/(n[o]-n[i])],c=this.parallelsLabels_[r].geom;return c.setCoordinates(u),c},e.prototype.getParallels=function(){return this.parallels_},e.prototype.updateProjectionInfo_=function(t){var e=Gr("EPSG:4326"),r=t.getWorldExtent();this.maxLat_=r[3],this.maxLon_=r[2],this.minLat_=r[1],this.minLon_=r[0];var n=Kr(t,e);if(this.minLon_<this.maxLon_)this.toLonLatTransform_=n;else{var i=this.minLon_+this.maxLon_/2;this.maxLon_+=360,this.toLonLatTransform_=function(t,e,r){for(var o=r||2,a=n(t,e,o),s=0,l=a.length;s<l;s+=o)a[s]<i&&(a[s]+=360);return a}}this.fromLonLatTransform_=Kr(e,t);var o=Ae([this.minLon_,this.minLat_,this.maxLon_,this.maxLat_],this.fromLonLatTransform_,void 0,8);this.minX_=o[0],this.maxX_=o[2],this.minY_=o[1],this.maxY_=o[3],this.bottomLeft_=this.fromLonLatTransform_([this.minLon_,this.minLat_]),this.bottomRight_=this.fromLonLatTransform_([this.maxLon_,this.minLat_]),this.topLeft_=this.fromLonLatTransform_([this.minLon_,this.maxLat_]),this.topRight_=this.fromLonLatTransform_([this.maxLon_,this.maxLat_]),this.projectionCenterLonLat_=this.toLonLatTransform_(xe(t.getExtent())),isNaN(this.projectionCenterLonLat_[1])&&(this.projectionCenterLonLat_[1]=Math.abs(this.maxLat_)>=Math.abs(this.minLat_)?this.maxLat_:this.minLat_),this.projection_=t},e}(Iy),Dy=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Gy="blur",zy="gradient",Uy="radius",By=["#00f","#0ff","#0f0","#ff0","#f00"];var Vy=function(t){function e(e){var r=this,n=e||{},i=O({},n);delete i.gradient,delete i.radius,delete i.blur,delete i.weight,(r=t.call(this,i)||this).gradient_=null,r.addEventListener(it(zy),r.handleGradientChanged_),r.setGradient(n.gradient?n.gradient:By),r.setBlur(void 0!==n.blur?n.blur:15),r.setRadius(void 0!==n.radius?n.radius:8);var o=n.weight?n.weight:"weight";return r.weightFunction_="string"==typeof o?function(t){return t.get(o)}:o,r.setRenderOrder(null),r}return Dy(e,t),e.prototype.getBlur=function(){return this.get(Gy)},e.prototype.getGradient=function(){return this.get(zy)},e.prototype.getRadius=function(){return this.get(Uy)},e.prototype.handleGradientChanged_=function(){this.gradient_=function(t){for(var e=uo(1,256),r=e.createLinearGradient(0,0,1,256),n=1/(t.length-1),i=0,o=t.length;i<o;++i)r.addColorStop(i*n,t[i]);return e.fillStyle=r,e.fillRect(0,0,1,256),e.canvas}(this.getGradient())},e.prototype.setBlur=function(t){this.set(Gy,t)},e.prototype.setGradient=function(t){this.set(zy,t)},e.prototype.setRadius=function(t){this.set(Uy,t)},e.prototype.createRenderer=function(){return new Eg(this,{className:this.getClassName(),attributes:[{name:"weight",callback:function(t){var e=this.weightFunction_(t);return void 0!==e?Ne(e,0,1):1}.bind(this)}],vertexShader:"\n precision mediump float;\n uniform mat4 u_projectionMatrix;\n uniform mat4 u_offsetScaleMatrix;\n uniform float u_size;\n attribute vec2 a_position;\n attribute float a_index;\n attribute float a_weight;\n\n varying vec2 v_texCoord;\n varying float v_weight;\n\n void main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix;\n float offsetX = a_index == 0.0 || a_index == 3.0 ? -u_size / 2.0 : u_size / 2.0;\n float offsetY = a_index == 0.0 || a_index == 1.0 ? -u_size / 2.0 : u_size / 2.0;\n vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);\n gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;\n float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;\n float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;\n v_texCoord = vec2(u, v);\n v_weight = a_weight;\n }",fragmentShader:"\n precision mediump float;\n uniform float u_blurSlope;\n\n varying vec2 v_texCoord;\n varying float v_weight;\n\n void main(void) {\n vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);\n float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;\n float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;\n float alpha = smoothstep(0.0, 1.0, value) * v_weight;\n gl_FragColor = vec4(alpha, alpha, alpha, alpha);\n }",hitVertexShader:"\n precision mediump float;\n uniform mat4 u_projectionMatrix;\n uniform mat4 u_offsetScaleMatrix;\n uniform float u_size;\n attribute vec2 a_position;\n attribute float a_index;\n attribute float a_weight;\n attribute vec4 a_hitColor;\n\n varying vec2 v_texCoord;\n varying float v_weight;\n varying vec4 v_hitColor;\n\n void main(void) {\n mat4 offsetMatrix = u_offsetScaleMatrix;\n float offsetX = a_index == 0.0 || a_index == 3.0 ? -u_size / 2.0 : u_size / 2.0;\n float offsetY = a_index == 0.0 || a_index == 1.0 ? -u_size / 2.0 : u_size / 2.0;\n vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);\n gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;\n float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;\n float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;\n v_texCoord = vec2(u, v);\n v_hitColor = a_hitColor;\n v_weight = a_weight;\n }",hitFragmentShader:"\n precision mediump float;\n uniform float u_blurSlope;\n\n varying vec2 v_texCoord;\n varying float v_weight;\n varying vec4 v_hitColor;\n\n void main(void) {\n vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);\n float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;\n float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;\n float alpha = smoothstep(0.0, 1.0, value) * v_weight;\n if (alpha < 0.05) {\n discard;\n }\n\n gl_FragColor = v_hitColor;\n }",uniforms:{u_size:function(){return 2*(this.get(Uy)+this.get(Gy))}.bind(this),u_blurSlope:function(){return this.get(Uy)/Math.max(1,this.get(Gy))}.bind(this)},postProcesses:[{fragmentShader:"\n precision mediump float;\n\n uniform sampler2D u_image;\n uniform sampler2D u_gradientTexture;\n\n varying vec2 v_texCoord;\n\n void main() {\n vec4 color = texture2D(u_image, v_texCoord);\n gl_FragColor.a = color.a;\n gl_FragColor.rgb = texture2D(u_gradientTexture, vec2(0.5, color.a)).rgb;\n gl_FragColor.rgb *= gl_FragColor.a;\n }",uniforms:{u_gradientTexture:function(){return this.gradient_}.bind(this)}}]})},e.prototype.renderDeclutter=function(){},e}(Iy),Yy=function(){function t(){this.dataProjection=null,this.defaultFeatureProjection=null}return t.prototype.getReadOptions=function(t,e){var r;if(e){var n=e.dataProjection?Gr(e.dataProjection):this.readProjection(t);e.extent&&n&&n.getUnits()===St.TILE_PIXELS&&(n=Gr(n)).setWorldExtent(e.extent),r={dataProjection:n,featureProjection:e.featureProjection}}return this.adaptOptions(r)},t.prototype.adaptOptions=function(t){return O({dataProjection:this.dataProjection,featureProjection:this.defaultFeatureProjection},t)},t.prototype.getType=function(){return n()},t.prototype.readFeature=function(t,e){return n()},t.prototype.readFeatures=function(t,e){return n()},t.prototype.readGeometry=function(t,e){return n()},t.prototype.readProjection=function(t){return n()},t.prototype.writeFeature=function(t,e){return n()},t.prototype.writeFeatures=function(t,e){return n()},t.prototype.writeGeometry=function(t,e){return n()},t}();function Wy(t,e,r){var n,i=r?Gr(r.featureProjection):null,o=r?Gr(r.dataProjection):null;if(n=i&&o&&!Xr(i,o)?(e?t.clone():t).transform(e?i:o,e?o:i):t,e&&r&&void 0!==r.decimals){var a=Math.pow(10,r.decimals);n===t&&(n=t.clone()),n.applyTransform((function(t){for(var e=0,r=t.length;e<r;++e)t[e]=Math.round(t[e]*a)/a;return t}))}return n}function qy(t,e){var r=e?Gr(e.featureProjection):null,n=e?Gr(e.dataProjection):null;return r&&n&&!Xr(r,n)?$r(t,n,r):t}var Xy=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Zy=function(t){function e(e,r,n){var i=t.call(this)||this;if(i.ends_=[],i.maxDelta_=-1,i.maxDeltaRevision_=-1,Array.isArray(e[0]))i.setCoordinates(e,r);else if(void 0!==r&&n)i.setFlatCoordinates(r,e),i.ends_=n;else{for(var o=i.getLayout(),a=e,s=[],l=[],u=0,c=a.length;u<c;++u){var h=a[u];0===u&&(o=h.getLayout()),v(s,h.getFlatCoordinates()),l.push(s.length)}i.setFlatCoordinates(o,s),i.ends_=l}return i}return Xy(e,t),e.prototype.appendLineString=function(t){this.flatCoordinates?v(this.flatCoordinates,t.getFlatCoordinates().slice()):this.flatCoordinates=t.getFlatCoordinates().slice(),this.ends_.push(this.flatCoordinates.length),this.changed()},e.prototype.clone=function(){var t=new e(this.flatCoordinates.slice(),this.layout,this.ends_.slice());return t.applyProperties(this),t},e.prototype.closestPointXY=function(t,e,r,n){return n<Jt(this.getExtent(),t,e)?n:(this.maxDeltaRevision_!=this.getRevision()&&(this.maxDelta_=Math.sqrt(xn(this.flatCoordinates,0,this.ends_,this.stride,0)),this.maxDeltaRevision_=this.getRevision()),En(this.flatCoordinates,0,this.ends_,this.stride,this.maxDelta_,!1,t,e,r,n))},e.prototype.getCoordinateAtM=function(t,e,r){if(this.layout!=vt&&this.layout!=_t||0===this.flatCoordinates.length)return null;var n=void 0!==e&&e,i=void 0!==r&&r;return wy(this.flatCoordinates,0,this.ends_,this.stride,t,n,i)},e.prototype.getCoordinates=function(){return Dn(this.flatCoordinates,0,this.ends_,this.stride)},e.prototype.getEnds=function(){return this.ends_},e.prototype.getLineString=function(t){return t<0||this.ends_.length<=t?null:new Py(this.flatCoordinates.slice(0===t?0:this.ends_[t-1],this.ends_[t]),this.layout)},e.prototype.getLineStrings=function(){for(var t=this.flatCoordinates,e=this.ends_,r=this.layout,n=[],i=0,o=0,a=e.length;o<a;++o){var s=e[o],l=new Py(t.slice(i,s),r);n.push(l),i=s}return n},e.prototype.getFlatMidpoints=function(){for(var t=[],e=this.flatCoordinates,r=0,n=this.ends_,i=this.stride,o=0,a=n.length;o<a;++o){var s=n[o];v(t,by(e,r,s,i,.5)),r=s}return t},e.prototype.getSimplifiedGeometryInternal=function(t){var r=[],n=[];return r.length=Ln(this.flatCoordinates,0,this.ends_,this.stride,t,r,0,n),new e(r,yt,n)},e.prototype.getType=function(){return bt.MULTI_LINE_STRING},e.prototype.intersectsExtent=function(t){return ei(this.flatCoordinates,0,this.ends_,this.stride,t)},e.prototype.setCoordinates=function(t,e){this.setLayout(e,t,2),this.flatCoordinates||(this.flatCoordinates=[]);var r=Pn(this.flatCoordinates,0,t,this.stride,this.ends_);this.flatCoordinates.length=0===r.length?0:r[r.length-1],this.changed()},e}(vn),Ky=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Hy=function(t){function e(e,r){var n=t.call(this)||this;return r&&!Array.isArray(e[0])?n.setFlatCoordinates(r,e):n.setCoordinates(e,r),n}return Ky(e,t),e.prototype.appendPoint=function(t){this.flatCoordinates?v(this.flatCoordinates,t.getFlatCoordinates()):this.flatCoordinates=t.getFlatCoordinates().slice(),this.changed()},e.prototype.clone=function(){var t=new e(this.flatCoordinates.slice(),this.layout);return t.applyProperties(this),t},e.prototype.closestPointXY=function(t,e,r,n){if(n<Jt(this.getExtent(),t,e))return n;for(var i=this.flatCoordinates,o=this.stride,a=0,s=i.length;a<s;a+=o){var l=Ue(t,e,i[a],i[a+1]);if(l<n){n=l;for(var u=0;u<o;++u)r[u]=i[a+u];r.length=o}}return n},e.prototype.getCoordinates=function(){return Nn(this.flatCoordinates,0,this.flatCoordinates.length,this.stride)},e.prototype.getPoint=function(t){var e=this.flatCoordinates?this.flatCoordinates.length/this.stride:0;return t<0||e<=t?null:new qn(this.flatCoordinates.slice(t*this.stride,(t+1)*this.stride),this.layout)},e.prototype.getPoints=function(){for(var t=this.flatCoordinates,e=this.layout,r=this.stride,n=[],i=0,o=t.length;i<o;i+=r){var a=new qn(t.slice(i,i+r),e);n.push(a)}return n},e.prototype.getType=function(){return bt.MULTI_POINT},e.prototype.intersectsExtent=function(t){for(var e=this.flatCoordinates,r=this.stride,n=0,i=e.length;n<i;n+=r){if(ee(t,e[n],e[n+1]))return!0}return!1},e.prototype.setCoordinates=function(t,e){this.setLayout(e,t,1),this.flatCoordinates||(this.flatCoordinates=[]),this.flatCoordinates.length=On(this.flatCoordinates,0,t,this.stride),this.changed()},e}(vn),$y=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Jy=function(t){function e(e,r,n){var i=t.call(this)||this;if(i.endss_=[],i.flatInteriorPointsRevision_=-1,i.flatInteriorPoints_=null,i.maxDelta_=-1,i.maxDeltaRevision_=-1,i.orientedRevision_=-1,i.orientedFlatCoordinates_=null,!n&&!Array.isArray(e[0])){for(var o=i.getLayout(),a=e,s=[],l=[],u=0,c=a.length;u<c;++u){var h=a[u];0===u&&(o=h.getLayout());for(var p=s.length,f=h.getEnds(),d=0,g=f.length;d<g;++d)f[d]+=p;v(s,h.getFlatCoordinates()),l.push(f)}r=o,e=s,n=l}return void 0!==r&&n?(i.setFlatCoordinates(r,e),i.endss_=n):i.setCoordinates(e,r),i}return $y(e,t),e.prototype.appendPolygon=function(t){var e;if(this.flatCoordinates){var r=this.flatCoordinates.length;v(this.flatCoordinates,t.getFlatCoordinates());for(var n=0,i=(e=t.getEnds().slice()).length;n<i;++n)e[n]+=r}else this.flatCoordinates=t.getFlatCoordinates().slice(),e=t.getEnds().slice(),this.endss_.push();this.endss_.push(e),this.changed()},e.prototype.clone=function(){for(var t=this.endss_.length,r=new Array(t),n=0;n<t;++n)r[n]=this.endss_[n].slice();var i=new e(this.flatCoordinates.slice(),this.layout,r);return i.applyProperties(this),i},e.prototype.closestPointXY=function(t,e,r,n){return n<Jt(this.getExtent(),t,e)?n:(this.maxDeltaRevision_!=this.getRevision()&&(this.maxDelta_=Math.sqrt(wn(this.flatCoordinates,0,this.endss_,this.stride,0)),this.maxDeltaRevision_=this.getRevision()),Tn(this.getOrientedFlatCoordinates(),0,this.endss_,this.stride,this.maxDelta_,!0,t,e,r,n))},e.prototype.containsXY=function(t,e){return Hn(this.getOrientedFlatCoordinates(),0,this.endss_,this.stride,t,e)},e.prototype.getArea=function(){return Bn(this.getOrientedFlatCoordinates(),0,this.endss_,this.stride)},e.prototype.getCoordinates=function(t){var e;return void 0!==t?ci(e=this.getOrientedFlatCoordinates().slice(),0,this.endss_,this.stride,t):e=this.flatCoordinates,Gn(e,0,this.endss_,this.stride)},e.prototype.getEndss=function(){return this.endss_},e.prototype.getFlatInteriorPoints=function(){if(this.flatInteriorPointsRevision_!=this.getRevision()){var t=Sy(this.flatCoordinates,0,this.endss_,this.stride);this.flatInteriorPoints_=Jn(this.getOrientedFlatCoordinates(),0,this.endss_,this.stride,t),this.flatInteriorPointsRevision_=this.getRevision()}return this.flatInteriorPoints_},e.prototype.getInteriorPoints=function(){return new Hy(this.getFlatInteriorPoints().slice(),vt)},e.prototype.getOrientedFlatCoordinates=function(){if(this.orientedRevision_!=this.getRevision()){var t=this.flatCoordinates;li(t,0,this.endss_,this.stride)?this.orientedFlatCoordinates_=t:(this.orientedFlatCoordinates_=t.slice(),this.orientedFlatCoordinates_.length=ci(this.orientedFlatCoordinates_,0,this.endss_,this.stride)),this.orientedRevision_=this.getRevision()}return this.orientedFlatCoordinates_},e.prototype.getSimplifiedGeometryInternal=function(t){var r=[],n=[];return r.length=jn(this.flatCoordinates,0,this.endss_,this.stride,Math.sqrt(t),r,0,n),new e(r,yt,n)},e.prototype.getPolygon=function(t){if(t<0||this.endss_.length<=t)return null;var e;if(0===t)e=0;else{var r=this.endss_[t-1];e=r[r.length-1]}var n=this.endss_[t].slice(),i=n[n.length-1];if(0!==e)for(var o=0,a=n.length;o<a;++o)n[o]-=e;return new fi(this.flatCoordinates.slice(e,i),this.layout,n)},e.prototype.getPolygons=function(){for(var t=this.layout,e=this.flatCoordinates,r=this.endss_,n=[],i=0,o=0,a=r.length;o<a;++o){var s=r[o].slice(),l=s[s.length-1];if(0!==i)for(var u=0,c=s.length;u<c;++u)s[u]-=i;var h=new fi(e.slice(i,l),t,s);n.push(h),i=l}return n},e.prototype.getType=function(){return bt.MULTI_POLYGON},e.prototype.intersectsExtent=function(t){return ii(this.getOrientedFlatCoordinates(),0,this.endss_,this.stride,t)},e.prototype.setCoordinates=function(t,e){this.setLayout(e,t,3),this.flatCoordinates||(this.flatCoordinates=[]);var r=Rn(this.flatCoordinates,0,t,this.stride,this.endss_);if(0===r.length)this.flatCoordinates.length=0;else{var n=r[r.length-1];this.flatCoordinates.length=0===n.length?0:n[n.length-1]}this.changed()},e}(vn),Qy=r(5),tm=r.n(Qy),em=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function rm(t,e,r){if(3===t){var n={keys:[],values:[],features:[]},i=r.readVarint()+r.pos;r.readFields(nm,n,i),n.length=n.features.length,n.length&&(e[n.name]=n)}}function nm(t,e,r){if(15===t)e.version=r.readVarint();else if(1===t)e.name=r.readString();else if(5===t)e.extent=r.readVarint();else if(2===t)e.features.push(r.pos);else if(3===t)e.keys.push(r.readString());else if(4===t){for(var n=null,i=r.readVarint()+r.pos;r.pos<i;)n=1===(t=r.readVarint()>>3)?r.readString():2===t?r.readFloat():3===t?r.readDouble():4===t?r.readVarint64():5===t?r.readVarint():6===t?r.readSVarint():7===t?r.readBoolean():null;e.values.push(n)}}function im(t,e,r){if(1==t)e.id=r.readVarint();else if(2==t)for(var n=r.readVarint()+r.pos;r.pos<n;){var i=e.layer.keys[r.readVarint()],o=e.layer.values[r.readVarint()];e.properties[i]=o}else 3==t?e.type=r.readVarint():4==t&&(e.geometry=r.pos)}function om(t,e,r){t.pos=e.features[r];var n=t.readVarint()+t.pos,i={layer:e,type:0,properties:{}};return t.readFields(im,i,n),i}var am=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.dataProjection=new je({code:"",units:St.TILE_PIXELS}),r.featureClass_=n.featureClass?n.featureClass:Cy,r.geometryName_=n.geometryName,r.layerName_=n.layerName?n.layerName:"layer",r.layers_=n.layers?n.layers:null,r.idProperty_=n.idProperty,r}return em(e,t),e.prototype.readRawGeometry_=function(t,e,r,n){t.pos=e.geometry;for(var i=t.readVarint()+t.pos,o=1,a=0,s=0,l=0,u=0,c=0;t.pos<i;){if(!a){var h=t.readVarint();o=7&h,a=h>>3}a--,1===o||2===o?(s+=t.readSVarint(),l+=t.readSVarint(),1===o&&u>c&&(n.push(u),c=u),r.push(s,l),u+=2):7===o?u>c&&(r.push(r[c],r[c+1]),u+=2):pt(!1,59)}u>c&&(n.push(u),c=u)},e.prototype.createFeature_=function(t,e,r){var n,i=e.type;if(0===i)return null;var o,a=e.properties;this.idProperty_?(o=a[this.idProperty_],delete a[this.idProperty_]):o=e.id,a[this.layerName_]=e.layer.name;var s=[],l=[];this.readRawGeometry_(t,e,s,l);var u=function(t,e){var r;1===t?r=1===e?bt.POINT:bt.MULTI_POINT:2===t?r=1===e?bt.LINE_STRING:bt.MULTI_LINE_STRING:3===t&&(r=bt.POLYGON);return r}(i,l.length);if(this.featureClass_===Cy)(n=new this.featureClass_(u,s,l,a,o)).transform(r.dataProjection);else{var c=void 0;if(u==bt.POLYGON){for(var h=[],p=0,f=0,d=0,g=l.length;d<g;++d){var y=l[d];if(ai(s,p,y,2)){if(0===h.length)continue;h[h.length-1].push(l[f])}else h.push(l.slice(f,d+1));f=d+1,p=y}c=h.length>1?new Jy(s,yt,h):new fi(s,yt,l)}else c=u===bt.POINT?new qn(s,yt):u===bt.LINE_STRING?new Py(s,yt):u===bt.POLYGON?new fi(s,yt,l):u===bt.MULTI_POINT?new Hy(s,yt):u===bt.MULTI_LINE_STRING?new Zy(s,yt,l):null;n=new(0,this.featureClass_),this.geometryName_&&n.setGeometryName(this.geometryName_);var m=Wy(c,!1,r);n.setGeometry(m),n.setId(o),n.setProperties(a,!0)}return n},e.prototype.getType=function(){return Cu},e.prototype.readFeatures=function(t,e){var r=this.layers_,n=this.adaptOptions(e),i=Gr(n.dataProjection);i.setWorldExtent(n.extent),n.dataProjection=i;var o=new tm.a(t),a=o.readFields(rm,{}),s=[];for(var l in a)if(!r||-1!=r.indexOf(l)){var u=a[l],c=u?[0,0,u.extent,u.extent]:null;i.setExtent(c);for(var h=0,p=u.length;h<p;++h){var f=om(o,u,h);s.push(this.createFeature_(o,f,n))}}return s},e.prototype.readProjection=function(t){return this.dataProjection},e.prototype.setLayers=function(t){this.layers_=t},e}(Yy),sm=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),lm=function(t){function e(e){var r=this,n=e||{},i=O({},n);delete i.preload,delete i.useInterimTilesOnError,r=t.call(this,i)||this;var o=n.renderMode||dy;return pt(null==o||o==fy||o==dy||o==gy,28),r.renderMode_=o,r.setPreload(n.preload?n.preload:0),r.setUseInterimTilesOnError(void 0===n.useInterimTilesOnError||n.useInterimTilesOnError),r}return sm(e,t),e.prototype.createRenderer=function(){return new _y(this)},e.prototype.getFeatures=function(e){return t.prototype.getFeatures.call(this,e)},e.prototype.getRenderMode=function(){return this.renderMode_},e.prototype.getPreload=function(){return this.get(gd)},e.prototype.getUseInterimTilesOnError=function(){return this.get(yd)},e.prototype.setPreload=function(t){this.set(gd,t)},e.prototype.setUseInterimTilesOnError=function(t){this.set(yd,t)},e}(wg),um=r(2),cm=r.n(um),hm=r(0);"function"==typeof Object.assign&&Object.assign;function pm(t){return t*Math.PI/180}var fm=function(){for(var t=[],e=78271.51696402048;t.length<=24;e/=2)t.push(e);return t}();function dm(t,e){if("undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope&&"undefined"!=typeof OffscreenCanvas)return new OffscreenCanvas(t,e);var r=document.createElement("canvas");return r.width=t,r.height=e,r}var gm,ym=Array(256).join(" ");function mm(t,e){if(e>=.05){for(var r="",n=t.split("\n"),i=ym.slice(0,Math.round(e/.1)),o=0,a=n.length;o<a;++o)o>0&&(r+="\n"),r+=n[o].split("").join(i);return r}return t}function vm(){return gm||(gm=dm(1,1).getContext("2d")),gm}function _m(t,e){return vm().measureText(t).width+(t.length-1)*e}var bm={};ga&&Z(ga,k,(function(){bm={}}));var xm,wm,Sm=hm.e.isFunction,Em=hm.e.convertFunction,Tm=hm.c.isExpression,Cm=hm.c.createPropertyExpression,Om={Point:1,MultiPoint:1,LineString:2,MultiLineString:2,Polygon:3,MultiPolygon:3},Pm={center:[.5,.5],left:[0,.5],right:[1,.5],top:[.5,0],bottom:[.5,1],"top-left":[0,0],"top-right":[1,0],"bottom-left":[0,1],"bottom-right":[1,1]},Rm={},Im={zoom:0},Lm={};function Mm(t,e,r,n,i){var o=t.id;Lm[o]||(Lm[o]={});var a=Lm[o];if(!a[r]){var s=(t[e]||Rm)[r],l=hm.f[e+"_"+t.type][r];void 0===s&&(s=l.default);var u=Tm(s);if(!u&&Sm(s)&&(s=Em(s,l),u=!0),u){var c=function(t,e){var r=Cm(t,e);if("error"===r.result)throw new Error(r.value.map((function(t){return t.key+": "+t.message})).join(", "));return r.value}(s,l);a[r]=c.evaluate.bind(c)}else"color"==l.type&&(s=hm.a.parse(s)),a[r]=function(){return s}}return Im.zoom=n,a[r](Im,i)}var Fm={};function Am(t,e){if(t){if(0===t.a||0===e)return;var r=t.a;return e=void 0===e?1:e,"rgba("+Math.round(255*t.r/r)+","+Math.round(255*t.g/r)+","+Math.round(255*t.b/r)+","+r*e+")"}return t}var km=/^([^]*)\{(.*)\}([^]*)$/;function jm(t,e){var r;do{if(r=t.match(km)){var n=e[r[2]]||"";t=r[1]+n+r[3]}}while(r);return t}var Nm=!1;var Dm=function(t,e,r,n,i,o,a){if(void 0===n&&(n=fm),"string"==typeof e&&(e=JSON.parse(e)),8!=e.version)throw new Error("glStyle version 8 required.");var s,l;if(o)if("undefined"!=typeof Image){var u=new Image;u.crossOrigin="anonymous",u.onload=function(){s=u,l=[u.width,u.height],t.changed(),u.onload=null},u.src=o}else if("undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope){var c=self;c.postMessage({action:"loadImage",src:o}),c.addEventListener("message",(function(t){"imageLoaded"===t.data.action&&t.data.src===o&&(s=t.data.image,l=[s.width,s.height])}))}for(var h,p=Object(hm.b)(e.layers),f={},d=[],g=0,y=p.length;g<y;++g){var m=p[g],v=m.id;if("string"==typeof r&&m.source==r||-1!==r.indexOf(v)){var _=m["source-layer"];if(!h){h=m.source;var b=e.sources[h];if(!b)throw new Error('Source "'+h+'" is not defined');var x=b.type;if("vector"!==x&&"geojson"!==x)throw new Error('Source "'+h+'" is not of type "vector" or "geojson", but "'+x+'"')}var w=f[_];w||(w=f[_]=[]),w.push({layer:m,index:g}),d.push(v)}delete Lm[v],delete Fm[v]}var S=new gp,E=new ep,T={},C={},O=[],P=function(t,e){var r=t.getProperties(),o=f[r.layer];if(o){var u=n.indexOf(e);-1==u&&(u=function(t,e){for(var r=0,n=e.length;r<n;++r){if(e[r]<t&&r+1<n){var i=e[r]/e[r+1];return r+Math.log(e[r]/t)/Math.log(i)}}return n-1}(e,n));for(var c,h=Om[t.getGeometry().getType()],p={properties:r,type:h},d=-1,g=function(n,f){var g=o[n],y=g.layer,m=y.id,v=y.layout||Rm,_=y.paint||Rm;if("none"===v.visibility||"minzoom"in y&&u<y.minzoom||"maxzoom"in y&&u>=y.maxzoom)return"continue";var b=y.filter;if(!b||function(t,e,r,n){return t in Fm||(Fm[t]=Object(hm.d)(e).filter),Im.zoom=n,Fm[t](Im,r)}(m,b,p,u)){c=y;var x=void 0,w=void 0,P=void 0,R=void 0,I=void 0,L=void 0,M=g.index;if(3==h&&("fill"==y.type||"fill-extrusion"==y.type))if(w=Mm(y,"paint",y.type+"-opacity",u,p),y.type+"-pattern"in _){var F=Mm(y,"paint",y.type+"-pattern",u,p);if(F){var A="string"==typeof F?jm(F,r):F.toString();if(s&&i&&i[A]){++d,(L=O[d])&&L.getFill()&&!L.getStroke()&&!L.getText()||(L=O[d]=new wp({fill:new ep})),P=L.getFill(),L.setZIndex(M);var k=C[ut=A+"."+w];if(!k)(pt=(ht=dm((ct=i[A]).width,ct.height)).getContext("2d")).globalAlpha=w,pt.drawImage(s,ct.x,ct.y,ct.width,ct.height,0,0,ct.width,ct.height),k=pt.createPattern(ht,"repeat"),C[ut]=k;P.setColor(k)}}}else(x=Am(Mm(y,"paint",y.type+"-color",u,p),w))&&(y.type+"-outline-color"in _&&(I=Am(Mm(y,"paint",y.type+"-outline-color",u,p),w)),I||(I=x),++d,(L=O[d])&&L.getFill()&&L.getStroke()&&!L.getText()||(L=O[d]=new wp({fill:new ep,stroke:new gp})),(P=L.getFill()).setColor(x),(R=L.getStroke()).setColor(I),R.setWidth(1),L.setZIndex(M));if(1!=h&&"line"==y.type){x=!("line-pattern"in _)&&"line-color"in _?Am(Mm(y,"paint","line-color",u,p),Mm(y,"paint","line-opacity",u,p)):void 0;var j=Mm(y,"paint","line-width",u,p);x&&j>0&&(++d,(L=O[d])&&L.getStroke()&&!L.getFill()&&!L.getText()||(L=O[d]=new wp({stroke:new gp})),(R=L.getStroke()).setLineCap(Mm(y,"layout","line-cap",u,p)),R.setLineJoin(Mm(y,"layout","line-join",u,p)),R.setMiterLimit(Mm(y,"layout","line-miter-limit",u,p)),R.setColor(x),R.setWidth(j),R.setLineDash(_["line-dasharray"]?Mm(y,"paint","line-dasharray",u,p).map((function(t){return t*j})):null),L.setZIndex(M))}var N=!1,D=null,G=0,z=void 0,U=void 0,B=void 0;if((1==h||2==h)&&"icon-image"in v){var V=Mm(y,"layout","icon-image",u,p);if(V){z="string"==typeof V?jm(V,r):V.toString();var Y=void 0;if(s&&i&&i[z]){var W=Mm(y,"layout","icon-rotation-alignment",u,p);if(2==h){var q=t.getGeometry();if(q.getFlatMidpoint||q.getFlatMidpoints){var X=q.getExtent();if(Math.sqrt(Math.max(Math.pow((X[2]-X[0])/e,2),Math.pow((X[3]-X[1])/e,2)))>150){var Z="MultiLineString"===q.getType()?q.getFlatMidpoints():q.getFlatMidpoint();if(wm||(wm=new Cy("Point",xm=[NaN,NaN],[],{},null)),Y=wm,xm[0]=Z[0],xm[1]=Z[1],"line"===(Mt=Mm(y,"layout","symbol-placement",u,p))&&"map"===W)for(var K=q.getStride(),H=q.getFlatCoordinates(),$=0,J=H.length-K;$<J;$+=K){var Q=H[$],tt=H[$+1],et=H[$+K],rt=H[$+K+1],nt=Math.min(Q,et),it=Math.min(tt,rt),ot=Math.max(Q,et),at=Math.max(tt,rt);if(Z[0]>=nt&&Z[0]<=ot&&Z[1]>=it&&Z[1]<=at){G=Math.atan2(tt-rt,et-Q);break}}}}}if(2!==h||Y){++d,(L=O[d])&&L.getImage()&&!L.getFill()&&!L.getStroke()||(L=O[d]=new wp),L.setGeometry(Y);var st=Mm(y,"layout","icon-size",u,p),lt=void 0!==_["icon-color"]?Mm(y,"paint","icon-color",u,p):null,ut=z+"."+st;if(null!==lt&&(ut+="."+lt),!(U=T[ut])){var ct=i[z];if(null!==lt){var ht,pt;(pt=(ht=dm(ct.width,ct.height)).getContext("2d")).drawImage(s,ct.x,ct.y,ct.width,ct.height,0,0,ct.width,ct.height);for(var ft=pt.getImageData(0,0,ht.width,ht.height),dt=0,gt=ft.data.length;dt<gt;dt+=4){var yt=lt.a;0!==yt&&(ft.data[dt]=255*lt.r/yt,ft.data[dt+1]=255*lt.g/yt,ft.data[dt+2]=255*lt.b/yt),ft.data[dt+3]=yt}pt.putImageData(ft,0,0),U=T[ut]=new dp({img:ht,imgSize:[ht.width,ht.height],scale:st/ct.pixelRatio})}else U=T[ut]=new dp({img:s,imgSize:l,size:[ct.width,ct.height],offset:[ct.x,ct.y],rotateWithView:"map"===W,scale:st/ct.pixelRatio})}U.setRotation(G+pm(Mm(y,"layout","icon-rotate",u,p))),U.setOpacity(Mm(y,"paint","icon-opacity",u,p)),U.setAnchor(Pm[Mm(y,"layout","icon-anchor",u,p)]),L.setImage(U),D=L.getText(),L.setText(void 0),L.setZIndex(M),N=!0,B=!1}else B=!0}}}if(1==h&&"circle-radius"in _){++d,(L=O[d])&&L.getImage()&&!L.getFill()&&!L.getStroke()||(L=O[d]=new wp);var mt=Mm(y,"paint","circle-radius",u,p),vt=Am(Mm(y,"paint","circle-stroke-color",u,p),Mm(y,"paint","circle-stroke-opacity",u,p)),_t=Am(Mm(y,"paint","circle-color",u,p),Mm(y,"paint","circle-opacity",u,p)),bt=Mm(y,"paint","circle-stroke-width",u,p),xt=mt+"."+vt+"."+_t+"."+bt;(U=T[xt])||(U=T[xt]=new tp({radius:mt,stroke:vt&&bt>0?new gp({width:bt,color:vt}):void 0,fill:_t?new ep({color:_t}):void 0})),L.setImage(U),D=L.getText(),L.setText(void 0),L.setGeometry(void 0),L.setZIndex(M),N=!0}var wt=void 0;if("text-field"in v)wt=jm(Mm(y,"layout","text-field",u,p).toString(),r).trim(),w=Mm(y,"paint","text-opacity",u,p);if(wt&&w&&!B){N||(++d,(L=O[d])&&L.getText()&&!L.getFill()&&!L.getStroke()||(L=O[d]=new wp),L.setImage(void 0),L.setGeometry(void 0)),L.getText()||L.setText(D||new Tp({padding:[2,2,2,2]})),D=L.getText();var St=Math.round(Mm(y,"layout","text-size",u,p)),Et=Mm(y,"layout","text-font",u,p),Tt=Mm(y,"layout","text-line-height",u,p),Ct=cm()(a?a(Et):Et,St,Tt),Ot=v["text-transform"];"uppercase"==Ot?wt=wt.toUpperCase():"lowercase"==Ot&&(wt=wt.toLowerCase());var Pt=Mm(y,"layout","text-max-width",u,p),Rt=Mm(y,"layout","text-letter-spacing",u,p),It=2==h?mm(wt,Rt):function t(e,r,n,i){if(-1!==e.indexOf("\n")){for(var o=e.split("\n"),a=[],s=0,l=o.length;s<l;++s)a.push(t(o[s],r,n,i));return a.join("\n")}var u=n+","+r+","+e+","+i,c=bm[u];if(!c){var h=e.split(" ");if(h.length>1){var p=vm();p.font=r;var f=p.measureText("M").width*n,d="";for(a=[],s=0,l=h.length;s<l;++s){var g=h[s],y=d+(d?" ":"")+g;_m(y,i)<=f?d=y:(d&&a.push(d),d=g)}d&&a.push(d);for(s=0,l=a.length;s<l&&l>1;++s){var m=a[s];if(_m(m,i)<.35*f){var v=s>0?_m(a[s-1],i):1/0,_=s<l-1?_m(a[s+1],i):1/0;a.splice(s,1),l-=1,v<_?(a[s-1]+=" "+m,s-=1):a[s]=m+" "+a[s]}}for(s=0,l=a.length-1;s<l;++s){var b=a[s],x=a[s+1];if(_m(b,i)>.7*f&&_m(x,i)<.6*f){var w=b.split(" "),S=w.pop();_m(S,i)<.2*f&&(a[s]=w.join(" "),a[s+1]=S+" "+x),l-=1}}c=a.join("\n")}else c=e;c=mm(c,i),bm[u]=c}return c}(wt,Ct,Pt,Rt);D.setText(It),D.setFont(Ct),D.setRotation(pm(Mm(y,"layout","text-rotate",u,p)));var Lt=Mm(y,"layout","text-anchor",u,p),Mt=N||1==h?"point":Mm(y,"layout","symbol-placement",u,p);D.setPlacement(Mt);var Ft=Mm(y,"paint","text-halo-width",u,p),At=Mm(y,"layout","text-offset",u,p),kt=Mm(y,"paint","text-translate",u,p),jt=0,Nt=0;if("point"==Mt){var Dt="center";-1!==Lt.indexOf("left")?(Dt="left",Nt=Ft):-1!==Lt.indexOf("right")&&(Dt="right",Nt=-Ft),D.setTextAlign(Dt);var Gt=Mm(y,"layout","text-rotation-alignment",u,p);D.setRotateWithView("map"==Gt)}else D.setMaxAngle(pm(Mm(y,"layout","text-max-angle",u,p))*wt.length/It.length),D.setTextAlign(),D.setRotateWithView(!1);var zt="middle";0==Lt.indexOf("bottom")?(zt="bottom",jt=-Ft-.5*(Tt-1)*St):0==Lt.indexOf("top")&&(zt="top",jt=Ft+.5*(Tt-1)*St),D.setTextBaseline(zt),D.setOffsetX(At[0]*St+Nt+kt[0]),D.setOffsetY(At[1]*St+jt+kt[1]),E.setColor(Am(Mm(y,"paint","text-color",u,p),w)),D.setFill(E);var Ut=Am(Mm(y,"paint","text-halo-color",u,p),w);if(Ut){S.setColor(Ut),Ft*=2;var Bt=.5*St;S.setWidth(Ft<=Bt?Ft:Bt),D.setStroke(S)}else D.setStroke(void 0);var Vt=Mm(y,"layout","text-padding",u,p),Yt=D.getPadding();Vt!==Yt[0]&&(Yt[0]=Yt[1]=Yt[2]=Yt[3]=Vt),L.setZIndex(M)}}},y=0,m=o.length;y<m;++y)g(y);return d>-1?(O.length=d+1,Nm&&("function"==typeof t.set?t.set("mapbox-layer",c):t.getProperties()["mapbox-layer"]=c),O):void 0}};return t.setStyle(P),t.set("mapbox-source",h),t.set("mapbox-layers",d),P},Gm=r(6),zm=r.n(Gm),Um=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Bm(t){for(var e=[],r=0,n=t.length;r<n;++r)e.push(t[r].clone());return e}var Vm=function(t){function e(e){var r=t.call(this)||this;return r.geometries_=e||null,r.changeEventsKeys_=[],r.listenGeometriesChange_(),r}return Um(e,t),e.prototype.unlistenGeometriesChange_=function(){this.changeEventsKeys_.forEach(H),this.changeEventsKeys_.length=0},e.prototype.listenGeometriesChange_=function(){if(this.geometries_)for(var t=0,e=this.geometries_.length;t<e;++t)this.changeEventsKeys_.push(Z(this.geometries_[t],F,this.changed,this))},e.prototype.clone=function(){var t=new e(null);return t.setGeometries(this.geometries_),t.applyProperties(this),t},e.prototype.closestPointXY=function(t,e,r,n){if(n<Jt(this.getExtent(),t,e))return n;for(var i=this.geometries_,o=0,a=i.length;o<a;++o)n=i[o].closestPointXY(t,e,r,n);return n},e.prototype.containsXY=function(t,e){for(var r=this.geometries_,n=0,i=r.length;n<i;++n)if(r[n].containsXY(t,e))return!0;return!1},e.prototype.computeExtent=function(t){oe(t);for(var e=this.geometries_,r=0,n=e.length;r<n;++r)he(t,e[r].getExtent());return t},e.prototype.getGeometries=function(){return Bm(this.geometries_)},e.prototype.getGeometriesArray=function(){return this.geometries_},e.prototype.getGeometriesArrayRecursive=function(){for(var t=[],e=this.geometries_,r=0,n=e.length;r<n;++r)e[r].getType()===this.getType()?t=t.concat(e[r].getGeometriesArrayRecursive()):t.push(e[r]);return t},e.prototype.getSimplifiedGeometry=function(t){if(this.simplifiedGeometryRevision!==this.getRevision()&&(this.simplifiedGeometryMaxMinSquaredTolerance=0,this.simplifiedGeometryRevision=this.getRevision()),t<0||0!==this.simplifiedGeometryMaxMinSquaredTolerance&&t<this.simplifiedGeometryMaxMinSquaredTolerance)return this;for(var r=[],n=this.geometries_,i=!1,o=0,a=n.length;o<a;++o){var s=n[o],l=s.getSimplifiedGeometry(t);r.push(l),l!==s&&(i=!0)}if(i){var u=new e(null);return u.setGeometriesArray(r),u}return this.simplifiedGeometryMaxMinSquaredTolerance=t,this},e.prototype.getType=function(){return bt.GEOMETRY_COLLECTION},e.prototype.intersectsExtent=function(t){for(var e=this.geometries_,r=0,n=e.length;r<n;++r)if(e[r].intersectsExtent(t))return!0;return!1},e.prototype.isEmpty=function(){return 0===this.geometries_.length},e.prototype.rotate=function(t,e){for(var r=this.geometries_,n=0,i=r.length;n<i;++n)r[n].rotate(t,e);this.changed()},e.prototype.scale=function(t,e,r){var n=r;n||(n=xe(this.getExtent()));for(var i=this.geometries_,o=0,a=i.length;o<a;++o)i[o].scale(t,e,n);this.changed()},e.prototype.setGeometries=function(t){this.setGeometriesArray(Bm(t))},e.prototype.setGeometriesArray=function(t){this.unlistenGeometriesChange_(),this.geometries_=t,this.listenGeometriesChange_(),this.changed()},e.prototype.applyTransform=function(t){for(var e=this.geometries_,r=0,n=e.length;r<n;++r)e[r].applyTransform(t);this.changed()},e.prototype.translate=function(t,e){for(var r=this.geometries_,n=0,i=r.length;n<i;++n)r[n].translate(t,e);this.changed()},e.prototype.disposeInternal=function(){this.unlistenGeometriesChange_(),t.prototype.disposeInternal.call(this)},e}(dn),Ym=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Wm(t){if("string"==typeof t){var e=JSON.parse(t);return e||null}return null!==t?t:null}var qm=function(t){function e(){return t.call(this)||this}return Ym(e,t),e.prototype.getType=function(){return Ou},e.prototype.readFeature=function(t,e){return this.readFeatureFromObject(Wm(t),this.getReadOptions(t,e))},e.prototype.readFeatures=function(t,e){return this.readFeaturesFromObject(Wm(t),this.getReadOptions(t,e))},e.prototype.readFeatureFromObject=function(t,e){return n()},e.prototype.readFeaturesFromObject=function(t,e){return n()},e.prototype.readGeometry=function(t,e){return this.readGeometryFromObject(Wm(t),this.getReadOptions(t,e))},e.prototype.readGeometryFromObject=function(t,e){return n()},e.prototype.readProjection=function(t){return this.readProjectionFromObject(Wm(t))},e.prototype.readProjectionFromObject=function(t){return n()},e.prototype.writeFeature=function(t,e){return JSON.stringify(this.writeFeatureObject(t,e))},e.prototype.writeFeatureObject=function(t,e){return n()},e.prototype.writeFeatures=function(t,e){return JSON.stringify(this.writeFeaturesObject(t,e))},e.prototype.writeFeaturesObject=function(t,e){return n()},e.prototype.writeGeometry=function(t,e){return JSON.stringify(this.writeGeometryObject(t,e))},e.prototype.writeGeometryObject=function(t,e){return n()},e}(Yy),Xm=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Zm(t,e){if(!t)return null;var r;switch(t.type){case bt.POINT:r=function(t){return new qn(t.coordinates)}(t);break;case bt.LINE_STRING:r=function(t){return new Py(t.coordinates)}(t);break;case bt.POLYGON:r=function(t){return new fi(t.coordinates)}(t);break;case bt.MULTI_POINT:r=function(t){return new Hy(t.coordinates)}(t);break;case bt.MULTI_LINE_STRING:r=function(t){return new Zy(t.coordinates)}(t);break;case bt.MULTI_POLYGON:r=function(t){return new Jy(t.coordinates)}(t);break;case bt.GEOMETRY_COLLECTION:r=function(t,e){var r=t.geometries.map((function(t){return Zm(t,e)}));return new Vm(r)}(t);break;default:throw new Error("Unsupported GeoJSON type: "+t.type)}return Wy(r,!1,e)}function Km(t,e){var r,n=(t=Wy(t,!0,e)).getType();switch(n){case bt.POINT:r=function(t,e){return{type:"Point",coordinates:t.getCoordinates()}}(t);break;case bt.LINE_STRING:r=function(t,e){return{type:"LineString",coordinates:t.getCoordinates()}}(t);break;case bt.POLYGON:r=function(t,e){var r;e&&(r=e.rightHanded);return{type:"Polygon",coordinates:t.getCoordinates(r)}}(t,e);break;case bt.MULTI_POINT:r=function(t,e){return{type:"MultiPoint",coordinates:t.getCoordinates()}}(t);break;case bt.MULTI_LINE_STRING:r=function(t,e){return{type:"MultiLineString",coordinates:t.getCoordinates()}}(t);break;case bt.MULTI_POLYGON:r=function(t,e){var r;e&&(r=e.rightHanded);return{type:"MultiPolygon",coordinates:t.getCoordinates(r)}}(t,e);break;case bt.GEOMETRY_COLLECTION:r=function(t,e){return{type:"GeometryCollection",geometries:t.getGeometriesArray().map((function(t){var r=O({},e);return delete r.featureProjection,Km(t,r)}))}}(t,e);break;case bt.CIRCLE:r={type:"GeometryCollection",geometries:[]};break;default:throw new Error("Unsupported geometry type: "+n)}return r}var Hm,$m=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this)||this).dataProjection=Gr(n.dataProjection?n.dataProjection:"EPSG:4326"),n.featureProjection&&(r.defaultFeatureProjection=Gr(n.featureProjection)),r.geometryName_=n.geometryName,r.extractGeometryName_=n.extractGeometryName,r}return Xm(e,t),e.prototype.readFeatureFromObject=function(t,e){var r=null,n=Zm((r="Feature"===t.type?t:{type:"Feature",geometry:t,properties:null}).geometry,e),i=new gt;return this.geometryName_?i.setGeometryName(this.geometryName_):this.extractGeometryName_&&"geometry_name"in r!==void 0&&i.setGeometryName(r.geometry_name),i.setGeometry(n),"id"in r&&i.setId(r.id),r.properties&&i.setProperties(r.properties,!0),i},e.prototype.readFeaturesFromObject=function(t,e){var r=null;if("FeatureCollection"===t.type){r=[];for(var n=t.features,i=0,o=n.length;i<o;++i)r.push(this.readFeatureFromObject(n[i],e))}else r=[this.readFeatureFromObject(t,e)];return r},e.prototype.readGeometryFromObject=function(t,e){return Zm(t,e)},e.prototype.readProjectionFromObject=function(t){var e,r=t.crs;return r?"name"==r.type?e=Gr(r.properties.name):"EPSG"===r.type?e=Gr("EPSG:"+r.properties.code):pt(!1,36):e=this.dataProjection,e},e.prototype.writeFeatureObject=function(t,e){e=this.adaptOptions(e);var r={type:"Feature",geometry:null,properties:null},n=t.getId();if(void 0!==n&&(r.id=n),!t.hasProperties())return r;var i=t.getProperties(),o=t.getGeometry();return o&&(r.geometry=Km(o,e),delete i[t.getGeometryName()]),I(i)||(r.properties=i),r},e.prototype.writeFeaturesObject=function(t,e){e=this.adaptOptions(e);for(var r=[],n=0,i=t.length;n<i;++n)r.push(this.writeFeatureObject(t[n],e));return{type:"FeatureCollection",features:r}},e.prototype.writeGeometryObject=function(t,e){return Km(t,this.adaptOptions(e))},e}(qm),Jm=/font-family: ?([^;]*);/,Qm=/("|')/g;function tv(t){if(!Hm){Hm={};for(var e=document.styleSheets,r=0,n=e.length;r<n;++r){var i=e[r];try{var o=i.rules||i.cssRules;if(o)for(var a=0,s=o.length;a<s;++a){var l=o[a];if(5==l.type){var u=l.cssText.match(Jm);Hm[u[1].replace(Qm,"")]=!0}}}catch(t){}}}return t in Hm}var ev={},rv=zm.a.getNames();function nv(t){var e=t.toString();if(e in ev)return t;for(var r=t.map((function(t){var e=cm()(t,1).split(" ");return[e.slice(3).join(" ").replace(/"/g,""),e[1]+e[0]]})),n=0,i=r.length;n<i;++n){var o=r[n],a=o[0];if(!tv(a)&&-1!==rv.indexOf(a)){var s="https://fonts.googleapis.com/css?family="+a.replace(/ /g,"+")+":"+o[1];if(!document.querySelector('link[href="'+s+'"]')){var l=document.createElement("link");l.href=s,l.rel="stylesheet",document.head.appendChild(l)}}}return ev[e]=!0,t}var iv=/^(.*)(\?.*)$/;function ov(t,e){return e&&0===t.indexOf(".")&&(t=e+t),t}function av(t,e,r){var n=(t=ov(t,e)).match(iv);return n?n[1]+r+(n.length>2?n[2]:""):t+r}function sv(t,e,r,n,i){return new Promise((function(o,a){if("object"!=typeof e&&(e=JSON.parse(e)),8!=e.version)return a(new Error("glStyle version 8 required."));if(!(t instanceof Iy||t instanceof lm))return a(new Error("Can only apply to VectorLayer or VectorTileLayer"));var s,l,u;function c(){u||e.sprite&&!s?u?(t.setStyle(u),o()):a(new Error("Something went wrong trying to apply style.")):(u=Dm(t,e,r,i,s,l,nv),t.getStyle()?o():a(new Error("Nothing to show for source ["+r+"]")))}if(e.sprite){var h=.5==(window.devicePixelRatio>=1.5?.5:1)?"@2x":"",p=av(e.sprite,n,h+".json");fetch(p,{credentials:"same-origin"}).then((function(t){return t.ok||""===h?t:(p=av(e.sprite,n,".json"),fetch(p,{credentials:"same-origin"}))})).then((function(t){if(t.ok)return t.json();a(new Error("Problem fetching sprite from "+p+": "+t.statusText))})).then((function(t){if(void 0===t)return a(new Error("No sprites found."));s=t,l=av(e.sprite,n,h+".png"),c()})).catch((function(t){a(new Error("Sprites cannot be loaded: "+p+": "+t.message))}))}else c()}))}new $m;var lv=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function uv(t){return 0!==t.indexOf("mapbox://")?"":t.slice("mapbox://".length)}function cv(t,e){var r=uv(t);if(!r)return t;if(0!==r.indexOf("sprites/"))throw new Error("unexpected sprites url: "+t);return"https://api.mapbox.com/styles/v1/"+r.slice("sprites/".length)+"/sprite?access_token="+e}function hv(t,e){var r=uv(t);if(!r)return t;if(0!==r.indexOf("fonts/"))throw new Error("unexpected fonts url: "+t);return"https://api.mapbox.com/fonts/v1/"+r.slice("fonts/".length)+"/0-255.pbf?access_token="+e}function pv(t,e){var r=uv(t);if(!r)return t;if(0!==r.indexOf("styles/"))throw new Error("unexpected style url: "+t);return"https://api.mapbox.com/styles/v1/"+r.slice("styles/".length)+"?&access_token="+e}function fv(t,e){var r=uv(t);return r?"https://{a-d}.tiles.mapbox.com/v4/"+r+"/{z}/{x}/{y}.vector.pbf?access_token="+e:t}var dv=function(t){function e(e){var r=t.call(this,A)||this;return r.error=e,r}return lv(e,t),e}(c),gv="vector",yv=function(t){function e(e){var r=this,n=!("declutter"in e)||e.declutter,i=new og({state:Jo,format:new am});return(r=t.call(this,{source:i,declutter:n,className:e.className,opacity:e.opacity,visible:e.visible,zIndex:e.zIndex,minResolution:e.minResolution,maxResolution:e.maxResolution,minZoom:e.minZoom,maxZoom:e.maxZoom,renderOrder:e.renderOrder,renderBuffer:e.renderBuffer,renderMode:e.renderMode,map:e.map,updateWhileAnimating:e.updateWhileAnimating,updateWhileInteracting:e.updateWhileInteracting,preload:e.preload,useInterimTilesOnError:e.useInterimTilesOnError})||this).sourceId=e.source,r.layers=e.layers,r.accessToken=e.accessToken,r.fetchStyle(e.styleUrl),r}return lv(e,t),e.prototype.fetchStyle=function(t){var e=this,r=pv(t,this.accessToken);fetch(r).then((function(t){if(!t.ok)throw new Error("unexpected response when fetching style: "+t.status);return t.json()})).then((function(t){e.onStyleLoad(t)})).catch((function(t){e.handleError(t)}))},e.prototype.onStyleLoad=function(t){var e,r,n=this;if(this.layers){for(var i={},o=0;o<t.layers.length;++o){var a=t.layers[o];a.source&&(i[a.id]=a.source)}var s=void 0;for(o=0;o<this.layers.length;++o){var l=i[this.layers[o]];if(!l)return void this.handleError(new Error("could not find source for "+this.layers[o]));if(s){if(s!==l)return void this.handleError(new Error("layers can only use a single source, found "+s+" and "+l))}else s=l}e=s,r=this.layers}else r=e=this.sourceId;r||(r=e=Object.keys(t.sources)[0]),t.sprite&&(t.sprite=cv(t.sprite,this.accessToken)),t.glyphs&&(t.glyphs=hv(t.glyphs,this.accessToken));var u=t.sources[e];if(u.type===gv){var c=this.getSource();c.setUrl(fv(u.url,this.accessToken)),sv(this,t,r).then((function(){c.setState(Qo)})).catch((function(t){n.handleError(t)}))}else this.handleError(new Error("only works for vector sources, found "+u.type))},e.prototype.handleError=function(t){this.dispatchEvent(new dv(t)),this.getSource().setState(ta)},e}(lm),mv=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),vv=function(t){function e(e){var r=this,n=e||{},i=O({},n);return delete i.imageRatio,(r=t.call(this,i)||this).imageRatio_=void 0!==n.imageRatio?n.imageRatio:1,r}return mv(e,t),e.prototype.getImageRatio=function(){return this.imageRatio_},e.prototype.createRenderer=function(){return new py(this)},e}(wg),_v=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),bv=function(t){function e(e){var r=this,n=O({},e);return(r=t.call(this,n)||this).parseResult_=Wh(e.style),r.hitDetectionDisabled_=!!e.disableHitDetection,r}return _v(e,t),e.prototype.createRenderer=function(){return new Eg(this,{className:this.getClassName(),vertexShader:this.parseResult_.builder.getSymbolVertexShader(),fragmentShader:this.parseResult_.builder.getSymbolFragmentShader(),hitVertexShader:!this.hitDetectionDisabled_&&this.parseResult_.builder.getSymbolVertexShader(!0),hitFragmentShader:!this.hitDetectionDisabled_&&this.parseResult_.builder.getSymbolFragmentShader(!0),uniforms:this.parseResult_.uniforms,attributes:this.parseResult_.attributes})},e.prototype.disposeInternal=function(){this.getRenderer().disposeInternal(),t.prototype.disposeInternal.call(this)},e}(na),xv=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),wv="addfeatures",Sv=function(t){function e(e,r,n,i){var o=t.call(this,e)||this;return o.features=n,o.file=r,o.projection=i,o}return xv(e,t),e}(c),Ev=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,{handleEvent:S})||this).readAsBuffer_=!1,r.formats_=[];for(var i=n.formatConstructors?n.formatConstructors:[],o=0,a=i.length;o<a;++o){var s=i[o];"function"==typeof s&&(s=new s),r.formats_.push(s),r.readAsBuffer_=r.readAsBuffer_||s.getType()===Cu}return r.projection_=n.projection?Gr(n.projection):null,r.dropListenKeys_=null,r.source_=n.source||null,r.target=n.target?n.target:null,r}return xv(e,t),e.prototype.handleResult_=function(t,e){var r,n=e.target.result,i=this.getMap(),o=this.projection_;o||(o=i.getView().getProjection());for(var a=this.formats_,s=0,l=a.length;s<l;++s){var u=a[s],c=n;this.readAsBuffer_&&u.getType()!==Cu&&(void 0===r&&(r=(new TextDecoder).decode(n)),c=r);var h=this.tryReadFeatures_(u,c,{featureProjection:o});if(h&&h.length>0){this.source_&&(this.source_.clear(),this.source_.addFeatures(h)),this.dispatchEvent(new Sv(wv,t,h,o));break}}},e.prototype.registerListeners_=function(){var t=this.getMap();if(t){var e=this.target?this.target:t.getViewport();this.dropListenKeys_=[Z(e,U,this.handleDrop,this),Z(e,G,this.handleStop,this),Z(e,z,this.handleStop,this),Z(e,U,this.handleStop,this)]}},e.prototype.setActive=function(e){!this.getActive()&&e&&this.registerListeners_(),this.getActive()&&!e&&this.unregisterListeners_(),t.prototype.setActive.call(this,e)},e.prototype.setMap=function(e){this.unregisterListeners_(),t.prototype.setMap.call(this,e),this.getActive()&&this.registerListeners_()},e.prototype.tryReadFeatures_=function(t,e,r){try{return t.readFeatures(e,r)}catch(t){return null}},e.prototype.unregisterListeners_=function(){this.dropListenKeys_&&(this.dropListenKeys_.forEach(H),this.dropListenKeys_=null)},e.prototype.handleDrop=function(t){for(var e=t.dataTransfer.files,r=0,n=e.length;r<n;++r){var i=e.item(r),o=new FileReader;o.addEventListener(Y,this.handleResult_.bind(this,i)),this.readAsBuffer_?o.readAsArrayBuffer(i):o.readAsText(i)}},e.prototype.handleStop=function(t){t.stopPropagation(),t.preventDefault(),t.dataTransfer.dropEffect="copy"},e}(qs),Tv=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Cv=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,n)||this).condition_=n.condition?n.condition:ll,r.lastAngle_=void 0,r.lastMagnitude_=void 0,r.lastScaleDelta_=0,r.duration_=void 0!==n.duration?n.duration:400,r}return Tv(e,t),e.prototype.handleDragEvent=function(t){if(cl(t)){var e=t.map,r=e.getSize(),n=t.pixel,i=n[0]-r[0]/2,o=r[1]/2-n[1],a=Math.atan2(o,i),s=Math.sqrt(i*i+o*o),l=e.getView();if(void 0!==this.lastAngle_){var u=this.lastAngle_-a;l.adjustRotationInternal(u)}this.lastAngle_=a,void 0!==this.lastMagnitude_&&l.adjustResolutionInternal(this.lastMagnitude_/s),void 0!==this.lastMagnitude_&&(this.lastScaleDelta_=this.lastMagnitude_/s),this.lastMagnitude_=s}},e.prototype.handleUpEvent=function(t){if(!cl(t))return!0;var e=t.map.getView(),r=this.lastScaleDelta_>1?1:-1;return e.endInteraction(this.duration_,r),this.lastScaleDelta_=0,!1},e.prototype.handleDownEvent=function(t){return!!cl(t)&&(!!this.condition_(t)&&(t.map.getView().beginInteraction(),this.lastAngle_=void 0,this.lastMagnitude_=void 0,!0))},e}($s),Ov=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Pv=function(t){function e(e,r,n){var i=t.call(this)||this;if(void 0!==n&&void 0===r)i.setFlatCoordinates(n,e);else{var o=r||0;i.setCenterAndRadius(e,o,n)}return i}return Ov(e,t),e.prototype.clone=function(){var t=new e(this.flatCoordinates.slice(),void 0,this.layout);return t.applyProperties(this),t},e.prototype.closestPointXY=function(t,e,r,n){var i=this.flatCoordinates,o=t-i[0],a=e-i[1],s=o*o+a*a;if(s<n){if(0===s)for(var l=0;l<this.stride;++l)r[l]=i[l];else{var u=this.getRadius()/Math.sqrt(s);r[0]=i[0]+u*o,r[1]=i[1]+u*a;for(l=2;l<this.stride;++l)r[l]=i[l]}return r.length=this.stride,s}return n},e.prototype.containsXY=function(t,e){var r=this.flatCoordinates,n=t-r[0],i=e-r[1];return n*n+i*i<=this.getRadiusSquared_()},e.prototype.getCenter=function(){return this.flatCoordinates.slice(0,this.stride)},e.prototype.computeExtent=function(t){var e=this.flatCoordinates,r=e[this.stride]-e[0];return ie(e[0]-r,e[1]-r,e[0]+r,e[1]+r,t)},e.prototype.getRadius=function(){return Math.sqrt(this.getRadiusSquared_())},e.prototype.getRadiusSquared_=function(){var t=this.flatCoordinates[this.stride]-this.flatCoordinates[0],e=this.flatCoordinates[this.stride+1]-this.flatCoordinates[1];return t*t+e*e},e.prototype.getType=function(){return bt.CIRCLE},e.prototype.intersectsExtent=function(t){if(Re(t,this.getExtent())){var e=this.getCenter();return t[0]<=e[0]&&t[2]>=e[0]||(t[1]<=e[1]&&t[3]>=e[1]||me(t,this.intersectsCoordinate.bind(this)))}return!1},e.prototype.setCenter=function(t){var e=this.stride,r=this.flatCoordinates[e]-this.flatCoordinates[0],n=t.slice();n[e]=n[0]+r;for(var i=1;i<e;++i)n[e+i]=t[i];this.setFlatCoordinates(this.layout,n),this.changed()},e.prototype.setCenterAndRadius=function(t,e,r){this.setLayout(r,t,0),this.flatCoordinates||(this.flatCoordinates=[]);var n=this.flatCoordinates,i=Cn(n,0,t,this.stride);n[i++]=n[0]+e;for(var o=1,a=this.stride;o<a;++o)n[i++]=n[o];n.length=i,this.changed()},e.prototype.getCoordinates=function(){return null},e.prototype.setCoordinates=function(t,e){},e.prototype.setRadius=function(t){this.flatCoordinates[this.stride]=this.flatCoordinates[0]+t,this.changed()},e.prototype.rotate=function(t,e){var r=this.getCenter(),n=this.getStride();this.setCenter(un(r,0,r.length,n,t,e,r)),this.changed()},e.prototype.translate=function(t,e){var r=this.getCenter(),n=this.getStride();this.setCenter(hn(r,0,r.length,n,t,e,r)),this.changed()},e}(vn);Pv.prototype.transform;var Rv=Pv,Iv=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Lv="Point",Mv="LineString",Fv="Polygon",Av="Circle",kv="drawstart",jv="drawend",Nv="drawabort",Dv=function(t){function e(e,r){var n=t.call(this,e)||this;return n.feature=r,n}return Iv(e,t),e}(c);var Gv=function(t){function e(e){var r=this,n=e;n.stopDown||(n.stopDown=E),(r=t.call(this,n)||this).shouldHandle_=!1,r.downPx_=null,r.downTimeout_,r.lastDragTime_,r.pointerType_,r.freehand_=!1,r.source_=e.source?e.source:null,r.features_=e.features?e.features:null,r.snapTolerance_=e.snapTolerance?e.snapTolerance:12,r.type_=e.type,r.mode_=function(t){var e;t===bt.POINT||t===bt.MULTI_POINT?e=Lv:t===bt.LINE_STRING||t===bt.MULTI_LINE_STRING?e=Mv:t===bt.POLYGON||t===bt.MULTI_POLYGON?e=Fv:t===bt.CIRCLE&&(e=Av);return e}(r.type_),r.stopClick_=!!e.stopClick,r.minPoints_=e.minPoints?e.minPoints:r.mode_===Fv?3:2,r.maxPoints_=r.mode_===Av?2:e.maxPoints?e.maxPoints:1/0,r.finishCondition_=e.finishCondition?e.finishCondition:S;var i,o=e.geometryFunction;if(!o){var a,s=r.mode_;if(s===Av)o=function(t,e,r){var n=e||new Rv([NaN,NaN]),i=rn(t[0],r),o=Rr(i,rn(t[t.length-1],r));n.setCenterAndRadius(i,Math.sqrt(o));var a=tn();return a&&n.transform(r,a),n};else s===Lv?a=qn:s===Mv?a=Py:s===Fv&&(a=fi),o=function(t,e,r){return e?s===Fv?t[0].length?e.setCoordinates([t[0].concat([t[0][0]])]):e.setCoordinates([]):e.setCoordinates(t):e=new a(t),e}}return r.geometryFunction_=o,r.dragVertexDelay_=void 0!==e.dragVertexDelay?e.dragVertexDelay:500,r.finishCoordinate_=null,r.sketchFeature_=null,r.sketchPoint_=null,r.sketchCoords_=null,r.sketchLine_=null,r.sketchLineCoords_=null,r.squaredClickTolerance_=e.clickTolerance?e.clickTolerance*e.clickTolerance:36,r.overlay_=new Iy({source:new hf({useSpatialIndex:!1,wrapX:!!e.wrapX&&e.wrapX}),style:e.style?e.style:(i=bp(),function(t,e){return i[t.getGeometry().getType()]}),updateWhileInteracting:!0}),r.geometryName_=e.geometryName,r.condition_=e.condition?e.condition:sl,r.freehandCondition_,e.freehand?r.freehandCondition_=nl:r.freehandCondition_=e.freehandCondition?e.freehandCondition:ll,r.addEventListener(it(Bs),r.updateState_),r}return Iv(e,t),e.prototype.setMap=function(e){t.prototype.setMap.call(this,e),this.updateState_()},e.prototype.getOverlay=function(){return this.overlay_},e.prototype.handleEvent=function(e){e.originalEvent.type===j&&e.originalEvent.preventDefault(),this.freehand_=this.mode_!==Lv&&this.freehandCondition_(e);var r=e.type===Ga.POINTERMOVE,n=!0;!this.freehand_&&this.lastDragTime_&&e.type===Ga.POINTERDRAG&&(Date.now()-this.lastDragTime_>=this.dragVertexDelay_?(this.downPx_=e.pixel,this.shouldHandle_=!this.freehand_,r=!0):this.lastDragTime_=void 0,this.shouldHandle_&&void 0!==this.downTimeout_&&(clearTimeout(this.downTimeout_),this.downTimeout_=void 0));return this.freehand_&&e.type===Ga.POINTERDRAG&&null!==this.sketchFeature_?(this.addToDrawing_(e.coordinate),n=!1):this.freehand_&&e.type===Ga.POINTERDOWN?n=!1:r&&this.getPointerCount()<2?(n=e.type===Ga.POINTERMOVE)&&this.freehand_?(this.handlePointerMove_(e),this.shouldHandle_&&e.originalEvent.preventDefault()):("mouse"===e.originalEvent.pointerType||e.type===Ga.POINTERDRAG&&void 0===this.downTimeout_)&&this.handlePointerMove_(e):e.type===Ga.DBLCLICK&&(n=!1),t.prototype.handleEvent.call(this,e)&&n},e.prototype.handleDownEvent=function(t){return this.shouldHandle_=!this.freehand_,this.freehand_?(this.downPx_=t.pixel,this.finishCoordinate_||this.startDrawing_(t.coordinate),!0):this.condition_(t)?(this.lastDragTime_=Date.now(),this.downTimeout_=setTimeout(function(){this.handlePointerMove_(new Da(Ga.POINTERMOVE,t.map,t.originalEvent,!1,t.frameState))}.bind(this),this.dragVertexDelay_),this.downPx_=t.pixel,!0):(this.lastDragTime_=void 0,!1)},e.prototype.handleUpEvent=function(t){var e=!0;if(0===this.getPointerCount())if(this.downTimeout_&&(clearTimeout(this.downTimeout_),this.downTimeout_=void 0),this.handlePointerMove_(t),this.shouldHandle_){switch(!0){case!this.finishCoordinate_:if(this.startDrawing_(t.coordinate),this.mode_!==Lv)break;case this.freehand_||this.atFinish_(t.pixel)&&this.finishCondition_(t):this.finishDrawing();break;case!this.freehand_:this.addToDrawing_(t.coordinate)}e=!1}else this.freehand_&&this.abortDrawing();return!e&&this.stopClick_&&t.originalEvent.stopPropagation(),e},e.prototype.handlePointerMove_=function(t){if(this.pointerType_=t.originalEvent.pointerType,this.downPx_&&(!this.freehand_&&this.shouldHandle_||this.freehand_&&!this.shouldHandle_)){var e=this.downPx_,r=t.pixel,n=e[0]-r[0],i=e[1]-r[1],o=n*n+i*i;if(this.shouldHandle_=this.freehand_?o>this.squaredClickTolerance_:o<=this.squaredClickTolerance_,!this.shouldHandle_)return}this.finishCoordinate_?this.modifyDrawing_(t.coordinate):this.createOrUpdateSketchPoint_(t)},e.prototype.atFinish_=function(t){var e=!1;if(this.sketchFeature_){var r=!1,n=[this.finishCoordinate_],i=this.mode_;if(i===Lv)e=!0;else if(i===Av)e=2===this.sketchCoords_.length;else if(i===Mv)r=this.sketchCoords_.length>this.minPoints_;else if(i===Fv){var o=this.sketchCoords_;r=o[0].length>this.minPoints_,n=[o[0][0],o[0][o[0].length-2]]}if(r)for(var a=this.getMap(),s=0,l=n.length;s<l;s++){var u=n[s],c=a.getPixelFromCoordinate(u),h=t[0]-c[0],p=t[1]-c[1],f=this.freehand_?1:this.snapTolerance_;if(e=Math.sqrt(h*h+p*p)<=f){this.finishCoordinate_=u;break}}}return e},e.prototype.createOrUpdateSketchPoint_=function(t){var e=t.coordinate.slice();this.sketchPoint_?this.sketchPoint_.getGeometry().setCoordinates(e):(this.sketchPoint_=new gt(new qn(e)),this.updateSketchFeatures_())},e.prototype.createOrUpdateCustomSketchLine_=function(t){this.sketchLine_||(this.sketchLine_=new gt);var e=t.getLinearRing(0),r=this.sketchLine_.getGeometry();r?(r.setFlatCoordinates(e.getLayout(),e.getFlatCoordinates()),r.changed()):(r=new Py(e.getFlatCoordinates(),e.getLayout()),this.sketchLine_.setGeometry(r))},e.prototype.startDrawing_=function(t){var e=this.getMap().getView().getProjection();this.finishCoordinate_=t,this.mode_===Lv?this.sketchCoords_=t.slice():this.mode_===Fv?(this.sketchCoords_=[[t.slice(),t.slice()]],this.sketchLineCoords_=this.sketchCoords_[0]):this.sketchCoords_=[t.slice(),t.slice()],this.sketchLineCoords_&&(this.sketchLine_=new gt(new Py(this.sketchLineCoords_)));var r=this.geometryFunction_(this.sketchCoords_,void 0,e);this.sketchFeature_=new gt,this.geometryName_&&this.sketchFeature_.setGeometryName(this.geometryName_),this.sketchFeature_.setGeometry(r),this.updateSketchFeatures_(),this.dispatchEvent(new Dv(kv,this.sketchFeature_))},e.prototype.modifyDrawing_=function(t){var e,r,n=this.getMap(),i=this.sketchFeature_.getGeometry(),o=n.getView().getProjection();(this.mode_===Lv?r=this.sketchCoords_:this.mode_===Fv?(r=(e=this.sketchCoords_[0])[e.length-1],this.atFinish_(n.getPixelFromCoordinate(t))&&(t=this.finishCoordinate_.slice())):r=(e=this.sketchCoords_)[e.length-1],r[0]=t[0],r[1]=t[1],this.geometryFunction_(this.sketchCoords_,i,o),this.sketchPoint_)&&this.sketchPoint_.getGeometry().setCoordinates(t);if(i.getType()===bt.POLYGON&&this.mode_!==Fv)this.createOrUpdateCustomSketchLine_(i);else if(this.sketchLineCoords_){this.sketchLine_.getGeometry().setCoordinates(this.sketchLineCoords_)}this.updateSketchFeatures_()},e.prototype.addToDrawing_=function(t){var e,r,n=this.sketchFeature_.getGeometry(),i=this.getMap().getView().getProjection(),o=this.mode_;o===Mv||o===Av?(this.finishCoordinate_=t.slice(),(r=this.sketchCoords_).length>=this.maxPoints_&&(this.freehand_?r.pop():e=!0),r.push(t.slice()),this.geometryFunction_(r,n,i)):o===Fv&&((r=this.sketchCoords_[0]).length>=this.maxPoints_&&(this.freehand_?r.pop():e=!0),r.push(t.slice()),e&&(this.finishCoordinate_=r[0]),this.geometryFunction_(this.sketchCoords_,n,i)),this.updateSketchFeatures_(),e&&this.finishDrawing()},e.prototype.removeLastPoint=function(){if(this.sketchFeature_){var t,e=this.sketchFeature_.getGeometry(),r=this.getMap().getView().getProjection(),n=this.mode_;if(n===Mv||n===Av){if((t=this.sketchCoords_).splice(-2,1),t.length>=2){this.finishCoordinate_=t[t.length-2].slice();var i=this.finishCoordinate_.slice();t[t.length-1]=i,this.sketchPoint_.setGeometry(new qn(i))}this.geometryFunction_(t,e,r),e.getType()===bt.POLYGON&&this.sketchLine_&&this.createOrUpdateCustomSketchLine_(e)}else if(n===Fv){(t=this.sketchCoords_[0]).splice(-2,1);var o=this.sketchLine_.getGeometry();if(t.length>=2){i=t[t.length-2].slice();t[t.length-1]=i,this.sketchPoint_.setGeometry(new qn(i))}o.setCoordinates(t),this.geometryFunction_(this.sketchCoords_,e,r)}1===t.length&&this.abortDrawing(),this.updateSketchFeatures_()}},e.prototype.finishDrawing=function(){var t=this.abortDrawing_();if(t){var e=this.sketchCoords_,r=t.getGeometry(),n=this.getMap().getView().getProjection();this.mode_===Mv?(e.pop(),this.geometryFunction_(e,r,n)):this.mode_===Fv&&(e[0].pop(),this.geometryFunction_(e,r,n),e=r.getCoordinates()),this.type_===bt.MULTI_POINT?t.setGeometry(new Hy([e])):this.type_===bt.MULTI_LINE_STRING?t.setGeometry(new Zy([e])):this.type_===bt.MULTI_POLYGON&&t.setGeometry(new Jy([e])),this.dispatchEvent(new Dv(jv,t)),this.features_&&this.features_.push(t),this.source_&&this.source_.addFeature(t)}},e.prototype.abortDrawing_=function(){this.finishCoordinate_=null;var t=this.sketchFeature_;return this.sketchFeature_=null,this.sketchPoint_=null,this.sketchLine_=null,this.overlay_.getSource().clear(!0),t},e.prototype.abortDrawing=function(){var t=this.abortDrawing_();t&&this.dispatchEvent(new Dv(Nv,t))},e.prototype.appendCoordinates=function(t){var e,r=this.mode_,n=!this.sketchFeature_;if(n&&this.startDrawing_(t[0]),r===Mv||r===Av)e=this.sketchCoords_;else{if(r!==Fv)return;e=this.sketchCoords_&&this.sketchCoords_.length?this.sketchCoords_[0]:[]}n&&e.shift(),e.pop();for(var i=0;i<t.length;i++)this.addToDrawing_(t[i]);var o=t[t.length-1];this.addToDrawing_(o),this.modifyDrawing_(o)},e.prototype.extend=function(t){var e=t.getGeometry();this.sketchFeature_=t,this.sketchCoords_=e.getCoordinates();var r=this.sketchCoords_[this.sketchCoords_.length-1];this.finishCoordinate_=r.slice(),this.sketchCoords_.push(r.slice()),this.sketchPoint_=new gt(new qn(r)),this.updateSketchFeatures_(),this.dispatchEvent(new Dv(kv,this.sketchFeature_))},e.prototype.updateSketchFeatures_=function(){var t=[];this.sketchFeature_&&t.push(this.sketchFeature_),this.sketchLine_&&t.push(this.sketchLine_),this.sketchPoint_&&t.push(this.sketchPoint_);var e=this.overlay_.getSource();e.clear(!0),e.addFeatures(t)},e.prototype.updateState_=function(){var t=this.getMap(),e=this.getActive();t&&e||this.abortDrawing(),this.overlay_.setMap(e?t:null)},e}($s),zv=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Uv="extentchanged",Bv=function(t){function e(e){var r=t.call(this,Uv)||this;return r.extent=e,r}return zv(e,t),e}(c);function Vv(){var t=bp();return function(e,r){return t[bt.POINT]}}function Yv(t){return function(e){return Kt([t,e])}}function Wv(t,e){return t[0]==e[0]?function(r){return Kt([t,[r[0],e[1]]])}:t[1]==e[1]?function(r){return Kt([t,[e[0],r[1]]])}:null}var qv=function(t){function e(e){var r,n=this,i=e||{};return(n=t.call(this,i)||this).condition_=i.condition?i.condition:nl,n.extent_=null,n.pointerHandler_=null,n.pixelTolerance_=void 0!==i.pixelTolerance?i.pixelTolerance:10,n.snappedToVertex_=!1,n.extentFeature_=null,n.vertexFeature_=null,e||(e={}),n.extentOverlay_=new Iy({source:new hf({useSpatialIndex:!1,wrapX:!!e.wrapX}),style:e.boxStyle?e.boxStyle:(r=bp(),function(t,e){return r[bt.POLYGON]}),updateWhileAnimating:!0,updateWhileInteracting:!0}),n.vertexOverlay_=new Iy({source:new hf({useSpatialIndex:!1,wrapX:!!e.wrapX}),style:e.pointerStyle?e.pointerStyle:Vv(),updateWhileAnimating:!0,updateWhileInteracting:!0}),e.extent&&n.setExtent(e.extent),n}return zv(e,t),e.prototype.snapToVertex_=function(t,e){var r=e.getCoordinateFromPixelInternal(t),n=this.getExtentInternal();if(n){var i=function(t){return[[[t[0],t[1]],[t[0],t[3]]],[[t[0],t[3]],[t[2],t[3]]],[[t[2],t[3]],[t[2],t[1]]],[[t[2],t[1]],[t[0],t[1]]]]}(n);i.sort((function(t,e){return Lr(r,t)-Lr(r,e)}));var o=i[0],a=Sr(r,o),s=e.getPixelFromCoordinateInternal(a);if(Ir(t,s)<=this.pixelTolerance_){var l=e.getPixelFromCoordinateInternal(o[0]),u=e.getPixelFromCoordinateInternal(o[1]),c=Rr(s,l),h=Rr(s,u),p=Math.sqrt(Math.min(c,h));return this.snappedToVertex_=p<=this.pixelTolerance_,this.snappedToVertex_&&(a=c>h?o[1]:o[0]),a}}return null},e.prototype.handlePointerMove_=function(t){var e=t.pixel,r=t.map,n=this.snapToVertex_(e,r);n||(n=r.getCoordinateFromPixelInternal(e)),this.createOrUpdatePointerFeature_(n)},e.prototype.createOrUpdateExtentFeature_=function(t){var e=this.extentFeature_;return e?t?e.setGeometry(gi(t)):e.setGeometry(void 0):(e=new gt(t?gi(t):{}),this.extentFeature_=e,this.extentOverlay_.getSource().addFeature(e)),e},e.prototype.createOrUpdatePointerFeature_=function(t){var e=this.vertexFeature_;e?e.getGeometry().setCoordinates(t):(e=new gt(new qn(t)),this.vertexFeature_=e,this.vertexOverlay_.getSource().addFeature(e));return e},e.prototype.handleEvent=function(e){return!e.originalEvent||!this.condition_(e)||(e.type!=Ga.POINTERMOVE||this.handlingDownUpSequence||this.handlePointerMove_(e),t.prototype.handleEvent.call(this,e),!1)},e.prototype.handleDownEvent=function(t){var e=t.pixel,r=t.map,n=this.getExtentInternal(),i=this.snapToVertex_(e,r),o=function(t){var e=null,r=null;return t[0]==n[0]?e=n[2]:t[0]==n[2]&&(e=n[0]),t[1]==n[1]?r=n[3]:t[1]==n[3]&&(r=n[1]),null!==e&&null!==r?[e,r]:null};if(i&&n){var a=i[0]==n[0]||i[0]==n[2]?i[0]:null,s=i[1]==n[1]||i[1]==n[3]?i[1]:null;null!==a&&null!==s?this.pointerHandler_=Yv(o(i)):null!==a?this.pointerHandler_=Wv(o([a,n[1]]),o([a,n[3]])):null!==s&&(this.pointerHandler_=Wv(o([n[0],s]),o([n[2],s])))}else i=r.getCoordinateFromPixelInternal(e),this.setExtent([i[0],i[1],i[0],i[1]]),this.pointerHandler_=Yv(i);return!0},e.prototype.handleDragEvent=function(t){if(this.pointerHandler_){var e=t.coordinate;this.setExtent(this.pointerHandler_(e)),this.createOrUpdatePointerFeature_(e)}},e.prototype.handleUpEvent=function(t){this.pointerHandler_=null;var e=this.getExtentInternal();return e&&0!==ve(e)||this.setExtent(null),!1},e.prototype.setMap=function(e){this.extentOverlay_.setMap(e),this.vertexOverlay_.setMap(e),t.prototype.setMap.call(this,e)},e.prototype.getExtent=function(){return nn(this.getExtentInternal(),this.getMap().getView().getProjection())},e.prototype.getExtentInternal=function(){return this.extent_},e.prototype.setExtent=function(t){this.extent_=t||null,this.createOrUpdateExtentFeature_(t),this.dispatchEvent(new Bv(this.extent_))},e}($s),Xv=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Zv=[0,0,0,0],Kv=[],Hv="modifystart",$v="modifyend",Jv=function(t){function e(e,r,n){var i=t.call(this,e)||this;return i.features=r,i.mapBrowserEvent=n,i}return Xv(e,t),e}(c);function Qv(t,e){return t.index-e.index}function t_(t,e,r){var n=e.geometry;if(n.getType()===bt.CIRCLE){var i=n;if(1===e.index){var o=tn();o&&(i=i.clone().transform(o,r));var a=Rr(i.getCenter(),rn(t,r)),s=Math.sqrt(a)-i.getRadius();return s*s}}var l=rn(t,r);return Kv[0]=rn(e.segment[0],r),Kv[1]=rn(e.segment[1],r),Lr(l,Kv)}function e_(t,e,r){var n=e.geometry;if(n.getType()===bt.CIRCLE&&1===e.index){var i=n,o=tn();return o&&(i=i.clone().transform(o,r)),en(i.getClosestPoint(rn(t,r)),r)}var a=rn(t,r);return Kv[0]=rn(e.segment[0],r),Kv[1]=rn(e.segment[1],r),en(Sr(a,Kv),r)}var r_=function(t){function e(e){var r,n,i=t.call(this,e)||this;if(i.boundHandleFeatureChange_=i.handleFeatureChange_.bind(i),i.condition_=e.condition?e.condition:hl,i.defaultDeleteCondition_=function(t){return Qs(t)&&al(t)},i.deleteCondition_=e.deleteCondition?e.deleteCondition:i.defaultDeleteCondition_,i.insertVertexCondition_=e.insertVertexCondition?e.insertVertexCondition:nl,i.vertexFeature_=null,i.vertexSegments_=null,i.lastPixel_=[0,0],i.ignoreNextSingleClick_=!1,i.featuresBeingModified_=null,i.rBush_=new Rp,i.pixelTolerance_=void 0!==e.pixelTolerance?e.pixelTolerance:10,i.snappedToVertex_=!1,i.changingFeature_=!1,i.dragSegments_=[],i.overlay_=new Iy({source:new hf({useSpatialIndex:!1,wrapX:!!e.wrapX}),style:e.style?e.style:(r=bp(),function(t,e){return r[bt.POINT]}),updateWhileAnimating:!0,updateWhileInteracting:!0}),i.SEGMENT_WRITERS_={Point:i.writePointGeometry_.bind(i),LineString:i.writeLineStringGeometry_.bind(i),LinearRing:i.writeLineStringGeometry_.bind(i),Polygon:i.writePolygonGeometry_.bind(i),MultiPoint:i.writeMultiPointGeometry_.bind(i),MultiLineString:i.writeMultiLineStringGeometry_.bind(i),MultiPolygon:i.writeMultiPolygonGeometry_.bind(i),Circle:i.writeCircleGeometry_.bind(i),GeometryCollection:i.writeGeometryCollectionGeometry_.bind(i)},i.source_=null,i.hitDetection_=null,e.features?n=e.features:e.source&&(i.source_=e.source,n=new ht(i.source_.getFeatures()),i.source_.addEventListener(ef,i.handleSourceAdd_.bind(i)),i.source_.addEventListener(of,i.handleSourceRemove_.bind(i))),!n)throw new Error("The modify interaction requires features, a source or a layer");return e.hitDetection&&(i.hitDetection_=e.hitDetection),i.features_=n,i.features_.forEach(i.addFeature_.bind(i)),i.features_.addEventListener(at,i.handleFeatureAdd_.bind(i)),i.features_.addEventListener(st,i.handleFeatureRemove_.bind(i)),i.lastPointerEvent_=null,i.delta_=[0,0],i}return Xv(e,t),e.prototype.addFeature_=function(t){var e=t.getGeometry();if(e){var r=this.SEGMENT_WRITERS_[e.getType()];r&&r(t,e)}var n=this.getMap();n&&n.isRendered()&&this.getActive()&&this.handlePointerAtPixel_(this.lastPixel_,n),t.addEventListener(F,this.boundHandleFeatureChange_)},e.prototype.willModifyFeatures_=function(t,e){if(!this.featuresBeingModified_){this.featuresBeingModified_=new ht;for(var r=this.featuresBeingModified_.getArray(),n=0,i=e.length;n<i;++n){var o=e[n][0].feature;-1===r.indexOf(o)&&this.featuresBeingModified_.push(o)}this.dispatchEvent(new Jv(Hv,this.featuresBeingModified_,t))}},e.prototype.removeFeature_=function(t){this.removeFeatureSegmentData_(t),this.vertexFeature_&&0===this.features_.getLength()&&(this.overlay_.getSource().removeFeature(this.vertexFeature_),this.vertexFeature_=null),t.removeEventListener(F,this.boundHandleFeatureChange_)},e.prototype.removeFeatureSegmentData_=function(t){var e=this.rBush_,r=[];e.forEach((function(e){t===e.feature&&r.push(e)}));for(var n=r.length-1;n>=0;--n){for(var i=r[n],o=this.dragSegments_.length-1;o>=0;--o)this.dragSegments_[o][0]===i&&this.dragSegments_.splice(o,1);e.remove(i)}},e.prototype.setActive=function(e){this.vertexFeature_&&!e&&(this.overlay_.getSource().removeFeature(this.vertexFeature_),this.vertexFeature_=null),t.prototype.setActive.call(this,e)},e.prototype.setMap=function(e){this.overlay_.setMap(e),t.prototype.setMap.call(this,e)},e.prototype.getOverlay=function(){return this.overlay_},e.prototype.handleSourceAdd_=function(t){t.feature&&this.features_.push(t.feature)},e.prototype.handleSourceRemove_=function(t){t.feature&&this.features_.remove(t.feature)},e.prototype.handleFeatureAdd_=function(t){this.addFeature_(t.element)},e.prototype.handleFeatureChange_=function(t){if(!this.changingFeature_){var e=t.target;this.removeFeature_(e),this.addFeature_(e)}},e.prototype.handleFeatureRemove_=function(t){var e=t.element;this.removeFeature_(e)},e.prototype.writePointGeometry_=function(t,e){var r=e.getCoordinates(),n={feature:t,geometry:e,segment:[r,r]};this.rBush_.insert(e.getExtent(),n)},e.prototype.writeMultiPointGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n){var o=r[n],a={feature:t,geometry:e,depth:[n],index:n,segment:[o,o]};this.rBush_.insert(e.getExtent(),a)}},e.prototype.writeLineStringGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length-1;n<i;++n){var o=r.slice(n,n+2),a={feature:t,geometry:e,index:n,segment:o};this.rBush_.insert(Kt(o),a)}},e.prototype.writeMultiLineStringGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n)for(var o=r[n],a=0,s=o.length-1;a<s;++a){var l=o.slice(a,a+2),u={feature:t,geometry:e,depth:[n],index:a,segment:l};this.rBush_.insert(Kt(l),u)}},e.prototype.writePolygonGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n)for(var o=r[n],a=0,s=o.length-1;a<s;++a){var l=o.slice(a,a+2),u={feature:t,geometry:e,depth:[n],index:a,segment:l};this.rBush_.insert(Kt(l),u)}},e.prototype.writeMultiPolygonGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n)for(var o=r[n],a=0,s=o.length;a<s;++a)for(var l=o[a],u=0,c=l.length-1;u<c;++u){var h=l.slice(u,u+2),p={feature:t,geometry:e,depth:[a,n],index:u,segment:h};this.rBush_.insert(Kt(h),p)}},e.prototype.writeCircleGeometry_=function(t,e){var r=e.getCenter(),n={feature:t,geometry:e,index:0,segment:[r,r]},i={feature:t,geometry:e,index:1,segment:[r,r]},o=[n,i];n.featureSegments=o,i.featureSegments=o,this.rBush_.insert(ae(r),n);var a=e,s=tn();if(s&&this.getMap()){var l=this.getMap().getView().getProjection();a=yi(a=a.clone().transform(s,l)).transform(l,s)}this.rBush_.insert(a.getExtent(),i)},e.prototype.writeGeometryCollectionGeometry_=function(t,e){for(var r=e.getGeometriesArray(),n=0;n<r.length;++n){var i=r[n];(0,this.SEGMENT_WRITERS_[i.getType()])(t,i)}},e.prototype.createOrUpdateVertexFeature_=function(t,e,r){var n=this.vertexFeature_;n?n.getGeometry().setCoordinates(t):(n=new gt(new qn(t)),this.vertexFeature_=n,this.overlay_.getSource().addFeature(n));return n.set("features",e),n.set("geometries",r),n},e.prototype.handleEvent=function(e){return!e.originalEvent||(this.lastPointerEvent_=e,e.map.getView().getInteracting()||e.type!=Ga.POINTERMOVE||this.handlingDownUpSequence||this.handlePointerMove_(e),this.vertexFeature_&&this.deleteCondition_(e)&&(r=!(e.type!=Ga.SINGLECLICK||!this.ignoreNextSingleClick_)||this.removePoint()),e.type==Ga.SINGLECLICK&&(this.ignoreNextSingleClick_=!1),t.prototype.handleEvent.call(this,e)&&!r);var r},e.prototype.handleDragEvent=function(t){this.ignoreNextSingleClick_=!1,this.willModifyFeatures_(t,this.dragSegments_);for(var e=[t.coordinate[0]+this.delta_[0],t.coordinate[1]+this.delta_[1]],r=[],n=[],i=0,o=this.dragSegments_.length;i<o;++i){var a=this.dragSegments_[i],s=a[0],l=s.feature;-1===r.indexOf(l)&&r.push(l);var u=s.geometry;-1===n.indexOf(u)&&n.push(u);for(var c=s.depth,h=void 0,p=s.segment,f=a[1];e.length<u.getStride();)e.push(p[f][e.length]);switch(u.getType()){case bt.POINT:h=e,p[0]=e,p[1]=e;break;case bt.MULTI_POINT:(h=u.getCoordinates())[s.index]=e,p[0]=e,p[1]=e;break;case bt.LINE_STRING:(h=u.getCoordinates())[s.index+f]=e,p[f]=e;break;case bt.MULTI_LINE_STRING:case bt.POLYGON:(h=u.getCoordinates())[c[0]][s.index+f]=e,p[f]=e;break;case bt.MULTI_POLYGON:(h=u.getCoordinates())[c[1]][c[0]][s.index+f]=e,p[f]=e;break;case bt.CIRCLE:if(p[0]=e,p[1]=e,0===s.index)this.changingFeature_=!0,u.setCenter(e),this.changingFeature_=!1;else{this.changingFeature_=!0;var d=t.map.getView().getProjection(),g=Ir(rn(u.getCenter(),d),rn(e,d)),y=tn();if(y){var m=u.clone().transform(y,d);m.setRadius(g),g=m.transform(d,y).getRadius()}u.setRadius(g),this.changingFeature_=!1}}h&&this.setGeometryCoordinates_(u,h)}this.createOrUpdateVertexFeature_(e,r,n)},e.prototype.handleDownEvent=function(t){if(!this.condition_(t))return!1;var e=t.coordinate;this.handlePointerAtPixel_(t.pixel,t.map,e),this.dragSegments_.length=0,this.featuresBeingModified_=null;var r=this.vertexFeature_;if(r){var n=t.map.getView().getProjection(),i=[],a=r.getGeometry().getCoordinates(),s=Kt([a]),l=this.rBush_.getInExtent(s),u={};l.sort(Qv);for(var c=0,h=l.length;c<h;++c){var p=l[c],f=p.segment,d=o(p.geometry),g=p.depth;if(g&&(d+="-"+g.join("-")),u[d]||(u[d]=new Array(2)),p.geometry.getType()!==bt.CIRCLE||1!==p.index)if(!Cr(f[0],a)||u[d][0])if(!Cr(f[1],a)||u[d][1])o(f)in this.vertexSegments_&&!u[d][0]&&!u[d][1]&&this.insertVertexCondition_(t)&&i.push(p);else{if((p.geometry.getType()===bt.LINE_STRING||p.geometry.getType()===bt.MULTI_LINE_STRING)&&u[d][0]&&0===u[d][0].index)continue;this.dragSegments_.push([p,1]),u[d][1]=p}else this.dragSegments_.push([p,0]),u[d][0]=p;else Cr(e_(e,p,n),a)&&!u[d][0]&&(this.dragSegments_.push([p,0]),u[d][0]=p)}i.length&&this.willModifyFeatures_(t,[i]);for(var y=i.length-1;y>=0;--y)this.insertVertex_(i[y],a)}return!!this.vertexFeature_},e.prototype.handleUpEvent=function(t){for(var e=this.dragSegments_.length-1;e>=0;--e){var r=this.dragSegments_[e][0],n=r.geometry;if(n.getType()===bt.CIRCLE){var i=n.getCenter(),o=r.featureSegments[0],a=r.featureSegments[1];o.segment[0]=i,o.segment[1]=i,a.segment[0]=i,a.segment[1]=i,this.rBush_.update(ae(i),o);var s=n,l=tn();if(l){var u=t.map.getView().getProjection();s=yi(s=s.clone().transform(l,u)).transform(u,l)}this.rBush_.update(s.getExtent(),a)}else this.rBush_.update(Kt(r.segment),r)}return this.featuresBeingModified_&&(this.dispatchEvent(new Jv($v,this.featuresBeingModified_,t)),this.featuresBeingModified_=null),!1},e.prototype.handlePointerMove_=function(t){this.lastPixel_=t.pixel,this.handlePointerAtPixel_(t.pixel,t.map,t.coordinate)},e.prototype.handlePointerAtPixel_=function(t,e,r){var n,i,a=this,s=r||e.getCoordinateFromPixel(t),l=e.getView().getProjection();if(this.hitDetection_){var u="object"==typeof this.hitDetection_?function(t){return t===a.hitDetection_}:void 0;e.forEachFeatureAtPixel(t,(function(t,e,r){if((r=r||t.getGeometry()).getType()===bt.POINT){i=r;var o=r.getCoordinates();n=[{feature:t,geometry:r,segment:[o,o]}]}return!0}),{layerFilter:u})}if(!n){var c=nn(Ht(on(ae(s,Zv),l),e.getView().getResolution()*this.pixelTolerance_,Zv),l);n=this.rBush_.getInExtent(c)}if(n&&n.length>0){var h=n.sort((function(t,e){return t_(s,t,l)-t_(s,e,l)}))[0],p=h.segment,f=e_(s,h,l),d=e.getPixelFromCoordinate(f),g=Ir(t,d);if(i||g<=this.pixelTolerance_){var y={};if(y[o(p)]=!0,this.delta_[0]=f[0]-s[0],this.delta_[1]=f[1]-s[1],h.geometry.getType()===bt.CIRCLE&&1===h.index)this.snappedToVertex_=!0,this.createOrUpdateVertexFeature_(f,[h.feature],[h.geometry]);else{var m=e.getPixelFromCoordinate(p[0]),v=e.getPixelFromCoordinate(p[1]),_=Rr(d,m),b=Rr(d,v);g=Math.sqrt(Math.min(_,b)),this.snappedToVertex_=g<=this.pixelTolerance_,this.snappedToVertex_&&(f=_>b?p[1]:p[0]),this.createOrUpdateVertexFeature_(f,[h.feature],[h.geometry]);var x={};x[o(h.geometry)]=!0;for(var w=1,S=n.length;w<S;++w){var E=n[w].segment;if(!(Cr(p[0],E[0])&&Cr(p[1],E[1])||Cr(p[0],E[1])&&Cr(p[1],E[0])))break;var T=o(n[w].geometry);T in x||(x[T]=!0,y[o(E)]=!0)}}return void(this.vertexSegments_=y)}}this.vertexFeature_&&(this.overlay_.getSource().removeFeature(this.vertexFeature_),this.vertexFeature_=null)},e.prototype.insertVertex_=function(t,e){for(var r,n=t.segment,i=t.feature,o=t.geometry,a=t.depth,s=t.index;e.length<o.getStride();)e.push(0);switch(o.getType()){case bt.MULTI_LINE_STRING:case bt.POLYGON:(r=o.getCoordinates())[a[0]].splice(s+1,0,e);break;case bt.MULTI_POLYGON:(r=o.getCoordinates())[a[1]][a[0]].splice(s+1,0,e);break;case bt.LINE_STRING:(r=o.getCoordinates()).splice(s+1,0,e);break;default:return}this.setGeometryCoordinates_(o,r);var l=this.rBush_;l.remove(t),this.updateSegmentIndices_(o,s,a,1);var u={segment:[n[0],e],feature:i,geometry:o,depth:a,index:s};l.insert(Kt(u.segment),u),this.dragSegments_.push([u,1]);var c={segment:[e,n[1]],feature:i,geometry:o,depth:a,index:s+1};l.insert(Kt(c.segment),c),this.dragSegments_.push([c,0]),this.ignoreNextSingleClick_=!0},e.prototype.removePoint=function(){if(this.lastPointerEvent_&&this.lastPointerEvent_.type!=Ga.POINTERDRAG){var t=this.lastPointerEvent_;this.willModifyFeatures_(t,this.dragSegments_);var e=this.removeVertex_();return this.dispatchEvent(new Jv($v,this.featuresBeingModified_,t)),this.featuresBeingModified_=null,e}return!1},e.prototype.removeVertex_=function(){var t,e,r,n,i,a,s,l,u,c,h,p=this.dragSegments_,f={},d=!1;for(i=p.length-1;i>=0;--i)h=o((c=(r=p[i])[0]).feature),c.depth&&(h+="-"+c.depth.join("-")),h in f||(f[h]={}),0===r[1]?(f[h].right=c,f[h].index=c.index):1==r[1]&&(f[h].left=c,f[h].index=c.index+1);for(h in f){switch(u=f[h].right,s=f[h].left,(l=(a=f[h].index)-1)<0&&(l=0),t=e=(n=(c=void 0!==s?s:u).geometry).getCoordinates(),d=!1,n.getType()){case bt.MULTI_LINE_STRING:e[c.depth[0]].length>2&&(e[c.depth[0]].splice(a,1),d=!0);break;case bt.LINE_STRING:e.length>2&&(e.splice(a,1),d=!0);break;case bt.MULTI_POLYGON:t=t[c.depth[1]];case bt.POLYGON:(t=t[c.depth[0]]).length>4&&(a==t.length-1&&(a=0),t.splice(a,1),d=!0,0===a&&(t.pop(),t.push(t[0]),l=t.length-1))}if(d){this.setGeometryCoordinates_(n,e);var g=[];if(void 0!==s&&(this.rBush_.remove(s),g.push(s.segment[0])),void 0!==u&&(this.rBush_.remove(u),g.push(u.segment[1])),void 0!==s&&void 0!==u){var y={depth:c.depth,feature:c.feature,geometry:c.geometry,index:l,segment:g};this.rBush_.insert(Kt(y.segment),y)}this.updateSegmentIndices_(n,a,c.depth,-1),this.vertexFeature_&&(this.overlay_.getSource().removeFeature(this.vertexFeature_),this.vertexFeature_=null),p.length=0}}return d},e.prototype.setGeometryCoordinates_=function(t,e){this.changingFeature_=!0,t.setCoordinates(e),this.changingFeature_=!1},e.prototype.updateSegmentIndices_=function(t,e,r,n){this.rBush_.forEachInExtent(t.getExtent(),(function(i){i.geometry===t&&(void 0===r||void 0===i.depth||b(i.depth,r))&&i.index>e&&(i.index+=n)}))},e}($s),n_=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),i_="select",o_=function(t){function e(e,r,n,i){var o=t.call(this,e)||this;return o.selected=r,o.deselected=n,o.mapBrowserEvent=i,o}return n_(e,t),e}(c),a_={};var s_=function(t){function e(e){var r,n,i=t.call(this)||this,o=e||{};if(i.boundAddFeature_=i.addFeature_.bind(i),i.boundRemoveFeature_=i.removeFeature_.bind(i),i.condition_=o.condition?o.condition:al,i.addCondition_=o.addCondition?o.addCondition:ol,i.removeCondition_=o.removeCondition?o.removeCondition:ol,i.toggleCondition_=o.toggleCondition?o.toggleCondition:ll,i.multi_=!!o.multi&&o.multi,i.filter_=o.filter?o.filter:S,i.hitTolerance_=o.hitTolerance?o.hitTolerance:0,i.style_=void 0!==o.style?o.style:(v((r=bp())[bt.POLYGON],r[bt.LINE_STRING]),v(r[bt.GEOMETRY_COLLECTION],r[bt.LINE_STRING]),function(t){return t.getGeometry()?r[t.getGeometry().getType()]:null}),i.features_=o.features||new ht,o.layers)if("function"==typeof o.layers)n=o.layers;else{var a=o.layers;n=function(t){return g(a,t)}}else n=S;return i.layerFilter_=n,i.featureLayerAssociation_={},i}return n_(e,t),e.prototype.addFeatureLayerAssociation_=function(t,e){this.featureLayerAssociation_[o(t)]=e},e.prototype.getFeatures=function(){return this.features_},e.prototype.getHitTolerance=function(){return this.hitTolerance_},e.prototype.getLayer=function(t){return this.featureLayerAssociation_[o(t)]},e.prototype.setHitTolerance=function(t){this.hitTolerance_=t},e.prototype.setMap=function(e){this.getMap()&&this.style_&&this.features_.forEach(this.restorePreviousStyle_.bind(this)),t.prototype.setMap.call(this,e),e?(this.features_.addEventListener(at,this.boundAddFeature_),this.features_.addEventListener(st,this.boundRemoveFeature_),this.style_&&this.features_.forEach(this.applySelectedStyle_.bind(this))):(this.features_.removeEventListener(at,this.boundAddFeature_),this.features_.removeEventListener(st,this.boundRemoveFeature_))},e.prototype.addFeature_=function(t){var e=t.element;this.style_&&this.applySelectedStyle_(e)},e.prototype.removeFeature_=function(t){var e=t.element;this.style_&&this.restorePreviousStyle_(e)},e.prototype.getStyle=function(){return this.style_},e.prototype.applySelectedStyle_=function(t){var e=o(t);e in a_||(a_[e]=t.getStyle()),t.setStyle(this.style_)},e.prototype.restorePreviousStyle_=function(t){for(var r=this.getMap().getInteractions().getArray(),n=r.length-1;n>=0;--n){var i=r[n];if(i!==this&&i instanceof e&&i.getStyle()&&-1!==i.getFeatures().getArray().lastIndexOf(t))return void t.setStyle(i.getStyle())}var a=o(t);t.setStyle(a_[a]),delete a_[a]},e.prototype.removeFeatureLayerAssociation_=function(t){delete this.featureLayerAssociation_[o(t)]},e.prototype.handleEvent=function(t){if(!this.condition_(t))return!0;var e=this.addCondition_(t),r=this.removeCondition_(t),n=this.toggleCondition_(t),i=!e&&!r&&!n,o=t.map,a=this.getFeatures(),s=[],l=[];if(i){P(this.featureLayerAssociation_),o.forEachFeatureAtPixel(t.pixel,function(t,e){if(this.filter_(t,e))return l.push(t),this.addFeatureLayerAssociation_(t,e),!this.multi_}.bind(this),{layerFilter:this.layerFilter_,hitTolerance:this.hitTolerance_});for(var u=a.getLength()-1;u>=0;--u){var c=a.item(u),h=l.indexOf(c);h>-1?l.splice(h,1):(a.remove(c),s.push(c))}0!==l.length&&a.extend(l)}else{o.forEachFeatureAtPixel(t.pixel,function(t,i){if(this.filter_(t,i))return!e&&!n||g(a.getArray(),t)?(r||n)&&g(a.getArray(),t)&&(s.push(t),this.removeFeatureLayerAssociation_(t)):(l.push(t),this.addFeatureLayerAssociation_(t,i)),!this.multi_}.bind(this),{layerFilter:this.layerFilter_,hitTolerance:this.hitTolerance_});for(var p=s.length-1;p>=0;--p)a.remove(s[p]);a.extend(l)}return(l.length>0||s.length>0)&&this.dispatchEvent(new o_(i_,l,s,t)),!0},e}(qs),l_=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function u_(t){return t.feature?t.feature:t.element?t.element:void 0}var c_=[],h_=function(t){function e(e){var r=this,n=e||{},i=n;return i.handleDownEvent||(i.handleDownEvent=S),i.stopDown||(i.stopDown=E),(r=t.call(this,i)||this).source_=n.source?n.source:null,r.vertex_=void 0===n.vertex||n.vertex,r.edge_=void 0===n.edge||n.edge,r.features_=n.features?n.features:null,r.featuresListenerKeys_=[],r.featureChangeListenerKeys_={},r.indexedFeaturesExtents_={},r.pendingFeatures_={},r.pixelTolerance_=void 0!==n.pixelTolerance?n.pixelTolerance:10,r.rBush_=new Rp,r.SEGMENT_WRITERS_={Point:r.writePointGeometry_.bind(r),LineString:r.writeLineStringGeometry_.bind(r),LinearRing:r.writeLineStringGeometry_.bind(r),Polygon:r.writePolygonGeometry_.bind(r),MultiPoint:r.writeMultiPointGeometry_.bind(r),MultiLineString:r.writeMultiLineStringGeometry_.bind(r),MultiPolygon:r.writeMultiPolygonGeometry_.bind(r),GeometryCollection:r.writeGeometryCollectionGeometry_.bind(r),Circle:r.writeCircleGeometry_.bind(r)},r}return l_(e,t),e.prototype.addFeature=function(t,e){var r=void 0===e||e,n=o(t),i=t.getGeometry();if(i){var a=this.SEGMENT_WRITERS_[i.getType()];a&&(this.indexedFeaturesExtents_[n]=i.getExtent([1/0,1/0,-1/0,-1/0]),a(t,i))}r&&(this.featureChangeListenerKeys_[n]=Z(t,F,this.handleFeatureChange_,this))},e.prototype.forEachFeatureAdd_=function(t){this.addFeature(t)},e.prototype.forEachFeatureRemove_=function(t){this.removeFeature(t)},e.prototype.getFeatures_=function(){var t;return this.features_?t=this.features_:this.source_&&(t=this.source_.getFeatures()),t},e.prototype.handleEvent=function(e){var r=this.snapTo(e.pixel,e.coordinate,e.map);return r.snapped&&(e.coordinate=r.vertex.slice(0,2),e.pixel=r.vertexPixel),t.prototype.handleEvent.call(this,e)},e.prototype.handleFeatureAdd_=function(t){var e=u_(t);this.addFeature(e)},e.prototype.handleFeatureRemove_=function(t){var e=u_(t);this.removeFeature(e)},e.prototype.handleFeatureChange_=function(t){var e=t.target;if(this.handlingDownUpSequence){var r=o(e);r in this.pendingFeatures_||(this.pendingFeatures_[r]=e)}else this.updateFeature_(e)},e.prototype.handleUpEvent=function(t){var e=R(this.pendingFeatures_);return e.length&&(e.forEach(this.updateFeature_.bind(this)),this.pendingFeatures_={}),!1},e.prototype.removeFeature=function(t,e){var r=void 0===e||e,n=o(t),i=this.indexedFeaturesExtents_[n];if(i){var a=this.rBush_,s=[];a.forEachInExtent(i,(function(e){t===e.feature&&s.push(e)}));for(var l=s.length-1;l>=0;--l)a.remove(s[l])}r&&(H(this.featureChangeListenerKeys_[n]),delete this.featureChangeListenerKeys_[n])},e.prototype.setMap=function(e){var r=this.getMap(),n=this.featuresListenerKeys_,i=this.getFeatures_();r&&(n.forEach(H),n.length=0,i.forEach(this.forEachFeatureRemove_.bind(this))),t.prototype.setMap.call(this,e),e&&(this.features_?n.push(Z(this.features_,at,this.handleFeatureAdd_,this),Z(this.features_,st,this.handleFeatureRemove_,this)):this.source_&&n.push(Z(this.source_,ef,this.handleFeatureAdd_,this),Z(this.source_,of,this.handleFeatureRemove_,this)),i.forEach(this.forEachFeatureAdd_.bind(this)))},e.prototype.snapTo=function(t,e,r){var n=Kt([r.getCoordinateFromPixel([t[0]-this.pixelTolerance_,t[1]+this.pixelTolerance_]),r.getCoordinateFromPixel([t[0]+this.pixelTolerance_,t[1]-this.pixelTolerance_])]),i=this.rBush_.getInExtent(n);this.vertex_&&!this.edge_&&(i=i.filter((function(t){return t.feature.getGeometry().getType()!==bt.CIRCLE})));var o=!1,a=null,s=null;if(0===i.length)return{snapped:o,vertex:a,vertexPixel:s};for(var l,u=r.getView().getProjection(),c=rn(e,u),h=1/0,p=0;p<i.length;++p){var f=i[p];c_[0]=rn(f.segment[0],u),c_[1]=rn(f.segment[1],u);var d=Lr(c,c_);d<h&&(l=f,h=d)}var g=l.segment;if(this.vertex_&&!this.edge_){var y=r.getPixelFromCoordinate(g[0]),m=r.getPixelFromCoordinate(g[1]),v=Rr(t,y),_=Rr(t,m);Math.sqrt(Math.min(v,_))<=this.pixelTolerance_&&(o=!0,a=v>_?g[1]:g[0],s=r.getPixelFromCoordinate(a))}else if(this.edge_){var b=l.feature.getGeometry().getType()===bt.CIRCLE;if(b){var x=l.feature.getGeometry(),w=tn();w&&(x=x.clone().transform(w,u)),a=en(wr(c,x),u)}else c_[0]=rn(g[0],u),c_[1]=rn(g[1],u),a=en(Sr(c,c_),u);if(Ir(t,s=r.getPixelFromCoordinate(a))<=this.pixelTolerance_&&(o=!0,this.vertex_&&!b)){y=r.getPixelFromCoordinate(g[0]),m=r.getPixelFromCoordinate(g[1]),v=Rr(s,y),_=Rr(s,m);Math.sqrt(Math.min(v,_))<=this.pixelTolerance_&&(a=v>_?g[1]:g[0],s=r.getPixelFromCoordinate(a))}}return o&&(s=[Math.round(s[0]),Math.round(s[1])]),{snapped:o,vertex:a,vertexPixel:s}},e.prototype.updateFeature_=function(t){this.removeFeature(t,!1),this.addFeature(t,!1)},e.prototype.writeCircleGeometry_=function(t,e){var r=this.getMap().getView().getProjection(),n=e,i=tn();i&&(n=n.clone().transform(i,r));var o=yi(n);i&&o.transform(r,i);for(var a=o.getCoordinates()[0],s=0,l=a.length-1;s<l;++s){var u=a.slice(s,s+2),c={feature:t,segment:u};this.rBush_.insert(Kt(u),c)}},e.prototype.writeGeometryCollectionGeometry_=function(t,e){for(var r=e.getGeometriesArray(),n=0;n<r.length;++n){var i=this.SEGMENT_WRITERS_[r[n].getType()];i&&i(t,r[n])}},e.prototype.writeLineStringGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length-1;n<i;++n){var o=r.slice(n,n+2),a={feature:t,segment:o};this.rBush_.insert(Kt(o),a)}},e.prototype.writeMultiLineStringGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n)for(var o=r[n],a=0,s=o.length-1;a<s;++a){var l=o.slice(a,a+2),u={feature:t,segment:l};this.rBush_.insert(Kt(l),u)}},e.prototype.writeMultiPointGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n){var o=r[n],a={feature:t,segment:[o,o]};this.rBush_.insert(e.getExtent(),a)}},e.prototype.writeMultiPolygonGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n)for(var o=r[n],a=0,s=o.length;a<s;++a)for(var l=o[a],u=0,c=l.length-1;u<c;++u){var h=l.slice(u,u+2),p={feature:t,segment:h};this.rBush_.insert(Kt(h),p)}},e.prototype.writePointGeometry_=function(t,e){var r=e.getCoordinates(),n={feature:t,segment:[r,r]};this.rBush_.insert(e.getExtent(),n)},e.prototype.writePolygonGeometry_=function(t,e){for(var r=e.getCoordinates(),n=0,i=r.length;n<i;++n)for(var o=r[n],a=0,s=o.length-1;a<s;++a){var l=o.slice(a,a+2),u={feature:t,segment:l};this.rBush_.insert(Kt(l),u)}},e}($s),p_=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),f_="translatestart",d_="translating",g_="translateend",y_=function(t){function e(e,r,n,i,o){var a=t.call(this,e)||this;return a.features=r,a.coordinate=n,a.startCoordinate=i,a.mapBrowserEvent=o,a}return p_(e,t),e}(c),m_=function(t){function e(e){var r,n=this,i=e||{};if((n=t.call(this,i)||this).lastCoordinate_=null,n.startCoordinate_=null,n.features_=void 0!==i.features?i.features:null,i.layers)if("function"==typeof i.layers)r=i.layers;else{var o=i.layers;r=function(t){return g(o,t)}}else r=S;return n.layerFilter_=r,n.filter_=i.filter?i.filter:S,n.hitTolerance_=i.hitTolerance?i.hitTolerance:0,n.lastFeature_=null,n.addEventListener(it(Bs),n.handleActiveChanged_),n}return p_(e,t),e.prototype.handleDownEvent=function(t){if(this.lastFeature_=this.featuresAtPixel_(t.pixel,t.map),!this.lastCoordinate_&&this.lastFeature_){this.startCoordinate_=t.coordinate,this.lastCoordinate_=t.coordinate,this.handleMoveEvent(t);var e=this.features_||new ht([this.lastFeature_]);return this.dispatchEvent(new y_(f_,e,t.coordinate,this.startCoordinate_,t)),!0}return!1},e.prototype.handleUpEvent=function(t){if(this.lastCoordinate_){this.lastCoordinate_=null,this.handleMoveEvent(t);var e=this.features_||new ht([this.lastFeature_]);return this.dispatchEvent(new y_(g_,e,t.coordinate,this.startCoordinate_,t)),this.startCoordinate_=null,!0}return!1},e.prototype.handleDragEvent=function(t){if(this.lastCoordinate_){var e=t.coordinate,r=e[0]-this.lastCoordinate_[0],n=e[1]-this.lastCoordinate_[1],i=this.features_||new ht([this.lastFeature_]);i.forEach((function(t){var e=t.getGeometry();e.translate(r,n),t.setGeometry(e)})),this.lastCoordinate_=e,this.dispatchEvent(new y_(d_,i,e,this.startCoordinate_,t))}},e.prototype.handleMoveEvent=function(t){var e=t.map.getViewport();this.featuresAtPixel_(t.pixel,t.map)?(e.classList.remove(this.lastCoordinate_?"ol-grab":"ol-grabbing"),e.classList.add(this.lastCoordinate_?"ol-grabbing":"ol-grab")):e.classList.remove("ol-grab","ol-grabbing")},e.prototype.featuresAtPixel_=function(t,e){return e.forEachFeatureAtPixel(t,function(t,e){if(this.filter_(t,e)&&(!this.features_||g(this.features_.getArray(),t)))return t}.bind(this),{layerFilter:this.layerFilter_,hitTolerance:this.hitTolerance_})},e.prototype.getHitTolerance=function(){return this.hitTolerance_},e.prototype.setHitTolerance=function(t){this.hitTolerance_=t},e.prototype.setMap=function(e){var r=this.getMap();t.prototype.setMap.call(this,e),this.updateState_(r)},e.prototype.handleActiveChanged_=function(){this.updateState_(null)},e.prototype.updateState_=function(t){var e=this.getMap(),r=this.getActive();e&&r||(e=e||t)&&e.getViewport().classList.remove("ol-grab","ol-grabbing")},e}($s);function v_(t,e,r,n,i,o){var a,s;void 0!==i?(a=i,s=void 0!==o?o:0):(a=[],s=0);for(var l=e;l<r;){var u=t[l++];a[s++]=t[l++],a[s++]=u;for(var c=2;c<n;++c)a[s++]=t[l++]}return a.length=s,a}var __=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),b_={};b_[bt.POINT]=function(t){var e;e=void 0!==t.m&&void 0!==t.z?new qn([t.x,t.y,t.z,t.m],_t):void 0!==t.z?new qn([t.x,t.y,t.z],mt):void 0!==t.m?new qn([t.x,t.y,t.m],vt):new qn([t.x,t.y]);return e},b_[bt.LINE_STRING]=function(t){var e=S_(t);return new Py(t.paths[0],e)},b_[bt.POLYGON]=function(t){var e=S_(t);return new fi(t.rings,e)},b_[bt.MULTI_POINT]=function(t){var e=S_(t);return new Hy(t.points,e)},b_[bt.MULTI_LINE_STRING]=function(t){var e=S_(t);return new Zy(t.paths,e)},b_[bt.MULTI_POLYGON]=function(t){var e=S_(t);return new Jy(t.rings,e)};var x_={};function w_(t,e){var r,n,i;if(!t)return null;if("number"==typeof t.x&&"number"==typeof t.y)i=bt.POINT;else if(t.points)i=bt.MULTI_POINT;else if(t.paths){i=1===t.paths.length?bt.LINE_STRING:bt.MULTI_LINE_STRING}else if(t.rings){var o=t,a=S_(o),s=function(t,e){var r,n,i=[],o=[],a=[];for(r=0,n=t.length;r<n;++r){i.length=0,On(i,0,t[r],e.length),ai(i,0,i.length,e.length)?o.push([t[r]]):a.push(t[r])}for(;a.length;){var s=a.shift(),l=!1;for(r=o.length-1;r>=0;r--){var u=o[r][0];if(te(new Yn(u).getExtent(),new Yn(s).getExtent())){o[r].push(s),l=!0;break}}l||o.push([s.reverse()])}return o}(o.rings,a);1===s.length?(i=bt.POLYGON,t=O({},t,((r={}).rings=s[0],r))):(i=bt.MULTI_POLYGON,t=O({},t,((n={}).rings=s,n)))}return Wy((0,b_[i])(t),!1,e)}function S_(t){var e=yt;return!0===t.hasZ&&!0===t.hasM?e=_t:!0===t.hasZ?e=mt:!0===t.hasM&&(e=vt),e}function E_(t){var e=t.getLayout();return{hasZ:e===mt||e===_t,hasM:e===vt||e===_t}}function T_(t,e){return(0,x_[t.getType()])(Wy(t,!0,e),e)}x_[bt.POINT]=function(t,e){var r,n=t.getCoordinates(),i=t.getLayout();i===mt?r={x:n[0],y:n[1],z:n[2]}:i===vt?r={x:n[0],y:n[1],m:n[2]}:i===_t?r={x:n[0],y:n[1],z:n[2],m:n[3]}:i===yt?r={x:n[0],y:n[1]}:pt(!1,34);return r},x_[bt.LINE_STRING]=function(t,e){var r=E_(t);return{hasZ:r.hasZ,hasM:r.hasM,paths:[t.getCoordinates()]}},x_[bt.POLYGON]=function(t,e){var r=E_(t);return{hasZ:r.hasZ,hasM:r.hasM,rings:t.getCoordinates(!1)}},x_[bt.MULTI_POINT]=function(t,e){var r=E_(t);return{hasZ:r.hasZ,hasM:r.hasM,points:t.getCoordinates()}},x_[bt.MULTI_LINE_STRING]=function(t,e){var r=E_(t);return{hasZ:r.hasZ,hasM:r.hasM,paths:t.getCoordinates()}},x_[bt.MULTI_POLYGON]=function(t,e){for(var r=E_(t),n=t.getCoordinates(!1),i=[],o=0;o<n.length;o++)for(var a=n[o].length-1;a>=0;a--)i.push(n[o][a]);return{hasZ:r.hasZ,hasM:r.hasM,rings:i}};var C_=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this)||this).geometryName_=n.geometryName,r}return __(e,t),e.prototype.readFeatureFromObject=function(t,e,r){var n=t,i=w_(n.geometry,e),o=new gt;if(this.geometryName_&&o.setGeometryName(this.geometryName_),o.setGeometry(i),n.attributes){o.setProperties(n.attributes,!0);var a=n.attributes[r];void 0!==a&&o.setId(a)}return o},e.prototype.readFeaturesFromObject=function(t,e){var r=e||{};if(t.features){for(var n=[],i=t.features,o=0,a=i.length;o<a;++o)n.push(this.readFeatureFromObject(i[o],r,t.objectIdFieldName));return n}return[this.readFeatureFromObject(t,r)]},e.prototype.readGeometryFromObject=function(t,e){return w_(t,e)},e.prototype.readProjectionFromObject=function(t){return t.spatialReference&&void 0!==t.spatialReference.wkid?Gr("EPSG:"+t.spatialReference.wkid):null},e.prototype.writeGeometryObject=function(t,e){return T_(t,this.adaptOptions(e))},e.prototype.writeFeatureObject=function(t,e){e=this.adaptOptions(e);var r={};if(!t.hasProperties())return r.attributes={},r;var n=t.getProperties(),i=t.getGeometry();if(i){r.geometry=T_(i,e);var o=e&&(e.dataProjection||e.featureProjection);o&&(r.geometry.spatialReference={wkid:Number(Gr(o).getCode().split(":").pop())}),delete n[t.getGeometryName()]}return I(n)?r.attributes={}:r.attributes=n,r},e.prototype.writeFeaturesObject=function(t,e){e=this.adaptOptions(e);for(var r=[],n=0,i=t.length;n<i;++n)r.push(this.writeFeatureObject(t[n],e));return{features:r}},e}(qm),O_=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),P_=function(t){function e(){var e=t.call(this)||this;return e.xmlSerializer_=Wc(),e}return O_(e,t),e.prototype.getType=function(){return Ru},e.prototype.readFeature=function(t,e){if(t){if("string"==typeof t){var r=Pc(t);return this.readFeatureFromDocument(r,e)}return Cc(t)?this.readFeatureFromDocument(t,e):this.readFeatureFromNode(t,e)}return null},e.prototype.readFeatureFromDocument=function(t,e){var r=this.readFeaturesFromDocument(t,e);return r.length>0?r[0]:null},e.prototype.readFeatureFromNode=function(t,e){return null},e.prototype.readFeatures=function(t,e){if(t){if("string"==typeof t){var r=Pc(t);return this.readFeaturesFromDocument(r,e)}return Cc(t)?this.readFeaturesFromDocument(t,e):this.readFeaturesFromNode(t,e)}return[]},e.prototype.readFeaturesFromDocument=function(t,e){for(var r=[],n=t.firstChild;n;n=n.nextSibling)n.nodeType==Node.ELEMENT_NODE&&v(r,this.readFeaturesFromNode(n,e));return r},e.prototype.readFeaturesFromNode=function(t,e){return n()},e.prototype.readGeometry=function(t,e){if(t){if("string"==typeof t){var r=Pc(t);return this.readGeometryFromDocument(r,e)}return Cc(t)?this.readGeometryFromDocument(t,e):this.readGeometryFromNode(t,e)}return null},e.prototype.readGeometryFromDocument=function(t,e){return null},e.prototype.readGeometryFromNode=function(t,e){return null},e.prototype.readProjection=function(t){if(t){if("string"==typeof t){var e=Pc(t);return this.readProjectionFromDocument(e)}return Cc(t)?this.readProjectionFromDocument(t):this.readProjectionFromNode(t)}return null},e.prototype.readProjectionFromDocument=function(t){return this.dataProjection},e.prototype.readProjectionFromNode=function(t){return this.dataProjection},e.prototype.writeFeature=function(t,e){var r=this.writeFeatureNode(t,e);return this.xmlSerializer_.serializeToString(r)},e.prototype.writeFeatureNode=function(t,e){return null},e.prototype.writeFeatures=function(t,e){var r=this.writeFeaturesNode(t,e);return this.xmlSerializer_.serializeToString(r)},e.prototype.writeFeaturesNode=function(t,e){return null},e.prototype.writeGeometry=function(t,e){var r=this.writeGeometryNode(t,e);return this.xmlSerializer_.serializeToString(r)},e.prototype.writeGeometryNode=function(t,e){return null},e}(Yy),R_=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),I_="http://www.opengis.net/gml",L_=/^[\s\xa0]*$/,M_=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.featureType=n.featureType,r.featureNS=n.featureNS,r.srsName=n.srsName,r.schemaLocation="",r.FEATURE_COLLECTION_PARSERS={},r.FEATURE_COLLECTION_PARSERS[r.namespace]={featureMember:Ic(r.readFeaturesInternal),featureMembers:Lc(r.readFeaturesInternal)},r}return R_(e,t),e.prototype.readFeaturesInternal=function(t,e){var r=t.localName,n=null;if("FeatureCollection"==r)n=Uc([],this.FEATURE_COLLECTION_PARSERS,t,e,this);else if("featureMembers"==r||"featureMember"==r||"member"==r){var i=e[0],o=i.featureType,a=i.featureNS;if(!o&&t.childNodes){o=[],a={};for(var s=0,l=t.childNodes.length;s<l;++s){var u=t.childNodes[s];if(1===u.nodeType){var c=u.nodeName.split(":").pop();if(-1===o.indexOf(c)){var h="",p=0,f=u.namespaceURI;for(var d in a){if(a[d]===f){h=d;break}++p}h||(a[h="p"+p]=f),o.push(h+":"+c)}}}"featureMember"!=r&&(i.featureType=o,i.featureNS=a)}if("string"==typeof a){var g=a;(a={}).p0=g}var y={},m=Array.isArray(o)?o:[o];for(var v in a){var _={};for(s=0,l=m.length;s<l;++s){(-1===m[s].indexOf(":")?"p0":m[s].split(":")[0])===v&&(_[m[s].split(":").pop()]="featureMembers"==r?Ic(this.readFeatureElement,this):Lc(this.readFeatureElement,this))}y[a[v]]=_}n=Uc("featureMember"==r||"member"==r?void 0:[],y,t,e)}return null===n&&(n=[]),n},e.prototype.readGeometryElement=function(t,e){var r=e[0];r.srsName=t.firstElementChild.getAttribute("srsName"),r.srsDimension=t.firstElementChild.getAttribute("srsDimension");var n=Uc(null,this.GEOMETRY_PARSERS,t,e,this);return n?Array.isArray(n)?qy(n,r):Wy(n,!1,r):void 0},e.prototype.readFeatureElementInternal=function(t,e,r){for(var n,i={},o=t.firstElementChild;o;o=o.nextElementSibling){var a=void 0,s=o.localName;0===o.childNodes.length||1===o.childNodes.length&&(3===o.firstChild.nodeType||4===o.firstChild.nodeType)?(a=Ec(o,!1),L_.test(a)&&(a=void 0)):(r&&(a=this.readGeometryElement(o,e)),a?"boundedBy"!==s&&(n=s):a=this.readFeatureElementInternal(o,e,!1)),i[s]?(i[s]instanceof Array||(i[s]=[i[s]]),i[s].push(a)):i[s]=a;var l=o.attributes.length;if(l>0){i[s]={_content_:i[s]};for(var u=0;u<l;u++){var c=o.attributes[u].name;i[s][c]=o.attributes[u].value}}}if(r){var h=new gt(i);n&&h.setGeometryName(n);var p=t.getAttribute("fid")||Oc(t,this.namespace,"id");return p&&h.setId(p),h}return i},e.prototype.readFeatureElement=function(t,e){return this.readFeatureElementInternal(t,e,!0)},e.prototype.readPoint=function(t,e){var r=this.readFlatCoordinatesFromNode(t,e);if(r)return new qn(r,mt)},e.prototype.readMultiPoint=function(t,e){var r=Uc([],this.MULTIPOINT_PARSERS,t,e,this);return r?new Hy(r):void 0},e.prototype.readMultiLineString=function(t,e){var r=Uc([],this.MULTILINESTRING_PARSERS,t,e,this);if(r)return new Zy(r)},e.prototype.readMultiPolygon=function(t,e){var r=Uc([],this.MULTIPOLYGON_PARSERS,t,e,this);if(r)return new Jy(r)},e.prototype.pointMemberParser=function(t,e){zc(this.POINTMEMBER_PARSERS,t,e,this)},e.prototype.lineStringMemberParser=function(t,e){zc(this.LINESTRINGMEMBER_PARSERS,t,e,this)},e.prototype.polygonMemberParser=function(t,e){zc(this.POLYGONMEMBER_PARSERS,t,e,this)},e.prototype.readLineString=function(t,e){var r=this.readFlatCoordinatesFromNode(t,e);return r?new Py(r,mt):void 0},e.prototype.readFlatLinearRing=function(t,e){var r=Uc(null,this.GEOMETRY_FLAT_COORDINATES_PARSERS,t,e,this);return r||void 0},e.prototype.readLinearRing=function(t,e){var r=this.readFlatCoordinatesFromNode(t,e);if(r)return new Yn(r,mt)},e.prototype.readPolygon=function(t,e){var r=Uc([null],this.FLAT_LINEAR_RINGS_PARSERS,t,e,this);if(r&&r[0]){var n,i=r[0],o=[i.length],a=void 0;for(a=1,n=r.length;a<n;++a)v(i,r[a]),o.push(i.length);return new fi(i,mt,o)}},e.prototype.readFlatCoordinatesFromNode=function(t,e){return Uc(null,this.GEOMETRY_FLAT_COORDINATES_PARSERS,t,e,this)},e.prototype.readGeometryFromNode=function(t,e){var r=this.readGeometryElement(t,[this.getReadOptions(t,e||{})]);return r||null},e.prototype.readFeaturesFromNode=function(t,e){var r={featureType:this.featureType,featureNS:this.featureNS};return e&&O(r,this.getReadOptions(t,e)),this.readFeaturesInternal(t,[r])||[]},e.prototype.readProjectionFromNode=function(t){return Gr(this.srsName?this.srsName:t.firstElementChild.getAttribute("srsName"))},e}(P_);M_.prototype.namespace=I_,M_.prototype.FLAT_LINEAR_RINGS_PARSERS={"http://www.opengis.net/gml":{}},M_.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS={"http://www.opengis.net/gml":{}},M_.prototype.GEOMETRY_PARSERS={"http://www.opengis.net/gml":{}},M_.prototype.MULTIPOINT_PARSERS={"http://www.opengis.net/gml":{pointMember:Ic(M_.prototype.pointMemberParser),pointMembers:Ic(M_.prototype.pointMemberParser)}},M_.prototype.MULTILINESTRING_PARSERS={"http://www.opengis.net/gml":{lineStringMember:Ic(M_.prototype.lineStringMemberParser),lineStringMembers:Ic(M_.prototype.lineStringMemberParser)}},M_.prototype.MULTIPOLYGON_PARSERS={"http://www.opengis.net/gml":{polygonMember:Ic(M_.prototype.polygonMemberParser),polygonMembers:Ic(M_.prototype.polygonMemberParser)}},M_.prototype.POINTMEMBER_PARSERS={"http://www.opengis.net/gml":{Point:Ic(M_.prototype.readFlatCoordinatesFromNode)}},M_.prototype.LINESTRINGMEMBER_PARSERS={"http://www.opengis.net/gml":{LineString:Ic(M_.prototype.readLineString)}},M_.prototype.POLYGONMEMBER_PARSERS={"http://www.opengis.net/gml":{Polygon:Ic(M_.prototype.readPolygon)}},M_.prototype.RING_PARSERS={"http://www.opengis.net/gml":{LinearRing:Lc(M_.prototype.readFlatLinearRing)}};var F_=M_;function A_(t){return k_(Ec(t,!1))}function k_(t){var e=/^\s*(true|1)|(false|0)\s*$/.exec(t);return e?void 0!==e[1]||!1:void 0}function j_(t){var e=Ec(t,!1),r=Date.parse(e);return isNaN(r)?void 0:r/1e3}function N_(t){return D_(Ec(t,!1))}function D_(t){var e=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)\s*$/i.exec(t);return e?parseFloat(e[1]):void 0}function G_(t){return z_(Ec(t,!1))}function z_(t){var e=/^\s*(\d+)\s*$/.exec(t);return e?parseInt(e[1],10):void 0}function U_(t){return Ec(t,!1).trim()}function B_(t,e){X_(t,e?"1":"0")}function V_(t,e){t.appendChild(Xc().createCDATASection(e))}function Y_(t,e){var r=new Date(1e3*e),n=r.getUTCFullYear()+"-"+_r(r.getUTCMonth()+1,2)+"-"+_r(r.getUTCDate(),2)+"T"+_r(r.getUTCHours(),2)+":"+_r(r.getUTCMinutes(),2)+":"+_r(r.getUTCSeconds(),2)+"Z";t.appendChild(Xc().createTextNode(n))}function W_(t,e){var r=e.toPrecision();t.appendChild(Xc().createTextNode(r))}function q_(t,e){var r=e.toString();t.appendChild(Xc().createTextNode(r))}function X_(t,e){t.appendChild(Xc().createTextNode(e))}var Z_=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),K_={MultiLineString:"lineStringMember",MultiCurve:"curveMember",MultiPolygon:"polygonMember",MultiSurface:"surfaceMember"},H_=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,n)||this).FEATURE_COLLECTION_PARSERS[I_].featureMember=Ic(r.readFeaturesInternal),r.schemaLocation=n.schemaLocation?n.schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/2.1.2/feature.xsd",r}return Z_(e,t),e.prototype.readFlatCoordinates=function(t,e){var r=Ec(t,!1).replace(/^\s*|\s*$/g,""),n=e[0].srsName,i="enu";if(n){var o=Gr(n);o&&(i=o.getAxisOrientation())}for(var a=r.trim().split(/\s+/),s=[],l=0,u=a.length;l<u;l++){var c=a[l].split(/,+/),h=parseFloat(c[0]),p=parseFloat(c[1]),f=3===c.length?parseFloat(c[2]):0;"en"===i.substr(0,2)?s.push(h,p,f):s.push(p,h,f)}return s},e.prototype.readBox=function(t,e){var r=Uc([null],this.BOX_PARSERS_,t,e,this);return ie(r[1][0],r[1][1],r[1][3],r[1][4])},e.prototype.innerBoundaryIsParser=function(t,e){var r=Uc(void 0,this.RING_PARSERS,t,e,this);r&&e[e.length-1].push(r)},e.prototype.outerBoundaryIsParser=function(t,e){var r=Uc(void 0,this.RING_PARSERS,t,e,this);r&&(e[e.length-1][0]=r)},e.prototype.GEOMETRY_NODE_FACTORY_=function(t,e,r){var n,i=e[e.length-1],o=i.multiSurface,a=i.surface,s=i.multiCurve;return Array.isArray(t)?n="Envelope":"MultiPolygon"===(n=t.getType())&&!0===o?n="MultiSurface":"Polygon"===n&&!0===a?n="Surface":"MultiLineString"===n&&!0===s&&(n="MultiCurve"),Sc("http://www.opengis.net/gml",n)},e.prototype.writeFeatureElement=function(t,e,r){var n=e.getId();n&&t.setAttribute("fid",n);var i=r[r.length-1],o=i.featureNS,a=e.getGeometryName();i.serializers||(i.serializers={},i.serializers[o]={});var s=[],l=[];if(e.hasProperties()){var u=e.getProperties();for(var c in u){var h=u[c];null!==h&&(s.push(c),l.push(h),c==a||"function"==typeof h.getSimplifiedGeometry?c in i.serializers[o]||(i.serializers[o][c]=Ac(this.writeGeometryElement,this)):c in i.serializers[o]||(i.serializers[o][c]=Ac(X_)))}}var p=O({},i);p.node=t,Vc(p,i.serializers,jc(void 0,o),l,r,s)},e.prototype.writeCurveOrLineString=function(t,e,r){var n=r[r.length-1].srsName;if("LineStringSegment"!==t.nodeName&&n&&t.setAttribute("srsName",n),"LineString"===t.nodeName||"LineStringSegment"===t.nodeName){var i=this.createCoordinatesNode_(t.namespaceURI);t.appendChild(i),this.writeCoordinates_(i,e,r)}else if("Curve"===t.nodeName){var o=Sc(t.namespaceURI,"segments");t.appendChild(o),this.writeCurveSegments_(o,e,r)}},e.prototype.writeLineStringOrCurveMember=function(t,e,r){var n=this.GEOMETRY_NODE_FACTORY_(e,r);n&&(t.appendChild(n),this.writeCurveOrLineString(n,e,r))},e.prototype.writeMultiCurveOrLineString=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName,a=n.curve;o&&t.setAttribute("srsName",o);var s=e.getLineStrings();Vc({node:t,hasZ:i,srsName:o,curve:a},this.LINESTRINGORCURVEMEMBER_SERIALIZERS,this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_,s,r,void 0,this)},e.prototype.writeGeometryElement=function(t,e,r){var n,i=r[r.length-1],o=O({},i);o.node=t,n=Array.isArray(e)?qy(e,i):Wy(e,!0,i),Vc(o,this.GEOMETRY_SERIALIZERS,this.GEOMETRY_NODE_FACTORY_,[n],r,void 0,this)},e.prototype.createCoordinatesNode_=function(t){var e=Sc(t,"coordinates");return e.setAttribute("decimal","."),e.setAttribute("cs",","),e.setAttribute("ts"," "),e},e.prototype.writeCoordinates_=function(t,e,r){for(var n=r[r.length-1],i=n.hasZ,o=n.srsName,a=e.getCoordinates(),s=a.length,l=new Array(s),u=0;u<s;++u){var c=a[u];l[u]=this.getCoords_(c,o,i)}X_(t,l.join(" "))},e.prototype.writeCurveSegments_=function(t,e,r){var n=Sc(t.namespaceURI,"LineStringSegment");t.appendChild(n),this.writeCurveOrLineString(n,e,r)},e.prototype.writeSurfaceOrPolygon=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName;if("PolygonPatch"!==t.nodeName&&o&&t.setAttribute("srsName",o),"Polygon"===t.nodeName||"PolygonPatch"===t.nodeName){var a=e.getLinearRings();Vc({node:t,hasZ:i,srsName:o},this.RING_SERIALIZERS,this.RING_NODE_FACTORY_,a,r,void 0,this)}else if("Surface"===t.nodeName){var s=Sc(t.namespaceURI,"patches");t.appendChild(s),this.writeSurfacePatches_(s,e,r)}},e.prototype.RING_NODE_FACTORY_=function(t,e,r){var n=e[e.length-1],i=n.node,o=n.exteriorWritten;return void 0===o&&(n.exteriorWritten=!0),Sc(i.namespaceURI,void 0!==o?"innerBoundaryIs":"outerBoundaryIs")},e.prototype.writeSurfacePatches_=function(t,e,r){var n=Sc(t.namespaceURI,"PolygonPatch");t.appendChild(n),this.writeSurfaceOrPolygon(n,e,r)},e.prototype.writeRing=function(t,e,r){var n=Sc(t.namespaceURI,"LinearRing");t.appendChild(n),this.writeLinearRing(n,e,r)},e.prototype.getCoords_=function(t,e,r){var n="enu";e&&(n=Gr(e).getAxisOrientation());var i="en"===n.substr(0,2)?t[0]+","+t[1]:t[1]+","+t[0];r&&(i+=","+(t[2]||0));return i},e.prototype.writePoint=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName;o&&t.setAttribute("srsName",o);var a=this.createCoordinatesNode_(t.namespaceURI);t.appendChild(a);var s=e.getCoordinates();X_(a,this.getCoords_(s,o,i))},e.prototype.writeMultiPoint=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName;o&&t.setAttribute("srsName",o);var a=e.getPoints();Vc({node:t,hasZ:i,srsName:o},this.POINTMEMBER_SERIALIZERS,jc("pointMember"),a,r,void 0,this)},e.prototype.writePointMember=function(t,e,r){var n=Sc(t.namespaceURI,"Point");t.appendChild(n),this.writePoint(n,e,r)},e.prototype.writeLinearRing=function(t,e,r){var n=r[r.length-1].srsName;n&&t.setAttribute("srsName",n);var i=this.createCoordinatesNode_(t.namespaceURI);t.appendChild(i),this.writeCoordinates_(i,e,r)},e.prototype.writeMultiSurfaceOrPolygon=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName,a=n.surface;o&&t.setAttribute("srsName",o);var s=e.getPolygons();Vc({node:t,hasZ:i,srsName:o,surface:a},this.SURFACEORPOLYGONMEMBER_SERIALIZERS,this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_,s,r,void 0,this)},e.prototype.writeSurfaceOrPolygonMember=function(t,e,r){var n=this.GEOMETRY_NODE_FACTORY_(e,r);n&&(t.appendChild(n),this.writeSurfaceOrPolygon(n,e,r))},e.prototype.writeEnvelope=function(t,e,r){var n=r[r.length-1].srsName;n&&t.setAttribute("srsName",n);var i=[e[0]+" "+e[1],e[2]+" "+e[3]];Vc({node:t},this.ENVELOPE_SERIALIZERS,Nc,i,r,["lowerCorner","upperCorner"],this)},e.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_=function(t,e,r){var n=e[e.length-1].node;return Sc("http://www.opengis.net/gml",K_[n.nodeName])},e}(F_);H_.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS={"http://www.opengis.net/gml":{coordinates:Lc(H_.prototype.readFlatCoordinates)}},H_.prototype.FLAT_LINEAR_RINGS_PARSERS={"http://www.opengis.net/gml":{innerBoundaryIs:H_.prototype.innerBoundaryIsParser,outerBoundaryIs:H_.prototype.outerBoundaryIsParser}},H_.prototype.BOX_PARSERS_={"http://www.opengis.net/gml":{coordinates:Ic(H_.prototype.readFlatCoordinates)}},H_.prototype.GEOMETRY_PARSERS={"http://www.opengis.net/gml":{Point:Lc(F_.prototype.readPoint),MultiPoint:Lc(F_.prototype.readMultiPoint),LineString:Lc(F_.prototype.readLineString),MultiLineString:Lc(F_.prototype.readMultiLineString),LinearRing:Lc(F_.prototype.readLinearRing),Polygon:Lc(F_.prototype.readPolygon),MultiPolygon:Lc(F_.prototype.readMultiPolygon),Box:Lc(H_.prototype.readBox)}},H_.prototype.GEOMETRY_SERIALIZERS={"http://www.opengis.net/gml":{Curve:Ac(H_.prototype.writeCurveOrLineString),MultiCurve:Ac(H_.prototype.writeMultiCurveOrLineString),Point:Ac(H_.prototype.writePoint),MultiPoint:Ac(H_.prototype.writeMultiPoint),LineString:Ac(H_.prototype.writeCurveOrLineString),MultiLineString:Ac(H_.prototype.writeMultiCurveOrLineString),LinearRing:Ac(H_.prototype.writeLinearRing),Polygon:Ac(H_.prototype.writeSurfaceOrPolygon),MultiPolygon:Ac(H_.prototype.writeMultiSurfaceOrPolygon),Surface:Ac(H_.prototype.writeSurfaceOrPolygon),MultiSurface:Ac(H_.prototype.writeMultiSurfaceOrPolygon),Envelope:Ac(H_.prototype.writeEnvelope)}},H_.prototype.LINESTRINGORCURVEMEMBER_SERIALIZERS={"http://www.opengis.net/gml":{lineStringMember:Ac(H_.prototype.writeLineStringOrCurveMember),curveMember:Ac(H_.prototype.writeLineStringOrCurveMember)}},H_.prototype.RING_SERIALIZERS={"http://www.opengis.net/gml":{outerBoundaryIs:Ac(H_.prototype.writeRing),innerBoundaryIs:Ac(H_.prototype.writeRing)}},H_.prototype.POINTMEMBER_SERIALIZERS={"http://www.opengis.net/gml":{pointMember:Ac(H_.prototype.writePointMember)}},H_.prototype.SURFACEORPOLYGONMEMBER_SERIALIZERS={"http://www.opengis.net/gml":{surfaceMember:Ac(H_.prototype.writeSurfaceOrPolygonMember),polygonMember:Ac(H_.prototype.writeSurfaceOrPolygonMember)}},H_.prototype.ENVELOPE_SERIALIZERS={"http://www.opengis.net/gml":{lowerCorner:Ac(X_),upperCorner:Ac(X_)}};var $_=H_,J_=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),Q_={MultiLineString:"lineStringMember",MultiCurve:"curveMember",MultiPolygon:"polygonMember",MultiSurface:"surfaceMember"},tb=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,n)||this).surface_=void 0!==n.surface&&n.surface,r.curve_=void 0!==n.curve&&n.curve,r.multiCurve_=void 0===n.multiCurve||n.multiCurve,r.multiSurface_=void 0===n.multiSurface||n.multiSurface,r.schemaLocation=n.schemaLocation?n.schemaLocation:"http://www.opengis.net/gml http://schemas.opengis.net/gml/3.1.1/profiles/gmlsfProfile/1.0.0/gmlsf.xsd",r.hasZ=void 0!==n.hasZ&&n.hasZ,r}return J_(e,t),e.prototype.readMultiCurve=function(t,e){var r=Uc([],this.MULTICURVE_PARSERS,t,e,this);return r?new Zy(r):void 0},e.prototype.readMultiSurface=function(t,e){var r=Uc([],this.MULTISURFACE_PARSERS,t,e,this);if(r)return new Jy(r)},e.prototype.curveMemberParser=function(t,e){zc(this.CURVEMEMBER_PARSERS,t,e,this)},e.prototype.surfaceMemberParser=function(t,e){zc(this.SURFACEMEMBER_PARSERS,t,e,this)},e.prototype.readPatch=function(t,e){return Uc([null],this.PATCHES_PARSERS,t,e,this)},e.prototype.readSegment=function(t,e){return Uc([null],this.SEGMENTS_PARSERS,t,e,this)},e.prototype.readPolygonPatch=function(t,e){return Uc([null],this.FLAT_LINEAR_RINGS_PARSERS,t,e,this)},e.prototype.readLineStringSegment=function(t,e){return Uc([null],this.GEOMETRY_FLAT_COORDINATES_PARSERS,t,e,this)},e.prototype.interiorParser=function(t,e){var r=Uc(void 0,this.RING_PARSERS,t,e,this);r&&e[e.length-1].push(r)},e.prototype.exteriorParser=function(t,e){var r=Uc(void 0,this.RING_PARSERS,t,e,this);r&&(e[e.length-1][0]=r)},e.prototype.readSurface=function(t,e){var r=Uc([null],this.SURFACE_PARSERS,t,e,this);if(r&&r[0]){var n,i=r[0],o=[i.length],a=void 0;for(a=1,n=r.length;a<n;++a)v(i,r[a]),o.push(i.length);return new fi(i,mt,o)}},e.prototype.readCurve=function(t,e){var r=Uc([null],this.CURVE_PARSERS,t,e,this);return r?new Py(r,mt):void 0},e.prototype.readEnvelope=function(t,e){var r=Uc([null],this.ENVELOPE_PARSERS,t,e,this);return ie(r[1][0],r[1][1],r[2][0],r[2][1])},e.prototype.readFlatPos=function(t,e){for(var r,n=Ec(t,!1),i=/^\s*([+\-]?\d*\.?\d+(?:[eE][+\-]?\d+)?)\s*/,o=[];r=i.exec(n);)o.push(parseFloat(r[1])),n=n.substr(r[0].length);if(""===n){var a=e[0].srsName,s="enu";if(a)s=Gr(a).getAxisOrientation();if("neu"===s){var l,u=void 0;for(u=0,l=o.length;u<l;u+=3){var c=o[u],h=o[u+1];o[u]=h,o[u+1]=c}}var p=o.length;if(2==p&&o.push(0),0!==p)return o}},e.prototype.readFlatPosList=function(t,e){var r=Ec(t,!1).replace(/^\s*|\s*$/g,""),n=e[0],i=n.srsName,o=n.srsDimension,a="enu";i&&(a=Gr(i).getAxisOrientation());var s,l,u,c=r.split(/\s+/),h=2;t.getAttribute("srsDimension")?h=z_(t.getAttribute("srsDimension")):t.getAttribute("dimension")?h=z_(t.getAttribute("dimension")):t.parentNode.getAttribute("srsDimension")?h=z_(t.parentNode.getAttribute("srsDimension")):o&&(h=z_(o));for(var p=[],f=0,d=c.length;f<d;f+=h)s=parseFloat(c[f]),l=parseFloat(c[f+1]),u=3===h?parseFloat(c[f+2]):0,"en"===a.substr(0,2)?p.push(s,l,u):p.push(l,s,u);return p},e.prototype.writePos_=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=i?"3":"2";t.setAttribute("srsDimension",o);var a=n.srsName,s="enu";a&&(s=Gr(a).getAxisOrientation());var l,u=e.getCoordinates();(l="en"===s.substr(0,2)?u[0]+" "+u[1]:u[1]+" "+u[0],i)&&(l+=" "+(u[2]||0));X_(t,l)},e.prototype.getCoords_=function(t,e,r){var n="enu";e&&(n=Gr(e).getAxisOrientation());var i="en"===n.substr(0,2)?t[0]+" "+t[1]:t[1]+" "+t[0];r&&(i+=" "+(t[2]||0));return i},e.prototype.writePosList_=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=i?"3":"2";t.setAttribute("srsDimension",o);for(var a,s=n.srsName,l=e.getCoordinates(),u=l.length,c=new Array(u),h=0;h<u;++h)a=l[h],c[h]=this.getCoords_(a,s,i);X_(t,c.join(" "))},e.prototype.writePoint=function(t,e,r){var n=r[r.length-1].srsName;n&&t.setAttribute("srsName",n);var i=Sc(t.namespaceURI,"pos");t.appendChild(i),this.writePos_(i,e,r)},e.prototype.writeEnvelope=function(t,e,r){var n=r[r.length-1].srsName;n&&t.setAttribute("srsName",n);var i=[e[0]+" "+e[1],e[2]+" "+e[3]];Vc({node:t},this.ENVELOPE_SERIALIZERS,Nc,i,r,["lowerCorner","upperCorner"],this)},e.prototype.writeLinearRing=function(t,e,r){var n=r[r.length-1].srsName;n&&t.setAttribute("srsName",n);var i=Sc(t.namespaceURI,"posList");t.appendChild(i),this.writePosList_(i,e,r)},e.prototype.RING_NODE_FACTORY_=function(t,e,r){var n=e[e.length-1],i=n.node,o=n.exteriorWritten;return void 0===o&&(n.exteriorWritten=!0),Sc(i.namespaceURI,void 0!==o?"interior":"exterior")},e.prototype.writeSurfaceOrPolygon=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName;if("PolygonPatch"!==t.nodeName&&o&&t.setAttribute("srsName",o),"Polygon"===t.nodeName||"PolygonPatch"===t.nodeName){var a=e.getLinearRings();Vc({node:t,hasZ:i,srsName:o},this.RING_SERIALIZERS,this.RING_NODE_FACTORY_,a,r,void 0,this)}else if("Surface"===t.nodeName){var s=Sc(t.namespaceURI,"patches");t.appendChild(s),this.writeSurfacePatches_(s,e,r)}},e.prototype.writeCurveOrLineString=function(t,e,r){var n=r[r.length-1].srsName;if("LineStringSegment"!==t.nodeName&&n&&t.setAttribute("srsName",n),"LineString"===t.nodeName||"LineStringSegment"===t.nodeName){var i=Sc(t.namespaceURI,"posList");t.appendChild(i),this.writePosList_(i,e,r)}else if("Curve"===t.nodeName){var o=Sc(t.namespaceURI,"segments");t.appendChild(o),this.writeCurveSegments_(o,e,r)}},e.prototype.writeMultiSurfaceOrPolygon=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName,a=n.surface;o&&t.setAttribute("srsName",o);var s=e.getPolygons();Vc({node:t,hasZ:i,srsName:o,surface:a},this.SURFACEORPOLYGONMEMBER_SERIALIZERS,this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_,s,r,void 0,this)},e.prototype.writeMultiPoint=function(t,e,r){var n=r[r.length-1],i=n.srsName,o=n.hasZ;i&&t.setAttribute("srsName",i);var a=e.getPoints();Vc({node:t,hasZ:o,srsName:i},this.POINTMEMBER_SERIALIZERS,jc("pointMember"),a,r,void 0,this)},e.prototype.writeMultiCurveOrLineString=function(t,e,r){var n=r[r.length-1],i=n.hasZ,o=n.srsName,a=n.curve;o&&t.setAttribute("srsName",o);var s=e.getLineStrings();Vc({node:t,hasZ:i,srsName:o,curve:a},this.LINESTRINGORCURVEMEMBER_SERIALIZERS,this.MULTIGEOMETRY_MEMBER_NODE_FACTORY_,s,r,void 0,this)},e.prototype.writeRing=function(t,e,r){var n=Sc(t.namespaceURI,"LinearRing");t.appendChild(n),this.writeLinearRing(n,e,r)},e.prototype.writeSurfaceOrPolygonMember=function(t,e,r){var n=this.GEOMETRY_NODE_FACTORY_(e,r);n&&(t.appendChild(n),this.writeSurfaceOrPolygon(n,e,r))},e.prototype.writePointMember=function(t,e,r){var n=Sc(t.namespaceURI,"Point");t.appendChild(n),this.writePoint(n,e,r)},e.prototype.writeLineStringOrCurveMember=function(t,e,r){var n=this.GEOMETRY_NODE_FACTORY_(e,r);n&&(t.appendChild(n),this.writeCurveOrLineString(n,e,r))},e.prototype.writeSurfacePatches_=function(t,e,r){var n=Sc(t.namespaceURI,"PolygonPatch");t.appendChild(n),this.writeSurfaceOrPolygon(n,e,r)},e.prototype.writeCurveSegments_=function(t,e,r){var n=Sc(t.namespaceURI,"LineStringSegment");t.appendChild(n),this.writeCurveOrLineString(n,e,r)},e.prototype.writeGeometryElement=function(t,e,r){var n,i=r[r.length-1],o=O({},i);o.node=t,n=Array.isArray(e)?qy(e,i):Wy(e,!0,i),Vc(o,this.GEOMETRY_SERIALIZERS,this.GEOMETRY_NODE_FACTORY_,[n],r,void 0,this)},e.prototype.writeFeatureElement=function(t,e,r){var n=e.getId();n&&t.setAttribute("fid",n);var i=r[r.length-1],o=i.featureNS,a=e.getGeometryName();i.serializers||(i.serializers={},i.serializers[o]={});var s=[],l=[];if(e.hasProperties()){var u=e.getProperties();for(var c in u){var h=u[c];null!==h&&(s.push(c),l.push(h),c==a||"function"==typeof h.getSimplifiedGeometry?c in i.serializers[o]||(i.serializers[o][c]=Ac(this.writeGeometryElement,this)):c in i.serializers[o]||(i.serializers[o][c]=Ac(X_)))}}var p=O({},i);p.node=t,Vc(p,i.serializers,jc(void 0,o),l,r,s)},e.prototype.writeFeatureMembers_=function(t,e,r){var n=r[r.length-1],i=n.featureType,o=n.featureNS,a={};a[o]={},a[o][i]=Ac(this.writeFeatureElement,this);var s=O({},n);s.node=t,Vc(s,a,jc(i,o),e,r)},e.prototype.MULTIGEOMETRY_MEMBER_NODE_FACTORY_=function(t,e,r){var n=e[e.length-1].node;return Sc(this.namespace,Q_[n.nodeName])},e.prototype.GEOMETRY_NODE_FACTORY_=function(t,e,r){var n,i=e[e.length-1],o=i.multiSurface,a=i.surface,s=i.curve,l=i.multiCurve;return Array.isArray(t)?n="Envelope":"MultiPolygon"===(n=t.getType())&&!0===o?n="MultiSurface":"Polygon"===n&&!0===a?n="Surface":"LineString"===n&&!0===s?n="Curve":"MultiLineString"===n&&!0===l&&(n="MultiCurve"),Sc(this.namespace,n)},e.prototype.writeGeometryNode=function(t,e){e=this.adaptOptions(e);var r=Sc(this.namespace,"geom"),n={node:r,hasZ:this.hasZ,srsName:this.srsName,curve:this.curve_,surface:this.surface_,multiSurface:this.multiSurface_,multiCurve:this.multiCurve_};return e&&O(n,e),this.writeGeometryElement(r,t,[n]),r},e.prototype.writeFeaturesNode=function(t,e){e=this.adaptOptions(e);var r=Sc(this.namespace,"featureMembers");r.setAttributeNS(wc,"xsi:schemaLocation",this.schemaLocation);var n={srsName:this.srsName,hasZ:this.hasZ,curve:this.curve_,surface:this.surface_,multiSurface:this.multiSurface_,multiCurve:this.multiCurve_,featureNS:this.featureNS,featureType:this.featureType};return e&&O(n,e),this.writeFeatureMembers_(r,t,[n]),r},e}(F_);tb.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS={"http://www.opengis.net/gml":{pos:Lc(tb.prototype.readFlatPos),posList:Lc(tb.prototype.readFlatPosList),coordinates:Lc($_.prototype.readFlatCoordinates)}},tb.prototype.FLAT_LINEAR_RINGS_PARSERS={"http://www.opengis.net/gml":{interior:tb.prototype.interiorParser,exterior:tb.prototype.exteriorParser}},tb.prototype.GEOMETRY_PARSERS={"http://www.opengis.net/gml":{Point:Lc(F_.prototype.readPoint),MultiPoint:Lc(F_.prototype.readMultiPoint),LineString:Lc(F_.prototype.readLineString),MultiLineString:Lc(F_.prototype.readMultiLineString),LinearRing:Lc(F_.prototype.readLinearRing),Polygon:Lc(F_.prototype.readPolygon),MultiPolygon:Lc(F_.prototype.readMultiPolygon),Surface:Lc(tb.prototype.readSurface),MultiSurface:Lc(tb.prototype.readMultiSurface),Curve:Lc(tb.prototype.readCurve),MultiCurve:Lc(tb.prototype.readMultiCurve),Envelope:Lc(tb.prototype.readEnvelope)}},tb.prototype.MULTICURVE_PARSERS={"http://www.opengis.net/gml":{curveMember:Ic(tb.prototype.curveMemberParser),curveMembers:Ic(tb.prototype.curveMemberParser)}},tb.prototype.MULTISURFACE_PARSERS={"http://www.opengis.net/gml":{surfaceMember:Ic(tb.prototype.surfaceMemberParser),surfaceMembers:Ic(tb.prototype.surfaceMemberParser)}},tb.prototype.CURVEMEMBER_PARSERS={"http://www.opengis.net/gml":{LineString:Ic(F_.prototype.readLineString),Curve:Ic(tb.prototype.readCurve)}},tb.prototype.SURFACEMEMBER_PARSERS={"http://www.opengis.net/gml":{Polygon:Ic(F_.prototype.readPolygon),Surface:Ic(tb.prototype.readSurface)}},tb.prototype.SURFACE_PARSERS={"http://www.opengis.net/gml":{patches:Lc(tb.prototype.readPatch)}},tb.prototype.CURVE_PARSERS={"http://www.opengis.net/gml":{segments:Lc(tb.prototype.readSegment)}},tb.prototype.ENVELOPE_PARSERS={"http://www.opengis.net/gml":{lowerCorner:Ic(tb.prototype.readFlatPosList),upperCorner:Ic(tb.prototype.readFlatPosList)}},tb.prototype.PATCHES_PARSERS={"http://www.opengis.net/gml":{PolygonPatch:Lc(tb.prototype.readPolygonPatch)}},tb.prototype.SEGMENTS_PARSERS={"http://www.opengis.net/gml":{LineStringSegment:Lc(tb.prototype.readLineStringSegment)}},tb.prototype.writeFeatures,tb.prototype.RING_SERIALIZERS={"http://www.opengis.net/gml":{exterior:Ac(tb.prototype.writeRing),interior:Ac(tb.prototype.writeRing)}},tb.prototype.ENVELOPE_SERIALIZERS={"http://www.opengis.net/gml":{lowerCorner:Ac(X_),upperCorner:Ac(X_)}},tb.prototype.SURFACEORPOLYGONMEMBER_SERIALIZERS={"http://www.opengis.net/gml":{surfaceMember:Ac(tb.prototype.writeSurfaceOrPolygonMember),polygonMember:Ac(tb.prototype.writeSurfaceOrPolygonMember)}},tb.prototype.POINTMEMBER_SERIALIZERS={"http://www.opengis.net/gml":{pointMember:Ac(tb.prototype.writePointMember)}},tb.prototype.LINESTRINGORCURVEMEMBER_SERIALIZERS={"http://www.opengis.net/gml":{lineStringMember:Ac(tb.prototype.writeLineStringOrCurveMember),curveMember:Ac(tb.prototype.writeLineStringOrCurveMember)}},tb.prototype.GEOMETRY_SERIALIZERS={"http://www.opengis.net/gml":{Curve:Ac(tb.prototype.writeCurveOrLineString),MultiCurve:Ac(tb.prototype.writeMultiCurveOrLineString),Point:Ac(tb.prototype.writePoint),MultiPoint:Ac(tb.prototype.writeMultiPoint),LineString:Ac(tb.prototype.writeCurveOrLineString),MultiLineString:Ac(tb.prototype.writeMultiCurveOrLineString),LinearRing:Ac(tb.prototype.writeLinearRing),Polygon:Ac(tb.prototype.writeSurfaceOrPolygon),MultiPolygon:Ac(tb.prototype.writeMultiSurfaceOrPolygon),Surface:Ac(tb.prototype.writeSurfaceOrPolygon),MultiSurface:Ac(tb.prototype.writeMultiSurfaceOrPolygon),Envelope:Ac(tb.prototype.writeEnvelope)}};var eb=tb,rb=eb;rb.prototype.writeFeatures,rb.prototype.writeFeaturesNode;var nb=rb,ib=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ob=function(t){function e(e){var r=this,n=e||{};return(r=t.call(this,n)||this).schemaLocation=n.schemaLocation?n.schemaLocation:r.namespace+" http://schemas.opengis.net/gml/3.2.1/gml.xsd",r}return ib(e,t),e}(eb);ob.prototype.namespace="http://www.opengis.net/gml/3.2",ob.prototype.GEOMETRY_FLAT_COORDINATES_PARSERS={"http://www.opengis.net/gml/3.2":{pos:Lc(eb.prototype.readFlatPos),posList:Lc(eb.prototype.readFlatPosList),coordinates:Lc($_.prototype.readFlatCoordinates)}},ob.prototype.FLAT_LINEAR_RINGS_PARSERS={"http://www.opengis.net/gml/3.2":{interior:eb.prototype.interiorParser,exterior:eb.prototype.exteriorParser}},ob.prototype.GEOMETRY_PARSERS={"http://www.opengis.net/gml/3.2":{Point:Lc(F_.prototype.readPoint),MultiPoint:Lc(F_.prototype.readMultiPoint),LineString:Lc(F_.prototype.readLineString),MultiLineString:Lc(F_.prototype.readMultiLineString),LinearRing:Lc(F_.prototype.readLinearRing),Polygon:Lc(F_.prototype.readPolygon),MultiPolygon:Lc(F_.prototype.readMultiPolygon),Surface:Lc(ob.prototype.readSurface),MultiSurface:Lc(eb.prototype.readMultiSurface),Curve:Lc(ob.prototype.readCurve),MultiCurve:Lc(eb.prototype.readMultiCurve),Envelope:Lc(ob.prototype.readEnvelope)}},ob.prototype.MULTICURVE_PARSERS={"http://www.opengis.net/gml/3.2":{curveMember:Ic(eb.prototype.curveMemberParser),curveMembers:Ic(eb.prototype.curveMemberParser)}},ob.prototype.MULTISURFACE_PARSERS={"http://www.opengis.net/gml/3.2":{surfaceMember:Ic(eb.prototype.surfaceMemberParser),surfaceMembers:Ic(eb.prototype.surfaceMemberParser)}},ob.prototype.CURVEMEMBER_PARSERS={"http://www.opengis.net/gml/3.2":{LineString:Ic(F_.prototype.readLineString),Curve:Ic(eb.prototype.readCurve)}},ob.prototype.SURFACEMEMBER_PARSERS={"http://www.opengis.net/gml/3.2":{Polygon:Ic(F_.prototype.readPolygon),Surface:Ic(eb.prototype.readSurface)}},ob.prototype.SURFACE_PARSERS={"http://www.opengis.net/gml/3.2":{patches:Lc(eb.prototype.readPatch)}},ob.prototype.CURVE_PARSERS={"http://www.opengis.net/gml/3.2":{segments:Lc(eb.prototype.readSegment)}},ob.prototype.ENVELOPE_PARSERS={"http://www.opengis.net/gml/3.2":{lowerCorner:Ic(eb.prototype.readFlatPosList),upperCorner:Ic(eb.prototype.readFlatPosList)}},ob.prototype.PATCHES_PARSERS={"http://www.opengis.net/gml/3.2":{PolygonPatch:Lc(eb.prototype.readPolygonPatch)}},ob.prototype.SEGMENTS_PARSERS={"http://www.opengis.net/gml/3.2":{LineStringSegment:Lc(eb.prototype.readLineStringSegment)}},ob.prototype.MULTIPOINT_PARSERS={"http://www.opengis.net/gml/3.2":{pointMember:Ic(F_.prototype.pointMemberParser),pointMembers:Ic(F_.prototype.pointMemberParser)}},ob.prototype.MULTILINESTRING_PARSERS={"http://www.opengis.net/gml/3.2":{lineStringMember:Ic(F_.prototype.lineStringMemberParser),lineStringMembers:Ic(F_.prototype.lineStringMemberParser)}},ob.prototype.MULTIPOLYGON_PARSERS={"http://www.opengis.net/gml/3.2":{polygonMember:Ic(F_.prototype.polygonMemberParser),polygonMembers:Ic(F_.prototype.polygonMemberParser)}},ob.prototype.POINTMEMBER_PARSERS={"http://www.opengis.net/gml/3.2":{Point:Ic(F_.prototype.readFlatCoordinatesFromNode)}},ob.prototype.LINESTRINGMEMBER_PARSERS={"http://www.opengis.net/gml/3.2":{LineString:Ic(F_.prototype.readLineString)}},ob.prototype.POLYGONMEMBER_PARSERS={"http://www.opengis.net/gml/3.2":{Polygon:Ic(F_.prototype.readPolygon)}},ob.prototype.RING_PARSERS={"http://www.opengis.net/gml/3.2":{LinearRing:Lc(F_.prototype.readFlatLinearRing)}},ob.prototype.RING_SERIALIZERS={"http://www.opengis.net/gml/3.2":{exterior:Ac(eb.prototype.writeRing),interior:Ac(eb.prototype.writeRing)}},ob.prototype.ENVELOPE_SERIALIZERS={"http://www.opengis.net/gml/3.2":{lowerCorner:Ac(X_),upperCorner:Ac(X_)}},ob.prototype.SURFACEORPOLYGONMEMBER_SERIALIZERS={"http://www.opengis.net/gml/3.2":{surfaceMember:Ac(eb.prototype.writeSurfaceOrPolygonMember),polygonMember:Ac(eb.prototype.writeSurfaceOrPolygonMember)}},ob.prototype.POINTMEMBER_SERIALIZERS={"http://www.opengis.net/gml/3.2":{pointMember:Ac(eb.prototype.writePointMember)}},ob.prototype.LINESTRINGORCURVEMEMBER_SERIALIZERS={"http://www.opengis.net/gml/3.2":{lineStringMember:Ac(eb.prototype.writeLineStringOrCurveMember),curveMember:Ac(eb.prototype.writeLineStringOrCurveMember)}},ob.prototype.GEOMETRY_SERIALIZERS={"http://www.opengis.net/gml/3.2":{Curve:Ac(eb.prototype.writeCurveOrLineString),MultiCurve:Ac(eb.prototype.writeMultiCurveOrLineString),Point:Ac(ob.prototype.writePoint),MultiPoint:Ac(eb.prototype.writeMultiPoint),LineString:Ac(eb.prototype.writeCurveOrLineString),MultiLineString:Ac(eb.prototype.writeMultiCurveOrLineString),LinearRing:Ac(eb.prototype.writeLinearRing),Polygon:Ac(eb.prototype.writeSurfaceOrPolygon),MultiPolygon:Ac(eb.prototype.writeMultiSurfaceOrPolygon),Surface:Ac(eb.prototype.writeSurfaceOrPolygon),MultiSurface:Ac(eb.prototype.writeMultiSurfaceOrPolygon),Envelope:Ac(eb.prototype.writeEnvelope)}};var ab=ob,sb=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),lb=[null,"http://www.topografix.com/GPX/1/0","http://www.topografix.com/GPX/1/1"],ub={rte:Nb,trk:Db,wpt:Gb},cb=Gc(lb,{rte:Ic(Nb),trk:Ic(Db),wpt:Ic(Gb)}),hb=Gc(lb,{text:Fc(U_,"linkText"),type:Fc(U_,"linkType")}),pb=Gc(lb,{rte:Ac((function(t,e,r){var n=r[0],i=e.getProperties(),o={node:t};o.properties=i;var a=e.getGeometry();if(a.getType()==bt.LINE_STRING){var s=Wy(a,!0,n);o.geometryLayout=s.getLayout(),i.rtept=s.getCoordinates()}var l=r[r.length-1].node,u=wb[l.namespaceURI],c=Dc(i,u);Vc(o,Sb,Nc,c,r,u)})),trk:Ac((function(t,e,r){var n=r[0],i=e.getProperties(),o={node:t};o.properties=i;var a=e.getGeometry();if(a.getType()==bt.MULTI_LINE_STRING){var s=Wy(a,!0,n);i.trkseg=s.getLineStrings()}var l=r[r.length-1].node,u=Tb[l.namespaceURI],c=Dc(i,u);Vc(o,Cb,Nc,c,r,u)})),wpt:Ac((function(t,e,r){var n=r[0],i=r[r.length-1];i.properties=e.getProperties();var o=e.getGeometry();if(o.getType()==bt.POINT){var a=Wy(o,!0,n);i.geometryLayout=a.getLayout(),Ub(t,a.getCoordinates(),r)}}))}),fb=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.dataProjection=Gr("EPSG:4326"),r.readExtensions_=n.readExtensions,r}return sb(e,t),e.prototype.handleReadExtensions_=function(t){t||(t=[]);for(var e=0,r=t.length;e<r;++e){var n=t[e];if(this.readExtensions_){var i=n.get("extensionsNode_")||null;this.readExtensions_(n,i)}n.set("extensionsNode_",void 0)}},e.prototype.readFeatureFromNode=function(t,e){if(!g(lb,t.namespaceURI))return null;var r=ub[t.localName];if(!r)return null;var n=r(t,[this.getReadOptions(t,e)]);return n?(this.handleReadExtensions_([n]),n):null},e.prototype.readFeaturesFromNode=function(t,e){if(!g(lb,t.namespaceURI))return[];if("gpx"==t.localName){var r=Uc([],cb,t,[this.getReadOptions(t,e)]);return r?(this.handleReadExtensions_(r),r):[]}return[]},e.prototype.writeFeaturesNode=function(t,e){e=this.adaptOptions(e);var r=Sc("http://www.topografix.com/GPX/1/1","gpx");return r.setAttributeNS("http://www.w3.org/2000/xmlns/","xmlns:xsi",wc),r.setAttributeNS(wc,"xsi:schemaLocation","http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd"),r.setAttribute("version","1.1"),r.setAttribute("creator","OpenLayers"),Vc({node:r},pb,Mb,t,[e]),r},e}(P_),db=Gc(lb,{name:Fc(U_),cmt:Fc(U_),desc:Fc(U_),src:Fc(U_),link:kb,number:Fc(G_),extensions:jb,type:Fc(U_),rtept:function(t,e){var r=Uc({},gb,t,e);if(r){var n=e[e.length-1],i=n.flatCoordinates,o=n.layoutOptions;Fb(i,o,t,r)}}}),gb=Gc(lb,{ele:Fc(N_),time:Fc(j_)}),yb=Gc(lb,{name:Fc(U_),cmt:Fc(U_),desc:Fc(U_),src:Fc(U_),link:kb,number:Fc(G_),type:Fc(U_),extensions:jb,trkseg:function(t,e){var r=e[e.length-1];zc(mb,t,e);var n=r.flatCoordinates;r.ends.push(n.length)}}),mb=Gc(lb,{trkpt:function(t,e){var r=Uc({},vb,t,e);if(r){var n=e[e.length-1],i=n.flatCoordinates,o=n.layoutOptions;Fb(i,o,t,r)}}}),vb=Gc(lb,{ele:Fc(N_),time:Fc(j_)}),_b=Gc(lb,{ele:Fc(N_),time:Fc(j_),magvar:Fc(N_),geoidheight:Fc(N_),name:Fc(U_),cmt:Fc(U_),desc:Fc(U_),src:Fc(U_),link:kb,sym:Fc(U_),type:Fc(U_),fix:Fc(U_),sat:Fc(G_),hdop:Fc(N_),vdop:Fc(N_),pdop:Fc(N_),ageofdgpsdata:Fc(N_),dgpsid:Fc(G_),extensions:jb}),bb=["text","type"],xb=Gc(lb,{text:Ac(X_),type:Ac(X_)}),wb=Gc(lb,["name","cmt","desc","src","link","number","type","rtept"]),Sb=Gc(lb,{name:Ac(X_),cmt:Ac(X_),desc:Ac(X_),src:Ac(X_),link:Ac(zb),number:Ac(q_),type:Ac(X_),rtept:kc(Ac(Ub))}),Eb=Gc(lb,["ele","time"]),Tb=Gc(lb,["name","cmt","desc","src","link","number","type","trkseg"]),Cb=Gc(lb,{name:Ac(X_),cmt:Ac(X_),desc:Ac(X_),src:Ac(X_),link:Ac(zb),number:Ac(q_),type:Ac(X_),trkseg:kc(Ac((function(t,e,r){var n={node:t};n.geometryLayout=e.getLayout(),n.properties={},Vc(n,Pb,Ob,e.getCoordinates(),r)})))}),Ob=jc("trkpt"),Pb=Gc(lb,{trkpt:Ac(Ub)}),Rb=Gc(lb,["ele","time","magvar","geoidheight","name","cmt","desc","src","link","sym","type","fix","sat","hdop","vdop","pdop","ageofdgpsdata","dgpsid"]),Ib=Gc(lb,{ele:Ac(W_),time:Ac(Y_),magvar:Ac(W_),geoidheight:Ac(W_),name:Ac(X_),cmt:Ac(X_),desc:Ac(X_),src:Ac(X_),link:Ac(zb),sym:Ac(X_),type:Ac(X_),fix:Ac(X_),sat:Ac(q_),hdop:Ac(W_),vdop:Ac(W_),pdop:Ac(W_),ageofdgpsdata:Ac(W_),dgpsid:Ac(q_)}),Lb={Point:"wpt",LineString:"rte",MultiLineString:"trk"};function Mb(t,e,r){var n=t.getGeometry();if(n){var i=Lb[n.getType()];if(i)return Sc(e[e.length-1].node.namespaceURI,i)}}function Fb(t,e,r,n){return t.push(parseFloat(r.getAttribute("lon")),parseFloat(r.getAttribute("lat"))),"ele"in n?(t.push(n.ele),delete n.ele,e.hasZ=!0):t.push(0),"time"in n?(t.push(n.time),delete n.time,e.hasM=!0):t.push(0),t}function Ab(t,e,r){var n=yt,i=2;if(t.hasZ&&t.hasM?(n=_t,i=4):t.hasZ?(n=mt,i=3):t.hasM&&(n=vt,i=3),4!==i){for(var o=0,a=e.length/4;o<a;o++)e[o*i]=e[4*o],e[o*i+1]=e[4*o+1],t.hasZ&&(e[o*i+2]=e[4*o+2]),t.hasM&&(e[o*i+2]=e[4*o+3]);if(e.length=e.length/4*i,r)for(o=0,a=r.length;o<a;o++)r[o]=r[o]/4*i}return n}function kb(t,e){var r=e[e.length-1],n=t.getAttribute("href");null!==n&&(r.link=n),zc(hb,t,e)}function jb(t,e){e[e.length-1].extensionsNode_=t}function Nb(t,e){var r=e[0],n=Uc({flatCoordinates:[],layoutOptions:{}},db,t,e);if(n){var i=n.flatCoordinates;delete n.flatCoordinates;var o=n.layoutOptions;delete n.layoutOptions;var a=Ab(o,i),s=new Py(i,a);Wy(s,!1,r);var l=new gt(s);return l.setProperties(n,!0),l}}function Db(t,e){var r=e[0],n=Uc({flatCoordinates:[],ends:[],layoutOptions:{}},yb,t,e);if(n){var i=n.flatCoordinates;delete n.flatCoordinates;var o=n.ends;delete n.ends;var a=n.layoutOptions;delete n.layoutOptions;var s=Ab(a,i,o),l=new Zy(i,s,o);Wy(l,!1,r);var u=new gt(l);return u.setProperties(n,!0),u}}function Gb(t,e){var r=e[0],n=Uc({},_b,t,e);if(n){var i={},o=Fb([],i,t,n),a=Ab(i,o),s=new qn(o,a);Wy(s,!1,r);var l=new gt(s);return l.setProperties(n,!0),l}}function zb(t,e,r){t.setAttribute("href",e);var n=r[r.length-1].properties,i=[n.linkText,n.linkType];Vc({node:t},xb,Nc,i,r,bb)}function Ub(t,e,r){var n=r[r.length-1],i=n.node.namespaceURI,o=n.properties;switch(t.setAttributeNS(null,"lat",String(e[1])),t.setAttributeNS(null,"lon",String(e[0])),n.geometryLayout){case _t:0!==e[3]&&(o.time=e[3]);case mt:0!==e[2]&&(o.ele=e[2]);break;case vt:0!==e[2]&&(o.time=e[2])}var a="rtept"==t.nodeName?Eb[i]:Rb[i],s=Dc(o,a);Vc({node:t,properties:o},Ib,Nc,s,r,a)}var Bb=fb,Vb=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function Yb(t){return"string"==typeof t?t:""}var Wb,qb,Xb,Zb,Kb,Hb,$b,Jb=function(t){function e(){return t.call(this)||this}return Vb(e,t),e.prototype.getType=function(){return Pu},e.prototype.readFeature=function(t,e){return this.readFeatureFromText(Yb(t),this.adaptOptions(e))},e.prototype.readFeatureFromText=function(t,e){return n()},e.prototype.readFeatures=function(t,e){return this.readFeaturesFromText(Yb(t),this.adaptOptions(e))},e.prototype.readFeaturesFromText=function(t,e){return n()},e.prototype.readGeometry=function(t,e){return this.readGeometryFromText(Yb(t),this.adaptOptions(e))},e.prototype.readGeometryFromText=function(t,e){return n()},e.prototype.readProjection=function(t){return this.readProjectionFromText(Yb(t))},e.prototype.readProjectionFromText=function(t){return this.dataProjection},e.prototype.writeFeature=function(t,e){return this.writeFeatureText(t,this.adaptOptions(e))},e.prototype.writeFeatureText=function(t,e){return n()},e.prototype.writeFeatures=function(t,e){return this.writeFeaturesText(t,this.adaptOptions(e))},e.prototype.writeFeaturesText=function(t,e){return n()},e.prototype.writeGeometry=function(t,e){return this.writeGeometryText(t,this.adaptOptions(e))},e.prototype.writeGeometryText=function(t,e){return n()},e}(Yy),Qb=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),tx="barometric",ex="gps",rx="none",nx=/^B(\d{2})(\d{2})(\d{2})(\d{2})(\d{5})([NS])(\d{3})(\d{5})([EW])([AV])(\d{5})(\d{5})/,ix=/^H.([A-Z]{3}).*?:(.*)/,ox=/^HFDTE(\d{2})(\d{2})(\d{2})/,ax=/\r\n|\r|\n/,sx=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.dataProjection=Gr("EPSG:4326"),r.altitudeMode_=n.altitudeMode?n.altitudeMode:rx,r}return Qb(e,t),e.prototype.readFeatureFromText=function(t,e){var r,n,i=this.altitudeMode_,o=t.split(ax),a={},s=[],l=2e3,u=0,c=1,h=-1;for(r=0,n=o.length;r<n;++r){var p=o[r],f=void 0;if("B"==p.charAt(0)){if(f=nx.exec(p)){var d=parseInt(f[1],10),g=parseInt(f[2],10),y=parseInt(f[3],10),m=parseInt(f[4],10)+parseInt(f[5],10)/6e4;"S"==f[6]&&(m=-m);var v=parseInt(f[7],10)+parseInt(f[8],10)/6e4;if("W"==f[9]&&(v=-v),s.push(v,m),i!=rx){var _=void 0;_=i==ex?parseInt(f[11],10):i==tx?parseInt(f[12],10):0,s.push(_)}var b=Date.UTC(l,u,c,d,g,y);b<h&&(b=Date.UTC(l,u,c+1,d,g,y)),s.push(b/1e3),h=b}}else"H"==p.charAt(0)&&((f=ox.exec(p))?(c=parseInt(f[1],10),u=parseInt(f[2],10)-1,l=2e3+parseInt(f[3],10)):(f=ix.exec(p))&&(a[f[1]]=f[2].trim()))}if(0===s.length)return null;var x=new Py(s,i==rx?vt:_t),w=new gt(Wy(x,!1,e));return w.setProperties(a,!0),w},e.prototype.readFeaturesFromText=function(t,e){var r=this.readFeatureFromText(t,e);return r?[r]:[]},e}(Jb),lx=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ux=["http://www.google.com/kml/ext/2.2"],cx=[null,"http://earth.google.com/kml/2.0","http://earth.google.com/kml/2.1","http://earth.google.com/kml/2.2","http://www.opengis.net/kml/2.2"],hx={fraction:rp,pixels:np,insetPixels:np},px=Gc(cx,{ExtendedData:sw,Region:lw,MultiGeometry:Fc(Jx,"geometry"),LineString:Fc(Kx,"geometry"),LinearRing:Fc(Hx,"geometry"),Point:Fc(Qx,"geometry"),Polygon:Fc(ew,"geometry"),Style:Fc(nw),StyleMap:function(t,e){var r=kx.call(this,t,e);if(!r)return;var n=e[e.length-1];Array.isArray(r)?n.Style=r:"string"==typeof r?n.styleUrl=r:pt(!1,38)},address:Fc(U_),description:Fc(U_),name:Fc(U_),open:Fc(A_),phoneNumber:Fc(U_),styleUrl:Fc(Mx),visibility:Fc(A_)},Gc(ux,{MultiTrack:Fc((function(t,e){var r=Uc([],Bx,t,e);if(!r)return;return new Zy(r)}),"geometry"),Track:Fc(Yx,"geometry")})),fx=Gc(cx,{ExtendedData:sw,Region:lw,Link:function(t,e){zc(dx,t,e)},address:Fc(U_),description:Fc(U_),name:Fc(U_),open:Fc(A_),phoneNumber:Fc(U_),visibility:Fc(A_)}),dx=Gc(cx,{href:Fc(Lx)}),gx=Gc(cx,{LatLonAltBox:function(t,e){var r=Uc({},hw,t,e);if(!r)return;var n=e[e.length-1],i=[parseFloat(r.west),parseFloat(r.south),parseFloat(r.east),parseFloat(r.north)];n.extent=i,n.altitudeMode=r.altitudeMode,n.minAltitude=parseFloat(r.minAltitude),n.maxAltitude=parseFloat(r.maxAltitude)},Lod:function(t,e){var r=Uc({},pw,t,e);if(!r)return;var n=e[e.length-1];n.minLodPixels=parseFloat(r.minLodPixels),n.maxLodPixels=parseFloat(r.maxLodPixels),n.minFadeExtent=parseFloat(r.minFadeExtent),n.maxFadeExtent=parseFloat(r.maxFadeExtent)}}),yx=Gc(cx,["Document","Placemark"]),mx=Gc(cx,{Document:Ac((function(t,e,r){Vc({node:t},mw,vw,e,r,void 0,this)})),Placemark:Ac(Bw)}),vx=null;var _x,bx=null;var xx,wx=null;var Sx=null;var Ex=null;var Tx,Cx=null;function Ox(t){return t}var Px=function(t){function e(e){var r=t.call(this)||this,n=e||{};return Cx||(vx=new ep({color:Wb=[255,255,255,1]}),bx=new dp({anchor:qb=[20,2],anchorOrigin:ip,anchorXUnits:Xb=np,anchorYUnits:Zb=np,crossOrigin:"anonymous",rotation:0,scale:$b=.5,size:Kb=[64,64],src:Hb="https://maps.google.com/mapfiles/kml/pushpin/ylw-pushpin.png"}),_x="NO_IMAGE",wx=new gp({color:Wb,width:1}),xx=new gp({color:[51,51,51,1],width:2}),Sx=new Tp({font:"bold 16px Helvetica",fill:vx,stroke:xx,scale:.8}),Ex=new wp({fill:vx,image:bx,text:Sx,stroke:wx,zIndex:0}),Cx=[Ex]),r.dataProjection=Gr("EPSG:4326"),r.defaultStyle_=n.defaultStyle?n.defaultStyle:Cx,r.extractStyles_=void 0===n.extractStyles||n.extractStyles,r.writeStyles_=void 0===n.writeStyles||n.writeStyles,r.sharedStyles_={},r.showPointNames_=void 0===n.showPointNames||n.showPointNames,r.crossOrigin_=void 0!==n.crossOrigin?n.crossOrigin:"anonymous",r.iconUrlFunction_=n.iconUrlFunction?n.iconUrlFunction:Ox,r}return lx(e,t),e.prototype.readDocumentOrFolder_=function(t,e){var r=Uc([],Gc(cx,{Document:Rc(this.readDocumentOrFolder_,this),Folder:Rc(this.readDocumentOrFolder_,this),Placemark:Ic(this.readPlacemark_,this),Style:this.readSharedStyle_.bind(this),StyleMap:this.readSharedStyleMap_.bind(this)}),t,e,this);return r||void 0},e.prototype.readPlacemark_=function(t,e){var r=Uc({geometry:null},px,t,e,this);if(r){var n=new gt,i=t.getAttribute("id");null!==i&&n.setId(i);var o=e[0],a=r.geometry;if(a&&Wy(a,!1,o),n.setGeometry(a),delete r.geometry,this.extractStyles_){var s=function(t,e,r,n,i){return function(o,a){var s=i,l="",u=[];if(s){var c=o.getGeometry();if(c){var h=c.getType();s=h===bt.GEOMETRY_COLLECTION?(u=c.getGeometriesArrayRecursive().filter((function(t){var e=t.getType();return e===bt.POINT||e===bt.MULTI_POINT}))).length>0:h===bt.POINT||h===bt.MULTI_POINT}}s&&(l=o.get("name"),(s=s&&!!l)&&l.search(/&[^&]+;/)>-1&&(Tx||(Tx=document.createElement("textarea")),Tx.innerHTML=l,l=Tx.value));var p=r;if(t?p=t:e&&(p=function t(e,r,n){return Array.isArray(e)?e:"string"==typeof e?t(n[e],r,n):r}(e,r,n)),s){var f=function(t,e){var r=[0,0],n="start",i=t.getImage();if(i){var o=i.getImageSize();if(null===o&&(o=Kb),2==o.length){var a=i.getScaleArray();r[0]=a[0]*o[0]/2,r[1]=-a[1]*o[1]/2,n="left"}}var s=t.getText();s?((s=s.clone()).setFont(s.getFont()||Sx.getFont()),s.setScale(s.getScale()||Sx.getScale()),s.setFill(s.getFill()||Sx.getFill()),s.setStroke(s.getStroke()||xx)):s=Sx.clone();return s.setText(e),s.setOffsetX(r[0]),s.setOffsetY(r[1]),s.setTextAlign(n),new wp({image:i,text:s})}(p[0],l);return u.length>0?(f.setGeometry(new Vm(u)),[f,new wp({geometry:p[0].getGeometry(),image:null,fill:p[0].getFill(),stroke:p[0].getStroke(),text:null})].concat(p.slice(1))):f}return p}}(r.Style,r.styleUrl,this.defaultStyle_,this.sharedStyles_,this.showPointNames_);n.setStyle(s)}return delete r.Style,n.setProperties(r,!0),n}},e.prototype.readSharedStyle_=function(t,e){var r=t.getAttribute("id");if(null!==r){var n=nw.call(this,t,e);if(n){var i=void 0,o=t.baseURI;if(o&&"about:blank"!=o||(o=window.location.href),o)i=new URL("#"+r,o).href;else i="#"+r;this.sharedStyles_[i]=n}}},e.prototype.readSharedStyleMap_=function(t,e){var r=t.getAttribute("id");if(null!==r){var n=kx.call(this,t,e);if(n){var i,o=t.baseURI;if(o&&"about:blank"!=o||(o=window.location.href),o)i=new URL("#"+r,o).href;else i="#"+r;this.sharedStyles_[i]=n}}},e.prototype.readFeatureFromNode=function(t,e){if(!g(cx,t.namespaceURI))return null;var r=this.readPlacemark_(t,[this.getReadOptions(t,e)]);return r||null},e.prototype.readFeaturesFromNode=function(t,e){if(!g(cx,t.namespaceURI))return[];var r,n=t.localName;if("Document"==n||"Folder"==n)return(r=this.readDocumentOrFolder_(t,[this.getReadOptions(t,e)]))||[];if("Placemark"==n){var i=this.readPlacemark_(t,[this.getReadOptions(t,e)]);return i?[i]:[]}if("kml"==n){r=[];for(var o=t.firstElementChild;o;o=o.nextElementSibling){var a=this.readFeaturesFromNode(o,e);a&&v(r,a)}return r}return[]},e.prototype.readName=function(t){if(t){if("string"==typeof t){var e=Pc(t);return this.readNameFromDocument(e)}return Cc(t)?this.readNameFromDocument(t):this.readNameFromNode(t)}},e.prototype.readNameFromDocument=function(t){for(var e=t.firstChild;e;e=e.nextSibling)if(e.nodeType==Node.ELEMENT_NODE){var r=this.readNameFromNode(e);if(r)return r}},e.prototype.readNameFromNode=function(t){for(var e=t.firstElementChild;e;e=e.nextElementSibling)if(g(cx,e.namespaceURI)&&"name"==e.localName)return U_(e);for(e=t.firstElementChild;e;e=e.nextElementSibling){var r=e.localName;if(g(cx,e.namespaceURI)&&("Document"==r||"Folder"==r||"Placemark"==r||"kml"==r)){var n=this.readNameFromNode(e);if(n)return n}}},e.prototype.readNetworkLinks=function(t){var e=[];if("string"==typeof t){var r=Pc(t);v(e,this.readNetworkLinksFromDocument(r))}else Cc(t)?v(e,this.readNetworkLinksFromDocument(t)):v(e,this.readNetworkLinksFromNode(t));return e},e.prototype.readNetworkLinksFromDocument=function(t){for(var e=[],r=t.firstChild;r;r=r.nextSibling)r.nodeType==Node.ELEMENT_NODE&&v(e,this.readNetworkLinksFromNode(r));return e},e.prototype.readNetworkLinksFromNode=function(t){for(var e=[],r=t.firstElementChild;r;r=r.nextElementSibling)if(g(cx,r.namespaceURI)&&"NetworkLink"==r.localName){var n=Uc({},fx,r,[]);e.push(n)}for(r=t.firstElementChild;r;r=r.nextElementSibling){var i=r.localName;!g(cx,r.namespaceURI)||"Document"!=i&&"Folder"!=i&&"kml"!=i||v(e,this.readNetworkLinksFromNode(r))}return e},e.prototype.readRegion=function(t){var e=[];if("string"==typeof t){var r=Pc(t);v(e,this.readRegionFromDocument(r))}else Cc(t)?v(e,this.readRegionFromDocument(t)):v(e,this.readRegionFromNode(t));return e},e.prototype.readRegionFromDocument=function(t){for(var e=[],r=t.firstChild;r;r=r.nextSibling)r.nodeType==Node.ELEMENT_NODE&&v(e,this.readRegionFromNode(r));return e},e.prototype.readRegionFromNode=function(t){for(var e=[],r=t.firstElementChild;r;r=r.nextElementSibling)if(g(cx,r.namespaceURI)&&"Region"==r.localName){var n=Uc({},gx,r,[]);e.push(n)}for(r=t.firstElementChild;r;r=r.nextElementSibling){var i=r.localName;!g(cx,r.namespaceURI)||"Document"!=i&&"Folder"!=i&&"kml"!=i||v(e,this.readRegionFromNode(r))}return e},e.prototype.writeFeaturesNode=function(t,e){e=this.adaptOptions(e);var r=Sc(cx[4],"kml"),n="http://www.w3.org/2000/xmlns/";r.setAttributeNS(n,"xmlns:gx",ux[0]),r.setAttributeNS(n,"xmlns:xsi",wc),r.setAttributeNS(wc,"xsi:schemaLocation","http://www.opengis.net/kml/2.2 https://developers.google.com/kml/schema/kml22gx.xsd");var i={node:r},o={};t.length>1?o.Document=t:1==t.length&&(o.Placemark=t[0]);var a=yx[r.namespaceURI],s=Dc(o,a);return Vc(i,mx,Nc,s,[e],a,this),r},e}(P_);function Rx(t){var e=Ec(t,!1),r=/^\s*#?\s*([0-9A-Fa-f]{8})\s*$/.exec(e);if(r){var n=r[1];return[parseInt(n.substr(6,2),16),parseInt(n.substr(4,2),16),parseInt(n.substr(2,2),16),parseInt(n.substr(0,2),16)/255]}}function Ix(t){var e=Ec(t,!1),r=[];e=e.replace(/\s*,\s*/g,",");for(var n,i=/^\s*([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?),([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s+|,|$)(?:([+\-]?\d*\.?\d+(?:e[+\-]?\d+)?)(?:\s+|$))?\s*/i;n=i.exec(e);){var o=parseFloat(n[1]),a=parseFloat(n[2]),s=n[3]?parseFloat(n[3]):0;r.push(o,a,s),e=e.substr(n[0].length)}if(""===e)return r}function Lx(t){var e=Ec(t,!1).trim(),r=t.baseURI;return r&&"about:blank"!=r||(r=window.location.href),r?new URL(e,r).href:e}function Mx(t){var e=Ec(t,!1).trim().replace(/^(?!.*#)/,"#"),r=t.baseURI;return r&&"about:blank"!=r||(r=window.location.href),r?new URL(e,r).href:e}function Fx(t){return N_(t)}var Ax=Gc(cx,{Pair:function(t,e){var r=Uc({},uw,t,e,this);if(!r)return;var n=r.key;if(n&&"normal"==n){var i=r.styleUrl;i&&(e[e.length-1]=i);var o=r.Style;o&&(e[e.length-1]=o)}}});function kx(t,e){return Uc(void 0,Ax,t,e,this)}var jx=Gc(cx,{Icon:Fc((function(t,e){var r=Uc({},Wx,t,e);return r||null})),color:Fc(Rx),heading:Fc(N_),hotSpot:Fc((function(t){var e,r=t.getAttribute("xunits"),n=t.getAttribute("yunits");return e="insetPixels"!==r?"insetPixels"!==n?ip:ap:"insetPixels"!==n?op:sp,{x:parseFloat(t.getAttribute("x")),xunits:hx[r],y:parseFloat(t.getAttribute("y")),yunits:hx[n],origin:e}})),scale:Fc(Fx)});var Nx=Gc(cx,{color:Fc(Rx),scale:Fc(Fx)});var Dx=Gc(cx,{color:Fc(Rx),width:Fc(N_)});var Gx=Gc(cx,{color:Fc(Rx),fill:Fc(A_),outline:Fc(A_)});var zx=Gc(cx,{coordinates:Lc(Ix)});function Ux(t,e){return Uc(null,zx,t,e)}var Bx=Gc(ux,{Track:Ic(Yx)});var Vx=Gc(cx,{when:function(t,e){var r=e[e.length-1].whens,n=Ec(t,!1),i=Date.parse(n);r.push(isNaN(i)?0:i)}},Gc(ux,{coord:function(t,e){var r=e[e.length-1].flatCoordinates,n=Ec(t,!1),i=/^\s*([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s+([+\-]?\d+(?:\.\d*)?(?:e[+\-]?\d*)?)\s*$/i.exec(n);if(i){var o=parseFloat(i[1]),a=parseFloat(i[2]),s=parseFloat(i[3]);r.push(o,a,s,0)}else r.push(0,0,0,0)}}));function Yx(t,e){var r=Uc({flatCoordinates:[],whens:[]},Vx,t,e);if(r){for(var n=r.flatCoordinates,i=r.whens,o=0,a=Math.min(n.length,i.length);o<a;++o)n[4*o+3]=i[o];return new Py(n,_t)}}var Wx=Gc(cx,{href:Fc(Lx)},Gc(ux,{x:Fc(N_),y:Fc(N_),w:Fc(N_),h:Fc(N_)}));var qx=Gc(cx,{coordinates:Lc(Ix)});function Xx(t,e){return Uc(null,qx,t,e)}var Zx=Gc(cx,{extrude:Fc(A_),tessellate:Fc(A_),altitudeMode:Fc(U_)});function Kx(t,e){var r=Uc({},Zx,t,e),n=Xx(t,e);if(n){var i=new Py(n,mt);return i.setProperties(r,!0),i}}function Hx(t,e){var r=Uc({},Zx,t,e),n=Xx(t,e);if(n){var i=new fi(n,mt,[n.length]);return i.setProperties(r,!0),i}}var $x=Gc(cx,{LineString:Ic(Kx),LinearRing:Ic(Hx),MultiGeometry:Ic(Jx),Point:Ic(Qx),Polygon:Ic(ew)});function Jx(t,e){var r,n=Uc([],$x,t,e);if(!n)return null;if(0===n.length)return new Vm(n);for(var i=!0,o=n[0].getType(),a=1,s=n.length;a<s;++a)if(n[a].getType()!=o){i=!1;break}if(i){var l=void 0,u=void 0;if(o==bt.POINT){var c=n[0];l=c.getLayout(),u=c.getFlatCoordinates();for(a=1,s=n.length;a<s;++a)v(u,n[a].getFlatCoordinates());iw(r=new Hy(u,l),n)}else o==bt.LINE_STRING?iw(r=new Zy(n),n):o==bt.POLYGON?iw(r=new Jy(n),n):o==bt.GEOMETRY_COLLECTION?r=new Vm(n):pt(!1,37)}else r=new Vm(n);return r}function Qx(t,e){var r=Uc({},Zx,t,e),n=Xx(t,e);if(n){var i=new qn(n,mt);return i.setProperties(r,!0),i}}var tw=Gc(cx,{innerBoundaryIs:function(t,e){var r=Uc(void 0,fw,t,e);if(r){e[e.length-1].push(r)}},outerBoundaryIs:function(t,e){var r=Uc(void 0,dw,t,e);if(r){e[e.length-1][0]=r}}});function ew(t,e){var r=Uc({},Zx,t,e),n=Uc([null],tw,t,e);if(n&&n[0]){for(var i=n[0],o=[i.length],a=1,s=n.length;a<s;++a)v(i,n[a]),o.push(i.length);var l=new fi(i,mt,o);return l.setProperties(r,!0),l}}var rw=Gc(cx,{IconStyle:function(t,e){var r=Uc({},jx,t,e);if(r){var n,i,o,a,s=e[e.length-1],l="Icon"in r?r.Icon:{},u=!("Icon"in r)||Object.keys(l).length>0,c=l.href;c?n=c:u&&(n=Hb);var h,p=ip,f=r.hotSpot;f?(i=[f.x,f.y],o=f.xunits,a=f.yunits,p=f.origin):n===Hb?(i=qb,o=Xb,a=Zb):/^http:\/\/maps\.(?:google|gstatic)\.com\//.test(n)&&(i=[.5,0],o=rp,a=rp);var d,g=l.x,y=l.y;void 0!==g&&void 0!==y&&(h=[g,y]);var m,v=l.w,_=l.h;void 0!==v&&void 0!==_&&(d=[v,_]);var b=r.heading;void 0!==b&&(m=Ye(b));var x=r.scale,w=r.color;if(u){n==Hb&&(d=Kb,void 0===x&&(x=$b));var S=new dp({anchor:i,anchorOrigin:p,anchorXUnits:o,anchorYUnits:a,crossOrigin:this.crossOrigin_,offset:h,offsetOrigin:ip,rotation:m,scale:x,size:d,src:this.iconUrlFunction_(n),color:w});s.imageStyle=S}else s.imageStyle=_x}},LabelStyle:function(t,e){var r=Uc({},Nx,t,e);if(r){var n=e[e.length-1],i=new Tp({fill:new ep({color:"color"in r?r.color:Wb}),scale:r.scale});n.textStyle=i}},LineStyle:function(t,e){var r=Uc({},Dx,t,e);if(r){var n=e[e.length-1],i=new gp({color:"color"in r?r.color:Wb,width:"width"in r?r.width:1});n.strokeStyle=i}},PolyStyle:function(t,e){var r=Uc({},Gx,t,e);if(r){var n=e[e.length-1],i=new ep({color:"color"in r?r.color:Wb});n.fillStyle=i;var o=r.fill;void 0!==o&&(n.fill=o);var a=r.outline;void 0!==a&&(n.outline=a)}}});function nw(t,e){var r=Uc({},rw,t,e,this);if(!r)return null;var n,i="fillStyle"in r?r.fillStyle:vx,o=r.fill;void 0===o||o||(i=null),"imageStyle"in r?r.imageStyle!=_x&&(n=r.imageStyle):n=bx;var a="textStyle"in r?r.textStyle:Sx,s="strokeStyle"in r?r.strokeStyle:wx,l=r.outline;return void 0===l||l?[new wp({fill:i,image:n,stroke:s,text:a,zIndex:void 0})]:[new wp({geometry:function(t){var e=t.getGeometry(),r=e.getType();return r===bt.GEOMETRY_COLLECTION?new Vm(e.getGeometriesArrayRecursive().filter((function(t){var e=t.getType();return e!==bt.POLYGON&&e!==bt.MULTI_POLYGON}))):r!==bt.POLYGON&&r!==bt.MULTI_POLYGON?e:void 0},fill:i,image:n,stroke:s,text:a,zIndex:void 0}),new wp({geometry:function(t){var e=t.getGeometry(),r=e.getType();return r===bt.GEOMETRY_COLLECTION?new Vm(e.getGeometriesArrayRecursive().filter((function(t){var e=t.getType();return e===bt.POLYGON||e===bt.MULTI_POLYGON}))):r===bt.POLYGON||r===bt.MULTI_POLYGON?e:void 0},fill:i,stroke:null,zIndex:void 0})]}function iw(t,e){var r,n,i,o=e.length,a=new Array(e.length),s=new Array(e.length),l=new Array(e.length);r=!1,n=!1,i=!1;for(var u=0;u<o;++u){var c=e[u];a[u]=c.get("extrude"),s[u]=c.get("tessellate"),l[u]=c.get("altitudeMode"),r=r||void 0!==a[u],n=n||void 0!==s[u],i=i||l[u]}r&&t.set("extrude",a),n&&t.set("tessellate",s),i&&t.set("altitudeMode",l)}var ow=Gc(cx,{displayName:Fc(U_),value:Fc(U_)});var aw=Gc(cx,{Data:function(t,e){var r=t.getAttribute("name");zc(ow,t,e);var n=e[e.length-1];r&&n.displayName?n[r]={value:n.value,displayName:n.displayName,toString:function(){return n.value}}:null!==r?n[r]=n.value:null!==n.displayName&&(n[n.displayName]=n.value),delete n.value},SchemaData:function(t,e){zc(cw,t,e)}});function sw(t,e){zc(aw,t,e)}function lw(t,e){zc(gx,t,e)}var uw=Gc(cx,{Style:Fc(nw),key:Fc(U_),styleUrl:Fc(Mx)});var cw=Gc(cx,{SimpleData:function(t,e){var r=t.getAttribute("name");if(null!==r){var n=U_(t);e[e.length-1][r]=n}}});var hw=Gc(cx,{altitudeMode:Fc(U_),minAltitude:Fc(N_),maxAltitude:Fc(N_),north:Fc(N_),south:Fc(N_),east:Fc(N_),west:Fc(N_)});var pw=Gc(cx,{minLodPixels:Fc(N_),maxLodPixels:Fc(N_),minFadeExtent:Fc(N_),maxFadeExtent:Fc(N_)});var fw=Gc(cx,{LinearRing:Lc(Ux)});var dw=Gc(cx,{LinearRing:Lc(Ux)});function gw(t,e){for(var r=Oo(e),n=[255*(4==r.length?r[3]:1),r[2],r[1],r[0]],i=0;i<4;++i){var o=Math.floor(n[i]).toString(16);n[i]=1==o.length?"0"+o:o}X_(t,n.join(""))}var yw=Gc(cx,{Data:Ac((function(t,e,r){t.setAttribute("name",e.name);var n={node:t},i=e.value;"object"==typeof i?(null!==i&&i.displayName&&Vc(n,yw,Nc,[i.displayName],r,["displayName"]),null!==i&&i.value&&Vc(n,yw,Nc,[i.value],r,["value"])):Vc(n,yw,Nc,[i],r,["value"])})),value:Ac((function(t,e){X_(t,e)})),displayName:Ac((function(t,e){V_(t,e)}))});var mw=Gc(cx,{Placemark:Ac(Bw)}),vw=function(t,e,r){return Sc(e[e.length-1].node.namespaceURI,"Placemark")};var _w=jc("Data");var bw=Gc(cx,["href"],Gc(ux,["x","y","w","h"])),xw=Gc(cx,{href:Ac(X_)},Gc(ux,{x:Ac(W_),y:Ac(W_),w:Ac(W_),h:Ac(W_)})),ww=function(t,e,r){return Sc(ux[0],"gx:"+r)};var Sw=Gc(cx,["scale","heading","Icon","color","hotSpot"]),Ew=Gc(cx,{Icon:Ac((function(t,e,r){var n={node:t},i=r[r.length-1].node,o=bw[i.namespaceURI],a=Dc(e,o);Vc(n,xw,Nc,a,r,o),a=Dc(e,o=bw[ux[0]]),Vc(n,xw,ww,a,r,o)})),color:Ac(gw),heading:Ac(W_),hotSpot:Ac((function(t,e){t.setAttribute("x",String(e.x)),t.setAttribute("y",String(e.y)),t.setAttribute("xunits",e.xunits),t.setAttribute("yunits",e.yunits)})),scale:Ac(Jw)});var Tw=Gc(cx,["color","scale"]),Cw=Gc(cx,{color:Ac(gw),scale:Ac(Jw)});var Ow=Gc(cx,["color","width"]),Pw=Gc(cx,{color:Ac(gw),width:Ac(W_)});var Rw={Point:"Point",LineString:"LineString",LinearRing:"LinearRing",Polygon:"Polygon",MultiPoint:"MultiGeometry",MultiLineString:"MultiGeometry",MultiPolygon:"MultiGeometry",GeometryCollection:"MultiGeometry"},Iw=function(t,e,r){if(t)return Sc(e[e.length-1].node.namespaceURI,Rw[t.getType()])},Lw=jc("Point"),Mw=jc("LineString"),Fw=jc("LinearRing"),Aw=jc("Polygon"),kw=Gc(cx,{LineString:Ac(Ww),Point:Ac(Ww),Polygon:Ac(Hw),GeometryCollection:Ac(jw)});function jw(t,e,r){var n,i={node:t},o=e.getType(),a=[];o===bt.GEOMETRY_COLLECTION?(e.getGeometriesArrayRecursive().forEach((function(t){var e=t.getType();e===bt.MULTI_POINT?a=a.concat(t.getPoints()):e===bt.MULTI_LINE_STRING?a=a.concat(t.getLineStrings()):e===bt.MULTI_POLYGON?a=a.concat(t.getPolygons()):e===bt.POINT||e===bt.LINE_STRING||e===bt.POLYGON?a.push(t):pt(!1,39)})),n=Iw):o===bt.MULTI_POINT?(a=e.getPoints(),n=Lw):o===bt.MULTI_LINE_STRING?(a=e.getLineStrings(),n=Mw):o===bt.MULTI_POLYGON?(a=e.getPolygons(),n=Aw):pt(!1,39),Vc(i,kw,n,a,r)}var Nw=Gc(cx,{LinearRing:Ac(Ww)});function Dw(t,e,r){Vc({node:t},Nw,Fw,[e],r)}var Gw=Gc(cx,{ExtendedData:Ac((function(t,e,r){for(var n={node:t},i=e.names,o=e.values,a=i.length,s=0;s<a;s++)Vc(n,yw,_w,[{name:i[s],value:o[s]}],r)})),MultiGeometry:Ac(jw),LineString:Ac(Ww),LinearRing:Ac(Ww),Point:Ac(Ww),Polygon:Ac(Hw),Style:Ac((function(t,e,r){var n={node:t},i={};if(e.pointStyles.length){var o=e.pointStyles[0].getText();o&&(i.LabelStyle=o);var a=e.pointStyles[0].getImage();a&&"function"==typeof a.getSrc&&(i.IconStyle=a)}if(e.lineStyles.length){(s=e.lineStyles[0].getStroke())&&(i.LineStyle=s)}if(e.polyStyles.length){var s;(s=e.polyStyles[0].getStroke())&&!i.LineStyle&&(i.LineStyle=s),i.PolyStyle=e.polyStyles[0]}var l=r[r.length-1].node,u=Qw[l.namespaceURI],c=Dc(i,u);Vc(n,tS,Nc,c,r,u)})),address:Ac(X_),description:Ac(X_),name:Ac(X_),open:Ac(B_),phoneNumber:Ac(X_),styleUrl:Ac(X_),visibility:Ac(B_)}),zw=Gc(cx,["name","open","visibility","address","phoneNumber","description","styleUrl","Style"]),Uw=jc("ExtendedData");function Bw(t,e,r){var n={node:t};e.getId()&&t.setAttribute("id",e.getId());var i=e.getProperties(),o={address:1,description:1,name:1,open:1,phoneNumber:1,styleUrl:1,visibility:1};o[e.getGeometryName()]=1;var a=Object.keys(i||{}).sort().filter((function(t){return!o[t]})),s=e.getStyleFunction();if(s){var l=s(e,0);if(l){var u=Array.isArray(l)?l:[l],c=u;if(e.getGeometry()&&(c=u.filter((function(t){var r=t.getGeometryFunction()(e);if(r){var n=r.getType();return n===bt.GEOMETRY_COLLECTION?r.getGeometriesArrayRecursive().filter((function(t){var e=t.getType();return e===bt.POINT||e===bt.MULTI_POINT})).length:n===bt.POINT||n===bt.MULTI_POINT}}))),this.writeStyles_){var h=u,p=u;e.getGeometry()&&(h=u.filter((function(t){var r=t.getGeometryFunction()(e);if(r){var n=r.getType();return n===bt.GEOMETRY_COLLECTION?r.getGeometriesArrayRecursive().filter((function(t){var e=t.getType();return e===bt.LINE_STRING||e===bt.MULTI_LINE_STRING})).length:n===bt.LINE_STRING||n===bt.MULTI_LINE_STRING}})),p=u.filter((function(t){var r=t.getGeometryFunction()(e);if(r){var n=r.getType();return n===bt.GEOMETRY_COLLECTION?r.getGeometriesArrayRecursive().filter((function(t){var e=t.getType();return e===bt.POLYGON||e===bt.MULTI_POLYGON})).length:n===bt.POLYGON||n===bt.MULTI_POLYGON}}))),i.Style={pointStyles:c,lineStyles:h,polyStyles:p}}if(c.length&&void 0===i.name){var f=c[0].getText();f&&(i.name=f.getText())}}}var d=r[r.length-1].node,g=zw[d.namespaceURI],y=Dc(i,g);if(Vc(n,Gw,Nc,y,r,g),a.length>0){var m=Dc(i,a);Vc(n,Gw,Uw,[{names:a,values:m}],r)}var v=r[0],_=e.getGeometry();_&&(_=Wy(_,!0,v)),Vc(n,Gw,Iw,[_],r)}var Vw=Gc(cx,["extrude","tessellate","altitudeMode","coordinates"]),Yw=Gc(cx,{extrude:Ac(B_),tessellate:Ac(B_),altitudeMode:Ac(X_),coordinates:Ac((function(t,e,r){var n,i=r[r.length-1],o=i.layout,a=i.stride;o==yt||o==vt?n=2:o==mt||o==_t?n=3:pt(!1,34);var s=e.length,l="";if(s>0){l+=e[0];for(var u=1;u<n;++u)l+=","+e[u];for(var c=a;c<s;c+=a){l+=" "+e[c];for(u=1;u<n;++u)l+=","+e[c+u]}}X_(t,l)}))});function Ww(t,e,r){var n=e.getFlatCoordinates(),i={node:t};i.layout=e.getLayout(),i.stride=e.getStride();var o=e.getProperties();o.coordinates=n;var a=r[r.length-1].node,s=Vw[a.namespaceURI],l=Dc(o,s);Vc(i,Yw,Nc,l,r,s)}var qw=Gc(cx,["color","fill","outline"]),Xw=Gc(cx,{outerBoundaryIs:Ac(Dw),innerBoundaryIs:Ac(Dw)}),Zw=jc("innerBoundaryIs"),Kw=jc("outerBoundaryIs");function Hw(t,e,r){var n=e.getLinearRings(),i=n.shift(),o={node:t};Vc(o,Xw,Zw,n,r),Vc(o,Xw,Kw,[i],r)}var $w=Gc(cx,{color:Ac(gw),fill:Ac(B_),outline:Ac(B_)});function Jw(t,e){W_(t,Math.round(1e6*e)/1e6)}var Qw=Gc(cx,["IconStyle","LabelStyle","LineStyle","PolyStyle"]),tS=Gc(cx,{IconStyle:Ac((function(t,e,r){var n={node:t},i={},o=e.getSrc(),a=e.getSize(),s=e.getImageSize(),l={href:o};if(a){l.w=a[0],l.h=a[1];var u=e.getAnchor(),c=e.getOrigin();if(c&&s&&0!==c[0]&&c[1]!==a[1]&&(l.x=c[0],l.y=s[1]-(c[1]+a[1])),u&&(u[0]!==a[0]/2||u[1]!==a[1]/2)){var h={x:u[0],xunits:np,y:a[1]-u[1],yunits:np};i.hotSpot=h}}i.Icon=l;var p=e.getScale();1!==p&&(i.scale=p);var f=e.getRotation();0!==f&&(i.heading=f);var d=e.getColor();d&&(i.color=d);var g=r[r.length-1].node,y=Sw[g.namespaceURI],m=Dc(i,y);Vc(n,Ew,Nc,m,r,y)})),LabelStyle:Ac((function(t,e,r){var n={node:t},i={},o=e.getFill();o&&(i.color=o.getColor());var a=e.getScale();a&&1!==a&&(i.scale=a);var s=r[r.length-1].node,l=Tw[s.namespaceURI],u=Dc(i,l);Vc(n,Cw,Nc,u,r,l)})),LineStyle:Ac((function(t,e,r){var n={node:t},i={color:e.getColor(),width:Number(e.getWidth())||1},o=r[r.length-1].node,a=Ow[o.namespaceURI],s=Dc(i,a);Vc(n,Pw,Nc,s,r,a)})),PolyStyle:Ac((function(t,e,r){var n={node:t},i=e.getFill(),o=e.getStroke(),a={color:i?i.getColor():void 0,fill:!!i&&void 0,outline:!!o&&void 0},s=r[r.length-1].node,l=qw[s.namespaceURI],u=Dc(a,l);Vc(n,$w,Nc,u,r,l)}))});var eS=Px,rS=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),nS=[null],iS=Gc(nS,{nd:function(t,e){e[e.length-1].ndrefs.push(t.getAttribute("ref"))},tag:lS}),oS=Gc(nS,{node:function(t,e){var r=e[0],n=e[e.length-1],i=t.getAttribute("id"),o=[parseFloat(t.getAttribute("lon")),parseFloat(t.getAttribute("lat"))];n.nodes[i]=o;var a=Uc({tags:{}},sS,t,e);if(!I(a.tags)){var s=new qn(o);Wy(s,!1,r);var l=new gt(s);l.setId(i),l.setProperties(a.tags,!0),n.features.push(l)}},way:function(t,e){var r=Uc({id:t.getAttribute("id"),ndrefs:[],tags:{}},iS,t,e);e[e.length-1].ways.push(r)}}),aS=function(t){function e(){var e=t.call(this)||this;return e.dataProjection=Gr("EPSG:4326"),e}return rS(e,t),e.prototype.readFeaturesFromNode=function(t,e){var r=this.getReadOptions(t,e);if("osm"==t.localName){for(var n=Uc({nodes:{},ways:[],features:[]},oS,t,[r]),i=0;i<n.ways.length;i++){for(var o=n.ways[i],a=[],s=0,l=o.ndrefs.length;s<l;s++){v(a,n.nodes[o.ndrefs[s]])}var u=void 0;Wy(u=o.ndrefs[0]==o.ndrefs[o.ndrefs.length-1]?new fi(a,yt,[a.length]):new Py(a,yt),!1,r);var c=new gt(u);c.setId(o.id),c.setProperties(o.tags,!0),n.features.push(c)}if(n.features)return n.features}return[]},e}(P_),sS=Gc(nS,{tag:lS});function lS(t,e){e[e.length-1].tags[t.getAttribute("k")]=t.getAttribute("v")}var uS=aS,cS=function(){function t(){}return t.prototype.read=function(t){if(t){if("string"==typeof t){var e=Pc(t);return this.readFromDocument(e)}return Cc(t)?this.readFromDocument(t):this.readFromNode(t)}return null},t.prototype.readFromDocument=function(t){for(var e=t.firstChild;e;e=e.nextSibling)if(e.nodeType==Node.ELEMENT_NODE)return this.readFromNode(e);return null},t.prototype.readFromNode=function(t){},t}();function hS(t){return t.getAttributeNS("http://www.w3.org/1999/xlink","href")}var pS=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),fS=[null,"http://www.opengis.net/ows/1.1"],dS=Gc(fS,{ServiceIdentification:Fc((function(t,e){return Uc({},OS,t,e)})),ServiceProvider:Fc((function(t,e){return Uc({},PS,t,e)})),OperationsMetadata:Fc((function(t,e){return Uc({},SS,t,e)}))}),gS=function(t){function e(){return t.call(this)||this}return pS(e,t),e.prototype.readFromNode=function(t){var e=Uc({},dS,t,[]);return e||null},e}(cS),yS=Gc(fS,{DeliveryPoint:Fc(U_),City:Fc(U_),AdministrativeArea:Fc(U_),PostalCode:Fc(U_),Country:Fc(U_),ElectronicMailAddress:Fc(U_)}),mS=Gc(fS,{Value:Mc((function(t,e){return U_(t)}))}),vS=Gc(fS,{AllowedValues:Fc((function(t,e){return Uc({},mS,t,e)}))}),_S=Gc(fS,{Phone:Fc((function(t,e){return Uc({},ES,t,e)})),Address:Fc((function(t,e){return Uc({},yS,t,e)}))}),bS=Gc(fS,{HTTP:Fc((function(t,e){return Uc({},xS,t,e)}))}),xS=Gc(fS,{Get:Mc((function(t,e){var r=hS(t);if(!r)return;return Uc({href:r},TS,t,e)})),Post:void 0}),wS=Gc(fS,{DCP:Fc((function(t,e){return Uc({},bS,t,e)}))}),SS=Gc(fS,{Operation:function(t,e){var r=t.getAttribute("name"),n=Uc({},wS,t,e);if(!n)return;e[e.length-1][r]=n}}),ES=Gc(fS,{Voice:Fc(U_),Facsimile:Fc(U_)}),TS=Gc(fS,{Constraint:Mc((function(t,e){var r=t.getAttribute("name");if(!r)return;return Uc({name:r},vS,t,e)}))}),CS=Gc(fS,{IndividualName:Fc(U_),PositionName:Fc(U_),ContactInfo:Fc((function(t,e){return Uc({},_S,t,e)}))}),OS=Gc(fS,{Abstract:Fc(U_),AccessConstraints:Fc(U_),Fees:Fc(U_),Title:Fc(U_),ServiceTypeVersion:Fc(U_),ServiceType:Fc(U_)}),PS=Gc(fS,{ProviderName:Fc(U_),ProviderSite:Fc(hS),ServiceContact:Fc((function(t,e){return Uc({},CS,t,e)}))});var RS=gS,IS=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}();function LS(t,e,r){var n,i=r||1e5,o=new Array(e);for(n=0;n<e;++n)o[n]=0;for(var a=0,s=t.length;a<s;)for(n=0;n<e;++n,++a){var l=t[a],u=l-o[n];o[n]=l,t[a]=u}return FS(t,i)}function MS(t,e,r){var n,i=r||1e5,o=new Array(e);for(n=0;n<e;++n)o[n]=0;for(var a=AS(t,i),s=0,l=a.length;s<l;)for(n=0;n<e;++n,++s)o[n]+=a[s],a[s]=o[n];return a}function FS(t,e){for(var r=e||1e5,n=0,i=t.length;n<i;++n)t[n]=Math.round(t[n]*r);return kS(t)}function AS(t,e){for(var r=e||1e5,n=jS(t),i=0,o=n.length;i<o;++i)n[i]/=r;return n}function kS(t){for(var e=0,r=t.length;e<r;++e){var n=t[e];t[e]=n<0?~(n<<1):n<<1}return NS(t)}function jS(t){for(var e=DS(t),r=0,n=e.length;r<n;++r){var i=e[r];e[r]=1&i?~(i>>1):i>>1}return e}function NS(t){for(var e="",r=0,n=t.length;r<n;++r)e+=GS(t[r]);return e}function DS(t){for(var e=[],r=0,n=0,i=0,o=t.length;i<o;++i){var a=t.charCodeAt(i)-63;r|=(31&a)<<n,a<32?(e.push(r),r=0,n=0):n+=5}return e}function GS(t){for(var e,r="";t>=32;)e=63+(32|31&t),r+=String.fromCharCode(e),t>>=5;return e=t+63,r+=String.fromCharCode(e)}var zS=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.dataProjection=Gr("EPSG:4326"),r.factor_=n.factor?n.factor:1e5,r.geometryLayout_=n.geometryLayout?n.geometryLayout:yt,r}return IS(e,t),e.prototype.readFeatureFromText=function(t,e){var r=this.readGeometryFromText(t,e);return new gt(r)},e.prototype.readFeaturesFromText=function(t,e){return[this.readFeatureFromText(t,e)]},e.prototype.readGeometryFromText=function(t,e){var r=yn(this.geometryLayout_),n=MS(t,r,this.factor_);v_(n,0,n.length,r,n);var i=Nn(n,0,n.length,r);return Wy(new Py(i,this.geometryLayout_),!1,this.adaptOptions(e))},e.prototype.writeFeatureText=function(t,e){var r=t.getGeometry();return r?this.writeGeometryText(r,e):(pt(!1,40),"")},e.prototype.writeFeaturesText=function(t,e){return this.writeFeatureText(t[0],e)},e.prototype.writeGeometryText=function(t,e){var r=(t=Wy(t,!0,this.adaptOptions(e))).getFlatCoordinates(),n=t.getStride();return v_(r,0,r.length,n,r),LS(r,n,this.factor_)},e}(Jb),US=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),BS=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.layerName_=n.layerName,r.layers_=n.layers?n.layers:null,r.dataProjection=Gr(n.dataProjection?n.dataProjection:"EPSG:4326"),r}return US(e,t),e.prototype.readFeaturesFromObject=function(t,e){if("Topology"==t.type){var r=t,n=void 0,i=null,o=null;r.transform&&(i=(n=r.transform).scale,o=n.translate);var a=r.arcs;n&&function(t,e,r){for(var n=0,i=t.length;n<i;++n)XS(t[n],e,r)}(a,i,o);var s=[],l=r.objects,u=this.layerName_,c=void 0;for(var h in l)this.layers_&&-1==this.layers_.indexOf(h)||("GeometryCollection"===l[h].type?(c=l[h],s.push.apply(s,WS(c,a,i,o,u,h,e))):(c=l[h],s.push(qS(c,a,i,o,u,h,e))));return s}return[]},e.prototype.readProjectionFromObject=function(t){return this.dataProjection},e}(qm),VS={Point:function(t,e,r){var n=t.coordinates;e&&r&&ZS(n,e,r);return new qn(n)},LineString:function(t,e){var r=YS(t.arcs,e);return new Py(r)},Polygon:function(t,e){for(var r=[],n=0,i=t.arcs.length;n<i;++n)r[n]=YS(t.arcs[n],e);return new fi(r)},MultiPoint:function(t,e,r){var n=t.coordinates;if(e&&r)for(var i=0,o=n.length;i<o;++i)ZS(n[i],e,r);return new Hy(n)},MultiLineString:function(t,e){for(var r=[],n=0,i=t.arcs.length;n<i;++n)r[n]=YS(t.arcs[n],e);return new Zy(r)},MultiPolygon:function(t,e){for(var r=[],n=0,i=t.arcs.length;n<i;++n){for(var o=t.arcs[n],a=[],s=0,l=o.length;s<l;++s)a[s]=YS(o[s],e);r[n]=a}return new Jy(r)}};function YS(t,e){for(var r,n,i=[],o=0,a=t.length;o<a;++o)r=t[o],o>0&&i.pop(),n=r>=0?e[r]:e[~r].slice().reverse(),i.push.apply(i,n);for(var s=0,l=i.length;s<l;++s)i[s]=i[s].slice();return i}function WS(t,e,r,n,i,o,a){for(var s=t.geometries,l=[],u=0,c=s.length;u<c;++u)l[u]=qS(s[u],e,r,n,i,o,a);return l}function qS(t,e,r,n,i,o,a){var s,l=t.type,u=VS[l];s="Point"===l||"MultiPoint"===l?u(t,r,n):u(t,e);var c=new gt;c.setGeometry(Wy(s,!1,a)),void 0!==t.id&&c.setId(t.id);var h=t.properties;return i&&(h||(h={}),h[i]=o),h&&c.setProperties(h,!0),c}function XS(t,e,r){for(var n=0,i=0,o=0,a=t.length;o<a;++o){var s=t[o];n+=s[0],i+=s[1],s[0]=n,s[1]=i,ZS(s,e,r)}}function ZS(t,e,r){t[0]=t[0]*e[0]+r[0],t[1]=t[1]*e[1]+r[1]}var KS=BS,HS=function(){function t(t){this.tagName_=t}return t.prototype.getTagName=function(){return this.tagName_},t}(),$S=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),JS=function(t){function e(e,r){var n=t.call(this,e)||this;return n.conditions=r,pt(n.conditions.length>=2,57),n}return $S(e,t),e}(HS),QS=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),tE=function(t){function e(e){return t.call(this,"And",Array.prototype.slice.call(arguments))||this}return QS(e,t),e}(JS),eE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),rE=function(t){function e(e,r,n){var i=t.call(this,"BBOX")||this;if(i.geometryName=e,i.extent=r,4!==r.length)throw new Error("Expected an extent with four values ([minX, minY, maxX, maxY])");return i.srsName=n,i}return eE(e,t),e}(HS),nE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),iE=function(t){function e(e,r,n,i){var o=t.call(this,e)||this;return o.geometryName=r||"the_geom",o.geometry=n,o.srsName=i,o}return nE(e,t),e}(HS),oE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),aE=function(t){function e(e,r,n){return t.call(this,"Contains",e,r,n)||this}return oE(e,t),e}(iE),sE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),lE=function(t){function e(e,r,n,i,o){var a=t.call(this,"DWithin",e,r,o)||this;return a.distance=n,a.unit=i,a}return sE(e,t),e}(iE),uE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),cE=function(t){function e(e,r,n){return t.call(this,"Disjoint",e,r,n)||this}return uE(e,t),e}(iE),hE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),pE=function(t){function e(e,r){var n=t.call(this,e)||this;return n.propertyName=r,n}return hE(e,t),e}(HS),fE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),dE=function(t){function e(e,r,n){var i=t.call(this,"During",e)||this;return i.begin=r,i.end=n,i}return fE(e,t),e}(pE),gE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),yE=function(t){function e(e,r,n,i){var o=t.call(this,e,r)||this;return o.expression=n,o.matchCase=i,o}return gE(e,t),e}(pE),mE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),vE=function(t){function e(e,r,n){return t.call(this,"PropertyIsEqualTo",e,r,n)||this}return mE(e,t),e}(yE),_E=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),bE=function(t){function e(e,r){return t.call(this,"PropertyIsGreaterThan",e,r)||this}return _E(e,t),e}(yE),xE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),wE=function(t){function e(e,r){return t.call(this,"PropertyIsGreaterThanOrEqualTo",e,r)||this}return xE(e,t),e}(yE),SE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),EE=function(t){function e(e,r,n){return t.call(this,"Intersects",e,r,n)||this}return SE(e,t),e}(iE),TE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),CE=function(t){function e(e,r,n){var i=t.call(this,"PropertyIsBetween",e)||this;return i.lowerBoundary=r,i.upperBoundary=n,i}return TE(e,t),e}(pE),OE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),PE=function(t){function e(e,r,n,i,o,a){var s=t.call(this,"PropertyIsLike",e)||this;return s.pattern=r,s.wildCard=void 0!==n?n:"*",s.singleChar=void 0!==i?i:".",s.escapeChar=void 0!==o?o:"!",s.matchCase=a,s}return OE(e,t),e}(pE),RE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),IE=function(t){function e(e){return t.call(this,"PropertyIsNull",e)||this}return RE(e,t),e}(pE),LE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ME=function(t){function e(e,r){return t.call(this,"PropertyIsLessThan",e,r)||this}return LE(e,t),e}(yE),FE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),AE=function(t){function e(e,r){return t.call(this,"PropertyIsLessThanOrEqualTo",e,r)||this}return FE(e,t),e}(yE),kE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),jE=function(t){function e(e){var r=t.call(this,"Not")||this;return r.condition=e,r}return kE(e,t),e}(HS),NE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),DE=function(t){function e(e,r,n){return t.call(this,"PropertyIsNotEqualTo",e,r,n)||this}return NE(e,t),e}(yE),GE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),zE=function(t){function e(e){return t.call(this,"Or",Array.prototype.slice.call(arguments))||this}return GE(e,t),e}(JS),UE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),BE=function(t){function e(e){var r=t.call(this,"ResourceId")||this;return r.rid=e,r}return UE(e,t),e}(HS),VE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),YE=function(t){function e(e,r,n){return t.call(this,"Within",e,r,n)||this}return VE(e,t),e}(iE);function WE(t){var e=[null].concat(Array.prototype.slice.call(arguments));return new(Function.prototype.bind.apply(tE,e))}function qE(t,e,r){return new rE(t,e,r)}var XE=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),ZE={"http://www.opengis.net/gml":{boundedBy:Fc(F_.prototype.readGeometryElement,"bounds")},"http://www.opengis.net/wfs/2.0":{member:Ic(F_.prototype.readFeaturesInternal)}},KE={"http://www.opengis.net/wfs":{totalInserted:Fc(G_),totalUpdated:Fc(G_),totalDeleted:Fc(G_)},"http://www.opengis.net/wfs/2.0":{totalInserted:Fc(G_),totalUpdated:Fc(G_),totalDeleted:Fc(G_)}},HE={"http://www.opengis.net/wfs":{TransactionSummary:Fc(sT,"transactionSummary"),InsertResults:Fc(hT,"insertIds")},"http://www.opengis.net/wfs/2.0":{TransactionSummary:Fc(sT,"transactionSummary"),InsertResults:Fc(hT,"insertIds")}},$E={"http://www.opengis.net/wfs":{PropertyName:Ac(X_)},"http://www.opengis.net/wfs/2.0":{PropertyName:Ac(X_)}},JE={"http://www.opengis.net/wfs":{Insert:Ac(pT),Update:Ac(yT),Delete:Ac(gT),Property:Ac(mT),Native:Ac(vT)},"http://www.opengis.net/wfs/2.0":{Insert:Ac(pT),Update:Ac(yT),Delete:Ac(gT),Property:Ac(mT),Native:Ac(vT)}},QE="http://www.w3.org/2000/xmlns/",tT={"2.0.0":"http://www.opengis.net/ogc/1.1","1.1.0":"http://www.opengis.net/ogc","1.0.0":"http://www.opengis.net/ogc"},eT={"2.0.0":"http://www.opengis.net/wfs/2.0","1.1.0":"http://www.opengis.net/wfs","1.0.0":"http://www.opengis.net/wfs"},rT={"2.0.0":"http://www.opengis.net/fes/2.0","1.1.0":"http://www.opengis.net/fes","1.0.0":"http://www.opengis.net/fes"},nT={"2.0.0":"http://www.opengis.net/wfs/2.0 http://schemas.opengis.net/wfs/2.0/wfs.xsd","1.1.0":"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.1.0/wfs.xsd","1.0.0":"http://www.opengis.net/wfs http://schemas.opengis.net/wfs/1.0.0/wfs.xsd"},iT={"2.0.0":ab,"1.1.0":eb,"1.0.0":$_},oT=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.version_=n.version?n.version:"1.1.0",r.featureType_=n.featureType,r.featureNS_=n.featureNS,r.gmlFormat_=n.gmlFormat?n.gmlFormat:new iT[r.version_],r.schemaLocation_=n.schemaLocation?n.schemaLocation:nT[r.version_],r}return XE(e,t),e.prototype.getFeatureType=function(){return this.featureType_},e.prototype.setFeatureType=function(t){this.featureType_=t},e.prototype.readFeaturesFromNode=function(t,e){var r={node:t};O(r,{featureType:this.featureType_,featureNS:this.featureNS_}),O(r,this.getReadOptions(t,e||{}));var n=[r],i=Uc([],"2.0.0"===this.version_?ZE:this.gmlFormat_.FEATURE_COLLECTION_PARSERS,t,n,this.gmlFormat_);return i||(i=[]),i},e.prototype.readTransactionResponse=function(t){if(t){if("string"==typeof t){var e=Pc(t);return this.readTransactionResponseFromDocument(e)}return Cc(t)?this.readTransactionResponseFromDocument(t):this.readTransactionResponseFromNode(t)}},e.prototype.readFeatureCollectionMetadata=function(t){if(t){if("string"==typeof t){var e=Pc(t);return this.readFeatureCollectionMetadataFromDocument(e)}return Cc(t)?this.readFeatureCollectionMetadataFromDocument(t):this.readFeatureCollectionMetadataFromNode(t)}},e.prototype.readFeatureCollectionMetadataFromDocument=function(t){for(var e=t.firstChild;e;e=e.nextSibling)if(e.nodeType==Node.ELEMENT_NODE)return this.readFeatureCollectionMetadataFromNode(e)},e.prototype.readFeatureCollectionMetadataFromNode=function(t){var e={},r=z_(t.getAttribute("numberOfFeatures"));return e.numberOfFeatures=r,Uc(e,ZE,t,[],this.gmlFormat_)},e.prototype.readTransactionResponseFromDocument=function(t){for(var e=t.firstChild;e;e=e.nextSibling)if(e.nodeType==Node.ELEMENT_NODE)return this.readTransactionResponseFromNode(e)},e.prototype.readTransactionResponseFromNode=function(t){return Uc({},HE,t,[])},e.prototype.writeGetFeature=function(t){var e=this,r=Sc(eT[this.version_],"GetFeature");r.setAttribute("service","WFS"),r.setAttribute("version",this.version_),t.handle&&r.setAttribute("handle",t.handle),t.outputFormat&&r.setAttribute("outputFormat",t.outputFormat),void 0!==t.maxFeatures&&r.setAttribute("maxFeatures",String(t.maxFeatures)),t.resultType&&r.setAttribute("resultType",t.resultType),void 0!==t.startIndex&&r.setAttribute("startIndex",String(t.startIndex)),void 0!==t.count&&r.setAttribute("count",String(t.count)),void 0!==t.viewParams&&r.setAttribute("viewParams",t.viewParams),r.setAttributeNS(wc,"xsi:schemaLocation",this.schemaLocation_);var n={node:r};if(O(n,{version:this.version_,srsName:t.srsName,featureNS:t.featureNS?t.featureNS:this.featureNS_,featurePrefix:t.featurePrefix,propertyNames:t.propertyNames?t.propertyNames:[]}),pt(Array.isArray(t.featureTypes),11),"string"==typeof t.featureTypes[0]){var i=t.filter;t.bbox&&(pt(t.geometryName,12),i=this.combineBboxAndFilter(t.geometryName,t.bbox,t.srsName,i)),O(n,{geometryName:t.geometryName,filter:i}),jT(r,t.featureTypes,[n])}else t.featureTypes.forEach((function(i){var o=e.combineBboxAndFilter(i.geometryName,i.bbox,t.srsName,t.filter);O(n,{geometryName:i.geometryName,filter:o}),jT(r,[i.name],[n])}));return r},e.prototype.combineBboxAndFilter=function(t,e,r,n){var i=qE(t,e,r);return n?WE(n,i):i},e.prototype.writeTransaction=function(t,e,r,n){var i,o=[],a=n.version?n.version:this.version_,s=Sc(eT[a],"Transaction");s.setAttribute("service","WFS"),s.setAttribute("version",a),n&&(i=n.gmlOptions?n.gmlOptions:{},n.handle&&s.setAttribute("handle",n.handle)),s.setAttributeNS(wc,"xsi:schemaLocation",nT[a]);var l=function(t,e,r,n){var i,o=n.featurePrefix?n.featurePrefix:"feature";"1.0.0"===r?i=2:"1.1.0"===r?i=3:"2.0.0"===r&&(i=3.2);return O({node:t},{version:r,featureNS:n.featureNS,featureType:n.featureType,featurePrefix:o,gmlVersion:i,hasZ:n.hasZ,srsName:n.srsName},e)}(s,i,a,n);return t&&aT("Insert",t,o,l),e&&aT("Update",e,o,l),r&&aT("Delete",r,o,l),n.nativeElements&&aT("Native",n.nativeElements,o,l),s},e.prototype.readProjectionFromDocument=function(t){for(var e=t.firstChild;e;e=e.nextSibling)if(e.nodeType==Node.ELEMENT_NODE)return this.readProjectionFromNode(e);return null},e.prototype.readProjectionFromNode=function(t){if(t.firstElementChild&&t.firstElementChild.firstElementChild)for(var e=(t=t.firstElementChild.firstElementChild).firstElementChild;e;e=e.nextElementSibling)if(0!==e.childNodes.length&&(1!==e.childNodes.length||3!==e.firstChild.nodeType)){var r=[{}];return this.gmlFormat_.readGeometryElement(e,r),Gr(r.pop().srsName)}return null},e}(P_);function aT(t,e,r,n){Vc(n,JE,jc(t),e,r)}function sT(t,e){return Uc({},KE,t,e)}var lT={"http://www.opengis.net/ogc":{FeatureId:Ic((function(t,e){return t.getAttribute("fid")}))},"http://www.opengis.net/ogc/1.1":{FeatureId:Ic((function(t,e){return t.getAttribute("fid")}))}};function uT(t,e){zc(lT,t,e)}var cT={"http://www.opengis.net/wfs":{Feature:uT},"http://www.opengis.net/wfs/2.0":{Feature:uT}};function hT(t,e){return Uc([],cT,t,e)}function pT(t,e,r){var n=r[r.length-1],i=n.featureType,o=n.featureNS,a=n.gmlVersion,s=Sc(o,i);t.appendChild(s),2===a?$_.prototype.writeFeatureElement(s,e,r):3===a?eb.prototype.writeFeatureElement(s,e,r):ab.prototype.writeFeatureElement(s,e,r)}function fT(t,e,r){var n=r[r.length-1].version,i=tT[n],o=Sc(i,"Filter"),a=Sc(i,"FeatureId");o.appendChild(a),a.setAttribute("fid",e),t.appendChild(o)}function dT(t,e){var r=(t=t||"feature")+":";return 0===e.indexOf(r)?e:r+e}function gT(t,e,r){var n=r[r.length-1];pt(void 0!==e.getId(),26);var i=n.featureType,o=n.featurePrefix,a=n.featureNS,s=dT(o,i);t.setAttribute("typeName",s),t.setAttributeNS(QE,"xmlns:"+o,a);var l=e.getId();void 0!==l&&fT(t,l,r)}function yT(t,e,r){var n=r[r.length-1];pt(void 0!==e.getId(),27);var i=n.version,o=n.featureType,a=n.featurePrefix,s=n.featureNS,l=dT(a,o),u=e.getGeometryName();t.setAttribute("typeName",l),t.setAttributeNS(QE,"xmlns:"+a,s);var c=e.getId();if(void 0!==c){for(var h=e.getKeys(),p=[],f=0,d=h.length;f<d;f++){var g=e.get(h[f]);if(void 0!==g){var y=h[f];g&&"function"==typeof g.getSimplifiedGeometry&&(y=u),p.push({name:y,value:g})}}Vc({version:i,gmlVersion:n.gmlVersion,node:t,hasZ:n.hasZ,srsName:n.srsName},JE,jc("Property"),p,r),fT(t,c,r)}}function mT(t,e,r){var n=r[r.length-1],i=n.version,o=eT[i],a=Sc(o,"Name"),s=n.gmlVersion;if(t.appendChild(a),X_(a,e.name),void 0!==e.value&&null!==e.value){var l=Sc(o,"Value");t.appendChild(l),e.value&&"function"==typeof e.value.getSimplifiedGeometry?2===s?$_.prototype.writeGeometryElement(l,e.value,r):3===s?eb.prototype.writeGeometryElement(l,e.value,r):ab.prototype.writeGeometryElement(l,e.value,r):X_(l,e.value)}}function vT(t,e,r){e.vendorId&&t.setAttribute("vendorId",e.vendorId),void 0!==e.safeToIgnore&&t.setAttribute("safeToIgnore",String(e.safeToIgnore)),void 0!==e.value&&X_(t,e.value)}var _T={"http://www.opengis.net/wfs":{Query:Ac(bT)},"http://www.opengis.net/wfs/2.0":{Query:Ac(bT)},"http://www.opengis.net/ogc":{During:Ac(TT),And:Ac(CT),Or:Ac(CT),Not:Ac(OT),BBOX:Ac(wT),Contains:Ac(ST),Intersects:Ac(ST),Within:Ac(ST),DWithin:Ac(ET),PropertyIsEqualTo:Ac(PT),PropertyIsNotEqualTo:Ac(PT),PropertyIsLessThan:Ac(PT),PropertyIsLessThanOrEqualTo:Ac(PT),PropertyIsGreaterThan:Ac(PT),PropertyIsGreaterThanOrEqualTo:Ac(PT),PropertyIsNull:Ac(RT),PropertyIsBetween:Ac(IT),PropertyIsLike:Ac(LT)},"http://www.opengis.net/fes/2.0":{During:Ac(TT),And:Ac(CT),Or:Ac(CT),Not:Ac(OT),BBOX:Ac(wT),Contains:Ac(ST),Disjoint:Ac(ST),Intersects:Ac(ST),ResourceId:Ac((function(t,e,r){t.setAttribute("rid",e.rid)})),Within:Ac(ST),DWithin:Ac(ET),PropertyIsEqualTo:Ac(PT),PropertyIsNotEqualTo:Ac(PT),PropertyIsLessThan:Ac(PT),PropertyIsLessThanOrEqualTo:Ac(PT),PropertyIsGreaterThan:Ac(PT),PropertyIsGreaterThanOrEqualTo:Ac(PT),PropertyIsNull:Ac(RT),PropertyIsBetween:Ac(IT),PropertyIsLike:Ac(LT)}};function bT(t,e,r){var n,i,o=r[r.length-1],a=o.version,s=o.featurePrefix,l=o.featureNS,u=o.propertyNames,c=o.srsName;n=s?dT(s,e):e,i="2.0.0"===a?"typeNames":"typeName",t.setAttribute(i,n),c&&t.setAttribute("srsName",c),l&&t.setAttributeNS(QE,"xmlns:"+s,l);var h=O({},o);h.node=t,Vc(h,$E,jc("PropertyName"),u,r);var p=o.filter;if(p){var f=Sc(NT(a),"Filter");t.appendChild(f),xT(f,p,r)}}function xT(t,e,r){var n=r[r.length-1],i={node:t};O(i,{context:n}),Vc(i,_T,jc(e.getTagName()),[e],r)}function wT(t,e,r){var n=r[r.length-1],i=n.context.version;n.srsName=e.srsName;var o=iT[i];AT(i,t,e.geometryName),o.prototype.writeGeometryElement(t,e.extent,r)}function ST(t,e,r){var n=r[r.length-1],i=n.context.version;n.srsName=e.srsName;var o=iT[i];AT(i,t,e.geometryName),o.prototype.writeGeometryElement(t,e.geometry,r)}function ET(t,e,r){var n=r[r.length-1].context.version;ST(t,e,r);var i=Sc(NT(n),"Distance");X_(i,e.distance.toString()),"2.0.0"===n?i.setAttribute("uom",e.unit):i.setAttribute("units",e.unit),t.appendChild(i)}function TT(t,e,r){var n=r[r.length-1].context.version;MT(rT[n],"ValueReference",t,e.propertyName);var i=Sc(I_,"TimePeriod");t.appendChild(i);var o=Sc(I_,"begin");i.appendChild(o),kT(o,e.begin);var a=Sc(I_,"end");i.appendChild(a),kT(a,e.end)}function CT(t,e,r){var n=r[r.length-1].context,i={node:t};O(i,{context:n});for(var o=e.conditions,a=0,s=o.length;a<s;++a){var l=o[a];Vc(i,_T,jc(l.getTagName()),[l],r)}}function OT(t,e,r){var n=r[r.length-1].context,i={node:t};O(i,{context:n});var o=e.condition;Vc(i,_T,jc(o.getTagName()),[o],r)}function PT(t,e,r){var n=r[r.length-1].context.version;void 0!==e.matchCase&&t.setAttribute("matchCase",e.matchCase.toString()),AT(n,t,e.propertyName),FT(n,t,""+e.expression)}function RT(t,e,r){AT(r[r.length-1].context.version,t,e.propertyName)}function IT(t,e,r){var n=r[r.length-1].context.version,i=NT(n);AT(n,t,e.propertyName);var o=Sc(i,"LowerBoundary");t.appendChild(o),FT(n,o,""+e.lowerBoundary);var a=Sc(i,"UpperBoundary");t.appendChild(a),FT(n,a,""+e.upperBoundary)}function LT(t,e,r){var n=r[r.length-1].context.version;t.setAttribute("wildCard",e.wildCard),t.setAttribute("singleChar",e.singleChar),t.setAttribute("escapeChar",e.escapeChar),void 0!==e.matchCase&&t.setAttribute("matchCase",e.matchCase.toString()),AT(n,t,e.propertyName),FT(n,t,""+e.pattern)}function MT(t,e,r,n){var i=Sc(t,e);X_(i,n),r.appendChild(i)}function FT(t,e,r){MT(NT(t),"Literal",e,r)}function AT(t,e,r){"2.0.0"===t?MT(rT[t],"ValueReference",e,r):MT(tT[t],"PropertyName",e,r)}function kT(t,e){var r=Sc(I_,"TimeInstant");t.appendChild(r);var n=Sc(I_,"timePosition");r.appendChild(n),X_(n,e)}function jT(t,e,r){var n=r[r.length-1],i=O({},n);i.node=t,Vc(i,_T,jc("Query"),e,r)}function NT(t){return"2.0.0"===t?rT[t]:tT[t]}var DT=oT,GT=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),zT={POINT:qn,LINESTRING:Py,POLYGON:fi,MULTIPOINT:Hy,MULTILINESTRING:Zy,MULTIPOLYGON:Jy},UT=1,BT=2,VT=3,YT=4,WT=5,qT=6,XT={};for(var ZT in bt)XT[ZT]=bt[ZT].toUpperCase();var KT=function(){function t(t){this.wkt=t,this.index_=-1}return t.prototype.isAlpha_=function(t){return t>="a"&&t<="z"||t>="A"&&t<="Z"},t.prototype.isNumeric_=function(t,e){return t>="0"&&t<="9"||"."==t&&!(void 0!==e&&e)},t.prototype.isWhiteSpace_=function(t){return" "==t||"\t"==t||"\r"==t||"\n"==t},t.prototype.nextChar_=function(){return this.wkt.charAt(++this.index_)},t.prototype.nextToken=function(){var t,e=this.nextChar_(),r=this.index_,n=e;if("("==e)t=BT;else if(","==e)t=WT;else if(")"==e)t=VT;else if(this.isNumeric_(e)||"-"==e)t=YT,n=this.readNumber_();else if(this.isAlpha_(e))t=UT,n=this.readText_();else{if(this.isWhiteSpace_(e))return this.nextToken();if(""!==e)throw new Error("Unexpected character: "+e);t=qT}return{position:r,value:n,type:t}},t.prototype.readNumber_=function(){var t,e=this.index_,r=!1,n=!1;do{"."==t?r=!0:"e"!=t&&"E"!=t||(n=!0),t=this.nextChar_()}while(this.isNumeric_(t,r)||!n&&("e"==t||"E"==t)||n&&("-"==t||"+"==t));return parseFloat(this.wkt.substring(e,this.index_--))},t.prototype.readText_=function(){var t,e=this.index_;do{t=this.nextChar_()}while(this.isAlpha_(t));return this.wkt.substring(e,this.index_--).toUpperCase()},t}(),HT=function(){function t(t){this.lexer_=t,this.token_,this.layout_=yt}return t.prototype.consume_=function(){this.token_=this.lexer_.nextToken()},t.prototype.isTokenType=function(t){return this.token_.type==t},t.prototype.match=function(t){var e=this.isTokenType(t);return e&&this.consume_(),e},t.prototype.parse=function(){return this.consume_(),this.parseGeometry_()},t.prototype.parseGeometryLayout_=function(){var t=yt,e=this.token_;if(this.isTokenType(UT)){var r=e.value;"Z"===r?t=mt:"M"===r?t=vt:"ZM"===r&&(t=_t),t!==yt&&this.consume_()}return t},t.prototype.parseGeometryCollectionText_=function(){if(this.match(BT)){var t=[];do{t.push(this.parseGeometry_())}while(this.match(WT));if(this.match(VT))return t}else if(this.isEmptyGeometry_())return[];throw new Error(this.formatErrorMessage_())},t.prototype.parsePointText_=function(){if(this.match(BT)){var t=this.parsePoint_();if(this.match(VT))return t}else if(this.isEmptyGeometry_())return null;throw new Error(this.formatErrorMessage_())},t.prototype.parseLineStringText_=function(){if(this.match(BT)){var t=this.parsePointList_();if(this.match(VT))return t}else if(this.isEmptyGeometry_())return[];throw new Error(this.formatErrorMessage_())},t.prototype.parsePolygonText_=function(){if(this.match(BT)){var t=this.parseLineStringTextList_();if(this.match(VT))return t}else if(this.isEmptyGeometry_())return[];throw new Error(this.formatErrorMessage_())},t.prototype.parseMultiPointText_=function(){if(this.match(BT)){var t=void 0;if(t=this.token_.type==BT?this.parsePointTextList_():this.parsePointList_(),this.match(VT))return t}else if(this.isEmptyGeometry_())return[];throw new Error(this.formatErrorMessage_())},t.prototype.parseMultiLineStringText_=function(){if(this.match(BT)){var t=this.parseLineStringTextList_();if(this.match(VT))return t}else if(this.isEmptyGeometry_())return[];throw new Error(this.formatErrorMessage_())},t.prototype.parseMultiPolygonText_=function(){if(this.match(BT)){var t=this.parsePolygonTextList_();if(this.match(VT))return t}else if(this.isEmptyGeometry_())return[];throw new Error(this.formatErrorMessage_())},t.prototype.parsePoint_=function(){for(var t=[],e=this.layout_.length,r=0;r<e;++r){var n=this.token_;if(!this.match(YT))break;t.push(n.value)}if(t.length==e)return t;throw new Error(this.formatErrorMessage_())},t.prototype.parsePointList_=function(){for(var t=[this.parsePoint_()];this.match(WT);)t.push(this.parsePoint_());return t},t.prototype.parsePointTextList_=function(){for(var t=[this.parsePointText_()];this.match(WT);)t.push(this.parsePointText_());return t},t.prototype.parseLineStringTextList_=function(){for(var t=[this.parseLineStringText_()];this.match(WT);)t.push(this.parseLineStringText_());return t},t.prototype.parsePolygonTextList_=function(){for(var t=[this.parsePolygonText_()];this.match(WT);)t.push(this.parsePolygonText_());return t},t.prototype.isEmptyGeometry_=function(){var t=this.isTokenType(UT)&&"EMPTY"==this.token_.value;return t&&this.consume_(),t},t.prototype.formatErrorMessage_=function(){return"Unexpected `"+this.token_.value+"` at position "+this.token_.position+" in `"+this.lexer_.wkt+"`"},t.prototype.parseGeometry_=function(){var t=this.token_;if(this.match(UT)){var e=t.value;if(this.layout_=this.parseGeometryLayout_(),"GEOMETRYCOLLECTION"==e){var r=this.parseGeometryCollectionText_();return new Vm(r)}var n=zT[e];if(!n)throw new Error("Invalid geometry type: "+e);var i=void 0;switch(e){case"POINT":i=this.parsePointText_();break;case"LINESTRING":i=this.parseLineStringText_();break;case"POLYGON":i=this.parsePolygonText_();break;case"MULTIPOINT":i=this.parseMultiPointText_();break;case"MULTILINESTRING":i=this.parseMultiLineStringText_();break;case"MULTIPOLYGON":i=this.parseMultiPolygonText_();break;default:throw new Error("Invalid geometry type: "+e)}return i||(i=n===zT.POINT?[NaN,NaN]:[]),new n(i,this.layout_)}throw new Error(this.formatErrorMessage_())},t}(),$T=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.splitCollection_=void 0!==n.splitCollection&&n.splitCollection,r}return GT(e,t),e.prototype.parse_=function(t){var e=new KT(t);return new HT(e).parse()},e.prototype.readFeatureFromText=function(t,e){var r=this.readGeometryFromText(t,e);if(r){var n=new gt;return n.setGeometry(r),n}return null},e.prototype.readFeaturesFromText=function(t,e){for(var r=[],n=this.readGeometryFromText(t,e),i=[],o=0,a=(r=this.splitCollection_&&n.getType()==bt.GEOMETRY_COLLECTION?n.getGeometriesArray():[n]).length;o<a;++o){var s=new gt;s.setGeometry(r[o]),i.push(s)}return i},e.prototype.readGeometryFromText=function(t,e){var r=this.parse_(t);return r?Wy(r,!1,e):null},e.prototype.writeFeatureText=function(t,e){var r=t.getGeometry();return r?this.writeGeometryText(r,e):""},e.prototype.writeFeaturesText=function(t,e){if(1==t.length)return this.writeFeatureText(t[0],e);for(var r=[],n=0,i=t.length;n<i;++n)r.push(t[n].getGeometry());var o=new Vm(r);return this.writeGeometryText(o,e)},e.prototype.writeGeometryText=function(t,e){return rC(Wy(t,!0,e))},e}(Jb);function JT(t){var e=t.getCoordinates();return 0===e.length?"":e.join(" ")}function QT(t){for(var e=t.getCoordinates(),r=[],n=0,i=e.length;n<i;++n)r.push(e[n].join(" "));return r.join(",")}function tC(t){for(var e=[],r=t.getLinearRings(),n=0,i=r.length;n<i;++n)e.push("("+QT(r[n])+")");return e.join(",")}var eC={Point:JT,LineString:QT,Polygon:tC,MultiPoint:function(t){for(var e=[],r=t.getPoints(),n=0,i=r.length;n<i;++n)e.push("("+JT(r[n])+")");return e.join(",")},MultiLineString:function(t){for(var e=[],r=t.getLineStrings(),n=0,i=r.length;n<i;++n)e.push("("+QT(r[n])+")");return e.join(",")},MultiPolygon:function(t){for(var e=[],r=t.getPolygons(),n=0,i=r.length;n<i;++n)e.push("("+tC(r[n])+")");return e.join(",")},GeometryCollection:function(t){for(var e=[],r=t.getGeometries(),n=0,i=r.length;n<i;++n)e.push(rC(r[n]));return e.join(",")}};function rC(t){var e=t.getType(),r=(0,eC[e])(t);if(e=e.toUpperCase(),"function"==typeof t.getFlatCoordinates){var n=function(t){var e=t.getLayout(),r="";return e!==mt&&e!==_t||(r+="Z"),e!==vt&&e!==_t||(r+="M"),r}(t);n.length>0&&(e+=" "+n)}return 0===r.length?e+" EMPTY":e+"("+r+")"}var nC=$T,iC=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),oC=[null,"http://www.opengis.net/wms"],aC=Gc(oC,{Service:Fc((function(t,e){return Uc({},uC,t,e)})),Capability:Fc((function(t,e){return Uc({},sC,t,e)}))}),sC=Gc(oC,{Request:Fc((function(t,e){return Uc({},mC,t,e)})),Exception:Fc((function(t,e){return Uc([],fC,t,e)})),Layer:Fc((function(t,e){var r=Uc({},dC,t,e);if(void 0===r.Layer)return Object.assign(r,EC(t,e));return r}))}),lC=function(t){function e(){var e=t.call(this)||this;return e.version=void 0,e}return iC(e,t),e.prototype.readFromNode=function(t){this.version=t.getAttribute("version").trim();var e=Uc({version:this.version},aC,t,[]);return e||null},e}(cS),uC=Gc(oC,{Name:Fc(U_),Title:Fc(U_),Abstract:Fc(U_),KeywordList:Fc(PC),OnlineResource:Fc(hS),ContactInformation:Fc((function(t,e){return Uc({},cC,t,e)})),Fees:Fc(U_),AccessConstraints:Fc(U_),LayerLimit:Fc(G_),MaxWidth:Fc(G_),MaxHeight:Fc(G_)}),cC=Gc(oC,{ContactPersonPrimary:Fc((function(t,e){return Uc({},hC,t,e)})),ContactPosition:Fc(U_),ContactAddress:Fc((function(t,e){return Uc({},pC,t,e)})),ContactVoiceTelephone:Fc(U_),ContactFacsimileTelephone:Fc(U_),ContactElectronicMailAddress:Fc(U_)}),hC=Gc(oC,{ContactPerson:Fc(U_),ContactOrganization:Fc(U_)}),pC=Gc(oC,{AddressType:Fc(U_),Address:Fc(U_),City:Fc(U_),StateOrProvince:Fc(U_),PostCode:Fc(U_),Country:Fc(U_)}),fC=Gc(oC,{Format:Ic(U_)}),dC=Gc(oC,{Name:Fc(U_),Title:Fc(U_),Abstract:Fc(U_),KeywordList:Fc(PC),CRS:Mc(U_),EX_GeographicBoundingBox:Fc((function(t,e){var r=Uc({},yC,t,e);if(!r)return;var n=r.westBoundLongitude,i=r.southBoundLatitude,o=r.eastBoundLongitude,a=r.northBoundLatitude;if(void 0===n||void 0===i||void 0===o||void 0===a)return;return[n,i,o,a]})),BoundingBox:Mc((function(t,e){var r=[D_(t.getAttribute("minx")),D_(t.getAttribute("miny")),D_(t.getAttribute("maxx")),D_(t.getAttribute("maxy"))],n=[D_(t.getAttribute("resx")),D_(t.getAttribute("resy"))];return{crs:t.getAttribute("CRS"),extent:r,res:n}})),Dimension:Mc((function(t,e){return{name:t.getAttribute("name"),units:t.getAttribute("units"),unitSymbol:t.getAttribute("unitSymbol"),default:t.getAttribute("default"),multipleValues:k_(t.getAttribute("multipleValues")),nearestValue:k_(t.getAttribute("nearestValue")),current:k_(t.getAttribute("current")),values:U_(t)}})),Attribution:Fc((function(t,e){return Uc({},gC,t,e)})),AuthorityURL:Mc((function(t,e){var r=TC(t,e);if(r)return r.name=t.getAttribute("name"),r;return})),Identifier:Mc(U_),MetadataURL:Mc((function(t,e){var r=TC(t,e);if(r)return r.type=t.getAttribute("type"),r;return})),DataURL:Mc(TC),FeatureListURL:Mc(TC),Style:Mc((function(t,e){return Uc({},xC,t,e)})),MinScaleDenominator:Fc(N_),MaxScaleDenominator:Fc(N_),Layer:Mc(EC)}),gC=Gc(oC,{Title:Fc(U_),OnlineResource:Fc(hS),LogoURL:Fc(OC)}),yC=Gc(oC,{westBoundLongitude:Fc(N_),eastBoundLongitude:Fc(N_),southBoundLatitude:Fc(N_),northBoundLatitude:Fc(N_)}),mC=Gc(oC,{GetCapabilities:Fc(CC),GetMap:Fc(CC),GetFeatureInfo:Fc(CC)}),vC=Gc(oC,{Format:Mc(U_),DCPType:Mc((function(t,e){return Uc({},_C,t,e)}))}),_C=Gc(oC,{HTTP:Fc((function(t,e){return Uc({},bC,t,e)}))}),bC=Gc(oC,{Get:Fc(TC),Post:Fc(TC)}),xC=Gc(oC,{Name:Fc(U_),Title:Fc(U_),Abstract:Fc(U_),LegendURL:Mc(OC),StyleSheetURL:Fc(TC),StyleURL:Fc(TC)}),wC=Gc(oC,{Format:Fc(U_),OnlineResource:Fc(hS)}),SC=Gc(oC,{Keyword:Ic(U_)});function EC(t,e){var r=e[e.length-1],n=Uc({},dC,t,e);if(n){var i=k_(t.getAttribute("queryable"));void 0===i&&(i=r.queryable),n.queryable=void 0!==i&&i;var o=z_(t.getAttribute("cascaded"));void 0===o&&(o=r.cascaded),n.cascaded=o;var a=k_(t.getAttribute("opaque"));void 0===a&&(a=r.opaque),n.opaque=void 0!==a&&a;var s=k_(t.getAttribute("noSubsets"));void 0===s&&(s=r.noSubsets),n.noSubsets=void 0!==s&&s;var l=D_(t.getAttribute("fixedWidth"));l||(l=r.fixedWidth),n.fixedWidth=l;var u=D_(t.getAttribute("fixedHeight"));u||(u=r.fixedHeight),n.fixedHeight=u;["Style","CRS","AuthorityURL"].forEach((function(t){if(t in r){var e=n[t]||[];n[t]=e.concat(r[t])}}));return["EX_GeographicBoundingBox","BoundingBox","Dimension","Attribution","MinScaleDenominator","MaxScaleDenominator"].forEach((function(t){if(!(t in n)){var e=r[t];n[t]=e}})),n}}function TC(t,e){return Uc({},wC,t,e)}function CC(t,e){return Uc({},vC,t,e)}function OC(t,e){var r=TC(t,e);if(r){var n=[z_(t.getAttribute("width")),z_(t.getAttribute("height"))];return r.size=n,r}}function PC(t,e){return Uc([],SC,t,e)}var RC=lC,IC=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),LC=function(t){function e(e){var r=t.call(this)||this,n=e||{};return r.featureNS_="http://mapserver.gis.umn.edu/mapserver",r.gmlFormat_=new $_,r.layers_=n.layers?n.layers:null,r}return IC(e,t),e.prototype.getLayers=function(){return this.layers_},e.prototype.setLayers=function(t){this.layers_=t},e.prototype.readFeatures_=function(t,e){t.setAttribute("namespaceURI",this.featureNS_);var r=t.localName,n=[];if(0===t.childNodes.length)return n;if("msGMLOutput"==r)for(var i=0,o=t.childNodes.length;i<o;i++){var a=t.childNodes[i];if(a.nodeType===Node.ELEMENT_NODE){var s=a,l=e[0],u=s.localName.replace("_layer","");if(!this.layers_||g(this.layers_,u)){var c=u+"_feature";l.featureType=c,l.featureNS=this.featureNS_;var h={};h[c]=Ic(this.gmlFormat_.readFeatureElement,this.gmlFormat_);var p=Gc([l.featureNS,null],h);s.setAttribute("namespaceURI",this.featureNS_);var f=Uc([],p,s,e,this.gmlFormat_);f&&v(n,f)}}}if("FeatureCollection"==r){var d=Uc([],this.gmlFormat_.FEATURE_COLLECTION_PARSERS,t,[{}],this.gmlFormat_);d&&(n=d)}return n},e.prototype.readFeaturesFromNode=function(t,e){var r={};return e&&O(r,this.getReadOptions(t,e)),this.readFeatures_(t,[r])},e}(P_),MC=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),FC=[null,"http://www.opengis.net/wmts/1.0"],AC=[null,"http://www.opengis.net/ows/1.1"],kC=Gc(FC,{Contents:Fc((function(t,e){return Uc({},NC,t,e)}))}),jC=function(t){function e(){var e=t.call(this)||this;return e.owsParser_=new RS,e}return MC(e,t),e.prototype.readFromNode=function(t){var e=t.getAttribute("version");e&&(e=e.trim());var r=this.owsParser_.readFromNode(t);return r?(r.version=e,(r=Uc(r,kC,t,[]))||null):null},e}(cS),NC=Gc(FC,{Layer:Mc((function(t,e){return Uc({},DC,t,e)})),TileMatrixSet:Mc((function(t,e){return Uc({},WC,t,e)}))}),DC=Gc(FC,{Style:Mc((function(t,e){var r=Uc({},GC,t,e);if(!r)return;var n="true"===t.getAttribute("isDefault");return r.isDefault=n,r})),Format:Mc(U_),TileMatrixSetLink:Mc((function(t,e){return Uc({},zC,t,e)})),Dimension:Mc((function(t,e){return Uc({},VC,t,e)})),ResourceURL:Mc((function(t,e){var r=t.getAttribute("format"),n=t.getAttribute("template"),i=t.getAttribute("resourceType"),o={};r&&(o.format=r);n&&(o.template=n);i&&(o.resourceType=i);return o}))},Gc(AC,{Title:Fc(U_),Abstract:Fc(U_),WGS84BoundingBox:Fc((function(t,e){var r=Uc([],YC,t,e);if(2!=r.length)return;return Kt(r)})),Identifier:Fc(U_)})),GC=Gc(FC,{LegendURL:Mc((function(t,e){var r={};return r.format=t.getAttribute("format"),r.href=hS(t),r}))},Gc(AC,{Title:Fc(U_),Identifier:Fc(U_)})),zC=Gc(FC,{TileMatrixSet:Fc(U_),TileMatrixSetLimits:Fc((function(t,e){return Uc([],UC,t,e)}))}),UC=Gc(FC,{TileMatrixLimits:Ic((function(t,e){return Uc({},BC,t,e)}))}),BC=Gc(FC,{TileMatrix:Fc(U_),MinTileRow:Fc(G_),MaxTileRow:Fc(G_),MinTileCol:Fc(G_),MaxTileCol:Fc(G_)}),VC=Gc(FC,{Default:Fc(U_),Value:Mc(U_)},Gc(AC,{Identifier:Fc(U_)})),YC=Gc(AC,{LowerCorner:Ic(XC),UpperCorner:Ic(XC)}),WC=Gc(FC,{WellKnownScaleSet:Fc(U_),TileMatrix:Mc((function(t,e){return Uc({},qC,t,e)}))},Gc(AC,{SupportedCRS:Fc(U_),Identifier:Fc(U_)})),qC=Gc(FC,{TopLeftCorner:Fc(XC),ScaleDenominator:Fc(N_),TileWidth:Fc(G_),TileHeight:Fc(G_),MatrixWidth:Fc(G_),MatrixHeight:Fc(G_)},Gc(AC,{Identifier:Fc(U_)}));function XC(t,e){var r=U_(t).split(/\s+/);if(r&&2==r.length){var n=+r[0],i=+r[1];if(!isNaN(n)&&!isNaN(i))return[n,i]}}var ZC=jC,KC=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),HC=["fullscreenchange","webkitfullscreenchange","MSFullscreenChange"],$C="enterfullscreen",JC="leavefullscreen";function QC(){var t=document.body;return!!(t.webkitRequestFullscreen||t.msRequestFullscreen&&document.msFullscreenEnabled||t.requestFullscreen&&document.fullscreenEnabled)}function tO(){return!!(document.webkitIsFullScreen||document.msFullscreenElement||document.fullscreenElement)}function eO(t){t.requestFullscreen?t.requestFullscreen():t.msRequestFullscreen?t.msRequestFullscreen():t.webkitRequestFullscreen&&t.webkitRequestFullscreen()}var rO=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,{element:document.createElement("div"),target:n.target})||this).cssClassName_=void 0!==n.className?n.className:"ol-full-screen",r.activeClassName_=void 0!==n.activeClassName?n.activeClassName.split(" "):[r.cssClassName_+"-true"],r.inactiveClassName_=void 0!==n.inactiveClassName?n.inactiveClassName.split(" "):[r.cssClassName_+"-false"];var i=void 0!==n.label?n.label:"⤢";r.labelNode_="string"==typeof i?document.createTextNode(i):i;var o=void 0!==n.labelActive?n.labelActive:"×";r.labelActiveNode_="string"==typeof o?document.createTextNode(o):o,r.button_=document.createElement("button");var a=n.tipLabel?n.tipLabel:"Toggle full-screen";r.setClassName_(r.button_,tO()),r.button_.setAttribute("type","button"),r.button_.title=a,r.button_.appendChild(r.labelNode_),r.button_.addEventListener(N,r.handleClick_.bind(r),!1);var s=r.cssClassName_+" ol-unselectable ol-control "+(QC()?"":"ol-unsupported"),l=r.element;return l.className=s,l.appendChild(r.button_),r.keys_=void 0!==n.keys&&n.keys,r.source_=n.source,r}return KC(e,t),e.prototype.handleClick_=function(t){t.preventDefault(),this.handleFullScreen_()},e.prototype.handleFullScreen_=function(){if(QC()){var t=this.getMap();if(t)if(tO())document.exitFullscreen?document.exitFullscreen():document.msExitFullscreen?document.msExitFullscreen():document.webkitExitFullscreen&&document.webkitExitFullscreen();else{var e=void 0;e=this.source_?"string"==typeof this.source_?document.getElementById(this.source_):this.source_:t.getTargetElement(),this.keys_?function(t){t.webkitRequestFullscreen?t.webkitRequestFullscreen():eO(t)}(e):eO(e)}}},e.prototype.handleFullScreenChange_=function(){var t=this.getMap();tO()?(this.setClassName_(this.button_,!0),po(this.labelActiveNode_,this.labelNode_),this.dispatchEvent($C)):(this.setClassName_(this.button_,!1),po(this.labelNode_,this.labelActiveNode_),this.dispatchEvent(JC)),t&&t.updateSize()},e.prototype.setClassName_=function(t,e){var r,n,i,o=this.activeClassName_,a=this.inactiveClassName_,s=e?o:a;(r=t.classList).remove.apply(r,o),(n=t.classList).remove.apply(n,a),(i=t.classList).add.apply(i,s)},e.prototype.setMap=function(e){if(t.prototype.setMap.call(this,e),e)for(var r=0,n=HC.length;r<n;++r)this.listenerKeys.push(Z(document,HC[r],this.handleFullScreenChange_,this))},e}(As),nO=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),iO=function(t){function e(e){var r=this,n=e||{},i=document.createElement("div");return i.className=void 0!==n.className?n.className:"ol-mouse-position",(r=t.call(this,{element:i,render:n.render,target:n.target})||this).addEventListener(it("projection"),r.handleProjectionChanged_),n.coordinateFormat&&r.setCoordinateFormat(n.coordinateFormat),n.projection&&r.setProjection(n.projection),r.undefinedHTML_=void 0!==n.undefinedHTML?n.undefinedHTML:" ",r.renderOnMouseOut_=!!r.undefinedHTML_,r.renderedHTML_=i.innerHTML,r.mapProjection_=null,r.transform_=null,r}return nO(e,t),e.prototype.handleProjectionChanged_=function(){this.transform_=null},e.prototype.getCoordinateFormat=function(){return this.get("coordinateFormat")},e.prototype.getProjection=function(){return this.get("projection")},e.prototype.handleMouseMove=function(t){var e=this.getMap();this.updateHTML_(e.getEventPixel(t))},e.prototype.handleMouseOut=function(t){this.updateHTML_(null)},e.prototype.setMap=function(e){if(t.prototype.setMap.call(this,e),e){var r=e.getViewport();this.listenerKeys.push(Z(r,za,this.handleMouseMove,this)),this.renderOnMouseOut_&&this.listenerKeys.push(Z(r,Va,this.handleMouseOut,this))}},e.prototype.setCoordinateFormat=function(t){this.set("coordinateFormat",t)},e.prototype.setProjection=function(t){this.set("projection",Gr(t))},e.prototype.updateHTML_=function(t){var e=this.undefinedHTML_;if(t&&this.mapProjection_){if(!this.transform_){var r=this.getProjection();this.transform_=r?Zr(this.mapProjection_,r):jr}var n=this.getMap().getCoordinateFromPixelInternal(t);if(n){var i=tn();i&&(this.transform_=Zr(this.mapProjection_,i)),this.transform_(n,n);var o=this.getCoordinateFormat();e=o?o(n):n.toString()}}this.renderedHTML_&&e===this.renderedHTML_||(this.element.innerHTML=e,this.renderedHTML_=e)},e.prototype.render=function(t){var e=t.frameState;e?this.mapProjection_!=e.viewState.projection&&(this.mapProjection_=e.viewState.projection,this.transform_=null):this.mapProjection_=null},e}(As),oO=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),aO=function(t){function e(){return null!==t&&t.apply(this,arguments)||this}return oO(e,t),e.prototype.createRenderer=function(){return new La(this)},e}(Ms),sO=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,{element:document.createElement("div"),render:n.render,target:n.target})||this).boundHandleRotationChanged_=r.handleRotationChanged_.bind(r),r.collapsed_=void 0===n.collapsed||n.collapsed,r.collapsible_=void 0===n.collapsible||n.collapsible,r.collapsible_||(r.collapsed_=!1),r.rotateWithView_=void 0!==n.rotateWithView&&n.rotateWithView,r.viewExtent_=void 0;var i=void 0!==n.className?n.className:"ol-overviewmap",o=void 0!==n.tipLabel?n.tipLabel:"Overview map",a=void 0!==n.collapseLabel?n.collapseLabel:"«";"string"==typeof a?(r.collapseLabel_=document.createElement("span"),r.collapseLabel_.textContent=a):r.collapseLabel_=a;var s=void 0!==n.label?n.label:"»";"string"==typeof s?(r.label_=document.createElement("span"),r.label_.textContent=s):r.label_=s;var l=r.collapsible_&&!r.collapsed_?r.collapseLabel_:r.label_,u=document.createElement("button");u.setAttribute("type","button"),u.title=o,u.appendChild(l),u.addEventListener(N,r.handleClick_.bind(r),!1),r.ovmapDiv_=document.createElement("div"),r.ovmapDiv_.className="ol-overviewmap-map",r.view_=n.view,r.ovmap_=new aO({view:n.view});var c=r.ovmap_;n.layers&&n.layers.forEach((function(t){c.addLayer(t)}));var h=document.createElement("div");h.className="ol-overviewmap-box",h.style.boxSizing="border-box",r.boxOverlay_=new su({position:[0,0],positioning:Hl,element:h}),r.ovmap_.addOverlay(r.boxOverlay_);var p=i+" ol-unselectable ol-control"+(r.collapsed_&&r.collapsible_?" ol-collapsed":"")+(r.collapsible_?"":" ol-uncollapsible"),f=r.element;f.className=p,f.appendChild(r.ovmapDiv_),f.appendChild(u);var d=r,g=r.boxOverlay_,y=r.boxOverlay_.getElement(),m=function(t){var e,r={clientX:(e=t).clientX,clientY:e.clientY},n=c.getEventCoordinateInternal(r);g.setPosition(n)},v=function(t){var e=c.getEventCoordinateInternal(t);d.getMap().getView().setCenterInternal(e),window.removeEventListener("mousemove",m),window.removeEventListener("mouseup",v)};return y.addEventListener("mousedown",(function(){window.addEventListener("mousemove",m),window.addEventListener("mouseup",v)})),r}return oO(e,t),e.prototype.setMap=function(e){var r=this.getMap();if(e!==r){if(r){var n=r.getView();n&&this.unbindView_(n),this.ovmap_.setTarget(null)}if(t.prototype.setMap.call(this,e),e){this.ovmap_.setTarget(this.ovmapDiv_),this.listenerKeys.push(Z(e,h,this.handleMapPropertyChange_,this));var i=e.getView();i&&(this.bindView_(i),i.isDef()&&(this.ovmap_.updateSize(),this.resetExtent_()))}}},e.prototype.handleMapPropertyChange_=function(t){if(t.key===Ja){var e=t.oldValue;e&&this.unbindView_(e);var r=this.getMap().getView();this.bindView_(r)}},e.prototype.bindView_=function(t){if(!this.view_){var e=new Cs({projection:t.getProjection()});this.ovmap_.setView(e)}t.addEventListener(it(ss),this.boundHandleRotationChanged_),this.handleRotationChanged_()},e.prototype.unbindView_=function(t){t.removeEventListener(it(ss),this.boundHandleRotationChanged_)},e.prototype.handleRotationChanged_=function(){this.rotateWithView_&&this.ovmap_.getView().setRotation(this.getMap().getView().getRotation())},e.prototype.validateExtent_=function(){var t=this.getMap(),e=this.ovmap_;if(t.isRendered()&&e.isRendered()){var r=t.getSize(),n=t.getView().calculateExtentInternal(r);if(!this.viewExtent_||!ue(n,this.viewExtent_)){this.viewExtent_=n;var i=e.getSize(),o=e.getView().calculateExtentInternal(i),a=e.getPixelFromCoordinateInternal(Ce(n)),s=e.getPixelFromCoordinateInternal(be(n)),l=Math.abs(a[0]-s[0]),u=Math.abs(a[1]-s[1]),c=i[0],h=i[1];l<.1*c||u<.1*h||l>.75*c||u>.75*h?this.resetExtent_():te(o,n)||this.recenter_()}}},e.prototype.resetExtent_=function(){var t=this.getMap(),e=this.ovmap_,r=t.getSize(),n=t.getView().calculateExtentInternal(r),i=e.getView(),o=Math.log(7.5)/Math.LN2;Me(n,1/(.1*Math.pow(2,o/2))),i.fitInternal(gi(n))},e.prototype.recenter_=function(){var t=this.getMap(),e=this.ovmap_,r=t.getView();e.getView().setCenterInternal(r.getCenterInternal())},e.prototype.updateBox_=function(){var t=this.getMap(),e=this.ovmap_;if(t.isRendered()&&e.isRendered()){var r=t.getSize(),n=t.getView(),i=e.getView(),o=this.rotateWithView_?0:-n.getRotation(),a=this.boxOverlay_,s=this.boxOverlay_.getElement(),l=n.getCenterInternal(),u=n.getResolution(),c=i.getResolution(),h=r[0]*u/c,p=r[1]*u/c;if(a.setPosition(l),s){s.style.width=h+"px",s.style.height=p+"px";var f="rotate("+o+"rad)";s.style.transform=f}}},e.prototype.handleClick_=function(t){t.preventDefault(),this.handleToggle_()},e.prototype.handleToggle_=function(){this.element.classList.toggle("ol-collapsed"),this.collapsed_?po(this.collapseLabel_,this.label_):po(this.label_,this.collapseLabel_),this.collapsed_=!this.collapsed_;var t=this.ovmap_;if(!this.collapsed_){if(t.isRendered())return this.viewExtent_=void 0,void t.render();t.updateSize(),this.resetExtent_(),K(t,qa,(function(t){this.updateBox_()}),this)}},e.prototype.getCollapsible=function(){return this.collapsible_},e.prototype.setCollapsible=function(t){this.collapsible_!==t&&(this.collapsible_=t,this.element.classList.toggle("ol-uncollapsible"),!t&&this.collapsed_&&this.handleToggle_())},e.prototype.setCollapsed=function(t){this.collapsible_&&this.collapsed_!==t&&this.handleToggle_()},e.prototype.getCollapsed=function(){return this.collapsed_},e.prototype.getRotateWithView=function(){return this.rotateWithView_},e.prototype.setRotateWithView=function(t){this.rotateWithView_!==t&&(this.rotateWithView_=t,0!==this.getMap().getView().getRotation()&&(this.rotateWithView_?this.handleRotationChanged_():this.ovmap_.getView().setRotation(0),this.viewExtent_=void 0,this.validateExtent_(),this.updateBox_()))},e.prototype.getOverviewMap=function(){return this.ovmap_},e.prototype.render=function(t){this.validateExtent_(),this.updateBox_()},e}(As),lO=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),uO="degrees",cO="imperial",hO="nautical",pO="metric",fO="us",dO=[1,2,5],gO=function(t){function e(e){var r=this,n=e||{},i=void 0!==n.className?n.className:n.bar?"ol-scale-bar":"ol-scale-line";return(r=t.call(this,{element:document.createElement("div"),render:n.render,target:n.target})||this).innerElement_=document.createElement("div"),r.innerElement_.className=i+"-inner",r.element.className=i+" ol-unselectable",r.element.appendChild(r.innerElement_),r.viewState_=null,r.minWidth_=void 0!==n.minWidth?n.minWidth:64,r.renderedVisible_=!1,r.renderedWidth_=void 0,r.renderedHTML_="",r.addEventListener(it("units"),r.handleUnitsChanged_),r.setUnits(n.units||pO),r.scaleBar_=n.bar||!1,r.scaleBarSteps_=n.steps||4,r.scaleBarText_=n.text||!1,r.dpi_=n.dpi||void 0,r}return lO(e,t),e.prototype.getUnits=function(){return this.get("units")},e.prototype.handleUnitsChanged_=function(){this.updateElement_()},e.prototype.setUnits=function(t){this.set("units",t)},e.prototype.setDpi=function(t){this.dpi_=t},e.prototype.updateElement_=function(){var t=this.viewState_;if(t){var e=t.center,r=t.projection,n=this.getUnits(),i=n==uO?St.DEGREES:St.METERS,o=zr(r,t.resolution,e,i),a=this.minWidth_*(this.dpi_||25.4/.28)/(25.4/.28),s=a*o,l="";if(n==uO){var u=wt[St.DEGREES];(s*=u)<u/60?(l="″",o*=3600):s<u?(l="′",o*=60):l="°"}else n==cO?s<.9144?(l="in",o/=.0254):s<1609.344?(l="ft",o/=.3048):(l="mi",o/=1609.344):n==hO?(o/=1852,l="nm"):n==pO?s<.001?(l="μm",o*=1e6):s<1?(l="mm",o*=1e3):s<1e3?l="m":(l="km",o/=1e3):n==fO?s<.9144?(l="in",o*=39.37):s<1609.344?(l="ft",o/=.30480061):(l="mi",o/=1609.3472):pt(!1,33);for(var c,h,p,f,d=3*Math.floor(Math.log(a*o)/Math.log(10));;){p=Math.floor(d/3);var g=Math.pow(10,p);if(c=dO[(d%3+3)%3]*g,h=Math.round(c/o),isNaN(h))return this.element.style.display="none",void(this.renderedVisible_=!1);if(h>=a)break;++d}f=this.scaleBar_?this.createScaleBar(h,c,l):c.toFixed(p<0?-p:0)+" "+l,this.renderedHTML_!=f&&(this.innerElement_.innerHTML=f,this.renderedHTML_=f),this.renderedWidth_!=h&&(this.innerElement_.style.width=h+"px",this.renderedWidth_=h),this.renderedVisible_||(this.element.style.display="",this.renderedVisible_=!0)}else this.renderedVisible_&&(this.element.style.display="none",this.renderedVisible_=!1)},e.prototype.createScaleBar=function(t,e,r){for(var n="1 : "+Math.round(this.getScaleForResolution()).toLocaleString(),i=[],o=t/this.scaleBarSteps_,a="#ffffff",s=0;s<this.scaleBarSteps_;s++)0===s&&i.push(this.createMarker("absolute",s)),i.push('<div><div class="ol-scale-singlebar" style="width: '+o+"px;background-color: "+a+';"></div>'+this.createMarker("relative",s)+(s%2==0||2===this.scaleBarSteps_?this.createStepText(s,t,!1,e,r):"")+"</div>"),s===this.scaleBarSteps_-1&&i.push(this.createStepText(s+1,t,!0,e,r)),a="#ffffff"===a?"#000000":"#ffffff";return'<div style="display: flex;">'+(this.scaleBarText_?'<div class="ol-scale-text" style="width: '+t+'px;">'+n+"</div>":"")+i.join("")+"</div>"},e.prototype.createMarker=function(t,e){return'<div class="ol-scale-step-marker" style="position: '+t+";top: "+("absolute"===t?3:-10)+'px;"></div>'},e.prototype.createStepText=function(t,e,r,n,i){var o=(0===t?0:Math.round(n/this.scaleBarSteps_*t*100)/100)+(0===t?"":" "+i);return'<div class="ol-scale-step-text" style="margin-left: '+(0===t?-3:e/this.scaleBarSteps_*-1)+"px;text-align: "+(0===t?"left":"center")+"; min-width: "+(0===t?0:e/this.scaleBarSteps_*2)+"px;left: "+(r?e+"px":"unset")+';">'+o+"</div>"},e.prototype.getScaleForResolution=function(){var t=zr(this.viewState_.projection,this.viewState_.resolution,this.viewState_.center),e=this.dpi_||25.4/.28,r=this.viewState_.projection.getMetersPerUnit();return parseFloat(t.toString())*r*(1e3/25.4)*e},e.prototype.render=function(t){var e=t.frameState;this.viewState_=e?e.viewState:null,this.updateElement_()},e}(As),yO=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),mO=0,vO=1,_O=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,{element:document.createElement("div"),render:n.render})||this).dragListenerKeys_=[],r.currentResolution_=void 0,r.direction_=mO,r.dragging_,r.heightLimit_=0,r.widthLimit_=0,r.startX_,r.startY_,r.thumbSize_=null,r.sliderInitialized_=!1,r.duration_=void 0!==n.duration?n.duration:200;var i=void 0!==n.className?n.className:"ol-zoomslider",o=document.createElement("button");o.setAttribute("type","button"),o.className=i+"-thumb ol-unselectable";var a=r.element;return a.className=i+" ol-unselectable ol-control",a.appendChild(o),a.addEventListener(Ua,r.handleDraggerStart_.bind(r),!1),a.addEventListener(za,r.handleDraggerDrag_.bind(r),!1),a.addEventListener(Ba,r.handleDraggerEnd_.bind(r),!1),a.addEventListener(N,r.handleContainerClick_.bind(r),!1),o.addEventListener(N,u,!1),r}return yO(e,t),e.prototype.setMap=function(e){t.prototype.setMap.call(this,e),e&&e.render()},e.prototype.initSlider_=function(){var t=this.element,e=t.offsetWidth,r=t.offsetHeight;if(0===e&&0===r)return this.sliderInitialized_=!1;var n=t.firstElementChild,i=getComputedStyle(n),o=n.offsetWidth+parseFloat(i.marginRight)+parseFloat(i.marginLeft),a=n.offsetHeight+parseFloat(i.marginTop)+parseFloat(i.marginBottom);return this.thumbSize_=[o,a],e>r?(this.direction_=vO,this.widthLimit_=e-o):(this.direction_=mO,this.heightLimit_=r-a),this.sliderInitialized_=!0},e.prototype.handleContainerClick_=function(t){var e=this.getMap().getView(),r=this.getRelativePosition_(t.offsetX-this.thumbSize_[0]/2,t.offsetY-this.thumbSize_[1]/2),n=this.getResolutionForPosition_(r),i=e.getConstrainedZoom(e.getZoomForResolution(n));e.animateInternal({zoom:i,duration:this.duration_,easing:io})},e.prototype.handleDraggerStart_=function(t){if(!this.dragging_&&t.target===this.element.firstElementChild){var e=this.element.firstElementChild;if(this.getMap().getView().beginInteraction(),this.startX_=t.clientX-parseFloat(e.style.left),this.startY_=t.clientY-parseFloat(e.style.top),this.dragging_=!0,0===this.dragListenerKeys_.length){var r=this.handleDraggerDrag_,n=this.handleDraggerEnd_,i=this.getMap().getOwnerDocument();this.dragListenerKeys_.push(Z(i,za,r,this),Z(i,Ba,n,this))}}},e.prototype.handleDraggerDrag_=function(t){if(this.dragging_){var e=t.clientX-this.startX_,r=t.clientY-this.startY_,n=this.getRelativePosition_(e,r);this.currentResolution_=this.getResolutionForPosition_(n),this.getMap().getView().setResolution(this.currentResolution_)}},e.prototype.handleDraggerEnd_=function(t){this.dragging_&&(this.getMap().getView().endInteraction(),this.dragging_=!1,this.startX_=void 0,this.startY_=void 0,this.dragListenerKeys_.forEach(H),this.dragListenerKeys_.length=0)},e.prototype.setThumbPosition_=function(t){var e=this.getPositionForResolution_(t),r=this.element.firstElementChild;this.direction_==vO?r.style.left=this.widthLimit_*e+"px":r.style.top=this.heightLimit_*e+"px"},e.prototype.getRelativePosition_=function(t,e){return Ne(this.direction_===vO?t/this.widthLimit_:e/this.heightLimit_,0,1)},e.prototype.getResolutionForPosition_=function(t){return this.getMap().getView().getResolutionForValueFunction()(1-t)},e.prototype.getPositionForResolution_=function(t){return Ne(1-this.getMap().getView().getValueForResolutionFunction()(t),0,1)},e.prototype.render=function(t){if(t.frameState&&(this.sliderInitialized_||this.initSlider_())){var e=t.frameState.viewState.resolution;this.currentResolution_=e,this.setThumbPosition_(e)}},e}(As),bO=function(){var t=function(e,r){return(t=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(t,e){t.__proto__=e}||function(t,e){for(var r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=e[r])})(e,r)};return function(e,r){function n(){this.constructor=e}t(e,r),e.prototype=null===r?Object.create(r):(n.prototype=r.prototype,new n)}}(),xO=function(t){function e(e){var r=this,n=e||{};(r=t.call(this,{element:document.createElement("div"),target:n.target})||this).extent=n.extent?n.extent:null;var i=void 0!==n.className?n.className:"ol-zoom-extent",o=void 0!==n.label?n.label:"E",a=void 0!==n.tipLabel?n.tipLabel:"Fit to extent",s=document.createElement("button");s.setAttribute("type","button"),s.title=a,s.appendChild("string"==typeof o?document.createTextNode(o):o),s.addEventListener(N,r.handleClick_.bind(r),!1);var l=i+" ol-unselectable ol-control",u=r.element;return u.className=l,u.appendChild(s),r}return bO(e,t),e.prototype.handleClick_=function(t){t.preventDefault(),this.handleZoomToExtent()},e.prototype.handleZoomToExtent=function(){var t=this.getMap().getView(),e=this.extent?this.extent:t.getProjection().getExtent();t.fitInternal(gi(e))},e}(As),wO={};wO.AssertionError=l||{},wO.Collection=ht||{},wO.Collection.CollectionEvent=ct||{},wO.Disposable=p||{},wO.Feature=gt||{},wO.Feature.createStyleFunction=dt||{},wO.Geolocation=Ii||{},wO.Image=Ki||{},wO.Image.listenImage=Zi||{},wO.ImageBase=Mi||{},wO.ImageCanvas=$i||{},wO.ImageTile=vo||{},wO.Kinetic=_o||{},wO.Map=Wl||{},wO.MapBrowserEvent=Da||{},wO.MapBrowserEventHandler=Wa||{},wO.MapEvent=ja||{},wO.Object=ot||{},wO.Object.ObjectEvent=et||{},wO.Object.getChangeEventType=it||{},wO.Observable=Q||{},wO.Observable.unByKey=J||{},wO.Overlay=su||{},wO.PluggableMap=Ms||{},wO.Tile=lo||{},wO.TileCache=yu||{},wO.TileQueue=es||{},wO.TileQueue.getTilePriority=rs||{},wO.TileRange=_u||{},wO.TileRange.createOrUpdate=vu||{},wO.VectorRenderTile=wu||{},wO.VectorTile=Eu||{},wO.View=Cs||{},wO.View.createCenterConstraint=xs||{},wO.View.createResolutionConstraint=ws||{},wO.View.createRotationConstraint=Ss||{},wO.View.isNoopAnimation=Es||{},wO.array={},wO.array.binarySearch=f||{},wO.array.equals=b||{},wO.array.extend=v||{},wO.array.find=_||{},wO.array.findIndex=x||{},wO.array.includes=g||{},wO.array.isSorted=w||{},wO.array.linearFindNearest=y||{},wO.array.numberSafeCompareFunction=d||{},wO.array.remove=function(t,e){var r=t.indexOf(e),n=r>-1;return n&&t.splice(r,1),n}||{},wO.array.reverseSubArray=m||{},wO.array.stableSort=function(t,e){var r,n=t.length,i=Array(t.length);for(r=0;r<n;r++)i[r]={index:r,value:t[r]};for(i.sort((function(t,r){return e(t.value,r.value)||t.index-r.index})),r=0;r<t.length;r++)t[r]=i[r].value}||{},wO.asserts={},wO.asserts.assert=pt||{},wO.centerconstraint={},wO.centerconstraint.createExtent=ls||{},wO.centerconstraint.none=us||{},wO.color={},wO.color.asArray=Oo||{},wO.color.asString=wo||{},wO.color.fromString=Co||{},wO.color.isStringColor=Io||{},wO.color.normalize=Po||{},wO.color.toString=Ro||{},wO.colorlike={},wO.colorlike.asColorLike=Tu||{},wO.control={},wO.control.Attribution=js||{},wO.control.Control=As||{},wO.control.FullScreen=rO||{},wO.control.MousePosition=iO||{},wO.control.OverviewMap=sO||{},wO.control.Rotate=Ds||{},wO.control.ScaleLine=gO||{},wO.control.Zoom=zs||{},wO.control.ZoomSlider=_O||{},wO.control.ZoomToExtent=xO||{},wO.control.defaults=Us||{},wO.coordinate={},wO.coordinate.add=xr||{},wO.coordinate.closestOnCircle=wr||{},wO.coordinate.closestOnSegment=Sr||{},wO.coordinate.createStringXY=function(t){return function(e){return Mr(e,t)}}||{},wO.coordinate.degreesToStringHDMS=Er||{},wO.coordinate.distance=Ir||{},wO.coordinate.equals=Cr||{},wO.coordinate.format=Tr||{},wO.coordinate.getWorldsAway=Ar||{},wO.coordinate.rotate=Or||{},wO.coordinate.scale=Pr||{},wO.coordinate.squaredDistance=Rr||{},wO.coordinate.squaredDistanceToSegment=Lr||{},wO.coordinate.toStringHDMS=function(t,e){return t?Er("NS",t[1],e)+" "+Er("EW",t[0],e):""}||{},wO.coordinate.toStringXY=Mr||{},wO.coordinate.wrapX=Fr||{},wO.css={},wO.css.CLASS_COLLAPSED="ol-collapsed",wO.css.CLASS_CONTROL="ol-control",wO.css.CLASS_HIDDEN="ol-hidden",wO.css.CLASS_SELECTABLE="ol-selectable",wO.css.CLASS_UNSELECTABLE="ol-unselectable",wO.css.CLASS_UNSUPPORTED="ol-unsupported",wO.css.getFontParameters=ha||{},wO.dom={},wO.dom.createCanvasContext2D=uo||{},wO.dom.outerHeight=ho||{},wO.dom.outerWidth=co||{},wO.dom.removeChildren=go||{},wO.dom.removeNode=fo||{},wO.dom.replaceChildren=yo||{},wO.dom.replaceNode=po||{},wO.easing={},wO.easing.easeIn=no||{},wO.easing.easeOut=io||{},wO.easing.inAndOut=oo||{},wO.easing.linear=ao||{},wO.easing.upAndDown=function(t){return t<.5?oo(2*t):1-oo(2*(t-.5))}||{},wO.events={},wO.events.Event=c||{},wO.events.Event.preventDefault=function(t){t.preventDefault()}||{},wO.events.Event.stopPropagation=u||{},wO.events.Target=M||{},wO.events.condition={},wO.events.condition.all=Js||{},wO.events.condition.altKeyOnly=Qs||{},wO.events.condition.altShiftKeysOnly=tl||{},wO.events.condition.always=nl||{},wO.events.condition.click=function(t){return t.type==Ga.CLICK}||{},wO.events.condition.doubleClick=function(t){return t.type==Ga.DBLCLICK}||{},wO.events.condition.focus=el||{},wO.events.condition.focusWithTabindex=rl||{},wO.events.condition.mouseActionButton=il||{},wO.events.condition.mouseOnly=cl||{},wO.events.condition.never=ol||{},wO.events.condition.noModifierKeys=sl||{},wO.events.condition.penOnly=function(t){var e=t.originalEvent;return pt(void 0!==e,56),"pen"===e.pointerType}||{},wO.events.condition.platformModifierKeyOnly=function(t){var e=t.originalEvent;return!e.altKey&&(Bi?e.metaKey:e.ctrlKey)&&!e.shiftKey}||{},wO.events.condition.pointerMove=function(t){return"pointermove"==t.type}||{},wO.events.condition.primaryAction=hl||{},wO.events.condition.shiftKeyOnly=ll||{},wO.events.condition.singleClick=al||{},wO.events.condition.targetNotEditable=ul||{},wO.events.condition.touchOnly=function(t){var e=t.originalEvent;return pt(void 0!==e,56),"touch"===e.pointerType}||{},wO.events.listen=Z||{},wO.events.listenOnce=K||{},wO.events.unlistenByKey=H||{},wO.extent={},wO.extent.applyTransform=Ae||{},wO.extent.approximatelyEquals=ce||{},wO.extent.boundingExtent=Kt||{},wO.extent.buffer=Ht||{},wO.extent.clone=$t||{},wO.extent.closestSquaredDistanceXY=Jt||{},wO.extent.containsCoordinate=Qt||{},wO.extent.containsExtent=te||{},wO.extent.containsXY=ee||{},wO.extent.coordinateRelationship=re||{},wO.extent.createEmpty=ne||{},wO.extent.createOrUpdate=ie||{},wO.extent.createOrUpdateEmpty=oe||{},wO.extent.createOrUpdateFromCoordinate=ae||{},wO.extent.createOrUpdateFromCoordinates=se||{},wO.extent.createOrUpdateFromFlatCoordinates=le||{},wO.extent.createOrUpdateFromRings=function(t,e){return ge(oe(e),t)}||{},wO.extent.equals=ue||{},wO.extent.extend=he||{},wO.extent.extendCoordinate=pe||{},wO.extent.extendCoordinates=fe||{},wO.extent.extendFlatCoordinates=de||{},wO.extent.extendRings=ge||{},wO.extent.extendXY=ye||{},wO.extent.forEachCorner=me||{},wO.extent.getArea=ve||{},wO.extent.getBottomLeft=_e||{},wO.extent.getBottomRight=be||{},wO.extent.getCenter=xe||{},wO.extent.getCorner=we||{},wO.extent.getEnlargedArea=function(t,e){var r=Math.min(t[0],e[0]),n=Math.min(t[1],e[1]);return(Math.max(t[2],e[2])-r)*(Math.max(t[3],e[3])-n)}||{},wO.extent.getForViewAndSize=Se||{},wO.extent.getHeight=Ee||{},wO.extent.getIntersection=Te||{},wO.extent.getIntersectionArea=function(t,e){return ve(Te(t,e))}||{},wO.extent.getMargin=function(t){return Pe(t)+Ee(t)}||{},wO.extent.getSize=function(t){return[t[2]-t[0],t[3]-t[1]]}||{},wO.extent.getTopLeft=Ce||{},wO.extent.getTopRight=Oe||{},wO.extent.getWidth=Pe||{},wO.extent.intersects=Re||{},wO.extent.intersectsSegment=Fe||{},wO.extent.isEmpty=Ie||{},wO.extent.returnOrUpdate=Le||{},wO.extent.scaleFromCenter=Me||{},wO.extent.wrapX=ke||{},wO.featureloader={},wO.featureloader.loadFeaturesXhr=Lu||{},wO.featureloader.setWithCredentials=function(t){Iu=t}||{},wO.featureloader.xhr=Mu||{},wO.format={},wO.format.EsriJSON=C_||{},wO.format.Feature=Yy||{},wO.format.Feature.transformExtentWithOptions=qy||{},wO.format.Feature.transformGeometryWithOptions=Wy||{},wO.format.GML=nb||{},wO.format.GML2=$_||{},wO.format.GML3=eb||{},wO.format.GML32=ab||{},wO.format.GMLBase=F_||{},wO.format.GMLBase.GMLNS=I_,wO.format.GPX=Bb||{},wO.format.GeoJSON=$m||{},wO.format.IGC=sx||{},wO.format.IIIFInfo=Pf||{},wO.format.JSONFeature=qm||{},wO.format.KML=eS||{},wO.format.KML.getDefaultFillStyle=function(){return vx}||{},wO.format.KML.getDefaultImageStyle=function(){return bx}||{},wO.format.KML.getDefaultStrokeStyle=function(){return wx}||{},wO.format.KML.getDefaultStyle=function(){return Ex}||{},wO.format.KML.getDefaultStyleArray=function(){return Cx}||{},wO.format.KML.getDefaultTextStyle=function(){return Sx}||{},wO.format.KML.readFlatCoordinates=Ix||{},wO.format.MVT=am||{},wO.format.OSMXML=uS||{},wO.format.OWS=RS||{},wO.format.Polyline=zS||{},wO.format.Polyline.decodeDeltas=MS||{},wO.format.Polyline.decodeFloats=AS||{},wO.format.Polyline.decodeSignedIntegers=jS||{},wO.format.Polyline.decodeUnsignedIntegers=DS||{},wO.format.Polyline.encodeDeltas=LS||{},wO.format.Polyline.encodeFloats=FS||{},wO.format.Polyline.encodeSignedIntegers=kS||{},wO.format.Polyline.encodeUnsignedInteger=GS||{},wO.format.Polyline.encodeUnsignedIntegers=NS||{},wO.format.TextFeature=Jb||{},wO.format.TopoJSON=KS||{},wO.format.WFS=DT||{},wO.format.WFS.writeFilter=function(t,e){var r=Sc(tT[e],"Filter"),n={node:r};return O(n,{version:e,filter:t}),xT(r,t,[n]),r}||{},wO.format.WKT=nC||{},wO.format.WMSCapabilities=RC||{},wO.format.WMSGetFeatureInfo=LC||{},wO.format.WMTSCapabilities=ZC||{},wO.format.XLink={},wO.format.XLink.readHref=hS||{},wO.format.XML=cS||{},wO.format.XMLFeature=P_||{},wO.format.filter={},wO.format.filter.And=tE||{},wO.format.filter.Bbox=rE||{},wO.format.filter.Comparison=pE||{},wO.format.filter.ComparisonBinary=yE||{},wO.format.filter.Contains=aE||{},wO.format.filter.DWithin=lE||{},wO.format.filter.Disjoint=cE||{},wO.format.filter.During=dE||{},wO.format.filter.EqualTo=vE||{},wO.format.filter.Filter=HS||{},wO.format.filter.GreaterThan=bE||{},wO.format.filter.GreaterThanOrEqualTo=wE||{},wO.format.filter.Intersects=EE||{},wO.format.filter.IsBetween=CE||{},wO.format.filter.IsLike=PE||{},wO.format.filter.IsNull=IE||{},wO.format.filter.LessThan=ME||{},wO.format.filter.LessThanOrEqualTo=AE||{},wO.format.filter.LogicalNary=JS||{},wO.format.filter.Not=jE||{},wO.format.filter.NotEqualTo=DE||{},wO.format.filter.Or=zE||{},wO.format.filter.ResourceId=BE||{},wO.format.filter.Spatial=iE||{},wO.format.filter.Within=YE||{},wO.format.filter.and=WE||{},wO.format.filter.bbox=qE||{},wO.format.filter.between=function(t,e,r){return new CE(t,e,r)}||{},wO.format.filter.contains=function(t,e,r){return new aE(t,e,r)}||{},wO.format.filter.disjoint=function(t,e,r){return new cE(t,e,r)}||{},wO.format.filter.during=function(t,e,r){return new dE(t,e,r)}||{},wO.format.filter.dwithin=function(t,e,r,n,i){return new lE(t,e,r,n,i)}||{},wO.format.filter.equalTo=function(t,e,r){return new vE(t,e,r)}||{},wO.format.filter.greaterThan=function(t,e){return new bE(t,e)}||{},wO.format.filter.greaterThanOrEqualTo=function(t,e){return new wE(t,e)}||{},wO.format.filter.intersects=function(t,e,r){return new EE(t,e,r)}||{},wO.format.filter.isNull=function(t){return new IE(t)}||{},wO.format.filter.lessThan=function(t,e){return new ME(t,e)}||{},wO.format.filter.lessThanOrEqualTo=function(t,e){return new AE(t,e)}||{},wO.format.filter.like=function(t,e,r,n,i,o){return new PE(t,e,r,n,i,o)}||{},wO.format.filter.not=function(t){return new jE(t)}||{},wO.format.filter.notEqualTo=function(t,e,r){return new DE(t,e,r)}||{},wO.format.filter.or=function(t){var e=[null].concat(Array.prototype.slice.call(arguments));return new(Function.prototype.bind.apply(zE,e))}||{},wO.format.filter.resourceId=function(t){return new BE(t)}||{},wO.format.filter.within=function(t,e,r){return new YE(t,e,r)}||{},wO.format.xsd={},wO.format.xsd.readBoolean=A_||{},wO.format.xsd.readBooleanString=k_||{},wO.format.xsd.readDateTime=j_||{},wO.format.xsd.readDecimal=N_||{},wO.format.xsd.readDecimalString=D_||{},wO.format.xsd.readNonNegativeInteger=G_||{},wO.format.xsd.readNonNegativeIntegerString=z_||{},wO.format.xsd.readString=U_||{},wO.format.xsd.writeBooleanTextNode=B_||{},wO.format.xsd.writeCDATASection=V_||{},wO.format.xsd.writeDateTimeTextNode=Y_||{},wO.format.xsd.writeDecimalTextNode=W_||{},wO.format.xsd.writeNonNegativeIntegerTextNode=q_||{},wO.format.xsd.writeStringTextNode=X_||{},wO.functions={},wO.functions.FALSE=E||{},wO.functions.TRUE=S||{},wO.functions.VOID=T||{},wO.functions.memoizeOne=C||{},wO.geom={},wO.geom.Circle=Rv||{},wO.geom.Geometry=dn||{},wO.geom.GeometryCollection=Vm||{},wO.geom.LineString=Py||{},wO.geom.LinearRing=Yn||{},wO.geom.MultiLineString=Zy||{},wO.geom.MultiPoint=Hy||{},wO.geom.MultiPolygon=Jy||{},wO.geom.Point=qn||{},wO.geom.Polygon=fi||{},wO.geom.Polygon.circular=di||{},wO.geom.Polygon.fromCircle=yi||{},wO.geom.Polygon.fromExtent=gi||{},wO.geom.Polygon.makeRegular=mi||{},wO.geom.SimpleGeometry=vn||{},wO.geom.SimpleGeometry.getStrideForLayout=yn||{},wO.geom.SimpleGeometry.transformGeom2D=mn||{},wO.geom.flat={},wO.geom.flat.area={},wO.geom.flat.area.linearRing=zn||{},wO.geom.flat.area.linearRings=Un||{},wO.geom.flat.area.linearRingss=Bn||{},wO.geom.flat.center={},wO.geom.flat.center.linearRingss=Sy||{},wO.geom.flat.closest={},wO.geom.flat.closest.arrayMaxSquaredDelta=xn||{},wO.geom.flat.closest.assignClosestArrayPoint=En||{},wO.geom.flat.closest.assignClosestMultiArrayPoint=Tn||{},wO.geom.flat.closest.assignClosestPoint=Sn||{},wO.geom.flat.closest.maxSquaredDelta=bn||{},wO.geom.flat.closest.multiArrayMaxSquaredDelta=wn||{},wO.geom.flat.contains={},wO.geom.flat.contains.linearRingContainsExtent=Xn||{},wO.geom.flat.contains.linearRingContainsXY=Zn||{},wO.geom.flat.contains.linearRingsContainsXY=Kn||{},wO.geom.flat.contains.linearRingssContainsXY=Hn||{},wO.geom.flat.deflate={},wO.geom.flat.deflate.deflateCoordinate=Cn||{},wO.geom.flat.deflate.deflateCoordinates=On||{},wO.geom.flat.deflate.deflateCoordinatesArray=Pn||{},wO.geom.flat.deflate.deflateMultiCoordinatesArray=Rn||{},wO.geom.flat.flip={},wO.geom.flat.flip.flipXY=v_||{},wO.geom.flat.geodesic={},wO.geom.flat.geodesic.greatCircleArc=function(t,e,r,n,i,o){var a=Gr("EPSG:4326"),s=Math.cos(Ye(e)),l=Math.sin(Ye(e)),u=Math.cos(Ye(n)),c=Math.sin(Ye(n)),h=Math.cos(Ye(r-t)),p=Math.sin(Ye(r-t)),f=l*c+s*u*h;return Ly((function(e){if(1<=f)return[r,n];var i=e*Math.acos(f),o=Math.cos(i),a=Math.sin(i),d=p*u,g=s*c-l*u*h,y=Math.atan2(d,g),m=Math.asin(l*o+s*a*Math.cos(y));return[Ve(Ye(t)+Math.atan2(Math.sin(y)*a*s,o-l*Math.sin(m))),Ve(m)]}),Kr(a,i),o)}||{},wO.geom.flat.geodesic.meridian=My||{},wO.geom.flat.geodesic.parallel=Fy||{},wO.geom.flat.inflate={},wO.geom.flat.inflate.inflateCoordinates=Nn||{},wO.geom.flat.inflate.inflateCoordinatesArray=Dn||{},wO.geom.flat.inflate.inflateMultiCoordinatesArray=Gn||{},wO.geom.flat.interiorpoint={},wO.geom.flat.interiorpoint.getInteriorPointOfArray=$n||{},wO.geom.flat.interiorpoint.getInteriorPointsOfMultiArray=Jn||{},wO.geom.flat.interpolate={},wO.geom.flat.interpolate.interpolatePoint=by||{},wO.geom.flat.interpolate.lineStringCoordinateAtM=xy||{},wO.geom.flat.interpolate.lineStringsCoordinateAtM=wy||{},wO.geom.flat.intersectsextent={},wO.geom.flat.intersectsextent.intersectsLineString=ti||{},wO.geom.flat.intersectsextent.intersectsLineStringArray=ei||{},wO.geom.flat.intersectsextent.intersectsLinearRing=ri||{},wO.geom.flat.intersectsextent.intersectsLinearRingArray=ni||{},wO.geom.flat.intersectsextent.intersectsLinearRingMultiArray=ii||{},wO.geom.flat.length={},wO.geom.flat.length.lineStringLength=qg||{},wO.geom.flat.length.linearRingLength=function(t,e,r,n){var i=qg(t,e,r,n),o=t[r-n]-t[e],a=t[r-n+1]-t[e+1];return i+=Math.sqrt(o*o+a*a)}||{},wO.geom.flat.orient={},wO.geom.flat.orient.linearRingIsClockwise=ai||{},wO.geom.flat.orient.linearRingsAreOriented=si||{},wO.geom.flat.orient.linearRingssAreOriented=li||{},wO.geom.flat.orient.orientLinearRings=ui||{},wO.geom.flat.orient.orientLinearRingsArray=ci||{},wO.geom.flat.reverse={},wO.geom.flat.reverse.coordinates=oi||{},wO.geom.flat.segments={},wO.geom.flat.segments.forEach=Qn||{},wO.geom.flat.simplify={},wO.geom.flat.simplify.douglasPeucker=In||{},wO.geom.flat.simplify.douglasPeuckerArray=Ln||{},wO.geom.flat.simplify.douglasPeuckerMultiArray=function(t,e,r,n,i,o,a,s){for(var l=0,u=r.length;l<u;++l){var c=r[l],h=[];a=Ln(t,e,c,n,i,o,a,h),s.push(h),e=c[c.length-1]}return a}||{},wO.geom.flat.simplify.quantize=An||{},wO.geom.flat.simplify.quantizeArray=kn||{},wO.geom.flat.simplify.quantizeMultiArray=jn||{},wO.geom.flat.simplify.radialDistance=Mn||{},wO.geom.flat.simplify.simplifyLineString=function(t,e,r,n,i,o,a){var s=void 0!==a?a:[];return o||(r=Mn(t,e,r,n,i,s,0),t=s,e=0,n=2),s.length=In(t,e,r,n,i,s,0),s}||{},wO.geom.flat.simplify.snap=Fn||{},wO.geom.flat.straightchunk={},wO.geom.flat.straightchunk.matchingChunk=Gg||{},wO.geom.flat.textpath={},wO.geom.flat.textpath.drawTextOnPath=Wg||{},wO.geom.flat.topology={},wO.geom.flat.topology.lineStringIsClosed=function(t,e,r,n){var i=r-n;return t[e]===t[i]&&t[e+1]===t[i+1]&&(r-e)/n>3&&!!zn(t,e,r,n)}||{},wO.geom.flat.transform={},wO.geom.flat.transform.rotate=un||{},wO.geom.flat.transform.scale=cn||{},wO.geom.flat.transform.transform2D=ln||{},wO.geom.flat.transform.translate=hn||{},wO.has={},wO.has.DEVICE_PIXEL_RATIO=Vi||{},wO.has.FIREFOX=Gi||{},wO.has.IMAGE_DECODE=Wi||{},wO.has.MAC=Bi||{},wO.has.PASSIVE_EVENT_LISTENERS=qi||{},wO.has.SAFARI=zi||{},wO.has.WEBKIT=Ui||{},wO.has.WORKER_OFFSCREEN_CANVAS=Yi||{},wO.interaction={},wO.interaction.DoubleClickZoom=Zs||{},wO.interaction.DragAndDrop=Ev||{},wO.interaction.DragAndDrop.DragAndDropEvent=Sv||{},wO.interaction.DragBox=El||{},wO.interaction.DragBox.DragBoxEvent=Sl||{},wO.interaction.DragPan=fl||{},wO.interaction.DragRotate=gl||{},wO.interaction.DragRotateAndZoom=Cv||{},wO.interaction.DragZoom=Cl||{},wO.interaction.Draw=Gv||{},wO.interaction.Draw.DrawEvent=Dv||{},wO.interaction.Draw.createBox=function(){return function(t,e,r){var n=Kt([t[0],t[t.length-1]].map((function(t){return rn(t,r)}))),i=[[_e(n),be(n),Oe(n),Ce(n),_e(n)]],o=e;o?o.setCoordinates(i):o=new fi(i);var a=tn();return a&&o.transform(r,a),o}}||{},wO.interaction.Draw.createRegularPolygon=function(t,e){return function(r,n,i){var o=rn(r[0],i),a=rn(r[r.length-1],i),s=Math.sqrt(Rr(o,a)),l=n||yi(new Rv(o),t),u=e;if(!e&&0!==e){var c=a[0]-o[0],h=a[1]-o[1];u=Math.atan2(h,c)}mi(l,o,s,u);var p=tn();return p&&l.transform(i,p),l}}||{},wO.interaction.Extent=qv||{},wO.interaction.Extent.ExtentEvent=Bv||{},wO.interaction.Interaction=qs||{},wO.interaction.Interaction.pan=Ys||{},wO.interaction.Interaction.zoomByDelta=Ws||{},wO.interaction.KeyboardPan=Ml||{},wO.interaction.KeyboardZoom=Al||{},wO.interaction.Modify=r_||{},wO.interaction.Modify.ModifyEvent=Jv||{},wO.interaction.MouseWheelZoom=Dl||{},wO.interaction.PinchRotate=zl||{},wO.interaction.PinchZoom=Bl||{},wO.interaction.Pointer=$s||{},wO.interaction.Pointer.centroid=Hs||{},wO.interaction.Select=s_||{},wO.interaction.Select.SelectEvent=o_||{},wO.interaction.Snap=h_||{},wO.interaction.Translate=m_||{},wO.interaction.Translate.TranslateEvent=y_||{},wO.interaction.defaults=Vl||{},wO.layer={},wO.layer.Base=Wo||{},wO.layer.BaseImage=ad||{},wO.layer.BaseTile=vd||{},wO.layer.BaseVector=wg||{},wO.layer.Graticule=Ny||{},wO.layer.Group=Aa||{},wO.layer.Heatmap=Vy||{},wO.layer.Image=dd||{},wO.layer.Layer=na||{},wO.layer.Layer.inView=ra||{},wO.layer.MapboxVector=yv||{},wO.layer.MapboxVector.getMapboxPath=uv||{},wO.layer.MapboxVector.normalizeGlyphsUrl=hv||{},wO.layer.MapboxVector.normalizeSourceUrl=fv||{},wO.layer.MapboxVector.normalizeSpriteUrl=cv||{},wO.layer.MapboxVector.normalizeStyleUrl=pv||{},wO.layer.Tile=Sd||{},wO.layer.Vector=Iy||{},wO.layer.VectorImage=vv||{},wO.layer.VectorTile=lm||{},wO.layer.WebGLPoints=bv||{},wO.loadingstrategy={},wO.loadingstrategy.all=Fu||{},wO.loadingstrategy.bbox=function(t,e){return[t]}||{},wO.loadingstrategy.tile=function(t){return function(e,r){var n=t.getZForResolution(r),i=t.getTileRangeForExtentAndZ(e,n),o=[],a=[n,0,0];for(a[1]=i.minX;a[1]<=i.maxX;++a[1])for(a[2]=i.minY;a[2]<=i.maxY;++a[2])o.push(t.getTileCoordExtent(a));return o}}||{},wO.math={},wO.math.clamp=Ne||{},wO.math.cosh=De||{},wO.math.lerp=qe||{},wO.math.log2=Ge||{},wO.math.modulo=We||{},wO.math.solveLinearSystem=Be||{},wO.math.squaredDistance=Ue||{},wO.math.squaredSegmentDistance=ze||{},wO.math.toDegrees=Ve||{},wO.math.toRadians=Ye||{},wO.net={},wO.net.jsonp=Au||{},wO.obj={},wO.obj.assign=O||{},wO.obj.clear=P||{},wO.obj.getValues=R||{},wO.obj.isEmpty=I||{},wO.proj={},wO.proj.Projection=je||{},wO.proj.Units=St||{},wO.proj.Units.METERS_PER_UNIT=wt||{},wO.proj.addCommon=sn||{},wO.proj.addCoordinateTransforms=Wr||{},wO.proj.addEquivalentProjections=Ur||{},wO.proj.addEquivalentTransforms=Br||{},wO.proj.addProjection=Nr||{},wO.proj.addProjections=Dr||{},wO.proj.clearAllProjections=function(){lr(),pr()}||{},wO.proj.clearUserProjection=function(){Jr=null}||{},wO.proj.cloneTransform=kr||{},wO.proj.createProjection=Vr||{},wO.proj.createSafeCoordinateTransform=an||{},wO.proj.createTransformFromCoordinateTransform=Yr||{},wO.proj.epsg3857={},wO.proj.epsg3857.EXTENT=Ke||{},wO.proj.epsg3857.HALF_SIZE=Ze||{},wO.proj.epsg3857.MAX_SAFE_Y=$e||{},wO.proj.epsg3857.PROJECTIONS=Qe||{},wO.proj.epsg3857.RADIUS=6378137,wO.proj.epsg3857.WORLD_EXTENT=He||{},wO.proj.epsg3857.fromEPSG4326=tr||{},wO.proj.epsg3857.toEPSG4326=er||{},wO.proj.epsg4326={},wO.proj.epsg4326.EXTENT=nr||{},wO.proj.epsg4326.METERS_PER_UNIT=ir||{},wO.proj.epsg4326.PROJECTIONS=ar||{},wO.proj.epsg4326.RADIUS=6378137,wO.proj.equivalent=Xr||{},wO.proj.fromLonLat=qr||{},wO.proj.fromUserCoordinate=rn||{},wO.proj.fromUserExtent=on||{},wO.proj.get=Gr||{},wO.proj.getPointResolution=zr||{},wO.proj.getTransform=Kr||{},wO.proj.getTransformFromProjections=Zr||{},wO.proj.getUserProjection=tn||{},wO.proj.identityTransform=jr||{},wO.proj.proj4={},wO.proj.proj4.register=function(t){var e,r,n=Object.keys(t.defs),i=n.length;for(e=0;e<i;++e){var o=n[e];if(!Gr(o)){var a=t.defs(o),s=a.units;s||"longlat"!==a.projName||(s=St.DEGREES),Nr(new je({code:o,axisOrientation:a.axis,metersPerUnit:a.to_meter,units:s}))}}for(e=0;e<i;++e){var l=n[e],u=Gr(l);for(r=0;r<i;++r){var c=n[r],h=Gr(c);if(!dr(l,c)){var p=t.defs(l),f=t.defs(c);if(p===f)Ur([u,h]);else{var d=t(O({},p,{axis:void 0}),O({},f,{axis:void 0}));Wr(u,h,an(u,h,d.forward),an(h,u,d.inverse))}}}}}||{},wO.proj.projections={},wO.proj.projections.add=cr||{},wO.proj.projections.clear=lr||{},wO.proj.projections.get=ur||{},wO.proj.setUserProjection=Qr||{},wO.proj.toLonLat=function(t,e){var r=Hr(t,void 0!==e?e:"EPSG:3857","EPSG:4326"),n=r[0];return(n<-180||n>180)&&(r[0]=We(n+180,360)-180),r}||{},wO.proj.toUserCoordinate=en||{},wO.proj.toUserExtent=nn||{},wO.proj.transform=Hr||{},wO.proj.transformExtent=$r||{},wO.proj.transformWithProjections=function(t,e,r){return Zr(e,r)(t)}||{},wO.proj.transforms={},wO.proj.transforms.add=fr||{},wO.proj.transforms.clear=pr||{},wO.proj.transforms.get=dr||{},wO.proj.transforms.remove=function(t,e){var r=t.getCode(),n=e.getCode(),i=hr[r][n];return delete hr[r][n],I(hr[r])&&delete hr[r],i}||{},wO.proj.useGeographic=function(){Qr("EPSG:4326")}||{},wO.render={},wO.render.Box=ml||{},wO.render.Event=la||{},wO.render.Feature=Cy||{},wO.render.VectorContext=ku||{},wO.render.canvas={},wO.render.canvas.Builder=Mg||{},wO.render.canvas.BuilderGroup=Yg||{},wO.render.canvas.Executor=ey||{},wO.render.canvas.ExecutorGroup=ay||{},wO.render.canvas.ExecutorGroup.getPixelIndexArray=oy||{},wO.render.canvas.ImageBuilder=Ag||{},wO.render.canvas.Immediate=Nu||{},wO.render.canvas.Instruction=Ig||{},wO.render.canvas.Instruction.beginPathInstruction=Pg||{},wO.render.canvas.Instruction.closePathInstruction=Rg||{},wO.render.canvas.Instruction.fillInstruction=Cg||{},wO.render.canvas.Instruction.strokeInstruction=Og||{},wO.render.canvas.LineStringBuilder=jg||{},wO.render.canvas.PolygonBuilder=Dg||{},wO.render.canvas.TextBuilder=Bg||{},wO.render.canvas.checkedFonts=da||{},wO.render.canvas.createTransformString=Ra||{},wO.render.canvas.defaultFillStyle="#000",wO.render.canvas.defaultFont="10px sans-serif",wO.render.canvas.defaultLineCap="round",wO.render.canvas.defaultLineDash=pa||{},wO.render.canvas.defaultLineDashOffset={},wO.render.canvas.defaultLineJoin="round",wO.render.canvas.defaultLineWidth=1,wO.render.canvas.defaultMiterLimit=10,wO.render.canvas.defaultPadding=fa||{},wO.render.canvas.defaultStrokeStyle="#000",wO.render.canvas.defaultTextAlign="center",wO.render.canvas.defaultTextBaseline="middle",wO.render.canvas.drawImageOrLabel=Oa||{},wO.render.canvas.hitdetect={},wO.render.canvas.hitdetect.createHitDetectionImageData=sy||{},wO.render.canvas.hitdetect.hitDetect=ly||{},wO.render.canvas.labelCache=ga||{},wO.render.canvas.measureAndCacheTextWidth=Ea||{},wO.render.canvas.measureTextHeight=xa||{},wO.render.canvas.measureTextWidth=Sa||{},wO.render.canvas.measureTextWidths=Ta||{},wO.render.canvas.registerFont=ba||{},wO.render.canvas.rotateAtOffset=Ca||{},wO.render.canvas.textHeights=_a||{},wO.render.getRenderPixel=function(t,e){var r=e.slice(0);return It(t.inversePixelTransform.slice(),r),r}||{},wO.render.getVectorContext=Ku||{},wO.render.toContext=function(t,e){var r=t.canvas,n=e||{},i=n.pixelRatio||Vi,o=n.size;o&&(r.width=o[0]*i,r.height=o[1]*i,r.style.width=o[0]+"px",r.style.height=o[1]+"px");var a=[0,0,r.width,r.height],s=Mt([1,0,0,1,0,0],i,i);return new Nu(t,i,a,s,0)}||{},wO.renderer={},wO.renderer.Composite=La||{},wO.renderer.Layer=ld||{},wO.renderer.Map=aa||{},wO.renderer.canvas={},wO.renderer.canvas.ImageLayer=pd||{},wO.renderer.canvas.Layer=cd||{},wO.renderer.canvas.TileLayer=xd||{},wO.renderer.canvas.VectorImageLayer=py||{},wO.renderer.canvas.VectorLayer=cy||{},wO.renderer.canvas.VectorTileLayer=_y||{},wO.renderer.vector={},wO.renderer.vector.defaultOrder=Wu||{},wO.renderer.vector.getSquaredTolerance=qu||{},wO.renderer.vector.getTolerance=Xu||{},wO.renderer.vector.renderFeature=Zu||{},wO.renderer.webgl={},wO.renderer.webgl.Layer=_g||{},wO.renderer.webgl.Layer.colorDecodeId=vg||{},wO.renderer.webgl.Layer.colorEncodeId=mg||{},wO.renderer.webgl.Layer.getBlankImageData=function(){var t=document.createElement("canvas").getContext("2d").createImageData(1,1);return t.data[0]=255,t.data[1]=255,t.data[2]=255,t.data[3]=255,t}||{},wO.renderer.webgl.Layer.writePointFeatureToBuffers=function(t,e,r,n,i,o){var a=3+i,s=t[e+0],l=t[e+1],u=dg;u.length=i;for(var c=0;c<u.length;c++)u[c]=t[e+2+c];var h=o?o.vertexPosition:0,p=o?o.indexPosition:0,f=h/a;return yg(r,h,s,l,0),u.length&&r.set(u,h+3),yg(r,h+=a,s,l,1),u.length&&r.set(u,h+3),yg(r,h+=a,s,l,2),u.length&&r.set(u,h+3),yg(r,h+=a,s,l,3),u.length&&r.set(u,h+3),h+=a,n[p++]=f,n[p++]=f+1,n[p++]=f+3,n[p++]=f+1,n[p++]=f+2,n[p++]=f+3,gg.vertexPosition=h,gg.indexPosition=p,gg}||{},wO.renderer.webgl.PointsLayer=Eg||{},wO.reproj={},wO.reproj.Image=Ff||{},wO.reproj.Tile=Mp||{},wO.reproj.Triangulation=Ip||{},wO.reproj.calculateSourceExtentResolution=ec||{},wO.reproj.calculateSourceResolution=tc||{},wO.reproj.common={},wO.reproj.common.ENABLE_RASTER_REPROJECTION=!0,wO.reproj.common.ERROR_THRESHOLD=.5,wO.reproj.render=rc||{},wO.resolutionconstraint={},wO.resolutionconstraint.createMinMaxResolution=ds||{},wO.resolutionconstraint.createSnapToPower=fs||{},wO.resolutionconstraint.createSnapToResolutions=ps||{},wO.rotationconstraint={},wO.rotationconstraint.createSnapToN=ms||{},wO.rotationconstraint.createSnapToZero=vs||{},wO.rotationconstraint.disable=gs||{},wO.rotationconstraint.none=ys||{},wO.size={},wO.size.buffer=Os||{},wO.size.hasArea=Ps||{},wO.size.scale=Rs||{},wO.size.toSize=Is||{},wO.source={},wO.source.BingMaps=Hp||{},wO.source.BingMaps.quadKey=Kp||{},wO.source.CartoDB=tf||{},wO.source.Cluster=ff||{},wO.source.IIIF=Lf||{},wO.source.Image=zf||{},wO.source.Image.ImageSourceEvent=Df||{},wO.source.Image.defaultImageLoadFunction=Gf||{},wO.source.ImageArcGISRest=Bf||{},wO.source.ImageCanvas=Yf||{},wO.source.ImageMapGuide=qf||{},wO.source.ImageStatic=Zf||{},wO.source.ImageWMS=ed||{},wO.source.OSM=id||{},wO.source.OSM.ATTRIBUTION=nd,wO.source.Raster=zd||{},wO.source.Raster.Processor=Id||{},wO.source.Raster.RasterSourceEvent=kd||{},wO.source.Raster.newImageData=Od||{},wO.source.Source=Dp||{},wO.source.Stamen=Wd||{},wO.source.Tile=Bp||{},wO.source.Tile.TileSourceEvent=Up||{},wO.source.TileArcGISRest=Xd||{},wO.source.TileDebug=Hd||{},wO.source.TileImage=Xp||{},wO.source.TileJSON=Jd||{},wO.source.TileWMS=tg||{},wO.source.UTFGrid=ng||{},wO.source.UTFGrid.CustomTile=rg||{},wO.source.UrlTile=Yp||{},wO.source.Vector=hf||{},wO.source.Vector.VectorSourceEvent=cf||{},wO.source.VectorTile=og||{},wO.source.VectorTile.defaultLoadFunction=ag||{},wO.source.WMTS=cg||{},wO.source.WMTS.optionsFromCapabilities=function(t,e){var r=_(t.Contents.Layer,(function(t,r,n){return t.Identifier==e.layer}));if(null===r)return null;var n,i=t.Contents.TileMatrixSet;(n=r.TileMatrixSetLink.length>1?x(r.TileMatrixSetLink,"projection"in e?function(t,r,n){var o=_(i,(function(e){return e.Identifier==t.TileMatrixSet})).SupportedCRS,a=Gr(o),s=Gr(e.projection);return a&&s?Xr(a,s):o==e.projection}:function(t,r,n){return t.TileMatrixSet==e.matrixSet}):0)<0&&(n=0);var o=r.TileMatrixSetLink[n].TileMatrixSet,a=r.TileMatrixSetLink[n].TileMatrixSetLimits,s=r.Format[0];"format"in e&&(s=e.format),(n=x(r.Style,(function(t,r,n){return"style"in e?t.Title==e.style:t.isDefault})))<0&&(n=0);var l=r.Style[n].Identifier,u={};"Dimension"in r&&r.Dimension.forEach((function(t,e,r){var n=t.Identifier,i=t.Default;void 0===i&&(i=t.Value[0]),u[n]=i}));var c,h=_(t.Contents.TileMatrixSet,(function(t,e,r){return t.Identifier==o})),p=h.SupportedCRS;if(p&&(c=Gr(p)),"projection"in e){var f=Gr(e.projection);f&&(c&&!Xr(f,c)||(c=f))}var d="ne"==c.getAxisOrientation().substr(0,2),y=h.TileMatrix[0],m={MinTileCol:0,MinTileRow:0,MaxTileCol:y.MatrixWidth-1,MaxTileRow:y.MatrixHeight-1};if(a){m=a[a.length-1];var v=_(h.TileMatrix,(function(t){return t.Identifier===m.TileMatrix||h.Identifier+":"+t.Identifier===m.TileMatrix}));v&&(y=v)}var b=28e-5*y.ScaleDenominator/c.getMetersPerUnit(),w=d?[y.TopLeftCorner[1],y.TopLeftCorner[0]]:y.TopLeftCorner,S=y.TileWidth*b,E=y.TileHeight*b,T=[w[0]+S*m.MinTileCol,w[1]-E*(1+m.MaxTileRow),w[0]+S*(1+m.MaxTileCol),w[1]-E*m.MinTileRow];null===c.getExtent()&&c.setExtent(T);var C=Kh(h,T,a),O=[],P=e.requestEncoding;if(P=void 0!==P?P:"","OperationsMetadata"in t&&"GetTile"in t.OperationsMetadata)for(var R=t.OperationsMetadata.GetTile.DCP.HTTP.Get,I=0,L=R.length;I<L;++I)if(R[I].Constraint){var M=_(R[I].Constraint,(function(t){return"GetEncoding"==t.name})).AllowedValues.Value;if(""===P&&(P=M[0]),P!==sg)break;g(M,sg)&&O.push(R[I].href)}else R[I].href&&(P=sg,O.push(R[I].href));return 0===O.length&&(P=lg,r.ResourceURL.forEach((function(t){"tile"===t.resourceType&&(s=t.format,O.push(t.template))}))),{urls:O,layer:e.layer,matrixSet:o,format:s,projection:c,requestEncoding:P,tileGrid:C,style:l,dimensions:u,wrapX:!1,crossOrigin:e.crossOrigin}}||{},wO.source.XYZ=Jp||{},wO.source.Zoomify=vf||{},wO.source.Zoomify.CustomTile=mf||{},wO.source.common={},wO.source.common.DEFAULT_WMS_VERSION="1.3.0",wO.source.common.IMAGE_SMOOTHING_DISABLED=$u||{},wO.sphere={},wO.sphere.DEFAULT_RADIUS=6371008.8,wO.sphere.getArea=function t(e,r){var n=r||{},i=n.radius||6371008.8,o=n.projection||"EPSG:3857",a=e.getType();a!==bt.GEOMETRY_COLLECTION&&(e=e.clone().transform(o,"EPSG:4326"));var s,l,u,c,h,p,f=0;switch(a){case bt.POINT:case bt.MULTI_POINT:case bt.LINE_STRING:case bt.MULTI_LINE_STRING:case bt.LINEAR_RING:break;case bt.POLYGON:for(s=e.getCoordinates(),f=Math.abs(mr(s[0],i)),u=1,c=s.length;u<c;++u)f-=Math.abs(mr(s[u],i));break;case bt.MULTI_POLYGON:for(u=0,c=(s=e.getCoordinates()).length;u<c;++u)for(l=s[u],f+=Math.abs(mr(l[0],i)),h=1,p=l.length;h<p;++h)f-=Math.abs(mr(l[h],i));break;case bt.GEOMETRY_COLLECTION:var d=e.getGeometries();for(u=0,c=d.length;u<c;++u)f+=t(d[u],r);break;default:throw new Error("Unsupported geometry type: "+a)}return f}||{},wO.sphere.getDistance=gr||{},wO.sphere.getLength=function t(e,r){var n=r||{},i=n.radius||6371008.8,o=n.projection||"EPSG:3857",a=e.getType();a!==bt.GEOMETRY_COLLECTION&&(e=e.clone().transform(o,"EPSG:4326"));var s,l,u,c,h,p,f=0;switch(a){case bt.POINT:case bt.MULTI_POINT:break;case bt.LINE_STRING:case bt.LINEAR_RING:f=yr(s=e.getCoordinates(),i);break;case bt.MULTI_LINE_STRING:case bt.POLYGON:for(u=0,c=(s=e.getCoordinates()).length;u<c;++u)f+=yr(s[u],i);break;case bt.MULTI_POLYGON:for(u=0,c=(s=e.getCoordinates()).length;u<c;++u)for(h=0,p=(l=s[u]).length;h<p;++h)f+=yr(l[h],i);break;case bt.GEOMETRY_COLLECTION:var d=e.getGeometries();for(u=0,c=d.length;u<c;++u)f+=t(d[u],r);break;default:throw new Error("Unsupported geometry type: "+a)}return f}||{},wO.sphere.offset=vr||{},wO.string={},wO.string.compareVersions=br||{},wO.string.padNumber=_r||{},wO.structs={},wO.structs.LRUCache=lu||{},wO.structs.LinkedList=Cp||{},wO.structs.PriorityQueue=Qa||{},wO.structs.PriorityQueue.DROP=1/0,wO.structs.RBush=Rp||{},wO.style={},wO.style.Circle=tp||{},wO.style.Fill=ep||{},wO.style.Icon=dp||{},wO.style.IconImage=pp||{},wO.style.IconImage.get=hp||{},wO.style.IconImageCache=Fo||{},wO.style.IconImageCache.shared=Ao||{},wO.style.Image=Hh||{},wO.style.LiteralStyle={},wO.style.RegularShape=Jh||{},wO.style.Stroke=gp||{},wO.style.Style=wp||{},wO.style.Style.createDefaultStyle=_p||{},wO.style.Style.createEditingStyle=bp||{},wO.style.Style.toFunction=mp||{},wO.style.Text=Tp||{},wO.style.expressions={},wO.style.expressions.Operators=Eh||{},wO.style.expressions.arrayToGlsl=Ph||{},wO.style.expressions.colorToGlsl=Rh||{},wO.style.expressions.expressionToGlsl=Mh||{},wO.style.expressions.getStringNumberEquivalent=Ih||{},wO.style.expressions.getValueType=Th||{},wO.style.expressions.isTypeUnique=Ch||{},wO.style.expressions.numberToGlsl=Oh||{},wO.style.expressions.stringToGlsl=Lh||{},wO.tilecoord={},wO.tilecoord.createOrUpdate=uu||{},wO.tilecoord.fromKey=pu||{},wO.tilecoord.getKey=hu||{},wO.tilecoord.getKeyZXY=cu||{},wO.tilecoord.hash=fu||{},wO.tilecoord.withinExtentAndZ=du||{},wO.tilegrid={},wO.tilegrid.TileGrid=ic||{},wO.tilegrid.WMTS=Zh||{},wO.tilegrid.WMTS.createFromCapabilitiesMatrixSet=Kh||{},wO.tilegrid.common={},wO.tilegrid.common.DEFAULT_MAX_ZOOM=42,wO.tilegrid.common.DEFAULT_TILE_SIZE=256,wO.tilegrid.createForExtent=sc||{},wO.tilegrid.createForProjection=cc||{},wO.tilegrid.createXYZ=lc||{},wO.tilegrid.extentFromProjection=hc||{},wO.tilegrid.getForProjection=oc||{},wO.tilegrid.wrapX=ac||{},wO.tileurlfunction={},wO.tileurlfunction.createFromTemplate=pc||{},wO.tileurlfunction.createFromTemplates=fc||{},wO.tileurlfunction.createFromTileUrlFunctions=dc||{},wO.tileurlfunction.expandUrl=yc||{},wO.tileurlfunction.nullTileUrlFunction=gc||{},wO.transform={},wO.transform.apply=It||{},wO.transform.compose=kt||{},wO.transform.composeCssTransform=function(t,e,r,n,i,o,a){return Dt(kt([1,0,0,1,0,0],t,e,r,n,i,o,a))}||{},wO.transform.create=Tt||{},wO.transform.determinant=Nt||{},wO.transform.invert=function(t){return jt(t,t)}||{},wO.transform.makeInverse=jt||{},wO.transform.makeScale=Ft||{},wO.transform.multiply=Ot||{},wO.transform.reset=Ct||{},wO.transform.rotate=Lt||{},wO.transform.scale=Mt||{},wO.transform.set=Pt||{},wO.transform.setFromArray=Rt||{},wO.transform.toString=Dt||{},wO.transform.translate=At||{},wO.uri={},wO.uri.appendParams=mc||{},wO.util={},wO.util.VERSION="6.5.0",wO.util.abstract=n||{},wO.util.getUid=o||{},wO.vec={},wO.vec.mat4={},wO.vec.mat4.create=nh||{},wO.vec.mat4.fromTransform=ih||{},wO.webgl={},wO.webgl.ARRAY_BUFFER=34962,wO.webgl.Buffer=Qc||{},wO.webgl.Buffer.getArrayClassForType=Jc||{},wO.webgl.DYNAMIC_DRAW=35048,wO.webgl.ELEMENT_ARRAY_BUFFER=34963,wO.webgl.FLOAT=5126,wO.webgl.Helper=gh||{},wO.webgl.Helper.computeAttributesStride=fh||{};wO.webgl.PostProcessingPass=rh||{},wO.webgl.RenderTarget=mh||{},wO.webgl.STATIC_DRAW=35044,wO.webgl.STREAM_DRAW=35040,wO.webgl.ShaderBuilder={},wO.webgl.ShaderBuilder.ShaderBuilder=Yh||{},wO.webgl.ShaderBuilder.parseLiteralStyle=Wh||{},wO.webgl.UNSIGNED_BYTE=5121,wO.webgl.UNSIGNED_INT=5125,wO.webgl.UNSIGNED_SHORT=5123,wO.webgl.getContext=bc||{},wO.webgl.getSupportedExtensions=xc||{},wO.worker={},wO.worker.version={},wO.worker.webgl={},wO.xml={},wO.xml.OBJECT_PROPERTY_NODE_FACTORY=Nc||{},wO.xml.XML_SCHEMA_INSTANCE_URI=wc,wO.xml.createElementNS=Sc||{},wO.xml.getAllTextContent=Ec||{},wO.xml.getAllTextContent_=Tc||{},wO.xml.getAttributeNS=Oc||{},wO.xml.getDocument=Xc||{},wO.xml.getXMLSerializer=Wc||{},wO.xml.isDocument=Cc||{},wO.xml.makeArrayExtender=Rc||{},wO.xml.makeArrayPusher=Ic||{},wO.xml.makeArraySerializer=kc||{},wO.xml.makeChildAppender=Ac||{},wO.xml.makeObjectPropertyPusher=Mc||{},wO.xml.makeObjectPropertySetter=Fc||{},wO.xml.makeReplacer=Lc||{},wO.xml.makeSequence=Dc||{},wO.xml.makeSimpleNodeFactory=jc||{},wO.xml.makeStructureNS=Gc||{},wO.xml.parse=Pc||{},wO.xml.parseNode=zc||{},wO.xml.pushParseAndPop=Uc||{},wO.xml.pushSerializeAndPop=Vc||{},wO.xml.registerDocument=function(t){qc=t}||{},wO.xml.registerXMLSerializer=function(t){Yc=t}||{},wO.xml.serialize=Bc||{};e.default=wO}]).default})); +//# sourceMappingURL=ol.js.map \ No newline at end of file diff --git a/src/main/webapp/js/appleFruitMothObservationSiteMap.js b/src/main/webapp/js/appleFruitMothObservationSiteMap.js index d859edea2bc0f074a316a928db4c07e606585dfa..664355561fe30048188cbdb6fdae743d103b2542 100755 --- a/src/main/webapp/js/appleFruitMothObservationSiteMap.js +++ b/src/main/webapp/js/appleFruitMothObservationSiteMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/appleFruitMothObservationSitesMap.js b/src/main/webapp/js/appleFruitMothObservationSitesMap.js index d6675744544d360eb257553906692ffab665562e..4502cfcd7d2fe57a3e6b6a6acb14dc25ca3c764e 100755 --- a/src/main/webapp/js/appleFruitMothObservationSitesMap.js +++ b/src/main/webapp/js/appleFruitMothObservationSitesMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/constants.js b/src/main/webapp/js/constants.js index ebcf5c32812017a5955f35847292153fb8e6fa1d..fe1615bef324e9acd0029844168975dedcc29615 100755 --- a/src/main/webapp/js/constants.js +++ b/src/main/webapp/js/constants.js @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/forecastConfigurationForm.js b/src/main/webapp/js/forecastConfigurationForm.js index 12ce726e0f9d67f0a170921e9e4e6d991ea538eb..12b455125fc0edf7c8e5b40a81c1bd3f10082d54 100755 --- a/src/main/webapp/js/forecastConfigurationForm.js +++ b/src/main/webapp/js/forecastConfigurationForm.js @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/mapModal.js b/src/main/webapp/js/mapModal.js new file mode 100644 index 0000000000000000000000000000000000000000..a7076fd49b4ea12020e123816307612d043a108d --- /dev/null +++ b/src/main/webapp/js/mapModal.js @@ -0,0 +1,676 @@ +// mapModal.js +import { + map, + divIcon, + tileLayer, + geoJSON, + circleMarker, + marker, + GeoJSON, + DomEvent, + Control, + DomUtil, + latLng +} from '/js/3rdparty/leaflet-src.esm.js'; + +/** + * This JavaScript module enables the display of a map modal centered on Norway, with a given set of + * coordinates representing points of interest. The map is primarily intended for use within VIPSLogic, + * but can also be imported and used in VIPSWeb or other applications within the VIPS sphere. + * + * Follow the steps below in order to set up the map: + * 1) Include the following stylesheets: + * <link type="text/css" rel="stylesheet" href="(https://logic.vips.nibio.no)/css/3rdparty/leaflet.css" /> + * <link type="text/css" rel="stylesheet" href="/https://logic.vips.nibio.no)/css/mapModal.css" /> + * 2) Include HTML to display a button, and a div in which the map will be opened: + * <i id="open-map-modal-icon" class="fa fa-map-marker" onclick="openLocationMap()"></i> + * <div id="location-map" class="map-modal"></div> + * 3) Include MapModal within a script tag of type 'module', and implement the function openLocationMap(), + * which initializes and opens the map modal. + * + * Uses css classes from bootstrap 3.4.1 + * Leaflet: https://unpkg.com/leaflet@1.9.4/dist/leaflet-src.esm.js + */ +class MapModal { + + static TRANSLATIONS = { + nb: { + selectLocation: 'Velg sted', + selectCoordinates: 'Velg punkt', + createNewLocation: 'Opprett nytt sted', + selectNewCoordinates: 'Velg nytt punkt', + name: 'Navn', + latitude: 'Breddegrad', + longitude: 'Lengdegrad', + type: 'Type', + zoomToLocation: 'Zoom til meg', + geolocationNotSupported: 'Geolokalisering støttes ikke av denne nettleseren', + geolocationFailed: 'Fant ikke din posisjon', + closeMap: 'Lukk kart', + poiType0: 'Uspesifisert', + poiType1: 'Værstasjon', + poiType2: 'Gård', + poiType3: 'Felt', + poiType5: 'Felle', + poiType6: 'Bigårdsplass', + poiType7: 'Planteskole', + }, + en: { + selectLocation: 'Select location', + selectCoordinates: 'Select point', + createNewLocation: 'Create New Location', + selectNewCoordinates: 'Select new point', + name: 'Name', + latitude: 'Latitude', + longitude: 'Longitude', + type: 'Type', + zoomToLocation: 'Zoom to My Location', + geolocationNotSupported: 'Geolocation is not supported by this browser', + geolocationFailed: 'Unable to retrieve your location', + closeMap: 'Close Map', + poiType0: 'Unspecified', + poiType1: 'Weather station', + poiType2: 'Farm', + poiType3: 'Field', + poiType5: 'Trap', + poiType6: 'Apiary site', + poiType7: 'Nursery', + } + }; + + /** + * @param mapModalId The id of the HTML element in which the modal should be opened + * @param geoJsonData GeoJson containing all features which should be displayed on the map + * @param language The language in which texts should be displayed, either 'nb' or 'en' + * @param isPoiMap True if the map operates on pois with an id, name and type, false if it operates on coordinates + * @param allowNewPoints Whether or not the user should be allowed to add new points + * @param callbackOnClose Callback function to call when closing the modal + */ + constructor(mapModalId, geoJsonData, language = 'nb', isPoiMap = true, allowNewPoints = false, callbackOnClose = null) { + this.mapModalElement = document.getElementById(mapModalId); + this.mapContainerId = mapModalId + "-container"; + this.mapContainerElement = this.addMapContainer(this.mapModalElement, this.mapContainerId); + + this.geoJsonData = geoJsonData && geoJsonData !== "{}" ? geoJsonData : { features: []}; + // Filter out invalid features + this.geoJsonData.features = this.geoJsonData.features.filter(feature => feature.geometry.type === "Point" && !isNaN(feature.geometry.coordinates[0]) && !isNaN(feature.geometry.coordinates[1])); + + if (language in MapModal.TRANSLATIONS) { + this.translations = MapModal.TRANSLATIONS[language]; + } else { + console.error("'" + language + "' is not a supported language"); + this.translations = MapModal.TRANSLATIONS['nb']; + } + this.isPoiMap = isPoiMap; + this.allowNewPoints = allowNewPoints; + this.callbackOnClose = callbackOnClose; + + this.map = null; + this.isMapInitialized = false; + this.markersByType = {}; + this.selectedNewPointMarker = null; + this.selectedExistingPointMarker = null; + this.coordinatePrecision = 6; + + this.zoomToLocationControl = new ZoomToLocationControl({ + translations: this.translations + }); + this.closeMapControl = new CloseMapControl({ + translations: this.translations, + onClose: () => { + this.closeModal() + } + }); + + // Colours for the available types of pois + this.typeColorMap = { + 0: "#5DADE2", // Bright Blue + 1: "#58D68D", // Vibrant Green + 2: "#AF7AC5", // Medium Lavender + 3: "#F5B041", // Warm Orange + 5: "#F7DC6F", // Bright Yellow + 6: "#DC7633", // Rich Brown + 7: "#FF33A6" // Vivid Magenta + }; + } + + addMapContainer(parentDiv, id) { + const mapContainer = document.createElement('div'); + mapContainer.id = id; + mapContainer.style.height = '100%'; + mapContainer.style.width = '100%'; + mapContainer.style.position = 'relative'; + parentDiv.appendChild(mapContainer); + return mapContainer; + } + + styleOfSelectedPointMarker(newPoint) { + const styleMap = { + radius: 12, + color: "#FFFFFF", + weight: 2, + opacity: 1, + fillOpacity: 1, + }; + if (newPoint) { + styleMap['fillColor'] = "#FF5733"; + } + return styleMap + } + + styleOfPointMarker(pointOfInterestTypeId) { + const color = this.typeColorMap[pointOfInterestTypeId] || "#3498DB"; + return { + radius: 8, + fillColor: color, + color: "#FFFFFF", + weight: 2, + opacity: 1, + fillOpacity: 0.8 + } + } + + initMap(latitude = 65, longitude = 14, zoomLevel = 5) { + if (this.isMapInitialized) { + console.error("Map is already initialized"); + return; + } + // Initialize the map centered on Norway + this.map = map(this.mapContainerId).setView([latitude, longitude], zoomLevel); + tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + minZoom: 3 + }).addTo(this.map); + console.info("Create map " + this.mapContainerId + " centered on (" + latitude + "," + longitude + ") with points", this.geoJsonData ? this.geoJsonData.features : null); + + this.map.addControl(this.zoomToLocationControl); + this.map.addControl(this.closeMapControl); + + // Add points to the map if given + if (this.geoJsonData && this.geoJsonData.features) { + geoJSON(this.geoJsonData, { + pointToLayer: (feature, latlng) => { + return circleMarker(latlng, this.styleOfPointMarker(feature.properties.pointOfInterestTypeId)); + }, + onEachFeature: (feature, layer) => { + const typeId = feature.properties.pointOfInterestTypeId; + this.bindActionToPoint(layer); + if (!this.markersByType[typeId]) { + this.markersByType[typeId] = []; + } + this.markersByType[typeId].push(layer); + } + }).addTo(this.map); + } + + // Poi type selection panel should only be included if map operates on pois + if (this.isPoiMap) { + this.legendControl = new LegendControl({ + typeColorMap: this.typeColorMap, + translations: this.translations, + markersByType: this.markersByType, + mapModalInstance: this + }); + this.map.addControl(this.legendControl); + } + + // Enable adding new points if allowed + if (this.allowNewPoints) { + this.enablePointCreation(); + } + this.isMapInitialized = true; + } + + // Function called when point is hidden (by deselecting its location type in legend box) + // If point is already selected, the popup is removed. + unbindActionToPoint(layer) { + if (this.selectedExistingPointMarker === layer) { + layer.closePopup(); + this.removeSelectedPointMarkerIfExists(); + } + layer.unbindPopup(); + layer.off('click'); + } + + bindActionToPoint(layer) { + layer.bindPopup(this.popupContent(layer.feature)); + layer.on('click', () => { + this.displaySelectedPoint(layer.feature, layer, false); + }); + } + + selectPointById(pointOfInterestId) { + const selectedFeature = this.getFeatureById(pointOfInterestId); + const selectedLayer = this.getLayerById(pointOfInterestId); + if(!selectedFeature || !selectedLayer) { + console.error("Unable to display selected point " + pointOfInterestId, this.geoJsonData.features) + return + } + this.displaySelectedPoint(selectedFeature, selectedLayer, true); + selectedLayer.openPopup(); + } + + getFeatureById(pointOfInterestId) { + return this.geoJsonData.features.find(feature => feature.properties.pointOfInterestId == pointOfInterestId); + } + + getLayerById(pointOfInterestId) { + let result = null; + this.map.eachLayer(layer => { + if (layer instanceof GeoJSON) { + layer.eachLayer(l => { + if (l.feature && l.feature.properties.pointOfInterestId == pointOfInterestId) { + result = l; + } + }); + } + }); + return result; + } + + displaySelectedPoint(feature, layer, zoomInToSelected = false) { + // Deselect previously selected point, if any + this.removeSelectedPointMarkerIfExists(); + this.removeNewPointMarkerIfExists(); + + this.selectedExistingPointMarker = layer; + this.selectedExistingPointMarker.setStyle(this.styleOfSelectedPointMarker(false)); + if (zoomInToSelected) { + const latLng = this.selectedExistingPointMarker.getLatLng(); + this.map.setView(latLng, 10); + } + } + + confirmSelection(feature) { + if (typeof this.callbackOnClose === 'function') { + const pointData = { + pointOfInterestId: feature.properties.pointOfInterestId, + name: feature.properties.pointOfInterestName, + pointOfInterestTypeId: feature.properties.pointOfInterestTypeId, + longitude: feature.geometry.coordinates[0], + latitude: feature.geometry.coordinates[1] + }; + this.callbackOnClose(pointData); + } + this.closeModal(); + } + + enablePointCreation() { + this.map.on('click', (e) => { + const latlng = e.latlng; + + // Click on the map should remove any previous selections + this.removeSelectedPointMarkerIfExists(); + this.removeNewPointMarkerIfExists(); + this.closeNewPointFormIfOpen(); + + // Calculate the pixel position from the map's click event + const containerPoint = this.map.latLngToContainerPoint(latlng); + + this.selectedNewPointMarker = circleMarker(latlng, this.styleOfSelectedPointMarker(true)).addTo(this.map); + const newPointFormElement = this.addHtmlElementNewPointForm(containerPoint.x, containerPoint.y, latlng.lat, latlng.lng) + + DomEvent.disableClickPropagation(newPointFormElement); + document.addEventListener('click', this.handleClickOutsidePointForm.bind(this), true); + + const closeButton = newPointFormElement.querySelector("#map-poi-close-button"); + const nameInput = newPointFormElement.querySelector('#map-poi-name'); + const latitudeInput = newPointFormElement.querySelector('#map-poi-latitude'); + const longitudeInput = newPointFormElement.querySelector('#map-poi-longitude'); + const typeInput = newPointFormElement.querySelector('#map-poi-type'); + const submitButton = newPointFormElement.querySelector('#map-poi-submit-button'); + + const validateInputs = () => { + const isValidLat = !isNaN(parseFloat(latitudeInput.value)) && isFinite(latitudeInput.value); + const isValidLng = !isNaN(parseFloat(longitudeInput.value)) && isFinite(longitudeInput.value); + if (isValidLat && isValidLng) { + this.updateMarkerPosition(this.selectedNewPointMarker, parseFloat(latitudeInput.value), parseFloat(longitudeInput.value)); + } + submitButton.disabled = !(isValidLat && isValidLng); + }; + latitudeInput.addEventListener('blur', validateInputs); + longitudeInput.addEventListener('blur', validateInputs); + + closeButton.addEventListener('click', () => { + newPointFormElement.remove(); + this.removeNewPointMarkerIfExists(); + }); + + submitButton.addEventListener('click', () => { + const formName = nameInput ? nameInput.value : ''; + const formType = typeInput ? parseInt(typeInput.value, 10) : ''; + const feature = this.createFeatureForPoint(formName, formType, parseFloat(longitudeInput.value), parseFloat(latitudeInput.value)); + this.confirmSelection(feature); + }); + }); + } + + updateMarkerPosition(marker, lat, lng) { + if (marker) { + marker.setLatLng([lat, lng]); + this.map.setView([lat, lng], this.map.getZoom()); + } + } + + removeNewPointMarkerIfExists() { + if (this.selectedNewPointMarker) { + this.map.removeLayer(this.selectedNewPointMarker); + } + } + + removeSelectedPointMarkerIfExists() { + if (this.selectedExistingPointMarker) { + const pointOfInterestTypeId = this.selectedExistingPointMarker.feature.properties.pointOfInterestTypeId; + this.selectedExistingPointMarker.setStyle(this.styleOfPointMarker(pointOfInterestTypeId)); + } + } + + handleClickOutsidePointForm(event) { + const formElement = document.getElementById('new-point-form'); + if (formElement && !formElement.contains(event.target)) { + this.closeNewPointFormIfOpen(); + } + } + + closeNewPointFormIfOpen() { + const formElement = document.getElementById('new-point-form'); + if (formElement) { + formElement.remove(); + } + document.removeEventListener('click', this.handleClickOutsidePointForm.bind(this), true); + } + + createFeatureForPoint(name, type, longitude, latitude) { + return { + "type": "Feature", + "geometry": { + "type": "Point", + "coordinates": [longitude, latitude] + }, + "properties": { + "pointOfInterestId": 0, + "pointOfInterestName": name, + "pointOfInterestTypeId": type + } + }; + } + + popupContent(feature) { + const popupElement = document.createElement("div"); + popupElement.id = 'poi-popup'; + const name = feature.properties.pointOfInterestName; + const type = this.translations['poiType' + feature.properties.pointOfInterestTypeId]; + const latitude = feature.geometry.coordinates[1].toFixed(this.coordinatePrecision); + const longitude = feature.geometry.coordinates[0].toFixed(this.coordinatePrecision); + const buttonLabel = this.isPoiMap ? this.translations.selectLocation : this.translations.selectCoordinates; + + if(this.isPoiMap) { + popupElement.innerHTML = `<h4>${name}</h4> + <b>${this.translations.latitude}</b> ${latitude}<br> + <b>${this.translations.longitude}</b> ${longitude}<br> + <b>${this.translations.type}</b> ${type}<br><br> + <button id="submit-button" class="btn btn-primary">${buttonLabel}</button>` + } else { + popupElement.innerHTML = `<b>${this.translations.latitude}</b> ${latitude}<br> + <b>${this.translations.longitude}</b> ${longitude}<br><br> + <button id="submit-button" class="btn btn-primary">${buttonLabel}</button>` + } + const buttonElement = popupElement.querySelector("#submit-button"); + buttonElement.addEventListener('click', () => { + this.confirmSelection(feature); + }); + return popupElement; + } + + /** + * Creates the HTML form for adding a new point, and add it to the map container. + * + * @param positionX Where to place the form on the x axis + * @param positionY Where to place the form on the y axis + * @param latitude Latitude of the point clicked + * @param longitude Longitude of the point clicked + * @returns {Element} + */ + addHtmlElementNewPointForm(positionX, positionY, latitude, longitude) { + const form = document.createElement("div"); + form.id = "new-point-form" + form.classList.add("panel"); + form.classList.add("panel-default"); + + // Adjust position so that the form is always displayed within the map + const mapWidth = this.mapModalElement.offsetWidth; + const mapHeight = this.mapModalElement.offsetHeight; + const formWidth = 200; // approximately + const formHeight = 400; // approximately + if (positionX + formWidth > mapWidth) { + positionX = mapWidth - formWidth - 10; // 10px padding from the edge + } + if (positionY + formHeight > mapHeight) { + positionY = mapHeight - formHeight - 10; // 10px padding from the edge + } + form.style.left = `${positionX}px`; + form.style.top = `${positionY}px`; + + form.innerHTML = ` + <div class="panel-heading"> + <h4 class="panel-title">${this.isPoiMap ? this.translations.createNewLocation : this.translations.selectNewCoordinates}</h4> + <span id="map-poi-close-button" style="position: absolute; top: 5px; right: 10px; cursor: pointer; font-size: 18px;">×</span> + </div> + <div class="panel-body"> + <div id="form-group-poi-name" class="form-group"> + <label for="map-poi-name">${this.translations.name}:</label> + <input type="text" class="form-control" id="map-poi-name" name="name"> + </div> + <div class="form-group"> + <label for="map-poi-latitude">${this.translations.latitude}:</label> + <input type="text" class="form-control" id="map-poi-latitude" name="latitude" value="${latitude.toFixed(this.coordinatePrecision)}"> + </div> + <div class="form-group"> + <label for="map-poi-longitude">${this.translations.longitude}:</label> + <input type="text" class="form-control" id="map-poi-longitude" name="longitude" value="${longitude.toFixed(this.coordinatePrecision)}"> + </div> + <div id="form-group-poi-type" class="form-group"> + <label for="map-poi-type">${this.translations.type}:</label> + <select class="form-control" id="map-poi-type" name="type"> + <option value="2">${this.translations['poiType2']}</option> + <option value="3">${this.translations['poiType3']}</option> + <option value="5">${this.translations['poiType5']}</option> + </select> + </div> + <div class="form-group text-right"> + <button id="map-poi-submit-button" class="btn btn-primary">${this.isPoiMap ? this.translations.selectLocation : this.translations.selectCoordinates}</button> + </div> + </div>`; + + // If map does not operate on pois, the form should not include input fields for name and type + if (!this.isPoiMap) { + form.querySelector("#form-group-poi-name").remove() + form.querySelector("#form-group-poi-type").remove() + } + + this.mapContainerElement.appendChild(form); + return form; + } + + /** + * Make modal visible. Initialise map with selected point marked, if given. + * + * @param selectedPointOfInterestId + * @param latitude + * @param longitude + * @param zoomLevel + */ + openModal(selectedPointOfInterestId, latitude, longitude, zoomLevel) { + this.mapModalElement.style.display = 'flex'; + this.mapModalElement.style.justifyContent = 'center'; + this.mapModalElement.style.alignItems = 'center'; + this.initMap(latitude, longitude, zoomLevel); + if (selectedPointOfInterestId) { + // Id -1 is used if the map should display the single given point as selected, with a form to enable lat/lng modification + if(selectedPointOfInterestId === -1) { + const layer = this.getLayerById(selectedPointOfInterestId) + const feature = this.getFeatureById(selectedPointOfInterestId) + this.map.removeLayer(layer); + this.simulateMapClick(this.map, feature.geometry.coordinates[1], feature.geometry.coordinates[0]) + } else { + this.selectPointById(selectedPointOfInterestId); + } + } + } + + simulateMapClick(map, lat, lng) { + const clickEvent = { + latlng: latLng(lat, lng), + layerPoint: map.latLngToLayerPoint(latLng(lat, lng)), + containerPoint: map.latLngToContainerPoint(latLng(lat, lng)) + }; + map.fire('click', clickEvent); + } + + /** + * Hide modal. Remove container element and map. + */ + closeModal() { + this.mapModalElement.style.display = 'none'; + this.mapContainerElement.remove(); + this.map.remove(); + this.map = null; + } + +} + +const ZoomToLocationControl = Control.extend({ + options: { + position: 'topleft', + translations: {} + }, + + onAdd: function (map) { + // Create the button element + const container = DomUtil.create('div', 'leaflet-bar leaflet-control'); + const zoomToLocationButton = DomUtil.create('a', 'map-button', container); + zoomToLocationButton.innerHTML = '<i class="fa fa-map-marker"></i>'; + zoomToLocationButton.href = '#'; + zoomToLocationButton.title = this.options.translations.zoomToLocation; + + DomEvent + .on(zoomToLocationButton, 'click', DomEvent.stop) + .on(zoomToLocationButton, 'click', () => { + if (navigator.geolocation) { + const locationIcon = divIcon({ + html: '<i class="fa fa-map-marker fa-3x"></i>', + iconSize: [40, 60], + className: 'location-marker', + iconAnchor: [20, 60] + }); + navigator.geolocation.getCurrentPosition((position) => { + const latitude = position.coords.latitude; + const longitude = position.coords.longitude; + + map.setView([latitude, longitude], 13); + marker([latitude, longitude], {icon: locationIcon}).addTo(map); + }, (error) => { + console.error('Geolocation failed: ' + error.message); + alert(this.options.translations.geolocationFailed); + }); + } else { + alert(this.options.translations.geolocationNotSupported); + } + }); + return container; + } +}); + + +const CloseMapControl = Control.extend({ + options: { + position: 'topright', + translations: {} + }, + + onAdd: function (map) { + // Create a container for the button + const container = DomUtil.create('div', 'leaflet-bar leaflet-control'); + + // Create the button element + const closeMapButton = DomUtil.create('a', 'map-button', container); + closeMapButton.innerHTML = '×'; // Unicode for close symbol + closeMapButton.href = '#'; + closeMapButton.title = this.options.translations.closeMap; + + DomEvent + .on(closeMapButton, 'click', DomEvent.stop) + .on(closeMapButton, 'click', () => { + if (this.options.onClose) { + this.options.onClose(); + } + }); + return container; + } +}); + +const LegendControl = Control.extend({ + options: { + position: 'bottomright', + typeColorMap: {}, + translations: {}, + markersByType: {}, + mapModalInstance: null, + }, + onAdd: function (map) { + const legendDiv = DomUtil.create('div', 'info legend'); + const typeColorMap = this.options.typeColorMap; + const translations = this.options.translations; + const markersByType = this.options.markersByType; + + DomEvent.disableClickPropagation(legendDiv); + + for (const type in typeColorMap) { + if (!markersByType[type]) { + continue; + } + const count = markersByType[type].length; + const color = typeColorMap[type]; + + const itemDiv = DomUtil.create('div', 'legend-item', legendDiv); + itemDiv.innerHTML = `<i style="background:${color};"></i> + <span>${translations['poiType' + type]} (${count})</span>`; + + DomEvent + .on(itemDiv, 'click', DomEvent.stop) + .on(itemDiv, 'click', () => { + this.toggleMarkers(type, markersByType[type], itemDiv); + }); + } + return legendDiv; + }, + + toggleMarkers: function (type, markers, itemDiv) { + if (!markers) return; + const wasVisible = markers[0].options.opacity !== 0; + const isVisible = !wasVisible; + + markers.forEach(marker => { + const markerElement = marker.getElement(); + if (wasVisible) { + this.options.mapModalInstance.unbindActionToPoint(marker); + if (markerElement) { + markerElement.style.pointerEvents = 'none'; + } + marker.setStyle({opacity: 0, fillOpacity: 0}); + } else { + marker.setStyle({opacity: 1, fillOpacity: 0.8}); + this.options.mapModalInstance.bindActionToPoint(marker); + if (markerElement) { + markerElement.style.pointerEvents = ''; + } + } + }); + // Mark hidden with line-through + itemDiv.style.textDecoration = isVisible ? "none" : "line-through solid black 2px"; + } + +}); + +// Export the module +export default MapModal; diff --git a/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteFormMap.js b/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteFormMap.js index 27fa3517f7a5ebd67a6b0ba0daa94d465c462704..6e2fd4176cb87c83c61a8e220d4762f2a7a52103 100644 --- a/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteFormMap.js +++ b/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteFormMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2020 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ @@ -46,13 +46,13 @@ }) }); var parser = new ol.format.WMTSCapabilities(); - fetch('https://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabilities').then(function(response) { + fetch('https://cache.kartverket.no/v1/wmts/1.0.0/WMTSCapabilities.xml').then(function(response) { return response.text(); }).then(function(text) { var result = parser.read(text); var options = ol.source.WMTS.optionsFromCapabilities(result, { - layer: 'topo4', - matrixSet: 'EPSG:3857' + layer: 'topo', + matrixSet: 'webmercator' }); var topo4 = new ol.layer.Tile({ diff --git a/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteListMap.js b/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteListMap.js index 45f18f6136ff6266168c35d785fc371467944be5..a24d2b44ceb8c33a705c9fb4b569ca1bca3d7393 100644 --- a/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteListMap.js +++ b/src/main/webapp/js/modules/barkbeetle/seasonTrapsiteListMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2020 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ @@ -27,16 +27,7 @@ var poiDetails; function initMap(season){ - // Background layer is OpenStreetMap - var backgroundLayer = new ol.layer.Tile({ - source: new ol.source.OSM({ - attributions: [ - new ol.Attribution({ - html: mapConstants.MAP_ATTRIBUTION - }) - ] - }) - }); + // The trapsite layer var trapLayer = new ol.layer.Vector({ @@ -55,13 +46,13 @@ element: document.getElementById("popover") }); var parser = new ol.format.WMTSCapabilities(); - fetch('https://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabilities').then(function(response) { + fetch('https://cache.kartverket.no/v1/wmts/1.0.0/WMTSCapabilities.xml').then(function(response) { return response.text(); }).then(function(text) { var result = parser.read(text); var options = ol.source.WMTS.optionsFromCapabilities(result, { - layer: 'topo4', - matrixSet: 'EPSG:3857' + layer: 'topo', + matrixSet: 'webmercator' }); var topo4 = new ol.layer.Tile({ @@ -80,7 +71,7 @@ // Setting zoom and center for the map (need to do this after creating map. so that we kan transform our // center to correct map projection) var view = new ol.View({ - center: ol.proj.transform([10.0,63.0], 'EPSG:4326', map.getView().getProjection().getCode()), + center: ol.proj.transform([7.0,63.0], 'EPSG:4326', map.getView().getProjection().getCode()), zoom: 5 }); map.setView(view); diff --git a/src/main/webapp/js/objectGISInfoMap.js b/src/main/webapp/js/objectGISInfoMap.js index 895b37f5f23c9101fce18f262b0a331358ce1c99..7aa33f4ad08da6dad093fe20fb9aa4bead6f9dda 100755 --- a/src/main/webapp/js/objectGISInfoMap.js +++ b/src/main/webapp/js/objectGISInfoMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2015-2016 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. * - * VIPSLogic is distributed in the hope that it will be useful, + * 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 - * NIBIO Open Source License for more details. - * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/observationDataHandler.js b/src/main/webapp/js/observationDataHandler.js index 7380cc9e01fd4d3c02fd310d9aa161be9a8c9d19..6292a567342595672b6a6666963141a9fdd023ca 100755 --- a/src/main/webapp/js/observationDataHandler.js +++ b/src/main/webapp/js/observationDataHandler.js @@ -2,18 +2,18 @@ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/observationMap.js b/src/main/webapp/js/observationMap.js index fa6cd64a9ed4d8576d4679941d629612f08d11e0..e56752026aa4158d931ada25587cc1bab8fb1278 100755 --- a/src/main/webapp/js/observationMap.js +++ b/src/main/webapp/js/observationMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/poiFormMap.js b/src/main/webapp/js/poiFormMap.js index 10ea2c942644d1be9ad8794ee69c9925a4e3a50b..09c7d911e0b9cc5fcfc69dfc8971d217a3f9c90f 100755 --- a/src/main/webapp/js/poiFormMap.js +++ b/src/main/webapp/js/poiFormMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2016 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/poiListMap.js b/src/main/webapp/js/poiListMap.js index 1493b3c9828eccb91982bac4cc6149038efcabc6..c8f46c4b8fc3b97907248f43e2221d9e1906db21 100755 --- a/src/main/webapp/js/poiListMap.js +++ b/src/main/webapp/js/poiListMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/util.js b/src/main/webapp/js/util.js index 025de9e68dde6ae9119673dd53e311e4fc008a9f..e92ca9fb10d92473489427ecd62fbb7c704c7dd9 100755 --- a/src/main/webapp/js/util.js +++ b/src/main/webapp/js/util.js @@ -2,24 +2,23 @@ * Copyright (c) 2017 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ -function setFieldValue(theForm, fieldName, value) -{ - theForm[fieldName] = value; +function setFieldValue(theForm, fieldName, value) { + theForm[fieldName] = value; } /* An easy way to sort list options alphabetically @@ -28,43 +27,35 @@ function setFieldValue(theForm, fieldName, value) * @param {type} b * @returns {Number} */ -var compareSelectListOptions = function(a,b) -{ - if(a.text < b.text) - { +var compareSelectListOptions = function (a, b) { + if (a.text < b.text) { return -1; } - if(a.text > b.text) - { + if (a.text > b.text) { return 1; } return 0; }; -var sortListAlphabetically = function(theList, keepFirst) -{ - keepFirst = keepFirst | 0; - var allOptions = []; - for(var i=keepFirst;i<theList.options.length;i++) - { - allOptions.push(theList.options[i]); - } - allOptions.sort(function(a,b){ - if(a.label < b.label) - { - return -1; +var sortListAlphabetically = function (theList, keepFirst) { + keepFirst = keepFirst | 0; + var allOptions = []; + for (var i = keepFirst; i < theList.options.length; i++) { + allOptions.push(theList.options[i]); } - if(a.label > b.label) - { - return 1; + allOptions.sort(function (a, b) { + if (a.label < b.label) { + return -1; + } + if (a.label > b.label) { + return 1; + } + return 0; + }); + theList.options.length = keepFirst; // Keeping the top items? + for (var i = 0; i < allOptions.length; i++) { + theList.options[theList.options.length] = allOptions[i]; } - return 0; - }); - theList.options.length=keepFirst; // Keeping the top items? - for(var i=0;i<allOptions.length;i++) - { - theList.options[theList.options.length] = allOptions[i]; - } }; /** @@ -73,42 +64,35 @@ var sortListAlphabetically = function(theList, keepFirst) * @param language if you want to override system settings, specify language here * @returns {String} */ -function getLocalizedOrganismName(organism, language) -{ - var preferredLanguage = language || environment.currentLanguage; - // Fallback in case nothing works - if(organism === null) - { - return gettext("Unnamed"); - } - // Attempting the following languages (in order): current language, default language, English - var languages = [preferredLanguage, environment.defaultLanguage, "en"]; - for(var j in languages) - { - for(var i in organism.organismLocaleSet) - { - var localeSet = organism.organismLocaleSet[i]; - //console.log(localeSet); - if(localeSet.organismLocalePK.locale == languages[j]) - { - return localeSet.localName; - } - } - } - // Then we try the latin name - if(organism.latinName !== null - && organism.latinName !== "") - { - return organism.latinName; - } - // Then the trade name - if(organism.tradeName !== null - && organism.tradeName !== "") - { - return organism.tradeName; - } - // Then we give up - return gettext("Unnamed"); +function getLocalizedOrganismName(organism, language) { + var preferredLanguage = language || environment.currentLanguage; + // Fallback in case nothing works + if (organism === null) { + return gettext("Unnamed"); + } + // Attempting the following languages (in order): current language, default language, English + var languages = [preferredLanguage, environment.defaultLanguage, "en"]; + for (var j in languages) { + for (var i in organism.organismLocaleSet) { + var localeSet = organism.organismLocaleSet[i]; + //console.log(localeSet); + if (localeSet.organismLocalePK.locale == languages[j]) { + return localeSet.localName; + } + } + } + // Then we try the latin name + if (organism.latinName !== null + && organism.latinName !== "") { + return organism.latinName; + } + // Then the trade name + if (organism.tradeName !== null + && organism.tradeName !== "") { + return organism.tradeName; + } + // Then we give up + return gettext("Unnamed"); } /** @@ -116,30 +100,24 @@ function getLocalizedOrganismName(organism, language) * @param cropCategory * @returns {String} */ -function getLocalizedCropCategoryName(cropCategory) -{ +function getLocalizedCropCategoryName(cropCategory) { // Fallback in case nothing works - if(cropCategory === null) - { + if (cropCategory === null) { return "Unnamed"; } // Attempting the following languages (in order): current language, default language, English var languages = [environment.currentLanguage, environment.defaultLanguage, "en"]; - for(var j in languages) - { - for(var i in cropCategory.cropCategoryLocalSet) - { + for (var j in languages) { + for (var i in cropCategory.cropCategoryLocalSet) { var localeSet = cropCategory.cropCategoryLocalSet[i]; - if(localeSet.cropCategoryLocalPK.locale.trim() == languages[j].trim()) - { + if (localeSet.cropCategoryLocalPK.locale.trim() == languages[j].trim()) { return localeSet.localName; } } } // Then we try the latin name - if(cropCategory.defaultName !== null - && cropCategory.defaultName !== "") - { + if (cropCategory.defaultName !== null + && cropCategory.defaultName !== "") { return cropCategory.defaultName; } // Then we give up @@ -147,32 +125,28 @@ function getLocalizedCropCategoryName(cropCategory) } function getLocalizedOptionsHTML(optionsList) { - var translatedOptionsHTML = ""; - var languages = [environment.currentLanguage, environment.defaultLanguage, "en"]; - - for(var i in optionsList){ - var option = optionsList[i]; - var label = null; - var labelList = option.label; - for(var j in languages) - { - for(var k in labelList) - { - if(k === languages[j]) - { - label = labelList[k]; - break; - } + var translatedOptionsHTML = ""; + var languages = [environment.currentLanguage, environment.defaultLanguage, "en"]; + + for (var i in optionsList) { + var option = optionsList[i]; + var label = null; + var labelList = option.label; + for (var j in languages) { + for (var k in labelList) { + if (k === languages[j]) { + label = labelList[k]; + break; + } + } + if (label !== null) { + break; + } } - if(label !== null) - { - break; - } - } - translatedOptionsHTML += '<option value="' + option.value + '"' + (option.selected === "true" ? ' selected="selected"' : '') + ">" + label + "</option>"; - } - - return translatedOptionsHTML; + translatedOptionsHTML += '<option value="' + option.value + '"' + (option.selected === "true" ? ' selected="selected"' : '') + ">" + label + "</option>"; + } + + return translatedOptionsHTML; } /** @@ -182,24 +156,19 @@ function getLocalizedOptionsHTML(optionsList) { * @param {type} ambiguousValue * @returns {Number} */ -function getUnixTimestampFromJSON(ambiguousValue) -{ +function getUnixTimestampFromJSON(ambiguousValue) { var possibleDateObject; - if(!isMomentJSAvailable()) - { + if (!isMomentJSAvailable()) { possibleDateObject = new Date(ambiguousValue); console.info("Warning: Parsing date without MomentJS. Can't guarantee correct result."); } - else - { + else { possibleDateObject = moment(ambiguousValue).toDate(); } - if(possibleDateObject.getTime() === NaN && typeof parseInt(ambiguousValue) === "number") - { + if (possibleDateObject.getTime() === NaN && typeof parseInt(ambiguousValue) === "number") { return parseInt(ambiguousValue); } - else - { + else { return possibleDateObject.getTime(); } } @@ -209,15 +178,56 @@ function getUnixTimestampFromJSON(ambiguousValue) * * @return {Boolean} */ -function isMomentJSAvailable() -{ +function isMomentJSAvailable() { try { moment(); return true; } - catch (err) - { + catch (err) { return false; } -} \ No newline at end of file +} + +/** Converts numeric degrees to radians + * Essential to make the calculateDistanceBetweenCoordinates to work + **/ +if (typeof Number.prototype.toRad == 'undefined') { + Number.prototype.toRad = function () { + return this * Math.PI / 180; + } +} + + + +/** + * Reference: <a href="http://www.movable-type.co.uk/scripts/latlong.html">this webpage</a> + * <pre> + * This uses the "haversine" formula to calculate the great-circle distance between two points ? that is, the shortest distance over the earth?s surface ? giving an ?as-the-crow-flies? distance between the points (ignoring any hills, of course!). + Haversine formula: + a = sin²(?lat/2) + cos(lat1).cos(lat2).sin²(?long/2) + c = 2.atan2(?a, ?(1?a)) + d = R.c + where R is earth's radius (mean radius = 6,371km); + Note that angles need to be in radians to pass to trig functions! + * </pre> + * @param lat1 + * @param lon1 + * @param lat2 + * @param lon2 + * @return distance in km between to coordinates + */ +function calculateDistanceBetweenCoordinates(lat1, lon1, lat2, lon2) { + var R = 6371; // km + var dLat = (lat2 - lat1).toRad(); + var dLon = (lon2 - lon1).toRad(); + lat1 = lat1.toRad(); + lat2 = lat2.toRad(); + + var a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2); + var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + var d = R * c; + + return d; +} diff --git a/src/main/webapp/js/validateForm.js b/src/main/webapp/js/validateForm.js index 3fa7365ff1fb573ac887fb1aad9974474990874c..833dfe22f7c1995643b4943c6cac1863557ec37f 100755 --- a/src/main/webapp/js/validateForm.js +++ b/src/main/webapp/js/validateForm.js @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, +* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ /* @@ -268,7 +268,8 @@ function validateFieldActual(fieldEl, theForm, formDefinitionKey) // Single select field - check for nullValue if(fieldDefinition.fieldType === fieldTypes.TYPE_SELECT_SINGLE) { - webValue = fieldEl.options[fieldEl.selectedIndex].value; + // Fallback if this is not a select list (could be a readonly list using a twin hidden field) + webValue = webValue = fieldEl.options != undefined ? fieldEl.options[fieldEl.selectedIndex].value : fieldEl.value; if(fieldDefinition.nullValue === webValue && fieldDefinition.required === true) { invalidizeField(fieldEl, theForm, getI18nMsg("fieldIsRequired",null)); @@ -471,7 +472,7 @@ function validateFieldActual(fieldEl, theForm, formDefinitionKey) } /** - * Recursive function to travers upwards in tree until we find the form + * Recursive function to traverse upwards in tree until we find the form * for the given element * @param {DOMElement} fieldEl * @returns {DOMelement} the form diff --git a/src/main/webapp/js/weatherStationFormMap.js b/src/main/webapp/js/weatherStationFormMap.js index 6264a3667fcb50358b5ff8ff7443dab608bbb8ab..a4984f4d711d178e2bf03cfbb673ca4ef8055616 100755 --- a/src/main/webapp/js/weatherStationFormMap.js +++ b/src/main/webapp/js/weatherStationFormMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/weatherStationListMap.js b/src/main/webapp/js/weatherStationListMap.js index 7e496be845b246d101036ba649072bda0920943c..d8b87cb834aeffb0af1107f746742a34c2baaea3 100755 --- a/src/main/webapp/js/weatherStationListMap.js +++ b/src/main/webapp/js/weatherStationListMap.js @@ -1,19 +1,18 @@ /* * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * - * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/js/weatherStationViewMap.js b/src/main/webapp/js/weatherStationViewMap.js index a8241159c6f2785cbf1e5dfc48a4da9d011fef36..8736c17f456b04511c85b35beca5cd4dc3370dde 100755 --- a/src/main/webapp/js/weatherStationViewMap.js +++ b/src/main/webapp/js/weatherStationViewMap.js @@ -2,18 +2,18 @@ * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/map_applications/fireblight/index.html b/src/main/webapp/map_applications/fireblight/index.html index a8d495dc9dd7252ed7c10771a9b5fff578d5daef..73174589db25563b95fe55405ec0ed19c4d8d7ab 100755 --- a/src/main/webapp/map_applications/fireblight/index.html +++ b/src/main/webapp/map_applications/fireblight/index.html @@ -16,7 +16,7 @@ <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <link rel="stylesheet" href="/css/3rdparty/font-awesome.min.css" media="screen" /> - <link rel="stylesheet" href="/css/3rdparty/ol.css?t=20170623" media="screen" /> + <link rel="stylesheet" href="/css/3rdparty/ol_6_5_0.css?t=20170623" media="screen" /> <style type="text/css"> html, body, #map { margin: 0; @@ -309,7 +309,7 @@ <script type="text/javascript" src="/js/util.js"></script> <script type="text/javascript" src="/js/constants.js"></script> <script type="text/javascript" src="/js/3rdparty/jquery.min.js"></script> - <script type="text/javascript" src="/js/3rdparty/ol.js?t=20170623"></script> + <script type="text/javascript" src="/js/3rdparty/ol_6_5_0.js"></script> <script type="text/javascript" src="/js/3rdparty/proj4.js"></script> <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> <script type="text/javascript" src="js/map.js?t=20170713"></script> diff --git a/src/main/webapp/map_applications/fireblight/js/map.js b/src/main/webapp/map_applications/fireblight/js/map.js index 1b9fc8b2c0b19eb2f0ff2edb870966cd92046cde..73ac8932d2be164d80f9405009b663915b1e632f 100755 --- a/src/main/webapp/map_applications/fireblight/js/map.js +++ b/src/main/webapp/map_applications/fireblight/js/map.js @@ -169,20 +169,21 @@ async function initMap() // Get the background layer for Norway from Statens kartverk // TODO: Use await var parser = new ol.format.WMTSCapabilities(); - fetch('https://opencache.statkart.no/gatekeeper/gk/gk.open_wmts?Version=1.0.0&service=wmts&request=getcapabilities').then(function (response) { + fetch('https://cache.kartverket.no/v1/wmts/1.0.0/WMTSCapabilities.xml').then(function (response) { return response.text(); }).then(function (text) { var result = parser.read(text); var options = ol.source.WMTS.optionsFromCapabilities(result, { - layer: 'topo4', - matrixSet: 'EPSG:3857' + layer: 'topo', + matrixSet: 'webmercator' }); + var topo4 = new ol.layer.Tile({ opacity: 1, source: new ol.source.WMTS(/** @type {!olx.source.WMTSOptions} */ (options)) }); - + nurseryPoisOverlay = new ol.layer.Vector({ source: new ol.source.Vector({ diff --git a/src/main/webapp/map_applications/phytophthora/index.html b/src/main/webapp/map_applications/phytophthora/index.html new file mode 100755 index 0000000000000000000000000000000000000000..532cc85d9fc5c139e3863db8077e5a6fbeaa5036 --- /dev/null +++ b/src/main/webapp/map_applications/phytophthora/index.html @@ -0,0 +1,334 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> + <meta name="description" content=""> + <meta name="author" content=""> + + <title>Phytophthoraregistrering</title> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> + <link rel="stylesheet" href="/css/3rdparty/font-awesome.min.css" media="screen" /> + <link rel="stylesheet" href="/css/3rdparty/ol_6_5_0.css?t=20170623" media="screen" /> + <style type="text/css"> + html, body, #map { + margin: 0; + width: 100%; + height: 100%; + font-family: 'Source Sans Pro', sans-serif; + } + + #searchFieldContainer { + position: fixed; + top: 0px; + left: 0px; + width: 100%; + z-index: 2000; + background-color: transparent; + + } + #searchFieldInnerContainer + { + background-color: white; + margin: 5px; + padding: 5px; + /*border: 1px solid #dddddd;*/ + } + .ol-zoom { + top: auto; + bottom: 1em; + left: auto; + right: .5em + } + + #searchResults { + display: none; + } + + #searchResults li { + cursor: pointer; + } + + .geo-location + { + top: auto; + right: 4em; + bottom: 1em; + left: auto; + z-index: 1000; + } + + #registerButton { + top: auto; + bottom: 1em; + right: 6em; + left: auto; + z-index: 1000; + } + + #registerButton button { + width: 1.375em; + height: 1.375em; + background-size: 20px 20px; + background-repeat: no-repeat; + background-position: 2px 2px; + background-color: rgba(0,60,136,.5); + border: none; + color: white; + } + + + .geo-location button { + + width: 1.375em; + height: 1.375em; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkY3RkRGRkNGQTU2MDExRTU5NzkwREJDNkE0NDk4ODlEIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkY3RkRGRkQwQTU2MDExRTU5NzkwREJDNkE0NDk4ODlEIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RjdGREZGQ0RBNTYwMTFFNTk3OTBEQkM2QTQ0OTg4OUQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RjdGREZGQ0VBNTYwMTFFNTk3OTBEQkM2QTQ0OTg4OUQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7kZLS4AAAABlBMVEX9/fwAAABwf477AAAAAnRSTlP/AOW3MEoAAAHzSURBVHja7NvBcsJADANQ+f9/misHsmvZkhNgfWwhes10htheEOXCe9Wvosm/H4ADOIADOIBZAD7WEADLcgOQKB8A6bIAQJUcALqkAJRKB0C1NAA0SgFAr7oAtKsHANwC2PM3BAzkLwWYyF8JMJK/EGAm/1qAofxLAabySQAwJUAx/8NDaU1QAlw+FRcEoPPXj+W0AGT+vi/wAlKNCSUAk5/tjHqA7LsJ3EpAAKjeMC1AlN9J/boPoLvj7I2s5gf7gh6gNB/I/S+XO3/2FTkA9Tm2/6DxAjSTFDjzRYAIsWASsL8ivPn3A+KRADCAGAQ4bsD2r3o8IH4T8P5wzXRhnqGqY/p5AAdwAAdwAAdAXlO/jiTS//SB5KnPhPGTgHZj8u2tGdec3t6eDw0oWACcNyA1pBqcEYlvAVSA4qCyMid86qi2BKgNq/MC07heti8oLyzy7zStbDQ7o87SSrC2623NsntH3+Kyubold7f08noHUCyvc1v4zA+r6/ttY3EB0B1g8HR3Nx9ioc6Q3H+KRi8IFhAz+VNnyaICiIn8mfOEUQWICNEAhDt/f6zXPdcyH2xOHFu2jv0yF3dOHkMGCFc88QUH01A1HONPbqiq6Lc77Tzd+0vTo/ZFJ1l4FfBRUb6Oav5zAAdwAH8PiK8FvAQYAObrJPi2gfjAAAAAAElFTkSuQmCC); + background-size: 20px 20px; + background-repeat: no-repeat; + background-position: 2px 2px; + background-color: rgba(0,60,136,.5); + border: none; + } + + #featureForm { + display: none; + width: auto; + max-width: 90%; + height: auto; + position: absolute; + top: 3.0em; + left: 10px; + z-index: 1999; + background-color: white; + border: 1px solid black; + padding: 10px; + opacity: 0.85; + } + + #seasons { + position: absolute; + bottom: 1em; + top: auto; + left: 10px; + z-index: 1999; + } + + #legend { + position: absolute; + top: 3.0em; + bottom: auto; + right: 10px; + z-index: 1999; + background-color: white; + border: 1px solid black; + padding: 10px; + opacity: 0.85; + } + + + + #legend ul { + list-style: none; + padding:0; + margin:0; + } + + #legend ul li:before { + content: ""; + line-height: 2em; + width: 0.75em; + height: 0.75em; + float: left; + margin: .05em .4em 0; + border-radius: 50%; + border: 1px solid black; + } + + #legend ul li.bok:before { background-color: rgb(255,0,0); } + #legend ul li.graor:before { background-color: rgb(239,133,19); } + #legend ul li.eik:before { background-color: rgb(239,236,19); } + #legend ul li.lonn:before { background-color: rgb(0,255,0); } + #legend ul li.svartor:before { background-color: rgb(122,175,131); } + #legend ul li.plante:before { background-color: rgb(0,0,255); } + + /* Screen size adjustments */ + @media (max-width: 500px) + { + #legend { + display: none; + } + + + } + + /* For finger pointing aka touch screen */ + @media (pointer: coarse) { + #registerButton button, .geo-location button { + width: 1.8em; + height: 1.8em; + } + + #registerButton { + right: 8.0em; + } + .geo-location button { + bottom: 8.0em; + background-position: 6px; + } + } + + @media (max-height: 500px) + { + #legend { + display: none; + } + } + + ul.resultList + { + width: auto; + list-style: none; + padding: 0px; + } + + ul.resultList li + { + background-color: #dddddd; + border-bottom: 1px solid white; + cursor: pointer; + padding: 5px; + } + + ul.resultList li:hover { + background-color: #aaaaaa; + } + + div.logo { + float: left; + } + + #searchField { + width: 100%; + + } + table { + border-spacing: 5px 15px; + } + select, button + { + font-size: large; + } + button { + margin-right: 5px; + } + </style> + </head> + + <body> + + <div id="map" class="map"> + <div class="geo-location ol-unselectable ol-control"> + <button onclick="toggleTracking(this);" title="Vis min posisjon er AV"></button> + </div> + <div id="registerButton" class="ol-unselectable ol-control"> + <button type="button" onclick="toggleRegistration(this);" title="Registrering er AV"><i class="fa fa-pencil" aria-hidden="true"></i></button> + </div> + </div> + <div id="searchFieldContainer"> + <div id="searchFieldInnerContainer"> + + <input id="searchField" type="text" placeholder="Søk etter stedsnavn" onkeyup="showResults(this);"/> + <div id="searchResults"></div> + </div> + </div> + + <div id="featureForm"></div> + <div id="seasons"> + <select name="startSeason" id="startSeason" onchange="getAndRenderObservations(this.options[this.options.selectedIndex].value);"> + + </select> + + </div> + <div id="legend"> + <h3>Registreringer</h3> + <ul> + <li class="bok">Bøk</li> + <li class="graor">Gråor</li> + <li class="eik">Eik</li> + <li class="lonn">Lønn</li> + <li class="svartor">Svartor</li> + <li class="plante">Annet</li> + </ul> + </div> + + + <!-- Bootstrap core JavaScript + ================================================== --> + <!-- Placed at the end of the document so the pages load faster --> + <script type="text/javascript" src="/js/environment.js"></script> + <script type="text/javascript" src="/js/util.js"></script> + <script type="text/javascript" src="/js/constants.js"></script> + <script type="text/javascript" src="/js/3rdparty/jquery.min.js"></script> + <script type="text/javascript" src="/js/3rdparty/ol_6_5_0.js"></script> + <script type="text/javascript" src="/js/3rdparty/proj4.js"></script> + <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> + <script type="text/javascript" src="js/map.js?t=20170713"></script> + <script type="text/javascript"> + + var stedsnavnProj = "+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs"; + proj4.defs("EPSG:32633", "+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"); + + $(document).ready(function() { + initForekomsttyper(); + // initMap() kalles i denne funksjonens callback + // Dette fordi vi må finne databaseId til pærebrann dynamisk først + initPhytophthora(); + }); + + function showResults(inputField) + { + var phrase = inputField.value; + if(phrase.trim().length > 2) + { + //console.log(phrase); + //$.getJSON( "https://ws.geonorge.no/SKWS3Index/ssr/sok?navn=" + phrase + "*&maxAnt=5&tilSosiKoordSyst=4258&fylkeKommuneListe=&eksakteForst=true", renderResults); + $.getJSON( "https://ws.geonorge.no/stedsnavn/v1/navn?sok=" + phrase + "*&utkoordsys=4326&treffPerSide=6&side=1&filtrer=navn.skrivem%C3%A5te%2Cnavn.navneobjekttype%2Cnavn.kommuner%2Cnavn.representasjonspunkt", renderResults); + } + else if(phrase.trim().length === 0) + { + var searchResultsEl = document.getElementById("searchResults"); + searchResultsEl.innerHTML = ""; + searchResultsEl.style.display="none"; + } + } + + var renderResults = function(data) { + //console.log(data); + var html = "<ul class='resultList'>"; + for(var i=0; i<Math.min(data.navn.length,6); i++) + { + var location = data.navn[i]; + var coordinateOrig = [parseFloat(location.representasjonspunkt.øst), parseFloat(location.representasjonspunkt.nord)]; + //var coordinateDec = proj4(location.representasjonspunkt.koordsys, "EPSG:4326", coordinateOrig); + html += "<li onclick=\"navigateTo([" + coordinateOrig + "]);\"><b>" + location.skrivemåte + "</b>, " + location.kommuner[0].kommunenavn + " (" + location.navneobjekttype + ")</li>"; + } + html += "</ul>" + var searchResultsEl = document.getElementById("searchResults"); + searchResultsEl.innerHTML = html; + searchResultsEl.style.display="block"; + + //console.log(location) + // Get EPSG projection in data, transform to decimal degrees + + } + + </script> + </body> +</html> diff --git a/src/main/webapp/map_applications/phytophthora/js/d3.min.js b/src/main/webapp/map_applications/phytophthora/js/d3.min.js new file mode 100644 index 0000000000000000000000000000000000000000..e809c60a55126648252abdc038ab71c09637bba0 --- /dev/null +++ b/src/main/webapp/map_applications/phytophthora/js/d3.min.js @@ -0,0 +1,2 @@ +// https://d3js.org v6.3.1 Copyright 2020 Mike Bostock +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports):"function"==typeof define&&define.amd?define(["exports"],n):n((t="undefined"!=typeof globalThis?globalThis:t||self).d3=t.d3||{})}(this,(function(t){"use strict";function n(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function e(t){let e=t,r=t;function i(t,n,e,i){for(null==e&&(e=0),null==i&&(i=t.length);e<i;){const o=e+i>>>1;r(t[o],n)<0?e=o+1:i=o}return e}return 1===t.length&&(e=(n,e)=>t(n)-e,r=function(t){return(e,r)=>n(t(e),r)}(t)),{left:i,center:function(t,n,r,o){null==r&&(r=0),null==o&&(o=t.length);const a=i(t,n,r,o-1);return a>r&&e(t[a-1],n)>-e(t[a],n)?a-1:a},right:function(t,n,e,i){for(null==e&&(e=0),null==i&&(i=t.length);e<i;){const o=e+i>>>1;r(t[o],n)>0?i=o:e=o+1}return e}}}function r(t){return null===t?NaN:+t}const i=e(n),o=i.right,a=i.left,u=e(r).center;function c(t,n){let e=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&++e;else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(i=+i)>=i&&++e}return e}function f(t){return 0|t.length}function s(t){return!(t>0)}function l(t){return"object"!=typeof t||"length"in t?t:Array.from(t)}function h(t,n){let e,r=0,i=0,o=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(e=n-i,i+=e/++r,o+=e*(n-i));else{let a=-1;for(let u of t)null!=(u=n(u,++a,t))&&(u=+u)>=u&&(e=u-i,i+=e/++r,o+=e*(u-i))}if(r>1)return o/(r-1)}function d(t,n){const e=h(t,n);return e?Math.sqrt(e):e}function p(t,n){let e,r;if(void 0===n)for(const n of t)null!=n&&(void 0===e?n>=n&&(e=r=n):(e>n&&(e=n),r<n&&(r=n)));else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(void 0===e?o>=o&&(e=r=o):(e>o&&(e=o),r<o&&(r=o)))}return[e,r]}class g{constructor(){this._partials=new Float64Array(32),this._n=0}add(t){const n=this._partials;let e=0;for(let r=0;r<this._n&&r<32;r++){const i=n[r],o=t+i,a=Math.abs(t)<Math.abs(i)?t-(o-i):i-(o-t);a&&(n[e++]=a),t=o}return n[e]=t,this._n=e+1,this}valueOf(){const t=this._partials;let n,e,r,i=this._n,o=0;if(i>0){for(o=t[--i];i>0&&(n=o,e=t[--i],o=n+e,r=e-(o-n),!r););i>0&&(r<0&&t[i-1]<0||r>0&&t[i-1]>0)&&(e=2*r,n=o+e,e==n-o&&(o=n))}return o}}function y(t){return t}function v(t){if(1!==t.length)throw new Error("duplicate key");return t[0]}function _(t,n,e,r){return function t(i,o){if(o>=r.length)return e(i);const a=new Map,u=r[o++];let c=-1;for(const t of i){const n=u(t,++c,i),e=a.get(n);e?e.push(t):a.set(n,[t])}for(const[n,e]of a)a.set(n,t(e,o));return n(a)}(t,0)}var b=Array.prototype.slice;function m(t){return function(){return t}}var x=Math.sqrt(50),w=Math.sqrt(10),M=Math.sqrt(2);function A(t,n,e){var r,i,o,a,u=-1;if(e=+e,(t=+t)===(n=+n)&&e>0)return[t];if((r=n<t)&&(i=t,t=n,n=i),0===(a=T(t,n,e))||!isFinite(a))return[];if(a>0)for(t=Math.ceil(t/a),n=Math.floor(n/a),o=new Array(i=Math.ceil(n-t+1));++u<i;)o[u]=(t+u)*a;else for(a=-a,t=Math.ceil(t*a),n=Math.floor(n*a),o=new Array(i=Math.ceil(n-t+1));++u<i;)o[u]=(t+u)/a;return r&&o.reverse(),o}function T(t,n,e){var r=(n-t)/Math.max(0,e),i=Math.floor(Math.log(r)/Math.LN10),o=r/Math.pow(10,i);return i>=0?(o>=x?10:o>=w?5:o>=M?2:1)*Math.pow(10,i):-Math.pow(10,-i)/(o>=x?10:o>=w?5:o>=M?2:1)}function S(t,n,e){var r=Math.abs(n-t)/Math.max(0,e),i=Math.pow(10,Math.floor(Math.log(r)/Math.LN10)),o=r/i;return o>=x?i*=10:o>=w?i*=5:o>=M&&(i*=2),n<t?-i:i}function E(t,n,e){let r;for(;;){const i=T(t,n,e);if(i===r||0===i||!isFinite(i))return[t,n];i>0?(t=Math.floor(t/i)*i,n=Math.ceil(n/i)*i):i<0&&(t=Math.ceil(t*i)/i,n=Math.floor(n*i)/i),r=i}}function k(t){return Math.ceil(Math.log(c(t))/Math.LN2)+1}function N(){var t=y,n=p,e=k;function r(r){Array.isArray(r)||(r=Array.from(r));var i,a,u=r.length,c=new Array(u);for(i=0;i<u;++i)c[i]=t(r[i],i,r);var f=n(c),s=f[0],l=f[1],h=e(c,s,l);if(!Array.isArray(h)){const t=l,e=+h;if(n===p&&([s,l]=E(s,l,e)),(h=A(s,l,e))[h.length-1]>=l)if(t>=l&&n===p){const t=T(s,l,e);isFinite(t)&&(t>0?l=(Math.floor(l/t)+1)*t:t<0&&(l=(Math.ceil(l*-t)+1)/-t))}else h.pop()}for(var d=h.length;h[0]<=s;)h.shift(),--d;for(;h[d-1]>l;)h.pop(),--d;var g,y=new Array(d+1);for(i=0;i<=d;++i)(g=y[i]=[]).x0=i>0?h[i-1]:s,g.x1=i<d?h[i]:l;for(i=0;i<u;++i)s<=(a=c[i])&&a<=l&&y[o(h,a,0,d)].push(r[i]);return y}return r.value=function(n){return arguments.length?(t="function"==typeof n?n:m(n),r):t},r.domain=function(t){return arguments.length?(n="function"==typeof t?t:m([t[0],t[1]]),r):n},r.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?m(b.call(t)):m(t),r):e},r}function C(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e<n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e<i||void 0===e&&i>=i)&&(e=i)}return e}function P(t,n){let e;if(void 0===n)for(const n of t)null!=n&&(e>n||void 0===e&&n>=n)&&(e=n);else{let r=-1;for(let i of t)null!=(i=n(i,++r,t))&&(e>i||void 0===e&&i>=i)&&(e=i)}return e}function z(t,e,r=0,i=t.length-1,o=n){for(;i>r;){if(i-r>600){const n=i-r+1,a=e-r+1,u=Math.log(n),c=.5*Math.exp(2*u/3),f=.5*Math.sqrt(u*c*(n-c)/n)*(a-n/2<0?-1:1);z(t,e,Math.max(r,Math.floor(e-a*c/n+f)),Math.min(i,Math.floor(e+(n-a)*c/n+f)),o)}const n=t[e];let a=r,u=i;for(D(t,r,e),o(t[i],n)>0&&D(t,r,i);a<u;){for(D(t,a,u),++a,--u;o(t[a],n)<0;)++a;for(;o(t[u],n)>0;)--u}0===o(t[r],n)?D(t,r,u):(++u,D(t,u,i)),u<=e&&(r=u+1),e<=u&&(i=u-1)}return t}function D(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function q(t,n,e){if(r=(t=Float64Array.from(function*(t,n){if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(yield n);else{let e=-1;for(let r of t)null!=(r=n(r,++e,t))&&(r=+r)>=r&&(yield r)}}(t,e))).length){if((n=+n)<=0||r<2)return P(t);if(n>=1)return C(t);var r,i=(r-1)*n,o=Math.floor(i),a=C(z(t,o).subarray(0,o+1));return a+(P(t.subarray(o+1))-a)*(i-o)}}function R(t,n,e=r){if(i=t.length){if((n=+n)<=0||i<2)return+e(t[0],0,t);if(n>=1)return+e(t[i-1],i-1,t);var i,o=(i-1)*n,a=Math.floor(o),u=+e(t[a],a,t);return u+(+e(t[a+1],a+1,t)-u)*(o-a)}}function F(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e<n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e<o||void 0===e&&o>=o)&&(e=o,r=i);return r}function O(t){return Array.from(function*(t){for(const n of t)yield*n}(t))}function U(t,n){let e,r=-1,i=-1;if(void 0===n)for(const n of t)++i,null!=n&&(e>n||void 0===e&&n>=n)&&(e=n,r=i);else for(let o of t)null!=(o=n(o,++i,t))&&(e>o||void 0===e&&o>=o)&&(e=o,r=i);return r}function I(t,n){return[t,n]}function B(t,n){return Array.from(n,n=>t[n])}function Y(t,n,e){t=+t,n=+n,e=(i=arguments.length)<2?(n=t,t=0,1):i<3?1:+e;for(var r=-1,i=0|Math.max(0,Math.ceil((n-t)/e)),o=new Array(i);++r<i;)o[r]=t+r*e;return o}function L(t,e=n){if(1===e.length)return U(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)<0)&&(r=n,i=o);return i}var j=H(Math.random);function H(t){return function(n,e=0,r=n.length){let i=r-(e=+e);for(;i;){const r=t()*i--|0,o=n[i+e];n[i+e]=n[r+e],n[r+e]=o}return n}}function X(t){if(!(i=t.length))return[];for(var n=-1,e=P(t,G),r=new Array(e);++n<e;)for(var i,o=-1,a=r[n]=new Array(i);++o<i;)a[o]=t[o][n];return r}function G(t){return t.length}function V(t){return t instanceof Set?t:new Set(t)}function $(t,n){const e=t[Symbol.iterator](),r=new Set;for(const t of n){if(r.has(t))continue;let n,i;for(;({value:n,done:i}=e.next());){if(i)return!1;if(r.add(n),Object.is(t,n))break}}return!0}var W=Array.prototype.slice;function Z(t){return t}var K=1e-6;function Q(t){return"translate("+(t+.5)+",0)"}function J(t){return"translate(0,"+(t+.5)+")"}function tt(t){return n=>+t(n)}function nt(t){var n=Math.max(0,t.bandwidth()-1)/2;return t.round()&&(n=Math.round(n)),function(e){return+t(e)+n}}function et(){return!this.__axis}function rt(t,n){var e=[],r=null,i=null,o=6,a=6,u=3,c=1===t||4===t?-1:1,f=4===t||2===t?"x":"y",s=1===t||3===t?Q:J;function l(l){var h=null==r?n.ticks?n.ticks.apply(n,e):n.domain():r,d=null==i?n.tickFormat?n.tickFormat.apply(n,e):Z:i,p=Math.max(o,0)+u,g=n.range(),y=+g[0]+.5,v=+g[g.length-1]+.5,_=(n.bandwidth?nt:tt)(n.copy()),b=l.selection?l.selection():l,m=b.selectAll(".domain").data([null]),x=b.selectAll(".tick").data(h,n).order(),w=x.exit(),M=x.enter().append("g").attr("class","tick"),A=x.select("line"),T=x.select("text");m=m.merge(m.enter().insert("path",".tick").attr("class","domain").attr("stroke","currentColor")),x=x.merge(M),A=A.merge(M.append("line").attr("stroke","currentColor").attr(f+"2",c*o)),T=T.merge(M.append("text").attr("fill","currentColor").attr(f,c*p).attr("dy",1===t?"0em":3===t?"0.71em":"0.32em")),l!==b&&(m=m.transition(l),x=x.transition(l),A=A.transition(l),T=T.transition(l),w=w.transition(l).attr("opacity",K).attr("transform",(function(t){return isFinite(t=_(t))?s(t):this.getAttribute("transform")})),M.attr("opacity",K).attr("transform",(function(t){var n=this.parentNode.__axis;return s(n&&isFinite(n=n(t))?n:_(t))}))),w.remove(),m.attr("d",4===t||2==t?a?"M"+c*a+","+y+"H0.5V"+v+"H"+c*a:"M0.5,"+y+"V"+v:a?"M"+y+","+c*a+"V0.5H"+v+"V"+c*a:"M"+y+",0.5H"+v),x.attr("opacity",1).attr("transform",(function(t){return s(_(t))})),A.attr(f+"2",c*o),T.attr(f,c*p).text(d),b.filter(et).attr("fill","none").attr("font-size",10).attr("font-family","sans-serif").attr("text-anchor",2===t?"start":4===t?"end":"middle"),b.each((function(){this.__axis=_}))}return l.scale=function(t){return arguments.length?(n=t,l):n},l.ticks=function(){return e=W.call(arguments),l},l.tickArguments=function(t){return arguments.length?(e=null==t?[]:W.call(t),l):e.slice()},l.tickValues=function(t){return arguments.length?(r=null==t?null:W.call(t),l):r&&r.slice()},l.tickFormat=function(t){return arguments.length?(i=t,l):i},l.tickSize=function(t){return arguments.length?(o=a=+t,l):o},l.tickSizeInner=function(t){return arguments.length?(o=+t,l):o},l.tickSizeOuter=function(t){return arguments.length?(a=+t,l):a},l.tickPadding=function(t){return arguments.length?(u=+t,l):u},l}var it={value:()=>{}};function ot(){for(var t,n=0,e=arguments.length,r={};n<e;++n){if(!(t=arguments[n]+"")||t in r||/[\s.]/.test(t))throw new Error("illegal type: "+t);r[t]=[]}return new at(r)}function at(t){this._=t}function ut(t,n){return t.trim().split(/^|\s+/).map((function(t){var e="",r=t.indexOf(".");if(r>=0&&(e=t.slice(r+1),t=t.slice(0,r)),t&&!n.hasOwnProperty(t))throw new Error("unknown type: "+t);return{type:t,name:e}}))}function ct(t,n){for(var e,r=0,i=t.length;r<i;++r)if((e=t[r]).name===n)return e.value}function ft(t,n,e){for(var r=0,i=t.length;r<i;++r)if(t[r].name===n){t[r]=it,t=t.slice(0,r).concat(t.slice(r+1));break}return null!=e&&t.push({name:n,value:e}),t}at.prototype=ot.prototype={constructor:at,on:function(t,n){var e,r=this._,i=ut(t+"",r),o=-1,a=i.length;if(!(arguments.length<2)){if(null!=n&&"function"!=typeof n)throw new Error("invalid callback: "+n);for(;++o<a;)if(e=(t=i[o]).type)r[e]=ft(r[e],t.name,n);else if(null==n)for(e in r)r[e]=ft(r[e],t.name,null);return this}for(;++o<a;)if((e=(t=i[o]).type)&&(e=ct(r[e],t.name)))return e},copy:function(){var t={},n=this._;for(var e in n)t[e]=n[e].slice();return new at(t)},call:function(t,n){if((e=arguments.length-2)>0)for(var e,r,i=new Array(e),o=0;o<e;++o)i[o]=arguments[o+2];if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(o=0,e=(r=this._[t]).length;o<e;++o)r[o].value.apply(n,i)},apply:function(t,n,e){if(!this._.hasOwnProperty(t))throw new Error("unknown type: "+t);for(var r=this._[t],i=0,o=r.length;i<o;++i)r[i].value.apply(n,e)}};var st="http://www.w3.org/1999/xhtml",lt={svg:"http://www.w3.org/2000/svg",xhtml:st,xlink:"http://www.w3.org/1999/xlink",xml:"http://www.w3.org/XML/1998/namespace",xmlns:"http://www.w3.org/2000/xmlns/"};function ht(t){var n=t+="",e=n.indexOf(":");return e>=0&&"xmlns"!==(n=t.slice(0,e))&&(t=t.slice(e+1)),lt.hasOwnProperty(n)?{space:lt[n],local:t}:t}function dt(t){return function(){var n=this.ownerDocument,e=this.namespaceURI;return e===st&&n.documentElement.namespaceURI===st?n.createElement(t):n.createElementNS(e,t)}}function pt(t){return function(){return this.ownerDocument.createElementNS(t.space,t.local)}}function gt(t){var n=ht(t);return(n.local?pt:dt)(n)}function yt(){}function vt(t){return null==t?yt:function(){return this.querySelector(t)}}function _t(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function bt(){return[]}function mt(t){return null==t?bt:function(){return this.querySelectorAll(t)}}function xt(t){return function(){return this.matches(t)}}function wt(t){return function(n){return n.matches(t)}}var Mt=Array.prototype.find;function At(){return this.firstElementChild}var Tt=Array.prototype.filter;function St(){return this.children}function Et(t){return new Array(t.length)}function kt(t,n){this.ownerDocument=t.ownerDocument,this.namespaceURI=t.namespaceURI,this._next=null,this._parent=t,this.__data__=n}function Nt(t){return function(){return t}}function Ct(t,n,e,r,i,o){for(var a,u=0,c=n.length,f=o.length;u<f;++u)(a=n[u])?(a.__data__=o[u],r[u]=a):e[u]=new kt(t,o[u]);for(;u<c;++u)(a=n[u])&&(i[u]=a)}function Pt(t,n,e,r,i,o,a){var u,c,f,s=new Map,l=n.length,h=o.length,d=new Array(l);for(u=0;u<l;++u)(c=n[u])&&(d[u]=f=a.call(c,c.__data__,u,n)+"",s.has(f)?i[u]=c:s.set(f,c));for(u=0;u<h;++u)f=a.call(t,o[u],u,o)+"",(c=s.get(f))?(r[u]=c,c.__data__=o[u],s.delete(f)):e[u]=new kt(t,o[u]);for(u=0;u<l;++u)(c=n[u])&&s.get(d[u])===c&&(i[u]=c)}function zt(t){return t.__data__}function Dt(t,n){return t<n?-1:t>n?1:t>=n?0:NaN}function qt(t){return function(){this.removeAttribute(t)}}function Rt(t){return function(){this.removeAttributeNS(t.space,t.local)}}function Ft(t,n){return function(){this.setAttribute(t,n)}}function Ot(t,n){return function(){this.setAttributeNS(t.space,t.local,n)}}function Ut(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttribute(t):this.setAttribute(t,e)}}function It(t,n){return function(){var e=n.apply(this,arguments);null==e?this.removeAttributeNS(t.space,t.local):this.setAttributeNS(t.space,t.local,e)}}function Bt(t){return t.ownerDocument&&t.ownerDocument.defaultView||t.document&&t||t.defaultView}function Yt(t){return function(){this.style.removeProperty(t)}}function Lt(t,n,e){return function(){this.style.setProperty(t,n,e)}}function jt(t,n,e){return function(){var r=n.apply(this,arguments);null==r?this.style.removeProperty(t):this.style.setProperty(t,r,e)}}function Ht(t,n){return t.style.getPropertyValue(n)||Bt(t).getComputedStyle(t,null).getPropertyValue(n)}function Xt(t){return function(){delete this[t]}}function Gt(t,n){return function(){this[t]=n}}function Vt(t,n){return function(){var e=n.apply(this,arguments);null==e?delete this[t]:this[t]=e}}function $t(t){return t.trim().split(/^|\s+/)}function Wt(t){return t.classList||new Zt(t)}function Zt(t){this._node=t,this._names=$t(t.getAttribute("class")||"")}function Kt(t,n){for(var e=Wt(t),r=-1,i=n.length;++r<i;)e.add(n[r])}function Qt(t,n){for(var e=Wt(t),r=-1,i=n.length;++r<i;)e.remove(n[r])}function Jt(t){return function(){Kt(this,t)}}function tn(t){return function(){Qt(this,t)}}function nn(t,n){return function(){(n.apply(this,arguments)?Kt:Qt)(this,t)}}function en(){this.textContent=""}function rn(t){return function(){this.textContent=t}}function on(t){return function(){var n=t.apply(this,arguments);this.textContent=null==n?"":n}}function an(){this.innerHTML=""}function un(t){return function(){this.innerHTML=t}}function cn(t){return function(){var n=t.apply(this,arguments);this.innerHTML=null==n?"":n}}function fn(){this.nextSibling&&this.parentNode.appendChild(this)}function sn(){this.previousSibling&&this.parentNode.insertBefore(this,this.parentNode.firstChild)}function ln(){return null}function hn(){var t=this.parentNode;t&&t.removeChild(this)}function dn(){var t=this.cloneNode(!1),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function pn(){var t=this.cloneNode(!0),n=this.parentNode;return n?n.insertBefore(t,this.nextSibling):t}function gn(t){return t.trim().split(/^|\s+/).map((function(t){var n="",e=t.indexOf(".");return e>=0&&(n=t.slice(e+1),t=t.slice(0,e)),{type:t,name:n}}))}function yn(t){return function(){var n=this.__on;if(n){for(var e,r=0,i=-1,o=n.length;r<o;++r)e=n[r],t.type&&e.type!==t.type||e.name!==t.name?n[++i]=e:this.removeEventListener(e.type,e.listener,e.options);++i?n.length=i:delete this.__on}}}function vn(t,n,e){return function(){var r,i=this.__on,o=function(t){return function(n){t.call(this,n,this.__data__)}}(n);if(i)for(var a=0,u=i.length;a<u;++a)if((r=i[a]).type===t.type&&r.name===t.name)return this.removeEventListener(r.type,r.listener,r.options),this.addEventListener(r.type,r.listener=o,r.options=e),void(r.value=n);this.addEventListener(t.type,o,e),r={type:t.type,name:t.name,value:n,listener:o,options:e},i?i.push(r):this.__on=[r]}}function _n(t,n,e){var r=Bt(t),i=r.CustomEvent;"function"==typeof i?i=new i(n,e):(i=r.document.createEvent("Event"),e?(i.initEvent(n,e.bubbles,e.cancelable),i.detail=e.detail):i.initEvent(n,!1,!1)),t.dispatchEvent(i)}function bn(t,n){return function(){return _n(this,t,n)}}function mn(t,n){return function(){return _n(this,t,n.apply(this,arguments))}}kt.prototype={constructor:kt,appendChild:function(t){return this._parent.insertBefore(t,this._next)},insertBefore:function(t,n){return this._parent.insertBefore(t,n)},querySelector:function(t){return this._parent.querySelector(t)},querySelectorAll:function(t){return this._parent.querySelectorAll(t)}},Zt.prototype={add:function(t){this._names.indexOf(t)<0&&(this._names.push(t),this._node.setAttribute("class",this._names.join(" ")))},remove:function(t){var n=this._names.indexOf(t);n>=0&&(this._names.splice(n,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(t){return this._names.indexOf(t)>=0}};var xn=[null];function wn(t,n){this._groups=t,this._parents=n}function Mn(){return new wn([[document.documentElement]],xn)}function An(t){return"string"==typeof t?new wn([[document.querySelector(t)]],[document.documentElement]):new wn([[t]],xn)}wn.prototype=Mn.prototype={constructor:wn,select:function(t){"function"!=typeof t&&(t=vt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a,u=n[i],c=u.length,f=r[i]=new Array(c),s=0;s<c;++s)(o=u[s])&&(a=t.call(o,o.__data__,s,u))&&("__data__"in o&&(a.__data__=o.__data__),f[s]=a);return new wn(r,this._parents)},selectAll:function(t){t="function"==typeof t?function(t){return function(){var n=t.apply(this,arguments);return null==n?[]:_t(n)}}(t):mt(t);for(var n=this._groups,e=n.length,r=[],i=[],o=0;o<e;++o)for(var a,u=n[o],c=u.length,f=0;f<c;++f)(a=u[f])&&(r.push(t.call(a,a.__data__,f,u)),i.push(a));return new wn(r,i)},selectChild:function(t){return this.select(null==t?At:function(t){return function(){return Mt.call(this.children,t)}}("function"==typeof t?t:wt(t)))},selectChildren:function(t){return this.selectAll(null==t?St:function(t){return function(){return Tt.call(this.children,t)}}("function"==typeof t?t:wt(t)))},filter:function(t){"function"!=typeof t&&(t=xt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new wn(r,this._parents)},data:function(t,n){if(!arguments.length)return Array.from(this,zt);var e=n?Pt:Ct,r=this._parents,i=this._groups;"function"!=typeof t&&(t=Nt(t));for(var o=i.length,a=new Array(o),u=new Array(o),c=new Array(o),f=0;f<o;++f){var s=r[f],l=i[f],h=l.length,d=_t(t.call(s,s&&s.__data__,f,r)),p=d.length,g=u[f]=new Array(p),y=a[f]=new Array(p),v=c[f]=new Array(h);e(s,l,g,y,v,d,n);for(var _,b,m=0,x=0;m<p;++m)if(_=g[m]){for(m>=x&&(x=m+1);!(b=y[x])&&++x<p;);_._next=b||null}}return(a=new wn(a,r))._enter=u,a._exit=c,a},enter:function(){return new wn(this._enter||this._groups.map(Et),this._parents)},exit:function(){return new wn(this._exit||this._groups.map(Et),this._parents)},join:function(t,n,e){var r=this.enter(),i=this,o=this.exit();return r="function"==typeof t?t(r):r.append(t+""),null!=n&&(i=n(i)),null==e?o.remove():e(o),r&&i?r.merge(i).order():i},merge:function(t){if(!(t instanceof wn))throw new Error("invalid merge");for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new wn(a,this._parents)},selection:function(){return this},order:function(){for(var t=this._groups,n=-1,e=t.length;++n<e;)for(var r,i=t[n],o=i.length-1,a=i[o];--o>=0;)(r=i[o])&&(a&&4^r.compareDocumentPosition(a)&&a.parentNode.insertBefore(r,a),a=r);return this},sort:function(t){function n(n,e){return n&&e?t(n.__data__,e.__data__):!n-!e}t||(t=Dt);for(var e=this._groups,r=e.length,i=new Array(r),o=0;o<r;++o){for(var a,u=e[o],c=u.length,f=i[o]=new Array(c),s=0;s<c;++s)(a=u[s])&&(f[s]=a);f.sort(n)}return new wn(i,this._parents).order()},call:function(){var t=arguments[0];return arguments[0]=this,t.apply(null,arguments),this},nodes:function(){return Array.from(this)},node:function(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r=t[n],i=0,o=r.length;i<o;++i){var a=r[i];if(a)return a}return null},size:function(){let t=0;for(const n of this)++t;return t},empty:function(){return!this.node()},each:function(t){for(var n=this._groups,e=0,r=n.length;e<r;++e)for(var i,o=n[e],a=0,u=o.length;a<u;++a)(i=o[a])&&t.call(i,i.__data__,a,o);return this},attr:function(t,n){var e=ht(t);if(arguments.length<2){var r=this.node();return e.local?r.getAttributeNS(e.space,e.local):r.getAttribute(e)}return this.each((null==n?e.local?Rt:qt:"function"==typeof n?e.local?It:Ut:e.local?Ot:Ft)(e,n))},style:function(t,n,e){return arguments.length>1?this.each((null==n?Yt:"function"==typeof n?jt:Lt)(t,n,null==e?"":e)):Ht(this.node(),t)},property:function(t,n){return arguments.length>1?this.each((null==n?Xt:"function"==typeof n?Vt:Gt)(t,n)):this.node()[t]},classed:function(t,n){var e=$t(t+"");if(arguments.length<2){for(var r=Wt(this.node()),i=-1,o=e.length;++i<o;)if(!r.contains(e[i]))return!1;return!0}return this.each(("function"==typeof n?nn:n?Jt:tn)(e,n))},text:function(t){return arguments.length?this.each(null==t?en:("function"==typeof t?on:rn)(t)):this.node().textContent},html:function(t){return arguments.length?this.each(null==t?an:("function"==typeof t?cn:un)(t)):this.node().innerHTML},raise:function(){return this.each(fn)},lower:function(){return this.each(sn)},append:function(t){var n="function"==typeof t?t:gt(t);return this.select((function(){return this.appendChild(n.apply(this,arguments))}))},insert:function(t,n){var e="function"==typeof t?t:gt(t),r=null==n?ln:"function"==typeof n?n:vt(n);return this.select((function(){return this.insertBefore(e.apply(this,arguments),r.apply(this,arguments)||null)}))},remove:function(){return this.each(hn)},clone:function(t){return this.select(t?pn:dn)},datum:function(t){return arguments.length?this.property("__data__",t):this.node().__data__},on:function(t,n,e){var r,i,o=gn(t+""),a=o.length;if(!(arguments.length<2)){for(u=n?vn:yn,r=0;r<a;++r)this.each(u(o[r],n,e));return this}var u=this.node().__on;if(u)for(var c,f=0,s=u.length;f<s;++f)for(r=0,c=u[f];r<a;++r)if((i=o[r]).type===c.type&&i.name===c.name)return c.value},dispatch:function(t,n){return this.each(("function"==typeof n?mn:bn)(t,n))},[Symbol.iterator]:function*(){for(var t=this._groups,n=0,e=t.length;n<e;++n)for(var r,i=t[n],o=0,a=i.length;o<a;++o)(r=i[o])&&(yield r)}};var Tn=0;function Sn(){return new En}function En(){this._="@"+(++Tn).toString(36)}function kn(t){let n;for(;n=t.sourceEvent;)t=n;return t}function Nn(t,n){if(t=kn(t),void 0===n&&(n=t.currentTarget),n){var e=n.ownerSVGElement||n;if(e.createSVGPoint){var r=e.createSVGPoint();return r.x=t.clientX,r.y=t.clientY,[(r=r.matrixTransform(n.getScreenCTM().inverse())).x,r.y]}if(n.getBoundingClientRect){var i=n.getBoundingClientRect();return[t.clientX-i.left-n.clientLeft,t.clientY-i.top-n.clientTop]}}return[t.pageX,t.pageY]}function Cn(t){t.stopImmediatePropagation()}function Pn(t){t.preventDefault(),t.stopImmediatePropagation()}function zn(t){var n=t.document.documentElement,e=An(t).on("dragstart.drag",Pn,!0);"onselectstart"in n?e.on("selectstart.drag",Pn,!0):(n.__noselect=n.style.MozUserSelect,n.style.MozUserSelect="none")}function Dn(t,n){var e=t.document.documentElement,r=An(t).on("dragstart.drag",null);n&&(r.on("click.drag",Pn,!0),setTimeout((function(){r.on("click.drag",null)}),0)),"onselectstart"in e?r.on("selectstart.drag",null):(e.style.MozUserSelect=e.__noselect,delete e.__noselect)}En.prototype=Sn.prototype={constructor:En,get:function(t){for(var n=this._;!(n in t);)if(!(t=t.parentNode))return;return t[n]},set:function(t,n){return t[this._]=n},remove:function(t){return this._ in t&&delete t[this._]},toString:function(){return this._}};var qn=t=>()=>t;function Rn(t,{sourceEvent:n,subject:e,target:r,identifier:i,active:o,x:a,y:u,dx:c,dy:f,dispatch:s}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},subject:{value:e,enumerable:!0,configurable:!0},target:{value:r,enumerable:!0,configurable:!0},identifier:{value:i,enumerable:!0,configurable:!0},active:{value:o,enumerable:!0,configurable:!0},x:{value:a,enumerable:!0,configurable:!0},y:{value:u,enumerable:!0,configurable:!0},dx:{value:c,enumerable:!0,configurable:!0},dy:{value:f,enumerable:!0,configurable:!0},_:{value:s}})}function Fn(t){return!t.ctrlKey&&!t.button}function On(){return this.parentNode}function Un(t,n){return null==n?{x:t.x,y:t.y}:n}function In(){return navigator.maxTouchPoints||"ontouchstart"in this}function Bn(t,n,e){t.prototype=n.prototype=e,e.constructor=t}function Yn(t,n){var e=Object.create(t.prototype);for(var r in n)e[r]=n[r];return e}function Ln(){}Rn.prototype.on=function(){var t=this._.on.apply(this._,arguments);return t===this._?this:t};var jn=.7,Hn=1/jn,Xn="\\s*([+-]?\\d+)\\s*",Gn="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)\\s*",Vn="\\s*([+-]?\\d*\\.?\\d+(?:[eE][+-]?\\d+)?)%\\s*",$n=/^#([0-9a-f]{3,8})$/,Wn=new RegExp("^rgb\\("+[Xn,Xn,Xn]+"\\)$"),Zn=new RegExp("^rgb\\("+[Vn,Vn,Vn]+"\\)$"),Kn=new RegExp("^rgba\\("+[Xn,Xn,Xn,Gn]+"\\)$"),Qn=new RegExp("^rgba\\("+[Vn,Vn,Vn,Gn]+"\\)$"),Jn=new RegExp("^hsl\\("+[Gn,Vn,Vn]+"\\)$"),te=new RegExp("^hsla\\("+[Gn,Vn,Vn,Gn]+"\\)$"),ne={aliceblue:15792383,antiquewhite:16444375,aqua:65535,aquamarine:8388564,azure:15794175,beige:16119260,bisque:16770244,black:0,blanchedalmond:16772045,blue:255,blueviolet:9055202,brown:10824234,burlywood:14596231,cadetblue:6266528,chartreuse:8388352,chocolate:13789470,coral:16744272,cornflowerblue:6591981,cornsilk:16775388,crimson:14423100,cyan:65535,darkblue:139,darkcyan:35723,darkgoldenrod:12092939,darkgray:11119017,darkgreen:25600,darkgrey:11119017,darkkhaki:12433259,darkmagenta:9109643,darkolivegreen:5597999,darkorange:16747520,darkorchid:10040012,darkred:9109504,darksalmon:15308410,darkseagreen:9419919,darkslateblue:4734347,darkslategray:3100495,darkslategrey:3100495,darkturquoise:52945,darkviolet:9699539,deeppink:16716947,deepskyblue:49151,dimgray:6908265,dimgrey:6908265,dodgerblue:2003199,firebrick:11674146,floralwhite:16775920,forestgreen:2263842,fuchsia:16711935,gainsboro:14474460,ghostwhite:16316671,gold:16766720,goldenrod:14329120,gray:8421504,green:32768,greenyellow:11403055,grey:8421504,honeydew:15794160,hotpink:16738740,indianred:13458524,indigo:4915330,ivory:16777200,khaki:15787660,lavender:15132410,lavenderblush:16773365,lawngreen:8190976,lemonchiffon:16775885,lightblue:11393254,lightcoral:15761536,lightcyan:14745599,lightgoldenrodyellow:16448210,lightgray:13882323,lightgreen:9498256,lightgrey:13882323,lightpink:16758465,lightsalmon:16752762,lightseagreen:2142890,lightskyblue:8900346,lightslategray:7833753,lightslategrey:7833753,lightsteelblue:11584734,lightyellow:16777184,lime:65280,limegreen:3329330,linen:16445670,magenta:16711935,maroon:8388608,mediumaquamarine:6737322,mediumblue:205,mediumorchid:12211667,mediumpurple:9662683,mediumseagreen:3978097,mediumslateblue:8087790,mediumspringgreen:64154,mediumturquoise:4772300,mediumvioletred:13047173,midnightblue:1644912,mintcream:16121850,mistyrose:16770273,moccasin:16770229,navajowhite:16768685,navy:128,oldlace:16643558,olive:8421376,olivedrab:7048739,orange:16753920,orangered:16729344,orchid:14315734,palegoldenrod:15657130,palegreen:10025880,paleturquoise:11529966,palevioletred:14381203,papayawhip:16773077,peachpuff:16767673,peru:13468991,pink:16761035,plum:14524637,powderblue:11591910,purple:8388736,rebeccapurple:6697881,red:16711680,rosybrown:12357519,royalblue:4286945,saddlebrown:9127187,salmon:16416882,sandybrown:16032864,seagreen:3050327,seashell:16774638,sienna:10506797,silver:12632256,skyblue:8900331,slateblue:6970061,slategray:7372944,slategrey:7372944,snow:16775930,springgreen:65407,steelblue:4620980,tan:13808780,teal:32896,thistle:14204888,tomato:16737095,turquoise:4251856,violet:15631086,wheat:16113331,white:16777215,whitesmoke:16119285,yellow:16776960,yellowgreen:10145074};function ee(){return this.rgb().formatHex()}function re(){return this.rgb().formatRgb()}function ie(t){var n,e;return t=(t+"").trim().toLowerCase(),(n=$n.exec(t))?(e=n[1].length,n=parseInt(n[1],16),6===e?oe(n):3===e?new fe(n>>8&15|n>>4&240,n>>4&15|240&n,(15&n)<<4|15&n,1):8===e?ae(n>>24&255,n>>16&255,n>>8&255,(255&n)/255):4===e?ae(n>>12&15|n>>8&240,n>>8&15|n>>4&240,n>>4&15|240&n,((15&n)<<4|15&n)/255):null):(n=Wn.exec(t))?new fe(n[1],n[2],n[3],1):(n=Zn.exec(t))?new fe(255*n[1]/100,255*n[2]/100,255*n[3]/100,1):(n=Kn.exec(t))?ae(n[1],n[2],n[3],n[4]):(n=Qn.exec(t))?ae(255*n[1]/100,255*n[2]/100,255*n[3]/100,n[4]):(n=Jn.exec(t))?de(n[1],n[2]/100,n[3]/100,1):(n=te.exec(t))?de(n[1],n[2]/100,n[3]/100,n[4]):ne.hasOwnProperty(t)?oe(ne[t]):"transparent"===t?new fe(NaN,NaN,NaN,0):null}function oe(t){return new fe(t>>16&255,t>>8&255,255&t,1)}function ae(t,n,e,r){return r<=0&&(t=n=e=NaN),new fe(t,n,e,r)}function ue(t){return t instanceof Ln||(t=ie(t)),t?new fe((t=t.rgb()).r,t.g,t.b,t.opacity):new fe}function ce(t,n,e,r){return 1===arguments.length?ue(t):new fe(t,n,e,null==r?1:r)}function fe(t,n,e,r){this.r=+t,this.g=+n,this.b=+e,this.opacity=+r}function se(){return"#"+he(this.r)+he(this.g)+he(this.b)}function le(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"rgb(":"rgba(")+Math.max(0,Math.min(255,Math.round(this.r)||0))+", "+Math.max(0,Math.min(255,Math.round(this.g)||0))+", "+Math.max(0,Math.min(255,Math.round(this.b)||0))+(1===t?")":", "+t+")")}function he(t){return((t=Math.max(0,Math.min(255,Math.round(t)||0)))<16?"0":"")+t.toString(16)}function de(t,n,e,r){return r<=0?t=n=e=NaN:e<=0||e>=1?t=n=NaN:n<=0&&(t=NaN),new ye(t,n,e,r)}function pe(t){if(t instanceof ye)return new ye(t.h,t.s,t.l,t.opacity);if(t instanceof Ln||(t=ie(t)),!t)return new ye;if(t instanceof ye)return t;var n=(t=t.rgb()).r/255,e=t.g/255,r=t.b/255,i=Math.min(n,e,r),o=Math.max(n,e,r),a=NaN,u=o-i,c=(o+i)/2;return u?(a=n===o?(e-r)/u+6*(e<r):e===o?(r-n)/u+2:(n-e)/u+4,u/=c<.5?o+i:2-o-i,a*=60):u=c>0&&c<1?0:a,new ye(a,u,c,t.opacity)}function ge(t,n,e,r){return 1===arguments.length?pe(t):new ye(t,n,e,null==r?1:r)}function ye(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function ve(t,n,e){return 255*(t<60?n+(e-n)*t/60:t<180?e:t<240?n+(e-n)*(240-t)/60:n)}Bn(Ln,ie,{copy:function(t){return Object.assign(new this.constructor,this,t)},displayable:function(){return this.rgb().displayable()},hex:ee,formatHex:ee,formatHsl:function(){return pe(this).formatHsl()},formatRgb:re,toString:re}),Bn(fe,ce,Yn(Ln,{brighter:function(t){return t=null==t?Hn:Math.pow(Hn,t),new fe(this.r*t,this.g*t,this.b*t,this.opacity)},darker:function(t){return t=null==t?jn:Math.pow(jn,t),new fe(this.r*t,this.g*t,this.b*t,this.opacity)},rgb:function(){return this},displayable:function(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:se,formatHex:se,formatRgb:le,toString:le})),Bn(ye,ge,Yn(Ln,{brighter:function(t){return t=null==t?Hn:Math.pow(Hn,t),new ye(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?jn:Math.pow(jn,t),new ye(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=this.h%360+360*(this.h<0),n=isNaN(t)||isNaN(this.s)?0:this.s,e=this.l,r=e+(e<.5?e:1-e)*n,i=2*e-r;return new fe(ve(t>=240?t-240:t+120,i,r),ve(t,i,r),ve(t<120?t+240:t-120,i,r),this.opacity)},displayable:function(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl:function(){var t=this.opacity;return(1===(t=isNaN(t)?1:Math.max(0,Math.min(1,t)))?"hsl(":"hsla(")+(this.h||0)+", "+100*(this.s||0)+"%, "+100*(this.l||0)+"%"+(1===t?")":", "+t+")")}}));const _e=Math.PI/180,be=180/Math.PI,me=.96422,xe=.82521,we=4/29,Me=6/29,Ae=3*Me*Me;function Te(t){if(t instanceof Ee)return new Ee(t.l,t.a,t.b,t.opacity);if(t instanceof qe)return Re(t);t instanceof fe||(t=ue(t));var n,e,r=Pe(t.r),i=Pe(t.g),o=Pe(t.b),a=ke((.2225045*r+.7168786*i+.0606169*o)/1);return r===i&&i===o?n=e=a:(n=ke((.4360747*r+.3850649*i+.1430804*o)/me),e=ke((.0139322*r+.0971045*i+.7141733*o)/xe)),new Ee(116*a-16,500*(n-a),200*(a-e),t.opacity)}function Se(t,n,e,r){return 1===arguments.length?Te(t):new Ee(t,n,e,null==r?1:r)}function Ee(t,n,e,r){this.l=+t,this.a=+n,this.b=+e,this.opacity=+r}function ke(t){return t>.008856451679035631?Math.pow(t,1/3):t/Ae+we}function Ne(t){return t>Me?t*t*t:Ae*(t-we)}function Ce(t){return 255*(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)}function Pe(t){return(t/=255)<=.04045?t/12.92:Math.pow((t+.055)/1.055,2.4)}function ze(t){if(t instanceof qe)return new qe(t.h,t.c,t.l,t.opacity);if(t instanceof Ee||(t=Te(t)),0===t.a&&0===t.b)return new qe(NaN,0<t.l&&t.l<100?0:NaN,t.l,t.opacity);var n=Math.atan2(t.b,t.a)*be;return new qe(n<0?n+360:n,Math.sqrt(t.a*t.a+t.b*t.b),t.l,t.opacity)}function De(t,n,e,r){return 1===arguments.length?ze(t):new qe(t,n,e,null==r?1:r)}function qe(t,n,e,r){this.h=+t,this.c=+n,this.l=+e,this.opacity=+r}function Re(t){if(isNaN(t.h))return new Ee(t.l,0,0,t.opacity);var n=t.h*_e;return new Ee(t.l,Math.cos(n)*t.c,Math.sin(n)*t.c,t.opacity)}Bn(Ee,Se,Yn(Ln,{brighter:function(t){return new Ee(this.l+18*(null==t?1:t),this.a,this.b,this.opacity)},darker:function(t){return new Ee(this.l-18*(null==t?1:t),this.a,this.b,this.opacity)},rgb:function(){var t=(this.l+16)/116,n=isNaN(this.a)?t:t+this.a/500,e=isNaN(this.b)?t:t-this.b/200;return new fe(Ce(3.1338561*(n=me*Ne(n))-1.6168667*(t=1*Ne(t))-.4906146*(e=xe*Ne(e))),Ce(-.9787684*n+1.9161415*t+.033454*e),Ce(.0719453*n-.2289914*t+1.4052427*e),this.opacity)}})),Bn(qe,De,Yn(Ln,{brighter:function(t){return new qe(this.h,this.c,this.l+18*(null==t?1:t),this.opacity)},darker:function(t){return new qe(this.h,this.c,this.l-18*(null==t?1:t),this.opacity)},rgb:function(){return Re(this).rgb()}}));var Fe=-.14861,Oe=1.78277,Ue=-.29227,Ie=-.90649,Be=1.97294,Ye=Be*Ie,Le=Be*Oe,je=Oe*Ue-Ie*Fe;function He(t){if(t instanceof Ge)return new Ge(t.h,t.s,t.l,t.opacity);t instanceof fe||(t=ue(t));var n=t.r/255,e=t.g/255,r=t.b/255,i=(je*r+Ye*n-Le*e)/(je+Ye-Le),o=r-i,a=(Be*(e-i)-Ue*o)/Ie,u=Math.sqrt(a*a+o*o)/(Be*i*(1-i)),c=u?Math.atan2(a,o)*be-120:NaN;return new Ge(c<0?c+360:c,u,i,t.opacity)}function Xe(t,n,e,r){return 1===arguments.length?He(t):new Ge(t,n,e,null==r?1:r)}function Ge(t,n,e,r){this.h=+t,this.s=+n,this.l=+e,this.opacity=+r}function Ve(t,n,e,r,i){var o=t*t,a=o*t;return((1-3*t+3*o-a)*n+(4-6*o+3*a)*e+(1+3*t+3*o-3*a)*r+a*i)/6}function $e(t){var n=t.length-1;return function(e){var r=e<=0?e=0:e>=1?(e=1,n-1):Math.floor(e*n),i=t[r],o=t[r+1],a=r>0?t[r-1]:2*i-o,u=r<n-1?t[r+2]:2*o-i;return Ve((e-r/n)*n,a,i,o,u)}}function We(t){var n=t.length;return function(e){var r=Math.floor(((e%=1)<0?++e:e)*n),i=t[(r+n-1)%n],o=t[r%n],a=t[(r+1)%n],u=t[(r+2)%n];return Ve((e-r/n)*n,i,o,a,u)}}Bn(Ge,Xe,Yn(Ln,{brighter:function(t){return t=null==t?Hn:Math.pow(Hn,t),new Ge(this.h,this.s,this.l*t,this.opacity)},darker:function(t){return t=null==t?jn:Math.pow(jn,t),new Ge(this.h,this.s,this.l*t,this.opacity)},rgb:function(){var t=isNaN(this.h)?0:(this.h+120)*_e,n=+this.l,e=isNaN(this.s)?0:this.s*n*(1-n),r=Math.cos(t),i=Math.sin(t);return new fe(255*(n+e*(Fe*r+Oe*i)),255*(n+e*(Ue*r+Ie*i)),255*(n+e*(Be*r)),this.opacity)}}));var Ze=t=>()=>t;function Ke(t,n){return function(e){return t+e*n}}function Qe(t,n){var e=n-t;return e?Ke(t,e>180||e<-180?e-360*Math.round(e/360):e):Ze(isNaN(t)?n:t)}function Je(t){return 1==(t=+t)?tr:function(n,e){return e-n?function(t,n,e){return t=Math.pow(t,e),n=Math.pow(n,e)-t,e=1/e,function(r){return Math.pow(t+r*n,e)}}(n,e,t):Ze(isNaN(n)?e:n)}}function tr(t,n){var e=n-t;return e?Ke(t,e):Ze(isNaN(t)?n:t)}var nr=function t(n){var e=Je(n);function r(t,n){var r=e((t=ce(t)).r,(n=ce(n)).r),i=e(t.g,n.g),o=e(t.b,n.b),a=tr(t.opacity,n.opacity);return function(n){return t.r=r(n),t.g=i(n),t.b=o(n),t.opacity=a(n),t+""}}return r.gamma=t,r}(1);function er(t){return function(n){var e,r,i=n.length,o=new Array(i),a=new Array(i),u=new Array(i);for(e=0;e<i;++e)r=ce(n[e]),o[e]=r.r||0,a[e]=r.g||0,u[e]=r.b||0;return o=t(o),a=t(a),u=t(u),r.opacity=1,function(t){return r.r=o(t),r.g=a(t),r.b=u(t),r+""}}}var rr=er($e),ir=er(We);function or(t,n){n||(n=[]);var e,r=t?Math.min(n.length,t.length):0,i=n.slice();return function(o){for(e=0;e<r;++e)i[e]=t[e]*(1-o)+n[e]*o;return i}}function ar(t){return ArrayBuffer.isView(t)&&!(t instanceof DataView)}function ur(t,n){var e,r=n?n.length:0,i=t?Math.min(r,t.length):0,o=new Array(i),a=new Array(r);for(e=0;e<i;++e)o[e]=pr(t[e],n[e]);for(;e<r;++e)a[e]=n[e];return function(t){for(e=0;e<i;++e)a[e]=o[e](t);return a}}function cr(t,n){var e=new Date;return t=+t,n=+n,function(r){return e.setTime(t*(1-r)+n*r),e}}function fr(t,n){return t=+t,n=+n,function(e){return t*(1-e)+n*e}}function sr(t,n){var e,r={},i={};for(e in null!==t&&"object"==typeof t||(t={}),null!==n&&"object"==typeof n||(n={}),n)e in t?r[e]=pr(t[e],n[e]):i[e]=n[e];return function(t){for(e in r)i[e]=r[e](t);return i}}var lr=/[-+]?(?:\d+\.?\d*|\.?\d+)(?:[eE][-+]?\d+)?/g,hr=new RegExp(lr.source,"g");function dr(t,n){var e,r,i,o=lr.lastIndex=hr.lastIndex=0,a=-1,u=[],c=[];for(t+="",n+="";(e=lr.exec(t))&&(r=hr.exec(n));)(i=r.index)>o&&(i=n.slice(o,i),u[a]?u[a]+=i:u[++a]=i),(e=e[0])===(r=r[0])?u[a]?u[a]+=r:u[++a]=r:(u[++a]=null,c.push({i:a,x:fr(e,r)})),o=hr.lastIndex;return o<n.length&&(i=n.slice(o),u[a]?u[a]+=i:u[++a]=i),u.length<2?c[0]?function(t){return function(n){return t(n)+""}}(c[0].x):function(t){return function(){return t}}(n):(n=c.length,function(t){for(var e,r=0;r<n;++r)u[(e=c[r]).i]=e.x(t);return u.join("")})}function pr(t,n){var e,r=typeof n;return null==n||"boolean"===r?Ze(n):("number"===r?fr:"string"===r?(e=ie(n))?(n=e,nr):dr:n instanceof ie?nr:n instanceof Date?cr:ar(n)?or:Array.isArray(n)?ur:"function"!=typeof n.valueOf&&"function"!=typeof n.toString||isNaN(n)?sr:fr)(t,n)}function gr(t,n){return t=+t,n=+n,function(e){return Math.round(t*(1-e)+n*e)}}var yr,vr=180/Math.PI,_r={translateX:0,translateY:0,rotate:0,skewX:0,scaleX:1,scaleY:1};function br(t,n,e,r,i,o){var a,u,c;return(a=Math.sqrt(t*t+n*n))&&(t/=a,n/=a),(c=t*e+n*r)&&(e-=t*c,r-=n*c),(u=Math.sqrt(e*e+r*r))&&(e/=u,r/=u,c/=u),t*r<n*e&&(t=-t,n=-n,c=-c,a=-a),{translateX:i,translateY:o,rotate:Math.atan2(n,t)*vr,skewX:Math.atan(c)*vr,scaleX:a,scaleY:u}}function mr(t,n,e,r){function i(t){return t.length?t.pop()+" ":""}return function(o,a){var u=[],c=[];return o=t(o),a=t(a),function(t,r,i,o,a,u){if(t!==i||r!==o){var c=a.push("translate(",null,n,null,e);u.push({i:c-4,x:fr(t,i)},{i:c-2,x:fr(r,o)})}else(i||o)&&a.push("translate("+i+n+o+e)}(o.translateX,o.translateY,a.translateX,a.translateY,u,c),function(t,n,e,o){t!==n?(t-n>180?n+=360:n-t>180&&(t+=360),o.push({i:e.push(i(e)+"rotate(",null,r)-2,x:fr(t,n)})):n&&e.push(i(e)+"rotate("+n+r)}(o.rotate,a.rotate,u,c),function(t,n,e,o){t!==n?o.push({i:e.push(i(e)+"skewX(",null,r)-2,x:fr(t,n)}):n&&e.push(i(e)+"skewX("+n+r)}(o.skewX,a.skewX,u,c),function(t,n,e,r,o,a){if(t!==e||n!==r){var u=o.push(i(o)+"scale(",null,",",null,")");a.push({i:u-4,x:fr(t,e)},{i:u-2,x:fr(n,r)})}else 1===e&&1===r||o.push(i(o)+"scale("+e+","+r+")")}(o.scaleX,o.scaleY,a.scaleX,a.scaleY,u,c),o=a=null,function(t){for(var n,e=-1,r=c.length;++e<r;)u[(n=c[e]).i]=n.x(t);return u.join("")}}}var xr=mr((function(t){const n=new("function"==typeof DOMMatrix?DOMMatrix:WebKitCSSMatrix)(t+"");return n.isIdentity?_r:br(n.a,n.b,n.c,n.d,n.e,n.f)}),"px, ","px)","deg)"),wr=mr((function(t){return null==t?_r:(yr||(yr=document.createElementNS("http://www.w3.org/2000/svg","g")),yr.setAttribute("transform",t),(t=yr.transform.baseVal.consolidate())?br((t=t.matrix).a,t.b,t.c,t.d,t.e,t.f):_r)}),", ",")",")");function Mr(t){return((t=Math.exp(t))+1/t)/2}var Ar=function t(n,e,r){function i(t,i){var o,a,u=t[0],c=t[1],f=t[2],s=i[0],l=i[1],h=i[2],d=s-u,p=l-c,g=d*d+p*p;if(g<1e-12)a=Math.log(h/f)/n,o=function(t){return[u+t*d,c+t*p,f*Math.exp(n*t*a)]};else{var y=Math.sqrt(g),v=(h*h-f*f+r*g)/(2*f*e*y),_=(h*h-f*f-r*g)/(2*h*e*y),b=Math.log(Math.sqrt(v*v+1)-v),m=Math.log(Math.sqrt(_*_+1)-_);a=(m-b)/n,o=function(t){var r=t*a,i=Mr(b),o=f/(e*y)*(i*function(t){return((t=Math.exp(2*t))-1)/(t+1)}(n*r+b)-function(t){return((t=Math.exp(t))-1/t)/2}(b));return[u+o*d,c+o*p,f*i/Mr(n*r+b)]}}return o.duration=1e3*a*n/Math.SQRT2,o}return i.rho=function(n){var e=Math.max(.001,+n),r=e*e;return t(e,r,r*r)},i}(Math.SQRT2,2,4);function Tr(t){return function(n,e){var r=t((n=ge(n)).h,(e=ge(e)).h),i=tr(n.s,e.s),o=tr(n.l,e.l),a=tr(n.opacity,e.opacity);return function(t){return n.h=r(t),n.s=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Sr=Tr(Qe),Er=Tr(tr);function kr(t){return function(n,e){var r=t((n=De(n)).h,(e=De(e)).h),i=tr(n.c,e.c),o=tr(n.l,e.l),a=tr(n.opacity,e.opacity);return function(t){return n.h=r(t),n.c=i(t),n.l=o(t),n.opacity=a(t),n+""}}}var Nr=kr(Qe),Cr=kr(tr);function Pr(t){return function n(e){function r(n,r){var i=t((n=Xe(n)).h,(r=Xe(r)).h),o=tr(n.s,r.s),a=tr(n.l,r.l),u=tr(n.opacity,r.opacity);return function(t){return n.h=i(t),n.s=o(t),n.l=a(Math.pow(t,e)),n.opacity=u(t),n+""}}return e=+e,r.gamma=n,r}(1)}var zr=Pr(Qe),Dr=Pr(tr);function qr(t,n){void 0===n&&(n=t,t=pr);for(var e=0,r=n.length-1,i=n[0],o=new Array(r<0?0:r);e<r;)o[e]=t(i,i=n[++e]);return function(t){var n=Math.max(0,Math.min(r-1,Math.floor(t*=r)));return o[n](t-n)}}var Rr,Fr,Or=0,Ur=0,Ir=0,Br=0,Yr=0,Lr=0,jr="object"==typeof performance&&performance.now?performance:Date,Hr="object"==typeof window&&window.requestAnimationFrame?window.requestAnimationFrame.bind(window):function(t){setTimeout(t,17)};function Xr(){return Yr||(Hr(Gr),Yr=jr.now()+Lr)}function Gr(){Yr=0}function Vr(){this._call=this._time=this._next=null}function $r(t,n,e){var r=new Vr;return r.restart(t,n,e),r}function Wr(){Xr(),++Or;for(var t,n=Rr;n;)(t=Yr-n._time)>=0&&n._call.call(null,t),n=n._next;--Or}function Zr(){Yr=(Br=jr.now())+Lr,Or=Ur=0;try{Wr()}finally{Or=0,function(){var t,n,e=Rr,r=1/0;for(;e;)e._call?(r>e._time&&(r=e._time),t=e,e=e._next):(n=e._next,e._next=null,e=t?t._next=n:Rr=n);Fr=t,Qr(r)}(),Yr=0}}function Kr(){var t=jr.now(),n=t-Br;n>1e3&&(Lr-=n,Br=t)}function Qr(t){Or||(Ur&&(Ur=clearTimeout(Ur)),t-Yr>24?(t<1/0&&(Ur=setTimeout(Zr,t-jr.now()-Lr)),Ir&&(Ir=clearInterval(Ir))):(Ir||(Br=jr.now(),Ir=setInterval(Kr,1e3)),Or=1,Hr(Zr)))}function Jr(t,n,e){var r=new Vr;return n=null==n?0:+n,r.restart(e=>{r.stop(),t(e+n)},n,e),r}Vr.prototype=$r.prototype={constructor:Vr,restart:function(t,n,e){if("function"!=typeof t)throw new TypeError("callback is not a function");e=(null==e?Xr():+e)+(null==n?0:+n),this._next||Fr===this||(Fr?Fr._next=this:Rr=this,Fr=this),this._call=t,this._time=e,Qr()},stop:function(){this._call&&(this._call=null,this._time=1/0,Qr())}};var ti=ot("start","end","cancel","interrupt"),ni=[];function ei(t,n,e,r,i,o){var a=t.__transition;if(a){if(e in a)return}else t.__transition={};!function(t,n,e){var r,i=t.__transition;function o(t){e.state=1,e.timer.restart(a,e.delay,e.time),e.delay<=t&&a(t-e.delay)}function a(o){var f,s,l,h;if(1!==e.state)return c();for(f in i)if((h=i[f]).name===e.name){if(3===h.state)return Jr(a);4===h.state?(h.state=6,h.timer.stop(),h.on.call("interrupt",t,t.__data__,h.index,h.group),delete i[f]):+f<n&&(h.state=6,h.timer.stop(),h.on.call("cancel",t,t.__data__,h.index,h.group),delete i[f])}if(Jr((function(){3===e.state&&(e.state=4,e.timer.restart(u,e.delay,e.time),u(o))})),e.state=2,e.on.call("start",t,t.__data__,e.index,e.group),2===e.state){for(e.state=3,r=new Array(l=e.tween.length),f=0,s=-1;f<l;++f)(h=e.tween[f].value.call(t,t.__data__,e.index,e.group))&&(r[++s]=h);r.length=s+1}}function u(n){for(var i=n<e.duration?e.ease.call(null,n/e.duration):(e.timer.restart(c),e.state=5,1),o=-1,a=r.length;++o<a;)r[o].call(t,i);5===e.state&&(e.on.call("end",t,t.__data__,e.index,e.group),c())}function c(){for(var r in e.state=6,e.timer.stop(),delete i[n],i)return;delete t.__transition}i[n]=e,e.timer=$r(o,0,e.time)}(t,e,{name:n,index:r,group:i,on:ti,tween:ni,time:o.time,delay:o.delay,duration:o.duration,ease:o.ease,timer:null,state:0})}function ri(t,n){var e=oi(t,n);if(e.state>0)throw new Error("too late; already scheduled");return e}function ii(t,n){var e=oi(t,n);if(e.state>3)throw new Error("too late; already running");return e}function oi(t,n){var e=t.__transition;if(!e||!(e=e[n]))throw new Error("transition not found");return e}function ai(t,n){var e,r,i,o=t.__transition,a=!0;if(o){for(i in n=null==n?null:n+"",o)(e=o[i]).name===n?(r=e.state>2&&e.state<5,e.state=6,e.timer.stop(),e.on.call(r?"interrupt":"cancel",t,t.__data__,e.index,e.group),delete o[i]):a=!1;a&&delete t.__transition}}function ui(t,n){var e,r;return function(){var i=ii(this,t),o=i.tween;if(o!==e)for(var a=0,u=(r=e=o).length;a<u;++a)if(r[a].name===n){(r=r.slice()).splice(a,1);break}i.tween=r}}function ci(t,n,e){var r,i;if("function"!=typeof e)throw new Error;return function(){var o=ii(this,t),a=o.tween;if(a!==r){i=(r=a).slice();for(var u={name:n,value:e},c=0,f=i.length;c<f;++c)if(i[c].name===n){i[c]=u;break}c===f&&i.push(u)}o.tween=i}}function fi(t,n,e){var r=t._id;return t.each((function(){var t=ii(this,r);(t.value||(t.value={}))[n]=e.apply(this,arguments)})),function(t){return oi(t,r).value[n]}}function si(t,n){var e;return("number"==typeof n?fr:n instanceof ie?nr:(e=ie(n))?(n=e,nr):dr)(t,n)}function li(t){return function(){this.removeAttribute(t)}}function hi(t){return function(){this.removeAttributeNS(t.space,t.local)}}function di(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttribute(t);return a===o?null:a===r?i:i=n(r=a,e)}}function pi(t,n,e){var r,i,o=e+"";return function(){var a=this.getAttributeNS(t.space,t.local);return a===o?null:a===r?i:i=n(r=a,e)}}function gi(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttribute(t))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttribute(t)}}function yi(t,n,e){var r,i,o;return function(){var a,u,c=e(this);if(null!=c)return(a=this.getAttributeNS(t.space,t.local))===(u=c+"")?null:a===r&&u===i?o:(i=u,o=n(r=a,c));this.removeAttributeNS(t.space,t.local)}}function vi(t,n){return function(e){this.setAttribute(t,n.call(this,e))}}function _i(t,n){return function(e){this.setAttributeNS(t.space,t.local,n.call(this,e))}}function bi(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&_i(t,i)),e}return i._value=n,i}function mi(t,n){var e,r;function i(){var i=n.apply(this,arguments);return i!==r&&(e=(r=i)&&vi(t,i)),e}return i._value=n,i}function xi(t,n){return function(){ri(this,t).delay=+n.apply(this,arguments)}}function wi(t,n){return n=+n,function(){ri(this,t).delay=n}}function Mi(t,n){return function(){ii(this,t).duration=+n.apply(this,arguments)}}function Ai(t,n){return n=+n,function(){ii(this,t).duration=n}}function Ti(t,n){if("function"!=typeof n)throw new Error;return function(){ii(this,t).ease=n}}function Si(t,n,e){var r,i,o=function(t){return(t+"").trim().split(/^|\s+/).every((function(t){var n=t.indexOf(".");return n>=0&&(t=t.slice(0,n)),!t||"start"===t}))}(n)?ri:ii;return function(){var a=o(this,t),u=a.on;u!==r&&(i=(r=u).copy()).on(n,e),a.on=i}}var Ei=Mn.prototype.constructor;function ki(t){return function(){this.style.removeProperty(t)}}function Ni(t,n,e){return function(r){this.style.setProperty(t,n.call(this,r),e)}}function Ci(t,n,e){var r,i;function o(){var o=n.apply(this,arguments);return o!==i&&(r=(i=o)&&Ni(t,o,e)),r}return o._value=n,o}function Pi(t){return function(n){this.textContent=t.call(this,n)}}function zi(t){var n,e;function r(){var r=t.apply(this,arguments);return r!==e&&(n=(e=r)&&Pi(r)),n}return r._value=t,r}var Di=0;function qi(t,n,e,r){this._groups=t,this._parents=n,this._name=e,this._id=r}function Ri(t){return Mn().transition(t)}function Fi(){return++Di}var Oi=Mn.prototype;qi.prototype=Ri.prototype={constructor:qi,select:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=vt(t));for(var r=this._groups,i=r.length,o=new Array(i),a=0;a<i;++a)for(var u,c,f=r[a],s=f.length,l=o[a]=new Array(s),h=0;h<s;++h)(u=f[h])&&(c=t.call(u,u.__data__,h,f))&&("__data__"in u&&(c.__data__=u.__data__),l[h]=c,ei(l[h],n,e,h,l,oi(u,e)));return new qi(o,this._parents,n,e)},selectAll:function(t){var n=this._name,e=this._id;"function"!=typeof t&&(t=mt(t));for(var r=this._groups,i=r.length,o=[],a=[],u=0;u<i;++u)for(var c,f=r[u],s=f.length,l=0;l<s;++l)if(c=f[l]){for(var h,d=t.call(c,c.__data__,l,f),p=oi(c,e),g=0,y=d.length;g<y;++g)(h=d[g])&&ei(h,n,e,g,d,p);o.push(d),a.push(c)}return new qi(o,a,n,e)},filter:function(t){"function"!=typeof t&&(t=xt(t));for(var n=this._groups,e=n.length,r=new Array(e),i=0;i<e;++i)for(var o,a=n[i],u=a.length,c=r[i]=[],f=0;f<u;++f)(o=a[f])&&t.call(o,o.__data__,f,a)&&c.push(o);return new qi(r,this._parents,this._name,this._id)},merge:function(t){if(t._id!==this._id)throw new Error;for(var n=this._groups,e=t._groups,r=n.length,i=e.length,o=Math.min(r,i),a=new Array(r),u=0;u<o;++u)for(var c,f=n[u],s=e[u],l=f.length,h=a[u]=new Array(l),d=0;d<l;++d)(c=f[d]||s[d])&&(h[d]=c);for(;u<r;++u)a[u]=n[u];return new qi(a,this._parents,this._name,this._id)},selection:function(){return new Ei(this._groups,this._parents)},transition:function(){for(var t=this._name,n=this._id,e=Fi(),r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)if(a=u[f]){var s=oi(a,n);ei(a,t,e,f,u,{time:s.time+s.delay+s.duration,delay:0,duration:s.duration,ease:s.ease})}return new qi(r,this._parents,t,e)},call:Oi.call,nodes:Oi.nodes,node:Oi.node,size:Oi.size,empty:Oi.empty,each:Oi.each,on:function(t,n){var e=this._id;return arguments.length<2?oi(this.node(),e).on.on(t):this.each(Si(e,t,n))},attr:function(t,n){var e=ht(t),r="transform"===e?wr:si;return this.attrTween(t,"function"==typeof n?(e.local?yi:gi)(e,r,fi(this,"attr."+t,n)):null==n?(e.local?hi:li)(e):(e.local?pi:di)(e,r,n))},attrTween:function(t,n){var e="attr."+t;if(arguments.length<2)return(e=this.tween(e))&&e._value;if(null==n)return this.tween(e,null);if("function"!=typeof n)throw new Error;var r=ht(t);return this.tween(e,(r.local?bi:mi)(r,n))},style:function(t,n,e){var r="transform"==(t+="")?xr:si;return null==n?this.styleTween(t,function(t,n){var e,r,i;return function(){var o=Ht(this,t),a=(this.style.removeProperty(t),Ht(this,t));return o===a?null:o===e&&a===r?i:i=n(e=o,r=a)}}(t,r)).on("end.style."+t,ki(t)):"function"==typeof n?this.styleTween(t,function(t,n,e){var r,i,o;return function(){var a=Ht(this,t),u=e(this),c=u+"";return null==u&&(this.style.removeProperty(t),c=u=Ht(this,t)),a===c?null:a===r&&c===i?o:(i=c,o=n(r=a,u))}}(t,r,fi(this,"style."+t,n))).each(function(t,n){var e,r,i,o,a="style."+n,u="end."+a;return function(){var c=ii(this,t),f=c.on,s=null==c.value[a]?o||(o=ki(n)):void 0;f===e&&i===s||(r=(e=f).copy()).on(u,i=s),c.on=r}}(this._id,t)):this.styleTween(t,function(t,n,e){var r,i,o=e+"";return function(){var a=Ht(this,t);return a===o?null:a===r?i:i=n(r=a,e)}}(t,r,n),e).on("end.style."+t,null)},styleTween:function(t,n,e){var r="style."+(t+="");if(arguments.length<2)return(r=this.tween(r))&&r._value;if(null==n)return this.tween(r,null);if("function"!=typeof n)throw new Error;return this.tween(r,Ci(t,n,null==e?"":e))},text:function(t){return this.tween("text","function"==typeof t?function(t){return function(){var n=t(this);this.textContent=null==n?"":n}}(fi(this,"text",t)):function(t){return function(){this.textContent=t}}(null==t?"":t+""))},textTween:function(t){var n="text";if(arguments.length<1)return(n=this.tween(n))&&n._value;if(null==t)return this.tween(n,null);if("function"!=typeof t)throw new Error;return this.tween(n,zi(t))},remove:function(){return this.on("end.remove",function(t){return function(){var n=this.parentNode;for(var e in this.__transition)if(+e!==t)return;n&&n.removeChild(this)}}(this._id))},tween:function(t,n){var e=this._id;if(t+="",arguments.length<2){for(var r,i=oi(this.node(),e).tween,o=0,a=i.length;o<a;++o)if((r=i[o]).name===t)return r.value;return null}return this.each((null==n?ui:ci)(e,t,n))},delay:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?xi:wi)(n,t)):oi(this.node(),n).delay},duration:function(t){var n=this._id;return arguments.length?this.each(("function"==typeof t?Mi:Ai)(n,t)):oi(this.node(),n).duration},ease:function(t){var n=this._id;return arguments.length?this.each(Ti(n,t)):oi(this.node(),n).ease},easeVarying:function(t){if("function"!=typeof t)throw new Error;return this.each(function(t,n){return function(){var e=n.apply(this,arguments);if("function"!=typeof e)throw new Error;ii(this,t).ease=e}}(this._id,t))},end:function(){var t,n,e=this,r=e._id,i=e.size();return new Promise((function(o,a){var u={value:a},c={value:function(){0==--i&&o()}};e.each((function(){var e=ii(this,r),i=e.on;i!==t&&((n=(t=i).copy())._.cancel.push(u),n._.interrupt.push(u),n._.end.push(c)),e.on=n})),0===i&&o()}))},[Symbol.iterator]:Oi[Symbol.iterator]};function Ui(t){return((t*=2)<=1?t*t:--t*(2-t)+1)/2}function Ii(t){return((t*=2)<=1?t*t*t:(t-=2)*t*t+2)/2}var Bi=function t(n){function e(t){return Math.pow(t,n)}return n=+n,e.exponent=t,e}(3),Yi=function t(n){function e(t){return 1-Math.pow(1-t,n)}return n=+n,e.exponent=t,e}(3),Li=function t(n){function e(t){return((t*=2)<=1?Math.pow(t,n):2-Math.pow(2-t,n))/2}return n=+n,e.exponent=t,e}(3),ji=Math.PI,Hi=ji/2;function Xi(t){return(1-Math.cos(ji*t))/2}function Gi(t){return 1.0009775171065494*(Math.pow(2,-10*t)-.0009765625)}function Vi(t){return((t*=2)<=1?Gi(1-t):2-Gi(t-1))/2}function $i(t){return((t*=2)<=1?1-Math.sqrt(1-t*t):Math.sqrt(1-(t-=2)*t)+1)/2}var Wi=4/11,Zi=7.5625;function Ki(t){return(t=+t)<Wi?Zi*t*t:t<.7272727272727273?Zi*(t-=.5454545454545454)*t+.75:t<.9090909090909091?Zi*(t-=.8181818181818182)*t+.9375:Zi*(t-=.9545454545454546)*t+.984375}var Qi=1.70158,Ji=function t(n){function e(t){return(t=+t)*t*(n*(t-1)+t)}return n=+n,e.overshoot=t,e}(Qi),to=function t(n){function e(t){return--t*t*((t+1)*n+t)+1}return n=+n,e.overshoot=t,e}(Qi),no=function t(n){function e(t){return((t*=2)<1?t*t*((n+1)*t-n):(t-=2)*t*((n+1)*t+n)+2)/2}return n=+n,e.overshoot=t,e}(Qi),eo=2*Math.PI,ro=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=eo);function i(t){return n*Gi(- --t)*Math.sin((r-t)/e)}return i.amplitude=function(n){return t(n,e*eo)},i.period=function(e){return t(n,e)},i}(1,.3),io=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=eo);function i(t){return 1-n*Gi(t=+t)*Math.sin((t+r)/e)}return i.amplitude=function(n){return t(n,e*eo)},i.period=function(e){return t(n,e)},i}(1,.3),oo=function t(n,e){var r=Math.asin(1/(n=Math.max(1,n)))*(e/=eo);function i(t){return((t=2*t-1)<0?n*Gi(-t)*Math.sin((r-t)/e):2-n*Gi(t)*Math.sin((r+t)/e))/2}return i.amplitude=function(n){return t(n,e*eo)},i.period=function(e){return t(n,e)},i}(1,.3),ao={time:null,delay:0,duration:250,ease:Ii};function uo(t,n){for(var e;!(e=t.__transition)||!(e=e[n]);)if(!(t=t.parentNode))throw new Error(`transition ${n} not found`);return e}Mn.prototype.interrupt=function(t){return this.each((function(){ai(this,t)}))},Mn.prototype.transition=function(t){var n,e;t instanceof qi?(n=t._id,t=t._name):(n=Fi(),(e=ao).time=Xr(),t=null==t?null:t+"");for(var r=this._groups,i=r.length,o=0;o<i;++o)for(var a,u=r[o],c=u.length,f=0;f<c;++f)(a=u[f])&&ei(a,t,n,f,u,e||uo(a,n));return new qi(r,this._parents,t,n)};var co=[null];var fo=t=>()=>t;function so(t,{sourceEvent:n,target:e,selection:r,mode:i,dispatch:o}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},selection:{value:r,enumerable:!0,configurable:!0},mode:{value:i,enumerable:!0,configurable:!0},_:{value:o}})}function lo(t){t.stopImmediatePropagation()}function ho(t){t.preventDefault(),t.stopImmediatePropagation()}var po={name:"drag"},go={name:"space"},yo={name:"handle"},vo={name:"center"};const{abs:_o,max:bo,min:mo}=Math;function xo(t){return[+t[0],+t[1]]}function wo(t){return[xo(t[0]),xo(t[1])]}var Mo={name:"x",handles:["w","e"].map(Po),input:function(t,n){return null==t?null:[[+t[0],n[0][1]],[+t[1],n[1][1]]]},output:function(t){return t&&[t[0][0],t[1][0]]}},Ao={name:"y",handles:["n","s"].map(Po),input:function(t,n){return null==t?null:[[n[0][0],+t[0]],[n[1][0],+t[1]]]},output:function(t){return t&&[t[0][1],t[1][1]]}},To={name:"xy",handles:["n","w","e","s","nw","ne","sw","se"].map(Po),input:function(t){return null==t?null:wo(t)},output:function(t){return t}},So={overlay:"crosshair",selection:"move",n:"ns-resize",e:"ew-resize",s:"ns-resize",w:"ew-resize",nw:"nwse-resize",ne:"nesw-resize",se:"nwse-resize",sw:"nesw-resize"},Eo={e:"w",w:"e",nw:"ne",ne:"nw",se:"sw",sw:"se"},ko={n:"s",s:"n",nw:"sw",ne:"se",se:"ne",sw:"nw"},No={overlay:1,selection:1,n:null,e:1,s:null,w:-1,nw:-1,ne:1,se:1,sw:-1},Co={overlay:1,selection:1,n:-1,e:null,s:1,w:null,nw:-1,ne:-1,se:1,sw:1};function Po(t){return{type:t}}function zo(t){return!t.ctrlKey&&!t.button}function Do(){var t=this.ownerSVGElement||this;return t.hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]}function qo(){return navigator.maxTouchPoints||"ontouchstart"in this}function Ro(t){for(;!t.__brush;)if(!(t=t.parentNode))return;return t.__brush}function Fo(t){return t[0][0]===t[1][0]||t[0][1]===t[1][1]}function Oo(t){var n,e=Do,r=zo,i=qo,o=!0,a=ot("start","brush","end"),u=6;function c(n){var e=n.property("__brush",g).selectAll(".overlay").data([Po("overlay")]);e.enter().append("rect").attr("class","overlay").attr("pointer-events","all").attr("cursor",So.overlay).merge(e).each((function(){var t=Ro(this).extent;An(this).attr("x",t[0][0]).attr("y",t[0][1]).attr("width",t[1][0]-t[0][0]).attr("height",t[1][1]-t[0][1])})),n.selectAll(".selection").data([Po("selection")]).enter().append("rect").attr("class","selection").attr("cursor",So.selection).attr("fill","#777").attr("fill-opacity",.3).attr("stroke","#fff").attr("shape-rendering","crispEdges");var r=n.selectAll(".handle").data(t.handles,(function(t){return t.type}));r.exit().remove(),r.enter().append("rect").attr("class",(function(t){return"handle handle--"+t.type})).attr("cursor",(function(t){return So[t.type]})),n.each(f).attr("fill","none").attr("pointer-events","all").on("mousedown.brush",h).filter(i).on("touchstart.brush",h).on("touchmove.brush",d).on("touchend.brush touchcancel.brush",p).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function f(){var t=An(this),n=Ro(this).selection;n?(t.selectAll(".selection").style("display",null).attr("x",n[0][0]).attr("y",n[0][1]).attr("width",n[1][0]-n[0][0]).attr("height",n[1][1]-n[0][1]),t.selectAll(".handle").style("display",null).attr("x",(function(t){return"e"===t.type[t.type.length-1]?n[1][0]-u/2:n[0][0]-u/2})).attr("y",(function(t){return"s"===t.type[0]?n[1][1]-u/2:n[0][1]-u/2})).attr("width",(function(t){return"n"===t.type||"s"===t.type?n[1][0]-n[0][0]+u:u})).attr("height",(function(t){return"e"===t.type||"w"===t.type?n[1][1]-n[0][1]+u:u}))):t.selectAll(".selection,.handle").style("display","none").attr("x",null).attr("y",null).attr("width",null).attr("height",null)}function s(t,n,e){var r=t.__brush.emitter;return!r||e&&r.clean?new l(t,n,e):r}function l(t,n,e){this.that=t,this.args=n,this.state=t.__brush,this.active=0,this.clean=e}function h(e){if((!n||e.touches)&&r.apply(this,arguments)){var i,a,u,c,l,h,d,p,g,y,v,_=this,b=e.target.__data__.type,m="selection"===(o&&e.metaKey?b="overlay":b)?po:o&&e.altKey?vo:yo,x=t===Ao?null:No[b],w=t===Mo?null:Co[b],M=Ro(_),A=M.extent,T=M.selection,S=A[0][0],E=A[0][1],k=A[1][0],N=A[1][1],C=0,P=0,z=x&&w&&o&&e.shiftKey,D=Array.from(e.touches||[e],t=>{const n=t.identifier;return(t=Nn(t,_)).point0=t.slice(),t.identifier=n,t});if("overlay"===b){T&&(g=!0);const n=[D[0],D[1]||D[0]];M.selection=T=[[i=t===Ao?S:mo(n[0][0],n[1][0]),u=t===Mo?E:mo(n[0][1],n[1][1])],[l=t===Ao?k:bo(n[0][0],n[1][0]),d=t===Mo?N:bo(n[0][1],n[1][1])]],D.length>1&&I()}else i=T[0][0],u=T[0][1],l=T[1][0],d=T[1][1];a=i,c=u,h=l,p=d;var q=An(_).attr("pointer-events","none"),R=q.selectAll(".overlay").attr("cursor",So[b]);ai(_);var F=s(_,arguments,!0).beforestart();if(e.touches)F.moved=U,F.ended=B;else{var O=An(e.view).on("mousemove.brush",U,!0).on("mouseup.brush",B,!0);o&&O.on("keydown.brush",Y,!0).on("keyup.brush",L,!0),zn(e.view)}f.call(_),F.start(e,m.name)}function U(t){for(const n of t.changedTouches||[t])for(const t of D)t.identifier===n.identifier&&(t.cur=Nn(n,_));if(z&&!y&&!v&&1===D.length){const t=D[0];_o(t.cur[0]-t[0])>_o(t.cur[1]-t[1])?v=!0:y=!0}for(const t of D)t.cur&&(t[0]=t.cur[0],t[1]=t.cur[1]);g=!0,ho(t),I(t)}function I(t){const n=D[0],e=n.point0;var r;switch(C=n[0]-e[0],P=n[1]-e[1],m){case go:case po:x&&(C=bo(S-i,mo(k-l,C)),a=i+C,h=l+C),w&&(P=bo(E-u,mo(N-d,P)),c=u+P,p=d+P);break;case yo:D[1]?(x&&(a=bo(S,mo(k,D[0][0])),h=bo(S,mo(k,D[1][0])),x=1),w&&(c=bo(E,mo(N,D[0][1])),p=bo(E,mo(N,D[1][1])),w=1)):(x<0?(C=bo(S-i,mo(k-i,C)),a=i+C,h=l):x>0&&(C=bo(S-l,mo(k-l,C)),a=i,h=l+C),w<0?(P=bo(E-u,mo(N-u,P)),c=u+P,p=d):w>0&&(P=bo(E-d,mo(N-d,P)),c=u,p=d+P));break;case vo:x&&(a=bo(S,mo(k,i-C*x)),h=bo(S,mo(k,l+C*x))),w&&(c=bo(E,mo(N,u-P*w)),p=bo(E,mo(N,d+P*w)))}h<a&&(x*=-1,r=i,i=l,l=r,r=a,a=h,h=r,b in Eo&&R.attr("cursor",So[b=Eo[b]])),p<c&&(w*=-1,r=u,u=d,d=r,r=c,c=p,p=r,b in ko&&R.attr("cursor",So[b=ko[b]])),M.selection&&(T=M.selection),y&&(a=T[0][0],h=T[1][0]),v&&(c=T[0][1],p=T[1][1]),T[0][0]===a&&T[0][1]===c&&T[1][0]===h&&T[1][1]===p||(M.selection=[[a,c],[h,p]],f.call(_),F.brush(t,m.name))}function B(t){if(lo(t),t.touches){if(t.touches.length)return;n&&clearTimeout(n),n=setTimeout((function(){n=null}),500)}else Dn(t.view,g),O.on("keydown.brush keyup.brush mousemove.brush mouseup.brush",null);q.attr("pointer-events","all"),R.attr("cursor",So.overlay),M.selection&&(T=M.selection),Fo(T)&&(M.selection=null,f.call(_)),F.end(t,m.name)}function Y(t){switch(t.keyCode){case 16:z=x&&w;break;case 18:m===yo&&(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=vo,I());break;case 32:m!==yo&&m!==vo||(x<0?l=h-C:x>0&&(i=a-C),w<0?d=p-P:w>0&&(u=c-P),m=go,R.attr("cursor",So.selection),I());break;default:return}ho(t)}function L(t){switch(t.keyCode){case 16:z&&(y=v=z=!1,I());break;case 18:m===vo&&(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=yo,I());break;case 32:m===go&&(t.altKey?(x&&(l=h-C*x,i=a+C*x),w&&(d=p-P*w,u=c+P*w),m=vo):(x<0?l=h:x>0&&(i=a),w<0?d=p:w>0&&(u=c),m=yo),R.attr("cursor",So[b]),I());break;default:return}ho(t)}}function d(t){s(this,arguments).moved(t)}function p(t){s(this,arguments).ended(t)}function g(){var n=this.__brush||{selection:null};return n.extent=wo(e.apply(this,arguments)),n.dim=t,n}return c.move=function(n,e){n.tween?n.on("start.brush",(function(t){s(this,arguments).beforestart().start(t)})).on("interrupt.brush end.brush",(function(t){s(this,arguments).end(t)})).tween("brush",(function(){var n=this,r=n.__brush,i=s(n,arguments),o=r.selection,a=t.input("function"==typeof e?e.apply(this,arguments):e,r.extent),u=pr(o,a);function c(t){r.selection=1===t&&null===a?null:u(t),f.call(n),i.brush()}return null!==o&&null!==a?c:c(1)})):n.each((function(){var n=this,r=arguments,i=n.__brush,o=t.input("function"==typeof e?e.apply(n,r):e,i.extent),a=s(n,r).beforestart();ai(n),i.selection=null===o?null:o,f.call(n),a.start().brush().end()}))},c.clear=function(t){c.move(t,null)},l.prototype={beforestart:function(){return 1==++this.active&&(this.state.emitter=this,this.starting=!0),this},start:function(t,n){return this.starting?(this.starting=!1,this.emit("start",t,n)):this.emit("brush",t),this},brush:function(t,n){return this.emit("brush",t,n),this},end:function(t,n){return 0==--this.active&&(delete this.state.emitter,this.emit("end",t,n)),this},emit:function(n,e,r){var i=An(this.that).datum();a.call(n,this.that,new so(n,{sourceEvent:e,target:c,selection:t.output(this.state.selection),mode:r,dispatch:a}),i)}},c.extent=function(t){return arguments.length?(e="function"==typeof t?t:fo(wo(t)),c):e},c.filter=function(t){return arguments.length?(r="function"==typeof t?t:fo(!!t),c):r},c.touchable=function(t){return arguments.length?(i="function"==typeof t?t:fo(!!t),c):i},c.handleSize=function(t){return arguments.length?(u=+t,c):u},c.keyModifiers=function(t){return arguments.length?(o=!!t,c):o},c.on=function(){var t=a.on.apply(a,arguments);return t===a?c:t},c}var Uo=Math.abs,Io=Math.cos,Bo=Math.sin,Yo=Math.PI,Lo=Yo/2,jo=2*Yo,Ho=Math.max,Xo=1e-12;function Go(t,n){return Array.from({length:n-t},(n,e)=>t+e)}function Vo(t){return function(n,e){return t(n.source.value+n.target.value,e.source.value+e.target.value)}}function $o(t,n){var e=0,r=null,i=null,o=null;function a(a){var u,c=a.length,f=new Array(c),s=Go(0,c),l=new Array(c*c),h=new Array(c),d=0;a=Float64Array.from({length:c*c},n?(t,n)=>a[n%c][n/c|0]:(t,n)=>a[n/c|0][n%c]);for(let n=0;n<c;++n){let e=0;for(let r=0;r<c;++r)e+=a[n*c+r]+t*a[r*c+n];d+=f[n]=e}u=(d=Ho(0,jo-e*c)/d)?e:jo/c;{let n=0;r&&s.sort((t,n)=>r(f[t],f[n]));for(const e of s){const r=n;if(t){const t=Go(1+~c,c).filter(t=>t<0?a[~t*c+e]:a[e*c+t]);i&&t.sort((t,n)=>i(t<0?-a[~t*c+e]:a[e*c+t],n<0?-a[~n*c+e]:a[e*c+n]));for(const r of t)if(r<0){(l[~r*c+e]||(l[~r*c+e]={source:null,target:null})).target={index:e,startAngle:n,endAngle:n+=a[~r*c+e]*d,value:a[~r*c+e]}}else{(l[e*c+r]||(l[e*c+r]={source:null,target:null})).source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}else{const t=Go(0,c).filter(t=>a[e*c+t]||a[t*c+e]);i&&t.sort((t,n)=>i(a[e*c+t],a[e*c+n]));for(const r of t){let t;if(e<r?(t=l[e*c+r]||(l[e*c+r]={source:null,target:null}),t.source={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]}):(t=l[r*c+e]||(l[r*c+e]={source:null,target:null}),t.target={index:e,startAngle:n,endAngle:n+=a[e*c+r]*d,value:a[e*c+r]},e===r&&(t.source=t.target)),t.source&&t.target&&t.source.value<t.target.value){const n=t.source;t.source=t.target,t.target=n}}h[e]={index:e,startAngle:r,endAngle:n,value:f[e]}}n+=u}}return(l=Object.values(l)).groups=h,o?l.sort(o):l}return a.padAngle=function(t){return arguments.length?(e=Ho(0,t),a):e},a.sortGroups=function(t){return arguments.length?(r=t,a):r},a.sortSubgroups=function(t){return arguments.length?(i=t,a):i},a.sortChords=function(t){return arguments.length?(null==t?o=null:(o=Vo(t))._=t,a):o&&o._},a}const Wo=Math.PI,Zo=2*Wo,Ko=1e-6,Qo=Zo-Ko;function Jo(){this._x0=this._y0=this._x1=this._y1=null,this._=""}function ta(){return new Jo}Jo.prototype=ta.prototype={constructor:Jo,moveTo:function(t,n){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)},closePath:function(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")},lineTo:function(t,n){this._+="L"+(this._x1=+t)+","+(this._y1=+n)},quadraticCurveTo:function(t,n,e,r){this._+="Q"+ +t+","+ +n+","+(this._x1=+e)+","+(this._y1=+r)},bezierCurveTo:function(t,n,e,r,i,o){this._+="C"+ +t+","+ +n+","+ +e+","+ +r+","+(this._x1=+i)+","+(this._y1=+o)},arcTo:function(t,n,e,r,i){t=+t,n=+n,e=+e,r=+r,i=+i;var o=this._x1,a=this._y1,u=e-t,c=r-n,f=o-t,s=a-n,l=f*f+s*s;if(i<0)throw new Error("negative radius: "+i);if(null===this._x1)this._+="M"+(this._x1=t)+","+(this._y1=n);else if(l>Ko)if(Math.abs(s*u-c*f)>Ko&&i){var h=e-o,d=r-a,p=u*u+c*c,g=h*h+d*d,y=Math.sqrt(p),v=Math.sqrt(l),_=i*Math.tan((Wo-Math.acos((p+l-g)/(2*y*v)))/2),b=_/v,m=_/y;Math.abs(b-1)>Ko&&(this._+="L"+(t+b*f)+","+(n+b*s)),this._+="A"+i+","+i+",0,0,"+ +(s*h>f*d)+","+(this._x1=t+m*u)+","+(this._y1=n+m*c)}else this._+="L"+(this._x1=t)+","+(this._y1=n);else;},arc:function(t,n,e,r,i,o){t=+t,n=+n,o=!!o;var a=(e=+e)*Math.cos(r),u=e*Math.sin(r),c=t+a,f=n+u,s=1^o,l=o?r-i:i-r;if(e<0)throw new Error("negative radius: "+e);null===this._x1?this._+="M"+c+","+f:(Math.abs(this._x1-c)>Ko||Math.abs(this._y1-f)>Ko)&&(this._+="L"+c+","+f),e&&(l<0&&(l=l%Zo+Zo),l>Qo?this._+="A"+e+","+e+",0,1,"+s+","+(t-a)+","+(n-u)+"A"+e+","+e+",0,1,"+s+","+(this._x1=c)+","+(this._y1=f):l>Ko&&(this._+="A"+e+","+e+",0,"+ +(l>=Wo)+","+s+","+(this._x1=t+e*Math.cos(i))+","+(this._y1=n+e*Math.sin(i))))},rect:function(t,n,e,r){this._+="M"+(this._x0=this._x1=+t)+","+(this._y0=this._y1=+n)+"h"+ +e+"v"+ +r+"h"+-e+"Z"},toString:function(){return this._}};var na=Array.prototype.slice;function ea(t){return function(){return t}}function ra(t){return t.source}function ia(t){return t.target}function oa(t){return t.radius}function aa(t){return t.startAngle}function ua(t){return t.endAngle}function ca(){return 0}function fa(){return 10}function sa(t){var n=ra,e=ia,r=oa,i=oa,o=aa,a=ua,u=ca,c=null;function f(){var f,s=n.apply(this,arguments),l=e.apply(this,arguments),h=u.apply(this,arguments)/2,d=na.call(arguments),p=+r.apply(this,(d[0]=s,d)),g=o.apply(this,d)-Lo,y=a.apply(this,d)-Lo,v=+i.apply(this,(d[0]=l,d)),_=o.apply(this,d)-Lo,b=a.apply(this,d)-Lo;if(c||(c=f=ta()),h>Xo&&(Uo(y-g)>2*h+Xo?y>g?(g+=h,y-=h):(g-=h,y+=h):g=y=(g+y)/2,Uo(b-_)>2*h+Xo?b>_?(_+=h,b-=h):(_-=h,b+=h):_=b=(_+b)/2),c.moveTo(p*Io(g),p*Bo(g)),c.arc(0,0,p,g,y),g!==_||y!==b)if(t){var m=+t.apply(this,arguments),x=v-m,w=(_+b)/2;c.quadraticCurveTo(0,0,x*Io(_),x*Bo(_)),c.lineTo(v*Io(w),v*Bo(w)),c.lineTo(x*Io(b),x*Bo(b))}else c.quadraticCurveTo(0,0,v*Io(_),v*Bo(_)),c.arc(0,0,v,_,b);if(c.quadraticCurveTo(0,0,p*Io(g),p*Bo(g)),c.closePath(),f)return c=null,f+""||null}return t&&(f.headRadius=function(n){return arguments.length?(t="function"==typeof n?n:ea(+n),f):t}),f.radius=function(t){return arguments.length?(r=i="function"==typeof t?t:ea(+t),f):r},f.sourceRadius=function(t){return arguments.length?(r="function"==typeof t?t:ea(+t),f):r},f.targetRadius=function(t){return arguments.length?(i="function"==typeof t?t:ea(+t),f):i},f.startAngle=function(t){return arguments.length?(o="function"==typeof t?t:ea(+t),f):o},f.endAngle=function(t){return arguments.length?(a="function"==typeof t?t:ea(+t),f):a},f.padAngle=function(t){return arguments.length?(u="function"==typeof t?t:ea(+t),f):u},f.source=function(t){return arguments.length?(n=t,f):n},f.target=function(t){return arguments.length?(e=t,f):e},f.context=function(t){return arguments.length?(c=null==t?null:t,f):c},f}var la=Array.prototype.slice;function ha(t,n){return t-n}var da=t=>()=>t;function pa(t,n){for(var e,r=-1,i=n.length;++r<i;)if(e=ga(t,n[r]))return e;return 0}function ga(t,n){for(var e=n[0],r=n[1],i=-1,o=0,a=t.length,u=a-1;o<a;u=o++){var c=t[o],f=c[0],s=c[1],l=t[u],h=l[0],d=l[1];if(ya(c,l,n))return 0;s>r!=d>r&&e<(h-f)*(r-s)/(d-s)+f&&(i=-i)}return i}function ya(t,n,e){var r,i,o,a;return function(t,n,e){return(n[0]-t[0])*(e[1]-t[1])==(e[0]-t[0])*(n[1]-t[1])}(t,n,e)&&(i=t[r=+(t[0]===n[0])],o=e[r],a=n[r],i<=o&&o<=a||a<=o&&o<=i)}function va(){}var _a=[[],[[[1,1.5],[.5,1]]],[[[1.5,1],[1,1.5]]],[[[1.5,1],[.5,1]]],[[[1,.5],[1.5,1]]],[[[1,1.5],[.5,1]],[[1,.5],[1.5,1]]],[[[1,.5],[1,1.5]]],[[[1,.5],[.5,1]]],[[[.5,1],[1,.5]]],[[[1,1.5],[1,.5]]],[[[.5,1],[1,.5]],[[1.5,1],[1,1.5]]],[[[1.5,1],[1,.5]]],[[[.5,1],[1.5,1]]],[[[1,1.5],[1.5,1]]],[[[.5,1],[1,1.5]]],[]];function ba(){var t=1,n=1,e=k,r=u;function i(t){var n=e(t);if(Array.isArray(n))n=n.slice().sort(ha);else{var r=p(t),i=r[0],a=r[1];n=S(i,a,n),n=Y(Math.floor(i/n)*n,Math.floor(a/n)*n,n)}return n.map((function(n){return o(t,n)}))}function o(e,i){var o=[],u=[];return function(e,r,i){var o,u,c,f,s,l,h=new Array,d=new Array;o=u=-1,f=e[0]>=r,_a[f<<1].forEach(p);for(;++o<t-1;)c=f,f=e[o+1]>=r,_a[c|f<<1].forEach(p);_a[f<<0].forEach(p);for(;++u<n-1;){for(o=-1,f=e[u*t+t]>=r,s=e[u*t]>=r,_a[f<<1|s<<2].forEach(p);++o<t-1;)c=f,f=e[u*t+t+o+1]>=r,l=s,s=e[u*t+o+1]>=r,_a[c|f<<1|s<<2|l<<3].forEach(p);_a[f|s<<3].forEach(p)}o=-1,s=e[u*t]>=r,_a[s<<2].forEach(p);for(;++o<t-1;)l=s,s=e[u*t+o+1]>=r,_a[s<<2|l<<3].forEach(p);function p(t){var n,e,r=[t[0][0]+o,t[0][1]+u],c=[t[1][0]+o,t[1][1]+u],f=a(r),s=a(c);(n=d[f])?(e=h[s])?(delete d[n.end],delete h[e.start],n===e?(n.ring.push(c),i(n.ring)):h[n.start]=d[e.end]={start:n.start,end:e.end,ring:n.ring.concat(e.ring)}):(delete d[n.end],n.ring.push(c),d[n.end=s]=n):(n=h[s])?(e=d[f])?(delete h[n.start],delete d[e.end],n===e?(n.ring.push(c),i(n.ring)):h[e.start]=d[n.end]={start:e.start,end:n.end,ring:e.ring.concat(n.ring)}):(delete h[n.start],n.ring.unshift(r),h[n.start=f]=n):h[f]=d[s]={start:f,end:s,ring:[r,c]}}_a[s<<3].forEach(p)}(e,i,(function(t){r(t,e,i),function(t){for(var n=0,e=t.length,r=t[e-1][1]*t[0][0]-t[e-1][0]*t[0][1];++n<e;)r+=t[n-1][1]*t[n][0]-t[n-1][0]*t[n][1];return r}(t)>0?o.push([t]):u.push(t)})),u.forEach((function(t){for(var n,e=0,r=o.length;e<r;++e)if(-1!==pa((n=o[e])[0],t))return void n.push(t)})),{type:"MultiPolygon",value:i,coordinates:o}}function a(n){return 2*n[0]+n[1]*(t+1)*4}function u(e,r,i){e.forEach((function(e){var o,a=e[0],u=e[1],c=0|a,f=0|u,s=r[f*t+c];a>0&&a<t&&c===a&&(o=r[f*t+c-1],e[0]=a+(i-o)/(s-o)-.5),u>0&&u<n&&f===u&&(o=r[(f-1)*t+c],e[1]=u+(i-o)/(s-o)-.5)}))}return i.contour=o,i.size=function(e){if(!arguments.length)return[t,n];var r=Math.floor(e[0]),o=Math.floor(e[1]);if(!(r>=0&&o>=0))throw new Error("invalid size");return t=r,n=o,i},i.thresholds=function(t){return arguments.length?(e="function"==typeof t?t:Array.isArray(t)?da(la.call(t)):da(t),i):e},i.smooth=function(t){return arguments.length?(r=t?u:va,i):r===u},i}function ma(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<i;++a)for(var u=0,c=0;u<r+e;++u)u<r&&(c+=t.data[u+a*r]),u>=e&&(u>=o&&(c-=t.data[u-o+a*r]),n.data[u-e+a*r]=c/Math.min(u+1,r-1+o-u,o))}function xa(t,n,e){for(var r=t.width,i=t.height,o=1+(e<<1),a=0;a<r;++a)for(var u=0,c=0;u<i+e;++u)u<i&&(c+=t.data[a+u*r]),u>=e&&(u>=o&&(c-=t.data[a+(u-o)*r]),n.data[a+(u-e)*r]=c/Math.min(u+1,i-1+o-u,o))}function wa(t){return t[0]}function Ma(t){return t[1]}function Aa(){return 1}const Ta=Math.pow(2,-52),Sa=new Uint32Array(512);class Ea{static from(t,n=Ra,e=Fa){const r=t.length,i=new Float64Array(2*r);for(let o=0;o<r;o++){const r=t[o];i[2*o]=n(r),i[2*o+1]=e(r)}return new Ea(i)}constructor(t){const n=t.length>>1;if(n>0&&"number"!=typeof t[0])throw new Error("Expected coords to contain numbers.");this.coords=t;const e=Math.max(2*n-5,0);this._triangles=new Uint32Array(3*e),this._halfedges=new Int32Array(3*e),this._hashSize=Math.ceil(Math.sqrt(n)),this._hullPrev=new Uint32Array(n),this._hullNext=new Uint32Array(n),this._hullTri=new Uint32Array(n),this._hullHash=new Int32Array(this._hashSize).fill(-1),this._ids=new Uint32Array(n),this._dists=new Float64Array(n),this.update()}update(){const{coords:t,_hullPrev:n,_hullNext:e,_hullTri:r,_hullHash:i}=this,o=t.length>>1;let a=1/0,u=1/0,c=-1/0,f=-1/0;for(let n=0;n<o;n++){const e=t[2*n],r=t[2*n+1];e<a&&(a=e),r<u&&(u=r),e>c&&(c=e),r>f&&(f=r),this._ids[n]=n}const s=(a+c)/2,l=(u+f)/2;let h,d,p,g=1/0;for(let n=0;n<o;n++){const e=ka(s,l,t[2*n],t[2*n+1]);e<g&&(h=n,g=e)}const y=t[2*h],v=t[2*h+1];g=1/0;for(let n=0;n<o;n++){if(n===h)continue;const e=ka(y,v,t[2*n],t[2*n+1]);e<g&&e>0&&(d=n,g=e)}let _=t[2*d],b=t[2*d+1],m=1/0;for(let n=0;n<o;n++){if(n===h||n===d)continue;const e=za(y,v,_,b,t[2*n],t[2*n+1]);e<m&&(p=n,m=e)}let x=t[2*p],w=t[2*p+1];if(m===1/0){for(let n=0;n<o;n++)this._dists[n]=t[2*n]-t[0]||t[2*n+1]-t[1];Da(this._ids,this._dists,0,o-1);const n=new Uint32Array(o);let e=0;for(let t=0,r=-1/0;t<o;t++){const i=this._ids[t];this._dists[i]>r&&(n[e++]=i,r=this._dists[i])}return this.hull=n.subarray(0,e),this.triangles=new Uint32Array(0),void(this.halfedges=new Uint32Array(0))}if(Ca(y,v,_,b,x,w)){const t=d,n=_,e=b;d=p,_=x,b=w,p=t,x=n,w=e}const M=function(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c);return{x:t+(f*s-u*l)*h,y:n+(a*l-c*s)*h}}(y,v,_,b,x,w);this._cx=M.x,this._cy=M.y;for(let n=0;n<o;n++)this._dists[n]=ka(t[2*n],t[2*n+1],M.x,M.y);Da(this._ids,this._dists,0,o-1),this._hullStart=h;let A=3;e[h]=n[p]=d,e[d]=n[h]=p,e[p]=n[d]=h,r[h]=0,r[d]=1,r[p]=2,i.fill(-1),i[this._hashKey(y,v)]=h,i[this._hashKey(_,b)]=d,i[this._hashKey(x,w)]=p,this.trianglesLen=0,this._addTriangle(h,d,p,-1,-1,-1);for(let o,a,u=0;u<this._ids.length;u++){const c=this._ids[u],f=t[2*c],s=t[2*c+1];if(u>0&&Math.abs(f-o)<=Ta&&Math.abs(s-a)<=Ta)continue;if(o=f,a=s,c===h||c===d||c===p)continue;let l=0;for(let t=0,n=this._hashKey(f,s);t<this._hashSize&&(l=i[(n+t)%this._hashSize],-1===l||l===e[l]);t++);l=n[l];let g,y=l;for(;g=e[y],!Ca(f,s,t[2*y],t[2*y+1],t[2*g],t[2*g+1]);)if(y=g,y===l){y=-1;break}if(-1===y)continue;let v=this._addTriangle(y,c,e[y],-1,-1,r[y]);r[c]=this._legalize(v+2),r[y]=v,A++;let _=e[y];for(;g=e[_],Ca(f,s,t[2*_],t[2*_+1],t[2*g],t[2*g+1]);)v=this._addTriangle(_,c,g,r[c],-1,r[_]),r[c]=this._legalize(v+2),e[_]=_,A--,_=g;if(y===l)for(;g=n[y],Ca(f,s,t[2*g],t[2*g+1],t[2*y],t[2*y+1]);)v=this._addTriangle(g,c,y,-1,r[y],r[g]),this._legalize(v+2),r[g]=v,e[y]=y,A--,y=g;this._hullStart=n[c]=y,e[y]=n[_]=c,e[c]=_,i[this._hashKey(f,s)]=c,i[this._hashKey(t[2*y],t[2*y+1])]=y}this.hull=new Uint32Array(A);for(let t=0,n=this._hullStart;t<A;t++)this.hull[t]=n,n=e[n];this.triangles=this._triangles.subarray(0,this.trianglesLen),this.halfedges=this._halfedges.subarray(0,this.trianglesLen)}_hashKey(t,n){return Math.floor(function(t,n){const e=t/(Math.abs(t)+Math.abs(n));return(n>0?3-e:1+e)/4}(t-this._cx,n-this._cy)*this._hashSize)%this._hashSize}_legalize(t){const{_triangles:n,_halfedges:e,coords:r}=this;let i=0,o=0;for(;;){const a=e[t],u=t-t%3;if(o=u+(t+2)%3,-1===a){if(0===i)break;t=Sa[--i];continue}const c=a-a%3,f=u+(t+1)%3,s=c+(a+2)%3,l=n[o],h=n[t],d=n[f],p=n[s];if(Pa(r[2*l],r[2*l+1],r[2*h],r[2*h+1],r[2*d],r[2*d+1],r[2*p],r[2*p+1])){n[t]=p,n[a]=l;const r=e[s];if(-1===r){let n=this._hullStart;do{if(this._hullTri[n]===s){this._hullTri[n]=t;break}n=this._hullPrev[n]}while(n!==this._hullStart)}this._link(t,r),this._link(a,e[o]),this._link(o,s);const u=c+(a+1)%3;i<Sa.length&&(Sa[i++]=u)}else{if(0===i)break;t=Sa[--i]}}return o}_link(t,n){this._halfedges[t]=n,-1!==n&&(this._halfedges[n]=t)}_addTriangle(t,n,e,r,i,o){const a=this.trianglesLen;return this._triangles[a]=t,this._triangles[a+1]=n,this._triangles[a+2]=e,this._link(a,r),this._link(a+1,i),this._link(a+2,o),this.trianglesLen+=3,a}}function ka(t,n,e,r){const i=t-e,o=n-r;return i*i+o*o}function Na(t,n,e,r,i,o){const a=(r-n)*(i-t),u=(e-t)*(o-n);return Math.abs(a-u)>=33306690738754716e-32*Math.abs(a+u)?a-u:0}function Ca(t,n,e,r,i,o){return(Na(i,o,t,n,e,r)||Na(t,n,e,r,i,o)||Na(e,r,i,o,t,n))<0}function Pa(t,n,e,r,i,o,a,u){const c=t-a,f=n-u,s=e-a,l=r-u,h=i-a,d=o-u,p=s*s+l*l,g=h*h+d*d;return c*(l*g-p*d)-f*(s*g-p*h)+(c*c+f*f)*(s*d-l*h)<0}function za(t,n,e,r,i,o){const a=e-t,u=r-n,c=i-t,f=o-n,s=a*a+u*u,l=c*c+f*f,h=.5/(a*f-u*c),d=(f*s-u*l)*h,p=(a*l-c*s)*h;return d*d+p*p}function Da(t,n,e,r){if(r-e<=20)for(let i=e+1;i<=r;i++){const r=t[i],o=n[r];let a=i-1;for(;a>=e&&n[t[a]]>o;)t[a+1]=t[a--];t[a+1]=r}else{let i=e+1,o=r;qa(t,e+r>>1,i),n[t[e]]>n[t[r]]&&qa(t,e,r),n[t[i]]>n[t[r]]&&qa(t,i,r),n[t[e]]>n[t[i]]&&qa(t,e,i);const a=t[i],u=n[a];for(;;){do{i++}while(n[t[i]]<u);do{o--}while(n[t[o]]>u);if(o<i)break;qa(t,i,o)}t[e+1]=t[o],t[o]=a,r-i+1>=o-e?(Da(t,n,i,r),Da(t,n,e,o-1)):(Da(t,n,e,o-1),Da(t,n,i,r))}}function qa(t,n,e){const r=t[n];t[n]=t[e],t[e]=r}function Ra(t){return t[0]}function Fa(t){return t[1]}const Oa=1e-6;class Ua{constructor(){this._x0=this._y0=this._x1=this._y1=null,this._=""}moveTo(t,n){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}`}closePath(){null!==this._x1&&(this._x1=this._x0,this._y1=this._y0,this._+="Z")}lineTo(t,n){this._+=`L${this._x1=+t},${this._y1=+n}`}arc(t,n,e){const r=(t=+t)+(e=+e),i=n=+n;if(e<0)throw new Error("negative radius");null===this._x1?this._+=`M${r},${i}`:(Math.abs(this._x1-r)>Oa||Math.abs(this._y1-i)>Oa)&&(this._+="L"+r+","+i),e&&(this._+=`A${e},${e},0,1,1,${t-e},${n}A${e},${e},0,1,1,${this._x1=r},${this._y1=i}`)}rect(t,n,e,r){this._+=`M${this._x0=this._x1=+t},${this._y0=this._y1=+n}h${+e}v${+r}h${-e}Z`}value(){return this._||null}}class Ia{constructor(){this._=[]}moveTo(t,n){this._.push([t,n])}closePath(){this._.push(this._[0].slice())}lineTo(t,n){this._.push([t,n])}value(){return this._.length?this._:null}}class Ba{constructor(t,[n,e,r,i]=[0,0,960,500]){if(!((r=+r)>=(n=+n)&&(i=+i)>=(e=+e)))throw new Error("invalid bounds");this.delaunay=t,this._circumcenters=new Float64Array(2*t.points.length),this.vectors=new Float64Array(2*t.points.length),this.xmax=r,this.xmin=n,this.ymax=i,this.ymin=e,this._init()}update(){return this.delaunay.update(),this._init(),this}_init(){const{delaunay:{points:t,hull:n,triangles:e},vectors:r}=this,i=this.circumcenters=this._circumcenters.subarray(0,e.length/3*2);for(let n,r,o=0,a=0,u=e.length;o<u;o+=3,a+=2){const u=2*e[o],c=2*e[o+1],f=2*e[o+2],s=t[u],l=t[u+1],h=t[c],d=t[c+1],p=t[f],g=t[f+1],y=h-s,v=d-l,_=p-s,b=g-l,m=y*y+v*v,x=_*_+b*b,w=2*(y*b-v*_);if(w)if(Math.abs(w)<1e-8)n=(s+p)/2,r=(l+g)/2;else{const t=1/w;n=s+(b*m-v*x)*t,r=l+(y*x-_*m)*t}else n=(s+p)/2-1e8*b,r=(l+g)/2+1e8*_;i[a]=n,i[a+1]=r}let o,a,u,c=n[n.length-1],f=4*c,s=t[2*c],l=t[2*c+1];r.fill(0);for(let e=0;e<n.length;++e)c=n[e],o=f,a=s,u=l,f=4*c,s=t[2*c],l=t[2*c+1],r[o+2]=r[f]=u-l,r[o+3]=r[f+1]=s-a}render(t){const n=null==t?t=new Ua:void 0,{delaunay:{halfedges:e,inedges:r,hull:i},circumcenters:o,vectors:a}=this;if(i.length<=1)return null;for(let n=0,r=e.length;n<r;++n){const r=e[n];if(r<n)continue;const i=2*Math.floor(n/3),a=2*Math.floor(r/3),u=o[i],c=o[i+1],f=o[a],s=o[a+1];this._renderSegment(u,c,f,s,t)}let u,c=i[i.length-1];for(let n=0;n<i.length;++n){u=c,c=i[n];const e=2*Math.floor(r[c]/3),f=o[e],s=o[e+1],l=4*u,h=this._project(f,s,a[l+2],a[l+3]);h&&this._renderSegment(f,s,h[0],h[1],t)}return n&&n.value()}renderBounds(t){const n=null==t?t=new Ua:void 0;return t.rect(this.xmin,this.ymin,this.xmax-this.xmin,this.ymax-this.ymin),n&&n.value()}renderCell(t,n){const e=null==n?n=new Ua:void 0,r=this._clip(t);if(null===r||!r.length)return;n.moveTo(r[0],r[1]);let i=r.length;for(;r[0]===r[i-2]&&r[1]===r[i-1]&&i>1;)i-=2;for(let t=2;t<i;t+=2)r[t]===r[t-2]&&r[t+1]===r[t-1]||n.lineTo(r[t],r[t+1]);return n.closePath(),e&&e.value()}*cellPolygons(){const{delaunay:{points:t}}=this;for(let n=0,e=t.length/2;n<e;++n){const t=this.cellPolygon(n);t&&(t.index=n,yield t)}}cellPolygon(t){const n=new Ia;return this.renderCell(t,n),n.value()}_renderSegment(t,n,e,r,i){let o;const a=this._regioncode(t,n),u=this._regioncode(e,r);0===a&&0===u?(i.moveTo(t,n),i.lineTo(e,r)):(o=this._clipSegment(t,n,e,r,a,u))&&(i.moveTo(o[0],o[1]),i.lineTo(o[2],o[3]))}contains(t,n,e){return(n=+n)==n&&(e=+e)==e&&this.delaunay._step(t,n,e)===t}*neighbors(t){const n=this._clip(t);if(n)for(const e of this.delaunay.neighbors(t)){const t=this._clip(e);if(t)t:for(let r=0,i=n.length;r<i;r+=2)for(let o=0,a=t.length;o<a;o+=2)if(n[r]==t[o]&&n[r+1]==t[o+1]&&n[(r+2)%i]==t[(o+a-2)%a]&&n[(r+3)%i]==t[(o+a-1)%a]){yield e;break t}}}_cell(t){const{circumcenters:n,delaunay:{inedges:e,halfedges:r,triangles:i}}=this,o=e[t];if(-1===o)return null;const a=[];let u=o;do{const e=Math.floor(u/3);if(a.push(n[2*e],n[2*e+1]),u=u%3==2?u-2:u+1,i[u]!==t)break;u=r[u]}while(u!==o&&-1!==u);return a}_clip(t){if(0===t&&1===this.delaunay.hull.length)return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];const n=this._cell(t);if(null===n)return null;const{vectors:e}=this,r=4*t;return e[r]||e[r+1]?this._clipInfinite(t,n,e[r],e[r+1],e[r+2],e[r+3]):this._clipFinite(t,n)}_clipFinite(t,n){const e=n.length;let r,i,o,a,u,c=null,f=n[e-2],s=n[e-1],l=this._regioncode(f,s);for(let h=0;h<e;h+=2)if(r=f,i=s,f=n[h],s=n[h+1],o=l,l=this._regioncode(f,s),0===o&&0===l)a=u,u=0,c?c.push(f,s):c=[f,s];else{let n,e,h,d,p;if(0===o){if(null===(n=this._clipSegment(r,i,f,s,o,l)))continue;[e,h,d,p]=n}else{if(null===(n=this._clipSegment(f,s,r,i,l,o)))continue;[d,p,e,h]=n,a=u,u=this._edgecode(e,h),a&&u&&this._edge(t,a,u,c,c.length),c?c.push(e,h):c=[e,h]}a=u,u=this._edgecode(d,p),a&&u&&this._edge(t,a,u,c,c.length),c?c.push(d,p):c=[d,p]}if(c)a=u,u=this._edgecode(c[0],c[1]),a&&u&&this._edge(t,a,u,c,c.length);else if(this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2))return[this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax,this.xmin,this.ymin];return c}_clipSegment(t,n,e,r,i,o){for(;;){if(0===i&&0===o)return[t,n,e,r];if(i&o)return null;let a,u,c=i||o;8&c?(a=t+(e-t)*(this.ymax-n)/(r-n),u=this.ymax):4&c?(a=t+(e-t)*(this.ymin-n)/(r-n),u=this.ymin):2&c?(u=n+(r-n)*(this.xmax-t)/(e-t),a=this.xmax):(u=n+(r-n)*(this.xmin-t)/(e-t),a=this.xmin),i?(t=a,n=u,i=this._regioncode(t,n)):(e=a,r=u,o=this._regioncode(e,r))}}_clipInfinite(t,n,e,r,i,o){let a,u=Array.from(n);if((a=this._project(u[0],u[1],e,r))&&u.unshift(a[0],a[1]),(a=this._project(u[u.length-2],u[u.length-1],i,o))&&u.push(a[0],a[1]),u=this._clipFinite(t,u))for(let n,e=0,r=u.length,i=this._edgecode(u[r-2],u[r-1]);e<r;e+=2)n=i,i=this._edgecode(u[e],u[e+1]),n&&i&&(e=this._edge(t,n,i,u,e),r=u.length);else this.contains(t,(this.xmin+this.xmax)/2,(this.ymin+this.ymax)/2)&&(u=[this.xmin,this.ymin,this.xmax,this.ymin,this.xmax,this.ymax,this.xmin,this.ymax]);return u}_edge(t,n,e,r,i){for(;n!==e;){let e,o;switch(n){case 5:n=4;continue;case 4:n=6,e=this.xmax,o=this.ymin;break;case 6:n=2;continue;case 2:n=10,e=this.xmax,o=this.ymax;break;case 10:n=8;continue;case 8:n=9,e=this.xmin,o=this.ymax;break;case 9:n=1;continue;case 1:n=5,e=this.xmin,o=this.ymin}r[i]===e&&r[i+1]===o||!this.contains(t,e,o)||(r.splice(i,0,e,o),i+=2)}if(r.length>4)for(let t=0;t<r.length;t+=2){const n=(t+2)%r.length,e=(t+4)%r.length;(r[t]===r[n]&&r[n]===r[e]||r[t+1]===r[n+1]&&r[n+1]===r[e+1])&&(r.splice(n,2),t-=2)}return i}_project(t,n,e,r){let i,o,a,u=1/0;if(r<0){if(n<=this.ymin)return null;(i=(this.ymin-n)/r)<u&&(a=this.ymin,o=t+(u=i)*e)}else if(r>0){if(n>=this.ymax)return null;(i=(this.ymax-n)/r)<u&&(a=this.ymax,o=t+(u=i)*e)}if(e>0){if(t>=this.xmax)return null;(i=(this.xmax-t)/e)<u&&(o=this.xmax,a=n+(u=i)*r)}else if(e<0){if(t<=this.xmin)return null;(i=(this.xmin-t)/e)<u&&(o=this.xmin,a=n+(u=i)*r)}return[o,a]}_edgecode(t,n){return(t===this.xmin?1:t===this.xmax?2:0)|(n===this.ymin?4:n===this.ymax?8:0)}_regioncode(t,n){return(t<this.xmin?1:t>this.xmax?2:0)|(n<this.ymin?4:n>this.ymax?8:0)}}const Ya=2*Math.PI,La=Math.pow;function ja(t){return t[0]}function Ha(t){return t[1]}function Xa(t,n,e){return[t+Math.sin(t+n)*e,n+Math.cos(t-n)*e]}class Ga{static from(t,n=ja,e=Ha,r){return new Ga("length"in t?function(t,n,e,r){const i=t.length,o=new Float64Array(2*i);for(let a=0;a<i;++a){const i=t[a];o[2*a]=n.call(r,i,a,t),o[2*a+1]=e.call(r,i,a,t)}return o}(t,n,e,r):Float64Array.from(function*(t,n,e,r){let i=0;for(const o of t)yield n.call(r,o,i,t),yield e.call(r,o,i,t),++i}(t,n,e,r)))}constructor(t){this._delaunator=new Ea(t),this.inedges=new Int32Array(t.length/2),this._hullIndex=new Int32Array(t.length/2),this.points=this._delaunator.coords,this._init()}update(){return this._delaunator.update(),this._init(),this}_init(){const t=this._delaunator,n=this.points;if(t.hull&&t.hull.length>2&&function(t){const{triangles:n,coords:e}=t;for(let t=0;t<n.length;t+=3){const r=2*n[t],i=2*n[t+1],o=2*n[t+2];if((e[o]-e[r])*(e[i+1]-e[r+1])-(e[i]-e[r])*(e[o+1]-e[r+1])>1e-10)return!1}return!0}(t)){this.collinear=Int32Array.from({length:n.length/2},(t,n)=>n).sort((t,e)=>n[2*t]-n[2*e]||n[2*t+1]-n[2*e+1]);const t=this.collinear[0],e=this.collinear[this.collinear.length-1],r=[n[2*t],n[2*t+1],n[2*e],n[2*e+1]],i=1e-8*Math.hypot(r[3]-r[1],r[2]-r[0]);for(let t=0,e=n.length/2;t<e;++t){const e=Xa(n[2*t],n[2*t+1],i);n[2*t]=e[0],n[2*t+1]=e[1]}this._delaunator=new Ea(n)}else delete this.collinear;const e=this.halfedges=this._delaunator.halfedges,r=this.hull=this._delaunator.hull,i=this.triangles=this._delaunator.triangles,o=this.inedges.fill(-1),a=this._hullIndex.fill(-1);for(let t=0,n=e.length;t<n;++t){const n=i[t%3==2?t-2:t+1];-1!==e[t]&&-1!==o[n]||(o[n]=t)}for(let t=0,n=r.length;t<n;++t)a[r[t]]=t;r.length<=2&&r.length>0&&(this.triangles=new Int32Array(3).fill(-1),this.halfedges=new Int32Array(3).fill(-1),this.triangles[0]=r[0],this.triangles[1]=r[1],this.triangles[2]=r[1],o[r[0]]=1,2===r.length&&(o[r[1]]=0))}voronoi(t){return new Ba(this,t)}*neighbors(t){const{inedges:n,hull:e,_hullIndex:r,halfedges:i,triangles:o,collinear:a}=this;if(a){const n=a.indexOf(t);return n>0&&(yield a[n-1]),void(n<a.length-1&&(yield a[n+1]))}const u=n[t];if(-1===u)return;let c=u,f=-1;do{if(yield f=o[c],c=c%3==2?c-2:c+1,o[c]!==t)return;if(c=i[c],-1===c){const n=e[(r[t]+1)%e.length];return void(n!==f&&(yield n))}}while(c!==u)}find(t,n,e=0){if((t=+t)!=t||(n=+n)!=n)return-1;const r=e;let i;for(;(i=this._step(e,t,n))>=0&&i!==e&&i!==r;)e=i;return i}_step(t,n,e){const{inedges:r,hull:i,_hullIndex:o,halfedges:a,triangles:u,points:c}=this;if(-1===r[t]||!c.length)return(t+1)%(c.length>>1);let f=t,s=La(n-c[2*t],2)+La(e-c[2*t+1],2);const l=r[t];let h=l;do{let r=u[h];const l=La(n-c[2*r],2)+La(e-c[2*r+1],2);if(l<s&&(s=l,f=r),h=h%3==2?h-2:h+1,u[h]!==t)break;if(h=a[h],-1===h){if(h=i[(o[t]+1)%i.length],h!==r&&La(n-c[2*h],2)+La(e-c[2*h+1],2)<s)return h;break}}while(h!==l);return f}render(t){const n=null==t?t=new Ua:void 0,{points:e,halfedges:r,triangles:i}=this;for(let n=0,o=r.length;n<o;++n){const o=r[n];if(o<n)continue;const a=2*i[n],u=2*i[o];t.moveTo(e[a],e[a+1]),t.lineTo(e[u],e[u+1])}return this.renderHull(t),n&&n.value()}renderPoints(t,n=2){const e=null==t?t=new Ua:void 0,{points:r}=this;for(let e=0,i=r.length;e<i;e+=2){const i=r[e],o=r[e+1];t.moveTo(i+n,o),t.arc(i,o,n,0,Ya)}return e&&e.value()}renderHull(t){const n=null==t?t=new Ua:void 0,{hull:e,points:r}=this,i=2*e[0],o=e.length;t.moveTo(r[i],r[i+1]);for(let n=1;n<o;++n){const i=2*e[n];t.lineTo(r[i],r[i+1])}return t.closePath(),n&&n.value()}hullPolygon(){const t=new Ia;return this.renderHull(t),t.value()}renderTriangle(t,n){const e=null==n?n=new Ua:void 0,{points:r,triangles:i}=this,o=2*i[t*=3],a=2*i[t+1],u=2*i[t+2];return n.moveTo(r[o],r[o+1]),n.lineTo(r[a],r[a+1]),n.lineTo(r[u],r[u+1]),n.closePath(),e&&e.value()}*trianglePolygons(){const{triangles:t}=this;for(let n=0,e=t.length/3;n<e;++n)yield this.trianglePolygon(n)}trianglePolygon(t){const n=new Ia;return this.renderTriangle(t,n),n.value()}}var Va={},$a={};function Wa(t){return new Function("d","return {"+t.map((function(t,n){return JSON.stringify(t)+": d["+n+'] || ""'})).join(",")+"}")}function Za(t){var n=Object.create(null),e=[];return t.forEach((function(t){for(var r in t)r in n||e.push(n[r]=r)})),e}function Ka(t,n){var e=t+"",r=e.length;return r<n?new Array(n-r+1).join(0)+e:e}function Qa(t){var n=t.getUTCHours(),e=t.getUTCMinutes(),r=t.getUTCSeconds(),i=t.getUTCMilliseconds();return isNaN(t)?"Invalid Date":function(t){return t<0?"-"+Ka(-t,6):t>9999?"+"+Ka(t,6):Ka(t,4)}(t.getUTCFullYear())+"-"+Ka(t.getUTCMonth()+1,2)+"-"+Ka(t.getUTCDate(),2)+(i?"T"+Ka(n,2)+":"+Ka(e,2)+":"+Ka(r,2)+"."+Ka(i,3)+"Z":r?"T"+Ka(n,2)+":"+Ka(e,2)+":"+Ka(r,2)+"Z":e||n?"T"+Ka(n,2)+":"+Ka(e,2)+"Z":"")}function Ja(t){var n=new RegExp('["'+t+"\n\r]"),e=t.charCodeAt(0);function r(t,n){var r,i=[],o=t.length,a=0,u=0,c=o<=0,f=!1;function s(){if(c)return $a;if(f)return f=!1,Va;var n,r,i=a;if(34===t.charCodeAt(i)){for(;a++<o&&34!==t.charCodeAt(a)||34===t.charCodeAt(++a););return(n=a)>=o?c=!0:10===(r=t.charCodeAt(a++))?f=!0:13===r&&(f=!0,10===t.charCodeAt(a)&&++a),t.slice(i+1,n-1).replace(/""/g,'"')}for(;a<o;){if(10===(r=t.charCodeAt(n=a++)))f=!0;else if(13===r)f=!0,10===t.charCodeAt(a)&&++a;else if(r!==e)continue;return t.slice(i,n)}return c=!0,t.slice(i,o)}for(10===t.charCodeAt(o-1)&&--o,13===t.charCodeAt(o-1)&&--o;(r=s())!==$a;){for(var l=[];r!==Va&&r!==$a;)l.push(r),r=s();n&&null==(l=n(l,u++))||i.push(l)}return i}function i(n,e){return n.map((function(n){return e.map((function(t){return a(n[t])})).join(t)}))}function o(n){return n.map(a).join(t)}function a(t){return null==t?"":t instanceof Date?Qa(t):n.test(t+="")?'"'+t.replace(/"/g,'""')+'"':t}return{parse:function(t,n){var e,i,o=r(t,(function(t,r){if(e)return e(t,r-1);i=t,e=n?function(t,n){var e=Wa(t);return function(r,i){return n(e(r),i,t)}}(t,n):Wa(t)}));return o.columns=i||[],o},parseRows:r,format:function(n,e){return null==e&&(e=Za(n)),[e.map(a).join(t)].concat(i(n,e)).join("\n")},formatBody:function(t,n){return null==n&&(n=Za(t)),i(t,n).join("\n")},formatRows:function(t){return t.map(o).join("\n")},formatRow:o,formatValue:a}}var tu=Ja(","),nu=tu.parse,eu=tu.parseRows,ru=tu.format,iu=tu.formatBody,ou=tu.formatRows,au=tu.formatRow,uu=tu.formatValue,cu=Ja("\t"),fu=cu.parse,su=cu.parseRows,lu=cu.format,hu=cu.formatBody,du=cu.formatRows,pu=cu.formatRow,gu=cu.formatValue;const yu=new Date("2019-01-01T00:00").getHours()||new Date("2019-07-01T00:00").getHours();function vu(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.blob()}function _u(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.arrayBuffer()}function bu(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);return t.text()}function mu(t,n){return fetch(t,n).then(bu)}function xu(t){return function(n,e,r){return 2===arguments.length&&"function"==typeof e&&(r=e,e=void 0),mu(n,e).then((function(n){return t(n,r)}))}}var wu=xu(nu),Mu=xu(fu);function Au(t){if(!t.ok)throw new Error(t.status+" "+t.statusText);if(204!==t.status&&205!==t.status)return t.json()}function Tu(t){return(n,e)=>mu(n,e).then(n=>(new DOMParser).parseFromString(n,t))}var Su=Tu("application/xml"),Eu=Tu("text/html"),ku=Tu("image/svg+xml");function Nu(t,n,e,r){if(isNaN(n)||isNaN(e))return t;var i,o,a,u,c,f,s,l,h,d=t._root,p={data:r},g=t._x0,y=t._y0,v=t._x1,_=t._y1;if(!d)return t._root=p,t;for(;d.length;)if((f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a,i=d,!(d=d[l=s<<1|f]))return i[l]=p,t;if(u=+t._x.call(null,d.data),c=+t._y.call(null,d.data),n===u&&e===c)return p.next=d,i?i[l]=p:t._root=p,t;do{i=i?i[l]=new Array(4):t._root=new Array(4),(f=n>=(o=(g+v)/2))?g=o:v=o,(s=e>=(a=(y+_)/2))?y=a:_=a}while((l=s<<1|f)==(h=(c>=a)<<1|u>=o));return i[h]=d,i[l]=p,t}function Cu(t,n,e,r,i){this.node=t,this.x0=n,this.y0=e,this.x1=r,this.y1=i}function Pu(t){return t[0]}function zu(t){return t[1]}function Du(t,n,e){var r=new qu(null==n?Pu:n,null==e?zu:e,NaN,NaN,NaN,NaN);return null==t?r:r.addAll(t)}function qu(t,n,e,r,i,o){this._x=t,this._y=n,this._x0=e,this._y0=r,this._x1=i,this._y1=o,this._root=void 0}function Ru(t){for(var n={data:t.data},e=n;t=t.next;)e=e.next={data:t.data};return n}var Fu=Du.prototype=qu.prototype;function Ou(t){return function(){return t}}function Uu(t){return 1e-6*(t()-.5)}function Iu(t){return t.x+t.vx}function Bu(t){return t.y+t.vy}function Yu(t){return t.index}function Lu(t,n){var e=t.get(n);if(!e)throw new Error("node not found: "+n);return e}Fu.copy=function(){var t,n,e=new qu(this._x,this._y,this._x0,this._y0,this._x1,this._y1),r=this._root;if(!r)return e;if(!r.length)return e._root=Ru(r),e;for(t=[{source:r,target:e._root=new Array(4)}];r=t.pop();)for(var i=0;i<4;++i)(n=r.source[i])&&(n.length?t.push({source:n,target:r.target[i]=new Array(4)}):r.target[i]=Ru(n));return e},Fu.add=function(t){const n=+this._x.call(null,t),e=+this._y.call(null,t);return Nu(this.cover(n,e),n,e,t)},Fu.addAll=function(t){var n,e,r,i,o=t.length,a=new Array(o),u=new Array(o),c=1/0,f=1/0,s=-1/0,l=-1/0;for(e=0;e<o;++e)isNaN(r=+this._x.call(null,n=t[e]))||isNaN(i=+this._y.call(null,n))||(a[e]=r,u[e]=i,r<c&&(c=r),r>s&&(s=r),i<f&&(f=i),i>l&&(l=i));if(c>s||f>l)return this;for(this.cover(c,f).cover(s,l),e=0;e<o;++e)Nu(this,a[e],u[e],t[e]);return this},Fu.cover=function(t,n){if(isNaN(t=+t)||isNaN(n=+n))return this;var e=this._x0,r=this._y0,i=this._x1,o=this._y1;if(isNaN(e))i=(e=Math.floor(t))+1,o=(r=Math.floor(n))+1;else{for(var a,u,c=i-e||1,f=this._root;e>t||t>=i||r>n||n>=o;)switch(u=(n<r)<<1|t<e,(a=new Array(4))[u]=f,f=a,c*=2,u){case 0:i=e+c,o=r+c;break;case 1:e=i-c,o=r+c;break;case 2:i=e+c,r=o-c;break;case 3:e=i-c,r=o-c}this._root&&this._root.length&&(this._root=f)}return this._x0=e,this._y0=r,this._x1=i,this._y1=o,this},Fu.data=function(){var t=[];return this.visit((function(n){if(!n.length)do{t.push(n.data)}while(n=n.next)})),t},Fu.extent=function(t){return arguments.length?this.cover(+t[0][0],+t[0][1]).cover(+t[1][0],+t[1][1]):isNaN(this._x0)?void 0:[[this._x0,this._y0],[this._x1,this._y1]]},Fu.find=function(t,n,e){var r,i,o,a,u,c,f,s=this._x0,l=this._y0,h=this._x1,d=this._y1,p=[],g=this._root;for(g&&p.push(new Cu(g,s,l,h,d)),null==e?e=1/0:(s=t-e,l=n-e,h=t+e,d=n+e,e*=e);c=p.pop();)if(!(!(g=c.node)||(i=c.x0)>h||(o=c.y0)>d||(a=c.x1)<s||(u=c.y1)<l))if(g.length){var y=(i+a)/2,v=(o+u)/2;p.push(new Cu(g[3],y,v,a,u),new Cu(g[2],i,v,y,u),new Cu(g[1],y,o,a,v),new Cu(g[0],i,o,y,v)),(f=(n>=v)<<1|t>=y)&&(c=p[p.length-1],p[p.length-1]=p[p.length-1-f],p[p.length-1-f]=c)}else{var _=t-+this._x.call(null,g.data),b=n-+this._y.call(null,g.data),m=_*_+b*b;if(m<e){var x=Math.sqrt(e=m);s=t-x,l=n-x,h=t+x,d=n+x,r=g.data}}return r},Fu.remove=function(t){if(isNaN(o=+this._x.call(null,t))||isNaN(a=+this._y.call(null,t)))return this;var n,e,r,i,o,a,u,c,f,s,l,h,d=this._root,p=this._x0,g=this._y0,y=this._x1,v=this._y1;if(!d)return this;if(d.length)for(;;){if((f=o>=(u=(p+y)/2))?p=u:y=u,(s=a>=(c=(g+v)/2))?g=c:v=c,n=d,!(d=d[l=s<<1|f]))return this;if(!d.length)break;(n[l+1&3]||n[l+2&3]||n[l+3&3])&&(e=n,h=l)}for(;d.data!==t;)if(r=d,!(d=d.next))return this;return(i=d.next)&&delete d.next,r?(i?r.next=i:delete r.next,this):n?(i?n[l]=i:delete n[l],(d=n[0]||n[1]||n[2]||n[3])&&d===(n[3]||n[2]||n[1]||n[0])&&!d.length&&(e?e[h]=d:this._root=d),this):(this._root=i,this)},Fu.removeAll=function(t){for(var n=0,e=t.length;n<e;++n)this.remove(t[n]);return this},Fu.root=function(){return this._root},Fu.size=function(){var t=0;return this.visit((function(n){if(!n.length)do{++t}while(n=n.next)})),t},Fu.visit=function(t){var n,e,r,i,o,a,u=[],c=this._root;for(c&&u.push(new Cu(c,this._x0,this._y0,this._x1,this._y1));n=u.pop();)if(!t(c=n.node,r=n.x0,i=n.y0,o=n.x1,a=n.y1)&&c.length){var f=(r+o)/2,s=(i+a)/2;(e=c[3])&&u.push(new Cu(e,f,s,o,a)),(e=c[2])&&u.push(new Cu(e,r,s,f,a)),(e=c[1])&&u.push(new Cu(e,f,i,o,s)),(e=c[0])&&u.push(new Cu(e,r,i,f,s))}return this},Fu.visitAfter=function(t){var n,e=[],r=[];for(this._root&&e.push(new Cu(this._root,this._x0,this._y0,this._x1,this._y1));n=e.pop();){var i=n.node;if(i.length){var o,a=n.x0,u=n.y0,c=n.x1,f=n.y1,s=(a+c)/2,l=(u+f)/2;(o=i[0])&&e.push(new Cu(o,a,u,s,l)),(o=i[1])&&e.push(new Cu(o,s,u,c,l)),(o=i[2])&&e.push(new Cu(o,a,l,s,f)),(o=i[3])&&e.push(new Cu(o,s,l,c,f))}r.push(n)}for(;n=r.pop();)t(n.node,n.x0,n.y0,n.x1,n.y1);return this},Fu.x=function(t){return arguments.length?(this._x=t,this):this._x},Fu.y=function(t){return arguments.length?(this._y=t,this):this._y};const ju=4294967296;function Hu(t){return t.x}function Xu(t){return t.y}var Gu=Math.PI*(3-Math.sqrt(5));function Vu(t,n){if((e=(t=n?t.toExponential(n-1):t.toExponential()).indexOf("e"))<0)return null;var e,r=t.slice(0,e);return[r.length>1?r[0]+r.slice(2):r,+t.slice(e+1)]}function $u(t){return(t=Vu(Math.abs(t)))?t[1]:NaN}var Wu,Zu=/^(?:(.)?([<>=^]))?([+\-( ])?([$#])?(0)?(\d+)?(,)?(\.\d+)?(~)?([a-z%])?$/i;function Ku(t){if(!(n=Zu.exec(t)))throw new Error("invalid format: "+t);var n;return new Qu({fill:n[1],align:n[2],sign:n[3],symbol:n[4],zero:n[5],width:n[6],comma:n[7],precision:n[8]&&n[8].slice(1),trim:n[9],type:n[10]})}function Qu(t){this.fill=void 0===t.fill?" ":t.fill+"",this.align=void 0===t.align?">":t.align+"",this.sign=void 0===t.sign?"-":t.sign+"",this.symbol=void 0===t.symbol?"":t.symbol+"",this.zero=!!t.zero,this.width=void 0===t.width?void 0:+t.width,this.comma=!!t.comma,this.precision=void 0===t.precision?void 0:+t.precision,this.trim=!!t.trim,this.type=void 0===t.type?"":t.type+""}function Ju(t,n){var e=Vu(t,n);if(!e)return t+"";var r=e[0],i=e[1];return i<0?"0."+new Array(-i).join("0")+r:r.length>i+1?r.slice(0,i+1)+"."+r.slice(i+1):r+new Array(i-r.length+2).join("0")}Ku.prototype=Qu.prototype,Qu.prototype.toString=function(){return this.fill+this.align+this.sign+this.symbol+(this.zero?"0":"")+(void 0===this.width?"":Math.max(1,0|this.width))+(this.comma?",":"")+(void 0===this.precision?"":"."+Math.max(0,0|this.precision))+(this.trim?"~":"")+this.type};var tc={"%":(t,n)=>(100*t).toFixed(n),b:t=>Math.round(t).toString(2),c:t=>t+"",d:function(t){return Math.abs(t=Math.round(t))>=1e21?t.toLocaleString("en").replace(/,/g,""):t.toString(10)},e:(t,n)=>t.toExponential(n),f:(t,n)=>t.toFixed(n),g:(t,n)=>t.toPrecision(n),o:t=>Math.round(t).toString(8),p:(t,n)=>Ju(100*t,n),r:Ju,s:function(t,n){var e=Vu(t,n);if(!e)return t+"";var r=e[0],i=e[1],o=i-(Wu=3*Math.max(-8,Math.min(8,Math.floor(i/3))))+1,a=r.length;return o===a?r:o>a?r+new Array(o-a+1).join("0"):o>0?r.slice(0,o)+"."+r.slice(o):"0."+new Array(1-o).join("0")+Vu(t,Math.max(0,n+o-1))[0]},X:t=>Math.round(t).toString(16).toUpperCase(),x:t=>Math.round(t).toString(16)};function nc(t){return t}var ec,rc=Array.prototype.map,ic=["y","z","a","f","p","n","µ","m","","k","M","G","T","P","E","Z","Y"];function oc(t){var n,e,r=void 0===t.grouping||void 0===t.thousands?nc:(n=rc.call(t.grouping,Number),e=t.thousands+"",function(t,r){for(var i=t.length,o=[],a=0,u=n[0],c=0;i>0&&u>0&&(c+u+1>r&&(u=Math.max(1,r-c)),o.push(t.substring(i-=u,i+u)),!((c+=u+1)>r));)u=n[a=(a+1)%n.length];return o.reverse().join(e)}),i=void 0===t.currency?"":t.currency[0]+"",o=void 0===t.currency?"":t.currency[1]+"",a=void 0===t.decimal?".":t.decimal+"",u=void 0===t.numerals?nc:function(t){return function(n){return n.replace(/[0-9]/g,(function(n){return t[+n]}))}}(rc.call(t.numerals,String)),c=void 0===t.percent?"%":t.percent+"",f=void 0===t.minus?"−":t.minus+"",s=void 0===t.nan?"NaN":t.nan+"";function l(t){var n=(t=Ku(t)).fill,e=t.align,l=t.sign,h=t.symbol,d=t.zero,p=t.width,g=t.comma,y=t.precision,v=t.trim,_=t.type;"n"===_?(g=!0,_="g"):tc[_]||(void 0===y&&(y=12),v=!0,_="g"),(d||"0"===n&&"="===e)&&(d=!0,n="0",e="=");var b="$"===h?i:"#"===h&&/[boxX]/.test(_)?"0"+_.toLowerCase():"",m="$"===h?o:/[%p]/.test(_)?c:"",x=tc[_],w=/[defgprs%]/.test(_);function M(t){var i,o,c,h=b,M=m;if("c"===_)M=x(t)+M,t="";else{var A=(t=+t)<0||1/t<0;if(t=isNaN(t)?s:x(Math.abs(t),y),v&&(t=function(t){t:for(var n,e=t.length,r=1,i=-1;r<e;++r)switch(t[r]){case".":i=n=r;break;case"0":0===i&&(i=r),n=r;break;default:if(!+t[r])break t;i>0&&(i=0)}return i>0?t.slice(0,i)+t.slice(n+1):t}(t)),A&&0==+t&&"+"!==l&&(A=!1),h=(A?"("===l?l:f:"-"===l||"("===l?"":l)+h,M=("s"===_?ic[8+Wu/3]:"")+M+(A&&"("===l?")":""),w)for(i=-1,o=t.length;++i<o;)if(48>(c=t.charCodeAt(i))||c>57){M=(46===c?a+t.slice(i+1):t.slice(i))+M,t=t.slice(0,i);break}}g&&!d&&(t=r(t,1/0));var T=h.length+t.length+M.length,S=T<p?new Array(p-T+1).join(n):"";switch(g&&d&&(t=r(S+t,S.length?p-M.length:1/0),S=""),e){case"<":t=h+t+M+S;break;case"=":t=h+S+t+M;break;case"^":t=S.slice(0,T=S.length>>1)+h+t+M+S.slice(T);break;default:t=S+h+t+M}return u(t)}return y=void 0===y?6:/[gprs]/.test(_)?Math.max(1,Math.min(21,y)):Math.max(0,Math.min(20,y)),M.toString=function(){return t+""},M}return{format:l,formatPrefix:function(t,n){var e=l(((t=Ku(t)).type="f",t)),r=3*Math.max(-8,Math.min(8,Math.floor($u(n)/3))),i=Math.pow(10,-r),o=ic[8+r/3];return function(t){return e(i*t)+o}}}}function ac(n){return ec=oc(n),t.format=ec.format,t.formatPrefix=ec.formatPrefix,ec}function uc(t){return Math.max(0,-$u(Math.abs(t)))}function cc(t,n){return Math.max(0,3*Math.max(-8,Math.min(8,Math.floor($u(n)/3)))-$u(Math.abs(t)))}function fc(t,n){return t=Math.abs(t),n=Math.abs(n)-t,Math.max(0,$u(n)-$u(t))+1}ac({thousands:",",grouping:[3],currency:["$",""]});var sc=1e-6,lc=1e-12,hc=Math.PI,dc=hc/2,pc=hc/4,gc=2*hc,yc=180/hc,vc=hc/180,_c=Math.abs,bc=Math.atan,mc=Math.atan2,xc=Math.cos,wc=Math.ceil,Mc=Math.exp,Ac=Math.hypot,Tc=Math.log,Sc=Math.pow,Ec=Math.sin,kc=Math.sign||function(t){return t>0?1:t<0?-1:0},Nc=Math.sqrt,Cc=Math.tan;function Pc(t){return t>1?0:t<-1?hc:Math.acos(t)}function zc(t){return t>1?dc:t<-1?-dc:Math.asin(t)}function Dc(t){return(t=Ec(t/2))*t}function qc(){}function Rc(t,n){t&&Oc.hasOwnProperty(t.type)&&Oc[t.type](t,n)}var Fc={Feature:function(t,n){Rc(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)Rc(e[r].geometry,n)}},Oc={Sphere:function(t,n){n.sphere()},Point:function(t,n){t=t.coordinates,n.point(t[0],t[1],t[2])},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)t=e[r],n.point(t[0],t[1],t[2])},LineString:function(t,n){Uc(t.coordinates,n,0)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Uc(e[r],n,0)},Polygon:function(t,n){Ic(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)Ic(e[r],n)},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)Rc(e[r],n)}};function Uc(t,n,e){var r,i=-1,o=t.length-e;for(n.lineStart();++i<o;)r=t[i],n.point(r[0],r[1],r[2]);n.lineEnd()}function Ic(t,n){var e=-1,r=t.length;for(n.polygonStart();++e<r;)Uc(t[e],n,1);n.polygonEnd()}function Bc(t,n){t&&Fc.hasOwnProperty(t.type)?Fc[t.type](t,n):Rc(t,n)}var Yc,Lc,jc,Hc,Xc,Gc,Vc,$c,Wc,Zc,Kc,Qc,Jc,tf,nf,ef,rf=new g,of=new g,af={point:qc,lineStart:qc,lineEnd:qc,polygonStart:function(){rf=new g,af.lineStart=uf,af.lineEnd=cf},polygonEnd:function(){var t=+rf;of.add(t<0?gc+t:t),this.lineStart=this.lineEnd=this.point=qc},sphere:function(){of.add(gc)}};function uf(){af.point=ff}function cf(){sf(Yc,Lc)}function ff(t,n){af.point=sf,Yc=t,Lc=n,jc=t*=vc,Hc=xc(n=(n*=vc)/2+pc),Xc=Ec(n)}function sf(t,n){var e=(t*=vc)-jc,r=e>=0?1:-1,i=r*e,o=xc(n=(n*=vc)/2+pc),a=Ec(n),u=Xc*a,c=Hc*o+u*xc(i),f=u*r*Ec(i);rf.add(mc(f,c)),jc=t,Hc=o,Xc=a}function lf(t){return[mc(t[1],t[0]),zc(t[2])]}function hf(t){var n=t[0],e=t[1],r=xc(e);return[r*xc(n),r*Ec(n),Ec(e)]}function df(t,n){return t[0]*n[0]+t[1]*n[1]+t[2]*n[2]}function pf(t,n){return[t[1]*n[2]-t[2]*n[1],t[2]*n[0]-t[0]*n[2],t[0]*n[1]-t[1]*n[0]]}function gf(t,n){t[0]+=n[0],t[1]+=n[1],t[2]+=n[2]}function yf(t,n){return[t[0]*n,t[1]*n,t[2]*n]}function vf(t){var n=Nc(t[0]*t[0]+t[1]*t[1]+t[2]*t[2]);t[0]/=n,t[1]/=n,t[2]/=n}var _f,bf,mf,xf,wf,Mf,Af,Tf,Sf,Ef,kf,Nf,Cf,Pf,zf,Df,qf={point:Rf,lineStart:Of,lineEnd:Uf,polygonStart:function(){qf.point=If,qf.lineStart=Bf,qf.lineEnd=Yf,tf=new g,af.polygonStart()},polygonEnd:function(){af.polygonEnd(),qf.point=Rf,qf.lineStart=Of,qf.lineEnd=Uf,rf<0?(Gc=-($c=180),Vc=-(Wc=90)):tf>sc?Wc=90:tf<-1e-6&&(Vc=-90),ef[0]=Gc,ef[1]=$c},sphere:function(){Gc=-($c=180),Vc=-(Wc=90)}};function Rf(t,n){nf.push(ef=[Gc=t,$c=t]),n<Vc&&(Vc=n),n>Wc&&(Wc=n)}function Ff(t,n){var e=hf([t*vc,n*vc]);if(Jc){var r=pf(Jc,e),i=pf([r[1],-r[0],0],r);vf(i),i=lf(i);var o,a=t-Zc,u=a>0?1:-1,c=i[0]*yc*u,f=_c(a)>180;f^(u*Zc<c&&c<u*t)?(o=i[1]*yc)>Wc&&(Wc=o):f^(u*Zc<(c=(c+360)%360-180)&&c<u*t)?(o=-i[1]*yc)<Vc&&(Vc=o):(n<Vc&&(Vc=n),n>Wc&&(Wc=n)),f?t<Zc?Lf(Gc,t)>Lf(Gc,$c)&&($c=t):Lf(t,$c)>Lf(Gc,$c)&&(Gc=t):$c>=Gc?(t<Gc&&(Gc=t),t>$c&&($c=t)):t>Zc?Lf(Gc,t)>Lf(Gc,$c)&&($c=t):Lf(t,$c)>Lf(Gc,$c)&&(Gc=t)}else nf.push(ef=[Gc=t,$c=t]);n<Vc&&(Vc=n),n>Wc&&(Wc=n),Jc=e,Zc=t}function Of(){qf.point=Ff}function Uf(){ef[0]=Gc,ef[1]=$c,qf.point=Rf,Jc=null}function If(t,n){if(Jc){var e=t-Zc;tf.add(_c(e)>180?e+(e>0?360:-360):e)}else Kc=t,Qc=n;af.point(t,n),Ff(t,n)}function Bf(){af.lineStart()}function Yf(){If(Kc,Qc),af.lineEnd(),_c(tf)>sc&&(Gc=-($c=180)),ef[0]=Gc,ef[1]=$c,Jc=null}function Lf(t,n){return(n-=t)<0?n+360:n}function jf(t,n){return t[0]-n[0]}function Hf(t,n){return t[0]<=t[1]?t[0]<=n&&n<=t[1]:n<t[0]||t[1]<n}var Xf={sphere:qc,point:Gf,lineStart:$f,lineEnd:Kf,polygonStart:function(){Xf.lineStart=Qf,Xf.lineEnd=Jf},polygonEnd:function(){Xf.lineStart=$f,Xf.lineEnd=Kf}};function Gf(t,n){t*=vc;var e=xc(n*=vc);Vf(e*xc(t),e*Ec(t),Ec(n))}function Vf(t,n,e){++_f,mf+=(t-mf)/_f,xf+=(n-xf)/_f,wf+=(e-wf)/_f}function $f(){Xf.point=Wf}function Wf(t,n){t*=vc;var e=xc(n*=vc);Pf=e*xc(t),zf=e*Ec(t),Df=Ec(n),Xf.point=Zf,Vf(Pf,zf,Df)}function Zf(t,n){t*=vc;var e=xc(n*=vc),r=e*xc(t),i=e*Ec(t),o=Ec(n),a=mc(Nc((a=zf*o-Df*i)*a+(a=Df*r-Pf*o)*a+(a=Pf*i-zf*r)*a),Pf*r+zf*i+Df*o);bf+=a,Mf+=a*(Pf+(Pf=r)),Af+=a*(zf+(zf=i)),Tf+=a*(Df+(Df=o)),Vf(Pf,zf,Df)}function Kf(){Xf.point=Gf}function Qf(){Xf.point=ts}function Jf(){ns(Nf,Cf),Xf.point=Gf}function ts(t,n){Nf=t,Cf=n,t*=vc,n*=vc,Xf.point=ns;var e=xc(n);Pf=e*xc(t),zf=e*Ec(t),Df=Ec(n),Vf(Pf,zf,Df)}function ns(t,n){t*=vc;var e=xc(n*=vc),r=e*xc(t),i=e*Ec(t),o=Ec(n),a=zf*o-Df*i,u=Df*r-Pf*o,c=Pf*i-zf*r,f=Ac(a,u,c),s=zc(f),l=f&&-s/f;Sf.add(l*a),Ef.add(l*u),kf.add(l*c),bf+=s,Mf+=s*(Pf+(Pf=r)),Af+=s*(zf+(zf=i)),Tf+=s*(Df+(Df=o)),Vf(Pf,zf,Df)}function es(t){return function(){return t}}function rs(t,n){function e(e,r){return e=t(e,r),n(e[0],e[1])}return t.invert&&n.invert&&(e.invert=function(e,r){return(e=n.invert(e,r))&&t.invert(e[0],e[1])}),e}function is(t,n){return[_c(t)>hc?t+Math.round(-t/gc)*gc:t,n]}function os(t,n,e){return(t%=gc)?n||e?rs(us(t),cs(n,e)):us(t):n||e?cs(n,e):is}function as(t){return function(n,e){return[(n+=t)>hc?n-gc:n<-hc?n+gc:n,e]}}function us(t){var n=as(t);return n.invert=as(-t),n}function cs(t,n){var e=xc(t),r=Ec(t),i=xc(n),o=Ec(n);function a(t,n){var a=xc(n),u=xc(t)*a,c=Ec(t)*a,f=Ec(n),s=f*e+u*r;return[mc(c*i-s*o,u*e-f*r),zc(s*i+c*o)]}return a.invert=function(t,n){var a=xc(n),u=xc(t)*a,c=Ec(t)*a,f=Ec(n),s=f*i-c*o;return[mc(c*i+f*o,u*e+s*r),zc(s*e-u*r)]},a}function fs(t){function n(n){return(n=t(n[0]*vc,n[1]*vc))[0]*=yc,n[1]*=yc,n}return t=os(t[0]*vc,t[1]*vc,t.length>2?t[2]*vc:0),n.invert=function(n){return(n=t.invert(n[0]*vc,n[1]*vc))[0]*=yc,n[1]*=yc,n},n}function ss(t,n,e,r,i,o){if(e){var a=xc(n),u=Ec(n),c=r*e;null==i?(i=n+r*gc,o=n-c/2):(i=ls(a,i),o=ls(a,o),(r>0?i<o:i>o)&&(i+=r*gc));for(var f,s=i;r>0?s>o:s<o;s-=c)f=lf([a,-u*xc(s),-u*Ec(s)]),t.point(f[0],f[1])}}function ls(t,n){(n=hf(n))[0]-=t,vf(n);var e=Pc(-n[1]);return((-n[2]<0?-e:e)+gc-sc)%gc}function hs(){var t,n=[];return{point:function(n,e,r){t.push([n,e,r])},lineStart:function(){n.push(t=[])},lineEnd:qc,rejoin:function(){n.length>1&&n.push(n.pop().concat(n.shift()))},result:function(){var e=n;return n=[],t=null,e}}}function ds(t,n){return _c(t[0]-n[0])<sc&&_c(t[1]-n[1])<sc}function ps(t,n,e,r){this.x=t,this.z=n,this.o=e,this.e=r,this.v=!1,this.n=this.p=null}function gs(t,n,e,r,i){var o,a,u=[],c=[];if(t.forEach((function(t){if(!((n=t.length-1)<=0)){var n,e,r=t[0],a=t[n];if(ds(r,a)){if(!r[2]&&!a[2]){for(i.lineStart(),o=0;o<n;++o)i.point((r=t[o])[0],r[1]);return void i.lineEnd()}a[0]+=2e-6}u.push(e=new ps(r,t,null,!0)),c.push(e.o=new ps(r,null,e,!1)),u.push(e=new ps(a,t,null,!1)),c.push(e.o=new ps(a,null,e,!0))}})),u.length){for(c.sort(n),ys(u),ys(c),o=0,a=c.length;o<a;++o)c[o].e=e=!e;for(var f,s,l=u[0];;){for(var h=l,d=!0;h.v;)if((h=h.n)===l)return;f=h.z,i.lineStart();do{if(h.v=h.o.v=!0,h.e){if(d)for(o=0,a=f.length;o<a;++o)i.point((s=f[o])[0],s[1]);else r(h.x,h.n.x,1,i);h=h.n}else{if(d)for(f=h.p.z,o=f.length-1;o>=0;--o)i.point((s=f[o])[0],s[1]);else r(h.x,h.p.x,-1,i);h=h.p}f=(h=h.o).z,d=!d}while(!h.v);i.lineEnd()}}}function ys(t){if(n=t.length){for(var n,e,r=0,i=t[0];++r<n;)i.n=e=t[r],e.p=i,i=e;i.n=e=t[0],e.p=i}}function vs(t){return _c(t[0])<=hc?t[0]:kc(t[0])*((_c(t[0])+hc)%gc-hc)}function _s(t,n){var e=vs(n),r=n[1],i=Ec(r),o=[Ec(e),-xc(e),0],a=0,u=0,c=new g;1===i?r=dc+sc:-1===i&&(r=-dc-sc);for(var f=0,s=t.length;f<s;++f)if(h=(l=t[f]).length)for(var l,h,d=l[h-1],p=vs(d),y=d[1]/2+pc,v=Ec(y),_=xc(y),b=0;b<h;++b,p=x,v=M,_=A,d=m){var m=l[b],x=vs(m),w=m[1]/2+pc,M=Ec(w),A=xc(w),T=x-p,S=T>=0?1:-1,E=S*T,k=E>hc,N=v*M;if(c.add(mc(N*S*Ec(E),_*A+N*xc(E))),a+=k?T+S*gc:T,k^p>=e^x>=e){var C=pf(hf(d),hf(m));vf(C);var P=pf(o,C);vf(P);var z=(k^T>=0?-1:1)*zc(P[2]);(r>z||r===z&&(C[0]||C[1]))&&(u+=k^T>=0?1:-1)}}return(a<-1e-6||a<sc&&c<-1e-12)^1&u}function bs(t,n,e,r){return function(i){var o,a,u,c=n(i),f=hs(),s=n(f),l=!1,h={point:d,lineStart:g,lineEnd:y,polygonStart:function(){h.point=v,h.lineStart=_,h.lineEnd=b,a=[],o=[]},polygonEnd:function(){h.point=d,h.lineStart=g,h.lineEnd=y,a=O(a);var t=_s(o,r);a.length?(l||(i.polygonStart(),l=!0),gs(a,xs,t,e,i)):t&&(l||(i.polygonStart(),l=!0),i.lineStart(),e(null,null,1,i),i.lineEnd()),l&&(i.polygonEnd(),l=!1),a=o=null},sphere:function(){i.polygonStart(),i.lineStart(),e(null,null,1,i),i.lineEnd(),i.polygonEnd()}};function d(n,e){t(n,e)&&i.point(n,e)}function p(t,n){c.point(t,n)}function g(){h.point=p,c.lineStart()}function y(){h.point=d,c.lineEnd()}function v(t,n){u.push([t,n]),s.point(t,n)}function _(){s.lineStart(),u=[]}function b(){v(u[0][0],u[0][1]),s.lineEnd();var t,n,e,r,c=s.clean(),h=f.result(),d=h.length;if(u.pop(),o.push(u),u=null,d)if(1&c){if((n=(e=h[0]).length-1)>0){for(l||(i.polygonStart(),l=!0),i.lineStart(),t=0;t<n;++t)i.point((r=e[t])[0],r[1]);i.lineEnd()}}else d>1&&2&c&&h.push(h.pop().concat(h.shift())),a.push(h.filter(ms))}return h}}function ms(t){return t.length>1}function xs(t,n){return((t=t.x)[0]<0?t[1]-dc-sc:dc-t[1])-((n=n.x)[0]<0?n[1]-dc-sc:dc-n[1])}is.invert=is;var ws=bs((function(){return!0}),(function(t){var n,e=NaN,r=NaN,i=NaN;return{lineStart:function(){t.lineStart(),n=1},point:function(o,a){var u=o>0?hc:-hc,c=_c(o-e);_c(c-hc)<sc?(t.point(e,r=(r+a)/2>0?dc:-dc),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),t.point(o,r),n=0):i!==u&&c>=hc&&(_c(e-i)<sc&&(e-=i*sc),_c(o-u)<sc&&(o-=u*sc),r=function(t,n,e,r){var i,o,a=Ec(t-e);return _c(a)>sc?bc((Ec(n)*(o=xc(r))*Ec(e)-Ec(r)*(i=xc(n))*Ec(t))/(i*o*a)):(n+r)/2}(e,r,o,a),t.point(i,r),t.lineEnd(),t.lineStart(),t.point(u,r),n=0),t.point(e=o,r=a),i=u},lineEnd:function(){t.lineEnd(),e=r=NaN},clean:function(){return 2-n}}}),(function(t,n,e,r){var i;if(null==t)i=e*dc,r.point(-hc,i),r.point(0,i),r.point(hc,i),r.point(hc,0),r.point(hc,-i),r.point(0,-i),r.point(-hc,-i),r.point(-hc,0),r.point(-hc,i);else if(_c(t[0]-n[0])>sc){var o=t[0]<n[0]?hc:-hc;i=e*o/2,r.point(-o,i),r.point(0,i),r.point(o,i)}else r.point(n[0],n[1])}),[-hc,-dc]);function Ms(t){var n=xc(t),e=6*vc,r=n>0,i=_c(n)>sc;function o(t,e){return xc(t)*xc(e)>n}function a(t,e,r){var i=[1,0,0],o=pf(hf(t),hf(e)),a=df(o,o),u=o[0],c=a-u*u;if(!c)return!r&&t;var f=n*a/c,s=-n*u/c,l=pf(i,o),h=yf(i,f);gf(h,yf(o,s));var d=l,p=df(h,d),g=df(d,d),y=p*p-g*(df(h,h)-1);if(!(y<0)){var v=Nc(y),_=yf(d,(-p-v)/g);if(gf(_,h),_=lf(_),!r)return _;var b,m=t[0],x=e[0],w=t[1],M=e[1];x<m&&(b=m,m=x,x=b);var A=x-m,T=_c(A-hc)<sc;if(!T&&M<w&&(b=w,w=M,M=b),T||A<sc?T?w+M>0^_[1]<(_c(_[0]-m)<sc?w:M):w<=_[1]&&_[1]<=M:A>hc^(m<=_[0]&&_[0]<=x)){var S=yf(d,(-p+v)/g);return gf(S,h),[_,lf(S)]}}}function u(n,e){var i=r?t:hc-t,o=0;return n<-i?o|=1:n>i&&(o|=2),e<-i?o|=4:e>i&&(o|=8),o}return bs(o,(function(t){var n,e,c,f,s;return{lineStart:function(){f=c=!1,s=1},point:function(l,h){var d,p=[l,h],g=o(l,h),y=r?g?0:u(l,h):g?u(l+(l<0?hc:-hc),h):0;if(!n&&(f=c=g)&&t.lineStart(),g!==c&&(!(d=a(n,p))||ds(n,d)||ds(p,d))&&(p[2]=1),g!==c)s=0,g?(t.lineStart(),d=a(p,n),t.point(d[0],d[1])):(d=a(n,p),t.point(d[0],d[1],2),t.lineEnd()),n=d;else if(i&&n&&r^g){var v;y&e||!(v=a(p,n,!0))||(s=0,r?(t.lineStart(),t.point(v[0][0],v[0][1]),t.point(v[1][0],v[1][1]),t.lineEnd()):(t.point(v[1][0],v[1][1]),t.lineEnd(),t.lineStart(),t.point(v[0][0],v[0][1],3)))}!g||n&&ds(n,p)||t.point(p[0],p[1]),n=p,c=g,e=y},lineEnd:function(){c&&t.lineEnd(),n=null},clean:function(){return s|(f&&c)<<1}}}),(function(n,r,i,o){ss(o,t,e,i,n,r)}),r?[0,-t]:[-hc,t-hc])}var As,Ts,Ss,Es,ks=1e9,Ns=-ks;function Cs(t,n,e,r){function i(i,o){return t<=i&&i<=e&&n<=o&&o<=r}function o(i,o,u,f){var s=0,l=0;if(null==i||(s=a(i,u))!==(l=a(o,u))||c(i,o)<0^u>0)do{f.point(0===s||3===s?t:e,s>1?r:n)}while((s=(s+u+4)%4)!==l);else f.point(o[0],o[1])}function a(r,i){return _c(r[0]-t)<sc?i>0?0:3:_c(r[0]-e)<sc?i>0?2:1:_c(r[1]-n)<sc?i>0?1:0:i>0?3:2}function u(t,n){return c(t.x,n.x)}function c(t,n){var e=a(t,1),r=a(n,1);return e!==r?e-r:0===e?n[1]-t[1]:1===e?t[0]-n[0]:2===e?t[1]-n[1]:n[0]-t[0]}return function(a){var c,f,s,l,h,d,p,g,y,v,_,b=a,m=hs(),x={point:w,lineStart:function(){x.point=M,f&&f.push(s=[]);v=!0,y=!1,p=g=NaN},lineEnd:function(){c&&(M(l,h),d&&y&&m.rejoin(),c.push(m.result()));x.point=w,y&&b.lineEnd()},polygonStart:function(){b=m,c=[],f=[],_=!0},polygonEnd:function(){var n=function(){for(var n=0,e=0,i=f.length;e<i;++e)for(var o,a,u=f[e],c=1,s=u.length,l=u[0],h=l[0],d=l[1];c<s;++c)o=h,a=d,h=(l=u[c])[0],d=l[1],a<=r?d>r&&(h-o)*(r-a)>(d-a)*(t-o)&&++n:d<=r&&(h-o)*(r-a)<(d-a)*(t-o)&&--n;return n}(),e=_&&n,i=(c=O(c)).length;(e||i)&&(a.polygonStart(),e&&(a.lineStart(),o(null,null,1,a),a.lineEnd()),i&&gs(c,u,n,o,a),a.polygonEnd());b=a,c=f=s=null}};function w(t,n){i(t,n)&&b.point(t,n)}function M(o,a){var u=i(o,a);if(f&&s.push([o,a]),v)l=o,h=a,d=u,v=!1,u&&(b.lineStart(),b.point(o,a));else if(u&&y)b.point(o,a);else{var c=[p=Math.max(Ns,Math.min(ks,p)),g=Math.max(Ns,Math.min(ks,g))],m=[o=Math.max(Ns,Math.min(ks,o)),a=Math.max(Ns,Math.min(ks,a))];!function(t,n,e,r,i,o){var a,u=t[0],c=t[1],f=0,s=1,l=n[0]-u,h=n[1]-c;if(a=e-u,l||!(a>0)){if(a/=l,l<0){if(a<f)return;a<s&&(s=a)}else if(l>0){if(a>s)return;a>f&&(f=a)}if(a=i-u,l||!(a<0)){if(a/=l,l<0){if(a>s)return;a>f&&(f=a)}else if(l>0){if(a<f)return;a<s&&(s=a)}if(a=r-c,h||!(a>0)){if(a/=h,h<0){if(a<f)return;a<s&&(s=a)}else if(h>0){if(a>s)return;a>f&&(f=a)}if(a=o-c,h||!(a<0)){if(a/=h,h<0){if(a>s)return;a>f&&(f=a)}else if(h>0){if(a<f)return;a<s&&(s=a)}return f>0&&(t[0]=u+f*l,t[1]=c+f*h),s<1&&(n[0]=u+s*l,n[1]=c+s*h),!0}}}}}(c,m,t,n,e,r)?u&&(b.lineStart(),b.point(o,a),_=!1):(y||(b.lineStart(),b.point(c[0],c[1])),b.point(m[0],m[1]),u||b.lineEnd(),_=!1)}p=o,g=a,y=u}return x}}var Ps={sphere:qc,point:qc,lineStart:function(){Ps.point=Ds,Ps.lineEnd=zs},lineEnd:qc,polygonStart:qc,polygonEnd:qc};function zs(){Ps.point=Ps.lineEnd=qc}function Ds(t,n){Ts=t*=vc,Ss=Ec(n*=vc),Es=xc(n),Ps.point=qs}function qs(t,n){t*=vc;var e=Ec(n*=vc),r=xc(n),i=_c(t-Ts),o=xc(i),a=r*Ec(i),u=Es*e-Ss*r*o,c=Ss*e+Es*r*o;As.add(mc(Nc(a*a+u*u),c)),Ts=t,Ss=e,Es=r}function Rs(t){return As=new g,Bc(t,Ps),+As}var Fs=[null,null],Os={type:"LineString",coordinates:Fs};function Us(t,n){return Fs[0]=t,Fs[1]=n,Rs(Os)}var Is={Feature:function(t,n){return Ys(t.geometry,n)},FeatureCollection:function(t,n){for(var e=t.features,r=-1,i=e.length;++r<i;)if(Ys(e[r].geometry,n))return!0;return!1}},Bs={Sphere:function(){return!0},Point:function(t,n){return Ls(t.coordinates,n)},MultiPoint:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Ls(e[r],n))return!0;return!1},LineString:function(t,n){return js(t.coordinates,n)},MultiLineString:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(js(e[r],n))return!0;return!1},Polygon:function(t,n){return Hs(t.coordinates,n)},MultiPolygon:function(t,n){for(var e=t.coordinates,r=-1,i=e.length;++r<i;)if(Hs(e[r],n))return!0;return!1},GeometryCollection:function(t,n){for(var e=t.geometries,r=-1,i=e.length;++r<i;)if(Ys(e[r],n))return!0;return!1}};function Ys(t,n){return!(!t||!Bs.hasOwnProperty(t.type))&&Bs[t.type](t,n)}function Ls(t,n){return 0===Us(t,n)}function js(t,n){for(var e,r,i,o=0,a=t.length;o<a;o++){if(0===(r=Us(t[o],n)))return!0;if(o>0&&(i=Us(t[o],t[o-1]))>0&&e<=i&&r<=i&&(e+r-i)*(1-Math.pow((e-r)/i,2))<lc*i)return!0;e=r}return!1}function Hs(t,n){return!!_s(t.map(Xs),Gs(n))}function Xs(t){return(t=t.map(Gs)).pop(),t}function Gs(t){return[t[0]*vc,t[1]*vc]}function Vs(t,n,e){var r=Y(t,n-sc,e).concat(n);return function(t){return r.map((function(n){return[t,n]}))}}function $s(t,n,e){var r=Y(t,n-sc,e).concat(n);return function(t){return r.map((function(n){return[n,t]}))}}function Ws(){var t,n,e,r,i,o,a,u,c,f,s,l,h=10,d=h,p=90,g=360,y=2.5;function v(){return{type:"MultiLineString",coordinates:_()}}function _(){return Y(wc(r/p)*p,e,p).map(s).concat(Y(wc(u/g)*g,a,g).map(l)).concat(Y(wc(n/h)*h,t,h).filter((function(t){return _c(t%p)>sc})).map(c)).concat(Y(wc(o/d)*d,i,d).filter((function(t){return _c(t%g)>sc})).map(f))}return v.lines=function(){return _().map((function(t){return{type:"LineString",coordinates:t}}))},v.outline=function(){return{type:"Polygon",coordinates:[s(r).concat(l(a).slice(1),s(e).reverse().slice(1),l(u).reverse().slice(1))]}},v.extent=function(t){return arguments.length?v.extentMajor(t).extentMinor(t):v.extentMinor()},v.extentMajor=function(t){return arguments.length?(r=+t[0][0],e=+t[1][0],u=+t[0][1],a=+t[1][1],r>e&&(t=r,r=e,e=t),u>a&&(t=u,u=a,a=t),v.precision(y)):[[r,u],[e,a]]},v.extentMinor=function(e){return arguments.length?(n=+e[0][0],t=+e[1][0],o=+e[0][1],i=+e[1][1],n>t&&(e=n,n=t,t=e),o>i&&(e=o,o=i,i=e),v.precision(y)):[[n,o],[t,i]]},v.step=function(t){return arguments.length?v.stepMajor(t).stepMinor(t):v.stepMinor()},v.stepMajor=function(t){return arguments.length?(p=+t[0],g=+t[1],v):[p,g]},v.stepMinor=function(t){return arguments.length?(h=+t[0],d=+t[1],v):[h,d]},v.precision=function(h){return arguments.length?(y=+h,c=Vs(o,i,90),f=$s(n,t,y),s=Vs(u,a,90),l=$s(r,e,y),v):y},v.extentMajor([[-180,-89.999999],[180,89.999999]]).extentMinor([[-180,-80.000001],[180,80.000001]])}var Zs,Ks,Qs,Js,tl=t=>t,nl=new g,el=new g,rl={point:qc,lineStart:qc,lineEnd:qc,polygonStart:function(){rl.lineStart=il,rl.lineEnd=ul},polygonEnd:function(){rl.lineStart=rl.lineEnd=rl.point=qc,nl.add(_c(el)),el=new g},result:function(){var t=nl/2;return nl=new g,t}};function il(){rl.point=ol}function ol(t,n){rl.point=al,Zs=Qs=t,Ks=Js=n}function al(t,n){el.add(Js*t-Qs*n),Qs=t,Js=n}function ul(){al(Zs,Ks)}var cl=1/0,fl=cl,sl=-cl,ll=sl,hl={point:function(t,n){t<cl&&(cl=t);t>sl&&(sl=t);n<fl&&(fl=n);n>ll&&(ll=n)},lineStart:qc,lineEnd:qc,polygonStart:qc,polygonEnd:qc,result:function(){var t=[[cl,fl],[sl,ll]];return sl=ll=-(fl=cl=1/0),t}};var dl,pl,gl,yl,vl=0,_l=0,bl=0,ml=0,xl=0,wl=0,Ml=0,Al=0,Tl=0,Sl={point:El,lineStart:kl,lineEnd:Pl,polygonStart:function(){Sl.lineStart=zl,Sl.lineEnd=Dl},polygonEnd:function(){Sl.point=El,Sl.lineStart=kl,Sl.lineEnd=Pl},result:function(){var t=Tl?[Ml/Tl,Al/Tl]:wl?[ml/wl,xl/wl]:bl?[vl/bl,_l/bl]:[NaN,NaN];return vl=_l=bl=ml=xl=wl=Ml=Al=Tl=0,t}};function El(t,n){vl+=t,_l+=n,++bl}function kl(){Sl.point=Nl}function Nl(t,n){Sl.point=Cl,El(gl=t,yl=n)}function Cl(t,n){var e=t-gl,r=n-yl,i=Nc(e*e+r*r);ml+=i*(gl+t)/2,xl+=i*(yl+n)/2,wl+=i,El(gl=t,yl=n)}function Pl(){Sl.point=El}function zl(){Sl.point=ql}function Dl(){Rl(dl,pl)}function ql(t,n){Sl.point=Rl,El(dl=gl=t,pl=yl=n)}function Rl(t,n){var e=t-gl,r=n-yl,i=Nc(e*e+r*r);ml+=i*(gl+t)/2,xl+=i*(yl+n)/2,wl+=i,Ml+=(i=yl*t-gl*n)*(gl+t),Al+=i*(yl+n),Tl+=3*i,El(gl=t,yl=n)}function Fl(t){this._context=t}Fl.prototype={_radius:4.5,pointRadius:function(t){return this._radius=t,this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._context.closePath(),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._context.moveTo(t,n),this._point=1;break;case 1:this._context.lineTo(t,n);break;default:this._context.moveTo(t+this._radius,n),this._context.arc(t,n,this._radius,0,gc)}},result:qc};var Ol,Ul,Il,Bl,Yl,Ll=new g,jl={point:qc,lineStart:function(){jl.point=Hl},lineEnd:function(){Ol&&Xl(Ul,Il),jl.point=qc},polygonStart:function(){Ol=!0},polygonEnd:function(){Ol=null},result:function(){var t=+Ll;return Ll=new g,t}};function Hl(t,n){jl.point=Xl,Ul=Bl=t,Il=Yl=n}function Xl(t,n){Bl-=t,Yl-=n,Ll.add(Nc(Bl*Bl+Yl*Yl)),Bl=t,Yl=n}function Gl(){this._string=[]}function Vl(t){return"m0,"+t+"a"+t+","+t+" 0 1,1 0,"+-2*t+"a"+t+","+t+" 0 1,1 0,"+2*t+"z"}function $l(t){return function(n){var e=new Wl;for(var r in t)e[r]=t[r];return e.stream=n,e}}function Wl(){}function Zl(t,n,e){var r=t.clipExtent&&t.clipExtent();return t.scale(150).translate([0,0]),null!=r&&t.clipExtent(null),Bc(e,t.stream(hl)),n(hl.result()),null!=r&&t.clipExtent(r),t}function Kl(t,n,e){return Zl(t,(function(e){var r=n[1][0]-n[0][0],i=n[1][1]-n[0][1],o=Math.min(r/(e[1][0]-e[0][0]),i/(e[1][1]-e[0][1])),a=+n[0][0]+(r-o*(e[1][0]+e[0][0]))/2,u=+n[0][1]+(i-o*(e[1][1]+e[0][1]))/2;t.scale(150*o).translate([a,u])}),e)}function Ql(t,n,e){return Kl(t,[[0,0],n],e)}function Jl(t,n,e){return Zl(t,(function(e){var r=+n,i=r/(e[1][0]-e[0][0]),o=(r-i*(e[1][0]+e[0][0]))/2,a=-i*e[0][1];t.scale(150*i).translate([o,a])}),e)}function th(t,n,e){return Zl(t,(function(e){var r=+n,i=r/(e[1][1]-e[0][1]),o=-i*e[0][0],a=(r-i*(e[1][1]+e[0][1]))/2;t.scale(150*i).translate([o,a])}),e)}Gl.prototype={_radius:4.5,_circle:Vl(4.5),pointRadius:function(t){return(t=+t)!==this._radius&&(this._radius=t,this._circle=null),this},polygonStart:function(){this._line=0},polygonEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){0===this._line&&this._string.push("Z"),this._point=NaN},point:function(t,n){switch(this._point){case 0:this._string.push("M",t,",",n),this._point=1;break;case 1:this._string.push("L",t,",",n);break;default:null==this._circle&&(this._circle=Vl(this._radius)),this._string.push("M",t,",",n,this._circle)}},result:function(){if(this._string.length){var t=this._string.join("");return this._string=[],t}return null}},Wl.prototype={constructor:Wl,point:function(t,n){this.stream.point(t,n)},sphere:function(){this.stream.sphere()},lineStart:function(){this.stream.lineStart()},lineEnd:function(){this.stream.lineEnd()},polygonStart:function(){this.stream.polygonStart()},polygonEnd:function(){this.stream.polygonEnd()}};var nh=xc(30*vc);function eh(t,n){return+n?function(t,n){function e(r,i,o,a,u,c,f,s,l,h,d,p,g,y){var v=f-r,_=s-i,b=v*v+_*_;if(b>4*n&&g--){var m=a+h,x=u+d,w=c+p,M=Nc(m*m+x*x+w*w),A=zc(w/=M),T=_c(_c(w)-1)<sc||_c(o-l)<sc?(o+l)/2:mc(x,m),S=t(T,A),E=S[0],k=S[1],N=E-r,C=k-i,P=_*N-v*C;(P*P/b>n||_c((v*N+_*C)/b-.5)>.3||a*h+u*d+c*p<nh)&&(e(r,i,o,a,u,c,E,k,T,m/=M,x/=M,w,g,y),y.point(E,k),e(E,k,T,m,x,w,f,s,l,h,d,p,g,y))}}return function(n){var r,i,o,a,u,c,f,s,l,h,d,p,g={point:y,lineStart:v,lineEnd:b,polygonStart:function(){n.polygonStart(),g.lineStart=m},polygonEnd:function(){n.polygonEnd(),g.lineStart=v}};function y(e,r){e=t(e,r),n.point(e[0],e[1])}function v(){s=NaN,g.point=_,n.lineStart()}function _(r,i){var o=hf([r,i]),a=t(r,i);e(s,l,f,h,d,p,s=a[0],l=a[1],f=r,h=o[0],d=o[1],p=o[2],16,n),n.point(s,l)}function b(){g.point=y,n.lineEnd()}function m(){v(),g.point=x,g.lineEnd=w}function x(t,n){_(r=t,n),i=s,o=l,a=h,u=d,c=p,g.point=_}function w(){e(s,l,f,h,d,p,i,o,r,a,u,c,16,n),g.lineEnd=b,b()}return g}}(t,n):function(t){return $l({point:function(n,e){n=t(n,e),this.stream.point(n[0],n[1])}})}(t)}var rh=$l({point:function(t,n){this.stream.point(t*vc,n*vc)}});function ih(t,n,e,r,i,o){if(!o)return function(t,n,e,r,i){function o(o,a){return[n+t*(o*=r),e-t*(a*=i)]}return o.invert=function(o,a){return[(o-n)/t*r,(e-a)/t*i]},o}(t,n,e,r,i);var a=xc(o),u=Ec(o),c=a*t,f=u*t,s=a/t,l=u/t,h=(u*e-a*n)/t,d=(u*n+a*e)/t;function p(t,o){return[c*(t*=r)-f*(o*=i)+n,e-f*t-c*o]}return p.invert=function(t,n){return[r*(s*t-l*n+h),i*(d-l*t-s*n)]},p}function oh(t){return ah((function(){return t}))()}function ah(t){var n,e,r,i,o,a,u,c,f,s,l=150,h=480,d=250,p=0,g=0,y=0,v=0,_=0,b=0,m=1,x=1,w=null,M=ws,A=null,T=tl,S=.5;function E(t){return c(t[0]*vc,t[1]*vc)}function k(t){return(t=c.invert(t[0],t[1]))&&[t[0]*yc,t[1]*yc]}function N(){var t=ih(l,0,0,m,x,b).apply(null,n(p,g)),r=ih(l,h-t[0],d-t[1],m,x,b);return e=os(y,v,_),u=rs(n,r),c=rs(e,u),a=eh(u,S),C()}function C(){return f=s=null,E}return E.stream=function(t){return f&&s===t?f:f=rh(function(t){return $l({point:function(n,e){var r=t(n,e);return this.stream.point(r[0],r[1])}})}(e)(M(a(T(s=t)))))},E.preclip=function(t){return arguments.length?(M=t,w=void 0,C()):M},E.postclip=function(t){return arguments.length?(T=t,A=r=i=o=null,C()):T},E.clipAngle=function(t){return arguments.length?(M=+t?Ms(w=t*vc):(w=null,ws),C()):w*yc},E.clipExtent=function(t){return arguments.length?(T=null==t?(A=r=i=o=null,tl):Cs(A=+t[0][0],r=+t[0][1],i=+t[1][0],o=+t[1][1]),C()):null==A?null:[[A,r],[i,o]]},E.scale=function(t){return arguments.length?(l=+t,N()):l},E.translate=function(t){return arguments.length?(h=+t[0],d=+t[1],N()):[h,d]},E.center=function(t){return arguments.length?(p=t[0]%360*vc,g=t[1]%360*vc,N()):[p*yc,g*yc]},E.rotate=function(t){return arguments.length?(y=t[0]%360*vc,v=t[1]%360*vc,_=t.length>2?t[2]%360*vc:0,N()):[y*yc,v*yc,_*yc]},E.angle=function(t){return arguments.length?(b=t%360*vc,N()):b*yc},E.reflectX=function(t){return arguments.length?(m=t?-1:1,N()):m<0},E.reflectY=function(t){return arguments.length?(x=t?-1:1,N()):x<0},E.precision=function(t){return arguments.length?(a=eh(u,S=t*t),C()):Nc(S)},E.fitExtent=function(t,n){return Kl(E,t,n)},E.fitSize=function(t,n){return Ql(E,t,n)},E.fitWidth=function(t,n){return Jl(E,t,n)},E.fitHeight=function(t,n){return th(E,t,n)},function(){return n=t.apply(this,arguments),E.invert=n.invert&&k,N()}}function uh(t){var n=0,e=hc/3,r=ah(t),i=r(n,e);return i.parallels=function(t){return arguments.length?r(n=t[0]*vc,e=t[1]*vc):[n*yc,e*yc]},i}function ch(t,n){var e=Ec(t),r=(e+Ec(n))/2;if(_c(r)<sc)return function(t){var n=xc(t);function e(t,e){return[t*n,Ec(e)/n]}return e.invert=function(t,e){return[t/n,zc(e*n)]},e}(t);var i=1+e*(2*r-e),o=Nc(i)/r;function a(t,n){var e=Nc(i-2*r*Ec(n))/r;return[e*Ec(t*=r),o-e*xc(t)]}return a.invert=function(t,n){var e=o-n,a=mc(t,_c(e))*kc(e);return e*r<0&&(a-=hc*kc(t)*kc(e)),[a/r,zc((i-(t*t+e*e)*r*r)/(2*r))]},a}function fh(){return uh(ch).scale(155.424).center([0,33.6442])}function sh(){return fh().parallels([29.5,45.5]).scale(1070).translate([480,250]).rotate([96,0]).center([-.6,38.7])}function lh(t){return function(n,e){var r=xc(n),i=xc(e),o=t(r*i);return o===1/0?[2,0]:[o*i*Ec(n),o*Ec(e)]}}function hh(t){return function(n,e){var r=Nc(n*n+e*e),i=t(r),o=Ec(i),a=xc(i);return[mc(n*o,r*a),zc(r&&e*o/r)]}}var dh=lh((function(t){return Nc(2/(1+t))}));dh.invert=hh((function(t){return 2*zc(t/2)}));var ph=lh((function(t){return(t=Pc(t))&&t/Ec(t)}));function gh(t,n){return[t,Tc(Cc((dc+n)/2))]}function yh(t){var n,e,r,i=oh(t),o=i.center,a=i.scale,u=i.translate,c=i.clipExtent,f=null;function s(){var o=hc*a(),u=i(fs(i.rotate()).invert([0,0]));return c(null==f?[[u[0]-o,u[1]-o],[u[0]+o,u[1]+o]]:t===gh?[[Math.max(u[0]-o,f),n],[Math.min(u[0]+o,e),r]]:[[f,Math.max(u[1]-o,n)],[e,Math.min(u[1]+o,r)]])}return i.scale=function(t){return arguments.length?(a(t),s()):a()},i.translate=function(t){return arguments.length?(u(t),s()):u()},i.center=function(t){return arguments.length?(o(t),s()):o()},i.clipExtent=function(t){return arguments.length?(null==t?f=n=e=r=null:(f=+t[0][0],n=+t[0][1],e=+t[1][0],r=+t[1][1]),s()):null==f?null:[[f,n],[e,r]]},s()}function vh(t){return Cc((dc+t)/2)}function _h(t,n){var e=xc(t),r=t===n?Ec(t):Tc(e/xc(n))/Tc(vh(n)/vh(t)),i=e*Sc(vh(t),r)/r;if(!r)return gh;function o(t,n){i>0?n<-dc+sc&&(n=-dc+sc):n>dc-sc&&(n=dc-sc);var e=i/Sc(vh(n),r);return[e*Ec(r*t),i-e*xc(r*t)]}return o.invert=function(t,n){var e=i-n,o=kc(r)*Nc(t*t+e*e),a=mc(t,_c(e))*kc(e);return e*r<0&&(a-=hc*kc(t)*kc(e)),[a/r,2*bc(Sc(i/o,1/r))-dc]},o}function bh(t,n){return[t,n]}function mh(t,n){var e=xc(t),r=t===n?Ec(t):(e-xc(n))/(n-t),i=e/r+t;if(_c(r)<sc)return bh;function o(t,n){var e=i-n,o=r*t;return[e*Ec(o),i-e*xc(o)]}return o.invert=function(t,n){var e=i-n,o=mc(t,_c(e))*kc(e);return e*r<0&&(o-=hc*kc(t)*kc(e)),[o/r,i-kc(r)*Nc(t*t+e*e)]},o}ph.invert=hh((function(t){return t})),gh.invert=function(t,n){return[t,2*bc(Mc(n))-dc]},bh.invert=bh;var xh=1.340264,wh=-.081106,Mh=893e-6,Ah=.003796,Th=Nc(3)/2;function Sh(t,n){var e=zc(Th*Ec(n)),r=e*e,i=r*r*r;return[t*xc(e)/(Th*(xh+3*wh*r+i*(7*Mh+9*Ah*r))),e*(xh+wh*r+i*(Mh+Ah*r))]}function Eh(t,n){var e=xc(n),r=xc(t)*e;return[e*Ec(t)/r,Ec(n)/r]}function kh(t,n){var e=n*n,r=e*e;return[t*(.8707-.131979*e+r*(r*(.003971*e-.001529*r)-.013791)),n*(1.007226+e*(.015085+r*(.028874*e-.044475-.005916*r)))]}function Nh(t,n){return[xc(n)*Ec(t),Ec(n)]}function Ch(t,n){var e=xc(n),r=1+xc(t)*e;return[e*Ec(t)/r,Ec(n)/r]}function Ph(t,n){return[Tc(Cc((dc+n)/2)),-t]}function zh(t,n){return t.parent===n.parent?1:2}function Dh(t,n){return t+n.x}function qh(t,n){return Math.max(t,n.y)}function Rh(t){var n=0,e=t.children,r=e&&e.length;if(r)for(;--r>=0;)n+=e[r].value;else n=1;t.value=n}function Fh(t,n){t instanceof Map?(t=[void 0,t],void 0===n&&(n=Uh)):void 0===n&&(n=Oh);for(var e,r,i,o,a,u=new Yh(t),c=[u];e=c.pop();)if((i=n(e.data))&&(a=(i=Array.from(i)).length))for(e.children=i,o=a-1;o>=0;--o)c.push(r=i[o]=new Yh(i[o])),r.parent=e,r.depth=e.depth+1;return u.eachBefore(Bh)}function Oh(t){return t.children}function Uh(t){return Array.isArray(t)?t[1]:null}function Ih(t){void 0!==t.data.value&&(t.value=t.data.value),t.data=t.data.data}function Bh(t){var n=0;do{t.height=n}while((t=t.parent)&&t.height<++n)}function Yh(t){this.data=t,this.depth=this.height=0,this.parent=null}function Lh(t){for(var n,e,r=0,i=(t=function(t){for(var n,e,r=t.length;r;)e=Math.random()*r--|0,n=t[r],t[r]=t[e],t[e]=n;return t}(Array.from(t))).length,o=[];r<i;)n=t[r],e&&Xh(e,n)?++r:(e=Vh(o=jh(o,n)),r=0);return e}function jh(t,n){var e,r;if(Gh(n,t))return[n];for(e=0;e<t.length;++e)if(Hh(n,t[e])&&Gh($h(t[e],n),t))return[t[e],n];for(e=0;e<t.length-1;++e)for(r=e+1;r<t.length;++r)if(Hh($h(t[e],t[r]),n)&&Hh($h(t[e],n),t[r])&&Hh($h(t[r],n),t[e])&&Gh(Wh(t[e],t[r],n),t))return[t[e],t[r],n];throw new Error}function Hh(t,n){var e=t.r-n.r,r=n.x-t.x,i=n.y-t.y;return e<0||e*e<r*r+i*i}function Xh(t,n){var e=t.r-n.r+1e-9*Math.max(t.r,n.r,1),r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Gh(t,n){for(var e=0;e<n.length;++e)if(!Xh(t,n[e]))return!1;return!0}function Vh(t){switch(t.length){case 1:return function(t){return{x:t.x,y:t.y,r:t.r}}(t[0]);case 2:return $h(t[0],t[1]);case 3:return Wh(t[0],t[1],t[2])}}function $h(t,n){var e=t.x,r=t.y,i=t.r,o=n.x,a=n.y,u=n.r,c=o-e,f=a-r,s=u-i,l=Math.sqrt(c*c+f*f);return{x:(e+o+c/l*s)/2,y:(r+a+f/l*s)/2,r:(l+i+u)/2}}function Wh(t,n,e){var r=t.x,i=t.y,o=t.r,a=n.x,u=n.y,c=n.r,f=e.x,s=e.y,l=e.r,h=r-a,d=r-f,p=i-u,g=i-s,y=c-o,v=l-o,_=r*r+i*i-o*o,b=_-a*a-u*u+c*c,m=_-f*f-s*s+l*l,x=d*p-h*g,w=(p*m-g*b)/(2*x)-r,M=(g*y-p*v)/x,A=(d*b-h*m)/(2*x)-i,T=(h*v-d*y)/x,S=M*M+T*T-1,E=2*(o+w*M+A*T),k=w*w+A*A-o*o,N=-(S?(E+Math.sqrt(E*E-4*S*k))/(2*S):k/E);return{x:r+w+M*N,y:i+A+T*N,r:N}}function Zh(t,n,e){var r,i,o,a,u=t.x-n.x,c=t.y-n.y,f=u*u+c*c;f?(i=n.r+e.r,i*=i,a=t.r+e.r,i>(a*=a)?(r=(f+a-i)/(2*f),o=Math.sqrt(Math.max(0,a/f-r*r)),e.x=t.x-r*u-o*c,e.y=t.y-r*c+o*u):(r=(f+i-a)/(2*f),o=Math.sqrt(Math.max(0,i/f-r*r)),e.x=n.x+r*u-o*c,e.y=n.y+r*c+o*u)):(e.x=n.x+e.r,e.y=n.y)}function Kh(t,n){var e=t.r+n.r-1e-6,r=n.x-t.x,i=n.y-t.y;return e>0&&e*e>r*r+i*i}function Qh(t){var n=t._,e=t.next._,r=n.r+e.r,i=(n.x*e.r+e.x*n.r)/r,o=(n.y*e.r+e.y*n.r)/r;return i*i+o*o}function Jh(t){this._=t,this.next=null,this.previous=null}function td(t){if(!(i=(t=function(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}(t)).length))return 0;var n,e,r,i,o,a,u,c,f,s,l;if((n=t[0]).x=0,n.y=0,!(i>1))return n.r;if(e=t[1],n.x=-e.r,e.x=n.r,e.y=0,!(i>2))return n.r+e.r;Zh(e,n,r=t[2]),n=new Jh(n),e=new Jh(e),r=new Jh(r),n.next=r.previous=e,e.next=n.previous=r,r.next=e.previous=n;t:for(u=3;u<i;++u){Zh(n._,e._,r=t[u]),r=new Jh(r),c=e.next,f=n.previous,s=e._.r,l=n._.r;do{if(s<=l){if(Kh(c._,r._)){e=c,n.next=e,e.previous=n,--u;continue t}s+=c._.r,c=c.next}else{if(Kh(f._,r._)){(n=f).next=e,e.previous=n,--u;continue t}l+=f._.r,f=f.previous}}while(c!==f.next);for(r.previous=n,r.next=e,n.next=e.previous=e=r,o=Qh(n);(r=r.next)!==e;)(a=Qh(r))<o&&(n=r,o=a);e=n.next}for(n=[e._],r=e;(r=r.next)!==e;)n.push(r._);for(r=Lh(n),u=0;u<i;++u)(n=t[u]).x-=r.x,n.y-=r.y;return r.r}function nd(t){return null==t?null:ed(t)}function ed(t){if("function"!=typeof t)throw new Error;return t}function rd(){return 0}function id(t){return function(){return t}}function od(t){return Math.sqrt(t.value)}function ad(t){return function(n){n.children||(n.r=Math.max(0,+t(n)||0))}}function ud(t,n){return function(e){if(r=e.children){var r,i,o,a=r.length,u=t(e)*n||0;if(u)for(i=0;i<a;++i)r[i].r+=u;if(o=td(r),u)for(i=0;i<a;++i)r[i].r-=u;e.r=o+u}}}function cd(t){return function(n){var e=n.parent;n.r*=t,e&&(n.x=e.x+t*n.x,n.y=e.y+t*n.y)}}function fd(t){t.x0=Math.round(t.x0),t.y0=Math.round(t.y0),t.x1=Math.round(t.x1),t.y1=Math.round(t.y1)}function sd(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(r-n)/t.value;++u<c;)(o=a[u]).y0=e,o.y1=i,o.x0=n,o.x1=n+=o.value*f}Sh.invert=function(t,n){for(var e,r=n,i=r*r,o=i*i*i,a=0;a<12&&(o=(i=(r-=e=(r*(xh+wh*i+o*(Mh+Ah*i))-n)/(xh+3*wh*i+o*(7*Mh+9*Ah*i)))*r)*i*i,!(_c(e)<lc));++a);return[Th*t*(xh+3*wh*i+o*(7*Mh+9*Ah*i))/xc(r),zc(Ec(r)/Th)]},Eh.invert=hh(bc),kh.invert=function(t,n){var e,r=n,i=25;do{var o=r*r,a=o*o;r-=e=(r*(1.007226+o*(.015085+a*(.028874*o-.044475-.005916*a)))-n)/(1.007226+o*(.045255+a*(.259866*o-.311325-.005916*11*a)))}while(_c(e)>sc&&--i>0);return[t/(.8707+(o=r*r)*(o*(o*o*o*(.003971-.001529*o)-.013791)-.131979)),r]},Nh.invert=hh(zc),Ch.invert=hh((function(t){return 2*bc(t)})),Ph.invert=function(t,n){return[-n,2*bc(Mc(t))-dc]},Yh.prototype=Fh.prototype={constructor:Yh,count:function(){return this.eachAfter(Rh)},each:function(t,n){let e=-1;for(const r of this)t.call(n,r,++e,this);return this},eachAfter:function(t,n){for(var e,r,i,o=this,a=[o],u=[],c=-1;o=a.pop();)if(u.push(o),e=o.children)for(r=0,i=e.length;r<i;++r)a.push(e[r]);for(;o=u.pop();)t.call(n,o,++c,this);return this},eachBefore:function(t,n){for(var e,r,i=this,o=[i],a=-1;i=o.pop();)if(t.call(n,i,++a,this),e=i.children)for(r=e.length-1;r>=0;--r)o.push(e[r]);return this},find:function(t,n){let e=-1;for(const r of this)if(t.call(n,r,++e,this))return r},sum:function(t){return this.eachAfter((function(n){for(var e=+t(n.data)||0,r=n.children,i=r&&r.length;--i>=0;)e+=r[i].value;n.value=e}))},sort:function(t){return this.eachBefore((function(n){n.children&&n.children.sort(t)}))},path:function(t){for(var n=this,e=function(t,n){if(t===n)return t;var e=t.ancestors(),r=n.ancestors(),i=null;t=e.pop(),n=r.pop();for(;t===n;)i=t,t=e.pop(),n=r.pop();return i}(n,t),r=[n];n!==e;)n=n.parent,r.push(n);for(var i=r.length;t!==e;)r.splice(i,0,t),t=t.parent;return r},ancestors:function(){for(var t=this,n=[t];t=t.parent;)n.push(t);return n},descendants:function(){return Array.from(this)},leaves:function(){var t=[];return this.eachBefore((function(n){n.children||t.push(n)})),t},links:function(){var t=this,n=[];return t.each((function(e){e!==t&&n.push({source:e.parent,target:e})})),n},copy:function(){return Fh(this).eachBefore(Ih)},[Symbol.iterator]:function*(){var t,n,e,r,i=this,o=[i];do{for(t=o.reverse(),o=[];i=t.pop();)if(yield i,n=i.children)for(e=0,r=n.length;e<r;++e)o.push(n[e])}while(o.length)}};var ld={depth:-1},hd={};function dd(t){return t.id}function pd(t){return t.parentId}function gd(t,n){return t.parent===n.parent?1:2}function yd(t){var n=t.children;return n?n[0]:t.t}function vd(t){var n=t.children;return n?n[n.length-1]:t.t}function _d(t,n,e){var r=e/(n.i-t.i);n.c-=r,n.s+=e,t.c+=r,n.z+=e,n.m+=e}function bd(t,n,e){return t.a.parent===n.parent?t.a:e}function md(t,n){this._=t,this.parent=null,this.children=null,this.A=null,this.a=this,this.z=0,this.m=0,this.c=0,this.s=0,this.t=null,this.i=n}function xd(t,n,e,r,i){for(var o,a=t.children,u=-1,c=a.length,f=t.value&&(i-e)/t.value;++u<c;)(o=a[u]).x0=n,o.x1=r,o.y0=e,o.y1=e+=o.value*f}md.prototype=Object.create(Yh.prototype);var wd=(1+Math.sqrt(5))/2;function Md(t,n,e,r,i,o){for(var a,u,c,f,s,l,h,d,p,g,y,v=[],_=n.children,b=0,m=0,x=_.length,w=n.value;b<x;){c=i-e,f=o-r;do{s=_[m++].value}while(!s&&m<x);for(l=h=s,y=s*s*(g=Math.max(f/c,c/f)/(w*t)),p=Math.max(h/y,y/l);m<x;++m){if(s+=u=_[m].value,u<l&&(l=u),u>h&&(h=u),y=s*s*g,(d=Math.max(h/y,y/l))>p){s-=u;break}p=d}v.push(a={value:s,dice:c<f,children:_.slice(b,m)}),a.dice?sd(a,e,r,i,w?r+=f*s/w:o):xd(a,e,r,w?e+=c*s/w:i,o),w-=s,b=m}return v}var Ad=function t(n){function e(t,e,r,i,o){Md(n,t,e,r,i,o)}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(wd);var Td=function t(n){function e(t,e,r,i,o){if((a=t._squarify)&&a.ratio===n)for(var a,u,c,f,s,l=-1,h=a.length,d=t.value;++l<h;){for(c=(u=a[l]).children,f=u.value=0,s=c.length;f<s;++f)u.value+=c[f].value;u.dice?sd(u,e,r,i,d?r+=(o-r)*u.value/d:o):xd(u,e,r,d?e+=(i-e)*u.value/d:i,o),d-=u.value}else t._squarify=a=Md(n,t,e,r,i,o),a.ratio=n}return e.ratio=function(n){return t((n=+n)>1?n:1)},e}(wd);function Sd(t,n,e){return(n[0]-t[0])*(e[1]-t[1])-(n[1]-t[1])*(e[0]-t[0])}function Ed(t,n){return t[0]-n[0]||t[1]-n[1]}function kd(t){const n=t.length,e=[0,1];let r,i=2;for(r=2;r<n;++r){for(;i>1&&Sd(t[e[i-2]],t[e[i-1]],t[r])<=0;)--i;e[i++]=r}return e.slice(0,i)}var Nd=Math.random,Cd=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,1===arguments.length?(e=t,t=0):e-=t,function(){return n()*e+t}}return e.source=t,e}(Nd),Pd=function t(n){function e(t,e){return arguments.length<2&&(e=t,t=0),t=Math.floor(t),e=Math.floor(e)-t,function(){return Math.floor(n()*e+t)}}return e.source=t,e}(Nd),zd=function t(n){function e(t,e){var r,i;return t=null==t?0:+t,e=null==e?1:+e,function(){var o;if(null!=r)o=r,r=null;else do{r=2*n()-1,o=2*n()-1,i=r*r+o*o}while(!i||i>1);return t+e*o*Math.sqrt(-2*Math.log(i)/i)}}return e.source=t,e}(Nd),Dd=function t(n){var e=zd.source(n);function r(){var t=e.apply(this,arguments);return function(){return Math.exp(t())}}return r.source=t,r}(Nd),qd=function t(n){function e(t){return(t=+t)<=0?()=>0:function(){for(var e=0,r=t;r>1;--r)e+=n();return e+r*n()}}return e.source=t,e}(Nd),Rd=function t(n){var e=qd.source(n);function r(t){if(0==(t=+t))return n;var r=e(t);return function(){return r()/t}}return r.source=t,r}(Nd),Fd=function t(n){function e(t){return function(){return-Math.log1p(-n())/t}}return e.source=t,e}(Nd),Od=function t(n){function e(t){if((t=+t)<0)throw new RangeError("invalid alpha");return t=1/-t,function(){return Math.pow(1-n(),t)}}return e.source=t,e}(Nd),Ud=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return function(){return Math.floor(n()+t)}}return e.source=t,e}(Nd),Id=function t(n){function e(t){if((t=+t)<0||t>1)throw new RangeError("invalid p");return 0===t?()=>1/0:1===t?()=>1:(t=Math.log1p(-t),function(){return 1+Math.floor(Math.log1p(-n())/t)})}return e.source=t,e}(Nd),Bd=function t(n){var e=zd.source(n)();function r(t,r){if((t=+t)<0)throw new RangeError("invalid k");if(0===t)return()=>0;if(r=null==r?1:+r,1===t)return()=>-Math.log1p(-n())*r;var i=(t<1?t+1:t)-1/3,o=1/(3*Math.sqrt(i)),a=t<1?()=>Math.pow(n(),1/t):()=>1;return function(){do{do{var t=e(),u=1+o*t}while(u<=0);u*=u*u;var c=1-n()}while(c>=1-.0331*t*t*t*t&&Math.log(c)>=.5*t*t+i*(1-u+Math.log(u)));return i*u*a()*r}}return r.source=t,r}(Nd),Yd=function t(n){var e=Bd.source(n);function r(t,n){var r=e(t),i=e(n);return function(){var t=r();return 0===t?0:t/(t+i())}}return r.source=t,r}(Nd),Ld=function t(n){var e=Id.source(n),r=Yd.source(n);function i(t,n){return t=+t,(n=+n)>=1?()=>t:n<=0?()=>0:function(){for(var i=0,o=t,a=n;o*a>16&&o*(1-a)>16;){var u=Math.floor((o+1)*a),c=r(u,o-u+1)();c<=a?(i+=u,o-=u,a=(a-c)/(1-c)):(o=u-1,a/=c)}for(var f=a<.5,s=e(f?a:1-a),l=s(),h=0;l<=o;++h)l+=s();return i+(f?h:o-h)}}return i.source=t,i}(Nd),jd=function t(n){function e(t,e,r){var i;return 0==(t=+t)?i=t=>-Math.log(t):(t=1/t,i=n=>Math.pow(n,t)),e=null==e?0:+e,r=null==r?1:+r,function(){return e+r*i(-Math.log1p(-n()))}}return e.source=t,e}(Nd),Hd=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){return t+e*Math.tan(Math.PI*n())}}return e.source=t,e}(Nd),Xd=function t(n){function e(t,e){return t=null==t?0:+t,e=null==e?1:+e,function(){var r=n();return t+e*Math.log(r/(1-r))}}return e.source=t,e}(Nd),Gd=function t(n){var e=Bd.source(n),r=Ld.source(n);function i(t){return function(){for(var i=0,o=t;o>16;){var a=Math.floor(.875*o),u=e(a)();if(u>o)return i+r(a-1,o/u)();i+=a,o-=u}for(var c=-Math.log1p(-n()),f=0;c<=o;++f)c-=Math.log1p(-n());return i+f}}return i.source=t,i}(Nd);const Vd=1/4294967296;function $d(t,n){switch(arguments.length){case 0:break;case 1:this.range(t);break;default:this.range(n).domain(t)}return this}function Wd(t,n){switch(arguments.length){case 0:break;case 1:"function"==typeof t?this.interpolator(t):this.range(t);break;default:this.domain(t),"function"==typeof n?this.interpolator(n):this.range(n)}return this}const Zd=Symbol("implicit");function Kd(){var t=new Map,n=[],e=[],r=Zd;function i(i){var o=i+"",a=t.get(o);if(!a){if(r!==Zd)return r;t.set(o,a=n.push(i))}return e[(a-1)%e.length]}return i.domain=function(e){if(!arguments.length)return n.slice();n=[],t=new Map;for(const r of e){const e=r+"";t.has(e)||t.set(e,n.push(r))}return i},i.range=function(t){return arguments.length?(e=Array.from(t),i):e.slice()},i.unknown=function(t){return arguments.length?(r=t,i):r},i.copy=function(){return Kd(n,e).unknown(r)},$d.apply(i,arguments),i}function Qd(){var t,n,e=Kd().unknown(void 0),r=e.domain,i=e.range,o=0,a=1,u=!1,c=0,f=0,s=.5;function l(){var e=r().length,l=a<o,h=l?a:o,d=l?o:a;t=(d-h)/Math.max(1,e-c+2*f),u&&(t=Math.floor(t)),h+=(d-h-t*(e-c))*s,n=t*(1-c),u&&(h=Math.round(h),n=Math.round(n));var p=Y(e).map((function(n){return h+t*n}));return i(l?p.reverse():p)}return delete e.unknown,e.domain=function(t){return arguments.length?(r(t),l()):r()},e.range=function(t){return arguments.length?([o,a]=t,o=+o,a=+a,l()):[o,a]},e.rangeRound=function(t){return[o,a]=t,o=+o,a=+a,u=!0,l()},e.bandwidth=function(){return n},e.step=function(){return t},e.round=function(t){return arguments.length?(u=!!t,l()):u},e.padding=function(t){return arguments.length?(c=Math.min(1,f=+t),l()):c},e.paddingInner=function(t){return arguments.length?(c=Math.min(1,t),l()):c},e.paddingOuter=function(t){return arguments.length?(f=+t,l()):f},e.align=function(t){return arguments.length?(s=Math.max(0,Math.min(1,t)),l()):s},e.copy=function(){return Qd(r(),[o,a]).round(u).paddingInner(c).paddingOuter(f).align(s)},$d.apply(l(),arguments)}function Jd(t){var n=t.copy;return t.padding=t.paddingOuter,delete t.paddingInner,delete t.paddingOuter,t.copy=function(){return Jd(n())},t}function tp(t){return+t}var np=[0,1];function ep(t){return t}function rp(t,n){return(n-=t=+t)?function(e){return(e-t)/n}:function(t){return function(){return t}}(isNaN(n)?NaN:.5)}function ip(t,n,e){var r=t[0],i=t[1],o=n[0],a=n[1];return i<r?(r=rp(i,r),o=e(a,o)):(r=rp(r,i),o=e(o,a)),function(t){return o(r(t))}}function op(t,n,e){var r=Math.min(t.length,n.length)-1,i=new Array(r),a=new Array(r),u=-1;for(t[r]<t[0]&&(t=t.slice().reverse(),n=n.slice().reverse());++u<r;)i[u]=rp(t[u],t[u+1]),a[u]=e(n[u],n[u+1]);return function(n){var e=o(t,n,1,r)-1;return a[e](i[e](n))}}function ap(t,n){return n.domain(t.domain()).range(t.range()).interpolate(t.interpolate()).clamp(t.clamp()).unknown(t.unknown())}function up(){var t,n,e,r,i,o,a=np,u=np,c=pr,f=ep;function s(){var t=Math.min(a.length,u.length);return f!==ep&&(f=function(t,n){var e;return t>n&&(e=t,t=n,n=e),function(e){return Math.max(t,Math.min(n,e))}}(a[0],a[t-1])),r=t>2?op:ip,i=o=null,l}function l(n){return isNaN(n=+n)?e:(i||(i=r(a.map(t),u,c)))(t(f(n)))}return l.invert=function(e){return f(n((o||(o=r(u,a.map(t),fr)))(e)))},l.domain=function(t){return arguments.length?(a=Array.from(t,tp),s()):a.slice()},l.range=function(t){return arguments.length?(u=Array.from(t),s()):u.slice()},l.rangeRound=function(t){return u=Array.from(t),c=gr,s()},l.clamp=function(t){return arguments.length?(f=!!t||ep,s()):f!==ep},l.interpolate=function(t){return arguments.length?(c=t,s()):c},l.unknown=function(t){return arguments.length?(e=t,l):e},function(e,r){return t=e,n=r,s()}}function cp(){return up()(ep,ep)}function fp(n,e,r,i){var o,a=S(n,e,r);switch((i=Ku(null==i?",f":i)).type){case"s":var u=Math.max(Math.abs(n),Math.abs(e));return null!=i.precision||isNaN(o=cc(a,u))||(i.precision=o),t.formatPrefix(i,u);case"":case"e":case"g":case"p":case"r":null!=i.precision||isNaN(o=fc(a,Math.max(Math.abs(n),Math.abs(e))))||(i.precision=o-("e"===i.type));break;case"f":case"%":null!=i.precision||isNaN(o=uc(a))||(i.precision=o-2*("%"===i.type))}return t.format(i)}function sp(t){var n=t.domain;return t.ticks=function(t){var e=n();return A(e[0],e[e.length-1],null==t?10:t)},t.tickFormat=function(t,e){var r=n();return fp(r[0],r[r.length-1],null==t?10:t,e)},t.nice=function(e){null==e&&(e=10);var r,i,o=n(),a=0,u=o.length-1,c=o[a],f=o[u],s=10;for(f<c&&(i=c,c=f,f=i,i=a,a=u,u=i);s-- >0;){if((i=T(c,f,e))===r)return o[a]=c,o[u]=f,n(o);if(i>0)c=Math.floor(c/i)*i,f=Math.ceil(f/i)*i;else{if(!(i<0))break;c=Math.ceil(c*i)/i,f=Math.floor(f*i)/i}r=i}return t},t}function lp(t,n){var e,r=0,i=(t=t.slice()).length-1,o=t[r],a=t[i];return a<o&&(e=r,r=i,i=e,e=o,o=a,a=e),t[r]=n.floor(o),t[i]=n.ceil(a),t}function hp(t){return Math.log(t)}function dp(t){return Math.exp(t)}function pp(t){return-Math.log(-t)}function gp(t){return-Math.exp(-t)}function yp(t){return isFinite(t)?+("1e"+t):t<0?0:t}function vp(t){return function(n){return-t(-n)}}function _p(n){var e,r,i=n(hp,dp),o=i.domain,a=10;function u(){return e=function(t){return t===Math.E?Math.log:10===t&&Math.log10||2===t&&Math.log2||(t=Math.log(t),function(n){return Math.log(n)/t})}(a),r=function(t){return 10===t?yp:t===Math.E?Math.exp:function(n){return Math.pow(t,n)}}(a),o()[0]<0?(e=vp(e),r=vp(r),n(pp,gp)):n(hp,dp),i}return i.base=function(t){return arguments.length?(a=+t,u()):a},i.domain=function(t){return arguments.length?(o(t),u()):o()},i.ticks=function(t){var n,i=o(),u=i[0],c=i[i.length-1];(n=c<u)&&(h=u,u=c,c=h);var f,s,l,h=e(u),d=e(c),p=null==t?10:+t,g=[];if(!(a%1)&&d-h<p){if(h=Math.floor(h),d=Math.ceil(d),u>0){for(;h<=d;++h)for(s=1,f=r(h);s<a;++s)if(!((l=f*s)<u)){if(l>c)break;g.push(l)}}else for(;h<=d;++h)for(s=a-1,f=r(h);s>=1;--s)if(!((l=f*s)<u)){if(l>c)break;g.push(l)}2*g.length<p&&(g=A(u,c,p))}else g=A(h,d,Math.min(d-h,p)).map(r);return n?g.reverse():g},i.tickFormat=function(n,o){if(null==o&&(o=10===a?".0e":","),"function"!=typeof o&&(o=t.format(o)),n===1/0)return o;null==n&&(n=10);var u=Math.max(1,a*n/i.ticks().length);return function(t){var n=t/r(Math.round(e(t)));return n*a<a-.5&&(n*=a),n<=u?o(t):""}},i.nice=function(){return o(lp(o(),{floor:function(t){return r(Math.floor(e(t)))},ceil:function(t){return r(Math.ceil(e(t)))}}))},i}function bp(t){return function(n){return Math.sign(n)*Math.log1p(Math.abs(n/t))}}function mp(t){return function(n){return Math.sign(n)*Math.expm1(Math.abs(n))*t}}function xp(t){var n=1,e=t(bp(n),mp(n));return e.constant=function(e){return arguments.length?t(bp(n=+e),mp(n)):n},sp(e)}function wp(t){return function(n){return n<0?-Math.pow(-n,t):Math.pow(n,t)}}function Mp(t){return t<0?-Math.sqrt(-t):Math.sqrt(t)}function Ap(t){return t<0?-t*t:t*t}function Tp(t){var n=t(ep,ep),e=1;function r(){return 1===e?t(ep,ep):.5===e?t(Mp,Ap):t(wp(e),wp(1/e))}return n.exponent=function(t){return arguments.length?(e=+t,r()):e},sp(n)}function Sp(){var t=Tp(up());return t.copy=function(){return ap(t,Sp()).exponent(t.exponent())},$d.apply(t,arguments),t}function Ep(t){return Math.sign(t)*t*t}function kp(t){return Math.sign(t)*Math.sqrt(Math.abs(t))}var Np=new Date,Cp=new Date;function Pp(t,n,e,r){function i(n){return t(n=0===arguments.length?new Date:new Date(+n)),n}return i.floor=function(n){return t(n=new Date(+n)),n},i.ceil=function(e){return t(e=new Date(e-1)),n(e,1),t(e),e},i.round=function(t){var n=i(t),e=i.ceil(t);return t-n<e-t?n:e},i.offset=function(t,e){return n(t=new Date(+t),null==e?1:Math.floor(e)),t},i.range=function(e,r,o){var a,u=[];if(e=i.ceil(e),o=null==o?1:Math.floor(o),!(e<r&&o>0))return u;do{u.push(a=new Date(+e)),n(e,o),t(e)}while(a<e&&e<r);return u},i.filter=function(e){return Pp((function(n){if(n>=n)for(;t(n),!e(n);)n.setTime(n-1)}),(function(t,r){if(t>=t)if(r<0)for(;++r<=0;)for(;n(t,-1),!e(t););else for(;--r>=0;)for(;n(t,1),!e(t););}))},e&&(i.count=function(n,r){return Np.setTime(+n),Cp.setTime(+r),t(Np),t(Cp),Math.floor(e(Np,Cp))},i.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?i.filter(r?function(n){return r(n)%t==0}:function(n){return i.count(0,n)%t==0}):i:null}),i}var zp=Pp((function(){}),(function(t,n){t.setTime(+t+n)}),(function(t,n){return n-t}));zp.every=function(t){return t=Math.floor(t),isFinite(t)&&t>0?t>1?Pp((function(n){n.setTime(Math.floor(n/t)*t)}),(function(n,e){n.setTime(+n+e*t)}),(function(n,e){return(e-n)/t})):zp:null};var Dp=zp.range,qp=1e3,Rp=6e4,Fp=36e5,Op=864e5,Up=6048e5,Ip=Pp((function(t){t.setTime(t-t.getMilliseconds())}),(function(t,n){t.setTime(+t+n*qp)}),(function(t,n){return(n-t)/qp}),(function(t){return t.getUTCSeconds()})),Bp=Ip.range,Yp=Pp((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*qp)}),(function(t,n){t.setTime(+t+n*Rp)}),(function(t,n){return(n-t)/Rp}),(function(t){return t.getMinutes()})),Lp=Yp.range,jp=Pp((function(t){t.setTime(t-t.getMilliseconds()-t.getSeconds()*qp-t.getMinutes()*Rp)}),(function(t,n){t.setTime(+t+n*Fp)}),(function(t,n){return(n-t)/Fp}),(function(t){return t.getHours()})),Hp=jp.range,Xp=Pp(t=>t.setHours(0,0,0,0),(t,n)=>t.setDate(t.getDate()+n),(t,n)=>(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Rp)/Op,t=>t.getDate()-1),Gp=Xp.range;function Vp(t){return Pp((function(n){n.setDate(n.getDate()-(n.getDay()+7-t)%7),n.setHours(0,0,0,0)}),(function(t,n){t.setDate(t.getDate()+7*n)}),(function(t,n){return(n-t-(n.getTimezoneOffset()-t.getTimezoneOffset())*Rp)/Up}))}var $p=Vp(0),Wp=Vp(1),Zp=Vp(2),Kp=Vp(3),Qp=Vp(4),Jp=Vp(5),tg=Vp(6),ng=$p.range,eg=Wp.range,rg=Zp.range,ig=Kp.range,og=Qp.range,ag=Jp.range,ug=tg.range,cg=Pp((function(t){t.setDate(1),t.setHours(0,0,0,0)}),(function(t,n){t.setMonth(t.getMonth()+n)}),(function(t,n){return n.getMonth()-t.getMonth()+12*(n.getFullYear()-t.getFullYear())}),(function(t){return t.getMonth()})),fg=cg.range,sg=Pp((function(t){t.setMonth(0,1),t.setHours(0,0,0,0)}),(function(t,n){t.setFullYear(t.getFullYear()+n)}),(function(t,n){return n.getFullYear()-t.getFullYear()}),(function(t){return t.getFullYear()}));sg.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Pp((function(n){n.setFullYear(Math.floor(n.getFullYear()/t)*t),n.setMonth(0,1),n.setHours(0,0,0,0)}),(function(n,e){n.setFullYear(n.getFullYear()+e*t)})):null};var lg=sg.range,hg=Pp((function(t){t.setUTCSeconds(0,0)}),(function(t,n){t.setTime(+t+n*Rp)}),(function(t,n){return(n-t)/Rp}),(function(t){return t.getUTCMinutes()})),dg=hg.range,pg=Pp((function(t){t.setUTCMinutes(0,0,0)}),(function(t,n){t.setTime(+t+n*Fp)}),(function(t,n){return(n-t)/Fp}),(function(t){return t.getUTCHours()})),gg=pg.range,yg=Pp((function(t){t.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCDate(t.getUTCDate()+n)}),(function(t,n){return(n-t)/Op}),(function(t){return t.getUTCDate()-1})),vg=yg.range;function _g(t){return Pp((function(n){n.setUTCDate(n.getUTCDate()-(n.getUTCDay()+7-t)%7),n.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCDate(t.getUTCDate()+7*n)}),(function(t,n){return(n-t)/Up}))}var bg=_g(0),mg=_g(1),xg=_g(2),wg=_g(3),Mg=_g(4),Ag=_g(5),Tg=_g(6),Sg=bg.range,Eg=mg.range,kg=xg.range,Ng=wg.range,Cg=Mg.range,Pg=Ag.range,zg=Tg.range,Dg=Pp((function(t){t.setUTCDate(1),t.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCMonth(t.getUTCMonth()+n)}),(function(t,n){return n.getUTCMonth()-t.getUTCMonth()+12*(n.getUTCFullYear()-t.getUTCFullYear())}),(function(t){return t.getUTCMonth()})),qg=Dg.range,Rg=Pp((function(t){t.setUTCMonth(0,1),t.setUTCHours(0,0,0,0)}),(function(t,n){t.setUTCFullYear(t.getUTCFullYear()+n)}),(function(t,n){return n.getUTCFullYear()-t.getUTCFullYear()}),(function(t){return t.getUTCFullYear()}));Rg.every=function(t){return isFinite(t=Math.floor(t))&&t>0?Pp((function(n){n.setUTCFullYear(Math.floor(n.getUTCFullYear()/t)*t),n.setUTCMonth(0,1),n.setUTCHours(0,0,0,0)}),(function(n,e){n.setUTCFullYear(n.getUTCFullYear()+e*t)})):null};var Fg=Rg.range;function Og(t){if(0<=t.y&&t.y<100){var n=new Date(-1,t.m,t.d,t.H,t.M,t.S,t.L);return n.setFullYear(t.y),n}return new Date(t.y,t.m,t.d,t.H,t.M,t.S,t.L)}function Ug(t){if(0<=t.y&&t.y<100){var n=new Date(Date.UTC(-1,t.m,t.d,t.H,t.M,t.S,t.L));return n.setUTCFullYear(t.y),n}return new Date(Date.UTC(t.y,t.m,t.d,t.H,t.M,t.S,t.L))}function Ig(t,n,e){return{y:t,m:n,d:e,H:0,M:0,S:0,L:0}}function Bg(t){var n=t.dateTime,e=t.date,r=t.time,i=t.periods,o=t.days,a=t.shortDays,u=t.months,c=t.shortMonths,f=$g(i),s=Wg(i),l=$g(o),h=Wg(o),d=$g(a),p=Wg(a),g=$g(u),y=Wg(u),v=$g(c),_=Wg(c),b={a:function(t){return a[t.getDay()]},A:function(t){return o[t.getDay()]},b:function(t){return c[t.getMonth()]},B:function(t){return u[t.getMonth()]},c:null,d:yy,e:yy,f:xy,g:zy,G:qy,H:vy,I:_y,j:by,L:my,m:wy,M:My,p:function(t){return i[+(t.getHours()>=12)]},q:function(t){return 1+~~(t.getMonth()/3)},Q:rv,s:iv,S:Ay,u:Ty,U:Sy,V:ky,w:Ny,W:Cy,x:null,X:null,y:Py,Y:Dy,Z:Ry,"%":ev},m={a:function(t){return a[t.getUTCDay()]},A:function(t){return o[t.getUTCDay()]},b:function(t){return c[t.getUTCMonth()]},B:function(t){return u[t.getUTCMonth()]},c:null,d:Fy,e:Fy,f:Yy,g:Qy,G:tv,H:Oy,I:Uy,j:Iy,L:By,m:Ly,M:jy,p:function(t){return i[+(t.getUTCHours()>=12)]},q:function(t){return 1+~~(t.getUTCMonth()/3)},Q:rv,s:iv,S:Hy,u:Xy,U:Gy,V:$y,w:Wy,W:Zy,x:null,X:null,y:Ky,Y:Jy,Z:nv,"%":ev},x={a:function(t,n,e){var r=d.exec(n.slice(e));return r?(t.w=p.get(r[0].toLowerCase()),e+r[0].length):-1},A:function(t,n,e){var r=l.exec(n.slice(e));return r?(t.w=h.get(r[0].toLowerCase()),e+r[0].length):-1},b:function(t,n,e){var r=v.exec(n.slice(e));return r?(t.m=_.get(r[0].toLowerCase()),e+r[0].length):-1},B:function(t,n,e){var r=g.exec(n.slice(e));return r?(t.m=y.get(r[0].toLowerCase()),e+r[0].length):-1},c:function(t,e,r){return A(t,n,e,r)},d:ay,e:ay,f:hy,g:ey,G:ny,H:cy,I:cy,j:uy,L:ly,m:oy,M:fy,p:function(t,n,e){var r=f.exec(n.slice(e));return r?(t.p=s.get(r[0].toLowerCase()),e+r[0].length):-1},q:iy,Q:py,s:gy,S:sy,u:Kg,U:Qg,V:Jg,w:Zg,W:ty,x:function(t,n,r){return A(t,e,n,r)},X:function(t,n,e){return A(t,r,n,e)},y:ey,Y:ny,Z:ry,"%":dy};function w(t,n){return function(e){var r,i,o,a=[],u=-1,c=0,f=t.length;for(e instanceof Date||(e=new Date(+e));++u<f;)37===t.charCodeAt(u)&&(a.push(t.slice(c,u)),null!=(i=Lg[r=t.charAt(++u)])?r=t.charAt(++u):i="e"===r?" ":"0",(o=n[r])&&(r=o(e,i)),a.push(r),c=u+1);return a.push(t.slice(c,u)),a.join("")}}function M(t,n){return function(e){var r,i,o=Ig(1900,void 0,1);if(A(o,t,e+="",0)!=e.length)return null;if("Q"in o)return new Date(o.Q);if("s"in o)return new Date(1e3*o.s+("L"in o?o.L:0));if(n&&!("Z"in o)&&(o.Z=0),"p"in o&&(o.H=o.H%12+12*o.p),void 0===o.m&&(o.m="q"in o?o.q:0),"V"in o){if(o.V<1||o.V>53)return null;"w"in o||(o.w=1),"Z"in o?(i=(r=Ug(Ig(o.y,0,1))).getUTCDay(),r=i>4||0===i?mg.ceil(r):mg(r),r=yg.offset(r,7*(o.V-1)),o.y=r.getUTCFullYear(),o.m=r.getUTCMonth(),o.d=r.getUTCDate()+(o.w+6)%7):(i=(r=Og(Ig(o.y,0,1))).getDay(),r=i>4||0===i?Wp.ceil(r):Wp(r),r=Xp.offset(r,7*(o.V-1)),o.y=r.getFullYear(),o.m=r.getMonth(),o.d=r.getDate()+(o.w+6)%7)}else("W"in o||"U"in o)&&("w"in o||(o.w="u"in o?o.u%7:"W"in o?1:0),i="Z"in o?Ug(Ig(o.y,0,1)).getUTCDay():Og(Ig(o.y,0,1)).getDay(),o.m=0,o.d="W"in o?(o.w+6)%7+7*o.W-(i+5)%7:o.w+7*o.U-(i+6)%7);return"Z"in o?(o.H+=o.Z/100|0,o.M+=o.Z%100,Ug(o)):Og(o)}}function A(t,n,e,r){for(var i,o,a=0,u=n.length,c=e.length;a<u;){if(r>=c)return-1;if(37===(i=n.charCodeAt(a++))){if(i=n.charAt(a++),!(o=x[i in Lg?n.charAt(a++):i])||(r=o(t,e,r))<0)return-1}else if(i!=e.charCodeAt(r++))return-1}return r}return b.x=w(e,b),b.X=w(r,b),b.c=w(n,b),m.x=w(e,m),m.X=w(r,m),m.c=w(n,m),{format:function(t){var n=w(t+="",b);return n.toString=function(){return t},n},parse:function(t){var n=M(t+="",!1);return n.toString=function(){return t},n},utcFormat:function(t){var n=w(t+="",m);return n.toString=function(){return t},n},utcParse:function(t){var n=M(t+="",!0);return n.toString=function(){return t},n}}}var Yg,Lg={"-":"",_:" ",0:"0"},jg=/^\s*\d+/,Hg=/^%/,Xg=/[\\^$*+?|[\]().{}]/g;function Gg(t,n,e){var r=t<0?"-":"",i=(r?-t:t)+"",o=i.length;return r+(o<e?new Array(e-o+1).join(n)+i:i)}function Vg(t){return t.replace(Xg,"\\$&")}function $g(t){return new RegExp("^(?:"+t.map(Vg).join("|")+")","i")}function Wg(t){return new Map(t.map((t,n)=>[t.toLowerCase(),n]))}function Zg(t,n,e){var r=jg.exec(n.slice(e,e+1));return r?(t.w=+r[0],e+r[0].length):-1}function Kg(t,n,e){var r=jg.exec(n.slice(e,e+1));return r?(t.u=+r[0],e+r[0].length):-1}function Qg(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.U=+r[0],e+r[0].length):-1}function Jg(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.V=+r[0],e+r[0].length):-1}function ty(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.W=+r[0],e+r[0].length):-1}function ny(t,n,e){var r=jg.exec(n.slice(e,e+4));return r?(t.y=+r[0],e+r[0].length):-1}function ey(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.y=+r[0]+(+r[0]>68?1900:2e3),e+r[0].length):-1}function ry(t,n,e){var r=/^(Z)|([+-]\d\d)(?::?(\d\d))?/.exec(n.slice(e,e+6));return r?(t.Z=r[1]?0:-(r[2]+(r[3]||"00")),e+r[0].length):-1}function iy(t,n,e){var r=jg.exec(n.slice(e,e+1));return r?(t.q=3*r[0]-3,e+r[0].length):-1}function oy(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.m=r[0]-1,e+r[0].length):-1}function ay(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.d=+r[0],e+r[0].length):-1}function uy(t,n,e){var r=jg.exec(n.slice(e,e+3));return r?(t.m=0,t.d=+r[0],e+r[0].length):-1}function cy(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.H=+r[0],e+r[0].length):-1}function fy(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.M=+r[0],e+r[0].length):-1}function sy(t,n,e){var r=jg.exec(n.slice(e,e+2));return r?(t.S=+r[0],e+r[0].length):-1}function ly(t,n,e){var r=jg.exec(n.slice(e,e+3));return r?(t.L=+r[0],e+r[0].length):-1}function hy(t,n,e){var r=jg.exec(n.slice(e,e+6));return r?(t.L=Math.floor(r[0]/1e3),e+r[0].length):-1}function dy(t,n,e){var r=Hg.exec(n.slice(e,e+1));return r?e+r[0].length:-1}function py(t,n,e){var r=jg.exec(n.slice(e));return r?(t.Q=+r[0],e+r[0].length):-1}function gy(t,n,e){var r=jg.exec(n.slice(e));return r?(t.s=+r[0],e+r[0].length):-1}function yy(t,n){return Gg(t.getDate(),n,2)}function vy(t,n){return Gg(t.getHours(),n,2)}function _y(t,n){return Gg(t.getHours()%12||12,n,2)}function by(t,n){return Gg(1+Xp.count(sg(t),t),n,3)}function my(t,n){return Gg(t.getMilliseconds(),n,3)}function xy(t,n){return my(t,n)+"000"}function wy(t,n){return Gg(t.getMonth()+1,n,2)}function My(t,n){return Gg(t.getMinutes(),n,2)}function Ay(t,n){return Gg(t.getSeconds(),n,2)}function Ty(t){var n=t.getDay();return 0===n?7:n}function Sy(t,n){return Gg($p.count(sg(t)-1,t),n,2)}function Ey(t){var n=t.getDay();return n>=4||0===n?Qp(t):Qp.ceil(t)}function ky(t,n){return t=Ey(t),Gg(Qp.count(sg(t),t)+(4===sg(t).getDay()),n,2)}function Ny(t){return t.getDay()}function Cy(t,n){return Gg(Wp.count(sg(t)-1,t),n,2)}function Py(t,n){return Gg(t.getFullYear()%100,n,2)}function zy(t,n){return Gg((t=Ey(t)).getFullYear()%100,n,2)}function Dy(t,n){return Gg(t.getFullYear()%1e4,n,4)}function qy(t,n){var e=t.getDay();return Gg((t=e>=4||0===e?Qp(t):Qp.ceil(t)).getFullYear()%1e4,n,4)}function Ry(t){var n=t.getTimezoneOffset();return(n>0?"-":(n*=-1,"+"))+Gg(n/60|0,"0",2)+Gg(n%60,"0",2)}function Fy(t,n){return Gg(t.getUTCDate(),n,2)}function Oy(t,n){return Gg(t.getUTCHours(),n,2)}function Uy(t,n){return Gg(t.getUTCHours()%12||12,n,2)}function Iy(t,n){return Gg(1+yg.count(Rg(t),t),n,3)}function By(t,n){return Gg(t.getUTCMilliseconds(),n,3)}function Yy(t,n){return By(t,n)+"000"}function Ly(t,n){return Gg(t.getUTCMonth()+1,n,2)}function jy(t,n){return Gg(t.getUTCMinutes(),n,2)}function Hy(t,n){return Gg(t.getUTCSeconds(),n,2)}function Xy(t){var n=t.getUTCDay();return 0===n?7:n}function Gy(t,n){return Gg(bg.count(Rg(t)-1,t),n,2)}function Vy(t){var n=t.getUTCDay();return n>=4||0===n?Mg(t):Mg.ceil(t)}function $y(t,n){return t=Vy(t),Gg(Mg.count(Rg(t),t)+(4===Rg(t).getUTCDay()),n,2)}function Wy(t){return t.getUTCDay()}function Zy(t,n){return Gg(mg.count(Rg(t)-1,t),n,2)}function Ky(t,n){return Gg(t.getUTCFullYear()%100,n,2)}function Qy(t,n){return Gg((t=Vy(t)).getUTCFullYear()%100,n,2)}function Jy(t,n){return Gg(t.getUTCFullYear()%1e4,n,4)}function tv(t,n){var e=t.getUTCDay();return Gg((t=e>=4||0===e?Mg(t):Mg.ceil(t)).getUTCFullYear()%1e4,n,4)}function nv(){return"+0000"}function ev(){return"%"}function rv(t){return+t}function iv(t){return Math.floor(+t/1e3)}function ov(n){return Yg=Bg(n),t.timeFormat=Yg.format,t.timeParse=Yg.parse,t.utcFormat=Yg.utcFormat,t.utcParse=Yg.utcParse,Yg}ov({dateTime:"%x, %X",date:"%-m/%-d/%Y",time:"%-I:%M:%S %p",periods:["AM","PM"],days:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],shortDays:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],months:["January","February","March","April","May","June","July","August","September","October","November","December"],shortMonths:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"]});var av="%Y-%m-%dT%H:%M:%S.%LZ";var uv=Date.prototype.toISOString?function(t){return t.toISOString()}:t.utcFormat(av);var cv=+new Date("2000-01-01T00:00:00.000Z")?function(t){var n=new Date(t);return isNaN(n)?null:n}:t.utcParse(av),fv=1e3,sv=6e4,lv=36e5,hv=864e5,dv=2592e6,pv=31536e6;function gv(t){return new Date(t)}function yv(t){return t instanceof Date?+t:+new Date(+t)}function vv(t,n,r,i,o,a,u,c,f){var s=cp(),l=s.invert,h=s.domain,d=f(".%L"),p=f(":%S"),g=f("%I:%M"),y=f("%I %p"),v=f("%a %d"),_=f("%b %d"),b=f("%B"),m=f("%Y"),x=[[u,1,fv],[u,5,5e3],[u,15,15e3],[u,30,3e4],[a,1,sv],[a,5,3e5],[a,15,9e5],[a,30,18e5],[o,1,lv],[o,3,108e5],[o,6,216e5],[o,12,432e5],[i,1,hv],[i,2,1728e5],[r,1,6048e5],[n,1,dv],[n,3,7776e6],[t,1,pv]];function w(e){return(u(e)<e?d:a(e)<e?p:o(e)<e?g:i(e)<e?y:n(e)<e?r(e)<e?v:_:t(e)<e?b:m)(e)}function M(n,r,i){if(null==n&&(n=10),"number"==typeof n){var o,a=Math.abs(i-r)/n,u=e((function(t){return t[2]})).right(x,a);return u===x.length?(o=S(r/pv,i/pv,n),n=t):u?(o=(u=x[a/x[u-1][2]<x[u][2]/a?u-1:u])[1],n=u[0]):(o=Math.max(S(r,i,n),1),n=c),n.every(o)}return n}return s.invert=function(t){return new Date(l(t))},s.domain=function(t){return arguments.length?h(Array.from(t,yv)):h().map(gv)},s.ticks=function(t){var n,e=h(),r=e[0],i=e[e.length-1],o=i<r;return o&&(n=r,r=i,i=n),n=(n=M(t,r,i))?n.range(r,i+1):[],o?n.reverse():n},s.tickFormat=function(t,n){return null==n?w:f(n)},s.nice=function(t){var n=h();return(t=M(t,n[0],n[n.length-1]))?h(lp(n,t)):s},s.copy=function(){return ap(s,vv(t,n,r,i,o,a,u,c,f))},s}function _v(){var t,n,e,r,i,o=0,a=1,u=ep,c=!1;function f(n){return isNaN(n=+n)?i:u(0===e?.5:(n=(r(n)-t)*e,c?Math.max(0,Math.min(1,n)):n))}function s(t){return function(n){var e,r;return arguments.length?([e,r]=n,u=t(e,r),f):[u(0),u(1)]}}return f.domain=function(i){return arguments.length?([o,a]=i,t=r(o=+o),n=r(a=+a),e=t===n?0:1/(n-t),f):[o,a]},f.clamp=function(t){return arguments.length?(c=!!t,f):c},f.interpolator=function(t){return arguments.length?(u=t,f):u},f.range=s(pr),f.rangeRound=s(gr),f.unknown=function(t){return arguments.length?(i=t,f):i},function(i){return r=i,t=i(o),n=i(a),e=t===n?0:1/(n-t),f}}function bv(t,n){return n.domain(t.domain()).interpolator(t.interpolator()).clamp(t.clamp()).unknown(t.unknown())}function mv(){var t=Tp(_v());return t.copy=function(){return bv(t,mv()).exponent(t.exponent())},Wd.apply(t,arguments)}function xv(){var t,n,e,r,i,o,a,u=0,c=.5,f=1,s=1,l=ep,h=!1;function d(t){return isNaN(t=+t)?a:(t=.5+((t=+o(t))-n)*(s*t<s*n?r:i),l(h?Math.max(0,Math.min(1,t)):t))}function p(t){return function(n){var e,r,i;return arguments.length?([e,r,i]=n,l=qr(t,[e,r,i]),d):[l(0),l(.5),l(1)]}}return d.domain=function(a){return arguments.length?([u,c,f]=a,t=o(u=+u),n=o(c=+c),e=o(f=+f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d):[u,c,f]},d.clamp=function(t){return arguments.length?(h=!!t,d):h},d.interpolator=function(t){return arguments.length?(l=t,d):l},d.range=p(pr),d.rangeRound=p(gr),d.unknown=function(t){return arguments.length?(a=t,d):a},function(a){return o=a,t=a(u),n=a(c),e=a(f),r=t===n?0:.5/(n-t),i=n===e?0:.5/(e-n),s=n<t?-1:1,d}}function wv(){var t=Tp(xv());return t.copy=function(){return bv(t,wv()).exponent(t.exponent())},Wd.apply(t,arguments)}function Mv(t){for(var n=t.length/6|0,e=new Array(n),r=0;r<n;)e[r]="#"+t.slice(6*r,6*++r);return e}var Av=Mv("1f77b4ff7f0e2ca02cd627289467bd8c564be377c27f7f7fbcbd2217becf"),Tv=Mv("7fc97fbeaed4fdc086ffff99386cb0f0027fbf5b17666666"),Sv=Mv("1b9e77d95f027570b3e7298a66a61ee6ab02a6761d666666"),Ev=Mv("a6cee31f78b4b2df8a33a02cfb9a99e31a1cfdbf6fff7f00cab2d66a3d9affff99b15928"),kv=Mv("fbb4aeb3cde3ccebc5decbe4fed9a6ffffcce5d8bdfddaecf2f2f2"),Nv=Mv("b3e2cdfdcdaccbd5e8f4cae4e6f5c9fff2aef1e2cccccccc"),Cv=Mv("e41a1c377eb84daf4a984ea3ff7f00ffff33a65628f781bf999999"),Pv=Mv("66c2a5fc8d628da0cbe78ac3a6d854ffd92fe5c494b3b3b3"),zv=Mv("8dd3c7ffffb3bebadafb807280b1d3fdb462b3de69fccde5d9d9d9bc80bdccebc5ffed6f"),Dv=Mv("4e79a7f28e2ce1575976b7b259a14fedc949af7aa1ff9da79c755fbab0ab"),qv=t=>rr(t[t.length-1]),Rv=new Array(3).concat("d8b365f5f5f55ab4ac","a6611adfc27d80cdc1018571","a6611adfc27df5f5f580cdc1018571","8c510ad8b365f6e8c3c7eae55ab4ac01665e","8c510ad8b365f6e8c3f5f5f5c7eae55ab4ac01665e","8c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e","8c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e","5430058c510abf812ddfc27df6e8c3c7eae580cdc135978f01665e003c30","5430058c510abf812ddfc27df6e8c3f5f5f5c7eae580cdc135978f01665e003c30").map(Mv),Fv=qv(Rv),Ov=new Array(3).concat("af8dc3f7f7f77fbf7b","7b3294c2a5cfa6dba0008837","7b3294c2a5cff7f7f7a6dba0008837","762a83af8dc3e7d4e8d9f0d37fbf7b1b7837","762a83af8dc3e7d4e8f7f7f7d9f0d37fbf7b1b7837","762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b7837","762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b7837","40004b762a839970abc2a5cfe7d4e8d9f0d3a6dba05aae611b783700441b","40004b762a839970abc2a5cfe7d4e8f7f7f7d9f0d3a6dba05aae611b783700441b").map(Mv),Uv=qv(Ov),Iv=new Array(3).concat("e9a3c9f7f7f7a1d76a","d01c8bf1b6dab8e1864dac26","d01c8bf1b6daf7f7f7b8e1864dac26","c51b7de9a3c9fde0efe6f5d0a1d76a4d9221","c51b7de9a3c9fde0eff7f7f7e6f5d0a1d76a4d9221","c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221","c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221","8e0152c51b7dde77aef1b6dafde0efe6f5d0b8e1867fbc414d9221276419","8e0152c51b7dde77aef1b6dafde0eff7f7f7e6f5d0b8e1867fbc414d9221276419").map(Mv),Bv=qv(Iv),Yv=new Array(3).concat("998ec3f7f7f7f1a340","5e3c99b2abd2fdb863e66101","5e3c99b2abd2f7f7f7fdb863e66101","542788998ec3d8daebfee0b6f1a340b35806","542788998ec3d8daebf7f7f7fee0b6f1a340b35806","5427888073acb2abd2d8daebfee0b6fdb863e08214b35806","5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b35806","2d004b5427888073acb2abd2d8daebfee0b6fdb863e08214b358067f3b08","2d004b5427888073acb2abd2d8daebf7f7f7fee0b6fdb863e08214b358067f3b08").map(Mv),Lv=qv(Yv),jv=new Array(3).concat("ef8a62f7f7f767a9cf","ca0020f4a58292c5de0571b0","ca0020f4a582f7f7f792c5de0571b0","b2182bef8a62fddbc7d1e5f067a9cf2166ac","b2182bef8a62fddbc7f7f7f7d1e5f067a9cf2166ac","b2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac","b2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac","67001fb2182bd6604df4a582fddbc7d1e5f092c5de4393c32166ac053061","67001fb2182bd6604df4a582fddbc7f7f7f7d1e5f092c5de4393c32166ac053061").map(Mv),Hv=qv(jv),Xv=new Array(3).concat("ef8a62ffffff999999","ca0020f4a582bababa404040","ca0020f4a582ffffffbababa404040","b2182bef8a62fddbc7e0e0e09999994d4d4d","b2182bef8a62fddbc7ffffffe0e0e09999994d4d4d","b2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d","b2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d","67001fb2182bd6604df4a582fddbc7e0e0e0bababa8787874d4d4d1a1a1a","67001fb2182bd6604df4a582fddbc7ffffffe0e0e0bababa8787874d4d4d1a1a1a").map(Mv),Gv=qv(Xv),Vv=new Array(3).concat("fc8d59ffffbf91bfdb","d7191cfdae61abd9e92c7bb6","d7191cfdae61ffffbfabd9e92c7bb6","d73027fc8d59fee090e0f3f891bfdb4575b4","d73027fc8d59fee090ffffbfe0f3f891bfdb4575b4","d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4","d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4","a50026d73027f46d43fdae61fee090e0f3f8abd9e974add14575b4313695","a50026d73027f46d43fdae61fee090ffffbfe0f3f8abd9e974add14575b4313695").map(Mv),$v=qv(Vv),Wv=new Array(3).concat("fc8d59ffffbf91cf60","d7191cfdae61a6d96a1a9641","d7191cfdae61ffffbfa6d96a1a9641","d73027fc8d59fee08bd9ef8b91cf601a9850","d73027fc8d59fee08bffffbfd9ef8b91cf601a9850","d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850","d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850","a50026d73027f46d43fdae61fee08bd9ef8ba6d96a66bd631a9850006837","a50026d73027f46d43fdae61fee08bffffbfd9ef8ba6d96a66bd631a9850006837").map(Mv),Zv=qv(Wv),Kv=new Array(3).concat("fc8d59ffffbf99d594","d7191cfdae61abdda42b83ba","d7191cfdae61ffffbfabdda42b83ba","d53e4ffc8d59fee08be6f59899d5943288bd","d53e4ffc8d59fee08bffffbfe6f59899d5943288bd","d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd","d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd","9e0142d53e4ff46d43fdae61fee08be6f598abdda466c2a53288bd5e4fa2","9e0142d53e4ff46d43fdae61fee08bffffbfe6f598abdda466c2a53288bd5e4fa2").map(Mv),Qv=qv(Kv),Jv=new Array(3).concat("e5f5f999d8c92ca25f","edf8fbb2e2e266c2a4238b45","edf8fbb2e2e266c2a42ca25f006d2c","edf8fbccece699d8c966c2a42ca25f006d2c","edf8fbccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45005824","f7fcfde5f5f9ccece699d8c966c2a441ae76238b45006d2c00441b").map(Mv),t_=qv(Jv),n_=new Array(3).concat("e0ecf49ebcda8856a7","edf8fbb3cde38c96c688419d","edf8fbb3cde38c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68856a7810f7c","edf8fbbfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d6e016b","f7fcfde0ecf4bfd3e69ebcda8c96c68c6bb188419d810f7c4d004b").map(Mv),e_=qv(n_),r_=new Array(3).concat("e0f3dba8ddb543a2ca","f0f9e8bae4bc7bccc42b8cbe","f0f9e8bae4bc7bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc443a2ca0868ac","f0f9e8ccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe08589e","f7fcf0e0f3dbccebc5a8ddb57bccc44eb3d32b8cbe0868ac084081").map(Mv),i_=qv(r_),o_=new Array(3).concat("fee8c8fdbb84e34a33","fef0d9fdcc8afc8d59d7301f","fef0d9fdcc8afc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59e34a33b30000","fef0d9fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301f990000","fff7ecfee8c8fdd49efdbb84fc8d59ef6548d7301fb300007f0000").map(Mv),a_=qv(o_),u_=new Array(3).concat("ece2f0a6bddb1c9099","f6eff7bdc9e167a9cf02818a","f6eff7bdc9e167a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf1c9099016c59","f6eff7d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016450","fff7fbece2f0d0d1e6a6bddb67a9cf3690c002818a016c59014636").map(Mv),c_=qv(u_),f_=new Array(3).concat("ece7f2a6bddb2b8cbe","f1eef6bdc9e174a9cf0570b0","f1eef6bdc9e174a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf2b8cbe045a8d","f1eef6d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0034e7b","fff7fbece7f2d0d1e6a6bddb74a9cf3690c00570b0045a8d023858").map(Mv),s_=qv(f_),l_=new Array(3).concat("e7e1efc994c7dd1c77","f1eef6d7b5d8df65b0ce1256","f1eef6d7b5d8df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0dd1c77980043","f1eef6d4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125691003f","f7f4f9e7e1efd4b9dac994c7df65b0e7298ace125698004367001f").map(Mv),h_=qv(l_),d_=new Array(3).concat("fde0ddfa9fb5c51b8a","feebe2fbb4b9f768a1ae017e","feebe2fbb4b9f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1c51b8a7a0177","feebe2fcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a0177","fff7f3fde0ddfcc5c0fa9fb5f768a1dd3497ae017e7a017749006a").map(Mv),p_=qv(d_),g_=new Array(3).concat("edf8b17fcdbb2c7fb8","ffffcca1dab441b6c4225ea8","ffffcca1dab441b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c42c7fb8253494","ffffccc7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea80c2c84","ffffd9edf8b1c7e9b47fcdbb41b6c41d91c0225ea8253494081d58").map(Mv),y_=qv(g_),v_=new Array(3).concat("f7fcb9addd8e31a354","ffffccc2e69978c679238443","ffffccc2e69978c67931a354006837","ffffccd9f0a3addd8e78c67931a354006837","ffffccd9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443005a32","ffffe5f7fcb9d9f0a3addd8e78c67941ab5d238443006837004529").map(Mv),__=qv(v_),b_=new Array(3).concat("fff7bcfec44fd95f0e","ffffd4fed98efe9929cc4c02","ffffd4fed98efe9929d95f0e993404","ffffd4fee391fec44ffe9929d95f0e993404","ffffd4fee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c028c2d04","ffffe5fff7bcfee391fec44ffe9929ec7014cc4c02993404662506").map(Mv),m_=qv(b_),x_=new Array(3).concat("ffeda0feb24cf03b20","ffffb2fecc5cfd8d3ce31a1c","ffffb2fecc5cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cf03b20bd0026","ffffb2fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cb10026","ffffccffeda0fed976feb24cfd8d3cfc4e2ae31a1cbd0026800026").map(Mv),w_=qv(x_),M_=new Array(3).concat("deebf79ecae13182bd","eff3ffbdd7e76baed62171b5","eff3ffbdd7e76baed63182bd08519c","eff3ffc6dbef9ecae16baed63182bd08519c","eff3ffc6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b5084594","f7fbffdeebf7c6dbef9ecae16baed64292c62171b508519c08306b").map(Mv),A_=qv(M_),T_=new Array(3).concat("e5f5e0a1d99b31a354","edf8e9bae4b374c476238b45","edf8e9bae4b374c47631a354006d2c","edf8e9c7e9c0a1d99b74c47631a354006d2c","edf8e9c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45005a32","f7fcf5e5f5e0c7e9c0a1d99b74c47641ab5d238b45006d2c00441b").map(Mv),S_=qv(T_),E_=new Array(3).concat("f0f0f0bdbdbd636363","f7f7f7cccccc969696525252","f7f7f7cccccc969696636363252525","f7f7f7d9d9d9bdbdbd969696636363252525","f7f7f7d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525","fffffff0f0f0d9d9d9bdbdbd969696737373525252252525000000").map(Mv),k_=qv(E_),N_=new Array(3).concat("efedf5bcbddc756bb1","f2f0f7cbc9e29e9ac86a51a3","f2f0f7cbc9e29e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8756bb154278f","f2f0f7dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a34a1486","fcfbfdefedf5dadaebbcbddc9e9ac8807dba6a51a354278f3f007d").map(Mv),C_=qv(N_),P_=new Array(3).concat("fee0d2fc9272de2d26","fee5d9fcae91fb6a4acb181d","fee5d9fcae91fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4ade2d26a50f15","fee5d9fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181d99000d","fff5f0fee0d2fcbba1fc9272fb6a4aef3b2ccb181da50f1567000d").map(Mv),z_=qv(P_),D_=new Array(3).concat("fee6cefdae6be6550d","feeddefdbe85fd8d3cd94701","feeddefdbe85fd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3ce6550da63603","feeddefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d948018c2d04","fff5ebfee6cefdd0a2fdae6bfd8d3cf16913d94801a636037f2704").map(Mv),q_=qv(D_);var R_=Dr(Xe(300,.5,0),Xe(-240,.5,1)),F_=Dr(Xe(-100,.75,.35),Xe(80,1.5,.8)),O_=Dr(Xe(260,.75,.35),Xe(80,1.5,.8)),U_=Xe();var I_=ce(),B_=Math.PI/3,Y_=2*Math.PI/3;function L_(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}}var j_=L_(Mv("44015444025645045745055946075a46085c460a5d460b5e470d60470e6147106347116447136548146748166848176948186a481a6c481b6d481c6e481d6f481f70482071482173482374482475482576482677482878482979472a7a472c7a472d7b472e7c472f7d46307e46327e46337f463480453581453781453882443983443a83443b84433d84433e85423f854240864241864142874144874045884046883f47883f48893e49893e4a893e4c8a3d4d8a3d4e8a3c4f8a3c508b3b518b3b528b3a538b3a548c39558c39568c38588c38598c375a8c375b8d365c8d365d8d355e8d355f8d34608d34618d33628d33638d32648e32658e31668e31678e31688e30698e306a8e2f6b8e2f6c8e2e6d8e2e6e8e2e6f8e2d708e2d718e2c718e2c728e2c738e2b748e2b758e2a768e2a778e2a788e29798e297a8e297b8e287c8e287d8e277e8e277f8e27808e26818e26828e26828e25838e25848e25858e24868e24878e23888e23898e238a8d228b8d228c8d228d8d218e8d218f8d21908d21918c20928c20928c20938c1f948c1f958b1f968b1f978b1f988b1f998a1f9a8a1e9b8a1e9c891e9d891f9e891f9f881fa0881fa1881fa1871fa28720a38620a48621a58521a68522a78522a88423a98324aa8325ab8225ac8226ad8127ad8128ae8029af7f2ab07f2cb17e2db27d2eb37c2fb47c31b57b32b67a34b67935b77937b87838b9773aba763bbb753dbc743fbc7340bd7242be7144bf7046c06f48c16e4ac16d4cc26c4ec36b50c46a52c56954c56856c66758c7655ac8645cc8635ec96260ca6063cb5f65cb5e67cc5c69cd5b6ccd5a6ece5870cf5773d05675d05477d1537ad1517cd2507fd34e81d34d84d44b86d54989d5488bd6468ed64590d74393d74195d84098d83e9bd93c9dd93ba0da39a2da37a5db36a8db34aadc32addc30b0dd2fb2dd2db5de2bb8de29bade28bddf26c0df25c2df23c5e021c8e020cae11fcde11dd0e11cd2e21bd5e21ad8e219dae319dde318dfe318e2e418e5e419e7e419eae51aece51befe51cf1e51df4e61ef6e620f8e621fbe723fde725")),H_=L_(Mv("00000401000501010601010802010902020b02020d03030f03031204041405041606051806051a07061c08071e0907200a08220b09240c09260d0a290e0b2b100b2d110c2f120d31130d34140e36150e38160f3b180f3d19103f1a10421c10441d11471e114920114b21114e22115024125325125527125829115a2a115c2c115f2d11612f116331116533106734106936106b38106c390f6e3b0f703d0f713f0f72400f74420f75440f764510774710784910784a10794c117a4e117b4f127b51127c52137c54137d56147d57157e59157e5a167e5c167f5d177f5f187f601880621980641a80651a80671b80681c816a1c816b1d816d1d816e1e81701f81721f817320817521817621817822817922827b23827c23827e24828025828125818326818426818627818827818928818b29818c29818e2a81902a81912b81932b80942c80962c80982d80992d809b2e7f9c2e7f9e2f7fa02f7fa1307ea3307ea5317ea6317da8327daa337dab337cad347cae347bb0357bb2357bb3367ab5367ab73779b83779ba3878bc3978bd3977bf3a77c03a76c23b75c43c75c53c74c73d73c83e73ca3e72cc3f71cd4071cf4070d0416fd2426fd3436ed5446dd6456cd8456cd9466bdb476adc4869de4968df4a68e04c67e24d66e34e65e44f64e55064e75263e85362e95462ea5661eb5760ec5860ed5a5fee5b5eef5d5ef05f5ef1605df2625df2645cf3655cf4675cf4695cf56b5cf66c5cf66e5cf7705cf7725cf8745cf8765cf9785df9795df97b5dfa7d5efa7f5efa815ffb835ffb8560fb8761fc8961fc8a62fc8c63fc8e64fc9065fd9266fd9467fd9668fd9869fd9a6afd9b6bfe9d6cfe9f6dfea16efea36ffea571fea772fea973feaa74feac76feae77feb078feb27afeb47bfeb67cfeb77efeb97ffebb81febd82febf84fec185fec287fec488fec68afec88cfeca8dfecc8ffecd90fecf92fed194fed395fed597fed799fed89afdda9cfddc9efddea0fde0a1fde2a3fde3a5fde5a7fde7a9fde9aafdebacfcecaefceeb0fcf0b2fcf2b4fcf4b6fcf6b8fcf7b9fcf9bbfcfbbdfcfdbf")),X_=L_(Mv("00000401000501010601010802010a02020c02020e03021004031204031405041706041907051b08051d09061f0a07220b07240c08260d08290e092b10092d110a30120a32140b34150b37160b39180c3c190c3e1b0c411c0c431e0c451f0c48210c4a230c4c240c4f260c51280b53290b552b0b572d0b592f0a5b310a5c320a5e340a5f3609613809623909633b09643d09653e0966400a67420a68440a68450a69470b6a490b6a4a0c6b4c0c6b4d0d6c4f0d6c510e6c520e6d540f6d550f6d57106e59106e5a116e5c126e5d126e5f136e61136e62146e64156e65156e67166e69166e6a176e6c186e6d186e6f196e71196e721a6e741a6e751b6e771c6d781c6d7a1d6d7c1d6d7d1e6d7f1e6c801f6c82206c84206b85216b87216b88226a8a226a8c23698d23698f24699025689225689326679526679727669827669a28659b29649d29649f2a63a02a63a22b62a32c61a52c60a62d60a82e5fa92e5eab2f5ead305dae305cb0315bb1325ab3325ab43359b63458b73557b93556ba3655bc3754bd3853bf3952c03a51c13a50c33b4fc43c4ec63d4dc73e4cc83f4bca404acb4149cc4248ce4347cf4446d04545d24644d34743d44842d54a41d74b3fd84c3ed94d3dda4e3cdb503bdd513ade5238df5337e05536e15635e25734e35933e45a31e55c30e65d2fe75e2ee8602de9612bea632aeb6429eb6628ec6726ed6925ee6a24ef6c23ef6e21f06f20f1711ff1731df2741cf3761bf37819f47918f57b17f57d15f67e14f68013f78212f78410f8850ff8870ef8890cf98b0bf98c0af98e09fa9008fa9207fa9407fb9606fb9706fb9906fb9b06fb9d07fc9f07fca108fca309fca50afca60cfca80dfcaa0ffcac11fcae12fcb014fcb216fcb418fbb61afbb81dfbba1ffbbc21fbbe23fac026fac228fac42afac62df9c72ff9c932f9cb35f8cd37f8cf3af7d13df7d340f6d543f6d746f5d949f5db4cf4dd4ff4df53f4e156f3e35af3e55df2e661f2e865f2ea69f1ec6df1ed71f1ef75f1f179f2f27df2f482f3f586f3f68af4f88ef5f992f6fa96f8fb9af9fc9dfafda1fcffa4")),G_=L_(Mv("0d088710078813078916078a19068c1b068d1d068e20068f2206902406912605912805922a05932c05942e05952f059631059733059735049837049938049a3a049a3c049b3e049c3f049c41049d43039e44039e46039f48039f4903a04b03a14c02a14e02a25002a25102a35302a35502a45601a45801a45901a55b01a55c01a65e01a66001a66100a76300a76400a76600a76700a86900a86a00a86c00a86e00a86f00a87100a87201a87401a87501a87701a87801a87a02a87b02a87d03a87e03a88004a88104a78305a78405a78606a68707a68808a68a09a58b0aa58d0ba58e0ca48f0da4910ea3920fa39410a29511a19613a19814a099159f9a169f9c179e9d189d9e199da01a9ca11b9ba21d9aa31e9aa51f99a62098a72197a82296aa2395ab2494ac2694ad2793ae2892b02991b12a90b22b8fb32c8eb42e8db52f8cb6308bb7318ab83289ba3388bb3488bc3587bd3786be3885bf3984c03a83c13b82c23c81c33d80c43e7fc5407ec6417dc7427cc8437bc9447aca457acb4679cc4778cc4977cd4a76ce4b75cf4c74d04d73d14e72d24f71d35171d45270d5536fd5546ed6556dd7566cd8576bd9586ada5a6ada5b69db5c68dc5d67dd5e66de5f65de6164df6263e06363e16462e26561e26660e3685fe4695ee56a5de56b5de66c5ce76e5be76f5ae87059e97158e97257ea7457eb7556eb7655ec7754ed7953ed7a52ee7b51ef7c51ef7e50f07f4ff0804ef1814df1834cf2844bf3854bf3874af48849f48948f58b47f58c46f68d45f68f44f79044f79143f79342f89441f89540f9973ff9983ef99a3efa9b3dfa9c3cfa9e3bfb9f3afba139fba238fca338fca537fca636fca835fca934fdab33fdac33fdae32fdaf31fdb130fdb22ffdb42ffdb52efeb72dfeb82cfeba2cfebb2bfebd2afebe2afec029fdc229fdc328fdc527fdc627fdc827fdca26fdcb26fccd25fcce25fcd025fcd225fbd324fbd524fbd724fad824fada24f9dc24f9dd25f8df25f8e125f7e225f7e425f6e626f6e826f5e926f5eb27f4ed27f3ee27f3f027f2f227f1f426f1f525f0f724f0f921"));function V_(t){return function(){return t}}var $_=Math.abs,W_=Math.atan2,Z_=Math.cos,K_=Math.max,Q_=Math.min,J_=Math.sin,tb=Math.sqrt,nb=1e-12,eb=Math.PI,rb=eb/2,ib=2*eb;function ob(t){return t>1?0:t<-1?eb:Math.acos(t)}function ab(t){return t>=1?rb:t<=-1?-rb:Math.asin(t)}function ub(t){return t.innerRadius}function cb(t){return t.outerRadius}function fb(t){return t.startAngle}function sb(t){return t.endAngle}function lb(t){return t&&t.padAngle}function hb(t,n,e,r,i,o,a,u){var c=e-t,f=r-n,s=a-i,l=u-o,h=l*c-s*f;if(!(h*h<nb))return[t+(h=(s*(n-o)-l*(t-i))/h)*c,n+h*f]}function db(t,n,e,r,i,o,a){var u=t-e,c=n-r,f=(a?o:-o)/tb(u*u+c*c),s=f*c,l=-f*u,h=t+s,d=n+l,p=e+s,g=r+l,y=(h+p)/2,v=(d+g)/2,_=p-h,b=g-d,m=_*_+b*b,x=i-o,w=h*g-p*d,M=(b<0?-1:1)*tb(K_(0,x*x*m-w*w)),A=(w*b-_*M)/m,T=(-w*_-b*M)/m,S=(w*b+_*M)/m,E=(-w*_+b*M)/m,k=A-y,N=T-v,C=S-y,P=E-v;return k*k+N*N>C*C+P*P&&(A=S,T=E),{cx:A,cy:T,x01:-s,y01:-l,x11:A*(i/x-1),y11:T*(i/x-1)}}var pb=Array.prototype.slice;function gb(t){return"object"==typeof t&&"length"in t?t:Array.from(t)}function yb(t){this._context=t}function vb(t){return new yb(t)}function _b(t){return t[0]}function bb(t){return t[1]}function mb(t,n){var e=V_(!0),r=null,i=vb,o=null;function a(a){var u,c,f,s=(a=gb(a)).length,l=!1;for(null==r&&(o=i(f=ta())),u=0;u<=s;++u)!(u<s&&e(c=a[u],u,a))===l&&((l=!l)?o.lineStart():o.lineEnd()),l&&o.point(+t(c,u,a),+n(c,u,a));if(f)return o=null,f+""||null}return t="function"==typeof t?t:void 0===t?_b:V_(t),n="function"==typeof n?n:void 0===n?bb:V_(n),a.x=function(n){return arguments.length?(t="function"==typeof n?n:V_(+n),a):t},a.y=function(t){return arguments.length?(n="function"==typeof t?t:V_(+t),a):n},a.defined=function(t){return arguments.length?(e="function"==typeof t?t:V_(!!t),a):e},a.curve=function(t){return arguments.length?(i=t,null!=r&&(o=i(r)),a):i},a.context=function(t){return arguments.length?(null==t?r=o=null:o=i(r=t),a):r},a}function xb(t,n,e){var r=null,i=V_(!0),o=null,a=vb,u=null;function c(c){var f,s,l,h,d,p=(c=gb(c)).length,g=!1,y=new Array(p),v=new Array(p);for(null==o&&(u=a(d=ta())),f=0;f<=p;++f){if(!(f<p&&i(h=c[f],f,c))===g)if(g=!g)s=f,u.areaStart(),u.lineStart();else{for(u.lineEnd(),u.lineStart(),l=f-1;l>=s;--l)u.point(y[l],v[l]);u.lineEnd(),u.areaEnd()}g&&(y[f]=+t(h,f,c),v[f]=+n(h,f,c),u.point(r?+r(h,f,c):y[f],e?+e(h,f,c):v[f]))}if(d)return u=null,d+""||null}function f(){return mb().defined(i).curve(a).context(o)}return t="function"==typeof t?t:void 0===t?_b:V_(+t),n="function"==typeof n?n:V_(void 0===n?0:+n),e="function"==typeof e?e:void 0===e?bb:V_(+e),c.x=function(n){return arguments.length?(t="function"==typeof n?n:V_(+n),r=null,c):t},c.x0=function(n){return arguments.length?(t="function"==typeof n?n:V_(+n),c):t},c.x1=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:V_(+t),c):r},c.y=function(t){return arguments.length?(n="function"==typeof t?t:V_(+t),e=null,c):n},c.y0=function(t){return arguments.length?(n="function"==typeof t?t:V_(+t),c):n},c.y1=function(t){return arguments.length?(e=null==t?null:"function"==typeof t?t:V_(+t),c):e},c.lineX0=c.lineY0=function(){return f().x(t).y(n)},c.lineY1=function(){return f().x(t).y(e)},c.lineX1=function(){return f().x(r).y(n)},c.defined=function(t){return arguments.length?(i="function"==typeof t?t:V_(!!t),c):i},c.curve=function(t){return arguments.length?(a=t,null!=o&&(u=a(o)),c):a},c.context=function(t){return arguments.length?(null==t?o=u=null:u=a(o=t),c):o},c}function wb(t,n){return n<t?-1:n>t?1:n>=t?0:NaN}function Mb(t){return t}yb.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._point=0},lineEnd:function(){(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:this._context.lineTo(t,n)}}};var Ab=Sb(vb);function Tb(t){this._curve=t}function Sb(t){function n(n){return new Tb(t(n))}return n._curve=t,n}function Eb(t){var n=t.curve;return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t.curve=function(t){return arguments.length?n(Sb(t)):n()._curve},t}function kb(){return Eb(mb().curve(Ab))}function Nb(){var t=xb().curve(Ab),n=t.curve,e=t.lineX0,r=t.lineX1,i=t.lineY0,o=t.lineY1;return t.angle=t.x,delete t.x,t.startAngle=t.x0,delete t.x0,t.endAngle=t.x1,delete t.x1,t.radius=t.y,delete t.y,t.innerRadius=t.y0,delete t.y0,t.outerRadius=t.y1,delete t.y1,t.lineStartAngle=function(){return Eb(e())},delete t.lineX0,t.lineEndAngle=function(){return Eb(r())},delete t.lineX1,t.lineInnerRadius=function(){return Eb(i())},delete t.lineY0,t.lineOuterRadius=function(){return Eb(o())},delete t.lineY1,t.curve=function(t){return arguments.length?n(Sb(t)):n()._curve},t}function Cb(t,n){return[(n=+n)*Math.cos(t-=Math.PI/2),n*Math.sin(t)]}function Pb(t){return t.source}function zb(t){return t.target}function Db(t){var n=Pb,e=zb,r=_b,i=bb,o=null;function a(){var a,u=pb.call(arguments),c=n.apply(this,u),f=e.apply(this,u);if(o||(o=a=ta()),t(o,+r.apply(this,(u[0]=c,u)),+i.apply(this,u),+r.apply(this,(u[0]=f,u)),+i.apply(this,u)),a)return o=null,a+""||null}return a.source=function(t){return arguments.length?(n=t,a):n},a.target=function(t){return arguments.length?(e=t,a):e},a.x=function(t){return arguments.length?(r="function"==typeof t?t:V_(+t),a):r},a.y=function(t){return arguments.length?(i="function"==typeof t?t:V_(+t),a):i},a.context=function(t){return arguments.length?(o=null==t?null:t,a):o},a}function qb(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n=(n+r)/2,e,n,i,r,i)}function Rb(t,n,e,r,i){t.moveTo(n,e),t.bezierCurveTo(n,e=(e+i)/2,r,e,r,i)}function Fb(t,n,e,r,i){var o=Cb(n,e),a=Cb(n,e=(e+i)/2),u=Cb(r,e),c=Cb(r,i);t.moveTo(o[0],o[1]),t.bezierCurveTo(a[0],a[1],u[0],u[1],c[0],c[1])}Tb.prototype={areaStart:function(){this._curve.areaStart()},areaEnd:function(){this._curve.areaEnd()},lineStart:function(){this._curve.lineStart()},lineEnd:function(){this._curve.lineEnd()},point:function(t,n){this._curve.point(n*Math.sin(t),n*-Math.cos(t))}};var Ob={draw:function(t,n){var e=Math.sqrt(n/eb);t.moveTo(e,0),t.arc(0,0,e,0,ib)}},Ub={draw:function(t,n){var e=Math.sqrt(n/5)/2;t.moveTo(-3*e,-e),t.lineTo(-e,-e),t.lineTo(-e,-3*e),t.lineTo(e,-3*e),t.lineTo(e,-e),t.lineTo(3*e,-e),t.lineTo(3*e,e),t.lineTo(e,e),t.lineTo(e,3*e),t.lineTo(-e,3*e),t.lineTo(-e,e),t.lineTo(-3*e,e),t.closePath()}},Ib=Math.sqrt(1/3),Bb=2*Ib,Yb={draw:function(t,n){var e=Math.sqrt(n/Bb),r=e*Ib;t.moveTo(0,-e),t.lineTo(r,0),t.lineTo(0,e),t.lineTo(-r,0),t.closePath()}},Lb=Math.sin(eb/10)/Math.sin(7*eb/10),jb=Math.sin(ib/10)*Lb,Hb=-Math.cos(ib/10)*Lb,Xb={draw:function(t,n){var e=Math.sqrt(.8908130915292852*n),r=jb*e,i=Hb*e;t.moveTo(0,-e),t.lineTo(r,i);for(var o=1;o<5;++o){var a=ib*o/5,u=Math.cos(a),c=Math.sin(a);t.lineTo(c*e,-u*e),t.lineTo(u*r-c*i,c*r+u*i)}t.closePath()}},Gb={draw:function(t,n){var e=Math.sqrt(n),r=-e/2;t.rect(r,r,e,e)}},Vb=Math.sqrt(3),$b={draw:function(t,n){var e=-Math.sqrt(n/(3*Vb));t.moveTo(0,2*e),t.lineTo(-Vb*e,-e),t.lineTo(Vb*e,-e),t.closePath()}},Wb=-.5,Zb=Math.sqrt(3)/2,Kb=1/Math.sqrt(12),Qb=3*(Kb/2+1),Jb={draw:function(t,n){var e=Math.sqrt(n/Qb),r=e/2,i=e*Kb,o=r,a=e*Kb+e,u=-o,c=a;t.moveTo(r,i),t.lineTo(o,a),t.lineTo(u,c),t.lineTo(Wb*r-Zb*i,Zb*r+Wb*i),t.lineTo(Wb*o-Zb*a,Zb*o+Wb*a),t.lineTo(Wb*u-Zb*c,Zb*u+Wb*c),t.lineTo(Wb*r+Zb*i,Wb*i-Zb*r),t.lineTo(Wb*o+Zb*a,Wb*a-Zb*o),t.lineTo(Wb*u+Zb*c,Wb*c-Zb*u),t.closePath()}},tm=[Ob,Ub,Yb,Gb,Xb,$b,Jb];function nm(){}function em(t,n,e){t._context.bezierCurveTo((2*t._x0+t._x1)/3,(2*t._y0+t._y1)/3,(t._x0+2*t._x1)/3,(t._y0+2*t._y1)/3,(t._x0+4*t._x1+n)/6,(t._y0+4*t._y1+e)/6)}function rm(t){this._context=t}function im(t){this._context=t}function om(t){this._context=t}function am(t,n){this._basis=new rm(t),this._beta=n}rm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){switch(this._point){case 3:em(this,this._x1,this._y1);case 2:this._context.lineTo(this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,this._context.lineTo((5*this._x0+this._x1)/6,(5*this._y0+this._y1)/6);default:em(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},im.prototype={areaStart:nm,areaEnd:nm,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._y0=this._y1=this._y2=this._y3=this._y4=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x2,this._y2),this._context.closePath();break;case 2:this._context.moveTo((this._x2+2*this._x3)/3,(this._y2+2*this._y3)/3),this._context.lineTo((this._x3+2*this._x2)/3,(this._y3+2*this._y2)/3),this._context.closePath();break;case 3:this.point(this._x2,this._y2),this.point(this._x3,this._y3),this.point(this._x4,this._y4)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x2=t,this._y2=n;break;case 1:this._point=2,this._x3=t,this._y3=n;break;case 2:this._point=3,this._x4=t,this._y4=n,this._context.moveTo((this._x0+4*this._x1+t)/6,(this._y0+4*this._y1+n)/6);break;default:em(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},om.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3;var e=(this._x0+4*this._x1+t)/6,r=(this._y0+4*this._y1+n)/6;this._line?this._context.lineTo(e,r):this._context.moveTo(e,r);break;case 3:this._point=4;default:em(this,t,n)}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n}},am.prototype={lineStart:function(){this._x=[],this._y=[],this._basis.lineStart()},lineEnd:function(){var t=this._x,n=this._y,e=t.length-1;if(e>0)for(var r,i=t[0],o=n[0],a=t[e]-i,u=n[e]-o,c=-1;++c<=e;)r=c/e,this._basis.point(this._beta*t[c]+(1-this._beta)*(i+r*a),this._beta*n[c]+(1-this._beta)*(o+r*u));this._x=this._y=null,this._basis.lineEnd()},point:function(t,n){this._x.push(+t),this._y.push(+n)}};var um=function t(n){function e(t){return 1===n?new rm(t):new am(t,n)}return e.beta=function(n){return t(+n)},e}(.85);function cm(t,n,e){t._context.bezierCurveTo(t._x1+t._k*(t._x2-t._x0),t._y1+t._k*(t._y2-t._y0),t._x2+t._k*(t._x1-n),t._y2+t._k*(t._y1-e),t._x2,t._y2)}function fm(t,n){this._context=t,this._k=(1-n)/6}fm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:cm(this,this._x1,this._y1)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2,this._x1=t,this._y1=n;break;case 2:this._point=3;default:cm(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var sm=function t(n){function e(t){return new fm(t,n)}return e.tension=function(n){return t(+n)},e}(0);function lm(t,n){this._context=t,this._k=(1-n)/6}lm.prototype={areaStart:nm,areaEnd:nm,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:cm(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var hm=function t(n){function e(t){return new lm(t,n)}return e.tension=function(n){return t(+n)},e}(0);function dm(t,n){this._context=t,this._k=(1-n)/6}dm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:cm(this,t,n)}this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var pm=function t(n){function e(t){return new dm(t,n)}return e.tension=function(n){return t(+n)},e}(0);function gm(t,n,e){var r=t._x1,i=t._y1,o=t._x2,a=t._y2;if(t._l01_a>nb){var u=2*t._l01_2a+3*t._l01_a*t._l12_a+t._l12_2a,c=3*t._l01_a*(t._l01_a+t._l12_a);r=(r*u-t._x0*t._l12_2a+t._x2*t._l01_2a)/c,i=(i*u-t._y0*t._l12_2a+t._y2*t._l01_2a)/c}if(t._l23_a>nb){var f=2*t._l23_2a+3*t._l23_a*t._l12_a+t._l12_2a,s=3*t._l23_a*(t._l23_a+t._l12_a);o=(o*f+t._x1*t._l23_2a-n*t._l12_2a)/s,a=(a*f+t._y1*t._l23_2a-e*t._l12_2a)/s}t._context.bezierCurveTo(r,i,o,a,t._x2,t._y2)}function ym(t,n){this._context=t,this._alpha=n}ym.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x2,this._y2);break;case 3:this.point(this._x2,this._y2)}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3;default:gm(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var vm=function t(n){function e(t){return n?new ym(t,n):new fm(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function _m(t,n){this._context=t,this._alpha=n}_m.prototype={areaStart:nm,areaEnd:nm,lineStart:function(){this._x0=this._x1=this._x2=this._x3=this._x4=this._x5=this._y0=this._y1=this._y2=this._y3=this._y4=this._y5=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){switch(this._point){case 1:this._context.moveTo(this._x3,this._y3),this._context.closePath();break;case 2:this._context.lineTo(this._x3,this._y3),this._context.closePath();break;case 3:this.point(this._x3,this._y3),this.point(this._x4,this._y4),this.point(this._x5,this._y5)}},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1,this._x3=t,this._y3=n;break;case 1:this._point=2,this._context.moveTo(this._x4=t,this._y4=n);break;case 2:this._point=3,this._x5=t,this._y5=n;break;default:gm(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var bm=function t(n){function e(t){return n?new _m(t,n):new lm(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function mm(t,n){this._context=t,this._alpha=n}mm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._x2=this._y0=this._y1=this._y2=NaN,this._l01_a=this._l12_a=this._l23_a=this._l01_2a=this._l12_2a=this._l23_2a=this._point=0},lineEnd:function(){(this._line||0!==this._line&&3===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){if(t=+t,n=+n,this._point){var e=this._x2-t,r=this._y2-n;this._l23_a=Math.sqrt(this._l23_2a=Math.pow(e*e+r*r,this._alpha))}switch(this._point){case 0:this._point=1;break;case 1:this._point=2;break;case 2:this._point=3,this._line?this._context.lineTo(this._x2,this._y2):this._context.moveTo(this._x2,this._y2);break;case 3:this._point=4;default:gm(this,t,n)}this._l01_a=this._l12_a,this._l12_a=this._l23_a,this._l01_2a=this._l12_2a,this._l12_2a=this._l23_2a,this._x0=this._x1,this._x1=this._x2,this._x2=t,this._y0=this._y1,this._y1=this._y2,this._y2=n}};var xm=function t(n){function e(t){return n?new mm(t,n):new dm(t,0)}return e.alpha=function(n){return t(+n)},e}(.5);function wm(t){this._context=t}function Mm(t){return t<0?-1:1}function Am(t,n,e){var r=t._x1-t._x0,i=n-t._x1,o=(t._y1-t._y0)/(r||i<0&&-0),a=(e-t._y1)/(i||r<0&&-0),u=(o*i+a*r)/(r+i);return(Mm(o)+Mm(a))*Math.min(Math.abs(o),Math.abs(a),.5*Math.abs(u))||0}function Tm(t,n){var e=t._x1-t._x0;return e?(3*(t._y1-t._y0)/e-n)/2:n}function Sm(t,n,e){var r=t._x0,i=t._y0,o=t._x1,a=t._y1,u=(o-r)/3;t._context.bezierCurveTo(r+u,i+u*n,o-u,a-u*e,o,a)}function Em(t){this._context=t}function km(t){this._context=new Nm(t)}function Nm(t){this._context=t}function Cm(t){this._context=t}function Pm(t){var n,e,r=t.length-1,i=new Array(r),o=new Array(r),a=new Array(r);for(i[0]=0,o[0]=2,a[0]=t[0]+2*t[1],n=1;n<r-1;++n)i[n]=1,o[n]=4,a[n]=4*t[n]+2*t[n+1];for(i[r-1]=2,o[r-1]=7,a[r-1]=8*t[r-1]+t[r],n=1;n<r;++n)e=i[n]/o[n-1],o[n]-=e,a[n]-=e*a[n-1];for(i[r-1]=a[r-1]/o[r-1],n=r-2;n>=0;--n)i[n]=(a[n]-i[n+1])/o[n];for(o[r-1]=(t[r]+i[r-1])/2,n=0;n<r-1;++n)o[n]=2*t[n+1]-i[n+1];return[i,o]}function zm(t,n){this._context=t,this._t=n}function Dm(t,n){if((i=t.length)>1)for(var e,r,i,o=1,a=t[n[0]],u=a.length;o<i;++o)for(r=a,a=t[n[o]],e=0;e<u;++e)a[e][1]+=a[e][0]=isNaN(r[e][1])?r[e][0]:r[e][1]}function qm(t){for(var n=t.length,e=new Array(n);--n>=0;)e[n]=n;return e}function Rm(t,n){return t[n]}function Fm(t){const n=[];return n.key=t,n}function Om(t){var n=t.map(Um);return qm(t).sort((function(t,e){return n[t]-n[e]}))}function Um(t){for(var n,e=-1,r=0,i=t.length,o=-1/0;++e<i;)(n=+t[e][1])>o&&(o=n,r=e);return r}function Im(t){var n=t.map(Bm);return qm(t).sort((function(t,e){return n[t]-n[e]}))}function Bm(t){for(var n,e=0,r=-1,i=t.length;++r<i;)(n=+t[r][1])&&(e+=n);return e}wm.prototype={areaStart:nm,areaEnd:nm,lineStart:function(){this._point=0},lineEnd:function(){this._point&&this._context.closePath()},point:function(t,n){t=+t,n=+n,this._point?this._context.lineTo(t,n):(this._point=1,this._context.moveTo(t,n))}},Em.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x0=this._x1=this._y0=this._y1=this._t0=NaN,this._point=0},lineEnd:function(){switch(this._point){case 2:this._context.lineTo(this._x1,this._y1);break;case 3:Sm(this,this._t0,Tm(this,this._t0))}(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line=1-this._line},point:function(t,n){var e=NaN;if(n=+n,(t=+t)!==this._x1||n!==this._y1){switch(this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;break;case 2:this._point=3,Sm(this,Tm(this,e=Am(this,t,n)),e);break;default:Sm(this,this._t0,e=Am(this,t,n))}this._x0=this._x1,this._x1=t,this._y0=this._y1,this._y1=n,this._t0=e}}},(km.prototype=Object.create(Em.prototype)).point=function(t,n){Em.prototype.point.call(this,n,t)},Nm.prototype={moveTo:function(t,n){this._context.moveTo(n,t)},closePath:function(){this._context.closePath()},lineTo:function(t,n){this._context.lineTo(n,t)},bezierCurveTo:function(t,n,e,r,i,o){this._context.bezierCurveTo(n,t,r,e,o,i)}},Cm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=[],this._y=[]},lineEnd:function(){var t=this._x,n=this._y,e=t.length;if(e)if(this._line?this._context.lineTo(t[0],n[0]):this._context.moveTo(t[0],n[0]),2===e)this._context.lineTo(t[1],n[1]);else for(var r=Pm(t),i=Pm(n),o=0,a=1;a<e;++o,++a)this._context.bezierCurveTo(r[0][o],i[0][o],r[1][o],i[1][o],t[a],n[a]);(this._line||0!==this._line&&1===e)&&this._context.closePath(),this._line=1-this._line,this._x=this._y=null},point:function(t,n){this._x.push(+t),this._y.push(+n)}},zm.prototype={areaStart:function(){this._line=0},areaEnd:function(){this._line=NaN},lineStart:function(){this._x=this._y=NaN,this._point=0},lineEnd:function(){0<this._t&&this._t<1&&2===this._point&&this._context.lineTo(this._x,this._y),(this._line||0!==this._line&&1===this._point)&&this._context.closePath(),this._line>=0&&(this._t=1-this._t,this._line=1-this._line)},point:function(t,n){switch(t=+t,n=+n,this._point){case 0:this._point=1,this._line?this._context.lineTo(t,n):this._context.moveTo(t,n);break;case 1:this._point=2;default:if(this._t<=0)this._context.lineTo(this._x,n),this._context.lineTo(t,n);else{var e=this._x*(1-this._t)+t*this._t;this._context.lineTo(e,this._y),this._context.lineTo(e,n)}}this._x=t,this._y=n}};var Ym=t=>()=>t;function Lm(t,{sourceEvent:n,target:e,transform:r,dispatch:i}){Object.defineProperties(this,{type:{value:t,enumerable:!0,configurable:!0},sourceEvent:{value:n,enumerable:!0,configurable:!0},target:{value:e,enumerable:!0,configurable:!0},transform:{value:r,enumerable:!0,configurable:!0},_:{value:i}})}function jm(t,n,e){this.k=t,this.x=n,this.y=e}jm.prototype={constructor:jm,scale:function(t){return 1===t?this:new jm(this.k*t,this.x,this.y)},translate:function(t,n){return 0===t&0===n?this:new jm(this.k,this.x+this.k*t,this.y+this.k*n)},apply:function(t){return[t[0]*this.k+this.x,t[1]*this.k+this.y]},applyX:function(t){return t*this.k+this.x},applyY:function(t){return t*this.k+this.y},invert:function(t){return[(t[0]-this.x)/this.k,(t[1]-this.y)/this.k]},invertX:function(t){return(t-this.x)/this.k},invertY:function(t){return(t-this.y)/this.k},rescaleX:function(t){return t.copy().domain(t.range().map(this.invertX,this).map(t.invert,t))},rescaleY:function(t){return t.copy().domain(t.range().map(this.invertY,this).map(t.invert,t))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var Hm=new jm(1,0,0);function Xm(t){for(;!t.__zoom;)if(!(t=t.parentNode))return Hm;return t.__zoom}function Gm(t){t.stopImmediatePropagation()}function Vm(t){t.preventDefault(),t.stopImmediatePropagation()}function $m(t){return!(t.ctrlKey&&"wheel"!==t.type||t.button)}function Wm(){var t=this;return t instanceof SVGElement?(t=t.ownerSVGElement||t).hasAttribute("viewBox")?[[(t=t.viewBox.baseVal).x,t.y],[t.x+t.width,t.y+t.height]]:[[0,0],[t.width.baseVal.value,t.height.baseVal.value]]:[[0,0],[t.clientWidth,t.clientHeight]]}function Zm(){return this.__zoom||Hm}function Km(t){return-t.deltaY*(1===t.deltaMode?.05:t.deltaMode?1:.002)*(t.ctrlKey?10:1)}function Qm(){return navigator.maxTouchPoints||"ontouchstart"in this}function Jm(t,n,e){var r=t.invertX(n[0][0])-e[0][0],i=t.invertX(n[1][0])-e[1][0],o=t.invertY(n[0][1])-e[0][1],a=t.invertY(n[1][1])-e[1][1];return t.translate(i>r?(r+i)/2:Math.min(0,r)||Math.max(0,i),a>o?(o+a)/2:Math.min(0,o)||Math.max(0,a))}Xm.prototype=jm.prototype,t.Adder=g,t.Delaunay=Ga,t.FormatSpecifier=Qu,t.Voronoi=Ba,t.active=function(t,n){var e,r,i=t.__transition;if(i)for(r in n=null==n?null:n+"",i)if((e=i[r]).state>1&&e.name===n)return new qi([[t]],co,n,+r);return null},t.arc=function(){var t=ub,n=cb,e=V_(0),r=null,i=fb,o=sb,a=lb,u=null;function c(){var c,f,s=+t.apply(this,arguments),l=+n.apply(this,arguments),h=i.apply(this,arguments)-rb,d=o.apply(this,arguments)-rb,p=$_(d-h),g=d>h;if(u||(u=c=ta()),l<s&&(f=l,l=s,s=f),l>nb)if(p>ib-nb)u.moveTo(l*Z_(h),l*J_(h)),u.arc(0,0,l,h,d,!g),s>nb&&(u.moveTo(s*Z_(d),s*J_(d)),u.arc(0,0,s,d,h,g));else{var y,v,_=h,b=d,m=h,x=d,w=p,M=p,A=a.apply(this,arguments)/2,T=A>nb&&(r?+r.apply(this,arguments):tb(s*s+l*l)),S=Q_($_(l-s)/2,+e.apply(this,arguments)),E=S,k=S;if(T>nb){var N=ab(T/s*J_(A)),C=ab(T/l*J_(A));(w-=2*N)>nb?(m+=N*=g?1:-1,x-=N):(w=0,m=x=(h+d)/2),(M-=2*C)>nb?(_+=C*=g?1:-1,b-=C):(M=0,_=b=(h+d)/2)}var P=l*Z_(_),z=l*J_(_),D=s*Z_(x),q=s*J_(x);if(S>nb){var R,F=l*Z_(b),O=l*J_(b),U=s*Z_(m),I=s*J_(m);if(p<eb&&(R=hb(P,z,U,I,F,O,D,q))){var B=P-R[0],Y=z-R[1],L=F-R[0],j=O-R[1],H=1/J_(ob((B*L+Y*j)/(tb(B*B+Y*Y)*tb(L*L+j*j)))/2),X=tb(R[0]*R[0]+R[1]*R[1]);E=Q_(S,(s-X)/(H-1)),k=Q_(S,(l-X)/(H+1))}}M>nb?k>nb?(y=db(U,I,P,z,l,k,g),v=db(F,O,D,q,l,k,g),u.moveTo(y.cx+y.x01,y.cy+y.y01),k<S?u.arc(y.cx,y.cy,k,W_(y.y01,y.x01),W_(v.y01,v.x01),!g):(u.arc(y.cx,y.cy,k,W_(y.y01,y.x01),W_(y.y11,y.x11),!g),u.arc(0,0,l,W_(y.cy+y.y11,y.cx+y.x11),W_(v.cy+v.y11,v.cx+v.x11),!g),u.arc(v.cx,v.cy,k,W_(v.y11,v.x11),W_(v.y01,v.x01),!g))):(u.moveTo(P,z),u.arc(0,0,l,_,b,!g)):u.moveTo(P,z),s>nb&&w>nb?E>nb?(y=db(D,q,F,O,s,-E,g),v=db(P,z,U,I,s,-E,g),u.lineTo(y.cx+y.x01,y.cy+y.y01),E<S?u.arc(y.cx,y.cy,E,W_(y.y01,y.x01),W_(v.y01,v.x01),!g):(u.arc(y.cx,y.cy,E,W_(y.y01,y.x01),W_(y.y11,y.x11),!g),u.arc(0,0,s,W_(y.cy+y.y11,y.cx+y.x11),W_(v.cy+v.y11,v.cx+v.x11),g),u.arc(v.cx,v.cy,E,W_(v.y11,v.x11),W_(v.y01,v.x01),!g))):u.arc(0,0,s,x,m,g):u.lineTo(D,q)}else u.moveTo(0,0);if(u.closePath(),c)return u=null,c+""||null}return c.centroid=function(){var e=(+t.apply(this,arguments)+ +n.apply(this,arguments))/2,r=(+i.apply(this,arguments)+ +o.apply(this,arguments))/2-eb/2;return[Z_(r)*e,J_(r)*e]},c.innerRadius=function(n){return arguments.length?(t="function"==typeof n?n:V_(+n),c):t},c.outerRadius=function(t){return arguments.length?(n="function"==typeof t?t:V_(+t),c):n},c.cornerRadius=function(t){return arguments.length?(e="function"==typeof t?t:V_(+t),c):e},c.padRadius=function(t){return arguments.length?(r=null==t?null:"function"==typeof t?t:V_(+t),c):r},c.startAngle=function(t){return arguments.length?(i="function"==typeof t?t:V_(+t),c):i},c.endAngle=function(t){return arguments.length?(o="function"==typeof t?t:V_(+t),c):o},c.padAngle=function(t){return arguments.length?(a="function"==typeof t?t:V_(+t),c):a},c.context=function(t){return arguments.length?(u=null==t?null:t,c):u},c},t.area=xb,t.areaRadial=Nb,t.ascending=n,t.autoType=function(t){for(var n in t){var e,r,i=t[n].trim();if(i)if("true"===i)i=!0;else if("false"===i)i=!1;else if("NaN"===i)i=NaN;else if(isNaN(e=+i)){if(!(r=i.match(/^([-+]\d{2})?\d{4}(-\d{2}(-\d{2})?)?(T\d{2}:\d{2}(:\d{2}(\.\d{3})?)?(Z|[-+]\d{2}:\d{2})?)?$/)))continue;yu&&r[4]&&!r[7]&&(i=i.replace(/-/g,"/").replace(/T/," ")),i=new Date(i)}else i=e;else i=null;t[n]=i}return t},t.axisBottom=function(t){return rt(3,t)},t.axisLeft=function(t){return rt(4,t)},t.axisRight=function(t){return rt(2,t)},t.axisTop=function(t){return rt(1,t)},t.bin=N,t.bisect=o,t.bisectCenter=u,t.bisectLeft=a,t.bisectRight=o,t.bisector=e,t.blob=function(t,n){return fetch(t,n).then(vu)},t.brush=function(){return Oo(To)},t.brushSelection=function(t){var n=t.__brush;return n?n.dim.output(n.selection):null},t.brushX=function(){return Oo(Mo)},t.brushY=function(){return Oo(Ao)},t.buffer=function(t,n){return fetch(t,n).then(_u)},t.chord=function(){return $o(!1,!1)},t.chordDirected=function(){return $o(!0,!1)},t.chordTranspose=function(){return $o(!1,!0)},t.cluster=function(){var t=zh,n=1,e=1,r=!1;function i(i){var o,a=0;i.eachAfter((function(n){var e=n.children;e?(n.x=function(t){return t.reduce(Dh,0)/t.length}(e),n.y=function(t){return 1+t.reduce(qh,0)}(e)):(n.x=o?a+=t(n,o):0,n.y=0,o=n)}));var u=function(t){for(var n;n=t.children;)t=n[0];return t}(i),c=function(t){for(var n;n=t.children;)t=n[n.length-1];return t}(i),f=u.x-t(u,c)/2,s=c.x+t(c,u)/2;return i.eachAfter(r?function(t){t.x=(t.x-i.x)*n,t.y=(i.y-t.y)*e}:function(t){t.x=(t.x-f)/(s-f)*n,t.y=(1-(i.y?t.y/i.y:1))*e})}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.color=ie,t.contourDensity=function(){var t=wa,n=Ma,e=Aa,r=960,i=500,o=20,a=2,u=3*o,c=r+2*u>>a,f=i+2*u>>a,s=da(20);function l(r){var i=new Float32Array(c*f),l=new Float32Array(c*f);r.forEach((function(r,o,s){var l=+t(r,o,s)+u>>a,h=+n(r,o,s)+u>>a,d=+e(r,o,s);l>=0&&l<c&&h>=0&&h<f&&(i[l+h*c]+=d)})),ma({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),xa({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),ma({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),xa({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a),ma({width:c,height:f,data:i},{width:c,height:f,data:l},o>>a),xa({width:c,height:f,data:l},{width:c,height:f,data:i},o>>a);var d=s(i);if(!Array.isArray(d)){var p=C(i);d=S(0,p,d),(d=Y(0,Math.floor(p/d)*d,d)).shift()}return ba().thresholds(d).size([c,f])(i).map(h)}function h(t){return t.value*=Math.pow(2,-2*a),t.coordinates.forEach(d),t}function d(t){t.forEach(p)}function p(t){t.forEach(g)}function g(t){t[0]=t[0]*Math.pow(2,a)-u,t[1]=t[1]*Math.pow(2,a)-u}function y(){return c=r+2*(u=3*o)>>a,f=i+2*u>>a,l}return l.x=function(n){return arguments.length?(t="function"==typeof n?n:da(+n),l):t},l.y=function(t){return arguments.length?(n="function"==typeof t?t:da(+t),l):n},l.weight=function(t){return arguments.length?(e="function"==typeof t?t:da(+t),l):e},l.size=function(t){if(!arguments.length)return[r,i];var n=+t[0],e=+t[1];if(!(n>=0&&e>=0))throw new Error("invalid size");return r=n,i=e,y()},l.cellSize=function(t){if(!arguments.length)return 1<<a;if(!((t=+t)>=1))throw new Error("invalid cell size");return a=Math.floor(Math.log(t)/Math.LN2),y()},l.thresholds=function(t){return arguments.length?(s="function"==typeof t?t:Array.isArray(t)?da(la.call(t)):da(t),l):s},l.bandwidth=function(t){if(!arguments.length)return Math.sqrt(o*(o+1));if(!((t=+t)>=0))throw new Error("invalid bandwidth");return o=Math.round((Math.sqrt(4*t*t+1)-1)/2),y()},l},t.contours=ba,t.count=c,t.create=function(t){return An(gt(t).call(document.documentElement))},t.creator=gt,t.cross=function(...t){const n="function"==typeof t[t.length-1]&&function(t){return n=>t(...n)}(t.pop()),e=(t=t.map(l)).map(f),r=t.length-1,i=new Array(r+1).fill(0),o=[];if(r<0||e.some(s))return o;for(;;){o.push(i.map((n,e)=>t[e][n]));let a=r;for(;++i[a]===e[a];){if(0===a)return n?o.map(n):o;i[a--]=0}}},t.csv=wu,t.csvFormat=ru,t.csvFormatBody=iu,t.csvFormatRow=au,t.csvFormatRows=ou,t.csvFormatValue=uu,t.csvParse=nu,t.csvParseRows=eu,t.cubehelix=Xe,t.cumsum=function(t,n){var e=0,r=0;return Float64Array.from(t,void 0===n?t=>e+=+t||0:i=>e+=+n(i,r++,t)||0)},t.curveBasis=function(t){return new rm(t)},t.curveBasisClosed=function(t){return new im(t)},t.curveBasisOpen=function(t){return new om(t)},t.curveBundle=um,t.curveCardinal=sm,t.curveCardinalClosed=hm,t.curveCardinalOpen=pm,t.curveCatmullRom=vm,t.curveCatmullRomClosed=bm,t.curveCatmullRomOpen=xm,t.curveLinear=vb,t.curveLinearClosed=function(t){return new wm(t)},t.curveMonotoneX=function(t){return new Em(t)},t.curveMonotoneY=function(t){return new km(t)},t.curveNatural=function(t){return new Cm(t)},t.curveStep=function(t){return new zm(t,.5)},t.curveStepAfter=function(t){return new zm(t,1)},t.curveStepBefore=function(t){return new zm(t,0)},t.descending=function(t,n){return n<t?-1:n>t?1:n>=t?0:NaN},t.deviation=d,t.difference=function(t,...n){t=new Set(t);for(const e of n)for(const n of e)t.delete(n);return t},t.disjoint=function(t,n){const e=n[Symbol.iterator](),r=new Set;for(const n of t){if(r.has(n))return!1;let t,i;for(;({value:t,done:i}=e.next())&&!i;){if(Object.is(n,t))return!1;r.add(t)}}return!0},t.dispatch=ot,t.drag=function(){var t,n,e,r,i=Fn,o=On,a=Un,u=In,c={},f=ot("start","drag","end"),s=0,l=0;function h(t){t.on("mousedown.drag",d).filter(u).on("touchstart.drag",y).on("touchmove.drag",v).on("touchend.drag touchcancel.drag",_).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function d(a,u){if(!r&&i.call(this,a,u)){var c=b(this,o.call(this,a,u),a,u,"mouse");c&&(An(a.view).on("mousemove.drag",p,!0).on("mouseup.drag",g,!0),zn(a.view),Cn(a),e=!1,t=a.clientX,n=a.clientY,c("start",a))}}function p(r){if(Pn(r),!e){var i=r.clientX-t,o=r.clientY-n;e=i*i+o*o>l}c.mouse("drag",r)}function g(t){An(t.view).on("mousemove.drag mouseup.drag",null),Dn(t.view,e),Pn(t),c.mouse("end",t)}function y(t,n){if(i.call(this,t,n)){var e,r,a=t.changedTouches,u=o.call(this,t,n),c=a.length;for(e=0;e<c;++e)(r=b(this,u,t,n,a[e].identifier,a[e]))&&(Cn(t),r("start",t,a[e]))}}function v(t){var n,e,r=t.changedTouches,i=r.length;for(n=0;n<i;++n)(e=c[r[n].identifier])&&(Pn(t),e("drag",t,r[n]))}function _(t){var n,e,i=t.changedTouches,o=i.length;for(r&&clearTimeout(r),r=setTimeout((function(){r=null}),500),n=0;n<o;++n)(e=c[i[n].identifier])&&(Cn(t),e("end",t,i[n]))}function b(t,n,e,r,i,o){var u,l,d,p=f.copy(),g=Nn(o||e,n);if(null!=(d=a.call(t,new Rn("beforestart",{sourceEvent:e,target:h,identifier:i,active:s,x:g[0],y:g[1],dx:0,dy:0,dispatch:p}),r)))return u=d.x-g[0]||0,l=d.y-g[1]||0,function e(o,a,f){var y,v=g;switch(o){case"start":c[i]=e,y=s++;break;case"end":delete c[i],--s;case"drag":g=Nn(f||a,n),y=s}p.call(o,t,new Rn(o,{sourceEvent:a,subject:d,target:h,identifier:i,active:y,x:g[0]+u,y:g[1]+l,dx:g[0]-v[0],dy:g[1]-v[1],dispatch:p}),r)}}return h.filter=function(t){return arguments.length?(i="function"==typeof t?t:qn(!!t),h):i},h.container=function(t){return arguments.length?(o="function"==typeof t?t:qn(t),h):o},h.subject=function(t){return arguments.length?(a="function"==typeof t?t:qn(t),h):a},h.touchable=function(t){return arguments.length?(u="function"==typeof t?t:qn(!!t),h):u},h.on=function(){var t=f.on.apply(f,arguments);return t===f?h:t},h.clickDistance=function(t){return arguments.length?(l=(t=+t)*t,h):Math.sqrt(l)},h},t.dragDisable=zn,t.dragEnable=Dn,t.dsv=function(t,n,e,r){3===arguments.length&&"function"==typeof e&&(r=e,e=void 0);var i=Ja(t);return mu(n,e).then((function(t){return i.parse(t,r)}))},t.dsvFormat=Ja,t.easeBack=no,t.easeBackIn=Ji,t.easeBackInOut=no,t.easeBackOut=to,t.easeBounce=Ki,t.easeBounceIn=function(t){return 1-Ki(1-t)},t.easeBounceInOut=function(t){return((t*=2)<=1?1-Ki(1-t):Ki(t-1)+1)/2},t.easeBounceOut=Ki,t.easeCircle=$i,t.easeCircleIn=function(t){return 1-Math.sqrt(1-t*t)},t.easeCircleInOut=$i,t.easeCircleOut=function(t){return Math.sqrt(1- --t*t)},t.easeCubic=Ii,t.easeCubicIn=function(t){return t*t*t},t.easeCubicInOut=Ii,t.easeCubicOut=function(t){return--t*t*t+1},t.easeElastic=io,t.easeElasticIn=ro,t.easeElasticInOut=oo,t.easeElasticOut=io,t.easeExp=Vi,t.easeExpIn=function(t){return Gi(1-+t)},t.easeExpInOut=Vi,t.easeExpOut=function(t){return 1-Gi(t)},t.easeLinear=t=>+t,t.easePoly=Li,t.easePolyIn=Bi,t.easePolyInOut=Li,t.easePolyOut=Yi,t.easeQuad=Ui,t.easeQuadIn=function(t){return t*t},t.easeQuadInOut=Ui,t.easeQuadOut=function(t){return t*(2-t)},t.easeSin=Xi,t.easeSinIn=function(t){return 1==+t?1:1-Math.cos(t*Hi)},t.easeSinInOut=Xi,t.easeSinOut=function(t){return Math.sin(t*Hi)},t.every=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(!n(r,++e,t))return!1;return!0},t.extent=p,t.filter=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");const e=[];let r=-1;for(const i of t)n(i,++r,t)&&e.push(i);return e},t.forceCenter=function(t,n){var e,r=1;function i(){var i,o,a=e.length,u=0,c=0;for(i=0;i<a;++i)u+=(o=e[i]).x,c+=o.y;for(u=(u/a-t)*r,c=(c/a-n)*r,i=0;i<a;++i)(o=e[i]).x-=u,o.y-=c}return null==t&&(t=0),null==n&&(n=0),i.initialize=function(t){e=t},i.x=function(n){return arguments.length?(t=+n,i):t},i.y=function(t){return arguments.length?(n=+t,i):n},i.strength=function(t){return arguments.length?(r=+t,i):r},i},t.forceCollide=function(t){var n,e,r,i=1,o=1;function a(){for(var t,a,c,f,s,l,h,d=n.length,p=0;p<o;++p)for(a=Du(n,Iu,Bu).visitAfter(u),t=0;t<d;++t)c=n[t],l=e[c.index],h=l*l,f=c.x+c.vx,s=c.y+c.vy,a.visit(g);function g(t,n,e,o,a){var u=t.data,d=t.r,p=l+d;if(!u)return n>f+p||o<f-p||e>s+p||a<s-p;if(u.index>c.index){var g=f-u.x-u.vx,y=s-u.y-u.vy,v=g*g+y*y;v<p*p&&(0===g&&(v+=(g=Uu(r))*g),0===y&&(v+=(y=Uu(r))*y),v=(p-(v=Math.sqrt(v)))/v*i,c.vx+=(g*=v)*(p=(d*=d)/(h+d)),c.vy+=(y*=v)*p,u.vx-=g*(p=1-p),u.vy-=y*p)}}}function u(t){if(t.data)return t.r=e[t.data.index];for(var n=t.r=0;n<4;++n)t[n]&&t[n].r>t.r&&(t.r=t[n].r)}function c(){if(n){var r,i,o=n.length;for(e=new Array(o),r=0;r<o;++r)i=n[r],e[i.index]=+t(i,r,n)}}return"function"!=typeof t&&(t=Ou(null==t?1:+t)),a.initialize=function(t,e){n=t,r=e,c()},a.iterations=function(t){return arguments.length?(o=+t,a):o},a.strength=function(t){return arguments.length?(i=+t,a):i},a.radius=function(n){return arguments.length?(t="function"==typeof n?n:Ou(+n),c(),a):t},a},t.forceLink=function(t){var n,e,r,i,o,a,u=Yu,c=function(t){return 1/Math.min(i[t.source.index],i[t.target.index])},f=Ou(30),s=1;function l(r){for(var i=0,u=t.length;i<s;++i)for(var c,f,l,h,d,p,g,y=0;y<u;++y)f=(c=t[y]).source,h=(l=c.target).x+l.vx-f.x-f.vx||Uu(a),d=l.y+l.vy-f.y-f.vy||Uu(a),h*=p=((p=Math.sqrt(h*h+d*d))-e[y])/p*r*n[y],d*=p,l.vx-=h*(g=o[y]),l.vy-=d*g,f.vx+=h*(g=1-g),f.vy+=d*g}function h(){if(r){var a,c,f=r.length,s=t.length,l=new Map(r.map((t,n)=>[u(t,n,r),t]));for(a=0,i=new Array(f);a<s;++a)(c=t[a]).index=a,"object"!=typeof c.source&&(c.source=Lu(l,c.source)),"object"!=typeof c.target&&(c.target=Lu(l,c.target)),i[c.source.index]=(i[c.source.index]||0)+1,i[c.target.index]=(i[c.target.index]||0)+1;for(a=0,o=new Array(s);a<s;++a)c=t[a],o[a]=i[c.source.index]/(i[c.source.index]+i[c.target.index]);n=new Array(s),d(),e=new Array(s),p()}}function d(){if(r)for(var e=0,i=t.length;e<i;++e)n[e]=+c(t[e],e,t)}function p(){if(r)for(var n=0,i=t.length;n<i;++n)e[n]=+f(t[n],n,t)}return null==t&&(t=[]),l.initialize=function(t,n){r=t,a=n,h()},l.links=function(n){return arguments.length?(t=n,h(),l):t},l.id=function(t){return arguments.length?(u=t,l):u},l.iterations=function(t){return arguments.length?(s=+t,l):s},l.strength=function(t){return arguments.length?(c="function"==typeof t?t:Ou(+t),d(),l):c},l.distance=function(t){return arguments.length?(f="function"==typeof t?t:Ou(+t),p(),l):f},l},t.forceManyBody=function(){var t,n,e,r,i,o=Ou(-30),a=1,u=1/0,c=.81;function f(e){var i,o=t.length,a=Du(t,Hu,Xu).visitAfter(l);for(r=e,i=0;i<o;++i)n=t[i],a.visit(h)}function s(){if(t){var n,e,r=t.length;for(i=new Array(r),n=0;n<r;++n)e=t[n],i[e.index]=+o(e,n,t)}}function l(t){var n,e,r,o,a,u=0,c=0;if(t.length){for(r=o=a=0;a<4;++a)(n=t[a])&&(e=Math.abs(n.value))&&(u+=n.value,c+=e,r+=e*n.x,o+=e*n.y);t.x=r/c,t.y=o/c}else{(n=t).x=n.data.x,n.y=n.data.y;do{u+=i[n.data.index]}while(n=n.next)}t.value=u}function h(t,o,f,s){if(!t.value)return!0;var l=t.x-n.x,h=t.y-n.y,d=s-o,p=l*l+h*h;if(d*d/c<p)return p<u&&(0===l&&(p+=(l=Uu(e))*l),0===h&&(p+=(h=Uu(e))*h),p<a&&(p=Math.sqrt(a*p)),n.vx+=l*t.value*r/p,n.vy+=h*t.value*r/p),!0;if(!(t.length||p>=u)){(t.data!==n||t.next)&&(0===l&&(p+=(l=Uu(e))*l),0===h&&(p+=(h=Uu(e))*h),p<a&&(p=Math.sqrt(a*p)));do{t.data!==n&&(d=i[t.data.index]*r/p,n.vx+=l*d,n.vy+=h*d)}while(t=t.next)}}return f.initialize=function(n,r){t=n,e=r,s()},f.strength=function(t){return arguments.length?(o="function"==typeof t?t:Ou(+t),s(),f):o},f.distanceMin=function(t){return arguments.length?(a=t*t,f):Math.sqrt(a)},f.distanceMax=function(t){return arguments.length?(u=t*t,f):Math.sqrt(u)},f.theta=function(t){return arguments.length?(c=t*t,f):Math.sqrt(c)},f},t.forceRadial=function(t,n,e){var r,i,o,a=Ou(.1);function u(t){for(var a=0,u=r.length;a<u;++a){var c=r[a],f=c.x-n||1e-6,s=c.y-e||1e-6,l=Math.sqrt(f*f+s*s),h=(o[a]-l)*i[a]*t/l;c.vx+=f*h,c.vy+=s*h}}function c(){if(r){var n,e=r.length;for(i=new Array(e),o=new Array(e),n=0;n<e;++n)o[n]=+t(r[n],n,r),i[n]=isNaN(o[n])?0:+a(r[n],n,r)}}return"function"!=typeof t&&(t=Ou(+t)),null==n&&(n=0),null==e&&(e=0),u.initialize=function(t){r=t,c()},u.strength=function(t){return arguments.length?(a="function"==typeof t?t:Ou(+t),c(),u):a},u.radius=function(n){return arguments.length?(t="function"==typeof n?n:Ou(+n),c(),u):t},u.x=function(t){return arguments.length?(n=+t,u):n},u.y=function(t){return arguments.length?(e=+t,u):e},u},t.forceSimulation=function(t){var n,e=1,r=.001,i=1-Math.pow(r,1/300),o=0,a=.6,u=new Map,c=$r(l),f=ot("tick","end"),s=function(){let t=1;return()=>(t=(1664525*t+1013904223)%ju)/ju}();function l(){h(),f.call("tick",n),e<r&&(c.stop(),f.call("end",n))}function h(r){var c,f,s=t.length;void 0===r&&(r=1);for(var l=0;l<r;++l)for(e+=(o-e)*i,u.forEach((function(t){t(e)})),c=0;c<s;++c)null==(f=t[c]).fx?f.x+=f.vx*=a:(f.x=f.fx,f.vx=0),null==f.fy?f.y+=f.vy*=a:(f.y=f.fy,f.vy=0);return n}function d(){for(var n,e=0,r=t.length;e<r;++e){if((n=t[e]).index=e,null!=n.fx&&(n.x=n.fx),null!=n.fy&&(n.y=n.fy),isNaN(n.x)||isNaN(n.y)){var i=10*Math.sqrt(.5+e),o=e*Gu;n.x=i*Math.cos(o),n.y=i*Math.sin(o)}(isNaN(n.vx)||isNaN(n.vy))&&(n.vx=n.vy=0)}}function p(n){return n.initialize&&n.initialize(t,s),n}return null==t&&(t=[]),d(),n={tick:h,restart:function(){return c.restart(l),n},stop:function(){return c.stop(),n},nodes:function(e){return arguments.length?(t=e,d(),u.forEach(p),n):t},alpha:function(t){return arguments.length?(e=+t,n):e},alphaMin:function(t){return arguments.length?(r=+t,n):r},alphaDecay:function(t){return arguments.length?(i=+t,n):+i},alphaTarget:function(t){return arguments.length?(o=+t,n):o},velocityDecay:function(t){return arguments.length?(a=1-t,n):1-a},randomSource:function(t){return arguments.length?(s=t,u.forEach(p),n):s},force:function(t,e){return arguments.length>1?(null==e?u.delete(t):u.set(t,p(e)),n):u.get(t)},find:function(n,e,r){var i,o,a,u,c,f=0,s=t.length;for(null==r?r=1/0:r*=r,f=0;f<s;++f)(a=(i=n-(u=t[f]).x)*i+(o=e-u.y)*o)<r&&(c=u,r=a);return c},on:function(t,e){return arguments.length>1?(f.on(t,e),n):f.on(t)}}},t.forceX=function(t){var n,e,r,i=Ou(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vx+=(r[o]-i.x)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Ou(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Ou(+t),a(),o):i},o.x=function(n){return arguments.length?(t="function"==typeof n?n:Ou(+n),a(),o):t},o},t.forceY=function(t){var n,e,r,i=Ou(.1);function o(t){for(var i,o=0,a=n.length;o<a;++o)(i=n[o]).vy+=(r[o]-i.y)*e[o]*t}function a(){if(n){var o,a=n.length;for(e=new Array(a),r=new Array(a),o=0;o<a;++o)e[o]=isNaN(r[o]=+t(n[o],o,n))?0:+i(n[o],o,n)}}return"function"!=typeof t&&(t=Ou(null==t?0:+t)),o.initialize=function(t){n=t,a()},o.strength=function(t){return arguments.length?(i="function"==typeof t?t:Ou(+t),a(),o):i},o.y=function(n){return arguments.length?(t="function"==typeof n?n:Ou(+n),a(),o):t},o},t.formatDefaultLocale=ac,t.formatLocale=oc,t.formatSpecifier=Ku,t.fsum=function(t,n){const e=new g;if(void 0===n)for(let n of t)(n=+n)&&e.add(n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&e.add(i)}return+e},t.geoAlbers=sh,t.geoAlbersUsa=function(){var t,n,e,r,i,o,a=sh(),u=fh().rotate([154,0]).center([-2,58.5]).parallels([55,65]),c=fh().rotate([157,0]).center([-3,19.9]).parallels([8,18]),f={point:function(t,n){o=[t,n]}};function s(t){var n=t[0],a=t[1];return o=null,e.point(n,a),o||(r.point(n,a),o)||(i.point(n,a),o)}function l(){return t=n=null,s}return s.invert=function(t){var n=a.scale(),e=a.translate(),r=(t[0]-e[0])/n,i=(t[1]-e[1])/n;return(i>=.12&&i<.234&&r>=-.425&&r<-.214?u:i>=.166&&i<.234&&r>=-.214&&r<-.115?c:a).invert(t)},s.stream=function(e){return t&&n===e?t:(r=[a.stream(n=e),u.stream(e),c.stream(e)],i=r.length,t={point:function(t,n){for(var e=-1;++e<i;)r[e].point(t,n)},sphere:function(){for(var t=-1;++t<i;)r[t].sphere()},lineStart:function(){for(var t=-1;++t<i;)r[t].lineStart()},lineEnd:function(){for(var t=-1;++t<i;)r[t].lineEnd()},polygonStart:function(){for(var t=-1;++t<i;)r[t].polygonStart()},polygonEnd:function(){for(var t=-1;++t<i;)r[t].polygonEnd()}});var r,i},s.precision=function(t){return arguments.length?(a.precision(t),u.precision(t),c.precision(t),l()):a.precision()},s.scale=function(t){return arguments.length?(a.scale(t),u.scale(.35*t),c.scale(t),s.translate(a.translate())):a.scale()},s.translate=function(t){if(!arguments.length)return a.translate();var n=a.scale(),o=+t[0],s=+t[1];return e=a.translate(t).clipExtent([[o-.455*n,s-.238*n],[o+.455*n,s+.238*n]]).stream(f),r=u.translate([o-.307*n,s+.201*n]).clipExtent([[o-.425*n+sc,s+.12*n+sc],[o-.214*n-sc,s+.234*n-sc]]).stream(f),i=c.translate([o-.205*n,s+.212*n]).clipExtent([[o-.214*n+sc,s+.166*n+sc],[o-.115*n-sc,s+.234*n-sc]]).stream(f),l()},s.fitExtent=function(t,n){return Kl(s,t,n)},s.fitSize=function(t,n){return Ql(s,t,n)},s.fitWidth=function(t,n){return Jl(s,t,n)},s.fitHeight=function(t,n){return th(s,t,n)},s.scale(1070)},t.geoArea=function(t){return of=new g,Bc(t,af),2*of},t.geoAzimuthalEqualArea=function(){return oh(dh).scale(124.75).clipAngle(179.999)},t.geoAzimuthalEqualAreaRaw=dh,t.geoAzimuthalEquidistant=function(){return oh(ph).scale(79.4188).clipAngle(179.999)},t.geoAzimuthalEquidistantRaw=ph,t.geoBounds=function(t){var n,e,r,i,o,a,u;if(Wc=$c=-(Gc=Vc=1/0),nf=[],Bc(t,qf),e=nf.length){for(nf.sort(jf),n=1,o=[r=nf[0]];n<e;++n)Hf(r,(i=nf[n])[0])||Hf(r,i[1])?(Lf(r[0],i[1])>Lf(r[0],r[1])&&(r[1]=i[1]),Lf(i[0],r[1])>Lf(r[0],r[1])&&(r[0]=i[0])):o.push(r=i);for(a=-1/0,n=0,r=o[e=o.length-1];n<=e;r=i,++n)i=o[n],(u=Lf(r[1],i[0]))>a&&(a=u,Gc=i[0],$c=r[1])}return nf=ef=null,Gc===1/0||Vc===1/0?[[NaN,NaN],[NaN,NaN]]:[[Gc,Vc],[$c,Wc]]},t.geoCentroid=function(t){_f=bf=mf=xf=wf=Mf=Af=Tf=0,Sf=new g,Ef=new g,kf=new g,Bc(t,Xf);var n=+Sf,e=+Ef,r=+kf,i=Ac(n,e,r);return i<lc&&(n=Mf,e=Af,r=Tf,bf<sc&&(n=mf,e=xf,r=wf),(i=Ac(n,e,r))<lc)?[NaN,NaN]:[mc(e,n)*yc,zc(r/i)*yc]},t.geoCircle=function(){var t,n,e=es([0,0]),r=es(90),i=es(6),o={point:function(e,r){t.push(e=n(e,r)),e[0]*=yc,e[1]*=yc}};function a(){var a=e.apply(this,arguments),u=r.apply(this,arguments)*vc,c=i.apply(this,arguments)*vc;return t=[],n=os(-a[0]*vc,-a[1]*vc,0).invert,ss(o,u,c,1),a={type:"Polygon",coordinates:[t]},t=n=null,a}return a.center=function(t){return arguments.length?(e="function"==typeof t?t:es([+t[0],+t[1]]),a):e},a.radius=function(t){return arguments.length?(r="function"==typeof t?t:es(+t),a):r},a.precision=function(t){return arguments.length?(i="function"==typeof t?t:es(+t),a):i},a},t.geoClipAntimeridian=ws,t.geoClipCircle=Ms,t.geoClipExtent=function(){var t,n,e,r=0,i=0,o=960,a=500;return e={stream:function(e){return t&&n===e?t:t=Cs(r,i,o,a)(n=e)},extent:function(u){return arguments.length?(r=+u[0][0],i=+u[0][1],o=+u[1][0],a=+u[1][1],t=n=null,e):[[r,i],[o,a]]}}},t.geoClipRectangle=Cs,t.geoConicConformal=function(){return uh(_h).scale(109.5).parallels([30,30])},t.geoConicConformalRaw=_h,t.geoConicEqualArea=fh,t.geoConicEqualAreaRaw=ch,t.geoConicEquidistant=function(){return uh(mh).scale(131.154).center([0,13.9389])},t.geoConicEquidistantRaw=mh,t.geoContains=function(t,n){return(t&&Is.hasOwnProperty(t.type)?Is[t.type]:Ys)(t,n)},t.geoDistance=Us,t.geoEqualEarth=function(){return oh(Sh).scale(177.158)},t.geoEqualEarthRaw=Sh,t.geoEquirectangular=function(){return oh(bh).scale(152.63)},t.geoEquirectangularRaw=bh,t.geoGnomonic=function(){return oh(Eh).scale(144.049).clipAngle(60)},t.geoGnomonicRaw=Eh,t.geoGraticule=Ws,t.geoGraticule10=function(){return Ws()()},t.geoIdentity=function(){var t,n,e,r,i,o,a,u=1,c=0,f=0,s=1,l=1,h=0,d=null,p=1,g=1,y=$l({point:function(t,n){var e=b([t,n]);this.stream.point(e[0],e[1])}}),v=tl;function _(){return p=u*s,g=u*l,o=a=null,b}function b(e){var r=e[0]*p,i=e[1]*g;if(h){var o=i*t-r*n;r=r*t+i*n,i=o}return[r+c,i+f]}return b.invert=function(e){var r=e[0]-c,i=e[1]-f;if(h){var o=i*t+r*n;r=r*t-i*n,i=o}return[r/p,i/g]},b.stream=function(t){return o&&a===t?o:o=y(v(a=t))},b.postclip=function(t){return arguments.length?(v=t,d=e=r=i=null,_()):v},b.clipExtent=function(t){return arguments.length?(v=null==t?(d=e=r=i=null,tl):Cs(d=+t[0][0],e=+t[0][1],r=+t[1][0],i=+t[1][1]),_()):null==d?null:[[d,e],[r,i]]},b.scale=function(t){return arguments.length?(u=+t,_()):u},b.translate=function(t){return arguments.length?(c=+t[0],f=+t[1],_()):[c,f]},b.angle=function(e){return arguments.length?(n=Ec(h=e%360*vc),t=xc(h),_()):h*yc},b.reflectX=function(t){return arguments.length?(s=t?-1:1,_()):s<0},b.reflectY=function(t){return arguments.length?(l=t?-1:1,_()):l<0},b.fitExtent=function(t,n){return Kl(b,t,n)},b.fitSize=function(t,n){return Ql(b,t,n)},b.fitWidth=function(t,n){return Jl(b,t,n)},b.fitHeight=function(t,n){return th(b,t,n)},b},t.geoInterpolate=function(t,n){var e=t[0]*vc,r=t[1]*vc,i=n[0]*vc,o=n[1]*vc,a=xc(r),u=Ec(r),c=xc(o),f=Ec(o),s=a*xc(e),l=a*Ec(e),h=c*xc(i),d=c*Ec(i),p=2*zc(Nc(Dc(o-r)+a*c*Dc(i-e))),g=Ec(p),y=p?function(t){var n=Ec(t*=p)/g,e=Ec(p-t)/g,r=e*s+n*h,i=e*l+n*d,o=e*u+n*f;return[mc(i,r)*yc,mc(o,Nc(r*r+i*i))*yc]}:function(){return[e*yc,r*yc]};return y.distance=p,y},t.geoLength=Rs,t.geoMercator=function(){return yh(gh).scale(961/gc)},t.geoMercatorRaw=gh,t.geoNaturalEarth1=function(){return oh(kh).scale(175.295)},t.geoNaturalEarth1Raw=kh,t.geoOrthographic=function(){return oh(Nh).scale(249.5).clipAngle(90.000001)},t.geoOrthographicRaw=Nh,t.geoPath=function(t,n){var e,r,i=4.5;function o(t){return t&&("function"==typeof i&&r.pointRadius(+i.apply(this,arguments)),Bc(t,e(r))),r.result()}return o.area=function(t){return Bc(t,e(rl)),rl.result()},o.measure=function(t){return Bc(t,e(jl)),jl.result()},o.bounds=function(t){return Bc(t,e(hl)),hl.result()},o.centroid=function(t){return Bc(t,e(Sl)),Sl.result()},o.projection=function(n){return arguments.length?(e=null==n?(t=null,tl):(t=n).stream,o):t},o.context=function(t){return arguments.length?(r=null==t?(n=null,new Gl):new Fl(n=t),"function"!=typeof i&&r.pointRadius(i),o):n},o.pointRadius=function(t){return arguments.length?(i="function"==typeof t?t:(r.pointRadius(+t),+t),o):i},o.projection(t).context(n)},t.geoProjection=oh,t.geoProjectionMutator=ah,t.geoRotation=fs,t.geoStereographic=function(){return oh(Ch).scale(250).clipAngle(142)},t.geoStereographicRaw=Ch,t.geoStream=Bc,t.geoTransform=function(t){return{stream:$l(t)}},t.geoTransverseMercator=function(){var t=yh(Ph),n=t.center,e=t.rotate;return t.center=function(t){return arguments.length?n([-t[1],t[0]]):[(t=n())[1],-t[0]]},t.rotate=function(t){return arguments.length?e([t[0],t[1],t.length>2?t[2]+90:90]):[(t=e())[0],t[1],t[2]-90]},e([0,0,90]).scale(159.155)},t.geoTransverseMercatorRaw=Ph,t.gray=function(t,n){return new Ee(t,0,0,null==n?1:n)},t.greatest=function(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)>0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)>0:0===e(n,n))&&(r=n,i=!0);return r},t.greatestIndex=function(t,e=n){if(1===e.length)return F(t,e);let r,i=-1,o=-1;for(const n of t)++o,(i<0?0===e(n,n):e(n,r)>0)&&(r=n,i=o);return i},t.group=function(t,...n){return _(t,y,y,n)},t.groups=function(t,...n){return _(t,Array.from,y,n)},t.hcl=De,t.hierarchy=Fh,t.histogram=N,t.hsl=ge,t.html=Eu,t.image=function(t,n){return new Promise((function(e,r){var i=new Image;for(var o in n)i[o]=n[o];i.onerror=r,i.onload=function(){e(i)},i.src=t}))},t.index=function(t,...n){return _(t,y,v,n)},t.indexes=function(t,...n){return _(t,Array.from,v,n)},t.interpolate=pr,t.interpolateArray=function(t,n){return(ar(n)?or:ur)(t,n)},t.interpolateBasis=$e,t.interpolateBasisClosed=We,t.interpolateBlues=A_,t.interpolateBrBG=Fv,t.interpolateBuGn=t_,t.interpolateBuPu=e_,t.interpolateCividis=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(-4.54-t*(35.34-t*(2381.73-t*(6402.7-t*(7024.72-2710.57*t)))))))+", "+Math.max(0,Math.min(255,Math.round(32.49+t*(170.73+t*(52.82-t*(131.46-t*(176.58-67.37*t)))))))+", "+Math.max(0,Math.min(255,Math.round(81.24+t*(442.36-t*(2482.43-t*(6167.24-t*(6614.94-2475.67*t)))))))+")"},t.interpolateCool=O_,t.interpolateCubehelix=zr,t.interpolateCubehelixDefault=R_,t.interpolateCubehelixLong=Dr,t.interpolateDate=cr,t.interpolateDiscrete=function(t){var n=t.length;return function(e){return t[Math.max(0,Math.min(n-1,Math.floor(e*n)))]}},t.interpolateGnBu=i_,t.interpolateGreens=S_,t.interpolateGreys=k_,t.interpolateHcl=Nr,t.interpolateHclLong=Cr,t.interpolateHsl=Sr,t.interpolateHslLong=Er,t.interpolateHue=function(t,n){var e=Qe(+t,+n);return function(t){var n=e(t);return n-360*Math.floor(n/360)}},t.interpolateInferno=X_,t.interpolateLab=function(t,n){var e=tr((t=Se(t)).l,(n=Se(n)).l),r=tr(t.a,n.a),i=tr(t.b,n.b),o=tr(t.opacity,n.opacity);return function(n){return t.l=e(n),t.a=r(n),t.b=i(n),t.opacity=o(n),t+""}},t.interpolateMagma=H_,t.interpolateNumber=fr,t.interpolateNumberArray=or,t.interpolateObject=sr,t.interpolateOrRd=a_,t.interpolateOranges=q_,t.interpolatePRGn=Uv,t.interpolatePiYG=Bv,t.interpolatePlasma=G_,t.interpolatePuBu=s_,t.interpolatePuBuGn=c_,t.interpolatePuOr=Lv,t.interpolatePuRd=h_,t.interpolatePurples=C_,t.interpolateRainbow=function(t){(t<0||t>1)&&(t-=Math.floor(t));var n=Math.abs(t-.5);return U_.h=360*t-100,U_.s=1.5-1.5*n,U_.l=.8-.9*n,U_+""},t.interpolateRdBu=Hv,t.interpolateRdGy=Gv,t.interpolateRdPu=p_,t.interpolateRdYlBu=$v,t.interpolateRdYlGn=Zv,t.interpolateReds=z_,t.interpolateRgb=nr,t.interpolateRgbBasis=rr,t.interpolateRgbBasisClosed=ir,t.interpolateRound=gr,t.interpolateSinebow=function(t){var n;return t=(.5-t)*Math.PI,I_.r=255*(n=Math.sin(t))*n,I_.g=255*(n=Math.sin(t+B_))*n,I_.b=255*(n=Math.sin(t+Y_))*n,I_+""},t.interpolateSpectral=Qv,t.interpolateString=dr,t.interpolateTransformCss=xr,t.interpolateTransformSvg=wr,t.interpolateTurbo=function(t){return t=Math.max(0,Math.min(1,t)),"rgb("+Math.max(0,Math.min(255,Math.round(34.61+t*(1172.33-t*(10793.56-t*(33300.12-t*(38394.49-14825.05*t)))))))+", "+Math.max(0,Math.min(255,Math.round(23.31+t*(557.33+t*(1225.33-t*(3574.96-t*(1073.77+707.56*t)))))))+", "+Math.max(0,Math.min(255,Math.round(27.2+t*(3211.1-t*(15327.97-t*(27814-t*(22569.18-6838.66*t)))))))+")"},t.interpolateViridis=j_,t.interpolateWarm=F_,t.interpolateYlGn=__,t.interpolateYlGnBu=y_,t.interpolateYlOrBr=m_,t.interpolateYlOrRd=w_,t.interpolateZoom=Ar,t.interrupt=ai,t.intersection=function(t,...n){t=new Set(t),n=n.map(V);t:for(const e of t)for(const r of n)if(!r.has(e)){t.delete(e);continue t}return t},t.interval=function(t,n,e){var r=new Vr,i=n;return null==n?(r.restart(t,n,e),r):(r._restart=r.restart,r.restart=function(t,n,e){n=+n,e=null==e?Xr():+e,r._restart((function o(a){a+=i,r._restart(o,i+=n,e),t(a)}),n,e)},r.restart(t,n,e),r)},t.isoFormat=uv,t.isoParse=cv,t.json=function(t,n){return fetch(t,n).then(Au)},t.lab=Se,t.lch=function(t,n,e,r){return 1===arguments.length?ze(t):new qe(e,n,t,null==r?1:r)},t.least=function(t,e=n){let r,i=!1;if(1===e.length){let o;for(const a of t){const t=e(a);(i?n(t,o)<0:0===n(t,t))&&(r=a,o=t,i=!0)}}else for(const n of t)(i?e(n,r)<0:0===e(n,n))&&(r=n,i=!0);return r},t.leastIndex=L,t.line=mb,t.lineRadial=kb,t.linkHorizontal=function(){return Db(qb)},t.linkRadial=function(){var t=Db(Fb);return t.angle=t.x,delete t.x,t.radius=t.y,delete t.y,t},t.linkVertical=function(){return Db(Rb)},t.local=Sn,t.map=function(t,n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");if("function"!=typeof n)throw new TypeError("mapper is not a function");return Array.from(t,(e,r)=>n(e,r,t))},t.matcher=xt,t.max=C,t.maxIndex=F,t.mean=function(t,n){let e=0,r=0;if(void 0===n)for(let n of t)null!=n&&(n=+n)>=n&&(++e,r+=n);else{let i=-1;for(let o of t)null!=(o=n(o,++i,t))&&(o=+o)>=o&&(++e,r+=o)}if(e)return r/e},t.median=function(t,n){return q(t,.5,n)},t.merge=O,t.min=P,t.minIndex=U,t.namespace=ht,t.namespaces=lt,t.nice=E,t.now=Xr,t.pack=function(){var t=null,n=1,e=1,r=rd;function i(i){return i.x=n/2,i.y=e/2,t?i.eachBefore(ad(t)).eachAfter(ud(r,.5)).eachBefore(cd(1)):i.eachBefore(ad(od)).eachAfter(ud(rd,1)).eachAfter(ud(r,i.r/Math.min(n,e))).eachBefore(cd(Math.min(n,e)/(2*i.r))),i}return i.radius=function(n){return arguments.length?(t=nd(n),i):t},i.size=function(t){return arguments.length?(n=+t[0],e=+t[1],i):[n,e]},i.padding=function(t){return arguments.length?(r="function"==typeof t?t:id(+t),i):r},i},t.packEnclose=Lh,t.packSiblings=function(t){return td(t),t},t.pairs=function(t,n=I){const e=[];let r,i=!1;for(const o of t)i&&e.push(n(r,o)),r=o,i=!0;return e},t.partition=function(){var t=1,n=1,e=0,r=!1;function i(i){var o=i.height+1;return i.x0=i.y0=e,i.x1=t,i.y1=n/o,i.eachBefore(function(t,n){return function(r){r.children&&sd(r,r.x0,t*(r.depth+1)/n,r.x1,t*(r.depth+2)/n);var i=r.x0,o=r.y0,a=r.x1-e,u=r.y1-e;a<i&&(i=a=(i+a)/2),u<o&&(o=u=(o+u)/2),r.x0=i,r.y0=o,r.x1=a,r.y1=u}}(n,o)),r&&i.eachBefore(fd),i}return i.round=function(t){return arguments.length?(r=!!t,i):r},i.size=function(e){return arguments.length?(t=+e[0],n=+e[1],i):[t,n]},i.padding=function(t){return arguments.length?(e=+t,i):e},i},t.path=ta,t.permute=B,t.pie=function(){var t=Mb,n=wb,e=null,r=V_(0),i=V_(ib),o=V_(0);function a(a){var u,c,f,s,l,h=(a=gb(a)).length,d=0,p=new Array(h),g=new Array(h),y=+r.apply(this,arguments),v=Math.min(ib,Math.max(-ib,i.apply(this,arguments)-y)),_=Math.min(Math.abs(v)/h,o.apply(this,arguments)),b=_*(v<0?-1:1);for(u=0;u<h;++u)(l=g[p[u]=u]=+t(a[u],u,a))>0&&(d+=l);for(null!=n?p.sort((function(t,e){return n(g[t],g[e])})):null!=e&&p.sort((function(t,n){return e(a[t],a[n])})),u=0,f=d?(v-h*b)/d:0;u<h;++u,y=s)c=p[u],s=y+((l=g[c])>0?l*f:0)+b,g[c]={data:a[c],index:u,value:l,startAngle:y,endAngle:s,padAngle:_};return g}return a.value=function(n){return arguments.length?(t="function"==typeof n?n:V_(+n),a):t},a.sortValues=function(t){return arguments.length?(n=t,e=null,a):n},a.sort=function(t){return arguments.length?(e=t,n=null,a):e},a.startAngle=function(t){return arguments.length?(r="function"==typeof t?t:V_(+t),a):r},a.endAngle=function(t){return arguments.length?(i="function"==typeof t?t:V_(+t),a):i},a.padAngle=function(t){return arguments.length?(o="function"==typeof t?t:V_(+t),a):o},a},t.piecewise=qr,t.pointRadial=Cb,t.pointer=Nn,t.pointers=function(t,n){return t.target&&(t=kn(t),void 0===n&&(n=t.currentTarget),t=t.touches||[t]),Array.from(t,t=>Nn(t,n))},t.polygonArea=function(t){for(var n,e=-1,r=t.length,i=t[r-1],o=0;++e<r;)n=i,i=t[e],o+=n[1]*i[0]-n[0]*i[1];return o/2},t.polygonCentroid=function(t){for(var n,e,r=-1,i=t.length,o=0,a=0,u=t[i-1],c=0;++r<i;)n=u,u=t[r],c+=e=n[0]*u[1]-u[0]*n[1],o+=(n[0]+u[0])*e,a+=(n[1]+u[1])*e;return[o/(c*=3),a/c]},t.polygonContains=function(t,n){for(var e,r,i=t.length,o=t[i-1],a=n[0],u=n[1],c=o[0],f=o[1],s=!1,l=0;l<i;++l)e=(o=t[l])[0],(r=o[1])>u!=f>u&&a<(c-e)*(u-r)/(f-r)+e&&(s=!s),c=e,f=r;return s},t.polygonHull=function(t){if((e=t.length)<3)return null;var n,e,r=new Array(e),i=new Array(e);for(n=0;n<e;++n)r[n]=[+t[n][0],+t[n][1],n];for(r.sort(Ed),n=0;n<e;++n)i[n]=[r[n][0],-r[n][1]];var o=kd(r),a=kd(i),u=a[0]===o[0],c=a[a.length-1]===o[o.length-1],f=[];for(n=o.length-1;n>=0;--n)f.push(t[r[o[n]][2]]);for(n=+u;n<a.length-c;++n)f.push(t[r[a[n]][2]]);return f},t.polygonLength=function(t){for(var n,e,r=-1,i=t.length,o=t[i-1],a=o[0],u=o[1],c=0;++r<i;)n=a,e=u,n-=a=(o=t[r])[0],e-=u=o[1],c+=Math.hypot(n,e);return c},t.precisionFixed=uc,t.precisionPrefix=cc,t.precisionRound=fc,t.quadtree=Du,t.quantile=q,t.quantileSorted=R,t.quantize=function(t,n){for(var e=new Array(n),r=0;r<n;++r)e[r]=t(r/(n-1));return e},t.quickselect=z,t.radialArea=Nb,t.radialLine=kb,t.randomBates=Rd,t.randomBernoulli=Ud,t.randomBeta=Yd,t.randomBinomial=Ld,t.randomCauchy=Hd,t.randomExponential=Fd,t.randomGamma=Bd,t.randomGeometric=Id,t.randomInt=Pd,t.randomIrwinHall=qd,t.randomLcg=function(t=Math.random()){let n=0|(0<=t&&t<1?t/Vd:Math.abs(t));return()=>(n=1664525*n+1013904223|0,Vd*(n>>>0))},t.randomLogNormal=Dd,t.randomLogistic=Xd,t.randomNormal=zd,t.randomPareto=Od,t.randomPoisson=Gd,t.randomUniform=Cd,t.randomWeibull=jd,t.range=Y,t.reduce=function(t,n,e){if("function"!=typeof n)throw new TypeError("reducer is not a function");const r=t[Symbol.iterator]();let i,o,a=-1;if(arguments.length<3){if(({done:i,value:e}=r.next()),i)return;++a}for(;({done:i,value:o}=r.next()),!i;)e=n(e,o,++a,t);return e},t.reverse=function(t){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return Array.from(t).reverse()},t.rgb=ce,t.ribbon=function(){return sa()},t.ribbonArrow=function(){return sa(fa)},t.rollup=function(t,n,...e){return _(t,y,n,e)},t.rollups=function(t,n,...e){return _(t,Array.from,n,e)},t.scaleBand=Qd,t.scaleDiverging=function t(){var n=sp(xv()(ep));return n.copy=function(){return bv(n,t())},Wd.apply(n,arguments)},t.scaleDivergingLog=function t(){var n=_p(xv()).domain([.1,1,10]);return n.copy=function(){return bv(n,t()).base(n.base())},Wd.apply(n,arguments)},t.scaleDivergingPow=wv,t.scaleDivergingSqrt=function(){return wv.apply(null,arguments).exponent(.5)},t.scaleDivergingSymlog=function t(){var n=xp(xv());return n.copy=function(){return bv(n,t()).constant(n.constant())},Wd.apply(n,arguments)},t.scaleIdentity=function t(n){var e;function r(t){return isNaN(t=+t)?e:t}return r.invert=r,r.domain=r.range=function(t){return arguments.length?(n=Array.from(t,tp),r):n.slice()},r.unknown=function(t){return arguments.length?(e=t,r):e},r.copy=function(){return t(n).unknown(e)},n=arguments.length?Array.from(n,tp):[0,1],sp(r)},t.scaleImplicit=Zd,t.scaleLinear=function t(){var n=cp();return n.copy=function(){return ap(n,t())},$d.apply(n,arguments),sp(n)},t.scaleLog=function t(){var n=_p(up()).domain([1,10]);return n.copy=function(){return ap(n,t()).base(n.base())},$d.apply(n,arguments),n},t.scaleOrdinal=Kd,t.scalePoint=function(){return Jd(Qd.apply(null,arguments).paddingInner(1))},t.scalePow=Sp,t.scaleQuantile=function t(){var e,r=[],i=[],a=[];function u(){var t=0,n=Math.max(1,i.length);for(a=new Array(n-1);++t<n;)a[t-1]=R(r,t/n);return c}function c(t){return isNaN(t=+t)?e:i[o(a,t)]}return c.invertExtent=function(t){var n=i.indexOf(t);return n<0?[NaN,NaN]:[n>0?a[n-1]:r[0],n<a.length?a[n]:r[r.length-1]]},c.domain=function(t){if(!arguments.length)return r.slice();r=[];for(let n of t)null==n||isNaN(n=+n)||r.push(n);return r.sort(n),u()},c.range=function(t){return arguments.length?(i=Array.from(t),u()):i.slice()},c.unknown=function(t){return arguments.length?(e=t,c):e},c.quantiles=function(){return a.slice()},c.copy=function(){return t().domain(r).range(i).unknown(e)},$d.apply(c,arguments)},t.scaleQuantize=function t(){var n,e=0,r=1,i=1,a=[.5],u=[0,1];function c(t){return t<=t?u[o(a,t,0,i)]:n}function f(){var t=-1;for(a=new Array(i);++t<i;)a[t]=((t+1)*r-(t-i)*e)/(i+1);return c}return c.domain=function(t){return arguments.length?([e,r]=t,e=+e,r=+r,f()):[e,r]},c.range=function(t){return arguments.length?(i=(u=Array.from(t)).length-1,f()):u.slice()},c.invertExtent=function(t){var n=u.indexOf(t);return n<0?[NaN,NaN]:n<1?[e,a[0]]:n>=i?[a[i-1],r]:[a[n-1],a[n]]},c.unknown=function(t){return arguments.length?(n=t,c):c},c.thresholds=function(){return a.slice()},c.copy=function(){return t().domain([e,r]).range(u).unknown(n)},$d.apply(sp(c),arguments)},t.scaleRadial=function t(){var n,e=cp(),r=[0,1],i=!1;function o(t){var r=kp(e(t));return isNaN(r)?n:i?Math.round(r):r}return o.invert=function(t){return e.invert(Ep(t))},o.domain=function(t){return arguments.length?(e.domain(t),o):e.domain()},o.range=function(t){return arguments.length?(e.range((r=Array.from(t,tp)).map(Ep)),o):r.slice()},o.rangeRound=function(t){return o.range(t).round(!0)},o.round=function(t){return arguments.length?(i=!!t,o):i},o.clamp=function(t){return arguments.length?(e.clamp(t),o):e.clamp()},o.unknown=function(t){return arguments.length?(n=t,o):n},o.copy=function(){return t(e.domain(),r).round(i).clamp(e.clamp()).unknown(n)},$d.apply(o,arguments),sp(o)},t.scaleSequential=function t(){var n=sp(_v()(ep));return n.copy=function(){return bv(n,t())},Wd.apply(n,arguments)},t.scaleSequentialLog=function t(){var n=_p(_v()).domain([1,10]);return n.copy=function(){return bv(n,t()).base(n.base())},Wd.apply(n,arguments)},t.scaleSequentialPow=mv,t.scaleSequentialQuantile=function t(){var e=[],r=ep;function i(t){if(!isNaN(t=+t))return r((o(e,t,1)-1)/(e.length-1))}return i.domain=function(t){if(!arguments.length)return e.slice();e=[];for(let n of t)null==n||isNaN(n=+n)||e.push(n);return e.sort(n),i},i.interpolator=function(t){return arguments.length?(r=t,i):r},i.range=function(){return e.map((t,n)=>r(n/(e.length-1)))},i.quantiles=function(t){return Array.from({length:t+1},(n,r)=>q(e,r/t))},i.copy=function(){return t(r).domain(e)},Wd.apply(i,arguments)},t.scaleSequentialSqrt=function(){return mv.apply(null,arguments).exponent(.5)},t.scaleSequentialSymlog=function t(){var n=xp(_v());return n.copy=function(){return bv(n,t()).constant(n.constant())},Wd.apply(n,arguments)},t.scaleSqrt=function(){return Sp.apply(null,arguments).exponent(.5)},t.scaleSymlog=function t(){var n=xp(up());return n.copy=function(){return ap(n,t()).constant(n.constant())},$d.apply(n,arguments)},t.scaleThreshold=function t(){var n,e=[.5],r=[0,1],i=1;function a(t){return t<=t?r[o(e,t,0,i)]:n}return a.domain=function(t){return arguments.length?(e=Array.from(t),i=Math.min(e.length,r.length-1),a):e.slice()},a.range=function(t){return arguments.length?(r=Array.from(t),i=Math.min(e.length,r.length-1),a):r.slice()},a.invertExtent=function(t){var n=r.indexOf(t);return[e[n-1],e[n]]},a.unknown=function(t){return arguments.length?(n=t,a):n},a.copy=function(){return t().domain(e).range(r).unknown(n)},$d.apply(a,arguments)},t.scaleTime=function(){return $d.apply(vv(sg,cg,$p,Xp,jp,Yp,Ip,zp,t.timeFormat).domain([new Date(2e3,0,1),new Date(2e3,0,2)]),arguments)},t.scaleUtc=function(){return $d.apply(vv(Rg,Dg,bg,yg,pg,hg,Ip,zp,t.utcFormat).domain([Date.UTC(2e3,0,1),Date.UTC(2e3,0,2)]),arguments)},t.scan=function(t,n){const e=L(t,n);return e<0?void 0:e},t.schemeAccent=Tv,t.schemeBlues=M_,t.schemeBrBG=Rv,t.schemeBuGn=Jv,t.schemeBuPu=n_,t.schemeCategory10=Av,t.schemeDark2=Sv,t.schemeGnBu=r_,t.schemeGreens=T_,t.schemeGreys=E_,t.schemeOrRd=o_,t.schemeOranges=D_,t.schemePRGn=Ov,t.schemePaired=Ev,t.schemePastel1=kv,t.schemePastel2=Nv,t.schemePiYG=Iv,t.schemePuBu=f_,t.schemePuBuGn=u_,t.schemePuOr=Yv,t.schemePuRd=l_,t.schemePurples=N_,t.schemeRdBu=jv,t.schemeRdGy=Xv,t.schemeRdPu=d_,t.schemeRdYlBu=Vv,t.schemeRdYlGn=Wv,t.schemeReds=P_,t.schemeSet1=Cv,t.schemeSet2=Pv,t.schemeSet3=zv,t.schemeSpectral=Kv,t.schemeTableau10=Dv,t.schemeYlGn=v_,t.schemeYlGnBu=g_,t.schemeYlOrBr=b_,t.schemeYlOrRd=x_,t.select=An,t.selectAll=function(t){return"string"==typeof t?new wn([document.querySelectorAll(t)],[document.documentElement]):new wn([null==t?[]:_t(t)],xn)},t.selection=Mn,t.selector=vt,t.selectorAll=mt,t.shuffle=j,t.shuffler=H,t.some=function(t,n){if("function"!=typeof n)throw new TypeError("test is not a function");let e=-1;for(const r of t)if(n(r,++e,t))return!0;return!1},t.sort=function(t,e=n){if("function"!=typeof t[Symbol.iterator])throw new TypeError("values is not iterable");return t=Array.from(t),1===e.length?(e=t.map(e),B(t,t.map((t,n)=>n).sort((t,r)=>n(e[t],e[r])))):t.sort(e)},t.stack=function(){var t=V_([]),n=qm,e=Dm,r=Rm;function i(i){var o,a,u=Array.from(t.apply(this,arguments),Fm),c=u.length,f=-1;for(const t of i)for(o=0,++f;o<c;++o)(u[o][f]=[0,+r(t,u[o].key,f,i)]).data=t;for(o=0,a=gb(n(u));o<c;++o)u[a[o]].index=o;return e(u,a),u}return i.keys=function(n){return arguments.length?(t="function"==typeof n?n:V_(Array.from(n)),i):t},i.value=function(t){return arguments.length?(r="function"==typeof t?t:V_(+t),i):r},i.order=function(t){return arguments.length?(n=null==t?qm:"function"==typeof t?t:V_(Array.from(t)),i):n},i.offset=function(t){return arguments.length?(e=null==t?Dm:t,i):e},i},t.stackOffsetDiverging=function(t,n){if((u=t.length)>0)for(var e,r,i,o,a,u,c=0,f=t[n[0]].length;c<f;++c)for(o=a=0,e=0;e<u;++e)(i=(r=t[n[e]][c])[1]-r[0])>0?(r[0]=o,r[1]=o+=i):i<0?(r[1]=a,r[0]=a+=i):(r[0]=0,r[1]=i)},t.stackOffsetExpand=function(t,n){if((r=t.length)>0){for(var e,r,i,o=0,a=t[0].length;o<a;++o){for(i=e=0;e<r;++e)i+=t[e][o][1]||0;if(i)for(e=0;e<r;++e)t[e][o][1]/=i}Dm(t,n)}},t.stackOffsetNone=Dm,t.stackOffsetSilhouette=function(t,n){if((e=t.length)>0){for(var e,r=0,i=t[n[0]],o=i.length;r<o;++r){for(var a=0,u=0;a<e;++a)u+=t[a][r][1]||0;i[r][1]+=i[r][0]=-u/2}Dm(t,n)}},t.stackOffsetWiggle=function(t,n){if((i=t.length)>0&&(r=(e=t[n[0]]).length)>0){for(var e,r,i,o=0,a=1;a<r;++a){for(var u=0,c=0,f=0;u<i;++u){for(var s=t[n[u]],l=s[a][1]||0,h=(l-(s[a-1][1]||0))/2,d=0;d<u;++d){var p=t[n[d]];h+=(p[a][1]||0)-(p[a-1][1]||0)}c+=l,f+=h*l}e[a-1][1]+=e[a-1][0]=o,c&&(o-=f/c)}e[a-1][1]+=e[a-1][0]=o,Dm(t,n)}},t.stackOrderAppearance=Om,t.stackOrderAscending=Im,t.stackOrderDescending=function(t){return Im(t).reverse()},t.stackOrderInsideOut=function(t){var n,e,r=t.length,i=t.map(Bm),o=Om(t),a=0,u=0,c=[],f=[];for(n=0;n<r;++n)e=o[n],a<u?(a+=i[e],c.push(e)):(u+=i[e],f.push(e));return f.reverse().concat(c)},t.stackOrderNone=qm,t.stackOrderReverse=function(t){return qm(t).reverse()},t.stratify=function(){var t=dd,n=pd;function e(e){var r,i,o,a,u,c,f,s=Array.from(e),l=s.length,h=new Map;for(i=0;i<l;++i)r=s[i],u=s[i]=new Yh(r),null!=(c=t(r,i,e))&&(c+="")&&(f=u.id=c,h.set(f,h.has(f)?hd:u)),null!=(c=n(r,i,e))&&(c+="")&&(u.parent=c);for(i=0;i<l;++i)if(c=(u=s[i]).parent){if(!(a=h.get(c)))throw new Error("missing: "+c);if(a===hd)throw new Error("ambiguous: "+c);a.children?a.children.push(u):a.children=[u],u.parent=a}else{if(o)throw new Error("multiple roots");o=u}if(!o)throw new Error("no root");if(o.parent=ld,o.eachBefore((function(t){t.depth=t.parent.depth+1,--l})).eachBefore(Bh),o.parent=null,l>0)throw new Error("cycle");return o}return e.id=function(n){return arguments.length?(t=ed(n),e):t},e.parentId=function(t){return arguments.length?(n=ed(t),e):n},e},t.style=Ht,t.subset=function(t,n){return $(n,t)},t.sum=function(t,n){let e=0;if(void 0===n)for(let n of t)(n=+n)&&(e+=n);else{let r=-1;for(let i of t)(i=+n(i,++r,t))&&(e+=i)}return e},t.superset=$,t.svg=ku,t.symbol=function(t,n){var e=null;function r(){var r;if(e||(e=r=ta()),t.apply(this,arguments).draw(e,+n.apply(this,arguments)),r)return e=null,r+""||null}return t="function"==typeof t?t:V_(t||Ob),n="function"==typeof n?n:V_(void 0===n?64:+n),r.type=function(n){return arguments.length?(t="function"==typeof n?n:V_(n),r):t},r.size=function(t){return arguments.length?(n="function"==typeof t?t:V_(+t),r):n},r.context=function(t){return arguments.length?(e=null==t?null:t,r):e},r},t.symbolCircle=Ob,t.symbolCross=Ub,t.symbolDiamond=Yb,t.symbolSquare=Gb,t.symbolStar=Xb,t.symbolTriangle=$b,t.symbolWye=Jb,t.symbols=tm,t.text=mu,t.thresholdFreedmanDiaconis=function(t,n,e){return Math.ceil((e-n)/(2*(q(t,.75)-q(t,.25))*Math.pow(c(t),-1/3)))},t.thresholdScott=function(t,n,e){return Math.ceil((e-n)/(3.5*d(t)*Math.pow(c(t),-1/3)))},t.thresholdSturges=k,t.tickFormat=fp,t.tickIncrement=T,t.tickStep=S,t.ticks=A,t.timeDay=Xp,t.timeDays=Gp,t.timeFormatDefaultLocale=ov,t.timeFormatLocale=Bg,t.timeFriday=Jp,t.timeFridays=ag,t.timeHour=jp,t.timeHours=Hp,t.timeInterval=Pp,t.timeMillisecond=zp,t.timeMilliseconds=Dp,t.timeMinute=Yp,t.timeMinutes=Lp,t.timeMonday=Wp,t.timeMondays=eg,t.timeMonth=cg,t.timeMonths=fg,t.timeSaturday=tg,t.timeSaturdays=ug,t.timeSecond=Ip,t.timeSeconds=Bp,t.timeSunday=$p,t.timeSundays=ng,t.timeThursday=Qp,t.timeThursdays=og,t.timeTuesday=Zp,t.timeTuesdays=rg,t.timeWednesday=Kp,t.timeWednesdays=ig,t.timeWeek=$p,t.timeWeeks=ng,t.timeYear=sg,t.timeYears=lg,t.timeout=Jr,t.timer=$r,t.timerFlush=Wr,t.transition=Ri,t.transpose=X,t.tree=function(){var t=gd,n=1,e=1,r=null;function i(i){var c=function(t){for(var n,e,r,i,o,a=new md(t,0),u=[a];n=u.pop();)if(r=n._.children)for(n.children=new Array(o=r.length),i=o-1;i>=0;--i)u.push(e=n.children[i]=new md(r[i],i)),e.parent=n;return(a.parent=new md(null,0)).children=[a],a}(i);if(c.eachAfter(o),c.parent.m=-c.z,c.eachBefore(a),r)i.eachBefore(u);else{var f=i,s=i,l=i;i.eachBefore((function(t){t.x<f.x&&(f=t),t.x>s.x&&(s=t),t.depth>l.depth&&(l=t)}));var h=f===s?1:t(f,s)/2,d=h-f.x,p=n/(s.x+h+d),g=e/(l.depth||1);i.eachBefore((function(t){t.x=(t.x+d)*p,t.y=t.depth*g}))}return i}function o(n){var e=n.children,r=n.parent.children,i=n.i?r[n.i-1]:null;if(e){!function(t){for(var n,e=0,r=0,i=t.children,o=i.length;--o>=0;)(n=i[o]).z+=e,n.m+=e,e+=n.s+(r+=n.c)}(n);var o=(e[0].z+e[e.length-1].z)/2;i?(n.z=i.z+t(n._,i._),n.m=n.z-o):n.z=o}else i&&(n.z=i.z+t(n._,i._));n.parent.A=function(n,e,r){if(e){for(var i,o=n,a=n,u=e,c=o.parent.children[0],f=o.m,s=a.m,l=u.m,h=c.m;u=vd(u),o=yd(o),u&&o;)c=yd(c),(a=vd(a)).a=n,(i=u.z+l-o.z-f+t(u._,o._))>0&&(_d(bd(u,n,r),n,i),f+=i,s+=i),l+=u.m,f+=o.m,h+=c.m,s+=a.m;u&&!vd(a)&&(a.t=u,a.m+=l-s),o&&!yd(c)&&(c.t=o,c.m+=f-h,r=n)}return r}(n,i,n.parent.A||r[0])}function a(t){t._.x=t.z+t.parent.m,t.m+=t.parent.m}function u(t){t.x*=n,t.y=t.depth*e}return i.separation=function(n){return arguments.length?(t=n,i):t},i.size=function(t){return arguments.length?(r=!1,n=+t[0],e=+t[1],i):r?null:[n,e]},i.nodeSize=function(t){return arguments.length?(r=!0,n=+t[0],e=+t[1],i):r?[n,e]:null},i},t.treemap=function(){var t=Ad,n=!1,e=1,r=1,i=[0],o=rd,a=rd,u=rd,c=rd,f=rd;function s(t){return t.x0=t.y0=0,t.x1=e,t.y1=r,t.eachBefore(l),i=[0],n&&t.eachBefore(fd),t}function l(n){var e=i[n.depth],r=n.x0+e,s=n.y0+e,l=n.x1-e,h=n.y1-e;l<r&&(r=l=(r+l)/2),h<s&&(s=h=(s+h)/2),n.x0=r,n.y0=s,n.x1=l,n.y1=h,n.children&&(e=i[n.depth+1]=o(n)/2,r+=f(n)-e,s+=a(n)-e,(l-=u(n)-e)<r&&(r=l=(r+l)/2),(h-=c(n)-e)<s&&(s=h=(s+h)/2),t(n,r,s,l,h))}return s.round=function(t){return arguments.length?(n=!!t,s):n},s.size=function(t){return arguments.length?(e=+t[0],r=+t[1],s):[e,r]},s.tile=function(n){return arguments.length?(t=ed(n),s):t},s.padding=function(t){return arguments.length?s.paddingInner(t).paddingOuter(t):s.paddingInner()},s.paddingInner=function(t){return arguments.length?(o="function"==typeof t?t:id(+t),s):o},s.paddingOuter=function(t){return arguments.length?s.paddingTop(t).paddingRight(t).paddingBottom(t).paddingLeft(t):s.paddingTop()},s.paddingTop=function(t){return arguments.length?(a="function"==typeof t?t:id(+t),s):a},s.paddingRight=function(t){return arguments.length?(u="function"==typeof t?t:id(+t),s):u},s.paddingBottom=function(t){return arguments.length?(c="function"==typeof t?t:id(+t),s):c},s.paddingLeft=function(t){return arguments.length?(f="function"==typeof t?t:id(+t),s):f},s},t.treemapBinary=function(t,n,e,r,i){var o,a,u=t.children,c=u.length,f=new Array(c+1);for(f[0]=a=o=0;o<c;++o)f[o+1]=a+=u[o].value;!function t(n,e,r,i,o,a,c){if(n>=e-1){var s=u[n];return s.x0=i,s.y0=o,s.x1=a,void(s.y1=c)}var l=f[n],h=r/2+l,d=n+1,p=e-1;for(;d<p;){var g=d+p>>>1;f[g]<h?d=g+1:p=g}h-f[d-1]<f[d]-h&&n+1<d&&--d;var y=f[d]-l,v=r-y;if(a-i>c-o){var _=r?(i*v+a*y)/r:a;t(n,d,y,i,o,_,c),t(d,e,v,_,o,a,c)}else{var b=r?(o*v+c*y)/r:c;t(n,d,y,i,o,a,b),t(d,e,v,i,b,a,c)}}(0,c,t.value,n,e,r,i)},t.treemapDice=sd,t.treemapResquarify=Td,t.treemapSlice=xd,t.treemapSliceDice=function(t,n,e,r,i){(1&t.depth?xd:sd)(t,n,e,r,i)},t.treemapSquarify=Ad,t.tsv=Mu,t.tsvFormat=lu,t.tsvFormatBody=hu,t.tsvFormatRow=pu,t.tsvFormatRows=du,t.tsvFormatValue=gu,t.tsvParse=fu,t.tsvParseRows=su,t.union=function(...t){const n=new Set;for(const e of t)for(const t of e)n.add(t);return n},t.utcDay=yg,t.utcDays=vg,t.utcFriday=Ag,t.utcFridays=Pg,t.utcHour=pg,t.utcHours=gg,t.utcMillisecond=zp,t.utcMilliseconds=Dp,t.utcMinute=hg,t.utcMinutes=dg,t.utcMonday=mg,t.utcMondays=Eg,t.utcMonth=Dg,t.utcMonths=qg,t.utcSaturday=Tg,t.utcSaturdays=zg,t.utcSecond=Ip,t.utcSeconds=Bp,t.utcSunday=bg,t.utcSundays=Sg,t.utcThursday=Mg,t.utcThursdays=Cg,t.utcTuesday=xg,t.utcTuesdays=kg,t.utcWednesday=wg,t.utcWednesdays=Ng,t.utcWeek=bg,t.utcWeeks=Sg,t.utcYear=Rg,t.utcYears=Fg,t.variance=h,t.version="6.3.1",t.window=Bt,t.xml=Su,t.zip=function(){return X(arguments)},t.zoom=function(){var t,n,e,r=$m,i=Wm,o=Jm,a=Km,u=Qm,c=[0,1/0],f=[[-1/0,-1/0],[1/0,1/0]],s=250,l=Ar,h=ot("start","zoom","end"),d=500,p=0,g=10;function y(t){t.property("__zoom",Zm).on("wheel.zoom",M).on("mousedown.zoom",A).on("dblclick.zoom",T).filter(u).on("touchstart.zoom",S).on("touchmove.zoom",E).on("touchend.zoom touchcancel.zoom",k).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function v(t,n){return(n=Math.max(c[0],Math.min(c[1],n)))===t.k?t:new jm(n,t.x,t.y)}function _(t,n,e){var r=n[0]-e[0]*t.k,i=n[1]-e[1]*t.k;return r===t.x&&i===t.y?t:new jm(t.k,r,i)}function b(t){return[(+t[0][0]+ +t[1][0])/2,(+t[0][1]+ +t[1][1])/2]}function m(t,n,e,r){t.on("start.zoom",(function(){x(this,arguments).event(r).start()})).on("interrupt.zoom end.zoom",(function(){x(this,arguments).event(r).end()})).tween("zoom",(function(){var t=this,o=arguments,a=x(t,o).event(r),u=i.apply(t,o),c=null==e?b(u):"function"==typeof e?e.apply(t,o):e,f=Math.max(u[1][0]-u[0][0],u[1][1]-u[0][1]),s=t.__zoom,h="function"==typeof n?n.apply(t,o):n,d=l(s.invert(c).concat(f/s.k),h.invert(c).concat(f/h.k));return function(t){if(1===t)t=h;else{var n=d(t),e=f/n[2];t=new jm(e,c[0]-n[0]*e,c[1]-n[1]*e)}a.zoom(null,t)}}))}function x(t,n,e){return!e&&t.__zooming||new w(t,n)}function w(t,n){this.that=t,this.args=n,this.active=0,this.sourceEvent=null,this.extent=i.apply(t,n),this.taps=0}function M(t,...n){if(r.apply(this,arguments)){var e=x(this,n).event(t),i=this.__zoom,u=Math.max(c[0],Math.min(c[1],i.k*Math.pow(2,a.apply(this,arguments)))),s=Nn(t);if(e.wheel)e.mouse[0][0]===s[0]&&e.mouse[0][1]===s[1]||(e.mouse[1]=i.invert(e.mouse[0]=s)),clearTimeout(e.wheel);else{if(i.k===u)return;e.mouse=[s,i.invert(s)],ai(this),e.start()}Vm(t),e.wheel=setTimeout(l,150),e.zoom("mouse",o(_(v(i,u),e.mouse[0],e.mouse[1]),e.extent,f))}function l(){e.wheel=null,e.end()}}function A(t,...n){if(!e&&r.apply(this,arguments)){var i=x(this,n,!0).event(t),a=An(t.view).on("mousemove.zoom",h,!0).on("mouseup.zoom",d,!0),u=Nn(t,c),c=t.currentTarget,s=t.clientX,l=t.clientY;zn(t.view),Gm(t),i.mouse=[u,this.__zoom.invert(u)],ai(this),i.start()}function h(t){if(Vm(t),!i.moved){var n=t.clientX-s,e=t.clientY-l;i.moved=n*n+e*e>p}i.event(t).zoom("mouse",o(_(i.that.__zoom,i.mouse[0]=Nn(t,c),i.mouse[1]),i.extent,f))}function d(t){a.on("mousemove.zoom mouseup.zoom",null),Dn(t.view,i.moved),Vm(t),i.event(t).end()}}function T(t,...n){if(r.apply(this,arguments)){var e=this.__zoom,a=Nn(t.changedTouches?t.changedTouches[0]:t,this),u=e.invert(a),c=e.k*(t.shiftKey?.5:2),l=o(_(v(e,c),a,u),i.apply(this,n),f);Vm(t),s>0?An(this).transition().duration(s).call(m,l,a,t):An(this).call(y.transform,l,a,t)}}function S(e,...i){if(r.apply(this,arguments)){var o,a,u,c,f=e.touches,s=f.length,l=x(this,i,e.changedTouches.length===s).event(e);for(Gm(e),a=0;a<s;++a)c=[c=Nn(u=f[a],this),this.__zoom.invert(c),u.identifier],l.touch0?l.touch1||l.touch0[2]===c[2]||(l.touch1=c,l.taps=0):(l.touch0=c,o=!0,l.taps=1+!!t);t&&(t=clearTimeout(t)),o&&(l.taps<2&&(n=c[0],t=setTimeout((function(){t=null}),d)),ai(this),l.start())}}function E(t,...n){if(this.__zooming){var e,r,i,a,u=x(this,n).event(t),c=t.changedTouches,s=c.length;for(Vm(t),e=0;e<s;++e)i=Nn(r=c[e],this),u.touch0&&u.touch0[2]===r.identifier?u.touch0[0]=i:u.touch1&&u.touch1[2]===r.identifier&&(u.touch1[0]=i);if(r=u.that.__zoom,u.touch1){var l=u.touch0[0],h=u.touch0[1],d=u.touch1[0],p=u.touch1[1],g=(g=d[0]-l[0])*g+(g=d[1]-l[1])*g,y=(y=p[0]-h[0])*y+(y=p[1]-h[1])*y;r=v(r,Math.sqrt(g/y)),i=[(l[0]+d[0])/2,(l[1]+d[1])/2],a=[(h[0]+p[0])/2,(h[1]+p[1])/2]}else{if(!u.touch0)return;i=u.touch0[0],a=u.touch0[1]}u.zoom("touch",o(_(r,i,a),u.extent,f))}}function k(t,...r){if(this.__zooming){var i,o,a=x(this,r).event(t),u=t.changedTouches,c=u.length;for(Gm(t),e&&clearTimeout(e),e=setTimeout((function(){e=null}),d),i=0;i<c;++i)o=u[i],a.touch0&&a.touch0[2]===o.identifier?delete a.touch0:a.touch1&&a.touch1[2]===o.identifier&&delete a.touch1;if(a.touch1&&!a.touch0&&(a.touch0=a.touch1,delete a.touch1),a.touch0)a.touch0[1]=this.__zoom.invert(a.touch0[0]);else if(a.end(),2===a.taps&&(o=Nn(o,this),Math.hypot(n[0]-o[0],n[1]-o[1])<g)){var f=An(this).on("dblclick.zoom");f&&f.apply(this,arguments)}}}return y.transform=function(t,n,e,r){var i=t.selection?t.selection():t;i.property("__zoom",Zm),t!==i?m(t,n,e,r):i.interrupt().each((function(){x(this,arguments).event(r).start().zoom(null,"function"==typeof n?n.apply(this,arguments):n).end()}))},y.scaleBy=function(t,n,e,r){y.scaleTo(t,(function(){var t=this.__zoom.k,e="function"==typeof n?n.apply(this,arguments):n;return t*e}),e,r)},y.scaleTo=function(t,n,e,r){y.transform(t,(function(){var t=i.apply(this,arguments),r=this.__zoom,a=null==e?b(t):"function"==typeof e?e.apply(this,arguments):e,u=r.invert(a),c="function"==typeof n?n.apply(this,arguments):n;return o(_(v(r,c),a,u),t,f)}),e,r)},y.translateBy=function(t,n,e,r){y.transform(t,(function(){return o(this.__zoom.translate("function"==typeof n?n.apply(this,arguments):n,"function"==typeof e?e.apply(this,arguments):e),i.apply(this,arguments),f)}),null,r)},y.translateTo=function(t,n,e,r,a){y.transform(t,(function(){var t=i.apply(this,arguments),a=this.__zoom,u=null==r?b(t):"function"==typeof r?r.apply(this,arguments):r;return o(Hm.translate(u[0],u[1]).scale(a.k).translate("function"==typeof n?-n.apply(this,arguments):-n,"function"==typeof e?-e.apply(this,arguments):-e),t,f)}),r,a)},w.prototype={event:function(t){return t&&(this.sourceEvent=t),this},start:function(){return 1==++this.active&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(t,n){return this.mouse&&"mouse"!==t&&(this.mouse[1]=n.invert(this.mouse[0])),this.touch0&&"touch"!==t&&(this.touch0[1]=n.invert(this.touch0[0])),this.touch1&&"touch"!==t&&(this.touch1[1]=n.invert(this.touch1[0])),this.that.__zoom=n,this.emit("zoom"),this},end:function(){return 0==--this.active&&(delete this.that.__zooming,this.emit("end")),this},emit:function(t){var n=An(this.that).datum();h.call(t,this.that,new Lm(t,{sourceEvent:this.sourceEvent,target:y,type:t,transform:this.that.__zoom,dispatch:h}),n)}},y.wheelDelta=function(t){return arguments.length?(a="function"==typeof t?t:Ym(+t),y):a},y.filter=function(t){return arguments.length?(r="function"==typeof t?t:Ym(!!t),y):r},y.touchable=function(t){return arguments.length?(u="function"==typeof t?t:Ym(!!t),y):u},y.extent=function(t){return arguments.length?(i="function"==typeof t?t:Ym([[+t[0][0],+t[0][1]],[+t[1][0],+t[1][1]]]),y):i},y.scaleExtent=function(t){return arguments.length?(c[0]=+t[0],c[1]=+t[1],y):[c[0],c[1]]},y.translateExtent=function(t){return arguments.length?(f[0][0]=+t[0][0],f[1][0]=+t[1][0],f[0][1]=+t[0][1],f[1][1]=+t[1][1],y):[[f[0][0],f[0][1]],[f[1][0],f[1][1]]]},y.constrain=function(t){return arguments.length?(o=t,y):o},y.duration=function(t){return arguments.length?(s=+t,y):s},y.interpolate=function(t){return arguments.length?(l=t,y):l},y.on=function(){var t=h.on.apply(h,arguments);return t===h?y:t},y.clickDistance=function(t){return arguments.length?(p=(t=+t)*t,y):Math.sqrt(p)},y.tapDistance=function(t){return arguments.length?(g=+t,y):g},y},t.zoomIdentity=Hm,t.zoomTransform=Xm,Object.defineProperty(t,"__esModule",{value:!0})})); diff --git a/src/main/webapp/map_applications/phytophthora/js/map.js b/src/main/webapp/map_applications/phytophthora/js/map.js new file mode 100755 index 0000000000000000000000000000000000000000..8c1efa5f66f733530f8e4fe8a24d3b0a22ac8b69 --- /dev/null +++ b/src/main/webapp/map_applications/phytophthora/js/map.js @@ -0,0 +1,762 @@ +/* + * Copyright (c) 2024 NIBIO <http://www.nibio.no/>. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + */ + +/* + * + * @author Tor-Einar Skog <tor-einar.skog@nibio.no> + */ + +// The globally available map objects +var map, featureOverlay, newFeatureOverlay; + +// Override localization settings for this particular web page +var hardcodedLanguage = "nb"; + +// If false, touching map will not create a new item +var registration = false; +var geolocation; + + +/** + * Initializes the map with all its layers + * @returns {undefined} + */ +async function initMap() { + var features = new ol.Collection(); + + // Icon styling for the observations layer + var iconRadius = 16; + + const colors = { + + 'fagus sylvatica': [255, 0, 0, 1], // Bøk = rød + 'alnus incana': [239, 133, 19, 1], // Gråor = dyp oransje + 'quercus': [239, 236, 19, 1], // Eik = gul + 'acer': [0, 255, 0, 1], // Lønn = grønn + 'alnus glutinosa': [122, 175, 131, 1], // Svartor = grågrønn + 'plantae': [0, 0, 255, 1] + }; + + var styles = { + // Bøk = rød + 'fagus sylvatica': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: [255, 0, 0, 1] }), + stroke: new ol.style.Stroke({ width: 1, color: [0, 0, 0, 1] }), + radius: iconRadius + }) + })], + // Gråor = dyp oransje + 'alnus incana': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: [239, 133, 19, 1] }), + stroke: new ol.style.Stroke({ width: 1, color: [0, 0, 0, 1] }), + radius: iconRadius + }) + })], + // Eik = gul + 'quercus': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: [239, 236, 19, 1] }), + stroke: new ol.style.Stroke({ width: 1, color: [0, 0, 0, 1] }), + radius: iconRadius + }) + })], + // Lønn = grønn + 'acer': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: [0, 255, 0, 1] }), + stroke: new ol.style.Stroke({ width: 1, color: [0, 0, 0, 1] }), + radius: iconRadius + }) + })], + // Svartor = grågrønn + 'alnus glutinosa': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: [122, 175, 131, 1] }), + stroke: new ol.style.Stroke({ width: 1, color: [0, 0, 0, 1] }), + radius: iconRadius + }) + })], + // Planteriket = blå + 'plantae': [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: [0, 0, 255, 1] }), + stroke: new ol.style.Stroke({ width: 1, color: [0, 0, 0, 1] }), + radius: iconRadius + }) + }) + ] + }; + + // Initialize the layer for observations. Empty features array at first + featureOverlay = new ol.layer.Vector({ + source: new ol.source.Vector({ + features: features + }), + style: function (feature, resolution) { + // Site that has been cleared is all black + var observationData = JSON.parse(feature.get("observationData")); + + var retVal = null; + const color = feature.get("cropOrganism") != null && feature.get("cropOrganism")["latinName"] != null ? + colors[feature.get("cropOrganism")["latinName"].toLowerCase()] + : colors["plantae"]; + + + retVal = [ + new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: (observationData["funn"] == "[Ukjent]" ? color : observationData["funn"] == "Sanns. Phyt." ? [204, 204, 204, 1] : [0, 0, 0, 1]) }), + stroke: new ol.style.Stroke({ width: (observationData["funn"] == "[Ukjent]" ? 0 : 4), color: (observationData["funn"] == "[Ukjent]" ? [0, 0, 0, 1] : color) }), + radius: iconRadius + }), + text: new ol.style.Text({ + text: observationData["provenummer"], + font: '20px Arial', + fill: new ol.style.Fill({ + color: '#000' + }), + stroke: new ol.style.Stroke({ + color: '#fff', + width: 2 + }) + }) + }) + ]; + + return retVal; + } + + }); + + // When user registers a new observation, this layer is used to place the marker + newFeatureOverlay = new ol.layer.Vector({ + source: new ol.source.Vector({ + features: new ol.Collection() + }), + style: [new ol.style.Style({ + image: new ol.style.Circle({ + fill: new ol.style.Fill({ color: [255, 255, 255, 1] }), + stroke: new ol.style.Stroke({ color: [0, 0, 0, 1], width: 3, lineDash: [2, 2] }), + radius: 10 + }) + })] + + }); + + // Get the background layer for Norway from Statens kartverk + var parser = new ol.format.WMTSCapabilities(); + fetch('https://cache.kartverket.no/v1/wmts/1.0.0/WMTSCapabilities.xml').then(function (response) { + return response.text(); + }).then(function (text) { + var result = parser.read(text); + var options = ol.source.WMTS.optionsFromCapabilities(result, { + layer: 'topo', + matrixSet: 'webmercator' + }); + + var topo = + new ol.layer.Tile({ + opacity: 1, + source: new ol.source.WMTS(/** @type {!olx.source.WMTSOptions} */(options)) + }); + + + map = new ol.Map({ + target: 'map', + controls: ol.control.defaults({ attribution: false }), // Hide the attribution + layers: [ + topo, + featureOverlay, + newFeatureOverlay + ], + view: new ol.View({ + center: ol.proj.fromLonLat([8.5, 60.8]), + zoom: 6 + }) + }); + + // Configure geolocation tracker + geolocation = new ol.Geolocation({ + trackingOptions: { + enableHighAccuracy: true + }, + projection: map.getView().getProjection() + }); + var positionFeature = new ol.Feature(); + positionFeature.setStyle( + new ol.style.Style({ + image: new ol.style.Circle({ + radius: 6, + fill: new ol.style.Fill({ + color: '#3399CC', + }), + stroke: new ol.style.Stroke({ + color: '#fff', + width: 2, + }), + }), + }) + ); + + geolocation.on('change:position', function () { + var coordinates = geolocation.getPosition(); + positionFeature.setGeometry(coordinates ? new ol.geom.Point(coordinates) : null); + }); + + new ol.layer.Vector({ + map: map, + source: new ol.source.Vector({ + features: [positionFeature] + }) + }); + + // TODO feature properties must be synchronized + var lastYear = new Date().getFullYear() - 1; + // Population the season select list, setting last year as default selected + initSeasonSelectList(lastYear); + //getAndRenderDiseaseSpreadingPois(); + getAndRenderObservations(lastYear); + + // Handle user click on map + map.on('click', function (evt) { + //features = [] + var feature = map.forEachFeatureAtPixel( + evt.pixel, function (ft, l) { + return ft; + } + ); + + var vectorSource = newFeatureOverlay.getSource(); + // Remove any new features already created + vectorSource.clear(); + + if (feature && feature.getProperties()["observationId"] != undefined) { + // Create a fake icon for highlighting + var fakeFeature = createFeature(feature.getGeometry().getCoordinates()); + vectorSource.addFeature(fakeFeature); + displayFeature(feature); + } else if (registration) { + var newFeature = createFeature(map.getCoordinateFromPixel(evt.pixel)); + vectorSource.addFeature(newFeature); + editFeature(newFeature.getId()); + } + }); + + }); // END FETCH + +} + +let openLayersDefaultStyle = undefined; + +function getOpenLayersDefaultStyle() { + if (openLayersDefaultStyle == undefined) { + var fill = new ol.style.Fill({ + color: 'rgba(255,255,255,0.4)' + }); + var stroke = new ol.style.Stroke({ + color: '#3399CC', + width: 1.25 + }); + openLayersDefaultStyle = [ + new ol.style.Style({ + image: new ol.style.Circle({ + fill: fill, + stroke: stroke, + radius: 5 + }), + fill: fill, + stroke: stroke + }) + ]; + } + + return openLayersDefaultStyle; +} + + +/** + * + * @param {type} fromSeason + * @returns {undefined} + */ +function getAndRenderObservations(fromSeason) { + //console.info("getAndRenderObservations(" + season + ")"); + $.getJSON("/rest/observation/filter/1/geoJSON?from=" + fromSeason + "-01-01&pestId=" + phytophthora.organismId, function (geoData) { + //console.info(geoData) + var format = new ol.format.GeoJSON(); + + var drawnfeatures = format.readFeatures(geoData, { + //dataProjection: "EPSG:32633", + dataProjection: "EPSG:4326", + featureProjection: map.getView().getProjection().getCode() + }); + featureOverlay.getSource().clear(); + featureOverlay.getSource().addFeatures(drawnfeatures); + }); +} + + +/** + * + * @param {type} fromSeason + * @param {type} countyNo + * @returns {undefined} + */ +function getAndRenderObservationsForReport(fromSeason, countyNo = "-1") { + //console.info("getAndRenderObservations(" + season + ")"); + $.getJSON("/rest/observation/filter/1/geoJSON?from=" + fromSeason + "-01-01&pestId=" + phytophthora.organismId, function (geoData) { + //console.info(geoData) + // Filter by county + $.getJSON("/corsproxy/https://ws.geonorge.no/kommuneinfo/v1/fylker/" + countyNo + "/omrade") + .always(function (serviceResponse) { + //console.info(geoData); + //console.info(serviceResponse); + + if (parseInt(countyNo) > 0) { + var filteredFeatures = []; + for (var i = 0; i < geoData.features.length; i++) { + var featureToBeFiltered = geoData.features[i]; + coordinate = proj4("EPSG:4326", "EPSG:4258", [featureToBeFiltered.geometry.coordinates[0], featureToBeFiltered.geometry.coordinates[1]]); + // For some weird reason, d3 returns NOT contains in our case + if (!d3.geoContains(serviceResponse.omrade, coordinate)) { + //console.info(featureToBeFiltered); + filteredFeatures.push(featureToBeFiltered); + } + //console.info(featureToBeFiltered); + } + //console.info(filteredFeatures); + geoData.features = filteredFeatures; + } + + var format = new ol.format.GeoJSON(); + + var drawnfeatures = format.readFeatures(geoData, { + //dataProjection: "EPSG:32633", + dataProjection: "EPSG:4326", + featureProjection: map.getView().getProjection().getCode() + }); + featureOverlay.getSource().clear(); + featureOverlay.getSource().addFeatures(drawnfeatures); + } + ); + }); +} + +function toggleRegistration(theButton) { + if (registration) { + theButton.title = "Registrering er AV"; + theButton.style.color = "white"; + } else { + theButton.title = "Registrering er PÅ"; + theButton.style.color = "red"; + } + registration = !registration; +} + +function toggleTracking(theButton) { + geolocation.setTracking(!geolocation.getTracking()); + theButton.style.backgroundColor = geolocation.getTracking() ? "green" : "rgba(0,60,136,.5)"; + theButton.title = geolocation.getTracking() ? "Vis min posisjon er PÅ" : "Vis min posisjon er AV"; +} + +/** + * Creates a new feature + * @param {type} coordinate + * @returns {createFeature.newFeature|ol.Feature} + */ +var createFeature = function (coordinate) { + if (coordinate.length == 2) { + coordinate = [coordinate[0], coordinate[1], 0]; + } + var point = new ol.geom.Point(coordinate); + var newFeature = new ol.Feature({ + name: "Ny observasjon", + geometry: point + }); + newFeature.setId(-1); + newFeature.setProperties({ + "observationId": -1, + "observationData": "{\"symptom\":\"\"}", + "cropOrganism": {}, + "observationText": "", + "timeOfObservation": moment().valueOf() + }); + + return newFeature; +} + +var displayFeature = function (feature) { + var featureForm = document.getElementById("featureForm"); + + var observationData = JSON.parse(feature.get("observationData")); + var timeOfObservation = new moment(feature.get("timeOfObservation")); + var html = [ + '<button type="button" onclick="unFocusForm()">X</button>', + '<button type="button" onclick="editFeature(\'', feature.getId(), '\');">Rediger</button>', + '<button type="button" onclick="deleteFeature(' + feature.getId() + ')">Slett</button>', + '<h3>Registrering</h3>', + '<table>', + '<tr><td>Plante</td><td>', getLocalizedOrganismName(feature.get("cropOrganism"), hardcodedLanguage), '</td></tr>', + '<tr><td>Plante spes</td><td>', observationData["plantespes"], '</td></tr>', + '<tr><td>Symptom</td><td>', observationData["symptom"], '</td></tr>', + '<tr><td>Sym spes</td><td>', observationData["symspes"], '</td></tr>', + '<tr><td>Prøvetype</td><td>', observationData["provetype"], '</td></tr>', + '<tr><td>Prøvenummer</td><td>', observationData["provenummer"], '</td></tr>', + '<tr><td>Funn</td><td>', observationData["funn"], '</td></tr>', + '<tr><td>Mer info</td><td>', feature.get("observationText"), '</td></tr>', + '<tr><td>Dato</td><td>', timeOfObservation.format("DD.MM.YYYY"), '</td></tr>', + '</table>' + ]; + featureForm.innerHTML = html.join(""); + focusForm(); +} + +var forekomsttypeLatinskeNavn = [ + "Fagus sylvatica", //"Bøk", + "Alnus incana", //"Gråor", + "Quercus", //"Eik", + "Acer", //"Lønn", + "Alnus glutinosa", // "Svartor" + "Plantae" // Planteriket (Annet) +]; + +var forekomsttyper = []; +var phytophthora = {}; + +function initForekomsttyper() { + $.getJSON("/rest/organism/search/latinnames?keywords=" + forekomsttypeLatinskeNavn.join(","), function (data) { + forekomsttyper = data; + }); +} + +function initPhytophthora() { + $.getJSON("/rest/organism/search/latinnames?keywords=Phytophthora sp", function (data) { + if (data.length == 1) { + phytophthora = data[0]; + initMap(); + } + }); +} + +var getCropOrganism = function (organismId) { + for (var i = 0; i < forekomsttyper.length; i++) { + if (forekomsttyper[i].organismId == organismId) { + return forekomsttyper[i]; + } + } +} + + +var symptoms = ["Flekker", "Glisne kroner", "Oppsprekking", "Død", "Andre symptom", "Andre skader", "Ikke symptom", "Irrelevant"]; +var funns = ["[Ukjent]", "Sanns. Phyt.", "Phytophthora gonapodyides", "Phytophthora lacustris", "Phytophthora plurivora", "Phytophthora cambivora", "Phytophthora cactorum", "Phytophthora sp"] +var provetypes = ["[Ikke prøve]", "Jord", "Vev", "Vann", "Blad", "Bait"]; + + +var editFeature = function (featureId) { + var feature = featureId > 0 ? featureOverlay.getSource().getFeatureById(featureId) + : newFeatureOverlay.getSource().getFeatureById(featureId); + var observationData = JSON.parse(feature.get("observationData")); + var timeOfObservation = new moment(feature.get("timeOfObservation")); + var featureForm = document.getElementById("featureForm"); + var html = + '<button type="button" onclick="unFocusForm()" title="Avbryt">X</button>' + + (featureId > 0 ? '<button type="button" onclick="deleteFeature(' + featureId + ')">Delete</button>' : '') + + '<h3>' + (featureId > 0 ? "R" : "Ny r") + 'egistrering</h3>' + + '<table>' + + '<tr><td>Plante</td><td>' + + generateCropSelect("forekomsttype", forekomsttyper, feature.get("cropOrganism")["organismId"]) + + '</td></tr>' + + '<tr><td>Plante spes.</td><td>' + + '<input type="text" id="plantespes" name="plantespes" size="15" value="' + (observationData["plantespes"] != null ? observationData["plantespes"] : "") + '"/></td></tr>' + + '<tr><td>Symptom</td><td>' + + generateSelect("symptom", symptoms, observationData["symptom"]) + + '</td></tr>' + + '<tr><td>Sym spes.</td><td>' + + '<input type="text" id="symspes" name="symspes" size="15" value="' + (observationData["symspes"] != null ? observationData["symspes"] : "") + '"/></td></tr>' + + + '<tr><td>Prøvetype</td><td>' + + generateSelect("provetype", provetypes, observationData["provetype"]) + + '</td></tr>' + + '<tr><td>Prøvenummer</td><td>' + + '<input type="text" id="provenummer" name="provenummer" size="15" value="' + (observationData["provenummer"] != null ? observationData["provenummer"] : "") + '"/></td></tr>' + + '<tr><td>Funn</td><td>' + + generateSelect("funn", funns, observationData["funn"]) + + '</td></tr>' + + '<tr><td>Mer info</td><td>' + + '<textarea id="beskrivelse" name="beskrivelse">' + (feature.get("observationText") != null ? feature.get("observationText") : "") + '</textarea>' + + '</td></tr>' + + '<tr><td>Dato</td><td>' + + '<input type="text" id="dato" name="dato" size="10" value="' + timeOfObservation.format("DD.MM.YYYY") + '"/></td></tr>' + + '<tr><td></td><td>' + + '<input type="submit" value="Lagre" onclick="storeFeature(' + feature.getId() + ');"/></td></tr>' + + '</table>'; + + + featureForm.innerHTML = html; + focusForm(); + //console.info(feature); +}; + +var storeFeature = function (featureId) { + var feature = featureId > 0 ? featureOverlay.getSource().getFeatureById(featureId) + : newFeatureOverlay.getSource().getFeatureById(featureId); + + // Store, clear newFeature layer + // Need to add feature as payload + var format = new ol.format.GeoJSON(); + + // Add the form data + var cropOrganism = getCropOrganism(document.getElementById("forekomsttype").options[document.getElementById("forekomsttype").options.selectedIndex].value); + //console.info(cropOrganism); + var plantespes = document.getElementById("plantespes").value; + var symptom = document.getElementById("symptom").options[document.getElementById("symptom").options.selectedIndex].value; + var symspes = document.getElementById("symspes").value; + var provetype = document.getElementById("provetype").options[document.getElementById("provetype").options.selectedIndex].value; + var provenummer = document.getElementById("provenummer").value; + var funn = document.getElementById("funn").options[document.getElementById("funn").options.selectedIndex].value; + var observationText = document.getElementById("beskrivelse").value; + var observationHeading = "Registrering av phytophthora"; + var timeOfObservation = moment(document.getElementById("dato").value + "+0200", "DD.MM.YYYYZ"); + if (timeOfObservation.year() < 2000) { + alert("Feil dato (før år 2000). Datoformat er DD.MM.ÅÅÅÅ"); + return; + } + + feature.setProperties({ + timeOfObservation: timeOfObservation.valueOf(), + cropOrganism: cropOrganism, + organism: phytophthora, + observationHeading: observationHeading, + observationText: observationText, + observationData: "{\"plantespes\":\"" + plantespes + "\",\"symptom\":\"" + symptom + "\",\"symspes\":\"" + symspes + "\",\"funn\":\"" + funn + "\",\"provetype\":\"" + provetype + "\",\"provenummer\":\"" + provenummer + "\"}", + statusTypeId: 3, + statusRemarks: "Registrert via phytophthora-overvåkningskartet", + isQuantified: true, + broadcastMessage: false + }); + var result = format.writeFeatures([feature], { + dataProjection: 'EPSG:4326', + featureProjection: map.getView().getProjection().getCode() + }); + + //console.log(feature); + + $.ajax({ + type: "POST", + url: "/rest/observation/gisobservation", + // The key needs to match your method's input parameter (case-sensitive). + data: result, + contentType: "application/json; charset=utf-8", + dataType: "json", + success: function (geoData) { + //console.info(geoData) + var format = new ol.format.GeoJSON(); + + var drawnfeatures = format.readFeatures(geoData, { + dataProjection: "EPSG:4326", + featureProjection: map.getView().getProjection().getCode() + }); + newFeatureOverlay.getSource().clear(true); + // If storing an existing feature, remove the one + // that was there before storing, since the returned + // one has a new gisId (featureId) + if (featureId > 0) { + featureOverlay.getSource().removeFeature(feature); + } + featureOverlay.getSource().addFeatures(drawnfeatures); + unFocusForm(); + }, + error: function (jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 401) { + if (confirm("Kan ikke lagre fordi du er logget ut av applikasjonen. Klikk OK for å logge inn.")) { + window.location.reload(); + } + } else { + alert("Beklager, en feil oppsto. Status = " + jqXHR.status + ", eventuell feilmelding: " + textStatus); + } + } + }); + + +} + +/** + * Delete an existing feature + * @param {type} featureId + * @returns {undefined} + */ +var deleteFeature = function (featureId) { + if (!confirm("Er du sikker på at du vil slette?")) { + return; + } + + var feature = featureOverlay.getSource().getFeatureById(featureId); + + $.ajax({ + type: "DELETE", + url: "/rest/observation/gisobservation/" + feature.getId(), + success: function (response) { + //console.info(response); + // If storing an existing feature, remove the one + // that was there before storing, since the returned + // one has a new gisId (featureId) + if (featureId > 0) { + featureOverlay.getSource().removeFeature(feature); + } + unFocusForm(); + }, + error: function (jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 401) { + if (confirm("Kan ikke slette fordi du er logget ut av applikasjonen. Klikk OK for å logge inn.")) { + window.location.reload(); + } + } else { + alert("Beklager, en feil oppsto. Status = " + jqXHR.status + ", eventuell feilmelding: " + textStatus); + } + } + }); +} + +var generateSelect = function (selectName, options, preselect) { + var retVal = '<select id="' + selectName + '" name="' + selectName + '">'; + for (var i = 0; i < options.length; i++) { + retVal += '<option value="' + options[i] + '"' + (options[i] == preselect ? " selected=\"selected\"" : "") + '">' + options[i] + '</option>'; + } + retVal += '</select>'; + return retVal; +} + +var generateCropSelect = function (selectName, cropOrganisms, preselect) { + var retVal = '<select id="' + selectName + '" name="' + selectName + '">'; + for (var c = 0; c < forekomsttypeLatinskeNavn.length; c++) { + currentLatinName = forekomsttypeLatinskeNavn[c]; + for (var i = 0; i < cropOrganisms.length; i++) { + if (cropOrganisms[i].latinName == currentLatinName) { + retVal += '<option value="' + cropOrganisms[i].organismId + '"' + (cropOrganisms[i].organismId == preselect ? " selected=\"selected\"" : "") + '">' + + (currentLatinName == "Plantae" ? "Annet" : getLocalizedOrganismName(cropOrganisms[i], hardcodedLanguage)) + + '</option>'; + } + } + } + retVal += '</select>'; + return retVal; +} + +var focusForm = function () { + var featureForm = document.getElementById("featureForm"); + featureForm.style.display = "block"; +} + +var unFocusForm = function () { + var featureForm = document.getElementById("featureForm"); + featureForm.style.display = "none"; + // Also remove feature (if one) on the New feature overlay + newFeatureOverlay.getSource().clear(); +} + +var navigateTo = function (center) { + var centerPosition = ol.proj.transform(center, 'EPSG:4326', 'EPSG:3857'); + view = new ol.View({ + center: centerPosition, + zoom: 16 + }); + + map.setView(view); + + var searchResultsEl = document.getElementById("searchResults"); + searchResultsEl.innerHTML = ""; + searchResultsEl.style.display = "none"; +}; + +/** + * Uses the client's geolocation information - displays it on the map + */ +function showLocation() { + if (navigator.geolocation) { + if (window.location.protocol === "http:") { + navigator.geolocation.getCurrentPosition(function (geopositionObj) { + // TODO: position and display location icon + } + ); + } else { + if (confirm("Lokalisering fungerer bare over https (sikker tilkobling mellom nettleser og tjener). Klikk OK for å gå til sikker tilkobling.")) { + window.location = "https:" + window.location.href.substring(window.location.protocol.length); + } + } + } else { + alert("Lokaliseringsfunksjonen er ikke tilgjengelig i denne nettleseren."); + } +} + +function navToLocation() { + if (navigator.geolocation) { + if (window.location.protocol === "https:") { + navigator.geolocation.getCurrentPosition(function (geopositionObj) { + navigateTo([geopositionObj.coords.longitude, geopositionObj.coords.latitude]); + } + ); + } else { + if (confirm("Lokalisering fungerer bare over https (sikker tilkobling mellom nettleser og tjener). Klikk OK for å gå til sikker tilkobling.")) { + window.location = "https:" + window.location.href.substring(window.location.protocol.length); + } + } + } else { + alert("Lokaliseringsfunksjonen er ikke tilgjengelig i denne nettleseren."); + } +} + +/** + * + * @param {type} selectedSeason + * @returns {undefined} + */ +function initSeasonSelectList(selectedSeason) { + // What's the current year? + var thisYear = new Date().getFullYear(); + // How many years do we go back? + $.ajax({ + url: "/rest/observation/first/" + phytophthora.organismId + }) + .done(function (data) { + var time = moment(data); + var firstYear = time.toDate().getFullYear(); + // Loop gjennom år, lag valgliste :-) + var startSeasonList = document.getElementById("startSeason"); + for (var i = firstYear; i <= thisYear; i++) { + var yearOpt = new Option("", i); + yearOpt.innerHTML = i + " →" + if (i == selectedSeason) { + yearOpt.selected = true; + } + startSeasonList.options[startSeasonList.options.length] = yearOpt; + } + }) + .fail(function (jqXHR, textStatus, errorThrown) { + if (jqXHR.status == 404) { + alert("Could not find any observations of organism with id=" + phytophthora.organismId); + document.getElementById("startSeason").options[0] = new Option("" + thisYear, thisYear); + } + else { + alert(textStatus + ": " + errorThrown); + } + }); + +} + diff --git a/src/main/webapp/map_applications/phytophthora/report.html b/src/main/webapp/map_applications/phytophthora/report.html new file mode 100755 index 0000000000000000000000000000000000000000..f97385489a926b4187779b8f4673bb1e3d93b266 --- /dev/null +++ b/src/main/webapp/map_applications/phytophthora/report.html @@ -0,0 +1,360 @@ +<!DOCTYPE html> +<html lang="en"> + <head> + <meta charset="utf-8"> + <meta http-equiv="X-UA-Compatible" content="IE=edge"> + <meta name="viewport" content="width=device-width, initial-scale=1"> + <!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags --> + <meta name="description" content=""> + <meta name="author" content=""> + + <title>Pærebrannregistrering - rapporteringsside</title> + + <!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries --> + <!--[if lt IE 9]> + <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> + <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> + <![endif]--> + <link rel="stylesheet" href="/css/3rdparty/font-awesome.min.css" media="screen" /> + <link rel="stylesheet" href="/css/3rdparty/ol.css?t=20170623" media="screen" /> + <style type="text/css"> + html, body, #map { + margin: 0; + width: 100%; + height: 100%; + font-family: 'Source Sans Pro', sans-serif; + } + + #searchFieldContainer { + position: fixed; + top: 0px; + left: 0px; + width: 100%; + z-index: 2000; + background-color: transparent; + + } + #searchFieldInnerContainer + { + background-color: white; + margin: 5px; + padding: 5px; + /*border: 1px solid #dddddd;*/ + } + .ol-zoom { + top: auto; + bottom: 3.5em; + left: auto; + right: .5em + } + + #searchResults { + display: none; + } + + #searchResults li { + cursor: pointer; + } + + .geo-location + { + top: auto; + right: 0.5em; + bottom: 10.0em; + left: auto; + z-index: 1000; + } + + #registerButton { + top: auto; + bottom: 12.0em; + right: 0.5em; + left: auto; + z-index: 1000; + } + + #registerButton button { + width: 1.375em; + height: 1.375em; + background-size: 20px 20px; + background-repeat: no-repeat; + background-position: 2px 2px; + background-color: rgba(0,60,136,.5); + border: none; + color: white; + } + + + .geo-location button { + + width: 1.375em; + height: 1.375em; + background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAACACAMAAAD04JH5AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNS1jMDIxIDc5LjE1NTc3MiwgMjAxNC8wMS8xMy0xOTo0NDowMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkY3RkRGRkNGQTU2MDExRTU5NzkwREJDNkE0NDk4ODlEIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkY3RkRGRkQwQTU2MDExRTU5NzkwREJDNkE0NDk4ODlEIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6RjdGREZGQ0RBNTYwMTFFNTk3OTBEQkM2QTQ0OTg4OUQiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6RjdGREZGQ0VBNTYwMTFFNTk3OTBEQkM2QTQ0OTg4OUQiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7kZLS4AAAABlBMVEX9/fwAAABwf477AAAAAnRSTlP/AOW3MEoAAAHzSURBVHja7NvBcsJADANQ+f9/misHsmvZkhNgfWwhes10htheEOXCe9Wvosm/H4ADOIADOIBZAD7WEADLcgOQKB8A6bIAQJUcALqkAJRKB0C1NAA0SgFAr7oAtKsHANwC2PM3BAzkLwWYyF8JMJK/EGAm/1qAofxLAabySQAwJUAx/8NDaU1QAlw+FRcEoPPXj+W0AGT+vi/wAlKNCSUAk5/tjHqA7LsJ3EpAAKjeMC1AlN9J/boPoLvj7I2s5gf7gh6gNB/I/S+XO3/2FTkA9Tm2/6DxAjSTFDjzRYAIsWASsL8ivPn3A+KRADCAGAQ4bsD2r3o8IH4T8P5wzXRhnqGqY/p5AAdwAAdwAAdAXlO/jiTS//SB5KnPhPGTgHZj8u2tGdec3t6eDw0oWACcNyA1pBqcEYlvAVSA4qCyMid86qi2BKgNq/MC07heti8oLyzy7zStbDQ7o87SSrC2623NsntH3+Kyubold7f08noHUCyvc1v4zA+r6/ttY3EB0B1g8HR3Nx9ioc6Q3H+KRi8IFhAz+VNnyaICiIn8mfOEUQWICNEAhDt/f6zXPdcyH2xOHFu2jv0yF3dOHkMGCFc88QUH01A1HONPbqiq6Lc77Tzd+0vTo/ZFJ1l4FfBRUb6Oav5zAAdwAH8PiK8FvAQYAObrJPi2gfjAAAAAAElFTkSuQmCC); + background-size: 20px 20px; + background-repeat: no-repeat; + background-position: 2px 2px; + background-color: rgba(0,60,136,.5); + border: none; + } + + #featureForm { + display: none; + width: auto; + max-width: 90%; + height: auto; + position: absolute; + top: 3.0em; + left: 10px; + z-index: 1999; + background-color: white; + border: 1px solid black; + padding: 10px; + opacity: 0.85; + } + + #seasons { + position: absolute; + bottom: 1em; + top: auto; + left: 10px; + z-index: 1999; + } + + #counties { + position: absolute; + bottom: 3em; + top: auto; + left: 10px; + z-index: 1999; + } + + #headingBox { + position: absolute; + bottom: auto; + top: 1em; + left: 10px; + border: 1px solid black; + z-index: 1999; + padding: 10px; + opacity: 0.85; + } + + #legend { + position: absolute; + top: 3.0em; + bottom: auto; + right: 10px; + z-index: 1999; + background-color: white; + border: 1px solid black; + padding: 10px; + opacity: 0.85; + } + + + + #legend ul { + list-style: none; + padding:0; + margin:0; + } + + #legend ul li:before { + content: ""; + line-height: 1em; + width: .7em; + height: .7em; + float: left; + margin: .25em .25em 0; + border-radius: 50%; + border: 1px solid black; + } + + #legend ul li.bulk:before { background-color: rgb(255,0,0); } + #legend ul li.sprik:before { background-color: rgb(239,133,19); } + #legend ul li.pil:before { background-color: rgb(239,236,19); } + #legend ul li.eple:before { background-color: rgb(0,255,0); } + #legend ul li.paere:before { background-color: rgb(122,175,131); } + #legend ul li.plante:before { background-color: rgb(0,0,255); } + + /* Screen size adjustments */ + @media (max-width: 500px) + { + #legend { + display: none; + } + + + } + + @media (pointer: coarse) { + #registerButton button, .geo-location button { + width: 1.8em; + height: 1.8em; + } + + #registerButton { + bottom: 13.0em; + } + .geo-location button { + bottom: 8.0em; + background-position: 6px; + } + } + + @media (max-height: 500px) + { + #legend { + display: none; + } + } + + ul.resultList + { + width: auto; + list-style: none; + padding: 0px; + } + + ul.resultList li + { + background-color: #dddddd; + border-bottom: 1px solid white; + cursor: pointer; + padding: 5px; + } + + ul.resultList li:hover { + background-color: #aaaaaa; + } + + div.logo { + float: left; + } + + #searchField { + width: 100%; + + } + table { + border-spacing: 5px 15px; + } + select, button + { + font-size: large; + } + button { + margin-right: 5px; + } + </style> + </head> + + <body> + + <div id="map" class="map"> + + + </div> + <div id="headingBox"> + <h1>Rapportering pr fylke</h1> + <p>Velg fylke i lista nedenfor. Vær tålmodig, <br/>det tar noen sekunder før utvalget er ferdig generert.</p> + </div> + <div id="featureForm"></div> + <div id="seasons"> + <select name="startSeason" id="startSeason" onchange="getAndRenderObservationsForReport(this.options[this.options.selectedIndex].value, document.getElementById('countyId').options[document.getElementById('countyId').options.selectedIndex].value);"> + + </select> + + </div> + <div id="counties"> + <select name="countyId" onchange="getAndRenderObservationsForReport(document.getElementById('startSeason').options[document.getElementById('startSeason').options.selectedIndex].value,this.options[this.options.selectedIndex].value);"> + <option value="-1">-- Velg fylke --</option> + <option value="03">Oslo</option> + <option value="30">Viken</option> + <option value="34">Innlandet</option> + <option value="38">Vestfold og Telemark</option> + <option value="42">Agder</option> + <option value="11">Rogaland</option> + <option value="46">Vestland</option> + <option value="15">Møre og Romsdal</option> + <option value="50">Trøndelag</option> + <option value="18">Nordland</option> + <option value="54">Troms og Finnmark</option> + </select> + </div> + <div id="legend"> + <ul> + <li class="bulk">Bulkemispel</li> + <li class="sprik">Sprikemispel</li> + <li class="pil">Pilemispel</li> + <li class="eple">Eple</li> + <li class="paere">Pære</li> + <li class="plante">Annet</li> + </ul> + </div> + + + <!-- Bootstrap core JavaScript + ================================================== --> + <!-- Placed at the end of the document so the pages load faster --> + <script type="text/javascript" src="/js/environment.js"></script> + <script type="text/javascript" src="/js/util.js"></script> + <script type="text/javascript" src="/js/constants.js"></script> + <script type="text/javascript" src="/js/3rdparty/jquery.min.js"></script> + <script type="text/javascript" src="/js/3rdparty/ol.js?t=20170623"></script> + <script type="text/javascript" src="/js/3rdparty/proj4.js"></script> + <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> + <script type="text/javascript" src="js/d3.min.js"></script> + <script type="text/javascript" src="js/map.js?t=20170713"></script> + <script type="text/javascript"> + + var stedsnavnProj = "+proj=utm +zone=33 +ellps=GRS80 +units=m +no_defs"; + proj4.defs("EPSG:32633", "+proj=utm +zone=33 +ellps=WGS84 +datum=WGS84 +units=m +no_defs"); + proj4.defs("EPSG:4258", "+proj=longlat +ellps=GRS80 +no_defs"); + + $(document).ready(function() { + initForekomsttyper(); + // initMap() kalles i denne funksjonens callback + // Dette fordi vi må finne databaseId til pærebrann dynamisk først + initPaerebrann(); + }); + + function showResults(inputField) + { + var phrase = inputField.value; + if(phrase.trim().length > 2) + { + //console.log(phrase); + $.getJSON( "https://ws.geonorge.no/SKWS3Index/ssr/sok?navn=" + phrase + "*&maxAnt=5&tilSosiKoordSyst=4258&fylkeKommuneListe=&eksakteForst=true", renderResults); + } + else if(phrase.trim().length === 0) + { + var searchResultsEl = document.getElementById("searchResults"); + searchResultsEl.innerHTML = ""; + searchResultsEl.style.display="none"; + } + } + + var renderResults = function(data) { + //console.log(data); + var html = "<ul class='resultList'>"; + for(var i=0; i<Math.min(data.stedsnavn.length,6); i++) + { + var location = data.stedsnavn[i]; + var coordinateOrig = [parseFloat(location.aust), parseFloat(location.nord)]; + var coordinateDec = proj4(stedsnavnProj, "EPSG:4326", coordinateOrig); + html += "<li onclick=\"navigateTo([" + coordinateDec + "]);\"><b>" + location.stedsnavn + "</b>, " + location.kommunenavn + " (" + location.navnetype + ")</li>"; + } + html += "</ul>" + var searchResultsEl = document.getElementById("searchResults"); + searchResultsEl.innerHTML = html; + searchResultsEl.style.display="block"; + + //console.log(location) + // Get EPSG projection in data, transform to decimal degrees + + } + + </script> + </body> +</html> diff --git a/src/main/webapp/public/documentation/Personvernerklaering_NIBIO-VIPS.pdf b/src/main/webapp/public/documentation/Personvernerklaering_NIBIO-VIPS.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a045c4ddfff3ff30e063ebd226c891936110d8a6 Binary files /dev/null and b/src/main/webapp/public/documentation/Personvernerklaering_NIBIO-VIPS.pdf differ diff --git a/src/main/webapp/public/documentation/Privacy_statement_NIBIO-VIPS.pdf b/src/main/webapp/public/documentation/Privacy_statement_NIBIO-VIPS.pdf new file mode 100644 index 0000000000000000000000000000000000000000..aa816be3cfe99e8f6d5d86444b371b2dbacc51cb Binary files /dev/null and b/src/main/webapp/public/documentation/Privacy_statement_NIBIO-VIPS.pdf differ diff --git a/src/main/webapp/public/images/station_icon_status_3b.png b/src/main/webapp/public/images/station_icon_status_3b.png new file mode 100644 index 0000000000000000000000000000000000000000..bb6892265bbab5bc2fa5efba8f63284bd660d496 Binary files /dev/null and b/src/main/webapp/public/images/station_icon_status_3b.png differ diff --git a/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.css b/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.css index c3e5c6305237e132dd740ddf28f2fe36d868f910..9b7c79806bf8e9eadc8d51601fb9bfbe17a4569d 100644 --- a/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.css +++ b/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.css @@ -2,18 +2,19 @@ Copyright (c) 2018 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. -VIPSLogic is free software: you can redistribute it and/or modify -it under the terms of the NIBIO Open Source License as published by -NIBIO, either version 1 of the License, or (at your option) any -later version. -VIPSLogic is distributed in the hope that it will be useful, +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -NIBIO Open Source License for more details. +GNU Affero General Public License for more details. -You should have received a copy of the NIBIO Open Source License -along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. */ /* diff --git a/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.js b/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.js index 67e08091b868a4f99b92d747c9891df78b9f7302..c87f5075dbd2fa483db668c0b61319a797e0b108 100644 --- a/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.js +++ b/src/main/webapp/public/nordic_septoria_map/nordic_septoria_map.js @@ -2,18 +2,18 @@ * Copyright (c) 2019 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, +* This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.css b/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.css index 9f0e77d4d84838c2eadf64093e7d7cb47ea96924..0b58a1fd309d6fc8cdf0fe85fffc0b46c0f8fbec 100644 --- a/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.css +++ b/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.css @@ -2,18 +2,19 @@ Copyright (c) 2018 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. -VIPSLogic is free software: you can redistribute it and/or modify -it under the terms of the NIBIO Open Source License as published by -NIBIO, either version 1 of the License, or (at your option) any -later version. -VIPSLogic is distributed in the hope that it will be useful, +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU Affero General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -NIBIO Open Source License for more details. +GNU Affero General Public License for more details. -You should have received a copy of the NIBIO Open Source License -along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. +You should have received a copy of the GNU Affero General Public License +along with this program. If not, see <https://www.gnu.org/licenses/>. */ /* diff --git a/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js b/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js index 7ed8f6582c87e82e9601efcb10b9960bd751769a..5498fab16dfcc489234090f866ae9409f618b6a7 100644 --- a/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js +++ b/src/main/webapp/public/nordic_septoria_whs/nordic_septoria_whs.js @@ -2,18 +2,18 @@ * Copyright (c) 2019 NIBIO <http://www.nibio.no/>. * * This file is part of VIPSLogic. - * VIPSLogic is free software: you can redistribute it and/or modify - * it under the terms of the NIBIO Open Source License as published by - * NIBIO, either version 1 of the License, or (at your option) any - * later version. - * - * VIPSLogic is distributed in the hope that it will be useful, + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * NIBIO Open Source License for more details. + * GNU Affero General Public License for more details. * - * You should have received a copy of the NIBIO Open Source License - * along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. * */ diff --git a/src/main/webapp/templates/403.ftl b/src/main/webapp/templates/403.ftl index c47107d85b89bc5d32d0ee4feb350c205febb541..34559c41ea0ea1deb25a10900f7db5be1c1cba39 100755 --- a/src/main/webapp/templates/403.ftl +++ b/src/main/webapp/templates/403.ftl @@ -10,7 +10,7 @@ <h1>ERROR 403 - Forbidden</h1> <p>${message}</p> - <#assign nextPage= Request["javax.servlet.forward.servlet_path"] + "?" + Request["javax.servlet.forward.query_string"]!""> + <#assign nextPage= Request["jakarta.servlet.forward.servlet_path"] + "?" + Request["jakarta.servlet.forward.query_string"]!""> <p><a href="/login?nextPage=${nextPage?url}">To login page</a></p> </#macro> <@page_html/> diff --git a/src/main/webapp/templates/appleFruitMothClusterForm.ftl b/src/main/webapp/templates/appleFruitMothClusterForm.ftl index 4e50de7fa029e049a34873971691b4b45d817799..91129151a310e38d60abcda73c6a6cf4752096d3 100644 --- a/src/main/webapp/templates/appleFruitMothClusterForm.ftl +++ b/src/main/webapp/templates/appleFruitMothClusterForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2017 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/appleFruitMothStationForm.ftl b/src/main/webapp/templates/appleFruitMothStationForm.ftl index bb7604e85e50a2d6375fdb149ff96679f6d98816..ab0e3bec0c3c8e5aae338e04083ceff9beeda208 100755 --- a/src/main/webapp/templates/appleFruitMothStationForm.ftl +++ b/src/main/webapp/templates/appleFruitMothStationForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/appleFruitMothStationList.ftl b/src/main/webapp/templates/appleFruitMothStationList.ftl index e86ade492a79a7366d676b3a6d7a80aae52ccb8f..9d25f3472a7e8d843e199e7acaa231566c9b935a 100755 --- a/src/main/webapp/templates/appleFruitMothStationList.ftl +++ b/src/main/webapp/templates/appleFruitMothStationList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. +This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/cropCategoryList.ftl b/src/main/webapp/templates/cropCategoryList.ftl index 12f7c07ecef184d30a4bc445747b17cc380644c7..de516c8fdfbbd144efb7d46c64b9513c1db93199 100755 --- a/src/main/webapp/templates/cropCategoryList.ftl +++ b/src/main/webapp/templates/cropCategoryList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/cropList.ftl b/src/main/webapp/templates/cropList.ftl index 9f45f5219d46c85189c5fca7d40834195cd1ed79..bc9dcfb487d6773f9792ba7a4dbe9d61953609ce 100755 --- a/src/main/webapp/templates/cropList.ftl +++ b/src/main/webapp/templates/cropList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/cropPestForm.ftl b/src/main/webapp/templates/cropPestForm.ftl index 46258b93fac5310ae56a4c9d1a5e08d3165133cb..30c736e101faec7ccaeafa845991281511c43677 100755 --- a/src/main/webapp/templates/cropPestForm.ftl +++ b/src/main/webapp/templates/cropPestForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/error_unknown.ftl b/src/main/webapp/templates/error_unknown.ftl index d53ec30701697063cd81699deb8a4066b515a624..5623b9b8b858cd037302e1dcaa3c93f58731f96a 100755 --- a/src/main/webapp/templates/error_unknown.ftl +++ b/src/main/webapp/templates/error_unknown.ftl @@ -2,29 +2,29 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro navbar_collapse> </#macro> <#macro page_head> - <title>ERROR ${Request["javax.servlet.error.status_code"]}</title> + <title>ERROR ${Request["jakarta.servlet.error.status_code"]}</title> </#macro> <#macro page_contentwrap_start></#macro> <#macro page_contentwrap_end></#macro> <#macro page_contents> - <h1>ERROR ${Request["javax.servlet.error.status_code"]}</h1> + <h1>ERROR ${Request["jakarta.servlet.error.status_code"]}</h1> <p>${message}</p> <p><a href="/">To front page</a></p> </#macro> diff --git a/src/main/webapp/templates/forecastConfigurationForm.ftl b/src/main/webapp/templates/forecastConfigurationForm.ftl index 803f5600cc96fd4fede4fbd35d3b2b0d9494d572..22f2da3bb02e68e8aff8c59715e6787c2edc2885 100755 --- a/src/main/webapp/templates/forecastConfigurationForm.ftl +++ b/src/main/webapp/templates/forecastConfigurationForm.ftl @@ -1,34 +1,239 @@ -<#-- - Copyright (c) 2016 NIBIO <http://www.nibio.no/>. - +<#-- + Copyright (c) 2016 NIBIO <http://www.nibio.no/>. + This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> +<#assign isGridForecastSupported = (user.organizationId.defaultGridWeatherStationDataSource?has_content)> <#macro page_head> - <title>${i18nBundle.viewForecastConfiguration}</title> + <title>${i18nBundle.viewForecastConfiguration}</title> </#macro> <#macro custom_js> - <script src="/js/resourcebundle.js"></script> - <script src="/js/forecastConfigurationForm.js"></script> - <script src="/js/validateForm.js"></script> - <script src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script> - <link href="//code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" /> - <script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script> - <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> - <script type="text/javascript" src="/js/environment.js"></script> - <script type="text/javascript" src="/js/util.js"></script> + <script src="/js/resourcebundle.js"></script> + <script src="/js/forecastConfigurationForm.js"></script> + <script src="/js/validateForm.js"></script> + <script src="//code.jquery.com/ui/1.10.3/jquery-ui.min.js"></script> + <link href="//code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" /> + <link rel="stylesheet" href="/css/3rdparty/leaflet.css" /> + <link rel="stylesheet" href="/css/mapModal.css" /> + <script type="text/javascript" src="/js/3rdparty/modernizr_custom.js"></script> + <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> + <script type="text/javascript" src="/js/environment.js"></script> + <script type="text/javascript" src="/js/util.js"></script> + <script type="text/javascript" src="/js/3rdparty/chosen.jquery.min.js"></script> + <script type="text/javascript"> + $(".chosen-select").chosen(); + </script> + <script type="module"> + import MapModal from '/js/mapModal.js'; + const selectLocationElement = document.querySelector('select[name="locationPointOfInterestId"]'); + const selectWeatherstationElement = document.querySelector('select[name="weatherStationPointOfInterestId"]') != null ? document.querySelector('select[name="weatherStationPointOfInterestId"]') : document.querySelector('select[name="weatherStationPointOfInterestIdDisabled"]'); + //console.info(selectWeatherstationElement); + + window.selectedPoiId = <#if forecastConfiguration.locationPointOfInterestId??>${forecastConfiguration.locationPointOfInterestId.pointOfInterestId!"undefined"}<#else>undefined</#if>; + window.selectedWeatherstationId = <#if forecastConfiguration.weatherStationPointOfInterestId??>${forecastConfiguration.weatherStationPointOfInterestId.pointOfInterestId!"undefined"}<#else>undefined</#if>; + + // Read the list of locations into javascript array, to be able to dynamically manipulate it + window.locationList = [ + <#list locationPointOfInterests as poi> + { + "pointOfInterestId": "${poi.pointOfInterestId}", + "name": "${poi.name?json_string}", + "pointOfInterestTypeId": ${poi.pointOfInterestTypeId}, + "location": <#if poi.longitude?? && poi.latitude??>[${poi.longitude?c}, ${poi.latitude?c}]<#else>null</#if> + }, + </#list> + ]; + + + const createOption = (value, text, isSelected = false) => { + const option = document.createElement('option'); + option.value = value; + option.textContent = text; + if (isSelected) option.selected = true; + return option; + }; + + renderPoiSelect(selectLocationElement, locationList, selectedPoiId); + + // Setting weather station select list state correct on page load + <#if isGridForecastSupported && forecastConfiguration.forecastConfigurationId??> + setUseGridWeatherData(<#if forecastConfiguration.useGridWeatherData>"true"<#else>"false"</#if>) + handleWeatherDatasourceSelected(<#if forecastConfiguration.weatherStationPointOfInterestId?has_content && forecastConfiguration.weatherStationPointOfInterestId.pointOfInterestId?has_content>${forecastConfiguration.weatherStationPointOfInterestId.pointOfInterestId}</#if>); + </#if> + + /** + * @param selectElement the select list to render to + * @param elementList the list of weather stations to list + * @param selectedId the id (optional) to be preselected + * @param coordinateToMatch [lon, lat] coordinate to match. Optional. If set: The closest weather stations are show at top of list, with distance to coordinate. + */ + window.renderWeatherstationSelect = function(selectElement, elementList, selectedId, coordinateToMatch) + { + selectElement.options.length = 0; + + // Add default option + selectElement.appendChild(createOption( + "-1", + "${i18nBundle.pleaseSelect} ${i18nBundle.weatherStationPointOfInterestId?lower_case}", + !selectedId + )); + + // Render all weather stations, order by distance to coordinate + if(coordinateToMatch != null) + { + let stations = []; + elementList.forEach(poi => { + if(poi.pointOfInterestTypeId == POI_TYPE_WEATHERSTATION) + { + poi.distance = calculateDistanceBetweenCoordinates(poi.location[1], poi.location[0], coordinateToMatch[1], coordinateToMatch[0]).toFixed(1); + stations.push(poi); + } + }); + stations.sort(function(a,b){ + return a.distance - b.distance; + }); + stations.forEach(poi => { + selectElement.appendChild(createOption( + poi.pointOfInterestId, + poi.name + (poi.distance > 0.0 ? " (" + poi.distance +" km)" : ""), + selectedId && poi.pointOfInterestId == selectedId + )); + }); + + } + else + { + // Render all weather stations alphabetically + elementList.forEach(poi => { + if(poi.pointOfInterestTypeId == POI_TYPE_WEATHERSTATION) + { + selectElement.appendChild(createOption( + poi.pointOfInterestId, + poi.name, + selectedId && poi.pointOfInterestId == selectedId + )); + } + }); + } + } + + // Populate select list for point of interest -> NOT GENERAL! Default value is specific to location. + function renderPoiSelect(selectElement, elementList, selectedId) { + selectElement.innerHTML = ''; + + // Add default option + selectElement.appendChild(createOption( + "-1", + "${i18nBundle.pleaseSelect} ${i18nBundle.locationPointOfInterestId?lower_case}", + !selectedId + )); + + // Add options from elementList + elementList.forEach(poi => { + selectElement.appendChild(createOption( + poi.pointOfInterestId, + poi.name, + selectedId && poi.pointOfInterestId == selectedId + )); + }); + } + + renderWeatherstationSelect(selectWeatherstationElement, locationList, selectedWeatherstationId, + <#if forecastConfiguration.weatherStationPointOfInterestId??>[${forecastConfiguration.weatherStationPointOfInterestId.longitude?c},${forecastConfiguration.weatherStationPointOfInterestId.latitude?c}]<#else>null</#if> + ); + + window.selectPoi = function(selectElement, selectedId) { + if (selectedId) { + const optionIndex = Array.from(selectElement.options).findIndex(option => option.value == selectedId); + if (optionIndex !== -1) { + selectElement.selectedIndex = optionIndex; + } else { + console.error("No matching option found for poi.id=" + selectedId); + } + } + } + + // Get id of currently selected poi from select element + function getSelectedPoiId(selectElement) { + const value = selectElement.value; + const parsedValue = parseInt(value, 10); + return (!isNaN(parsedValue) && parsedValue > 0) ? parsedValue : undefined; + } + + function callbackOnCloseLocationMap(poiData) { + if(!poiData.pointOfInterestId) { + persistNewLocation(poiData, handleLocationChanged); + } else { + selectPoi(selectLocationElement, poiData.pointOfInterestId); + handleLocationChanged(); + } + + } + + function persistNewLocation(poiData, callback) { + fetch("/rest/poi", { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'Authorization': '${user.userUuid!'NOT LOGGED IN?'}' + }, + body: JSON.stringify(poiData) + }) + .then(response => response.json()) + .then(poi => { + poi.location=[poi.longitude, poi.latitude]; + locationList.push(poi); + renderPoiSelect(selectLocationElement, locationList, poi.pointOfInterestId); + // Assuming that this is not a weather station, since weather stations cannot be created using the + // map, the user must have created a .... MAYBE HANDLED AUTOMATICALLY?? by the change event?? + //console.info("Point of interest successfully persisted", poi); + callback(); + }) + .catch(error => { + console.error("Unable to persist new point of interest", error); + }); + } + + // Make function globally available + window.openLocationMap = () => { + let poiIds = locationList.map(poi => poi.pointOfInterestId); + fetch("/rest/poi/geojson", { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Accept': 'application/json' + }, + body: JSON.stringify(poiIds) + }) + .then(response => response.json()) + .then(geoJson => { + const isPoiMap = true; // Map should operate on pois (not only coordinates) + const allowNewPoints = true; // User should be able to create new pois + const locationMapInstance = new MapModal('location-map', geoJson, '${currentLanguage}', isPoiMap, allowNewPoints, callbackOnCloseLocationMap); + const selectedPoiId = getSelectedPoiId(selectLocationElement); + locationMapInstance.openModal(selectedPoiId, ${user.organizationId.defaultMapCenter.y?c}, ${user.organizationId.defaultMapCenter.x?c}, ${user.organizationId.defaultMapZoom} + 1); + }) + .catch(error => { + console.error('Unable to open map', error); + }); + } + + </script> <script type="text/javascript"> + const POI_TYPE_WEATHERSTATION = 1; $(document).ready(function() { // Make sure that there is a date picker present for HTML5 // date input fields @@ -186,15 +391,129 @@ } } }; + + window.handleWeatherDatasourceSelected = function(weatherStationPointOfInterestId) { + let weatherStationList = document.getElementById("weatherStationPointOfInterestId"); + let listContainer = document.getElementById("weatherstationListContainer"); + weatherStationPointOfInterestIdHiddenField = document.getElementById("weatherStationPointOfInterestIdHidden"); + // Which data source is selected? + let useGridWeatherData; + const radios = document.getElementsByName("useGridWeatherData"); + for(const radio of radios) + { + if(radio.checked) + { + useGridWeatherData = radio.value; + break; + } + } + //console.info("useGridWeatherData=" + useGridWeatherData) + if(useGridWeatherData == "true") + { + // Select weatherStationId -2 + weatherStationList.selectedIndex = 0; + // Disable the weatherstation select list + weatherStationList.disabled=true; + listContainer.style.display="none"; + weatherStationList.name="weatherStationPointOfInterestIdDisabled"; + + // Enable the hidden field + weatherStationPointOfInterestIdHiddenField.disabled=false + weatherStationPointOfInterestIdHiddenField.name="weatherStationPointOfInterestId"; + } + else if(useGridWeatherData == "false") + { + // Select weatherStationId -1 OR the optionally provided weatherStationPointOfInterestId + if(weatherStationPointOfInterestId == undefined || weatherStationPointOfInterestId == null) + { + weatherStationList.selectedIndex = 1; + } + else + { + for(let i=0;i<weatherStationList.options.length;i++) + { + weatherStationList.options[i].selected = parseInt(weatherStationList.options[i].value) == weatherStationPointOfInterestId; + } + } + // Enable the weather station select list + weatherStationList.disabled=false; + listContainer.style.display="block"; + + weatherStationList.name="weatherStationPointOfInterestId"; + // Disable the hidden field + weatherStationPointOfInterestIdHiddenField.disabled=true + weatherStationPointOfInterestIdHiddenField.name="weatherStationPointOfInterestIdDisabled"; + } + }; + + window.setUseGridWeatherData = function(useGridWeatherData) + { + //console.info("setuseGridWeatherData, input value=" + useGridWeatherData); + const radios = document.getElementsByName("useGridWeatherData"); + for(const radio of radios) + { + //console.info("radio value=" + radio.value + ", so the radio should " + (radio.value == useGridWeatherData ? "": "NOT") + " be checked" ); + radio.checked = radio.value == useGridWeatherData; + } + } + + + + window.handleLocationChanged = function(){ + let weatherstationSelect = document.getElementById("weatherStationPointOfInterestId"); + let weatherDatasourceFieldset = document.getElementById("weatherDatasourceFieldset"); + // Which location has been selected? + let selectedPoiId = document.getElementById("locationPointOfInterestId").options[document.getElementById("locationPointOfInterestId").selectedIndex].value; + if(selectedPoiId <= 0) + { + if(weatherDatasourceFieldset != null) weatherDatasourceFieldset.disabled = true; + weatherstationSelect.selectedIndex = 0; + return; + } + // Enable the weather datasource fieldset + if(weatherDatasourceFieldset != null) weatherDatasourceFieldset.disabled = false; + + let selectedLocation = undefined; + for(let i=0; i<locationList.length;i++) + { + if(locationList[i].pointOfInterestId == selectedPoiId) + { + selectedLocation = locationList[i]; + } + } + + if(selectedLocation.pointOfInterestTypeId == POI_TYPE_WEATHERSTATION) + { + renderWeatherstationSelect(weatherstationSelect,locationList, selectedLocation.pointOfInterestId, selectedLocation.location); + } + else + { + renderWeatherstationSelect(weatherstationSelect,locationList, null, selectedLocation.location); + weatherstationSelect.selectedIndex = 0; + } + + <#if isGridForecastSupported> + + setUseGridWeatherData(selectedLocation.pointOfInterestTypeId == POI_TYPE_WEATHERSTATION ? "false" : "true"); + handleWeatherDatasourceSelected(selectedLocation.pointOfInterestTypeId == POI_TYPE_WEATHERSTATION ? selectedLocation.pointOfInterestId: undefined); + + </#if> + } </script> </#macro> +<#macro custom_css> + <link href="/css/3rdparty/chosen.min.css" rel="stylesheet" /> +</#macro> <#macro page_contents> <div class="singleBlockContainer"> <p><a href="/forecastConfiguration" class="btn btn-default back" role="button">${i18nBundle.back}</a></p> - <h1>${i18nBundle.viewForecastConfiguration}</h1> - <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>> - <#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if> + <h1>${i18nBundle.viewForecastConfiguration}</h1> + <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>> + <#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if> </div> + <#if multipleNew> + <div class="alert alert-warning">${i18nBundle.multipleNewWarningMsg}</div> + </#if> <#if messageKey?has_content> <div class="alert alert-success">${i18nBundle(messageKey)}</div> </#if> @@ -246,6 +565,7 @@ <#if ! user.isSuperUser() && ! user.isOrganizationAdmin()> readonly="readonly" disabled="disabled"</#if>/> </label> ${i18nBundle.isPrivate} + <span class="help-block" id="${formId}_isPrivate_validation"></span> </div> </div> <div class="form-group"> @@ -265,29 +585,57 @@ <#if !multipleNew?has_content || !multipleNew> <div class="form-group"> <label for="locationPointOfInterestId">${i18nBundle.locationPointOfInterestId}</label> - <select class="form-control" name="locationPointOfInterestId" onblur="validateField(this);"> - <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.locationPointOfInterestId?lower_case}</option> - <#list locationPointOfInterests?sort_by("name") as poi> - <option value="${poi.pointOfInterestId}"<#if forecastConfiguration.locationPointOfInterestId?has_content && poi.pointOfInterestId == forecastConfiguration.locationPointOfInterestId.pointOfInterestId> selected="selected"</#if>>${poi.name}</option> - </#list> - </select> + <div class="select-container" style="flex: 1; display: flex; align-items: center;"> + <select class="form-control" id="locationPointOfInterestId" name="locationPointOfInterestId" onchange="handleLocationChanged();" onblur="validateField(this);" style="width: calc(100% - 30px);"> + </select> + <button type="button" class="btn btn-primary" onclick="openLocationMap()"><i class="fa fa-map-marker fa-lg"></i> Velg i kart</button> + + <div id="location-map" class="map-modal"></div> + </div> <span class="help-block" id="${formId}_locationPointOfInterestId_validation"></span> </div> - <div class="form-group"> - <label for="weatherStationPointOfInterestId">${i18nBundle.weatherStationPointOfInterestId}</label> - <select class="form-control" name="weatherStationPointOfInterestId" onblur="validateField(this);"> - <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.weatherStationPointOfInterestId?lower_case}</option> - <#list weatherStationPointOfInterests?sort_by("name") as poi> - <option value="${poi.pointOfInterestId}"<#if forecastConfiguration.weatherStationPointOfInterestId?has_content && poi.pointOfInterestId == forecastConfiguration.weatherStationPointOfInterestId.pointOfInterestId> selected="selected"</#if>>${poi.name}</option> - </#list> - </select> - <span class="help-block" id="${formId}_weatherStationPointOfInterestId_validation"></span> - </div> + <#if isGridForecastSupported> + <div class="alert alert-info" role="alert">Velg sted ovenfor først, og velg deretter værdatakilde. Du kan enten velge en av de tilgjengelige værstasjonene (sortert etter avstand til stedet), + eller at ditt valgte steds plassering brukes til å hente værdata fra en ekstern tjeneste. Hvis ditt sted ligger nær + en av værstasjonene, gir det som oftest den beste kvaliteten på værdata.</div> + <#else> + <div class="alert alert-info" role="alert">Velg sted ovenfor først, og velg deretter værstasjon. Hvis stedet du har valgt ikke er en værstasjon, vil værstasjonslista sorteres etter avstand til ditt sted.</div> + </#if> + <#if isGridForecastSupported> + <fieldset id="weatherDatasourceFieldset" <#if !forecastConfiguration.weatherStationPointOfInterestId?has_content>disabled</#if>> + <legend style="margin-bottom: 0px;">${i18nBundle.weatherDatasource}</legend> + + <input type="hidden" id="weatherStationPointOfInterestIdHidden" name="weatherStationPointOfInterestIdDisabled" value="-2" disabled="disabled"/> + <div class="form-group"> + <div class="radio"> + <label> + <input type="radio" id="useGridWeatherData" value="true" name="useGridWeatherData"<#if forecastConfiguration.useGridWeatherData?has_content && forecastConfiguration.useGridWeatherData == true> checked="checked"</#if> onclick="handleWeatherDatasourceSelected();"/> + </label> + ${i18nBundle.useGridWeatherData} + </div> + </#if> + <#if isGridForecastSupported><div class="radio"> + <label> + <input type="radio" name="useGridWeatherData" id="useWeatherstationRadio" value="false" onclick="handleWeatherDatasourceSelected();"> + ${i18nBundle.useWeatherStation} + </label> + </#if> + <div class="form-group" id="weatherstationListContainer" style="display: <#if isGridForecastSupported>none<#else>block</#if>;"> + <#if !isGridForecastSupported><label for="weatherStationPointOfInterestId">${i18nBundle.weatherStationPointOfInterestId}</label></#if> + <select class="form-control" id="weatherStationPointOfInterestId" name="weatherStationPointOfInterestId" onblur="if(document.getElementById('useWeatherstationRadio') == null || document.getElementById('useWeatherstationRadio').checked) {validateField(this);}"> + + </select> + <span class="help-block" id="${formId}_weatherStationPointOfInterestId_validation"></span> + </div> + <#if isGridForecastSupported> + </div> + </fieldset> + </#if> <#else> <input type="hidden" name="multipleNew" value="true"/> <div class="form-group"> <label for="weatherStationPointOfInterestIds">${i18nBundle.weatherStationPointOfInterestIds}</label> - <select class="form-control" name="weatherStationPointOfInterestIds" onblur="validateField(this);" multiple="multiple" size="5"> + <select class="form-control chosen-select" name="weatherStationPointOfInterestIds" onblur="validateField(this);" multiple="multiple"> <#list weatherStationPointOfInterests?sort_by("name") as poi> <option value="${poi.pointOfInterestId}">${poi.name}</option> </#list> diff --git a/src/main/webapp/templates/forecastConfigurationList.ftl b/src/main/webapp/templates/forecastConfigurationList.ftl index 46a9a094177ff09a8e53026d715ac67eca039c95..804aa699a88ac3bf421094c61f07a20cfefe9be6 100755 --- a/src/main/webapp/templates/forecastConfigurationList.ftl +++ b/src/main/webapp/templates/forecastConfigurationList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2017 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.forecasts}</title> @@ -68,7 +68,7 @@ </form> </div> </div> - <button type="button" class="btn btn-default" onclick="window.location.href='/forecastConfiguration?action=viewForecastConfiguration&forecastConfigurationId=-1&multipleNew=true'">${i18nBundle.addMultipleNew}</button> + <button type="button" class="btn btn-default" onclick="window.location.href='/forecastConfiguration?action=viewForecastConfiguration&forecastConfigurationId=-1&multipleNew=true'">${i18nBundle.addNewForMultipleWeatherStations}</button> </#if> <h2>${i18nBundle.privateForecasts}</h2> <div class="table-responsive"> diff --git a/src/main/webapp/templates/index.ftl b/src/main/webapp/templates/index.ftl index 1915ff655f1de983ad4ac895b914757d6441ee8e..b7d7569e1e53917d452eb4df903246f578ca995f 100755 --- a/src/main/webapp/templates/index.ftl +++ b/src/main/webapp/templates/index.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.greeting} VIPSLogic</title> diff --git a/src/main/webapp/templates/login.ftl b/src/main/webapp/templates/login.ftl index e0a5e522c0483945bd4bed81dbde6167f169fdd4..535c31508cf42647be6d509677ab2f58ad4e6b20 100755 --- a/src/main/webapp/templates/login.ftl +++ b/src/main/webapp/templates/login.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.pleaselogin}</title> @@ -47,7 +47,8 @@ <button class="btn btn-lg btn-primary btn-block" type="submit">${i18nBundle.login}</button> <input type="checkbox" name="rememberUser"<#if checkRemember?has_content && checkRemember> checked="checked"</#if>/> ${i18nBundle.rememberLogin}<br/> <a href="/user?action=registerNewUserForm&userAuthenticationTypeId=1">${i18nBundle.registerNewUser}</a><br/> - <a href="/user?action=resetPasswordRequestForm">${i18nBundle.forgottenPassword}</a> + <a href="/user?action=resetPasswordRequestForm">${i18nBundle.forgottenPassword}</a><br/> + <a href="/public/documentation/${i18nBundle.privacyStatementFileName}" target="new">${i18nBundle.privacyStatement}</a> </form> </div> </#macro> diff --git a/src/main/webapp/templates/master.ftl b/src/main/webapp/templates/master.ftl index 50aa9196cf4050b1bb997f3fb58944e785e37c70..712e6aafac85f7a6ec85871ea3f78bac317a28ec 100755 --- a/src/main/webapp/templates/master.ftl +++ b/src/main/webapp/templates/master.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --> <#macro page_head> <title>master title</title> @@ -59,6 +59,9 @@ <#else> <li><a href="/user?action=viewUser&userId=${user.userId}">${i18nBundle.myAccount}</a></li> </#if> + <#if user.isOrganizationAdmin() || user.isSuperUser()> + <li><a href="/weatherstationdatasource">${i18nBundle.weatherStationDataSources}</a></li> + </#if> <li><a href="/poi">${i18nBundle.pois}</a></li> <#if user.isOrganizationAdmin() || user.isSuperUser() || user.isMessageAuthor()> <li><a href="/message">${i18nBundle.messages}</a></li> diff --git a/src/main/webapp/templates/master_errorpages.ftl b/src/main/webapp/templates/master_errorpages.ftl index a349760063461a137417d84bc229cbc755ea32d9..034bbc1e7adbbbceec380248fe337545ef129c77 100755 --- a/src/main/webapp/templates/master_errorpages.ftl +++ b/src/main/webapp/templates/master_errorpages.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#macro page_head> <title>master title</title> </#macro> diff --git a/src/main/webapp/templates/messageForm.ftl b/src/main/webapp/templates/messageForm.ftl index f76c36a5b2c453c922b40851249e5093c9ddf275..2c5abca6ecc43f884fef01813c154577b49e1949 100755 --- a/src/main/webapp/templates/messageForm.ftl +++ b/src/main/webapp/templates/messageForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#if message.getLocalMessage(messageLocale)?has_content> diff --git a/src/main/webapp/templates/messageList.ftl b/src/main/webapp/templates/messageList.ftl index e7daaabba455770667db94f410d59c3aa8c7555d..d8e3f59bc2d476f3ac489417cf7cf149bf065012 100755 --- a/src/main/webapp/templates/messageList.ftl +++ b/src/main/webapp/templates/messageList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.messages}</title> diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteCandidateList.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteCandidateList.ftl index de62e7c0af748894e44e6eb013511c33ae392a7c..009dac4437401b45cf1b8bc089aed44214fc0bbf 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteCandidateList.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteCandidateList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2020 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteDeleteForm.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteDeleteForm.ftl index 84b62f57bf41c49a0b1984385c01b3e1affb73ae..0039106acdee56d62c768b1edb554ac9222ce744 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteDeleteForm.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteDeleteForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2020 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl index cc9561a3c8d8cb186364c746f5896433b5240eb6..cfddb54f5b86ba46f4dd1538d3694e2f823aeab0 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2020 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#macro page_head> @@ -21,7 +21,7 @@ </#macro> <#macro custom_js> <script type="text/javascript" src="/js/constants.js"></script> - <script type="text/javascript" src="/js/3rdparty/ol.js"></script> + <script type="text/javascript" src="/js/3rdparty/ol_6_5_0.js"></script> <script type="text/javascript" src="/js/modules/barkbeetle/seasonTrapsiteFormMap.js"></script> <script type="text/javascript" src="/js/resourcebundle.js"></script> <script src="/js/validateForm.js"></script> @@ -31,6 +31,7 @@ <script type="text/javascript" src="/js/3rdparty/moment.min.js"></script> <script type="text/javascript"> var theForm = document.getElementById("${formId}"); + const municipalityPolygonServiceUrl = "https://proxy03.nibio.no/municipality_cache_ws/kommuneListe/N5/4326"; $(document).ready(function() { // Make sure that there is a date picker present for HTML5 // date input fields @@ -73,7 +74,7 @@ }); // Get County and municipality - fetch("/corsproxy/https://proxy1.nibio.no/municipality_cache_ws/kommuneListe/N2000/4326/?lon=" + lon + "&lat=" + lat) + fetch("/corsproxy/" + municipalityPolygonServiceUrl + "?lon=" + lon + "&lat=" + lat) .then(response => response.json()) .then(municInfo =>{ if(municInfo.length == 0) @@ -97,7 +98,7 @@ .catch( error => console.info(error)); // Get County and municipality from before 2018 - fetch("/corsproxy/https://proxy1.nibio.no/municipality_cache_ws/kommuneListe/N2000/4326/2017?lon=" + lon + "&lat=" + lat) + fetch("/corsproxy//" + municipalityPolygonServiceUrl + "/2017?lon=" + lon + "&lat=" + lat) .then(response => response.json()) .then(municInfo =>{ if(municInfo.length == 0) @@ -167,7 +168,7 @@ </#macro> <#macro custom_css> <link href="//code.jquery.com/ui/1.10.3/themes/redmond/jquery-ui.css" rel="stylesheet" /> - <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css"/ > + <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol_6_5_0.css"/ > <style type="text/css"> #seasonTrapsiteFormMap { height: 600px; @@ -271,7 +272,7 @@ </div> <div class="form-group"> <label for="ownerName">Tlf til eier av lokalitet</label> - <input type="text" class="form-control" name="ownerPhone" placeholder="Tlf til eier av lokalitet" value="${(seasonTrapsite.ownerPhone)!""}" onblur="validateField(this);"/> + <input type="text" class="form-control" maxlength="31" name="ownerPhone" placeholder="Tlf til eier av lokalitet" value="${(seasonTrapsite.ownerPhone)!""}" onblur="validateField(this);"/> <span class="help-block" id="${formId}_ownerPhone_validation"></span> </div> <#if userIsAdmin || userIsCountyAdmin> diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl index e43b0f8dc833ee3ed3c0c044205eae2d9b311255..acf33707ad4259da88669e7152142b37a2e0a788 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2020 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#macro page_head> @@ -85,6 +85,15 @@ <div class="col-md-4"> <div id="seasonTrapsiteListMap" class="map" style="border: 1px solid black; background-color: white;"> <div id="popover"></div> + <div id="warningLegend" class="mapBoxPlacement_4"> + <ul> + <li class="warning_5"><span>> 15 000 biller/felle</span></li> + <li class="warning_4"><span>10 000 - 15 000 biller/felle</span></li> + <li class="warning_3"><span>5 000 - 10 000 biller/felle</span></li> + <li class="warning_2"><span>0 - 5 000 biller/felle</span></li> + <li class="warning_1"><span>Ikke registrert måling</span></li> + </ul> + </div> </div> </div> </div> @@ -148,7 +157,7 @@ </#macro> <#macro custom_js> <script type="text/javascript" src="/js/constants.js"></script> - <script type="text/javascript" src="/js/3rdparty/ol.js"></script> + <script type="text/javascript" src="/js/3rdparty/ol_6_5_0.js"></script> <script type="text/javascript" src="/js/modules/barkbeetle/seasonTrapsiteListMap.js"></script> <script type="text/javascript"> $(document).ready(function() { @@ -177,7 +186,7 @@ function filter(searchTxt){ </script> </#macro> <#macro custom_css> - <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css"/ > + <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol_6_5_0.css"/ > <style type="text/css"> td.status_1 { background-color: #ffe066 !important; @@ -196,6 +205,40 @@ function filter(searchTxt){ div.popover { min-width: 250px !important; } + + #warningLegend { + position: absolute; + left: 10px; + top: 70px; + } + #warningLegend ul li span { + position: relative; + top: -7px; + } + #warningLegend ul li.warning_2 + { + list-style-image: url("/images/modules/barkbeetle/station_icon_status_2.png"); + } + #warningLegend ul li.warning_3 + { + list-style-image: url("/images/modules/barkbeetle/station_icon_status_3.png"); + } + #warningLegend ul li.warning_4 + { + list-style-image: url("/images/modules/barkbeetle/station_icon_status_4.png"); + } + #warningLegend ul li.warning_5 + { + list-style-image: url("/images/modules/barkbeetle/station_icon_status_5.png"); + } + #warningLegend ul li.warning_0 + { + list-style-image: url("/images/modules/barkbeetle/station_icon_status_0.png"); + } + #warningLegend ul li.warning_1 + { + list-style-image: url("/images/modules/barkbeetle/station_icon_status_1.png"); + } </style> </#macro> <@page_html/> \ No newline at end of file diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteMaintenanceList.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteMaintenanceList.ftl index ddd82fd30f457b28e8d49a2112eb86e066f268f0..1f12591ac8aae3e827be2acb3dab54e68a5ab186 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteMaintenanceList.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsiteMaintenanceList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2020 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsitesStatus.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsitesStatus.ftl index d18027a5dcd312e05be5a0babf67db730c2d1551..23e1e90332c852b397d04ad3e8b0ecaf7615cbd8 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsitesStatus.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleSeasonTrapsitesStatus.ftl @@ -2,18 +2,18 @@ Copyright (c) 2021 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleTimeseriesCalculation.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleTimeseriesCalculation.ftl index b79d00424cd401f6d0c4b906a42101fd25c0046f..43cda9e962aaabfe321a558d93ca615ed074b246 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleTimeseriesCalculation.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleTimeseriesCalculation.ftl @@ -2,18 +2,18 @@ Copyright (c) 2020 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl b/src/main/webapp/templates/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl index a84f63a9af15a4d2f2555a234c41945abb97e3d2..768335288c5ab7b83d2177bf22d9cdbcd5a052b2 100644 --- a/src/main/webapp/templates/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl +++ b/src/main/webapp/templates/modules/barkbeetle/barkbeetleTrapsiteRegistrationForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2022 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "../../master.ftl"> <#assign siteName= seasonTrapsite.countyName + "/" + seasonTrapsite.municipalityName + "/" + seasonTrapsite.ownerName> @@ -127,7 +127,10 @@ </tr> <#if seasonTrapsite.season gt 2021> <tr> - <td>Er det observert angrep av stor granbarkbille på stående gran i nærområdet/kommunen? Beskriv hva som er observert (omfang, sted m.m.; <a href="/images/modules/barkbeetle/${FILENAME_KJENN_IGJEN_ANGREP}" target="new">instruksjon</a>)</td> + <td>Er det observert angrep av stor granbarkbille på stående gran i nærområdet/kommunen? + Beskriv omfang og symptomer. Symptomer tidlig i sesong: Boremel eller fjorårets drepte trær som har mistet litt bark og har grå kroner. + Symptomer sent i sesong: Årets drepte trær, med røde kroner. Det er også mulig å rapportere skader på + <a href="https://skogskader.nibio.no/skogskader2/meld-skade" target="new">skogskader.nibio.no</a></td> <td colspan="8"> <textarea class="form-control" name="${reg.trapsiteRegistrationPK.week}_observedAttacksDescription"<#if tooEarly> disabled="disabled"</#if>>${reg.observedAttacksDescription!""}</textarea> </td> diff --git a/src/main/webapp/templates/notificationSubscriptionForm.ftl b/src/main/webapp/templates/notificationSubscriptionForm.ftl index edf0b8cbdffc85f97787da19cab586da797830b3..ed10641b5454980d882e89c8e77c970f0ace6777 100755 --- a/src/main/webapp/templates/notificationSubscriptionForm.ftl +++ b/src/main/webapp/templates/notificationSubscriptionForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.user}</title> diff --git a/src/main/webapp/templates/observationForm.ftl b/src/main/webapp/templates/observationForm.ftl index 24bd4a96734a5a81fba65880447344c36c05f3c8..ed54a05a75721de21b52149fca468f43adb1bba6 100755 --- a/src/main/webapp/templates/observationForm.ftl +++ b/src/main/webapp/templates/observationForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2017 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title><#if observation.observationId?has_content>${i18nBundle.editObservation}<#else>${i18nBundle.newObservation}</#if></title> @@ -42,7 +42,7 @@ <script type="text/javascript" src="/js/poiFormMap.js"></script> <script type="text/javascript"> var organizationId = ${user.organizationId.organizationId}; - var selectedCropId = <#if observation.cropOrganism?has_content>${observation.cropOrganism.organismId}<#else>null</#if>; + var selectedCropId = <#if observation.cropOrganism?has_content>${observation.cropOrganism.organismId?c}<#else>null</#if>; $(document).ready(function() { @@ -230,38 +230,41 @@ var allPois = []; - /** - * Fetches locations, farms, fields and weather stations, renders the list - */ - function refreshLocationPointOfInterests(pointOfInterestId) + /** + * Fetches locations, farms, fields, traps and weather stations, renders the list + */ + function refreshLocationPointOfInterests(selectedPointOfInterestId) { - var poiTypes = ["${i18nBundle.genericPlaces}","${i18nBundle.weatherStations}","${i18nBundle.farms}","${i18nBundle.fields}"]; - $.getJSON("/rest/poi/user", function( json ) { - allPois = json; - var theList = document.getElementById("locationPointOfInterestId"); - theList.options.length = 1; - // Locations first, weather stations next - for(var h=0;h<poiTypes.length;h++) - { - var option = new Option("-- " + poiTypes[h] + " --","-1"); - theList.options[theList.options.length] = option; - for(var i=0;i< allPois.length;i++) - { - var poi = allPois[i]; - if(poi.pointOfInterestTypeId == h) - { - var option = new Option(poi.name, poi.pointOfInterestId); - if(poi.pointOfInterestId == pointOfInterestId) - { - option.selected=true; - } - theList.options[theList.options.length] = option; - } - } - } - showCorrectMap(); + const poiTypes = { + 0: "${i18nBundle.genericPlaces}", + 1: "${i18nBundle.weatherStations}", + 2: "${i18nBundle.farms}", + 3: "${i18nBundle.fields}", + 5: "${i18nBundle.traps}" + }; + $.getJSON("/rest/poi/user", function(json) { + const allPois = json; + const poiListElement = document.getElementById("locationPointOfInterestId"); + poiListElement.options.length = 1; + // Iterate through each point of interest type + for (const [typeId, typeName] of Object.entries(poiTypes)) { + poiListElement.options[poiListElement.options.length] = new Option("-- " + typeName + " --", "-1"); + + // Iterate through all POIs and add them to the list if they match the type + for (let i = 0; i < allPois.length; i++) { + const poi = allPois[i]; + + if (poi.pointOfInterestTypeId == typeId) { + const poiOption = new Option(poi.name, poi.pointOfInterestId); + if (poi.pointOfInterestId === selectedPointOfInterestId) { + poiOption.selected = true; } - ); + poiListElement.options[poiListElement.options.length] = poiOption; + } + } + } + showCorrectMap(); + }); } @@ -447,8 +450,9 @@ </#if> var cropList = [ <#if ! observation.observationId?has_content || user.isSuperUser() || user.isOrganizationAdmin()> + {organismId: -10, displayName: "${i18nBundle.missingInDatabase}", hierarchyCategoryId: -1}, <#list allCrops as cropOrganism> - {organismId: ${cropOrganism.organismId}, displayName: "${cropOrganism.getLocalName(currentLocale.language)!""} (${cropOrganism.latinName!""}) ${hierarchyCategories.getName(cropOrganism.hierarchyCategoryId)?upper_case}", hierarchyCategoryId: ${cropOrganism.hierarchyCategoryId}}<#sep>, + {organismId: ${cropOrganism.organismId?c}, displayName: "${cropOrganism.getLocalName(currentLocale.language)!""} (${cropOrganism.latinName!""}) ${hierarchyCategories.getName(cropOrganism.hierarchyCategoryId)?upper_case}", hierarchyCategoryId: ${cropOrganism.hierarchyCategoryId!"-1"}}<#sep>, </#list> <#else> <#list allCrops as cropOrganism> @@ -514,7 +518,7 @@ <input type="hidden" name="observationData" value=""/> <input type="hidden" name="observationId" value="${observation.observationId!"-1"}"/> <!--button type="button" onclick="var theForm=document.getElementById('observationForm');theForm['geoInfo'].value=getFeatures();try{mw.save();theForm['observationData'].value=JSON.stringify(mw.toInspect);return validateForm(theForm) && validateGIS(theForm);}catch(e){console.log(e.message);console.log(e);return false;}">Test</button--> - <#if observation.user?has_content> + <#if observation.user?has_content> <div class="form-group"> <label>${i18nBundle.observer}: ${observation.user.firstName} ${observation.user.lastName}</label> </div> diff --git a/src/main/webapp/templates/observationList.ftl b/src/main/webapp/templates/observationList.ftl index 10f856ffd2ab037069a37a22fe3f9f00dbcdcd8d..90db0a5a6acc884a9626c53ad5ff2f3722113ce6 100755 --- a/src/main/webapp/templates/observationList.ftl +++ b/src/main/webapp/templates/observationList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#setting time_zone=user.organizationId.defaultTimeZone!"UTC"> <#macro page_head> diff --git a/src/main/webapp/templates/observationMap.ftl b/src/main/webapp/templates/observationMap.ftl index 4adc17aa76a196a5c2ca470c2d7d841a49e0b5d6..08edca4b6135dc27c62c9ed50af7fe06c293da04 100755 --- a/src/main/webapp/templates/observationMap.ftl +++ b/src/main/webapp/templates/observationMap.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic 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 - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#setting time_zone=user.organizationId.defaultTimeZone!"UTC"> <#macro page_head> diff --git a/src/main/webapp/templates/organism.ftl b/src/main/webapp/templates/organism.ftl index c1fb8fbc4ee4fdc8c2afbd534272e766440b86bd..07a2dbe744a302a56f244b95ae93350317e9adbe 100755 --- a/src/main/webapp/templates/organism.ftl +++ b/src/main/webapp/templates/organism.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.organisms}</title> diff --git a/src/main/webapp/templates/organismDetails.ftl b/src/main/webapp/templates/organismDetails.ftl index 854f61dcd1beac4b9f424638a1b590a8c46af837..091f4d6797c44ac62bcc7846eff0b7d39662a45b 100755 --- a/src/main/webapp/templates/organismDetails.ftl +++ b/src/main/webapp/templates/organismDetails.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${organism.getLocalName(currentLocale.language)!""}<#if organism.tradeName?has_content> / ${organism.tradeName}</#if> (${organism.latinName!""})</title> diff --git a/src/main/webapp/templates/organismForm.ftl b/src/main/webapp/templates/organismForm.ftl index 60fb939962e4b75752c7c3fc458c5755af664212..af37b76e48ace8f8cb552165d53450085b3af569 100755 --- a/src/main/webapp/templates/organismForm.ftl +++ b/src/main/webapp/templates/organismForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/organismList.ftl b/src/main/webapp/templates/organismList.ftl index 03489d91d7e6ced1b32d5feb3d0cf934ddcdd4c3..73957b29fc765f42fb1e38a5f443f822b9b7952e 100755 --- a/src/main/webapp/templates/organismList.ftl +++ b/src/main/webapp/templates/organismList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/organizationForm.ftl b/src/main/webapp/templates/organizationForm.ftl index 78fa94ded9ba695ffc662de0b22d216c0f059054..cb907e210e7a0fffae2d438bd39fc540d2b57633 100644 --- a/src/main/webapp/templates/organizationForm.ftl +++ b/src/main/webapp/templates/organizationForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title><#if organization.organizationId?has_content>${i18nBundle.editOrganization} ${organization.organizationName}<#else>${i18nBundle.newOrganization}</#if></title> @@ -119,7 +119,7 @@ <input type="text" class="form-control" name="vipswebUrl" placeholder="${i18nBundle.vipswebUrl}" value="${(organization.vipswebUrl)!""}" onblur="validateField(this); "/> <span class="help-block" id="${formId}_vipswebUrl_validation"></span> </div> - <div class="form-group"> + <div class="form-group"> <label for="archiveUserId">${i18nBundle.archiveUserId}</label> <select class="form-control" name="archiveUserId" onblur="validateField(this);"> <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.archiveUserId?lower_case} @@ -131,21 +131,33 @@ </select> <span class="help-block" id="${formId}_archiveUserId_validation"></span> </div> - <div class="form-group"> + <div class="form-group"> <label for="defaultVipsCoreUserId">${i18nBundle.defaultVipsCoreUserId}</label> <input type="number" class="form-control" name="defaultVipsCoreUserId" placeholder="${i18nBundle.defaultVipsCoreUserId}" value="${(organization.defaultVipsCoreUserId)!""}" onblur="validateField(this); "/> <span class="help-block" id="${formId}_defaultVipsCoreUserId_validation"></span> </div> - <div class="form-group"> + <div class="form-group"> <label for="defaultMapZoom">${i18nBundle.defaultMapZoom}</label> <input type="number" class="form-control" name="defaultMapZoom" placeholder="${i18nBundle.defaultMapZoom}" value="${(organization.defaultMapZoom)!""}" onblur="validateField(this); "/> <span class="help-block" id="${formId}_defaultMapZoom_validation"></span> </div> - <div class="form-group"> + <div class="form-group"> <label for="defaultMapCenter">${i18nBundle.defaultMapCenter} (WGS84 longitude,latitude)</label> <input type="text" class="form-control" name="defaultMapCenter" placeholder="${i18nBundle.defaultMapCenter}" value="${(defaultMapCenterLon?c)!""},${(defaultMapCenterLat?c)!""}" onblur="validateField(this); "/> <span class="help-block" id="${formId}_defaultMapCenter_validation"></span> </div> + <div class="form-group"> + <label for="defaultGridWeatherStationDataSourceId">${i18nBundle.defaultGridWeatherStationDataSource}</label> + <select class="form-control" name="defaultGridWeatherStationDataSourceId" onblur="validateField(this);"> + <option value="-1">${i18nBundle.pleaseSelect} ${i18nBundle.defaultGridWeatherStationDataSource?lower_case} + <#list gridWeatherDataSources as dSource> + <option value="${dSource.weatherStationDataSourceId}" + <#if organization.defaultGridWeatherStationDataSource?has_content && organization.defaultGridWeatherStationDataSource.weatherStationDataSourceId == dSource.weatherStationDataSourceId>selected="selected"</#if> + >${dSource.name}</option> + </#list> + </select> + <span class="help-block" id="${formId}_defaultGridWeatherStationDataSourceId_validation"></span> + </div> <button type="submit" class="btn btn-default">${i18nBundle.submit}</button> <#if organization.organizationId?has_content> <button type="button" class="btn btn-danger" onclick="if(confirm('${i18nBundle.confirmDelete}')){alert('Sorry, but this functionality has not yet been implemented');}">${i18nBundle.delete}</button> diff --git a/src/main/webapp/templates/organizationGroupForm.ftl b/src/main/webapp/templates/organizationGroupForm.ftl index 67636aad9e32c44023525cbb2e2951773bf3bc63..35e34e8628310bf4a0c35a4f223ddc717ed42b78 100755 --- a/src/main/webapp/templates/organizationGroupForm.ftl +++ b/src/main/webapp/templates/organizationGroupForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.edit} ${organizationGroup.groupName!i18nBundle.newGroup?lower_case}</title> diff --git a/src/main/webapp/templates/organizationGroupList.ftl b/src/main/webapp/templates/organizationGroupList.ftl index 29e65a01b5f71cd94c8643d6568f8e919759cb4c..260c558ce6c925f2e1ada5c4f49e51a414cc582f 100755 --- a/src/main/webapp/templates/organizationGroupList.ftl +++ b/src/main/webapp/templates/organizationGroupList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.organizationGroupList}</title> diff --git a/src/main/webapp/templates/organizationList.ftl b/src/main/webapp/templates/organizationList.ftl index 917b85a675008e22e8fd5475c52e2ce4fe59bf09..5c3da5149173c7df4b02b6bda0afa033d8dcce99 100644 --- a/src/main/webapp/templates/organizationList.ftl +++ b/src/main/webapp/templates/organizationList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2019 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.organizations}</title> diff --git a/src/main/webapp/templates/pestList.ftl b/src/main/webapp/templates/pestList.ftl index 9b860efe6f9e1e534fb0a0d45ec5b8b8e7aee411..cbec07b41646a17d35467d95f932b9729a264232 100755 --- a/src/main/webapp/templates/pestList.ftl +++ b/src/main/webapp/templates/pestList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/poi.ftl b/src/main/webapp/templates/poi.ftl index 960dd8238c1da3a9eb967692ebd1e195e24444b9..c041605b102c0ee161932051ec00d9322934c0d2 100755 --- a/src/main/webapp/templates/poi.ftl +++ b/src/main/webapp/templates/poi.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>POI</title> diff --git a/src/main/webapp/templates/poiDeletePreview.ftl b/src/main/webapp/templates/poiDeletePreview.ftl index bccee4564c1d02ca082c914c6203c68f1855483c..07cf886cc946dc8e8ab7a511d1cb7c41f51f22ca 100644 --- a/src/main/webapp/templates/poiDeletePreview.ftl +++ b/src/main/webapp/templates/poiDeletePreview.ftl @@ -2,18 +2,18 @@ Copyright (c) 2015 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.deletePoi}</title> diff --git a/src/main/webapp/templates/poiForm.ftl b/src/main/webapp/templates/poiForm.ftl index 64127ddab64ad8ed755c0f3c1d833cc36f2816b1..7e7287849cd1f53bb998f4eacb0da65abe7f648c 100755 --- a/src/main/webapp/templates/poiForm.ftl +++ b/src/main/webapp/templates/poiForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title><#if poi.pointOfInterestId?has_content>${i18nBundle.editPoi}<#else>${i18nBundle.newPoi}</#if></title> @@ -81,6 +81,14 @@ <input type="text" class="form-control" name="name" placeholder="${i18nBundle.name}" value="${(poi.name)!""}" onblur="validateField(this); checkPoiNameAvailability(this);"/> <span class="help-block" id="${formId}_name_validation"></span> </div> + <div class="form-group"> + <div class="checkbox"> + <label> + <input type="checkbox" name="isPrivate"<#if poi.isPrivate?has_content && poi.isPrivate == true> checked="checked"<#else></#if>/> + </label> + ${i18nBundle.isPrivate} + </div> + </div> <div class="form-group"> <label for="pointOfInterestTypeId">${i18nBundle.pointOfInterestType}</label> <select class="form-control" name="pointOfInterestTypeId" onblur="validateField(this);"> diff --git a/src/main/webapp/templates/poiList.ftl b/src/main/webapp/templates/poiList.ftl index 12bd313f568a55f62abd029a0bde6694cd48d301..c9360f82e75ce3b5cc5514899c4d25ca7c29096f 100755 --- a/src/main/webapp/templates/poiList.ftl +++ b/src/main/webapp/templates/poiList.ftl @@ -1,19 +1,18 @@ <#-- Copyright (c) 2014 NIBIO <http://www.nibio.no/>. - This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.pois}</title> diff --git a/src/main/webapp/templates/registerOpenIdForm.ftl b/src/main/webapp/templates/registerOpenIdForm.ftl index 0103893f0200341715e370f28c34c892d976ea6a..86271ae182000199825520060ebe37967c0f5854 100755 --- a/src/main/webapp/templates/registerOpenIdForm.ftl +++ b/src/main/webapp/templates/registerOpenIdForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.pleaselogin}</title> diff --git a/src/main/webapp/templates/resetPasswordForm.ftl b/src/main/webapp/templates/resetPasswordForm.ftl index 69d9e3c38424635a4f286033fb2386b37406a267..2ee39d7b7c05b97c0e49cafea011ba99f56d9ac0 100755 --- a/src/main/webapp/templates/resetPasswordForm.ftl +++ b/src/main/webapp/templates/resetPasswordForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.resetPassword}</title> diff --git a/src/main/webapp/templates/resetPasswordRequestForm.ftl b/src/main/webapp/templates/resetPasswordRequestForm.ftl index 72f277eae227cfb1fa2e4028e5ff49476fc558b5..788df79546a4ca577f507af49f680bf339caed0e 100755 --- a/src/main/webapp/templates/resetPasswordRequestForm.ftl +++ b/src/main/webapp/templates/resetPasswordRequestForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.resetPasswordRequest}</title> diff --git a/src/main/webapp/templates/runTaskManuallyForm.ftl b/src/main/webapp/templates/runTaskManuallyForm.ftl index 698fd9ebed86ac322e02fd07fcfee7b17d6372fd..eb1064c8926b35ecc66c5acd4c77b64c3425b019 100755 --- a/src/main/webapp/templates/runTaskManuallyForm.ftl +++ b/src/main/webapp/templates/runTaskManuallyForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> diff --git a/src/main/webapp/templates/taskHistoryDetails.ftl b/src/main/webapp/templates/taskHistoryDetails.ftl index fb482fa35efc1437b8cd92ea128ff5021eededf8..2cdaceb4e6366b57e404b061746c7fb359d3c4fd 100755 --- a/src/main/webapp/templates/taskHistoryDetails.ftl +++ b/src/main/webapp/templates/taskHistoryDetails.ftl @@ -1,19 +1,18 @@ <#-- Copyright (c) 2014 NIBIO <http://www.nibio.no/>. - This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.taskHistoryDetails}</title> diff --git a/src/main/webapp/templates/taskList.ftl b/src/main/webapp/templates/taskList.ftl index 353c2c232e29779696ba9604201cb7919b87398c..440ebc529c0f477d7e4a61372d18783b8c783ebd 100755 --- a/src/main/webapp/templates/taskList.ftl +++ b/src/main/webapp/templates/taskList.ftl @@ -1,19 +1,18 @@ <#-- Copyright (c) 2014 NIBIO <http://www.nibio.no/>. - This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.tasks}</title> diff --git a/src/main/webapp/templates/userDeleteForm.ftl b/src/main/webapp/templates/userDeleteForm.ftl index 7cf11937fa862a50ea4a04c357497bcad530c436..913557fc25ee0407df06f537b47d5536dc7e0dee 100755 --- a/src/main/webapp/templates/userDeleteForm.ftl +++ b/src/main/webapp/templates/userDeleteForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2015 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - NIBIO is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.deleteUser}</title> @@ -35,7 +35,10 @@ <li>${i18nBundle.weatherStations}: ${userResources.pois?size}</li> <li>${i18nBundle.messages}: ${userResources.messageLocales?size}</li> <li>${i18nBundle.forecasts}: ${userResources.forecastConfigurations?size}</li> - <li>${i18nBundle.observations}: ${userResources.observations?size}</li> + <li>${i18nBundle.observations}: ${userResources.observations?size}</li> + <#if userBarkbeetleSeasonTrapsites?size gt 0 > + <li>Barkbillefellelokaliteter: ${userBarkbeetleSeasonTrapsites?size}</li> + </#if> </ul> <h2>${i18nBundle.transferResources}</h2> <form action="/user?action=deleteUser" method="POST" onsubmit="return confirm('${i18nBundle.confirmDelete}');"/> @@ -48,7 +51,7 @@ </#if> <#list users as user> <#if user.userId != viewUser.userId> - <option value="${user.userId}">${user.firstName!""} ${user.lastName}</option> + <option value="${user.userId}">${user.lastName}, ${user.firstName!""}</option> </#if> </#list> </select> diff --git a/src/main/webapp/templates/userForm.ftl b/src/main/webapp/templates/userForm.ftl index e2dae36ade26ea17deb8c2a0b6bb5067a771489e..b0e54a4b8286b81247c51ff9b4e95061cf6fb4a0 100755 --- a/src/main/webapp/templates/userForm.ftl +++ b/src/main/webapp/templates/userForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.user}</title> diff --git a/src/main/webapp/templates/userList.ftl b/src/main/webapp/templates/userList.ftl index b5a0d5ba96d48a5451368b3d0ae189f68a9cc421..fee115be72901a7cff0db1ee6e51ef4543db41f0 100755 --- a/src/main/webapp/templates/userList.ftl +++ b/src/main/webapp/templates/userList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.users}</title> diff --git a/src/main/webapp/templates/userOrganizationGroupsList.ftl b/src/main/webapp/templates/userOrganizationGroupsList.ftl index 2dc46747e5d5f9e9579c8de674111ca55983c266..d50eab75c67090b62fcf5aed3a9a073a791296af 100755 --- a/src/main/webapp/templates/userOrganizationGroupsList.ftl +++ b/src/main/webapp/templates/userOrganizationGroupsList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2016 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.user}: ${i18nBundle.organizationGroupList?lower_case}</title> diff --git a/src/main/webapp/templates/userRegistrationForm.ftl b/src/main/webapp/templates/userRegistrationForm.ftl index 25dbeeda88a46d2b538456071d3276dde85cfa32..23e64638a1765df697bf4e72548aae4088e0642a 100755 --- a/src/main/webapp/templates/userRegistrationForm.ftl +++ b/src/main/webapp/templates/userRegistrationForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.registerNewUser}</title> diff --git a/src/main/webapp/templates/weatherStationDataSourceForm.ftl b/src/main/webapp/templates/weatherStationDataSourceForm.ftl new file mode 100644 index 0000000000000000000000000000000000000000..d386d502e3a02eaea22d83ad0139cc8254c53674 --- /dev/null +++ b/src/main/webapp/templates/weatherStationDataSourceForm.ftl @@ -0,0 +1,97 @@ +<#-- + Copyright (c) 2024 NIBIO <http://www.nibio.no/>. + + This file is part of VIPSLogic. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +--><#include "master.ftl"> +<#assign formId = "weatherStationDataSourceForm"> +<#macro page_head> + <title><#if weatherStationDataSource.weatherStationDataSourceId?has_content>${i18nBundle.editWeatherStationDataSource} ${weatherStationDataSource.name}<#else>${i18nBundle.newWeatherStationDataSource}</#if></title> +</#macro> +<#macro custom_css> + <link rel="stylesheet" type="text/css" href="/css/3rdparty/ol.css"/ > +</#macro> +<#macro custom_js> + <script type="text/javascript" src="/js/constants.js"></script> + <script type="text/javascript" src="/js/resourcebundle.js"></script> + <script type="text/javascript" src="/js/validateForm.js"></script> + <script type="text/javascript"> + $(document).ready(function() { + // Load main form definition (for validation) + loadFormDefinition("${formId}"); + + }); + function handleWeatherStationDataSourceDelete(weatherStationDataSourceId){ + window.location.href="/weatherstationdatasource?action=deleteWeatherStationDataSource&weatherStationDataSourceId=" + weatherStationDataSourceId; + } + + </script> +</#macro> +<#macro page_contents> +<div class="singleBlockContainer"> + <p><a href="/weatherstationdatasource" class="btn btn-default back" role="button">${i18nBundle.back}</a></p> + <h1><#if weatherStationDataSource.weatherStationDataSourceId?has_content>${i18nBundle.editWeatherStationDataSource} ${weatherStationDataSource.name}<#else>${i18nBundle.newWeatherStationDataSource}</#if></h1> + <div id="errorMsgEl" class="alert alert-danger" <#if !formValidation?has_content> style="display:none;"</#if>> + <#if formValidation?has_content>${formValidation.validationMessages?replace("\n", "<br>")}</#if> + </div> + <#if messageKey?has_content> + <div class="alert alert-success">${i18nBundle(messageKey)}</div> + </#if> + <div class="row"> + <div class="col-md-12"> + <form id="${formId}" role="form" action="/weatherstationdatasource?action=weatherStationDataSourceFormSubmit" method="POST" onsubmit="return validateForm(this);"> + <input type="hidden" name="weatherStationDataSourceId" value="${weatherStationDataSource.weatherStationDataSourceId!"-1"}"/> + <div class="form-group"> + <label for="name">${i18nBundle.name}</label> + <input type="text" class="form-control" name="name" placeholder="${i18nBundle.name}" value="${(weatherStationDataSource.name)!""}" onblur="validateField(this); "/> + <span class="help-block" id="${formId}_name_validation"></span> + </div> + <div class="form-group"> + <label for="defaultDescription">${i18nBundle.description}</label> + <input type="text" class="form-control" name="defaultDescription" placeholder="${i18nBundle.description}" value="${(weatherStationDataSource.defaultDescription)!""}" onblur="validateField(this); "/> + <span class="help-block" id="${formId}_defaultDescription_validation"></span> + </div> + <div class="form-group"> + <label for="uri">URI</label> + <input type="url" class="form-control" name="uri" placeholder="URI" value="${(weatherStationDataSource.uri)!""}" onblur="validateField(this); "/> + <span class="help-block" id="${formId}_uri_validation"></span> + </div> + <div class="form-group"> + <label for="datafetchUriExpression">${i18nBundle.datafetchUriExpression}</label> + <input type="url" class="form-control" name="datafetchUriExpression" placeholder="${i18nBundle.datafetchUriExpression}" value="${(weatherStationDataSource.datafetchUriExpression)!""}" onblur="validateField(this); "/> + <span class="help-block" id="${formId}_datafetchUriExpression_validation"></span> + </div> + <div class="form-group"> + <label for="infoUriExpression">${i18nBundle.infoUriExpression}</label> + <input type="url" class="form-control" name="infoUriExpression" placeholder="${i18nBundle.infoUriExpression}" value="${(weatherStationDataSource.infoUriExpression)!""}" onblur="validateField(this); "/> + <span class="help-block" id="${formId}_infoUriExpression_validation"></span> + </div> + <div class="form-group"> + <div class="checkbox"> + <label> + <input type="checkbox" id="isGrid" name="isGrid" value="true"<#if weatherStationDataSource.isGrid?has_content && weatherStationDataSource.isGrid == true> checked="checked"</#if>/> + </label> + ${i18nBundle.isGridWeatherDataSource} + <span class="help-block" id="${formId}_isGrid_validation"></span> + </div> + <button type="submit" class="btn btn-default">${i18nBundle.submit}</button> + <#if weatherStationDataSource.weatherStationDataSourceId?has_content> + <button type="button" class="btn btn-danger" onclick="if(confirm('${i18nBundle.confirmDelete}')){handleWeatherStationDataSourceDelete(${weatherStationDataSource.weatherStationDataSourceId});}">${i18nBundle.delete}</button> + </#if> + </form> + </div> + </div> +</div> +</#macro> +<@page_html/> \ No newline at end of file diff --git a/src/main/webapp/templates/weatherStationDataSourceList.ftl b/src/main/webapp/templates/weatherStationDataSourceList.ftl new file mode 100644 index 0000000000000000000000000000000000000000..82c6b0eb62b9c386636027ee68973a20de718fd0 --- /dev/null +++ b/src/main/webapp/templates/weatherStationDataSourceList.ftl @@ -0,0 +1,39 @@ +<#-- + Copyright (c) 2024 NIBIO <http://www.nibio.no/>. + + This file is part of VIPSLogic. + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. +--><#include "master.ftl"> +<#macro page_head> + <title>${i18nBundle.weatherStationDataSources}</title> +</#macro> +<#macro custom_css> +</#macro> +<#macro custom_js> +</#macro> +<#macro page_contents> +<div class="singleBlockContainer"> +<#if messageKey?has_content> + <div class="alert alert-success">${i18nBundle(messageKey)}</div> +</#if> +<h1>${i18nBundle.weatherStationDataSources}</h1> +<ul> +<#list weatherStationDataSources as dSource> +<li><a href="/weatherstationdatasource?action=editWeatherStationDataSource&weatherStationDataSourceId=${dSource.weatherStationDataSourceId}">${dSource.name}</a></li> +</#list> +</ul> +<p><a href="/weatherstationdatasource?action=newWeatherStationDataSource" class="btn btn-default back" role="button">${i18nBundle.newWeatherStationDataSource}</a></p> +</div> +</#macro> +<@page_html/> diff --git a/src/main/webapp/templates/weatherstationDeletePreview.ftl b/src/main/webapp/templates/weatherstationDeletePreview.ftl index 366bd7eaab0adb23f1faf2d2b159a794de9f124f..3fa661e7a052c09de7cfcb7cb0bd43a4d77e9f04 100755 --- a/src/main/webapp/templates/weatherstationDeletePreview.ftl +++ b/src/main/webapp/templates/weatherstationDeletePreview.ftl @@ -2,18 +2,18 @@ Copyright (c) 2015 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.deleteWeatherStation}</title> diff --git a/src/main/webapp/templates/weatherstationForm.ftl b/src/main/webapp/templates/weatherstationForm.ftl index a3292f9baf30bc4b759ff43d15fd15211c93b39e..07089514dc6edd1e353b7987412894b487a08845 100755 --- a/src/main/webapp/templates/weatherstationForm.ftl +++ b/src/main/webapp/templates/weatherstationForm.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title><#if weatherStation.pointOfInterestId?has_content>${i18nBundle.editWeatherStation}<#else>${i18nBundle.newWeatherStation}</#if></title> @@ -71,6 +71,14 @@ </label> </div> </div> + <div class="form-group"> + <div class="checkbox"> + <label> + <input type="checkbox" name="isPrivate"<#if weatherStation.isPrivate?has_content && weatherStation.isPrivate == true> checked="checked"<#else></#if>/> + </label> + ${i18nBundle.isPrivate} + </div> + </div> <div class="form-group"> <label for="location">${i18nBundle.location} (<a href="http://en.wikipedia.org/wiki/World_Geodetic_System#A_new_World_Geodetic_System:_WGS_84" target="new">WGS84</a>: ${i18nBundle.longitude},${i18nBundle.latitude})</label> <input type="text" class="form-control" id="location" name="location" placeholder="${i18nBundle.location}" value="${(weatherStation.longitude?c)!""},${(weatherStation.latitude?c)!""}" onblur="validateField(this);" onchange="if(validateField(this)){updateMarkerPosition();}" /> diff --git a/src/main/webapp/templates/weatherstationList.ftl b/src/main/webapp/templates/weatherstationList.ftl index 3e7246bc737e4455112008e2e2fae8706e8a9e9c..95199f8dbd15615d7d5f025783f2af576a707cc5 100755 --- a/src/main/webapp/templates/weatherstationList.ftl +++ b/src/main/webapp/templates/weatherstationList.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${i18nBundle.weatherStations}</title> diff --git a/src/main/webapp/templates/weatherstationView.ftl b/src/main/webapp/templates/weatherstationView.ftl index 8c9ca4ca5f91f4e6943eeaed9ff4e3d3b550a8ec..316cf035d7dc20abd91457cb28ded09e6dfae9e9 100755 --- a/src/main/webapp/templates/weatherstationView.ftl +++ b/src/main/webapp/templates/weatherstationView.ftl @@ -2,18 +2,18 @@ Copyright (c) 2014 NIBIO <http://www.nibio.no/>. This file is part of VIPSLogic. - VIPSLogic is free software: you can redistribute it and/or modify - it under the terms of the NIBIO Open Source License as published by - NIBIO, either version 1 of the License, or (at your option) any - later version. - - VIPSLogic is distributed in the hope that it will be useful, + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - NIBIO Open Source License for more details. - - You should have received a copy of the NIBIO Open Source License - along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see <https://www.gnu.org/licenses/>. --><#include "master.ftl"> <#macro page_head> <title>${weatherStation.name}</title> diff --git a/src/main/webapp/test/mock.kml b/src/main/webapp/test/mock.kml index 3effc4404b4c5f35d339529163d423291ab0d83a..beef83de5d32cfd155e8ceb88c33be339f301207 100755 --- a/src/main/webapp/test/mock.kml +++ b/src/main/webapp/test/mock.kml @@ -4,19 +4,18 @@ * # # Copyright (c) 2014 NIBIO <http://www.nibio.no/>. # - # This file is part of VIPSLogic. - # VIPSLogic is free software: you can redistribute it and/or modify - # it under the terms of the NIBIO Open Source License as published by - # NIBIO, either version 1 of the License, or (at your option) any - # later version. - # - # VIPSLogic is distributed in the hope that it will be useful, + # This program is free software: you can redistribute it and/or modify + # it under the terms of the GNU Affero General Public License as published by + # the Free Software Foundation, either version 3 of the License, or + # (at your option) any later version. + # + # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - # NIBIO Open Source License for more details. - # - # You should have received a copy of the NIBIO Open Source License - # along with VIPSLogic. If not, see <http://www.nibio.no/licenses/>. + # GNU Affero General Public License for more details. + # + # You should have received a copy of the GNU Affero General Public License + # along with this program. If not, see <https://www.gnu.org/licenses/>. # * */ diff --git a/src/test/java/no/nibio/vips/logic/entity/rest/PointMappingRequestTest.java b/src/test/java/no/nibio/vips/logic/entity/rest/PointMappingRequestTest.java index ddb73f2d30c28f4f5ee7113aed3282dbd58a1cff..d0ea65c47482c1029673bc6abdfb4deb04b87292 100644 --- a/src/test/java/no/nibio/vips/logic/entity/rest/PointMappingRequestTest.java +++ b/src/test/java/no/nibio/vips/logic/entity/rest/PointMappingRequestTest.java @@ -19,11 +19,11 @@ package no.nibio.vips.logic.entity.rest; import java.util.ArrayList; import java.util.List; -import javax.ws.rs.client.Client; -import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.client.Entity; -import javax.ws.rs.client.WebTarget; -import javax.ws.rs.core.MediaType; +import jakarta.ws.rs.client.Client; +import jakarta.ws.rs.client.ClientBuilder; +import jakarta.ws.rs.client.Entity; +import jakarta.ws.rs.client.WebTarget; +import jakarta.ws.rs.core.MediaType; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; diff --git a/src/test/java/no/nibio/vips/logic/forms/HTMLFormGeneratorTest.java b/src/test/java/no/nibio/vips/logic/forms/HTMLFormGeneratorTest.java index e915e328a07c80238764e6bd4a5cd41c8ebba298..5c38d92f9104df1d97c4fd96b6db08823859c212 100755 --- a/src/test/java/no/nibio/vips/logic/forms/HTMLFormGeneratorTest.java +++ b/src/test/java/no/nibio/vips/logic/forms/HTMLFormGeneratorTest.java @@ -1,83 +1,81 @@ /* - * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. + * Copyright (c) 2014 NIBIO <http://www.nibio.no/>. * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. + * This program is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General + * Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any + * later version. * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied + * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more + * details. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see <https://www.gnu.org/licenses/>. + * You should have received a copy of the GNU Affero General Public License along with this program. If not, see + * <https://www.gnu.org/licenses/>. * */ package no.nibio.vips.logic.forms; -import com.fasterxml.jackson.core.JsonFactory; -import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.databind.JsonNode; -import com.fasterxml.jackson.databind.ObjectMapper; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; -import no.nibio.web.forms.HTMLFormGenerator; import org.junit.After; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; -import static org.junit.Assert.*; +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import no.nibio.web.forms.HTMLFormGenerator; /** * * @author Tor-Einar Skog <tor-einar.skog@nibio.no> */ public class HTMLFormGeneratorTest { - - public HTMLFormGeneratorTest() { - } - + + public HTMLFormGeneratorTest() {} + @BeforeClass - public static void setUpClass() { - } - + public static void setUpClass() {} + @AfterClass - public static void tearDownClass() { - } - + public static void tearDownClass() {} + @Before - public void setUp() { - } - + public void setUp() {} + @After - public void tearDown() { - } + public void tearDown() {} @Test public void testGetHTMLForm() { try { - String language="no"; + String language = "no"; HTMLFormGenerator t = new HTMLFormGenerator(); assertNotNull(t); - InputStream in = this.getClass().getResourceAsStream("/HTMLFormGeneratorTest/forecastConfigurationForm.json"); - InputStreamReader reader = new InputStreamReader(in,"UTF-8"); + InputStream in = + this.getClass().getResourceAsStream("/HTMLFormGeneratorTest/forecastConfigurationForm.json"); + InputStreamReader reader = new InputStreamReader(in, "UTF-8"); ObjectMapper mapper = new ObjectMapper(); JsonFactory factory = mapper.getFactory(); JsonParser parser = factory.createParser(reader); JsonNode formDefinition = mapper.readTree(parser); - InputStream in2 = this.getClass().getResourceAsStream("/HTMLFormGeneratorTest/forecastConfigurationForm_result.html"); + InputStream in2 = + this.getClass().getResourceAsStream("/HTMLFormGeneratorTest/forecastConfigurationForm_result.html"); InputStreamReader reader2 = new InputStreamReader(in2, "UTF-8"); java.util.Scanner s = new java.util.Scanner(reader2).useDelimiter("\\A"); String result = s.hasNext() ? s.next() : ""; - //System.out.println("expectedResult=\n" + result); - String HTMLForm = t.getHTMLFormFields(formDefinition,"forecastConfigurationForm",language); - //System.out.println("HTMLForm=\n" + HTMLForm); - assertEquals(result,HTMLForm); + // System.out.println("expectedResult=\n" + result); + String HTMLForm = t.getHTMLFormFields(formDefinition, "forecastConfigurationForm", language); + System.out.println("HTMLForm=\n" + HTMLForm); + assertEquals(HTMLForm, result); + } catch (IOException ex) { fail(ex.getMessage()); } diff --git a/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java b/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java index b69b046f07a23a99a17ad5682784a2effee98a6e..1bd00d82c596e79403615937e6d4b758e59d9c8b 100755 --- a/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java +++ b/src/test/java/no/nibio/vips/logic/messaging/UniversalMessagingTest.java @@ -22,7 +22,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import java.io.IOException; import java.util.ArrayList; import java.util.List; -import javax.ws.rs.core.Response; +import jakarta.ws.rs.core.Response; import no.nibio.vips.logic.util.RESTAuthenticator; import org.jboss.resteasy.client.jaxrs.ResteasyClient; import org.jboss.resteasy.client.jaxrs.ResteasyClientBuilder; diff --git a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.json b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.json index c5c4bb56d4d553486dbae47afa27f5b5b2d598cc..690b874fcbe92abc5e67ffdc873437c20d84ec8c 100755 --- a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.json +++ b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.json @@ -1,73 +1,122 @@ { - "_comment" : "Structure of the forecastConfigurationForm and how to validate it", + "_comment": "Structure of the forecastConfigurationForm and how to validate it", "fields": [ { - "name" : "forecastConfigurationId", - "fieldType" : "HIDDEN", - "dataType" : "INTEGER", - "webValue" : ["7"], - "required" : true + "name": "forecastConfigurationId", + "fieldType": "HIDDEN", + "dataType": "INTEGER", + "webValue": [ + "7" + ], + "required": true }, { - "name" : "vipsLogicUserId", - "dataType" : "INTEGER", - "fieldType" : "SELECT_SINGLE", + "name": "vipsLogicUserId", + "dataType": "INTEGER", + "fieldType": "SELECT_SINGLE", "nullValue": "-1", - "required" : true, - "options":[ - {"value":"-1","label":"Vennligst velg bruker","selected":false}, - {"value":"1","label":"Skog, Tor-Einar","selected":true} - ] + "required": true, + "options": [ + { + "value": "-1", + "label": "Vennligst velg bruker", + "selected": false + }, + { + "value": "1", + "label": "Skog, Tor-Einar", + "selected": true + } + ] }, { - "name" : "modelId", - "fieldType" : "SELECT_SINGLE", - "dataType" : "INTEGER", + "name": "modelId", + "fieldType": "SELECT_SINGLE", + "dataType": "INTEGER", "nullValue": "-1", - "required" : true, - "options":[ - {"value":"-1","label":"Vennligst velg varslingsmodell","selected":false}, - {"value":"NAERSTADMO","label":"Nærstads modell","selected":true}, - {"value":"APPLESCABM","label":"Epleskurvmodell","selected":false} - ] + "required": true, + "options": [ + { + "value": "-1", + "label": "Vennligst velg varslingsmodell", + "selected": false + }, + { + "value": "NAERSTADMO", + "label": "Nærstads modell", + "selected": true + }, + { + "value": "APPLESCABM", + "label": "Epleskurvmodell", + "selected": false + } + ] }, { - "name" : "locationPointOfInterestId", - "dataType" : "INTEGER", - "fieldType" : "SELECT_SINGLE", + "name": "locationPointOfInterestId", + "dataType": "INTEGER", + "fieldType": "SELECT_SINGLE", "nullValue": "-1", - "required" : true, - "options":[ - {"value":"-1","label":"Vennligst velg målestasjon","selected":false}, - {"value":"38","label":"Ullensvang","selected":false}, - {"value":"72","label":"Ås","selected":true} - ] + "required": true, + "options": [ + { + "value": "-1", + "label": "Vennligst velg værstasjon", + "selected": false + }, + { + "value": "38", + "label": "Ullensvang", + "selected": false + }, + { + "value": "72", + "label": "Ås", + "selected": true + } + ] }, { - "name" : "weatherStationPointOfInterestId", - "dataType" : "INTEGER", - "fieldType" : "SELECT_SINGLE", + "name": "weatherStationPointOfInterestId", + "dataType": "INTEGER", + "fieldType": "SELECT_SINGLE", "nullValue": "-1", - "required" : true, - "options":[ - {"value":"-1","label":"Vennligst velg lokalitet","selected":false}, - {"value":"38","label":"Ullensvang","selected":false}, - {"value":"72","label":"Ås","selected":true} - ] + "required": true, + "options": [ + { + "value": "-1", + "label": "Vennligst velg lokalitet", + "selected": false + }, + { + "value": "38", + "label": "Ullensvang", + "selected": false + }, + { + "value": "72", + "label": "Ås", + "selected": true + } + ] }, { - "name" : "dateStart", - "dataType" : "DATE", - "required" : true + "name": "dateStart", + "dataType": "DATE", + "required": true }, { - "name" : "dateEnd", - "dataType" : "DATE", - "required" : true + "name": "dateEnd", + "dataType": "DATE", + "required": true } - ], - "relations":[ - {"primaryField":"dateEnd","secondaryField":"dateStart", "relationType": "AFTER"} + "relations": [ + { + "primaryField": "dateEnd", + "secondaryField": "dateStart", + "relationType": "AFTER" + } ] -} +} \ No newline at end of file diff --git a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.output b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.output index ce39fc6dbe56f6d38a0b44ad4ba33d4921ad9003..fcd948a78e6b1fdb71deb7122742bb3e0bb2f617 100755 --- a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.output +++ b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm.output @@ -26,7 +26,7 @@ <span class="help-block" id="forecastConfigurationForm_locationPointOfInterestId_validation"></span> </div> <div class="form-group"> -<label for="weatherStationPointOfInterestId">Målestasjon</label> +<label for="weatherStationPointOfInterestId">Værstasjon</label> <select class="form-control" name="weatherStationPointOfInterestId" onblur="validateField(this);"> <option value="-1">Vennligst velg lokalitet</option> <option value="38">Ullensvang</option> diff --git a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result index b09a9bb9259d82f9a2ce1f90c63783058b6eff9c..6fc69f7535dd88fd4844e4213ea0062fb4323524 100755 --- a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result +++ b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result @@ -130,9 +130,9 @@ <span class="help-block" id="forecastConfigurationForm_locationPointOfInterestId_validation"></span> </div> <div class="form-group"> - <label for="weatherStationPointOfInterestId">Målestasjon</label> + <label for="weatherStationPointOfInterestId">Værstasjon</label> <select class="form-control" name="weatherStationPointOfInterestId" onblur="validateField(this);"> - <option value="-1">Vennligst velg målestasjon</option> + <option value="-1">Vennligst velg værstasjon</option> <option value="54">Alvdal</option> <option value="91" selected="selected">Apelsvoll</option> <option value="30">Balestrand</option> diff --git a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.html b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.html index 92f82d74c599925b4fa6869a9f780a92c10e9558..1295df57636ab29e1f8a23d77b9f40808220267e 100755 --- a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.html +++ b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.html @@ -17,16 +17,16 @@ <span class="help-block" id="forecastConfigurationForm_modelId_validation"></span> </div> <div class="form-group"> -<label for="locationPointOfInterestId">Lokalitet</label> +<label for="locationPointOfInterestId">Sted</label> <select class="form-control" name="locationPointOfInterestId" onblur="validateField(this);"> -<option value="-1">Vennligst velg målestasjon</option> +<option value="-1">Vennligst velg værstasjon</option> <option value="38">Ullensvang</option> <option value="72" selected="selected">Ås</option> </select> <span class="help-block" id="forecastConfigurationForm_locationPointOfInterestId_validation"></span> </div> <div class="form-group"> -<label for="weatherStationPointOfInterestId">Målestasjon</label> +<label for="weatherStationPointOfInterestId">Værstasjon</label> <select class="form-control" name="weatherStationPointOfInterestId" onblur="validateField(this);"> <option value="-1">Vennligst velg lokalitet</option> <option value="38">Ullensvang</option> diff --git a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.txt b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.txt index b09a9bb9259d82f9a2ce1f90c63783058b6eff9c..6fc69f7535dd88fd4844e4213ea0062fb4323524 100755 --- a/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.txt +++ b/src/test/resources/HTMLFormGeneratorTest/forecastConfigurationForm_result.txt @@ -130,9 +130,9 @@ <span class="help-block" id="forecastConfigurationForm_locationPointOfInterestId_validation"></span> </div> <div class="form-group"> - <label for="weatherStationPointOfInterestId">Målestasjon</label> + <label for="weatherStationPointOfInterestId">Værstasjon</label> <select class="form-control" name="weatherStationPointOfInterestId" onblur="validateField(this);"> - <option value="-1">Vennligst velg målestasjon</option> + <option value="-1">Vennligst velg værstasjon</option> <option value="54">Alvdal</option> <option value="91" selected="selected">Apelsvoll</option> <option value="30">Balestrand</option>