Repository: GitSquared/edex-ui Branch: master Commit: 04a00c407990 Files: 103 Total size: 5.7 MB Directory structure: gitextract_5fyty_j9/ ├── .github/ │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── config.yml │ │ └── issue_template.md │ └── workflows/ │ ├── build-binaries.yaml │ └── codeql-analysis.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── README.md ├── SECURITY.md ├── file-icons-generator.js ├── media/ │ └── icon.icns ├── package.json ├── prebuild-minify.js └── src/ ├── _boot.js ├── _multithread.js ├── _renderer.js ├── assets/ │ ├── css/ │ │ ├── boot_screen.css │ │ ├── extra_ratios.css │ │ ├── filesystem.css │ │ ├── keyboard.css │ │ ├── main.css │ │ ├── main_shell.css │ │ ├── media_player.css │ │ ├── mod_clock.css │ │ ├── mod_column.css │ │ ├── mod_conninfo.css │ │ ├── mod_cpuinfo.css │ │ ├── mod_fuzzyFinder.css │ │ ├── mod_globe.css │ │ ├── mod_hardwareInspector.css │ │ ├── mod_netstat.css │ │ ├── mod_processlist.css │ │ ├── mod_ramwatcher.css │ │ ├── mod_sysinfo.css │ │ ├── mod_toplist.css │ │ └── modal.css │ ├── icons/ │ │ ├── file-icons.json │ │ └── icon.icns │ ├── kb_layouts/ │ │ ├── da-DK.json │ │ ├── de-DE.json │ │ ├── en-COLEMAK.json │ │ ├── en-DVORAK.json │ │ ├── en-GB.json │ │ ├── en-NORMAN.json │ │ ├── en-US.json │ │ ├── en-WORKMAN.json │ │ ├── es-ES.json │ │ ├── es-LAT.json │ │ ├── fr-BEPO.json │ │ ├── fr-FR.json │ │ ├── hu-HU.json │ │ ├── it-IT.json │ │ ├── nl-BE.json │ │ ├── pt-BR.json │ │ ├── sv-SE.json │ │ ├── tr-TR-F.json │ │ └── tr-TR-Q.json │ ├── misc/ │ │ ├── boot_log.txt │ │ ├── file-icons-match.js │ │ └── grid.json │ ├── themes/ │ │ ├── apollo-notype.json │ │ ├── apollo.json │ │ ├── blade.json │ │ ├── chalkboard-ligatures.json │ │ ├── chalkboard-notype.json │ │ ├── chalkboard.json │ │ ├── cyborg-focus.json │ │ ├── cyborg.json │ │ ├── interstellar.json │ │ ├── matrix.json │ │ ├── navy-disrupted.json │ │ ├── navy-notype.json │ │ ├── navy.json │ │ ├── nord.json │ │ ├── red.json │ │ ├── tron-colorfilter.json │ │ ├── tron-disrupted.json │ │ ├── tron-fulltype.json │ │ ├── tron-notype.json │ │ ├── tron-typeleft.json │ │ └── tron.json │ └── vendor/ │ └── encom-globe.js ├── classes/ │ ├── audiofx.class.js │ ├── clock.class.js │ ├── conninfo.class.js │ ├── cpuinfo.class.js │ ├── docReader.class.js │ ├── filesystem.class.js │ ├── fuzzyFinder.class.js │ ├── hardwareInspector.class.js │ ├── keyboard.class.js │ ├── locationGlobe.class.js │ ├── mediaPlayer.class.js │ ├── modal.class.js │ ├── netstat.class.js │ ├── ramwatcher.class.js │ ├── sysinfo.class.js │ ├── terminal.class.js │ ├── toplist.class.js │ └── updateChecker.class.js ├── package.json └── ui.html ================================================ FILE CONTENTS ================================================ ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms github: GitSquared custom: ['https://gaby.dev/donate'] ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ blank_issues_enabled: true contact_links: - name: Feature Ideas url: https://github.com/GitSquared/edex-ui/discussions/new?category=ideas about: Have a crazy idea for eDEX you'd like to share? Please do so here! - name: Questions url: https://github.com/GitSquared/edex-ui/discussions/new?category=questions about: Confused? Ask all your questions here. ================================================ FILE: .github/ISSUE_TEMPLATE/issue_template.md ================================================ --- name: Bug report about: Something's broken or screaming error messages at you? Let's fix it. title: '' labels: investigation --- ## Technical information **Using version:** - [ ] `master` (running from GitHub-published source code, currently `v2.2.8-pre`) - [ ] `latest` (latest release, currently `v2.2.7`) - [ ] `vX.X.X` (specify other version) **Running on:** - [ ] Linux - [ ] Windows - [ ] macOS **How comfortable you are with your system and/or IT in general:** - [ ] I'm kind of lost, honestly - [ ] I know what's up, I could help you run some commands or checks - [ ] My machine is fully under my control, tell me what you need - [ ] I attended [Defcon](https://defcon.org) last year --- ## Problem (Write your report here. Screenshots and step-by-step instructions can help a lot!) ================================================ FILE: .github/workflows/build-binaries.yaml ================================================ name: Build packaged binaries on: [push, pull_request, create] jobs: build-linux: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Cache node modules uses: actions/cache@v2 env: cache-name: cache-node-modules with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Cache Electron binaries uses: actions/cache@v2 env: cache-name: cache-electron-bins with: # cache location is described here: # https://github.com/electron/get#how-it-works path: ~/.cache/electron key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Install system dependencies for x64->x32 cross-build run: | sudo apt update sudo apt install libc6-dev-i386 gcc-multilib g++-multilib - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 14 - name: Setup npm run: sudo npm i -g npm@7 - name: Install build deps run: npm install - name: Run prebuild script run: npm run prebuild-linux - name: Build for x64 / ia32 run: ./node_modules/.bin/electron-builder build -l --x64 --ia32 env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/upload-artifact@v2 with: name: Linux-AppImages path: dist/*.AppImage if-no-files-found: error build-linux-arm32: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup QEMU uses: docker/setup-qemu-action@v1 with: platforms: arm - name: Cache node modules uses: actions/cache@v2 env: cache-name: cache-node-modules with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Cache Electron binaries uses: actions/cache@v2 env: cache-name: cache-electron-bins with: # cache location is described here: # https://github.com/electron/get#how-it-works path: ~/.cache/electron key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Run prebuild outside of QEMU emulator run: sudo npm i -g npm@7 && npm install && rsync -a --info=progress2 src/ prebuild-src --exclude node_modules && node prebuild-minify.js && rm -rf node_modules - name: Build for arm32v7 (aka armv7l) uses: docker://arm32v7/node:14-buster with: args: bash -c "npm i -g npm@7 && npm install && ./node_modules/.bin/electron-builder build -l --armv7l" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/upload-artifact@v2 with: name: Linux-arm32-AppImage path: dist/*.AppImage if-no-files-found: error build-linux-arm64: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: Setup QEMU uses: docker/setup-qemu-action@v1 with: platforms: arm64 - name: Cache node modules uses: actions/cache@v2 env: cache-name: cache-node-modules with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Cache Electron binaries uses: actions/cache@v2 env: cache-name: cache-electron-bins with: # cache location is described here: # https://github.com/electron/get#how-it-works path: ~/.cache/electron key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Run prebuild outside of QEMU emulator run: sudo npm i -g npm@7 && npm install && rsync -a --info=progress2 src/ prebuild-src --exclude node_modules && node prebuild-minify.js && rm -rf node_modules - name: Build for arm64 (aka arm64v8) uses: docker://arm64v8/node:14-buster with: args: bash -c "npm i -g npm@7 && npm install && ./node_modules/.bin/electron-builder build -l --arm64" env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/upload-artifact@v2 with: name: Linux-arm64-AppImage path: dist/*.AppImage if-no-files-found: error build-windows: runs-on: windows-latest steps: - uses: actions/checkout@v1 - name: Get npm cache directory id: npm-cache run: | echo "::set-output name=dir::$(npm config get cache)" - uses: actions/cache@v2 with: path: ${{ steps.npm-cache.outputs.dir }} key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} - name: Cache Electron binaries uses: actions/cache@v2 env: cache-name: cache-electron-bins with: # cache location is described here: # https://github.com/electron/get#how-it-works path: ~/AppData/Local/electron/Cache key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 14 - name: Setup npm run: npm i -g npm@7 - name: npm install run: npm install - name: npm build run: npm run build-windows env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/upload-artifact@v2 with: name: Windows-Installer path: dist/*.exe if-no-files-found: error build-darwin: runs-on: macos-latest steps: - uses: actions/checkout@v1 - name: Cache node modules uses: actions/cache@v2 env: cache-name: cache-node-modules with: # npm cache files are stored in `~/.npm` on Linux/macOS path: ~/.npm key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Cache Electron binaries uses: actions/cache@v2 env: cache-name: cache-electron-bins with: # cache location is described here: # https://github.com/electron/get#how-it-works path: ~/Library/Caches/electron key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }} - name: Setup Node.js uses: actions/setup-node@v1 with: node-version: 14 - name: Setup npm run: sudo npm i -g npm@7 - name: npm install run: npm install - name: npm build run: npm run build-darwin env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - uses: actions/upload-artifact@v2 with: name: MacOS-Image path: dist/*.dmg if-no-files-found: error ================================================ FILE: .github/workflows/codeql-analysis.yml ================================================ # For most projects, this workflow file will not need changing; you simply need # to commit it to your repository. # # You may wish to alter this file to override the set of languages analyzed, # or to provide custom queries or build logic. # # ******** NOTE ******** # We have attempted to detect the languages in your repository. Please check # the `language` matrix defined below to confirm you have the correct set of # supported CodeQL languages. # name: "CodeQL" on: push: branches: [ master ] pull_request: # The branches below must be a subset of the branches above branches: [ master ] schedule: - cron: '20 1 * * 5' jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'javascript' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python' ] # Learn more: # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed steps: - name: Checkout repository uses: actions/checkout@v2 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v1 with: languages: ${{ matrix.language }} # If you wish to specify custom queries, you can do so here or in a config file. # By default, queries listed here will override any specified in a config file. # Prefix the list here with "+" to use these queries and those in the config file. # queries: ./path/to/local/query, your-org/your-repo/queries@main # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v1 # ℹ️ Command-line programs to run using the OS shell. # 📚 https://git.io/JvXDl # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines # and modify them (or add more) to build your code if your project # uses a compiled language #- run: | # make bootstrap # make release - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v1 ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* # Runtime data pids *.pid *.seed # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # nyc test coverage .nyc_output # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt # node-waf configuration .lock-wscript # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release # Dependency directories node_modules jspm_packages # Optional npm cache directory .npm # Optional REPL history .node_repl_history # JetBrains IDE project folder (e.g. WebStorm) .idea dist prebuild-src src/node_modules ================================================ FILE: .gitmodules ================================================ [submodule "file-icons/atom"] path = file-icons/atom url = https://github.com/file-icons/atom.git [submodule "file-icons/devopicons"] path = file-icons/devopicons url = https://github.com/file-icons/DevOpicons.git [submodule "file-icons/mfixx"] path = file-icons/mfixx url = https://github.com/file-icons/MFixx.git [submodule "file-icons/source"] path = file-icons/source url = https://github.com/file-icons/source.git [submodule "file-icons/font-awesome"] path = file-icons/font-awesome url = https://github.com/FortAwesome/Font-Awesome.git [submodule "file-icons/bytesize-icons"] path = file-icons/bytesize-icons url = git@github.com:danklammer/bytesize-icons.git ================================================ FILE: LICENSE ================================================ GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS ================================================ FILE: README.md ================================================


Logo

undefined
undefined undefined undefined
undefined undefined undefined undefined undefined
(Project archived oct. 18th 2021)


eDEX-UI is a fullscreen, cross-platform terminal emulator and system monitor that looks and feels like a sci-fi computer interface. --- Demo on YouTube Heavily inspired from the [TRON Legacy movie effects](https://web.archive.org/web/20170511000410/http://jtnimoy.com/blogs/projects/14881671) (especially the [Board Room sequence](https://gmunk.com/TRON-Board-Room)), the eDEX-UI project was originally meant to be *"[DEX-UI](https://github.com/seenaburns/dex-ui) with less « art » and more « distributable software »"*. While keeping a futuristic look and feel, it strives to maintain a certain level of functionality and to be usable in real-life scenarios, with the larger goal of bringing science-fiction UXs to the mainstream.
It might or might not be a joke taken too seriously. ---

Jump to:
FeaturesScreenshotsQuestions & AnswersDownloadFeatured InContributor InstructionsCredits

## Sponsor **Want to help support my open-source experiments and learn some cool JavaScript tricks at the same time?** Click the banner below and sign up to **Bytes**, the only newsletter cool enough to be recommended by eDEX-UI. [![Bytes by UI.dev](media/sponsor-uidev-bytes.jpg)](https://ui.dev/bytes/?r=gabriel) ## Features - Fully featured terminal emulator with tabs, colors, mouse events, and support for `curses` and `curses`-like applications. - Real-time system (CPU, RAM, swap, processes) and network (GeoIP, active connections, transfer rates) monitoring. - Full support for touch-enabled displays, including an on-screen keyboard. - Directory viewer that follows the CWD (current working directory) of the terminal. - Advanced customization using themes, on-screen keyboard layouts, CSS injections. See the [wiki](https://github.com/GitSquared/edex-ui/wiki) for more info. - Optional sound effects made by a talented sound designer for maximum hollywood hacking vibe. ## Screenshots ![Default screenshot](media/screenshot_default.png) _[neofetch](https://github.com/dylanaraps/neofetch) on eDEX-UI 2.2 with the default "tron" theme & QWERTY keyboard_ ![Blade screenshot](media/screenshot_blade.png) _Checking out available themes in [eDEX's config dir](https://github.com/GitSquared/edex-ui/wiki/userData) with [`ranger`](https://github.com/ranger/ranger) on eDEX-UI 2.2 with the "blade" theme_ ![Disrupted screenshot](media/screenshot_disrupted.png) _[cmatrix](https://github.com/abishekvashok/cmatrix) on eDEX-UI 2.2 with the experimental "tron-disrupted" theme, and the user-contributed DVORAK keyboard_ ![Horizon screenshot](media/screenshot_horizon.png) _Editing eDEX-UI source code with `nvim` on eDEX-UI 2.2 with the custom [`horizon-full`](https://github.com/GitSquared/horizon-edex-theme) theme_ ## Q&A #### How do I get it? Click on the little badges under the eDEX logo at the top of this page, or go to the [Releases](https://github.com/GitSquared/edex-ui/releases) tab, or download it through [one of the available repositories](https://repology.org/project/edex-ui/versions) (Homebrew, AUR...). Public release binaries are unsigned ([why](https://gaby.dev/posts/code-signing)). On Linux, you will need to `chmod +x` the AppImage file in order to run it. #### I have a problem! Search through the [Issues](https://github.com/GitSquared/edex-ui/issues) to see if yours has already been reported. If you're confident it hasn't been reported yet, feel free to open up a new one. If you see your issue and it's been closed, it probably means that the fix for it will ship in the next version, and you'll have to wait a bit. #### Can you disable the keyboard/the filesystem display? You can't disable them (yet) but you can hide them. See the `tron-notype` theme. #### Why is the file browser saying that "Tracking Failed"? (Windows only) On Linux and macOS, eDEX tracks where you're going in your terminal tab to display the content of the current folder on-screen. Sadly, this is technically impossible to do on Windows right now, so the file browser reverts back to a "detached" mode. You can still use it to browse files & directories and click on files to input their path in the terminal. #### Can this run on a Raspberry Pi / ARM device? We provide prebuilt arm64 builds. For other platforms, see [this issue comment](https://github.com/GitSquared/edex-ui/issues/313#issuecomment-443465345), and the thread on issue [#818](https://github.com/GitSquared/edex-ui/issues/818). #### Is this repo actively maintained? No, after a 3 years run, this project has been archived. See the [announcement](https://github.com/GitSquared/edex-ui/releases/tag/v2.2.8). #### How did you make this? Glad you're interested! See [#272](https://github.com/GitSquared/edex-ui/issues/272). #### This is so cool. Thanks! If you feel like it, you can [follow me on Twitter](https://gaby.dev/twitter) to hear about new stuff I'm making. ## Featured in... - [Linux Uprising Blog](https://www.linuxuprising.com/2018/11/edex-ui-fully-functioning-sci-fi.html) - [My post on r/unixporn](https://www.reddit.com/r/unixporn/comments/9ysbx7/oc_a_little_project_that_ive_been_working_on/) - [Korben article (in french)](https://korben.info/une-interface-futuriste-pour-vos-ecrans-tactiles.html) - [Hacker News](https://news.ycombinator.com/item?id=18509828) - [This tweet that made me smile](https://twitter.com/mikemaccana/status/1065615451940667396) - [BoingBoing article](https://boingboing.net/2018/11/23/simulacrum-sf.html) - Apparently i'm a "French hacker" - [OReilly 4 short links](https://www.oreilly.com/ideas/four-short-links-23-november-2018) - [Hackaday](https://hackaday.com/2018/11/23/look-like-a-movie-hacker/) - [Developpez.com (another french link)](https://www.developpez.com/actu/234808/Une-application-de-bureau-ressemble-a-une-interface-d-ordinateur-de-science-fiction-inspiree-des-effets-du-film-TRON-Legacy/) - [GitHub Blog's Release Radar November 2018](https://blog.github.com/2018-12-21-release-radar-november-2018/) - [opensource.com Productive Tools for 2019](https://opensource.com/article/19/1/productivity-tool-edex-ui) - [O'Reilly 4 short links (again)](https://www.oreilly.com/radar/four-short-links-7-july-2020/) - [LinuxLinks](https://www.linuxlinks.com/linux-candy-edex-ui-sci-fi-computer-terminal-emulator-system-monitor/) - [Linux For Everyone (Youtube)](https://www.youtube.com/watch?v=gbzqCAjm--g) - [BestOfJS Rising Stars 2020](https://risingstars.js.org/2020/en#edex-ui) - [The Geek Freaks (Youtube/German)](https://youtu.be/TSjMIeLG0Sk) - [JSNation Open Source Awards 2021](https://osawards.com/javascript/#nominees) (Nominee - Fun Side Project of the Year) ## Useful commands for the nerds **IMPORTANT NOTE:** the following instructions are meant for running eDEX from the latest unoptimized, unreleased, development version. If you'd like to get stable software instead, refer to [these](#how-do-i-get-it) instructions. #### Starting from source: on *nix systems (You'll need the Xcode command line tools on macOS): - clone the repository - `npm run install-linux` - `npm run start` on Windows: - start cmd or powershell **as administrator** - clone the repository - `npm run install-windows` - `npm run start` #### Building Note: Due to native modules, you can only build targets for the host OS you are using. - `npm install` (NOT `install-linux` or `install-windows`) - `npm run build-linux` or `build-windows` or `build-darwin` The script will minify the source code, recompile native dependencies and create distributable assets in the `dist` folder. #### Getting the bleeding edge If you're interested in running the latest in-development version but don't want to compile source code yourself, you can can get pre-built nightly binaries on [GitHub Actions](https://github.com/GitSquared/edex-ui/actions): click the latest commits, and download the artifacts bundle for your OS. ## Credits eDEX-UI's source code was primarily written by me, [Squared](https://github.com/GitSquared). If you want to get in touch with me or find other projects I'm involved in, check out [my website](https://gaby.dev). [PixelyIon](https://github.com/PixelyIon) helped me get started with Windows compatibility and offered some precious advice when I started to work on this project seriously. [IceWolf](https://soundcloud.com/iamicewolf) composed the sound effects on v2.1.x and above. He makes really cool stuff, check out his music! ## Thanks Of course, eDEX would never have existed if I hadn't stumbled upon the amazing work of [Seena](https://github.com/seenaburns) on [r/unixporn](https://reddit.com/r/unixporn). This project uses a bunch of open-source libraries, frameworks and tools, see [the full dependency graph](https://github.com/GitSquared/edex-ui/network/dependencies). I want to namely thank the developers behind [xterm.js](https://github.com/xtermjs/xterm.js), [systeminformation](https://github.com/sebhildebrandt/systeminformation) and [SmoothieCharts](https://github.com/joewalnes/smoothie). Huge thanks to [Rob "Arscan" Scanlon](https://github.com/arscan) for making the fantastic [ENCOM Globe](https://github.com/arscan/encom-globe), also inspired by the TRON: Legacy movie, and distributing it freely. His work really puts the icing on the cake. ## Licensing Licensed under the [GPLv3.0](https://github.com/GitSquared/edex-ui/blob/master/LICENSE). ================================================ FILE: SECURITY.md ================================================ # Security Policy ## Supported Versions We support the [latest released version](https://github.com/GitSquared/edex-ui/releases/latest), and the current development version (`master` branch). ## Reporting a Vulnerability If you're concerned about a potential or proven security vulnerability in this software, please get in touch by sending an email at [`gabriel@saillard.dev`](mailto:%22Gabriel%20SAILLARD%22%20%3Cgabriel%40saillard.dev%3E?subject=%5BSECURITY%5D%20eDEX-UI%20vulnerability%20concern&body=(Please%20describe%20what%20code%20you%20think%20is%20vulnerable%2C%20and%20provide%20a%20way%20to%20reproduce%20the%20issue%20if%20possible)). If your email subject contains the `[SECURITY]` tag, you will be surfaced to the front of my inbox and should expect a response in 24 hours or less. The link above will set you up with a subject template. ================================================ FILE: file-icons-generator.js ================================================ // This is an helper script to generate the resources used by eDEX to display file-specific icons in fsDisp, from a fresh file-icons/source GitHub clone. // Generated files are: // - src/assets/icons/file-icons.json: monolithic JSON files containing SVG data needed to draw all the icons. // - src/assets/misc/file-icons-match.js: script to match filenames to icons by using regex expressions. // // The generated files are pretty-printed. See prebuild-minify.js for automatic, on-CI minification of source files before bundling them in binary release assets. // BEFORE RUNNING THIS SCRIPT: // - npm run init-file-icons // You can then use `npm run update-file-icons` which will pull the git submodules and run this script. const fs = require("fs"); const path = require("path"); const CSON = require("cson-parser"); var fileIconsObject = {}; // Get file icons from fontawesome fs.readdirSync(path.join(__dirname, "file-icons", "font-awesome", "svgs", "brands")).forEach(icon => { let iconName = icon.replace(".svg", ""); let text = fs.readFileSync(path.join(__dirname, "file-icons", "font-awesome", "svgs", "brands", icon), {encoding: "utf8"}); let width = text.substr(text.indexOf('viewBox="0 0 ')+13); width = Number(width.slice(0, width.indexOf(" "))); let height = text.substr(text.indexOf('viewBox="0 0 ')+13+width.toString().length+1); height = Number(height.slice(0, height.indexOf('"'))); let svg = text.substr(text.indexOf(">")+1); svg = svg.replace("", ""); if (width === null || height === null) console.log(icon); fileIconsObject[iconName] = { width, height, svg }; }); // Get file icons from file-icons/source fs.readdirSync(path.join(__dirname, "file-icons", "source", "svg")).forEach(icon => { let iconName = icon.toLowerCase().replace(".svg", "").replace("-1", ""); let text = fs.readFileSync(path.join(__dirname, "file-icons", "source", "svg", icon), {encoding: "utf8"}); let width = text.substr(text.indexOf('width="')+7); width = Number(width.slice(0, width.indexOf("px"))); let height = text.substr(text.indexOf('height="')+8); height = Number(height.slice(0, height.indexOf("px"))); let svg = text.substr(text.indexOf(">")+1); svg = svg.replace("", ""); if (width === null || height === null) console.log(icon); fileIconsObject[iconName] = { width, height, svg }; }); // Get file icons from file-icons/devopicons fs.readdirSync(path.join(__dirname, "file-icons", "devopicons", "svg")).forEach(icon => { if (!icon.endsWith(".svg")) return; let iconName = icon.toLowerCase().replace(".svg", "").replace("-1", ""); let text = fs.readFileSync(path.join(__dirname, "file-icons", "devopicons", "svg", icon), {encoding: "utf8"}); let width = text.substr(text.indexOf('width="')+7); width = Number(width.slice(0, width.indexOf("px"))); let height = text.substr(text.indexOf('height="')+8); height = Number(height.slice(0, height.indexOf("px"))); let svg = text.substr(text.indexOf(">")+1); svg = svg.replace("", ""); if (width === null || height === null) console.log(icon); fileIconsObject[iconName] = { width, height, svg }; }); // Get file icons from file-icons/mfixx fs.readdirSync(path.join(__dirname, "file-icons", "mfixx", "svg")).forEach(icon => { if (!icon.endsWith(".svg")) return; let iconName = icon.toLowerCase().replace(".svg", "").replace("-1", ""); let text = fs.readFileSync(path.join(__dirname, "file-icons", "mfixx", "svg", icon), {encoding: "utf8"}); let width = text.substr(text.indexOf('width="')+7); width = Number(width.slice(0, width.indexOf("px"))); let height = text.substr(text.indexOf('height="')+8); height = Number(height.slice(0, height.indexOf("px"))); let svg = text.substr(text.indexOf(">")+1); svg = svg.replace("", ""); if (width === null || height === null) console.log(icon); fileIconsObject[iconName] = { width, height, svg }; }); // Get file icons from file-icons/bytesize-icons fs.readdirSync(path.join(__dirname, "file-icons", "bytesize-icons", "dist", "icons")).forEach(icon => { if (!icon.endsWith(".svg")) return; let iconName = icon.toLowerCase().replace(".svg", ""); let text = fs.readFileSync(path.join(__dirname, "file-icons", "bytesize-icons", "dist", "icons", icon), {encoding: "utf8"}); let dimensions = text.match(/viewBox="0 0 (\d+) (\d+)"/); let width = dimensions[1]; let height = dimensions[2]; let svg = text.substr(text.indexOf(">")+1); svg = svg.replace("", ""); if (width === null || height === null) console.log(icon); fileIconsObject[iconName] = { width, height, svg }; }); // Override with eDEX-specific icons fileIconsObject.showDisks = { width: 24, height: 24, svg: '' }; fileIconsObject.up = { width: 24, height: 24, svg: '' }; fileIconsObject.dir = { width: 24, height: 24, svg: '' }; fileIconsObject.symlink = { width: 24, height: 24, svg: '' }; fileIconsObject.file = { width: 24, height: 24, svg: '' }; fileIconsObject.other = { width: 24, height: 24, svg: '' }; fileIconsObject.disk = { width: 24, height: 24, svg: '' }; fileIconsObject.rom = { width: 24, height: 24, svg: '' }; fileIconsObject.usb = { width: 24, height: 24, svg: '' }; fileIconsObject.audio = fileIconsObject.volume; // Write the file fs.writeFileSync(path.join(__dirname, "src", "assets", "icons", "file-icons.json"), JSON.stringify(fileIconsObject, "", 4)); console.log("Wrote file-icons.json"); var fileIconsMatchScript = `/* * Thanks everyone for pointing out this is probably on of the ugliest source code files on GitHub * This is script-generated code, however, so it might disqualify * See file-icons-generator.js at root dir of git tree */ function matchIcon(filename) {\n`; // Parse the configuration file of file-icons/atom let atomConfig = CSON.parse(fs.readFileSync(path.join(__dirname, "file-icons", "atom", "config.cson"), {encoding: "utf8"})); Object.keys(atomConfig.directoryIcons).forEach(key => { let config = atomConfig.directoryIcons[key]; if (config.icon.startsWith("_")) config.icon = config.icon.substr(1); if (Array.isArray(config.match)) { config.match.forEach(key => { let match = key[0]; if (typeof match === "string") match = new RegExp(match.replace(/\./g, "\\.")+"$", "i"); // lgtm [js/incomplete-sanitization] fileIconsMatchScript += ` if (${match}.test(filename)) { return "${config.icon}"; }\n`; }); } else { if (typeof config.match === "string") config.match = new RegExp(config.match.replace(/\./g, "\\.")+"$", "i"); // lgtm [js/incomplete-sanitization] fileIconsMatchScript += ` if (${config.match}.test(filename)) { return "${config.icon}"; }\n`; if (config.alias) { if (typeof config.alias === "string") config.alias = new RegExp(config.alias.replace(/\./g, "\\.")+"$", "i"); // lgtm [js/incomplete-sanitization] fileIconsMatchScript += ` if (${config.alias}.test(filename)) { return "${config.icon}"; }\n`; } } }); Object.keys(atomConfig.fileIcons).forEach(key => { let config = atomConfig.fileIcons[key]; if (config.icon.startsWith("_")) config.icon = config.icon.substr(1); if (Array.isArray(config.match)) { config.match.forEach(key => { let match = key[0]; if (typeof match === "string") match = new RegExp(match.replace(/\./g, "\\.")+"$", "i"); // lgtm [js/incomplete-sanitization] fileIconsMatchScript += ` if (${match}.test(filename)) { return "${config.icon}"; }\n`; }); } else { if (typeof config.match === "string") config.match = new RegExp(config.match.replace(/\./g, "\\.")+"$", "i"); // lgtm [js/incomplete-sanitization] fileIconsMatchScript += ` if (${config.match}.test(filename)) { return "${config.icon}"; }\n`; if (config.alias) { if (typeof config.alias === "string") config.alias = new RegExp(config.alias.replace(/\./g, "\\.")+"$", "i"); // lgtm [js/incomplete-sanitization] fileIconsMatchScript += ` if (${config.alias}.test(filename)) { return "${config.icon}"; }\n`; } } }); // End script fileIconsMatchScript += "}\nmodule.exports = matchIcon;"; // Write the script fs.writeFileSync(path.join(__dirname, "src", "assets", "misc", "file-icons-match.js"), fileIconsMatchScript); console.log("Wrote file-icons-match.js"); ================================================ FILE: package.json ================================================ { "name": "edex-ui", "productName": "eDEX-UI", "version": "2.2.8", "description": "A science fiction desktop running everywhere. Awesome.", "keywords": [ "desktop", "sci-fi", "gui", "portable", "tty", "terminal" ], "main": "src/_boot.js", "scripts": { "start": "electron src --nointro", "install-linux": "npm install && cd src && npm install && ./../node_modules/.bin/electron-rebuild -f -w node-pty && cd ..", "preinstall-windows": "npm install --global --production windows-build-tools && npm install --global node-gyp && setx PYTHON \"%USERPROFILE%\\.windows-build-tools\\python27\\python.exe\"", "install-windows": "npm install && cd src && npm install && ..\\node_modules\\.bin\\electron-rebuild -f -w node-pty && cd ..", "prebuild-linux": "rsync -a --info=progress2 src/ prebuild-src --exclude node_modules && node prebuild-minify.js && cd prebuild-src && npm install", "prebuild-darwin": "rsync -a src/ prebuild-src --exclude node_modules && node prebuild-minify.js && cd prebuild-src && npm install", "prebuild-windows": "mkdir prebuild-src && xcopy src\\* prebuild-src\\ /E /C /Q /Y && node prebuild-minify.js && cd prebuild-src && npm install", "build-linux": "./node_modules/.bin/electron-builder build -l --x64 --ia32 --arm64 --armv7l", "build-darwin": "./node_modules/.bin/electron-builder build -m", "build-windows": "node_modules\\.bin\\electron-builder build -w", "postbuild-linux": "rm -R prebuild-src", "postbuild-darwin": "rm -R prebuild-src", "postbuild-windows": "rmdir /S /Q prebuild-src", "test": "rsync -a --info=progress2 src/ prebuild-src --exclude node_modules && node prebuild-minify.js && cd prebuild-src && npm install && snyk test && cd .. && rm -R prebuild-src", "init-file-icons": "git submodule update --init", "update-file-icons": "git submodule foreach git pull origin master && node file-icons-generator.js" }, "repository": { "type": "git", "url": "git+https://github.com/GitSquared/edex-ui.git" }, "author": "Gabriel 'Squared' SAILLARD (https://gaby.dev)", "license": "GPL-3.0", "bugs": { "url": "https://github.com/GitSquared/edex-ui/issues" }, "homepage": "https://github.com/GitSquared/edex-ui#readme", "build": { "appId": "com.edex.ui", "productName": "eDEX-UI", "publish": "github", "asar": true, "compression": "normal", "copyright": "Copyright © 2017-2021 Gabriel 'Squared' SAILLARD (https://gaby.dev)", "directories": { "output": "dist", "app": "prebuild-src" }, "forceCodeSigning": false, "npmRebuild": true, "artifactName": "eDEX-UI-${os}-${arch}.${ext}", "linux": { "target": [ "AppImage" ], "category": "System", "icon": "media/linuxIcons" }, "appImage": { "artifactName": "eDEX-UI-Linux-${arch}.AppImage" }, "mac": { "target": [ { "target": "dmg", "arch": [ "x64" ] } ], "category": "public.app-category.utilities", "icon": "media/icon.icns" }, "dmg": { "artifactName": "eDEX-UI-macOS-${arch}.dmg" }, "win": { "target": [ { "target": "nsis", "arch": [ "x64", "ia32" ] } ], "icon": "media/icon.ico" }, "nsis": { "artifactName": "eDEX-UI-Windows-${arch}.exe", "oneClick": false, "allowToChangeInstallationDirectory": true, "deleteAppDataOnUninstall": true } }, "dependencies": { "clean-css": "5.2.1", "electron": "^12.1.0", "electron-builder": "^22.14.5", "electron-rebuild": "^2.3.5", "mime-types": "^2.1.33", "node-abi": "2.30.1", "node-json-minify": "1.0.0", "terser": "^5.9.0" }, "optionalDependencies": { "cson-parser": "4.0.9" } } ================================================ FILE: prebuild-minify.js ================================================ const fs = require("fs"); const path = require("path"); const stdout = process.stdout; const UglifyJS = require("terser"); const CleanCSS = require("clean-css"); JSON.minify = require("node-json-minify"); function writeMinified(path, data) { return new Promise((res, rej) => { fs.writeFile(path, data, (err) => { if (err) { stdout.write(" - ❌\n\n\n", () => { rej(err); }); } stdout.write(" - ✓\n", () => { res(); }); }); }); } async function recursiveMinify(dirPath) { try { var files = fs.readdirSync(dirPath); } catch(e) { return; } if (files.length > 0) { for (let i = 0; i < files.length; i++) { let filePath = dirPath + '/' + files[i]; if (fs.statSync(filePath).isFile()) { // Do not process grid.json because it's heavy and pre-minified, and themes and keyboard files to leave them in a human-readable state if (filePath.endsWith(".json") && !filePath.endsWith("icons.json")) return; // See #446 if (filePath.endsWith("file-icons-match.js")) return; await stdout.write(filePath.slice(filePath.indexOf('prebuild-src/')+13)+'...'); switch (filePath.split(".").pop()) { case "js": let minified = await UglifyJS.minify(fs.readFileSync(filePath, {encoding: "utf-8"}), { compress: { dead_code: false, unused: false, warnings: true }, output: { beautify: false, ecma: 6 } }); if (!minified.error) { await writeMinified(filePath, minified.code).catch(e => { throw e; }); } else { stdout.write(" - ❌\n\n\n"); throw minified.error; } break; case "css": let output = new CleanCSS({level:2}).minify(fs.readFileSync(filePath, {encoding:"utf-8"})); if (output.errors.length >= 1) { stdout.write(" - ❌\n\n\n"); throw output.errors; } else { await writeMinified(filePath, output.styles).catch(e => { throw e; }); } break; case "json": let out; try { out = JSON.minify(fs.readFileSync(filePath, {encoding:"utf-8"})); } catch(err) { stdout.write(" - ❌\n\n\n"); throw err; } await writeMinified(filePath, out).catch(e => { throw e; }); break; default: stdout.write("\n"); } } else { await recursiveMinify(filePath); } } } } recursiveMinify(path.join(__dirname, "prebuild-src")); ================================================ FILE: src/_boot.js ================================================ const signale = require("signale"); const {app, BrowserWindow, dialog, shell} = require("electron"); process.on("uncaughtException", e => { signale.fatal(e); dialog.showErrorBox("eDEX-UI crashed", e.message || "Cannot retrieve error message."); if (tty) { tty.close(); } if (extraTtys) { Object.keys(extraTtys).forEach(key => { if (extraTtys[key] !== null) { extraTtys[key].close(); } }); } process.exit(1); }); signale.start(`Starting eDEX-UI v${app.getVersion()}`); signale.info(`With Node ${process.versions.node} and Electron ${process.versions.electron}`); signale.info(`Renderer is Chrome ${process.versions.chrome}`); const gotLock = app.requestSingleInstanceLock(); if (!gotLock) { signale.fatal("Error: Another instance of eDEX is already running. Cannot proceed."); app.exit(1); } signale.time("Startup"); const electron = require("electron"); require('@electron/remote/main').initialize() const ipc = electron.ipcMain; const path = require("path"); const url = require("url"); const fs = require("fs"); const which = require("which"); const Terminal = require("./classes/terminal.class.js").Terminal; ipc.on("log", (e, type, content) => { signale[type](content); }); var win, tty, extraTtys; const settingsFile = path.join(electron.app.getPath("userData"), "settings.json"); const shortcutsFile = path.join(electron.app.getPath("userData"), "shortcuts.json"); const lastWindowStateFile = path.join(electron.app.getPath("userData"), "lastWindowState.json"); const themesDir = path.join(electron.app.getPath("userData"), "themes"); const innerThemesDir = path.join(__dirname, "assets/themes"); const kblayoutsDir = path.join(electron.app.getPath("userData"), "keyboards"); const innerKblayoutsDir = path.join(__dirname, "assets/kb_layouts"); const fontsDir = path.join(electron.app.getPath("userData"), "fonts"); const innerFontsDir = path.join(__dirname, "assets/fonts"); // Unset proxy env variables to avoid connection problems on the internal websockets // See #222 if (process.env.http_proxy) delete process.env.http_proxy; if (process.env.https_proxy) delete process.env.https_proxy; // Bypass GPU acceleration blocklist, trading a bit of stability for a great deal of performance, mostly on Linux app.commandLine.appendSwitch("ignore-gpu-blocklist"); app.commandLine.appendSwitch("enable-gpu-rasterization"); app.commandLine.appendSwitch("enable-video-decode"); // Fix userData folder not setup on Windows try { fs.mkdirSync(electron.app.getPath("userData")); signale.info(`Created config dir at ${electron.app.getPath("userData")}`); } catch(e) { signale.info(`Base config dir is ${electron.app.getPath("userData")}`); } // Create default settings file if (!fs.existsSync(settingsFile)) { fs.writeFileSync(settingsFile, JSON.stringify({ shell: (process.platform === "win32") ? "powershell.exe" : "bash", shellArgs: '', cwd: electron.app.getPath("userData"), keyboard: "en-US", theme: "tron", termFontSize: 15, audio: true, audioVolume: 1.0, disableFeedbackAudio: false, clockHours: 24, pingAddr: "1.1.1.1", port: 3000, nointro: false, nocursor: false, forceFullscreen: true, allowWindowed: false, excludeThreadsFromToplist: true, hideDotfiles: false, fsListView: false, experimentalGlobeFeatures: false, experimentalFeatures: false }, "", 4)); signale.info(`Default settings written to ${settingsFile}`); } // Create default shortcuts file if (!fs.existsSync(shortcutsFile)) { fs.writeFileSync(shortcutsFile, JSON.stringify([ { type: "app", trigger: "Ctrl+Shift+C", action: "COPY", enabled: true }, { type: "app", trigger: "Ctrl+Shift+V", action: "PASTE", enabled: true }, { type: "app", trigger: "Ctrl+Tab", action: "NEXT_TAB", enabled: true }, { type: "app", trigger: "Ctrl+Shift+Tab", action: "PREVIOUS_TAB", enabled: true }, { type: "app", trigger: "Ctrl+X", action: "TAB_X", enabled: true }, { type: "app", trigger: "Ctrl+Shift+S", action: "SETTINGS", enabled: true }, { type: "app", trigger: "Ctrl+Shift+K", action: "SHORTCUTS", enabled: true }, { type: "app", trigger: "Ctrl+Shift+F", action: "FUZZY_SEARCH", enabled: true }, { type: "app", trigger: "Ctrl+Shift+L", action: "FS_LIST_VIEW", enabled: true }, { type: "app", trigger: "Ctrl+Shift+H", action: "FS_DOTFILES", enabled: true }, { type: "app", trigger: "Ctrl+Shift+P", action: "KB_PASSMODE", enabled: true }, { type: "app", trigger: "Ctrl+Shift+I", action: "DEV_DEBUG", enabled: false }, { type: "app", trigger: "Ctrl+Shift+F5", action: "DEV_RELOAD", enabled: true }, { type: "shell", trigger: "Ctrl+Shift+Alt+Space", action: "neofetch", linebreak: true, enabled: false } ], "", 4)); signale.info(`Default keymap written to ${shortcutsFile}`); } //Create default window state file if(!fs.existsSync(lastWindowStateFile)) { fs.writeFileSync(lastWindowStateFile, JSON.stringify({ useFullscreen: true }, "", 4)); signale.info(`Default last window state written to ${lastWindowStateFile}`); } // Copy default themes & keyboard layouts & fonts signale.pending("Mirroring internal assets..."); try { fs.mkdirSync(themesDir); } catch(e) { // Folder already exists } fs.readdirSync(innerThemesDir).forEach(e => { fs.writeFileSync(path.join(themesDir, e), fs.readFileSync(path.join(innerThemesDir, e), {encoding:"utf-8"})); }); try { fs.mkdirSync(kblayoutsDir); } catch(e) { // Folder already exists } fs.readdirSync(innerKblayoutsDir).forEach(e => { fs.writeFileSync(path.join(kblayoutsDir, e), fs.readFileSync(path.join(innerKblayoutsDir, e), {encoding:"utf-8"})); }); try { fs.mkdirSync(fontsDir); } catch(e) { // Folder already exists } fs.readdirSync(innerFontsDir).forEach(e => { fs.writeFileSync(path.join(fontsDir, e), fs.readFileSync(path.join(innerFontsDir, e))); }); // Version history logging const versionHistoryPath = path.join(electron.app.getPath("userData"), "versions_log.json"); var versionHistory = fs.existsSync(versionHistoryPath) ? require(versionHistoryPath) : {}; var version = app.getVersion(); if (typeof versionHistory[version] === "undefined") { versionHistory[version] = { firstSeen: Date.now(), lastSeen: Date.now() }; } else { versionHistory[version].lastSeen = Date.now(); } fs.writeFileSync(versionHistoryPath, JSON.stringify(versionHistory, 0, 2), {encoding:"utf-8"}); function createWindow(settings) { signale.info("Creating window..."); let display; if (!isNaN(settings.monitor)) { display = electron.screen.getAllDisplays()[settings.monitor] || electron.screen.getPrimaryDisplay(); } else { display = electron.screen.getPrimaryDisplay(); } let {x, y, width, height} = display.bounds; width++; height++; win = new BrowserWindow({ title: "eDEX-UI", x, y, width, height, show: false, resizable: true, movable: settings.allowWindowed || false, fullscreen: settings.forceFullscreen || false, autoHideMenuBar: true, frame: settings.allowWindowed || false, backgroundColor: '#000000', webPreferences: { devTools: true, enableRemoteModule: true, contextIsolation: false, backgroundThrottling: false, webSecurity: true, nodeIntegration: true, nodeIntegrationInSubFrames: false, allowRunningInsecureContent: false, experimentalFeatures: settings.experimentalFeatures || false } }); win.loadURL(url.format({ pathname: path.join(__dirname, 'ui.html'), protocol: 'file:', slashes: true })); signale.complete("Frontend window created!"); win.show(); if (!settings.allowWindowed) { win.setResizable(false); } else if (!require(lastWindowStateFile)["useFullscreen"]) { win.setFullScreen(false); } signale.watch("Waiting for frontend connection..."); } app.on('ready', async () => { signale.pending(`Loading settings file...`); let settings = require(settingsFile); signale.pending(`Resolving shell path...`); settings.shell = await which(settings.shell).catch(e => { throw(e) }); signale.info(`Shell found at ${settings.shell}`); signale.success(`Settings loaded!`); if (!require("fs").existsSync(settings.cwd)) throw new Error("Configured cwd path does not exist."); // See #366 let cleanEnv = await require("shell-env")(settings.shell).catch(e => { throw e; }); Object.assign(cleanEnv, { TERM: "xterm-256color", COLORTERM: "truecolor", TERM_PROGRAM: "eDEX-UI", TERM_PROGRAM_VERSION: app.getVersion() }, settings.env); signale.pending(`Creating new terminal process on port ${settings.port || '3000'}`); tty = new Terminal({ role: "server", shell: settings.shell, params: settings.shellArgs || '', cwd: settings.cwd, env: cleanEnv, port: settings.port || 3000 }); signale.success(`Terminal back-end initialized!`); tty.onclosed = (code, signal) => { tty.ondisconnected = () => {}; signale.complete("Terminal exited", code, signal); app.quit(); }; tty.onopened = () => { signale.success("Connected to frontend!"); signale.timeEnd("Startup"); }; tty.onresized = (cols, rows) => { signale.info("Resized TTY to ", cols, rows); }; tty.ondisconnected = () => { signale.error("Lost connection to frontend"); signale.watch("Waiting for frontend connection..."); }; // Support for multithreaded systeminformation calls signale.pending("Starting multithreaded calls controller..."); require("./_multithread.js"); createWindow(settings); // Support for more terminals, used for creating tabs (currently limited to 4 extra terms) extraTtys = {}; let basePort = settings.port || 3000; basePort = Number(basePort) + 2; for (let i = 0; i < 4; i++) { extraTtys[basePort+i] = null; } ipc.on("ttyspawn", (e, arg) => { let port = null; Object.keys(extraTtys).forEach(key => { if (extraTtys[key] === null && port === null) { extraTtys[key] = {}; port = key; } }); if (port === null) { signale.error("TTY spawn denied (Reason: exceeded max TTYs number)"); e.sender.send("ttyspawn-reply", "ERROR: max number of ttys reached"); } else { signale.pending(`Creating new TTY process on port ${port}`); let term = new Terminal({ role: "server", shell: settings.shell, params: settings.shellArgs || '', cwd: tty.tty._cwd || settings.cwd, env: cleanEnv, port: port }); signale.success(`New terminal back-end initialized at ${port}`); term.onclosed = (code, signal) => { term.ondisconnected = () => {}; term.wss.close(); signale.complete(`TTY exited at ${port}`, code, signal); extraTtys[term.port] = null; term = null; }; term.onopened = pid => { signale.success(`TTY ${port} connected to frontend (process PID ${pid})`); }; term.onresized = () => {}; term.ondisconnected = () => { term.onclosed = () => {}; term.close(); term.wss.close(); extraTtys[term.port] = null; term = null; }; extraTtys[port] = term; e.sender.send("ttyspawn-reply", "SUCCESS: "+port); } }); // Backend support for theme and keyboard hotswitch let themeOverride = null; let kbOverride = null; ipc.on("getThemeOverride", (e, arg) => { e.sender.send("getThemeOverride", themeOverride); }); ipc.on("getKbOverride", (e, arg) => { e.sender.send("getKbOverride", kbOverride); }); ipc.on("setThemeOverride", (e, arg) => { themeOverride = arg; }); ipc.on("setKbOverride", (e, arg) => { kbOverride = arg; }); }); app.on('web-contents-created', (e, contents) => { // Prevent creating more than one window contents.on('new-window', (e, url) => { e.preventDefault(); shell.openExternal(url); }); // Prevent loading something else than the UI contents.on('will-navigate', (e, url) => { if (url !== contents.getURL()) e.preventDefault(); }); }); app.on('window-all-closed', () => { signale.info("All windows closed"); app.quit(); }); app.on('before-quit', () => { tty.close(); Object.keys(extraTtys).forEach(key => { if (extraTtys[key] !== null) { extraTtys[key].close(); } }); signale.complete("Shutting down..."); }); ================================================ FILE: src/_multithread.js ================================================ const cluster = require("cluster"); if (cluster.isMaster) { const electron = require("electron"); const ipc = electron.ipcMain; const signale = require("signale"); // Also, leave a core available for the renderer process const osCPUs = require("os").cpus().length - 1; // See #904 const numCPUs = (osCPUs > 7) ? 7 : osCPUs; const si = require("systeminformation"); cluster.setupMaster({ exec: require("path").join(__dirname, "_multithread.js") }); let workers = []; cluster.on("fork", worker => { workers.push(worker.id); }); for (let i = 0; i < numCPUs; i++) { cluster.fork(); } signale.success("Multithreaded controller ready"); var lastID = 0; function dispatch(type, id, arg) { let selectedID = lastID+1; if (selectedID > numCPUs-1) selectedID = 0; cluster.workers[workers[selectedID]].send(JSON.stringify({ id, type, arg })); lastID = selectedID; } var queue = {}; ipc.on("systeminformation-call", (e, type, id, ...args) => { if (!si[type]) { signale.warn("Illegal request for systeminformation"); return; } if (args.length > 1 || workers.length <= 0) { si[type](...args).then(res => { if (e.sender) { e.sender.send("systeminformation-reply-"+id, res); } }); } else { queue[id] = e.sender; dispatch(type, id, args[0]); } }); cluster.on("message", (worker, msg) => { msg = JSON.parse(msg); try { if (!queue[msg.id].isDestroyed()) { queue[msg.id].send("systeminformation-reply-"+msg.id, msg.res); delete queue[msg.id]; } } catch(e) { // Window has been closed, ignore. } }); } else if (cluster.isWorker) { const signale = require("signale"); const si = require("systeminformation"); signale.info("Multithread worker started at "+process.pid); process.on("message", msg => { msg = JSON.parse(msg); si[msg.type](msg.arg).then(res => { process.send(JSON.stringify({ id: msg.id, res })); }); }); } ================================================ FILE: src/_renderer.js ================================================ // Disable eval() window.eval = global.eval = function () { throw new Error("eval() is disabled for security reasons."); }; // Security helper :) window._escapeHtml = text => { let map = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return text.replace(/[&<>"']/g, m => {return map[m];}); }; window._encodePathURI = uri => { return encodeURI(uri).replace(/#/g, "%23"); }; window._purifyCSS = str => { if (typeof str === "undefined") return ""; if (typeof str !== "string") { str = str.toString(); } return str.replace(/[<]/g, ""); }; window._delay = ms => { return new Promise((resolve, reject) => { setTimeout(resolve, ms); }); }; // Initiate basic error handling window.onerror = (msg, path, line, col, error) => { document.getElementById("boot_screen").innerHTML += `${error} : ${msg}
==> at ${path} ${line}:${col}`; }; const path = require("path"); const fs = require("fs"); const electron = require("electron"); const remote = require("@electron/remote"); const ipc = electron.ipcRenderer; const settingsDir = remote.app.getPath("userData"); const themesDir = path.join(settingsDir, "themes"); const keyboardsDir = path.join(settingsDir, "keyboards"); const fontsDir = path.join(settingsDir, "fonts"); const settingsFile = path.join(settingsDir, "settings.json"); const shortcutsFile = path.join(settingsDir, "shortcuts.json"); const lastWindowStateFile = path.join(settingsDir, "lastWindowState.json"); // Load config window.settings = require(settingsFile); window.shortcuts = require(shortcutsFile); window.lastWindowState = require(lastWindowStateFile); // Load CLI parameters if (remote.process.argv.includes("--nointro")) { window.settings.nointroOverride = true; } else { window.settings.nointroOverride = false; } if (electron.remote.process.argv.includes("--nocursor")) { window.settings.nocursorOverride = true; } else { window.settings.nocursorOverride = false; } // Retrieve theme override (hotswitch) ipc.once("getThemeOverride", (e, theme) => { if (theme !== null) { window.settings.theme = theme; window.settings.nointroOverride = true; _loadTheme(require(path.join(themesDir, window.settings.theme+".json"))); } else { _loadTheme(require(path.join(themesDir, window.settings.theme+".json"))); } }); ipc.send("getThemeOverride"); // Same for keyboard override/hotswitch ipc.once("getKbOverride", (e, layout) => { if (layout !== null) { window.settings.keyboard = layout; window.settings.nointroOverride = true; } }); ipc.send("getKbOverride"); // Load UI theme window._loadTheme = theme => { if (document.querySelector("style.theming")) { document.querySelector("style.theming").remove(); } // Load fonts let mainFont = new FontFace(theme.cssvars.font_main, `url("${path.join(fontsDir, theme.cssvars.font_main.toLowerCase().replace(/ /g, '_')+'.woff2').replace(/\\/g, '/')}")`); let lightFont = new FontFace(theme.cssvars.font_main_light, `url("${path.join(fontsDir, theme.cssvars.font_main_light.toLowerCase().replace(/ /g, '_')+'.woff2').replace(/\\/g, '/')}")`); let termFont = new FontFace(theme.terminal.fontFamily, `url("${path.join(fontsDir, theme.terminal.fontFamily.toLowerCase().replace(/ /g, '_')+'.woff2').replace(/\\/g, '/')}")`); document.fonts.add(mainFont); document.fonts.load("12px "+theme.cssvars.font_main); document.fonts.add(lightFont); document.fonts.load("12px "+theme.cssvars.font_main_light); document.fonts.add(termFont); document.fonts.load("12px "+theme.terminal.fontFamily); document.querySelector("head").innerHTML += ``; window.theme = theme; window.theme.r = theme.colors.r; window.theme.g = theme.colors.g; window.theme.b = theme.colors.b; }; function initGraphicalErrorHandling() { window.edexErrorsModals = []; window.onerror = (msg, path, line, col, error) => { let errorModal = new Modal({ type: "error", title: error, message: `${msg}
at ${path} ${line}:${col}` }); window.edexErrorsModals.push(errorModal); ipc.send("log", "error", `${error}: ${msg}`); ipc.send("log", "debug", `at ${path} ${line}:${col}`); }; } function waitForFonts() { return new Promise(resolve => { if (document.readyState !== "complete" || document.fonts.status !== "loaded") { document.addEventListener("readystatechange", () => { if (document.readyState === "complete") { if (document.fonts.status === "loaded") { resolve(); } else { document.fonts.onloadingdone = () => { if (document.fonts.status === "loaded") resolve(); }; } } }); } else { resolve(); } }); } // A proxy function used to add multithreading to systeminformation calls - see backend process manager @ _multithread.js function initSystemInformationProxy() { const { nanoid } = require("nanoid/non-secure"); window.si = new Proxy({}, { apply: () => {throw new Error("Cannot use sysinfo proxy directly as a function")}, set: () => {throw new Error("Cannot set a property on the sysinfo proxy")}, get: (target, prop, receiver) => { return function(...args) { let callback = (typeof args[args.length - 1] === "function") ? true : false; return new Promise((resolve, reject) => { let id = nanoid(); ipc.once("systeminformation-reply-"+id, (e, res) => { if (callback) { args[args.length - 1](res); } resolve(res); }); ipc.send("systeminformation-call", prop, id, ...args); }); }; } }); } // Init audio window.audioManager = new AudioManager(); // See #223 electron.remote.app.focus(); let i = 0; if (window.settings.nointro || window.settings.nointroOverride) { initGraphicalErrorHandling(); initSystemInformationProxy(); document.getElementById("boot_screen").remove(); document.body.setAttribute("class", ""); waitForFonts().then(initUI); } else { displayLine(); } // Startup boot log function displayLine() { let bootScreen = document.getElementById("boot_screen"); let log = fs.readFileSync(path.join(__dirname, "assets", "misc", "boot_log.txt")).toString().split('\n'); function isArchUser() { return require("os").platform() === "linux" && fs.existsSync("/etc/os-release") && fs.readFileSync("/etc/os-release").toString().includes("arch"); } if (typeof log[i] === "undefined") { setTimeout(displayTitleScreen, 300); return; } if (log[i] === "Boot Complete") { window.audioManager.granted.play(); } else { window.audioManager.stdout.play(); } bootScreen.innerHTML += log[i]+"
"; i++; switch(true) { case i === 2: bootScreen.innerHTML += `eDEX-UI Kernel version ${electron.remote.app.getVersion()} boot at ${Date().toString()}; root:xnu-1699.22.73~1/RELEASE_X86_64`; case i === 4: setTimeout(displayLine, 500); break; case i > 4 && i < 25: setTimeout(displayLine, 30); break; case i === 25: setTimeout(displayLine, 400); break; case i === 42: setTimeout(displayLine, 300); break; case i > 42 && i < 82: setTimeout(displayLine, 25); break; case i === 83: if (isArchUser()) bootScreen.innerHTML += "btw i use arch
"; setTimeout(displayLine, 25); break; case i >= log.length-2 && i < log.length: setTimeout(displayLine, 300); break; default: setTimeout(displayLine, Math.pow(1 - (i/1000), 3)*25); } } // Show "logo" and background grid async function displayTitleScreen() { let bootScreen = document.getElementById("boot_screen"); if (bootScreen === null) { bootScreen = document.createElement("section"); bootScreen.setAttribute("id", "boot_screen"); bootScreen.setAttribute("style", "z-index: 9999999"); document.body.appendChild(bootScreen); } bootScreen.innerHTML = ""; window.audioManager.theme.play(); await _delay(400); document.body.setAttribute("class", ""); bootScreen.setAttribute("class", "center"); bootScreen.innerHTML = "

eDEX-UI

"; let title = document.querySelector("section > h1"); await _delay(200); document.body.setAttribute("class", "solidBackground"); await _delay(100); title.setAttribute("style", `background-color: rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b});border-bottom: 5px solid rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b});`); await _delay(300); title.setAttribute("style", `border: 5px solid rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b});`); await _delay(100); title.setAttribute("style", ""); title.setAttribute("class", "glitch"); await _delay(500); document.body.setAttribute("class", ""); title.setAttribute("class", ""); title.setAttribute("style", `border: 5px solid rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b});`); await _delay(1000); if (window.term) { bootScreen.remove(); return true; } initGraphicalErrorHandling(); initSystemInformationProxy(); waitForFonts().then(() => { bootScreen.remove(); initUI(); }); } // Returns the user's desired display name async function getDisplayName() { let user = settings.username || null; if (user) return user; try { user = await require("username")(); } catch (e) {} return user; } // Create the UI's html structure and initialize the terminal client and the keyboard async function initUI() { document.body.innerHTML += `

PANEL

SYSTEM

TERMINAL

MAIN SHELL

PANEL

NETWORK

`; await _delay(10); window.audioManager.expand.play(); document.getElementById("main_shell").setAttribute("style", "height:0%;margin-bottom:30vh;"); await _delay(500); document.getElementById("main_shell").setAttribute("style", "margin-bottom: 30vh;"); document.querySelector("#main_shell > h3.title").setAttribute("style", ""); await _delay(700); document.getElementById("main_shell").setAttribute("style", "opacity: 0;"); document.body.innerHTML += `
`; window.keyboard = new Keyboard({ layout: path.join(keyboardsDir, settings.keyboard+".json"), container: "keyboard" }); await _delay(10); document.getElementById("main_shell").setAttribute("style", ""); await _delay(270); let greeter = document.getElementById("main_shell_greeting"); getDisplayName().then(user => { if (user) { greeter.innerHTML += `Welcome back, ${user}`; } else { greeter.innerHTML += "Welcome back"; } }); greeter.setAttribute("style", "opacity: 1;"); document.getElementById("filesystem").setAttribute("style", ""); document.getElementById("keyboard").setAttribute("style", ""); document.getElementById("keyboard").setAttribute("class", "animation_state_1"); window.audioManager.keyboard.play(); await _delay(100); document.getElementById("keyboard").setAttribute("class", "animation_state_1 animation_state_2"); await _delay(1000); greeter.setAttribute("style", "opacity: 0;"); await _delay(100); document.getElementById("keyboard").setAttribute("class", ""); await _delay(400); greeter.remove(); // Initialize modules window.mods = {}; // Left column window.mods.clock = new Clock("mod_column_left"); window.mods.sysinfo = new Sysinfo("mod_column_left"); window.mods.hardwareInspector = new HardwareInspector("mod_column_left"); window.mods.cpuinfo = new Cpuinfo("mod_column_left"); window.mods.ramwatcher = new RAMwatcher("mod_column_left"); window.mods.toplist = new Toplist("mod_column_left"); // Right column window.mods.netstat = new Netstat("mod_column_right"); window.mods.globe = new LocationGlobe("mod_column_right"); window.mods.conninfo = new Conninfo("mod_column_right"); // Fade-in animations document.querySelectorAll(".mod_column").forEach(e => { e.setAttribute("class", "mod_column activated"); }); let i = 0; let left = document.querySelectorAll("#mod_column_left > div"); let right = document.querySelectorAll("#mod_column_right > div"); let x = setInterval(() => { if (!left[i] && !right[i]) { clearInterval(x); } else { window.audioManager.panels.play(); if (left[i]) { left[i].setAttribute("style", "animation-play-state: running;"); } if (right[i]) { right[i].setAttribute("style", "animation-play-state: running;"); } i++; } }, 500); await _delay(100); // Initialize the terminal let shellContainer = document.getElementById("main_shell"); shellContainer.innerHTML += `
  • MAIN SHELL

  • EMPTY

  • EMPTY

  • EMPTY

  • EMPTY


            

            

            

            

        
`; window.term = { 0: new Terminal({ role: "client", parentId: "terminal0", port: window.settings.port || 3000 }) }; window.currentTerm = 0; window.term[0].onprocesschange = p => { document.getElementById("shell_tab0").innerHTML = `

MAIN - ${p}

`; }; // Prevent losing hardware keyboard focus on the terminal when using touch keyboard window.onmouseup = e => { if (window.keyboard.linkedToTerm) window.term[window.currentTerm].term.focus(); }; window.term[0].term.writeln("\033[1m"+`Welcome to eDEX-UI v${electron.remote.app.getVersion()} - Electron v${process.versions.electron}`+"\033[0m"); await _delay(100); window.fsDisp = new FilesystemDisplay({ parentId: "filesystem" }); await _delay(200); document.getElementById("filesystem").setAttribute("style", "opacity: 1;"); // Resend terminal CWD to fsDisp if we're hot reloading if (window.performance.navigation.type === 1) { window.term[window.currentTerm].resendCWD(); } await _delay(200); window.updateCheck = new UpdateChecker(); } window.themeChanger = theme => { ipc.send("setThemeOverride", theme); setTimeout(() => { window.location.reload(true); }, 100); }; window.remakeKeyboard = layout => { document.getElementById("keyboard").innerHTML = ""; window.keyboard = new Keyboard({ layout: path.join(keyboardsDir, layout+".json" || settings.keyboard+".json"), container: "keyboard" }); ipc.send("setKbOverride", layout); }; window.focusShellTab = number => { window.audioManager.folder.play(); if (number !== window.currentTerm && window.term[number]) { window.currentTerm = number; document.querySelectorAll(`ul#main_shell_tabs > li:not(:nth-child(${number+1}))`).forEach(e => { e.setAttribute("class", ""); }); document.getElementById("shell_tab"+number).setAttribute("class", "active"); document.querySelectorAll(`div#main_shell_innercontainer > pre:not(:nth-child(${number+1}))`).forEach(e => { e.setAttribute("class", ""); }); document.getElementById("terminal"+number).setAttribute("class", "active"); window.term[number].fit(); window.term[number].term.focus(); window.term[number].resendCWD(); window.fsDisp.followTab(); } else if (number > 0 && number <= 4 && window.term[number] !== null && typeof window.term[number] !== "object") { window.term[number] = null; document.getElementById("shell_tab"+number).innerHTML = "

LOADING...

"; ipc.send("ttyspawn", "true"); ipc.once("ttyspawn-reply", (e, r) => { if (r.startsWith("ERROR")) { document.getElementById("shell_tab"+number).innerHTML = "

ERROR

"; } else if (r.startsWith("SUCCESS")) { let port = Number(r.substr(9)); window.term[number] = new Terminal({ role: "client", parentId: "terminal"+number, port }); window.term[number].onclose = e => { delete window.term[number].onprocesschange; document.getElementById("shell_tab"+number).innerHTML = "

EMPTY

"; document.getElementById("terminal"+number).innerHTML = ""; window.term[number].term.dispose(); delete window.term[number]; window.useAppShortcut("PREVIOUS_TAB"); }; window.term[number].onprocesschange = p => { document.getElementById("shell_tab"+number).innerHTML = `

#${number+1} - ${p}

`; }; document.getElementById("shell_tab"+number).innerHTML = `

::${port}

`; setTimeout(() => { window.focusShellTab(number); }, 500); } }); } }; // Settings editor window.openSettings = async () => { if (document.getElementById("settingsEditor")) return; // Build lists of available keyboards, themes, monitors let keyboards, themes, monitors, ifaces; fs.readdirSync(keyboardsDir).forEach(kb => { if (!kb.endsWith(".json")) return; kb = kb.replace(".json", ""); if (kb === window.settings.keyboard) return; keyboards += ``; }); fs.readdirSync(themesDir).forEach(th => { if (!th.endsWith(".json")) return; th = th.replace(".json", ""); if (th === window.settings.theme) return; themes += ``; }); for (let i = 0; i < electron.remote.screen.getAllDisplays().length; i++) { if (i !== window.settings.monitor) monitors += ``; } let nets = await window.si.networkInterfaces(); nets.forEach(net => { if (net.iface !== window.mods.netstat.iface) ifaces += ``; }); // Unlink the tactile keyboard from the terminal emulator to allow filling in the settings fields window.keyboard.detach(); new Modal({ type: "custom", title: `Settings (v${electron.remote.app.getVersion()})`, html: `
Key Description Value
shell The program to run as a terminal emulator
shellArgs Arguments to pass to the shell
cwd Working Directory to start in
env Custom shell environment override
username Custom username to display at boot
keyboard On-screen keyboard layout code
theme Name of the theme to load
termFontSize Size of the terminal text in pixels
audio Activate audio sound effects
audioVolume Set default volume for sound effects (0.0 - 1.0)
disableFeedbackAudio Disable recurring feedback sound FX (input/output, mostly)
port Local port to use for UI-shell connection
pingAddr IPv4 address to test Internet connectivity
clockHours Clock format (12/24 hours)
monitor Which monitor to spawn the UI in (defaults to primary display)
nointro Skip the intro boot log and logo${(window.settings.nointroOverride) ? " (Currently overridden by CLI flag)" : ""}
nocursor Hide the mouse cursor${(window.settings.nocursorOverride) ? " (Currently overridden by CLI flag)" : ""}
iface Override the interface used for network monitoring
allowWindowed Allow using F11 key to set the UI in windowed mode
keepGeometry Try to keep a 16:9 aspect ratio in windowed mode
excludeThreadsFromToplist Display threads in the top processes list
hideDotfiles Hide files and directories starting with a dot in file display
fsListView Show files in a more detailed list instead of an icon grid
experimentalGlobeFeatures Toggle experimental features for the network globe
experimentalFeatures Toggle Chrome's experimental web features (DANGEROUS)
Loaded values from memory

`, buttons: [ {label: "Open in External Editor", action:`electron.shell.openPath('${settingsFile}');electronWin.minimize();`}, {label: "Save to Disk", action: "window.writeSettingsFile()"}, {label: "Reload UI", action: "window.location.reload(true);"}, {label: "Restart eDEX", action: "electron.remote.app.relaunch();electron.remote.app.quit();"} ] }, () => { // Link the keyboard back to the terminal window.keyboard.attach(); // Focus back on the term window.term[window.currentTerm].term.focus(); }); }; window.writeFile = (path) => { fs.writeFile(path, document.getElementById("fileEdit").value, "utf-8", () => { document.getElementById("fedit-status").innerHTML = "File saved."; }); }; window.writeSettingsFile = () => { window.settings = { shell: document.getElementById("settingsEditor-shell").value, shellArgs: document.getElementById("settingsEditor-shellArgs").value, cwd: document.getElementById("settingsEditor-cwd").value, env: document.getElementById("settingsEditor-env").value, username: document.getElementById("settingsEditor-username").value, keyboard: document.getElementById("settingsEditor-keyboard").value, theme: document.getElementById("settingsEditor-theme").value, termFontSize: Number(document.getElementById("settingsEditor-termFontSize").value), audio: (document.getElementById("settingsEditor-audio").value === "true"), audioVolume: Number(document.getElementById("settingsEditor-audioVolume").value), disableFeedbackAudio: (document.getElementById("settingsEditor-disableFeedbackAudio").value === "true"), pingAddr: document.getElementById("settingsEditor-pingAddr").value, clockHours: Number(document.getElementById("settingsEditor-clockHours").value), port: Number(document.getElementById("settingsEditor-port").value), monitor: Number(document.getElementById("settingsEditor-monitor").value), nointro: (document.getElementById("settingsEditor-nointro").value === "true"), nocursor: (document.getElementById("settingsEditor-nocursor").value === "true"), iface: document.getElementById("settingsEditor-iface").value, allowWindowed: (document.getElementById("settingsEditor-allowWindowed").value === "true"), forceFullscreen: window.settings.forceFullscreen, keepGeometry: (document.getElementById("settingsEditor-keepGeometry").value === "true"), excludeThreadsFromToplist: (document.getElementById("settingsEditor-excludeThreadsFromToplist").value === "true"), hideDotfiles: (document.getElementById("settingsEditor-hideDotfiles").value === "true"), fsListView: (document.getElementById("settingsEditor-fsListView").value === "true"), experimentalGlobeFeatures: (document.getElementById("settingsEditor-experimentalGlobeFeatures").value === "true"), experimentalFeatures: (document.getElementById("settingsEditor-experimentalFeatures").value === "true") }; Object.keys(window.settings).forEach(key => { if (window.settings[key] === "undefined") { delete window.settings[key]; } }); fs.writeFileSync(settingsFile, JSON.stringify(window.settings, "", 4)); document.getElementById("settingsEditorStatus").innerText = "New values written to settings.json file at "+new Date().toTimeString(); }; window.toggleFullScreen = () => { let useFullscreen = (electronWin.isFullScreen() ? false : true); electronWin.setFullScreen(useFullscreen); //Update settings window.lastWindowState["useFullscreen"] = useFullscreen; fs.writeFileSync(lastWindowStateFile, JSON.stringify(window.lastWindowState, "", 4)); }; // Display available keyboard shortcuts and custom shortcuts helper window.openShortcutsHelp = () => { if (document.getElementById("settingsEditor")) return; const shortcutsDefinition = { "COPY": "Copy selected buffer from the terminal.", "PASTE": "Paste system clipboard to the terminal.", "NEXT_TAB": "Switch to the next opened terminal tab (left to right order).", "PREVIOUS_TAB": "Switch to the previous opened terminal tab (right to left order).", "TAB_X": "Switch to terminal tab X, or create it if it hasn't been opened yet.", "SETTINGS": "Open the settings editor.", "SHORTCUTS": "List and edit available keyboard shortcuts.", "FUZZY_SEARCH": "Search for entries in the current working directory.", "FS_LIST_VIEW": "Toggle between list and grid view in the file browser.", "FS_DOTFILES": "Toggle hidden files and directories in the file browser.", "KB_PASSMODE": "Toggle the on-screen keyboard's \"Password Mode\", which allows you to safely
type sensitive information even if your screen might be recorded (disable visual input feedback).", "DEV_DEBUG": "Open Chromium Dev Tools, for debugging purposes.", "DEV_RELOAD": "Trigger front-end hot reload." }; let appList = ""; window.shortcuts.filter(e => e.type === "app").forEach(cut => { let action = (cut.action.startsWith("TAB_")) ? "TAB_X" : cut.action; appList += ` ${(cut.enabled) ? 'YES' : 'NO'} ${shortcutsDefinition[action]} `; }); let customList = ""; window.shortcuts.filter(e => e.type === "shell").forEach(cut => { customList += ` ${(cut.enabled) ? 'YES' : 'NO'} `; }); window.keyboard.detach(); new Modal({ type: "custom", title: `Available Keyboard Shortcuts (v${electron.remote.app.getVersion()})`, html: `
Using either the on-screen or a physical keyboard, you can use the following shortcuts:
Emulator shortcuts ${appList}
Enabled Trigger Action

Custom command shortcuts ${customList}
Enabled Trigger Command

`, buttons: [ {label: "Open Shortcuts File", action:`electron.shell.openPath('${shortcutsFile}');electronWin.minimize();`}, {label: "Reload UI", action: "window.location.reload(true);"}, ] }, () => { window.keyboard.attach(); window.term[window.currentTerm].term.focus(); }); let wrap1 = document.getElementById('shortcutsHelpAccordeon1'); let wrap2 = document.getElementById('shortcutsHelpAccordeon2'); wrap1.addEventListener('toggle', e => { wrap2.open = !wrap1.open; }); wrap2.addEventListener('toggle', e => { wrap1.open = !wrap2.open; }); }; window.useAppShortcut = action => { switch(action) { case "COPY": window.term[window.currentTerm].clipboard.copy(); return true; case "PASTE": window.term[window.currentTerm].clipboard.paste(); return true; case "NEXT_TAB": if (window.term[window.currentTerm+1]) { window.focusShellTab(window.currentTerm+1); } else if (window.term[window.currentTerm+2]) { window.focusShellTab(window.currentTerm+2); } else if (window.term[window.currentTerm+3]) { window.focusShellTab(window.currentTerm+3); } else if (window.term[window.currentTerm+4]) { window.focusShellTab(window.currentTerm+4); } else { window.focusShellTab(0); } return true; case "PREVIOUS_TAB": let i = window.currentTerm || 4; if (window.term[i] && i !== window.currentTerm) { window.focusShellTab(i); } else if (window.term[i-1]) { window.focusShellTab(i-1); } else if (window.term[i-2]) { window.focusShellTab(i-2); } else if (window.term[i-3]) { window.focusShellTab(i-3); } else if (window.term[i-4]) { window.focusShellTab(i-4); } return true; case "TAB_1": window.focusShellTab(0); return true; case "TAB_2": window.focusShellTab(1); return true; case "TAB_3": window.focusShellTab(2); return true; case "TAB_4": window.focusShellTab(3); return true; case "TAB_5": window.focusShellTab(4); return true; case "SETTINGS": window.openSettings(); return true; case "SHORTCUTS": window.openShortcutsHelp(); return true; case "FUZZY_SEARCH": window.activeFuzzyFinder = new FuzzyFinder(); return true; case "FS_LIST_VIEW": window.fsDisp.toggleListview(); return true; case "FS_DOTFILES": window.fsDisp.toggleHidedotfiles(); return true; case "KB_PASSMODE": window.keyboard.togglePasswordMode(); return true; case "DEV_DEBUG": electron.remote.getCurrentWindow().webContents.toggleDevTools(); return true; case "DEV_RELOAD": window.location.reload(true); return true; default: console.warn(`Unknown "${action}" app shortcut action`); return false; } }; // Global keyboard shortcuts const globalShortcut = electron.remote.globalShortcut; globalShortcut.unregisterAll(); window.registerKeyboardShortcuts = () => { window.shortcuts.forEach(cut => { if (!cut.enabled) return; if (cut.type === "app") { if (cut.action === "TAB_X") { for (let i = 1; i <= 5; i++) { let trigger = cut.trigger.replace("X", i); let dfn = () => { window.useAppShortcut(`TAB_${i}`) }; globalShortcut.register(trigger, dfn); } } else { globalShortcut.register(cut.trigger, () => { window.useAppShortcut(cut.action); }); } } else if (cut.type === "shell") { globalShortcut.register(cut.trigger, () => { let fn = (cut.linebreak) ? "writelr" : "write"; window.term[window.currentTerm][fn](cut.action); }); } else { console.warn(`${cut.trigger} has unknown type`); } }); }; window.registerKeyboardShortcuts(); // See #361 window.addEventListener("focus", () => { window.registerKeyboardShortcuts(); }); window.addEventListener("blur", () => { globalShortcut.unregisterAll(); }); // Prevent showing menu, exiting fullscreen or app with keyboard shortcuts document.addEventListener("keydown", e => { if (e.key === "Alt") { e.preventDefault(); } if (e.code.startsWith("Alt") && e.ctrlKey && e.shiftKey) { e.preventDefault(); } if (e.key === "F11" && !settings.allowWindowed) { e.preventDefault(); } if (e.code === "KeyD" && e.ctrlKey) { e.preventDefault(); } if (e.code === "KeyA" && e.ctrlKey) { e.preventDefault(); } }); // Fix #265 window.addEventListener("keyup", e => { if (require("os").platform() === "win32" && e.key === "F4" && e.altKey === true) { electron.remote.app.quit(); } }); // Fix double-tap zoom on touchscreens electron.webFrame.setVisualZoomLevelLimits(1, 1); // Resize terminal with window window.onresize = () => { if (typeof window.currentTerm !== "undefined") { if (typeof window.term[window.currentTerm] !== "undefined") { window.term[window.currentTerm].fit(); } } }; // See #413 window.resizeTimeout = null; let electronWin = electron.remote.getCurrentWindow(); electronWin.on("resize", () => { if (settings.keepGeometry === false) return; clearTimeout(window.resizeTimeout); window.resizeTimeout = setTimeout(() => { let win = electron.remote.getCurrentWindow(); if (win.isFullScreen()) return false; if (win.isMaximized()) { win.unmaximize(); win.setFullScreen(true); return false; } let size = win.getSize(); if (size[0] >= size[1]) { win.setSize(size[0], parseInt(size[0] * 9 / 16)); } else { win.setSize(size[1], parseInt(size[1] * 9 / 16)); } }, 100); }); electronWin.on("leave-full-screen", () => { electron.remote.getCurrentWindow().setSize(960, 540); }); ================================================ FILE: src/assets/css/boot_screen.css ================================================ section#boot_screen { position: fixed; top: 0vh; left: 0vh; width: 100%; height: 100%; padding: 0vh; margin: 0vh; overflow: hidden; font-family: monospace; font-size: 1.4vh; text-align: left; display: flex; align-items: flex-end; justify-content: flex-start; } section#boot_screen.center { align-items: center; justify-content: center; } section#boot_screen h1 { font-family: var(--font_main); font-size: 10vh; text-align: center; border-bottom: 0.46vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); padding-top: 2vh; padding-right: 2vh; padding-left: 1.5vh; background-color: transparent; opacity: 0; animation-name: fadeInTitle; animation-duration: 300ms; animation-timing-function: linear; animation-fill-mode: forwards; animation-iteration-count: 1; } section#boot_screen h1.glitch { border: none; color: transparent; } @keyframes fadeInTitle { from { opacity: 0; } to { opacity: 1; } } section#boot_screen h1::before { content: "eDEX-UI"; display: block; transform: translateY(100%) translateX(-2%); clip-path: polygon(100% 0%, 100% 40%, 0% 40%, 0% 0%); color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.8); animation-name: derezzer_top; animation-duration: 50ms; animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate-reverse; animation-play-state: paused; height: 0px; opacity: 0; } section#boot_screen h1.glitch::before { height: auto; opacity: 1; animation-play-state: running; } @keyframes derezzer_top { from {transform: translateY(100%) translateX(-1%);} to {transform: translateY(100%) translateX(-5%);} } section#boot_screen h1::after { content: "eDEX-UI"; display: block; transform: translateY(-100%) translateX(2%); clip-path: polygon(100% 40%, 100% 100%, 0% 100%, 0% 40%); color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.9); animation-name: derezzer_bottom; animation-duration: 50ms; animation-timing-function: linear; animation-iteration-count: infinite; animation-direction: alternate-reverse; animation-play-state: paused; height: 0px; opacity: 0; } section#boot_screen h1.glitch::after { height: auto; opacity: 1; animation-play-state: running; } @keyframes derezzer_bottom { from {transform: translateY(-100%) translateX(1%);} to {transform: translateY(-100%) translateX(3%);} } ================================================ FILE: src/assets/css/extra_ratios.css ================================================ /* Support for other screen ratios than 16:9 */ @media (aspect-ratio: 16/10) { section#filesystem > h3.title { width: 43.5vw; } div.keyboard_key { height: 2.5vw; min-width: 2.5vw; } div.keyboard_row:last-child { left: 0.8vh; } div.keyboard_row:last-child div { white-space: nowrap; } div.keyboard_row:last-child div:first-child { width: 6.5vh; min-width: 6.5vh; } div.keyboard_row:last-child div#keyboard_spacebar { width: 45vh; min-width: 45vh; } div.keyboard_row#row_2 > div.keyboard_enter { top: -0.9vh; right: -0.9vh; } /* See #317 */ section.mod_column { width: 17.5%; } div#mod_toplist i { font-size: 1.10vh; } table#mod_toplist_table { padding-left: 0.2vh; } div#mod_toplist::after { right: -15.6vw; } div#mod_netstat_innercontainer { font-size: 1vh; } div#mod_conninfo canvas { height: 10vh; } } @media (aspect-ratio: 64/27) { /* Commercial name of 64/27 ratio is 21:9 */ div.keyboard_row#row_1 > div.keyboard_enter { height: 2.1vw; margin-top: 0.2vh; } div.keyboard_row#row_2 > div.keyboard_enter { height: 6vh; } div.keyboard_key#keyboard_spacebar { width: 60vh; } div.keyboard_row#row_space { left: 1.6vw; } div#mod_cpuinfo > div > div { width: 94%; } table#mod_toplist_table { margin-top: -1vh; } div#mod_netstat_inner { width: 100%; } div#mod_globe canvas { width: 85%; } div#mod_conninfo canvas { height: 8vh; } } @media (aspect-ratio: 5/4), (aspect-ratio: 4/3) { section#filesystem { display: none; } div.keyboard_row#row_1 > div.keyboard_enter { height: 4.9vh; left: 0.1vh } section#keyboard div.keyboard_key { margin: 0vh 1vh; } section#keyboard div.keyboard_key#keyboard_spacebar { min-width: 36vw; width: 36vw; } div.keyboard_key > *:not(h1) { font-size: 1.2vh; } div.keyboard_key > h2 { top: 0.1vh; left: 0.1vh; } div.keyboard_key > h3 { bottom: 0.1vh; right: 0.1vh; } div#mod_clock h1 > * { margin: 0vh -0.1vh; } div#mod_sysinfo h1 { font-size: 1vh; } div#mod_sysinfo h2 { font-size: 1.1vh; } div#mod_cpuinfo_innercontainer > h1:first-child > i { font-size: 0.8vh; } div#mod_cpuinfo h1 { font-size: 1.1vh; } div#mod_cpuinfo i { font-size: 1vh; } div#mod_ramwatcher_inner > h1:first-child > i { font-size: 0.8vh; } div#mod_toplist i { opacity: 0; } table#mod_toplist_table td { font-size: 1.1vh; } table#mod_toplist_table td:nth-child(2) { min-width: 4vw; max-width: 4vw; } div#mod_netstat_inner > h1:first-child > i { opacity: 0; } div#mod_netstat_innercontainer { grid-template-columns: 1fr 1fr; grid-template-rows: 1fr 1fr; grid-template-areas: "state ping" "ip ip"; } div#mod_netstat_innercontainer div:nth-child(1) { grid-area: state; } div#mod_netstat_innercontainer div:nth-child(2) { grid-area: ip; border-top: 2px solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.2); } div#mod_netstat_innercontainer div:nth-child(2) > * { position: relative; top: 1vh; } div#mod_netstat_innercontainer div:nth-child(3) { grid-area: ping; } div#mod_netstat_innercontainer div { align-items: center; } div#mod_globe_innercontainer > h1 > i { opacity: 0 } div#mod_globe_innercontainer > h2 { font-size: 0.9vh; color: rgba(0,0,0,0); } div#mod_globe_innercontainer > h2 > i { font-size: 1.1vh; color: rgb(var(--color_r), var(--color_g), var(--color_b)); text-align: left; } div#mod_conninfo_innercontainer > h1 > i { opacity: 0; } div#mod_conninfo_innercontainer > h2 { font-size: 0.9vh; color: rgba(0,0,0,0); } div#mod_conninfo_innercontainer > h2 > i { font-size: 1.1vh; color: rgb(var(--color_r), var(--color_g), var(--color_b)); text-align: left; } } ================================================ FILE: src/assets/css/filesystem.css ================================================ section#filesystem { position: relative; top: -0.925vh; width: 43vw; height: 30vh; margin-right: 0.5vw; opacity: 0; transition: opacity .5s cubic-bezier(0.4, 0, 1, 1); } section#filesystem > h3.title { width: 43vw; padding-right: 0; } section#filesystem.hideDotfiles > h3.title > p#fs_disp_title_dir::before { content: "dotfiles hidden - "; } h2#fs_disp_error { font-weight: bold; text-align: center; padding-top: 12vh; } div#fs_disp_container { position: relative; left: .35vw; top: 1.5vh; height: 25.5vh; width: 43vw; overflow: auto; display: grid; grid-template-columns: repeat(auto-fill, minmax(8.5vh, 1fr)); grid-auto-rows: 8.5vh; grid-gap: 1vh; box-sizing: border-box; } div#fs_disp_container > * { overflow: hidden; width: 8.5vh; height: 8.5vh; text-align: center; display: flex; flex-direction: column; align-items: center; justify-content: center; cursor: pointer; opacity: 1; transition: opacity .2s linear; } div#fs_disp_container > *.animationWait { opacity: 0 !important; } div#fs_disp_container > *:active { animation-name: blink; animation-iteration-count: infinite; animation-duration: .1s; } @keyframes blink { 0% {background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.0);} 50% {background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 1);} 100% {background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.0);} } div#fs_disp_container > *.hidden { opacity: 0.7; } section#filesystem.hideDotfiles > div#fs_disp_container > *.hidden { display: none; } div#fs_disp_container > * > svg { width: 5vh; } /* Add padding around non-edex icons */ div#fs_disp_container > * > svg:not([viewBox="0 0 24 24"]) { padding: 0.5vh; box-sizing: border-box; } div#fs_disp_container > * > h3 { font-size: 1.3vh; max-width: 100%; max-height: 30%; margin: 0px; padding-top: .5vh; box-sizing: border-box; white-space: nowrap; text-overflow: ellipsis; overflow: hidden; } section#filesystem:not(.list-view) > div#fs_disp_container > div > h4 { display: none; } div#fs_disp_container.disks > div > h4 { display: none; } section#filesystem.list-view > div#fs_disp_container { grid-template-columns: 1fr; grid-auto-rows: 2vh; grid-gap: 0.5vh; padding-right: 0.5vh; } section#filesystem.list-view > div#fs_disp_container:not(.disks) > * { width: auto; height: 2vh; flex-direction: row; justify-content: flex-start; } section#filesystem.list-view > div#fs_disp_container:not(.disks) > div > svg { height: 2vh; margin: 0; width: auto; margin-right: 2%; } section#filesystem.list-view > div#fs_disp_container:not(.disks) > div > h3 { max-height: unset; padding-top: .2vh; text-align: left; width: 32%; } section#filesystem.list-view > div#fs_disp_container:not(.disks) > div > h4 { font-size: 1.3vh; font-weight: normal; padding-top: .2vh; text-align: right; overflow: hidden; } section#filesystem.list-view > div#fs_disp_container:not(.disks) > div > h4:nth-of-type(1) { width: 15%; } section#filesystem.list-view > div#fs_disp_container:not(.disks) > div > h4:nth-of-type(2) { width: 10%; } section#filesystem.list-view > div#fs_disp_container:not(.disks) > div > h4:nth-of-type(3) { width: 38%; } div#fs_disp_container.disks { display: flex; align-items: center; justify-content: space-evenly; border: 0.4vh double rgba(var(--color_r), var(--color_g), var(--color_b), 0.8); flex-wrap: wrap; } div#fs_disp_container.disks > * { width: auto; max-width: 8vw; } section#filesystem:not(.list-view) div.fs_disp_showDisks > svg, section#filesystem:not(.list-view) div.fs_disp_up > svg { width: 4vh !important; margin-bottom: 0.5vh; margin-top: 0.5vh; } div.fs_disp_file > h3 { font-weight: normal; } div.fs_disp_symlink > h3 { font-weight: normal; text-decoration: underline; } div.fs_disp_other > h3 { font-style: italic; } div#fs_space_bar { position: relative; top: 1.5vh; left: .15vw; } div#fs_space_bar > h1 { display: none; background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.1); height: 3.2vh; width: 100%; position: relative; bottom: .7vh; left: .3vh; align-items: center; justify-content: center; box-sizing: border-box; border: 2px solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); border-radius: 2px; font-family: var(--font_main); font-weight: bold; font-size: 1.5vh; cursor: pointer; } div#fs_disp_container.disks+div#fs_space_bar > h1 { display: flex; } div#fs_disp_container.disks+div#fs_space_bar > *:not(h1) { display: none; } div#fs_space_bar > h3 { width: 30%; margin: 0; display: inline-block; font-size: 1.4vh; font-weight: normal; white-space: nowrap; position: relative; bottom: .4vh; } div#fs_space_bar > progress { width: 70%; height: 2.2vh; padding-top: .5vh; -webkit-appearance: none; } div#fs_space_bar > progress::after { content: ""; position: absolute; right: -.1vh; top: .45vh; width: .1vh; height: 1.7vh; background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.8); } div#fs_space_bar > progress:not([value])::after { animation: space_bar_working 1.7s ease-in-out alternate infinite; background: rgba(var(--color_r), var(--color_g), var(--color_b), 1); } @keyframes space_bar_working { 0% { right: 0%; } 100% { right: 70%; } } div#fs_space_bar > progress::-webkit-progress-bar { background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.4); height: .7vh; position: relative; top: .7vh; } div#fs_space_bar > progress::-webkit-progress-value { background: rgb(var(--color_r), var(--color_g), var(--color_b)); height: .7vh; position: relative; bottom: .7vh; transition: width .5s cubic-bezier(0.4, 0, 1, 1); } .pdf_container { text-align: center; background: var(--color_light_black); color: rgb(var(--color_r), var(--color_g), var(--color_b)); border: 0.15vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); padding: 0.4vh 0.2vh; font-size: 1.4vh; resize: none; overflow: auto; width: 50vw; height: 50vh; } .pdf_options button { width: 40px; height: 40px; padding: 5px; } .pdf_options span { margin-left: 1.5vh; font-size: 24px; } ================================================ FILE: src/assets/css/keyboard.css ================================================ section#keyboard { display: flex; flex-direction: column; align-items: center; width: 55.5vw; position: relative; top: -0.925vh; } section#keyboard[data-password-mode="true"] { opacity: 0.5 !important; cursor: none !important; } div.keyboard_row { display: flex; flex-direction: row; align-items: center; justify-content: center; flex-wrap: nowrap; margin: 0.46vh 0vh; height: 5.28vh; } section#keyboard.animation_state_2 > div.keyboard_row:nth-child(1) { transition: width .7s cubic-bezier(0.4, 0, 1, 1) .3s, filter .1s linear .8s; } section#keyboard.animation_state_2 > div.keyboard_row:nth-child(2) { transition: width .7s cubic-bezier(0.4, 0, 1, 1) .2s, filter .1s linear .6s; } section#keyboard.animation_state_2 > div.keyboard_row:nth-child(3) { transition: width .7s cubic-bezier(0.4, 0, 1, 1), filter .1s linear .5s; } section#keyboard.animation_state_2 > div.keyboard_row:nth-child(4) { transition: width .7s cubic-bezier(0.4, 0, 1, 1) .25s, filter .1s linear .8s; } section#keyboard.animation_state_2 > div.keyboard_row:nth-child(5) { transition: width .6s cubic-bezier(0.4, 0, 1, 1) .2s, filter .1s linear .6s; } section#keyboard.animation_state_1 > * { filter: brightness(170%); width: 0vh; overflow: hidden; } section#keyboard.animation_state_2 > * { filter: brightness(100%); width: 100vw; overflow: hidden; } div.keyboard_row:last-child { position: relative; left: 2.4vh; } div.keyboard_key { height: 2.7vw; min-width: 2.7vw; overflow: hidden; border-radius: 0.46vh; background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.0); border: 0.18vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.0); margin: 0vh 0.46vh; display: flex; align-items: center; justify-content: center; position: relative; cursor: pointer; } section#keyboard:not([data-password-mode="true"]) div.keyboard_key:active, section#keyboard:not([data-password-mode="true"]) div.keyboard_key.active { border: 0.18vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.0); background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 1); } section#keyboard:not([data-password-mode="true"]) div.keyboard_key.blink { animation-name: blink; animation-duration: .5s; animation-iteration-count: infinite; animation-timing-function: linear; } @keyframes blink { 0% {background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.0);} 50% {background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 1);} 100% {background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.0);} } div.keyboard_key > * { margin: 0vh 0.46vh; padding: 0vh; -webkit-margin-after: 0vh; -webkit-margin-before: 0vh; } div.keyboard_key > h1, div.keyboard_key > h4, div.keyboard_row > .keyboard_key:last-child > *, div.keyboard_row > .keyboard_key:first-child > * { position: relative; top: 0.278vh; font-size: 2.4vh; } div.keyboard_row:not(:nth-child(4)) > .keyboard_key:last-child > *, div.keyboard_row > .keyboard_key:first-child > *, div.keyboard_row:last-child > .keyboard_key > *, div.keyboard_row:nth-child(4) > .keyboard_key:nth-last-child(2) > * { font-size: 1.85vh; } div.keyboard_row:last-child > .keyboard_key:nth-last-child(-n+3) > * { font-size: 2.4vh; } div.keyboard_key > svg { width: calc(100% - 1vh); height: calc(100% - 1vh); top: .5vh !important; opacity: 1 !important; fill: rgb(var(--color_r), var(--color_g), var(--color_b)); } div.keyboard_key > *:not(h1) { margin: 0vh; font-size: 1.67vh; position: absolute; } div.keyboard_key > h2 { top: 0.278vh; left: 0.278vh; } div.keyboard_key > h3 { bottom: 0.278vh; right: 0.278vh; } div.keyboard_key > h5 { top: 0.278vh; right: 0.278vh; } div.keyboard_key > h4, div.keyboard_row > .keyboard_key:last-child > *:not(h1), div.keyboard_row > .keyboard_key:first-child > *:not(h1) { opacity: 0; position: absolute; } div.keyboard_row:not(:nth-child(4)):not(:last-child) > .keyboard_key:last-child, div.keyboard_row > .keyboard_key:first-child { width: 8.33vh; min-width: 8.33vh; } div.keyboard_key#keyboard_spacebar { border: 0.19vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); } div.keyboard_row#row_1 > div.keyboard_enter { border: 0.19vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); border-bottom-right-radius: 0vh; width: 9.72vh; min-width: 9.72vh; } div.keyboard_row#row_2 > div.keyboard_enter { border: 0.19vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); border-top-left-radius: 0vh; border-top: 0.3vh solid var(--color_light_black); width: 7.78vh; min-width: 7.78vh; margin-top: 0vh; height: 6.389vh; top: -0.37vh; right: -1vh; } div.keyboard_row#row_2 > div.keyboard_enter:active, div.keyboard_row#row_2 > div.keyboard_enter.active { border-top: 0.3vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); } div.keyboard_key#keyboard_spacebar { width: 47.68vh; min-width: 47.68vh; height: 3.52vh; } div.keyboard_row:nth-child(4) > div.keyboard_key:last-child { position: relative; top: 0.278vh; } div.keyboard_row:last-child > div.keyboard_key:nth-last-child(-n+3) { margin: 0vh; position: relative; bottom: 0.278vh; } section#keyboard[data-is-caps-lck-on="true"] div.keyboard_key[data-cmd="ESCAPED|-- CAPSLCK: ON"] { background-color: rgb(var(--color_r), var(--color_g), var(--color_b)); color: var(--color_black); } section#keyboard[data-is-shift-on="true"] > div.keyboard_row > div.keyboard_key > h2:not(:empty), section#keyboard[data-is-caps-lck-on="true"] > div.keyboard_row > div.keyboard_key > h2:not(:empty) { position: relative; top: 0.278vh; font-size: 2.4vh; margin: 0vh 0.46vh; } section#keyboard[data-is-shift-on="true"] > div.keyboard_row:first-child > div.keyboard_key:last-child > h2, section#keyboard[data-is-caps-lck-on="true"] > div.keyboard_row:first-child > div.keyboard_key:last-child > h2 { font-size: 1.85vh; opacity: 1; } section#keyboard[data-is-shift-on="true"] > div.keyboard_row > div.keyboard_key > h2:not(:empty) + h1, section#keyboard[data-is-caps-lck-on="true"] > div.keyboard_row > div.keyboard_key > h2:not(:empty) + h1 { margin: 0vh; font-size: 1.67vh; position: absolute; top: 0.278vh; left: 0.278vh; } section#keyboard[data-is-shift-on="true"] > div.keyboard_row:first-child > div.keyboard_key:last-child > h2 + h1, section#keyboard[data-is-caps-lck-on="true"] > div.keyboard_row:first-child > div.keyboard_key:last-child > h2 + h1 { opacity: 0; } section#keyboard[data-is-fn-on="true"] div.keyboard_key[data-cmd="ESCAPED|-- FN: ON"] { background-color: rgb(var(--color_r), var(--color_g), var(--color_b)); color: var(--color_black); } section#keyboard[data-is-fn-on="true"] > div.keyboard_row > div.keyboard_key > h4:not(:empty) { position: relative; top: 0.278vh; font-size: 2.4vh; margin: 0vh 0.46vh; opacity: 1; } section#keyboard[data-is-fn-on="true"] > div.keyboard_row > div.keyboard_key > h4:not(:empty) + h3, section#keyboard[data-is-fn-on="true"] > div.keyboard_row > div.keyboard_key > h4:not(:empty) + h3 + h2, section#keyboard[data-is-fn-on="true"] > div.keyboard_row > div.keyboard_key > h4:not(:empty) + h3 + h2 + h1 { position: absolute; opacity: 0; } ================================================ FILE: src/assets/css/main.css ================================================ html, body { width: 100%; height: 100%; margin: 0vh; padding: 0vh; overflow: hidden; } body { user-select: none !important; padding-top: 1.85vh; color: rgb(var(--color_r), var(--color_g), var(--color_b)); display: flex; flex-direction: row; align-items: center; justify-content: center; flex-wrap: wrap; background: linear-gradient(90deg, var(--color_light_black) 1.85vh, transparent 1%) center, linear-gradient(var(--color_light_black) 1.85vh, transparent 1%) center, var(--color_grey); background-size: 2.04vh 2.04vh; } body.solidBackground { background: var(--color_light_black); } ::-webkit-scrollbar { width: 8px; } ::-webkit-scrollbar-button { display: none; } ::-webkit-scrollbar-track { background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.4); border: 3px solid var(--color_light_black); } ::-webkit-scrollbar-thumb { background: rgb(var(--color_r), var(--color_g), var(--color_b)); height: auto; } section > h3.title:first-child { position: fixed; margin: 0vh; padding: 0vh 0.925vh; font-size: 1.02vh; border-bottom: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); } section > h3.title:first-child > p { display: inline-block; margin: 0vh; width: 49.4%; } section > h3.title:first-child > p:last-child { text-align: right; white-space: nowrap; } section > h3.title:first-child::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; left: -0.925vh; bottom: -0.555vh; height: 0.46vh; } section > h3.title:first-child::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -1.2vh; bottom: -0.555vh; height: 0.46vh; } ================================================ FILE: src/assets/css/main_shell.css ================================================ section#main_shell { width: 65%; height: 60.3%; padding: 0.74vh; /* border: 0.18vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); */ /* border-radius: 0.278vh; */ --aug-border: 0.18vh; --aug-border-bg: rgb(var(--color_r), var(--color_g), var(--color_b)); --aug-border-opacity: 0.5; display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-start; overflow: hidden; transition: width .5s cubic-bezier(0.85, 0.5, 0.85, 0.5), height .5s cubic-bezier(0.85, 0.5, 0.85, 0.5); } h1#main_shell_greeting { font-size: 3.9vh; font-weight: normal; margin: auto; opacity: 0; transition: opacity .5s cubic-bezier(0.4, 0, 1, 1); } h1#main_shell_greeting > em { font-style: normal; font-weight: bold; } section#main_shell > h3.title { top: 0.74vh; left: 16.5vw; width: 66%; transition: opacity .5s cubic-bezier(0.4, 0, 1, 1) .5s; } section#main_shell > h3.title > p { width: 49.8%; } ul#main_shell_tabs { margin: 0; margin-top: -0.70vh; margin-left: -0.74vh; padding: 0; width: calc(100% + 1.48vh); display: flex; box-sizing: border-box; border-bottom: 0.18vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); border-top-left-radius: 0.278vh; border-top-right-radius: 0.278vh; flex-direction: row; align-items: center; justify-content: space-evenly; flex-wrap: nowrap; overflow: hidden; } ul#main_shell_tabs > li { cursor: pointer; display: block; font-family: var(--font_main); font-weight: normal; width: 100%; padding-top: 0.7vh; padding-bottom: 0.4vh; text-align: center; box-sizing: border-box; background: var(--color_light_black); transform: skewX(35deg); } ul#main_shell_tabs > li > p { margin: 0; transform: skewX(-35deg); } ul#main_shell_tabs > li:not(:first-child) { border-left: 0.18vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); } ul#main_shell_tabs > li.active { background: rgb(var(--color_r), var(--color_g), var(--color_b)); color: var(--color_light_black); font-weight: bold; transform: skewX(35deg) scale(1.2); z-index: -1; } div#main_shell_innercontainer, div#main_shell_innercontainer pre { height: 100%; width: 100%; margin: 0vh; overflow: hidden; } div#main_shell_innercontainer pre { z-index: -999; opacity: 0; position: relative; } div#main_shell_innercontainer pre.active { z-index: inherit; opacity: 1; } div#main_shell_innercontainer pre#terminal1 { top: -100%; } div#main_shell_innercontainer pre#terminal2 { top: -200%; } div#main_shell_innercontainer pre#terminal3 { top: -300%; } div#main_shell_innercontainer pre#terminal4 { top: -400%; } .terminal .xterm-viewport { overflow: hidden; cursor: default; position: absolute; right: 0; left: 0; top: 0; bottom: 0; padding-bottom: 10px; } .xterm { font-family: monospace; font-feature-settings: "liga" 0; position: relative; user-select: none; -webkit-user-select: none; } .xterm.focus, .xterm:focus { outline: none; } .xterm .xterm-helpers { position: absolute; top: 0; z-index: 10; } .xterm .xterm-helper-textarea { position: absolute; opacity: 0; left: -9999em; top: 0; width: 0; height: 0; z-index: -10; white-space: nowrap; overflow: hidden; resize: none; } .xterm .composition-view { background: #000; color: #FFF; display: none; position: absolute; white-space: nowrap; z-index: 1; } .xterm .composition-view.active { display: block; } .xterm .xterm-viewport { background-color: #000; overflow-y: hidden; } .xterm .xterm-screen { position: relative; } .xterm canvas { position: absolute; left: 0; top: 0; } .xterm .xterm-scroll-area { visibility: hidden; } .xterm .xterm-char-measure-element { display: inline-block; visibility: hidden; position: absolute; left: -9999em; line-height: normal; } .xterm.enable-mouse-events { /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ cursor: default; } .xterm:not(.enable-mouse-events) { cursor: text; } ================================================ FILE: src/assets/css/media_player.css ================================================ .media_container[data-fullscreen=true] .media { height: 95%; width: 100%; max-width: none; max-height: none; } .media_controls { border: 2px solid rgb(var(--color_r), var(--color_g), var(--color_b)); background: var(--color_light_black); } .media_controls>div { text-align: center; display: inline-block; vertical-align: middle; padding-left: 0.1em; padding-right: 0.1em; } .media_controls .media_button { font-size: 1.5em; height: 1em; width: 1em; } .media_controls .media_button:hover { cursor: pointer; background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); } .media_controls .media_time { margin-right: 2vw; width: 4vw; } .media_controls .volume_icon { font-size: 1.5em; height: 1em; width: 1em; } .media_controls .volume { height: 2vh; z-index: 100; width: 5vw; cursor: pointer; } .media_controls .volume_bkg { position: absolute; border-style: solid; border-width: 0 0 2vh 5vw; border-color: transparent transparent rgba(var(--color_r), var(--color_g), var(--color_b), 0.7) transparent; } .media_controls .volume_bar { position: absolute; clip: rect(0px, 5vw, 2vh, 0px); width: 5vw; border-style: solid; border-width: 0 0 2vh 5vw; border-color: transparent transparent rgb(var(--color_r), var(--color_g), var(--color_b)) transparent; } .fs { float: right; } .media_controls .progress_container { min-width: 20vw; } .media_controls .progress { display: block; cursor: pointer; width: 100%; background-color: rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); height: 5px; } .media_controls .progress_bar { width: 0%; height: 100%; display: block; background-color: rgb(var(--color_r), var(--color_g), var(--color_b)); } .fullscreen_hidden { visibility: hidden; opacity: 0; transition: visibility 0s 2s, opacity 2s linear; } .volume_icon:hover { cursor: pointer; } ================================================ FILE: src/assets/css/mod_clock.css ================================================ div#mod_clock { display: flex; height: 7.41vh; padding-top: 0.645vh; border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); } div#mod_clock::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_clock::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_clock h1 { margin: auto; font-size: 4vh; } div#mod_clock span, div#mod_clock em { display: inline-block; text-align: center; } div#mod_clock span { margin: 0vh 0.2vh; width: 2.3vh; } div#mod_clock em { font-style: normal; margin: 0vh 0.3vh; width: 2.5vh; } div#mod_clock.mod_clock_twelve h1 span:last-child { font-size: 1.5vh; } ================================================ FILE: src/assets/css/mod_column.css ================================================ section.mod_column { width: 17%; top: 2.5vh; min-height: 10%; max-height: 96%; padding: 1.39vh; padding-bottom: 0vh; box-sizing: border-box; position: absolute; display: flex; flex-direction: column; justify-content: space-between; opacity: 0; transition: opacity .5s cubic-bezier(0.4, 0, 1, 1); } section.mod_column.activated { opacity: 1; } section.mod_column > h3.title { top: 0.74vh; width: 14.8%; } section.mod_column > div { width: 100%; opacity: 0; animation-name: fadeIn; animation-duration: .5s; animation-timing-function: cubic-bezier(0.4, 0, 1, 1); animation-delay: 0s; animation-iteration-count: 1; animation-fill-mode: forwards; animation-play-state: paused; } @keyframes fadeIn { from {opacity: 0;} to {opacity: 1;} } section#mod_column_left { left: -0.555vh; align-items: flex-end; } section#mod_column_left > h3.title { left: 0.555vh; } section#mod_column_right { right: -0.555vh; align-items: flex-start; } section#mod_column_right > h3.title { right: 0.555vh; } ================================================ FILE: src/assets/css/mod_conninfo.css ================================================ div#mod_conninfo { border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); letter-spacing: 0.092vh; padding: 0.645vh 0vh; display: flex; } div#mod_conninfo::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); align-self: flex-start; position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_conninfo::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_conninfo_innercontainer { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; } div#mod_conninfo h1 { font-size: 1.48vh; margin: 0vh; margin-bottom: -1vh; width: 98%; } div#mod_conninfo h2 { font-size: 1.4vh; margin: 0vh; margin-bottom: -0.7vh; width: 98%; opacity: .5; } div#mod_conninfo i { font-style: normal; font-size: 1.20vh; opacity: 0.5; text-align: right; display: inline-block; position: relative; bottom: 1.5vh; width: 100%; } div#mod_conninfo canvas { width: 100%; height: 8.7vh; z-index: 10; border-top: 0.092vh dashed rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); border-bottom: 0.092vh dashed rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); margin: 0.46vh 0vh; opacity: 1; } div#mod_conninfo canvas#mod_conninfo_canvas_top { border-bottom: none; margin-bottom: 0vh; } div#mod_conninfo canvas#mod_conninfo_canvas_bottom { border-top: 0.139vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.4); margin-top: -0.092vh; } div#mod_conninfo h3:last-child { position: absolute; font-size: 2vh; z-index: 15; opacity: 0; } div#mod_conninfo.offline canvas { opacity: 0.3; } div#mod_conninfo.offline h3:last-child { opacity: 1; } ================================================ FILE: src/assets/css/mod_cpuinfo.css ================================================ div#mod_cpuinfo { border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); letter-spacing: 0.092vh; padding: 0.645vh 0vh; display: flex; } div#mod_cpuinfo::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); align-self: flex-start; position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_cpuinfo::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_cpuinfo > div#mod_cpuinfo_innercontainer { display: flex; flex-direction: column; align-items: center; justify-content: space-between; width: 100%; } div#mod_cpuinfo_innercontainer > h1:first-child { font-size: 1.48vh; margin: 0vh; width: 98%; padding-left: 2%; margin-bottom: -1.5vh; } div#mod_cpuinfo_innercontainer > h1:first-child > i { font-style: normal; font-size: 1.20vh; opacity: 0.5; text-align: right; display: inline-block; position: relative; bottom: 1.9vh; width: 100%; } div#mod_cpuinfo > div > div { display: flex; flex-direction: row; align-items: center; justify-content: space-between; width: 100%; margin: 0.278vh 0vh; } div#mod_cpuinfo > div > div:last-child { width: 95%; border-top: 0.092vh dashed rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); padding-top: 0.838vh; } div#mod_cpuinfo > div > div:last-child > div { width: 20%; text-align: center; } div#mod_cpuinfo h1 { font-size: 1.3vh; line-height: 1.5vh; margin: 0vh; } div#mod_cpuinfo em { font-family: var(--font_main); font-style: normal; } div#mod_cpuinfo span { width: 1em; position: relative; top: 0.37vh; right: 0.278vh; text-align: center; overflow: hidden; display: inline-block; } div#mod_cpuinfo i { font-style: normal; font-size: 1.3vh; opacity: 0.5; margin-top: 0.5vh; } div#mod_cpuinfo canvas { width: 76%; height: 4.167vh; border-top: 0.092vh dashed rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); border-bottom: 0.092vh dashed rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); margin: 0.46vh 0vh; } ================================================ FILE: src/assets/css/mod_fuzzyFinder.css ================================================ input#fuzzyFinder { width: 100%; background: var(--color_light_black); color: rgb(var(--color_r), var(--color_g), var(--color_b)); border: 0.15vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); padding: 0.4vh 0.2vh; font-size: 1.4vh; box-sizing: border-box; margin-bottom: 1.5vh; } input#fuzzyFinder:active, input#fuzzyFinder:focus { outline: none !important; background: rgb(var(--color_r), var(--color_g), var(--color_b)); color: var(--color_light_black); } ul#fuzzyFinder-results { padding: 0; } ul#fuzzyFinder-results li { display: block; min-width: 50vw; font-family: var(--font_main); background: var(--color_light_black); color: rgb(var(--color_r), var(--color_g), var(--color_b)); height: 1.6vh; font-size: 1.5vh; padding: 0.2vh 0.4vh; padding-top: 0.4vh; } ul#fuzzyFinder-results li.fuzzyFinderMatchSelected { background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.75); color: var(--color_light_black); } ================================================ FILE: src/assets/css/mod_globe.css ================================================ div#mod_globe { border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); letter-spacing: 0.092vh; padding: 0.645vh 0vh; display: flex; } div#mod_globe::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); align-self: flex-start; position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_globe::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_globe_innercontainer { display: flex; flex-direction: column; align-items: center; justify-content: center; width: 100%; } div#mod_globe h1 { font-size: 1.48vh; margin: 0vh; margin-bottom: -1vh; width: 98%; } div#mod_globe h2 { font-size: 1.4vh; margin: 0vh; margin-bottom: -0.7vh; width: 98%; opacity: .5; } div#mod_globe i { font-style: normal; font-size: 1.20vh; opacity: 0.5; text-align: right; display: inline-block; position: relative; bottom: 1.5vh; width: 100%; } div#mod_globe i.mod_globe_headerInfo { padding-top: .2vh; } div#mod_globe canvas { width: 109%; margin: 0px; margin-top: -1.5vh; } div#mod_globe_canvas_placeholder { width: 109%; height: 0px; padding-bottom: 100%; margin: 0px; margin-top: -1.5vh; } div#mod_globe h3 { position: absolute; font-size: 2vh; z-index: 15; opacity: 0; } div#mod_globe.offline canvas { opacity: 0.3; } div#mod_globe.offline h3 { opacity: 1; } ================================================ FILE: src/assets/css/mod_hardwareInspector.css ================================================ div#mod_hardwareInspector { border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); letter-spacing: 0.092vh; padding: 0.645vh 0vh; display: flex; } div#mod_hardwareInspector::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); align-self: flex-start; position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_hardwareInspector::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_hardwareInspector_inner { display: flex; flex-direction: row; align-items: center; justify-content: space-evenly; flex-wrap: wrap; width: 100%; } div#mod_hardwareInspector_inner > div { text-align: left; } div#mod_hardwareInspector_inner > div > * { font-size: 1.3vh; line-height: 1.5vh; margin: 0vh; } div#mod_hardwareInspector_inner > div > h2 { opacity: 0.5; } ================================================ FILE: src/assets/css/mod_netstat.css ================================================ div#mod_netstat { border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); letter-spacing: 0.092vh; font-size: 1.111vh; padding: 0vh; padding-top: 0.645vh; display: flex; } div#mod_netstat::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); align-self: flex-start; position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_netstat::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_netstat_inner > h1:first-child { font-size: 1.48vh; margin: 0vh; width: 98%; padding-left: 2%; } div#mod_netstat_inner > h1:first-child > i { font-style: normal; font-size: 1.20vh; opacity: 0.5; text-align: right; display: inline-block; position: relative; bottom: 1.6vh; right: 0.3vw; width: 100%; } div#mod_netstat_innercontainer { display: grid; grid-template-columns: repeat(4, 1fr); grid-template-rows: 1fr; grid-gap: 0.46vh; position: relative; top: -1.5vh; } div#mod_netstat_innercontainer div { padding: 0.925vh 0.46vh; display: flex; flex-direction: column; align-items: flex-start; justify-content: space-around; } div#mod_netstat_innercontainer div:nth-child(2) { grid-column: 2 / 4; } div#mod_netstat_innercontainer h1 { margin: 0vh; opacity: 0.5; } div#mod_netstat_innercontainer h2 { margin: 0vh; } ================================================ FILE: src/assets/css/mod_processlist.css ================================================ table#processContainer { display: block; max-height: 60vh; overflow: auto; } table#processContainer td.header { font-weight: bold; background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.6); color: var(--color_light_black); text-align: center; } table#processContainer td.header:hover { cursor: pointer; } table#processContainer td.pid { width: 5vw; } table#processContainer td.name { width: 12vw; } table#processContainer td.user { width: 7vw; } table#processContainer td.cpu { width: 3vw; text-align: center; } table#processContainer td.mem{ width: 3vw; text-align: center; } table#processContainer td.state { width: 6vw; text-align: center; } table#processContainer td.started { width: 11vw; } table#processContainer td.runtime { width: 5vw; } ================================================ FILE: src/assets/css/mod_ramwatcher.css ================================================ div#mod_ramwatcher { border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); letter-spacing: 0.092vh; font-size: 1.111vh; padding: 0vh; padding-top: 0.645vh; display: flex; } div#mod_ramwatcher::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); align-self: flex-start; position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_ramwatcher::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_ramwatcher_inner { width: 100%; } div#mod_ramwatcher_inner > h1:first-child { font-size: 1.48vh; margin: 0vh; width: 98%; padding-left: 2%; margin-bottom: -1.5vh; } div#mod_ramwatcher_inner > h1:first-child > i { font-style: normal; font-size: 1.20vh; opacity: 0.5; text-align: right; display: inline-block; position: relative; bottom: 1.6vh; width: 100%; } div#mod_ramwatcher_pointmap { display: grid; grid-template-columns: repeat(40, 1fr); grid-template-rows: repeat(11, 1fr); grid-auto-flow: column; grid-gap: 0.23vh; padding-top: 0.5vh; padding-left: 0.5vh; margin-bottom: 0.8vh; } div.mod_ramwatcher_point { width: 0.2vh; height: 0.25vh; background: rgb(var(--color_r), var(--color_g), var(--color_b)); } div.mod_ramwatcher_point.free { opacity: 0.1; } div.mod_ramwatcher_point.available { opacity: 0.3; } div.mod_ramwatcher_point.active { opacity: 1; } div#mod_ramwatcher_swapcontainer { display: grid; grid-template-columns: 15% 65% 20%; padding-left: 0.5vh; margin-bottom: 0.5vh; } div#mod_ramwatcher_swapcontainer h1 { font-size: 1.3vh; line-height: 1.5vh; margin: 0vh; align-self: center; } progress#mod_ramwatcher_swapbar { width: 100%; align-self: center; -webkit-appearance: none; border-right: .1vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.8); } progress#mod_ramwatcher_swapbar::-webkit-progress-bar { background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.4); height: .25vh; position: relative; top: .55vh; } progress#mod_ramwatcher_swapbar::-webkit-progress-value { background: rgb(var(--color_r), var(--color_g), var(--color_b)); height: .4vh; transition: width .5s cubic-bezier(0.4, 0, 1, 1); position: relative; bottom: .4vh; } h3#mod_ramwatcher_swaptext { font-style: normal; font-size: 1.3vh; line-height: 1.5vh; opacity: 0.5; margin: 0vh; white-space: nowrap; align-self: center; text-align: right; } ================================================ FILE: src/assets/css/mod_sysinfo.css ================================================ div#mod_sysinfo { display: flex; flex-direction: row; align-items: center; justify-content: space-between; height: 5.556vh; border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-size: 1.111vh; font-family: var(--font_main_light); letter-spacing: 0.092vh; } div#mod_sysinfo::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; left: -0.092vh; top: -2.87vh; height: 0.833vh; } div#mod_sysinfo::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -0.092vh; top: -2.87vh; height: 0.833vh; } div#mod_sysinfo div { height: 100%; box-sizing: border-box; padding: 0.925vh 0.46vh; display: flex; flex-direction: column; align-items: flex-start; justify-content: space-around; } div#mod_sysinfo h1 { margin: 0vh; opacity: 0.5; } div#mod_sysinfo h2 { margin: 0vh; } ================================================ FILE: src/assets/css/mod_toplist.css ================================================ div#mod_toplist { border-top: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); font-family: var(--font_main_light); letter-spacing: 0.092vh; padding: 0.645vh 0vh; display: flex; flex-wrap: wrap; } div#mod_toplist::before { content: ""; border-left: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); align-self: flex-start; position: relative; left: -0.092vh; top: -1.111vh; height: 0.833vh; } div#mod_toplist:hover { cursor: pointer; } div#mod_toplist::after { content: ""; border-right: 0.092vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.3); position: relative; right: -15.4vw; top: -12.7vh; height: 0.833vh; } div#mod_toplist h1 { font-size: 1.48vh; margin: 0vh; margin-bottom: -1vh; width: 97%; padding-left: 0.5vh; } div#mod_toplist i { font-style: normal; font-size: 1.20vh; opacity: 0.5; text-align: right; display: inline-block; position: relative; bottom: 1.6vh; width: 100%; } table#mod_toplist_table { margin: 0px; margin-top: 0.2vh; width: 99%; padding-left: 0.5vh; } table#mod_toplist_table td { font-size: 1.50vh; } table#mod_toplist_table td:nth-child(2) { max-width: 7vw; min-width: 7vw; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; } table#mod_toplist_table td:nth-child(3), table#mod_toplist_table td:nth-child(4) { text-align: right; max-width: 2.4vw; min-width: 2.4vw; } ================================================ FILE: src/assets/css/modal.css ================================================ div.modal_popup { position: absolute; min-width: 38vh; background: var(--color_light_black); border-color: rgb(var(--color_r), var(--color_g), var(--color_b)); padding: 2vh; padding-bottom: 0vh; display: flex; flex-direction: column; align-items: flex-start; justify-content: center; cursor: default; --aug-border: 0.2vh; --aug-border-bg: rgb(var(--color_r), var(--color_g), var(--color_b)); --aug-inset: 5px; --aug-inset-bg: var(--color_light_black); } div.modal_popup.error { --aug-bl-height: 3vh; --aug-bl-width: 30%; border-top: 0.2vh solid var(--color_red); border-bottom: 0.2vh solid transparent; padding-bottom: 0.2vh; } div.modal_popup.warning { --aug-b-width: 20%; --aug-b-origin-x: 30%; border-top: 0.2vh solid var(--color_yellow); border-bottom: 0.2vh solid transparent; padding-bottom: 0.2vh; } div.modal_popup.info { --aug-border: 0.2vh; } div.modal_popup.focus { z-index: 2500 !important; } div.modal_popup.blink { border: none; animation-name: blink; animation-duration: .1s; animation-iteration-count: infinite; animation-timing-function: linear; } @keyframes blink { 0% {background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.0);} 100% {background: rgba(var(--color_r), var(--color_g), var(--color_b), 1);} } div.modal_popup > h1 { width: 100%; cursor: move; font-size: 4vh; margin: 0vh; margin-bottom: 2vh; } div.modal_popup > h1 i { font-size: 2.3vh; opacity: 0.6; font-style: normal; } div.modal_popup > h5 { font-size: 2vh; font-weight: normal; margin: 0vh; margin-bottom: 2vh; } div.modal_popup > h5 > a { color: inherit; } div.modal_popup > h5 > a:hover { font-weight: bold; } div.modal_popup > div:last-child { width: 100%; display: flex; align-items: stretch; justify-content: flex-end; position: relative; top: 0.2vh; } div.modal_popup button { background: transparent; border: 0.19vh solid rgba(var(--color_r), var(--color_g), var(--color_b), 0.7); border-radius: 0.278vh; color: rgb(var(--color_r), var(--color_g), var(--color_b)); font-size: 1.85vh; font-weight: bold; padding: 0.5vh 0.9vh; margin-left: 1.5vh; border-bottom-left-radius: 0vh; border-bottom-right-radius: 0vh; padding-bottom: 0.7vh; cursor: pointer; } div.modal_popup button:hover { background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.5); } div.modal_popup table, div.modal_popup table th, div.modal_popup table td { border: 0.15vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); border-collapse: collapse; } div.modal_popup table th, div.modal_popup table td { padding: 0.3vh; } div.modal_popup table th { font-size: 2vh; background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.6); color: var(--color_light_black); } div.modal_popup table td { font-size: 1.7vh; } div.modal_popup table#settingsEditor tbody { display: block; position: relative; max-height: 60vh; overflow: auto; } div.modal_popup table#settingsEditor tbody tr:first-child { position: sticky; top: 0px; } div.modal_popup table:not(#settingsEditor) td:first-child { text-align: center; } div.modal_popup textarea { background: var(--color_light_black); color: rgb(var(--color_r), var(--color_g), var(--color_b)); border: 0.15vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); padding: 0.4vh 0.2vh; font-size: 1.4vh; resize: none; } div.modal_popup textarea:active, div.modal_popup textarea:focus { outline: none !important; } div.modal_popup td input { width: 100%; background: var(--color_light_black); color: rgb(var(--color_r), var(--color_g), var(--color_b)); border: 0.15vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); padding: 0.4vh 0.2vh; font-size: 1.4vh; box-sizing: border-box; } div.modal_popup td input::placeholder { color: rgb(var(--color_r), var(--color_g), var(--color_b)); opacity: 0.7; } div.modal_popup td input:active, div.modal_popup td input:focus { outline: none !important; background: rgb(var(--color_r), var(--color_g), var(--color_b)); color: var(--color_light_black); } div.modal_popup td input:active::placeholder, div.modal_popup td input:focus::placeholder { color: var(--color_light_black); } div.modal_popup td select { cursor: pointer; width: 100%; background: var(--color_light_black); color: rgb(var(--color_r), var(--color_g), var(--color_b)); border: 0.15vh solid rgb(var(--color_r), var(--color_g), var(--color_b)); padding: 0.4vh; font-size: 1.4vh; } div.modal_popup summary { font-size: 1.9vh; font-weight: normal; outline: none !important; cursor: pointer; } div.modal_popup summary+table { margin-top: 1.5vh; } /* Settings editor modal */ h6#settingsEditorStatus { margin: 0; margin-top: 1vh; font-size: 1.5vh; font-style: italic; } /* Keyboard shortcuts modal */ table.shortcutsHelp td:nth-child(2) input { border: none; } table.shortcutsHelp td:first-child { word-spacing: .3vh; font-weight: bold; padding: .8vh; } table.shortcutsHelp td:nth-child(3) { max-width: 40vw; } details#shortcutsHelpAccordeon2 table td:nth-child(3) { display: flex; align-items: center; } details#shortcutsHelpAccordeon2 table td:nth-child(3) input:first-child { font-family: var(--font_mono); min-width: 30vw; } details#shortcutsHelpAccordeon2 table td:nth-child(3) input[type="checkbox"] { width: auto; } /* fsDisp media displayer */ .fsDisp_mediaDisp { max-width: 50vw; max-height: 50vh; outline: none !important; } ================================================ FILE: src/assets/icons/file-icons.json ================================================ { "500px": { "width": 448, "height": 512, "svg": "" }, "accessible-icon": { "width": 448, "height": 512, "svg": "" }, "accusoft": { "width": 640, "height": 512, "svg": "" }, "acquisitions-incorporated": { "width": 384, "height": 512, "svg": "" }, "adn": { "width": 496, "height": 512, "svg": "" }, "adversal": { "width": 512, "height": 512, "svg": "" }, "affiliatetheme": { "width": 512, "height": 512, "svg": "" }, "airbnb": { "width": 448, "height": 512, "svg": "" }, "algolia": { "width": 448, "height": 512, "svg": "" }, "alipay": { "width": 448, "height": 512, "svg": "" }, "amazon-pay": { "width": 640, "height": 512, "svg": "" }, "amazon": { "width": 448, "height": 512, "svg": "" }, "amilia": { "width": 448, "height": 512, "svg": "" }, "android": { "width": 435, "height": 512, "svg": "" }, "angellist": { "width": 448, "height": 512, "svg": "" }, "angrycreative": { "width": 640, "height": 512, "svg": "" }, "angular": { "width": 484, "height": 512, "svg": "" }, "app-store-ios": { "width": 448, "height": 512, "svg": "" }, "app-store": { "width": 512, "height": 512, "svg": "" }, "apper": { "width": 640, "height": 512, "svg": "" }, "apple-pay": { "width": 640, "height": 512, "svg": "" }, "apple": { "width": 417, "height": 512, "svg": "" }, "artstation": { "width": 512, "height": 512, "svg": "" }, "asymmetrik": { "width": 576, "height": 512, "svg": "" }, "atlassian": { "width": 512, "height": 512, "svg": "" }, "audible": { "width": 640, "height": 512, "svg": "" }, "autoprefixer": { "width": 640, "height": 512, "svg": "" }, "avianex": { "width": 512, "height": 512, "svg": "" }, "aviato": { "width": 640, "height": 512, "svg": "" }, "aws": { "width": 512, "height": 512, "svg": "" }, "bandcamp": { "width": 512, "height": 512, "svg": "" }, "battle-net": { "width": 512, "height": 512, "svg": "" }, "behance-square": { "width": 448, "height": 512, "svg": "" }, "behance": { "width": 576, "height": 512, "svg": "" }, "bimobject": { "width": 448, "height": 512, "svg": "" }, "bitbucket": { "width": 455, "height": 512, "svg": "" }, "bitcoin": { "width": 512, "height": 512, "svg": "" }, "bity": { "width": 496, "height": 512, "svg": "" }, "black-tie": { "width": 448, "height": 512, "svg": "" }, "blackberry": { "width": 512, "height": 512, "svg": "" }, "blogger-b": { "width": 448, "height": 512, "svg": "" }, "blogger": { "width": 448, "height": 512, "svg": "" }, "bluetooth-b": { "width": 320, "height": 512, "svg": "" }, "bluetooth": { "width": 448, "height": 512, "svg": "" }, "bootstrap": { "width": 576, "height": 512, "svg": "" }, "btc": { "width": 384, "height": 512, "svg": "" }, "buffer": { "width": 448, "height": 512, "svg": "" }, "buromobelexperte": { "width": 448, "height": 512, "svg": "" }, "buy-n-large": { "width": 576, "height": 512, "svg": "" }, "buysellads": { "width": 448, "height": 512, "svg": "" }, "canadian-maple-leaf": { "width": 512, "height": 512, "svg": "" }, "cc-amazon-pay": { "width": 576, "height": 512, "svg": "" }, "cc-amex": { "width": 576, "height": 512, "svg": "" }, "cc-apple-pay": { "width": 576, "height": 512, "svg": "" }, "cc-diners-club": { "width": 576, "height": 512, "svg": "" }, "cc-discover": { "width": 576, "height": 512, "svg": "" }, "cc-jcb": { "width": 576, "height": 512, "svg": "" }, "cc-mastercard": { "width": 576, "height": 512, "svg": "" }, "cc-paypal": { "width": 576, "height": 512, "svg": "" }, "cc-stripe": { "width": 576, "height": 512, "svg": "" }, "cc-visa": { "width": 576, "height": 512, "svg": "" }, "centercode": { "width": 512, "height": 512, "svg": "" }, "centos": { "width": 512, "height": 512, "svg": "" }, "chrome": { "width": 512, "height": 512, "svg": "" }, "chromecast": { "width": 512, "height": 512, "svg": "" }, "cloudflare": { "width": 640, "height": 512, "svg": "" }, "cloudscale": { "width": 448, "height": 512, "svg": "" }, "cloudsmith": { "width": 332, "height": 512, "svg": "" }, "cloudversify": { "width": 616, "height": 512, "svg": "" }, "codepen": { "width": 512, "height": 512, "svg": "" }, "codiepie": { "width": 472, "height": 512, "svg": "" }, "confluence": { "width": 512, "height": 512, "svg": "" }, "connectdevelop": { "width": 576, "height": 512, "svg": "" }, "contao": { "width": 512, "height": 512, "svg": "" }, "cotton-bureau": { "width": 512, "height": 512, "svg": "" }, "cpanel": { "width": 640, "height": 512, "svg": "" }, "creative-commons-by": { "width": 496, "height": 512, "svg": "" }, "creative-commons-nc-eu": { "width": 496, "height": 512, "svg": "" }, "creative-commons-nc-jp": { "width": 496, "height": 512, "svg": "" }, "creative-commons-nc": { "width": 496, "height": 512, "svg": "" }, "creative-commons-nd": { "width": 496, "height": 512, "svg": "" }, "creative-commons-pd-alt": { "width": 496, "height": 512, "svg": "" }, "creative-commons-pd": { "width": 496, "height": 512, "svg": "" }, "creative-commons-remix": { "width": 496, "height": 512, "svg": "" }, "creative-commons-sa": { "width": 496, "height": 512, "svg": "" }, "creative-commons-sampling-plus": { "width": 496, "height": 512, "svg": "" }, "creative-commons-sampling": { "width": 496, "height": 512, "svg": "" }, "creative-commons-share": { "width": 496, "height": 512, "svg": "" }, "creative-commons-zero": { "width": 496, "height": 512, "svg": "" }, "creative-commons": { "width": 496, "height": 512, "svg": "" }, "critical-role": { "width": 448, "height": 512, "svg": "" }, "css3-alt": { "width": 384, "height": 512, "svg": "" }, "css3": { "width": 452, "height": 512, "svg": "" }, "cuttlefish": { "width": 440, "height": 512, "svg": "" }, "d-and-d-beyond": { "width": 640, "height": 512, "svg": "" }, "d-and-d": { "width": 576, "height": 512, "svg": "" }, "dailymotion": { "width": 448, "height": 512, "svg": "" }, "dashcube": { "width": 448, "height": 512, "svg": "" }, "deezer": { "width": 576, "height": 512, "svg": "" }, "delicious": { "width": 448, "height": 512, "svg": "" }, "deploydog": { "width": 512, "height": 512, "svg": "" }, "deskpro": { "width": 480, "height": 512, "svg": "" }, "dev": { "width": 448, "height": 512, "svg": "" }, "deviantart": { "width": 320, "height": 512, "svg": "" }, "dhl": { "width": 640, "height": 512, "svg": "" }, "diaspora": { "width": 512, "height": 512, "svg": "" }, "digg": { "width": 512, "height": 512, "svg": "" }, "digital-ocean": { "width": 512, "height": 512, "svg": "" }, "discord": { "width": 640, "height": 512, "svg": "" }, "discourse": { "width": 448, "height": 512, "svg": "" }, "dochub": { "width": 416, "height": 512, "svg": "" }, "docker": { "width": 512, "height": 512, "svg": "" }, "draft2digital": { "width": 480, "height": 512, "svg": "" }, "dribbble-square": { "width": 448, "height": 512, "svg": "" }, "dribbble": { "width": 512, "height": 512, "svg": "" }, "dropbox": { "width": 512, "height": 512, "svg": "" }, "drupal": { "width": 447.8739929, "height": 512, "svg": "" }, "dyalog": { "width": null, "height": null, "svg": "" }, "earlybirds": { "width": 480, "height": 512, "svg": "" }, "ebay": { "width": 640, "height": 512, "svg": "" }, "edge-legacy": { "width": 512, "height": 512, "svg": "" }, "edge": { "width": 512, "height": 512, "svg": "" }, "elementor": { "width": 448, "height": 512, "svg": "" }, "ello": { "width": 496, "height": 512, "svg": "" }, "ember": { "width": 512, "height": 512, "svg": "" }, "empire": { "width": 496, "height": 512, "svg": "" }, "envira": { "width": 448, "height": 512, "svg": "" }, "erlang": { "width": 512, "height": 512, "svg": "" }, "ethereum": { "width": 320, "height": 512, "svg": "" }, "etsy": { "width": 384, "height": 512, "svg": "" }, "evernote": { "width": 384, "height": 512, "svg": "" }, "expeditedssl": { "width": 496, "height": 512, "svg": "" }, "facebook-f": { "width": 320, "height": 512, "svg": "" }, "facebook-messenger": { "width": 512, "height": 512, "svg": "" }, "facebook-square": { "width": 448, "height": 512, "svg": "" }, "facebook": { "width": 512, "height": 512, "svg": "" }, "fantasy-flight-games": { "width": 512, "height": 512, "svg": "" }, "fedex": { "width": 640, "height": 512, "svg": "" }, "fedora": { "width": 512, "height": 512, "svg": "" }, "figma": { "width": 340, "height": 512, "svg": "" }, "firefox-browser": { "width": 512, "height": 512, "svg": "" }, "firefox": { "width": 512, "height": 512, "svg": "" }, "first-order-alt": { "width": 496, "height": 512, "svg": "" }, "first-order": { "width": 448, "height": 512, "svg": "" }, "firstdraft": { "width": 384, "height": 512, "svg": "" }, "flickr": { "width": 448, "height": 512, "svg": "" }, "flipboard": { "width": 448, "height": 512, "svg": "" }, "fly": { "width": 384, "height": 512, "svg": "" }, "font-awesome-alt": { "width": 448, "height": 512, "svg": "" }, "font-awesome-flag": { "width": 448, "height": 512, "svg": "" }, "font-awesome-logo-full": { "width": 3992, "height": 512, "svg": "" }, "font-awesome": { "width": 448, "height": 512, "svg": "" }, "fonticons-fi": { "width": 384, "height": 512, "svg": "" }, "fonticons": { "width": 448, "height": 512, "svg": "" }, "fort-awesome-alt": { "width": 512, "height": 512, "svg": "" }, "fort-awesome": { "width": 512, "height": 512, "svg": "" }, "forumbee": { "width": 448, "height": 512, "svg": "" }, "foursquare": { "width": 368, "height": 512, "svg": "" }, "free-code-camp": { "width": 576, "height": 512, "svg": "" }, "freebsd": { "width": 512, "height": 512, "svg": "" }, "fulcrum": { "width": 320, "height": 512, "svg": "" }, "galactic-republic": { "width": 496, "height": 512, "svg": "" }, "galactic-senate": { "width": 512, "height": 512, "svg": "" }, "get-pocket": { "width": 448, "height": 512, "svg": "" }, "gg-circle": { "width": 512, "height": 512, "svg": "" }, "gg": { "width": 512, "height": 512, "svg": "" }, "git-alt": { "width": 448, "height": 512, "svg": "" }, "git-square": { "width": 448, "height": 512, "svg": "" }, "git": { "width": 512, "height": 512, "svg": "" }, "github-alt": { "width": 512, "height": 512, "svg": "" }, "github-square": { "width": 448, "height": 512, "svg": "" }, "github": { "width": "64", "height": "64", "svg": "\n \n" }, "gitkraken": { "width": 592, "height": 512, "svg": "" }, "gitlab": { "width": 512, "height": 512, "svg": "" }, "gitter": { "width": 384, "height": 512, "svg": "" }, "glide-g": { "width": 448, "height": 512, "svg": "" }, "glide": { "width": 512, "height": 512, "svg": "" }, "gofore": { "width": 400, "height": 512, "svg": "" }, "goodreads-g": { "width": 384, "height": 512, "svg": "" }, "goodreads": { "width": 448, "height": 512, "svg": "" }, "google-drive": { "width": 512, "height": 512, "svg": "" }, "google-pay": { "width": 640, "height": 512, "svg": "" }, "google-play": { "width": 512, "height": 512, "svg": "" }, "google-plus-g": { "width": 640, "height": 512, "svg": "" }, "google-plus-square": { "width": 448, "height": 512, "svg": "" }, "google-plus": { "width": 512, "height": 512, "svg": "" }, "google-wallet": { "width": 448, "height": 512, "svg": "" }, "google": { "width": 481, "height": 512, "svg": "" }, "gratipay": { "width": 496, "height": 512, "svg": "" }, "grav": { "width": 512, "height": 512, "svg": "" }, "gripfire": { "width": 384, "height": 512, "svg": "" }, "grunt": { "width": 383, "height": 512, "svg": "" }, "guilded": { "width": 448, "height": 512, "svg": "" }, "gulp": { "width": 230, "height": 512, "svg": "" }, "hacker-news-square": { "width": 448, "height": 512, "svg": "" }, "hacker-news": { "width": 448, "height": 512, "svg": "" }, "hackerrank": { "width": 512, "height": 512, "svg": "" }, "hips": { "width": 640, "height": 512, "svg": "" }, "hire-a-helper": { "width": 512, "height": 512, "svg": "" }, "hive": { "width": 512, "height": 512, "svg": "" }, "hooli": { "width": 640, "height": 512, "svg": "" }, "hornbill": { "width": 512, "height": 512, "svg": "" }, "hotjar": { "width": 448, "height": 512, "svg": "" }, "houzz": { "width": 448, "height": 512, "svg": "" }, "html5": { "width": 451, "height": 512, "svg": "" }, "hubspot": { "width": 512, "height": 512, "svg": "" }, "ideal": { "width": 576, "height": 512, "svg": "" }, "imdb": { "width": 448, "height": 512, "svg": "" }, "innosoft": { "width": 448, "height": 512, "svg": "" }, "instagram-square": { "width": 448, "height": 512, "svg": "" }, "instagram": { "width": 448, "height": 512, "svg": "" }, "instalod": { "width": 512, "height": 512, "svg": "" }, "intercom": { "width": 448, "height": 512, "svg": "" }, "internet-explorer": { "width": 512, "height": 512, "svg": "" }, "invision": { "width": 448, "height": 512, "svg": "" }, "ioxhost": { "width": 640, "height": 512, "svg": "" }, "itch-io": { "width": 512, "height": 512, "svg": "" }, "itunes-note": { "width": 384, "height": 512, "svg": "" }, "itunes": { "width": 448, "height": 512, "svg": "" }, "java": { "width": 374, "height": 512, "svg": "" }, "jedi-order": { "width": 448, "height": 512, "svg": "" }, "jenkins": { "width": 371, "height": 512, "svg": "" }, "jira": { "width": 388, "height": 512, "svg": "" }, "joget": { "width": 496, "height": 512, "svg": "" }, "joomla": { "width": 512, "height": 512, "svg": "" }, "js-square": { "width": 448, "height": 512, "svg": "" }, "js": { "width": 512, "height": 512, "svg": "" }, "jsfiddle": { "width": 576, "height": 512, "svg": "" }, "kaggle": { "width": 320, "height": 512, "svg": "" }, "keybase": { "width": 472, "height": 512, "svg": "" }, "keycdn": { "width": 512, "height": 512, "svg": "" }, "kickstarter-k": { "width": 384, "height": 512, "svg": "" }, "kickstarter": { "width": 448, "height": 512, "svg": "" }, "korvue": { "width": 446, "height": 512, "svg": "" }, "laravel": { "width": 512, "height": 512, "svg": "" }, "lastfm-square": { "width": 448, "height": 512, "svg": "" }, "lastfm": { "width": 512, "height": 512, "svg": "" }, "leanpub": { "width": 576, "height": 512, "svg": "" }, "less": { "width": 512, "height": 512, "svg": "" }, "line": { "width": 448, "height": 512, "svg": "" }, "linkedin-in": { "width": 448, "height": 512, "svg": "" }, "linkedin": { "width": 448, "height": 512, "svg": "" }, "linode": { "width": 448, "height": 512, "svg": "" }, "linux": { "width": 436, "height": 512, "svg": "" }, "lyft": { "width": 512, "height": 512, "svg": "" }, "magento": { "width": 436, "height": 512, "svg": "" }, "mailchimp": { "width": 512, "height": 512, "svg": "" }, "mandalorian": { "width": 448, "height": 512, "svg": "" }, "markdown": { "width": 512, "height": 512, "svg": "" }, "mastodon": { "width": 448, "height": 512, "svg": "" }, "maxcdn": { "width": 512, "height": 512, "svg": "" }, "mdb": { "width": 576, "height": 512, "svg": "" }, "medapps": { "width": 320, "height": 512, "svg": "" }, "medium-m": { "width": 512, "height": 512, "svg": "" }, "medium": { "width": 448, "height": 512, "svg": "" }, "medrt": { "width": 544, "height": 512, "svg": "" }, "meetup": { "width": 512, "height": 512, "svg": "" }, "megaport": { "width": 496, "height": 512, "svg": "" }, "mendeley": { "width": 640, "height": 512, "svg": "" }, "microblog": { "width": 448, "height": 512, "svg": "" }, "microsoft": { "width": 448, "height": 512, "svg": "" }, "mix": { "width": 448, "height": 512, "svg": "" }, "mixcloud": { "width": 640, "height": 512, "svg": "" }, "mixer": { "width": 512, "height": 512, "svg": "" }, "mizuni": { "width": 496, "height": 512, "svg": "" }, "modx": { "width": 448, "height": 512, "svg": "" }, "monero": { "width": 496, "height": 512, "svg": "" }, "napster": { "width": 496, "height": 512, "svg": "" }, "neos": { "width": 512, "height": 512, "svg": "" }, "nimblr": { "width": 384, "height": 512, "svg": "" }, "node-js": { "width": 448, "height": 512, "svg": "" }, "node": { "width": 640, "height": 512, "svg": "" }, "npm": { "width": 512, "height": 512, "svg": "" }, "ns8": { "width": 640, "height": 512, "svg": "" }, "nutritionix": { "width": 400, "height": 512, "svg": "" }, "octopus-deploy": { "width": 512, "height": 512, "svg": "" }, "odnoklassniki-square": { "width": 448, "height": 512, "svg": "" }, "odnoklassniki": { "width": 320, "height": 512, "svg": "" }, "old-republic": { "width": 496, "height": 512, "svg": "" }, "opencart": { "width": 640, "height": 512, "svg": "" }, "openid": { "width": 448, "height": 512, "svg": "" }, "opera": { "width": 480, "height": 512, "svg": "" }, "optin-monster": { "width": 576, "height": 512, "svg": "" }, "orcid": { "width": 512, "height": 512, "svg": "" }, "osi": { "width": 512, "height": 512, "svg": "" }, "page4": { "width": 496, "height": 512, "svg": "" }, "pagelines": { "width": 384, "height": 512, "svg": "" }, "palfed": { "width": 576, "height": 512, "svg": "" }, "patreon": { "width": 512, "height": 512, "svg": "" }, "paypal": { "width": 384, "height": 512, "svg": "" }, "penny-arcade": { "width": 640, "height": 512, "svg": "" }, "perbyte": { "width": 448, "height": 512, "svg": "" }, "periscope": { "width": 448, "height": 512, "svg": "" }, "phabricator": { "width": 496, "height": 512, "svg": "" }, "phoenix-framework": { "width": 640, "height": 512, "svg": "" }, "phoenix-squadron": { "width": 512, "height": 512, "svg": "" }, "php": { "width": 512, "height": 512, "svg": "" }, "pied-piper-alt": { "width": 576, "height": 512, "svg": "" }, "pied-piper-hat": { "width": 640, "height": 512, "svg": "" }, "pied-piper-pp": { "width": 448, "height": 512, "svg": "" }, "pied-piper-square": { "width": 448, "height": 512, "svg": "" }, "pied-piper": { "width": 480, "height": 512, "svg": "" }, "pinterest-p": { "width": 384, "height": 512, "svg": "" }, "pinterest-square": { "width": 448, "height": 512, "svg": "" }, "pinterest": { "width": 496, "height": 512, "svg": "" }, "playstation": { "width": 576, "height": 512, "svg": "" }, "product-hunt": { "width": 512, "height": 512, "svg": "" }, "pushed": { "width": 432, "height": 512, "svg": "" }, "python": { "width": 492, "height": 512, "svg": "" }, "qq": { "width": 448, "height": 512, "svg": "" }, "quinscape": { "width": 512, "height": 512, "svg": "" }, "quora": { "width": 448, "height": 512, "svg": "" }, "r-project": { "width": 581, "height": 512, "svg": "" }, "raspberry-pi": { "width": 401, "height": 512, "svg": "" }, "ravelry": { "width": 512, "height": 512, "svg": "" }, "react": { "width": 512, "height": 512, "svg": "" }, "reacteurope": { "width": 576, "height": 512, "svg": "" }, "readme": { "width": 576, "height": 512, "svg": "" }, "rebel": { "width": 512, "height": 512, "svg": "" }, "red-river": { "width": 448, "height": 512, "svg": "" }, "reddit-alien": { "width": 512, "height": 512, "svg": "" }, "reddit-square": { "width": 448, "height": 512, "svg": "" }, "reddit": { "width": 512, "height": 512, "svg": "" }, "redhat": { "width": 512, "height": 512, "svg": "" }, "renren": { "width": 512, "height": 512, "svg": "" }, "replyd": { "width": 448, "height": 512, "svg": "" }, "researchgate": { "width": 448, "height": 512, "svg": "" }, "resolving": { "width": 496, "height": 512, "svg": "" }, "rev": { "width": 448, "height": 512, "svg": "" }, "rocketchat": { "width": 576, "height": 512, "svg": "" }, "rockrms": { "width": 496, "height": 512, "svg": "" }, "rust": { "width": 512, "height": 512, "svg": "" }, "safari": { "width": 461, "height": 512, "svg": "" }, "salesforce": { "width": 640, "height": 512, "svg": "" }, "sass": { "width": 512, "height": 512, "svg": "" }, "schlix": { "width": 448, "height": 512, "svg": "" }, "scribd": { "width": 384, "height": 512, "svg": "" }, "searchengin": { "width": 460, "height": 512, "svg": "" }, "sellcast": { "width": 448, "height": 512, "svg": "" }, "sellsy": { "width": 640, "height": 512, "svg": "" }, "servicestack": { "width": 496, "height": 512, "svg": "" }, "shirtsinbulk": { "width": 448, "height": 512, "svg": "" }, "shopify": { "width": 452, "height": 512, "svg": "" }, "shopware": { "width": 512, "height": 512, "svg": "" }, "simplybuilt": { "width": 512, "height": 512, "svg": "" }, "sistrix": { "width": 448, "height": 512, "svg": "" }, "sith": { "width": 448, "height": 512, "svg": "" }, "sketch": { "width": 512, "height": 512, "svg": "" }, "skyatlas": { "width": 640, "height": 512, "svg": "" }, "skype": { "width": 448, "height": 512, "svg": "" }, "slack-hash": { "width": 448, "height": 512, "svg": "" }, "slack": { "width": 448, "height": 512, "svg": "" }, "slideshare": { "width": 512, "height": 512, "svg": "" }, "snapchat-ghost": { "width": 512, "height": 512, "svg": "" }, "snapchat-square": { "width": 448, "height": 512, "svg": "" }, "snapchat": { "width": 496, "height": 512, "svg": "" }, "soundcloud": { "width": 640, "height": 512, "svg": "" }, "sourcetree": { "width": 448, "height": 512, "svg": "" }, "speakap": { "width": 448, "height": 512, "svg": "" }, "speaker-deck": { "width": 512, "height": 512, "svg": "" }, "spotify": { "width": 496, "height": 512, "svg": "" }, "squarespace": { "width": 512, "height": 512, "svg": "" }, "stack-exchange": { "width": 448, "height": 512, "svg": "" }, "stack-overflow": { "width": 384, "height": 512, "svg": "" }, "stackpath": { "width": 448, "height": 512, "svg": "" }, "staylinked": { "width": 440, "height": 512, "svg": "" }, "steam-square": { "width": 448, "height": 512, "svg": "" }, "steam-symbol": { "width": 448, "height": 512, "svg": "" }, "steam": { "width": 496, "height": 512, "svg": "" }, "sticker-mule": { "width": 576, "height": 512, "svg": "" }, "strava": { "width": 384, "height": 512, "svg": "" }, "stripe-s": { "width": 384, "height": 512, "svg": "" }, "stripe": { "width": 640, "height": 512, "svg": "" }, "studiovinari": { "width": 512, "height": 512, "svg": "" }, "stumbleupon-circle": { "width": 496, "height": 512, "svg": "" }, "stumbleupon": { "width": 512, "height": 512, "svg": "" }, "superpowers": { "width": 448, "height": 512, "svg": "" }, "supple": { "width": 640, "height": 512, "svg": "" }, "suse": { "width": 512, "height": 512, "svg": "" }, "swift": { "width": 512, "height": 512, "svg": "" }, "symfony": { "width": 512, "height": 512, "svg": "" }, "teamspeak": { "width": 512, "height": 512, "svg": "" }, "telegram-plane": { "width": 448, "height": 512, "svg": "" }, "telegram": { "width": 512, "height": 512, "svg": "" }, "tencent-weibo": { "width": 384, "height": 512, "svg": "" }, "the-red-yeti": { "width": 512, "height": 512, "svg": "" }, "themeco": { "width": 448, "height": 512, "svg": "" }, "themeisle": { "width": 512, "height": 512, "svg": "" }, "think-peaks": { "width": 576, "height": 512, "svg": "" }, "tiktok": { "width": 448, "height": 512, "svg": "" }, "trade-federation": { "width": 496, "height": 512, "svg": "" }, "trello": { "width": 512, "height": 512, "svg": "" }, "tripadvisor": { "width": 576, "height": 512, "svg": "" }, "tumblr-square": { "width": 448, "height": 512, "svg": "" }, "tumblr": { "width": 320, "height": 512, "svg": "" }, "twitch": { "width": 512, "height": 512, "svg": "" }, "twitter-square": { "width": 448, "height": 512, "svg": "" }, "twitter": { "width": "64", "height": "64", "svg": "\n \n" }, "typo3": { "width": 512, "height": 512, "svg": "" }, "uber": { "width": 448, "height": 512, "svg": "" }, "ubuntu": { "width": 496, "height": 512, "svg": "" }, "uikit": { "width": 443, "height": 512, "svg": "" }, "umbraco": { "width": 510, "height": 512, "svg": "" }, "uncharted": { "width": 448, "height": 512, "svg": "" }, "uniregistry": { "width": 384, "height": 512, "svg": "" }, "unity": { "width": 512, "height": 512, "svg": "" }, "unsplash": { "width": 448, "height": 512, "svg": "" }, "untappd": { "width": 640, "height": 512, "svg": "" }, "ups": { "width": 384, "height": 512, "svg": "" }, "usb": { "width": 24, "height": 24, "svg": "" }, "usps": { "width": 576, "height": 512, "svg": "" }, "ussunnah": { "width": 512, "height": 512, "svg": "" }, "vaadin": { "width": 448, "height": 512, "svg": "" }, "viacoin": { "width": 384, "height": 512, "svg": "" }, "viadeo-square": { "width": 448, "height": 512, "svg": "" }, "viadeo": { "width": 448, "height": 512, "svg": "" }, "viber": { "width": 512, "height": 512, "svg": "" }, "vimeo-square": { "width": 448, "height": 512, "svg": "" }, "vimeo-v": { "width": 448, "height": 512, "svg": "" }, "vimeo": { "width": 448, "height": 512, "svg": "" }, "vine": { "width": 384, "height": 512, "svg": "" }, "vk": { "width": 576, "height": 512, "svg": "" }, "vnv": { "width": 640, "height": 512, "svg": "" }, "vuejs": { "width": 448, "height": 512, "svg": "" }, "watchman-monitoring": { "width": 512, "height": 512, "svg": "" }, "waze": { "width": 512, "height": 512, "svg": "" }, "weebly": { "width": 512, "height": 512, "svg": "" }, "weibo": { "width": 512, "height": 512, "svg": "" }, "weixin": { "width": 576, "height": 512, "svg": "" }, "whatsapp-square": { "width": 448, "height": 512, "svg": "" }, "whatsapp": { "width": 448, "height": 512, "svg": "" }, "whmcs": { "width": 448, "height": 512, "svg": "" }, "wikipedia-w": { "width": 640, "height": 512, "svg": "" }, "windows": { "width": 500, "height": 512, "svg": "" }, "wix": { "width": 512, "height": 512, "svg": "" }, "wizards-of-the-coast": { "width": 640, "height": 512, "svg": "" }, "wodu": { "width": 640, "height": 512, "svg": "" }, "wolf-pack-battalion": { "width": 512, "height": 512, "svg": "" }, "wordpress-simple": { "width": 512, "height": 512, "svg": "" }, "wordpress": { "width": 512, "height": 512, "svg": "" }, "wpbeginner": { "width": 512, "height": 512, "svg": "" }, "wpexplorer": { "width": 512, "height": 512, "svg": "" }, "wpforms": { "width": 448, "height": 512, "svg": "" }, "wpressr": { "width": 496, "height": 512, "svg": "" }, "xbox": { "width": 512, "height": 512, "svg": "" }, "xing-square": { "width": 448, "height": 512, "svg": "" }, "xing": { "width": 384, "height": 512, "svg": "" }, "y-combinator": { "width": 448, "height": 512, "svg": "" }, "yahoo": { "width": 512, "height": 512, "svg": "" }, "yammer": { "width": 512, "height": 512, "svg": "" }, "yandex-international": { "width": 320, "height": 512, "svg": "" }, "yandex": { "width": 256, "height": 512, "svg": "" }, "yarn": { "width": 477, "height": 512, "svg": "" }, "yelp": { "width": 384, "height": 512, "svg": "" }, "yoast": { "width": 448, "height": 512, "svg": "" }, "youtube-square": { "width": 448, "height": 512, "svg": "" }, "youtube": { "width": 576, "height": 512, "svg": "" }, "zhihu": { "width": 640, "height": 512, "svg": "" }, "1c-alt": { "width": 512, "height": 512, "svg": "" }, "1c": { "width": 512, "height": 512, "svg": "" }, "3d-model": { "width": 512, "height": 512, "svg": "" }, "3ds-max": { "width": 512, "height": 502, "svg": "" }, "4d": { "width": 512, "height": 512, "svg": "" }, "a+": { "width": 512, "height": 512, "svg": "" }, "abap": { "width": 512, "height": 512, "svg": "" }, "abif": { "width": 512, "height": 512, "svg": "" }, "agc": { "width": 512, "height": 512, "svg": "" }, "amd": { "width": 512, "height": 512, "svg": "" }, "ampl": { "width": 512, "height": 512, "svg": "" }, "antlr": { "width": 512, "height": 512, "svg": "" }, "api-blueprint": { "width": 512, "height": 512, "svg": "" }, "apiextractor": { "width": 435, "height": 512, "svg": "" }, "apl-old": { "width": null, "height": null, "svg": "" }, "apl": { "width": 481, "height": 512, "svg": "" }, "arm": { "width": 512, "height": 512, "svg": "" }, "ats": { "width": 512, "height": 512, "svg": "" }, "att": { "width": 512, "height": 512, "svg": "" }, "avr": { "width": 512, "height": 512, "svg": "" }, "acre": { "width": 444, "height": 512, "svg": "" }, "actionscript": { "width": 512, "height": 512, "svg": "" }, "ada": { "width": 512, "height": 583, "svg": "" }, "adobe-acrobat": { "width": 512, "height": 512, "svg": "" }, "adobe-aftereffects": { "width": 512, "height": 512, "svg": "" }, "adobe-animate": { "width": 512, "height": 512, "svg": "" }, "adobe-audition": { "width": 512, "height": 512, "svg": "" }, "adobe-bridge": { "width": 512, "height": 512, "svg": "" }, "adobe-characteranimator": { "width": 512, "height": 512, "svg": "" }, "adobe-creativecloud": { "width": 512, "height": 512, "svg": "" }, "adobe-dimension": { "width": 512, "height": 512, "svg": "" }, "adobe-dreamweaver": { "width": 512, "height": 512, "svg": "" }, "adobe-flash": { "width": 512, "height": 512, "svg": "" }, "adobe-fuse": { "width": 512, "height": 512, "svg": "" }, "adobe-illustrator": { "width": 512, "height": 512, "svg": "" }, "adobe-incopy": { "width": 512, "height": 512, "svg": "" }, "adobe-indesign": { "width": 512, "height": 512, "svg": "" }, "adobe-lightroom": { "width": 512, "height": 512, "svg": "" }, "adobe-mediaencoder": { "width": 512, "height": 512, "svg": "" }, "adobe-photoshop": { "width": 512, "height": 512, "svg": "" }, "adobe-prelude": { "width": 512, "height": 512, "svg": "" }, "adobe-premiere": { "width": 512, "height": 512, "svg": "" }, "adobe-premiererush": { "width": 512, "height": 512, "svg": "" }, "adobe-xd": { "width": 512, "height": 512, "svg": "" }, "adobe": { "width": 512, "height": 512, "svg": "" }, "adonisjs": { "width": 512, "height": 512, "svg": "" }, "aeternity": { "width": 512, "height": 512, "svg": "" }, "affectscript": { "width": 512, "height": 512, "svg": "" }, "affinitydesigner": { "width": 512, "height": 512, "svg": "" }, "agda": { "width": 512, "height": 512, "svg": "" }, "akka": { "width": 512, "height": 512, "svg": "" }, "alacritty-alt": { "width": 512, "height": 512, "svg": "" }, "alacritty": { "width": 449, "height": 512, "svg": "" }, "alex": { "width": 264, "height": 512, "svg": "" }, "alloy": { "width": 512, "height": 512, "svg": "" }, "alpine-linux": { "width": 512, "height": 512, "svg": "" }, "amigaos": { "width": 512, "height": 512, "svg": "" }, "amusewiki": { "width": 512, "height": 512, "svg": "" }, "analytica": { "width": 512, "height": 512, "svg": "" }, "angelscript": { "width": 512, "height": 512, "svg": "" }, "animestudio": { "width": 512, "height": 512, "svg": "" }, "ansible-alt": { "width": 469, "height": 512, "svg": "" }, "ansible": { "width": 512, "height": 512, "svg": "" }, "antwar": { "width": 512, "height": 512, "svg": "" }, "anyscript": { "width": 512, "height": 512, "svg": "" }, "apache-ant": { "width": 512, "height": 512, "svg": "" }, "apollo": { "width": 448, "height": 512, "svg": "" }, "appveyor": { "width": 512, "height": 512, "svg": "" }, "arc": { "width": 512, "height": 512, "svg": "" }, "arch-linux": { "width": 512, "height": 512, "svg": "" }, "arduino": { "width": 512, "height": 512, "svg": "" }, "arttext": { "width": 512, "height": 512, "svg": "" }, "arttext4": { "width": 432, "height": 512, "svg": "" }, "asciidoc": { "width": 439, "height": 512, "svg": "" }, "asciidoctor": { "width": null, "height": null, "svg": "" }, "assembly-agc": { "width": 512, "height": 512, "svg": "" }, "assembly-amd": { "width": 512, "height": 512, "svg": "" }, "assembly-arm": { "width": 512, "height": 512, "svg": "" }, "assembly-att": { "width": 512, "height": 512, "svg": "" }, "assembly-avr": { "width": 512, "height": 512, "svg": "" }, "assembly-generic": { "width": 512, "height": 512, "svg": "" }, "assembly-hitachi": { "width": 512, "height": 512, "svg": "" }, "assembly-intel": { "width": 512, "height": 512, "svg": "" }, "assembly-motorola": { "width": 512, "height": 512, "svg": "" }, "assembly-powerpc": { "width": 512, "height": 512, "svg": "" }, "assembly-riscv": { "width": 512, "height": 512, "svg": "" }, "assembly-sparc": { "width": 512, "height": 512, "svg": "" }, "assembly-vax": { "width": 512, "height": 512, "svg": "" }, "assembly-zilog": { "width": 512, "height": 512, "svg": "" }, "asymptote-alt": { "width": 476, "height": 512, "svg": "" }, "asymptote": { "width": 512, "height": 512, "svg": "" }, "atoum": { "width": 512, "height": 512, "svg": "" }, "audacity": { "width": 512, "height": 512, "svg": "" }, "augeas": { "width": 372, "height": 512, "svg": "" }, "aurelia": { "width": 512, "height": 512, "svg": "" }, "autohotkey": { "width": 512, "height": 512, "svg": "" }, "autoit": { "width": 512, "height": 512, "svg": "" }, "automator": { "width": 474, "height": 512, "svg": "" }, "avro": { "width": 512, "height": 512, "svg": "" }, "awk": { "width": 491, "height": 512, "svg": "" }, "azure-pipelines": { "width": 512, "height": 512, "svg": "" }, "bem": { "width": 512, "height": 512, "svg": "" }, "bnf": { "width": 512, "height": 512, "svg": "" }, "byond": { "width": 512, "height": 512, "svg": "" }, "babel": { "width": 422, "height": 512, "svg": "" }, "ballerina": { "width": 283, "height": 512, "svg": "" }, "bazaar": { "width": 500, "height": 512, "svg": "" }, "bazel-old": { "width": 355, "height": 512, "svg": "" }, "bazel": { "width": 512, "height": 512, "svg": "" }, "behat": { "width": 385, "height": 512, "svg": "" }, "bibtex": { "width": null, "height": null, "svg": "" }, "bikeshed": { "width": 496, "height": 512, "svg": "" }, "biml": { "width": 512, "height": 512, "svg": "" }, "bintray": { "width": 512, "height": 512, "svg": "" }, "binder": { "width": 401, "height": 512, "svg": "" }, "bison": { "width": 512, "height": 512, "svg": "" }, "blender": { "width": 512, "height": 512, "svg": "" }, "blitzbasic": { "width": 512, "height": 512, "svg": "" }, "bloc": { "width": 428, "height": 512, "svg": "" }, "bluespec": { "width": 402, "height": 512, "svg": "" }, "boo": { "width": 512, "height": 512, "svg": "" }, "bors": { "width": 480, "height": 512, "svg": "" }, "bosque": { "width": 512, "height": 512, "svg": "" }, "brainfuck": { "width": 512, "height": 512, "svg": "" }, "brakeman": { "width": 334, "height": 512, "svg": "" }, "bro": { "width": 512, "height": 512, "svg": "" }, "broccoli": { "width": 512, "height": 512, "svg": "" }, "brotli-old": { "width": 374, "height": 512, "svg": "" }, "brotli": { "width": 512, "height": 512, "svg": "" }, "browserslist": { "width": 512, "height": 512, "svg": "" }, "browsersync": { "width": 360, "height": 512, "svg": "" }, "brunch": { "width": 512, "height": 512, "svg": "" }, "buck": { "width": 512, "height": 512, "svg": "" }, "build-boot": { "width": 356, "height": 512, "svg": "" }, "buildkite": { "width": 512, "height": 512, "svg": "" }, "bundler": { "width": 481, "height": 512, "svg": "" }, "c#-script": { "width": 459, "height": 512, "svg": "" }, "c#": { "width": 455, "height": 512, "svg": "" }, "c++": { "width": 512, "height": 512, "svg": "" }, "casc": { "width": 512, "height": 512, "svg": "" }, "cdf": { "width": 494, "height": 512, "svg": "" }, "ckeditor": { "width": 464, "height": 512, "svg": "" }, "clips": { "width": 417, "height": 512, "svg": "" }, "cnab": { "width": 470, "height": 512, "svg": "" }, "cobol": { "width": 512, "height": 512, "svg": "" }, "cpan": { "width": 496, "height": 512, "svg": "" }, "csound": { "width": 508, "height": 512, "svg": "" }, "cvs": { "width": 512, "height": 512, "svg": "" }, "cwl": { "width": 150, "height": 512, "svg": "" }, "cabal": { "width": 512, "height": 512, "svg": "" }, "caddy-old": { "width": 512, "height": 512, "svg": "" }, "caddy": { "width": 507, "height": 512, "svg": "" }, "caffe": { "width": 469, "height": 512, "svg": "" }, "caffe2": { "width": 448, "height": 512, "svg": "" }, "cairo": { "width": 396, "height": 512, "svg": "" }, "cake": { "width": 456, "height": 512, "svg": "" }, "cakephp-old": { "width": 512, "height": 512, "svg": "" }, "cakephp": { "width": 512, "height": 512, "svg": "" }, "cakefile": { "width": 512, "height": 512, "svg": "" }, "calva": { "width": 512, "height": 512, "svg": "" }, "carthage": { "width": 512, "height": 512, "svg": "" }, "ceylon": { "width": 512, "height": 512, "svg": "" }, "chai": { "width": 444, "height": 512, "svg": "" }, "chapel": { "width": 512, "height": 512, "svg": "" }, "chartjs": { "width": 444, "height": 512, "svg": "" }, "cheetah3d": { "width": 512, "height": 512, "svg": "" }, "chef": { "width": 512, "height": 512, "svg": "" }, "chocolatey": { "width": 512, "height": 512, "svg": "" }, "chuck": { "width": 512, "height": 512, "svg": "" }, "circleci": { "width": 505, "height": 512, "svg": "" }, "cirru": { "width": 512, "height": 512, "svg": "" }, "clarion": { "width": 512, "height": 512, "svg": "" }, "clean": { "width": 319, "height": 512, "svg": "" }, "click": { "width": 512, "height": 512, "svg": "" }, "clojurejs": { "width": 512, "height": 512, "svg": "" }, "closuretemplate": { "width": 512, "height": 512, "svg": "" }, "cloudfoundry": { "width": 343, "height": 512, "svg": "" }, "cmake": { "width": 512, "height": 512, "svg": "" }, "conll": { "width": 512, "height": 512, "svg": "" }, "cocoapods": { "width": 512, "height": 512, "svg": "" }, "codacy": { "width": 512, "height": 512, "svg": "" }, "code-climate": { "width": 512, "height": 512, "svg": "" }, "codekit": { "width": 512, "height": 512, "svg": "" }, "codemeta": { "width": 436, "height": 512, "svg": "" }, "codemirror": { "width": 512, "height": 512, "svg": "" }, "codeship": { "width": 512, "height": 512, "svg": "" }, "codecov": { "width": 468, "height": 512, "svg": "" }, "coldfusion": { "width": 512, "height": 512, "svg": "" }, "commitlint": { "width": 512, "height": 512, "svg": "" }, "commitizen": { "width": 512, "height": 512, "svg": "" }, "common-lisp": { "width": 512, "height": 512, "svg": "" }, "component-pascal": { "width": 512, "height": 512, "svg": "" }, "composer": { "width": 393, "height": 512, "svg": "" }, "conan": { "width": 481, "height": 512, "svg": "" }, "conda": { "width": 445, "height": 512, "svg": "" }, "config-coffeescript": { "width": 512, "height": 512, "svg": "" }, "config-go": { "width": 512, "height": 512, "svg": "" }, "config-haskell": { "width": 512, "height": 512, "svg": "" }, "config-js": { "width": 512, "height": 512, "svg": "" }, "config-perl": { "width": 512, "height": 512, "svg": "" }, "config-python": { "width": 512, "height": 512, "svg": "" }, "config-react": { "width": 512, "height": 512, "svg": "" }, "config-ruby": { "width": 512, "height": 512, "svg": "" }, "config-rust": { "width": 512, "height": 512, "svg": "" }, "config-typescript": { "width": 512, "height": 512, "svg": "" }, "config": { "width": 512, "height": 512, "svg": "" }, "coq": { "width": 342, "height": 512, "svg": "" }, "cordova": { "width": 512, "height": 512, "svg": "" }, "coreldraw-alt": { "width": 371, "height": 512, "svg": "" }, "coreldraw": { "width": 512, "height": 512, "svg": "" }, "coveralls": { "width": 512, "height": 512, "svg": "" }, "cpcdosc+": { "width": 500, "height": 512, "svg": "" }, "crafttweaker": { "width": 500, "height": 512, "svg": "" }, "creole": { "width": 512, "height": 512, "svg": "" }, "crowdin": { "width": 512, "height": 512, "svg": "" }, "crystal": { "width": null, "height": null, "svg": "" }, "cubit": { "width": 440, "height": 512, "svg": "" }, "cucumber": { "width": 435, "height": 512, "svg": "" }, "cuneiform": { "width": 512, "height": 512, "svg": "" }, "curl-lang": { "width": 512, "height": 512, "svg": "" }, "curry": { "width": 512, "height": 512, "svg": "" }, "cython": { "width": 512, "height": 512, "svg": "" }, "d3": { "width": 512, "height": 512, "svg": "" }, "dna": { "width": 506, "height": 512, "svg": "" }, "dom": { "width": 512, "height": 512, "svg": "" }, "dosbox-alt": { "width": 456, "height": 512, "svg": "" }, "dosbox": { "width": 512, "height": 512, "svg": "" }, "dvc": { "width": 512, "height": 512, "svg": "" }, "dafny": { "width": 512, "height": 512, "svg": "" }, "darcs-patch": { "width": 512, "height": 512, "svg": "" }, "dashboard": { "width": 512, "height": 512, "svg": "" }, "dataweave": { "width": 512, "height": 512, "svg": "" }, "default": { "width": 384, "height": 512, "svg": "" }, "delphi": { "width": 440, "height": 512, "svg": "" }, "deno": { "width": 512, "height": 512, "svg": "" }, "dependabot": { "width": 480, "height": 512, "svg": "" }, "devcontainer": { "width": 512, "height": 512, "svg": "" }, "devicetree": { "width": 512, "height": 512, "svg": "" }, "dhall": { "width": 243, "height": 512, "svg": "" }, "dia": { "width": 512, "height": 512, "svg": "" }, "diff": { "width": 512, "height": 512, "svg": "" }, "digdag": { "width": 512, "height": 512, "svg": "" }, "docbook": { "width": 512, "height": 512, "svg": "" }, "docpad": { "width": 512, "height": 512, "svg": "" }, "doclets": { "width": 512, "height": 512, "svg": "" }, "docz": { "width": 511.9989929, "height": 511.9989929, "svg": "" }, "dogescript": { "width": 512, "height": 512, "svg": "" }, "donejs": { "width": 512, "height": 512, "svg": "" }, "doxygen": { "width": 438, "height": 512, "svg": "" }, "dragonflybsd": { "width": 441, "height": 512, "svg": "" }, "dragula": { "width": 438, "height": 512, "svg": "" }, "drone": { "width": 512, "height": 512, "svg": "" }, "dub": { "width": 512, "height": 512, "svg": "" }, "dylib": { "width": 503, "height": 512, "svg": "" }, "e": { "width": 406, "height": 512, "svg": "" }, "eclipse-lang": { "width": 512, "height": 512, "svg": "" }, "ejs": { "width": 512, "height": 512, "svg": "" }, "eq": { "width": 512, "height": 512, "svg": "" }, "esdoc": { "width": 512, "height": 512, "svg": "" }, "eslint-old": { "width": null, "height": null, "svg": "" }, "eslint": { "width": 512, "height": 512, "svg": "" }, "eagle": { "width": 512, "height": 512, "svg": "" }, "easybuild": { "width": 355, "height": 512, "svg": "" }, "ecere": { "width": 512, "height": 512, "svg": "" }, "editorconfig": { "width": 512, "height": 512, "svg": "" }, "eiffel": { "width": 512, "height": 512, "svg": "" }, "electron": { "width": 474, "height": 512, "svg": "" }, "elementaryos": { "width": 512, "height": 512, "svg": "" }, "elm": { "width": 512, "height": 512, "svg": "" }, "emacs": { "width": 512, "height": 512, "svg": "" }, "emberscript": { "width": 512, "height": 512, "svg": "" }, "ensime": { "width": 450, "height": 512, "svg": "" }, "expo": { "width": 457, "height": 512, "svg": "" }, "fbx": { "width": 388, "height": 512, "svg": "" }, "ffmpeg": { "width": 512, "height": 512, "svg": "" }, "fossa": { "width": 438, "height": 512, "svg": "" }, "fabfile": { "width": 512, "height": 512, "svg": "" }, "fabric": { "width": 476, "height": 512, "svg": "" }, "factor": { "width": 512, "height": 512, "svg": "" }, "falcon": { "width": 512, "height": 512, "svg": "" }, "fancy": { "width": 341, "height": 512, "svg": "" }, "fantom": { "width": 512, "height": 512, "svg": "" }, "fauna": { "width": 416, "height": 512, "svg": "" }, "faust": { "width": 442, "height": 512, "svg": "" }, "fexl": { "width": 512, "height": 512, "svg": "" }, "fiddle": { "width": 512, "height": 512, "svg": "" }, "finaldraft": { "width": 331, "height": 512, "svg": "" }, "finder": { "width": 465, "height": 512, "svg": "" }, "firebase-bolt": { "width": 272, "height": 512, "svg": "" }, "firebase": { "width": 411, "height": 512, "svg": "" }, "flask": { "width": 512, "height": 512, "svg": "" }, "floobits": { "width": 512, "height": 512, "svg": "" }, "flow": { "width": 413, "height": 512, "svg": "" }, "flutter": { "width": 416, "height": 512, "svg": "" }, "flux": { "width": 512, "height": 512, "svg": "" }, "font-bitmap": { "width": 512, "height": 512, "svg": "" }, "font-outline": { "width": 512, "height": 512, "svg": "" }, "font": { "width": null, "height": null, "svg": "" }, "fontforge": { "width": 450, "height": 512, "svg": "" }, "fortherecord": { "width": 512, "height": 512, "svg": "" }, "fork": { "width": 512, "height": 512, "svg": "" }, "fortran": { "width": null, "height": null, "svg": "" }, "fossil": { "width": 449, "height": 512, "svg": "" }, "fountain": { "width": 512, "height": 512, "svg": "" }, "franca": { "width": 512, "height": 512, "svg": "" }, "freedos": { "width": 512, "height": 512, "svg": "" }, "freedesktop": { "width": 512, "height": 512, "svg": "" }, "freemarker": { "width": 512, "height": 512, "svg": "" }, "freemat": { "width": 489, "height": 512, "svg": "" }, "frege": { "width": 441, "height": 512, "svg": "" }, "fuelux": { "width": 512, "height": 512, "svg": "" }, "fusebox": { "width": 490, "height": 512, "svg": "" }, "futhark": { "width": 512, "height": 512, "svg": "" }, "gams": { "width": 512, "height": 512, "svg": "" }, "gap": { "width": 512, "height": 512, "svg": "" }, "gauss": { "width": 512, "height": 512, "svg": "" }, "gdb": { "width": 512, "height": 512, "svg": "" }, "gf": { "width": 512, "height": 512, "svg": "" }, "gimp": { "width": 512, "height": 512, "svg": "" }, "gn": { "width": 512, "height": 512, "svg": "" }, "gnu": { "width": 512, "height": 512, "svg": "" }, "galaxy": { "width": 512, "height": 512, "svg": "" }, "galen": { "width": 512, "height": 512, "svg": "" }, "gamemaker": { "width": 512, "height": 512, "svg": "" }, "gatsby": { "width": 512, "height": 512, "svg": "" }, "genstat": { "width": 512, "height": 512, "svg": "" }, "genshi": { "width": 310, "height": 512, "svg": "" }, "gentoo": { "width": 489, "height": 512, "svg": "" }, "ghostscript": { "width": 410, "height": 512, "svg": "" }, "gitpod": { "width": 444, "height": 512, "svg": "" }, "glade": { "width": 512, "height": 512, "svg": "" }, "glyphs": { "width": 512, "height": 512, "svg": "" }, "gnuplot": { "width": 512, "height": 512, "svg": "" }, "go-old": { "width": null, "height": null, "svg": "" }, "go": { "width": 376, "height": 512, "svg": "" }, "goreleaser": { "width": 391, "height": 512, "svg": "" }, "godot": { "width": 512, "height": 512, "svg": "" }, "golo": { "width": 512, "height": 512, "svg": "" }, "gosu": { "width": 512, "height": 512, "svg": "" }, "gradle": { "width": 509, "height": 512, "svg": "" }, "graphql-codegenerator": { "width": 393, "height": 512, "svg": "" }, "graphql": { "width": 512, "height": 512, "svg": "" }, "graphviz": { "width": null, "height": null, "svg": "" }, "grapher": { "width": 487, "height": 512, "svg": "" }, "graphite": { "width": 512, "height": 512, "svg": "" }, "gravit-designer": { "width": 512, "height": 512, "svg": "" }, "greenkeeper": { "width": 512, "height": 512, "svg": "" }, "gridsome": { "width": 512, "height": 512, "svg": "" }, "groovy": { "width": 512, "height": 512, "svg": "" }, "hie": { "width": 512, "height": 512, "svg": "" }, "hjson": { "width": 512, "height": 512, "svg": "" }, "hack": { "width": 350, "height": 512, "svg": "" }, "haml": { "width": 396, "height": 512, "svg": "" }, "harbour": { "width": 512, "height": 512, "svg": "" }, "hashicorp": { "width": 512, "height": 512, "svg": "" }, "haxe": { "width": 512, "height": 512, "svg": "" }, "haxedevelop": { "width": 512, "height": 512, "svg": "" }, "helix": { "width": 448, "height": 512, "svg": "" }, "hewlettpackard": { "width": 512, "height": 512, "svg": "" }, "hitachi": { "width": 512, "height": 512, "svg": "" }, "homebrew": { "width": 397, "height": 512, "svg": "" }, "hop": { "width": 512, "height": 512, "svg": "" }, "hoplon": { "width": 512, "height": 512, "svg": "" }, "houdini": { "width": 512, "height": 512, "svg": "" }, "houndci": { "width": 512, "height": 512, "svg": "" }, "hugo": { "width": 456, "height": 512, "svg": "" }, "husky": { "width": 487, "height": 512, "svg": "" }, "hy": { "width": 512, "height": 512, "svg": "" }, "hygen": { "width": 512, "height": 512, "svg": "" }, "hyper": { "width": 512, "height": 512, "svg": "" }, "icu": { "width": 512, "height": 512, "svg": "" }, "idl": { "width": 512, "height": 512, "svg": "" }, "igor-pro": { "width": 512, "height": 512, "svg": "" }, "icomoon": { "width": 512, "height": 512, "svg": "" }, "idris": { "width": 279, "height": 512, "svg": "" }, "image": { "width": 439, "height": 512, "svg": "" }, "imba-alt": { "width": 512, "height": 512, "svg": "" }, "imba-old": { "width": 512, "height": 512, "svg": "" }, "imba": { "width": 512, "height": 512, "svg": "" }, "imgbot": { "width": 360, "height": 512, "svg": "" }, "influxdata": { "width": 504, "height": 512, "svg": "" }, "inform7": { "width": 512, "height": 512, "svg": "" }, "ink": { "width": 512, "height": 512, "svg": "" }, "inkscape": { "width": 512, "height": 512, "svg": "" }, "innosetup": { "width": 512, "height": 512, "svg": "" }, "intel": { "width": 512, "height": 512, "svg": "" }, "io": { "width": 512, "height": 512, "svg": "" }, "ioke": { "width": 512, "height": 512, "svg": "" }, "ionic-project": { "width": 512, "height": 512, "svg": "" }, "isabelle": { "width": 512, "height": 512, "svg": "" }, "istanbul": { "width": null, "height": null, "svg": "" }, "j": { "width": 512, "height": 512, "svg": "" }, "json": { "width": 512, "height": 512, "svg": "" }, "json-2": { "width": 512, "height": 512, "svg": "" }, "json-ld1": { "width": 512, "height": 512, "svg": "" }, "json-ld2": { "width": 512, "height": 512, "svg": "" }, "json5": { "width": 512, "height": 512, "svg": "" }, "jsx-alt": { "width": 512, "height": 512, "svg": "" }, "jsx-atom": { "width": 512, "height": 512, "svg": "" }, "jsx": { "width": 512, "height": 512, "svg": "" }, "jade": { "width": null, "height": null, "svg": "" }, "jakefile": { "width": 512, "height": 512, "svg": "" }, "janet": { "width": 455, "height": 512, "svg": "" }, "jasmine": { "width": 512, "height": 512, "svg": "" }, "jest": { "width": 450, "height": 512, "svg": "" }, "jinja": { "width": 512, "height": 512, "svg": "" }, "jison": { "width": 473, "height": 512, "svg": "" }, "jolie": { "width": 512, "height": 512, "svg": "" }, "jsonnet": { "width": 512, "height": 512, "svg": "" }, "julia": { "width": 512, "height": 512, "svg": "" }, "junos": { "width": 472, "height": 512, "svg": "" }, "jupyter": { "width": 376, "height": 512, "svg": "" }, "knime": { "width": 512, "height": 512, "svg": "" }, "krl": { "width": 512, "height": 512, "svg": "" }, "kaitai": { "width": 512, "height": 512, "svg": "" }, "karma": { "width": 512, "height": 512, "svg": "" }, "keynote": { "width": 434, "height": 512, "svg": "" }, "khronos": { "width": 512, "height": 512, "svg": "" }, "kicad": { "width": 512, "height": 512, "svg": "" }, "kibo": { "width": 512, "height": 512, "svg": "" }, "kitchenci": { "width": 476, "height": 512, "svg": "" }, "kivy": { "width": null, "height": null, "svg": "" }, "knockout": { "width": 512, "height": 512, "svg": "" }, "kotlin": { "width": 512, "height": 512, "svg": "" }, "kubernetes": { "width": 512, "height": 512, "svg": "" }, "kusto-alt": { "width": 512, "height": 512, "svg": "" }, "kusto": { "width": 512, "height": 512, "svg": "" }, "kx": { "width": 512, "height": 512, "svg": "" }, "lfe": { "width": 434, "height": 512, "svg": "" }, "lgtm": { "width": 512, "height": 512, "svg": "" }, "linqpad": { "width": 485, "height": 512, "svg": "" }, "llvm": { "width": 512, "height": 512, "svg": "" }, "lolcode": { "width": 411, "height": 512, "svg": "" }, "lsl": { "width": 377, "height": 512, "svg": "" }, "latex": { "width": null, "height": null, "svg": "" }, "labview": { "width": 512, "height": 512, "svg": "" }, "lark": { "width": 497, "height": 512, "svg": "" }, "lasso": { "width": 512, "height": 512, "svg": "" }, "latino": { "width": 512, "height": 512, "svg": "" }, "leaflet": { "width": 460, "height": 512, "svg": "" }, "lean": { "width": 315, "height": 512, "svg": "" }, "lefthook-alt": { "width": 512, "height": 512, "svg": "" }, "lefthook": { "width": 512, "height": 512, "svg": "" }, "leiningen": { "width": 305, "height": 512, "svg": "" }, "lektor": { "width": 512, "height": 512, "svg": "" }, "lerna": { "width": 512, "height": 512, "svg": "" }, "lex-alt": { "width": 512, "height": 512, "svg": "" }, "lex": { "width": 500, "height": 512, "svg": "" }, "lightwave": { "width": 512, "height": 512, "svg": "" }, "lighthouse": { "width": 512, "height": 512, "svg": "" }, "lilypond": { "width": 512, "height": 512, "svg": "" }, "lime": { "width": 405, "height": 512, "svg": "" }, "lisp": { "width": 512, "height": 512, "svg": "" }, "livescript": { "width": null, "height": null, "svg": "" }, "logtalk": { "width": 512, "height": 512, "svg": "" }, "lookml": { "width": 329, "height": 512, "svg": "" }, "lua": { "width": 512, "height": 512, "svg": "" }, "matlab": { "width": 512, "height": 512, "svg": "" }, "mdx": { "width": 512, "height": 512, "svg": "" }, "melpa": { "width": 512, "height": 512, "svg": "" }, "mjml": { "width": 512, "height": 512, "svg": "" }, "ms-dos": { "width": 408, "height": 512, "svg": "" }, "macvim": { "width": 512, "height": 512, "svg": "" }, "macaulay2": { "width": 388, "height": 512, "svg": "" }, "magit": { "width": 512, "height": 512, "svg": "" }, "mako": { "width": 338, "height": 512, "svg": "" }, "manjaro": { "width": 512, "height": 512, "svg": "" }, "manpage": { "width": 512, "height": 512, "svg": "" }, "mapbox": { "width": 512, "height": 512, "svg": "" }, "markdownlint": { "width": 512, "height": 512, "svg": "" }, "marko": { "width": null, "height": null, "svg": "" }, "mathjax": { "width": 512, "height": 512, "svg": "" }, "mathematica": { "width": 512, "height": 512, "svg": "" }, "matroska": { "width": 512, "height": 512, "svg": "" }, "max": { "width": 512, "height": 512, "svg": "" }, "maya": { "width": 512, "height": 512, "svg": "" }, "mediawiki": { "width": 512, "height": 512, "svg": "" }, "mercurial": { "width": 512, "height": 512, "svg": "" }, "mercury": { "width": 512, "height": 512, "svg": "" }, "mermaid": { "width": 367, "height": 512, "svg": "" }, "meson-old": { "width": 512, "height": 512, "svg": "" }, "meson": { "width": 512, "height": 512, "svg": "" }, "metapost": { "width": 512, "height": 512, "svg": "" }, "metal": { "width": 512, "height": 512, "svg": "" }, "meteor": { "width": 512, "height": 512, "svg": "" }, "microsoft-access": { "width": 512, "height": 512, "svg": "" }, "microsoft-excel": { "width": 512, "height": 512, "svg": "" }, "microsoft-infopath": { "width": 512, "height": 512, "svg": "" }, "microsoft-lync": { "width": 512, "height": 512, "svg": "" }, "microsoft-onenote": { "width": 512, "height": 512, "svg": "" }, "microsoft-outlook": { "width": 507, "height": 512, "svg": "" }, "microsoft-powerpoint": { "width": 512, "height": 512, "svg": "" }, "microsoft-project": { "width": 512, "height": 512, "svg": "" }, "microsoft-publisher": { "width": 512, "height": 512, "svg": "" }, "microsoft-visio": { "width": 512, "height": 512, "svg": "" }, "microsoft-word": { "width": 512, "height": 512, "svg": "" }, "minecraft": { "width": 512, "height": 512, "svg": "" }, "minizinc": { "width": 512, "height": 512, "svg": "" }, "mint": { "width": 512, "height": 512, "svg": "" }, "mirah": { "width": 311, "height": 512, "svg": "" }, "miranda": { "width": 300, "height": 512, "svg": "" }, "mixin": { "width": 418, "height": 512, "svg": "" }, "mocha": { "width": 310, "height": 512, "svg": "" }, "modelica": { "width": 512, "height": 512, "svg": "" }, "modernweb": { "width": 512, "height": 512, "svg": "" }, "modo": { "width": 512, "height": 512, "svg": "" }, "modula-2": { "width": 512, "height": 512, "svg": "" }, "modula-3": { "width": 512, "height": 512, "svg": "" }, "moho": { "width": 512, "height": 512, "svg": "" }, "moleculer": { "width": 512, "height": 512, "svg": "" }, "moment-timezone": { "width": 512, "height": 512, "svg": "" }, "moment": { "width": 512, "height": 512, "svg": "" }, "monkey": { "width": 512, "height": 512, "svg": "" }, "mono": { "width": 512, "height": 512, "svg": "" }, "monotone": { "width": 415, "height": 512, "svg": "" }, "motorola": { "width": 512, "height": 512, "svg": "" }, "moustache": { "width": 512, "height": 512, "svg": "" }, "mruby": { "width": 460, "height": 512, "svg": "" }, "mupad": { "width": null, "height": null, "svg": "" }, "nasm": { "width": 512, "height": 512, "svg": "" }, "nant": { "width": 512, "height": 512, "svg": "" }, "ndepend": { "width": 512, "height": 512, "svg": "" }, "neon": { "width": 470, "height": 512, "svg": "" }, "npm-old": { "width": null, "height": null, "svg": "" }, "nsis-old": { "width": 512, "height": 512, "svg": "" }, "nsis": { "width": 512, "height": 512, "svg": "" }, "nsri-alt": { "width": 355, "height": 512, "svg": "" }, "nsri": { "width": 426, "height": 512, "svg": "" }, "nvidia": { "width": 512, "height": 512, "svg": "" }, "nwscript": { "width": 512, "height": 512, "svg": "" }, "nxc": { "width": 343, "height": 512, "svg": "" }, "nano": { "width": 383, "height": 512, "svg": "" }, "nanoc": { "width": 512, "height": 512, "svg": "" }, "neko": { "width": 486, "height": 512, "svg": "" }, "nemerle": { "width": 512, "height": 512, "svg": "" }, "neo4j": { "width": 459, "height": 512, "svg": "" }, "nessus": { "width": 512, "height": 512, "svg": "" }, "nestjs": { "width": 512, "height": 512, "svg": "" }, "netlinx": { "width": 512, "height": 512, "svg": "" }, "netlogo": { "width": 512, "height": 512, "svg": "" }, "netlify": { "width": 512, "height": 512, "svg": "" }, "new-relic": { "width": 512, "height": 512, "svg": "" }, "nextjs": { "width": 512, "height": 512, "svg": "" }, "nextflow": { "width": 512, "height": 512, "svg": "" }, "ngrx": { "width": 478, "height": 512, "svg": "" }, "nib": { "width": 512, "height": 512, "svg": "" }, "nickle": { "width": 512, "height": 512, "svg": "" }, "nightwatch": { "width": 423, "height": 512, "svg": "" }, "nimble": { "width": 512, "height": 512, "svg": "" }, "nimrod": { "width": 512, "height": 512, "svg": "" }, "nintendo64": { "width": 512, "height": 512, "svg": "" }, "nit": { "width": 512, "height": 512, "svg": "" }, "nix": { "width": 512, "height": 512, "svg": "" }, "nmap": { "width": 512, "height": 512, "svg": "" }, "nodemon": { "width": 451, "height": 512, "svg": "" }, "nokogiri": { "width": 512, "height": 512, "svg": "" }, "nomad": { "width": 438, "height": 512, "svg": "" }, "noon": { "width": 512, "height": 512, "svg": "" }, "normalise": { "width": 512, "height": 512, "svg": "" }, "nuget": { "width": 512, "height": 512, "svg": "" }, "nuclide": { "width": 427, "height": 512, "svg": "" }, "numpy-old": { "width": 512, "height": 512, "svg": "" }, "numpy": { "width": 480, "height": 512, "svg": "" }, "nunjucks": { "width": null, "height": null, "svg": "" }, "nuxt": { "width": 512, "height": 512, "svg": "" }, "nx": { "width": 512, "height": 512, "svg": "" }, "ocaml": { "width": 512, "height": 512, "svg": "" }, "ooc": { "width": 387, "height": 512, "svg": "" }, "os2": { "width": 512, "height": 512, "svg": "" }, "owl": { "width": 318, "height": 512, "svg": "" }, "oberon": { "width": 512, "height": 512, "svg": "" }, "objective-j": { "width": 512, "height": 512, "svg": "" }, "octave": { "width": 512, "height": 512, "svg": "" }, "odin": { "width": 512, "height": 512, "svg": "" }, "ogone": { "width": 461, "height": 512, "svg": "" }, "omnigraffle": { "width": 512, "height": 512, "svg": "" }, "opa": { "width": 512, "height": 512, "svg": "" }, "openapi": { "width": 512, "height": 512, "svg": "" }, "openbsd-alt": { "width": 512, "height": 512, "svg": "" }, "openbsd": { "width": 512, "height": 512, "svg": "" }, "opencl": { "width": 512, "height": 512, "svg": "" }, "opencv": { "width": 512, "height": 512, "svg": "" }, "openexr": { "width": 481, "height": 512, "svg": "" }, "opengl": { "width": 512, "height": 512, "svg": "" }, "openindiana": { "width": 512, "height": 512, "svg": "" }, "openoffice": { "width": 512, "height": 512, "svg": "" }, "openpolicyagent": { "width": 460, "height": 512, "svg": "" }, "opensolaris": { "width": 512, "height": 512, "svg": "" }, "openstack": { "width": 512, "height": 512, "svg": "" }, "openvms": { "width": null, "height": null, "svg": "" }, "openvpn": { "width": 512, "height": 512, "svg": "" }, "openzfs": { "width": 512, "height": 512, "svg": "" }, "openscad": { "width": 641, "height": 512, "svg": "" }, "org-mode": { "width": 467, "height": 512, "svg": "" }, "ox": { "width": 512, "height": 512, "svg": "" }, "oxygene": { "width": 512, "height": 512, "svg": "" }, "oz": { "width": 512, "height": 512, "svg": "" }, "p4": { "width": 512, "height": 512, "svg": "" }, "pawn": { "width": 242, "height": 512, "svg": "" }, "pcd": { "width": 512, "height": 512, "svg": "" }, "phpunit": { "width": 512, "height": 512, "svg": "" }, "pico-8": { "width": null, "height": null, "svg": "" }, "pm2": { "width": 512, "height": 512, "svg": "" }, "pnpm": { "width": 512, "height": 512, "svg": "" }, "pov-ray": { "width": 371, "height": 512, "svg": "" }, "pros": { "width": 512, "height": 512, "svg": "" }, "pan": { "width": 512, "height": 512, "svg": "" }, "papyrus": { "width": 512, "height": 512, "svg": "" }, "parrot": { "width": 375, "height": 512, "svg": "" }, "pascal": { "width": 512, "height": 512, "svg": "" }, "patch": { "width": 512, "height": 512, "svg": "" }, "pegjs": { "width": 417, "height": 512, "svg": "" }, "perl6": { "width": 512, "height": 512, "svg": "" }, "phalcon": { "width": 448, "height": 512, "svg": "" }, "phoenix": { "width": 512, "height": 512, "svg": "" }, "photorec": { "width": 512, "height": 512, "svg": "" }, "phraseapp": { "width": 512, "height": 512, "svg": "" }, "pickle": { "width": 370, "height": 512, "svg": "" }, "picolisp": { "width": 512, "height": 512, "svg": "" }, "pike": { "width": 512, "height": 512, "svg": "" }, "pinescript": { "width": 512, "height": 512, "svg": "" }, "pipenv": { "width": 512, "height": 512, "svg": "" }, "platformio": { "width": 425, "height": 512, "svg": "" }, "pod": { "width": 512, "height": 512, "svg": "" }, "pogoscript": { "width": 286, "height": 512, "svg": "" }, "pointwise": { "width": 512, "height": 512, "svg": "" }, "polymer": { "width": 512, "height": 512, "svg": "" }, "pony": { "width": 512, "height": 512, "svg": "" }, "postcss": { "width": null, "height": null, "svg": "" }, "postscript": { "width": 512, "height": 512, "svg": "" }, "powerbuilder": { "width": 497, "height": 512, "svg": "" }, "powerpc": { "width": 512, "height": 512, "svg": "" }, "powershell": { "width": 512, "height": 512, "svg": "" }, "precision": { "width": 512, "height": 512, "svg": "" }, "precommit": { "width": 512, "height": 512, "svg": "" }, "prettier": { "width": 439, "height": 512, "svg": "" }, "prisma": { "width": null, "height": null, "svg": "" }, "processing": { "width": 512, "height": 512, "svg": "" }, "progress-old": { "width": 512, "height": 512, "svg": "" }, "progress": { "width": 479, "height": 512, "svg": "" }, "propeller": { "width": 512, "height": 512, "svg": "" }, "proselint": { "width": 512, "height": 512, "svg": "" }, "protractor": { "width": 512, "height": 512, "svg": "" }, "pug-old": { "width": 512, "height": 512, "svg": "" }, "pug": { "width": 512, "height": 512, "svg": "" }, "pullapprove": { "width": 512, "height": 512, "svg": "" }, "puppet": { "width": 335, "height": 512, "svg": "" }, "pure": { "width": 293, "height": 512, "svg": "" }, "purebasic": { "width": 512, "height": 512, "svg": "" }, "purescript": { "width": 512, "height": 512, "svg": "" }, "pypi": { "width": 454, "height": 512, "svg": "" }, "pyup": { "width": 443, "height": 512, "svg": "" }, "pyret": { "width": 512, "height": 500, "svg": "" }, "q#": { "width": 382, "height": 512, "svg": "" }, "qt": { "width": 512, "height": 512, "svg": "" }, "qiskit": { "width": 512, "height": 512, "svg": "" }, "qlikview": { "width": 512, "height": 512, "svg": "" }, "quasar": { "width": 512, "height": 512, "svg": "" }, "r": { "width": 512, "height": 512, "svg": "" }, "raml": { "width": null, "height": null, "svg": "" }, "rdata": { "width": 512, "height": 512, "svg": "" }, "rdoc": { "width": 512, "height": 512, "svg": "" }, "realbasic": { "width": 512, "height": 512, "svg": "" }, "risc-v": { "width": 512, "height": 512, "svg": "" }, "rspec": { "width": 512, "height": 512, "svg": "" }, "rstudio": { "width": 512, "height": 512, "svg": "" }, "racket": { "width": 512, "height": 512, "svg": "" }, "rascal": { "width": 512, "height": 512, "svg": "" }, "razzle": { "width": 403, "height": 512, "svg": "" }, "rescript": { "width": 512, "height": 512, "svg": "" }, "reactos": { "width": 512, "height": 512, "svg": "" }, "readthedocs": { "width": 402, "height": 512, "svg": "" }, "reason": { "width": 512, "height": 512, "svg": "" }, "reasonstudios-alt": { "width": 512, "height": 512, "svg": "" }, "reasonstudios": { "width": 456, "height": 512, "svg": "" }, "rebol": { "width": 512, "height": 512, "svg": "" }, "red-old": { "width": 512, "height": 512, "svg": "" }, "red": { "width": 512, "height": 512, "svg": "" }, "redux": { "width": 512, "height": 512, "svg": "" }, "reek": { "width": 512, "height": 512, "svg": "" }, "regex": { "width": 512, "height": 512, "svg": "" }, "remark": { "width": 512, "height": 512, "svg": "" }, "renovate": { "width": 512, "height": 512, "svg": "" }, "rexx": { "width": 353, "height": 512, "svg": "" }, "rhino3d": { "width": 512, "height": 512, "svg": "" }, "ring": { "width": 454, "height": 512, "svg": "" }, "riot-old": { "width": 512, "height": 512, "svg": "" }, "riot": { "width": 512, "height": 512, "svg": "" }, "rmarkdown": { "width": 512, "height": 512, "svg": "" }, "robotframework-old": { "width": 512, "height": 512, "svg": "" }, "robotframework": { "width": 512, "height": 512, "svg": "" }, "robots": { "width": 512, "height": 512, "svg": "" }, "rollup-old": { "width": 446, "height": 512, "svg": "" }, "rollup": { "width": 387, "height": 512, "svg": "" }, "rubocop": { "width": 433, "height": 512, "svg": "" }, "rubygems": { "width": 447, "height": 512, "svg": "" }, "sac": { "width": 384, "height": 512, "svg": "" }, "sas": { "width": 342, "height": 512, "svg": "" }, "sbt": { "width": 512, "height": 512, "svg": "" }, "sparc": { "width": 286, "height": 512, "svg": "" }, "sqf": { "width": 512, "height": 512, "svg": "" }, "sqlite": { "width": 458, "height": 512, "svg": "" }, "svn": { "width": 512, "height": 512, "svg": "" }, "sage": { "width": 512, "height": 512, "svg": "" }, "sails": { "width": 512, "height": 512, "svg": "" }, "saltstack": { "width": 500, "height": 512, "svg": "" }, "san": { "width": 425, "height": 512, "svg": "" }, "sandbox": { "width": 512, "height": 512, "svg": "" }, "scheme": { "width": 350, "height": 512, "svg": "" }, "scilab": { "width": 512, "height": 512, "svg": "" }, "scilla": { "width": 512, "height": 512, "svg": "" }, "scratch": { "width": 271, "height": 512, "svg": "" }, "scrutinizer": { "width": 447, "height": 512, "svg": "" }, "self": { "width": 512, "height": 512, "svg": "" }, "semanticrelease": { "width": 444, "height": 512, "svg": "" }, "sentry": { "width": 512, "height": 512, "svg": "" }, "sequelize": { "width": 443, "height": 512, "svg": "" }, "serverless": { "width": 512, "height": 512, "svg": "" }, "service-fabric": { "width": 512, "height": 512, "svg": "" }, "shadowcljs": { "width": 512, "height": 512, "svg": "" }, "shellcheck": { "width": 512, "height": 512, "svg": "" }, "shen": { "width": null, "height": null, "svg": "" }, "shipit": { "width": 512, "height": 512, "svg": "" }, "shippable": { "width": 512, "height": 512, "svg": "" }, "shuriken": { "width": 512, "height": 512, "svg": "" }, "sigils": { "width": null, "height": null, "svg": "" }, "silicongraphics": { "width": 506, "height": 512, "svg": "" }, "silverstripe": { "width": 508, "height": 512, "svg": "" }, "sinatra": { "width": 512, "height": 512, "svg": "" }, "sketchup-layout": { "width": 512, "height": 512, "svg": "" }, "sketchup-make": { "width": 475, "height": 512, "svg": "" }, "sketchup-stylebuilder": { "width": 482, "height": 512, "svg": "" }, "slash": { "width": 512, "height": 512, "svg": "" }, "smartos-alt": { "width": 512, "height": 512, "svg": "" }, "smartos": { "width": 512, "height": 512, "svg": "" }, "snapcraft": { "width": 512, "height": 512, "svg": "" }, "snort": { "width": 512, "height": 512, "svg": "" }, "snowpack": { "width": 512, "height": 512, "svg": "" }, "snyk": { "width": 280, "height": 512, "svg": "" }, "solidarity": { "width": 346, "height": 512, "svg": "" }, "solidity": { "width": 330, "height": 512, "svg": "" }, "sophia": { "width": 489, "height": 512, "svg": "" }, "sorbet": { "width": 397, "height": 512, "svg": "" }, "source": { "width": 512, "height": 512, "svg": "" }, "spacemacs": { "width": 512, "height": 512, "svg": "" }, "spacengine": { "width": 474, "height": 512, "svg": "" }, "spray": { "width": 448, "height": 512, "svg": "" }, "stan": { "width": 512, "height": 512, "svg": "" }, "stata": { "width": 512, "height": 512, "svg": "" }, "stdlibjs": { "width": 460, "height": 512, "svg": "" }, "stencil": { "width": 405, "height": 512, "svg": "" }, "stitches": { "width": 512, "height": 512, "svg": "" }, "storybook": { "width": null, "height": null, "svg": "" }, "storyist": { "width": 512, "height": 512, "svg": "" }, "strings": { "width": null, "height": null, "svg": "" }, "stylable": { "width": 455, "height": 512, "svg": "" }, "styledcomponents": { "width": 512, "height": 512, "svg": "" }, "stylelint": { "width": null, "height": null, "svg": "" }, "stylishhaskell": { "width": 417, "height": 512, "svg": "" }, "stylus-orb": { "width": 512, "height": 512, "svg": "" }, "stylus-s": { "width": 376, "height": 512, "svg": "" }, "stylus": { "width": 512, "height": 512, "svg": "" }, "sublime": { "width": 512, "height": 512, "svg": "" }, "supercollider": { "width": 512, "height": 512, "svg": "" }, "svelte": { "width": 426, "height": 512, "svg": "" }, "swagger": { "width": 512, "height": 512, "svg": "" }, "systemverilog": { "width": 512, "height": 512, "svg": "" }, "tfs": { "width": 510, "height": 512, "svg": "" }, "tla+": { "width": 512, "height": 512, "svg": "" }, "toml": { "width": 512, "height": 512, "svg": "" }, "totvs": { "width": 502, "height": 512, "svg": "" }, "tsx-alt": { "width": 512, "height": 512, "svg": "" }, "tsx": { "width": 512, "height": 512, "svg": "" }, "ttcn-3": { "width": 400, "height": 512, "svg": "" }, "txl": { "width": 512, "height": 512, "svg": "" }, "tag": { "width": "32", "height": "32", "svg": "\n \n \n" }, "tailwind": { "width": 512, "height": 512, "svg": "" }, "tcl": { "width": 242, "height": 512, "svg": "" }, "templatetoolkit": { "width": 512, "height": 512, "svg": "" }, "templeos": { "width": 473, "height": 512, "svg": "" }, "terminal": { "width": 512, "height": 512, "svg": "" }, "tern": { "width": 491, "height": 512, "svg": "" }, "terraform": { "width": 458, "height": 512, "svg": "" }, "terser": { "width": 512, "height": 512, "svg": "" }, "test-coffeescript": { "width": 512, "height": 512, "svg": "" }, "test-directory": { "width": 512, "height": 512, "svg": "" }, "test-generic": { "width": 512, "height": 512, "svg": "" }, "test-go": { "width": 512, "height": 512, "svg": "" }, "test-haskell": { "width": 512, "height": 512, "svg": "" }, "test-js": { "width": 512, "height": 512, "svg": "" }, "test-perl": { "width": 512, "height": 512, "svg": "" }, "test-python": { "width": 512, "height": 512, "svg": "" }, "test-react": { "width": 512, "height": 512, "svg": "" }, "test-ruby": { "width": 512, "height": 512, "svg": "" }, "test-rust": { "width": 512, "height": 512, "svg": "" }, "test-typescript": { "width": 512, "height": 512, "svg": "" }, "testcafe": { "width": 512, "height": 512, "svg": "" }, "textmate": { "width": 512, "height": 512, "svg": "" }, "textile": { "width": 512, "height": 512, "svg": "" }, "thor": { "width": 512, "height": 512, "svg": "" }, "tilt": { "width": 470, "height": 512, "svg": "" }, "tinymce": { "width": 512, "height": 512, "svg": "" }, "tipe": { "width": 331, "height": 512, "svg": "" }, "tortoisesvn": { "width": 512, "height": 512, "svg": "" }, "truffle": { "width": 490, "height": 512, "svg": "" }, "turing": { "width": 512, "height": 512, "svg": "" }, "twig": { "width": 409, "height": 512, "svg": "" }, "twine": { "width": 448, "height": 512, "svg": "" }, "typedoc": { "width": 467, "height": 512, "svg": "" }, "typescript-alt": { "width": 512, "height": 512, "svg": "" }, "typescript": { "width": 512, "height": 512, "svg": "" }, "typings": { "width": 512, "height": 512, "svg": "" }, "ufo": { "width": 512, "height": 512, "svg": "" }, "uno": { "width": 512, "height": 512, "svg": "" }, "unibeautify": { "width": 395, "height": 512, "svg": "" }, "unicode": { "width": 512, "height": 512, "svg": "" }, "unrealscript": { "width": 512, "height": 512, "svg": "" }, "urweb": { "width": 512, "height": 512, "svg": "" }, "v-ray": { "width": 512, "height": 512, "svg": "" }, "v": { "width": 512, "height": 512, "svg": "" }, "v8-turbofan": { "width": 512, "height": 512, "svg": "" }, "v8": { "width": 512, "height": 512, "svg": "" }, "vax": { "width": 512, "height": 512, "svg": "" }, "vcl": { "width": 512, "height": 512, "svg": "" }, "vhdl": { "width": 512, "height": 512, "svg": "" }, "vmware": { "width": 512, "height": 512, "svg": "" }, "vscode": { "width": 512, "height": 512, "svg": "" }, "vsts": { "width": 512, "height": 512, "svg": "" }, "vagrant": { "width": null, "height": null, "svg": "" }, "vala": { "width": 512, "height": 512, "svg": "" }, "velocity": { "width": 457, "height": 512, "svg": "" }, "verilog": { "width": 512, "height": 512, "svg": "" }, "vertexshader": { "width": 512, "height": 512, "svg": "" }, "video": { "width": "32", "height": "32", "svg": "\n \n" }, "virtualbox-alt": { "width": 512, "height": 512, "svg": "" }, "virtualbox": { "width": 440, "height": 512, "svg": "" }, "vite": { "width": 510, "height": 512, "svg": "" }, "vue": { "width": 512, "height": 512, "svg": "" }, "vyper": { "width": 512, "height": 512, "svg": "" }, "w3c": { "width": 512, "height": 512, "svg": "" }, "wasi": { "width": 512, "height": 512, "svg": "" }, "wdl": { "width": 356, "height": 512, "svg": "" }, "wallaby": { "width": 512, "height": 512, "svg": "" }, "walt": { "width": 512, "height": 512, "svg": "" }, "warcraft-iii": { "width": 512, "height": 512, "svg": "" }, "watchman": { "width": 512, "height": 512, "svg": "" }, "webassembly": { "width": 512, "height": 512, "svg": "" }, "webgl": { "width": 512, "height": 512, "svg": "" }, "webvtt": { "width": 512, "height": 512, "svg": "" }, "webhint": { "width": 512, "height": 512, "svg": "" }, "webpack-old": { "width": 450, "height": 512, "svg": "" }, "webpack": { "width": 462, "height": 512, "svg": "" }, "wenyan": { "width": 300, "height": 512, "svg": "" }, "wercker": { "width": 384, "height": 512, "svg": "" }, "wget": { "width": 512, "height": 512, "svg": "" }, "winui": { "width": 512, "height": 512, "svg": "" }, "windi": { "width": 472, "height": 512, "svg": "" }, "wine": { "width": 302, "height": 512, "svg": "" }, "wolfram": { "width": 512, "height": 512, "svg": "" }, "workbox": { "width": 512, "height": 512, "svg": "" }, "wurst": { "width": 512, "height": 512, "svg": "" }, "x10": { "width": 512, "height": 512, "svg": "" }, "xmos": { "width": 512, "height": 512, "svg": "" }, "xpages": { "width": 512, "height": 512, "svg": "" }, "xamarin": { "width": 512, "height": 512, "svg": "" }, "xtend": { "width": 512, "height": 512, "svg": "" }, "xubuntu": { "width": 512, "height": 512, "svg": "" }, "yaml-alt1": { "width": 512, "height": 512, "svg": "" }, "yaml-alt2": { "width": 512, "height": 512, "svg": "" }, "yaml-alt3": { "width": 512, "height": 512, "svg": "" }, "yaml-alt4": { "width": 512, "height": 512, "svg": "" }, "yaml": { "width": 457, "height": 512, "svg": "" }, "yamllint": { "width": 512, "height": 512, "svg": "" }, "yang": { "width": 512, "height": 512, "svg": "" }, "yara": { "width": 512, "height": 512, "svg": "" }, "yui": { "width": 512, "height": 512, "svg": "" }, "yasm": { "width": 462, "height": 512, "svg": "" }, "yorick": { "width": 417, "height": 512, "svg": "" }, "zbrush": { "width": 512, "height": 512, "svg": "" }, "zeit": { "width": 512, "height": 512, "svg": "" }, "zephir": { "width": 512, "height": 512, "svg": "" }, "zig": { "width": 512, "height": 512, "svg": "" }, "zilog": { "width": 512, "height": 512, "svg": "" }, "zimpl": { "width": 476, "height": 512, "svg": "" }, "zorinos": { "width": 512, "height": 512, "svg": "" }, "zork": { "width": 470, "height": 512, "svg": "" }, "bithound": { "width": 466, "height": 512, "svg": "" }, "curl": { "width": 512, "height": 512, "svg": "" }, "dbase": { "width": 512, "height": 512, "svg": "" }, "dotenv": { "width": 512, "height": 512, "svg": "" }, "dotjs": { "width": 512, "height": 512, "svg": "" }, "draw.io": { "width": 512, "height": 512, "svg": "" }, "ec": { "width": 512, "height": 512, "svg": "" }, "fthtml": { "width": 512, "height": 512, "svg": "" }, "gltf": { "width": 512, "height": 512, "svg": "" }, "illumos": { "width": 394, "height": 512, "svg": "" }, "jscpd": { "width": 512, "height": 512, "svg": "" }, "kos": { "width": 512, "height": 512, "svg": "" }, "libuv": { "width": 435, "height": 512, "svg": "" }, "mirc": { "width": 512, "height": 512, "svg": "" }, "nginx": { "width": 512, "height": 512, "svg": "" }, "pkgsrc": { "width": 487, "height": 512, "svg": "" }, "pytest": { "width": 512, "height": 512, "svg": "" }, "restructuredtext": { "width": 512, "height": 512, "svg": "" }, "restql": { "width": 458, "height": 512, "svg": "" }, "rsync": { "width": 512, "height": 512, "svg": "" }, "tmux": { "width": 512, "height": 512, "svg": "" }, "xmake": { "width": 512, "height": 512, "svg": "" }, "appcelerator": { "width": 512, "height": 512, "svg": "" }, "appstore": { "width": 512, "height": 512, "svg": "" }, "aptana": { "width": 512, "height": 512, "svg": "" }, "asterisk": { "width": 512, "height": 512, "svg": "" }, "atom": { "width": 512, "height": 512, "svg": "" }, "backbone": { "width": 413, "height": 512, "svg": "" }, "bing": { "width": 410, "height": 512, "svg": "" }, "bloatstrap": { "width": 512, "height": 512, "svg": "" }, "bower": { "width": 512, "height": 512, "svg": "" }, "brackets": { "width": 512, "height": 512, "svg": "" }, "bugsense": { "width": 512, "height": 512, "svg": "" }, "celluloid": { "width": 512, "height": 512, "svg": "" }, "cisco": { "width": 512, "height": 512, "svg": "" }, "clojure-alt": { "width": 512, "height": 512, "svg": "" }, "clojure": { "width": 512, "height": 512, "svg": "" }, "cloud9": { "width": 512, "height": 512, "svg": "" }, "coda": { "width": 512, "height": 512, "svg": "" }, "code-badge": { "width": 439, "height": 512, "svg": "" }, "code": { "width": "32", "height": "32", "svg": "\n \n" }, "codeigniter": { "width": 427, "height": 512, "svg": "" }, "codrops": { "width": 512, "height": 512, "svg": "" }, "coffeescript": { "width": 512, "height": 512, "svg": "" }, "compass": { "width": 512, "height": 512, "svg": "" }, "creativecommons-badge": { "width": 512, "height": 512, "svg": "" }, "creativecommons": { "width": 512, "height": 512, "svg": "" }, "css3-full": { "width": 512, "height": 512, "svg": "" }, "cssdeck": { "width": 512, "height": 512, "svg": "" }, "csstricks": { "width": 478, "height": 512, "svg": "" }, "dart": { "width": 512, "height": 512, "svg": "" }, "database": { "width": 390, "height": 512, "svg": "" }, "debian": { "width": 410, "height": 512, "svg": "" }, "django": { "width": 512, "height": 512, "svg": "" }, "dlang": { "width": 512, "height": 512, "svg": "" }, "doctrine": { "width": 388, "height": 512, "svg": "" }, "dojo": { "width": 512, "height": 512, "svg": "" }, "dotnet": { "width": 512, "height": 512, "svg": "" }, "dreamweaver": { "width": 512, "height": 512, "svg": "" }, "eclipse": { "width": 512, "height": 512, "svg": "" }, "envato": { "width": 449, "height": 512, "svg": "" }, "extjs": { "width": 512, "height": 512, "svg": "" }, "fsharp": { "width": 512, "height": 512, "svg": "" }, "ghost-small": { "width": 512, "height": 512, "svg": "" }, "ghost": { "width": 499, "height": 512, "svg": "" }, "git-branch": { "width": 366, "height": 512, "svg": "" }, "git-commit": { "width": 512, "height": 512, "svg": "" }, "git-compare": { "width": 443, "height": 512, "svg": "" }, "git-merge": { "width": 439, "height": 512, "svg": "" }, "git-pullrequest": { "width": 410, "height": 512, "svg": "" }, "github-badge": { "width": 512, "height": 512, "svg": "" }, "github-full": { "width": 512, "height": 512, "svg": "" }, "google-analytics": { "width": 512, "height": 512, "svg": "" }, "google-cloudplatform": { "width": 512, "height": 512, "svg": "" }, "grails": { "width": 512, "height": 512, "svg": "" }, "hackernews": { "width": 512, "height": 512, "svg": "" }, "haskell": { "width": 512, "height": 512, "svg": "" }, "heroku": { "width": 331, "height": 512, "svg": "" }, "html5-3deffects": { "width": 512, "height": 512, "svg": "" }, "html5-connectivity": { "width": 512, "height": 512, "svg": "" }, "html5-deviceaccess": { "width": 512, "height": 512, "svg": "" }, "html5-multimedia": { "width": 512, "height": 512, "svg": "" }, "ie": { "width": 498, "height": 512, "svg": "" }, "illustrator": { "width": 512, "height": 512, "svg": "" }, "intellij": { "width": 512, "height": 512, "svg": "" }, "ionic": { "width": 512, "height": 512, "svg": "" }, "jekyll": { "width": 280, "height": 512, "svg": "" }, "jquery-ui": { "width": 512, "height": 512, "svg": "" }, "jquery": { "width": 512, "height": 512, "svg": "" }, "js-badge": { "width": 512, "height": 512, "svg": "" }, "js-shield": { "width": 452, "height": 512, "svg": "" }, "komodo": { "width": 512, "height": 512, "svg": "" }, "krakenjs-badge": { "width": 479, "height": 512, "svg": "" }, "krakenjs": { "width": 489, "height": 512, "svg": "" }, "materialize": { "width": 512, "height": 512, "svg": "" }, "meteor-full": { "width": 512, "height": 512, "svg": "" }, "mit": { "width": 512, "height": 512, "svg": "" }, "modernizr": { "width": 512, "height": 512, "svg": "" }, "mongodb": { "width": 219, "height": 512, "svg": "" }, "mootools-badge": { "width": 182, "height": 512, "svg": "" }, "mootools": { "width": 512, "height": 512, "svg": "" }, "mozilla": { "width": 512, "height": 512, "svg": "" }, "msql-server": { "width": 468, "height": 512, "svg": "" }, "mysql": { "width": 486, "height": 512, "svg": "" }, "nancy": { "width": 327, "height": 512, "svg": "" }, "net-magazine": { "width": 512, "height": 512, "svg": "" }, "netbeans": { "width": 485, "height": 512, "svg": "" }, "nodejs-small": { "width": 455, "height": 512, "svg": "" }, "nodejs": { "width": 455, "height": 512, "svg": "" }, "onedrive": { "width": 512, "height": 512, "svg": "" }, "openshift": { "width": 512, "height": 512, "svg": "" }, "opensource": { "width": 512, "height": 512, "svg": "" }, "perl": { "width": 512, "height": 512, "svg": "" }, "phonegap": { "width": 512, "height": 512, "svg": "" }, "photoshop": { "width": 512, "height": 512, "svg": "" }, "postgresql": { "width": 512, "height": 512, "svg": "" }, "prolog": { "width": 456, "height": 512, "svg": "" }, "rackspace": { "width": 497, "height": 512, "svg": "" }, "raphael": { "width": 512, "height": 512, "svg": "" }, "rasberry-pi": { "width": 401, "height": 512, "svg": "" }, "redis": { "width": 512, "height": 512, "svg": "" }, "requirejs": { "width": 426, "height": 512, "svg": "" }, "responsive": { "width": 512, "height": 512, "svg": "" }, "ruby-on-rails": { "width": 512, "height": 512, "svg": "" }, "ruby-rough": { "width": 512, "height": 512, "svg": "" }, "ruby": { "width": 512, "height": 512, "svg": "" }, "scala": { "width": 376, "height": 512, "svg": "" }, "scriptcs": { "width": 512, "height": 512, "svg": "" }, "scrum": { "width": 512, "height": 512, "svg": "" }, "senchatouch": { "width": 338, "height": 512, "svg": "" }, "sizzlejs": { "width": 512, "height": 512, "svg": "" }, "smashing-magazine": { "width": 512, "height": 512, "svg": "" }, "snapsvg": { "width": 309, "height": 512, "svg": "" }, "spark": { "width": 512, "height": 512, "svg": "" }, "sqllite": { "width": 229, "height": 512, "svg": "" }, "stackoverflow": { "width": 401, "height": 512, "svg": "" }, "streamline": { "width": 466, "height": 512, "svg": "" }, "symfony-badge": { "width": 512, "height": 512, "svg": "" }, "techcrunch": { "width": 512, "height": 512, "svg": "" }, "terminal-badge": { "width": 512, "height": 512, "svg": "" }, "travis": { "width": 512, "height": 512, "svg": "" }, "vim": { "width": 512, "height": 512, "svg": "" }, "visualstudio": { "width": 512, "height": 512, "svg": "" }, "webplatform": { "width": 512, "height": 512, "svg": "" }, "yahoo-small": { "width": 512, "height": 512, "svg": "" }, "yeoman": { "width": 457, "height": 512, "svg": "" }, "yii": { "width": 479, "height": 512, "svg": "" }, "zend": { "width": 512, "height": 512, "svg": "" }, "3dprint": { "width": 512, "height": 512, "svg": "" }, "antenna": { "width": 302, "height": 512, "svg": "" }, "apache": { "width": 512, "height": 512, "svg": "" }, "archlinux": { "width": 512, "height": 512, "svg": "" }, "bomb": { "width": 365, "height": 512, "svg": "" }, "c": { "width": 469, "height": 512, "svg": "" }, "cassandra": { "width": 512, "height": 512, "svg": "" }, "coffee-bean": { "width": 436, "height": 512, "svg": "" }, "csharp": { "width": 512, "height": 512, "svg": "" }, "css": { "width": 472, "height": 512, "svg": "" }, "database-alt1": { "width": 381, "height": 512, "svg": "" }, "database-alt2": { "width": 448, "height": 512, "svg": "" }, "dreamhost": { "width": 512, "height": 512, "svg": "" }, "elixir": { "width": 332, "height": 512, "svg": "" }, "exherbo": { "width": 503, "height": 512, "svg": "" }, "fire": { "width": 385, "height": 512, "svg": "" }, "gnome": { "width": 403, "height": 512, "svg": "" }, "google-alt": { "width": 512, "height": 512, "svg": "" }, "google-code": { "width": 461, "height": 512, "svg": "" }, "google-developers": { "width": 512, "height": 512, "svg": "" }, "grails-alt": { "width": 512, "height": 512, "svg": "" }, "hadoop": { "width": 512, "height": 512, "svg": "" }, "html": { "width": 471, "height": 512, "svg": "" }, "iphone": { "width": 256, "height": 512, "svg": "" }, "java-bold": { "width": 369, "height": 512, "svg": "" }, "java-duke": { "width": 284, "height": 512, "svg": "" }, "javascript-alt": { "width": 512, "height": 512, "svg": "" }, "javascript": { "width": 512, "height": 512, "svg": "" }, "jetty": { "width": 512, "height": 512, "svg": "" }, "kde": { "width": 485, "height": 512, "svg": "" }, "linegraph": { "width": 512, "height": 512, "svg": "" }, "linuxmint": { "width": 512, "height": 512, "svg": "" }, "looking": { "width": 448, "height": 512, "svg": "" }, "mariadb": { "width": 512, "height": 512, "svg": "" }, "maven": { "width": 379, "height": 512, "svg": "" }, "microscope": { "width": 329, "height": 512, "svg": "" }, "mobiledevice": { "width": 512, "height": 512, "svg": "" }, "mobilephone-alt": { "width": 240, "height": 512, "svg": "" }, "mobilephone-broadcast": { "width": 326, "height": 512, "svg": "" }, "mysql-alt": { "width": 487, "height": 512, "svg": "" }, "netbsd": { "width": 491, "height": 512, "svg": "" }, "nginx-alt1": { "width": 512, "height": 512, "svg": "" }, "nginx-alt2": { "width": 322, "height": 512, "svg": "" }, "objc": { "width": 471, "height": 512, "svg": "" }, "oracle-alt": { "width": 512, "height": 512, "svg": "" }, "oracle": { "width": 512, "height": 512, "svg": "" }, "osx": { "width": 432, "height": 512, "svg": "" }, "phone-alt": { "width": 380, "height": 512, "svg": "" }, "phone-retro": { "width": 512, "height": 512, "svg": "" }, "php-alt": { "width": 472, "height": 512, "svg": "" }, "playframework-alt": { "width": 448, "height": 512, "svg": "" }, "playframework": { "width": 448, "height": 512, "svg": "" }, "plone": { "width": 512, "height": 512, "svg": "" }, "postgresql-alt": { "width": 512, "height": 512, "svg": "" }, "rails-alt": { "width": 398, "height": 512, "svg": "" }, "rails": { "width": 426, "height": 512, "svg": "" }, "satellite": { "width": 512, "height": 512, "svg": "" }, "scala-alt": { "width": 375, "height": 512, "svg": "" }, "script-alt": { "width": 471, "height": 512, "svg": "" }, "script": { "width": 512, "height": 512, "svg": "" }, "shell": { "width": 512, "height": 512, "svg": "" }, "solaris": { "width": 512, "height": 512, "svg": "" }, "splatter": { "width": 512, "height": 512, "svg": "" }, "spring": { "width": 512, "height": 512, "svg": "" }, "svg": { "width": 512, "height": 512, "svg": "" }, "tomcat": { "width": 512, "height": 512, "svg": "" }, "wireless": { "width": 512, "height": 512, "svg": "" }, "x11": { "width": 512, "height": 512, "svg": "" }, "activity": { "width": "32", "height": "32", "svg": "\n \n" }, "alert": { "width": "32", "height": "32", "svg": "\n \n" }, "archive": { "width": "32", "height": "32", "svg": "\n \n" }, "arrow-bottom": { "width": "32", "height": "32", "svg": "\n \n" }, "arrow-left": { "width": "32", "height": "32", "svg": "\n \n" }, "arrow-right": { "width": "32", "height": "32", "svg": "\n \n" }, "arrow-top": { "width": "32", "height": "32", "svg": "\n \n" }, "backwards": { "width": "32", "height": "32", "svg": "\n \n" }, "bag": { "width": "32", "height": "32", "svg": "\n \n" }, "ban": { "width": "32", "height": "32", "svg": "\n \n \n" }, "bell": { "width": "32", "height": "32", "svg": "\n \n" }, "book": { "width": "32", "height": "32", "svg": "\n \n" }, "bookmark": { "width": "32", "height": "32", "svg": "\n \n" }, "calendar": { "width": "32", "height": "32", "svg": "\n \n" }, "camera": { "width": "32", "height": "32", "svg": "\n \n \n" }, "caret-bottom": { "width": "32", "height": "32", "svg": "\n \n" }, "caret-left": { "width": "32", "height": "32", "svg": "\n \n" }, "caret-right": { "width": "32", "height": "32", "svg": "\n \n" }, "caret-top": { "width": "32", "height": "32", "svg": "\n \n" }, "cart": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "checkmark": { "width": "32", "height": "32", "svg": "\n \n" }, "chevron-bottom": { "width": "32", "height": "32", "svg": "\n \n" }, "chevron-left": { "width": "32", "height": "32", "svg": "\n \n" }, "chevron-right": { "width": "32", "height": "32", "svg": "\n \n" }, "chevron-top": { "width": "32", "height": "32", "svg": "\n \n" }, "clipboard": { "width": "32", "height": "32", "svg": "\n \n" }, "clock": { "width": "32", "height": "32", "svg": "\n \n \n" }, "close": { "width": "32", "height": "32", "svg": "\n \n" }, "compose": { "width": "32", "height": "32", "svg": "\n \n" }, "creditcard": { "width": "32", "height": "32", "svg": "\n \n \n" }, "desktop": { "width": "32", "height": "32", "svg": "\n \n\n" }, "download": { "width": "32", "height": "32", "svg": "\n \n" }, "edit": { "width": "32", "height": "32", "svg": "\n \n" }, "eject": { "width": "32", "height": "32", "svg": "\n \n" }, "ellipsis-horizontal": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "ellipsis-vertical": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "end": { "width": "32", "height": "32", "svg": "\n \n" }, "export": { "width": "32", "height": "32", "svg": "\n \n" }, "external": { "width": "32", "height": "32", "svg": "\n \n" }, "eye": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "feed": { "width": "32", "height": "32", "svg": "\n \n \n" }, "file": { "width": 24, "height": 24, "svg": "" }, "filter": { "width": "32", "height": "32", "svg": "\n \n\n\n" }, "flag": { "width": "32", "height": "32", "svg": "\n \n" }, "folder-open": { "width": "32", "height": "32", "svg": "\n \n" }, "folder": { "width": "32", "height": "32", "svg": "\n \n" }, "forwards": { "width": "32", "height": "32", "svg": "\n \n" }, "fullscreen-exit": { "width": "32", "height": "32", "svg": "\n \n" }, "fullscreen": { "width": "32", "height": "32", "svg": "\n \n" }, "gift": { "width": "32", "height": "32", "svg": "\n \n" }, "heart": { "width": "32", "height": "32", "svg": "\n \n" }, "home": { "width": "32", "height": "32", "svg": "\n \n" }, "import": { "width": "32", "height": "32", "svg": "\n \n" }, "inbox": { "width": "32", "height": "32", "svg": "\n \n" }, "info": { "width": "32", "height": "32", "svg": "\n \n \n" }, "lightning": { "width": "32", "height": "32", "svg": "\n \n" }, "link": { "width": "32", "height": "32", "svg": "\n \n" }, "location": { "width": "32", "height": "32", "svg": "\n \n \n" }, "lock": { "width": "32", "height": "32", "svg": "\n \n \n" }, "mail": { "width": "32", "height": "32", "svg": "\n \n" }, "menu": { "width": "32", "height": "32", "svg": "\n \n" }, "message": { "width": "32", "height": "32", "svg": "\n \n" }, "microphone": { "width": "32", "height": "32", "svg": "\n \n" }, "minus": { "width": "32", "height": "32", "svg": "\n \n" }, "mobile": { "width": "32", "height": "32", "svg": "\n \n" }, "moon": { "width": "32", "height": "32", "svg": "\n \n" }, "move": { "width": "32", "height": "32", "svg": "\n \n" }, "music": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "mute": { "width": "32", "height": "32", "svg": "\n \n" }, "options": { "width": "32", "height": "32", "svg": "\n \n" }, "paperclip": { "width": "32", "height": "32", "svg": "\n \n" }, "pause": { "width": "32", "height": "32", "svg": "\n \n" }, "photo": { "width": "32", "height": "32", "svg": "\n \n \n" }, "play": { "width": "32", "height": "32", "svg": "\n \n" }, "plus": { "width": "32", "height": "32", "svg": "\n \n" }, "portfolio": { "width": "32", "height": "32", "svg": "\n \n" }, "print": { "width": "32", "height": "32", "svg": "\n \n" }, "reload": { "width": "32", "height": "32", "svg": "\n \n" }, "reply": { "width": "32", "height": "32", "svg": "\n \n" }, "search": { "width": "32", "height": "32", "svg": "\n \n \n" }, "send": { "width": "32", "height": "32", "svg": "\n \n" }, "settings": { "width": "32", "height": "32", "svg": "\n \n \n" }, "sign-in": { "width": "32", "height": "32", "svg": "\n \n\n" }, "sign-out": { "width": "32", "height": "32", "svg": "\n \n" }, "star": { "width": "32", "height": "32", "svg": "\n \n" }, "start": { "width": "32", "height": "32", "svg": "\n \n" }, "telephone": { "width": "32", "height": "32", "svg": "\n \n \n" }, "trash": { "width": "32", "height": "32", "svg": "\n \n" }, "unlock": { "width": "32", "height": "32", "svg": "\n \n \n" }, "upload": { "width": "32", "height": "32", "svg": "\n \n" }, "user": { "width": "32", "height": "32", "svg": "\n \n" }, "volume": { "width": "32", "height": "32", "svg": "\n \n" }, "work": { "width": "32", "height": "32", "svg": "\n \n" }, "zoom-in": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "zoom-out": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "zoom-reset": { "width": "32", "height": "32", "svg": "\n \n \n \n" }, "showDisks": { "width": 24, "height": 24, "svg": "" }, "up": { "width": 24, "height": 24, "svg": "" }, "dir": { "width": 24, "height": 24, "svg": "" }, "symlink": { "width": 24, "height": 24, "svg": "" }, "other": { "width": 24, "height": 24, "svg": "" }, "disk": { "width": 24, "height": 24, "svg": "" }, "rom": { "width": 24, "height": 24, "svg": "" }, "audio": { "width": "32", "height": "32", "svg": "\n \n" } } ================================================ FILE: src/assets/kb_layouts/da-DK.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "½", "cmd": "½", "shift_name": "§", "shift_cmd": "§" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "@", "alt_name": "@", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_name": "£", "alt_cmd": "£", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "¤", "shift_cmd": "¤", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_name": "$", "alt_cmd": "$", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "/", "shift_cmd": "/", "alt_name": "{", "alt_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "alt_name": "[", "alt_cmd": "[", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_name": "]", "alt_cmd": "]", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_name": "}", "alt_cmd": "}", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "+", "cmd": "+", "shift_name": "?", "shift_cmd": "?", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "´", "cmd": "´", "shift_name": "`", "shift_cmd": "`", "alt_cmd": "|", "alt_name": "|", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "alt_name": "€", "alt_cmd": "€", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "Å", "cmd": "å", "shift_cmd": "Å", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "¨", "cmd": "¨", "shift_name": "^", "shift_cmd": "^", "alt_name": "~", "alt_cmd": "~", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Æ", "cmd": "æ", "shift_cmd": "Æ" }, { "name": "Ø", "cmd": "ø", "shift_cmd": "Ø" }, { "name": "'", "cmd": "'", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "alt_name": "\\", "alt_cmd": "\\", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/de-DE.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "^", "cmd": "^", "shift_name": "°", "shift_cmd": "°" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "§", "shift_cmd": "§", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "/", "shift_cmd": "/", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "ß", "cmd": "ß", "shift_name": "?", "shift_cmd": "?", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "´", "cmd": "´", "shift_name": "`", "shift_cmd": "`", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "Ü", "cmd": "ü", "shift_cmd": "Ü", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "+", "cmd": "+", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Ö", "cmd": "ö", "shift_cmd": "Ö" }, { "name": "Ä", "cmd": "ä", "shift_cmd": "Ä" }, { "name": "#", "cmd": "#", "shift_name": "'", "shift_cmd": "'", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Y", "cmd": "y", "shift_name": "Y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/en-COLEMAK.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "`", "cmd": "`", "shift_name": "~", "shift_cmd": "~" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "@", "shift_cmd": "@", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": "(", "shift_cmd": "(", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": ";", "cmd": ";", "shift_name": ":", "shift_cmd": ":" }, { "name": "[", "cmd": "[", "shift_name": "{", "shift_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "]", "cmd": "]", "shift_name": "}", "shift_cmd": "}", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "'", "cmd": "'", "shift_name": "\"", "shift_cmd": "\"" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": "<", "shift_cmd": "<" }, { "name": ".", "cmd": ".", "shift_name": ">", "shift_cmd": ">" }, { "name": "\\/", "cmd": "\\/", "shift_name": "?", "shift_cmd": "?" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/en-DVORAK.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "`", "cmd": "`", "shift_name": "~", "shift_cmd": "~" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "@", "shift_cmd": "@", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": "(", "shift_cmd": "(", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "[", "cmd": "[", "shift_name": "{", "shift_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "]", "cmd": "]", "shift_name": "}", "shift_cmd": "}", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "'", "cmd": "'", "shift_name": "\"", "shift_cmd": "\"" }, { "name": ",", "cmd": ",", "shift_name": "<", "shift_cmd": "<" }, { "name": ".", "cmd": ".", "shift_name": ">", "shift_cmd": ">" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "\/", "cmd": "\/", "shift_name": "?", "shift_cmd": "?" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": ";", "cmd": ";", "shift_name": ":", "shift_cmd": ":" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/en-GB.json ================================================ { "row_numbers": [{ "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "`", "cmd": "`", "shift_name": "¬", "shift_cmd": "¬" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "£", "shift_cmd": "£", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": "(", "shift_cmd": "(", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" }], "row_1": [{ "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "[", "cmd": "[", "shift_name": "{", "shift_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "]", "cmd": "]", "shift_name": "}", "shift_cmd": "}", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" }], "row_2": [{ "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": ";", "cmd": ";", "shift_name": ":", "shift_cmd": ":" }, { "name": "'", "cmd": "'", "shift_name": "@", "shift_cmd": "@" }, { "name": "#", "cmd": "#", "shift_name": "~", "shift_cmd": "~", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" }], "row_3": [{ "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": "<", "shift_cmd": "<" }, { "name": ".", "cmd": ".", "shift_name": ">", "shift_cmd": ">" }, { "name": "\/", "cmd": "\/", "shift_name": "?", "shift_cmd": "?" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" }], "row_space": [{ "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" }] } ================================================ FILE: src/assets/kb_layouts/en-NORMAN.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "`", "cmd": "`", "shift_name": "~", "shift_cmd": "~" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "@", "shift_cmd": "@", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": "(", "shift_cmd": "(", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": ";", "cmd": ";", "shift_name": ":", "shift_cmd": ":" }, { "name": "[", "cmd": "[", "shift_name": "{", "shift_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "]", "cmd": "]", "shift_name": "}", "shift_cmd": "}", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "'", "cmd": "'", "shift_name": "\"", "shift_cmd": "\"" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": "<", "shift_cmd": "<" }, { "name": ".", "cmd": ".", "shift_name": ">", "shift_cmd": ">" }, { "name": "\/", "cmd": "\/", "shift_name": "?", "shift_cmd": "?" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "ALT", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/en-US.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "`", "cmd": "`", "shift_name": "~", "shift_cmd": "~" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "@", "shift_cmd": "@", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": "(", "shift_cmd": "(", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "[", "cmd": "[", "shift_name": "{", "shift_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "]", "cmd": "]", "shift_name": "}", "shift_cmd": "}", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": ";", "cmd": ";", "shift_name": ":", "shift_cmd": ":" }, { "name": "'", "cmd": "'", "shift_name": "\"", "shift_cmd": "\"" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": "<", "shift_cmd": "<" }, { "name": ".", "cmd": ".", "shift_name": ">", "shift_cmd": ">" }, { "name": "\/", "cmd": "\/", "shift_name": "?", "shift_cmd": "?" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/en-WORKMAN.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "`", "cmd": "`", "shift_name": "~", "shift_cmd": "~" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "@", "shift_cmd": "@", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": "(", "shift_cmd": "(", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "F", "cmd": "F", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "U", "cmd": "U", "shift_cmd": "U", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": ":", "cmd": ":", "shift_cmd": ":", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~;" }, { "name": "[", "cmd": "[", "shift_name": "{", "shift_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "]", "cmd": "]", "shift_name": "}", "shift_cmd": "}", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "T", "cmd": "t", "shift_cmd": "t", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "I", "cmd": "i", "shift_name": "I", "shift_cmd": "I" }, { "name": "'", "cmd": "'", "shift_name": "\"", "shift_cmd": "\"" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": ",", "cmd": ",", "shift_name": "<", "shift_cmd": "<" }, { "name": ".", "cmd": ".", "shift_name": ">", "shift_cmd": ">" }, { "name": "\/", "cmd": "\/", "shift_name": "?", "shift_cmd": "?" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "ALT", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] ================================================ FILE: src/assets/kb_layouts/es-ES.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "°", "cmd": "°", "shift_name": "ª", "shift_cmd": "ª", "alt_name": "\\", "alt_cmd": "\\" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_name": "|", "alt_cmd": "|", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_name": "@", "alt_cmd": "@", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "·", "shift_cmd": "·", "alt_name": "#", "alt_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "alt_name": "~", "alt_cmd": "ESCAPED|-- TILDE", "ctrl_cmd": "~~~CTRLSEQ2~~~", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "alt_name": "€", "alt_cmd": "€", "ctrl_cmd": "~~~CTRLSEQ3~~~", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "alt_name": "¬", "alt_cmd": "¬", "ctrl_cmd": "~~~CTRLSEQ4~~~", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "/", "shift_cmd": "/", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "'", "cmd": "'", "shift_name": "?", "shift_cmd": "?", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "¡", "cmd": "¡", "shift_name": "¿", "shift_cmd": "¿", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "alt_name": "€", "alt_cmd": "€", "ctrl_cmd": "\r" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "`", "cmd": "ESCAPED|-- GRAVE", "shift_name": "^", "shift_cmd": "ESCAPED|-- CIRCUM", "alt_name": "[", "alt_cmd": "[", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "+", "cmd": "+", "shift_name": "*", "shift_cmd": "*", "alt_name": "~", "alt_cmd": "~", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Ñ", "cmd": "ñ", "shift_cmd": "Ñ", "alt_cmd": "~~~CTRLSEQ1~~~ñ" }, { "name": "´", "cmd": "ESCAPED|-- ACUTE", "shift_name": "¨", "shift_cmd": "ESCAPED|-- TREMA", "alt_name": "{", "alt_cmd": "{" }, { "name": "Ç", "cmd": "ç", "shift_cmd": "Ç", "alt_name": "}", "alt_cmd": "}", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/es-LAT.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "|", "cmd": "|", "shift_name": "°", "shift_cmd": "°", "alt_name": "¬", "alt_cmd": "¬" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "/", "shift_cmd": "/", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "'", "cmd": "'", "shift_name": "?", "shift_cmd": "?", "alt_name": "\\", "alt_cmd": "\\", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "¿", "cmd": "¿", "shift_name": "¡", "shift_cmd": "¡", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "alt_name": "@", "alt_cmd": "@", "ctrl_cmd": "~~~CTRLSEQ6~~~" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "´", "cmd": "ESCAPED|-- ACUTE", "shift_name": "¨", "shift_cmd": "ESCAPED|-- TREMA", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "+", "cmd": "+", "shift_name": "*", "shift_cmd": "*", "alt_name": "~", "alt_cmd": "~", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Ñ", "cmd": "ñ", "shift_cmd": "Ñ", "alt_cmd": "~~~CTRLSEQ1~~~ñ" }, { "name": "{", "cmd": "{", "shift_name": "[", "shift_cmd": "[", "alt_name": "^", "alt_cmd": "ESCAPED|-- CIRCUM" }, { "name": "}", "cmd": "}", "shift_name": "]", "shift_cmd": "]", "alt_name": "`", "alt_cmd": "ESCAPED|-- GRAVE", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/fr-BEPO.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "$", "cmd": "$", "shift_name": "#", "shift_cmd": "#", "alt_name": "–", "alt_cmd": "–", "altshift_name": "¶", "altshift_cmd": "¶" }, { "name": "\"", "cmd": "\"", "shift_name": "1", "shift_cmd": "1", "alt_name": "––", "alt_cmd": "—", "altshift_name": "„", "altshift_cmd": "„", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "«", "cmd": "«", "shift_name": "2", "shift_cmd": "2", "alt_name": "<", "alt_cmd": "<", "altshift_name": "“", "altshift_cmd": "“", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "»", "cmd": "»", "shift_name": "3", "shift_cmd": "3", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_name": ">", "alt_cmd": ">", "altshift_name": "”", "altshift_cmd": "”", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "(", "cmd": "(", "shift_name": "4", "shift_cmd": "4", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_name": "[", "alt_cmd": "[", "altshift_name": "≤", "altshift_cmd": "≤", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": ")", "cmd": ")", "shift_name": "5", "shift_cmd": "5", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_name": "]", "alt_cmd": "]", "altshift_name": "≥", "altshift_cmd": "≥", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "@", "cmd": "@", "shift_name": "6", "shift_cmd": "6", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_name": "^", "alt_cmd": "^", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "+", "cmd": "+", "shift_name": "7", "shift_cmd": "7", "ctrl_cmd": "~~~CTRLSEQ5~~~", "alt_name": "±", "alt_cmd": "±", "altshift_name": "¬", "altshift_cmd": "¬", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "-", "cmd": "-", "shift_name": "8", "shift_cmd": "8", "ctrl_cmd": "\r", "alt_name": "−", "alt_cmd": "−", "altshift_name": "¼", "altshift_cmd": "¼", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "/", "cmd": "/", "shift_name": "9", "shift_cmd": "9", "alt_name": "÷", "alt_cmd": "÷", "altshift_name": "½", "altshift_cmd": "½", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "*", "cmd": "*", "shift_name": "0", "shift_cmd": "0", "alt_name": "×", "alt_cmd": "×", "altshift_name": "¾", "altshift_cmd": "¾", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "=", "cmd": "=", "shift_name": "°", "shift_cmd": "°", "alt_name": "≠", "alt_cmd": "≠", "altshift_name": "′", "altshift_cmd": "′", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "%", "cmd": "%", "shift_name": "`", "shift_cmd": "`", "alt_name": "‰", "alt_cmd": "‰", "altshift_name": "″", "altshift_cmd": "″", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "alt_name": "|", "alt_cmd": "|", "altshift_name": "¦", "altshift_cmd": "¦", "ctrl_cmd": "~~~CTRLSEQ21~~~" }, { "name": "É", "cmd": "é", "shift_cmd": "É", "alt_name": "´", "alt_cmd": "ESCAPED|-- ACUTE" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "alt_name": "&", "alt_cmd": "&", "altshift_name": "§", "altshift_cmd": "§", "ctrl_cmd": "~~~CTRLSEQ12~~~" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_name": "œ", "alt_cmd": "œ", "altshift_name": "Œ", "altshift_cmd": "Œ", "ctrl_cmd": "~~~CTRLSEQ8~~~" }, { "name": "È", "cmd": "è", "shift_cmd": "È", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_name": "`", "alt_cmd": "ESCAPED|-- GRAVE", "altshift_name": "`", "altshift_cmd": "`" }, { "name": "^", "cmd": "ESCAPED|-- CIRCUM", "capslck_cmd": "ESCAPED|-- CIRCUM", "shift_name": "!", "shift_cmd": "!", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_name": "¡", "alt_cmd": "¡" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_name": "ˇ", "alt_cmd": "ESCAPED|-- CARON" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_name": "ð", "alt_cmd": "ð", "altshift_name": "Ð", "altshift_cmd": "Ð" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_name": "/", "alt_cmd": "ESCAPED|-- BAR" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_name": "ij", "alt_cmd": "ij", "altshift_name": "IJ", "altshift_cmd": "IJ" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "alt_name": "ə", "alt_cmd": "ə", "altshift_name": "Ə", "altshift_cmd": "Ə", "ctrl_cmd": "~~~CTRLSEQ17~~~" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "alt_name": "˘", "alt_cmd": "ESCAPED|-- BREVE", "ctrl_cmd": "~~~CTRLSEQ7~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_name": "æ", "alt_cmd": "æ", "altshift_name": "Æ", "altshift_cmd": "Æ" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_name": "ù", "alt_cmd": "ù", "altshift_name": "Ù", "altshift_cmd": "Ù" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_name": "¨", "alt_cmd": "ESCAPED|-- TREMA" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_name": "€", "alt_cmd": "€" }, { "name": ",", "cmd": ",", "capslck_cmd": ",", "shift_name": ";", "shift_cmd": ";", "alt_name": "’", "alt_cmd": "’" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_name": "©", "alt_cmd": "©", "altshift_name": "ſ", "altshift_cmd": "ſ" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_name": "þ", "alt_cmd": "þ", "altshift_name": "Þ", "altshift_cmd": "Þ" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_name": "ß", "alt_cmd": "ß" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_name": "®", "alt_cmd": "®", "altshift_name": "™", "altshift_cmd": "™" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_name": "~", "alt_cmd": "ESCAPED|-- TILDE" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "alt_name": "¯", "ctrl_cmd": "\r", "alt_cmd": "ESCAPED|-- MACRON", "altshift_name": "º", "altshift_cmd": "º" }, { "name": "Ç", "cmd": "ç", "shift_cmd": "Ç", "alt_name": "¸", "alt_cmd": "ESCAPED|-- CEDILLA", "altshift_name": ",", "altshift_cmd": "ESCAPED|-- IOTASUB" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "Ê", "cmd": "ê", "shift_cmd": "À", "alt_name": "/", "alt_cmd": "/" }, { "name": "À", "cmd": "à", "shift_cmd": "À", "alt_name": "\\", "alt_cmd": "\\" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_name": "{", "alt_cmd": "{", "altshift_name": "‘", "altshift_cmd": "‘" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_name": "}", "alt_cmd": "}", "altshift_name": "’", "altshift_cmd": "’" }, { "name": ".", "cmd": ".", "capslck_cmd": ".", "shift_name": ":", "shift_cmd": ":", "alt_name": "…", "alt_cmd": "…", "altshift_name": "·", "altshift_cmd": "·" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_name": "~", "alt_cmd": "~" }, { "name": "'", "cmd": "'", "capslck_cmd": "'", "shift_name": "?", "shift_cmd": "?", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_name": "¿", "alt_cmd": "¿" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_name": "°", "alt_cmd": "ESCAPED|-- OVERRING" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_name": "µ", "alt_cmd": "ESCAPED|-- GREEK" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_name": "†", "alt_cmd": "†", "altshift_name": "‡", "altshift_cmd": "‡" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_name": "˛", "alt_cmd": "ESCAPED|-- IOTASUB", "altshift_name": "ª", "altshift_cmd": "ª" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " ", "shift_cmd": "\u00A0", "alt_cmd": "_" }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/fr-FR.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "²", "cmd": "²", "shift_cmd": "~", "alt_cmd": "¬" }, { "name": "&", "cmd": "&", "shift_name": "1", "shift_cmd": "1", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "é", "cmd": "é", "shift_name": "2", "shift_cmd": "2", "capslck_cmd": "É", "alt_name": "~", "alt_cmd": "~", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "\"", "cmd": "\"", "shift_name": "3", "shift_cmd": "3", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_name": "#", "alt_cmd": "#", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "'", "cmd": "'", "shift_name": "4", "shift_cmd": "4", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_name": "{", "alt_cmd": "{", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "(", "cmd": "(", "shift_name": "5", "shift_cmd": "5", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_name": "[", "alt_cmd": "[", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "-", "cmd": "-", "shift_name": "6", "shift_cmd": "6", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_name": "|", "alt_cmd": "|", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "è", "cmd": "è", "shift_name": "7", "shift_cmd": "7", "capslck_cmd": "È", "ctrl_cmd": "~~~CTRLSEQ5~~~", "alt_name": "`", "alt_cmd": "`", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "_", "cmd": "_", "shift_name": "8", "shift_cmd": "8", "ctrl_cmd": "\r", "alt_name": "\\", "alt_cmd": "\\", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "ç", "cmd": "ç", "shift_name": "9", "shift_cmd": "9", "capslck_cmd": "Ç", "alt_name": "^", "alt_cmd": "^", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "à", "cmd": "à", "shift_name": "0", "shift_cmd": "0", "capslck_cmd": "À", "alt_name": "@", "alt_cmd": "@", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": ")", "cmd": ")", "shift_name": "°", "shift_cmd": "°", "alt_name": "]", "alt_cmd": "]", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "alt_name": "}", "alt_cmd": "}", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "alt_name": "€", "alt_cmd": "€", "ctrl_cmd": "\r" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "^", "cmd": "ESCAPED|-- CIRCUM", "shift_name": "¨", "shift_cmd": "ESCAPED|-- TREMA", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "$", "cmd": "$", "shift_name": "£", "shift_cmd": "£", "alt_name": "¤", "alt_cmd": "¤", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": "ù", "cmd": "ù", "shift_name": "%", "shift_cmd": "%", "capslck_cmd": "Ù" }, { "name": "*", "cmd": "*", "shift_name": "µ", "shift_cmd": "µ" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": ",", "cmd": ",", "shift_name": "?", "shift_cmd": "?" }, { "name": ";", "cmd": ";", "shift_name": ".", "shift_cmd": "." }, { "name": ":", "cmd": ":", "shift_name": "\/", "shift_cmd": "\/" }, { "name": "!", "cmd": "!", "shift_name": "§", "shift_cmd": "§" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/hu-HU.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "0", "cmd": "0", "shift_name": "§", "shift_cmd": "§" }, { "name": "1", "cmd": "1", "shift_name": "'", "shift_cmd": "'", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "+", "shift_cmd": "+", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "!", "shift_cmd": "!", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "/", "shift_cmd": "/", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "=", "shift_cmd": "=", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "Ö", "cmd": "ö", "shift_cmd": "Ö", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "Ü", "cmd": "ü", "shift_cmd": "Ü", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "Ó", "cmd": "ó", "shift_cmd": "Ó", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "alt_cmd": "~~~CTRLSEQ1~~~q", "alt_name": "\\", "ctrl_cmd": "~~~CTRLSEQ6~~~" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "alt_cmd": "~~~CTRLSEQ1~~~w", "alt_name": "|", "ctrl_cmd": "~~~CTRLSEQ7~~~" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "Ő", "cmd": "ő", "shift_cmd": "Ő", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "Ú", "cmd": "ú", "shift_cmd": "Ú", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "alt_cmd": "~~~CTRLSEQ1~~~f", "alt_name": "[", "ctrl_cmd": "~~~CTRLSEQ16~~~" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "alt_cmd": "~~~CTRLSEQ1~~~g", "alt_name": "]", "ctrl_cmd": "\r" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "É", "cmd": "é", "shift_cmd": "É" }, { "name": "Á", "cmd": "á", "shift_cmd": "Á" }, { "name": "Ű", "cmd": "ű", "shift_cmd": "Ű", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "Í", "cmd": "í", "shift_cmd": "Í", "alt_cmd": "<", "alt_name": "<", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "alt_cmd": "~~~CTRLSEQ1~~~y", "alt_name": ">", "ctrl_cmd": "~~~CTRLSEQ17~~~" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "alt_cmd": "~~~CTRLSEQ1~~~x", "alt_name": "#", "ctrl_cmd": "~~~CTRLSEQ18~~~" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "alt_cmd": "~~~CTRLSEQ1~~~c", "alt_name": "&", "ctrl_cmd": "~~~CTRLSEQ19~~~" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "alt_cmd": "~~~CTRLSEQ1~~~v", "alt_name": "@", "ctrl_cmd": "~~~CTRLSEQ20~~~" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "alt_cmd": "~~~CTRLSEQ1~~~b", "alt_name": "{", "ctrl_cmd": "~~~CTRLSEQ21~~~" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n", "alt_name": "}" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": "?", "shift_cmd": "?", "alt_cmd": ";", "alt_name": ";" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "alt_cmd": "*", "alt_name": "*" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/it-IT.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "£", "shift_cmd": "£", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "/", "shift_cmd": "/", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "?", "cmd": "?", "shift_name": "'", "shift_cmd": "'", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[22~", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "ì", "cmd": "ì", "shift_name": "^", "shift_cmd": "^", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[23~", "alt_name": "~", "alt_cmd": "~", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_name": "€", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "è", "cmd": "è", "shift_name": "é", "shift_cmd": "é", "alt_name": "[", "alt_cmd": "[", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "+", "cmd": "+", "shift_name": "*", "shift_cmd": "*", "alt_name": "]", "alt_cmd": "]", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "ò", "cmd": "ò", "shift_name": "ç", "shift_cmd": "ç", "alt_name": "@", "alt_cmd": "@" }, { "name": "à", "cmd": "à", "shift_name": "°", "shift_cmd": "°", "alt_name": "#", "alt_cmd": "#" }, { "name": "ù", "cmd": "ù", "shift_name": "§", "shift_cmd": "§", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/nl-BE.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "²", "cmd": "²", "shift_name": "³", "shift_cmd": "³", "alt_cmd": "¬" }, { "name": "&", "cmd": "&", "shift_name": "1", "shift_cmd": "1", "alt_name": "|", "alt_cmd": "|", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "é", "cmd": "é", "shift_name": "2", "shift_cmd": "2", "capslck_cmd": "É", "alt_name": "@", "alt_cmd": "@", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "\"", "cmd": "\"", "shift_name": "3", "shift_cmd": "3", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_name": "#", "alt_cmd": "#", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "'", "cmd": "'", "shift_name": "4", "shift_cmd": "4", "ctrl_cmd": "~~~CTRLSEQ2~~~", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "(", "cmd": "(", "shift_name": "5", "shift_cmd": "5", "ctrl_cmd": "~~~CTRLSEQ3~~~", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "§", "cmd": "§", "shift_name": "6", "shift_cmd": "6", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_name": "^", "alt_cmd": "|^", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "è", "cmd": "è", "shift_name": "7", "shift_cmd": "7", "capslck_cmd": "È", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "!", "cmd": "!", "shift_name": "8", "shift_cmd": "8", "ctrl_cmd": "\r", "alt_name": "\\", "alt_cmd": "\\", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "ç", "cmd": "ç", "shift_name": "9", "shift_cmd": "9", "capslck_cmd": "Ç", "alt_name": "{", "alt_cmd": "{", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "à", "cmd": "à", "shift_name": "0", "shift_cmd": "0", "capslck_cmd": "À", "alt_name": "}", "alt_cmd": "@}", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": ")", "cmd": ")", "shift_name": "°", "shift_cmd": "°", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "alt_name": "€", "alt_cmd": "€", "ctrl_cmd": "\r" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "^", "cmd": "ESCAPED|-- CIRCUM", "shift_name": "¨", "shift_cmd": "ESCAPED|-- TREMA", "alt_name": "[", "alt_cmd": "[", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "$", "cmd": "$", "shift_name": "*", "shift_cmd": "*", "alt_name": "]", "alt_cmd": "]", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": "ù", "cmd": "ù", "shift_name": "%", "shift_cmd": "%", "alt_name": "'", "alt_cmd": "'", "capslck_cmd": "Ù" }, { "name": "µ", "cmd": "µ", "shift_name": "£", "shift_cmd": "£", "alt_name": "`", "alt_cmd": "`" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "alt_name": "\\", "alt_cmd": "\\", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": ",", "cmd": ",", "shift_name": "?", "shift_cmd": "?" }, { "name": ";", "cmd": ";", "shift_name": ".", "shift_cmd": "." }, { "name": ":", "cmd": ":", "shift_name": "\/", "shift_cmd": "\/" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "alt_name": "~", "alt_cmd": "~" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/pt-BR.json ================================================ { "row_numbers": [{ "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "'", "cmd": "'", "shift_name": "\"", "shift_cmd": "\"" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "@", "shift_cmd": "@", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_cmd": "~~~CTRLSEQ1~~~3", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "¨", "shift_cmd": "¨", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": "(", "shift_cmd": "(", "alt_cmd": "~~~CTRLSEQ1~~~9", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": ")", "shift_cmd": ")", "alt_cmd": "~~~CTRLSEQ1~~~0", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "=", "cmd": "=", "shift_name": "+", "shift_cmd": "+", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "BACKSPACE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" }], "row_1": [{ "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "`", "cmd": "`", "shift_name": "´", "shift_cmd": "´", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "{", "cmd": "{", "shift_name": "[", "shift_cmd": "[", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" }], "row_2": [{ "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Ç", "cmd": "ç", "shift_cmd": "Ç", "alt_cmd": "~~~CTRLSEQ1~~~ç" }, { "name": "^", "cmd": "^", "shift_name": "~", "shift_cmd": "~" }, { "name": "}", "cmd": "}", "shift_name": "]", "shift_cmd": "]" }, { "name": "", "cmd": "\r" }], "row_3": [{ "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "\\", "cmd": "\\", "shift_name": "|", "shift_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": "<", "cmd": "<", "shift_name": ",", "shift_cmd": "," }, { "name": ">", "cmd": ">", "shift_name": ".", "shift_cmd": "." }, { "name": ":", "cmd": ":", "shift_name": ";", "shift_cmd": ";" }, { "name": "?", "cmd": "?", "shift_name": "\/", "shift_cmd": "\/" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" }], "row_space": [{ "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" }] } ================================================ FILE: src/assets/kb_layouts/sv-SE.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "½", "cmd": "½", "shift_name": "§", "shift_cmd": "§" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "@", "alt_name": "@", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "#", "shift_cmd": "#", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_name": "£", "alt_cmd": "£", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "¤", "shift_cmd": "¤", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_name": "$", "alt_cmd": "$", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "/", "shift_cmd": "/", "alt_name": "{", "alt_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "alt_name": "[", "alt_cmd": "[", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_name": "]", "alt_cmd": "]", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_name": "}", "alt_cmd": "}", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "+", "cmd": "+", "shift_name": "?", "shift_cmd": "?", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "´", "cmd": "´", "shift_name": "`", "shift_cmd": "`", "alt_cmd": "|", "alt_name": "|", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_cmd": "~~~CTRLSEQ1~~~q" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "alt_name": "€", "alt_cmd": "€", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "Å", "cmd": "å", "shift_cmd": "Å", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "¨", "cmd": "¨", "shift_name": "^", "shift_cmd": "^", "alt_name": "~", "alt_cmd": "~", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Ä", "cmd": "ä", "shift_cmd": "Ä" }, { "name": "Ö", "cmd": "ö", "shift_cmd": "Ö" }, { "name": "'", "cmd": "'", "shift_name": "*", "shift_cmd": "*", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "alt_name": "\\", "alt_cmd": "\\", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/tr-TR-F.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "+", "cmd": "+", "shift_name": "*", "shift_cmd": "*" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "\"", "shift_cmd": "\"", "alt_cmd": "~~~CTRLSEQ1~~~2", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_name": "#", "alt_cmd": "#", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "$", "shift_cmd": "$", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_cmd": "~~~CTRLSEQ1~~~4", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_cmd": "~~~CTRLSEQ1~~~5", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_cmd": "~~~CTRLSEQ1~~~6", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "'", "shift_cmd": "'", "alt_name": "{", "alt_cmd": "{", "ctrl_cmd": "~~~CTRLSEQ5~~~", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "alt_name": "[", "alt_cmd": "[", "ctrl_cmd": "\r", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_name": "]", "alt_cmd": "]", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_name": "}", "alt_cmd": "}", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "/", "cmd": "/", "shift_name": "?", "shift_cmd": "?", "alt_name": "\\", "alt_cmd": "\\", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "alt_name": "|", "alt_cmd": "|", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_name": "@", "alt_cmd": "@" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "Ğ", "cmd": "ğ", "shift_cmd": "Ğ", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~e" }, { "name": "I", "cmd": "ı", "shift_cmd": "I", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_cmd": "~~~CTRLSEQ1~~~t" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_name": "~", "alt_cmd":"~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "İ", "cmd": "i", "shift_cmd": "İ", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_name": "€", "alt_cmd": "€" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "Ü", "cmd": "ü", "shift_cmd": "Ü", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "alt_name": "₺", "alt_cmd": "₺" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y" }, { "name": "Ş", "cmd": "ş", "shift_cmd": "Ş" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_name": "`", "alt_cmd": "`" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "Ö", "cmd": "ö", "shift_cmd": "Ö", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "Ç", "cmd": "ç", "shift_cmd": "Ç", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": "B", "cmd": "b", "shift_cmd": "B" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/kb_layouts/tr-TR-Q.json ================================================ { "row_numbers": [ { "name": "ESC", "cmd": "~~~CTRLSEQ1~~~" }, { "name": "\"", "cmd": "\"", "shift_name": "é", "shift_cmd": "é" }, { "name": "1", "cmd": "1", "shift_name": "!", "shift_cmd": "!", "alt_cmd": "~~~CTRLSEQ1~~~1", "fn_name": "F1", "fn_cmd": "~~~CTRLSEQ1~~~OP" }, { "name": "2", "cmd": "2", "shift_name": "'", "shift_cmd": "'", "alt_name": "£", "alt_cmd": "£", "fn_name": "F2", "fn_cmd": "~~~CTRLSEQ1~~~OQ" }, { "name": "3", "cmd": "3", "shift_name": "^", "shift_cmd": "^", "ctrl_cmd": "~~~CTRLSEQ1~~~", "alt_name": "#", "alt_cmd": "#", "fn_name": "F3", "fn_cmd": "~~~CTRLSEQ1~~~OR" }, { "name": "4", "cmd": "4", "shift_name": "+", "shift_cmd": "+", "ctrl_cmd": "~~~CTRLSEQ2~~~", "alt_name": "$", "alt_cmd": "$", "fn_name": "F4", "fn_cmd": "~~~CTRLSEQ1~~~OS" }, { "name": "5", "cmd": "5", "shift_name": "%", "shift_cmd": "%", "ctrl_cmd": "~~~CTRLSEQ3~~~", "alt_name": "½", "alt_cmd": "½", "fn_name": "F5", "fn_cmd": "~~~CTRLSEQ1~~~[15~" }, { "name": "6", "cmd": "6", "shift_name": "&", "shift_cmd": "&", "ctrl_cmd": "~~~CTRLSEQ4~~~", "alt_name": "§", "alt_cmd": "§", "fn_name": "F6", "fn_cmd": "~~~CTRLSEQ1~~~[17~" }, { "name": "7", "cmd": "7", "shift_name": "/", "shift_cmd": "/", "ctrl_cmd": "~~~CTRLSEQ5~~~", "alt_name": "{", "alt_cmd": "{", "fn_name": "F7", "fn_cmd": "~~~CTRLSEQ1~~~[18~" }, { "name": "8", "cmd": "8", "shift_name": "(", "shift_cmd": "(", "ctrl_cmd": "\r", "alt_name": "[", "alt_cmd": "[", "fn_name": "F8", "fn_cmd": "~~~CTRLSEQ1~~~[19~" }, { "name": "9", "cmd": "9", "shift_name": ")", "shift_cmd": ")", "alt_name": "]", "alt_cmd": "]", "fn_name": "F9", "fn_cmd": "~~~CTRLSEQ1~~~[20~" }, { "name": "0", "cmd": "0", "shift_name": "=", "shift_cmd": "=", "alt_name": "}", "alt_cmd": "}", "fn_name": "F10", "fn_cmd": "~~~CTRLSEQ1~~~[21~" }, { "name": "*", "cmd": "*", "shift_name": "?", "shift_cmd": "?", "alt_name": "\\", "alt_cmd": "\\", "fn_name": "F11", "fn_cmd": "~~~CTRLSEQ1~~~[23~" }, { "name": "-", "cmd": "-", "shift_name": "_", "shift_cmd": "_", "alt_name": "|", "alt_cmd": "|", "fn_name": "F12", "fn_cmd": "~~~CTRLSEQ1~~~[24~" }, { "name": "BACK", "cmd": "\b", "shift_name": "DELETE", "shift_cmd": "~~~CTRLSEQ1~~~[3~" } ], "row_1": [ { "name": "TAB", "cmd": "\t" }, { "name": "Q", "cmd": "q", "shift_cmd": "Q", "ctrl_cmd": "~~~CTRLSEQ6~~~", "alt_name": "@", "alt_cmd": "@" }, { "name": "W", "cmd": "w", "shift_cmd": "W", "ctrl_cmd": "~~~CTRLSEQ7~~~", "alt_cmd": "~~~CTRLSEQ1~~~w" }, { "name": "E", "cmd": "e", "shift_cmd": "E", "ctrl_cmd": "\r", "alt_name": "€", "alt_cmd": "€" }, { "name": "R", "cmd": "r", "shift_cmd": "R", "ctrl_cmd": "~~~CTRLSEQ8~~~", "alt_cmd": "~~~CTRLSEQ1~~~r" }, { "name": "T", "cmd": "t", "shift_cmd": "T", "ctrl_cmd": "~~~CTRLSEQ9~~~", "alt_name": "₺", "alt_cmd": "₺" }, { "name": "Y", "cmd": "y", "shift_cmd": "Y", "ctrl_cmd": "~~~CTRLSEQ10~~~", "alt_cmd": "~~~CTRLSEQ1~~~y" }, { "name": "U", "cmd": "u", "shift_cmd": "U", "ctrl_cmd": "~~~CTRLSEQ11~~~", "alt_cmd": "~~~CTRLSEQ1~~~u" }, { "name": "I", "cmd": "i", "shift_cmd": "I", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~i" }, { "name": "O", "cmd": "o", "shift_cmd": "O", "alt_cmd": "~~~CTRLSEQ1~~~o" }, { "name": "P", "cmd": "p", "shift_cmd": "P", "ctrl_cmd": "~~~CTRLSEQ12~~~", "alt_cmd": "~~~CTRLSEQ1~~~p" }, { "name": "Ğ", "cmd": "ğ", "shift_cmd": "Ğ", "ctrl_cmd": "~~~CTRLSEQ1~~~" }, { "name": "Ü", "cmd": "ü", "shift_cmd": "Ü", "alt_name": "~", "alt_cmd": "~", "ctrl_cmd": "~~~CTRLSEQ3~~~" }, { "name": "ENTER", "cmd": "\r" } ], "row_2": [ { "name": "CAPS", "cmd": "ESCAPED|-- CAPSLCK: ON", "shift_cmd": "ESCAPED|-- CAPSLCK: OFF" }, { "name": "A", "cmd": "a", "shift_cmd": "A", "ctrl_cmd": "~~~CTRLSEQ13~~~", "alt_cmd": "~~~CTRLSEQ1~~~a" }, { "name": "S", "cmd": "s", "shift_cmd": "S", "ctrl_cmd": "~~~CTRLSEQ14~~~", "alt_cmd": "~~~CTRLSEQ1~~~s" }, { "name": "D", "cmd": "d", "shift_cmd": "D", "ctrl_cmd": "~~~CTRLSEQ15~~~", "alt_cmd": "~~~CTRLSEQ1~~~d" }, { "name": "F", "cmd": "f", "shift_cmd": "F", "ctrl_cmd": "~~~CTRLSEQ16~~~", "alt_cmd": "~~~CTRLSEQ1~~~f" }, { "name": "G", "cmd": "g", "shift_cmd": "G", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~g" }, { "name": "H", "cmd": "h", "shift_cmd": "H", "alt_cmd": "~~~CTRLSEQ1~~~h" }, { "name": "J", "cmd": "j", "shift_cmd": "J", "alt_cmd": "~~~CTRLSEQ1~~~j" }, { "name": "K", "cmd": "k", "shift_cmd": "K", "alt_cmd": "~~~CTRLSEQ1~~~k" }, { "name": "L", "cmd": "l", "shift_cmd": "L", "alt_cmd": "~~~CTRLSEQ1~~~l" }, { "name": "Ş", "cmd": "ş", "shift_cmd": "Ş" }, { "name": "İ", "cmd": "i", "shift_cmd": "İ" }, { "name": ",", "cmd": ",", "shift_name": ";", "shift_cmd": ";", "alt_name": "`", "alt_cmd": "`", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "", "cmd": "\r" } ], "row_3": [ { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: LEFT" }, { "name": "<", "cmd": "<", "shift_name": ">", "shift_cmd": ">", "alt_name": "|", "alt_cmd": "|", "ctrl_cmd": "~~~CTRLSEQ2~~~" }, { "name": "Z", "cmd": "z", "shift_cmd": "Z", "ctrl_cmd": "~~~CTRLSEQ17~~~", "alt_cmd": "~~~CTRLSEQ1~~~z" }, { "name": "X", "cmd": "x", "shift_cmd": "X", "ctrl_cmd": "~~~CTRLSEQ18~~~", "alt_cmd": "~~~CTRLSEQ1~~~x" }, { "name": "C", "cmd": "c", "shift_cmd": "C", "ctrl_cmd": "~~~CTRLSEQ19~~~", "alt_cmd": "~~~CTRLSEQ1~~~c" }, { "name": "V", "cmd": "v", "shift_cmd": "V", "ctrl_cmd": "~~~CTRLSEQ20~~~", "alt_cmd": "~~~CTRLSEQ1~~~v" }, { "name": "B", "cmd": "b", "shift_cmd": "B", "ctrl_cmd": "~~~CTRLSEQ21~~~", "alt_cmd": "~~~CTRLSEQ1~~~b" }, { "name": "N", "cmd": "n", "shift_cmd": "N", "alt_cmd": "~~~CTRLSEQ1~~~n" }, { "name": "M", "cmd": "m", "shift_cmd": "M", "ctrl_cmd": "\r", "alt_cmd": "~~~CTRLSEQ1~~~m" }, { "name": "Ö", "cmd": "ö", "shift_cmd": "Ö" }, { "name": "Ç", "cmd": "ç", "shift_cmd": "Ç" }, { "name": ".", "cmd": ".", "shift_name": ":", "shift_cmd": ":" }, { "name": "SHIFT", "cmd": "ESCAPED|-- SHIFT: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_UP", "cmd": "~~~CTRLSEQ1~~~OA" } ], "row_space": [ { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: LEFT" }, { "name": "FN", "cmd": "ESCAPED|-- FN: ON", "fn_cmd": "ESCAPED|-- FN: OFF" }, { "name": "", "cmd": " " }, { "name": "ALT GR", "cmd": "ESCAPED|-- ALT: RIGHT" }, { "name": "CTRL", "cmd": "ESCAPED|-- CTRL: RIGHT" }, { "name": "ESCAPED|-- ICON: ARROW_LEFT", "cmd": "~~~CTRLSEQ1~~~OD" }, { "name": "ESCAPED|-- ICON: ARROW_DOWN", "cmd": "~~~CTRLSEQ1~~~OB" }, { "name": "ESCAPED|-- ICON: ARROW_RIGHT", "cmd": "~~~CTRLSEQ1~~~OC" } ] } ================================================ FILE: src/assets/misc/boot_log.txt ================================================ Welcome to eDEX-UI! vm_page_bootstrap: 987323 free pages and 53061 wired pages kext submap [0xffffff7f8072e000 - 0xffffff8000000000], kernel text [0xffffff8000200000 - 0xffffff800072e000] zone leak detection enabled standard timeslicing quantum is 10000 us mig_table_max_displ = 72 TSC Deadline Timer supported and enabled eDEXACPICPU: ProcessorId=1 LocalApicId=0 Enabled eDEXACPICPU: ProcessorId=2 LocalApicId=2 Enabled eDEXACPICPU: ProcessorId=3 LocalApicId=1 Enabled eDEXACPICPU: ProcessorId=4 LocalApicId=3 Enabled eDEXACPICPU: ProcessorId=5 LocalApicId=255 Disabled eDEXACPICPU: ProcessorId=6 LocalApicId=255 Disabled eDEXACPICPU: ProcessorId=7 LocalApicId=255 Disabled eDEXACPICPU: ProcessorId=8 LocalApicId=255 Disabled calling mpo_policy_init for TMSafetyNet Security policy loaded: Safety net for Rollback (TMSafetyNet) calling mpo_policy_init for Sandbox Security policy loaded: Seatbelt sandbox policy (Sandbox) calling mpo_policy_init for Quarantine Security policy loaded: Quarantine policy (Quarantine) Copyright (c) 1982, 1986, 1989, 1991, 1993, 2015 The Regents of the University of Adelaide. All rights reserved. HN_ Framework successfully initialized using 16384 buffer headers and 10240 cluster IO buffer headers IOAPIC: Version 0x20 Vectors 64:87 ACPI: System State [S0 S3 S4 S5] (S3) PFM64 0xf10000000, 0xf0000000 [ PCI configuration begin ] eDEXIntelCPUPowerManagement: Turbo Ratios 0046 eDEXIntelCPUPowerManagement: (built 13:08:12 Jun 18 2011) initialization complete console relocated to 0xf10000000 PCI configuration changed (bridge=16 device=4 cardbus=0) [ PCI configuration end, bridges 12 devices 16 ] mbinit: done [64 MB total pool size, (42/21) split] Pthread support ABORTS when sync kernel primitives misused com.eDEX.eDEXFSCompressionTypeZlib kmod start com.eDEX.eDEXTrololoBootScreen kmod start com.eDEX.eDEXFSCompressionTypeZlib load succeeded com.eDEX.eDEXFSCompressionTypeDataless load succeeded eDEXIntelCPUPowerManagementClient: ready BTCOEXIST off wl0: Broadcom BCM4331 802.11 Wireless Controller 5.100.98.75 FireWire (OHCI) Lucent ID 5901 built-in now active, GUID c82a14fffee4a086; max speed s800. rooting via boot-uuid from /chosen: F5670083-AC74-33D3-8361-AC1977EE4AA2 Waiting on <dict ID="0"><key>IOProviderClass</key><string ID="1"> IOResources</string><key>IOResourceMatch</key><string ID="2">boot-uuid-media</string></dict> Got boot device = IOService:/eDEXACPIPlatformExpert/PCI0@0/eDEXACPIPCI/SATA@1F,2/ eDEXIntelPchSeriesAHCI/PRT0@0/IOAHCIDevice@0/eDEXAHCIDiskDriver/SarahI@sTheBestDriverIOAHCIBlockStorageDevice/IOBlockStorageDriver/ eDEX SSD TS128C Media/IOGUIDPartitionScheme/Customer@2 BSD root: disk0s2, major 14, minor 2 Kernel is LP64 IOThunderboltSwitch::i2cWriteDWord - status = 0xe00002ed IOThunderboltSwitch::i2cWriteDWord - status = 0x00000000 IOThunderboltSwitch::i2cWriteDWord - status = 0xe00002ed IOThunderboltSwitch::i2cWriteDWord - status = 0xe00002ed eDEXUSBMultitouchDriver::checkStatus - received Status Packet, Payload 2: device was reinitialized MottIsAScrub::checkstatus - true, Mott::Scrub [IOBluetoothHCIController::setConfigState] calling registerService AirPort_Brcm4331: Ethernet address e4:ce:8f:46:18:d2 IO80211Controller::dataLinkLayerAttachComplete(): adding eDEXEFINVRAM notification IO80211Interface::efiNVRAMPublished(): Created virtif 0xffffff800c32ee00 p2p0 BCM5701Enet: Ethernet address c8:2a:14:57:a4:7a Previous Shutdown Cause: 3 NTFS driver 3.8 [Flags: R/W]. NTFS volume name BOOTCAMP, version 3.1. DSMOS has arrived en1: 802.11d country code set to 'US'. en1: Supported channels 1 2 3 4 5 6 7 8 9 10 11 36 40 44 48 52 56 60 64 100 104 108 112 116 120 124 128 132 136 140 149 153 157 161 165 m_thebest MacAuthEvent en1 Auth result for: 00:60:64:1e:e9:e4 MAC AUTH succeeded MacAuthEvent en1 Auth result for: 00:60:64:1e:e9:e4 Unsolicited Auth wlEvent: en1 en1 Link UP AirPort: Link Up on en1 en1: BSSID changed to 00:60:64:1e:e9:e4 virtual bool IOHIDEventSystemUserClient::initWithTask(task*, void*, UInt32): Client task not privileged to open IOHIDSystem for mapping memory (e00002c1) Boot Complete ================================================ FILE: src/assets/misc/file-icons-match.js ================================================ /* * Thanks everyone for pointing out this is probably on of the ugliest source code files on GitHub * This is script-generated code, however, so it might disqualify * See file-icons-generator.js at root dir of git tree */ function matchIcon(filename) { if (/^APLSource$/.test(filename)) { return "acre"; } if (/^\.acre$/.test(filename)) { return "acre"; } if (/^\.agda$/i.test(filename)) { return "agda"; } if (/\/\.config\/alacritty$/i.test(filename)) { return "alacritty-alt"; } if (/\.(app|xcodeproj|xcworkspace)$/i.test(filename)) { return "appstore"; } if (/\.artx$/i.test(filename)) { return "arttext"; } if (/\.art4$/i.test(filename)) { return "arttext4"; } if (/^\.atom(-ci)?$/.test(filename)) { return "atom"; } if (/[^\s.]\.(c?action|definition|workflow)$/i.test(filename)) { return "automator"; } if (/^\.azure-pipelines$/i.test(filename)) { return "azurepipelines"; } if (/^\.bzr$/.test(filename)) { return "bazaar"; } if (/^\.bitcoin$/i.test(filename)) { return "bitcoin"; } if (/^bloc$/i.test(filename)) { return "bloc"; } if (/^bower[-_]components$/.test(filename)) { return "bower"; } if (/^\.buildkite$/.test(filename)) { return "buildkite"; } if (/^\.cabal$/i.test(filename)) { return "cabal"; } if (/\.chef$/.test(filename)) { return "chef"; } if (/^\.circleci$/.test(filename)) { return "circleci"; } if (/^cnab$/i.test(filename)) { return "cnab"; } if (/^\.cpan$/i.test(filename)) { return "cpan"; } if (/^\.cpanplus$/i.test(filename)) { return "cpan"; } if (/^cubits?$/i.test(filename)) { return "cubit"; } if (/^CVS$/.test(filename)) { return "cvs"; } if (/\.deno$/i.test(filename)) { return "deno"; } if (/\.dependabot$/i.test(filename)) { return "dependabot"; } if (/^\.devcontainer$/i.test(filename)) { return "devcontainer"; } if (/^\.docker$/.test(filename)) { return "docker"; } if (/^(Dropbox|\.dropbox\.cache)$/.test(filename)) { return "dropbox"; } if (/^\.dub$/.test(filename)) { return "dub"; } if (/^\.dvc$/.test(filename)) { return "dvc"; } if (/^\.emacs\.d$/.test(filename)) { return "emacs"; } if (/^\.expo(-shared)?$/i.test(filename)) { return "expo"; } if (/^\.fossil-settings$/i.test(filename)) { return "fossil"; } if (/\.git$/.test(filename)) { return "git"; } if (/^\.github$/.test(filename)) { return "github"; } if (/^\.gitlab$/.test(filename)) { return "gitlab"; } if (/^\.nyc[-_]output$/.test(filename)) { return "istanbul"; } if (/.\.(appex|bundle|ccl|component|framework|framework|ideplugin|kext|mdimporter|osax|(osirix)?plugin|qlgenerator)$/i.test(filename)) { return "dylib"; } if (/^\.meteor$/.test(filename)) { return "meteor"; } if (/^\.hg$/.test(filename)) { return "hg"; } if (/^node_modules$/.test(filename)) { return "node"; } if (/^\.node-gyp$/.test(filename)) { return "node"; } if (/^\.(bundle|paket)$/i.test(filename)) { return "package"; } if (/^\.svn$/i.test(filename)) { return "svn"; } if (/\.tmBundle$/i.test(filename)) { return "textmate"; } if (/\.ufo\d?$/i.test(filename)) { return "ufo"; } if (/\.vagrant$/i.test(filename)) { return "vagrant"; } if (/\.vagrant\.d$/i.test(filename)) { return "vagrant"; } if (/^\.vim$/i.test(filename)) { return "vim"; } if (/^\.vscode$/i.test(filename)) { return "vs"; } if (/^\.wine$/i.test(filename)) { return "wine"; } if (/^\.yarn$/i.test(filename)) { return "yarn"; } if (/\.bsl$/i.test(filename)) { return "1c"; } if (/\.sdbl$/i.test(filename)) { return "1c"; } if (/\.os$/i.test(filename)) { return "1c"; } if (/\.mdo$/i.test(filename)) { return "1c-alt"; } if (/\.4dm$/i.test(filename)) { return "4d"; } if (/\.a?\+$/i.test(filename)) { return "a-plus"; } if (/\.abap$/i.test(filename)) { return "abap"; } if (/\.abif$/i.test(filename)) { return "abif"; } if (/\.ab1$/i.test(filename)) { return "abif"; } if (/\.fsa$/i.test(filename)) { return "abif"; } if (/^acre\.config$/i.test(filename)) { return "acre"; } if (/\.swf$/i.test(filename)) { return "as"; } if (/\.as$/i.test(filename)) { return "as"; } if (/\.jsfl$/i.test(filename)) { return "as"; } if (/\.swc$/i.test(filename)) { return "as"; } if (/\.(ada|adb|ads)$/i.test(filename)) { return "ada"; } if (/^(ada95|ada2005)$/i.test(filename)) { return "ada"; } if (/\.aep$/i.test(filename)) { return "ae"; } if (/\.aet$/i.test(filename)) { return "ae"; } if (/\.fla$/i.test(filename)) { return "animate"; } if (/\.ai$/i.test(filename)) { return "ai"; } if (/\.ait$/i.test(filename)) { return "ai"; } if (/\.indd$/i.test(filename)) { return "indesign"; } if (/\.indl$/i.test(filename)) { return "indesign"; } if (/\.indt$/i.test(filename)) { return "indesign"; } if (/\.indb$/i.test(filename)) { return "indesign"; } if (/\.idml$/i.test(filename)) { return "indesign"; } if (/\.psd$/i.test(filename)) { return "psd"; } if (/\.psb$/i.test(filename)) { return "psd"; } if (/\.prproj$/i.test(filename)) { return "premiere"; } if (/\.prel$/i.test(filename)) { return "premiere"; } if (/\.psq$/i.test(filename)) { return "premiere"; } if (/\.prw$/i.test(filename)) { return "totvs"; } if (/\.ahu$/i.test(filename)) { return "totvs"; } if (/\.aph$/i.test(filename)) { return "totvs"; } if (/\.tlpp$/i.test(filename)) { return "totvs"; } if (/\.affect$/i.test(filename)) { return "affectscript"; } if (/\.afdesign$/i.test(filename)) { return "affinity"; } if (/\.afphoto$/i.test(filename)) { return "affinity"; } if (/\.afpub$/i.test(filename)) { return "affinity"; } if (/\.agda$/i.test(filename)) { return "agda"; } if (/\.lagda$/i.test(filename)) { return "agda"; } if (/^\.?alacritty\.ya?ml$/i.test(filename)) { return "alacritty"; } if (/\.alexrc$/i.test(filename)) { return "alex"; } if (/\.alexignore$/i.test(filename)) { return "alex"; } if (/\.als$/i.test(filename)) { return "alloy"; } if (/(\.|^)APKBUILD$/.test(filename)) { return "alpine"; } if (/\.ampl$/i.test(filename)) { return "ampl"; } if (/\.muse$/i.test(filename)) { return "amusewiki"; } if (/Muse$/i.test(filename)) { return "amusewiki"; } if (/\.ana$/i.test(filename)) { return "analytica"; } if (/\.smali$/i.test(filename)) { return "android"; } if (/\.rsh$/i.test(filename)) { return "android"; } if (/\.webarchivexml$/i.test(filename)) { return "android"; } if (/\.(acs|angelscript)$/i.test(filename)) { return "angelscript"; } if (/AngelCode$/i.test(filename)) { return "angelscript"; } if (/^angular[^.]*\.[cm]?js$/i.test(filename)) { return "angular"; } if (/\.anme$/i.test(filename)) { return "animestudio"; } if (/\.anime$/i.test(filename)) { return "animestudio"; } if (/\.animeaction$/i.test(filename)) { return "animestudio"; } if (/\.animebrush$/i.test(filename)) { return "animestudio"; } if (/\.animeexport$/i.test(filename)) { return "animestudio"; } if (/\.animeproj$/i.test(filename)) { return "animestudio"; } if (/\.animestyle$/i.test(filename)) { return "animestudio"; } if (/(^|\.)ansible(\.ya?ml)?$/i.test(filename)) { return "ansible"; } if (/([\\\/])roles\1[^\\\/]+\1(?:tasks|handlers|tests)\1.*\.ya?ml$/i.test(filename)) { return "ansible"; } if (/([\\\/])roles\1[^\\\/]+\1(?:defaults|vars|meta)\1.*\.ya?ml$/i.test(filename)) { return "ansible"; } if (/([\\\/])(?:group_vars|host_vars)\1.*\.ya?ml$/i.test(filename)) { return "ansible"; } if (/(^|.*(\.|-|\/))vault\.ya?ml$$/i.test(filename)) { return "lock"; } if (/\.ansiweatherrc$/i.test(filename)) { return "sun"; } if (/^ant\.xml$|\.ant$/i.test(filename)) { return "ant"; } if (/\.g$/i.test(filename)) { return "antlr"; } if (/\.g4$/i.test(filename)) { return "antlr"; } if (/^\.?antwar\.conf(ig)?\.[cm]?js$/i.test(filename)) { return "antwar"; } if (/\.any$/i.test(filename)) { return "anyscript"; } if (/^(apache2?|httpd)(\.[-\w]+)*\.conf$/i.test(filename)) { return "apache"; } if (/\.apacheconf$/i.test(filename)) { return "apache"; } if (/^httpd\.conf/i.test(filename)) { return "apache"; } if (/apache2\/magic$/i.test(filename)) { return "apache"; } if (/\.vhost$/i.test(filename)) { return "apache"; } if (/\.thrift$/i.test(filename)) { return "apache"; } if (/\.apib$/i.test(filename)) { return "api"; } if (/^api-extractor(-base)?\.json$/i.test(filename)) { return "apiextractor"; } if (/\.apl[acfino]?$/i.test(filename)) { return "apl"; } if (/\.apl\.history$/i.test(filename)) { return "apl"; } if (/^apollo\.config\.js$/i.test(filename)) { return "apollo"; } if (/^appcelerator\.[cm]?js$/i.test(filename)) { return "appcelerator"; } if (/\.(applescript|scpt)$/i.test(filename)) { return "apple"; } if (/^com\.apple\./.test(filename)) { return "apple"; } if (/^\.?appveyor\.yml$/i.test(filename)) { return "appveyor"; } if (/\.arc$/i.test(filename)) { return "arc"; } if (/^\.install$/.test(filename)) { return "archlinux"; } if (/^\.SRCINFO$/.test(filename)) { return "archlinux"; } if (/^pacman\.conf$/.test(filename)) { return "archlinux"; } if (/^pamac\.conf$/.test(filename)) { return "archlinux"; } if (/^PKGBUILD$/.test(filename)) { return "archlinux"; } if (/yaourtrc$/i.test(filename)) { return "archlinux"; } if (/\.ino$/i.test(filename)) { return "arduino"; } if (/\.(ad|adoc|asc|asciidoc)$/i.test(filename)) { return "asciidoctor"; } if (/\.asp$/i.test(filename)) { return "asp"; } if (/\.asax$/i.test(filename)) { return "asp"; } if (/\.ascx$/i.test(filename)) { return "asp"; } if (/\.ashx$/i.test(filename)) { return "asp"; } if (/\.asmx$/i.test(filename)) { return "asp"; } if (/\.aspx$/i.test(filename)) { return "asp"; } if (/\.axd$/i.test(filename)) { return "asp"; } if (/\.aj$/i.test(filename)) { return "eclipse"; } if (/\.a$/i.test(filename)) { return "asm"; } if (/\.i$/i.test(filename)) { return "asm"; } if (/\.s$/i.test(filename)) { return "asm"; } if (/\.asm$/i.test(filename)) { return "asm"; } if (/\.a51$/i.test(filename)) { return "asm"; } if (/\.agc$/i.test(filename)) { return "asm-agc"; } if (/^(Virtual\s*)?AGC$|^Apollo([-_\s]*11)?\s*Guidance\s*Computer$/i.test(filename)) { return "asm-agc"; } if (/\.arm$/i.test(filename)) { return "asm-arm"; } if (/\.avr$/i.test(filename)) { return "asm-avr"; } if (/\.h8(SX?|\d{3})?$/i.test(filename)) { return "asm-hitachi"; } if (/^(h8(SX?|\/?\d{3})?)$/i.test(filename)) { return "asm-hitachi"; } if (/\.((x|i(a[-_]?))(32|86|64)(asm)?|i386|80386)$/i.test(filename)) { return "asm-intel"; } if (/^(x86|x64|x86[-_]?64|i(a[-_]?)?(32|64)|i386|80386|Intel|Itanium|[ftm]asm)$/i.test(filename)) { return "asm-intel"; } if (/\.m68k$/i.test(filename)) { return "asm-m68k"; } if (/\.lst$/i.test(filename)) { return "asm-m68k"; } if (/\.v(ax|masm)$/i.test(filename)) { return "asm-vax"; } if (/^(Macro[-_\s]?32|VAX\s+Macro|vmasm)$/i.test(filename)) { return "asm-vax"; } if (/\.z80$/i.test(filename)) { return "asm-zilog"; } if (/\.PLX(COPY)?$/.test(filename)) { return "asm-zilog"; } if (/\.asy$/i.test(filename)) { return "asymptote"; } if (/\.atomproject\.[jc]son$/i.test(filename)) { return "atom"; } if (/^\.?apmrc$/i.test(filename)) { return "atom"; } if (/^\.?atoum(\.[^.]+)*\.php/i.test(filename)) { return "atoum"; } if (/\.dats$/i.test(filename)) { return "ats"; } if (/\.hats$/i.test(filename)) { return "ats"; } if (/\.sats$/i.test(filename)) { return "ats"; } if (/\.aup$/i.test(filename)) { return "audacity"; } if (/\.mp3$/i.test(filename)) { return "audio"; } if (/\.wav$/i.test(filename)) { return "audio"; } if (/\.(aac|ac3|m4p)$/i.test(filename)) { return "audio"; } if (/\.aif[fc]?$/i.test(filename)) { return "audio"; } if (/\.au$/i.test(filename)) { return "audio"; } if (/\.flac$/i.test(filename)) { return "audio"; } if (/\.f4[ab]$/i.test(filename)) { return "audio"; } if (/\.it$/i.test(filename)) { return "audio"; } if (/\.m4a$/i.test(filename)) { return "audio"; } if (/\.mka$/i.test(filename)) { return "audio"; } if (/\.(mpc|mp\+)$/i.test(filename)) { return "audio"; } if (/\.oga$/i.test(filename)) { return "audio"; } if (/\.opus$/i.test(filename)) { return "audio"; } if (/\.r[am]$/i.test(filename)) { return "audio"; } if (/\.s3m$/i.test(filename)) { return "audio"; } if (/\.sndh$/i.test(filename)) { return "audio"; } if (/\.wma$/i.test(filename)) { return "audio"; } if (/\.aug$/i.test(filename)) { return "augeas"; } if (/^aurelia\.json$/i.test(filename)) { return "aurelia"; } if (/\.ahk$/i.test(filename)) { return "ahk"; } if (/\.ahkl$/i.test(filename)) { return "ahk"; } if (/\.au3$/i.test(filename)) { return "autoit"; } if (/^(AutoIt3|AutoItScript|au3)$/i.test(filename)) { return "autoit"; } if (/\.av(cs|sc|dl)$/i.test(filename)) { return "avro"; } if (/\.awk$/i.test(filename)) { return "awk"; } if (/\.gawk$/i.test(filename)) { return "awk"; } if (/\.mawk$/i.test(filename)) { return "awk"; } if (/\.nawk$/i.test(filename)) { return "awk"; } if (/\.auk$/i.test(filename)) { return "awk"; } if (/^azure-pipelines\.ya?ml$/i.test(filename)) { return "azurepipelines"; } if (/\.(babelrc|babelrc\.[cm]?js|languagebabel|babel)$/i.test(filename)) { return "babel"; } if (/babel(\.[\w\-]+)*\.conf(ig)?\./i.test(filename)) { return "babel"; } if (/\.babelignore$/i.test(filename)) { return "babel"; } if (/^backbone([-.]min|dev)?\.[cm]?js$/i.test(filename)) { return "backbone"; } if (/\.(bak|old|orig)$/.test(filename)) { return "backup"; } if (/\.bal$/i.test(filename)) { return "ballerina"; } if (/\.balx$/i.test(filename)) { return "ballerina"; } if (/\.bzrignore$/i.test(filename)) { return "bazaar"; } if (/\.bc$/i.test(filename)) { return "calc"; } if (/\.dc$/i.test(filename)) { return "calc"; } if (/^bc\.library$/i.test(filename)) { return "calc"; } if (/^\.?dcrc$/i.test(filename)) { return "calc"; } if (/^behat(\.[^.]+)*\.ya?ml$/i.test(filename)) { return "behat"; } if (/\.bemjson(\.[cm]?js)?$/i.test(filename)) { return "bem"; } if (/\.cbx$/i.test(filename)) { return "bibtex"; } if (/\.bbl$/i.test(filename)) { return "bibtex"; } if (/\.bbx$/i.test(filename)) { return "bibtex"; } if (/\.bib(tex)?$/i.test(filename)) { return "bibtex"; } if (/\.bst$/i.test(filename)) { return "bibtex"; } if (/\.bs$/i.test(filename)) { return "bikeshed"; } if (/\.biml$/i.test(filename)) { return "biml"; } if (/\.([ls]?o|out)$/i.test(filename)) { return "binary"; } if (/\.axf$/i.test(filename)) { return "binary"; } if (/\.elf$/i.test(filename)) { return "binary"; } if (/\.la$/i.test(filename)) { return "binary"; } if (/\.ko$/i.test(filename)) { return "binary"; } if (/\.((c([+px]{2}?)?-?)?objdump|bsdiff|bin|dat|pak|pdb)$/i.test(filename)) { return "binary"; } if (/\.d-objdump$/i.test(filename)) { return "binary"; } if (/\.(gco?|gcode|[cdhk]nc)$/i.test(filename)) { return "binary"; } if (/\.rpy[bc]$/i.test(filename)) { return "binary"; } if (/\.py[cdo]$/i.test(filename)) { return "binary"; } if (/\.prx$/i.test(filename)) { return "binary"; } if (/\.puff$/i.test(filename)) { return "binary"; } if (/\.swp$/i.test(filename)) { return "binary"; } if (/^\.rnd$/i.test(filename)) { return "binary"; } if (/^binder[-_]requirements\.(in|txt)$/i.test(filename)) { return "binder"; } if (/^\.bintray\.json$/i.test(filename)) { return "bintray"; } if (/\.bison$/i.test(filename)) { return "bison"; } if (/\.y$/i.test(filename)) { return "bison"; } if (/\.yacc$/i.test(filename)) { return "bison"; } if (/\.yy$/i.test(filename)) { return "bison"; } if (/^bitbucket-pipelines\.ya?ml$/i.test(filename)) { return "bitbucket"; } if (/^bitcoin\.conf$/i.test(filename)) { return "bitcoin"; } if (/\.bithoundrc$/i.test(filename)) { return "bithound"; } if (/\.blend$/i.test(filename)) { return "blender"; } if (/\.blend\d+$/i.test(filename)) { return "blender"; } if (/\.bphys$/i.test(filename)) { return "blender"; } if (/\.bb$/i.test(filename)) { return "blitzbasic"; } if (/\.decls$/i.test(filename)) { return "blitzbasic"; } if (/\.bsv$/i.test(filename)) { return "bluespec"; } if (/\.boo$/i.test(filename)) { return "boo"; } if (/\.boot$/i.test(filename)) { return "boot"; } if (/^Makefile\.boot$/i.test(filename)) { return "boot"; } if (/^bors\.toml$/i.test(filename)) { return "bors"; } if (/^(custom\.)?bootstrap\S*\.js$/i.test(filename)) { return "bootstrap"; } if (/^(custom\.)?bootstrap\S*\.cjs$/i.test(filename)) { return "bootstrap"; } if (/^(custom\.)?bootstrap\S*\.mjs$/i.test(filename)) { return "bootstrap"; } if (/^(custom\.)?bootstrap\S*\.css$/i.test(filename)) { return "bootstrap"; } if (/^(custom\.)?bootstrap\S*\.less$/i.test(filename)) { return "bootstrap"; } if (/^(custom\.)?bootstrap\S*\.scss$/i.test(filename)) { return "bootstrap"; } if (/^(custom\.)?bootstrap\S*\.styl$/i.test(filename)) { return "bootstrap"; } if (/\.bootstraprc$/i.test(filename)) { return "bootstrap"; } if (/\.bsq$/i.test(filename)) { return "bosque"; } if (/^(\.bowerrc|bower\.json|Bowerfile)$/i.test(filename)) { return "bower"; } if (/\.bf?$/i.test(filename)) { return "brain"; } if (/^(bf|Brainf\**ck)$/i.test(filename)) { return "brain"; } if (/brakeman\.yml$/i.test(filename)) { return "brakeman"; } if (/^brakeman\.ignore$/i.test(filename)) { return "brakeman"; } if (/\.bro$/i.test(filename)) { return "bro"; } if (/^Brocfile\./i.test(filename)) { return "broccoli"; } if (/\.br$/i.test(filename)) { return "brotli"; } if (/^(browserslist|\.browserslistrc)$/i.test(filename)) { return "browserslist"; } if (/^(bs-config|browser-sync)\.([cm]?js|json)$/i.test(filename)) { return "browsersync"; } if (/^brunch-config\.([cm]?js|coffee|ts)$/i.test(filename)) { return "brunch"; } if (/\.buckconfig$/i.test(filename)) { return "buck"; } if (/^BUCK$/.test(filename)) { return "buck"; } if (/^Gemfile(\.lock)?$/i.test(filename)) { return "bundler"; } if (/\.gemfile$/i.test(filename)) { return "bundler"; } if (/gemfile/i.test(filename)) { return "bundler"; } if (/\.dm$/i.test(filename)) { return "byond"; } if (/^(DM|Dream\s*Maker(\s*Script)?)$/i.test(filename)) { return "byond"; } if (/\.c$/i.test(filename)) { return "c"; } if (/\.h$/i.test(filename)) { return "c"; } if (/\.cats$/i.test(filename)) { return "c"; } if (/\.idc$/i.test(filename)) { return "c"; } if (/\.w$/i.test(filename)) { return "c"; } if (/\.nc$/i.test(filename)) { return "c"; } if (/\.upc$/i.test(filename)) { return "c"; } if (/\.xbm$/i.test(filename)) { return "c"; } if (/\.xpm$/i.test(filename)) { return "c"; } if (/(\\|\/)share(?:\1misc)?\1getopts?\d?$/.test(filename)) { return "c"; } if (/\.c[+px]{2}$|\.cc$/i.test(filename)) { return "cpp"; } if (/\.h[+px]{2}$/i.test(filename)) { return "cpp"; } if (/\.[it]pp$/i.test(filename)) { return "cpp"; } if (/\.(tcc|inl)$/i.test(filename)) { return "cpp"; } if (/\.cs$/i.test(filename)) { return "csharp"; } if (/^c\s*sharp$/i.test(filename)) { return "csharp"; } if (/\.csx$/i.test(filename)) { return "csscript"; } if (/\.cabal$/i.test(filename)) { return "cabal"; } if (/^cabal\.(config|project)$/i.test(filename)) { return "cabal"; } if (/^cabal-ghcjs\.project$/i.test(filename)) { return "cabal"; } if (/^cabal\../i.test(filename)) { return "cabal"; } if (/^Caddyfile($|[-.])/i.test(filename)) { return "caddy"; } if (/\.caffemodel$/i.test(filename)) { return "caffe"; } if (/\.solverstate$/i.test(filename)) { return "caffe"; } if (/\.caffe2model$/i.test(filename)) { return "caffe2"; } if (/^(init|predict)_net\.pb$/i.test(filename)) { return "caffe2"; } if (/^(deploy|solver|train_val)\.prototxt$/i.test(filename)) { return "caffe2"; } if (/\.cake$/i.test(filename)) { return "cake"; } if (/^Cakefile$/.test(filename)) { return "cakefile"; } if (/\.ctp$/i.test(filename)) { return "cakephp"; } if (/\.calva-repl$/i.test(filename)) { return "calva"; } if (/^Cartfile(\.|$)/.test(filename)) { return "carthage"; } if (/\.casc?$/i.test(filename)) { return "casc"; } if (/\.ceylon$/i.test(filename)) { return "ceylon"; } if (/^chai\.([jt]sx?|es6?|coffee)$/i.test(filename)) { return "chai"; } if (/\.chpl$/i.test(filename)) { return "chapel"; } if (/chpl$/i.test(filename)) { return "chapel"; } if (/^Chart(\.bundle)?(\.min)?\.[cm]?js$/i.test(filename)) { return "chartjs"; } if (/TODO/.test(filename)) { return "checklist"; } if (/^todo\.txt$/i.test(filename)) { return "checklist"; } if (/\.(todo|taskpaper)$/i.test(filename)) { return "checklist"; } if (/\.jas$/i.test(filename)) { return "cheetah3d"; } if (/^chefignore$|^(Berks|Policy)file(\.lock)?$/i.test(filename)) { return "chef"; } if (/^chocolatey.*\.ps1$/i.test(filename)) { return "chocolatey"; } if (/\.ck$/i.test(filename)) { return "chuck"; } if (/\.crx$/i.test(filename)) { return "chrome"; } if (/^circle\.yml$/i.test(filename)) { return "circleci"; } if (/\.brd$/i.test(filename)) { return "icon-circuit-board"; } if (/\.sch$/i.test(filename)) { return "icon-circuit-board"; } if (/\.pcb$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gbr$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gtl$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gbl$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gbs$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gto$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gts$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gtp$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gbo$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gbp$/i.test(filename)) { return "icon-circuit-board"; } if (/\.drl$/i.test(filename)) { return "icon-circuit-board"; } if (/\.dsn$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gko$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gpt$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gpb$/i.test(filename)) { return "icon-circuit-board"; } if (/\.gm\d+$/i.test(filename)) { return "icon-circuit-board"; } if (/\.g[0-9]+$/i.test(filename)) { return "icon-circuit-board"; } if (/^PCB\.[0-9]+(\.backup~?)?$/.test(filename)) { return "icon-circuit-board"; } if (/\.(cir|ckt|struct|tech)$/i.test(filename)) { return "icon-circuit-board"; } if (/\.fab$/i.test(filename)) { return "icon-circuit-board"; } if (/\.net$/i.test(filename)) { return "icon-circuit-board"; } if (/\.pho$/i.test(filename)) { return "icon-circuit-board"; } if (/\.cirru$/i.test(filename)) { return "cirru"; } if (/\.clw$/i.test(filename)) { return "clarion"; } if (/\.icl$/i.test(filename)) { return "clean"; } if (/\.dcl$/i.test(filename)) { return "clean"; } if (/\.abc$/i.test(filename)) { return "clean"; } if (/\.click$/i.test(filename)) { return "click"; } if (/Click!$/i.test(filename)) { return "click"; } if (/\.clp$/i.test(filename)) { return "clips"; } if (/\.clj$/i.test(filename)) { return "clojure"; } if (/\.cl2$/i.test(filename)) { return "clojure"; } if (/\.cljc$/i.test(filename)) { return "clojure"; } if (/\.cljx$/i.test(filename)) { return "clojure"; } if (/\.hic$/i.test(filename)) { return "clojure"; } if (/\.cljs(cm)?$/i.test(filename)) { return "cljs"; } if (/\.soy$/i.test(filename)) { return "closure-tpl"; } if (/\.cfignore$/i.test(filename)) { return "cloudfoundry"; } if (/\.cmake$/i.test(filename)) { return "cmake"; } if (/^CMakeLists\.txt$/.test(filename)) { return "cmake"; } if (/\.(cob|ccp|cbl|cobol|cpy)$/i.test(filename)) { return "cobol"; } if (/\.podspec$/i.test(filename)) { return "cocoapods"; } if (/\.codacy\.ya?ml$/i.test(filename)) { return "codacy"; } if (/\.codeclimate\.yml$/i.test(filename)) { return "cc"; } if (/^\.?codecov\.ya?ml$/i.test(filename)) { return "codecov"; } if (/(^config)?\.codekit\d*$/i.test(filename)) { return "codekit"; } if (/^codemeta\.json(ld)?$/i.test(filename)) { return "codemeta"; } if (/^codeship-[\w.-]+\.ya?ml$/i.test(filename)) { return "codeship"; } if (/\.coffee$/i.test(filename)) { return "coffee"; } if (/\.cjsx$/i.test(filename)) { return "coffee"; } if (/\.coffee\.ecr$/i.test(filename)) { return "coffee"; } if (/\.coffee\.erb$/i.test(filename)) { return "coffee"; } if (/\.coffee\.md$/i.test(filename)) { return "coffee"; } if (/\.litcoffee$/i.test(filename)) { return "coffee"; } if (/\.iced$/i.test(filename)) { return "coffee"; } if (/\.cfc$/i.test(filename)) { return "cf"; } if (/\.cfml?$/i.test(filename)) { return "cf"; } if (/\.(dae|collada)$/i.test(filename)) { return "khronos"; } if (/^commitlint\.config\.js$|^\.commitlintrc\.(json|js|ya?ml)$/i.test(filename)) { return "commitlint"; } if (/^\.?cz\.(json|toml|ya?ml)$/i.test(filename)) { return "commitizen"; } if (/\.cl$/i.test(filename)) { return "cl"; } if (/^c?lisp$/i.test(filename)) { return "cl"; } if (/^_?(compass|lemonade)\.scss$/i.test(filename)) { return "compass"; } if (/\.cp$/i.test(filename)) { return "cp"; } if (/\.cps$/i.test(filename)) { return "cp"; } if (/^composer\.(json|lock)$/i.test(filename)) { return "composer"; } if (/^composer\.phar$/i.test(filename)) { return "composer"; } if (/\.(zip|z|xz)$/i.test(filename)) { return "zip"; } if (/\.rar$/i.test(filename)) { return "zip"; } if (/\.t?gz$/i.test(filename)) { return "zip"; } if (/\.(lzo?|lzma|tlz|tar\.lzma)$/i.test(filename)) { return "zip"; } if (/\.7z$/i.test(filename)) { return "zip"; } if (/\.apk$/i.test(filename)) { return "zip"; } if (/\.tar$/i.test(filename)) { return "zip"; } if (/\.bz2$/i.test(filename)) { return "zip"; } if (/\.maff$/i.test(filename)) { return "zip"; } if (/\.iso$/i.test(filename)) { return "zip"; } if (/\.hqx$/i.test(filename)) { return "zip"; } if (/\.xpi$/i.test(filename)) { return "zip"; } if (/\.gem$/i.test(filename)) { return "zip"; } if (/\.whl$/i.test(filename)) { return "zip"; } if (/\.epub$/i.test(filename)) { return "zip"; } if (/\.jar$/i.test(filename)) { return "zip"; } if (/\.war$/i.test(filename)) { return "zip"; } if (/\.wgt$/i.test(filename)) { return "zip"; } if (/\.xar$/i.test(filename)) { return "zip"; } if (/\.dsk$/i.test(filename)) { return "zip"; } if (/\.ear$/i.test(filename)) { return "zip"; } if (/\.egg$/i.test(filename)) { return "zip"; } if (/\.sit$/i.test(filename)) { return "zip"; } if (/\.hak$/i.test(filename)) { return "zip"; } if (/\.cdf$/i.test(filename)) { return "cdf"; } if (/^(conanfile\.(txt|py)|conan\.conf)$/i.test(filename)) { return "conan"; } if (/^\.?condarc$/i.test(filename)) { return "conda"; } if (/\.(ini|desktop|directory|cfg|co?nf|prefs)$/i.test(filename)) { return "config"; } if (/\.properties$/i.test(filename)) { return "config"; } if (/\.ld$/i.test(filename)) { return "config"; } if (/\.ldif$/i.test(filename)) { return "config"; } if (/\.lds$/i.test(filename)) { return "config"; } if (/\.mcf$/i.test(filename)) { return "config"; } if (/\.opts$/i.test(filename)) { return "config"; } if (/^pf\.os$/i.test(filename)) { return "config"; } if (/\.sdl(ang)?$/i.test(filename)) { return "config"; } if (/^mimeapps\.list$/i.test(filename)) { return "config"; } if (/(\.|^)terminal(rc)?$/i.test(filename)) { return "config"; } if (/^ld\.script$/i.test(filename)) { return "config"; } if (/^(shells|rpc)$/i.test(filename)) { return "config"; } if (/^\.?XCompose$/.test(filename)) { return "config"; } if (/^buildozer\.spec$/i.test(filename)) { return "config"; } if (/^settings\.bsp$/i.test(filename)) { return "config"; } if (/config|settings|option|pref/i.test(filename)) { return "config"; } if (/\.flc$/i.test(filename)) { return "config"; } if (/\.kys$/i.test(filename)) { return "config"; } if (/\/(dev[-\w]+|troff)\/([^\/]+\/)*(DESC|Foundry|download|symbolmap)(\.(in|proto|8400))?$/i.test(filename)) { return "config"; } if (/[\/\\]fontforge[\/\\]hotkeys[\/\\][^\/\\]+/i.test(filename)) { return "config"; } if (/\.git[\/\\](config|info[\/\\][-\w]+)$/.test(filename)) { return "config"; } if (/(^|[\/\\])\.fossil-settings\1(?:[^\/\/]+)/.test(filename)) { return "config"; } if (/(^|[\/\\])\.ssh[\/\\]config$/.test(filename)) { return "config"; } if (/^\/(private\/)?etc\/([^\/]+\/)*[^\/]*\.(cf|conf|ini)(\.default)?$/i.test(filename)) { return "config"; } if (/^\/(private\/)?etc\/(aliases|auto_(home|master)|ftpusers|group|gettytab|hosts(\.equiv)?|manpaths|networks|paths|protocols|services|shells|sudoers|ttys)$/i.test(filename)) { return "config"; } if (/^coffeelint\.json$/i.test(filename)) { return "config-coffee"; } if (/\.coffeelintignore$/i.test(filename)) { return "config-coffee"; } if (/^go\.mod$/i.test(filename)) { return "config-go"; } if (/^go\.sum$/i.test(filename)) { return "config-go"; } if (/^haskellconfig\.json$/i.test(filename)) { return "config-hs"; } if (/\.js(beautify|cs|hint)rc$|^(jsconfig(\..+)?|\.?eshost(-config)?)\.json$/i.test(filename)) { return "config-js"; } if (/^perl[56]?-?config\.json$/i.test(filename)) { return "config-perl"; } if (/^python-?config\.json$/i.test(filename)) { return "config-python"; } if (/^pyproject\.toml$/i.test(filename)) { return "config-python"; } if (/^poetry\.lock$/i.test(filename)) { return "config-python"; } if (/^\.coveragerc$/i.test(filename)) { return "config-python"; } if (/^MANIFEST\.in$/i.test(filename)) { return "config-python"; } if (/\.python-version$/i.test(filename)) { return "config-python"; } if (/^jsxconfig\.json$/i.test(filename)) { return "config-react"; } if (/^rubyconfig\.json$|\.(autotest|cross_rubies|gemtest|hoerc|kick|simplecov|yardopts)$/i.test(filename)) { return "config-ruby"; } if (/^\.yardopts/i.test(filename)) { return "config-ruby"; } if (/^rustconfig\.json$/i.test(filename)) { return "config-rust"; } if (/^rust-toolchain$/i.test(filename)) { return "config-rust"; } if (/^tsconfig(\..+)?\.json$/i.test(filename)) { return "config-ts"; } if (/^tslint\.json$/i.test(filename)) { return "config-ts"; } if (/\.conll$/i.test(filename)) { return "conll"; } if (/\.conllu$/i.test(filename)) { return "conll"; } if (/\.coq$/i.test(filename)) { return "coq"; } if (/^cordova([^.]*\.|-(\d\.)+)[cm]?js$/i.test(filename)) { return "cordova"; } if (/\.(cmx|ccx)$/i.test(filename)) { return "corel"; } if (/\.(cdrx?|cdt)$/i.test(filename)) { return "coreldraw"; } if (/^\.coveralls\.ya?ml$/i.test(filename)) { return "coveralls"; } if (/^cpanfile$/i.test(filename)) { return "cpan"; } if (/^META\.yml$/.test(filename)) { return "cpan"; } if (/^META\.json$/.test(filename)) { return "cpan"; } if (/^MANIFEST\.SKIP$/.test(filename)) { return "cpan"; } if (/\.cpc$/i.test(filename)) { return "cpcdosc"; } if (/\.creole$/i.test(filename)) { return "creole"; } if (/^crowdin\.ya?ml$/i.test(filename)) { return "crowdin"; } if (/\.e?cr$/i.test(filename)) { return "crystal"; } if (/\.orc$/i.test(filename)) { return "csound"; } if (/\.udo$/i.test(filename)) { return "csound"; } if (/\.csd$/i.test(filename)) { return "csound"; } if (/\.sco$/i.test(filename)) { return "csound"; } if (/\.css$/i.test(filename)) { return "css3"; } if (/\.less$/i.test(filename)) { return "css3"; } if (/\.tss$/i.test(filename)) { return "css3"; } if (/\.feature$/i.test(filename)) { return "cucumber"; } if (/gherkin$/i.test(filename)) { return "cucumber"; } if (/\.cu$/i.test(filename)) { return "nvidia"; } if (/\.cuh$/i.test(filename)) { return "nvidia"; } if (/\.cfl$/i.test(filename)) { return "cuneiform"; } if (/(^|\.)curlrc$|^_curlrc$/i.test(filename)) { return "curl"; } if (/\.curry$/i.test(filename)) { return "curry"; } if (/\.cvsignore$/i.test(filename)) { return "cvs"; } if (/\.cwl$/i.test(filename)) { return "cwl"; } if (/Common Workflow Language$/i.test(filename)) { return "cwl"; } if (/\.pyx$/i.test(filename)) { return "cython"; } if (/\.pxd$/i.test(filename)) { return "cython"; } if (/\.pxi$/i.test(filename)) { return "cython"; } if (/\.di?$/i.test(filename)) { return "dlang"; } if (/^d3(\.v\d+)?[^.]*\.[cm]?js$/i.test(filename)) { return "d3"; } if (/\.(dfy|dafny)$/i.test(filename)) { return "dafny"; } if (/\.dnh$/i.test(filename)) { return "yang"; } if (/\.d(arcs)?patch$/i.test(filename)) { return "darcs"; } if (/^\.boringignore$/i.test(filename)) { return "darcs"; } if (/\.dart$/i.test(filename)) { return "dart"; } if (/\.s[kl]im$/i.test(filename)) { return "dashboard"; } if (/\.cpuprofile$/i.test(filename)) { return "dashboard"; } if (/\.cloc$/i.test(filename)) { return "dashboard"; } if (/\.aff$/i.test(filename)) { return "database"; } if (/\.cson$/i.test(filename)) { return "database"; } if (/\.dict?$/i.test(filename)) { return "database"; } if (/\.hson$/i.test(filename)) { return "database"; } if (/\.http$/i.test(filename)) { return "database"; } if (/\.ndjson$/i.test(filename)) { return "database"; } if (/\.fea$/i.test(filename)) { return "database"; } if (/\.json\.eex$/i.test(filename)) { return "database"; } if (/\.cbor$/i.test(filename)) { return "database"; } if (/\.(proto|protote?xt|pbte?xt)$/i.test(filename)) { return "database"; } if (/\.pytb$/i.test(filename)) { return "database"; } if (/\.pydeps$/i.test(filename)) { return "database"; } if (/\.pot?$/i.test(filename)) { return "database"; } if (/\.ejson$/i.test(filename)) { return "database"; } if (/\.edn$/i.test(filename)) { return "database"; } if (/\.eam\.fs$/i.test(filename)) { return "database"; } if (/\.son$/i.test(filename)) { return "database"; } if (/\.ston$/i.test(filename)) { return "database"; } if (/\.ttl$/i.test(filename)) { return "database"; } if (/\.schema$/i.test(filename)) { return "database"; } if (/\.sy$/i.test(filename)) { return "database"; } if (/\.syntax$/i.test(filename)) { return "database"; } if (/\.webmanifest$/i.test(filename)) { return "database"; } if (/\.tgn$/i.test(filename)) { return "database"; } if (/\.2da$/i.test(filename)) { return "database"; } if (/\.(od|onlydata)$/i.test(filename)) { return "database"; } if (/\.dbi$/i.test(filename)) { return "database"; } if (/\.snip(pets?)?$/i.test(filename)) { return "database"; } if (/\.yas(nippet)?$/i.test(filename)) { return "database"; } if (/(^|\.)fonts\.(dir|scale|alias)$/i.test(filename)) { return "database"; } if (/(^|\.)encodings\.dir$/i.test(filename)) { return "database"; } if (/^pkginfo$/i.test(filename)) { return "database"; } if (/^term(cap|info)/i.test(filename)) { return "database"; } if (/^eign$/.test(filename)) { return "database"; } if (/^(birthtoken|flowers)$/.test(filename)) { return "database"; } if (/(\\|\/)share(?:\1misc)?\1(?:ascii|trace\.codes)$/.test(filename)) { return "database"; } if (/^(mime\.types|fstab)$/i.test(filename)) { return "database"; } if (/^METADATA\.pb$/.test(filename)) { return "database"; } if (/\.(ldj|ldjson|jsonl)$/.test(filename)) { return "database"; } if (/\.(irb-history|lesshst)$/i.test(filename)) { return "database"; } if (/^(magic\.mgc|figmagic)$/i.test(filename)) { return "database"; } if (/[\/\\](?:magic[\/\\]Magdir|file[\/\\]magic)[\/\\][-.\w]+$/i.test(filename)) { return "database"; } if (/(\\|\/)dev[-\w]+\1(?:[^\\\/]+\1)*(?!DESC|NOTES)(?:[A-Z][-A-Z]*)(?:\.in)?$/.test(filename)) { return "database"; } if (/term\/O?tab\.[^\/]+$|\/dev[-\w]+\/(APL\.bug|[A-Z][-A-Za-z0-9]*)(\.fd)?$/i.test(filename)) { return "database"; } if (/(^|\/)n?term\/O?tab\.(X|lpr)$/i.test(filename)) { return "database"; } if (/\.ssh[\/\\](authorized_keys|known_hosts)$/.test(filename)) { return "database"; } if (/^\.icondb\.js$/.test(filename)) { return "database"; } if (/^index\.(bt|db|dir|pag)$/i.test(filename)) { return "database"; } if (/^whatis$/i.test(filename)) { return "database"; } if (/^(language-subtag-registry(\.txt)?|nametable)$/.test(filename)) { return "database"; } if (/\.git[\/\\](.*[\/\\])?(HEAD|ORIG_HEAD|packed-refs|logs[\/\\](.+[\/\\])?[^\/\\]+)$/.test(filename)) { return "database"; } if (/\.dwl$/i.test(filename)) { return "dataweave"; } if (/\.dbf$/i.test(filename)) { return "dbase"; } if (/\.deb$/i.test(filename)) { return "debian"; } if (/(^|\.)(control|dsc)$/.test(filename)) { return "debian"; } if (/^rules$/.test(filename)) { return "debian"; } if (/\.dfm$/i.test(filename)) { return "delphi"; } if (/\.dof$/i.test(filename)) { return "delphi"; } if (/\.dpr$/i.test(filename)) { return "delphi"; } if (/\.dmark$/i.test(filename)) { return "icon-star"; } if (/^d[_\W]?mark$/i.test(filename)) { return "icon-star"; } if (/^dependabot\.ya?ml$/i.test(filename)) { return "dependabot"; } if (/^devcontainer\.json$/i.test(filename)) { return "devcontainer"; } if (/\.dts$/i.test(filename)) { return "devicetree"; } if (/\.dtsi$/i.test(filename)) { return "devicetree"; } if (/\.dhall$/i.test(filename)) { return "dhall"; } if (/\.dia$/i.test(filename)) { return "dia"; } if (/\.diff$/i.test(filename)) { return "diff"; } if (/\.diffs$/i.test(filename)) { return "diff"; } if (/\.dig$/i.test(filename)) { return "digdag"; } if (/\.dit(roff)?$/i.test(filename)) { return "binary"; } if (/\.zone$/i.test(filename)) { return "earth"; } if (/\.arpa$/i.test(filename)) { return "earth"; } if (/^CNAME$/.test(filename)) { return "earth"; } if (/\.(dbk|docbook)$/i.test(filename)) { return "docbook"; } if (/^(Dockerfile|docker-compose)|\.docker(file|ignore)$/i.test(filename)) { return "docker"; } if (/^docker-sync\.yml$/i.test(filename)) { return "docker"; } if (/\.doclets\.ya?ml$/i.test(filename)) { return "doclets"; } if (/\.eco$/i.test(filename)) { return "docpad"; } if (/(^|\.)docz(rc)?(\.config)?\.[cm]?js$/i.test(filename)) { return "docz"; } if (/(^|\.)docz(rc)?(\.config)?\.json$/i.test(filename)) { return "docz"; } if (/\.djs$/i.test(filename)) { return "doge"; } if (/^dojo\.[cm]?js$/i.test(filename)) { return "dojo"; } if (/^dosbox(\b|_).*(\.conf|pref\w*)$/i.test(filename)) { return "dosbox"; } if (/^\.env(\.|$)/i.test(filename)) { return "dotenv"; } if (/\.dot$/i.test(filename)) { return "dotjs"; } if (/\.crdownload$/i.test(filename)) { return "download"; } if (/^\.?Doxyfile$/i.test(filename)) { return "doxygen"; } if (/^dragula(\.min)?\.([cm]?js|css)$/i.test(filename)) { return "dragula"; } if (/^\.drawio($|\.)|\.d(raw)?io(\.png|\.svg)?$/i.test(filename)) { return "drawio"; } if (/\.drone\.ya?ml$/i.test(filename)) { return "drone"; } if (/^dub(\.selections)?\.(json|sdl)$/i.test(filename)) { return "dub"; } if (/\.dyalog$/i.test(filename)) { return "dyalog"; } if (/\.dyapp$/i.test(filename)) { return "dyalog"; } if (/\.mipage$/i.test(filename)) { return "dyalog"; } if (/\.(dylib|bundle)$/i.test(filename)) { return "dylib"; } if (/\.E$/.test(filename)) { return "e"; } if (/\.eup$/i.test(filename)) { return "eagle"; } if (/\.eb$/i.test(filename)) { return "easybuild"; } if (/\.ec$/i.test(filename)) { return "ec"; } if (/\.eh$/i.test(filename)) { return "ec"; } if (/\.epj$/i.test(filename)) { return "ecere"; } if (/\.c?project$/.test(filename)) { return "eclipse"; } if (/\.classpath$/i.test(filename)) { return "eclipse"; } if (/\.ecl(\.txt)?$/i.test(filename)) { return "eclipse-lang"; } if (/\.editorconfig$/i.test(filename)) { return "editorconfig"; } if (/\.ecrc$/i.test(filename)) { return "editorconfig"; } if (/\.edge$/i.test(filename)) { return "edge"; } if (/\.e$/.test(filename)) { return "eiffel"; } if (/\.ejs$/i.test(filename)) { return "ejs"; } if (/\.compilerc(\.json)?$/i.test(filename)) { return "electron"; } if (/(^|\.)forge\.config\.js$/i.test(filename)) { return "electron"; } if (/\.ex$/i.test(filename)) { return "elixir"; } if (/\.(exs|l?eex)$/i.test(filename)) { return "elixir"; } if (/^mix\.(exs?|lock)$/i.test(filename)) { return "elixir"; } if (/\.elm$/i.test(filename)) { return "elm"; } if (/(^|\.)(el|_?emacs|emacs\.desktop|abbrev[-_]defs)$/i.test(filename)) { return "emacs"; } if (/(^|\.)(elc|eld)$/i.test(filename)) { return "emacs"; } if (/\.gnus$/i.test(filename)) { return "emacs"; } if (/\.viper$/i.test(filename)) { return "emacs"; } if (/^Cask$/.test(filename)) { return "emacs"; } if (/^Project\.ede$/i.test(filename)) { return "emacs"; } if (/^(authors|(code)?owners)$/i.test(filename)) { return "at"; } if (/^(EML|mbox|e?-?mail)$/i.test(filename)) { return "at"; } if (/^ember(\.|(-[^.]+)?-(\d+\.)+(debug\.)?)[cm]?js$/i.test(filename)) { return "ember"; } if (/\.emberscript$/i.test(filename)) { return "em"; } if (/\.em(blem)?$/i.test(filename)) { return "mustache"; } if (/\.ensime$/i.test(filename)) { return "ensime"; } if (/\.eq$/i.test(filename)) { return "eq"; } if (/\.erl$/i.test(filename)) { return "erlang"; } if (/\.beam$/i.test(filename)) { return "erlang"; } if (/\.hrl$/i.test(filename)) { return "erlang"; } if (/\.xrl$/i.test(filename)) { return "erlang"; } if (/\.yrl$/i.test(filename)) { return "erlang"; } if (/\.app\.src$/i.test(filename)) { return "erlang"; } if (/^Emakefile$/.test(filename)) { return "erlang"; } if (/^rebar(\.config)?\.lock$/i.test(filename)) { return "erlang"; } if (/^\.?esdoc\.([cm]?js|json)$/i.test(filename)) { return "esdoc"; } if (/\.eslint(cache|ignore)$/i.test(filename)) { return "eslint"; } if (/\.eslintrc($|\.)/i.test(filename)) { return "eslint"; } if (/\bExtjs(-ext)?\.[cm]?js$/i.test(filename)) { return "extjs"; } if (/^fabric\.mod\.json$/i.test(filename)) { return "fabric"; } if (/^fabfile\.py$/i.test(filename)) { return "fabfile"; } if (/\.factor$/i.test(filename)) { return "factor"; } if (/\.factor-rc$/i.test(filename)) { return "factor"; } if (/\.factor-boot-rc$/i.test(filename)) { return "factor"; } if (/\.fal(con)?$/i.test(filename)) { return "falcon"; } if (/\.fy$/i.test(filename)) { return "fancy"; } if (/\.fancypack$/i.test(filename)) { return "fancy"; } if (/^Fakefile$/.test(filename)) { return "fancy"; } if (/\.fan$/i.test(filename)) { return "fantom"; } if (/\.(fasta|fas?|seq|fsa)$/i.test(filename)) { return "dna"; } if (/\.(fastq|fq)$/i.test(filename)) { return "dna"; } if (/\.(faa|mpfa)$/i.test(filename)) { return "dna"; } if (/\.fna$/i.test(filename)) { return "dna"; } if (/\.ffn$/i.test(filename)) { return "dna"; } if (/\.frn$/i.test(filename)) { return "dna"; } if (/\.sam$/i.test(filename)) { return "dna"; } if (/\.fql$/i.test(filename)) { return "fauna"; } if (/\.faunarc$/i.test(filename)) { return "fauna"; } if (/\.dsp$/i.test(filename)) { return "faust"; } if (/\.fbx$/i.test(filename)) { return "fbx"; } if (/\.fxl$/i.test(filename)) { return "fexl"; } if (/\.figma$/i.test(filename)) { return "figma"; } if (/\.fdx$/i.test(filename)) { return "finaldraft"; } if (/^Icon\r$/.test(filename)) { return "finder"; } if (/\.rsrc$/i.test(filename)) { return "finder"; } if (/^\._./.test(filename)) { return "finder"; } if (/\.DS_Store$/i.test(filename)) { return "finder"; } if (/^firebase\.json$/i.test(filename)) { return "firebase"; } if (/^firestore\.indexes\.json$/i.test(filename)) { return "firebase"; } if (/^firestore\.rules?$/i.test(filename)) { return "firebase"; } if (/\.firebaserc$/i.test(filename)) { return "firebase"; } if (/\.bolt$/i.test(filename)) { return "firebase-bolt"; } if (/\.webapp$/i.test(filename)) { return "firefox"; } if (/^flask([-_.].*)\.py$/i.test(filename)) { return "flask"; } if (/\.flooignore$/i.test(filename)) { return "floobits"; } if (/\.(flowconfig|js\.flow|flow)$/i.test(filename)) { return "flow"; } if (/\.fx$/i.test(filename)) { return "flux"; } if (/\.flux$/i.test(filename)) { return "flux"; } if (/\.flutter-plugins$/i.test(filename)) { return "flutter"; } if (/\.woff2$/i.test(filename)) { return "font"; } if (/\.woff$/i.test(filename)) { return "font"; } if (/\.eot$/i.test(filename)) { return "font"; } if (/\.ttc$/i.test(filename)) { return "font"; } if (/\.ttf$/i.test(filename)) { return "font"; } if (/\.otf$/i.test(filename)) { return "font"; } if (/\.pfb$/i.test(filename)) { return "font"; } if (/\.pfm$/i.test(filename)) { return "font"; } if (/\.tfm$/i.test(filename)) { return "font"; } if (/\.dfont$/i.test(filename)) { return "font"; } if (/\.psfu?$/i.test(filename)) { return "font-bitmap"; } if (/\.pcf$/i.test(filename)) { return "font-bitmap"; } if (/\.psftx$/i.test(filename)) { return "font-bitmap"; } if (/\.bdf$/i.test(filename)) { return "font-bitmap"; } if (/\.fnt$/i.test(filename)) { return "font-bitmap"; } if (/\.fon$/i.test(filename)) { return "font-bitmap"; } if (/\.snf$/i.test(filename)) { return "font-bitmap"; } if (/\.flf$/i.test(filename)) { return "font-bitmap"; } if (/\.tlf$/i.test(filename)) { return "font-bitmap"; } if (/\.(ff|pe)$/i.test(filename)) { return "ff"; } if (/\.sfd$/i.test(filename)) { return "ff"; } if (/^\.issuetracker$/i.test(filename)) { return "fork"; } if (/\.trm$/i.test(filename)) { return "ftr"; } if (/\.f$/i.test(filename)) { return "fortran"; } if (/\.f90$/i.test(filename)) { return "fortran"; } if (/\.f03$/i.test(filename)) { return "fortran"; } if (/\.f08$/i.test(filename)) { return "fortran"; } if (/\.f77$/i.test(filename)) { return "fortran"; } if (/\.f95$/i.test(filename)) { return "fortran"; } if (/\.for$/i.test(filename)) { return "fortran"; } if (/\.fpp$/i.test(filename)) { return "fortran"; } if (/\.pfo$/i.test(filename)) { return "fortran"; } if (/\.fossa\.ya?ml$/i.test(filename)) { return "fossa"; } if (/\.fossaignore$/i.test(filename)) { return "fossa"; } if (/\.fountain$/i.test(filename)) { return "fountain"; } if (/\.fi?dl$/i.test(filename)) { return "franca"; } if (/\.fdepl$/i.test(filename)) { return "franca"; } if (/\.ftl$/i.test(filename)) { return "freemarker"; } if (/ftl$/i.test(filename)) { return "freemarker"; } if (/\.fr$/i.test(filename)) { return "frege"; } if (/\.fs[xi]?$/i.test(filename)) { return "fsharp"; } if (/f#$/i.test(filename)) { return "fsharp"; } if (/\.fthtml$/i.test(filename)) { return "fthtml"; } if (/^fuelux(\.min)?\.(css|[cm]?js)$/i.test(filename)) { return "fuelux"; } if (/^fuse\.[cm]?js$/.test(filename)) { return "fusebox"; } if (/\.fut$/i.test(filename)) { return "futhark"; } if (/^galaxy\.ini$/i.test(filename)) { return "galaxy"; } if (/\.gspec$/i.test(filename)) { return "galen"; } if (/\.gtest$/i.test(filename)) { return "galen"; } if (/\.gml$/i.test(filename)) { return "gml"; } if (/\.gms$/i.test(filename)) { return "gams"; } if (/\.gap$/i.test(filename)) { return "gap"; } if (/\.gi$/i.test(filename)) { return "gap"; } if (/\.tst$/i.test(filename)) { return "gap"; } if (/^gatsby-.+\.[jt]s$/i.test(filename)) { return "gatsby"; } if (/\.gss$/i.test(filename)) { return "gauss"; } if (/\.gdb$/i.test(filename)) { return "gdb"; } if (/gdbinit$/i.test(filename)) { return "gdb"; } if (/^\.htaccess$/i.test(filename)) { return "gear"; } if (/^\.htpasswd$/i.test(filename)) { return "gear"; } if (/^\.lesshintrc$/i.test(filename)) { return "gear"; } if (/^\.csscomb\.json$/i.test(filename)) { return "gear"; } if (/^text\.enc$/.test(filename)) { return "gear"; } if (/\.csslintrc$/i.test(filename)) { return "gear"; } if (/\.htmlhintrc$/i.test(filename)) { return "gear"; } if (/\.module$/i.test(filename)) { return "gear"; } if (/\.codoopts$/i.test(filename)) { return "gear"; } if (/\.arcconfig$/i.test(filename)) { return "gear"; } if (/\.pairs$/i.test(filename)) { return "gear"; } if (/\.lintstagedrc$/i.test(filename)) { return "gear"; } if (/\.indent\.pro$/i.test(filename)) { return "gear"; } if (/^\./.test(filename)) { return "gear"; } if (/\.dll$/i.test(filename)) { return "gears"; } if (/\.xml$/i.test(filename)) { return "code"; } if (/\.xmp$/i.test(filename)) { return "code"; } if (/\.rdf$/i.test(filename)) { return "code"; } if (/\.config$/i.test(filename)) { return "code"; } if (/^_service$/.test(filename)) { return "code"; } if (/^configure\.ac$/.test(filename)) { return "code"; } if (/^Settings\.StyleCop$/.test(filename)) { return "code"; } if (/\.4th$/i.test(filename)) { return "code"; } if (/\.adm[lx]$/i.test(filename)) { return "code"; } if (/\.[ad]sl$/i.test(filename)) { return "code"; } if (/\.aepx$/i.test(filename)) { return "code"; } if (/\.appxmanifest$/i.test(filename)) { return "code"; } if (/\.ash$/i.test(filename)) { return "code"; } if (/\.asn1?$/i.test(filename)) { return "code"; } if (/\.axml$/i.test(filename)) { return "code"; } if (/\.bc$/i.test(filename)) { return "code"; } if (/\.befunge$/i.test(filename)) { return "code"; } if (/\.bmx$/i.test(filename)) { return "code"; } if (/\.brs$/i.test(filename)) { return "code"; } if (/\.capnp$/i.test(filename)) { return "code"; } if (/\.ccxml$/i.test(filename)) { return "code"; } if (/\.cscfg$/i.test(filename)) { return "code"; } if (/\.cgi$/i.test(filename)) { return "code"; } if (/\.ch$/i.test(filename)) { return "code"; } if (/\.clixml$/i.test(filename)) { return "code"; } if (/\.cocci$/i.test(filename)) { return "code"; } if (/\.ct$/i.test(filename)) { return "code"; } if (/\.cw$/i.test(filename)) { return "code"; } if (/\.cy$/i.test(filename)) { return "code"; } if (/\.rdg$/i.test(filename)) { return "code"; } if (/\.dita$/i.test(filename)) { return "code"; } if (/\.ditamap$/i.test(filename)) { return "code"; } if (/\.ditaval$/i.test(filename)) { return "code"; } if (/\.dotsettings$/i.test(filename)) { return "code"; } if (/\.dtd$/i.test(filename)) { return "code"; } if (/\.dyl$/i.test(filename)) { return "code"; } if (/\.dylan$/i.test(filename)) { return "code"; } if (/\.eclxml$/i.test(filename)) { return "code"; } if (/\.ed$/i.test(filename)) { return "code"; } if (/\.fcgi$/i.test(filename)) { return "code"; } if (/\.fidl$/i.test(filename)) { return "code"; } if (/\.filters$/i.test(filename)) { return "code"; } if (/\.fo$/i.test(filename)) { return "code"; } if (/\.forth$/i.test(filename)) { return "code"; } if (/\.frt$/i.test(filename)) { return "code"; } if (/\.fsproj$/i.test(filename)) { return "code"; } if (/\.fth$/i.test(filename)) { return "code"; } if (/\.fun$/i.test(filename)) { return "code"; } if (/\.fxml$/i.test(filename)) { return "code"; } if (/\.grace$/i.test(filename)) { return "code"; } if (/\.grxml$/i.test(filename)) { return "code"; } if (/\.iml$/i.test(filename)) { return "code"; } if (/\.intr$/i.test(filename)) { return "code"; } if (/\.ivy$/i.test(filename)) { return "code"; } if (/\.jelly$/i.test(filename)) { return "code"; } if (/\.jf?lex$/i.test(filename)) { return "code"; } if (/\.joy$/i.test(filename)) { return "code"; } if (/\.jsproj$/i.test(filename)) { return "code"; } if (/\.jspx$/i.test(filename)) { return "code"; } if (/\.launch$/i.test(filename)) { return "code"; } if (/\.lid$/i.test(filename)) { return "code"; } if (/\.lp$/i.test(filename)) { return "code"; } if (/\.m4$/i.test(filename)) { return "code"; } if (/\.manifest$/i.test(filename)) { return "code"; } if (/\.mask$/i.test(filename)) { return "code"; } if (/\.mdpolicy$/i.test(filename)) { return "code"; } if (/\.menu$/i.test(filename)) { return "code"; } if (/\.ML$/.test(filename)) { return "code"; } if (/\.mq[45h]$/i.test(filename)) { return "code"; } if (/\.mtml$/i.test(filename)) { return "code"; } if (/\.muf$/i.test(filename)) { return "code"; } if (/\.mumps$/i.test(filename)) { return "code"; } if (/\.mxml$/i.test(filename)) { return "code"; } if (/\.myt$/i.test(filename)) { return "code"; } if (/\.natvis$/i.test(filename)) { return "code"; } if (/\.odd$/i.test(filename)) { return "code"; } if (/\.ohm$/i.test(filename)) { return "code"; } if (/\.omgrofl$/i.test(filename)) { return "code"; } if (/\.osm$/i.test(filename)) { return "code"; } if (/\.pig$/i.test(filename)) { return "code"; } if (/\.plist$/i.test(filename)) { return "code"; } if (/\.prg$/i.test(filename)) { return "code"; } if (/\.proj$/i.test(filename)) { return "code"; } if (/\.props$/i.test(filename)) { return "code"; } if (/\.psc1$/i.test(filename)) { return "code"; } if (/\.pt$/i.test(filename)) { return "code"; } if (/\.qhelp$/i.test(filename)) { return "code"; } if (/\.resx$/i.test(filename)) { return "code"; } if (/\.rl$/i.test(filename)) { return "code"; } if (/\.scxml$/i.test(filename)) { return "code"; } if (/\.sed$/i.test(filename)) { return "code"; } if (/\.sgml?$/i.test(filename)) { return "code"; } if (/\.sig$/i.test(filename)) { return "code"; } if (/\.sk$/i.test(filename)) { return "code"; } if (/\.sk[12]$/i.test(filename)) { return "code"; } if (/\.sml$/i.test(filename)) { return "code"; } if (/\.smt$/i.test(filename)) { return "code"; } if (/\.smt2$/i.test(filename)) { return "code"; } if (/\.spthy$/i.test(filename)) { return "code"; } if (/\.srdf$/i.test(filename)) { return "code"; } if (/\.ssmssln$/i.test(filename)) { return "code"; } if (/\.st$/i.test(filename)) { return "code"; } if (/\.stellaris$/i.test(filename)) { return "code"; } if (/\.storyboard$/i.test(filename)) { return "code"; } if (/\.tagx$/i.test(filename)) { return "code"; } if (/\.targets$/i.test(filename)) { return "code"; } if (/\.tera$/i.test(filename)) { return "code"; } if (/\.tml$/i.test(filename)) { return "code"; } if (/\.ui$/i.test(filename)) { return "code"; } if (/\.urdf$/i.test(filename)) { return "code"; } if (/\.ux$/i.test(filename)) { return "code"; } if (/\.vxml$/i.test(filename)) { return "code"; } if (/\.webidl$/i.test(filename)) { return "code"; } if (/\.wisp$/i.test(filename)) { return "code"; } if (/\.wlp(4|ppp)$/i.test(filename)) { return "code"; } if (/\.wsdl$/i.test(filename)) { return "code"; } if (/\.wsf$/i.test(filename)) { return "code"; } if (/\.x3d$/i.test(filename)) { return "code"; } if (/\.xacro$/i.test(filename)) { return "code"; } if (/\.xib$/i.test(filename)) { return "code"; } if (/\.xlf$/i.test(filename)) { return "code"; } if (/\.xliff$/i.test(filename)) { return "code"; } if (/\.xmi$/i.test(filename)) { return "code"; } if (/\.xproj$/i.test(filename)) { return "code"; } if (/\.xsd$/i.test(filename)) { return "code"; } if (/\.xsl$/i.test(filename)) { return "code"; } if (/\.xslt$/i.test(filename)) { return "code"; } if (/\.xul$/i.test(filename)) { return "code"; } if (/\.zcml$/i.test(filename)) { return "code"; } if (/\.kid$/i.test(filename)) { return "genshi"; } if (/^xml\+(genshi|kid)$/i.test(filename)) { return "genshi"; } if (/\.gen$/i.test(filename)) { return "genstat"; } if (/\.gpi$/i.test(filename)) { return "genstat"; } if (/\.ebuild$/i.test(filename)) { return "gentoo"; } if (/\.eclass$/i.test(filename)) { return "gentoo"; } if (/\.xcf$/i.test(filename)) { return "gimp"; } if (/\.ggr$/i.test(filename)) { return "gimp"; } if (/\.gih$/i.test(filename)) { return "gimp"; } if (/\.gpl$/i.test(filename)) { return "gimp"; } if (/\.vbr$/i.test(filename)) { return "gimp"; } if (/^\.git|^\.keep$|\.(lfsconfig|mailmap)$/i.test(filename)) { return "git"; } if (/\.git(ignore|config|attributes)$/i.test(filename)) { return "git"; } if (/^(ATOM_)?COMMIT_EDITMSG$/.test(filename)) { return "git-commit"; } if (/^MERGE_(HEAD|MODE|MSG)$/.test(filename)) { return "git-merge"; } if (/^\.gitlab-ci\.yml$/.test(filename)) { return "gitlab"; } if (/^\.?gitpod\.ya?ml$/i.test(filename)) { return "gitpod"; } if (/\.glade$/i.test(filename)) { return "glade"; } if (/^glide\.ya?ml$/i.test(filename)) { return "glide"; } if (/\.gltf$/i.test(filename)) { return "gltf"; } if (/\.glf$/i.test(filename)) { return "pointwise"; } if (/\.glyphs$/i.test(filename)) { return "glyphs"; } if (/\.gn$/i.test(filename)) { return "gn"; } if (/\.gni$/i.test(filename)) { return "gn"; } if (/\.(gnu|gplv[23])$/i.test(filename)) { return "gnu"; } if (/^([AL]?GPL|GFDL)(\b|_)/.test(filename)) { return "gnu"; } if (/\.gtk/.test(filename)) { return "gnome"; } if (/\.(gp|plo?t|gnuplot)$/i.test(filename)) { return "gnuplot"; } if (/\.go$/i.test(filename)) { return "go"; } if (/\.gd$/i.test(filename)) { return "godot"; } if (/\.godot$/i.test(filename)) { return "godot"; } if (/\.tres$/i.test(filename)) { return "godot"; } if (/\.tscn$/i.test(filename)) { return "godot"; } if (/\.import$/i.test(filename)) { return "godot"; } if (/\.golo$/i.test(filename)) { return "golo"; } if (/^\.goreleaser\.ya?ml$/i.test(filename)) { return "goreleaser"; } if (/\.gs$/i.test(filename)) { return "gosu"; } if (/\.gst$/i.test(filename)) { return "gosu"; } if (/\.gsx$/i.test(filename)) { return "gosu"; } if (/\.vark$/i.test(filename)) { return "gosu"; } if (/\.gradle$/i.test(filename)) { return "gradle"; } if (/gradlew$/i.test(filename)) { return "gradle"; } if (/\.bnf$/i.test(filename)) { return "bnf"; } if (/\.abnf$/i.test(filename)) { return "bnf"; } if (/\.ebnf$/i.test(filename)) { return "bnf"; } if (/\.cddl$/i.test(filename)) { return "bnf"; } if (/\.(cf|lbnf)$/i.test(filename)) { return "bnf"; } if (/\.grammar$/i.test(filename)) { return "bnf"; } if (/\.gf$/i.test(filename)) { return "gf"; } if (/\.gcx$/i.test(filename)) { return "grapher"; } if (/\.graphql$/i.test(filename)) { return "graphql"; } if (/\.graphqls$/i.test(filename)) { return "graphql"; } if (/\.gql$/i.test(filename)) { return "graphql"; } if (/^\.graphqlrc(?:\.(?:json|js|ya?ml))?$/i.test(filename)) { return "graphql"; } if (/^graphql\.config\.js$/.test(filename)) { return "graphql"; } if (/^codegen\.(json|ya?ml)$/i.test(filename)) { return "gql-codegen"; } if (/\.gv$/i.test(filename)) { return "graphviz"; } if (/\.dot$/i.test(filename)) { return "graphviz"; } if (/\.(plantuml|[ip]uml|pu)$/i.test(filename)) { return "graphviz"; } if (/\.gvdesign$/i.test(filename)) { return "gvdesign"; } if (/^greenkeeper\.json$/i.test(filename)) { return "greenkeeper"; } if (/\bgridsome\.(config|client|server)\.[jt]s$/i.test(filename)) { return "gridsome"; } if (/\.(groovy|grt|gtpl|gsp|gvy)$/i.test(filename)) { return "groovy"; } if (/gsp$/i.test(filename)) { return "groovy"; } if (/^gruntfile.*\.([cm]?js|jsx)$/i.test(filename)) { return "grunt"; } if (/^gruntfile.*\.(lit)?coffee$/i.test(filename)) { return "grunt"; } if (/^gruntfile.*\.tsx?$/i.test(filename)) { return "grunt"; } if (/^gulpfile.*\.([cm]?js|jsx)$/i.test(filename)) { return "gulp"; } if (/^gulpfile.*\.(lit)?coffee$/i.test(filename)) { return "gulp"; } if (/^gulpfile.*\.tsx?$/i.test(filename)) { return "gulp"; } if (/\.hh$/i.test(filename)) { return "hack"; } if (/\.hhi$/i.test(filename)) { return "hack"; } if (/\.hack$/i.test(filename)) { return "hack"; } if (/\.haml$/i.test(filename)) { return "haml"; } if (/\.hamlc$/i.test(filename)) { return "haml"; } if (/\.haml\.deface$/i.test(filename)) { return "haml"; } if (/\.hb$/i.test(filename)) { return "harbour"; } if (/\.hcl$/i.test(filename)) { return "hashicorp"; } if (/\.workflow$/i.test(filename)) { return "hashicorp"; } if (/\.hs$/i.test(filename)) { return "haskell"; } if (/\.hsc$/i.test(filename)) { return "haskell"; } if (/\.c2hs$/i.test(filename)) { return "haskell"; } if (/\.lhs$/i.test(filename)) { return "haskell"; } if (/\.hs-boot$/i.test(filename)) { return "haskell"; } if (/\.hsig$/i.test(filename)) { return "haskell"; } if (/^hie\.ya?ml($|\.)/i.test(filename)) { return "hie"; } if (/\.hx([sm]l|)?$/.test(filename)) { return "haxe"; } if (/\.hxproj$/i.test(filename)) { return "haxedevelop"; } if (/^\.p4ignore$/i.test(filename)) { return "helix"; } if (/\.chm$/i.test(filename)) { return "question"; } if (/\.hlp$/i.test(filename)) { return "question"; } if (/^(Proc|Apt)file$/.test(filename)) { return "heroku"; } if (/\.buildpacks$/i.test(filename)) { return "heroku"; } if (/\.slugignore$/i.test(filename)) { return "heroku"; } if (/^\.vendor_urls$/.test(filename)) { return "heroku"; } if (/\.hpgl$/i.test(filename)) { return "hp"; } if (/\.hjson$/i.test(filename)) { return "hjson"; } if (/\.hc$/i.test(filename)) { return "templeos"; } if (/\.hc\.z$/i.test(filename)) { return "templeos"; } if (/^Brewfile$/.test(filename)) { return "brew"; } if (/\.hl$/i.test(filename)) { return "hoplon"; } if (/\.(hipnc|hip|i3d|picnc)$/i.test(filename)) { return "houdini"; } if (/\.vfl$/i.test(filename)) { return "houdini"; } if (/\.hound\.ya?ml$/i.test(filename)) { return "houndci"; } if (/\.x?html?$/i.test(filename)) { return "html5"; } if (/\.cshtml$/i.test(filename)) { return "html5"; } if (/\.gohtml$/i.test(filename)) { return "html5"; } if (/\.html\.eex$/i.test(filename)) { return "html5"; } if (/\.jsp$/i.test(filename)) { return "html5"; } if (/\.jspf$/i.test(filename)) { return "html5"; } if (/\.kit$/i.test(filename)) { return "html5"; } if (/\.isml$/i.test(filename)) { return "html5"; } if (/\.latte$/i.test(filename)) { return "html5"; } if (/\.phtml$/i.test(filename)) { return "html5"; } if (/\.shtml$/i.test(filename)) { return "html5"; } if (/\.scaml$/i.test(filename)) { return "html5"; } if (/\.swig$/i.test(filename)) { return "html5"; } if (/\.vash$/i.test(filename)) { return "html5"; } if (/\.xht$/i.test(filename)) { return "html5"; } if (/\.dtml$/i.test(filename)) { return "html5"; } if (/\.mht(ml)?$/i.test(filename)) { return "html5"; } if (/\.html?\.ecr$/i.test(filename)) { return "html5"; } if (/\.(html?\.erb(\.deface)?|rhtml)$/i.test(filename)) { return "html5"; } if (/\.huskyrc$/i.test(filename)) { return "husky"; } if (/\.huskyrc\.js$/i.test(filename)) { return "husky"; } if (/\.huskyrc\.json$/i.test(filename)) { return "husky"; } if (/\.huskyrc\.cjs$/i.test(filename)) { return "husky"; } if (/\.huskyrc\.mjs$/i.test(filename)) { return "husky"; } if (/\.huskyrc\.ya?ml$/i.test(filename)) { return "husky"; } if (/\.hy$/i.test(filename)) { return "hy"; } if (/hylang$/i.test(filename)) { return "hy"; } if (/\.ejs\.t$/i.test(filename)) { return "hygen"; } if (/^\.hyper\.[cm]?js$/i.test(filename)) { return "hyper"; } if (/\.dlm$/i.test(filename)) { return "idl"; } if (/^icomoon(\.[-\w]+)*\.json$/i.test(filename)) { return "icomoon"; } if (/\.idr$/i.test(filename)) { return "idris"; } if (/\.lidr$/i.test(filename)) { return "idris"; } if (/\.ipf$/i.test(filename)) { return "igorpro"; } if (/igor$/i.test(filename)) { return "igorpro"; } if (/\.a?png$/i.test(filename)) { return "image"; } if (/\.gif$/i.test(filename)) { return "image"; } if (/\.jpe?g$/i.test(filename)) { return "image"; } if (/\.(avif|heifs?|hif)$/i.test(filename)) { return "image"; } if (/\.ico$/i.test(filename)) { return "image"; } if (/\.webp$/i.test(filename)) { return "image"; } if (/\.bmp$/i.test(filename)) { return "image"; } if (/\.bpg$/i.test(filename)) { return "image"; } if (/\.cin$/i.test(filename)) { return "image"; } if (/\.cd5$/i.test(filename)) { return "image"; } if (/\.cgm$/i.test(filename)) { return "image"; } if (/\.cr2$/i.test(filename)) { return "image"; } if (/\.dcm$/i.test(filename)) { return "image"; } if (/\.dds$/i.test(filename)) { return "image"; } if (/\.djvu?$/i.test(filename)) { return "image"; } if (/\.dpx$/i.test(filename)) { return "image"; } if (/\.ecw$/i.test(filename)) { return "image"; } if (/\.fig$/i.test(filename)) { return "image"; } if (/\.fits?$/i.test(filename)) { return "image"; } if (/\.flif$/i.test(filename)) { return "image"; } if (/\.fts$/i.test(filename)) { return "image"; } if (/\.(gsrc|gr(emli)?n)$/i.test(filename)) { return "image"; } if (/\.hdp$/i.test(filename)) { return "image"; } if (/\.hdr$/i.test(filename)) { return "image"; } if (/\.heic$/i.test(filename)) { return "image"; } if (/\.icns$/i.test(filename)) { return "image"; } if (/\.iff$/i.test(filename)) { return "image"; } if (/\.(jp[f2xm]|j2c|mj2)$/i.test(filename)) { return "image"; } if (/\.jps$/i.test(filename)) { return "image"; } if (/\.jng$/i.test(filename)) { return "image"; } if (/\.jxr$/i.test(filename)) { return "image"; } if (/\.lbm$/i.test(filename)) { return "image"; } if (/\.liff$/i.test(filename)) { return "image"; } if (/\.mpo$/i.test(filename)) { return "image"; } if (/\.mng$/i.test(filename)) { return "image"; } if (/\.nrrd$/i.test(filename)) { return "image"; } if (/\.ora$/i.test(filename)) { return "image"; } if (/\.pcx$/i.test(filename)) { return "image"; } if (/\.pict$/i.test(filename)) { return "image"; } if (/\.pxr$/i.test(filename)) { return "image"; } if (/\.raw$/i.test(filename)) { return "image"; } if (/\.sct$/i.test(filename)) { return "image"; } if (/\.sgi$/i.test(filename)) { return "image"; } if (/\.svgz$/i.test(filename)) { return "image"; } if (/\.tga$/i.test(filename)) { return "image"; } if (/\.tiff?$/i.test(filename)) { return "image"; } if (/\.vsdx?$/i.test(filename)) { return "image"; } if (/\.wbm$/i.test(filename)) { return "image"; } if (/\.wbmp$/i.test(filename)) { return "image"; } if (/\.(wmf|emf|wmz|apm)$/i.test(filename)) { return "image"; } if (/\.wdp$/i.test(filename)) { return "image"; } if (/\.xwd$/i.test(filename)) { return "image"; } if (/\.pxm$/i.test(filename)) { return "image"; } if (/\.pxb$/i.test(filename)) { return "image"; } if (/\.pxg$/i.test(filename)) { return "image"; } if (/\.pxls$/i.test(filename)) { return "image"; } if (/\.pxs$/i.test(filename)) { return "image"; } if (/\.imba$/i.test(filename)) { return "imba"; } if (/^\.imgbotconfig$/i.test(filename)) { return "imgbot"; } if (/\.ni$/i.test(filename)) { return "inform7"; } if (/\.i7x$/i.test(filename)) { return "inform7"; } if (/\.ink$/i.test(filename)) { return "ink"; } if (/\.ink2$/i.test(filename)) { return "ink"; } if (/\.inx$/i.test(filename)) { return "inkscape"; } if (/\.iss$/i.test(filename)) { return "inno"; } if (/\.isl$/i.test(filename)) { return "inno"; } if (/\.io$/i.test(filename)) { return "io"; } if (/\.ik$/i.test(filename)) { return "ioke"; } if (/^ionic\.(project|config\.json)$/.test(filename)) { return "ionic"; } if (/\.thy$/i.test(filename)) { return "isabelle"; } if (/^ROOT$/.test(filename)) { return "isabelle"; } if (/^\.nycrc(\.json)?$/i.test(filename)) { return "istanbul"; } if (/^\.nycrc\.ya?ml$/i.test(filename)) { return "istanbul"; } if (/^nyc\.config\.js$/i.test(filename)) { return "istanbul"; } if (/^nyc\.config\.cjs$/i.test(filename)) { return "istanbul"; } if (/^nyc\.config\.mjs$/i.test(filename)) { return "istanbul"; } if (/\.ijs$/i.test(filename)) { return "j"; } if (/\.jade$/i.test(filename)) { return "jade"; } if (/^Jakefile$/.test(filename)) { return "jake"; } if (/\.jake$/i.test(filename)) { return "jake"; } if (/^\.?jasmine\.json$|^jasmine\.([-\w]+\.)?([cm]?js|ts|coffee)$/i.test(filename)) { return "jasmine"; } if (/\.java$/i.test(filename)) { return "java"; } if (/\.class$/i.test(filename)) { return "java"; } if (/\.js$/i.test(filename)) { return "js"; } if (/\._js$/i.test(filename)) { return "js"; } if (/\.jsb$/i.test(filename)) { return "js"; } if (/\.jsm$/i.test(filename)) { return "js"; } if (/\.jss$/i.test(filename)) { return "js"; } if (/\.es\d?$/i.test(filename)) { return "js"; } if (/\.cjs$/i.test(filename)) { return "js"; } if (/\.mjs$/i.test(filename)) { return "js"; } if (/\.sjs$/i.test(filename)) { return "js"; } if (/\.ssjs$/i.test(filename)) { return "js"; } if (/\.jspre$/i.test(filename)) { return "js"; } if (/\.jscript$/i.test(filename)) { return "js"; } if (/\.jse$/i.test(filename)) { return "js"; } if (/\.jslib$/i.test(filename)) { return "js"; } if (/\.xsjs$/i.test(filename)) { return "js"; } if (/\.xsjslib$/i.test(filename)) { return "js"; } if (/\.dust$/i.test(filename)) { return "js"; } if (/\.htc$/i.test(filename)) { return "js"; } if (/\.pac$/i.test(filename)) { return "js"; } if (/\.pjs$/i.test(filename)) { return "js"; } if (/\.js\.ecr$/i.test(filename)) { return "js"; } if (/\.js\.erb$/i.test(filename)) { return "js"; } if (/([\/\\])cartridge\1scripts(?:\1.+)?\1[^\\\/]+\.ds$/i.test(filename)) { return "js"; } if (/^_config\.yml$/.test(filename)) { return "jekyll"; } if (/\.nojekyll$/i.test(filename)) { return "jekyll"; } if (/^Jenkinsfile$/.test(filename)) { return "jenkins"; } if (/^jest(\.config)?(\.babel)?\.(js(on|x)?|[cm]js|tsx?)$/i.test(filename)) { return "jest"; } if (/^\.jestrc($|\.)/i.test(filename)) { return "jest"; } if (/\.(mjs|tsx?)\.snap$/i.test(filename)) { return "jest"; } if (/\.cjs\.snap$/i.test(filename)) { return "jest"; } if (/\.snap$/i.test(filename)) { return "jest"; } if (/\.jinja$/i.test(filename)) { return "jinja"; } if (/\.j(inja)?2$/i.test(filename)) { return "jinja"; } if (/\.jison$/i.test(filename)) { return "jison"; } if (/\.jisonlex$/i.test(filename)) { return "jison"; } if (/\.ol$/i.test(filename)) { return "jolie"; } if (/\.iol$/i.test(filename)) { return "jolie"; } if (/^jquery([-.](min|latest|slim|\d\.\d+(\.\d+)?))*\.([jt]sx?|es6?|coffee|map)$/i.test(filename)) { return "jquery"; } if (/^jquery([-_.](ui[-_.](custom|dialog-?\w*)|effects)(\.[^.]*)?|[-.]?ui(-\d\.\d+(\.\d+)?)?(\.\w+)?)([-_.]?min|dev)?\.([jt]sx?|es6?|coffee|map|s?css|less|styl)$/i.test(filename)) { return "jqueryui"; } if (/\.jscpd(\.json)?$|^jscpd-report\.json/i.test(filename)) { return "jscpd"; } if (/\.jscpd\.html$/i.test(filename)) { return "jscpd"; } if (/\.jscpd\.xml$/i.test(filename)) { return "jscpd"; } if (/\.(h|geo|topo)?json$/i.test(filename)) { return "json"; } if (/\.jsonc$/i.test(filename)) { return "json"; } if (/\.rsj$/i.test(filename)) { return "json"; } if (/\.json5$/i.test(filename)) { return "json5"; } if (/\.jsonld$/i.test(filename)) { return "jsonld"; } if (/\.jq$/i.test(filename)) { return "sql"; } if (/\.jsonnet$/i.test(filename)) { return "jsonnet"; } if (/\.libsonnet$/i.test(filename)) { return "jsonnet"; } if (/\.jsx$/i.test(filename)) { return "jsx"; } if (/\.jl$/i.test(filename)) { return "julia"; } if (/\.jos$/i.test(filename)) { return "junos"; } if (/\.slax$/i.test(filename)) { return "junos"; } if (/\.ipynb$/i.test(filename)) { return "jupyter"; } if (/^Notebook$/.test(filename)) { return "jupyter"; } if (/\.ksy$/i.test(filename)) { return "kaitai"; } if (/^karma\.conf(ig)?\.[cm]?js$/i.test(filename)) { return "karma"; } if (/^karma\.conf(ig)?\.coffee$/i.test(filename)) { return "karma"; } if (/^karma\.conf(ig)?\.ts$/i.test(filename)) { return "karma"; } if (/\.ks$/i.test(filename)) { return "kos"; } if (/^keybase\.txt$/i.test(filename)) { return "keybase"; } if (/\.keynote$/i.test(filename)) { return "keynote"; } if (/\.knt$/i.test(filename)) { return "keynote"; } if (/\.hypr$/i.test(filename)) { return "kibo"; } if (/\.hypr\.live$/i.test(filename)) { return "kibo"; } if (/\.kicad_pcb$/i.test(filename)) { return "kicad"; } if (/\.kicad_pcb-bak$/i.test(filename)) { return "kicad"; } if (/\.kicad_mod$/i.test(filename)) { return "kicad"; } if (/\.kicad_wks$/i.test(filename)) { return "kicad"; } if (/^fp-lib-table$/i.test(filename)) { return "kicad"; } if (/^\.?kitchen(\.[-\w]*)*\.ya?ml$/i.test(filename)) { return "kitchenci"; } if (/\.kv$/i.test(filename)) { return "kivy"; } if (/\.kml$/i.test(filename)) { return "earth"; } if (/^knockout[-.](\d+\.){3}(debug\.)?[cm]?js$/i.test(filename)) { return "knockout"; } if (/\.kt$/i.test(filename)) { return "kotlin"; } if (/\.ktm$/i.test(filename)) { return "kotlin"; } if (/\.kts$/i.test(filename)) { return "kotlin"; } if (/\.krl$/i.test(filename)) { return "krl"; } if (/^kubernetes.*\.ya?ml$/i.test(filename)) { return "kubernetes"; } if (/(^|\.)kazelcfg\.json$/i.test(filename)) { return "kubernetes"; } if (/\.(csl|kusto)$/i.test(filename)) { return "kusto"; } if (/Kusto (Query.?Language|Explorer)|^KQL$/i.test(filename)) { return "kusto"; } if (/\.lv(proj|lib)$/i.test(filename)) { return "labview"; } if (/\.blade(\.php)?$/i.test(filename)) { return "laravel"; } if (/\.lark$/i.test(filename)) { return "lark"; } if (/\.lasso$/i.test(filename)) { return "lasso"; } if (/\.las$/i.test(filename)) { return "lasso"; } if (/\.lasso8$/i.test(filename)) { return "lasso"; } if (/\.lasso9$/i.test(filename)) { return "lasso"; } if (/\.lassoapp$/i.test(filename)) { return "lasso"; } if (/\.ldml$/i.test(filename)) { return "lasso"; } if (/\.lat$/i.test(filename)) { return "latino"; } if (/^leaflet\.(draw-src|draw|spin|coordinates-(\d+\.)\d+\.\d+\.src)\.([cm]?js|css)$|^wicket-leaflet\.[cm]?js$/i.test(filename)) { return "leaflet"; } if (/\.lean$/i.test(filename)) { return "lean"; } if (/\.hlean$/i.test(filename)) { return "lean"; } if (/\.ledger$/i.test(filename)) { return "graph"; } if (/\.hledger$/i.test(filename)) { return "graph"; } if (/^lefthook(-local)?\.ya?ml$/i.test(filename)) { return "lefthook"; } if (/\.lr$/i.test(filename)) { return "lektor"; } if (/\.lektorproject$/i.test(filename)) { return "lektor"; } if (/^lerna\.json$/i.test(filename)) { return "lerna"; } if (/project\.clj$/i.test(filename)) { return "lein"; } if (/\.l(e?x)?$/i.test(filename)) { return "lex"; } if (/^lexer\.x$/i.test(filename)) { return "lex"; } if (/\.flex$/i.test(filename)) { return "lex"; } if (/\.lfe$/i.test(filename)) { return "lfe"; } if (/^\.?lgtm\.ya?ml$/i.test(filename)) { return "lgtm"; } if (/^\.?lighthouserc\.(json|js|ya?ml)$/i.test(filename)) { return "lighthouse"; } if (/\.lwo$/i.test(filename)) { return "lightwave"; } if (/\.lws$/i.test(filename)) { return "lightwave"; } if (/\.ly$/i.test(filename)) { return "lilypond"; } if (/\.ily$/i.test(filename)) { return "lilypond"; } if (/\.hxp$/i.test(filename)) { return "lime"; } if (/\.url$/i.test(filename)) { return "link"; } if (/\.lnk$/i.test(filename)) { return "link"; } if (/\.alias$/.test(filename)) { return "link"; } if (/\.linq$/i.test(filename)) { return "linqpad"; } if (/\.lisp$/i.test(filename)) { return "lisp"; } if (/\.lsp$/i.test(filename)) { return "lisp"; } if (/\.nl$/i.test(filename)) { return "lisp"; } if (/\.ny$/i.test(filename)) { return "lisp"; } if (/\.podsl$/i.test(filename)) { return "lisp"; } if (/\.sexp$/i.test(filename)) { return "lisp"; } if (/\.sbclrc$/i.test(filename)) { return "lisp"; } if (/\.ls$/i.test(filename)) { return "ls"; } if (/\._ls$/i.test(filename)) { return "ls"; } if (/^Slakefile$/.test(filename)) { return "ls"; } if (/\.ll$/i.test(filename)) { return "llvm"; } if (/\.clang-(format|tidy)$/i.test(filename)) { return "llvm"; } if (/^ubsan\.blacklist$/i.test(filename)) { return "llvm"; } if (/\.xm$/i.test(filename)) { return "mobile"; } if (/\.xi$/i.test(filename)) { return "mobile"; } if (/\.(logtalk|lgt)$/i.test(filename)) { return "logtalk"; } if (/\.lol$/i.test(filename)) { return "lolcode"; } if (/\.(lookml|lkml)$/i.test(filename)) { return "lookml"; } if (/\.lsl$/i.test(filename)) { return "lsl"; } if (/\.lslp$/i.test(filename)) { return "lsl"; } if (/\.lua$/i.test(filename)) { return "lua"; } if (/\.pd_lua$/i.test(filename)) { return "lua"; } if (/\.rbxs$/i.test(filename)) { return "lua"; } if (/\.wlua$/i.test(filename)) { return "lua"; } if (/^Lakefile$/i.test(filename)) { return "lua"; } if (/\.luacheckrc$/i.test(filename)) { return "lua"; } if (/\.rockspec$/i.test(filename)) { return "lua"; } if (/\.m2$/i.test(filename)) { return "macaulay2"; } if (/m2$/i.test(filename)) { return "macaulay2"; } if (/^Makefile/.test(filename)) { return "checklist"; } if (/^mk\.config$/.test(filename)) { return "checklist"; } if (/\.(mk|mak|make)$/i.test(filename)) { return "checklist"; } if (/^contrib\.make?([-.]|$)/i.test(filename)) { return "checklist"; } if (/^BSDmakefile$/i.test(filename)) { return "checklist"; } if (/^GNUmakefile$/i.test(filename)) { return "checklist"; } if (/^makefile\.sco$/i.test(filename)) { return "checklist"; } if (/^Kbuild$/.test(filename)) { return "checklist"; } if (/^makefile$/.test(filename)) { return "checklist"; } if (/^mkfile$/i.test(filename)) { return "checklist"; } if (/^\.?qmake$/i.test(filename)) { return "checklist"; } if (/\.am$/i.test(filename)) { return "checklist"; } if (/^DEPS$/.test(filename)) { return "checklist"; } if (/\.mms$/i.test(filename)) { return "checklist"; } if (/\.mmk$/i.test(filename)) { return "checklist"; } if (/\.pri$/i.test(filename)) { return "checklist"; } if (/^justfile$/i.test(filename)) { return "checklist"; } if (/\.eml$/i.test(filename)) { return "icon-mail"; } if (/\.mbo?x$/i.test(filename)) { return "icon-mail"; } if (/\.mak?o$/i.test(filename)) { return "mako"; } if (/\.(1([bcmstx]|has|in)?|[24568]|3(avl|bsm|cfgadm|in|[cmx]|perl|pm?|qt)?|7(d|fs|i|ipp|m|p)?|9[efps]?|eqn|groff|man|mandoc|mdoc|me|mom|nr?|nroff|roff?|tmac|tmac-u|tr|troff)$/i.test(filename)) { return "manpage"; } if (/^(man|mdoc)\.template$/i.test(filename)) { return "manpage"; } if (/\.(chem|dformat|pic)$|^grap(\.tex)?\.defines$/i.test(filename)) { return "manpage"; } if (/\.(rnh|rno|run|runoff)$/i.test(filename)) { return "manpage"; } if (/(^|\.)((troff|eqn)rc(-end)?)$/i.test(filename)) { return "manpage"; } if (/^tmac\.|^(mmn|mmt|toc\.entries)$/i.test(filename)) { return "manpage"; } if (/(^|\/)samples\/(eqn|mm|[nt]?roff|pic|tbl)\.[a-z]+$/i.test(filename)) { return "manpage"; } if (/(\\|\/)(?:man(\w+)\1[^\\\/]+\.\2|(?:tmac|eqnchar)\.d\1(?:ms\.)?[^\\\/.]+(?:\.in)?|picasso\1(?:defs\.\w+|disclaimer))$/.test(filename)) { return "manpage"; } if (/\.css\.map$/i.test(filename)) { return "sourcemap"; } if (/\.js\.map$/i.test(filename)) { return "sourcemap"; } if (/\.cjs\.map$/i.test(filename)) { return "sourcemap"; } if (/\.mjs\.map$/i.test(filename)) { return "sourcemap"; } if (/\.cidmap$/i.test(filename)) { return "sourcemap"; } if (/\.map$/i.test(filename)) { return "sourcemap"; } if (/\.mapping$/i.test(filename)) { return "sourcemap"; } if (/\.enigma$/i.test(filename)) { return "sourcemap"; } if (/\.match$/i.test(filename)) { return "sourcemap"; } if (/\.tiny$/i.test(filename)) { return "sourcemap"; } if (/\.tinyv2$/i.test(filename)) { return "sourcemap"; } if (/\.unpick$/i.test(filename)) { return "sourcemap"; } if (/\.mss$/i.test(filename)) { return "mapbox"; } if (/^Carto(CSS)?$/i.test(filename)) { return "mapbox"; } if (/\.(md(te?xt)?|mdown|markdown|mkd|mkdown|mdwn|mkdn|ron|pmd|jmd)$/i.test(filename)) { return "markdown"; } if (/^(CommonMark|GFM|Pandoc)$|\bMarkdown\b/i.test(filename)) { return "markdown"; } if (/^\.markdownlint/i.test(filename)) { return "markdownlint"; } if (/^\.?mdlrc(\.style)?\.rb$/i.test(filename)) { return "markdownlint"; } if (/^\.?mdlrc$/i.test(filename)) { return "markdownlint"; } if (/\.marko$/i.test(filename)) { return "marko"; } if (/\.marko\.[cm]?js$/i.test(filename)) { return "marko"; } if (/^materialize(\.min)?\.([cm]?js|css)$/i.test(filename)) { return "materialize"; } if (/\.mathematica$/i.test(filename)) { return "mathematica"; } if (/\.ma$/i.test(filename)) { return "mathematica"; } if (/\.mt$/i.test(filename)) { return "mathematica"; } if (/\.nb$/i.test(filename)) { return "mathematica"; } if (/\.nbp$/i.test(filename)) { return "mathematica"; } if (/^MathJax[^.]*\.[cm]?js$/i.test(filename)) { return "mathjax"; } if (/\.matlab$/i.test(filename)) { return "matlab"; } if (/\.mlappinstall$/i.test(filename)) { return "matlab"; } if (/\.mlpkginstall$/i.test(filename)) { return "matlab"; } if (/\.mltbx$/i.test(filename)) { return "matlab"; } if (/\.mdlp$/i.test(filename)) { return "matlab"; } if (/\.mn$/i.test(filename)) { return "matlab"; } if (/\.sldd$/i.test(filename)) { return "matlab"; } if (/\.slx$/i.test(filename)) { return "matlab"; } if (/\.slxp$/i.test(filename)) { return "matlab"; } if (/\.maxpat$/i.test(filename)) { return "max"; } if (/\.maxhelp$/i.test(filename)) { return "max"; } if (/\.maxproj$/i.test(filename)) { return "max"; } if (/\.mxt$/i.test(filename)) { return "max"; } if (/\.pat$/i.test(filename)) { return "max"; } if (/\.ms$/i.test(filename)) { return "maxscript"; } if (/\.mcr$/i.test(filename)) { return "maxscript"; } if (/\.mce$/i.test(filename)) { return "maxscript"; } if (/\.max$/i.test(filename)) { return "maxscript"; } if (/\.3ds$/i.test(filename)) { return "maxscript"; } if (/\.mb$/i.test(filename)) { return "maya"; } if (/\.mel$/i.test(filename)) { return "maya"; } if (/\.mcf[ip]$/i.test(filename)) { return "maya"; } if (/\.mdx$/i.test(filename)) { return "mdx"; } if (/\.mediawiki$/i.test(filename)) { return "mediawiki"; } if (/\.wiki$/i.test(filename)) { return "mediawiki"; } if (/^\.mention-bot$/i.test(filename)) { return "bullhorn"; } if (/\.hgignore$/i.test(filename)) { return "hg"; } if (/\.?hgrc$/i.test(filename)) { return "hg"; } if (/\.hgsub$/i.test(filename)) { return "hg"; } if (/\.hgsubstate$/i.test(filename)) { return "hg"; } if (/\.moo$/i.test(filename)) { return "mercury"; } if (/\.(mmd|mermaid)$/i.test(filename)) { return "mermaid"; } if (/^(meson\.build|meson_options\.txt)$/i.test(filename)) { return "meson"; } if (/\.metal$/i.test(filename)) { return "metal"; } if (/\.mp$/i.test(filename)) { return "metapost"; } if (/\.mf$/i.test(filename)) { return "metapost"; } if (/\.accda$/i.test(filename)) { return "access"; } if (/\.accdb$/i.test(filename)) { return "access"; } if (/\.accde$/i.test(filename)) { return "access"; } if (/\.accdr$/i.test(filename)) { return "access"; } if (/\.accdt$/i.test(filename)) { return "access"; } if (/\.adn$/i.test(filename)) { return "access"; } if (/\.laccdb$/i.test(filename)) { return "access"; } if (/\.mdw$/i.test(filename)) { return "access"; } if (/\.xls$/i.test(filename)) { return "excel"; } if (/\.xlsx$/i.test(filename)) { return "excel"; } if (/\.xlsm$/i.test(filename)) { return "excel"; } if (/\.xlsb$/i.test(filename)) { return "excel"; } if (/\.xlt$/i.test(filename)) { return "excel"; } if (/\.xla$/i.test(filename)) { return "excel"; } if (/\.xlam$/i.test(filename)) { return "excel"; } if (/\.xltm$/i.test(filename)) { return "excel"; } if (/\.xltx$/i.test(filename)) { return "excel"; } if (/\.(infopathxml|xsn|xsf|xtp2)$/i.test(filename)) { return "infopath"; } if (/\.o?crec$/i.test(filename)) { return "lync"; } if (/\.one$/i.test(filename)) { return "onenote"; } if (/\.pst$/i.test(filename)) { return "outlook"; } if (/\.bcmx$/i.test(filename)) { return "outlook"; } if (/\.oab$/i.test(filename)) { return "outlook"; } if (/\.otm$/i.test(filename)) { return "outlook"; } if (/\.oft$/i.test(filename)) { return "outlook"; } if (/\.nk2$/i.test(filename)) { return "outlook"; } if (/\.olk14\w*$/i.test(filename)) { return "outlook"; } if (/\.pps$/i.test(filename)) { return "powerpoint"; } if (/\.ppsx$/i.test(filename)) { return "powerpoint"; } if (/\.ppt$/i.test(filename)) { return "powerpoint"; } if (/\.pptx$/i.test(filename)) { return "powerpoint"; } if (/\.potm$/i.test(filename)) { return "powerpoint"; } if (/\.mpp$/i.test(filename)) { return "msproject"; } if (/\.mpt$/i.test(filename)) { return "msproject"; } if (/\.puz$/i.test(filename)) { return "publisher"; } if (/\.doc$/i.test(filename)) { return "word"; } if (/\.docx$/i.test(filename)) { return "word"; } if (/\.docm$/i.test(filename)) { return "word"; } if (/\.docxml$/i.test(filename)) { return "word"; } if (/\.dotm$/i.test(filename)) { return "word"; } if (/\.dotx$/i.test(filename)) { return "word"; } if (/\.wri$/i.test(filename)) { return "word"; } if (/\.wll$/i.test(filename)) { return "word"; } if (/\.vsdx$/i.test(filename)) { return "visio"; } if (/\.vdw$/i.test(filename)) { return "visio"; } if (/\.vdx$/i.test(filename)) { return "visio"; } if (/\.vsd$/i.test(filename)) { return "visio"; } if (/\.vsdm$/i.test(filename)) { return "visio"; } if (/\.vsw$/i.test(filename)) { return "visio"; } if (/\.vsx$/i.test(filename)) { return "visio"; } if (/\.vtx$/i.test(filename)) { return "visio"; } if (/\.vrd$/i.test(filename)) { return "visio"; } if (/\.vsl$/i.test(filename)) { return "visio"; } if (/\.vs[st][mx]?$/i.test(filename)) { return "visio"; } if (/^mcmod\.info$/i.test(filename)) { return "minecraft"; } if (/\.mcfunction$/i.test(filename)) { return "minecraft"; } if (/\.mclevel$/i.test(filename)) { return "minecraft"; } if (/\.mcpack$/i.test(filename)) { return "minecraft"; } if (/\.mcworld$/i.test(filename)) { return "minecraft"; } if (/^pack\.mcmeta$/i.test(filename)) { return "minecraft"; } if (/\.png\.mcmeta$/.test(filename)) { return "minecraft"; } if (/\.mzn$/i.test(filename)) { return "minizinc"; } if (/\.dzn$/i.test(filename)) { return "minizinc"; } if (/\.mint$/i.test(filename)) { return "mint"; } if (/\.dr?uby$/g.test(filename)) { return "mirah"; } if (/\.mir(ah)?$/g.test(filename)) { return "mirah"; } if (/\.m$/i.test(filename)) { return "miranda"; } if (/\.mrc$/i.test(filename)) { return "mirc"; } if (/\.mjml$/i.test(filename)) { return "mjml"; } if (/\.mjmlslim$/i.test(filename)) { return "mjml"; } if (/^\.?mkdocs\.ya?ml$/i.test(filename)) { return "book-alt"; } if (/\.mocharc\.(jsonc?|[cm]?js|ya?ml)$/i.test(filename)) { return "mocha"; } if (/^mocha(\.min)?\.([jt]sx?|es6?|coffee)$/i.test(filename)) { return "mocha"; } if (/^mocha(\.min)?\.(s?css|less|styl)$/i.test(filename)) { return "mocha"; } if (/mocha\.opts$/i.test(filename)) { return "mocha"; } if (/\.obj$/i.test(filename)) { return "model"; } if (/\.mtl$/i.test(filename)) { return "model"; } if (/\.shader$/i.test(filename)) { return "model"; } if (/\.geo(m|metry)?$/i.test(filename)) { return "model"; } if (/\.c4d$/i.test(filename)) { return "model"; } if (/\.comp$/i.test(filename)) { return "model"; } if (/\.tesc$/i.test(filename)) { return "model"; } if (/\.tese$/i.test(filename)) { return "model"; } if (/\.cginc$/i.test(filename)) { return "model"; } if (/\.dxf$/i.test(filename)) { return "model"; } if (/\.dwg$/i.test(filename)) { return "model"; } if (/\.mdl$/i.test(filename)) { return "model"; } if (/\.ply$/i.test(filename)) { return "model"; } if (/\.fnc$/i.test(filename)) { return "model"; } if (/\.stl$/i.test(filename)) { return "model"; } if (/\.u3d$/i.test(filename)) { return "model"; } if (/\.(rviz|vcg)$/i.test(filename)) { return "model"; } if (/\.(ste?p|p21)$/i.test(filename)) { return "model"; } if (/\.x$/i.test(filename)) { return "model"; } if (/\.mo$/i.test(filename)) { return "modelica"; } if (/^\.?modernizr(rc)?\.[cm]?js$|^modernizr([-\.]custom|-\d\.\d+)(\.\d+)?\.[cm]?js$/i.test(filename)) { return "modernizr"; } if (/^web-(dev-server|test-runner)\.config\.([cm]?js)$/i.test(filename)) { return "modernweb"; } if (/\.lxo$/i.test(filename)) { return "modo"; } if (/\.mod$/i.test(filename)) { return "modula2"; } if (/\.def$/i.test(filename)) { return "modula2"; } if (/\.i3$/i.test(filename)) { return "modula3"; } if (/\.ig$/i.test(filename)) { return "modula3"; } if (/\.m3$/i.test(filename)) { return "modula3"; } if (/\.mg$/i.test(filename)) { return "modula3"; } if (/^m3(makefile|overrides)$/i.test(filename)) { return "modula3"; } if (/\.moho$/i.test(filename)) { return "moho"; } if (/\.mohoaction$/i.test(filename)) { return "moho"; } if (/\.mohobrush$/i.test(filename)) { return "moho"; } if (/\.mohoexport$/i.test(filename)) { return "moho"; } if (/\.mohoproj$/i.test(filename)) { return "moho"; } if (/\.mohostyle$/i.test(filename)) { return "moho"; } if (/^moleculer\.config\.([cm]?js|json|ts)$/i.test(filename)) { return "moleculer"; } if (/^moment(-with-locales)?(\.min)?\.[cm]?js$/i.test(filename)) { return "moment"; } if (/^moment-timezone(-with-data)?(-\d{4}-\d{4})?(\.min)?\.[cm]?js$/i.test(filename)) { return "moment-tz"; } if (/\.monkey$/i.test(filename)) { return "monkey"; } if (/\.mtn-ignore$/i.test(filename)) { return "monotone"; } if (/\.moon$/i.test(filename)) { return "moon"; } if (/^mootools[^.]*\d+\.\d+(\.\d+)?[^.]*\.[cm]?js$/i.test(filename)) { return "mootools"; } if (/\.mrb$/i.test(filename)) { return "mruby"; } if (/\.dsql$/i.test(filename)) { return "msql"; } if (/\.mu$/i.test(filename)) { return "mupad"; } if (/\.chord$/i.test(filename)) { return "music"; } if (/\.midi?$/i.test(filename)) { return "music"; } if (/\.pd$/i.test(filename)) { return "music"; } if (/\.(hb[st]|handlebars|(mu)?stache)$/i.test(filename)) { return "mustache"; } if (/^(hbs|htmlbars|handlebars)$/i.test(filename)) { return "mustache"; } if (/\.nanorc$/i.test(filename)) { return "nano"; } if (/^\.?nanoc\.ya?ml$/i.test(filename)) { return "nanoc"; } if (/\.build$/i.test(filename)) { return "nant"; } if (/\.nasm$/i.test(filename)) { return "nasm"; } if (/\.ncl$/i.test(filename)) { return "earth"; } if (/\.neon$/i.test(filename)) { return "neon"; } if (/\.nd?proj$/i.test(filename)) { return "ndepend"; } if (/\.neko$/i.test(filename)) { return "neko"; } if (/^run\.n$/.test(filename)) { return "neko"; } if (/\.cyp(her)?$/i.test(filename)) { return "neo4j"; } if (/\.nasl$/i.test(filename)) { return "nessus"; } if (/\.axs$/i.test(filename)) { return "amx"; } if (/\.axi$/i.test(filename)) { return "amx"; } if (/\.nlogo$/i.test(filename)) { return "netlogo"; } if (/^netlify\.toml$/i.test(filename)) { return "netlify"; } if (/^newrelic\.yml/i.test(filename)) { return "newrelic"; } if (/\.nf$/i.test(filename)) { return "nextflow"; } if (/^nextflow\.config$/i.test(filename)) { return "nextflow"; } if (/^next\.config\.[cm]?js$/i.test(filename)) { return "nextjs"; } if (/^nestconfig\.json$/i.test(filename)) { return "nestjs"; } if (/\.pbm$/i.test(filename)) { return "image"; } if (/\.pgm$/i.test(filename)) { return "image"; } if (/\.ppm$/i.test(filename)) { return "image"; } if (/\.pnm$/i.test(filename)) { return "image"; } if (/^nginx(\.[-\w]+)*\.conf$/i.test(filename)) { return "nginx"; } if (/\.nginx(conf)?$/i.test(filename)) { return "nginx"; } if (/\.nib$/i.test(filename)) { return "nib"; } if (/\.5c$/i.test(filename)) { return "nickle"; } if (/^nightwatch\.conf(ig)?\.[cm]?js$/i.test(filename)) { return "nightwatch"; } if (/\.nim(rod)?$/i.test(filename)) { return "nimrod"; } if (/Nimrod$/i.test(filename)) { return "nimrod"; } if (/\.nimble$/i.test(filename)) { return "nimble"; } if (/\.ninja$/i.test(filename)) { return "shuriken"; } if (/\.ninja\.d$/i.test(filename)) { return "shuriken"; } if (/\.n64$/i.test(filename)) { return "n64"; } if (/\.z64$/i.test(filename)) { return "n64"; } if (/\.nit$/i.test(filename)) { return "nit"; } if (/\.nix$/i.test(filename)) { return "nix"; } if (/nixos$/i.test(filename)) { return "nix"; } if (/\.nse$/i.test(filename)) { return "nmap"; } if (/\.njs$/i.test(filename)) { return "node"; } if (/\.nvmrc$/i.test(filename)) { return "node"; } if (/\.node$/i.test(filename)) { return "node"; } if (/\.node-version$/i.test(filename)) { return "node"; } if (/^BUNDLED_NODE_VERSION$/.test(filename)) { return "node"; } if (/\.node_repl_history$/i.test(filename)) { return "node"; } if (/^nodemon\.json$|\.nodemonignore$/i.test(filename)) { return "nodemon"; } if (/^\.?nokogirirc($|\.)/i.test(filename)) { return "nokogiri"; } if (/\.nomad$/i.test(filename)) { return "nomad"; } if (/\.noon$/i.test(filename)) { return "noon"; } if (/^normalize(\.min)?\.(css|less|scss|styl)$/i.test(filename)) { return "normalize"; } if (/^(package\.json|\.npmignore|\.?npmrc|npm-debug\.log|npm-shrinkwrap\.json|package-lock\.json)$/i.test(filename)) { return "npm"; } if (/\.nsi$/i.test(filename)) { return "nsis"; } if (/\.nsh$/i.test(filename)) { return "nsis"; } if (/^\.nsrirc(\.(json|(config\.)?[cm]?js|ya?ml))?$/i.test(filename)) { return "nsri"; } if (/^\.nsriignore(\.(json|(config\.)?[cm]?js|ya?ml))?$/i.test(filename)) { return "nsri"; } if (/\.integrity\.json$/i.test(filename)) { return "nsri-alt"; } if (/\.nu$/i.test(filename)) { return "recycle"; } if (/^Nukefile$/.test(filename)) { return "recycle"; } if (/\.nuspec$/i.test(filename)) { return "nuget"; } if (/\.nupkg$/i.test(filename)) { return "nuget"; } if (/\.pkgproj$/i.test(filename)) { return "nuget"; } if (/\.snupkg$/i.test(filename)) { return "nuget"; } if (/\.psmdcp$/i.test(filename)) { return "nuget"; } if (/\.npy$/i.test(filename)) { return "numpy"; } if (/\.npz$/i.test(filename)) { return "numpy"; } if (/\.numpy$/i.test(filename)) { return "numpy"; } if (/\.numpyw$/i.test(filename)) { return "numpy"; } if (/\.numsc$/i.test(filename)) { return "numpy"; } if (/\.(nunjucks|njk)$/i.test(filename)) { return "nunjucks"; } if (/^nuxt\.config\.[jt]s$/i.test(filename)) { return "nuxt"; } if (/\.nss$/i.test(filename)) { return "nwscript"; } if (/\.ncs$/i.test(filename)) { return "nwscript"; } if (/\.ndb$/i.test(filename)) { return "nwscript"; } if (/^nx\.json$/i.test(filename)) { return "nx"; } if (/\.nxc$/i.test(filename)) { return "nxc"; } if (/\.ob2$/i.test(filename)) { return "oberon"; } if (/\.mm?$/i.test(filename)) { return "objc"; } if (/\.pch$/i.test(filename)) { return "objc"; } if (/\.x$/i.test(filename)) { return "objc"; } if (/\.j$/i.test(filename)) { return "objj"; } if (/\.sj$/i.test(filename)) { return "objj"; } if (/\.ml$/i.test(filename)) { return "ocaml"; } if (/\.mli$/i.test(filename)) { return "ocaml"; } if (/\.eliom$/i.test(filename)) { return "ocaml"; } if (/\.eliomi$/i.test(filename)) { return "ocaml"; } if (/\.ml4$/i.test(filename)) { return "ocaml"; } if (/\.mll$/i.test(filename)) { return "ocaml"; } if (/\.mly$/i.test(filename)) { return "ocaml"; } if (/\.octave$/i.test(filename)) { return "octave"; } if (/\.octave_hist$/i.test(filename)) { return "octave"; } if (/\.octaverc$/i.test(filename)) { return "octave"; } if (/\.odin$/i.test(filename)) { return "odin"; } if (/\.graffle$/i.test(filename)) { return "omnigraffle"; } if (/\.gdiagramstyle$/i.test(filename)) { return "omnigraffle"; } if (/\.gstencil$/i.test(filename)) { return "omnigraffle"; } if (/\.gtemplate$/i.test(filename)) { return "omnigraffle"; } if (/\.(o3|ogone)$/i.test(filename)) { return "ogone"; } if (/\.ooc$/i.test(filename)) { return "ooc"; } if (/\.opa$/i.test(filename)) { return "opa"; } if (/^\+(CONTENTS|DESC|DISPLAY)$/.test(filename)) { return "openbsd"; } if (/\.opencl$/i.test(filename)) { return "opencl"; } if (/\.(p|abl)$/i.test(filename)) { return "progress"; } if (/^(progress|openedge|abl)$/i.test(filename)) { return "progress"; } if (/\.exr$/i.test(filename)) { return "openexr"; } if (/\.(glslv?|gsh|gshader)$/i.test(filename)) { return "opengl"; } if (/^(GLSL|GLslang)$/i.test(filename)) { return "opengl"; } if (/\.(vert|vrx|vertex|vsh(ader)?)$/i.test(filename)) { return "vertex"; } if (/\.(fra?g|fp|fsh|fshader)$/i.test(filename)) { return "vertex"; } if (/\.odt$/i.test(filename)) { return "openoffice"; } if (/\.ott$/i.test(filename)) { return "openoffice"; } if (/\.fodt$/i.test(filename)) { return "openoffice"; } if (/\.ods$/i.test(filename)) { return "openoffice"; } if (/\.ots$/i.test(filename)) { return "openoffice"; } if (/\.fods$/i.test(filename)) { return "openoffice"; } if (/\.odp$/i.test(filename)) { return "openoffice"; } if (/\.otp$/i.test(filename)) { return "openoffice"; } if (/\.fodp$/i.test(filename)) { return "openoffice"; } if (/\.odg$/i.test(filename)) { return "openoffice"; } if (/\.otg$/i.test(filename)) { return "openoffice"; } if (/\.fodg$/i.test(filename)) { return "openoffice"; } if (/\.odf$/i.test(filename)) { return "openoffice"; } if (/\.odb$/i.test(filename)) { return "openoffice"; } if (/\.rego$/i.test(filename)) { return "openpolicy"; } if (/\.scad$/i.test(filename)) { return "scad"; } if (/\.jscad$/i.test(filename)) { return "scad"; } if (/\.hlb$/i.test(filename)) { return "openvms"; } if (/\.cld$/i.test(filename)) { return "openvms"; } if (/\.com$/i.test(filename)) { return "openvms"; } if (/\.ovpn$/i.test(filename)) { return "openvpn"; } if (/^vdev\d+$/.test(filename)) { return "openzfs"; } if (/\.org$/i.test(filename)) { return "org"; } if (/\.dmg$/i.test(filename)) { return "osx"; } if (/\.ox$/i.test(filename)) { return "ox"; } if (/\.oxh$/i.test(filename)) { return "ox"; } if (/\.oxo$/i.test(filename)) { return "ox"; } if (/\.oxygene$/i.test(filename)) { return "oxygene"; } if (/\.oz$/i.test(filename)) { return "oz"; } if (/\.p4$/i.test(filename)) { return "p4"; } if (/Cargo\.toml$/i.test(filename)) { return "package"; } if (/Cargo\.lock$/i.test(filename)) { return "package"; } if (/\.packages$/i.test(filename)) { return "package"; } if (/^pubspec\.lock$/i.test(filename)) { return "package"; } if (/^pubspec\.ya?ml$/i.test(filename)) { return "package"; } if (/^paket\.(dependencies|lock|references|local|template)$/i.test(filename)) { return "package"; } if (/\.pan$/i.test(filename)) { return "pan"; } if (/\.psc$/i.test(filename)) { return "papyrus"; } if (/\.parrot$/i.test(filename)) { return "parrot"; } if (/\.pasm$/i.test(filename)) { return "parrot"; } if (/\.pir$/i.test(filename)) { return "parrot"; } if (/\.pas(cal)?$/i.test(filename)) { return "pascal"; } if (/\.lpr$/i.test(filename)) { return "pascal"; } if (/\.lfm$/i.test(filename)) { return "pascal"; } if (/\.lps$/i.test(filename)) { return "pascal"; } if (/\.lpi$/i.test(filename)) { return "pascal"; } if (/\.lpk$/i.test(filename)) { return "pascal"; } if (/\.lrs$/i.test(filename)) { return "pascal"; } if (/\.lrt$/i.test(filename)) { return "pascal"; } if (/\.or$/i.test(filename)) { return "pascal"; } if (/\.ppu$/i.test(filename)) { return "pascal"; } if (/\.patch$/i.test(filename)) { return "patch"; } if (/^PATR(ONS|EON)\.md$/.test(filename)) { return "patreon"; } if (/\.pwn$/i.test(filename)) { return "pawn"; } if (/\.pcd$/i.test(filename)) { return "pcd"; } if (/\.pdf$/i.test(filename)) { return "icon-file-pdf"; } if (/\.(pegjs|peggy)$/i.test(filename)) { return "peg"; } if (/\.pegcoffee$/i.test(filename)) { return "peg"; } if (/\.p(er)?l$/i.test(filename)) { return "perl"; } if (/\.al$/i.test(filename)) { return "perl"; } if (/\.ph$/i.test(filename)) { return "perl"; } if (/\.plx$/i.test(filename)) { return "perl"; } if (/\.pm$/i.test(filename)) { return "perl"; } if (/\.(psgi|xs)$/i.test(filename)) { return "perl"; } if (/\.volt$/i.test(filename)) { return "phalcon"; } if (/\.php([st\d]|_cs)?$/i.test(filename)) { return "php"; } if (/^Phakefile/.test(filename)) { return "php"; } if (/\.engine$/i.test(filename)) { return "php"; } if (/\.phar$/i.test(filename)) { return "php"; } if (/^phpunit\.xml$/i.test(filename)) { return "phpunit"; } if (/^phoenix\.ex$/i.test(filename)) { return "phoenix"; } if (/^phoenix\.[cm]?js$/i.test(filename)) { return "phoenix"; } if (/^\.photorec\.cfg$/i.test(filename)) { return "photorec"; } if (/^\.phraseapp\.ya?ml$/i.test(filename)) { return "phraseapp"; } if (/\.(pkl|pickle)$/i.test(filename)) { return "pickle"; } if (/\.p8$/i.test(filename)) { return "pico8"; } if (/^pico\W8$/i.test(filename)) { return "pico8"; } if (/\.l$/i.test(filename)) { return "picolisp"; } if (/^Pipfile(\.lock)?$/i.test(filename)) { return "pipenv"; } if (/\.pike$/i.test(filename)) { return "pike"; } if (/\.pmod$/i.test(filename)) { return "pike"; } if (/\.pine$/i.test(filename)) { return "pinescript"; } if (/^platformio\.ini$/i.test(filename)) { return "platformio"; } if (/\.pls$/i.test(filename)) { return "sql"; } if (/\.pck$/i.test(filename)) { return "sql"; } if (/\.pks$/i.test(filename)) { return "sql"; } if (/\.plb$/i.test(filename)) { return "sql"; } if (/\.plsql$/i.test(filename)) { return "sql"; } if (/\.pkb$/i.test(filename)) { return "sql"; } if (/^ecosystem\.conf(ig)?\./i.test(filename)) { return "pm2"; } if (/^pnpm-(lock|workspace)\.ya?ml$/i.test(filename)) { return "pnpm"; } if (/^pnpmfile\.js$/i.test(filename)) { return "pnpm"; } if (/\.pod$/i.test(filename)) { return "pod"; } if (/\.pogo$/i.test(filename)) { return "pogo"; } if (/^polymer\.json$/i.test(filename)) { return "polymer"; } if (/\.pony$/i.test(filename)) { return "pony"; } if (/\.p(ost)?css$/i.test(filename)) { return "postcss"; } if (/\.sss$/i.test(filename)) { return "postcss"; } if (/\.postcssrc(\.([cm]?js|json|ya?ml))?$/i.test(filename)) { return "postcss"; } if (/\bpostcss\.config\.[cm]?js$/i.test(filename)) { return "postcss"; } if (/\.pgsql$/i.test(filename)) { return "pgsql"; } if (/PL\/pgSQL$/i.test(filename)) { return "pgsql"; } if (/\.ps$/i.test(filename)) { return "postscript"; } if (/\.eps$/i.test(filename)) { return "postscript"; } if (/\.pfa$/i.test(filename)) { return "postscript"; } if (/\.bez$/i.test(filename)) { return "postscript"; } if (/^fontinfo$/i.test(filename)) { return "postscript"; } if (/\.a[fm]m$/i.test(filename)) { return "postscript"; } if (/\/Resource\/[A-Z]\w+\/[^\/]+$|(^|\/)(cidfmap|xlatmap|PPI_CUtils|Pscript5Idiom)$/i.test(filename)) { return "postscript"; } if (/\.eps[fi]$/i.test(filename)) { return "postscript"; } if (/^Fontmap(\.GS)?$/i.test(filename)) { return "postscript"; } if (/\.gsf$/i.test(filename)) { return "postscript"; } if (/\.pov$/i.test(filename)) { return "povray"; } if (/\.pbl$/i.test(filename)) { return "powerbuilder"; } if (/\.pbt$/i.test(filename)) { return "powerbuilder"; } if (/\.srw$/i.test(filename)) { return "powerbuilder"; } if (/\.sru$/i.test(filename)) { return "powerbuilder"; } if (/\.srp$/i.test(filename)) { return "powerbuilder"; } if (/\.sra$/i.test(filename)) { return "powerbuilder"; } if (/\.srj$/i.test(filename)) { return "powerbuilder"; } if (/\.ps1$/i.test(filename)) { return "powershell"; } if (/\.psd1$/i.test(filename)) { return "powershell"; } if (/\.psm1$/i.test(filename)) { return "powershell"; } if (/\.ps1xml$/i.test(filename)) { return "powershell"; } if (/^\.pre-commit\b.*\.ya?ml$/i.test(filename)) { return "precommit"; } if (/\.prettierrc(\.([cm]?js|json5?|ya?ml))?$|^prettier\.config\.[cm]?js$/i.test(filename)) { return "prettier"; } if (/\.prettierignore$/i.test(filename)) { return "prettier"; } if (/\.ppd$/i.test(filename)) { return "print"; } if (/\.upp$/i.test(filename)) { return "print"; } if (/\.joboptions$/i.test(filename)) { return "print"; } if (/\.prisma$/i.test(filename)) { return "prisma"; } if (/^project\.pros$/i.test(filename)) { return "pros"; } if (/\.pde$/i.test(filename)) { return "processing"; } if (/\.pro$/i.test(filename)) { return "prolog"; } if (/\.prolog$/i.test(filename)) { return "prolog"; } if (/\.yap$/i.test(filename)) { return "prolog"; } if (/\.spin$/i.test(filename)) { return "propeller"; } if (/\.proselintrc$/i.test(filename)) { return "proselint"; } if (/^protractor\.(conf|config)\./i.test(filename)) { return "protractor"; } if (/\.pug$/i.test(filename)) { return "pug"; } if (/^\.pug-lintrc/i.test(filename)) { return "pug"; } if (/^\.?pullapprove\.ya?ml$/i.test(filename)) { return "pullapprove"; } if (/\.pp$/i.test(filename)) { return "puppet"; } if (/\.epp$/i.test(filename)) { return "puppet"; } if (/Modulefile$/i.test(filename)) { return "puppet"; } if (/\.pure$/i.test(filename)) { return "pure"; } if (/\.pb$/i.test(filename)) { return "purebasic"; } if (/\.pbi$/i.test(filename)) { return "purebasic"; } if (/\.purs$/i.test(filename)) { return "purescript"; } if (/^((dev|docs?|tests?)[-_]requirements|requirements([-_](dev|docs?|tests?))?)\.(in|txt)$/i.test(filename)) { return "pypi"; } if (/\.arr$/i.test(filename)) { return "pyret"; } if (/^pytest\.ini$/.test(filename)) { return "pytest"; } if (/\.py$/i.test(filename)) { return "python"; } if (/\.ipy$/i.test(filename)) { return "python"; } if (/\.isolate$/i.test(filename)) { return "python"; } if (/\.pep$/i.test(filename)) { return "python"; } if (/\.gyp$/i.test(filename)) { return "python"; } if (/\.gypi$/i.test(filename)) { return "python"; } if (/\.pyde$/i.test(filename)) { return "python"; } if (/\.pyp$/i.test(filename)) { return "python"; } if (/\.pyt$/i.test(filename)) { return "python"; } if (/\.py3$/i.test(filename)) { return "python"; } if (/\.pyi$/i.test(filename)) { return "python"; } if (/\.pyw$/i.test(filename)) { return "python"; } if (/\.pyz$/i.test(filename)) { return "python"; } if (/\.tac$/i.test(filename)) { return "python"; } if (/\.wsgi$/i.test(filename)) { return "python"; } if (/\.xpy$/i.test(filename)) { return "python"; } if (/\.smk$/i.test(filename)) { return "python"; } if (/\.rpy$/i.test(filename)) { return "python"; } if (/^py\.typed$/i.test(filename)) { return "python"; } if (/\.?(pypirc|pythonrc|python-venv)$/i.test(filename)) { return "python"; } if (/^(SConstruct|SConscript)$/.test(filename)) { return "python"; } if (/^(Snakefile|WATCHLISTS)$/.test(filename)) { return "python"; } if (/^wscript$/.test(filename)) { return "python"; } if (/^\.pyup(\.ya?ml)?$/i.test(filename)) { return "pyup"; } if (/\.q$/i.test(filename)) { return "kx"; } if (/\.k$/i.test(filename)) { return "kx"; } if (/\.qs$/i.test(filename)) { return "qsharp"; } if (/qsharp$/i.test(filename)) { return "qsharp"; } if (/\.qasm$/i.test(filename)) { return "qiskit"; } if (/OpenQASM$/i.test(filename)) { return "qiskit"; } if (/\.qvw$/i.test(filename)) { return "qlik"; } if (/\.qvd$/i.test(filename)) { return "qlik"; } if (/\.qml$/i.test(filename)) { return "qt"; } if (/\.qmlproject$/i.test(filename)) { return "qt"; } if (/\.qbs$/i.test(filename)) { return "qt"; } if (/^(toolchain_)?installscript\.qs$/i.test(filename)) { return "qt"; } if (/^quasar\.conf\.[cm]?js$/i.test(filename)) { return "quasar"; } if (/\.(r|Rprofile|Rhistory|rsx|rd)$/i.test(filename)) { return "r"; } if (/^(Rscript|splus|Rlang)$/i.test(filename)) { return "r"; } if (/\.rkt$/i.test(filename)) { return "racket"; } if (/\.rktd$/i.test(filename)) { return "racket"; } if (/\.rktl$/i.test(filename)) { return "racket"; } if (/\.scrbl$/i.test(filename)) { return "racket"; } if (/\.pl6$/i.test(filename)) { return "perl6"; } if (/\.[tp]6$|\.6pl$/i.test(filename)) { return "perl6"; } if (/\.(pm6|p6m)$/i.test(filename)) { return "perl6"; } if (/\.6pm$/i.test(filename)) { return "perl6"; } if (/\.nqp$/i.test(filename)) { return "perl6"; } if (/\.p6l$/i.test(filename)) { return "perl6"; } if (/\.pod6$/i.test(filename)) { return "perl6"; } if (/\.raku$/i.test(filename)) { return "perl6"; } if (/\.rakumod$/i.test(filename)) { return "perl6"; } if (/\.rakutest$/i.test(filename)) { return "perl6"; } if (/^Rexfile$/.test(filename)) { return "perl6"; } if (/\.raml$/i.test(filename)) { return "raml"; } if (/^raphael(\.min|\.no-deps)*\.[cm]?js$/i.test(filename)) { return "raphael"; } if (/\.rsc$/i.test(filename)) { return "rascal"; } if (/^razzle\.config\./i.test(filename)) { return "razzle"; } if (/^\.?readthedocs\.ya?ml$/i.test(filename)) { return "readthedocs"; } if (/^\.rehyperc(\.([cm]?js|json|ya?ml))?$/i.test(filename)) { return "remark"; } if (/^\.remarkrc(\.([cm]?js|json|ya?ml))?$/i.test(filename)) { return "remark"; } if (/^\.retextrc(\.([cm]?js|json|ya?ml))?$/i.test(filename)) { return "remark"; } if (/\.rehypeignore$/i.test(filename)) { return "remark"; } if (/\.remarkignore$/i.test(filename)) { return "remark"; } if (/\.retextignore$/i.test(filename)) { return "remark"; } if (/\.r(est)?ql$/i.test(filename)) { return "restql"; } if (/^restql\.ya?ml$/i.test(filename)) { return "restql"; } if (/\.Rdata$/i.test(filename)) { return "rdata"; } if (/\.rdb$/i.test(filename)) { return "rdata"; } if (/\.rds$/i.test(filename)) { return "rdata"; } if (/\.rdx$/i.test(filename)) { return "rdata"; } if (/\.rdoc$/i.test(filename)) { return "rdoc"; } if (/^react(-[^.]*)?\.[cm]?js$/i.test(filename)) { return "react"; } if (/\.react\.[cm]?js$/i.test(filename)) { return "react"; } if (/^README(\b|_)|^((un)?licen[sc]es?(\.mysql)?|(read|readme|click|delete|keep|test)\.me)(\.(md|txt))?$|\.(readme|1st|licen[sc]es?)$/i.test(filename)) { return "book"; } if (/^(notice|bugs|changes|change[-_]?log([-._]?\d+)?|contribute|contributing|contributors|copy(ing|right)(\.regex)?|faq|fixes|hacking|history|install|maintainers|manifest|more\.stuff|notes|problems|projects|revision|terms|thanks|warnings)(_\w+)?$/i.test(filename)) { return "book"; } if (/\b(changelog|copying(v?\d)?|install|notes?|notices?|read[-_]?me)\b|^licen[sc]es?[-._]/i.test(filename)) { return "book"; } if (/^(news|release[-_.]?notes)([-_.]?[-\d]+)?$/i.test(filename)) { return "book"; } if (/^zork\d\.(?!pre$|pur$)[a-z]+$/.test(filename)) { return "book"; } if (/^zork\d\.doc$/.test(filename)) { return "book"; } if (/^sudo[-_]lecture$/i.test(filename)) { return "book"; } if (/\.changes$/i.test(filename)) { return "book"; } if (/\.journal$/i.test(filename)) { return "book"; } if (/\.faq$/i.test(filename)) { return "book"; } if (/\.yo$/i.test(filename)) { return "book"; } if (/\.rbbas$/i.test(filename)) { return "xojo"; } if (/\.rbfrm$/i.test(filename)) { return "xojo"; } if (/\.rbmnu$/i.test(filename)) { return "xojo"; } if (/\.rbres$/i.test(filename)) { return "xojo"; } if (/\.rbtbar$/i.test(filename)) { return "xojo"; } if (/\.rbuistate$/i.test(filename)) { return "xojo"; } if (/\.re$/i.test(filename)) { return "reason"; } if (/\.rei$/i.test(filename)) { return "reason"; } if (/\.reason$/i.test(filename)) { return "reasonstudios"; } if (/\.rns$/i.test(filename)) { return "reasonstudios"; } if (/\.rsn$/i.test(filename)) { return "reasonstudios"; } if (/\.rx2$/i.test(filename)) { return "reasonstudios"; } if (/\.sxt$/i.test(filename)) { return "reasonstudios"; } if (/\.reb(ol)?$/i.test(filename)) { return "rebol"; } if (/\.r2$/i.test(filename)) { return "rebol"; } if (/\.r3$/i.test(filename)) { return "rebol"; } if (/\.red$/i.test(filename)) { return "red"; } if (/\.reds$/i.test(filename)) { return "red"; } if (/\.rpm(macros)?$/i.test(filename)) { return "red-hat"; } if (/\.spec$/i.test(filename)) { return "red-hat"; } if (/\.reek$/i.test(filename)) { return "reek"; } if (/\.regexp?$/i.test(filename)) { return "regex"; } if (/(?!^renovate$)(\.|^)renovate(rc)?(\.json)?$/i.test(filename)) { return "renovate"; } if (/^require([-.]min|dev)?\.[cm]?js$/i.test(filename)) { return "requirejs"; } if (/\.resi$/i.test(filename)) { return "rescript"; } if (/\.re?st(\.txt)?$/i.test(filename)) { return "rst"; } if (/^re?st$/i.test(filename)) { return "rst"; } if (/\.rexx?$/i.test(filename)) { return "rexx"; } if (/\.pprx$/i.test(filename)) { return "rexx"; } if (/\.3dm$/i.test(filename)) { return "rhino"; } if (/\.rvb$/i.test(filename)) { return "rhino"; } if (/^riemann\.config$/i.test(filename)) { return "clojure"; } if (/\.ring$/i.test(filename)) { return "ring"; } if (/\.tag$/i.test(filename)) { return "riot"; } if (/\.(rmd|rmarkdown)$/i.test(filename)) { return "rmarkdown"; } if (/\.robot$/i.test(filename)) { return "robot"; } if (/^robots\.txt$/i.test(filename)) { return "robots"; } if (/^rollup\.config\./i.test(filename)) { return "rollup"; } if (/\.rg$/i.test(filename)) { return "clojure"; } if (/\.rspec$/i.test(filename)) { return "rspec"; } if (/\.rss$/i.test(filename)) { return "rss"; } if (/\.rproj$/i.test(filename)) { return "rstudio"; } if (/^rsyncd\.conf$/i.test(filename)) { return "rsync"; } if (/\.(rb|ru|ruby|erb|god|mspec|pluginspec|podspec|rabl|rake|opal)$/i.test(filename)) { return "ruby"; } if (/^\.?(irbrc|gemrc|pryrc|ruby-(gemset|version))$/i.test(filename)) { return "ruby"; } if (/^(Appraisals|(Rake|App|[bB]uild|Cap|Danger|Deliver|Fast|Guard|Jar|Maven|Pod|Puppet|Snap)file(\.lock)?)$/.test(filename)) { return "ruby"; } if (/\.(jbuilder|rbuild|rb[wx]|builder)$/i.test(filename)) { return "ruby"; } if (/^rails$/.test(filename)) { return "ruby"; } if (/\.watchr$/i.test(filename)) { return "ruby"; } if (/^\.rubocop(_todo)?\.ya?ml$/i.test(filename)) { return "rubocop"; } if (/\.gemspec$/i.test(filename)) { return "rubygems"; } if (/\.rs$/i.test(filename)) { return "rust"; } if (/\.rlib$/i.test(filename)) { return "rust"; } if (/^rust-toolchain$/.test(filename)) { return "rust"; } if (/\.sac$/i.test(filename)) { return "sac"; } if (/\.san$/i.test(filename)) { return "san"; } if (/\.webarchive$/i.test(filename)) { return "safari"; } if (/\.sage$/i.test(filename)) { return "sage"; } if (/\.sagews$/i.test(filename)) { return "sage"; } if (/^\.sailsrc$/i.test(filename)) { return "sails"; } if (/\.sls$/i.test(filename)) { return "saltstack"; } if (/^Salt(State)?$/i.test(filename)) { return "saltstack"; } if (/\.sb$/i.test(filename)) { return "sandbox"; } if (/^(Sandbox Profile Language|SBPL)$/i.test(filename)) { return "sandbox"; } if (/\.sas$/i.test(filename)) { return "sas"; } if (/\.scss$/i.test(filename)) { return "sass"; } if (/\.sass$/i.test(filename)) { return "sass"; } if (/^\.sassrc(\.[cm]?js)?$/i.test(filename)) { return "sass"; } if (/\.sbt$/i.test(filename)) { return "sbt"; } if (/\.(sc|scala)$/i.test(filename)) { return "scala"; } if (/\.kojo$/i.test(filename)) { return "scala"; } if (/\.scm$/i.test(filename)) { return "scheme"; } if (/\.sld$/i.test(filename)) { return "scheme"; } if (/\.sps$/i.test(filename)) { return "scheme"; } if (/\.xtm$/i.test(filename)) { return "scheme"; } if (/\.scilla$/i.test(filename)) { return "scilla"; } if (/\.sci$/i.test(filename)) { return "scilab"; } if (/\.sce$/i.test(filename)) { return "scilab"; } if (/\.tst$/i.test(filename)) { return "scilab"; } if (/\.sb2$/i.test(filename)) { return "scratch"; } if (/\.sb3$/i.test(filename)) { return "scratch"; } if (/\.scrutinizer\.yml$/i.test(filename)) { return "scrutinizer"; } if (/\.secret$/i.test(filename)) { return "secret"; } if (/\.self$/i.test(filename)) { return "self"; } if (/^\.releaserc(\.(ya?ml|[cm]?js|json))?$/i.test(filename)) { return "semrelease"; } if (/^sencha(\.min)?\.[cm]?js$/i.test(filename)) { return "sencha"; } if (/\.sentryclirc$/i.test(filename)) { return "sentry"; } if (/\.csv$/i.test(filename)) { return "graph"; } if (/\.(tab|tsv)$/i.test(filename)) { return "graph"; } if (/\.dif$/i.test(filename)) { return "graph"; } if (/\.slk$/i.test(filename)) { return "graph"; } if (/\.prn$/i.test(filename)) { return "graph"; } if (/(^|\.)serverless\.ya?ml$/i.test(filename)) { return "serverless"; } if (/\.sfproj$/i.test(filename)) { return "sf"; } if (/\.sequelizerc(\.[cm]?js|\.json)?$/i.test(filename)) { return "sequelize"; } if (/\.(sgi|iris)$/i.test(filename)) { return "sgi"; } if (/^shadow-cljs\.edn$/i.test(filename)) { return "shadowcljs"; } if (/\.(sh|rc|bash|tool|install|command)$/i.test(filename)) { return "terminal"; } if (/^(\.?bash(rc|[-_]?(profile|login|logout|history|prompt))|_osc|config|install-sh)$/i.test(filename)) { return "terminal"; } if (/\.(ksh|mksh|pdksh)$/i.test(filename)) { return "terminal"; } if (/\.sh-session$/i.test(filename)) { return "terminal"; } if (/\.zsh(-theme|_history)?$|^\.?(antigen|zpreztorc|zlogin|zlogout|zprofile|zshenv|zshrc)$/i.test(filename)) { return "terminal"; } if (/\.fish$|^\.fishrc$/i.test(filename)) { return "terminal"; } if (/^\.?(login|profile)$/.test(filename)) { return "terminal"; } if (/^\.?_?dir_?colors$/i.test(filename)) { return "terminal"; } if (/\.inputrc$/i.test(filename)) { return "terminal"; } if (/\.tmux$/i.test(filename)) { return "terminal"; } if (/rc_Apple_Terminal$/i.test(filename)) { return "terminal"; } if (/^(configure|config\.(guess|rpath|status|sub)|depcomp|libtool|compile)$/.test(filename)) { return "terminal"; } if (/^\/(private\/)?etc\/([^\/]+\/)*(profile$|nanorc$|rc\.|csh\.)/i.test(filename)) { return "terminal"; } if (/^\.?cshrc$/i.test(filename)) { return "terminal"; } if (/\.profile$/i.test(filename)) { return "terminal"; } if (/\.tcsh$/i.test(filename)) { return "terminal"; } if (/\.csh$/i.test(filename)) { return "terminal"; } if (/^\.?shellcheckrc$/i.test(filename)) { return "shellcheck"; } if (/\.shen$/i.test(filename)) { return "shen"; } if (/^shipitfile(\b.+)?\.[cm]?js$/i.test(filename)) { return "shipit"; } if (/^shippable\.ya?ml$/i.test(filename)) { return "shippable"; } if (/\.liquid$/i.test(filename)) { return "shopify"; } if (/\.sieve$/i.test(filename)) { return "filter"; } if (/\.sigils$/i.test(filename)) { return "sigils"; } if (/\.ss$/i.test(filename)) { return "silverstripe"; } if (/\.sketch$/i.test(filename)) { return "sketch"; } if (/\.layout$/i.test(filename)) { return "sketchup-lo"; } if (/\.skp$/i.test(filename)) { return "sketchup-mk"; } if (/\.style$/i.test(filename)) { return "sketchup-sb"; } if (/\.eskip$/i.test(filename)) { return "anchor"; } if (/\.sl$/i.test(filename)) { return "slash"; } if (/\.tpl$/i.test(filename)) { return "smarty"; } if (/^snapcraft\.ya?ml$/i.test(filename)) { return "snapcraft"; } if (/^snap\.svg([-.]min)?\.[cm]?js$/i.test(filename)) { return "snapsvg"; } if (/\.snort$/i.test(filename)) { return "snort"; } if (/^snowpack\.config\.([cm]?js|ts|json)$/i.test(filename)) { return "snowpack"; } if (/\.snyk$/i.test(filename)) { return "snyk"; } if (/^\.solidarity(\.json)?$/i.test(filename)) { return "solidarity"; } if (/\.sol(idity)?$/i.test(filename)) { return "solidity"; } if (/\.aes$/i.test(filename)) { return "sophia"; } if (/\.rbi$/i.test(filename)) { return "sorbet"; } if (/\.(sma|sp)$/i.test(filename)) { return "clojure"; } if (/\.inc$/i.test(filename)) { return "clojure"; } if (/\.spe$/i.test(filename)) { return "spacengine"; } if (/(^|\.)spacemacs$/i.test(filename)) { return "spacemacs"; } if (/\.sparql$/i.test(filename)) { return "sparql"; } if (/\.rq$/i.test(filename)) { return "sparql"; } if (/\.mixins?\.json$/i.test(filename)) { return "mixin"; } if (/\.jsont$/i.test(filename)) { return "squarespace"; } if (/^(json[-_]?t|json[-_\s]?template)$/i.test(filename)) { return "squarespace"; } if (/\.sqf$/i.test(filename)) { return "sqf"; } if (/\.hqf$/i.test(filename)) { return "sqf"; } if (/\.(my)?sql$/i.test(filename)) { return "sql"; } if (/\.ddl$/i.test(filename)) { return "sql"; } if (/\.udf$/i.test(filename)) { return "sql"; } if (/\.hql$/i.test(filename)) { return "sql"; } if (/\.viw$/i.test(filename)) { return "sql"; } if (/\.prc$/i.test(filename)) { return "sql"; } if (/\.cql$/i.test(filename)) { return "sql"; } if (/\.db2$/i.test(filename)) { return "sql"; } if (/\.4gl$/i.test(filename)) { return "sql"; } if (/\.per$/i.test(filename)) { return "sql"; } if (/\.spsql$/i.test(filename)) { return "sql"; } if (/\.sqlite$/i.test(filename)) { return "sqlite"; } if (/\.sqlite3$/i.test(filename)) { return "sqlite"; } if (/\.db$/i.test(filename)) { return "sqlite"; } if (/\.db3$/i.test(filename)) { return "sqlite"; } if (/\.nut$/i.test(filename)) { return "squirrel"; } if (/\.gnut$/i.test(filename)) { return "squirrel"; } if (/\.pub$/i.test(filename)) { return "key"; } if (/\.pem$/i.test(filename)) { return "key"; } if (/\.key$/i.test(filename)) { return "key"; } if (/\.crt$/i.test(filename)) { return "key"; } if (/\.der$/i.test(filename)) { return "key"; } if (/^id_rsa/.test(filename)) { return "key"; } if (/\.glyphs\d*License$/i.test(filename)) { return "key"; } if (/^(master\.)?passwd$/i.test(filename)) { return "key"; } if (/^git-credential-osxkeychain$/i.test(filename)) { return "key"; } if (/\.ssh[\/\\][^\/\\\s]+$/.test(filename)) { return "key"; } if (/\.stan$/i.test(filename)) { return "stan"; } if (/^(\.bazelrc|bazel\.rc|bazel\.bazelrc)$/i.test(filename)) { return "bazel"; } if (/^(BUILD|WORKSPACE)(\.[Bb][Aa][Zz][Ee][Ll])?$/.test(filename)) { return "bazel"; } if (/\.(bazel|bzl|star)$/i.test(filename)) { return "bazel"; } if (/^\.gazelcfg\.json$/i.test(filename)) { return "bazel"; } if (/\.do$/i.test(filename)) { return "stata"; } if (/\.ado$/i.test(filename)) { return "stata"; } if (/\.doh$/i.test(filename)) { return "stata"; } if (/\.ihlp$/i.test(filename)) { return "stata"; } if (/\.mata$/i.test(filename)) { return "stata"; } if (/\.matah$/i.test(filename)) { return "stata"; } if (/\.sthlp$/i.test(filename)) { return "stata"; } if (/\.stencil$/i.test(filename)) { return "stencil"; } if (/^stdlib(-.+)?\.[cm]?js$/i.test(filename)) { return "stdlibjs"; } if (/^stdlib(-.+)?\.[cm]?js\.gz$/i.test(filename)) { return "stdlibjs"; } if (/^\.?stitches\.config\.([cm]?js|ts)$/i.test(filename)) { return "stitches"; } if (/\.(story|stories)\.([cm]?js|jsx)$/i.test(filename)) { return "storybook"; } if (/\.(story|stories)\.tsx?$/i.test(filename)) { return "storybook"; } if (/\.story$/i.test(filename)) { return "storyist"; } if (/\.strings$/i.test(filename)) { return "strings"; } if (/\.st\.css$/i.test(filename)) { return "stylable"; } if (/\.sc\.js$/i.test(filename)) { return "nailpolish"; } if (/\.sc\.jsx$/i.test(filename)) { return "nailpolish"; } if (/\.sc\.mjs$/i.test(filename)) { return "nailpolish"; } if (/\.sc\.cjs$/i.test(filename)) { return "nailpolish"; } if (/\.sc\.ts$/i.test(filename)) { return "nailpolish"; } if (/\.sc\.tsx$/i.test(filename)) { return "nailpolish"; } if (/^\.stylelintrc(\.|$)/i.test(filename)) { return "stylelint"; } if (/^stylelint\.config\.[cm]?js$/i.test(filename)) { return "stylelint"; } if (/\.stylelint(ignore|cache)$/i.test(filename)) { return "stylelint"; } if (/^\.stylish-haskell\.ya?ml$/i.test(filename)) { return "stylishhaskell"; } if (/\.(styl|stylus)$/i.test(filename)) { return "stylus"; } if (/\.(stTheme|sublime[-_](build|commands|completions|keymap|macro|menu|mousemap|project|settings|theme|workspace|metrics|session|snippet))$/i.test(filename)) { return "sublime"; } if (/\.sublime-syntax$/i.test(filename)) { return "sublime"; } if (/\.scd$/i.test(filename)) { return "scd"; } if (/\.svg$/i.test(filename)) { return "svg"; } if (/^(openapi|swagger)\.(json|yaml|yml)$/i.test(filename)) { return "swagger"; } if (/\.swagger-codegen-ignore$/i.test(filename)) { return "swagger"; } if (/\.swift$/i.test(filename)) { return "swift"; } if (/\.svelte$/i.test(filename)) { return "svelte"; } if (/\.sv$/i.test(filename)) { return "sysverilog"; } if (/\.svh$/i.test(filename)) { return "sysverilog"; } if (/\.vh$/i.test(filename)) { return "sysverilog"; } if (/\.toc$/i.test(filename)) { return "toc"; } if (/^\.listing(\.\d+)?$/.test(filename)) { return "toc"; } if (/\.?c?tags$/i.test(filename)) { return "tag"; } if (/\.gemtags/i.test(filename)) { return "tag"; } if (/\.hgtags$|^localtags$/i.test(filename)) { return "tag"; } if (/^\.?VERSION$/i.test(filename)) { return "tag"; } if (/^\.atom-socket-.+\.\d$/.test(filename)) { return "tag"; } if (/\.pid$/i.test(filename)) { return "tag"; } if (/\.tld$/i.test(filename)) { return "tag"; } if (/(\.|^)sha(256|sum)?$/i.test(filename)) { return "tag"; } if (/(\.|^)(check|ck|crc(32)?|md5|rmd160|sha(224|256|384|512|1|2|3)?)?(sums?|(?<=\w))$/i.test(filename)) { return "tag"; } if (/^\.?tailwind(\.config)?\.([cm]?js|ts|coffee)$/i.test(filename)) { return "tailwind"; } if (/\.tcl$/i.test(filename)) { return "tcl"; } if (/\.adp$/i.test(filename)) { return "tcl"; } if (/\.tm$/i.test(filename)) { return "tcl"; } if (/\.exp$/i.test(filename)) { return "tcl"; } if (/^\.tkcvs/i.test(filename)) { return "tcl"; } if (/^\.tkdiffrc$/.test(filename)) { return "tcl"; } if (/\.tea$/i.test(filename)) { return "coffee"; } if (/\.tfignore$/i.test(filename)) { return "tfs"; } if (/tfs$/i.test(filename)) { return "tfs"; } if (/\.tl$/i.test(filename)) { return "telegram"; } if (/\.xps$/i.test(filename)) { return "telegram"; } if (/\.tt2?$/i.test(filename)) { return "tt"; } if (/\.tt3$/i.test(filename)) { return "tt"; } if (/\.tern-project$/i.test(filename)) { return "tern"; } if (/\.tern-config$/i.test(filename)) { return "tern"; } if (/\.tf(vars)?$/i.test(filename)) { return "terraform"; } if (/\.tf\.json$/i.test(filename)) { return "terraform"; } if (/\.tfstate(\.backup)?$/i.test(filename)) { return "terraform"; } if (/^\.(terser|uglify)rc(\.\w+)?$/i.test(filename)) { return "terser"; } if (/^\.testcaferc\.json$/i.test(filename)) { return "testcafe"; } if (/([._-](spec|test)s?|^test[-_].*)\.((lit)?coffee|iced|cjsx)$/i.test(filename)) { return "test-coffee"; } if (/([\\\/])t\1t?\d+(?:(?!\1).)+\.sh$|[._-](spec|test)s?\.sh$/i.test(filename)) { return "test-generic"; } if (/\.bats$/i.test(filename)) { return "test-generic"; } if (/\.test$/i.test(filename)) { return "test-generic"; } if (/\.xspec$/i.test(filename)) { return "test-generic"; } if (/(^test[._-].*|[._-](spec|test)s?)\.go$/i.test(filename)) { return "test-go"; } if (/(^test[._-].*|[._-](spec|test)s?)\.(hsc?|c2hs|lhs)$/i.test(filename)) { return "test-hs"; } if (/([._-](spec|test)s?|^test[._-].*)\.([_s]?js|js[bms]|es\d*)$/i.test(filename)) { return "test-js"; } if (/([._-](spec|test)s?|^test[._-].*)\.mjs$/i.test(filename)) { return "test-js"; } if (/([._-](spec|test)s?|^test[._-].*)\.cjs$/i.test(filename)) { return "test-js"; } if (/([\\\/])(?:(spec|test)s?|t)\1(?:\d+[-.])+(?!-)[^.\\\/]+\.js$/i.test(filename)) { return "test-js"; } if (/([\\\/])(?:(spec|test)s?|t)\1(?:\d+[-.])+(?!-)[^.\\\/]+\.mjs$/i.test(filename)) { return "test-js"; } if (/([\\\/])(?:(spec|test)s?|t)\1(?:\d+[-.])+(?!-)[^.\\\/]+\.cjs$/i.test(filename)) { return "test-js"; } if (/\.t$/i.test(filename)) { return "test-perl"; } if (/^test[._-].*\.pl$/i.test(filename)) { return "test-perl"; } if (/([\\\x2F])t\1(?:(?!\1).)+\.t$/i.test(filename)) { return "test-perl"; } if (/([\\\x2F])(test|spec)s?(\1((?!\1).)+)*\1((?!\1).)+[._-](spec|test)s?\.p(er)?l$/i.test(filename)) { return "test-perl"; } if (/(^test[._-].*|[._-](spec|test)s?)\.py(3|thon)?/i.test(filename)) { return "test-python"; } if (/([\\\x2F])(test|spec)s?(\1((?!\1).)+)*\1(((?!\1).)+[._-](?:spec|test)s?|(?:spec|test)s?[._-].+)\.py(3|thon)?$/i.test(filename)) { return "test-python"; } if (/(^test[._-].*|[._-](spec|test)s?)\.(jsx|react\.[cm]?js)$/.test(filename)) { return "test-react"; } if (/([\\\/])(spec|test)s?\1(?:\d+[-.])+(?!-)[^.\\\/]+\.(jsx|react\.[cm]?js)$/i.test(filename)) { return "test-react"; } if (/(^test[._-].*|[._-](spec|test)s?)\.(rb|ruby)$/i.test(filename)) { return "test-ruby"; } if (/([\\\x2F])(t|tests?|specs?)\1+(?:(?!\1).)*\.(rb|ruby)$/.test(filename)) { return "test-ruby"; } if (/(^test[-_].*|[._-](spec|test)s?)\.rs$/i.test(filename)) { return "test-rust"; } if (/(^test[._-].*|[._-](spec|test)s?)\.ts$/i.test(filename)) { return "test-ts"; } if (/(^test[._-].*|[._-](spec|test)s?)\.tsx$/i.test(filename)) { return "test-ts"; } if (/([\\\/])(spec|test)s?\1(?:\d+[-.])+(?!-)[^.\\\/]+\.ts$/i.test(filename)) { return "test-ts"; } if (/([\\\/])(spec|test)s?\1(?:\d+[-.])+(?!-)[^.\\\/]+\.tsx$/i.test(filename)) { return "test-ts"; } if (/\.tex$/i.test(filename)) { return "tex"; } if (/\.ltx$/i.test(filename)) { return "tex"; } if (/\.aux$/i.test(filename)) { return "tex"; } if (/\.sty$/i.test(filename)) { return "tex"; } if (/\.dtx$/i.test(filename)) { return "tex"; } if (/\.cls$/i.test(filename)) { return "tex"; } if (/\.ins$/i.test(filename)) { return "tex"; } if (/\.lbx$/i.test(filename)) { return "tex"; } if (/\.mkiv$/i.test(filename)) { return "tex"; } if (/\.mkvi$/i.test(filename)) { return "tex"; } if (/\.mkii$/i.test(filename)) { return "tex"; } if (/\.pgf$/i.test(filename)) { return "tex"; } if (/\.tikz$/i.test(filename)) { return "tex"; } if (/\.(texi(nfo)?|txi)$/i.test(filename)) { return "tex"; } if (/^hyphen(ex)?\.(cs|den|det|fr|sv|us)$/.test(filename)) { return "tex"; } if (/\.te?xt$/i.test(filename)) { return "icon-file-text"; } if (/\.log$|^Terminal[-_\s]Saved[-_\s]Output$/i.test(filename)) { return "icon-file-text"; } if (/\.git[\/\\]description$/.test(filename)) { return "icon-file-text"; } if (/(\\|\/)share(?:\1misc)?\1(?:operator|mail\.(?:tilde)?help)$/.test(filename)) { return "icon-file-text"; } if (/\.err$|\.std(err|out)$/i.test(filename)) { return "icon-file-text"; } if (/\.rtf$/i.test(filename)) { return "icon-file-text"; } if (/\.(i?nfo|lcov)$/i.test(filename)) { return "icon-file-text"; } if (/\.abt$/i.test(filename)) { return "icon-file-text"; } if (/\.ans$/i.test(filename)) { return "icon-file-text"; } if (/\.brf$/i.test(filename)) { return "icon-file-text"; } if (/\.dri$/i.test(filename)) { return "icon-file-text"; } if (/\.etx$/i.test(filename)) { return "icon-file-text"; } if (/\.irclog$/i.test(filename)) { return "icon-file-text"; } if (/\.more$/i.test(filename)) { return "icon-file-text"; } if (/\.msg$/i.test(filename)) { return "icon-file-text"; } if (/\.no$/i.test(filename)) { return "icon-file-text"; } if (/\.rpt$/i.test(filename)) { return "icon-file-text"; } if (/\.srt$/i.test(filename)) { return "icon-file-text"; } if (/\.sub$/i.test(filename)) { return "icon-file-text"; } if (/^(bug-report|fdl|for-release|tests)$/i.test(filename)) { return "icon-file-text"; } if (/\.(utxt|utf8)$/i.test(filename)) { return "icon-file-text"; } if (/\.weechatlog$/i.test(filename)) { return "icon-file-text"; } if (/\.uof$/i.test(filename)) { return "icon-file-text"; } if (/\.uot$/i.test(filename)) { return "icon-file-text"; } if (/\.uos$/i.test(filename)) { return "icon-file-text"; } if (/\.uop$/i.test(filename)) { return "icon-file-text"; } if (/\.textile$/i.test(filename)) { return "textile"; } if (/\.(tm_properties|tmProperties)$/i.test(filename)) { return "textmate"; } if (/\.tmcg$/i.test(filename)) { return "textmate"; } if (/\.tmLanguage$/i.test(filename)) { return "textmate"; } if (/\.tmCommand$/i.test(filename)) { return "textmate"; } if (/\.tmPreferences$/i.test(filename)) { return "textmate"; } if (/\.tmSnippet$/i.test(filename)) { return "textmate"; } if (/\.tmTheme$/i.test(filename)) { return "textmate"; } if (/\.tmMacro$/i.test(filename)) { return "textmate"; } if (/\.yaml-tmlanguage$/i.test(filename)) { return "textmate"; } if (/\.JSON-tmLanguage$/i.test(filename)) { return "textmate"; } if (/\.theme$/i.test(filename)) { return "icon-paintcan"; } if (/\.thor$/i.test(filename)) { return "thor"; } if (/^Thorfile$/i.test(filename)) { return "thor"; } if (/\.8x[pk](\.txt)?$/i.test(filename)) { return "calc"; } if (/^Tiltfile$/i.test(filename)) { return "tilt"; } if (/\.tipe$/i.test(filename)) { return "tipe"; } if (/\.tla$/i.test(filename)) { return "tla"; } if (/(\.|_|^)tmux\.conf$/i.test(filename)) { return "tmux"; } if (/\.toml$/i.test(filename)) { return "toml"; } if (/^\.tgitconfig$/i.test(filename)) { return "tortoise"; } if (/^\.travis/i.test(filename)) { return "travis"; } if (/^\.?truffle\.[cm]?js$/i.test(filename)) { return "truffle"; } if (/\.tsx$/i.test(filename)) { return "tsx"; } if (/\.ttcn3?$/i.test(filename)) { return "ttcn3"; } if (/\.tu$/i.test(filename)) { return "turing"; } if (/\.twig$/i.test(filename)) { return "twig"; } if (/\.tw$/i.test(filename)) { return "twine"; } if (/SugarCube$/i.test(filename)) { return "twine"; } if (/\.txl$/i.test(filename)) { return "txl"; } if (/^typedoc\.json$/i.test(filename)) { return "typedoc"; } if (/\.ts$/i.test(filename)) { return "ts"; } if (/^(ts|Type[-\s]*Script)$/i.test(filename)) { return "ts"; } if (/^typings\.json$/i.test(filename)) { return "typings"; } if (/\.(typoscript|tsconfig)$/i.test(filename)) { return "typo3"; } if (/typo3$/i.test(filename)) { return "typo3"; } if (/^uikit(\.min)?\.[cm]?js$/i.test(filename)) { return "uikit"; } if (/\.unibeautifyrc$/i.test(filename)) { return "unibeautify"; } if (/^unibeautify\.config\.[cm]?js$/i.test(filename)) { return "unibeautify"; } if (/\.unibeautifyrc\.([cm]?js|json)$/i.test(filename)) { return "unibeautify"; } if (/\.unibeautifyrc\.ya?ml$/i.test(filename)) { return "unibeautify"; } if (/^(ArabicShaping|Bidi(Brackets|CharacterTest|Mirroring|Test)|Blocks|CJKRadicals|CaseFolding|CompositionExclusions|Derived(Age|Name|Numeric(Type|Values)|BidiClass|BinaryProperties|CombiningClass|CoreProperties|DecompositionType|EastAsianWidth|GeneralCategory|Joining(Group|Type)|LineBreak|NormalizationProps)|EastAsianWidth|EmojiSources|EquivalentUnifiedIdeograph|(Grapheme|Line|Sentence|Word)Break(Property|Test)|HangulSyllableType|Index|Indic(Positional|Syllabic)Category|Jamo|LineBreak|NameAliases|NamedSequences(Prov)?|NamesList|Normalization(Corrections|Test)|NushuSources|PropList|Property(Value)?Aliases|Script(Extension)?s|SpecialCasing|StandardizedVariants|TangutSources|Unihan(_\w+)?|U(nicode|Source)Data|VerticalOrientation)\.txt$/.test(filename)) { return "unicode"; } if (/^NamesList\.(lst|txt)$/.test(filename)) { return "unicode"; } if (/([\\\/])(UNIDATA|UCD)(?:\1(?:auxiliary|emoji|extracted|unihan))?\1(?!ReadMe)[^\\\/]+\.txt$/i.test(filename)) { return "unicode"; } if (/\.units$/i.test(filename)) { return "scales"; } if (/^units\.(lib|dat)$|^unittab$/i.test(filename)) { return "scales"; } if (/^\.?units[-_]?history$/i.test(filename)) { return "scales"; } if (/\.anim$/i.test(filename)) { return "unity3d"; } if (/\.asset$/i.test(filename)) { return "unity3d"; } if (/\.cubemap$/i.test(filename)) { return "unity3d"; } if (/\.mat$/i.test(filename)) { return "unity3d"; } if (/\.meta$/i.test(filename)) { return "unity3d"; } if (/\.physics?Material(2D)?$/i.test(filename)) { return "unity3d"; } if (/\.prefab$/i.test(filename)) { return "unity3d"; } if (/\.unity$/i.test(filename)) { return "unity3d"; } if (/\.unityproj$/i.test(filename)) { return "unity3d"; } if (/\.unitypackage$/i.test(filename)) { return "unity3d"; } if (/\.uno$/i.test(filename)) { return "uno"; } if (/\.uc$/i.test(filename)) { return "unreal"; } if (/\.uasset$/i.test(filename)) { return "unreal"; } if (/\.ur$/i.test(filename)) { return "urweb"; } if (/\.urs$/i.test(filename)) { return "urweb"; } if (/\.v$/i.test(filename)) { return "v"; } if (/\.vh$/i.test(filename)) { return "v"; } if (/^([dv]8|v8[-_.][^.]*|mksnapshot|mkpeephole)$/i.test(filename)) { return "v8"; } if (/^\.v8flags\b/.test(filename)) { return "v8"; } if (/^\.c8rc(\.json)?$/i.test(filename)) { return "v8"; } if (/^Vagrantfile$/i.test(filename)) { return "vagrant"; } if (/\.vala$/i.test(filename)) { return "vala"; } if (/\.vapi$/i.test(filename)) { return "vala"; } if (/\.bsp$/i.test(filename)) { return "source"; } if (/\.vpk$/i.test(filename)) { return "source"; } if (/\.vtfx$/i.test(filename)) { return "source"; } if (/\.vmt$/i.test(filename)) { return "source"; } if (/\.vtf$/i.test(filename)) { return "source"; } if (/\.vmf$/i.test(filename)) { return "source"; } if (/\.res$/i.test(filename)) { return "source"; } if (/\.vcl$/i.test(filename)) { return "varnish"; } if (/\.vm$/i.test(filename)) { return "velocity"; } if (/^(vercel|now)\.json$/i.test(filename)) { return "zeit"; } if (/^\.(vercel|now)ignore$/i.test(filename)) { return "zeit"; } if (/\.v$/i.test(filename)) { return "verilog"; } if (/\.veo$/i.test(filename)) { return "verilog"; } if (/\.vhdl$/i.test(filename)) { return "vhdl"; } if (/\.vhf$/i.test(filename)) { return "vhdl"; } if (/\.vhi$/i.test(filename)) { return "vhdl"; } if (/\.vho$/i.test(filename)) { return "vhdl"; } if (/\.vhs$/i.test(filename)) { return "vhdl"; } if (/\.vht$/i.test(filename)) { return "vhdl"; } if (/\.vhw$/i.test(filename)) { return "vhdl"; } if (/\.3gpp?$/i.test(filename)) { return "video"; } if (/\.(mp4|m4v|h264)$/i.test(filename)) { return "video"; } if (/\.asx$/i.test(filename)) { return "video"; } if (/\.avi$/i.test(filename)) { return "video"; } if (/\.mov$/i.test(filename)) { return "video"; } if (/\.mk(v|s|3d)$/i.test(filename)) { return "video"; } if (/\.flv$/i.test(filename)) { return "video"; } if (/\.webm$/i.test(filename)) { return "video"; } if (/\.mpe?g$/i.test(filename)) { return "video"; } if (/\.(asf|wmv)$/i.test(filename)) { return "video"; } if (/\.(ogm|og[gv])$/i.test(filename)) { return "video"; } if (/\.(vim|[gn]?vimrc)$/i.test(filename)) { return "vim"; } if (/^[.gn_]?vim(rc|info)$/i.test(filename)) { return "vim"; } if (/\.vmb$/i.test(filename)) { return "vim"; } if (/(^|\.)n?exrc$/i.test(filename)) { return "vim"; } if (/\.ova$/i.test(filename)) { return "virtualbox"; } if (/\.ovf$/i.test(filename)) { return "virtualbox"; } if (/\.vhd$/i.test(filename)) { return "virtualbox"; } if (/\.vhdx$/i.test(filename)) { return "virtualbox"; } if (/\.vbox_version$/i.test(filename)) { return "virtualbox"; } if (/\.vbox(-prev)?$/i.test(filename)) { return "virtualbox"; } if (/^vite\.config\.[jt]s$/i.test(filename)) { return "vite"; } if (/\.(vba?|fr[mx]|bas)$/i.test(filename)) { return "vs"; } if (/\.vbhtml$/i.test(filename)) { return "vs"; } if (/\.vbs$/i.test(filename)) { return "vs"; } if (/\.vsix$/i.test(filename)) { return "vs"; } if (/\.csproj$/i.test(filename)) { return "vs"; } if (/\.vbproj$/i.test(filename)) { return "vs"; } if (/\.vcx?proj(\.[-\w]+)*$/i.test(filename)) { return "vs"; } if (/\.vssettings(\.json)?$/i.test(filename)) { return "vs"; } if (/\.vscodeignore(\.json)?$/i.test(filename)) { return "vs"; } if (/\.vstemplate$/i.test(filename)) { return "vs"; } if (/\.vsixmanifest$/i.test(filename)) { return "vs"; } if (/\.code-workspace$/i.test(filename)) { return "vs"; } if (/\.builds$/i.test(filename)) { return "vs"; } if (/\.dbproj$/i.test(filename)) { return "vs"; } if (/\.lsproj$/i.test(filename)) { return "vs"; } if (/\.modelproj$/i.test(filename)) { return "vs"; } if (/\.sln$/i.test(filename)) { return "vs"; } if (/\.njsproj$/i.test(filename)) { return "vs"; } if (/\.sqlproj$/i.test(filename)) { return "vs"; } if (/\.vcxitems$/i.test(filename)) { return "vs"; } if (/\.wmaproj$/i.test(filename)) { return "vs"; } if (/\.vmdk$/i.test(filename)) { return "vmware"; } if (/\.nvram$/i.test(filename)) { return "vmware"; } if (/\.vmsd$/i.test(filename)) { return "vmware"; } if (/\.vmsn$/i.test(filename)) { return "vmware"; } if (/\.vmss$/i.test(filename)) { return "vmware"; } if (/\.vmtm$/i.test(filename)) { return "vmware"; } if (/\.vmx$/i.test(filename)) { return "vmware"; } if (/\.vmxf$/i.test(filename)) { return "vmware"; } if (/\.vrimg$/i.test(filename)) { return "vray"; } if (/^\.vsts-ci\.ya?ml$/i.test(filename)) { return "vsts"; } if (/\.vue$/i.test(filename)) { return "vue"; } if (/^vue\.config\.[cm]?js$/i.test(filename)) { return "vue"; } if (/\.vy$/i.test(filename)) { return "vyper"; } if (/^w3c\.json$/i.test(filename)) { return "w3c"; } if (/^\.wallaby\.[cm]?js$/i.test(filename)) { return "wallaby"; } if (/\.walt$/i.test(filename)) { return "walt"; } if (/\.wc3$/i.test(filename)) { return "warcraft3"; } if (/\.jass$/i.test(filename)) { return "warcraft3"; } if (/\.zn$/i.test(filename)) { return "warcraft3"; } if (/\.watchmanconfig$|^watchman\.json$/i.test(filename)) { return "watchman"; } if (/\.wdl$/i.test(filename)) { return "wdl"; } if (/Workflow Description Language$/i.test(filename)) { return "wdl"; } if (/\.was?t$/i.test(filename)) { return "wasm"; } if (/\.wasm$/i.test(filename)) { return "wasm"; } if (/^\.hintrc$/i.test(filename)) { return "webhint"; } if (/\.webgl$/i.test(filename)) { return "webgl"; } if (/\.owl$/i.test(filename)) { return "owl"; } if (/(^|\.)webpack(file)?.*\.([jt]sx?|[cm]js|json|(lit)?coffee)$/i.test(filename)) { return "webpack"; } if (/\.vtt$/i.test(filename)) { return "webvtt"; } if (/^wgetrc$|\.wgetrc$/i.test(filename)) { return "wget"; } if (/\.wget-hsts$/i.test(filename)) { return "wget"; } if (/\.wxml$/i.test(filename)) { return "wechat"; } if (/\.wxss$/i.test(filename)) { return "wechat"; } if (/\.wy$/i.test(filename)) { return "wenyan"; } if (/^wercker\.ya?ml$/i.test(filename)) { return "wercker"; } if (/^windi\.config\.[tj]s$/i.test(filename)) { return "windi"; } if (/\.bat$/i.test(filename)) { return "windows"; } if (/\.cmd$/i.test(filename)) { return "windows"; } if (/\.(exe|com|msi)$/i.test(filename)) { return "windows"; } if (/\.reg$/i.test(filename)) { return "windows"; } if (/\.xaml$/i.test(filename)) { return "winui"; } if (/\.baml$/i.test(filename)) { return "winui"; } if (/\.wixproj$/i.test(filename)) { return "wix"; } if (/\.wixobj$/i.test(filename)) { return "wix"; } if (/\.wxs$/i.test(filename)) { return "wix"; } if (/\.wxi$/i.test(filename)) { return "wix"; } if (/\.wxl$/i.test(filename)) { return "wix"; } if (/\.wix$/i.test(filename)) { return "wix"; } if (/\.wl$/i.test(filename)) { return "wolfram"; } if (/\.wls$/i.test(filename)) { return "wolfram"; } if (/\.wlt$/i.test(filename)) { return "wolfram"; } if (/^workbox-config\.[cm]?js$/i.test(filename)) { return "workbox"; } if (/\.wurst$/i.test(filename)) { return "wurst"; } if (/WurstLang$/i.test(filename)) { return "wurst"; } if (/\.x10$/i.test(filename)) { return "x10"; } if (/xten$/i.test(filename)) { return "x10"; } if (/\.X(authority|clients|initrc|inputrc|profile|resources|session-errors|screensaver)$/i.test(filename)) { return "x11"; } if (/\.workbook$/i.test(filename)) { return "xamarin"; } if (/\.xc$/i.test(filename)) { return "xmos"; } if (/\.pbxproj$/i.test(filename)) { return "appstore"; } if (/\.pbxuser$/i.test(filename)) { return "appstore"; } if (/\.xccheckout$/i.test(filename)) { return "appstore"; } if (/\.xcplugindata$/i.test(filename)) { return "appstore"; } if (/\.xcrequiredplugins$/i.test(filename)) { return "appstore"; } if (/\.xcscheme$/i.test(filename)) { return "appstore"; } if (/\.xcscmblueprint$/i.test(filename)) { return "appstore"; } if (/\.xcsettings$/i.test(filename)) { return "appstore"; } if (/\.xcuserstate$/i.test(filename)) { return "appstore"; } if (/\.xcworkspacedata$/i.test(filename)) { return "appstore"; } if (/\.mode\dv3$/i.test(filename)) { return "appstore"; } if (/^xmake\.lua$/i.test(filename)) { return "xmake"; } if (/\.xojo_code$/i.test(filename)) { return "xojo"; } if (/\.xojo_menu$/i.test(filename)) { return "xojo"; } if (/\.xojo_report$/i.test(filename)) { return "xojo"; } if (/\.xojo_script$/i.test(filename)) { return "xojo"; } if (/\.xojo_toolbar$/i.test(filename)) { return "xojo"; } if (/\.xojo_window$/i.test(filename)) { return "xojo"; } if (/\.xsp-config$/i.test(filename)) { return "xpages"; } if (/\.xsp\.metadata$/i.test(filename)) { return "xpages"; } if (/\.xpl$/i.test(filename)) { return "xmos"; } if (/\.xproc$/i.test(filename)) { return "xmos"; } if (/\.(xquery|xq|xql|xqm|xqy)$/i.test(filename)) { return "sql"; } if (/\.xtend$/i.test(filename)) { return "xtend"; } if (/\.ya?ml$/i.test(filename)) { return "yaml"; } if (/\.ya?ml\.mysql$/i.test(filename)) { return "yaml"; } if (/\.ya?ml\.sed$/i.test(filename)) { return "yaml"; } if (/^\.yamllint(\.ya?ml)?$/i.test(filename)) { return "yamllint"; } if (/^\.yaspellerrc($|\.)|^\.yaspeller\.json$/i.test(filename)) { return "yandex"; } if (/\.yang$/i.test(filename)) { return "yang"; } if (/\.yara?$/i.test(filename)) { return "yara"; } if (/^yarn\.lock$|\.yarn-metadata(\.json)?$/i.test(filename)) { return "yarn"; } if (/\.(yarnrc|yarnclean|yarn-integrity)$/i.test(filename)) { return "yarn"; } if (/\.yo-rc\.json$/i.test(filename)) { return "yeoman"; } if (/\.yorick$/i.test(filename)) { return "yorick"; } if (/^(yahoo-|yui)[^.]*\.[cm]?js$/i.test(filename)) { return "yui"; } if (/\.zpr$/i.test(filename)) { return "zbrush"; } if (/\.ztl$/i.test(filename)) { return "zbrush"; } if (/\.zs$/i.test(filename)) { return "crafttweaker"; } if (/^\.zsrc\.json$/i.test(filename)) { return "crafttweaker"; } if (/\.zep$/i.test(filename)) { return "zephir"; } if (/\.zig$/i.test(filename)) { return "zig"; } if (/\.(zimpl|zmpl|zpl)$/i.test(filename)) { return "zimpl"; } if (/\.zap$/i.test(filename)) { return "zork"; } if (/\.xzap$/i.test(filename)) { return "zork"; } if (/^s4\.errors$/i.test(filename)) { return "zork"; } if (/\.zabstr?$/i.test(filename)) { return "zork"; } if (/\.zil$/i.test(filename)) { return "zork"; } if (/\.mud$/i.test(filename)) { return "zork"; } } module.exports = matchIcon; ================================================ FILE: src/assets/misc/grid.json ================================================ {"tiles":[{"lat":-31.72,"lon":90,"b":[{"x":0,"y":265.52,"z":423.63},{"x":-3,"y":263.67,"z":424.77},{"x":-1.85,"y":260.67,"z":426.62},{"x":1.85,"y":260.67,"z":426.62},{"x":3,"y":263.67,"z":424.77}]},{"lat":-31.72,"lon":-90,"b":[{"x":0,"y":265.52,"z":-423.63},{"x":-3,"y":263.67,"z":-424.77},{"x":-1.85,"y":260.67,"z":-426.62},{"x":1.85,"y":260.67,"z":-426.62},{"x":3,"y":263.67,"z":-424.77}]},{"lat":0,"lon":31.72,"b":[{"x":-424.77,"y":3,"z":263.67},{"x":-423.63,"y":0,"z":265.52},{"x":-424.77,"y":-3,"z":263.67},{"x":-426.62,"y":-1.85,"z":260.67},{"x":-426.62,"y":1.85,"z":260.67}]},{"lat":-62.88,"lon":-180,"b":[{"x":228.77,"y":444.58,"z":0.55},{"x":228.06,"y":444.94,"z":1.1},{"x":227.17,"y":445.4,"z":0.55},{"x":227.17,"y":445.4,"z":-0.55},{"x":228.06,"y":444.94,"z":-1.1},{"x":228.77,"y":444.58,"z":-0.55}]},{"lat":-64.51,"lon":-180,"b":[{"x":215.77,"y":451.03,"z":0.36},{"x":215.28,"y":451.27,"z":0.73},{"x":214.67,"y":451.56,"z":0.37},{"x":214.67,"y":451.56,"z":-0.37},{"x":215.28,"y":451.27,"z":-0.73},{"x":215.77,"y":451.03,"z":-0.36}]},{"lat":-66.18,"lon":-180,"b":[{"x":204.78,"y":456.08,"z":1.72},{"x":202.38,"y":457.15,"z":3.46},{"x":199.45,"y":458.44,"z":1.74},{"x":199.45,"y":458.44,"z":-1.74},{"x":202.38,"y":457.15,"z":-3.46},{"x":204.78,"y":456.08,"z":-1.72}]},{"lat":-67.9,"lon":-180,"b":[{"x":191.52,"y":461.8,"z":1.99},{"x":188.64,"y":462.97,"z":4.01},{"x":185.19,"y":464.38,"z":2.02},{"x":185.19,"y":464.38,"z":-2.02},{"x":188.64,"y":462.97,"z":-4.01},{"x":191.52,"y":461.8,"z":-1.99}]},{"lat":-71.45,"lon":-180,"b":[{"x":159.87,"y":473.73,"z":0.47},{"x":159.14,"y":473.98,"z":0.95},{"x":158.29,"y":474.26,"z":0.48},{"x":158.29,"y":474.26,"z":-0.48},{"x":159.14,"y":473.98,"z":-0.95},{"x":159.87,"y":473.73,"z":-0.47}]},{"lat":-59.87,"lon":164.91,"b":[{"x":242.04,"y":432.94,"z":62.76},{"x":240.36,"y":433.67,"z":64.19},{"x":240.6,"y":433.14,"z":66.8},{"x":242.67,"y":431.86,"z":67.59},{"x":244.48,"y":431.12,"z":65.76},{"x":244.08,"y":431.68,"z":63.55}]},{"lat":-59.98,"lon":161.49,"b":[{"x":237.12,"y":433.16,"z":78.29},{"x":236.37,"y":433.45,"z":78.92},{"x":236.46,"y":433.2,"z":80.06},{"x":237.36,"y":432.64,"z":80.41},{"x":238.17,"y":432.34,"z":79.61},{"x":238.01,"y":432.61,"z":78.63}]},{"lat":-59.92,"lon":154.39,"b":[{"x":225.82,"y":433.42,"z":105.37},{"x":223.74,"y":434.08,"z":107.11},{"x":223.88,"y":433.25,"z":110.11},{"x":226.27,"y":431.78,"z":111.02},{"x":228.48,"y":431.15,"z":108.92},{"x":228.18,"y":431.97,"z":106.27}]},{"lat":-59.74,"lon":150.75,"b":[{"x":219.67,"y":432.98,"z":119.21},{"x":216.85,"y":433.76,"z":121.54},{"x":216.99,"y":432.56,"z":125.5},{"x":220.15,"y":430.61,"z":126.71},{"x":223.14,"y":429.87,"z":123.94},{"x":222.8,"y":431.05,"z":120.4}]},{"lat":-59.45,"lon":147.09,"b":[{"x":213.24,"y":431.78,"z":134.29},{"x":210.43,"y":432.44,"z":136.58},{"x":210.51,"y":431.18,"z":140.4},{"x":213.58,"y":429.28,"z":141.57},{"x":216.54,"y":428.67,"z":138.92},{"x":216.28,"y":429.9,"z":135.45}]},{"lat":-59.05,"lon":143.44,"b":[{"x":206.48,"y":429.63,"z":150.82},{"x":204.7,"y":429.98,"z":152.25},{"x":204.72,"y":429.13,"z":154.59},{"x":206.62,"y":427.96,"z":155.32},{"x":208.48,"y":427.64,"z":153.69},{"x":208.36,"y":428.46,"z":151.54}]},{"lat":-58.55,"lon":139.83,"b":[{"x":199.31,"y":428.13,"z":164.07},{"x":196,"y":428.65,"z":166.67},{"x":195.98,"y":426.99,"z":170.89},{"x":199.43,"y":424.86,"z":172.21},{"x":202.88,"y":424.4,"z":169.3},{"x":202.74,"y":426.01,"z":165.37}]},{"lat":-57.94,"lon":136.29,"b":[{"x":191.85,"y":425.45,"z":179.21},{"x":188.45,"y":425.86,"z":181.84},{"x":188.38,"y":424.07,"z":186.03},{"x":191.85,"y":421.93,"z":187.36},{"x":195.37,"y":421.58,"z":184.48},{"x":195.3,"y":423.32,"z":180.53}]},{"lat":-57.23,"lon":132.83,"b":[{"x":184.08,"y":422.24,"z":194.32},{"x":180.59,"y":422.53,"z":196.96},{"x":180.48,"y":420.61,"z":201.11},{"x":183.96,"y":418.46,"z":202.44},{"x":187.54,"y":418.23,"z":199.61},{"x":187.55,"y":420.09,"z":195.65}]},{"lat":-56.41,"lon":129.49,"b":[{"x":176.01,"y":418.48,"z":209.34},{"x":172.44,"y":418.65,"z":211.97},{"x":172.29,"y":416.62,"z":216.06},{"x":175.78,"y":414.46,"z":217.39},{"x":179.42,"y":414.34,"z":214.63},{"x":179.5,"y":416.33,"z":210.67}]},{"lat":-55.51,"lon":126.28,"b":[{"x":167.68,"y":414.19,"z":224.2},{"x":164.03,"y":414.23,"z":226.8},{"x":163.84,"y":412.08,"z":230.83},{"x":167.34,"y":409.91,"z":232.16},{"x":171.03,"y":409.91,"z":229.48},{"x":171.17,"y":412.03,"z":225.53}]},{"lat":-54.52,"lon":123.2,"b":[{"x":159.09,"y":409.36,"z":238.84},{"x":155.38,"y":409.28,"z":241.42},{"x":155.15,"y":407.01,"z":245.35},{"x":158.66,"y":404.85,"z":246.69},{"x":162.39,"y":404.95,"z":244.09},{"x":162.6,"y":407.2,"z":240.18}]},{"lat":-53.46,"lon":120.27,"b":[{"x":150.3,"y":404.01,"z":253.21},{"x":146.53,"y":403.8,"z":255.74},{"x":146.27,"y":401.44,"z":259.59},{"x":149.77,"y":399.27,"z":260.92},{"x":153.53,"y":399.47,"z":258.42},{"x":153.8,"y":401.85,"z":254.55}]},{"lat":-52.33,"lon":117.49,"b":[{"x":141.32,"y":398.16,"z":267.26},{"x":137.5,"y":397.83,"z":269.73},{"x":137.23,"y":395.37,"z":273.47},{"x":140.72,"y":393.21,"z":274.8},{"x":144.5,"y":393.51,"z":272.4},{"x":144.82,"y":396,"z":268.59}]},{"lat":-51.14,"lon":114.87,"b":[{"x":132.2,"y":391.84,"z":280.92},{"x":128.34,"y":391.39,"z":283.33},{"x":128.05,"y":388.84,"z":286.95},{"x":131.53,"y":386.68,"z":288.28},{"x":135.32,"y":387.08,"z":286},{"x":135.69,"y":389.68,"z":282.26}]},{"lat":-49.91,"lon":112.39,"b":[{"x":122.96,"y":385.07,"z":294.17},{"x":119.07,"y":384.5,"z":296.5},{"x":118.77,"y":381.87,"z":299.99},{"x":122.24,"y":379.73,"z":301.32},{"x":126.02,"y":380.21,"z":299.16},{"x":126.44,"y":382.91,"z":295.5}]},{"lat":-48.63,"lon":110.06,"b":[{"x":113.65,"y":377.88,"z":306.95},{"x":109.74,"y":377.21,"z":309.2},{"x":109.44,"y":374.52,"z":312.56},{"x":112.89,"y":372.39,"z":313.87},{"x":116.66,"y":372.94,"z":311.84},{"x":117.12,"y":375.74,"z":308.28}]},{"lat":-47.33,"lon":107.87,"b":[{"x":104.3,"y":370.33,"z":319.24},{"x":100.38,"y":369.55,"z":321.39},{"x":100.09,"y":366.8,"z":324.61},{"x":103.52,"y":364.69,"z":325.92},{"x":107.26,"y":365.3,"z":324.01},{"x":107.75,"y":368.2,"z":320.56}]},{"lat":-46,"lon":105.82,"b":[{"x":94.95,"y":362.44,"z":331},{"x":91.03,"y":361.57,"z":333.04},{"x":90.75,"y":358.77,"z":336.13},{"x":94.15,"y":356.67,"z":337.42},{"x":97.86,"y":357.35,"z":335.65},{"x":98.37,"y":360.32,"z":332.31}]},{"lat":-44.66,"lon":103.89,"b":[{"x":85.63,"y":354.25,"z":342.22},{"x":81.73,"y":353.3,"z":344.15},{"x":81.46,"y":350.47,"z":347.09},{"x":84.82,"y":348.39,"z":348.37},{"x":88.49,"y":349.11,"z":346.74},{"x":89.03,"y":352.15,"z":343.51}]},{"lat":-43.32,"lon":102.08,"b":[{"x":76.37,"y":345.82,"z":352.87},{"x":72.49,"y":344.79,"z":354.69},{"x":72.24,"y":341.94,"z":357.48},{"x":75.58,"y":339.88,"z":358.76},{"x":79.2,"y":340.65,"z":357.25},{"x":79.74,"y":343.74,"z":354.15}]},{"lat":-41.97,"lon":100.38,"b":[{"x":67.21,"y":337.19,"z":362.95},{"x":63.36,"y":336.09,"z":364.65},{"x":63.13,"y":333.23,"z":367.3},{"x":66.43,"y":331.19,"z":368.56},{"x":69.99,"y":331.99,"z":367.19},{"x":70.55,"y":335.12,"z":364.22}]},{"lat":-40.62,"lon":98.78,"b":[{"x":58.17,"y":328.39,"z":372.45},{"x":54.36,"y":327.23,"z":374.04},{"x":54.15,"y":324.38,"z":376.55},{"x":57.42,"y":322.36,"z":377.8},{"x":60.92,"y":323.18,"z":376.55},{"x":61.47,"y":326.35,"z":373.71}]},{"lat":-39.29,"lon":97.29,"b":[{"x":49.28,"y":319.47,"z":381.39},{"x":45.51,"y":318.26,"z":382.86},{"x":45.34,"y":315.42,"z":385.23},{"x":48.56,"y":313.43,"z":386.46},{"x":51.99,"y":314.26,"z":385.34},{"x":52.54,"y":317.46,"z":382.63}]},{"lat":-37.97,"lon":95.88,"b":[{"x":40.55,"y":310.48,"z":389.75},{"x":36.83,"y":309.23,"z":391.11},{"x":36.69,"y":306.4,"z":393.34},{"x":39.87,"y":304.44,"z":394.56},{"x":43.23,"y":305.27,"z":393.56},{"x":43.77,"y":308.49,"z":390.98}]},{"lat":-36.68,"lon":94.56,"b":[{"x":32.01,"y":301.44,"z":397.57},{"x":28.35,"y":300.16,"z":398.81},{"x":28.25,"y":297.35,"z":400.91},{"x":31.38,"y":295.42,"z":402.11},{"x":34.66,"y":296.25,"z":401.22},{"x":35.19,"y":299.48,"z":398.78}]},{"lat":-35.4,"lon":93.32,"b":[{"x":23.68,"y":292.39,"z":404.84},{"x":20.08,"y":291.09,"z":405.98},{"x":20.01,"y":288.32,"z":407.95},{"x":23.1,"y":286.41,"z":409.13},{"x":26.3,"y":287.24,"z":408.35},{"x":26.81,"y":290.46,"z":406.04}]},{"lat":-34.14,"lon":92.15,"b":[{"x":15.56,"y":283.37,"z":411.6},{"x":12.02,"y":282.05,"z":412.62},{"x":11.99,"y":279.32,"z":414.48},{"x":15.03,"y":277.44,"z":415.64},{"x":18.15,"y":278.26,"z":414.96},{"x":18.65,"y":281.46,"z":412.78}]},{"lat":-32.92,"lon":91.04,"b":[{"x":7.66,"y":274.41,"z":417.85},{"x":4.2,"y":273.07,"z":418.77},{"x":4.2,"y":270.38,"z":420.51},{"x":7.19,"y":268.53,"z":421.66},{"x":10.23,"y":269.34,"z":421.08},{"x":10.71,"y":272.53,"z":419.01}]},{"lat":-63.4,"lon":176.69,"b":[{"x":222.9,"y":447.42,"z":9.04},{"x":226.03,"y":445.81,"z":10.95},{"x":226.58,"y":445.41,"z":14.83},{"x":224,"y":446.64,"z":16.85},{"x":220.82,"y":448.29,"z":14.94},{"x":220.29,"y":448.66,"z":11}]},{"lat":-62.22,"lon":173.63,"b":[{"x":231.04,"y":442.82,"z":21.94},{"x":234.09,"y":441.12,"z":23.82},{"x":234.61,"y":440.61,"z":27.72},{"x":232.06,"y":441.82,"z":29.8},{"x":228.96,"y":443.56,"z":27.92},{"x":228.45,"y":444.05,"z":23.96}]},{"lat":-60.98,"lon":170.81,"b":[{"x":238.94,"y":437.77,"z":34.85},{"x":241.9,"y":436,"z":36.68},{"x":242.37,"y":435.38,"z":40.56},{"x":239.88,"y":436.56,"z":42.68},{"x":236.88,"y":438.37,"z":40.86},{"x":236.41,"y":438.97,"z":36.91}]},{"lat":-65.06,"lon":176.44,"b":[{"x":209.92,"y":453.65,"z":9.44},{"x":212.92,"y":452.21,"z":11.25},{"x":213.42,"y":451.86,"z":14.9},{"x":210.9,"y":452.98,"z":16.81},{"x":207.84,"y":454.45,"z":15},{"x":207.36,"y":454.78,"z":11.29}]},{"lat":-63.85,"lon":173.17,"b":[{"x":218.23,"y":449.25,"z":22.26},{"x":221.4,"y":447.6,"z":24.17},{"x":221.91,"y":447.12,"z":28.13},{"x":219.22,"y":448.3,"z":30.24},{"x":216,"y":449.99,"z":28.33},{"x":215.51,"y":450.45,"z":24.31}]},{"lat":-62.58,"lon":170.16,"b":[{"x":226.36,"y":444.36,"z":35.34},{"x":229.46,"y":442.62,"z":37.22},{"x":229.93,"y":442.02,"z":41.2},{"x":227.29,"y":443.17,"z":43.36},{"x":224.14,"y":444.96,"z":41.49},{"x":223.68,"y":445.54,"z":37.45}]},{"lat":-61.25,"lon":167.42,"b":[{"x":234.26,"y":439.01,"z":48.38},{"x":237.28,"y":437.18,"z":50.22},{"x":237.71,"y":436.46,"z":54.21},{"x":235.1,"y":437.59,"z":56.42},{"x":232.03,"y":439.47,"z":54.6},{"x":231.61,"y":440.17,"z":50.54}]},{"lat":-66.76,"lon":176.14,"b":[{"x":196.31,"y":459.7,"z":9.29},{"x":199.65,"y":458.22,"z":11.25},{"x":200.17,"y":457.87,"z":15.24},{"x":197.32,"y":459.03,"z":17.32},{"x":193.92,"y":460.55,"z":15.35},{"x":193.43,"y":460.87,"z":11.31}]},{"lat":-65.53,"lon":172.62,"b":[{"x":204.86,"y":455.48,"z":22.57},{"x":208.15,"y":453.9,"z":24.51},{"x":208.64,"y":453.43,"z":28.53},{"x":205.83,"y":454.57,"z":30.66},{"x":202.49,"y":456.2,"z":28.72},{"x":202.02,"y":456.65,"z":24.64}]},{"lat":-64.23,"lon":169.42,"b":[{"x":213.22,"y":450.77,"z":35.85},{"x":216.45,"y":449.08,"z":37.76},{"x":216.9,"y":448.5,"z":41.81},{"x":214.12,"y":449.62,"z":44},{"x":210.85,"y":451.35,"z":42.09},{"x":210.41,"y":451.92,"z":37.99}]},{"lat":-62.86,"lon":166.52,"b":[{"x":221.36,"y":445.57,"z":49.1},{"x":224.51,"y":443.79,"z":50.98},{"x":224.93,"y":443.08,"z":55.03},{"x":222.18,"y":444.18,"z":57.27},{"x":218.98,"y":446.01,"z":55.41},{"x":218.58,"y":446.69,"z":51.29}]},{"lat":-61.44,"lon":163.88,"b":[{"x":229.48,"y":439.48,"z":64.57},{"x":230.82,"y":438.66,"z":65.37},{"x":230.99,"y":438.3,"z":67.15},{"x":229.8,"y":438.77,"z":68.15},{"x":228.43,"y":439.61,"z":67.36},{"x":228.27,"y":439.96,"z":65.55}]},{"lat":-68.5,"lon":175.79,"b":[{"x":182.2,"y":465.46,"z":9.41},{"x":185.66,"y":464.06,"z":11.4},{"x":186.15,"y":463.74,"z":15.44},{"x":183.17,"y":464.85,"z":17.54},{"x":179.66,"y":466.29,"z":15.54},{"x":179.19,"y":466.58,"z":11.45}]},{"lat":-67.25,"lon":171.99,"b":[{"x":190.95,"y":461.47,"z":22.86},{"x":194.35,"y":459.95,"z":24.83},{"x":194.82,"y":459.51,"z":28.91},{"x":191.87,"y":460.61,"z":31.07},{"x":188.42,"y":462.16,"z":29.09},{"x":187.97,"y":462.58,"z":24.96}]},{"lat":-65.91,"lon":168.57,"b":[{"x":199.52,"y":456.96,"z":36.34},{"x":202.86,"y":455.33,"z":38.29},{"x":203.31,"y":454.77,"z":42.39},{"x":200.39,"y":455.85,"z":44.61},{"x":197,"y":457.51,"z":42.66},{"x":196.57,"y":458.06,"z":38.5}]},{"lat":-64.51,"lon":165.49,"b":[{"x":207.89,"y":451.93,"z":49.81},{"x":211.16,"y":450.2,"z":51.71},{"x":211.57,"y":449.52,"z":55.83},{"x":208.69,"y":450.57,"z":58.1},{"x":205.36,"y":452.34,"z":56.2},{"x":204.97,"y":453.01,"z":52.02}]},{"lat":-63.04,"lon":162.72,"b":[{"x":216.02,"y":446.41,"z":63.21},{"x":219.22,"y":444.59,"z":65.07},{"x":219.58,"y":443.78,"z":69.19},{"x":216.74,"y":444.81,"z":71.51},{"x":213.49,"y":446.67,"z":69.66},{"x":213.14,"y":447.47,"z":65.47}]},{"lat":-61.54,"lon":160.22,"b":[{"x":224.01,"y":440.13,"z":77.86},{"x":226.1,"y":438.85,"z":79.07},{"x":226.31,"y":438.23,"z":81.83},{"x":224.43,"y":438.9,"z":83.42},{"x":222.31,"y":440.2,"z":82.21},{"x":222.1,"y":440.82,"z":79.41}]},{"lat":-69.01,"lon":171.24,"b":[{"x":176.65,"y":467.07,"z":24.4},{"x":179.09,"y":466.07,"z":25.79},{"x":179.4,"y":465.78,"z":28.67},{"x":177.25,"y":466.5,"z":30.19},{"x":174.77,"y":467.53,"z":28.79},{"x":174.48,"y":467.8,"z":25.88}]},{"lat":-67.64,"lon":167.56,"b":[{"x":185.27,"y":462.88,"z":36.82},{"x":188.72,"y":461.33,"z":38.79},{"x":189.14,"y":460.78,"z":42.95},{"x":186.09,"y":461.81,"z":45.19},{"x":182.59,"y":463.4,"z":43.21},{"x":182.18,"y":463.93,"z":39}]},{"lat":-66.19,"lon":164.28,"b":[{"x":193.85,"y":458.06,"z":50.48},{"x":197.24,"y":456.39,"z":52.42},{"x":197.63,"y":455.72,"z":56.6},{"x":194.61,"y":456.72,"z":58.89},{"x":191.17,"y":458.42,"z":56.95},{"x":190.8,"y":459.08,"z":52.72}]},{"lat":-64.68,"lon":161.37,"b":[{"x":202.21,"y":452.7,"z":64.1},{"x":205.54,"y":450.94,"z":66},{"x":205.89,"y":450.14,"z":70.18},{"x":202.9,"y":451.12,"z":72.52},{"x":199.53,"y":452.92,"z":70.63},{"x":199.19,"y":453.71,"z":66.39}]},{"lat":-63.13,"lon":158.78,"b":[{"x":210.33,"y":446.85,"z":77.62},{"x":213.58,"y":444.99,"z":79.47},{"x":213.89,"y":444.07,"z":83.64},{"x":210.94,"y":445.02,"z":86.03},{"x":207.65,"y":446.92,"z":84.2},{"x":207.35,"y":447.83,"z":79.96}]},{"lat":-61.53,"lon":156.46,"b":[{"x":218.22,"y":440.42,"z":91.4},{"x":221.07,"y":438.66,"z":93.02},{"x":221.31,"y":437.73,"z":96.77},{"x":218.68,"y":438.55,"z":98.96},{"x":215.79,"y":440.34,"z":97.37},{"x":215.56,"y":441.28,"z":93.56}]},{"lat":-69.41,"lon":166.36,"b":[{"x":170.72,"y":468.23,"z":39.78},{"x":172.15,"y":467.64,"z":40.59},{"x":172.31,"y":467.43,"z":42.28},{"x":171.04,"y":467.82,"z":43.19},{"x":169.58,"y":468.42,"z":42.38},{"x":169.43,"y":468.62,"z":40.67}]},{"lat":-67.92,"lon":162.87,"b":[{"x":179.25,"y":463.89,"z":51.13},{"x":182.75,"y":462.3,"z":53.1},{"x":183.13,"y":461.64,"z":57.34},{"x":179.97,"y":462.59,"z":59.65},{"x":176.41,"y":464.21,"z":57.67},{"x":176.06,"y":464.85,"z":53.38}]},{"lat":-66.36,"lon":159.81,"b":[{"x":187.83,"y":458.74,"z":64.95},{"x":191.27,"y":457.04,"z":66.89},{"x":191.61,"y":456.25,"z":71.13},{"x":188.49,"y":457.17,"z":73.5},{"x":185,"y":458.9,"z":71.56},{"x":184.68,"y":459.68,"z":67.26}]},{"lat":-64.75,"lon":157.12,"b":[{"x":196.19,"y":453.05,"z":78.69},{"x":199.56,"y":451.25,"z":80.58},{"x":199.86,"y":450.33,"z":84.82},{"x":196.77,"y":451.23,"z":87.23},{"x":193.35,"y":453.06,"z":85.35},{"x":193.07,"y":453.97,"z":81.06}]},{"lat":-63.1,"lon":154.74,"b":[{"x":204.3,"y":446.86,"z":92.3},{"x":207.59,"y":444.96,"z":94.14},{"x":207.85,"y":443.92,"z":98.36},{"x":204.8,"y":444.78,"z":100.81},{"x":201.46,"y":446.72,"z":99},{"x":201.21,"y":447.75,"z":94.71}]},{"lat":-61.42,"lon":152.63,"b":[{"x":212.13,"y":440.18,"z":105.74},{"x":215.34,"y":438.19,"z":107.5},{"x":215.55,"y":437.04,"z":111.7},{"x":212.53,"y":437.87,"z":114.19},{"x":209.28,"y":439.89,"z":112.44},{"x":209.08,"y":441.04,"z":108.19}]},{"lat":-69.66,"lon":161.19,"b":[{"x":164.3,"y":469.09,"z":54.07},{"x":165.95,"y":468.41,"z":54.99},{"x":166.11,"y":468.11,"z":56.94},{"x":164.61,"y":468.51,"z":58},{"x":162.94,"y":469.21,"z":57.08},{"x":162.79,"y":469.5,"z":55.11}]},{"lat":-68.05,"lon":157.98,"b":[{"x":172.88,"y":464.46,"z":65.76},{"x":176.44,"y":462.84,"z":67.74},{"x":176.77,"y":462.06,"z":72.04},{"x":173.51,"y":462.92,"z":74.42},{"x":169.9,"y":464.57,"z":72.45},{"x":169.6,"y":465.33,"z":68.09}]},{"lat":-66.39,"lon":155.19,"b":[{"x":181.47,"y":458.96,"z":79.72},{"x":184.96,"y":457.23,"z":81.65},{"x":185.25,"y":456.32,"z":85.95},{"x":182.02,"y":457.16,"z":88.38},{"x":178.48,"y":458.92,"z":86.46},{"x":178.21,"y":459.82,"z":82.1}]},{"lat":-64.68,"lon":152.76,"b":[{"x":189.82,"y":452.93,"z":93.56},{"x":193.24,"y":451.1,"z":95.44},{"x":193.49,"y":450.06,"z":99.72},{"x":190.3,"y":450.86,"z":102.19},{"x":186.83,"y":452.73,"z":100.33},{"x":186.6,"y":453.77,"z":95.98}]},{"lat":-62.95,"lon":150.63,"b":[{"x":197.91,"y":446.39,"z":107.23},{"x":201.26,"y":444.46,"z":109.04},{"x":201.45,"y":443.3,"z":113.3},{"x":198.3,"y":444.07,"z":115.81},{"x":194.91,"y":446.03,"z":114.02},{"x":194.72,"y":447.2,"z":109.7}]},{"lat":-61.2,"lon":148.75,"b":[{"x":205.72,"y":439.37,"z":120.68},{"x":208.98,"y":437.36,"z":122.43},{"x":209.13,"y":436.08,"z":126.65},{"x":206.01,"y":436.81,"z":129.18},{"x":202.71,"y":438.86,"z":127.47},{"x":202.57,"y":440.14,"z":123.19}]},{"lat":-69.77,"lon":155.8,"b":[{"x":157.39,"y":469.83,"z":66.52},{"x":161.06,"y":468.29,"z":68.54},{"x":161.36,"y":467.53,"z":72.89},{"x":157.97,"y":468.3,"z":75.29},{"x":154.25,"y":469.86,"z":73.27},{"x":153.98,"y":470.62,"z":68.86}]},{"lat":-68.04,"lon":152.93,"b":[{"x":166.18,"y":464.55,"z":80.69},{"x":169.79,"y":462.9,"z":82.66},{"x":170.06,"y":462,"z":87.02},{"x":166.7,"y":462.75,"z":89.46},{"x":163.04,"y":464.43,"z":87.49},{"x":162.79,"y":465.33,"z":83.08}]},{"lat":-66.28,"lon":150.48,"b":[{"x":174.76,"y":458.71,"z":94.75},{"x":178.31,"y":456.94,"z":96.67},{"x":178.54,"y":455.91,"z":101.02},{"x":175.21,"y":456.64,"z":103.5},{"x":171.62,"y":458.43,"z":101.59},{"x":171.4,"y":459.46,"z":97.19}]},{"lat":-64.49,"lon":148.35,"b":[{"x":183.11,"y":452.33,"z":108.65},{"x":186.57,"y":450.46,"z":110.51},{"x":186.76,"y":449.3,"z":114.83},{"x":183.47,"y":450,"z":117.35},{"x":179.96,"y":451.89,"z":115.51},{"x":179.78,"y":453.06,"z":111.13}]},{"lat":-62.68,"lon":146.5,"b":[{"x":191.18,"y":445.44,"z":122.35},{"x":194.57,"y":443.48,"z":124.14},{"x":194.71,"y":442.19,"z":128.42},{"x":191.46,"y":442.86,"z":130.97},{"x":188.03,"y":444.84,"z":129.21},{"x":187.89,"y":446.14,"z":124.87}]},{"lat":-60.86,"lon":144.87,"b":[{"x":198.96,"y":438.07,"z":135.79},{"x":202.27,"y":436.03,"z":137.5},{"x":202.36,"y":434.63,"z":141.74},{"x":199.14,"y":435.26,"z":144.31},{"x":195.8,"y":437.33,"z":142.63},{"x":195.71,"y":438.74,"z":138.34}]},{"lat":-69.7,"lon":150.27,"b":[{"x":150.36,"y":469.75,"z":81.6},{"x":154.08,"y":468.19,"z":83.61},{"x":154.33,"y":467.3,"z":88.02},{"x":150.84,"y":467.97,"z":90.47},{"x":147.07,"y":469.55,"z":88.46},{"x":146.84,"y":470.44,"z":84}]},{"lat":-67.87,"lon":147.82,"b":[{"x":159.15,"y":464.13,"z":95.87},{"x":162.8,"y":462.45,"z":97.84},{"x":163.02,"y":461.41,"z":102.24},{"x":159.56,"y":462.06,"z":104.73},{"x":155.86,"y":463.76,"z":102.77},{"x":155.66,"y":464.8,"z":98.32}]},{"lat":-66.02,"lon":145.73,"b":[{"x":167.72,"y":457.93,"z":110},{"x":171.31,"y":456.14,"z":111.91},{"x":171.49,"y":454.97,"z":116.29},{"x":168.06,"y":455.6,"z":118.81},{"x":164.43,"y":457.41,"z":116.92},{"x":164.26,"y":458.58,"z":112.49}]},{"lat":-64.15,"lon":143.94,"b":[{"x":176.05,"y":451.2,"z":123.93},{"x":179.56,"y":449.3,"z":125.77},{"x":179.7,"y":448.01,"z":130.11},{"x":176.31,"y":448.6,"z":132.67},{"x":172.75,"y":450.52,"z":130.86},{"x":172.62,"y":451.82,"z":126.46}]},{"lat":-62.28,"lon":142.39,"b":[{"x":184.1,"y":443.96,"z":137.61},{"x":187.54,"y":441.97,"z":139.38},{"x":187.62,"y":440.56,"z":143.67},{"x":184.27,"y":441.12,"z":146.26},{"x":180.8,"y":443.12,"z":144.52},{"x":180.72,"y":444.55,"z":140.17}]},{"lat":-60.41,"lon":141.03,"b":[{"x":191.87,"y":436.25,"z":151.01},{"x":195.21,"y":434.19,"z":152.69},{"x":195.24,"y":432.66,"z":156.92},{"x":191.93,"y":433.18,"z":159.53},{"x":188.55,"y":435.27,"z":157.88},{"x":188.52,"y":436.81,"z":153.59}]},{"lat":-71.34,"lon":147.09,"b":[{"x":134.04,"y":474.44,"z":82.91},{"x":137.45,"y":473.14,"z":84.74},{"x":137.66,"y":472.35,"z":88.72},{"x":134.43,"y":472.86,"z":90.91},{"x":130.98,"y":474.18,"z":89.08},{"x":130.79,"y":474.97,"z":85.06}]},{"lat":-69.45,"lon":144.71,"b":[{"x":142.99,"y":469.14,"z":96.91},{"x":146.76,"y":467.56,"z":98.92},{"x":146.96,"y":466.53,"z":103.37},{"x":143.37,"y":467.08,"z":105.87},{"x":139.56,"y":468.68,"z":103.86},{"x":139.38,"y":469.71,"z":99.36}]},{"lat":-67.54,"lon":142.71,"b":[{"x":151.78,"y":463.16,"z":111.26},{"x":155.48,"y":461.45,"z":113.21},{"x":155.65,"y":460.29,"z":117.64},{"x":152.1,"y":460.82,"z":120.17},{"x":148.34,"y":462.54,"z":118.23},{"x":148.19,"y":463.71,"z":113.75}]},{"lat":-65.61,"lon":141.03,"b":[{"x":160.34,"y":456.61,"z":125.42},{"x":163.98,"y":454.79,"z":127.31},{"x":164.11,"y":453.49,"z":131.7},{"x":160.59,"y":454,"z":134.27},{"x":156.91,"y":455.83,"z":132.4},{"x":156.79,"y":457.14,"z":127.95}]},{"lat":-63.68,"lon":139.58,"b":[{"x":168.66,"y":449.52,"z":139.34},{"x":172.22,"y":447.61,"z":141.15},{"x":172.3,"y":446.18,"z":145.5},{"x":168.82,"y":446.65,"z":148.09},{"x":165.21,"y":448.59,"z":146.31},{"x":165.14,"y":450.03,"z":141.9}]},{"lat":-61.75,"lon":138.33,"b":[{"x":176.69,"y":441.94,"z":152.97},{"x":180.17,"y":439.93,"z":154.71},{"x":180.2,"y":438.38,"z":159},{"x":176.76,"y":438.83,"z":161.61},{"x":173.24,"y":440.85,"z":159.91},{"x":173.21,"y":442.41,"z":155.56}]},{"lat":-59.84,"lon":137.24,"b":[{"x":184.43,"y":433.9,"z":166.28},{"x":187.82,"y":431.81,"z":167.92},{"x":187.8,"y":430.16,"z":172.14},{"x":184.4,"y":430.56,"z":174.77},{"x":180.97,"y":432.66,"z":173.16},{"x":180.99,"y":434.34,"z":168.89}]},{"lat":-74.87,"lon":146.01,"b":[{"x":108.1,"y":482.89,"z":71.45},{"x":109.41,"y":482.49,"z":72.15},{"x":109.48,"y":482.25,"z":73.64},{"x":108.24,"y":482.41,"z":74.43},{"x":106.92,"y":482.81,"z":73.73},{"x":106.86,"y":483.05,"z":72.23}]},{"lat":-72.96,"lon":143.25,"b":[{"x":117.36,"y":478.26,"z":86.4},{"x":118.48,"y":477.88,"z":87},{"x":118.54,"y":477.63,"z":88.29},{"x":117.47,"y":477.76,"z":88.99},{"x":116.34,"y":478.15,"z":88.39},{"x":116.29,"y":478.4,"z":87.09}]},{"lat":-71,"lon":141.03,"b":[{"x":126.34,"y":473.68,"z":97.97},{"x":130.1,"y":472.24,"z":99.97},{"x":130.28,"y":471.24,"z":104.35},{"x":126.68,"y":471.68,"z":106.78},{"x":122.87,"y":473.13,"z":104.78},{"x":122.71,"y":474.13,"z":100.36}]},{"lat":-69.03,"lon":139.21,"b":[{"x":135.31,"y":467.96,"z":112.41},{"x":139.12,"y":466.35,"z":114.41},{"x":139.28,"y":465.18,"z":118.9},{"x":135.6,"y":465.61,"z":121.42},{"x":131.74,"y":467.23,"z":119.43},{"x":131.6,"y":468.41,"z":114.9}]},{"lat":-67.04,"lon":137.69,"b":[{"x":144.09,"y":461.62,"z":126.79},{"x":147.84,"y":459.89,"z":128.73},{"x":147.96,"y":458.58,"z":133.18},{"x":144.31,"y":458.99,"z":135.74},{"x":140.52,"y":460.73,"z":133.82},{"x":140.41,"y":462.05,"z":129.32}]},{"lat":-65.05,"lon":136.42,"b":[{"x":152.64,"y":454.71,"z":140.95},{"x":156.33,"y":452.88,"z":142.81},{"x":156.4,"y":451.44,"z":147.22},{"x":152.79,"y":451.82,"z":149.81},{"x":149.07,"y":453.67,"z":147.96},{"x":149,"y":455.12,"z":143.51}]},{"lat":-63.07,"lon":135.32,"b":[{"x":160.95,"y":447.28,"z":154.82},{"x":164.55,"y":445.34,"z":156.61},{"x":164.58,"y":443.78,"z":160.95},{"x":161.01,"y":444.13,"z":163.56},{"x":157.36,"y":446.08,"z":161.8},{"x":157.34,"y":447.66,"z":157.41}]},{"lat":-61.1,"lon":134.38,"b":[{"x":168.97,"y":439.35,"z":168.37},{"x":172.48,"y":437.33,"z":170.07},{"x":172.47,"y":435.65,"z":174.34},{"x":168.93,"y":435.97,"z":176.97},{"x":165.38,"y":438.01,"z":175.3},{"x":165.39,"y":439.71,"z":170.98}]},{"lat":-59.15,"lon":133.56,"b":[{"x":176.68,"y":430.99,"z":181.55},{"x":180.11,"y":428.89,"z":183.16},{"x":180.04,"y":427.11,"z":187.35},{"x":176.55,"y":427.4,"z":189.98},{"x":173.09,"y":429.5,"z":188.41},{"x":173.15,"y":431.31,"z":184.17}]},{"lat":-74.51,"lon":138.57,"b":[{"x":100.08,"y":482.08,"z":86.92},{"x":101.37,"y":481.69,"z":87.61},{"x":101.43,"y":481.4,"z":89.07},{"x":100.19,"y":481.52,"z":89.86},{"x":98.89,"y":481.91,"z":89.17},{"x":98.84,"y":482.19,"z":87.69}]},{"lat":-70.46,"lon":135.12,"b":[{"x":118.36,"y":472.22,"z":113.69},{"x":122.06,"y":470.81,"z":115.63},{"x":122.19,"y":469.7,"z":119.92},{"x":118.6,"y":470,"z":122.31},{"x":114.86,"y":471.43,"z":120.37},{"x":114.75,"y":472.54,"z":116.05}]},{"lat":-68.42,"lon":133.87,"b":[{"x":127.32,"y":466.17,"z":128.05},{"x":131.18,"y":464.55,"z":130.04},{"x":131.29,"y":463.24,"z":134.54},{"x":127.53,"y":463.54,"z":137.09},{"x":123.63,"y":465.17,"z":135.11},{"x":123.53,"y":466.49,"z":130.57}]},{"lat":-66.38,"lon":132.83,"b":[{"x":136.1,"y":459.48,"z":142.42},{"x":139.89,"y":457.74,"z":144.35},{"x":139.96,"y":456.28,"z":148.8},{"x":136.23,"y":456.56,"z":151.38},{"x":132.4,"y":458.32,"z":149.48},{"x":132.33,"y":459.78,"z":144.98}]},{"lat":-64.35,"lon":131.95,"b":[{"x":144.64,"y":452.22,"z":156.53},{"x":148.37,"y":450.37,"z":158.38},{"x":148.4,"y":448.79,"z":162.77},{"x":144.7,"y":449.04,"z":165.37},{"x":140.94,"y":450.9,"z":163.55},{"x":140.91,"y":452.5,"z":159.11}]},{"lat":-62.33,"lon":131.2,"b":[{"x":152.93,"y":444.44,"z":170.32},{"x":156.57,"y":442.5,"z":172.08},{"x":156.56,"y":440.8,"z":176.4},{"x":152.9,"y":441.02,"z":179.02},{"x":149.22,"y":442.98,"z":177.29},{"x":149.24,"y":444.7,"z":172.92}]},{"lat":-60.33,"lon":130.55,"b":[{"x":160.94,"y":436.2,"z":183.74},{"x":164.49,"y":434.16,"z":185.41},{"x":164.43,"y":432.35,"z":189.65},{"x":160.81,"y":432.55,"z":192.27},{"x":157.22,"y":434.59,"z":190.64},{"x":157.28,"y":436.42,"z":186.35}]},{"lat":-58.36,"lon":129.99,"b":[{"x":168.64,"y":427.53,"z":196.76},{"x":172.1,"y":425.42,"z":198.33},{"x":171.98,"y":423.51,"z":202.47},{"x":168.41,"y":423.68,"z":205.1},{"x":164.91,"y":425.78,"z":203.58},{"x":165.02,"y":427.72,"z":199.38}]},{"lat":-71.81,"lon":130.36,"b":[{"x":101.07,"y":475.17,"z":118.26},{"x":101.68,"y":474.96,"z":118.58},{"x":101.69,"y":474.78,"z":119.27},{"x":101.1,"y":474.81,"z":119.65},{"x":100.49,"y":475.02,"z":119.34},{"x":100.47,"y":475.2,"z":118.64}]},{"lat":-69.72,"lon":129.49,"b":[{"x":110.08,"y":470.24,"z":129.16},{"x":114.04,"y":468.73,"z":131.2},{"x":114.14,"y":467.41,"z":135.75},{"x":110.26,"y":467.59,"z":138.29},{"x":106.27,"y":469.11,"z":136.25},{"x":106.19,"y":470.44,"z":131.67}]},{"lat":-67.64,"lon":128.78,"b":[{"x":119.05,"y":463.77,"z":143.76},{"x":122.95,"y":462.14,"z":145.73},{"x":123.02,"y":460.68,"z":150.23},{"x":119.17,"y":460.84,"z":152.8},{"x":115.24,"y":462.49,"z":150.84},{"x":115.18,"y":463.96,"z":146.3}]},{"lat":-65.56,"lon":128.19,"b":[{"x":127.82,"y":456.72,"z":158.09},{"x":131.66,"y":454.97,"z":159.99},{"x":131.68,"y":453.37,"z":164.44},{"x":127.87,"y":453.52,"z":167.02},{"x":124,"y":455.28,"z":165.14},{"x":123.98,"y":456.88,"z":160.65}]},{"lat":-63.5,"lon":127.69,"b":[{"x":136.36,"y":449.12,"z":172.11},{"x":140.12,"y":447.26,"z":173.93},{"x":140.11,"y":445.54,"z":178.3},{"x":136.33,"y":445.66,"z":180.9},{"x":132.54,"y":447.53,"z":179.11},{"x":132.55,"y":449.26,"z":174.69}]},{"lat":-61.46,"lon":127.26,"b":[{"x":144.63,"y":441.02,"z":185.77},{"x":148.31,"y":439.06,"z":187.5},{"x":148.25,"y":437.23,"z":191.79},{"x":144.52,"y":437.32,"z":194.39},{"x":140.81,"y":439.28,"z":192.7},{"x":140.86,"y":441.14,"z":188.37}]},{"lat":-59.45,"lon":126.89,"b":[{"x":152.63,"y":432.46,"z":199.03},{"x":156.22,"y":430.42,"z":200.66},{"x":156.11,"y":428.48,"z":204.85},{"x":152.42,"y":428.55,"z":207.46},{"x":148.79,"y":430.59,"z":205.87},{"x":148.89,"y":432.55,"z":201.64}]},{"lat":-57.46,"lon":126.56,"b":[{"x":160.31,"y":423.5,"z":211.85},{"x":163.81,"y":421.39,"z":213.37},{"x":163.65,"y":419.36,"z":217.46},{"x":160.01,"y":419.4,"z":220.07},{"x":156.47,"y":421.5,"z":218.59},{"x":156.62,"y":423.57,"z":214.46}]},{"lat":-73.04,"lon":124.81,"b":[{"x":83.19,"y":479.01,"z":116.47},{"x":86.1,"y":478.13,"z":118},{"x":86.17,"y":477.29,"z":121.29},{"x":83.32,"y":477.34,"z":123.07},{"x":80.39,"y":478.23,"z":121.53},{"x":80.33,"y":479.07,"z":118.22}]},{"lat":-70.92,"lon":124.48,"b":[{"x":92.42,"y":473.76,"z":130.13},{"x":96.46,"y":472.37,"z":132.22},{"x":96.55,"y":471.05,"z":136.81},{"x":92.58,"y":471.1,"z":139.33},{"x":88.5,"y":472.5,"z":137.24},{"x":88.43,"y":473.83,"z":132.62}]},{"lat":-68.8,"lon":124.21,"b":[{"x":101.56,"y":467.55,"z":144.93},{"x":105.55,"y":466.03,"z":146.96},{"x":105.61,"y":464.56,"z":151.5},{"x":101.66,"y":464.6,"z":154.05},{"x":97.64,"y":466.13,"z":152.02},{"x":97.59,"y":467.61,"z":147.45}]},{"lat":-66.7,"lon":123.99,"b":[{"x":110.52,"y":460.73,"z":159.48},{"x":114.46,"y":459.09,"z":161.44},{"x":114.49,"y":457.48,"z":165.93},{"x":110.57,"y":457.5,"z":168.49},{"x":106.6,"y":459.15,"z":166.54},{"x":106.58,"y":460.77,"z":162.02}]},{"lat":-64.6,"lon":123.8,"b":[{"x":119.29,"y":453.34,"z":173.73},{"x":123.16,"y":451.58,"z":175.61},{"x":123.14,"y":449.84,"z":180.02},{"x":119.26,"y":449.84,"z":182.6},{"x":115.36,"y":451.61,"z":180.74},{"x":115.37,"y":453.36,"z":176.29}]},{"lat":-62.53,"lon":123.65,"b":[{"x":127.81,"y":445.41,"z":187.62},{"x":131.61,"y":443.54,"z":189.41},{"x":131.56,"y":441.68,"z":193.74},{"x":127.71,"y":441.67,"z":196.32},{"x":123.88,"y":443.53,"z":194.57},{"x":123.93,"y":445.41,"z":190.19}]},{"lat":-60.48,"lon":123.51,"b":[{"x":136.08,"y":436.99,"z":201.11},{"x":139.79,"y":435.03,"z":202.81},{"x":139.7,"y":433.07,"z":207.04},{"x":135.89,"y":433.03,"z":209.63},{"x":132.15,"y":434.98,"z":207.97},{"x":132.24,"y":436.98,"z":203.7}]},{"lat":-58.46,"lon":123.39,"b":[{"x":144.06,"y":428.14,"z":214.17},{"x":147.69,"y":426.11,"z":215.76},{"x":147.54,"y":424.04,"z":219.89},{"x":143.78,"y":423.98,"z":222.48},{"x":140.12,"y":426.01,"z":220.93},{"x":140.26,"y":428.1,"z":216.76}]},{"lat":-56.47,"lon":123.29,"b":[{"x":151.74,"y":418.91,"z":226.75},{"x":155.27,"y":416.81,"z":228.23},{"x":155.08,"y":414.66,"z":232.26},{"x":151.36,"y":414.58,"z":234.83},{"x":147.8,"y":416.67,"z":233.4},{"x":147.98,"y":418.85,"z":229.34}]},{"lat":-71.98,"lon":118.78,"b":[{"x":74.4,"y":476.7,"z":130.94},{"x":78.51,"y":475.44,"z":133.08},{"x":78.58,"y":474.12,"z":137.7},{"x":74.52,"y":474.04,"z":140.19},{"x":70.38,"y":475.3,"z":138.05},{"x":70.33,"y":476.63,"z":133.41}]},{"lat":-69.85,"lon":119.08,"b":[{"x":83.67,"y":470.77,"z":145.93},{"x":87.74,"y":469.38,"z":148.02},{"x":87.79,"y":467.9,"z":152.59},{"x":83.75,"y":467.81,"z":155.11},{"x":79.65,"y":469.21,"z":153.03},{"x":79.61,"y":470.69,"z":148.42}]},{"lat":-67.72,"lon":119.33,"b":[{"x":92.8,"y":464.21,"z":160.68},{"x":96.83,"y":462.68,"z":162.7},{"x":96.85,"y":461.06,"z":167.23},{"x":92.84,"y":460.96,"z":169.76},{"x":88.78,"y":462.49,"z":167.75},{"x":88.76,"y":464.12,"z":163.2}]},{"lat":-65.61,"lon":119.53,"b":[{"x":101.76,"y":457.04,"z":175.15},{"x":105.73,"y":455.39,"z":177.09},{"x":105.72,"y":453.64,"z":181.54},{"x":101.74,"y":453.52,"z":184.09},{"x":97.74,"y":455.17,"z":182.17},{"x":97.75,"y":456.94,"z":177.68}]},{"lat":-63.51,"lon":119.7,"b":[{"x":110.52,"y":449.32,"z":189.27},{"x":114.42,"y":447.55,"z":191.12},{"x":114.37,"y":445.68,"z":195.49},{"x":110.43,"y":445.54,"z":198.04},{"x":106.5,"y":447.3,"z":196.22},{"x":106.54,"y":449.2,"z":191.81}]},{"lat":-61.44,"lon":119.85,"b":[{"x":119.04,"y":441.07,"z":202.99},{"x":122.87,"y":439.21,"z":204.75},{"x":122.78,"y":437.22,"z":209.03},{"x":118.87,"y":437.07,"z":211.58},{"x":115.02,"y":438.92,"z":209.86},{"x":115.09,"y":440.94,"z":205.55}]},{"lat":-59.39,"lon":119.98,"b":[{"x":127.3,"y":432.37,"z":216.28},{"x":131.04,"y":430.41,"z":217.94},{"x":130.91,"y":428.32,"z":222.11},{"x":127.05,"y":428.15,"z":224.66},{"x":123.27,"y":430.09,"z":223.04},{"x":123.39,"y":432.22,"z":218.84}]},{"lat":-57.38,"lon":120.09,"b":[{"x":135.27,"y":423.25,"z":229.1},{"x":138.93,"y":421.22,"z":230.65},{"x":138.75,"y":419.04,"z":234.71},{"x":134.93,"y":418.85,"z":237.25},{"x":131.25,"y":420.86,"z":235.75},{"x":131.41,"y":423.08,"z":231.65}]},{"lat":-55.4,"lon":120.19,"b":[{"x":142.94,"y":413.78,"z":241.42},{"x":146.51,"y":411.69,"z":242.85},{"x":146.28,"y":409.42,"z":246.79},{"x":142.51,"y":409.22,"z":249.33},{"x":138.92,"y":411.29,"z":247.93},{"x":139.13,"y":413.59,"z":243.96}]},{"lat":-74.97,"lon":111.12,"b":[{"x":46.66,"y":483.82,"z":116.93},{"x":50.24,"y":482.99,"z":118.84},{"x":50.29,"y":481.98,"z":122.84},{"x":46.75,"y":481.8,"z":124.93},{"x":43.14,"y":482.63,"z":123.01},{"x":43.11,"y":483.64,"z":119}]},{"lat":-72.86,"lon":112.39,"b":[{"x":56.07,"y":478.97,"z":131.78},{"x":60.05,"y":477.9,"z":133.88},{"x":60.11,"y":476.63,"z":138.32},{"x":56.16,"y":476.42,"z":140.68},{"x":52.16,"y":477.49,"z":138.57},{"x":52.12,"y":478.77,"z":134.12}]},{"lat":-70.74,"lon":113.39,"b":[{"x":65.44,"y":473.4,"z":146.74},{"x":69.58,"y":472.14,"z":148.88},{"x":69.62,"y":470.65,"z":153.49},{"x":65.51,"y":470.43,"z":155.98},{"x":61.34,"y":471.69,"z":153.84},{"x":61.31,"y":473.18,"z":149.21}]},{"lat":-68.62,"lon":114.2,"b":[{"x":74.7,"y":467.11,"z":161.69},{"x":78.81,"y":465.71,"z":163.77},{"x":78.82,"y":464.08,"z":168.32},{"x":74.73,"y":463.85,"z":170.82},{"x":70.61,"y":465.25,"z":168.75},{"x":70.59,"y":466.89,"z":164.17}]},{"lat":-66.5,"lon":114.87,"b":[{"x":83.83,"y":460.21,"z":176.36},{"x":87.89,"y":458.67,"z":178.37},{"x":87.88,"y":456.91,"z":182.85},{"x":83.82,"y":456.66,"z":185.36},{"x":79.74,"y":458.19,"z":183.37},{"x":79.74,"y":459.97,"z":178.86}]},{"lat":-64.39,"lon":115.43,"b":[{"x":92.79,"y":452.71,"z":190.7},{"x":96.79,"y":451.06,"z":192.62},{"x":96.75,"y":449.16,"z":197.02},{"x":92.72,"y":448.9,"z":199.54},{"x":88.69,"y":450.55,"z":197.64},{"x":88.73,"y":452.46,"z":193.21}]},{"lat":-62.31,"lon":115.9,"b":[{"x":101.54,"y":444.67,"z":204.65},{"x":105.48,"y":442.91,"z":206.47},{"x":105.4,"y":440.89,"z":210.79},{"x":101.4,"y":440.62,"z":213.3},{"x":97.45,"y":442.37,"z":211.5},{"x":97.51,"y":444.41,"z":207.16}]},{"lat":-60.24,"lon":116.31,"b":[{"x":110.06,"y":436.13,"z":218.17},{"x":113.92,"y":434.27,"z":219.89},{"x":113.8,"y":432.15,"z":224.1},{"x":109.84,"y":431.86,"z":226.61},{"x":105.96,"y":433.71,"z":224.92},{"x":106.06,"y":435.86,"z":220.68}]},{"lat":-58.21,"lon":116.66,"b":[{"x":118.32,"y":427.16,"z":231.22},{"x":122.09,"y":425.22,"z":232.83},{"x":121.93,"y":423,"z":236.93},{"x":118.01,"y":422.7,"z":239.43},{"x":114.22,"y":424.62,"z":237.85},{"x":114.36,"y":426.87,"z":233.73}]},{"lat":-56.21,"lon":116.97,"b":[{"x":126.29,"y":417.8,"z":243.76},{"x":129.98,"y":415.78,"z":245.27},{"x":129.77,"y":413.49,"z":249.24},{"x":125.9,"y":413.17,"z":251.73},{"x":122.19,"y":415.17,"z":250.27},{"x":122.38,"y":417.5,"z":246.27}]},{"lat":-54.25,"lon":117.25,"b":[{"x":133.96,"y":408.12,"z":255.78},{"x":137.55,"y":406.04,"z":257.18},{"x":137.3,"y":403.67,"z":261.02},{"x":133.48,"y":403.34,"z":263.49},{"x":129.86,"y":405.39,"z":262.14},{"x":130.09,"y":407.8,"z":258.27}]},{"lat":-79.55,"lon":95.88,"b":[{"x":9.28,"y":492.27,"z":86.7},{"x":12.41,"y":491.9,"z":88.43},{"x":12.44,"y":491.25,"z":91.94},{"x":9.3,"y":490.99,"z":93.71},{"x":6.15,"y":491.37,"z":91.96},{"x":6.15,"y":492.01,"z":88.45}]},{"lat":-77.6,"lon":100.01,"b":[{"x":18.67,"y":488.47,"z":105.04},{"x":19.3,"y":488.37,"z":105.38},{"x":19.31,"y":488.22,"z":106.09},{"x":18.68,"y":488.16,"z":106.45},{"x":18.04,"y":488.26,"z":106.1},{"x":18.04,"y":488.42,"z":105.39}]},{"lat":-75.58,"lon":103.05,"b":[{"x":28.07,"y":485.33,"z":116.58},{"x":32.27,"y":484.51,"z":118.86},{"x":32.32,"y":483.33,"z":123.54},{"x":28.13,"y":482.97,"z":125.95},{"x":23.9,"y":483.79,"z":123.66},{"x":23.88,"y":484.97,"z":118.97}]},{"lat":-73.53,"lon":105.36,"b":[{"x":37.51,"y":480.62,"z":132.37},{"x":41.42,"y":479.72,"z":134.46},{"x":41.45,"y":478.48,"z":138.79},{"x":37.57,"y":478.14,"z":141.04},{"x":33.65,"y":479.04,"z":138.95},{"x":33.63,"y":480.28,"z":134.61}]},{"lat":-71.44,"lon":107.17,"b":[{"x":46.94,"y":475.4,"z":147.36},{"x":51.13,"y":474.28,"z":149.56},{"x":51.16,"y":472.79,"z":154.19},{"x":46.99,"y":472.41,"z":156.64},{"x":42.78,"y":473.54,"z":154.44},{"x":42.76,"y":475.03,"z":149.79}]},{"lat":-69.35,"lon":108.63,"b":[{"x":56.3,"y":469.41,"z":162.48},{"x":60.47,"y":468.15,"z":164.62},{"x":60.48,"y":466.51,"z":169.2},{"x":56.33,"y":466.13,"z":171.66},{"x":52.14,"y":467.4,"z":169.53},{"x":52.13,"y":469.04,"z":164.93}]},{"lat":-67.25,"lon":109.83,"b":[{"x":65.57,"y":462.78,"z":177.35},{"x":69.7,"y":461.38,"z":179.42},{"x":69.69,"y":459.6,"z":183.93},{"x":65.56,"y":459.21,"z":186.4},{"x":61.41,"y":460.61,"z":184.34},{"x":61.41,"y":462.4,"z":179.81}]},{"lat":-65.15,"lon":110.82,"b":[{"x":74.7,"y":455.54,"z":191.89},{"x":78.78,"y":454.01,"z":193.88},{"x":78.74,"y":452.1,"z":198.31},{"x":74.64,"y":451.7,"z":200.78},{"x":70.54,"y":453.23,"z":198.82},{"x":70.56,"y":455.15,"z":194.36}]},{"lat":-63.07,"lon":111.67,"b":[{"x":83.65,"y":447.73,"z":206.06},{"x":87.68,"y":446.08,"z":207.95},{"x":87.61,"y":444.05,"z":212.3},{"x":83.53,"y":443.64,"z":214.77},{"x":79.49,"y":445.28,"z":212.9},{"x":79.55,"y":447.34,"z":208.53}]},{"lat":-61,"lon":112.39,"b":[{"x":92.41,"y":439.4,"z":219.8},{"x":96.36,"y":437.64,"z":221.6},{"x":96.26,"y":435.5,"z":225.84},{"x":92.22,"y":435.08,"z":228.3},{"x":88.24,"y":436.83,"z":226.53},{"x":88.33,"y":438.99,"z":222.27}]},{"lat":-58.96,"lon":113.02,"b":[{"x":100.92,"y":430.6,"z":233.08},{"x":104.8,"y":428.75,"z":234.77},{"x":104.66,"y":426.5,"z":238.89},{"x":100.66,"y":426.08,"z":241.35},{"x":96.76,"y":427.91,"z":239.69},{"x":96.88,"y":430.18,"z":235.54}]},{"lat":-56.95,"lon":113.57,"b":[{"x":109.18,"y":421.38,"z":245.85},{"x":112.97,"y":419.45,"z":247.43},{"x":112.79,"y":417.12,"z":251.43},{"x":108.83,"y":416.69,"z":253.88},{"x":105.02,"y":418.6,"z":252.33},{"x":105.18,"y":420.96,"z":248.31}]},{"lat":-54.97,"lon":114.05,"b":[{"x":117.15,"y":411.81,"z":258.1},{"x":120.86,"y":409.81,"z":259.56},{"x":120.63,"y":407.41,"z":263.43},{"x":116.72,"y":406.97,"z":265.86},{"x":112.99,"y":408.94,"z":264.44},{"x":113.2,"y":411.38,"z":260.54}]},{"lat":-53.04,"lon":114.48,"b":[{"x":124.83,"y":401.94,"z":269.79},{"x":128.44,"y":399.89,"z":271.14},{"x":128.17,"y":397.43,"z":274.88},{"x":124.31,"y":396.98,"z":277.29},{"x":120.68,"y":399,"z":275.98},{"x":120.92,"y":401.5,"z":272.22}]},{"lat":-75.9,"lon":94.42,"b":[{"x":9.38,"y":485.33,"z":119.73},{"x":10.92,"y":485.08,"z":120.58},{"x":10.93,"y":484.66,"z":122.29},{"x":9.39,"y":484.47,"z":123.16},{"x":7.84,"y":484.71,"z":122.3},{"x":7.84,"y":485.14,"z":120.59}]},{"lat":-73.94,"lon":97.82,"b":[{"x":18.8,"y":481.72,"z":132.32},{"x":23.02,"y":480.9,"z":134.61},{"x":23.05,"y":479.57,"z":139.29},{"x":18.83,"y":479.05,"z":141.68},{"x":14.59,"y":479.87,"z":139.38},{"x":14.58,"y":481.21,"z":134.69}]},{"lat":-71.93,"lon":100.5,"b":[{"x":28.24,"y":476.74,"z":147.78},{"x":32.47,"y":475.77,"z":150.03},{"x":32.49,"y":474.28,"z":154.67},{"x":28.27,"y":473.76,"z":157.08},{"x":24.03,"y":474.73,"z":154.83},{"x":24.02,"y":476.22,"z":150.17}]},{"lat":-69.89,"lon":102.67,"b":[{"x":37.67,"y":471.07,"z":163.06},{"x":41.88,"y":469.95,"z":165.26},{"x":41.89,"y":468.31,"z":169.86},{"x":37.68,"y":467.78,"z":172.27},{"x":33.46,"y":468.9,"z":170.08},{"x":33.45,"y":470.55,"z":165.46}]},{"lat":-67.83,"lon":104.44,"b":[{"x":47.03,"y":464.74,"z":178.1},{"x":51.22,"y":463.48,"z":180.23},{"x":51.21,"y":461.69,"z":184.77},{"x":47.02,"y":461.16,"z":187.19},{"x":42.83,"y":462.42,"z":185.07},{"x":42.83,"y":464.22,"z":180.51}]},{"lat":-65.77,"lon":105.92,"b":[{"x":56.3,"y":457.78,"z":192.83},{"x":60.45,"y":456.38,"z":194.89},{"x":60.42,"y":454.46,"z":199.35},{"x":56.25,"y":453.92,"z":201.77},{"x":52.09,"y":455.32,"z":199.73},{"x":52.11,"y":457.25,"z":195.25}]},{"lat":-63.7,"lon":107.17,"b":[{"x":65.43,"y":450.23,"z":207.21},{"x":69.53,"y":448.7,"z":209.17},{"x":69.47,"y":446.65,"z":213.54},{"x":65.33,"y":446.11,"z":215.96},{"x":61.22,"y":447.63,"z":214.01},{"x":61.26,"y":449.69,"z":209.63}]},{"lat":-61.65,"lon":108.24,"b":[{"x":74.38,"y":442.12,"z":221.16},{"x":78.42,"y":440.48,"z":223.03},{"x":78.34,"y":438.32,"z":227.3},{"x":74.23,"y":437.77,"z":229.71},{"x":70.17,"y":439.4,"z":227.87},{"x":70.24,"y":441.58,"z":223.58}]},{"lat":-59.61,"lon":109.17,"b":[{"x":83.13,"y":433.53,"z":234.66},{"x":87.11,"y":431.78,"z":236.43},{"x":86.99,"y":429.51,"z":240.58},{"x":82.91,"y":428.96,"z":242.98},{"x":78.93,"y":430.69,"z":241.25},{"x":79.02,"y":432.98,"z":237.08}]},{"lat":-57.6,"lon":109.98,"b":[{"x":91.65,"y":424.48,"z":247.66},{"x":95.55,"y":422.65,"z":249.32},{"x":95.39,"y":420.29,"z":253.34},{"x":91.36,"y":419.74,"z":255.73},{"x":87.45,"y":421.55,"z":254.11},{"x":87.58,"y":423.94,"z":250.07}]},{"lat":-55.62,"lon":110.69,"b":[{"x":99.91,"y":415.06,"z":260.13},{"x":103.73,"y":413.15,"z":261.68},{"x":103.53,"y":410.71,"z":265.57},{"x":99.54,"y":410.15,"z":267.94},{"x":95.71,"y":412.04,"z":266.44},{"x":95.88,"y":414.51,"z":262.52}]},{"lat":-53.68,"lon":111.32,"b":[{"x":107.89,"y":405.31,"z":272.05},{"x":111.62,"y":403.34,"z":273.48},{"x":111.38,"y":400.83,"z":277.23},{"x":107.44,"y":400.27,"z":279.59},{"x":103.69,"y":402.22,"z":278.2},{"x":103.91,"y":404.75,"z":274.42}]},{"lat":-51.77,"lon":111.89,"b":[{"x":115.58,"y":395.29,"z":283.4},{"x":119.21,"y":393.27,"z":284.71},{"x":118.92,"y":390.72,"z":288.32},{"x":115.04,"y":390.15,"z":290.65},{"x":111.39,"y":392.14,"z":289.39},{"x":111.64,"y":394.73,"z":285.75}]},{"lat":-80.43,"lon":63.69,"b":[{"x":-36.82,"y":493.15,"z":73.68},{"x":-36.09,"y":493.14,"z":74.1},{"x":-36.1,"y":493.02,"z":74.92},{"x":-36.85,"y":492.9,"z":75.33},{"x":-37.58,"y":492.91,"z":74.9},{"x":-37.56,"y":493.04,"z":74.08}]},{"lat":-74.08,"lon":90,"b":[{"x":0,"y":482.06,"z":132.41},{"x":4.23,"y":481.4,"z":134.75},{"x":4.24,"y":480.06,"z":139.43},{"x":0,"y":479.39,"z":141.78},{"x":-4.24,"y":480.06,"z":139.43},{"x":-4.23,"y":481.4,"z":134.75}]},{"lat":-72.19,"lon":93.54,"b":[{"x":9.43,"y":477.42,"z":147.99},{"x":13.67,"y":476.6,"z":150.29},{"x":13.68,"y":475.1,"z":154.94},{"x":9.44,"y":474.43,"z":157.3},{"x":5.19,"y":475.25,"z":155},{"x":5.19,"y":476.75,"z":150.34}]},{"lat":-70.23,"lon":96.41,"b":[{"x":18.87,"y":472.08,"z":163.41},{"x":23.11,"y":471.1,"z":165.66},{"x":23.12,"y":469.46,"z":170.27},{"x":18.88,"y":468.78,"z":172.64},{"x":14.64,"y":469.76,"z":170.39},{"x":14.63,"y":471.41,"z":165.77}]},{"lat":-68.24,"lon":98.78,"b":[{"x":28.3,"y":466.06,"z":178.61},{"x":32.52,"y":464.94,"z":180.8},{"x":32.52,"y":463.15,"z":185.35},{"x":28.29,"y":462.47,"z":187.72},{"x":24.06,"y":463.59,"z":185.53},{"x":24.06,"y":465.39,"z":180.97}]},{"lat":-66.22,"lon":100.77,"b":[{"x":37.67,"y":459.4,"z":193.52},{"x":41.86,"y":458.14,"z":195.64},{"x":41.84,"y":456.2,"z":200.12},{"x":37.63,"y":455.52,"z":202.48},{"x":33.43,"y":456.78,"z":200.37},{"x":33.44,"y":458.73,"z":195.88}]},{"lat":-64.2,"lon":102.45,"b":[{"x":46.93,"y":452.13,"z":208.08},{"x":51.09,"y":450.73,"z":210.12},{"x":51.05,"y":448.67,"z":214.51},{"x":46.86,"y":447.99,"z":216.87},{"x":42.69,"y":449.37,"z":214.85},{"x":42.72,"y":451.45,"z":210.45}]},{"lat":-62.17,"lon":103.89,"b":[{"x":56.06,"y":444.28,"z":222.24},{"x":60.17,"y":442.76,"z":224.19},{"x":60.1,"y":440.58,"z":228.47},{"x":55.94,"y":439.9,"z":230.83},{"x":51.82,"y":441.4,"z":228.91},{"x":51.87,"y":443.6,"z":224.61}]},{"lat":-60.16,"lon":105.13,"b":[{"x":65.02,"y":435.91,"z":235.95},{"x":69.07,"y":434.28,"z":237.8},{"x":68.97,"y":431.99,"z":241.97},{"x":64.84,"y":431.31,"z":244.31},{"x":60.78,"y":432.92,"z":242.5},{"x":60.85,"y":435.23,"z":238.31}]},{"lat":-58.16,"lon":106.22,"b":[{"x":73.77,"y":427.08,"z":249.17},{"x":77.76,"y":425.35,"z":250.91},{"x":77.62,"y":422.96,"z":254.96},{"x":73.53,"y":422.28,"z":257.28},{"x":69.53,"y":423.99,"z":255.58},{"x":69.64,"y":426.39,"z":251.52}]},{"lat":-56.18,"lon":107.17,"b":[{"x":82.29,"y":417.83,"z":261.87},{"x":86.2,"y":416.01,"z":263.49},{"x":86.03,"y":413.55,"z":267.4},{"x":81.98,"y":412.87,"z":269.72},{"x":78.06,"y":414.65,"z":268.13},{"x":78.2,"y":417.15,"z":264.2}]},{"lat":-54.24,"lon":108.02,"b":[{"x":90.56,"y":408.22,"z":274.01},{"x":94.39,"y":406.34,"z":275.51},{"x":94.18,"y":403.8,"z":279.29},{"x":90.17,"y":403.13,"z":281.58},{"x":86.33,"y":404.98,"z":280.11},{"x":86.5,"y":407.54,"z":276.32}]},{"lat":-52.33,"lon":108.77,"b":[{"x":98.55,"y":398.33,"z":285.57},{"x":102.29,"y":396.38,"z":286.96},{"x":102.04,"y":393.79,"z":290.6},{"x":98.08,"y":393.12,"z":292.86},{"x":94.33,"y":395.03,"z":291.52},{"x":94.54,"y":397.65,"z":287.87}]},{"lat":-50.46,"lon":109.45,"b":[{"x":106.25,"y":388.19,"z":296.56},{"x":109.9,"y":386.2,"z":297.82},{"x":109.6,"y":383.57,"z":301.32},{"x":105.7,"y":382.9,"z":303.56},{"x":102.03,"y":384.86,"z":302.33},{"x":102.29,"y":387.52,"z":298.83}]},{"lat":-80.2,"lon":19.78,"b":[{"x":-79.99,"y":492.77,"z":27.62},{"x":-78.97,"y":492.89,"z":28.21},{"x":-79.03,"y":492.82,"z":29.39},{"x":-80.1,"y":492.61,"z":29.97},{"x":-81.12,"y":492.48,"z":29.36},{"x":-81.05,"y":492.56,"z":28.19}]},{"lat":-73.94,"lon":82.18,"b":[{"x":-18.82,"y":480.62,"z":136.51},{"x":-18.36,"y":480.57,"z":136.76},{"x":-18.36,"y":480.43,"z":137.27},{"x":-18.82,"y":480.34,"z":137.51},{"x":-19.27,"y":480.39,"z":137.26},{"x":-19.27,"y":480.54,"z":136.76}]},{"lat":-72.19,"lon":86.46,"b":[{"x":-9.43,"y":477.42,"z":147.99},{"x":-5.19,"y":476.75,"z":150.34},{"x":-5.19,"y":475.25,"z":155},{"x":-9.44,"y":474.43,"z":157.3},{"x":-13.68,"y":475.1,"z":154.94},{"x":-13.67,"y":476.6,"z":150.29}]},{"lat":-70.35,"lon":90,"b":[{"x":0,"y":472.42,"z":163.52},{"x":4.25,"y":471.59,"z":165.83},{"x":4.25,"y":469.94,"z":170.45},{"x":0,"y":469.12,"z":172.76},{"x":-4.25,"y":469.94,"z":170.45},{"x":-4.25,"y":471.59,"z":165.83}]},{"lat":-68.44,"lon":92.95,"b":[{"x":9.45,"y":466.73,"z":178.86},{"x":13.69,"y":465.75,"z":181.11},{"x":13.69,"y":463.95,"z":185.68},{"x":9.44,"y":463.13,"z":187.99},{"x":5.2,"y":464.1,"z":185.74},{"x":5.2,"y":465.9,"z":181.17}]},{"lat":-66.5,"lon":95.43,"b":[{"x":18.87,"y":460.38,"z":193.93},{"x":23.1,"y":459.26,"z":196.12},{"x":23.09,"y":457.32,"z":200.61},{"x":18.86,"y":456.5,"z":202.91},{"x":14.62,"y":457.61,"z":200.74},{"x":14.63,"y":459.56,"z":196.24}]},{"lat":-64.53,"lon":97.54,"b":[{"x":28.24,"y":453.41,"z":208.67},{"x":32.44,"y":452.15,"z":210.78},{"x":32.42,"y":450.07,"z":215.18},{"x":28.2,"y":449.25,"z":217.48},{"x":23.99,"y":450.5,"z":215.39},{"x":24,"y":452.58,"z":210.98}]},{"lat":-62.55,"lon":99.36,"b":[{"x":37.5,"y":445.84,"z":223.02},{"x":41.67,"y":444.45,"z":225.04},{"x":41.62,"y":442.26,"z":229.34},{"x":37.43,"y":441.44,"z":231.63},{"x":33.25,"y":442.81,"z":229.63},{"x":33.28,"y":445.02,"z":225.32}]},{"lat":-60.57,"lon":100.93,"b":[{"x":46.63,"y":437.73,"z":236.94},{"x":50.75,"y":436.22,"z":238.86},{"x":50.68,"y":433.91,"z":243.05},{"x":46.51,"y":433.1,"z":245.32},{"x":42.38,"y":434.59,"z":243.43},{"x":42.43,"y":436.91,"z":239.23}]},{"lat":-58.6,"lon":102.31,"b":[{"x":55.59,"y":429.12,"z":250.37},{"x":59.65,"y":427.51,"z":252.18},{"x":59.55,"y":425.11,"z":256.25},{"x":55.41,"y":424.29,"z":258.51},{"x":51.34,"y":425.89,"z":256.72},{"x":51.42,"y":428.31,"z":252.65}]},{"lat":-56.65,"lon":103.51,"b":[{"x":64.35,"y":420.08,"z":263.28},{"x":68.34,"y":418.37,"z":264.98},{"x":68.2,"y":415.88,"z":268.91},{"x":64.1,"y":415.08,"z":271.16},{"x":60.1,"y":416.76,"z":269.49},{"x":60.21,"y":419.27,"z":265.54}]},{"lat":-54.71,"lon":104.59,"b":[{"x":72.88,"y":410.66,"z":275.64},{"x":76.8,"y":408.87,"z":277.23},{"x":76.62,"y":406.31,"z":281.02},{"x":72.56,"y":405.51,"z":283.24},{"x":68.63,"y":407.26,"z":281.69},{"x":68.77,"y":409.85,"z":277.88}]},{"lat":-52.81,"lon":105.54,"b":[{"x":81.15,"y":400.91,"z":287.43},{"x":84.99,"y":399.05,"z":288.89},{"x":84.78,"y":396.43,"z":292.55},{"x":80.76,"y":395.64,"z":294.74},{"x":76.92,"y":397.46,"z":293.31},{"x":77.09,"y":400.11,"z":289.65}]},{"lat":-50.94,"lon":106.4,"b":[{"x":89.16,"y":390.9,"z":298.63},{"x":92.91,"y":388.99,"z":299.97},{"x":92.65,"y":386.33,"z":303.48},{"x":88.69,"y":385.54,"z":305.65},{"x":84.93,"y":387.42,"z":304.34},{"x":85.14,"y":390.11,"z":300.82}]},{"lat":-49.12,"lon":107.17,"b":[{"x":96.88,"y":380.69,"z":309.23},{"x":100.54,"y":378.73,"z":310.46},{"x":100.24,"y":376.04,"z":313.82},{"x":96.32,"y":375.27,"z":315.96},{"x":92.66,"y":377.18,"z":314.78},{"x":92.91,"y":379.9,"z":311.4}]},{"lat":-78.31,"lon":16.39,"b":[{"x":-97,"y":489.79,"z":25.24},{"x":-94.13,"y":490.26,"z":26.95},{"x":-94.32,"y":490.03,"z":30.35},{"x":-97.41,"y":489.31,"z":32.02},{"x":-100.27,"y":488.85,"z":30.27},{"x":-100.05,"y":489.09,"z":26.89}]},{"lat":-76.23,"lon":62.09,"b":[{"x":-55.68,"y":485.89,"z":103.83},{"x":-54.51,"y":485.88,"z":104.52},{"x":-54.53,"y":485.59,"z":105.85},{"x":-55.73,"y":485.31,"z":106.49},{"x":-56.89,"y":485.33,"z":105.79},{"x":-56.87,"y":485.62,"z":104.47}]},{"lat":-71.93,"lon":79.5,"b":[{"x":-28.25,"y":476.32,"z":149.19},{"x":-25.31,"y":475.96,"z":150.86},{"x":-25.31,"y":474.92,"z":154.11},{"x":-28.27,"y":474.24,"z":155.68},{"x":-31.21,"y":474.6,"z":154},{"x":-31.2,"y":475.64,"z":150.76}]},{"lat":-70.23,"lon":83.59,"b":[{"x":-18.88,"y":471.73,"z":164.44},{"x":-15.58,"y":471.21,"z":166.28},{"x":-15.58,"y":469.93,"z":169.87},{"x":-18.88,"y":469.17,"z":171.62},{"x":-22.17,"y":469.7,"z":169.78},{"x":-22.17,"y":470.98,"z":166.2}]},{"lat":-68.44,"lon":87.05,"b":[{"x":-9.45,"y":466.73,"z":178.86},{"x":-5.2,"y":465.9,"z":181.17},{"x":-5.2,"y":464.1,"z":185.74},{"x":-9.44,"y":463.13,"z":187.99},{"x":-13.69,"y":463.95,"z":185.68},{"x":-13.69,"y":465.75,"z":181.11}]},{"lat":-66.6,"lon":90,"b":[{"x":0,"y":460.71,"z":194.07},{"x":4.25,"y":459.74,"z":196.32},{"x":4.24,"y":457.79,"z":200.81},{"x":0,"y":456.82,"z":203.06},{"x":-4.24,"y":457.79,"z":200.81},{"x":-4.25,"y":459.74,"z":196.32}]},{"lat":-64.7,"lon":92.53,"b":[{"x":9.43,"y":454.05,"z":208.97},{"x":13.66,"y":452.93,"z":211.14},{"x":13.65,"y":450.85,"z":215.55},{"x":9.41,"y":449.89,"z":217.79},{"x":5.18,"y":451,"z":215.62},{"x":5.18,"y":453.08,"z":211.21}]},{"lat":-62.79,"lon":94.71,"b":[{"x":18.79,"y":446.78,"z":223.49},{"x":23,"y":445.53,"z":225.59},{"x":22.97,"y":443.33,"z":229.9},{"x":18.75,"y":442.37,"z":232.12},{"x":14.55,"y":443.61,"z":230.05},{"x":14.56,"y":445.82,"z":225.73}]},{"lat":-60.86,"lon":96.61,"b":[{"x":28.06,"y":438.95,"z":237.6},{"x":32.23,"y":437.58,"z":239.6},{"x":32.18,"y":435.26,"z":243.8},{"x":27.98,"y":434.3,"z":246.01},{"x":23.81,"y":435.66,"z":244.03},{"x":23.84,"y":437.99,"z":239.82}]},{"lat":-58.93,"lon":98.27,"b":[{"x":37.19,"y":430.6,"z":251.23},{"x":41.31,"y":429.12,"z":253.13},{"x":41.24,"y":426.69,"z":257.21},{"x":37.07,"y":425.75,"z":259.4},{"x":32.95,"y":427.22,"z":257.53},{"x":32.99,"y":429.65,"z":253.44}]},{"lat":-57,"lon":99.74,"b":[{"x":46.15,"y":421.79,"z":264.35},{"x":50.22,"y":420.2,"z":266.14},{"x":50.11,"y":417.69,"z":270.09},{"x":45.97,"y":416.76,"z":272.26},{"x":41.91,"y":418.33,"z":270.5},{"x":41.98,"y":420.85,"z":266.54}]},{"lat":-55.09,"lon":101.04,"b":[{"x":54.91,"y":412.58,"z":276.93},{"x":58.91,"y":410.9,"z":278.6},{"x":58.77,"y":408.31,"z":282.41},{"x":54.67,"y":407.39,"z":284.56},{"x":50.67,"y":409.04,"z":282.92},{"x":50.78,"y":411.64,"z":279.1}]},{"lat":-53.21,"lon":102.21,"b":[{"x":63.45,"y":403.01,"z":288.93},{"x":67.38,"y":401.25,"z":290.48},{"x":67.2,"y":398.61,"z":294.15},{"x":63.14,"y":397.7,"z":296.27},{"x":59.22,"y":399.42,"z":294.76},{"x":59.35,"y":402.09,"z":291.08}]},{"lat":-51.35,"lon":103.25,"b":[{"x":71.74,"y":393.16,"z":300.35},{"x":75.58,"y":391.34,"z":301.78},{"x":75.37,"y":388.64,"z":305.3},{"x":71.35,"y":387.75,"z":307.4},{"x":67.51,"y":389.53,"z":306},{"x":67.68,"y":392.25,"z":302.47}]},{"lat":-49.53,"lon":104.19,"b":[{"x":79.76,"y":383.07,"z":311.17},{"x":83.52,"y":381.2,"z":312.48},{"x":83.26,"y":378.47,"z":315.85},{"x":79.3,"y":377.59,"z":317.92},{"x":75.54,"y":379.42,"z":316.65},{"x":75.75,"y":382.18,"z":313.27}]},{"lat":-47.75,"lon":105.04,"b":[{"x":87.5,"y":372.81,"z":321.38},{"x":91.17,"y":370.9,"z":322.57},{"x":90.87,"y":368.15,"z":325.79},{"x":86.96,"y":367.28,"z":327.84},{"x":83.29,"y":369.15,"z":326.69},{"x":83.53,"y":371.93,"z":323.46}]},{"lat":-72.86,"lon":67.61,"b":[{"x":-56.13,"y":477.94,"z":135.7},{"x":-55.65,"y":477.91,"z":135.99},{"x":-55.65,"y":477.76,"z":136.53},{"x":-56.14,"y":477.63,"z":136.78},{"x":-56.62,"y":477.65,"z":136.49},{"x":-56.61,"y":477.81,"z":135.96}]},{"lat":-71.44,"lon":72.83,"b":[{"x":-46.95,"y":474.88,"z":149.11},{"x":-44.34,"y":474.65,"z":150.63},{"x":-44.35,"y":473.71,"z":153.53},{"x":-46.98,"y":473.01,"z":154.91},{"x":-49.59,"y":473.24,"z":153.38},{"x":-49.57,"y":474.18,"z":150.48}]},{"lat":-69.89,"lon":77.33,"b":[{"x":-37.67,"y":471.07,"z":163.06},{"x":-33.45,"y":470.55,"z":165.46},{"x":-33.46,"y":468.9,"z":170.08},{"x":-37.68,"y":467.78,"z":172.27},{"x":-41.89,"y":468.31,"z":169.86},{"x":-41.88,"y":469.95,"z":165.26}]},{"lat":-68.24,"lon":81.22,"b":[{"x":-28.3,"y":466.06,"z":178.61},{"x":-24.06,"y":465.39,"z":180.97},{"x":-24.06,"y":463.59,"z":185.53},{"x":-28.29,"y":462.47,"z":187.72},{"x":-32.52,"y":463.15,"z":185.35},{"x":-32.52,"y":464.94,"z":180.8}]},{"lat":-66.5,"lon":84.57,"b":[{"x":-18.87,"y":460.38,"z":193.93},{"x":-14.63,"y":459.56,"z":196.24},{"x":-14.62,"y":457.61,"z":200.74},{"x":-18.86,"y":456.5,"z":202.91},{"x":-23.09,"y":457.32,"z":200.61},{"x":-23.1,"y":459.26,"z":196.12}]},{"lat":-64.7,"lon":87.47,"b":[{"x":-9.43,"y":454.05,"z":208.97},{"x":-5.18,"y":453.08,"z":211.21},{"x":-5.18,"y":451,"z":215.62},{"x":-9.41,"y":449.89,"z":217.79},{"x":-13.65,"y":450.85,"z":215.55},{"x":-13.66,"y":452.93,"z":211.14}]},{"lat":-62.87,"lon":90,"b":[{"x":0,"y":447.1,"z":223.65},{"x":4.23,"y":445.99,"z":225.82},{"x":4.22,"y":443.78,"z":230.13},{"x":0,"y":442.68,"z":232.29},{"x":-4.22,"y":443.78,"z":230.13},{"x":-4.23,"y":445.99,"z":225.82}]},{"lat":-61,"lon":92.21,"b":[{"x":9.37,"y":439.57,"z":237.93},{"x":13.57,"y":438.33,"z":240.01},{"x":13.54,"y":436,"z":244.22},{"x":9.34,"y":434.91,"z":246.35},{"x":5.15,"y":436.14,"z":244.29},{"x":5.15,"y":438.47,"z":240.08}]},{"lat":-59.12,"lon":94.16,"b":[{"x":18.63,"y":431.5,"z":251.75},{"x":22.8,"y":430.14,"z":253.73},{"x":22.75,"y":427.71,"z":257.82},{"x":18.57,"y":426.63,"z":259.93},{"x":14.41,"y":427.97,"z":257.98},{"x":14.43,"y":430.41,"z":253.89}]},{"lat":-57.24,"lon":95.88,"b":[{"x":27.77,"y":422.95,"z":265.08},{"x":31.89,"y":421.48,"z":266.95},{"x":31.81,"y":418.95,"z":270.9},{"x":27.66,"y":417.89,"z":273},{"x":23.55,"y":419.34,"z":271.15},{"x":23.58,"y":421.87,"z":267.19}]},{"lat":-55.37,"lon":97.41,"b":[{"x":36.73,"y":413.97,"z":277.86},{"x":40.8,"y":412.4,"z":279.62},{"x":40.69,"y":409.8,"z":283.44},{"x":36.57,"y":408.75,"z":285.51},{"x":32.51,"y":410.29,"z":283.78},{"x":32.58,"y":412.9,"z":279.95}]},{"lat":-53.51,"lon":98.78,"b":[{"x":45.5,"y":404.61,"z":290.08},{"x":49.5,"y":402.96,"z":291.72},{"x":49.37,"y":400.29,"z":295.39},{"x":45.28,"y":399.26,"z":297.44},{"x":41.29,"y":400.88,"z":295.83},{"x":41.38,"y":403.56,"z":292.15}]},{"lat":-51.68,"lon":100.01,"b":[{"x":54.05,"y":394.94,"z":301.71},{"x":57.97,"y":393.22,"z":303.23},{"x":57.8,"y":390.5,"z":306.76},{"x":53.76,"y":389.48,"z":308.78},{"x":49.84,"y":391.17,"z":307.29},{"x":49.96,"y":393.91,"z":303.76}]},{"lat":-49.87,"lon":101.13,"b":[{"x":62.35,"y":385.01,"z":312.74},{"x":66.19,"y":383.23,"z":314.14},{"x":65.99,"y":380.47,"z":317.52},{"x":61.99,"y":379.48,"z":319.51},{"x":58.15,"y":381.22,"z":318.15},{"x":58.3,"y":384,"z":314.76}]},{"lat":-48.09,"lon":102.13,"b":[{"x":70.39,"y":374.89,"z":323.17},{"x":74.15,"y":373.06,"z":324.44},{"x":73.9,"y":370.28,"z":327.67},{"x":69.95,"y":369.3,"z":329.64},{"x":66.19,"y":371.09,"z":328.4},{"x":66.39,"y":373.89,"z":325.16}]},{"lat":-46.36,"lon":103.05,"b":[{"x":78.15,"y":364.62,"z":332.99},{"x":81.82,"y":362.75,"z":334.14},{"x":81.54,"y":359.96,"z":337.22},{"x":77.63,"y":359,"z":339.16},{"x":73.97,"y":360.82,"z":338.04},{"x":74.2,"y":363.64,"z":334.96}]},{"lat":-73.04,"lon":55.19,"b":[{"x":-83.2,"y":478.95,"z":116.75},{"x":-80.58,"y":479,"z":118.36},{"x":-80.64,"y":478.23,"z":121.38},{"x":-83.32,"y":477.42,"z":122.78},{"x":-85.92,"y":477.37,"z":121.16},{"x":-85.86,"y":478.14,"z":118.15}]},{"lat":-70.74,"lon":66.61,"b":[{"x":-65.47,"y":472.43,"z":149.97},{"x":-64.22,"y":472.37,"z":150.72},{"x":-64.23,"y":471.91,"z":152.13},{"x":-65.5,"y":471.53,"z":152.78},{"x":-66.74,"y":471.6,"z":152.02},{"x":-66.73,"y":472.05,"z":150.62}]},{"lat":-69.35,"lon":71.37,"b":[{"x":-56.31,"y":469.15,"z":163.27},{"x":-52.85,"y":468.84,"z":165.3},{"x":-52.85,"y":467.48,"z":169.12},{"x":-56.33,"y":466.43,"z":170.89},{"x":-59.78,"y":466.74,"z":168.85},{"x":-59.77,"y":468.1,"z":165.05}]},{"lat":-67.83,"lon":75.56,"b":[{"x":-47.04,"y":464.32,"z":179.25},{"x":-43.88,"y":463.92,"z":181.06},{"x":-43.88,"y":462.58,"z":184.47},{"x":-47.03,"y":461.63,"z":186.06},{"x":-50.17,"y":462.03,"z":184.25},{"x":-50.17,"y":463.37,"z":180.85}]},{"lat":-66.22,"lon":79.23,"b":[{"x":-37.67,"y":459.4,"z":193.52},{"x":-33.44,"y":458.73,"z":195.88},{"x":-33.43,"y":456.78,"z":200.37},{"x":-37.63,"y":455.52,"z":202.48},{"x":-41.84,"y":456.2,"z":200.12},{"x":-41.86,"y":458.14,"z":195.64}]},{"lat":-64.53,"lon":82.46,"b":[{"x":-28.24,"y":453.41,"z":208.67},{"x":-24,"y":452.58,"z":210.98},{"x":-23.99,"y":450.5,"z":215.39},{"x":-28.2,"y":449.25,"z":217.48},{"x":-32.42,"y":450.07,"z":215.18},{"x":-32.44,"y":452.15,"z":210.78}]},{"lat":-62.79,"lon":85.29,"b":[{"x":-18.79,"y":446.78,"z":223.49},{"x":-14.56,"y":445.82,"z":225.73},{"x":-14.55,"y":443.61,"z":230.05},{"x":-18.75,"y":442.37,"z":232.12},{"x":-22.97,"y":443.33,"z":229.9},{"x":-23,"y":445.53,"z":225.59}]},{"lat":-61,"lon":87.79,"b":[{"x":-9.37,"y":439.57,"z":237.93},{"x":-5.15,"y":438.47,"z":240.08},{"x":-5.15,"y":436.14,"z":244.29},{"x":-9.34,"y":434.91,"z":246.35},{"x":-13.54,"y":436,"z":244.22},{"x":-13.57,"y":438.33,"z":240.01}]},{"lat":-59.19,"lon":90,"b":[{"x":0,"y":431.8,"z":251.93},{"x":4.19,"y":430.57,"z":253.99},{"x":4.18,"y":428.14,"z":258.08},{"x":0,"y":426.92,"z":260.11},{"x":-4.18,"y":428.14,"z":258.08},{"x":-4.19,"y":430.57,"z":253.99}]},{"lat":-57.37,"lon":91.97,"b":[{"x":9.27,"y":423.53,"z":265.44},{"x":13.43,"y":422.19,"z":267.39},{"x":13.39,"y":419.65,"z":271.36},{"x":9.23,"y":418.46,"z":273.37},{"x":5.09,"y":419.78,"z":271.44},{"x":5.09,"y":422.32,"z":267.48}]},{"lat":-55.54,"lon":93.72,"b":[{"x":18.4,"y":414.81,"z":278.42},{"x":22.51,"y":413.36,"z":280.27},{"x":22.45,"y":410.74,"z":284.09},{"x":18.32,"y":409.57,"z":286.08},{"x":14.22,"y":410.99,"z":284.27},{"x":14.25,"y":413.61,"z":280.44}]},{"lat":-53.72,"lon":95.3,"b":[{"x":27.37,"y":405.69,"z":290.85},{"x":31.43,"y":404.15,"z":292.58},{"x":31.34,"y":401.47,"z":296.26},{"x":27.24,"y":400.31,"z":298.22},{"x":23.2,"y":401.82,"z":296.53},{"x":23.24,"y":404.51,"z":292.84}]},{"lat":-51.91,"lon":96.71,"b":[{"x":36.15,"y":396.23,"z":302.69},{"x":40.14,"y":394.61,"z":304.3},{"x":40.02,"y":391.87,"z":307.84},{"x":35.95,"y":390.74,"z":309.77},{"x":31.98,"y":392.33,"z":308.2},{"x":32.05,"y":395.08,"z":304.66}]},{"lat":-50.13,"lon":98,"b":[{"x":44.71,"y":386.49,"z":313.94},{"x":48.62,"y":384.8,"z":315.42},{"x":48.47,"y":382.02,"z":318.81},{"x":44.44,"y":380.92,"z":320.72},{"x":40.54,"y":382.56,"z":319.27},{"x":40.64,"y":385.36,"z":315.88}]},{"lat":-48.37,"lon":99.16,"b":[{"x":53.02,"y":376.52,"z":324.58},{"x":56.86,"y":374.78,"z":325.94},{"x":56.67,"y":371.97,"z":329.18},{"x":52.69,"y":370.89,"z":331.06},{"x":48.86,"y":372.59,"z":329.73},{"x":49,"y":375.42,"z":326.49}]},{"lat":-46.65,"lon":100.22,"b":[{"x":61.08,"y":366.39,"z":334.61},{"x":64.84,"y":364.6,"z":335.85},{"x":64.6,"y":361.78,"z":338.93},{"x":60.67,"y":360.72,"z":340.79},{"x":56.92,"y":362.46,"z":339.58},{"x":57.1,"y":365.31,"z":336.49}]},{"lat":-44.96,"lon":101.19,"b":[{"x":68.87,"y":356.14,"z":344.04},{"x":72.54,"y":354.32,"z":345.15},{"x":72.27,"y":351.5,"z":348.09},{"x":68.38,"y":350.46,"z":349.91},{"x":64.72,"y":352.23,"z":348.83},{"x":64.93,"y":355.08,"z":345.89}]},{"lat":-70.92,"lon":55.52,"b":[{"x":-92.48,"y":473.1,"z":132.6},{"x":-90.62,"y":473.13,"z":133.76},{"x":-90.66,"y":472.51,"z":135.9},{"x":-92.55,"y":471.87,"z":136.87},{"x":-94.4,"y":471.84,"z":135.7},{"x":-94.36,"y":472.46,"z":133.57}]},{"lat":-69.85,"lon":60.92,"b":[{"x":-83.72,"y":469.77,"z":149.26},{"x":-82.59,"y":469.75,"z":149.95},{"x":-82.6,"y":469.34,"z":151.23},{"x":-83.74,"y":468.95,"z":151.8},{"x":-84.86,"y":468.98,"z":151.11},{"x":-84.84,"y":469.39,"z":149.84}]},{"lat":-68.62,"lon":65.8,"b":[{"x":-74.72,"y":466.61,"z":163.21},{"x":-71.96,"y":466.45,"z":164.87},{"x":-71.97,"y":465.36,"z":167.94},{"x":-74.74,"y":464.42,"z":169.32},{"x":-77.48,"y":464.58,"z":167.65},{"x":-77.46,"y":465.67,"z":164.6}]},{"lat":-67.25,"lon":70.17,"b":[{"x":-65.57,"y":462.77,"z":177.39},{"x":-61.45,"y":462.39,"z":179.82},{"x":-61.44,"y":460.62,"z":184.32},{"x":-65.56,"y":459.23,"z":186.36},{"x":-69.65,"y":459.61,"z":183.91},{"x":-69.66,"y":461.38,"z":179.44}]},{"lat":-65.77,"lon":74.08,"b":[{"x":-56.3,"y":457.78,"z":192.83},{"x":-52.11,"y":457.25,"z":195.25},{"x":-52.09,"y":455.32,"z":199.73},{"x":-56.25,"y":453.92,"z":201.77},{"x":-60.42,"y":454.46,"z":199.35},{"x":-60.45,"y":456.38,"z":194.89}]},{"lat":-64.2,"lon":77.55,"b":[{"x":-46.93,"y":452.13,"z":208.08},{"x":-42.72,"y":451.45,"z":210.45},{"x":-42.69,"y":449.37,"z":214.85},{"x":-46.86,"y":447.99,"z":216.87},{"x":-51.05,"y":448.67,"z":214.51},{"x":-51.09,"y":450.73,"z":210.12}]},{"lat":-62.55,"lon":80.64,"b":[{"x":-37.5,"y":445.84,"z":223.02},{"x":-33.28,"y":445.02,"z":225.32},{"x":-33.25,"y":442.81,"z":229.63},{"x":-37.43,"y":441.44,"z":231.63},{"x":-41.62,"y":442.26,"z":229.34},{"x":-41.67,"y":444.45,"z":225.04}]},{"lat":-60.86,"lon":83.39,"b":[{"x":-28.06,"y":438.95,"z":237.6},{"x":-23.84,"y":437.99,"z":239.82},{"x":-23.81,"y":435.66,"z":244.03},{"x":-27.98,"y":434.3,"z":246.01},{"x":-32.18,"y":435.26,"z":243.8},{"x":-32.23,"y":437.58,"z":239.6}]},{"lat":-59.12,"lon":85.84,"b":[{"x":-18.63,"y":431.5,"z":251.75},{"x":-14.43,"y":430.41,"z":253.89},{"x":-14.41,"y":427.97,"z":257.98},{"x":-18.57,"y":426.63,"z":259.93},{"x":-22.75,"y":427.71,"z":257.82},{"x":-22.8,"y":430.14,"z":253.73}]},{"lat":-57.37,"lon":88.03,"b":[{"x":-9.27,"y":423.53,"z":265.44},{"x":-5.09,"y":422.32,"z":267.48},{"x":-5.09,"y":419.78,"z":271.44},{"x":-9.23,"y":418.46,"z":273.37},{"x":-13.39,"y":419.65,"z":271.36},{"x":-13.43,"y":422.19,"z":267.39}]},{"lat":-55.59,"lon":90,"b":[{"x":0,"y":415.09,"z":278.61},{"x":4.14,"y":413.77,"z":280.54},{"x":4.12,"y":411.14,"z":284.37},{"x":0,"y":409.85,"z":286.27},{"x":-4.12,"y":411.14,"z":284.37},{"x":-4.14,"y":413.77,"z":280.54}]},{"lat":-53.82,"lon":91.77,"b":[{"x":9.14,"y":406.23,"z":291.24},{"x":13.23,"y":404.81,"z":293.05},{"x":13.19,"y":402.12,"z":296.74},{"x":9.09,"y":400.84,"z":298.62},{"x":5.01,"y":402.23,"z":296.83},{"x":5.01,"y":404.93,"z":293.14}]},{"lat":-52.06,"lon":93.37,"b":[{"x":18.11,"y":397.01,"z":303.29},{"x":22.15,"y":395.5,"z":304.99},{"x":22.08,"y":392.75,"z":308.53},{"x":18.01,"y":391.5,"z":310.37},{"x":13.99,"y":392.98,"z":308.71},{"x":14.01,"y":395.73,"z":305.16}]},{"lat":-50.3,"lon":94.82,"b":[{"x":26.89,"y":387.48,"z":314.75},{"x":30.87,"y":385.9,"z":316.32},{"x":30.76,"y":383.1,"z":319.71},{"x":26.73,"y":381.88,"z":321.53},{"x":22.77,"y":383.43,"z":319.99},{"x":22.83,"y":386.23,"z":316.59}]},{"lat":-48.57,"lon":96.13,"b":[{"x":35.46,"y":377.7,"z":325.6},{"x":39.37,"y":376.06,"z":327.05},{"x":39.23,"y":373.23,"z":330.29},{"x":35.23,"y":372.04,"z":332.08},{"x":31.34,"y":373.65,"z":330.66},{"x":31.43,"y":376.48,"z":327.42}]},{"lat":-46.87,"lon":97.34,"b":[{"x":43.79,"y":367.73,"z":335.84},{"x":47.62,"y":366.04,"z":337.17},{"x":47.44,"y":363.19,"z":340.26},{"x":43.49,"y":362.03,"z":342.02},{"x":39.68,"y":363.68,"z":340.72},{"x":39.8,"y":366.54,"z":337.63}]},{"lat":-45.2,"lon":98.44,"b":[{"x":51.87,"y":357.63,"z":345.47},{"x":55.61,"y":355.89,"z":346.68},{"x":55.4,"y":353.04,"z":349.62},{"x":51.5,"y":351.91,"z":351.35},{"x":47.76,"y":353.6,"z":350.18},{"x":47.92,"y":356.46,"z":347.24}]},{"lat":-43.56,"lon":99.45,"b":[{"x":59.68,"y":347.43,"z":354.5},{"x":63.34,"y":345.66,"z":355.59},{"x":63.09,"y":342.81,"z":358.38},{"x":59.23,"y":341.71,"z":360.09},{"x":55.58,"y":343.43,"z":359.03},{"x":55.77,"y":346.3,"z":356.24}]},{"lat":-67.72,"lon":60.67,"b":[{"x":-92.8,"y":464.11,"z":160.97},{"x":-89.02,"y":464.03,"z":163.33},{"x":-89.04,"y":462.5,"z":167.6},{"x":-92.84,"y":461.07,"z":169.48},{"x":-96.6,"y":461.16,"z":167.1},{"x":-96.58,"y":462.68,"z":162.86}]},{"lat":-66.5,"lon":65.13,"b":[{"x":-83.83,"y":460.21,"z":176.36},{"x":-79.74,"y":459.97,"z":178.86},{"x":-79.74,"y":458.19,"z":183.37},{"x":-83.82,"y":456.66,"z":185.36},{"x":-87.88,"y":456.91,"z":182.85},{"x":-87.89,"y":458.67,"z":178.37}]},{"lat":-65.15,"lon":69.18,"b":[{"x":-74.7,"y":455.54,"z":191.89},{"x":-70.56,"y":455.15,"z":194.36},{"x":-70.54,"y":453.23,"z":198.82},{"x":-74.64,"y":451.7,"z":200.78},{"x":-78.74,"y":452.1,"z":198.31},{"x":-78.78,"y":454.01,"z":193.88}]},{"lat":-63.7,"lon":72.83,"b":[{"x":-65.43,"y":450.23,"z":207.21},{"x":-61.26,"y":449.69,"z":209.63},{"x":-61.22,"y":447.63,"z":214.01},{"x":-65.33,"y":446.11,"z":215.96},{"x":-69.47,"y":446.65,"z":213.54},{"x":-69.53,"y":448.7,"z":209.17}]},{"lat":-62.17,"lon":76.11,"b":[{"x":-56.06,"y":444.28,"z":222.24},{"x":-51.87,"y":443.6,"z":224.61},{"x":-51.82,"y":441.4,"z":228.91},{"x":-55.94,"y":439.9,"z":230.83},{"x":-60.1,"y":440.58,"z":228.47},{"x":-60.17,"y":442.76,"z":224.19}]},{"lat":-60.57,"lon":79.07,"b":[{"x":-46.63,"y":437.73,"z":236.94},{"x":-42.43,"y":436.91,"z":239.23},{"x":-42.38,"y":434.59,"z":243.43},{"x":-46.51,"y":433.1,"z":245.32},{"x":-50.68,"y":433.91,"z":243.05},{"x":-50.75,"y":436.22,"z":238.86}]},{"lat":-58.93,"lon":81.73,"b":[{"x":-37.19,"y":430.6,"z":251.23},{"x":-32.99,"y":429.65,"z":253.44},{"x":-32.95,"y":427.22,"z":257.53},{"x":-37.07,"y":425.75,"z":259.4},{"x":-41.24,"y":426.69,"z":257.21},{"x":-41.31,"y":429.12,"z":253.13}]},{"lat":-57.24,"lon":84.12,"b":[{"x":-27.77,"y":422.95,"z":265.08},{"x":-23.58,"y":421.87,"z":267.19},{"x":-23.55,"y":419.34,"z":271.15},{"x":-27.66,"y":417.89,"z":273},{"x":-31.81,"y":418.95,"z":270.9},{"x":-31.89,"y":421.48,"z":266.95}]},{"lat":-55.54,"lon":86.28,"b":[{"x":-18.4,"y":414.81,"z":278.42},{"x":-14.25,"y":413.61,"z":280.44},{"x":-14.22,"y":410.99,"z":284.27},{"x":-18.32,"y":409.57,"z":286.08},{"x":-22.45,"y":410.74,"z":284.09},{"x":-22.51,"y":413.36,"z":280.27}]},{"lat":-53.82,"lon":88.23,"b":[{"x":-9.14,"y":406.23,"z":291.24},{"x":-5.01,"y":404.93,"z":293.14},{"x":-5.01,"y":402.23,"z":296.83},{"x":-9.09,"y":400.84,"z":298.62},{"x":-13.19,"y":402.12,"z":296.74},{"x":-13.23,"y":404.81,"z":293.05}]},{"lat":-52.1,"lon":90,"b":[{"x":0,"y":397.27,"z":303.49},{"x":4.08,"y":395.87,"z":305.27},{"x":4.05,"y":393.12,"z":308.82},{"x":0,"y":391.76,"z":310.58},{"x":-4.05,"y":393.12,"z":308.82},{"x":-4.08,"y":395.87,"z":305.27}]},{"lat":-50.39,"lon":91.61,"b":[{"x":8.98,"y":387.98,"z":315.15},{"x":13,"y":386.5,"z":316.82},{"x":12.95,"y":383.7,"z":320.21},{"x":8.92,"y":382.37,"z":321.94},{"x":4.92,"y":383.81,"z":320.31},{"x":4.92,"y":386.62,"z":316.91}]},{"lat":-48.7,"lon":93.08,"b":[{"x":17.76,"y":378.42,"z":326.21},{"x":21.72,"y":376.87,"z":327.76},{"x":21.64,"y":374.03,"z":331},{"x":17.65,"y":372.74,"z":332.7},{"x":13.71,"y":374.24,"z":331.19},{"x":13.74,"y":377.09,"z":327.94}]},{"lat":-47.02,"lon":94.42,"b":[{"x":26.34,"y":368.64,"z":336.67},{"x":30.23,"y":367.04,"z":338.09},{"x":30.11,"y":364.18,"z":341.18},{"x":26.16,"y":362.91,"z":342.85},{"x":22.29,"y":364.47,"z":341.46},{"x":22.35,"y":367.34,"z":338.37}]},{"lat":-45.37,"lon":95.65,"b":[{"x":34.68,"y":358.7,"z":346.51},{"x":38.5,"y":357.05,"z":347.81},{"x":38.34,"y":354.18,"z":350.75},{"x":34.43,"y":352.95,"z":352.39},{"x":30.64,"y":354.55,"z":351.12},{"x":30.73,"y":357.44,"z":348.18}]},{"lat":-43.75,"lon":96.78,"b":[{"x":42.78,"y":348.65,"z":355.75},{"x":46.51,"y":346.96,"z":356.92},{"x":46.32,"y":344.09,"z":359.72},{"x":42.46,"y":342.9,"z":361.33},{"x":38.74,"y":344.53,"z":360.19},{"x":38.87,"y":347.42,"z":357.39}]},{"lat":-42.17,"lon":97.82,"b":[{"x":50.61,"y":338.53,"z":364.39},{"x":54.26,"y":336.81,"z":365.45},{"x":54.03,"y":333.96,"z":368.1},{"x":50.22,"y":332.8,"z":369.69},{"x":46.58,"y":334.46,"z":368.66},{"x":46.74,"y":337.33,"z":366.01}]},{"lat":-69.66,"lon":18.81,"b":[{"x":-164.32,"y":469.07,"z":54.26},{"x":-162.96,"y":469.43,"z":55.2},{"x":-163.09,"y":469.17,"z":56.98},{"x":-164.6,"y":468.54,"z":57.81},{"x":-165.95,"y":468.18,"z":56.85},{"x":-165.81,"y":468.45,"z":55.09}]},{"lat":-69.77,"lon":24.2,"b":[{"x":-157.47,"y":469.67,"z":67.54},{"x":-154.85,"y":470.28,"z":69.34},{"x":-155.06,"y":469.7,"z":72.72},{"x":-157.92,"y":468.5,"z":74.26},{"x":-160.52,"y":467.9,"z":72.43},{"x":-160.29,"y":468.49,"z":69.08}]},{"lat":-69.7,"lon":29.73,"b":[{"x":-150.44,"y":469.5,"z":82.96},{"x":-148,"y":469.98,"z":84.62},{"x":-148.16,"y":469.36,"z":87.71},{"x":-150.78,"y":468.27,"z":89.1},{"x":-153.19,"y":467.8,"z":87.41},{"x":-153.02,"y":468.42,"z":84.35}]},{"lat":-69.45,"lon":35.29,"b":[{"x":-143.2,"y":468.3,"z":100.91},{"x":-142.81,"y":468.36,"z":101.17},{"x":-142.83,"y":468.25,"z":101.65},{"x":-143.24,"y":468.08,"z":101.86},{"x":-143.62,"y":468.02,"z":101.6},{"x":-143.6,"y":468.13,"z":101.12}]},{"lat":-68.42,"lon":46.13,"b":[{"x":-127.44,"y":465.12,"z":131.93},{"x":-126.9,"y":465.17,"z":132.29},{"x":-126.91,"y":464.98,"z":132.94},{"x":-127.47,"y":464.75,"z":133.22},{"x":-128.01,"y":464.7,"z":132.86},{"x":-127.99,"y":464.89,"z":132.22}]},{"lat":-67.64,"lon":51.22,"b":[{"x":-119.07,"y":463.51,"z":144.61},{"x":-115.93,"y":463.66,"z":146.67},{"x":-115.97,"y":462.47,"z":150.36},{"x":-119.17,"y":461.13,"z":151.95},{"x":-122.29,"y":461,"z":149.87},{"x":-122.24,"y":462.19,"z":146.21}]},{"lat":-66.7,"lon":56.01,"b":[{"x":-110.52,"y":460.73,"z":159.48},{"x":-106.58,"y":460.77,"z":162.02},{"x":-106.6,"y":459.15,"z":166.54},{"x":-110.57,"y":457.5,"z":168.49},{"x":-114.49,"y":457.48,"z":165.93},{"x":-114.46,"y":459.09,"z":161.44}]},{"lat":-65.61,"lon":60.47,"b":[{"x":-101.76,"y":457.04,"z":175.15},{"x":-97.75,"y":456.94,"z":177.68},{"x":-97.74,"y":455.17,"z":182.17},{"x":-101.74,"y":453.52,"z":184.09},{"x":-105.72,"y":453.64,"z":181.54},{"x":-105.73,"y":455.39,"z":177.09}]},{"lat":-64.39,"lon":64.57,"b":[{"x":-92.79,"y":452.71,"z":190.7},{"x":-88.73,"y":452.46,"z":193.21},{"x":-88.69,"y":450.55,"z":197.64},{"x":-92.72,"y":448.9,"z":199.54},{"x":-96.75,"y":449.16,"z":197.02},{"x":-96.79,"y":451.06,"z":192.62}]},{"lat":-63.07,"lon":68.33,"b":[{"x":-83.65,"y":447.73,"z":206.06},{"x":-79.55,"y":447.34,"z":208.53},{"x":-79.49,"y":445.28,"z":212.9},{"x":-83.53,"y":443.64,"z":214.77},{"x":-87.61,"y":444.05,"z":212.3},{"x":-87.68,"y":446.08,"z":207.95}]},{"lat":-61.65,"lon":71.76,"b":[{"x":-74.38,"y":442.12,"z":221.16},{"x":-70.24,"y":441.58,"z":223.58},{"x":-70.17,"y":439.4,"z":227.87},{"x":-74.23,"y":437.77,"z":229.71},{"x":-78.34,"y":438.32,"z":227.3},{"x":-78.42,"y":440.48,"z":223.03}]},{"lat":-60.16,"lon":74.87,"b":[{"x":-65.02,"y":435.91,"z":235.95},{"x":-60.85,"y":435.23,"z":238.31},{"x":-60.78,"y":432.92,"z":242.5},{"x":-64.84,"y":431.31,"z":244.31},{"x":-68.97,"y":431.99,"z":241.97},{"x":-69.07,"y":434.28,"z":237.8}]},{"lat":-58.6,"lon":77.69,"b":[{"x":-55.59,"y":429.12,"z":250.37},{"x":-51.42,"y":428.31,"z":252.65},{"x":-51.34,"y":425.89,"z":256.72},{"x":-55.41,"y":424.29,"z":258.51},{"x":-59.55,"y":425.11,"z":256.25},{"x":-59.65,"y":427.51,"z":252.18}]},{"lat":-57,"lon":80.26,"b":[{"x":-46.15,"y":421.79,"z":264.35},{"x":-41.98,"y":420.85,"z":266.54},{"x":-41.91,"y":418.33,"z":270.5},{"x":-45.97,"y":416.76,"z":272.26},{"x":-50.11,"y":417.69,"z":270.09},{"x":-50.22,"y":420.2,"z":266.14}]},{"lat":-55.37,"lon":82.59,"b":[{"x":-36.73,"y":413.97,"z":277.86},{"x":-32.58,"y":412.9,"z":279.95},{"x":-32.51,"y":410.29,"z":283.78},{"x":-36.57,"y":408.75,"z":285.51},{"x":-40.69,"y":409.8,"z":283.44},{"x":-40.8,"y":412.4,"z":279.62}]},{"lat":-53.72,"lon":84.7,"b":[{"x":-27.37,"y":405.69,"z":290.85},{"x":-23.24,"y":404.51,"z":292.84},{"x":-23.2,"y":401.82,"z":296.53},{"x":-27.24,"y":400.31,"z":298.22},{"x":-31.34,"y":401.47,"z":296.26},{"x":-31.43,"y":404.15,"z":292.58}]},{"lat":-52.06,"lon":86.63,"b":[{"x":-18.11,"y":397.01,"z":303.29},{"x":-14.01,"y":395.73,"z":305.16},{"x":-13.99,"y":392.98,"z":308.71},{"x":-18.01,"y":391.5,"z":310.37},{"x":-22.08,"y":392.75,"z":308.53},{"x":-22.15,"y":395.5,"z":304.99}]},{"lat":-50.39,"lon":88.39,"b":[{"x":-8.98,"y":387.98,"z":315.15},{"x":-4.92,"y":386.62,"z":316.91},{"x":-4.92,"y":383.81,"z":320.31},{"x":-8.92,"y":382.37,"z":321.94},{"x":-12.95,"y":383.7,"z":320.21},{"x":-13,"y":386.5,"z":316.82}]},{"lat":-48.74,"lon":90,"b":[{"x":0,"y":378.66,"z":326.42},{"x":4,"y":377.22,"z":328.06},{"x":3.97,"y":374.37,"z":331.3},{"x":0,"y":372.97,"z":332.91},{"x":-3.97,"y":374.37,"z":331.3},{"x":-4,"y":377.22,"z":328.06}]},{"lat":-47.1,"lon":91.48,"b":[{"x":8.79,"y":369.1,"z":337.08},{"x":12.73,"y":367.59,"z":338.6},{"x":12.67,"y":364.72,"z":341.69},{"x":8.73,"y":363.35,"z":343.27},{"x":4.82,"y":364.82,"z":341.78},{"x":4.82,"y":367.69,"z":338.69}]},{"lat":-45.48,"lon":92.83,"b":[{"x":17.37,"y":359.35,"z":347.14},{"x":21.24,"y":357.79,"z":348.53},{"x":21.15,"y":354.91,"z":351.47},{"x":17.25,"y":353.58,"z":353.02},{"x":13.4,"y":355.09,"z":351.66},{"x":13.43,"y":357.98,"z":348.72}]},{"lat":-43.88,"lon":94.08,"b":[{"x":25.73,"y":349.46,"z":356.58},{"x":29.52,"y":347.86,"z":357.85},{"x":29.39,"y":344.98,"z":360.65},{"x":25.53,"y":343.69,"z":362.17},{"x":21.76,"y":345.25,"z":360.93},{"x":21.82,"y":348.14,"z":358.14}]},{"lat":-42.32,"lon":95.23,"b":[{"x":33.84,"y":339.5,"z":365.43},{"x":37.55,"y":337.86,"z":366.58},{"x":37.39,"y":334.98,"z":369.23},{"x":33.57,"y":333.73,"z":370.73},{"x":29.88,"y":335.32,"z":369.6},{"x":29.97,"y":338.21,"z":366.96}]},{"lat":-40.79,"lon":96.3,"b":[{"x":41.69,"y":329.48,"z":373.69},{"x":45.32,"y":327.82,"z":374.72},{"x":45.12,"y":324.97,"z":377.23},{"x":41.35,"y":323.76,"z":378.7},{"x":37.74,"y":325.37,"z":377.7},{"x":37.87,"y":328.24,"z":375.19}]},{"lat":-67.92,"lon":17.13,"b":[{"x":-179.36,"y":463.73,"z":52.29},{"x":-177.05,"y":464.43,"z":53.93},{"x":-177.3,"y":463.96,"z":57.04},{"x":-179.88,"y":462.79,"z":58.47},{"x":-182.17,"y":462.1,"z":56.8},{"x":-181.9,"y":462.58,"z":53.73}]},{"lat":-68.05,"lon":22.02,"b":[{"x":-172.88,"y":464.46,"z":65.76},{"x":-169.6,"y":465.33,"z":68.09},{"x":-169.9,"y":464.57,"z":72.45},{"x":-173.51,"y":462.92,"z":74.42},{"x":-176.77,"y":462.06,"z":72.04},{"x":-176.44,"y":462.84,"z":67.74}]},{"lat":-68.04,"lon":27.07,"b":[{"x":-166.18,"y":464.55,"z":80.69},{"x":-162.79,"y":465.33,"z":83.08},{"x":-163.04,"y":464.43,"z":87.49},{"x":-166.7,"y":462.75,"z":89.46},{"x":-170.06,"y":462,"z":87.02},{"x":-169.79,"y":462.9,"z":82.66}]},{"lat":-67.87,"lon":32.18,"b":[{"x":-159.15,"y":464.13,"z":95.87},{"x":-155.66,"y":464.8,"z":98.32},{"x":-155.86,"y":463.76,"z":102.77},{"x":-159.56,"y":462.06,"z":104.73},{"x":-163.02,"y":461.41,"z":102.24},{"x":-162.8,"y":462.45,"z":97.84}]},{"lat":-67.54,"lon":37.29,"b":[{"x":-151.78,"y":463.16,"z":111.26},{"x":-148.19,"y":463.71,"z":113.75},{"x":-148.34,"y":462.54,"z":118.23},{"x":-152.1,"y":460.82,"z":120.17},{"x":-155.65,"y":460.29,"z":117.64},{"x":-155.48,"y":461.45,"z":113.21}]},{"lat":-67.04,"lon":42.31,"b":[{"x":-144.22,"y":460.54,"z":130.72},{"x":-143.76,"y":460.6,"z":131.04},{"x":-143.78,"y":460.43,"z":131.6},{"x":-144.25,"y":460.22,"z":131.84},{"x":-144.71,"y":460.17,"z":131.52},{"x":-144.69,"y":460.33,"z":130.96}]},{"lat":-66.38,"lon":47.17,"b":[{"x":-136.14,"y":458.99,"z":144.03},{"x":-133.72,"y":459.18,"z":145.67},{"x":-133.76,"y":458.24,"z":148.56},{"x":-136.22,"y":457.12,"z":149.79},{"x":-138.62,"y":456.94,"z":148.13},{"x":-138.57,"y":457.87,"z":145.27}]},{"lat":-65.56,"lon":51.81,"b":[{"x":-127.82,"y":456.72,"z":158.09},{"x":-123.98,"y":456.88,"z":160.65},{"x":-124,"y":455.28,"z":165.14},{"x":-127.87,"y":453.52,"z":167.02},{"x":-131.68,"y":453.37,"z":164.44},{"x":-131.66,"y":454.97,"z":159.99}]},{"lat":-64.6,"lon":56.2,"b":[{"x":-119.29,"y":453.34,"z":173.73},{"x":-115.37,"y":453.36,"z":176.29},{"x":-115.36,"y":451.61,"z":180.74},{"x":-119.26,"y":449.84,"z":182.6},{"x":-123.14,"y":449.84,"z":180.02},{"x":-123.16,"y":451.58,"z":175.61}]},{"lat":-63.51,"lon":60.3,"b":[{"x":-110.52,"y":449.32,"z":189.27},{"x":-106.54,"y":449.2,"z":191.81},{"x":-106.5,"y":447.3,"z":196.22},{"x":-110.43,"y":445.54,"z":198.04},{"x":-114.37,"y":445.68,"z":195.49},{"x":-114.42,"y":447.55,"z":191.12}]},{"lat":-62.31,"lon":64.1,"b":[{"x":-101.54,"y":444.67,"z":204.65},{"x":-97.51,"y":444.41,"z":207.16},{"x":-97.45,"y":442.37,"z":211.5},{"x":-101.4,"y":440.62,"z":213.3},{"x":-105.4,"y":440.89,"z":210.79},{"x":-105.48,"y":442.91,"z":206.47}]},{"lat":-61,"lon":67.61,"b":[{"x":-92.41,"y":439.4,"z":219.8},{"x":-88.33,"y":438.99,"z":222.27},{"x":-88.24,"y":436.83,"z":226.53},{"x":-92.22,"y":435.08,"z":228.3},{"x":-96.26,"y":435.5,"z":225.84},{"x":-96.36,"y":437.64,"z":221.6}]},{"lat":-59.61,"lon":70.83,"b":[{"x":-83.13,"y":433.53,"z":234.66},{"x":-79.02,"y":432.98,"z":237.08},{"x":-78.93,"y":430.69,"z":241.25},{"x":-82.91,"y":428.96,"z":242.98},{"x":-86.99,"y":429.51,"z":240.58},{"x":-87.11,"y":431.78,"z":236.43}]},{"lat":-58.16,"lon":73.78,"b":[{"x":-73.77,"y":427.08,"z":249.17},{"x":-69.64,"y":426.39,"z":251.52},{"x":-69.53,"y":423.99,"z":255.58},{"x":-73.53,"y":422.28,"z":257.28},{"x":-77.62,"y":422.96,"z":254.96},{"x":-77.76,"y":425.35,"z":250.91}]},{"lat":-56.65,"lon":76.49,"b":[{"x":-64.35,"y":420.08,"z":263.28},{"x":-60.21,"y":419.27,"z":265.54},{"x":-60.1,"y":416.76,"z":269.49},{"x":-64.1,"y":415.08,"z":271.16},{"x":-68.2,"y":415.88,"z":268.91},{"x":-68.34,"y":418.37,"z":264.98}]},{"lat":-55.09,"lon":78.96,"b":[{"x":-54.91,"y":412.58,"z":276.93},{"x":-50.78,"y":411.64,"z":279.1},{"x":-50.67,"y":409.04,"z":282.92},{"x":-54.67,"y":407.39,"z":284.56},{"x":-58.77,"y":408.31,"z":282.41},{"x":-58.91,"y":410.9,"z":278.6}]},{"lat":-53.51,"lon":81.22,"b":[{"x":-45.5,"y":404.61,"z":290.08},{"x":-41.38,"y":403.56,"z":292.15},{"x":-41.29,"y":400.88,"z":295.83},{"x":-45.28,"y":399.26,"z":297.44},{"x":-49.37,"y":400.29,"z":295.39},{"x":-49.5,"y":402.96,"z":291.72}]},{"lat":-51.91,"lon":83.29,"b":[{"x":-36.15,"y":396.23,"z":302.69},{"x":-32.05,"y":395.08,"z":304.66},{"x":-31.98,"y":392.33,"z":308.2},{"x":-35.95,"y":390.74,"z":309.77},{"x":-40.02,"y":391.87,"z":307.84},{"x":-40.14,"y":394.61,"z":304.3}]},{"lat":-50.3,"lon":85.18,"b":[{"x":-26.89,"y":387.48,"z":314.75},{"x":-22.83,"y":386.23,"z":316.59},{"x":-22.77,"y":383.43,"z":319.99},{"x":-26.73,"y":381.88,"z":321.53},{"x":-30.76,"y":383.1,"z":319.71},{"x":-30.87,"y":385.9,"z":316.32}]},{"lat":-48.7,"lon":86.92,"b":[{"x":-17.76,"y":378.42,"z":326.21},{"x":-13.74,"y":377.09,"z":327.94},{"x":-13.71,"y":374.24,"z":331.19},{"x":-17.65,"y":372.74,"z":332.7},{"x":-21.64,"y":374.03,"z":331},{"x":-21.72,"y":376.87,"z":327.76}]},{"lat":-47.1,"lon":88.52,"b":[{"x":-8.79,"y":369.1,"z":337.08},{"x":-4.82,"y":367.69,"z":338.69},{"x":-4.82,"y":364.82,"z":341.78},{"x":-8.73,"y":363.35,"z":343.27},{"x":-12.67,"y":364.72,"z":341.69},{"x":-12.73,"y":367.59,"z":338.6}]},{"lat":-45.51,"lon":90,"b":[{"x":0,"y":359.56,"z":347.35},{"x":3.91,"y":358.1,"z":348.83},{"x":3.88,"y":355.21,"z":351.77},{"x":0,"y":353.79,"z":353.23},{"x":-3.88,"y":355.21,"z":351.77},{"x":-3.91,"y":358.1,"z":348.83}]},{"lat":-43.95,"lon":91.36,"b":[{"x":8.59,"y":349.88,"z":357},{"x":12.43,"y":348.36,"z":358.37},{"x":12.37,"y":345.47,"z":361.16},{"x":8.52,"y":344.09,"z":362.59},{"x":4.71,"y":345.56,"z":361.25},{"x":4.71,"y":348.45,"z":358.46}]},{"lat":-42.41,"lon":92.62,"b":[{"x":16.95,"y":340.08,"z":366.06},{"x":20.72,"y":338.52,"z":367.3},{"x":20.62,"y":335.64,"z":369.95},{"x":16.81,"y":334.3,"z":371.36},{"x":13.07,"y":335.81,"z":370.14},{"x":13.1,"y":338.7,"z":367.49}]},{"lat":-40.9,"lon":93.79,"b":[{"x":25.07,"y":330.22,"z":374.53},{"x":28.77,"y":328.63,"z":375.65},{"x":28.63,"y":325.76,"z":378.16},{"x":24.87,"y":324.47,"z":379.54},{"x":21.19,"y":326,"z":378.44},{"x":21.26,"y":328.88,"z":375.93}]},{"lat":-39.42,"lon":94.87,"b":[{"x":32.94,"y":320.34,"z":382.42},{"x":36.56,"y":318.73,"z":383.43},{"x":36.39,"y":315.89,"z":385.79},{"x":32.67,"y":314.64,"z":387.15},{"x":29.07,"y":316.19,"z":386.17},{"x":29.18,"y":319.05,"z":383.8}]},{"lat":-66.19,"lon":15.72,"b":[{"x":-193.85,"y":458.06,"z":50.48},{"x":-190.8,"y":459.08,"z":52.72},{"x":-191.17,"y":458.42,"z":56.95},{"x":-194.61,"y":456.72,"z":58.89},{"x":-197.63,"y":455.72,"z":56.6},{"x":-197.24,"y":456.39,"z":52.42}]},{"lat":-66.36,"lon":20.19,"b":[{"x":-187.83,"y":458.74,"z":64.95},{"x":-184.68,"y":459.68,"z":67.26},{"x":-185,"y":458.9,"z":71.56},{"x":-188.49,"y":457.17,"z":73.5},{"x":-191.61,"y":456.25,"z":71.13},{"x":-191.27,"y":457.04,"z":66.89}]},{"lat":-66.39,"lon":24.81,"b":[{"x":-181.47,"y":458.96,"z":79.72},{"x":-178.21,"y":459.82,"z":82.1},{"x":-178.48,"y":458.92,"z":86.46},{"x":-182.02,"y":457.16,"z":88.38},{"x":-185.25,"y":456.32,"z":85.95},{"x":-184.96,"y":457.23,"z":81.65}]},{"lat":-66.28,"lon":29.52,"b":[{"x":-174.76,"y":458.71,"z":94.75},{"x":-171.4,"y":459.46,"z":97.19},{"x":-171.62,"y":458.43,"z":101.59},{"x":-175.21,"y":456.64,"z":103.5},{"x":-178.54,"y":455.91,"z":101.02},{"x":-178.31,"y":456.94,"z":96.67}]},{"lat":-66.02,"lon":34.27,"b":[{"x":-167.79,"y":457.55,"z":111.53},{"x":-165.54,"y":457.98,"z":113.16},{"x":-165.65,"y":457.21,"z":116.05},{"x":-168.02,"y":456.03,"z":117.28},{"x":-170.25,"y":455.63,"z":115.63},{"x":-170.14,"y":456.39,"z":112.78}]},{"lat":-65.61,"lon":38.97,"b":[{"x":-160.46,"y":455.75,"z":128.54},{"x":-159.41,"y":455.9,"z":129.29},{"x":-159.44,"y":455.52,"z":130.6},{"x":-160.53,"y":454.98,"z":131.16},{"x":-161.57,"y":454.83,"z":130.4},{"x":-161.53,"y":455.21,"z":129.1}]},{"lat":-65.05,"lon":43.58,"b":[{"x":-152.64,"y":454.71,"z":140.95},{"x":-149,"y":455.12,"z":143.51},{"x":-149.07,"y":453.67,"z":147.96},{"x":-152.79,"y":451.82,"z":149.81},{"x":-156.4,"y":451.44,"z":147.22},{"x":-156.33,"y":452.88,"z":142.81}]},{"lat":-64.35,"lon":48.05,"b":[{"x":-144.64,"y":452.22,"z":156.53},{"x":-140.91,"y":452.5,"z":159.11},{"x":-140.94,"y":450.9,"z":163.55},{"x":-144.7,"y":449.04,"z":165.37},{"x":-148.4,"y":448.79,"z":162.77},{"x":-148.37,"y":450.37,"z":158.38}]},{"lat":-63.5,"lon":52.31,"b":[{"x":-136.36,"y":449.12,"z":172.11},{"x":-132.55,"y":449.26,"z":174.69},{"x":-132.54,"y":447.53,"z":179.11},{"x":-136.33,"y":445.66,"z":180.9},{"x":-140.11,"y":445.54,"z":178.3},{"x":-140.12,"y":447.26,"z":173.93}]},{"lat":-62.53,"lon":56.35,"b":[{"x":-127.81,"y":445.41,"z":187.62},{"x":-123.93,"y":445.41,"z":190.19},{"x":-123.88,"y":443.53,"z":194.57},{"x":-127.71,"y":441.67,"z":196.32},{"x":-131.56,"y":441.68,"z":193.74},{"x":-131.61,"y":443.54,"z":189.41}]},{"lat":-61.44,"lon":60.15,"b":[{"x":-119.04,"y":441.07,"z":202.99},{"x":-115.09,"y":440.94,"z":205.55},{"x":-115.02,"y":438.92,"z":209.86},{"x":-118.87,"y":437.07,"z":211.58},{"x":-122.78,"y":437.22,"z":209.03},{"x":-122.87,"y":439.21,"z":204.75}]},{"lat":-60.24,"lon":63.69,"b":[{"x":-110.06,"y":436.13,"z":218.17},{"x":-106.06,"y":435.86,"z":220.68},{"x":-105.96,"y":433.71,"z":224.92},{"x":-109.84,"y":431.86,"z":226.61},{"x":-113.8,"y":432.15,"z":224.1},{"x":-113.92,"y":434.27,"z":219.89}]},{"lat":-58.96,"lon":66.98,"b":[{"x":-100.92,"y":430.6,"z":233.08},{"x":-96.88,"y":430.18,"z":235.54},{"x":-96.76,"y":427.91,"z":239.69},{"x":-100.66,"y":426.08,"z":241.35},{"x":-104.66,"y":426.5,"z":238.89},{"x":-104.8,"y":428.75,"z":234.77}]},{"lat":-57.6,"lon":70.02,"b":[{"x":-91.65,"y":424.48,"z":247.66},{"x":-87.58,"y":423.94,"z":250.07},{"x":-87.45,"y":421.55,"z":254.11},{"x":-91.36,"y":419.74,"z":255.73},{"x":-95.39,"y":420.29,"z":253.34},{"x":-95.55,"y":422.65,"z":249.32}]},{"lat":-56.18,"lon":72.83,"b":[{"x":-82.29,"y":417.83,"z":261.87},{"x":-78.2,"y":417.15,"z":264.2},{"x":-78.06,"y":414.65,"z":268.13},{"x":-81.98,"y":412.87,"z":269.72},{"x":-86.03,"y":413.55,"z":267.4},{"x":-86.2,"y":416.01,"z":263.49}]},{"lat":-54.71,"lon":75.41,"b":[{"x":-72.88,"y":410.66,"z":275.64},{"x":-68.77,"y":409.85,"z":277.88},{"x":-68.63,"y":407.26,"z":281.69},{"x":-72.56,"y":405.51,"z":283.24},{"x":-76.62,"y":406.31,"z":281.02},{"x":-76.8,"y":408.87,"z":277.23}]},{"lat":-53.21,"lon":77.79,"b":[{"x":-63.45,"y":403.01,"z":288.93},{"x":-59.35,"y":402.09,"z":291.08},{"x":-59.22,"y":399.42,"z":294.76},{"x":-63.14,"y":397.7,"z":296.27},{"x":-67.2,"y":398.61,"z":294.15},{"x":-67.38,"y":401.25,"z":290.48}]},{"lat":-51.68,"lon":79.99,"b":[{"x":-54.05,"y":394.94,"z":301.71},{"x":-49.96,"y":393.91,"z":303.76},{"x":-49.84,"y":391.17,"z":307.29},{"x":-53.76,"y":389.48,"z":308.78},{"x":-57.8,"y":390.5,"z":306.76},{"x":-57.97,"y":393.22,"z":303.23}]},{"lat":-50.13,"lon":82,"b":[{"x":-44.71,"y":386.49,"z":313.94},{"x":-40.64,"y":385.36,"z":315.88},{"x":-40.54,"y":382.56,"z":319.27},{"x":-44.44,"y":380.92,"z":320.72},{"x":-48.47,"y":382.02,"z":318.81},{"x":-48.62,"y":384.8,"z":315.42}]},{"lat":-48.57,"lon":83.87,"b":[{"x":-35.46,"y":377.7,"z":325.6},{"x":-31.43,"y":376.48,"z":327.42},{"x":-31.34,"y":373.65,"z":330.66},{"x":-35.23,"y":372.04,"z":332.08},{"x":-39.23,"y":373.23,"z":330.29},{"x":-39.37,"y":376.06,"z":327.05}]},{"lat":-47.02,"lon":85.58,"b":[{"x":-26.34,"y":368.64,"z":336.67},{"x":-22.35,"y":367.34,"z":338.37},{"x":-22.29,"y":364.47,"z":341.46},{"x":-26.16,"y":362.91,"z":342.85},{"x":-30.11,"y":364.18,"z":341.18},{"x":-30.23,"y":367.04,"z":338.09}]},{"lat":-45.48,"lon":87.17,"b":[{"x":-17.37,"y":359.35,"z":347.14},{"x":-13.43,"y":357.98,"z":348.72},{"x":-13.4,"y":355.09,"z":351.66},{"x":-17.25,"y":353.58,"z":353.02},{"x":-21.15,"y":354.91,"z":351.47},{"x":-21.24,"y":357.79,"z":348.53}]},{"lat":-43.95,"lon":88.64,"b":[{"x":-8.59,"y":349.88,"z":357},{"x":-4.71,"y":348.45,"z":358.46},{"x":-4.71,"y":345.56,"z":361.25},{"x":-8.52,"y":344.09,"z":362.59},{"x":-12.37,"y":345.47,"z":361.16},{"x":-12.43,"y":348.36,"z":358.37}]},{"lat":-42.44,"lon":90,"b":[{"x":0,"y":340.28,"z":366.27},{"x":3.82,"y":338.81,"z":367.61},{"x":3.78,"y":335.91,"z":370.25},{"x":0,"y":334.49,"z":371.57},{"x":-3.78,"y":335.91,"z":370.25},{"x":-3.82,"y":338.81,"z":367.61}]},{"lat":-40.95,"lon":91.26,"b":[{"x":8.37,"y":330.59,"z":374.95},{"x":12.11,"y":329.08,"z":376.16},{"x":12.04,"y":326.2,"z":378.67},{"x":8.3,"y":324.83,"z":379.95},{"x":4.58,"y":326.28,"z":378.76},{"x":4.58,"y":329.17,"z":376.26}]},{"lat":-39.49,"lon":92.44,"b":[{"x":16.5,"y":320.86,"z":383.04},{"x":20.17,"y":319.33,"z":384.14},{"x":20.07,"y":316.47,"z":386.51},{"x":16.36,"y":315.14,"z":387.77},{"x":12.72,"y":316.62,"z":386.69},{"x":12.75,"y":319.49,"z":384.33}]},{"lat":-38.07,"lon":93.54,"b":[{"x":24.38,"y":311.13,"z":390.58},{"x":27.98,"y":309.58,"z":391.56},{"x":27.84,"y":306.75,"z":393.79},{"x":24.17,"y":305.47,"z":395.04},{"x":20.61,"y":306.97,"z":394.07},{"x":20.68,"y":309.8,"z":391.84}]},{"lat":-64.23,"lon":10.58,"b":[{"x":-213.54,"y":450.44,"z":38.45},{"x":-212.53,"y":450.85,"z":39.22},{"x":-212.69,"y":450.65,"z":40.68},{"x":-213.86,"y":450.03,"z":41.36},{"x":-214.86,"y":449.63,"z":40.58},{"x":-214.69,"y":449.84,"z":39.14}]},{"lat":-64.51,"lon":14.51,"b":[{"x":-207.89,"y":451.93,"z":49.81},{"x":-204.97,"y":453.01,"z":52.02},{"x":-205.36,"y":452.34,"z":56.2},{"x":-208.69,"y":450.57,"z":58.1},{"x":-211.57,"y":449.52,"z":55.83},{"x":-211.16,"y":450.2,"z":51.71}]},{"lat":-64.68,"lon":18.63,"b":[{"x":-202.21,"y":452.7,"z":64.1},{"x":-199.19,"y":453.71,"z":66.39},{"x":-199.53,"y":452.92,"z":70.63},{"x":-202.9,"y":451.12,"z":72.52},{"x":-205.89,"y":450.14,"z":70.18},{"x":-205.54,"y":450.94,"z":66}]},{"lat":-64.68,"lon":27.24,"b":[{"x":-189.82,"y":452.93,"z":93.56},{"x":-186.6,"y":453.77,"z":95.98},{"x":-186.83,"y":452.73,"z":100.33},{"x":-190.3,"y":450.86,"z":102.19},{"x":-193.49,"y":450.06,"z":99.72},{"x":-193.24,"y":451.1,"z":95.44}]},{"lat":-64.49,"lon":31.65,"b":[{"x":-183.11,"y":452.33,"z":108.65},{"x":-179.78,"y":453.06,"z":111.13},{"x":-179.96,"y":451.89,"z":115.51},{"x":-183.47,"y":450,"z":117.35},{"x":-186.76,"y":449.3,"z":114.83},{"x":-186.57,"y":450.46,"z":110.51}]},{"lat":-64.15,"lon":36.06,"b":[{"x":-176.14,"y":450.55,"z":126.28},{"x":-174.55,"y":450.83,"z":127.45},{"x":-174.61,"y":450.23,"z":129.49},{"x":-176.26,"y":449.34,"z":130.34},{"x":-177.84,"y":449.06,"z":129.15},{"x":-177.77,"y":449.67,"z":127.13}]},{"lat":-63.68,"lon":40.42,"b":[{"x":-168.66,"y":449.52,"z":139.34},{"x":-165.14,"y":450.03,"z":141.9},{"x":-165.21,"y":448.59,"z":146.31},{"x":-168.82,"y":446.65,"z":148.09},{"x":-172.3,"y":446.18,"z":145.5},{"x":-172.22,"y":447.61,"z":141.15}]},{"lat":-63.07,"lon":44.68,"b":[{"x":-160.95,"y":447.28,"z":154.82},{"x":-157.34,"y":447.66,"z":157.41},{"x":-157.36,"y":446.08,"z":161.8},{"x":-161.01,"y":444.13,"z":163.56},{"x":-164.58,"y":443.78,"z":160.95},{"x":-164.55,"y":445.34,"z":156.61}]},{"lat":-62.33,"lon":48.8,"b":[{"x":-152.93,"y":444.44,"z":170.32},{"x":-149.24,"y":444.7,"z":172.92},{"x":-149.22,"y":442.98,"z":177.29},{"x":-152.9,"y":441.02,"z":179.02},{"x":-156.56,"y":440.8,"z":176.4},{"x":-156.57,"y":442.5,"z":172.08}]},{"lat":-61.46,"lon":52.74,"b":[{"x":-144.63,"y":441.02,"z":185.77},{"x":-140.86,"y":441.14,"z":188.37},{"x":-140.81,"y":439.28,"z":192.7},{"x":-144.52,"y":437.32,"z":194.39},{"x":-148.25,"y":437.23,"z":191.79},{"x":-148.31,"y":439.06,"z":187.5}]},{"lat":-60.48,"lon":56.49,"b":[{"x":-136.08,"y":436.99,"z":201.11},{"x":-132.24,"y":436.98,"z":203.7},{"x":-132.15,"y":434.98,"z":207.97},{"x":-135.89,"y":433.03,"z":209.63},{"x":-139.7,"y":433.07,"z":207.04},{"x":-139.79,"y":435.03,"z":202.81}]},{"lat":-59.39,"lon":60.02,"b":[{"x":-127.3,"y":432.37,"z":216.28},{"x":-123.39,"y":432.22,"z":218.84},{"x":-123.27,"y":430.09,"z":223.04},{"x":-127.05,"y":428.15,"z":224.66},{"x":-130.91,"y":428.32,"z":222.11},{"x":-131.04,"y":430.41,"z":217.94}]},{"lat":-58.21,"lon":63.34,"b":[{"x":-118.32,"y":427.16,"z":231.22},{"x":-114.36,"y":426.87,"z":233.73},{"x":-114.22,"y":424.62,"z":237.85},{"x":-118.01,"y":422.7,"z":239.43},{"x":-121.93,"y":423,"z":236.93},{"x":-122.09,"y":425.22,"z":232.83}]},{"lat":-56.95,"lon":66.43,"b":[{"x":-109.18,"y":421.38,"z":245.85},{"x":-105.18,"y":420.96,"z":248.31},{"x":-105.02,"y":418.6,"z":252.33},{"x":-108.83,"y":416.69,"z":253.88},{"x":-112.79,"y":417.12,"z":251.43},{"x":-112.97,"y":419.45,"z":247.43}]},{"lat":-55.62,"lon":69.31,"b":[{"x":-99.91,"y":415.06,"z":260.13},{"x":-95.88,"y":414.51,"z":262.52},{"x":-95.71,"y":412.04,"z":266.44},{"x":-99.54,"y":410.15,"z":267.94},{"x":-103.53,"y":410.71,"z":265.57},{"x":-103.73,"y":413.15,"z":261.68}]},{"lat":-54.24,"lon":71.98,"b":[{"x":-90.56,"y":408.22,"z":274.01},{"x":-86.5,"y":407.54,"z":276.32},{"x":-86.33,"y":404.98,"z":280.11},{"x":-90.17,"y":403.13,"z":281.58},{"x":-94.18,"y":403.8,"z":279.29},{"x":-94.39,"y":406.34,"z":275.51}]},{"lat":-52.81,"lon":74.46,"b":[{"x":-81.15,"y":400.91,"z":287.43},{"x":-77.09,"y":400.11,"z":289.65},{"x":-76.92,"y":397.46,"z":293.31},{"x":-80.76,"y":395.64,"z":294.74},{"x":-84.78,"y":396.43,"z":292.55},{"x":-84.99,"y":399.05,"z":288.89}]},{"lat":-51.35,"lon":76.75,"b":[{"x":-71.74,"y":393.16,"z":300.35},{"x":-67.68,"y":392.25,"z":302.47},{"x":-67.51,"y":389.53,"z":306},{"x":-71.35,"y":387.75,"z":307.4},{"x":-75.37,"y":388.64,"z":305.3},{"x":-75.58,"y":391.34,"z":301.78}]},{"lat":-49.87,"lon":78.87,"b":[{"x":-62.35,"y":385.01,"z":312.74},{"x":-58.3,"y":384,"z":314.76},{"x":-58.15,"y":381.22,"z":318.15},{"x":-61.99,"y":379.48,"z":319.51},{"x":-65.99,"y":380.47,"z":317.52},{"x":-66.19,"y":383.23,"z":314.14}]},{"lat":-48.37,"lon":80.84,"b":[{"x":-53.02,"y":376.52,"z":324.58},{"x":-49,"y":375.42,"z":326.49},{"x":-48.86,"y":372.59,"z":329.73},{"x":-52.69,"y":370.89,"z":331.06},{"x":-56.67,"y":371.97,"z":329.18},{"x":-56.86,"y":374.78,"z":325.94}]},{"lat":-46.87,"lon":82.66,"b":[{"x":-43.79,"y":367.73,"z":335.84},{"x":-39.8,"y":366.54,"z":337.63},{"x":-39.68,"y":363.68,"z":340.72},{"x":-43.49,"y":362.03,"z":342.02},{"x":-47.44,"y":363.19,"z":340.26},{"x":-47.62,"y":366.04,"z":337.17}]},{"lat":-45.37,"lon":84.35,"b":[{"x":-34.68,"y":358.7,"z":346.51},{"x":-30.73,"y":357.44,"z":348.18},{"x":-30.64,"y":354.55,"z":351.12},{"x":-34.43,"y":352.95,"z":352.39},{"x":-38.34,"y":354.18,"z":350.75},{"x":-38.5,"y":357.05,"z":347.81}]},{"lat":-43.88,"lon":85.92,"b":[{"x":-25.73,"y":349.46,"z":356.58},{"x":-21.82,"y":348.14,"z":358.14},{"x":-21.76,"y":345.25,"z":360.93},{"x":-25.53,"y":343.69,"z":362.17},{"x":-29.39,"y":344.98,"z":360.65},{"x":-29.52,"y":347.86,"z":357.85}]},{"lat":-42.41,"lon":87.38,"b":[{"x":-16.95,"y":340.08,"z":366.06},{"x":-13.1,"y":338.7,"z":367.49},{"x":-13.07,"y":335.81,"z":370.14},{"x":-16.81,"y":334.3,"z":371.36},{"x":-20.62,"y":335.64,"z":369.95},{"x":-20.72,"y":338.52,"z":367.3}]},{"lat":-40.95,"lon":88.74,"b":[{"x":-8.37,"y":330.59,"z":374.95},{"x":-4.58,"y":329.17,"z":376.26},{"x":-4.58,"y":326.28,"z":378.76},{"x":-8.3,"y":324.83,"z":379.95},{"x":-12.04,"y":326.2,"z":378.67},{"x":-12.11,"y":329.08,"z":376.16}]},{"lat":-39.52,"lon":90,"b":[{"x":0,"y":321.04,"z":383.25},{"x":3.71,"y":319.58,"z":384.44},{"x":3.68,"y":316.72,"z":386.81},{"x":0,"y":315.31,"z":387.98},{"x":-3.68,"y":316.72,"z":386.81},{"x":-3.71,"y":319.58,"z":384.44}]},{"lat":-38.12,"lon":91.18,"b":[{"x":8.14,"y":311.46,"z":390.99},{"x":11.78,"y":309.98,"z":392.07},{"x":11.71,"y":307.15,"z":394.3},{"x":8.07,"y":305.79,"z":395.45},{"x":4.46,"y":307.22,"z":394.39},{"x":4.46,"y":310.06,"z":392.16}]},{"lat":-36.74,"lon":92.28,"b":[{"x":16.03,"y":301.9,"z":398.18},{"x":19.6,"y":300.41,"z":399.15},{"x":19.49,"y":297.61,"z":401.25},{"x":15.89,"y":296.3,"z":402.38},{"x":12.35,"y":297.74,"z":401.43},{"x":12.39,"y":300.55,"z":399.33}]},{"lat":-62.22,"lon":6.37,"b":[{"x":-231.29,"y":442.62,"z":23.72},{"x":-229.88,"y":443.29,"z":24.82},{"x":-230.16,"y":443.02,"z":26.98},{"x":-231.85,"y":442.08,"z":28},{"x":-233.23,"y":441.42,"z":26.87},{"x":-232.95,"y":441.69,"z":24.74}]},{"lat":-62.58,"lon":9.84,"b":[{"x":-226.38,"y":444.35,"z":35.45},{"x":-223.77,"y":445.5,"z":37.5},{"x":-224.21,"y":444.93,"z":41.43},{"x":-227.28,"y":443.19,"z":43.26},{"x":-229.85,"y":442.07,"z":41.15},{"x":-229.39,"y":442.65,"z":37.28}]},{"lat":-62.86,"lon":13.48,"b":[{"x":-221.36,"y":445.57,"z":49.1},{"x":-218.58,"y":446.69,"z":51.29},{"x":-218.98,"y":446.01,"z":55.41},{"x":-222.18,"y":444.18,"z":57.27},{"x":-224.93,"y":443.08,"z":55.03},{"x":-224.51,"y":443.79,"z":50.98}]},{"lat":-63.04,"lon":17.28,"b":[{"x":-216.02,"y":446.41,"z":63.21},{"x":-213.14,"y":447.47,"z":65.47},{"x":-213.49,"y":446.67,"z":69.66},{"x":-216.74,"y":444.81,"z":71.51},{"x":-219.58,"y":443.78,"z":69.19},{"x":-219.22,"y":444.59,"z":65.07}]},{"lat":-63.13,"lon":21.22,"b":[{"x":-210.63,"y":446.13,"z":81.18},{"x":-210.18,"y":446.28,"z":81.53},{"x":-210.22,"y":446.14,"z":82.18},{"x":-210.72,"y":445.85,"z":82.45},{"x":-211.17,"y":445.71,"z":82.09},{"x":-211.12,"y":445.85,"z":81.46}]},{"lat":-63.1,"lon":25.26,"b":[{"x":-204.3,"y":446.86,"z":92.3},{"x":-201.21,"y":447.75,"z":94.71},{"x":-201.46,"y":446.72,"z":99},{"x":-204.8,"y":444.78,"z":100.81},{"x":-207.85,"y":443.92,"z":98.36},{"x":-207.59,"y":444.96,"z":94.14}]},{"lat":-62.95,"lon":29.37,"b":[{"x":-197.91,"y":446.39,"z":107.23},{"x":-194.72,"y":447.2,"z":109.7},{"x":-194.91,"y":446.03,"z":114.02},{"x":-198.3,"y":444.07,"z":115.81},{"x":-201.45,"y":443.3,"z":113.3},{"x":-201.26,"y":444.46,"z":109.04}]},{"lat":-62.68,"lon":33.5,"b":[{"x":-191.18,"y":445.44,"z":122.35},{"x":-187.89,"y":446.14,"z":124.87},{"x":-188.03,"y":444.84,"z":129.21},{"x":-191.46,"y":442.86,"z":130.97},{"x":-194.71,"y":442.19,"z":128.42},{"x":-194.57,"y":443.48,"z":124.14}]},{"lat":-62.28,"lon":37.61,"b":[{"x":-184.1,"y":443.96,"z":137.61},{"x":-180.72,"y":444.55,"z":140.17},{"x":-180.8,"y":443.12,"z":144.52},{"x":-184.27,"y":441.12,"z":146.26},{"x":-187.62,"y":440.56,"z":143.67},{"x":-187.54,"y":441.97,"z":139.38}]},{"lat":-61.75,"lon":41.67,"b":[{"x":-176.69,"y":441.94,"z":152.97},{"x":-173.21,"y":442.41,"z":155.56},{"x":-173.24,"y":440.85,"z":159.91},{"x":-176.76,"y":438.83,"z":161.61},{"x":-180.2,"y":438.38,"z":159},{"x":-180.17,"y":439.93,"z":154.71}]},{"lat":-61.1,"lon":45.62,"b":[{"x":-168.97,"y":439.35,"z":168.37},{"x":-165.39,"y":439.71,"z":170.98},{"x":-165.38,"y":438.01,"z":175.3},{"x":-168.93,"y":435.97,"z":176.97},{"x":-172.47,"y":435.65,"z":174.34},{"x":-172.48,"y":437.33,"z":170.07}]},{"lat":-60.33,"lon":49.45,"b":[{"x":-160.94,"y":436.2,"z":183.74},{"x":-157.28,"y":436.42,"z":186.35},{"x":-157.22,"y":434.59,"z":190.64},{"x":-160.81,"y":432.55,"z":192.27},{"x":-164.43,"y":432.35,"z":189.65},{"x":-164.49,"y":434.16,"z":185.41}]},{"lat":-59.45,"lon":53.11,"b":[{"x":-152.63,"y":432.46,"z":199.03},{"x":-148.89,"y":432.55,"z":201.64},{"x":-148.79,"y":430.59,"z":205.87},{"x":-152.42,"y":428.55,"z":207.46},{"x":-156.11,"y":428.48,"z":204.85},{"x":-156.22,"y":430.42,"z":200.66}]},{"lat":-58.46,"lon":56.61,"b":[{"x":-144.06,"y":428.14,"z":214.17},{"x":-140.26,"y":428.1,"z":216.76},{"x":-140.12,"y":426.01,"z":220.93},{"x":-143.78,"y":423.98,"z":222.48},{"x":-147.54,"y":424.04,"z":219.89},{"x":-147.69,"y":426.11,"z":215.76}]},{"lat":-57.38,"lon":59.91,"b":[{"x":-135.27,"y":423.25,"z":229.1},{"x":-131.41,"y":423.08,"z":231.65},{"x":-131.25,"y":420.86,"z":235.75},{"x":-134.93,"y":418.85,"z":237.25},{"x":-138.75,"y":419.04,"z":234.71},{"x":-138.93,"y":421.22,"z":230.65}]},{"lat":-56.21,"lon":63.03,"b":[{"x":-126.29,"y":417.8,"z":243.76},{"x":-122.38,"y":417.5,"z":246.27},{"x":-122.19,"y":415.17,"z":250.27},{"x":-125.9,"y":413.17,"z":251.73},{"x":-129.77,"y":413.49,"z":249.24},{"x":-129.98,"y":415.78,"z":245.27}]},{"lat":-54.97,"lon":65.95,"b":[{"x":-117.15,"y":411.81,"z":258.1},{"x":-113.2,"y":411.38,"z":260.54},{"x":-112.99,"y":408.94,"z":264.44},{"x":-116.72,"y":406.97,"z":265.86},{"x":-120.63,"y":407.41,"z":263.43},{"x":-120.86,"y":409.81,"z":259.56}]},{"lat":-53.68,"lon":68.68,"b":[{"x":-107.89,"y":405.31,"z":272.05},{"x":-103.91,"y":404.75,"z":274.42},{"x":-103.69,"y":402.22,"z":278.2},{"x":-107.44,"y":400.27,"z":279.59},{"x":-111.38,"y":400.83,"z":277.23},{"x":-111.62,"y":403.34,"z":273.48}]},{"lat":-52.33,"lon":71.23,"b":[{"x":-98.55,"y":398.33,"z":285.57},{"x":-94.54,"y":397.65,"z":287.87},{"x":-94.33,"y":395.03,"z":291.52},{"x":-98.08,"y":393.12,"z":292.86},{"x":-102.04,"y":393.79,"z":290.6},{"x":-102.29,"y":396.38,"z":286.96}]},{"lat":-50.94,"lon":73.6,"b":[{"x":-89.16,"y":390.9,"z":298.63},{"x":-85.14,"y":390.11,"z":300.82},{"x":-84.93,"y":387.42,"z":304.34},{"x":-88.69,"y":385.54,"z":305.65},{"x":-92.65,"y":386.33,"z":303.48},{"x":-92.91,"y":388.99,"z":299.97}]},{"lat":-49.53,"lon":75.81,"b":[{"x":-79.76,"y":383.07,"z":311.17},{"x":-75.75,"y":382.18,"z":313.27},{"x":-75.54,"y":379.42,"z":316.65},{"x":-79.3,"y":377.59,"z":317.92},{"x":-83.26,"y":378.47,"z":315.85},{"x":-83.52,"y":381.2,"z":312.48}]},{"lat":-48.09,"lon":77.87,"b":[{"x":-70.39,"y":374.89,"z":323.17},{"x":-66.39,"y":373.89,"z":325.16},{"x":-66.19,"y":371.09,"z":328.4},{"x":-69.95,"y":369.3,"z":329.64},{"x":-73.9,"y":370.28,"z":327.67},{"x":-74.15,"y":373.06,"z":324.44}]},{"lat":-46.65,"lon":79.78,"b":[{"x":-61.08,"y":366.39,"z":334.61},{"x":-57.1,"y":365.31,"z":336.49},{"x":-56.92,"y":362.46,"z":339.58},{"x":-60.67,"y":360.72,"z":340.79},{"x":-64.6,"y":361.78,"z":338.93},{"x":-64.84,"y":364.6,"z":335.85}]},{"lat":-45.2,"lon":81.56,"b":[{"x":-51.87,"y":357.63,"z":345.47},{"x":-47.92,"y":356.46,"z":347.24},{"x":-47.76,"y":353.6,"z":350.18},{"x":-51.5,"y":351.91,"z":351.35},{"x":-55.4,"y":353.04,"z":349.62},{"x":-55.61,"y":355.89,"z":346.68}]},{"lat":-43.75,"lon":83.22,"b":[{"x":-42.78,"y":348.65,"z":355.75},{"x":-38.87,"y":347.42,"z":357.39},{"x":-38.74,"y":344.53,"z":360.19},{"x":-42.46,"y":342.9,"z":361.33},{"x":-46.32,"y":344.09,"z":359.72},{"x":-46.51,"y":346.96,"z":356.92}]},{"lat":-42.32,"lon":84.77,"b":[{"x":-33.84,"y":339.5,"z":365.43},{"x":-29.97,"y":338.21,"z":366.96},{"x":-29.88,"y":335.32,"z":369.6},{"x":-33.57,"y":333.73,"z":370.73},{"x":-37.39,"y":334.98,"z":369.23},{"x":-37.55,"y":337.86,"z":366.58}]},{"lat":-40.9,"lon":86.21,"b":[{"x":-25.07,"y":330.22,"z":374.53},{"x":-21.26,"y":328.88,"z":375.93},{"x":-21.19,"y":326,"z":378.44},{"x":-24.87,"y":324.47,"z":379.54},{"x":-28.63,"y":325.76,"z":378.16},{"x":-28.77,"y":328.63,"z":375.65}]},{"lat":-39.49,"lon":87.56,"b":[{"x":-16.5,"y":320.86,"z":383.04},{"x":-12.75,"y":319.49,"z":384.33},{"x":-12.72,"y":316.62,"z":386.69},{"x":-16.36,"y":315.14,"z":387.77},{"x":-20.07,"y":316.47,"z":386.51},{"x":-20.17,"y":319.33,"z":384.14}]},{"lat":-38.12,"lon":88.82,"b":[{"x":-8.14,"y":311.46,"z":390.99},{"x":-4.46,"y":310.06,"z":392.16},{"x":-4.46,"y":307.22,"z":394.39},{"x":-8.07,"y":305.79,"z":395.45},{"x":-11.71,"y":307.15,"z":394.3},{"x":-11.78,"y":309.98,"z":392.07}]},{"lat":-36.76,"lon":90,"b":[{"x":0,"y":302.06,"z":398.38},{"x":3.61,"y":300.63,"z":399.44},{"x":3.57,"y":297.82,"z":401.54},{"x":0,"y":296.45,"z":402.58},{"x":-3.57,"y":297.82,"z":401.54},{"x":-3.61,"y":300.63,"z":399.44}]},{"lat":-35.44,"lon":91.11,"b":[{"x":7.9,"y":292.69,"z":405.25},{"x":11.44,"y":291.24,"z":406.2},{"x":11.37,"y":288.47,"z":408.17},{"x":7.83,"y":287.15,"z":409.2},{"x":4.33,"y":288.54,"z":408.26},{"x":4.33,"y":291.31,"z":406.29}]},{"lat":-60.64,"lon":5.96,"b":[{"x":-243.39,"y":436.14,"z":22.29},{"x":-241.37,"y":437.18,"z":23.93},{"x":-241.8,"y":436.76,"z":27.14},{"x":-244.25,"y":435.29,"z":28.66},{"x":-246.24,"y":434.27,"z":26.97},{"x":-245.81,"y":434.71,"z":23.81}]},{"lat":-60.98,"lon":9.19,"b":[{"x":-238.93,"y":437.77,"z":34.82},{"x":-236.39,"y":438.98,"z":36.9},{"x":-236.86,"y":438.38,"z":40.88},{"x":-239.89,"y":436.55,"z":42.72},{"x":-242.4,"y":435.37,"z":40.58},{"x":-241.92,"y":435.99,"z":36.66}]},{"lat":-61.25,"lon":12.58,"b":[{"x":-234.26,"y":439.01,"z":48.38},{"x":-231.61,"y":440.17,"z":50.54},{"x":-232.03,"y":439.47,"z":54.6},{"x":-235.1,"y":437.59,"z":56.42},{"x":-237.71,"y":436.46,"z":54.21},{"x":-237.28,"y":437.18,"z":50.22}]},{"lat":-61.44,"lon":16.12,"b":[{"x":-229.25,"y":439.89,"z":62.35},{"x":-226.55,"y":440.97,"z":64.56},{"x":-226.91,"y":440.17,"z":68.61},{"x":-229.98,"y":438.29,"z":70.39},{"x":-232.64,"y":437.24,"z":68.13},{"x":-232.27,"y":438.05,"z":64.15}]},{"lat":-61.53,"lon":23.54,"b":[{"x":-218.18,"y":440.52,"z":90.99},{"x":-215.24,"y":441.47,"z":93.38},{"x":-215.49,"y":440.43,"z":97.6},{"x":-218.7,"y":438.44,"z":99.37},{"x":-221.61,"y":437.53,"z":96.94},{"x":-221.35,"y":438.57,"z":92.79}]},{"lat":-61.42,"lon":27.37,"b":[{"x":-212.13,"y":440.18,"z":105.74},{"x":-209.08,"y":441.04,"z":108.19},{"x":-209.28,"y":439.89,"z":112.44},{"x":-212.53,"y":437.87,"z":114.19},{"x":-215.55,"y":437.04,"z":111.7},{"x":-215.34,"y":438.19,"z":107.5}]},{"lat":-61.2,"lon":31.25,"b":[{"x":-205.72,"y":439.37,"z":120.68},{"x":-202.57,"y":440.14,"z":123.19},{"x":-202.71,"y":438.86,"z":127.47},{"x":-206.01,"y":436.81,"z":129.18},{"x":-209.13,"y":436.08,"z":126.65},{"x":-208.98,"y":437.36,"z":122.43}]},{"lat":-60.86,"lon":35.13,"b":[{"x":-198.96,"y":438.07,"z":135.79},{"x":-195.71,"y":438.74,"z":138.34},{"x":-195.8,"y":437.33,"z":142.63},{"x":-199.14,"y":435.26,"z":144.31},{"x":-202.36,"y":434.63,"z":141.74},{"x":-202.27,"y":436.03,"z":137.5}]},{"lat":-60.41,"lon":38.97,"b":[{"x":-191.87,"y":436.25,"z":151.01},{"x":-188.52,"y":436.81,"z":153.59},{"x":-188.55,"y":435.27,"z":157.88},{"x":-191.93,"y":433.18,"z":159.53},{"x":-195.24,"y":432.66,"z":156.92},{"x":-195.21,"y":434.19,"z":152.69}]},{"lat":-59.84,"lon":42.76,"b":[{"x":-184.43,"y":433.9,"z":166.28},{"x":-180.99,"y":434.34,"z":168.89},{"x":-180.97,"y":432.66,"z":173.16},{"x":-184.4,"y":430.56,"z":174.77},{"x":-187.8,"y":430.16,"z":172.14},{"x":-187.82,"y":431.81,"z":167.92}]},{"lat":-59.15,"lon":46.44,"b":[{"x":-176.68,"y":430.99,"z":181.55},{"x":-173.15,"y":431.31,"z":184.17},{"x":-173.09,"y":429.5,"z":188.41},{"x":-176.55,"y":427.4,"z":189.98},{"x":-180.04,"y":427.11,"z":187.35},{"x":-180.11,"y":428.89,"z":183.16}]},{"lat":-58.36,"lon":50.01,"b":[{"x":-168.64,"y":427.53,"z":196.76},{"x":-165.02,"y":427.72,"z":199.38},{"x":-164.91,"y":425.78,"z":203.58},{"x":-168.41,"y":423.68,"z":205.1},{"x":-171.98,"y":423.51,"z":202.47},{"x":-172.1,"y":425.42,"z":198.33}]},{"lat":-57.46,"lon":53.44,"b":[{"x":-160.31,"y":423.5,"z":211.85},{"x":-156.62,"y":423.57,"z":214.46},{"x":-156.47,"y":421.5,"z":218.59},{"x":-160.01,"y":419.4,"z":220.07},{"x":-163.65,"y":419.36,"z":217.46},{"x":-163.81,"y":421.39,"z":213.37}]},{"lat":-56.47,"lon":56.71,"b":[{"x":-151.74,"y":418.91,"z":226.75},{"x":-147.98,"y":418.85,"z":229.34},{"x":-147.8,"y":416.67,"z":233.4},{"x":-151.36,"y":414.58,"z":234.83},{"x":-155.08,"y":414.66,"z":232.26},{"x":-155.27,"y":416.81,"z":228.23}]},{"lat":-55.4,"lon":59.81,"b":[{"x":-142.94,"y":413.78,"z":241.42},{"x":-139.13,"y":413.59,"z":243.96},{"x":-138.92,"y":411.29,"z":247.93},{"x":-142.51,"y":409.22,"z":249.33},{"x":-146.28,"y":409.42,"z":246.79},{"x":-146.51,"y":411.69,"z":242.85}]},{"lat":-54.25,"lon":62.75,"b":[{"x":-133.96,"y":408.12,"z":255.78},{"x":-130.09,"y":407.8,"z":258.27},{"x":-129.86,"y":405.39,"z":262.14},{"x":-133.48,"y":403.34,"z":263.49},{"x":-137.3,"y":403.67,"z":261.02},{"x":-137.55,"y":406.04,"z":257.18}]},{"lat":-53.04,"lon":65.52,"b":[{"x":-124.83,"y":401.94,"z":269.79},{"x":-120.92,"y":401.5,"z":272.22},{"x":-120.68,"y":399,"z":275.98},{"x":-124.31,"y":396.98,"z":277.29},{"x":-128.17,"y":397.43,"z":274.88},{"x":-128.44,"y":399.89,"z":271.14}]},{"lat":-51.77,"lon":68.11,"b":[{"x":-115.58,"y":395.29,"z":283.4},{"x":-111.64,"y":394.73,"z":285.75},{"x":-111.39,"y":392.14,"z":289.39},{"x":-115.04,"y":390.15,"z":290.65},{"x":-118.92,"y":390.72,"z":288.32},{"x":-119.21,"y":393.27,"z":284.71}]},{"lat":-50.46,"lon":70.55,"b":[{"x":-106.25,"y":388.19,"z":296.56},{"x":-102.29,"y":387.52,"z":298.83},{"x":-102.03,"y":384.86,"z":302.33},{"x":-105.7,"y":382.9,"z":303.56},{"x":-109.6,"y":383.57,"z":301.32},{"x":-109.9,"y":386.2,"z":297.82}]},{"lat":-49.12,"lon":72.83,"b":[{"x":-96.88,"y":380.69,"z":309.23},{"x":-92.91,"y":379.9,"z":311.4},{"x":-92.66,"y":377.18,"z":314.78},{"x":-96.32,"y":375.27,"z":315.96},{"x":-100.24,"y":376.04,"z":313.82},{"x":-100.54,"y":378.73,"z":310.46}]},{"lat":-47.75,"lon":74.96,"b":[{"x":-87.5,"y":372.81,"z":321.38},{"x":-83.53,"y":371.93,"z":323.46},{"x":-83.29,"y":369.15,"z":326.69},{"x":-86.96,"y":367.28,"z":327.84},{"x":-90.87,"y":368.15,"z":325.79},{"x":-91.17,"y":370.9,"z":322.57}]},{"lat":-46.36,"lon":76.95,"b":[{"x":-78.15,"y":364.62,"z":332.99},{"x":-74.2,"y":363.64,"z":334.96},{"x":-73.97,"y":360.82,"z":338.04},{"x":-77.63,"y":359,"z":339.16},{"x":-81.54,"y":359.96,"z":337.22},{"x":-81.82,"y":362.75,"z":334.14}]},{"lat":-44.96,"lon":78.81,"b":[{"x":-68.87,"y":356.14,"z":344.04},{"x":-64.93,"y":355.08,"z":345.89},{"x":-64.72,"y":352.23,"z":348.83},{"x":-68.38,"y":350.46,"z":349.91},{"x":-72.27,"y":351.5,"z":348.09},{"x":-72.54,"y":354.32,"z":345.15}]},{"lat":-43.56,"lon":80.55,"b":[{"x":-59.68,"y":347.43,"z":354.5},{"x":-55.77,"y":346.3,"z":356.24},{"x":-55.58,"y":343.43,"z":359.03},{"x":-59.23,"y":341.71,"z":360.09},{"x":-63.09,"y":342.81,"z":358.38},{"x":-63.34,"y":345.66,"z":355.59}]},{"lat":-42.17,"lon":82.18,"b":[{"x":-50.61,"y":338.53,"z":364.39},{"x":-46.74,"y":337.33,"z":366.01},{"x":-46.58,"y":334.46,"z":368.66},{"x":-50.22,"y":332.8,"z":369.69},{"x":-54.03,"y":333.96,"z":368.1},{"x":-54.26,"y":336.81,"z":365.45}]},{"lat":-40.79,"lon":83.7,"b":[{"x":-41.69,"y":329.48,"z":373.69},{"x":-37.87,"y":328.24,"z":375.19},{"x":-37.74,"y":325.37,"z":377.7},{"x":-41.35,"y":323.76,"z":378.7},{"x":-45.12,"y":324.97,"z":377.23},{"x":-45.32,"y":327.82,"z":374.72}]},{"lat":-39.42,"lon":85.13,"b":[{"x":-32.94,"y":320.34,"z":382.42},{"x":-29.18,"y":319.05,"z":383.8},{"x":-29.07,"y":316.19,"z":386.17},{"x":-32.67,"y":314.64,"z":387.15},{"x":-36.39,"y":315.89,"z":385.79},{"x":-36.56,"y":318.73,"z":383.43}]},{"lat":-38.07,"lon":86.46,"b":[{"x":-24.38,"y":311.13,"z":390.58},{"x":-20.68,"y":309.8,"z":391.84},{"x":-20.61,"y":306.97,"z":394.07},{"x":-24.17,"y":305.47,"z":395.04},{"x":-27.84,"y":306.75,"z":393.79},{"x":-27.98,"y":309.58,"z":391.56}]},{"lat":-36.74,"lon":87.72,"b":[{"x":-16.03,"y":301.9,"z":398.18},{"x":-12.39,"y":300.55,"z":399.33},{"x":-12.35,"y":297.74,"z":401.43},{"x":-15.89,"y":296.3,"z":402.38},{"x":-19.49,"y":297.61,"z":401.25},{"x":-19.6,"y":300.41,"z":399.15}]},{"lat":-35.44,"lon":88.89,"b":[{"x":-7.9,"y":292.69,"z":405.25},{"x":-4.33,"y":291.31,"z":406.29},{"x":-4.33,"y":288.54,"z":408.26},{"x":-7.83,"y":287.15,"z":409.2},{"x":-11.37,"y":288.47,"z":408.17},{"x":-11.44,"y":291.24,"z":406.2}]},{"lat":-34.16,"lon":90,"b":[{"x":0,"y":283.51,"z":411.8},{"x":3.5,"y":282.12,"z":412.73},{"x":3.47,"y":279.39,"z":414.59},{"x":0,"y":278.05,"z":415.51},{"x":-3.47,"y":279.39,"z":414.59},{"x":-3.5,"y":282.12,"z":412.73}]},{"lat":-59.1,"lon":5.6,"b":[{"x":-255.25,"y":429.29,"z":22.93},{"x":-253.94,"y":430.01,"z":24.04},{"x":-254.24,"y":429.71,"z":26.2},{"x":-255.98,"y":428.63,"z":26.86},{"x":-257.39,"y":427.87,"z":25.36},{"x":-256.96,"y":428.23,"z":23.59}]},{"lat":-59.42,"lon":8.63,"b":[{"x":-250.95,"y":431.05,"z":34.28},{"x":-248.53,"y":432.28,"z":36.33},{"x":-249.01,"y":431.66,"z":40.25},{"x":-252.14,"y":429.72,"z":41.45},{"x":-254.75,"y":428.43,"z":38.71},{"x":-254.04,"y":429.14,"z":35.46}]},{"lat":-59.68,"lon":11.79,"b":[{"x":-246.58,"y":432.29,"z":47.64},{"x":-244.07,"y":433.48,"z":49.78},{"x":-244.5,"y":432.76,"z":53.77},{"x":-247.67,"y":430.8,"z":54.98},{"x":-250.38,"y":429.57,"z":52.19},{"x":-249.71,"y":430.36,"z":48.84}]},{"lat":-59.87,"lon":15.09,"b":[{"x":-241.89,"y":433.22,"z":61.34},{"x":-239.28,"y":434.34,"z":63.55},{"x":-239.65,"y":433.53,"z":67.61},{"x":-242.87,"y":431.54,"z":68.84},{"x":-245.67,"y":430.39,"z":66},{"x":-245.06,"y":431.25,"z":62.55}]},{"lat":-59.98,"lon":18.51,"b":[{"x":-237.04,"y":433.34,"z":77.42},{"x":-235.71,"y":433.87,"z":78.54},{"x":-235.87,"y":433.41,"z":80.56},{"x":-237.47,"y":432.42,"z":81.17},{"x":-238.9,"y":431.9,"z":79.76},{"x":-238.62,"y":432.36,"z":78.02}]},{"lat":-60,"lon":22.02,"b":[{"x":-231.67,"y":433.37,"z":92.17},{"x":-230.59,"y":433.75,"z":93.09},{"x":-230.69,"y":433.35,"z":94.69},{"x":-231.96,"y":432.57,"z":95.17},{"x":-233.11,"y":432.19,"z":94.05},{"x":-232.92,"y":432.59,"z":92.65}]},{"lat":-59.92,"lon":25.61,"b":[{"x":-225.88,"y":433.15,"z":106.41},{"x":-224.53,"y":433.58,"z":107.54},{"x":-224.63,"y":433.04,"z":109.49},{"x":-226.18,"y":432.08,"z":110.09},{"x":-227.62,"y":431.67,"z":108.72},{"x":-227.42,"y":432.2,"z":107}]},{"lat":-59.74,"lon":29.25,"b":[{"x":-219.72,"y":432.72,"z":120.12},{"x":-217.55,"y":433.31,"z":121.92},{"x":-217.66,"y":432.4,"z":124.95},{"x":-220.08,"y":430.9,"z":125.88},{"x":-222.37,"y":430.33,"z":123.76},{"x":-222.12,"y":431.24,"z":121.04}]},{"lat":-59.45,"lon":32.91,"b":[{"x":-213.22,"y":431.91,"z":133.88},{"x":-210.11,"y":432.64,"z":136.42},{"x":-210.2,"y":431.24,"z":140.65},{"x":-213.6,"y":429.14,"z":141.95},{"x":-216.88,"y":428.46,"z":139},{"x":-216.59,"y":429.83,"z":135.17}]},{"lat":-59.05,"lon":36.56,"b":[{"x":-206.44,"y":430.27,"z":148.94},{"x":-203.23,"y":430.9,"z":151.52},{"x":-203.26,"y":429.38,"z":155.75},{"x":-206.69,"y":427.26,"z":157.06},{"x":-210.05,"y":426.69,"z":154.12},{"x":-209.84,"y":428.17,"z":150.23}]},{"lat":-58.55,"lon":40.17,"b":[{"x":-199.31,"y":428.13,"z":164.07},{"x":-196,"y":428.65,"z":166.67},{"x":-195.98,"y":426.99,"z":170.89},{"x":-199.43,"y":424.86,"z":172.21},{"x":-202.88,"y":424.4,"z":169.3},{"x":-202.74,"y":426.01,"z":165.37}]},{"lat":-57.94,"lon":43.71,"b":[{"x":-191.85,"y":425.45,"z":179.21},{"x":-188.45,"y":425.86,"z":181.84},{"x":-188.38,"y":424.07,"z":186.03},{"x":-191.85,"y":421.93,"z":187.36},{"x":-195.37,"y":421.58,"z":184.48},{"x":-195.3,"y":423.32,"z":180.53}]},{"lat":-57.23,"lon":47.17,"b":[{"x":-184.08,"y":422.24,"z":194.32},{"x":-180.59,"y":422.53,"z":196.96},{"x":-180.48,"y":420.61,"z":201.11},{"x":-183.96,"y":418.46,"z":202.44},{"x":-187.54,"y":418.23,"z":199.61},{"x":-187.55,"y":420.09,"z":195.65}]},{"lat":-56.41,"lon":50.51,"b":[{"x":-176.01,"y":418.48,"z":209.34},{"x":-172.44,"y":418.65,"z":211.97},{"x":-172.29,"y":416.62,"z":216.06},{"x":-175.78,"y":414.46,"z":217.39},{"x":-179.42,"y":414.34,"z":214.63},{"x":-179.5,"y":416.33,"z":210.67}]},{"lat":-55.51,"lon":53.72,"b":[{"x":-167.68,"y":414.19,"z":224.2},{"x":-164.03,"y":414.23,"z":226.8},{"x":-163.84,"y":412.08,"z":230.83},{"x":-167.34,"y":409.91,"z":232.16},{"x":-171.03,"y":409.91,"z":229.48},{"x":-171.17,"y":412.03,"z":225.53}]},{"lat":-54.52,"lon":56.8,"b":[{"x":-159.09,"y":409.36,"z":238.84},{"x":-155.38,"y":409.28,"z":241.42},{"x":-155.15,"y":407.01,"z":245.35},{"x":-158.66,"y":404.85,"z":246.69},{"x":-162.39,"y":404.95,"z":244.09},{"x":-162.6,"y":407.2,"z":240.18}]},{"lat":-53.46,"lon":59.73,"b":[{"x":-150.3,"y":404.01,"z":253.21},{"x":-146.53,"y":403.8,"z":255.74},{"x":-146.27,"y":401.44,"z":259.59},{"x":-149.77,"y":399.27,"z":260.92},{"x":-153.53,"y":399.47,"z":258.42},{"x":-153.8,"y":401.85,"z":254.55}]},{"lat":-52.33,"lon":62.51,"b":[{"x":-141.32,"y":398.16,"z":267.26},{"x":-137.5,"y":397.83,"z":269.73},{"x":-137.23,"y":395.37,"z":273.47},{"x":-140.72,"y":393.21,"z":274.8},{"x":-144.5,"y":393.51,"z":272.4},{"x":-144.82,"y":396,"z":268.59}]},{"lat":-51.14,"lon":65.13,"b":[{"x":-132.2,"y":391.84,"z":280.92},{"x":-128.34,"y":391.39,"z":283.33},{"x":-128.05,"y":388.84,"z":286.95},{"x":-131.53,"y":386.68,"z":288.28},{"x":-135.32,"y":387.08,"z":286},{"x":-135.69,"y":389.68,"z":282.26}]},{"lat":-49.91,"lon":67.61,"b":[{"x":-122.96,"y":385.07,"z":294.17},{"x":-119.07,"y":384.5,"z":296.5},{"x":-118.77,"y":381.87,"z":299.99},{"x":-122.24,"y":379.73,"z":301.32},{"x":-126.02,"y":380.21,"z":299.16},{"x":-126.44,"y":382.91,"z":295.5}]},{"lat":-48.63,"lon":69.94,"b":[{"x":-113.65,"y":377.88,"z":306.95},{"x":-109.74,"y":377.21,"z":309.2},{"x":-109.44,"y":374.52,"z":312.56},{"x":-112.89,"y":372.39,"z":313.87},{"x":-116.66,"y":372.94,"z":311.84},{"x":-117.12,"y":375.74,"z":308.28}]},{"lat":-47.33,"lon":72.13,"b":[{"x":-104.3,"y":370.33,"z":319.24},{"x":-100.38,"y":369.55,"z":321.39},{"x":-100.09,"y":366.8,"z":324.61},{"x":-103.52,"y":364.69,"z":325.92},{"x":-107.26,"y":365.3,"z":324.01},{"x":-107.75,"y":368.2,"z":320.56}]},{"lat":-46,"lon":74.18,"b":[{"x":-94.95,"y":362.44,"z":331},{"x":-91.03,"y":361.57,"z":333.04},{"x":-90.75,"y":358.77,"z":336.13},{"x":-94.15,"y":356.67,"z":337.42},{"x":-97.86,"y":357.35,"z":335.65},{"x":-98.37,"y":360.32,"z":332.31}]},{"lat":-44.66,"lon":76.11,"b":[{"x":-85.63,"y":354.25,"z":342.22},{"x":-81.73,"y":353.3,"z":344.15},{"x":-81.46,"y":350.47,"z":347.09},{"x":-84.82,"y":348.39,"z":348.37},{"x":-88.49,"y":349.11,"z":346.74},{"x":-89.03,"y":352.15,"z":343.51}]},{"lat":-43.32,"lon":77.92,"b":[{"x":-76.37,"y":345.82,"z":352.87},{"x":-72.49,"y":344.79,"z":354.69},{"x":-72.24,"y":341.94,"z":357.48},{"x":-75.58,"y":339.88,"z":358.76},{"x":-79.2,"y":340.65,"z":357.25},{"x":-79.74,"y":343.74,"z":354.15}]},{"lat":-41.97,"lon":79.62,"b":[{"x":-67.21,"y":337.19,"z":362.95},{"x":-63.36,"y":336.09,"z":364.65},{"x":-63.13,"y":333.23,"z":367.3},{"x":-66.43,"y":331.19,"z":368.56},{"x":-69.99,"y":331.99,"z":367.19},{"x":-70.55,"y":335.12,"z":364.22}]},{"lat":-40.62,"lon":81.22,"b":[{"x":-58.17,"y":328.39,"z":372.45},{"x":-54.36,"y":327.23,"z":374.04},{"x":-54.15,"y":324.38,"z":376.55},{"x":-57.42,"y":322.36,"z":377.8},{"x":-60.92,"y":323.18,"z":376.55},{"x":-61.47,"y":326.35,"z":373.71}]},{"lat":-39.29,"lon":82.71,"b":[{"x":-49.28,"y":319.47,"z":381.39},{"x":-45.51,"y":318.26,"z":382.86},{"x":-45.34,"y":315.42,"z":385.23},{"x":-48.56,"y":313.43,"z":386.46},{"x":-51.99,"y":314.26,"z":385.34},{"x":-52.54,"y":317.46,"z":382.63}]},{"lat":-37.97,"lon":84.12,"b":[{"x":-40.55,"y":310.48,"z":389.75},{"x":-36.83,"y":309.23,"z":391.11},{"x":-36.69,"y":306.4,"z":393.34},{"x":-39.87,"y":304.44,"z":394.56},{"x":-43.23,"y":305.27,"z":393.56},{"x":-43.77,"y":308.49,"z":390.98}]},{"lat":-36.68,"lon":85.44,"b":[{"x":-32.01,"y":301.44,"z":397.57},{"x":-28.35,"y":300.16,"z":398.81},{"x":-28.25,"y":297.35,"z":400.91},{"x":-31.38,"y":295.42,"z":402.11},{"x":-34.66,"y":296.25,"z":401.22},{"x":-35.19,"y":299.48,"z":398.78}]},{"lat":-35.4,"lon":86.68,"b":[{"x":-23.68,"y":292.39,"z":404.84},{"x":-20.08,"y":291.09,"z":405.98},{"x":-20.01,"y":288.32,"z":407.95},{"x":-23.1,"y":286.41,"z":409.13},{"x":-26.3,"y":287.24,"z":408.35},{"x":-26.81,"y":290.46,"z":406.04}]},{"lat":-34.14,"lon":87.85,"b":[{"x":-15.56,"y":283.37,"z":411.6},{"x":-12.02,"y":282.05,"z":412.62},{"x":-11.99,"y":279.32,"z":414.48},{"x":-15.03,"y":277.44,"z":415.64},{"x":-18.15,"y":278.26,"z":414.96},{"x":-18.65,"y":281.46,"z":412.78}]},{"lat":-32.92,"lon":88.96,"b":[{"x":-7.66,"y":274.41,"z":417.85},{"x":-4.2,"y":273.07,"z":418.77},{"x":-4.2,"y":270.38,"z":420.51},{"x":-7.19,"y":268.53,"z":421.66},{"x":-10.23,"y":269.34,"z":421.08},{"x":-10.71,"y":272.53,"z":419.01}]},{"lat":-53.08,"lon":6.09,"b":[{"x":-297.4,"y":400.65,"z":31.69},{"x":-297.72,"y":400.31,"z":32.95},{"x":-298.96,"y":399.38,"z":33.15},{"x":-299.71,"y":398.91,"z":31.93},{"x":-299.22,"y":399.39,"z":30.53},{"x":-298.15,"y":400.19,"z":30.48}]},{"lat":-51.64,"lon":7.48,"b":[{"x":-304.44,"y":394.56,"z":39.87},{"x":-305.27,"y":393.56,"z":43.23},{"x":-308.49,"y":390.98,"z":43.77},{"x":-310.48,"y":389.75,"z":40.55},{"x":-309.23,"y":391.11,"z":36.83},{"x":-306.4,"y":393.34,"z":36.69}]},{"lat":-50.15,"lon":8.81,"b":[{"x":-313.43,"y":386.46,"z":48.56},{"x":-314.26,"y":385.34,"z":51.99},{"x":-317.46,"y":382.63,"z":52.54},{"x":-319.47,"y":381.39,"z":49.28},{"x":-318.26,"y":382.86,"z":45.51},{"x":-315.42,"y":385.23,"z":45.34}]},{"lat":-48.6,"lon":10.09,"b":[{"x":-322.36,"y":377.8,"z":57.42},{"x":-323.18,"y":376.55,"z":60.92},{"x":-326.35,"y":373.71,"z":61.47},{"x":-328.39,"y":372.45,"z":58.17},{"x":-327.23,"y":374.04,"z":54.36},{"x":-324.38,"y":376.55,"z":54.15}]},{"lat":-47,"lon":11.33,"b":[{"x":-331.19,"y":368.56,"z":66.43},{"x":-331.99,"y":367.19,"z":69.99},{"x":-335.12,"y":364.22,"z":70.55},{"x":-337.19,"y":362.95,"z":67.21},{"x":-336.09,"y":364.65,"z":63.36},{"x":-333.23,"y":367.3,"z":63.13}]},{"lat":-45.36,"lon":12.51,"b":[{"x":-340.91,"y":357.76,"z":75.75},{"x":-341.42,"y":356.75,"z":78.18},{"x":-343.5,"y":354.68,"z":78.54},{"x":-344.89,"y":353.82,"z":76.28},{"x":-344.2,"y":355.04,"z":73.68},{"x":-342.29,"y":356.91,"z":73.52}]},{"lat":-43.67,"lon":13.65,"b":[{"x":-350.94,"y":345.77,"z":85.26},{"x":-351.06,"y":345.49,"z":85.88},{"x":-351.58,"y":344.95,"z":85.97},{"x":-351.94,"y":344.72,"z":85.4},{"x":-351.78,"y":345.05,"z":84.73},{"x":-351.3,"y":345.55,"z":84.69}]},{"lat":-41.94,"lon":14.74,"b":[{"x":-358.26,"y":335.71,"z":94.42},{"x":-358.58,"y":334.87,"z":96.17},{"x":-359.98,"y":333.29,"z":96.42},{"x":-360.99,"y":332.67,"z":94.8},{"x":-360.57,"y":333.64,"z":92.94},{"x":-359.25,"y":335.09,"z":92.81}]},{"lat":-40.17,"lon":15.8,"b":[{"x":-365.13,"y":325.41,"z":103.59},{"x":-365.65,"y":323.79,"z":106.77},{"x":-368.11,"y":320.86,"z":107.18},{"x":-369.92,"y":319.74,"z":104.26},{"x":-369.26,"y":321.56,"z":100.93},{"x":-366.93,"y":324.3,"z":100.68}]},{"lat":-38.37,"lon":16.81,"b":[{"x":-373.91,"y":312.01,"z":113.14},{"x":-374.17,"y":311.06,"z":114.89},{"x":-375.48,"y":309.41,"z":115.1},{"x":-376.47,"y":308.79,"z":113.49},{"x":-376.16,"y":309.84,"z":111.68},{"x":-374.91,"y":311.4,"z":111.54}]},{"lat":-30.94,"lon":20.48,"b":[{"x":-399.6,"y":260.41,"z":149.81},{"x":-399.77,"y":258.24,"z":153.07},{"x":-401.83,"y":254.89,"z":153.31},{"x":-403.71,"y":253.73,"z":150.27},{"x":-403.53,"y":255.92,"z":147},{"x":-401.47,"y":259.25,"z":146.78}]},{"lat":-29.05,"lon":21.32,"b":[{"x":-404.85,"y":246.69,"z":158.66},{"x":-404.95,"y":244.09,"z":162.39},{"x":-407.2,"y":240.18,"z":162.6},{"x":-409.36,"y":238.84,"z":159.09},{"x":-409.28,"y":241.42,"z":155.38},{"x":-407.01,"y":245.35,"z":155.15}]},{"lat":-27.16,"lon":22.12,"b":[{"x":-409.91,"y":232.16,"z":167.34},{"x":-409.91,"y":229.48,"z":171.03},{"x":-412.03,"y":225.53,"z":171.17},{"x":-414.19,"y":224.2,"z":167.68},{"x":-414.23,"y":226.8,"z":164.03},{"x":-412.08,"y":230.83,"z":163.84}]},{"lat":-25.27,"lon":22.89,"b":[{"x":-414.46,"y":217.39,"z":175.78},{"x":-414.34,"y":214.63,"z":179.42},{"x":-416.33,"y":210.67,"z":179.5},{"x":-418.48,"y":209.34,"z":176.01},{"x":-418.65,"y":211.97,"z":172.44},{"x":-416.62,"y":216.06,"z":172.29}]},{"lat":-23.39,"lon":23.64,"b":[{"x":-418.46,"y":202.44,"z":183.96},{"x":-418.23,"y":199.61,"z":187.54},{"x":-420.09,"y":195.65,"z":187.55},{"x":-422.24,"y":194.32,"z":184.08},{"x":-422.53,"y":196.96,"z":180.59},{"x":-420.61,"y":201.11,"z":180.48}]},{"lat":-21.52,"lon":24.36,"b":[{"x":-421.93,"y":187.36,"z":191.85},{"x":-421.58,"y":184.48,"z":195.37},{"x":-423.32,"y":180.53,"z":195.3},{"x":-425.45,"y":179.21,"z":191.85},{"x":-425.86,"y":181.84,"z":188.45},{"x":-424.07,"y":186.03,"z":188.38}]},{"lat":-19.67,"lon":25.05,"b":[{"x":-424.86,"y":172.21,"z":199.43},{"x":-424.4,"y":169.3,"z":202.88},{"x":-426.01,"y":165.37,"z":202.74},{"x":-428.13,"y":164.07,"z":199.31},{"x":-428.65,"y":166.67,"z":196},{"x":-426.99,"y":170.89,"z":195.98}]},{"lat":-17.84,"lon":25.72,"b":[{"x":-427.26,"y":157.06,"z":206.69},{"x":-426.69,"y":154.12,"z":210.05},{"x":-428.17,"y":150.23,"z":209.84},{"x":-430.27,"y":148.94,"z":206.44},{"x":-430.9,"y":151.52,"z":203.23},{"x":-429.38,"y":155.75,"z":203.26}]},{"lat":-16.03,"lon":26.36,"b":[{"x":-429.14,"y":141.95,"z":213.6},{"x":-428.46,"y":139,"z":216.88},{"x":-429.83,"y":135.17,"z":216.59},{"x":-431.91,"y":133.88,"z":213.22},{"x":-432.64,"y":136.42,"z":210.11},{"x":-431.24,"y":140.65,"z":210.2}]},{"lat":-14.26,"lon":26.98,"b":[{"x":-430.53,"y":126.94,"z":220.17},{"x":-429.74,"y":124,"z":223.35},{"x":-431,"y":120.22,"z":223},{"x":-433.06,"y":118.95,"z":219.66},{"x":-433.88,"y":121.44,"z":216.65},{"x":-432.61,"y":125.66,"z":216.8}]},{"lat":-12.52,"lon":27.58,"b":[{"x":-431.43,"y":112.09,"z":226.38},{"x":-430.55,"y":109.15,"z":229.47},{"x":-431.69,"y":105.45,"z":229.05},{"x":-433.73,"y":104.19,"z":225.75},{"x":-434.65,"y":106.62,"z":222.83},{"x":-433.49,"y":110.81,"z":223.04}]},{"lat":-10.81,"lon":28.16,"b":[{"x":-431.88,"y":97.42,"z":232.23},{"x":-430.9,"y":94.51,"z":235.23},{"x":-431.95,"y":90.89,"z":234.74},{"x":-433.97,"y":89.64,"z":231.47},{"x":-434.96,"y":92,"z":228.66},{"x":-433.92,"y":96.16,"z":228.93}]},{"lat":-9.14,"lon":28.72,"b":[{"x":-431.91,"y":83,"z":237.72},{"x":-430.84,"y":80.11,"z":240.63},{"x":-431.79,"y":76.58,"z":240.07},{"x":-433.78,"y":75.35,"z":236.85},{"x":-434.85,"y":77.64,"z":234.14},{"x":-433.92,"y":81.75,"z":234.46}]},{"lat":-7.51,"lon":29.26,"b":[{"x":-431.54,"y":68.84,"z":242.87},{"x":-430.39,"y":66,"z":245.67},{"x":-431.25,"y":62.55,"z":245.06},{"x":-433.22,"y":61.34,"z":241.89},{"x":-434.34,"y":63.55,"z":239.28},{"x":-433.53,"y":67.61,"z":239.65}]},{"lat":-5.92,"lon":29.79,"b":[{"x":-430.8,"y":54.98,"z":247.67},{"x":-429.57,"y":52.19,"z":250.38},{"x":-430.36,"y":48.84,"z":249.71},{"x":-432.29,"y":47.64,"z":246.58},{"x":-433.48,"y":49.78,"z":244.07},{"x":-432.76,"y":53.77,"z":244.5}]},{"lat":-4.38,"lon":30.29,"b":[{"x":-429.72,"y":41.45,"z":252.14},{"x":-428.43,"y":38.71,"z":254.75},{"x":-429.14,"y":35.46,"z":254.04},{"x":-431.05,"y":34.28,"z":250.95},{"x":-432.28,"y":36.33,"z":248.53},{"x":-431.66,"y":40.25,"z":249.01}]},{"lat":-2.87,"lon":30.78,"b":[{"x":-428.34,"y":28.26,"z":256.29},{"x":-426.99,"y":25.58,"z":258.8},{"x":-427.63,"y":22.44,"z":258.04},{"x":-429.51,"y":21.28,"z":255},{"x":-430.78,"y":23.24,"z":252.67},{"x":-430.25,"y":27.08,"z":253.2}]},{"lat":-1.41,"lon":31.26,"b":[{"x":-426.68,"y":15.44,"z":260.13},{"x":-425.27,"y":12.83,"z":262.55},{"x":-425.85,"y":9.78,"z":261.74},{"x":-427.7,"y":8.64,"z":258.75},{"x":-429.01,"y":10.52,"z":256.51},{"x":-428.56,"y":14.28,"z":257.08}]},{"lat":-57.79,"lon":7.18,"b":[{"x":-265.74,"y":422.3,"z":31.93},{"x":-264.06,"y":423.37,"z":31.67},{"x":-262.75,"y":424.07,"z":33.06},{"x":-263.12,"y":423.71,"z":34.74},{"x":-264.83,"y":422.62,"z":35.02},{"x":-266.14,"y":421.91,"z":33.6}]},{"lat":-56.42,"lon":8.7,"b":[{"x":-274.71,"y":415.78,"z":40.37},{"x":-273,"y":416.94,"z":40.09},{"x":-271.66,"y":417.66,"z":41.53},{"x":-272.05,"y":417.23,"z":43.29},{"x":-273.79,"y":416.06,"z":43.59},{"x":-275.13,"y":415.33,"z":42.11}]},{"lat":-53.32,"lon":8.76,"b":[{"x":-296.93,"y":399.88,"z":43.45},{"x":-294.6,"y":401.65,"z":43.06},{"x":-292.84,"y":402.71,"z":45.09},{"x":-293.4,"y":402.01,"z":47.54},{"x":-295.77,"y":400.23,"z":47.94},{"x":-297.53,"y":399.16,"z":45.88}]},{"lat":-54.99,"lon":10.14,"b":[{"x":-283.91,"y":408.63,"z":48.83},{"x":-281.93,"y":410.04,"z":48.5},{"x":-280.4,"y":410.88,"z":50.19},{"x":-280.84,"y":410.32,"z":52.25},{"x":-282.85,"y":408.9,"z":52.61},{"x":-284.38,"y":408.05,"z":50.88}]},{"lat":-58.27,"lon":13.3,"b":[{"x":-258.59,"y":423.97,"z":57.67},{"x":-255.25,"y":426.07,"z":57.08},{"x":-252.55,"y":427.3,"z":59.87},{"x":-253.16,"y":426.43,"z":63.32},{"x":-256.54,"y":424.32,"z":63.96},{"x":-259.26,"y":423.08,"z":61.11}]},{"lat":-51.83,"lon":10.12,"b":[{"x":-306.6,"y":391.54,"z":51.42},{"x":-303.38,"y":394.11,"z":50.88},{"x":-300.95,"y":395.59,"z":53.74},{"x":-301.73,"y":394.5,"z":57.2},{"x":-304.99,"y":391.9,"z":57.77},{"x":-307.43,"y":390.41,"z":54.85}]},{"lat":-53.5,"lon":11.53,"b":[{"x":-293.31,"y":400.81,"z":57.27},{"x":-290.82,"y":402.68,"z":56.84},{"x":-288.9,"y":403.75,"z":59.01},{"x":-289.45,"y":402.95,"z":61.66},{"x":-291.97,"y":401.06,"z":62.11},{"x":-293.9,"y":399.99,"z":59.9}]},{"lat":-55.16,"lon":13.06,"b":[{"x":-279.25,"y":409.84,"z":63.48},{"x":-278,"y":410.72,"z":63.26},{"x":-277.01,"y":411.22,"z":64.33},{"x":-277.26,"y":410.84,"z":65.65},{"x":-278.53,"y":409.95,"z":65.89},{"x":-279.52,"y":409.44,"z":64.79}]},{"lat":-56.79,"lon":14.73,"b":[{"x":-267.52,"y":417.04,"z":66.74},{"x":-264.16,"y":419.28,"z":66.12},{"x":-261.44,"y":420.52,"z":68.98},{"x":-262.05,"y":419.54,"z":72.5},{"x":-265.45,"y":417.29,"z":73.16},{"x":-268.19,"y":416.03,"z":70.25}]},{"lat":-58.4,"lon":16.54,"b":[{"x":-253.51,"y":424.83,"z":72.11},{"x":-250.61,"y":426.65,"z":71.56},{"x":-248.21,"y":427.63,"z":74},{"x":-248.68,"y":426.82,"z":77.03},{"x":-251.61,"y":424.99,"z":77.62},{"x":-254.04,"y":423.99,"z":75.13}]},{"lat":-50.28,"lon":11.42,"b":[{"x":-315.56,"y":383.05,"z":60.34},{"x":-312.36,"y":385.75,"z":59.8},{"x":-309.93,"y":387.24,"z":62.72},{"x":-310.7,"y":386.03,"z":66.25},{"x":-313.95,"y":383.3,"z":66.83},{"x":-316.38,"y":381.8,"z":63.85}]},{"lat":-51.96,"lon":12.86,"b":[{"x":-302.9,"y":392.29,"z":65.62},{"x":-299.64,"y":394.88,"z":65.05},{"x":-297.09,"y":396.3,"z":67.97},{"x":-297.81,"y":395.13,"z":71.54},{"x":-301.13,"y":392.51,"z":72.14},{"x":-303.67,"y":391.08,"z":69.16}]},{"lat":-53.62,"lon":14.4,"b":[{"x":-288.98,"y":401.61,"z":71.85},{"x":-286.79,"y":403.25,"z":71.45},{"x":-285.04,"y":404.14,"z":73.38},{"x":-285.48,"y":403.39,"z":75.75},{"x":-287.7,"y":401.73,"z":76.17},{"x":-289.45,"y":400.83,"z":74.2}]},{"lat":-56.87,"lon":17.9,"b":[{"x":-260.53,"y":418.51,"z":83.44},{"x":-259.89,"y":418.93,"z":83.32},{"x":-259.36,"y":419.15,"z":83.86},{"x":-259.47,"y":418.95,"z":84.54},{"x":-260.11,"y":418.52,"z":84.67},{"x":-260.65,"y":418.3,"z":84.12}]},{"lat":-48.68,"lon":12.67,"b":[{"x":-324.44,"y":373.98,"z":69.43},{"x":-321.26,"y":376.82,"z":68.88},{"x":-318.83,"y":378.31,"z":71.86},{"x":-319.59,"y":376.98,"z":75.46},{"x":-322.81,"y":374.1,"z":76.04},{"x":-325.23,"y":372.6,"z":73}]},{"lat":-50.36,"lon":14.12,"b":[{"x":-311.84,"y":383.53,"z":74.84},{"x":-308.59,"y":386.27,"z":74.26},{"x":-306.04,"y":387.7,"z":77.25},{"x":-306.75,"y":386.4,"z":80.87},{"x":-310.05,"y":383.63,"z":81.49},{"x":-312.59,"y":382.2,"z":78.44}]},{"lat":-52.02,"lon":15.69,"b":[{"x":-298.82,"y":392.7,"z":80.19},{"x":-295.51,"y":395.33,"z":79.58},{"x":-292.86,"y":396.68,"z":82.57},{"x":-293.51,"y":395.42,"z":86.22},{"x":-296.87,"y":392.77,"z":86.86},{"x":-299.53,"y":391.4,"z":83.82}]},{"lat":-53.67,"lon":17.37,"b":[{"x":-285.43,"y":401.45,"z":85.46},{"x":-282.06,"y":403.97,"z":84.83},{"x":-279.31,"y":405.24,"z":87.8},{"x":-279.91,"y":404,"z":91.48},{"x":-283.32,"y":401.47,"z":92.15},{"x":-286.09,"y":400.19,"z":89.12}]},{"lat":-56.87,"lon":21.17,"b":[{"x":-255.85,"y":418.32,"z":97.61},{"x":-254.62,"y":419.13,"z":97.36},{"x":-253.57,"y":419.51,"z":98.41},{"x":-253.74,"y":419.1,"z":99.73},{"x":-254.99,"y":418.28,"z":100},{"x":-256.04,"y":417.89,"z":98.93}]},{"lat":-58.42,"lon":23.3,"b":[{"x":-242.09,"y":425.38,"z":102.01},{"x":-240.24,"y":426.53,"z":101.62},{"x":-238.63,"y":427.05,"z":103.18},{"x":-238.86,"y":426.44,"z":105.16},{"x":-240.72,"y":425.29,"z":105.58},{"x":-242.35,"y":424.76,"z":103.99}]},{"lat":-47.03,"lon":13.87,"b":[{"x":-333.19,"y":364.33,"z":78.66},{"x":-330.05,"y":367.3,"z":78.1},{"x":-327.63,"y":368.8,"z":81.15},{"x":-328.35,"y":367.33,"z":84.8},{"x":-331.54,"y":364.32,"z":85.38},{"x":-333.96,"y":362.82,"z":82.28}]},{"lat":-48.71,"lon":15.34,"b":[{"x":-320.68,"y":374.19,"z":84.2},{"x":-317.45,"y":377.06,"z":83.62},{"x":-314.91,"y":378.49,"z":86.67},{"x":-315.59,"y":377.06,"z":90.36},{"x":-318.86,"y":374.16,"z":90.97},{"x":-321.4,"y":372.72,"z":87.86}]},{"lat":-50.37,"lon":16.91,"b":[{"x":-307.71,"y":383.68,"z":89.69},{"x":-304.42,"y":386.44,"z":89.07},{"x":-301.76,"y":387.8,"z":92.12},{"x":-302.39,"y":386.41,"z":95.84},{"x":-305.74,"y":383.61,"z":96.48},{"x":-308.4,"y":382.24,"z":93.38}]},{"lat":-52.02,"lon":18.6,"b":[{"x":-294.34,"y":392.76,"z":95.09},{"x":-290.98,"y":395.41,"z":94.44},{"x":-288.22,"y":396.69,"z":97.48},{"x":-288.8,"y":395.33,"z":101.22},{"x":-292.2,"y":392.65,"z":101.9},{"x":-294.98,"y":391.36,"z":98.81}]},{"lat":-53.64,"lon":20.42,"b":[{"x":-280.61,"y":401.4,"z":100.39},{"x":-277.2,"y":403.93,"z":99.71},{"x":-274.33,"y":405.12,"z":102.73},{"x":-274.87,"y":403.79,"z":106.49},{"x":-278.31,"y":401.23,"z":107.21},{"x":-281.19,"y":400.03,"z":104.13}]},{"lat":-55.23,"lon":22.39,"b":[{"x":-266.55,"y":409.56,"z":105.57},{"x":-263.11,"y":411.97,"z":104.86},{"x":-260.15,"y":413.07,"z":107.85},{"x":-260.63,"y":411.76,"z":111.62},{"x":-264.11,"y":409.34,"z":112.38},{"x":-267.08,"y":408.23,"z":109.33}]},{"lat":-56.78,"lon":24.5,"b":[{"x":-251.78,"y":417.39,"z":111.06},{"x":-248.83,"y":419.33,"z":110.43},{"x":-246.26,"y":420.17,"z":112.95},{"x":-246.61,"y":419.09,"z":116.15},{"x":-249.59,"y":417.14,"z":116.83},{"x":-252.18,"y":416.29,"z":114.26}]},{"lat":-58.29,"lon":26.79,"b":[{"x":-237.69,"y":424.38,"z":115.5},{"x":-234.21,"y":426.53,"z":114.71},{"x":-231.12,"y":427.42,"z":117.65},{"x":-231.47,"y":426.16,"z":121.42},{"x":-234.98,"y":424,"z":122.26},{"x":-238.11,"y":423.1,"z":119.28}]},{"lat":-45.34,"lon":15.02,"b":[{"x":-341.7,"y":354.15,"z":88.09},{"x":-338.71,"y":357.14,"z":87.56},{"x":-336.37,"y":358.59,"z":90.57},{"x":-337.04,"y":357.04,"z":94.15},{"x":-340.07,"y":354.01,"z":94.7},{"x":-342.4,"y":352.56,"z":91.64}]},{"lat":-47.01,"lon":16.5,"b":[{"x":-329.38,"y":364.24,"z":93.68},{"x":-326.19,"y":367.25,"z":93.11},{"x":-323.65,"y":368.68,"z":96.22},{"x":-324.3,"y":367.11,"z":99.96},{"x":-327.53,"y":364.07,"z":100.56},{"x":-330.07,"y":362.64,"z":97.39}]},{"lat":-48.67,"lon":18.07,"b":[{"x":-316.5,"y":374.04,"z":99.31},{"x":-313.23,"y":376.94,"z":98.7},{"x":-310.57,"y":378.31,"z":101.81},{"x":-311.17,"y":376.77,"z":105.58},{"x":-314.48,"y":373.84,"z":106.22},{"x":-317.15,"y":372.47,"z":103.06}]},{"lat":-50.32,"lon":19.77,"b":[{"x":-303.17,"y":383.44,"z":104.85},{"x":-299.83,"y":386.24,"z":104.21},{"x":-297.06,"y":387.53,"z":107.31},{"x":-297.62,"y":386.02,"z":111.1},{"x":-301,"y":383.2,"z":111.78},{"x":-303.78,"y":381.91,"z":108.63}]},{"lat":-51.94,"lon":21.58,"b":[{"x":-289.45,"y":392.42,"z":110.29},{"x":-286.05,"y":395.1,"z":109.61},{"x":-283.17,"y":396.3,"z":112.68},{"x":-283.68,"y":394.83,"z":116.5},{"x":-287.12,"y":392.12,"z":117.22},{"x":-290.01,"y":390.91,"z":114.08}]},{"lat":-53.53,"lon":23.54,"b":[{"x":-275.37,"y":400.93,"z":115.59},{"x":-271.93,"y":403.49,"z":114.87},{"x":-268.95,"y":404.59,"z":117.92},{"x":-269.41,"y":403.15,"z":121.76},{"x":-272.89,"y":400.57,"z":122.52},{"x":-275.88,"y":399.46,"z":119.41}]},{"lat":-55.09,"lon":25.64,"b":[{"x":-260.99,"y":408.95,"z":120.74},{"x":-257.51,"y":411.38,"z":119.99},{"x":-254.46,"y":412.38,"z":123.01},{"x":-254.86,"y":410.96,"z":126.85},{"x":-258.37,"y":408.52,"z":127.66},{"x":-261.45,"y":407.5,"z":124.58}]},{"lat":-56.6,"lon":27.89,"b":[{"x":-246.37,"y":416.45,"z":125.74},{"x":-242.86,"y":418.75,"z":124.94},{"x":-239.74,"y":419.64,"z":127.92},{"x":-240.08,"y":418.25,"z":131.76},{"x":-243.61,"y":415.94,"z":132.62},{"x":-246.77,"y":415.03,"z":129.58}]},{"lat":-58.06,"lon":30.31,"b":[{"x":-231.55,"y":423.41,"z":130.55},{"x":-228.04,"y":425.58,"z":129.71},{"x":-224.85,"y":426.36,"z":132.65},{"x":-225.14,"y":424.99,"z":136.49},{"x":-228.67,"y":422.82,"z":137.38},{"x":-231.89,"y":422.02,"z":134.39}]},{"lat":-43.6,"lon":16.13,"b":[{"x":-349.41,"y":343.77,"z":98.41},{"x":-347.34,"y":345.97,"z":98.05},{"x":-345.7,"y":346.99,"z":100.2},{"x":-346.14,"y":345.8,"z":102.76},{"x":-348.24,"y":343.57,"z":103.14},{"x":-349.87,"y":342.56,"z":100.94}]},{"lat":-45.26,"lon":17.6,"b":[{"x":-337.89,"y":353.7,"z":103.26},{"x":-334.76,"y":356.84,"z":102.69},{"x":-332.22,"y":358.27,"z":105.86},{"x":-332.83,"y":356.56,"z":109.65},{"x":-336.01,"y":353.39,"z":110.23},{"x":-338.54,"y":351.96,"z":107.01}]},{"lat":-46.92,"lon":19.18,"b":[{"x":-325.12,"y":363.79,"z":109.04},{"x":-321.89,"y":366.83,"z":108.44},{"x":-319.23,"y":368.2,"z":111.6},{"x":-319.8,"y":366.52,"z":115.43},{"x":-323.07,"y":363.44,"z":116.05},{"x":-325.73,"y":362.08,"z":112.83}]},{"lat":-48.57,"lon":20.88,"b":[{"x":-311.88,"y":373.5,"z":114.73},{"x":-308.57,"y":376.44,"z":114.09},{"x":-305.79,"y":377.73,"z":117.25},{"x":-306.31,"y":376.09,"z":121.1},{"x":-309.66,"y":373.12,"z":121.76},{"x":-312.45,"y":371.82,"z":118.55}]},{"lat":-50.19,"lon":22.69,"b":[{"x":-298.2,"y":382.8,"z":120.3},{"x":-294.82,"y":385.63,"z":119.63},{"x":-291.93,"y":386.84,"z":122.76},{"x":-292.41,"y":385.22,"z":126.63},{"x":-295.82,"y":382.37,"z":127.35},{"x":-298.72,"y":381.16,"z":124.15}]},{"lat":-51.78,"lon":24.62,"b":[{"x":-284.13,"y":391.65,"z":125.74},{"x":-280.69,"y":394.36,"z":125.02},{"x":-277.7,"y":395.47,"z":128.13},{"x":-278.13,"y":393.89,"z":132.02},{"x":-281.6,"y":391.16,"z":132.78},{"x":-284.61,"y":390.04,"z":129.61}]},{"lat":-53.34,"lon":26.7,"b":[{"x":-269.72,"y":400.02,"z":131.02},{"x":-266.24,"y":402.6,"z":130.26},{"x":-263.16,"y":403.61,"z":133.34},{"x":-263.54,"y":402.05,"z":137.24},{"x":-267.05,"y":399.45,"z":138.04},{"x":-270.15,"y":398.43,"z":134.91}]},{"lat":-54.86,"lon":28.92,"b":[{"x":-255.03,"y":407.87,"z":136.13},{"x":-251.52,"y":410.32,"z":135.32},{"x":-248.36,"y":411.23,"z":138.36},{"x":-248.68,"y":409.7,"z":142.26},{"x":-252.22,"y":407.23,"z":143.11},{"x":-255.41,"y":406.32,"z":140.02}]},{"lat":-56.32,"lon":31.3,"b":[{"x":-240.11,"y":415.19,"z":141.04},{"x":-236.59,"y":417.51,"z":140.19},{"x":-233.36,"y":418.3,"z":143.18},{"x":-233.63,"y":416.79,"z":147.08},{"x":-237.18,"y":414.47,"z":147.98},{"x":-240.44,"y":413.66,"z":144.94}]},{"lat":-57.72,"lon":33.85,"b":[{"x":-225.03,"y":421.96,"z":145.75},{"x":-221.5,"y":424.14,"z":144.85},{"x":-218.22,"y":424.82,"z":147.8},{"x":-218.43,"y":423.33,"z":151.68},{"x":-221.98,"y":421.14,"z":152.63},{"x":-225.3,"y":420.46,"z":149.64}]},{"lat":-43.48,"lon":18.67,"b":[{"x":-346.18,"y":342.56,"z":112.89},{"x":-343.1,"y":345.83,"z":112.34},{"x":-340.58,"y":347.25,"z":115.56},{"x":-341.13,"y":345.41,"z":119.39},{"x":-344.25,"y":342.1,"z":119.95},{"x":-346.77,"y":340.69,"z":116.67}]},{"lat":-45.13,"lon":20.25,"b":[{"x":-333.55,"y":352.92,"z":118.83},{"x":-330.37,"y":356.1,"z":118.25},{"x":-327.71,"y":357.46,"z":121.47},{"x":-328.24,"y":355.64,"z":125.33},{"x":-331.46,"y":352.43,"z":125.94},{"x":-334.11,"y":351.07,"z":122.66}]},{"lat":-46.77,"lon":21.93,"b":[{"x":-320.42,"y":362.93,"z":124.68},{"x":-317.14,"y":366.01,"z":124.06},{"x":-314.36,"y":367.3,"z":127.27},{"x":-314.85,"y":365.51,"z":131.16},{"x":-318.15,"y":362.4,"z":131.81},{"x":-320.94,"y":361.11,"z":128.55}]},{"lat":-48.39,"lon":23.73,"b":[{"x":-306.81,"y":372.55,"z":130.41},{"x":-303.46,"y":375.52,"z":129.74},{"x":-300.56,"y":376.73,"z":132.94},{"x":-301,"y":374.97,"z":136.85},{"x":-304.39,"y":371.97,"z":137.55},{"x":-307.29,"y":370.76,"z":134.3}]},{"lat":-49.98,"lon":25.65,"b":[{"x":-292.78,"y":381.73,"z":136},{"x":-289.36,"y":384.58,"z":135.28},{"x":-286.35,"y":385.7,"z":138.45},{"x":-286.75,"y":383.97,"z":142.38},{"x":-290.2,"y":381.09,"z":143.13},{"x":-293.22,"y":379.97,"z":139.91}]},{"lat":-51.54,"lon":27.71,"b":[{"x":-278.37,"y":390.44,"z":141.41},{"x":-274.9,"y":393.17,"z":140.65},{"x":-271.8,"y":394.19,"z":143.79},{"x":-272.14,"y":392.48,"z":147.73},{"x":-275.64,"y":389.73,"z":148.53},{"x":-278.77,"y":388.71,"z":145.34}]},{"lat":-53.06,"lon":29.9,"b":[{"x":-263.65,"y":398.65,"z":146.64},{"x":-260.13,"y":401.24,"z":145.83},{"x":-256.95,"y":402.16,"z":148.93},{"x":-257.24,"y":400.48,"z":152.88},{"x":-260.78,"y":397.86,"z":153.73},{"x":-263.99,"y":396.94,"z":150.58}]},{"lat":-54.53,"lon":32.23,"b":[{"x":-248.66,"y":406.32,"z":151.67},{"x":-245.12,"y":408.79,"z":150.81},{"x":-241.86,"y":409.59,"z":153.86},{"x":-242.11,"y":407.94,"z":157.8},{"x":-245.67,"y":405.45,"z":158.71},{"x":-248.96,"y":404.64,"z":155.61}]},{"lat":-55.94,"lon":34.72,"b":[{"x":-233.47,"y":413.45,"z":156.47},{"x":-229.92,"y":415.78,"z":155.57},{"x":-226.6,"y":416.47,"z":158.56},{"x":-226.8,"y":414.83,"z":162.5},{"x":-230.36,"y":412.49,"z":163.46},{"x":-233.72,"y":411.79,"z":160.42}]},{"lat":-57.28,"lon":37.37,"b":[{"x":-218.14,"y":420.01,"z":161.04},{"x":-214.6,"y":422.2,"z":160.09},{"x":-211.23,"y":422.78,"z":163.03},{"x":-211.37,"y":421.17,"z":166.95},{"x":-214.93,"y":418.96,"z":167.96},{"x":-218.34,"y":418.38,"z":164.98}]},{"lat":-40.01,"lon":18.2,"b":[{"x":-364.72,"y":320.86,"z":118.3},{"x":-363.56,"y":322.25,"z":118.1},{"x":-362.6,"y":322.84,"z":119.42},{"x":-362.81,"y":322.03,"z":120.95},{"x":-363.99,"y":320.62,"z":121.15},{"x":-364.94,"y":320.04,"z":119.82}]},{"lat":-41.65,"lon":19.68,"b":[{"x":-353.84,"y":331.06,"z":123.02},{"x":-351.28,"y":333.95,"z":122.57},{"x":-349.13,"y":335.16,"z":125.37},{"x":-349.55,"y":333.46,"z":128.66},{"x":-352.15,"y":330.54,"z":129.11},{"x":-354.29,"y":329.35,"z":126.27}]},{"lat":-43.29,"lon":21.26,"b":[{"x":-341.74,"y":341.46,"z":128.66},{"x":-338.62,"y":344.76,"z":128.1},{"x":-335.97,"y":346.12,"z":131.37},{"x":-336.43,"y":344.16,"z":135.26},{"x":-339.59,"y":340.82,"z":135.84},{"x":-342.24,"y":339.47,"z":132.51}]},{"lat":-44.92,"lon":22.94,"b":[{"x":-328.74,"y":351.74,"z":134.68},{"x":-325.52,"y":354.96,"z":134.07},{"x":-322.73,"y":356.24,"z":137.34},{"x":-323.17,"y":354.31,"z":141.26},{"x":-326.42,"y":351.06,"z":141.89},{"x":-329.21,"y":349.78,"z":138.57}]},{"lat":-46.54,"lon":24.72,"b":[{"x":-315.24,"y":361.66,"z":140.57},{"x":-311.93,"y":364.77,"z":139.92},{"x":-309.02,"y":365.98,"z":143.17},{"x":-309.42,"y":364.07,"z":147.12},{"x":-312.76,"y":360.93,"z":147.79},{"x":-315.67,"y":359.72,"z":144.5}]},{"lat":-48.13,"lon":26.63,"b":[{"x":-301.27,"y":371.15,"z":146.31},{"x":-297.89,"y":374.15,"z":145.61},{"x":-294.87,"y":375.27,"z":148.83},{"x":-295.22,"y":373.39,"z":152.8},{"x":-298.64,"y":370.37,"z":153.53},{"x":-301.67,"y":369.25,"z":150.26}]},{"lat":-49.69,"lon":28.65,"b":[{"x":-286.9,"y":380.2,"z":151.88},{"x":-283.45,"y":383.08,"z":151.13},{"x":-280.33,"y":384.1,"z":154.31},{"x":-280.64,"y":382.25,"z":158.3},{"x":-284.12,"y":379.34,"z":159.08},{"x":-287.26,"y":378.32,"z":155.85}]},{"lat":-51.21,"lon":30.81,"b":[{"x":-272.17,"y":388.75,"z":157.24},{"x":-268.67,"y":391.5,"z":156.44},{"x":-265.46,"y":392.42,"z":159.59},{"x":-265.72,"y":390.59,"z":163.58},{"x":-269.25,"y":387.82,"z":164.41},{"x":-272.48,"y":386.9,"z":161.23}]},{"lat":-52.69,"lon":33.1,"b":[{"x":-257.15,"y":396.78,"z":162.39},{"x":-253.61,"y":399.4,"z":161.54},{"x":-250.32,"y":400.21,"z":164.63},{"x":-250.53,"y":398.41,"z":168.62},{"x":-254.09,"y":395.77,"z":169.52},{"x":-257.41,"y":394.95,"z":166.38}]},{"lat":-54.11,"lon":35.54,"b":[{"x":-241.88,"y":404.26,"z":167.31},{"x":-238.33,"y":406.75,"z":166.41},{"x":-234.97,"y":407.44,"z":169.44},{"x":-235.14,"y":405.66,"z":173.43},{"x":-238.71,"y":403.17,"z":174.38},{"x":-242.1,"y":402.46,"z":171.3}]},{"lat":-55.46,"lon":38.12,"b":[{"x":-226.45,"y":411.19,"z":171.98},{"x":-222.88,"y":413.53,"z":171.02},{"x":-219.48,"y":414.11,"z":174},{"x":-219.59,"y":412.36,"z":177.97},{"x":-223.16,"y":410,"z":178.98},{"x":-226.61,"y":409.41,"z":175.96}]},{"lat":-56.74,"lon":40.84,"b":[{"x":-210.9,"y":417.54,"z":176.39},{"x":-207.34,"y":419.75,"z":175.38},{"x":-203.9,"y":420.21,"z":178.29},{"x":-203.97,"y":418.47,"z":182.24},{"x":-207.53,"y":416.25,"z":183.3},{"x":-211.02,"y":415.78,"z":180.36}]},{"lat":-39.79,"lon":20.66,"b":[{"x":-361.84,"y":318.61,"z":132.26},{"x":-358.99,"y":322.02,"z":131.78},{"x":-356.54,"y":323.39,"z":135.02},{"x":-356.96,"y":321.32,"z":138.8},{"x":-359.85,"y":317.86,"z":139.28},{"x":-362.29,"y":316.52,"z":135.99}]},{"lat":-41.42,"lon":22.23,"b":[{"x":-349.64,"y":329.4,"z":138.48},{"x":-346.59,"y":332.83,"z":137.94},{"x":-343.94,"y":334.18,"z":141.27},{"x":-344.35,"y":332.08,"z":145.18},{"x":-347.43,"y":328.61,"z":145.73},{"x":-350.07,"y":327.28,"z":142.35}]},{"lat":-43.04,"lon":23.89,"b":[{"x":-336.81,"y":339.94,"z":144.68},{"x":-333.65,"y":343.28,"z":144.1},{"x":-330.86,"y":344.56,"z":147.42},{"x":-331.24,"y":342.49,"z":151.36},{"x":-334.43,"y":339.11,"z":151.96},{"x":-337.21,"y":337.84,"z":148.59}]},{"lat":-44.65,"lon":25.67,"b":[{"x":-323.44,"y":350.13,"z":150.75},{"x":-320.18,"y":353.38,"z":150.12},{"x":-317.27,"y":354.58,"z":153.42},{"x":-317.61,"y":352.53,"z":157.39},{"x":-320.9,"y":349.25,"z":158.04},{"x":-323.81,"y":348.06,"z":154.69}]},{"lat":-46.24,"lon":27.55,"b":[{"x":-309.58,"y":359.93,"z":156.65},{"x":-306.23,"y":363.07,"z":155.98},{"x":-303.2,"y":364.19,"z":159.25},{"x":-303.5,"y":362.16,"z":163.24},{"x":-306.88,"y":358.99,"z":163.94},{"x":-309.92,"y":357.88,"z":160.63}]},{"lat":-47.8,"lon":29.55,"b":[{"x":-295.27,"y":369.29,"z":162.38},{"x":-291.85,"y":372.32,"z":161.65},{"x":-288.71,"y":373.35,"z":164.88},{"x":-288.97,"y":371.34,"z":168.89},{"x":-292.42,"y":368.29,"z":169.65},{"x":-295.57,"y":367.27,"z":166.37}]},{"lat":-49.32,"lon":31.67,"b":[{"x":-280.57,"y":378.18,"z":167.89},{"x":-277.09,"y":381.08,"z":167.11},{"x":-273.85,"y":382.01,"z":170.3},{"x":-274.07,"y":380.03,"z":174.32},{"x":-277.57,"y":377.1,"z":175.14},{"x":-280.83,"y":376.18,"z":171.9}]},{"lat":-50.8,"lon":33.92,"b":[{"x":-265.53,"y":386.56,"z":173.18},{"x":-262.01,"y":389.33,"z":172.34},{"x":-258.69,"y":390.15,"z":175.48},{"x":-258.86,"y":388.2,"z":179.5},{"x":-262.41,"y":385.4,"z":180.38},{"x":-265.75,"y":384.58,"z":177.2}]},{"lat":-52.22,"lon":36.3,"b":[{"x":-250.22,"y":394.4,"z":178.22},{"x":-246.67,"y":397.04,"z":177.32},{"x":-243.28,"y":397.74,"z":180.4},{"x":-243.41,"y":395.81,"z":184.42},{"x":-246.98,"y":393.16,"z":185.36},{"x":-250.4,"y":392.45,"z":182.24}]},{"lat":-53.58,"lon":38.81,"b":[{"x":-234.71,"y":401.69,"z":183},{"x":-231.14,"y":404.19,"z":182.04},{"x":-227.69,"y":404.77,"z":185.06},{"x":-227.77,"y":402.87,"z":189.06},{"x":-231.35,"y":400.35,"z":190.06},{"x":-234.84,"y":399.76,"z":187.01}]},{"lat":-54.88,"lon":41.47,"b":[{"x":-219.05,"y":408.4,"z":187.5},{"x":-215.47,"y":410.76,"z":186.49},{"x":-211.98,"y":411.23,"z":189.44},{"x":-212.02,"y":409.34,"z":193.43},{"x":-215.6,"y":406.97,"z":194.48},{"x":-219.13,"y":406.49,"z":191.5}]},{"lat":-56.09,"lon":44.25,"b":[{"x":-203.31,"y":414.54,"z":191.72},{"x":-199.75,"y":416.76,"z":190.66},{"x":-196.23,"y":417.1,"z":193.53},{"x":-196.22,"y":415.24,"z":197.49},{"x":-199.78,"y":413.01,"z":198.61},{"x":-203.35,"y":412.65,"z":195.71}]},{"lat":-37.91,"lon":21.59,"b":[{"x":-368.3,"y":306.32,"z":143.08},{"x":-366.58,"y":308.51,"z":142.81},{"x":-365.06,"y":309.35,"z":144.86},{"x":-365.27,"y":307.98,"z":147.22},{"x":-367.02,"y":305.76,"z":147.5},{"x":-368.53,"y":304.94,"z":145.42}]},{"lat":-39.52,"lon":23.15,"b":[{"x":-355.57,"y":317.67,"z":150.43},{"x":-354.5,"y":318.94,"z":150.25},{"x":-353.56,"y":319.41,"z":151.46},{"x":-353.68,"y":318.61,"z":152.86},{"x":-354.75,"y":317.33,"z":153.04},{"x":-355.69,"y":316.86,"z":151.82}]},{"lat":-41.13,"lon":24.81,"b":[{"x":-344.38,"y":327.64,"z":154.88},{"x":-341.51,"y":330.86,"z":154.37},{"x":-338.93,"y":332.04,"z":157.5},{"x":-339.21,"y":329.98,"z":161.18},{"x":-342.11,"y":326.73,"z":161.69},{"x":-344.69,"y":325.56,"z":158.52}]},{"lat":-42.73,"lon":26.57,"b":[{"x":-331.36,"y":337.99,"z":160.89},{"x":-328.17,"y":341.37,"z":160.3},{"x":-325.26,"y":342.57,"z":163.64},{"x":-325.53,"y":340.37,"z":167.63},{"x":-328.76,"y":336.96,"z":168.24},{"x":-331.67,"y":335.78,"z":164.85}]},{"lat":-44.31,"lon":28.43,"b":[{"x":-316.92,"y":348.35,"z":167.78},{"x":-314.42,"y":350.84,"z":167.29},{"x":-312.12,"y":351.69,"z":169.81},{"x":-312.3,"y":350.04,"z":172.85},{"x":-314.82,"y":347.53,"z":173.36},{"x":-317.13,"y":346.69,"z":170.81}]},{"lat":-45.86,"lon":30.4,"b":[{"x":-301.97,"y":358.25,"z":174.44},{"x":-300.19,"y":359.93,"z":174.07},{"x":-298.52,"y":360.47,"z":175.8},{"x":-298.63,"y":359.33,"z":177.92},{"x":-300.42,"y":357.64,"z":178.31},{"x":-302.09,"y":357.1,"z":176.55}]},{"lat":-47.38,"lon":32.48,"b":[{"x":-288.79,"y":366.94,"z":178.55},{"x":-285.34,"y":370,"z":177.79},{"x":-282.09,"y":370.92,"z":181.02},{"x":-282.26,"y":368.79,"z":185.06},{"x":-285.72,"y":365.72,"z":185.85},{"x":-288.99,"y":364.79,"z":182.57}]},{"lat":-48.86,"lon":34.69,"b":[{"x":-273.78,"y":375.66,"z":183.98},{"x":-270.28,"y":378.59,"z":183.17},{"x":-266.93,"y":379.41,"z":186.35},{"x":-267.06,"y":377.3,"z":190.39},{"x":-270.58,"y":374.35,"z":191.24},{"x":-273.95,"y":373.53,"z":188.02}]},{"lat":-50.29,"lon":37.02,"b":[{"x":-258.46,"y":383.86,"z":189.16},{"x":-254.91,"y":386.65,"z":188.28},{"x":-251.49,"y":387.36,"z":191.4},{"x":-251.58,"y":385.27,"z":195.44},{"x":-255.13,"y":382.46,"z":196.36},{"x":-258.59,"y":381.75,"z":193.2}]},{"lat":-51.66,"lon":39.47,"b":[{"x":-242.89,"y":391.5,"z":194.06},{"x":-239.32,"y":394.16,"z":193.12},{"x":-235.84,"y":394.75,"z":196.17},{"x":-235.88,"y":392.69,"z":200.2},{"x":-239.46,"y":390.01,"z":201.18},{"x":-242.98,"y":389.42,"z":198.1}]},{"lat":-52.97,"lon":42.05,"b":[{"x":-227.14,"y":398.58,"z":198.67},{"x":-223.57,"y":401.09,"z":197.67},{"x":-220.03,"y":401.57,"z":200.65},{"x":-220.04,"y":399.53,"z":204.66},{"x":-223.62,"y":397,"z":205.71},{"x":-227.19,"y":396.52,"z":202.69}]},{"lat":-54.2,"lon":44.75,"b":[{"x":-211.29,"y":405.08,"z":202.97},{"x":-207.71,"y":407.45,"z":201.92},{"x":-204.15,"y":407.81,"z":204.82},{"x":-204.11,"y":405.79,"z":208.81},{"x":-207.68,"y":403.4,"z":209.92},{"x":-211.29,"y":403.04,"z":206.99}]},{"lat":-55.35,"lon":47.57,"b":[{"x":-195.38,"y":410.99,"z":206.98},{"x":-191.83,"y":413.23,"z":205.86},{"x":-188.24,"y":413.46,"z":208.68},{"x":-188.17,"y":411.47,"z":212.65},{"x":-191.72,"y":409.22,"z":213.81},{"x":-195.35,"y":408.98,"z":210.97}]},{"lat":-35.99,"lon":22.48,"b":[{"x":-374.21,"y":293.61,"z":154.1},{"x":-373.74,"y":294.24,"z":154.03},{"x":-373.32,"y":294.47,"z":154.61},{"x":-373.37,"y":294.06,"z":155.27},{"x":-373.84,"y":293.43,"z":155.34},{"x":-374.26,"y":293.2,"z":154.75}]},{"lat":-37.59,"lon":24.04,"b":[{"x":-362.7,"y":304.54,"z":160.24},{"x":-361.75,"y":305.75,"z":160.09},{"x":-360.87,"y":306.18,"z":161.22},{"x":-360.96,"y":305.4,"z":162.52},{"x":-361.92,"y":304.18,"z":162.67},{"x":-362.79,"y":303.76,"z":161.52}]},{"lat":-39.18,"lon":25.68,"b":[{"x":-349.85,"y":315.62,"z":167.25},{"x":-349.23,"y":316.36,"z":167.14},{"x":-348.66,"y":316.62,"z":167.85},{"x":-348.7,"y":316.13,"z":168.66},{"x":-349.33,"y":315.39,"z":168.76},{"x":-349.9,"y":315.13,"z":168.05}]},{"lat":-40.77,"lon":27.42,"b":[{"x":-338.32,"y":325.55,"z":171.76},{"x":-335.92,"y":328.24,"z":171.33},{"x":-333.68,"y":329.15,"z":173.94},{"x":-333.84,"y":327.35,"z":177},{"x":-336.26,"y":324.64,"z":177.43},{"x":-338.49,"y":323.74,"z":174.79}]},{"lat":-45.41,"lon":33.25,"b":[{"x":-295.47,"y":355.46,"z":190.52},{"x":-293.46,"y":357.35,"z":190.09},{"x":-291.53,"y":357.89,"z":192.03},{"x":-291.6,"y":356.55,"z":194.41},{"x":-293.61,"y":354.65,"z":194.85},{"x":-295.55,"y":354.1,"z":192.9}]},{"lat":-46.88,"lon":35.41,"b":[{"x":-281.65,"y":364.14,"z":194.94},{"x":-278.37,"y":367.05,"z":194.19},{"x":-275.18,"y":367.83,"z":197.24},{"x":-275.26,"y":365.69,"z":201.07},{"x":-278.55,"y":362.76,"z":201.85},{"x":-281.76,"y":361.98,"z":198.76}]},{"lat":-48.32,"lon":37.69,"b":[{"x":-266.53,"y":372.63,"z":200.09},{"x":-263.01,"y":375.57,"z":199.23},{"x":-259.56,"y":376.29,"z":202.39},{"x":-259.6,"y":374.05,"z":206.44},{"x":-263.13,"y":371.08,"z":207.33},{"x":-266.61,"y":370.37,"z":204.13}]},{"lat":-49.69,"lon":40.08,"b":[{"x":-250.95,"y":380.62,"z":205.12},{"x":-247.4,"y":383.44,"z":204.2},{"x":-243.88,"y":384.03,"z":207.29},{"x":-243.88,"y":381.82,"z":211.33},{"x":-247.44,"y":378.99,"z":212.29},{"x":-250.99,"y":378.39,"z":209.17}]},{"lat":-51.01,"lon":42.59,"b":[{"x":-235.15,"y":388.06,"z":209.85},{"x":-231.58,"y":390.74,"z":208.86},{"x":-228,"y":391.22,"z":211.88},{"x":-227.97,"y":389.03,"z":215.9},{"x":-231.55,"y":386.33,"z":216.93},{"x":-235.16,"y":385.85,"z":213.89}]},{"lat":-52.26,"lon":45.22,"b":[{"x":-219.21,"y":394.93,"z":214.26},{"x":-215.63,"y":397.46,"z":213.21},{"x":-212.02,"y":397.82,"z":216.14},{"x":-211.95,"y":395.65,"z":220.15},{"x":-215.52,"y":393.1,"z":221.24},{"x":-219.18,"y":392.74,"z":218.28}]},{"lat":-53.42,"lon":47.95,"b":[{"x":-203.19,"y":401.21,"z":218.34},{"x":-199.62,"y":403.6,"z":217.23},{"x":-195.98,"y":403.84,"z":220.08},{"x":-195.87,"y":401.69,"z":224.06},{"x":-199.44,"y":399.29,"z":225.22},{"x":-203.12,"y":399.04,"z":222.35}]},{"lat":-54.51,"lon":50.79,"b":[{"x":-187.15,"y":406.91,"z":222.1},{"x":-183.61,"y":409.16,"z":220.93},{"x":-179.96,"y":409.28,"z":223.69},{"x":-179.82,"y":407.15,"z":227.64},{"x":-183.35,"y":404.89,"z":228.86},{"x":-187.05,"y":404.76,"z":226.08}]},{"lat":-32.5,"lon":21.87,"b":[{"x":-392.46,"y":267.94,"z":155.37},{"x":-391.22,"y":269.85,"z":155.21},{"x":-390.06,"y":270.52,"z":156.93},{"x":-390.16,"y":269.27,"z":158.84},{"x":-391.42,"y":267.34,"z":158.99},{"x":-392.57,"y":266.69,"z":157.25}]},{"lat":-38.78,"lon":28.23,"b":[{"x":-346.22,"y":311.97,"z":180.92},{"x":-343.19,"y":315.59,"z":180.42},{"x":-340.28,"y":316.75,"z":183.85},{"x":-340.4,"y":314.28,"z":187.82},{"x":-343.46,"y":310.63,"z":188.33},{"x":-346.36,"y":309.49,"z":184.86}]},{"lat":-40.34,"lon":30.05,"b":[{"x":-332.71,"y":322.57,"z":187.55},{"x":-329.71,"y":325.95,"z":187.01},{"x":-326.8,"y":327,"z":190.26},{"x":-326.9,"y":324.65,"z":194.08},{"x":-329.92,"y":321.25,"z":194.62},{"x":-332.83,"y":320.21,"z":191.34}]},{"lat":-44.87,"lon":36.1,"b":[{"x":-287.4,"y":352.47,"z":207.7},{"x":-286.29,"y":353.51,"z":207.46},{"x":-285.2,"y":353.77,"z":208.51},{"x":-285.2,"y":353,"z":209.81},{"x":-286.31,"y":351.95,"z":210.06},{"x":-287.41,"y":351.69,"z":209}]},{"lat":-46.31,"lon":38.32,"b":[{"x":-272.65,"y":361.13,"z":212.61},{"x":-270.95,"y":362.64,"z":212.21},{"x":-269.26,"y":362.99,"z":213.77},{"x":-269.25,"y":361.83,"z":215.74},{"x":-270.95,"y":360.3,"z":216.16},{"x":-272.66,"y":359.95,"z":214.58}]},{"lat":-47.69,"lon":40.66,"b":[{"x":-258.85,"y":369.06,"z":216.13},{"x":-255.32,"y":372.03,"z":215.24},{"x":-251.77,"y":372.63,"z":218.36},{"x":-251.72,"y":370.27,"z":222.4},{"x":-255.25,"y":367.28,"z":223.32},{"x":-258.83,"y":366.68,"z":220.18}]},{"lat":-49.01,"lon":43.1,"b":[{"x":-243.03,"y":376.86,"z":220.99},{"x":-239.47,"y":379.69,"z":220.03},{"x":-235.86,"y":380.17,"z":223.08},{"x":-235.78,"y":377.83,"z":227.1},{"x":-239.34,"y":374.98,"z":228.1},{"x":-242.98,"y":374.49,"z":225.03}]},{"lat":-50.27,"lon":45.65,"b":[{"x":-227.03,"y":384.08,"z":225.52},{"x":-223.46,"y":386.78,"z":224.49},{"x":-219.81,"y":387.14,"z":227.45},{"x":-219.69,"y":384.82,"z":231.46},{"x":-223.26,"y":382.11,"z":232.52},{"x":-226.95,"y":381.74,"z":229.54}]},{"lat":-51.46,"lon":48.3,"b":[{"x":-210.92,"y":390.73,"z":229.7},{"x":-207.35,"y":393.28,"z":228.61},{"x":-203.67,"y":393.53,"z":231.48},{"x":-203.52,"y":391.23,"z":235.46},{"x":-207.09,"y":388.67,"z":236.6},{"x":-210.81,"y":388.41,"z":233.71}]},{"lat":-52.56,"lon":51.05,"b":[{"x":-194.77,"y":396.8,"z":233.54},{"x":-191.21,"y":399.21,"z":232.38},{"x":-187.52,"y":399.33,"z":235.16},{"x":-187.34,"y":397.06,"z":239.11},{"x":-190.88,"y":394.64,"z":240.32},{"x":-194.62,"y":394.5,"z":237.52}]},{"lat":-53.59,"lon":53.89,"b":[{"x":-178.64,"y":402.28,"z":237.03},{"x":-175.11,"y":404.55,"z":235.81},{"x":-171.42,"y":404.56,"z":238.5},{"x":-171.21,"y":402.31,"z":242.41},{"x":-174.72,"y":400.03,"z":243.68},{"x":-178.46,"y":400.01,"z":240.98}]},{"lat":-30.58,"lon":22.7,"b":[{"x":-399.32,"y":253.04,"z":162.63},{"x":-396.95,"y":256.91,"z":162.36},{"x":-394.65,"y":258.22,"z":165.85},{"x":-394.74,"y":255.61,"z":169.63},{"x":-397.14,"y":251.7,"z":169.87},{"x":-399.42,"y":250.44,"z":166.36}]},{"lat":-32.12,"lon":24.16,"b":[{"x":-386.73,"y":265.65,"z":172.8},{"x":-386.37,"y":266.19,"z":172.76},{"x":-386.02,"y":266.38,"z":173.26},{"x":-386.03,"y":266.01,"z":173.8},{"x":-386.39,"y":265.45,"z":173.84},{"x":-386.74,"y":265.28,"z":173.34}]},{"lat":-36.78,"lon":29.01,"b":[{"x":-352.56,"y":298.37,"z":191.34},{"x":-350.15,"y":301.42,"z":190.97},{"x":-347.76,"y":302.37,"z":193.82},{"x":-347.79,"y":300.23,"z":197.06},{"x":-350.22,"y":297.15,"z":197.43},{"x":-352.6,"y":296.23,"z":194.56}]},{"lat":-38.32,"lon":30.8,"b":[{"x":-339.91,"y":308.9,"z":197.39},{"x":-336.86,"y":312.55,"z":196.88},{"x":-333.81,"y":313.63,"z":200.32},{"x":-333.83,"y":311.04,"z":204.3},{"x":-336.9,"y":307.36,"z":204.81},{"x":-339.95,"y":306.3,"z":201.34}]},{"lat":-39.85,"lon":32.68,"b":[{"x":-326.19,"y":319.32,"z":203.86},{"x":-323.02,"y":322.89,"z":203.29},{"x":-319.84,"y":323.89,"z":206.68},{"x":-319.83,"y":321.31,"z":210.68},{"x":-323.02,"y":317.72,"z":211.26},{"x":-326.2,"y":316.73,"z":207.83}]},{"lat":-41.35,"lon":34.66,"b":[{"x":-310.72,"y":329.74,"z":211.35},{"x":-308.68,"y":331.9,"z":210.96},{"x":-306.62,"y":332.48,"z":213.05},{"x":-306.6,"y":330.87,"z":215.55},{"x":-308.65,"y":328.69,"z":215.96},{"x":-310.72,"y":328.13,"z":213.85}]},{"lat":-44.26,"lon":38.92,"b":[{"x":-281.06,"y":348.39,"z":222.63},{"x":-278.61,"y":350.71,"z":222.08},{"x":-276.11,"y":351.22,"z":224.38},{"x":-276.05,"y":349.41,"z":227.26},{"x":-278.51,"y":347.08,"z":227.83},{"x":-281.02,"y":346.57,"z":225.51}]},{"lat":-45.65,"lon":41.2,"b":[{"x":-266.54,"y":356.83,"z":227.04},{"x":-263.05,"y":359.95,"z":226.19},{"x":-259.47,"y":360.56,"z":229.34},{"x":-259.36,"y":358.05,"z":233.36},{"x":-262.85,"y":354.91,"z":234.24},{"x":-266.45,"y":354.3,"z":231.07}]},{"lat":-46.98,"lon":43.58,"b":[{"x":-250.74,"y":364.97,"z":232.05},{"x":-247.2,"y":367.96,"z":231.13},{"x":-243.56,"y":368.45,"z":234.19},{"x":-243.42,"y":365.96,"z":238.21},{"x":-246.96,"y":362.95,"z":239.16},{"x":-250.63,"y":362.46,"z":236.07}]},{"lat":-48.25,"lon":46.06,"b":[{"x":-234.72,"y":372.56,"z":236.71},{"x":-231.16,"y":375.4,"z":235.71},{"x":-227.47,"y":375.78,"z":238.69},{"x":-227.3,"y":373.31,"z":242.69},{"x":-230.86,"y":370.44,"z":243.72},{"x":-234.58,"y":370.06,"z":240.72}]},{"lat":-49.45,"lon":48.63,"b":[{"x":-218.56,"y":379.57,"z":241.01},{"x":-214.99,"y":382.28,"z":239.94},{"x":-211.26,"y":382.53,"z":242.83},{"x":-211.07,"y":380.08,"z":246.8},{"x":-214.63,"y":377.36,"z":247.91},{"x":-218.39,"y":377.1,"z":245}]},{"lat":-50.57,"lon":51.29,"b":[{"x":-202.31,"y":386,"z":244.94},{"x":-198.75,"y":388.57,"z":243.8},{"x":-195.01,"y":388.7,"z":246.59},{"x":-194.79,"y":386.28,"z":250.54},{"x":-198.34,"y":383.7,"z":251.72},{"x":-202.12,"y":383.56,"z":248.91}]},{"lat":-51.62,"lon":54.04,"b":[{"x":-186.06,"y":391.86,"z":248.5},{"x":-182.52,"y":394.28,"z":247.3},{"x":-178.78,"y":394.3,"z":250},{"x":-178.53,"y":391.9,"z":253.91},{"x":-182.06,"y":389.46,"z":255.15},{"x":-185.85,"y":389.44,"z":252.45}]},{"lat":-52.58,"lon":56.85,"b":[{"x":-169.87,"y":397.14,"z":251.7},{"x":-166.36,"y":399.42,"z":250.44},{"x":-162.63,"y":399.32,"z":253.04},{"x":-162.36,"y":396.95,"z":256.91},{"x":-165.85,"y":394.65,"z":258.22},{"x":-169.63,"y":394.74,"z":255.61}]},{"lat":-28.65,"lon":23.5,"b":[{"x":-404.56,"y":238.5,"z":171.42},{"x":-402.31,"y":242.41,"z":171.21},{"x":-400.03,"y":243.68,"z":174.72},{"x":-400.01,"y":240.98,"z":178.46},{"x":-402.28,"y":237.03,"z":178.64},{"x":-404.55,"y":235.81,"z":175.11}]},{"lat":-30.17,"lon":24.94,"b":[{"x":-394.3,"y":250,"z":178.78},{"x":-391.9,"y":253.91,"z":178.53},{"x":-389.46,"y":255.15,"z":182.06},{"x":-389.44,"y":252.45,"z":185.85},{"x":-391.86,"y":248.5,"z":186.06},{"x":-394.28,"y":247.3,"z":182.52}]},{"lat":-36.28,"lon":31.52,"b":[{"x":-344.72,"y":295.45,"z":209.38},{"x":-343.61,"y":296.86,"z":209.21},{"x":-342.47,"y":297.26,"z":210.51},{"x":-342.44,"y":296.24,"z":211.99},{"x":-343.56,"y":294.82,"z":212.16},{"x":-344.7,"y":294.44,"z":210.85}]},{"lat":-37.79,"lon":33.37,"b":[{"x":-333.06,"y":305.38,"z":213.86},{"x":-329.98,"y":309.05,"z":213.35},{"x":-326.81,"y":310.04,"z":216.78},{"x":-326.71,"y":307.33,"z":220.74},{"x":-329.81,"y":303.64,"z":221.25},{"x":-332.98,"y":302.66,"z":217.8}]},{"lat":-39.29,"lon":35.32,"b":[{"x":-319,"y":315.65,"z":220.29},{"x":-315.81,"y":319.24,"z":219.71},{"x":-312.51,"y":320.14,"z":223.09},{"x":-312.39,"y":317.45,"z":227.06},{"x":-315.6,"y":313.84,"z":227.65},{"x":-318.9,"y":312.94,"z":224.25}]},{"lat":-40.75,"lon":37.35,"b":[{"x":-303.32,"y":325.82,"z":227.55},{"x":-301.12,"y":328.16,"z":227.11},{"x":-298.83,"y":328.71,"z":229.34},{"x":-298.74,"y":326.91,"z":232.01},{"x":-300.95,"y":324.56,"z":232.45},{"x":-303.24,"y":324.02,"z":230.21}]},{"lat":-43.57,"lon":41.71,"b":[{"x":-273.97,"y":343.96,"z":237.8},{"x":-270.53,"y":347.22,"z":237},{"x":-266.93,"y":347.83,"z":240.17},{"x":-266.75,"y":345.17,"z":244.17},{"x":-270.2,"y":341.89,"z":244.99},{"x":-273.82,"y":341.29,"z":241.8}]},{"lat":-44.91,"lon":44.03,"b":[{"x":-258.23,"y":352.42,"z":242.97},{"x":-254.73,"y":355.56,"z":242.09},{"x":-251.06,"y":356.05,"z":245.18},{"x":-250.86,"y":353.42,"z":249.17},{"x":-254.35,"y":350.27,"z":250.07},{"x":-258.05,"y":349.77,"z":246.97}]},{"lat":-46.19,"lon":46.44,"b":[{"x":-242.23,"y":360.35,"z":247.78},{"x":-238.69,"y":363.36,"z":246.82},{"x":-234.97,"y":363.73,"z":249.82},{"x":-234.75,"y":361.12,"z":253.79},{"x":-238.27,"y":358.1,"z":254.77},{"x":-242.03,"y":357.72,"z":251.76}]},{"lat":-47.4,"lon":48.94,"b":[{"x":-226.04,"y":367.73,"z":252.2},{"x":-222.49,"y":370.59,"z":251.17},{"x":-218.73,"y":370.85,"z":254.07},{"x":-218.48,"y":368.26,"z":258.02},{"x":-222.02,"y":365.38,"z":259.09},{"x":-225.82,"y":365.11,"z":256.17}]},{"lat":-48.55,"lon":51.52,"b":[{"x":-209.74,"y":374.53,"z":256.24},{"x":-206.19,"y":377.25,"z":255.14},{"x":-202.4,"y":377.39,"z":257.94},{"x":-202.14,"y":374.82,"z":261.87},{"x":-205.68,"y":372.09,"z":263.01},{"x":-209.5,"y":371.93,"z":260.19}]},{"lat":-49.62,"lon":54.18,"b":[{"x":-193.41,"y":380.75,"z":259.9},{"x":-189.86,"y":383.33,"z":258.72},{"x":-186.07,"y":383.36,"z":261.43},{"x":-185.78,"y":380.81,"z":265.32},{"x":-189.31,"y":378.22,"z":266.53},{"x":-193.14,"y":378.18,"z":263.82}]},{"lat":-50.6,"lon":56.9,"b":[{"x":-177.1,"y":386.4,"z":263.17},{"x":-173.58,"y":388.84,"z":261.92},{"x":-169.8,"y":388.75,"z":264.53},{"x":-169.49,"y":386.23,"z":268.38},{"x":-172.98,"y":383.77,"z":269.67},{"x":-176.81,"y":383.85,"z":267.06}]},{"lat":-51.51,"lon":59.68,"b":[{"x":-160.88,"y":391.48,"z":266.06},{"x":-157.4,"y":393.78,"z":264.76},{"x":-153.64,"y":393.57,"z":267.26},{"x":-153.32,"y":391.08,"z":271.07},{"x":-156.77,"y":388.77,"z":272.42},{"x":-160.58,"y":388.96,"z":269.92}]},{"lat":-26.73,"lon":24.26,"b":[{"x":-409.28,"y":223.69,"z":179.96},{"x":-407.15,"y":227.64,"z":179.82},{"x":-404.89,"y":228.86,"z":183.35},{"x":-404.76,"y":226.08,"z":187.05},{"x":-406.91,"y":222.1,"z":187.15},{"x":-409.16,"y":220.93,"z":183.61}]},{"lat":-28.21,"lon":25.7,"b":[{"x":-399.33,"y":235.16,"z":187.52},{"x":-397.06,"y":239.11,"z":187.34},{"x":-394.64,"y":240.32,"z":190.88},{"x":-394.5,"y":237.52,"z":194.62},{"x":-396.8,"y":233.54,"z":194.77},{"x":-399.21,"y":232.38,"z":191.21}]},{"lat":-29.71,"lon":27.21,"b":[{"x":-388.7,"y":246.59,"z":195.01},{"x":-386.28,"y":250.54,"z":194.79},{"x":-383.7,"y":251.72,"z":198.34},{"x":-383.56,"y":248.91,"z":202.12},{"x":-386,"y":244.94,"z":202.31},{"x":-388.57,"y":243.8,"z":198.75}]},{"lat":-31.21,"lon":28.79,"b":[{"x":-375.06,"y":258.97,"z":205.55},{"x":-374.76,"y":259.43,"z":205.52},{"x":-374.45,"y":259.56,"z":205.93},{"x":-374.43,"y":259.23,"z":206.37},{"x":-374.73,"y":258.78,"z":206.4},{"x":-375.05,"y":258.65,"z":205.99}]},{"lat":-34.23,"lon":32.2,"b":[{"x":-350.25,"y":281.09,"z":219.77},{"x":-349.84,"y":281.64,"z":219.71},{"x":-349.41,"y":281.79,"z":220.21},{"x":-349.38,"y":281.38,"z":220.77},{"x":-349.79,"y":280.83,"z":220.83},{"x":-350.23,"y":280.68,"z":220.32}]},{"lat":-35.73,"lon":34.02,"b":[{"x":-337.34,"y":291.65,"z":226.08},{"x":-336.46,"y":292.77,"z":225.95},{"x":-335.52,"y":293.05,"z":226.97},{"x":-335.46,"y":292.22,"z":228.13},{"x":-336.35,"y":291.09,"z":228.26},{"x":-337.29,"y":290.81,"z":227.23}]},{"lat":-37.21,"lon":35.93,"b":[{"x":-325.56,"y":301.43,"z":230.38},{"x":-322.57,"y":305,"z":229.89},{"x":-319.38,"y":305.86,"z":233.17},{"x":-319.18,"y":303.14,"z":236.96},{"x":-322.19,"y":299.55,"z":237.45},{"x":-325.37,"y":298.7,"z":234.15}]},{"lat":-38.66,"lon":37.93,"b":[{"x":-311.29,"y":311.5,"z":236.61},{"x":-308.08,"y":315.11,"z":236.03},{"x":-304.66,"y":315.92,"z":239.37},{"x":-304.44,"y":313.11,"z":243.31},{"x":-307.66,"y":309.48,"z":243.9},{"x":-311.08,"y":308.68,"z":240.54}]},{"lat":-40.09,"lon":40.02,"b":[{"x":-296.11,"y":321.28,"z":242.95},{"x":-293.1,"y":324.47,"z":242.35},{"x":-289.89,"y":325.12,"z":245.33},{"x":-289.68,"y":322.57,"z":248.92},{"x":-292.69,"y":319.36,"z":249.53},{"x":-295.91,"y":318.72,"z":246.54}]},{"lat":-41.48,"lon":42.19,"b":[{"x":-280.47,"y":330.59,"z":248.95},{"x":-277.71,"y":333.37,"z":248.34},{"x":-274.75,"y":333.87,"z":250.95},{"x":-274.54,"y":331.58,"z":254.18},{"x":-277.31,"y":328.79,"z":254.81},{"x":-280.28,"y":328.3,"z":252.18}]},{"lat":-42.82,"lon":44.45,"b":[{"x":-265.46,"y":339.24,"z":253.7},{"x":-262.02,"y":342.52,"z":252.88},{"x":-258.32,"y":343.02,"z":255.98},{"x":-258.05,"y":340.24,"z":259.93},{"x":-261.5,"y":336.95,"z":260.77},{"x":-265.21,"y":336.45,"z":257.65}]},{"lat":-44.1,"lon":46.8,"b":[{"x":-248.25,"y":347.66,"z":259.71},{"x":-245.94,"y":349.74,"z":259.11},{"x":-243.46,"y":350,"z":261.1},{"x":-243.27,"y":348.17,"z":263.7},{"x":-245.57,"y":346.08,"z":264.31},{"x":-248.07,"y":345.82,"z":262.31}]},{"lat":-45.33,"lon":49.23,"b":[{"x":-230.05,"y":355.53,"z":265.83},{"x":-229.6,"y":355.92,"z":265.7},{"x":-229.11,"y":355.95,"z":266.08},{"x":-229.07,"y":355.6,"z":266.58},{"x":-229.52,"y":355.21,"z":266.71},{"x":-230.02,"y":355.17,"z":266.33}]},{"lat":-46.49,"lon":51.73,"b":[{"x":-214.57,"y":362.53,"z":269.25},{"x":-213.31,"y":363.56,"z":268.87},{"x":-211.94,"y":363.61,"z":269.88},{"x":-211.83,"y":362.64,"z":271.27},{"x":-213.09,"y":361.61,"z":271.66},{"x":-214.47,"y":361.55,"z":270.65}]},{"lat":-47.58,"lon":54.31,"b":[{"x":-200.64,"y":368.97,"z":271.16},{"x":-197.1,"y":371.71,"z":270.02},{"x":-193.26,"y":371.74,"z":272.73},{"x":-192.93,"y":369.05,"z":276.59},{"x":-196.44,"y":366.3,"z":277.77},{"x":-200.32,"y":366.26,"z":275.05}]},{"lat":-48.59,"lon":56.94,"b":[{"x":-184.24,"y":374.99,"z":274.52},{"x":-180.72,"y":377.58,"z":273.31},{"x":-176.89,"y":377.51,"z":275.92},{"x":-176.54,"y":374.84,"z":279.74},{"x":-180.03,"y":372.23,"z":280.99},{"x":-183.91,"y":372.3,"z":278.38}]},{"lat":-49.52,"lon":59.63,"b":[{"x":-167.91,"y":380.44,"z":277.49},{"x":-164.42,"y":382.89,"z":276.2},{"x":-160.61,"y":382.7,"z":278.7},{"x":-160.24,"y":380.07,"z":282.49},{"x":-163.7,"y":377.6,"z":283.81},{"x":-167.56,"y":377.78,"z":281.31}]},{"lat":-50.37,"lon":62.37,"b":[{"x":-151.71,"y":385.33,"z":280.06},{"x":-148.26,"y":387.65,"z":278.71},{"x":-144.48,"y":387.35,"z":281.11},{"x":-144.1,"y":384.74,"z":284.85},{"x":-147.52,"y":382.41,"z":286.23},{"x":-151.35,"y":382.7,"z":283.84}]},{"lat":-24.82,"lon":25,"b":[{"x":-413.46,"y":208.68,"z":188.24},{"x":-411.47,"y":212.65,"z":188.17},{"x":-409.22,"y":213.81,"z":191.72},{"x":-408.98,"y":210.97,"z":195.35},{"x":-410.99,"y":206.98,"z":195.38},{"x":-413.23,"y":205.86,"z":191.83}]},{"lat":-26.26,"lon":26.43,"b":[{"x":-403.84,"y":220.08,"z":195.98},{"x":-401.69,"y":224.06,"z":195.87},{"x":-399.29,"y":225.22,"z":199.44},{"x":-399.04,"y":222.35,"z":203.12},{"x":-401.21,"y":218.34,"z":203.19},{"x":-403.6,"y":217.23,"z":199.62}]},{"lat":-27.73,"lon":27.92,"b":[{"x":-393.53,"y":231.48,"z":203.67},{"x":-391.23,"y":235.46,"z":203.52},{"x":-388.67,"y":236.6,"z":207.09},{"x":-388.41,"y":233.71,"z":210.81},{"x":-390.73,"y":229.7,"z":210.92},{"x":-393.28,"y":228.61,"z":207.35}]},{"lat":-29.2,"lon":29.49,"b":[{"x":-382.53,"y":242.83,"z":211.26},{"x":-380.08,"y":246.8,"z":211.07},{"x":-377.36,"y":247.91,"z":214.63},{"x":-377.1,"y":245,"z":218.39},{"x":-379.57,"y":241.01,"z":218.56},{"x":-382.28,"y":239.94,"z":214.99}]},{"lat":-30.69,"lon":31.13,"b":[{"x":-370.53,"y":254.2,"z":219.14},{"x":-368.24,"y":257.69,"z":218.92},{"x":-365.69,"y":258.63,"z":222.05},{"x":-365.45,"y":256.05,"z":225.41},{"x":-367.77,"y":252.54,"z":225.61},{"x":-370.3,"y":251.63,"z":222.47}]},{"lat":-35.11,"lon":36.52,"b":[{"x":-331.55,"y":286.77,"z":240.35},{"x":-328.9,"y":290.12,"z":239.96},{"x":-325.97,"y":290.9,"z":242.99},{"x":-325.71,"y":288.31,"z":246.41},{"x":-328.37,"y":284.94,"z":246.79},{"x":-331.29,"y":284.18,"z":243.76}]},{"lat":-36.56,"lon":38.48,"b":[{"x":-317.76,"y":296.96,"z":246.51},{"x":-314.64,"y":300.67,"z":246},{"x":-311.22,"y":301.47,"z":249.36},{"x":-310.9,"y":298.54,"z":253.24},{"x":-314.03,"y":294.81,"z":253.75},{"x":-317.46,"y":294.02,"z":250.38}]},{"lat":-37.97,"lon":40.52,"b":[{"x":-303.08,"y":306.88,"z":252.75},{"x":-299.86,"y":310.51,"z":252.16},{"x":-296.32,"y":311.22,"z":255.45},{"x":-296,"y":308.29,"z":259.34},{"x":-299.23,"y":304.65,"z":259.94},{"x":-302.77,"y":303.95,"z":256.64}]},{"lat":-39.36,"lon":42.65,"b":[{"x":-287.94,"y":316.4,"z":258.65},{"x":-284.63,"y":319.92,"z":257.98},{"x":-281,"y":320.53,"z":261.19},{"x":-280.66,"y":317.61,"z":265.08},{"x":-283.97,"y":314.08,"z":265.76},{"x":-287.61,"y":313.47,"z":262.55}]},{"lat":-40.7,"lon":44.85,"b":[{"x":-272.4,"y":325.46,"z":264.18},{"x":-269.02,"y":328.87,"z":263.42},{"x":-265.31,"y":329.37,"z":266.54},{"x":-264.96,"y":326.47,"z":270.43},{"x":-268.34,"y":323.05,"z":271.21},{"x":-272.07,"y":322.54,"z":268.07}]},{"lat":-41.99,"lon":47.14,"b":[{"x":-256.4,"y":334.04,"z":269.43},{"x":-253.09,"y":337.22,"z":268.62},{"x":-249.44,"y":337.59,"z":271.53},{"x":-249.1,"y":334.81,"z":275.27},{"x":-252.41,"y":331.63,"z":276.1},{"x":-256.07,"y":331.24,"z":273.18}]},{"lat":-44.4,"lon":51.93,"b":[{"x":-223.78,"y":349.6,"z":278.62},{"x":-220.58,"y":352.36,"z":277.69},{"x":-217.06,"y":352.51,"z":280.26},{"x":-216.72,"y":349.91,"z":283.76},{"x":-219.9,"y":347.15,"z":284.71},{"x":-223.44,"y":346.99,"z":282.13}]},{"lat":-45.51,"lon":54.43,"b":[{"x":-207.71,"y":356.53,"z":282.25},{"x":-204.19,"y":359.42,"z":281.15},{"x":-200.31,"y":359.47,"z":283.86},{"x":-199.93,"y":356.64,"z":287.68},{"x":-203.42,"y":353.75,"z":288.8},{"x":-207.33,"y":353.68,"z":286.08}]},{"lat":-46.54,"lon":56.99,"b":[{"x":-191.26,"y":362.92,"z":285.71},{"x":-187.75,"y":365.67,"z":284.54},{"x":-183.87,"y":365.6,"z":287.14},{"x":-183.48,"y":362.8,"z":290.92},{"x":-186.96,"y":360.04,"z":292.12},{"x":-190.87,"y":360.09,"z":289.52}]},{"lat":-47.5,"lon":59.59,"b":[{"x":-174.85,"y":368.74,"z":288.76},{"x":-171.35,"y":371.35,"z":287.51},{"x":-167.5,"y":371.17,"z":290},{"x":-167.09,"y":368.4,"z":293.75},{"x":-170.55,"y":365.78,"z":295.03},{"x":-174.45,"y":365.94,"z":292.54}]},{"lat":-48.38,"lon":62.24,"b":[{"x":-158.54,"y":374.01,"z":291.39},{"x":-155.08,"y":376.48,"z":290.07},{"x":-151.25,"y":376.19,"z":292.46},{"x":-150.83,"y":373.45,"z":296.16},{"x":-154.26,"y":370.97,"z":297.52},{"x":-158.13,"y":371.24,"z":295.14}]},{"lat":-49.19,"lon":64.91,"b":[{"x":-142.38,"y":378.73,"z":293.64},{"x":-138.97,"y":381.06,"z":292.25},{"x":-135.18,"y":380.67,"z":294.54},{"x":-134.76,"y":377.96,"z":298.19},{"x":-138.14,"y":375.61,"z":299.61},{"x":-141.97,"y":375.99,"z":297.34}]},{"lat":-22.91,"lon":25.71,"b":[{"x":-417.1,"y":193.53,"z":196.23},{"x":-415.24,"y":197.49,"z":196.22},{"x":-413.01,"y":198.61,"z":199.78},{"x":-412.65,"y":195.71,"z":203.35},{"x":-414.54,"y":191.72,"z":203.31},{"x":-416.76,"y":190.66,"z":199.75}]},{"lat":-24.32,"lon":27.12,"b":[{"x":-407.81,"y":204.82,"z":204.15},{"x":-405.79,"y":208.81,"z":204.11},{"x":-403.4,"y":209.92,"z":207.68},{"x":-403.04,"y":206.99,"z":211.29},{"x":-405.08,"y":202.97,"z":211.29},{"x":-407.45,"y":201.92,"z":207.71}]},{"lat":-25.75,"lon":28.6,"b":[{"x":-397.82,"y":216.14,"z":212.02},{"x":-395.65,"y":220.15,"z":211.95},{"x":-393.1,"y":221.24,"z":215.52},{"x":-392.74,"y":218.28,"z":219.18},{"x":-394.93,"y":214.26,"z":219.21},{"x":-397.46,"y":213.21,"z":215.63}]},{"lat":-27.2,"lon":30.15,"b":[{"x":-387.14,"y":227.45,"z":219.81},{"x":-384.82,"y":231.46,"z":219.69},{"x":-382.11,"y":232.52,"z":223.26},{"x":-381.74,"y":229.54,"z":226.95},{"x":-384.08,"y":225.52,"z":227.03},{"x":-386.78,"y":224.49,"z":223.46}]},{"lat":-28.65,"lon":31.77,"b":[{"x":-375.78,"y":238.69,"z":227.47},{"x":-373.31,"y":242.69,"z":227.3},{"x":-370.44,"y":243.72,"z":230.86},{"x":-370.06,"y":240.72,"z":234.58},{"x":-372.56,"y":236.71,"z":234.72},{"x":-375.4,"y":235.71,"z":231.16}]},{"lat":-30.11,"lon":33.47,"b":[{"x":-363.73,"y":249.82,"z":234.97},{"x":-361.12,"y":253.79,"z":234.75},{"x":-358.1,"y":254.77,"z":238.27},{"x":-357.72,"y":251.76,"z":242.03},{"x":-360.35,"y":247.78,"z":242.23},{"x":-363.36,"y":246.82,"z":238.69}]},{"lat":-31.57,"lon":35.24,"b":[{"x":-350.53,"y":260.93,"z":242.84},{"x":-348.23,"y":264.22,"z":242.6},{"x":-345.59,"y":264.99,"z":245.52},{"x":-345.26,"y":262.46,"z":248.68},{"x":-347.58,"y":259.17,"z":248.9},{"x":-350.21,"y":258.41,"z":245.98}]},{"lat":-33.01,"lon":37.08,"b":[{"x":-337.71,"y":271.5,"z":249.32},{"x":-334.82,"y":275.38,"z":248.96},{"x":-331.52,"y":276.24,"z":252.4},{"x":-331.12,"y":273.21,"z":256.19},{"x":-334.03,"y":269.32,"z":256.54},{"x":-337.32,"y":268.47,"z":253.1}]},{"lat":-34.44,"lon":39,"b":[{"x":-323.79,"y":281.95,"z":256.09},{"x":-320.78,"y":285.76,"z":255.66},{"x":-317.35,"y":286.55,"z":259.03},{"x":-316.95,"y":283.51,"z":262.84},{"x":-319.97,"y":279.69,"z":263.27},{"x":-323.39,"y":278.92,"z":259.89}]},{"lat":-35.85,"lon":41,"b":[{"x":-309.33,"y":292.07,"z":262.54},{"x":-306.21,"y":295.8,"z":262.03},{"x":-302.67,"y":296.5,"z":265.33},{"x":-302.25,"y":293.46,"z":269.15},{"x":-305.39,"y":289.72,"z":269.66},{"x":-308.93,"y":289.03,"z":266.35}]},{"lat":-37.23,"lon":43.08,"b":[{"x":-294.38,"y":301.81,"z":268.64},{"x":-291.16,"y":305.44,"z":268.05},{"x":-287.52,"y":306.05,"z":271.27},{"x":-287.1,"y":303.02,"z":275.09},{"x":-290.33,"y":299.37,"z":275.69},{"x":-293.97,"y":298.77,"z":272.46}]},{"lat":-38.56,"lon":45.23,"b":[{"x":-279.01,"y":311.12,"z":274.37},{"x":-275.7,"y":314.65,"z":273.68},{"x":-271.97,"y":315.16,"z":276.81},{"x":-271.54,"y":312.13,"z":280.63},{"x":-274.85,"y":308.59,"z":281.32},{"x":-278.59,"y":308.09,"z":278.19}]},{"lat":-39.86,"lon":47.46,"b":[{"x":-263.27,"y":319.97,"z":279.69},{"x":-259.89,"y":323.39,"z":278.92},{"x":-256.09,"y":323.79,"z":281.95},{"x":-255.66,"y":320.78,"z":285.76},{"x":-259.03,"y":317.35,"z":286.55},{"x":-262.84,"y":316.95,"z":283.51}]},{"lat":-41.1,"lon":49.76,"b":[{"x":-244.23,"y":328.62,"z":286.95},{"x":-243.5,"y":329.33,"z":286.76},{"x":-242.67,"y":329.39,"z":287.39},{"x":-242.58,"y":328.75,"z":288.2},{"x":-243.31,"y":328.04,"z":288.39},{"x":-244.14,"y":327.98,"z":287.76}]},{"lat":-42.29,"lon":52.12,"b":[{"x":-228.44,"y":336.34,"z":290.96},{"x":-227.25,"y":337.42,"z":290.63},{"x":-225.92,"y":337.48,"z":291.6},{"x":-225.77,"y":336.46,"z":292.89},{"x":-226.95,"y":335.38,"z":293.23},{"x":-228.29,"y":335.31,"z":292.26}]},{"lat":-43.41,"lon":54.54,"b":[{"x":-214.59,"y":343.47,"z":293.09},{"x":-211.1,"y":346.5,"z":292.05},{"x":-207.19,"y":346.57,"z":294.76},{"x":-206.75,"y":343.61,"z":298.51},{"x":-210.21,"y":340.57,"z":299.58},{"x":-214.15,"y":340.49,"z":296.86}]},{"lat":-44.47,"lon":57.02,"b":[{"x":-198.13,"y":350.22,"z":296.67},{"x":-194.63,"y":353.12,"z":295.55},{"x":-190.72,"y":353.06,"z":298.15},{"x":-190.27,"y":350.13,"z":301.88},{"x":-193.74,"y":347.23,"z":303.02},{"x":-197.68,"y":347.26,"z":300.43}]},{"lat":-45.45,"lon":59.55,"b":[{"x":-181.67,"y":356.41,"z":299.82},{"x":-178.18,"y":359.17,"z":298.62},{"x":-174.28,"y":359.01,"z":301.11},{"x":-173.83,"y":356.1,"z":304.8},{"x":-177.28,"y":353.33,"z":306.03},{"x":-181.22,"y":353.48,"z":303.55}]},{"lat":-46.36,"lon":62.12,"b":[{"x":-165.27,"y":362.05,"z":302.55},{"x":-161.81,"y":364.67,"z":301.27},{"x":-157.94,"y":364.4,"z":303.64},{"x":-157.48,"y":361.52,"z":307.29},{"x":-160.9,"y":358.89,"z":308.6},{"x":-164.82,"y":359.14,"z":306.23}]},{"lat":-47.2,"lon":64.71,"b":[{"x":-149.01,"y":367.14,"z":304.85},{"x":-145.59,"y":369.62,"z":303.5},{"x":-141.76,"y":369.25,"z":305.77},{"x":-141.3,"y":366.41,"z":309.37},{"x":-144.68,"y":363.91,"z":310.75},{"x":-148.56,"y":364.27,"z":308.5}]},{"lat":-47.95,"lon":67.32,"b":[{"x":-132.94,"y":371.7,"z":306.76},{"x":-129.57,"y":374.05,"z":305.34},{"x":-125.79,"y":373.57,"z":307.5},{"x":-125.33,"y":370.77,"z":311.06},{"x":-128.66,"y":368.4,"z":312.5},{"x":-132.49,"y":368.86,"z":310.36}]},{"lat":-21.02,"lon":26.39,"b":[{"x":-420.21,"y":178.29,"z":203.9},{"x":-418.47,"y":182.24,"z":203.97},{"x":-416.25,"y":183.3,"z":207.53},{"x":-415.78,"y":180.36,"z":211.02},{"x":-417.54,"y":176.39,"z":210.9},{"x":-419.75,"y":175.38,"z":207.34}]},{"lat":-22.39,"lon":27.79,"b":[{"x":-411.23,"y":189.44,"z":211.98},{"x":-409.34,"y":193.43,"z":212.02},{"x":-406.97,"y":194.48,"z":215.6},{"x":-406.49,"y":191.5,"z":219.13},{"x":-408.4,"y":187.5,"z":219.05},{"x":-410.76,"y":186.49,"z":215.47}]},{"lat":-23.79,"lon":29.26,"b":[{"x":-401.57,"y":200.65,"z":220.03},{"x":-399.53,"y":204.66,"z":220.04},{"x":-397,"y":205.71,"z":223.62},{"x":-396.52,"y":202.69,"z":227.19},{"x":-398.58,"y":198.67,"z":227.14},{"x":-401.09,"y":197.67,"z":223.57}]},{"lat":-25.2,"lon":30.79,"b":[{"x":-391.22,"y":211.88,"z":228},{"x":-389.03,"y":215.9,"z":227.97},{"x":-386.33,"y":216.93,"z":231.55},{"x":-385.85,"y":213.89,"z":235.16},{"x":-388.06,"y":209.85,"z":235.15},{"x":-390.74,"y":208.86,"z":231.58}]},{"lat":-26.63,"lon":32.39,"b":[{"x":-380.17,"y":223.08,"z":235.86},{"x":-377.83,"y":227.1,"z":235.78},{"x":-374.98,"y":228.1,"z":239.34},{"x":-374.49,"y":225.03,"z":242.98},{"x":-376.86,"y":220.99,"z":243.03},{"x":-379.69,"y":220.03,"z":239.47}]},{"lat":-28.06,"lon":34.06,"b":[{"x":-367.49,"y":234.52,"z":244.74},{"x":-365.82,"y":237.21,"z":244.64},{"x":-363.81,"y":237.85,"z":247.01},{"x":-363.48,"y":235.78,"z":249.47},{"x":-365.16,"y":233.08,"z":249.55},{"x":-367.16,"y":232.46,"z":247.18}]},{"lat":-29.49,"lon":35.8,"b":[{"x":-356.05,"y":245.18,"z":251.06},{"x":-353.42,"y":249.17,"z":250.86},{"x":-350.27,"y":250.07,"z":254.35},{"x":-349.77,"y":246.97,"z":258.05},{"x":-352.42,"y":242.97,"z":258.23},{"x":-355.56,"y":242.09,"z":254.73}]},{"lat":-30.91,"lon":37.61,"b":[{"x":-343.02,"y":255.98,"z":258.32},{"x":-340.24,"y":259.93,"z":258.05},{"x":-336.95,"y":260.77,"z":261.5},{"x":-336.45,"y":257.65,"z":265.21},{"x":-339.24,"y":253.7,"z":265.46},{"x":-342.52,"y":252.88,"z":262.02}]},{"lat":-32.33,"lon":39.5,"b":[{"x":-329.37,"y":266.54,"z":265.31},{"x":-326.47,"y":270.43,"z":264.96},{"x":-323.05,"y":271.21,"z":268.34},{"x":-322.54,"y":268.07,"z":272.07},{"x":-325.46,"y":264.18,"z":272.4},{"x":-328.87,"y":263.42,"z":269.02}]},{"lat":-33.72,"lon":41.46,"b":[{"x":-315.16,"y":276.81,"z":271.97},{"x":-312.13,"y":280.63,"z":271.54},{"x":-308.59,"y":281.32,"z":274.85},{"x":-308.09,"y":278.19,"z":278.59},{"x":-311.12,"y":274.37,"z":279.01},{"x":-314.65,"y":273.68,"z":275.7}]},{"lat":-35.09,"lon":43.49,"b":[{"x":-300.43,"y":286.74,"z":278.28},{"x":-297.3,"y":290.48,"z":277.77},{"x":-293.65,"y":291.08,"z":280.99},{"x":-293.14,"y":287.94,"z":284.73},{"x":-296.28,"y":284.2,"z":285.24},{"x":-299.92,"y":283.6,"z":282.01}]},{"lat":-36.42,"lon":45.59,"b":[{"x":-285.24,"y":296.28,"z":284.2},{"x":-282.01,"y":299.92,"z":283.6},{"x":-278.28,"y":300.43,"z":286.74},{"x":-277.77,"y":297.3,"z":290.48},{"x":-280.99,"y":293.65,"z":291.08},{"x":-284.73,"y":293.14,"z":287.94}]},{"lat":-37.71,"lon":47.76,"b":[{"x":-269.66,"y":305.39,"z":289.72},{"x":-266.35,"y":308.93,"z":289.03},{"x":-262.54,"y":309.33,"z":292.07},{"x":-262.03,"y":306.21,"z":295.8},{"x":-265.33,"y":302.67,"z":296.5},{"x":-269.15,"y":302.25,"z":293.46}]},{"lat":-40.16,"lon":52.3,"b":[{"x":-234.22,"y":322.41,"z":301.95},{"x":-233.77,"y":322.85,"z":301.84},{"x":-233.24,"y":322.88,"z":302.22},{"x":-233.17,"y":322.46,"z":302.71},{"x":-233.63,"y":322.02,"z":302.83},{"x":-234.15,"y":321.99,"z":302.45}]},{"lat":-41.29,"lon":54.65,"b":[{"x":-220.13,"y":329.85,"z":304.43},{"x":-217.66,"y":332.12,"z":303.74},{"x":-214.85,"y":332.18,"z":305.67},{"x":-214.49,"y":329.98,"z":308.3},{"x":-216.93,"y":327.71,"z":309},{"x":-219.76,"y":327.64,"z":307.07}]},{"lat":-42.37,"lon":57.06,"b":[{"x":-204.81,"y":336.9,"z":307.36},{"x":-201.34,"y":339.95,"z":306.3},{"x":-197.39,"y":339.91,"z":308.9},{"x":-196.88,"y":336.86,"z":312.55},{"x":-200.32,"y":333.81,"z":313.63},{"x":-204.3,"y":333.83,"z":311.04}]},{"lat":-43.38,"lon":59.51,"b":[{"x":-188.33,"y":343.46,"z":310.63},{"x":-184.86,"y":346.36,"z":309.49},{"x":-180.92,"y":346.22,"z":311.97},{"x":-180.42,"y":343.19,"z":315.59},{"x":-183.85,"y":340.28,"z":316.75},{"x":-187.82,"y":340.4,"z":314.28}]},{"lat":-44.31,"lon":62,"b":[{"x":-171.89,"y":349.46,"z":313.46},{"x":-168.44,"y":352.23,"z":312.23},{"x":-164.52,"y":351.98,"z":314.59},{"x":-164.02,"y":348.98,"z":318.18},{"x":-167.43,"y":346.21,"z":319.43},{"x":-171.38,"y":346.44,"z":317.07}]},{"lat":-45.18,"lon":64.52,"b":[{"x":-155.55,"y":354.93,"z":315.84},{"x":-152.13,"y":357.56,"z":314.54},{"x":-148.25,"y":357.2,"z":316.79},{"x":-147.75,"y":354.24,"z":320.33},{"x":-151.13,"y":351.6,"z":321.66},{"x":-155.05,"y":351.93,"z":319.43}]},{"lat":-45.97,"lon":67.05,"b":[{"x":-139.38,"y":359.86,"z":317.81},{"x":-136,"y":362.36,"z":316.43},{"x":-132.17,"y":361.9,"z":318.57},{"x":-131.68,"y":358.97,"z":322.07},{"x":-135.01,"y":356.46,"z":323.47},{"x":-138.88,"y":356.9,"z":321.35}]},{"lat":-46.69,"lon":69.59,"b":[{"x":-123.43,"y":364.28,"z":319.37},{"x":-120.11,"y":366.64,"z":317.93},{"x":-116.34,"y":366.09,"z":319.97},{"x":-115.85,"y":363.2,"z":323.42},{"x":-119.12,"y":360.82,"z":324.88},{"x":-122.94,"y":361.35,"z":322.87}]},{"lat":-19.15,"lon":27.05,"b":[{"x":-422.78,"y":163.03,"z":211.23},{"x":-421.17,"y":166.95,"z":211.37},{"x":-418.96,"y":167.96,"z":214.93},{"x":-418.38,"y":164.98,"z":218.34},{"x":-420.01,"y":161.04,"z":218.14},{"x":-422.2,"y":160.09,"z":214.6}]},{"lat":-20.49,"lon":28.44,"b":[{"x":-414.11,"y":174,"z":219.48},{"x":-412.36,"y":177.97,"z":219.59},{"x":-410,"y":178.98,"z":223.16},{"x":-409.41,"y":175.96,"z":226.61},{"x":-411.19,"y":171.98,"z":226.45},{"x":-413.53,"y":171.02,"z":222.88}]},{"lat":-21.85,"lon":29.89,"b":[{"x":-404.77,"y":185.06,"z":227.69},{"x":-402.87,"y":189.06,"z":227.77},{"x":-400.35,"y":190.06,"z":231.35},{"x":-399.76,"y":187.01,"z":234.84},{"x":-401.69,"y":183,"z":234.71},{"x":-404.19,"y":182.04,"z":231.14}]},{"lat":-23.22,"lon":31.4,"b":[{"x":-394.75,"y":196.17,"z":235.84},{"x":-392.69,"y":200.2,"z":235.88},{"x":-390.01,"y":201.18,"z":239.46},{"x":-389.42,"y":198.1,"z":242.98},{"x":-391.5,"y":194.06,"z":242.89},{"x":-394.16,"y":193.12,"z":239.32}]},{"lat":-24.61,"lon":32.98,"b":[{"x":-384.03,"y":207.29,"z":243.88},{"x":-381.82,"y":211.33,"z":243.88},{"x":-378.99,"y":212.29,"z":247.44},{"x":-378.39,"y":209.17,"z":250.99},{"x":-380.62,"y":205.12,"z":250.95},{"x":-383.44,"y":204.2,"z":247.4}]},{"lat":-26.01,"lon":34.63,"b":[{"x":-370.57,"y":219.03,"z":254.31},{"x":-369.9,"y":220.19,"z":254.3},{"x":-369.04,"y":220.45,"z":255.31},{"x":-368.87,"y":219.55,"z":256.33},{"x":-369.55,"y":218.4,"z":256.33},{"x":-370.4,"y":218.14,"z":255.33}]},{"lat":-27.42,"lon":36.34,"b":[{"x":-360.53,"y":229.35,"z":259.5},{"x":-358.04,"y":233.34,"z":259.39},{"x":-354.93,"y":234.21,"z":262.85},{"x":-354.33,"y":231.06,"z":266.42},{"x":-356.84,"y":227.07,"z":266.51},{"x":-359.93,"y":226.23,"z":263.04}]},{"lat":-28.82,"lon":38.12,"b":[{"x":-347.83,"y":240.17,"z":266.93},{"x":-345.17,"y":244.17,"z":266.75},{"x":-341.89,"y":244.99,"z":270.2},{"x":-341.29,"y":241.8,"z":273.82},{"x":-343.96,"y":237.8,"z":273.97},{"x":-347.22,"y":237,"z":270.53}]},{"lat":-30.21,"lon":39.97,"b":[{"x":-334.47,"y":250.81,"z":274.12},{"x":-331.68,"y":254.76,"z":273.87},{"x":-328.27,"y":255.52,"z":277.25},{"x":-327.66,"y":252.31,"z":280.89},{"x":-330.47,"y":248.36,"z":281.12},{"x":-333.86,"y":247.62,"z":277.74}]},{"lat":-31.59,"lon":41.89,"b":[{"x":-320.53,"y":261.19,"z":281},{"x":-317.61,"y":265.08,"z":280.66},{"x":-314.08,"y":265.76,"z":283.97},{"x":-313.47,"y":262.55,"z":287.61},{"x":-316.4,"y":258.65,"z":287.94},{"x":-319.92,"y":257.98,"z":284.63}]},{"lat":-32.95,"lon":43.87,"b":[{"x":-306.05,"y":271.27,"z":287.52},{"x":-303.02,"y":275.09,"z":287.1},{"x":-299.37,"y":275.69,"z":290.33},{"x":-298.77,"y":272.46,"z":293.97},{"x":-301.81,"y":268.64,"z":294.38},{"x":-305.44,"y":268.05,"z":291.16}]},{"lat":-34.27,"lon":45.93,"b":[{"x":-291.08,"y":280.99,"z":293.65},{"x":-287.94,"y":284.73,"z":293.14},{"x":-284.2,"y":285.24,"z":296.28},{"x":-283.6,"y":282.01,"z":299.92},{"x":-286.74,"y":278.28,"z":300.43},{"x":-290.48,"y":277.77,"z":297.3}]},{"lat":-35.56,"lon":48.05,"b":[{"x":-275.69,"y":290.33,"z":299.37},{"x":-272.46,"y":293.97,"z":298.77},{"x":-268.64,"y":294.38,"z":301.81},{"x":-268.05,"y":291.16,"z":305.44},{"x":-271.27,"y":287.52,"z":306.05},{"x":-275.09,"y":287.1,"z":303.02}]},{"lat":-36.81,"lon":50.23,"b":[{"x":-258.33,"y":299.39,"z":305.91},{"x":-256.41,"y":301.44,"z":305.51},{"x":-254.16,"y":301.62,"z":307.21},{"x":-253.81,"y":299.75,"z":309.31},{"x":-255.72,"y":297.7,"z":309.72},{"x":-257.98,"y":297.51,"z":308.02}]},{"lat":-39.16,"lon":54.76,"b":[{"x":-227.65,"y":315.6,"z":313.84},{"x":-224.25,"y":318.9,"z":312.94},{"x":-220.29,"y":319,"z":315.65},{"x":-219.71,"y":315.81,"z":319.24},{"x":-223.09,"y":312.51,"z":320.14},{"x":-227.06,"y":312.39,"z":317.45}]},{"lat":-40.25,"lon":57.1,"b":[{"x":-211.26,"y":323.02,"z":317.72},{"x":-207.83,"y":326.2,"z":316.73},{"x":-203.86,"y":326.19,"z":319.32},{"x":-203.29,"y":323.02,"z":322.89},{"x":-206.68,"y":319.84,"z":323.89},{"x":-210.68,"y":319.83,"z":321.31}]},{"lat":-41.28,"lon":59.48,"b":[{"x":-194.8,"y":329.92,"z":321.13},{"x":-191.36,"y":332.97,"z":320.05},{"x":-187.39,"y":332.85,"z":322.52},{"x":-186.83,"y":329.7,"z":326.06},{"x":-190.23,"y":326.66,"z":327.15},{"x":-194.23,"y":326.75,"z":324.7}]},{"lat":-42.24,"lon":61.89,"b":[{"x":-178.35,"y":336.29,"z":324.08},{"x":-174.92,"y":339.2,"z":322.91},{"x":-170.96,"y":338.97,"z":325.26},{"x":-170.41,"y":335.86,"z":328.76},{"x":-173.8,"y":332.94,"z":329.95},{"x":-177.79,"y":333.15,"z":327.61}]},{"lat":-43.14,"lon":64.33,"b":[{"x":-161.97,"y":342.12,"z":326.56},{"x":-158.56,"y":344.9,"z":325.31},{"x":-154.64,"y":344.57,"z":327.55},{"x":-154.1,"y":341.48,"z":331.02},{"x":-157.46,"y":338.7,"z":332.28},{"x":-161.42,"y":339.01,"z":330.07}]},{"lat":-43.96,"lon":66.79,"b":[{"x":-145.73,"y":347.43,"z":328.61},{"x":-142.35,"y":350.07,"z":327.28},{"x":-138.48,"y":349.64,"z":329.4},{"x":-137.94,"y":346.59,"z":332.83},{"x":-141.27,"y":343.94,"z":334.18},{"x":-145.18,"y":344.35,"z":332.08}]},{"lat":-44.71,"lon":69.26,"b":[{"x":-129.68,"y":352.22,"z":330.24},{"x":-126.35,"y":354.73,"z":328.84},{"x":-122.54,"y":354.2,"z":330.85},{"x":-122.01,"y":351.19,"z":334.23},{"x":-125.29,"y":348.67,"z":335.65},{"x":-129.15,"y":349.17,"z":333.66}]},{"lat":-45.39,"lon":71.73,"b":[{"x":-113.88,"y":356.51,"z":331.46},{"x":-110.61,"y":358.89,"z":330},{"x":-106.86,"y":358.27,"z":331.9},{"x":-106.35,"y":355.3,"z":335.24},{"x":-109.57,"y":352.91,"z":336.72},{"x":-113.36,"y":353.5,"z":334.85}]},{"lat":-17.3,"lon":27.68,"b":[{"x":-424.82,"y":147.8,"z":218.22},{"x":-423.33,"y":151.68,"z":218.43},{"x":-421.14,"y":152.63,"z":221.98},{"x":-420.46,"y":149.64,"z":225.3},{"x":-421.96,"y":145.75,"z":225.03},{"x":-424.14,"y":144.85,"z":221.5}]},{"lat":-18.6,"lon":29.06,"b":[{"x":-416.47,"y":158.56,"z":226.6},{"x":-414.83,"y":162.5,"z":226.8},{"x":-412.49,"y":163.46,"z":230.36},{"x":-411.79,"y":160.42,"z":233.72},{"x":-413.45,"y":156.47,"z":233.47},{"x":-415.78,"y":155.57,"z":229.92}]},{"lat":-19.92,"lon":30.5,"b":[{"x":-407.44,"y":169.44,"z":234.97},{"x":-405.66,"y":173.43,"z":235.14},{"x":-403.17,"y":174.38,"z":238.71},{"x":-402.46,"y":171.3,"z":242.1},{"x":-404.26,"y":167.31,"z":241.88},{"x":-406.75,"y":166.41,"z":238.33}]},{"lat":-21.26,"lon":31.99,"b":[{"x":-397.74,"y":180.4,"z":243.28},{"x":-395.81,"y":184.42,"z":243.41},{"x":-393.16,"y":185.36,"z":246.98},{"x":-392.45,"y":182.24,"z":250.4},{"x":-394.4,"y":178.22,"z":250.22},{"x":-397.04,"y":177.32,"z":246.67}]},{"lat":-22.62,"lon":33.55,"b":[{"x":-387.36,"y":191.4,"z":251.49},{"x":-385.27,"y":195.44,"z":251.58},{"x":-382.46,"y":196.36,"z":255.13},{"x":-381.75,"y":193.2,"z":258.59},{"x":-383.86,"y":189.16,"z":258.46},{"x":-386.65,"y":188.28,"z":254.91}]},{"lat":-23.99,"lon":35.17,"b":[{"x":-375.39,"y":202.67,"z":260.67},{"x":-373.85,"y":205.45,"z":260.7},{"x":-371.81,"y":206.07,"z":263.13},{"x":-371.32,"y":203.87,"z":265.52},{"x":-372.87,"y":201.09,"z":265.47},{"x":-374.9,"y":200.5,"z":263.05}]},{"lat":-25.36,"lon":36.85,"b":[{"x":-363,"y":213.76,"z":269.24},{"x":-361.83,"y":215.75,"z":269.23},{"x":-360.29,"y":216.17,"z":270.95},{"x":-359.94,"y":214.58,"z":272.67},{"x":-361.13,"y":212.6,"z":272.67},{"x":-362.65,"y":212.19,"z":270.95}]},{"lat":-26.74,"lon":38.6,"b":[{"x":-352.13,"y":224.14,"z":275.12},{"x":-349.59,"y":228.17,"z":275.03},{"x":-346.33,"y":228.97,"z":278.47},{"x":-345.62,"y":225.72,"z":281.99},{"x":-348.17,"y":221.7,"z":282.05},{"x":-351.41,"y":220.92,"z":278.61}]},{"lat":-28.11,"lon":40.42,"b":[{"x":-339.08,"y":234.81,"z":282.51},{"x":-336.41,"y":238.8,"z":282.35},{"x":-333.01,"y":239.55,"z":285.73},{"x":-332.3,"y":236.28,"z":289.26},{"x":-334.98,"y":232.28,"z":289.4},{"x":-338.36,"y":231.56,"z":286.02}]},{"lat":-29.47,"lon":42.3,"b":[{"x":-325.43,"y":245.26,"z":289.59},{"x":-322.62,"y":249.21,"z":289.35},{"x":-319.1,"y":249.88,"z":292.66},{"x":-318.39,"y":246.6,"z":296.2},{"x":-321.21,"y":242.65,"z":296.42},{"x":-324.72,"y":241.99,"z":293.12}]},{"lat":-30.81,"lon":44.24,"b":[{"x":-311.22,"y":255.45,"z":296.32},{"x":-308.29,"y":259.34,"z":296},{"x":-304.65,"y":259.94,"z":299.23},{"x":-303.95,"y":256.64,"z":302.77},{"x":-306.88,"y":252.75,"z":303.08},{"x":-310.51,"y":252.16,"z":299.86}]},{"lat":-32.13,"lon":46.25,"b":[{"x":-296.5,"y":265.33,"z":302.67},{"x":-293.46,"y":269.15,"z":302.25},{"x":-289.72,"y":269.66,"z":305.39},{"x":-289.03,"y":266.35,"z":308.93},{"x":-292.07,"y":262.54,"z":309.33},{"x":-295.8,"y":262.03,"z":306.21}]},{"lat":-33.41,"lon":48.32,"b":[{"x":-281.32,"y":274.85,"z":308.59},{"x":-278.19,"y":278.59,"z":308.09},{"x":-274.37,"y":279.01,"z":311.12},{"x":-273.68,"y":275.7,"z":314.65},{"x":-276.81,"y":271.97,"z":315.16},{"x":-280.63,"y":271.54,"z":312.13}]},{"lat":-34.66,"lon":50.44,"b":[{"x":-265.76,"y":283.97,"z":314.08},{"x":-262.55,"y":287.61,"z":313.47},{"x":-258.65,"y":287.94,"z":316.4},{"x":-257.98,"y":284.63,"z":319.92},{"x":-261.19,"y":281,"z":320.53},{"x":-265.08,"y":280.66,"z":317.61}]},{"lat":-35.87,"lon":52.62,"b":[{"x":-249.78,"y":292.67,"z":319.18},{"x":-246.58,"y":296.11,"z":318.49},{"x":-242.74,"y":296.33,"z":321.23},{"x":-242.1,"y":293.11,"z":324.64},{"x":-245.28,"y":289.68,"z":325.34},{"x":-249.12,"y":289.45,"z":322.61}]},{"lat":-37.02,"lon":54.85,"b":[{"x":-233.76,"y":300.89,"z":323.64},{"x":-230.42,"y":304.31,"z":322.84},{"x":-226.44,"y":304.42,"z":325.53},{"x":-225.79,"y":301.14,"z":329.02},{"x":-229.1,"y":297.72,"z":329.84},{"x":-233.1,"y":297.59,"z":327.15}]},{"lat":-38.13,"lon":57.13,"b":[{"x":-217.46,"y":308.62,"z":327.7},{"x":-214.08,"y":311.92,"z":326.79},{"x":-210.08,"y":311.93,"z":329.37},{"x":-209.45,"y":308.66,"z":332.84},{"x":-212.79,"y":305.37,"z":333.75},{"x":-216.81,"y":305.33,"z":331.19}]},{"lat":-39.17,"lon":59.44,"b":[{"x":-201.05,"y":315.85,"z":331.27},{"x":-197.66,"y":319.03,"z":330.27},{"x":-193.66,"y":318.93,"z":332.72},{"x":-193.04,"y":315.68,"z":336.16},{"x":-196.4,"y":312.51,"z":337.18},{"x":-200.42,"y":312.58,"z":334.74}]},{"lat":-40.16,"lon":61.79,"b":[{"x":-184.62,"y":322.56,"z":334.35},{"x":-181.22,"y":325.61,"z":333.26},{"x":-177.24,"y":325.41,"z":335.59},{"x":-176.63,"y":322.19,"z":339},{"x":-179.99,"y":319.14,"z":340.11},{"x":-184,"y":319.32,"z":337.79}]},{"lat":-41.08,"lon":64.16,"b":[{"x":-168.24,"y":328.76,"z":336.96},{"x":-164.85,"y":331.67,"z":335.78},{"x":-160.89,"y":331.36,"z":337.99},{"x":-160.3,"y":328.17,"z":341.37},{"x":-163.64,"y":325.26,"z":342.57},{"x":-167.63,"y":325.53,"z":340.37}]},{"lat":-41.93,"lon":66.55,"b":[{"x":-151.96,"y":334.43,"z":339.11},{"x":-148.59,"y":337.21,"z":337.84},{"x":-144.68,"y":336.81,"z":339.94},{"x":-144.1,"y":333.65,"z":343.28},{"x":-147.42,"y":330.86,"z":344.56},{"x":-151.36,"y":331.24,"z":342.49}]},{"lat":-42.71,"lon":68.95,"b":[{"x":-135.84,"y":339.59,"z":340.82},{"x":-132.51,"y":342.24,"z":339.47},{"x":-128.66,"y":341.74,"z":341.46},{"x":-128.1,"y":338.62,"z":344.76},{"x":-131.37,"y":335.97,"z":346.12},{"x":-135.26,"y":336.43,"z":344.16}]},{"lat":-43.43,"lon":71.35,"b":[{"x":-119.95,"y":344.25,"z":342.1},{"x":-116.67,"y":346.77,"z":340.69},{"x":-112.89,"y":346.18,"z":342.56},{"x":-112.34,"y":343.1,"z":345.83},{"x":-115.56,"y":340.58,"z":347.25},{"x":-119.39,"y":341.13,"z":345.41}]},{"lat":-44.08,"lon":73.74,"b":[{"x":-104.33,"y":348.43,"z":342.99},{"x":-101.11,"y":350.83,"z":341.51},{"x":-97.4,"y":350.15,"z":343.28},{"x":-96.87,"y":347.12,"z":346.51},{"x":-100.03,"y":344.71,"z":348},{"x":-103.79,"y":345.36,"z":346.26}]},{"lat":-15.49,"lon":28.29,"b":[{"x":-426.36,"y":132.65,"z":224.85},{"x":-424.99,"y":136.49,"z":225.14},{"x":-422.82,"y":137.38,"z":228.67},{"x":-422.02,"y":134.39,"z":231.89},{"x":-423.41,"y":130.55,"z":231.55},{"x":-425.58,"y":129.71,"z":228.04}]},{"lat":-16.75,"lon":29.66,"b":[{"x":-418.3,"y":143.18,"z":233.36},{"x":-416.79,"y":147.08,"z":233.63},{"x":-414.47,"y":147.98,"z":237.18},{"x":-413.66,"y":144.94,"z":240.44},{"x":-415.19,"y":141.04,"z":240.11},{"x":-417.51,"y":140.19,"z":236.59}]},{"lat":-18.03,"lon":31.08,"b":[{"x":-409.59,"y":153.86,"z":241.86},{"x":-407.94,"y":157.8,"z":242.11},{"x":-405.45,"y":158.71,"z":245.67},{"x":-404.64,"y":155.61,"z":248.96},{"x":-406.32,"y":151.67,"z":248.66},{"x":-408.79,"y":150.81,"z":245.12}]},{"lat":-19.33,"lon":32.56,"b":[{"x":-400.21,"y":164.63,"z":250.32},{"x":-398.41,"y":168.62,"z":250.53},{"x":-395.77,"y":169.52,"z":254.09},{"x":-394.95,"y":166.38,"z":257.41},{"x":-396.78,"y":162.39,"z":257.15},{"x":-399.4,"y":161.54,"z":253.61}]},{"lat":-20.65,"lon":34.09,"b":[{"x":-390.15,"y":175.48,"z":258.69},{"x":-388.2,"y":179.5,"z":258.86},{"x":-385.4,"y":180.38,"z":262.41},{"x":-384.58,"y":177.2,"z":265.75},{"x":-386.56,"y":173.18,"z":265.53},{"x":-389.33,"y":172.34,"z":262.01}]},{"lat":-21.99,"lon":35.69,"b":[{"x":-379.38,"y":186.35,"z":266.96},{"x":-377.3,"y":190.36,"z":267.09},{"x":-374.37,"y":191.21,"z":270.57},{"x":-373.56,"y":188.01,"z":273.91},{"x":-375.67,"y":184.01,"z":273.75},{"x":-378.57,"y":183.2,"z":270.28}]},{"lat":-24.68,"lon":39.06,"b":[{"x":-355.91,"y":207.97,"z":282.85},{"x":-353.5,"y":212.01,"z":282.86},{"x":-350.26,"y":212.79,"z":286.29},{"x":-349.44,"y":209.5,"z":289.7},{"x":-351.86,"y":205.46,"z":289.65},{"x":-355.09,"y":204.71,"z":286.24}]},{"lat":-26.02,"lon":40.85,"b":[{"x":-343.18,"y":218.62,"z":290.44},{"x":-340.63,"y":222.64,"z":290.38},{"x":-337.25,"y":223.37,"z":293.75},{"x":-336.44,"y":220.05,"z":297.17},{"x":-339,"y":216.04,"z":297.2},{"x":-342.36,"y":215.33,"z":293.84}]},{"lat":-27.36,"lon":42.69,"b":[{"x":-329.84,"y":229.1,"z":297.72},{"x":-327.15,"y":233.1,"z":297.59},{"x":-323.64,"y":233.76,"z":300.89},{"x":-322.84,"y":230.42,"z":304.31},{"x":-325.53,"y":226.44,"z":304.42},{"x":-329.02,"y":225.79,"z":301.14}]},{"lat":-28.69,"lon":44.59,"b":[{"x":-315.92,"y":239.37,"z":304.66},{"x":-313.11,"y":243.31,"z":304.44},{"x":-309.48,"y":243.9,"z":307.66},{"x":-308.68,"y":240.54,"z":311.08},{"x":-311.5,"y":236.61,"z":311.29},{"x":-315.11,"y":236.03,"z":308.08}]},{"lat":-29.99,"lon":46.55,"b":[{"x":-301.47,"y":249.36,"z":311.22},{"x":-298.54,"y":253.24,"z":310.9},{"x":-294.81,"y":253.75,"z":314.03},{"x":-294.02,"y":250.38,"z":317.46},{"x":-296.96,"y":246.51,"z":317.76},{"x":-300.67,"y":246,"z":314.64}]},{"lat":-31.27,"lon":48.57,"b":[{"x":-286.55,"y":259.03,"z":317.35},{"x":-283.51,"y":262.84,"z":316.95},{"x":-279.69,"y":263.27,"z":319.97},{"x":-278.92,"y":259.89,"z":323.39},{"x":-281.95,"y":256.09,"z":323.79},{"x":-285.76,"y":255.66,"z":320.78}]},{"lat":-32.51,"lon":50.65,"b":[{"x":-271.21,"y":268.34,"z":323.05},{"x":-268.07,"y":272.07,"z":322.54},{"x":-264.18,"y":272.4,"z":325.46},{"x":-263.42,"y":269.02,"z":328.87},{"x":-266.54,"y":265.31,"z":329.37},{"x":-270.43,"y":264.96,"z":326.47}]},{"lat":-33.72,"lon":52.77,"b":[{"x":-255.52,"y":277.25,"z":328.27},{"x":-252.31,"y":280.89,"z":327.66},{"x":-248.36,"y":281.12,"z":330.47},{"x":-247.62,"y":277.74,"z":333.86},{"x":-250.81,"y":274.12,"z":334.47},{"x":-254.76,"y":273.87,"z":331.68}]},{"lat":-34.88,"lon":54.95,"b":[{"x":-239.55,"y":285.73,"z":333.01},{"x":-236.28,"y":289.26,"z":332.3},{"x":-232.28,"y":289.4,"z":334.98},{"x":-231.56,"y":286.02,"z":338.36},{"x":-234.81,"y":282.51,"z":339.08},{"x":-238.8,"y":282.35,"z":336.41}]},{"lat":-35.99,"lon":57.16,"b":[{"x":-223.37,"y":293.75,"z":337.25},{"x":-220.05,"y":297.17,"z":336.44},{"x":-216.04,"y":297.2,"z":339},{"x":-215.33,"y":293.84,"z":342.36},{"x":-218.62,"y":290.44,"z":343.18},{"x":-222.64,"y":290.38,"z":340.63}]},{"lat":-37.06,"lon":59.41,"b":[{"x":-207.06,"y":301.29,"z":340.99},{"x":-203.71,"y":304.58,"z":340.08},{"x":-199.69,"y":304.51,"z":342.52},{"x":-199,"y":301.17,"z":345.85},{"x":-202.32,"y":297.89,"z":346.77},{"x":-206.35,"y":297.93,"z":344.35}]},{"lat":-38.06,"lon":61.7,"b":[{"x":-190.69,"y":308.33,"z":344.23},{"x":-187.32,"y":311.5,"z":343.22},{"x":-183.31,"y":311.33,"z":345.54},{"x":-182.65,"y":308.01,"z":348.85},{"x":-185.97,"y":304.85,"z":349.87},{"x":-190,"y":304.99,"z":347.57}]},{"lat":-39,"lon":64,"b":[{"x":-174.32,"y":314.87,"z":346.98},{"x":-170.96,"y":317.91,"z":345.87},{"x":-166.98,"y":317.64,"z":348.07},{"x":-166.33,"y":314.35,"z":351.35},{"x":-169.65,"y":311.31,"z":352.47},{"x":-173.66,"y":311.55,"z":350.29}]},{"lat":-39.88,"lon":66.33,"b":[{"x":-158.04,"y":320.9,"z":349.25},{"x":-154.69,"y":323.81,"z":348.06},{"x":-150.75,"y":323.44,"z":350.13},{"x":-150.12,"y":320.18,"z":353.38},{"x":-153.42,"y":317.27,"z":354.58},{"x":-157.39,"y":317.61,"z":352.53}]},{"lat":-40.7,"lon":68.66,"b":[{"x":-141.89,"y":326.42,"z":351.06},{"x":-138.57,"y":329.21,"z":349.78},{"x":-134.68,"y":328.74,"z":351.74},{"x":-134.07,"y":325.52,"z":354.96},{"x":-137.34,"y":322.73,"z":356.24},{"x":-141.26,"y":323.17,"z":354.31}]},{"lat":-41.45,"lon":70.99,"b":[{"x":-125.94,"y":331.46,"z":352.43},{"x":-122.66,"y":334.11,"z":351.07},{"x":-118.83,"y":333.55,"z":352.92},{"x":-118.25,"y":330.37,"z":356.1},{"x":-121.47,"y":327.71,"z":357.46},{"x":-125.33,"y":328.24,"z":355.64}]},{"lat":-42.13,"lon":73.32,"b":[{"x":-110.23,"y":336.01,"z":353.39},{"x":-107.01,"y":338.54,"z":351.96},{"x":-103.26,"y":337.89,"z":353.7},{"x":-102.69,"y":334.76,"z":356.84},{"x":-105.86,"y":332.22,"z":358.27},{"x":-109.65,"y":332.83,"z":356.56}]},{"lat":-42.76,"lon":75.63,"b":[{"x":-94.82,"y":340.1,"z":353.95},{"x":-91.66,"y":342.5,"z":352.46},{"x":-87.99,"y":341.78,"z":354.1},{"x":-87.44,"y":338.68,"z":357.19},{"x":-90.55,"y":336.27,"z":358.69},{"x":-94.26,"y":336.96,"z":357.09}]},{"lat":-13.7,"lon":28.88,"b":[{"x":-427.42,"y":117.65,"z":231.12},{"x":-426.16,"y":121.42,"z":231.47},{"x":-424,"y":122.26,"z":234.98},{"x":-423.1,"y":119.28,"z":238.11},{"x":-424.38,"y":115.5,"z":237.69},{"x":-426.53,"y":114.71,"z":234.21}]},{"lat":-14.92,"lon":30.23,"b":[{"x":-419.64,"y":127.92,"z":239.74},{"x":-418.25,"y":131.76,"z":240.08},{"x":-415.94,"y":132.62,"z":243.61},{"x":-415.03,"y":129.58,"z":246.77},{"x":-416.45,"y":125.74,"z":246.37},{"x":-418.75,"y":124.94,"z":242.86}]},{"lat":-16.16,"lon":31.64,"b":[{"x":-411.23,"y":138.36,"z":248.36},{"x":-409.7,"y":142.26,"z":248.68},{"x":-407.23,"y":143.11,"z":252.22},{"x":-406.32,"y":140.02,"z":255.41},{"x":-407.87,"y":136.13,"z":255.03},{"x":-410.32,"y":135.32,"z":251.52}]},{"lat":-17.43,"lon":33.1,"b":[{"x":-402.16,"y":148.93,"z":256.95},{"x":-400.48,"y":152.88,"z":257.24},{"x":-397.86,"y":153.73,"z":260.78},{"x":-396.94,"y":150.58,"z":263.99},{"x":-398.65,"y":146.64,"z":263.65},{"x":-401.24,"y":145.83,"z":260.13}]},{"lat":-18.71,"lon":34.61,"b":[{"x":-392.42,"y":159.59,"z":265.46},{"x":-390.59,"y":163.58,"z":265.72},{"x":-387.82,"y":164.41,"z":269.25},{"x":-386.9,"y":161.23,"z":272.48},{"x":-388.75,"y":157.24,"z":272.17},{"x":-391.5,"y":156.44,"z":268.67}]},{"lat":-20.01,"lon":36.19,"b":[{"x":-382.01,"y":170.3,"z":273.85},{"x":-380.03,"y":174.32,"z":274.07},{"x":-377.1,"y":175.14,"z":277.57},{"x":-376.18,"y":171.9,"z":280.83},{"x":-378.18,"y":167.89,"z":280.57},{"x":-381.08,"y":167.11,"z":277.09}]},{"lat":-22.64,"lon":39.51,"b":[{"x":-358.78,"y":191.81,"z":290.54},{"x":-356.79,"y":195.35,"z":290.64},{"x":-353.97,"y":196.01,"z":293.63},{"x":-353.16,"y":193.1,"z":296.51},{"x":-355.17,"y":189.58,"z":296.38},{"x":-357.97,"y":188.94,"z":293.41}]},{"lat":-23.96,"lon":41.25,"b":[{"x":-346.77,"y":202.32,"z":297.89},{"x":-344.35,"y":206.35,"z":297.93},{"x":-340.99,"y":207.06,"z":301.29},{"x":-340.08,"y":203.71,"z":304.58},{"x":-342.52,"y":199.69,"z":304.51},{"x":-345.85,"y":199,"z":301.17}]},{"lat":-25.27,"lon":43.06,"b":[{"x":-333.75,"y":212.79,"z":305.37},{"x":-331.19,"y":216.81,"z":305.33},{"x":-327.7,"y":217.46,"z":308.62},{"x":-326.79,"y":214.08,"z":311.92},{"x":-329.37,"y":210.08,"z":311.93},{"x":-332.84,"y":209.45,"z":308.66}]},{"lat":-26.58,"lon":44.92,"b":[{"x":-320.14,"y":223.09,"z":312.51},{"x":-317.45,"y":227.06,"z":312.39},{"x":-313.84,"y":227.65,"z":315.6},{"x":-312.94,"y":224.25,"z":318.9},{"x":-315.65,"y":220.29,"z":319},{"x":-319.24,"y":219.71,"z":315.81}]},{"lat":-27.87,"lon":46.84,"b":[{"x":-305.99,"y":233.15,"z":319.27},{"x":-303.17,"y":237.08,"z":319.06},{"x":-299.45,"y":237.59,"z":322.18},{"x":-298.57,"y":234.17,"z":325.48},{"x":-301.39,"y":230.26,"z":325.67},{"x":-305.09,"y":229.75,"z":322.57}]},{"lat":-30.37,"lon":50.84,"b":[{"x":-276.24,"y":252.4,"z":331.52},{"x":-273.21,"y":256.19,"z":331.12},{"x":-269.32,"y":256.54,"z":334.03},{"x":-268.47,"y":253.1,"z":337.32},{"x":-271.5,"y":249.32,"z":337.71},{"x":-275.38,"y":248.96,"z":334.82}]},{"lat":-31.58,"lon":52.91,"b":[{"x":-260.77,"y":261.5,"z":336.95},{"x":-257.65,"y":265.21,"z":336.45},{"x":-253.7,"y":265.46,"z":339.24},{"x":-252.88,"y":262.02,"z":342.52},{"x":-255.98,"y":258.32,"z":343.02},{"x":-259.93,"y":258.05,"z":340.24}]},{"lat":-32.74,"lon":55.03,"b":[{"x":-244.99,"y":270.2,"z":341.89},{"x":-241.8,"y":273.82,"z":341.29},{"x":-237.8,"y":273.97,"z":343.96},{"x":-237,"y":270.53,"z":347.22},{"x":-240.17,"y":266.93,"z":347.83},{"x":-244.17,"y":266.75,"z":345.17}]},{"lat":-33.86,"lon":57.19,"b":[{"x":-228.97,"y":278.47,"z":346.33},{"x":-225.72,"y":281.99,"z":345.62},{"x":-221.7,"y":282.05,"z":348.17},{"x":-220.92,"y":278.61,"z":351.41},{"x":-224.14,"y":275.12,"z":352.13},{"x":-228.17,"y":275.03,"z":349.59}]},{"lat":-34.93,"lon":59.38,"b":[{"x":-212.79,"y":286.29,"z":350.26},{"x":-209.5,"y":289.7,"z":349.44},{"x":-205.46,"y":289.65,"z":351.86},{"x":-204.71,"y":286.24,"z":355.09},{"x":-207.97,"y":282.85,"z":355.91},{"x":-212.01,"y":282.86,"z":353.5}]},{"lat":-35.95,"lon":61.6,"b":[{"x":-196.51,"y":293.64,"z":353.67},{"x":-193.19,"y":296.93,"z":352.75},{"x":-189.16,"y":296.78,"z":355.05},{"x":-188.44,"y":293.39,"z":358.25},{"x":-191.71,"y":290.11,"z":359.17},{"x":-195.75,"y":290.22,"z":356.89}]},{"lat":-36.92,"lon":63.85,"b":[{"x":-180.2,"y":300.5,"z":356.58},{"x":-176.88,"y":303.67,"z":355.56},{"x":-172.87,"y":303.43,"z":357.73},{"x":-172.17,"y":300.05,"z":360.91},{"x":-175.45,"y":296.9,"z":361.93},{"x":-179.48,"y":297.11,"z":359.78}]},{"lat":-37.82,"lon":66.11,"b":[{"x":-163.94,"y":306.88,"z":358.99},{"x":-160.63,"y":309.92,"z":357.88},{"x":-156.65,"y":309.58,"z":359.93},{"x":-155.98,"y":306.23,"z":363.07},{"x":-159.25,"y":303.2,"z":364.19},{"x":-163.24,"y":303.5,"z":362.16}]},{"lat":-38.67,"lon":68.38,"b":[{"x":-147.79,"y":312.76,"z":360.93},{"x":-144.5,"y":315.67,"z":359.72},{"x":-140.57,"y":315.24,"z":361.66},{"x":-139.92,"y":311.93,"z":364.77},{"x":-143.17,"y":309.02,"z":365.98},{"x":-147.12,"y":309.42,"z":364.07}]},{"lat":-39.45,"lon":70.65,"b":[{"x":-131.81,"y":318.15,"z":362.4},{"x":-128.55,"y":320.94,"z":361.11},{"x":-124.68,"y":320.42,"z":362.93},{"x":-124.06,"y":317.14,"z":366.01},{"x":-127.27,"y":314.36,"z":367.3},{"x":-131.16,"y":314.85,"z":365.51}]},{"lat":-40.17,"lon":72.92,"b":[{"x":-116.05,"y":323.07,"z":363.44},{"x":-112.83,"y":325.73,"z":362.08},{"x":-109.04,"y":325.12,"z":363.79},{"x":-108.44,"y":321.89,"z":366.83},{"x":-111.6,"y":319.23,"z":368.2},{"x":-115.43,"y":319.8,"z":366.52}]},{"lat":-40.83,"lon":75.17,"b":[{"x":-100.56,"y":327.53,"z":364.07},{"x":-97.39,"y":330.07,"z":362.64},{"x":-93.68,"y":329.38,"z":364.24},{"x":-93.11,"y":326.19,"z":367.25},{"x":-96.22,"y":323.65,"z":368.68},{"x":-99.96,"y":324.3,"z":367.11}]},{"lat":-41.43,"lon":77.41,"b":[{"x":-85.38,"y":331.54,"z":364.32},{"x":-82.28,"y":333.96,"z":362.82},{"x":-78.66,"y":333.19,"z":364.33},{"x":-78.1,"y":330.05,"z":367.3},{"x":-81.15,"y":327.63,"z":368.8},{"x":-84.8,"y":328.35,"z":367.33}]},{"lat":-11.96,"lon":29.45,"b":[{"x":-428.01,"y":102.83,"z":237.01},{"x":-426.86,"y":106.53,"z":237.44},{"x":-424.71,"y":107.32,"z":240.92},{"x":-423.72,"y":104.35,"z":243.95},{"x":-424.89,"y":100.65,"z":243.47},{"x":-427.03,"y":99.91,"z":240.01}]},{"lat":-13.13,"lon":30.79,"b":[{"x":-420.51,"y":112.83,"z":245.73},{"x":-419.23,"y":116.6,"z":246.15},{"x":-416.93,"y":117.4,"z":249.65},{"x":-415.93,"y":114.38,"z":252.7},{"x":-417.23,"y":110.61,"z":252.23},{"x":-419.51,"y":109.86,"z":248.76}]},{"lat":-14.33,"lon":32.18,"b":[{"x":-412.38,"y":123.01,"z":254.46},{"x":-410.96,"y":126.85,"z":254.86},{"x":-408.52,"y":127.66,"z":258.37},{"x":-407.5,"y":124.58,"z":261.45},{"x":-408.95,"y":120.74,"z":260.99},{"x":-411.38,"y":119.99,"z":257.51}]},{"lat":-15.56,"lon":33.62,"b":[{"x":-403.61,"y":133.34,"z":263.16},{"x":-402.05,"y":137.24,"z":263.54},{"x":-399.45,"y":138.04,"z":267.05},{"x":-398.43,"y":134.91,"z":270.15},{"x":-400.02,"y":131.02,"z":269.72},{"x":-402.6,"y":130.26,"z":266.24}]},{"lat":-16.81,"lon":35.11,"b":[{"x":-394.19,"y":143.79,"z":271.8},{"x":-392.48,"y":147.73,"z":272.14},{"x":-389.73,"y":148.53,"z":275.64},{"x":-388.71,"y":145.34,"z":278.77},{"x":-390.44,"y":141.41,"z":278.37},{"x":-393.17,"y":140.65,"z":274.9}]},{"lat":-18.07,"lon":36.66,"b":[{"x":-384.1,"y":154.31,"z":280.33},{"x":-382.25,"y":158.3,"z":280.64},{"x":-379.34,"y":159.08,"z":284.12},{"x":-378.32,"y":155.85,"z":287.26},{"x":-380.2,"y":151.88,"z":286.9},{"x":-383.08,"y":151.13,"z":283.45}]},{"lat":-20.63,"lon":39.93,"b":[{"x":-361.07,"y":175.65,"z":297.85},{"x":-359.52,"y":178.56,"z":298},{"x":-357.2,"y":179.09,"z":300.46},{"x":-356.47,"y":176.69,"z":302.75},{"x":-358.04,"y":173.79,"z":302.57},{"x":-360.33,"y":173.28,"z":300.13}]},{"lat":-21.92,"lon":41.64,"b":[{"x":-349.87,"y":185.97,"z":304.85},{"x":-347.57,"y":190,"z":304.99},{"x":-344.23,"y":190.69,"z":308.33},{"x":-343.22,"y":187.32,"z":311.5},{"x":-345.54,"y":183.31,"z":311.33},{"x":-348.85,"y":182.65,"z":308.01}]},{"lat":-23.21,"lon":43.42,"b":[{"x":-337.18,"y":196.4,"z":312.51},{"x":-334.74,"y":200.42,"z":312.58},{"x":-331.27,"y":201.05,"z":315.85},{"x":-330.27,"y":197.66,"z":319.03},{"x":-332.72,"y":193.66,"z":318.93},{"x":-336.16,"y":193.04,"z":315.68}]},{"lat":-24.49,"lon":45.24,"b":[{"x":-323.89,"y":206.68,"z":319.84},{"x":-321.31,"y":210.68,"z":319.83},{"x":-317.72,"y":211.26,"z":323.02},{"x":-316.73,"y":207.83,"z":326.2},{"x":-319.32,"y":203.86,"z":326.19},{"x":-322.89,"y":203.29,"z":323.02}]},{"lat":-25.76,"lon":47.12,"b":[{"x":-310.04,"y":216.78,"z":326.81},{"x":-307.33,"y":220.74,"z":326.71},{"x":-303.64,"y":221.25,"z":329.81},{"x":-302.66,"y":217.8,"z":332.98},{"x":-305.38,"y":213.86,"z":333.06},{"x":-309.05,"y":213.35,"z":329.98}]},{"lat":-27.02,"lon":49.05,"b":[{"x":-294.55,"y":226.78,"z":334.29},{"x":-292.58,"y":229.51,"z":334.16},{"x":-289.94,"y":229.81,"z":336.25},{"x":-289.27,"y":227.39,"z":338.45},{"x":-291.24,"y":224.69,"z":338.58},{"x":-293.87,"y":224.38,"z":336.5}]},{"lat":-28.24,"lon":51.03,"b":[{"x":-279.22,"y":236.39,"z":340.74},{"x":-277.54,"y":238.59,"z":340.58},{"x":-275.33,"y":238.79,"z":342.23},{"x":-274.8,"y":236.8,"z":344.04},{"x":-276.47,"y":234.61,"z":344.2},{"x":-278.68,"y":234.4,"z":342.56}]},{"lat":-29.44,"lon":53.05,"b":[{"x":-265.63,"y":245.46,"z":345.12},{"x":-262.61,"y":249.24,"z":344.72},{"x":-258.66,"y":249.51,"z":347.5},{"x":-257.76,"y":246.02,"z":350.65},{"x":-260.77,"y":242.27,"z":351.04},{"x":-264.7,"y":241.98,"z":348.28}]},{"lat":-30.61,"lon":55.12,"b":[{"x":-250.07,"y":254.35,"z":350.27},{"x":-246.97,"y":258.05,"z":349.77},{"x":-242.97,"y":258.23,"z":352.42},{"x":-242.09,"y":254.73,"z":355.56},{"x":-245.18,"y":251.06,"z":356.05},{"x":-249.17,"y":250.86,"z":353.42}]},{"lat":-31.74,"lon":57.22,"b":[{"x":-234.24,"y":262.85,"z":354.91},{"x":-231.07,"y":266.45,"z":354.3},{"x":-227.04,"y":266.54,"z":356.83},{"x":-226.19,"y":263.05,"z":359.95},{"x":-229.34,"y":259.47,"z":360.56},{"x":-233.36,"y":259.36,"z":358.05}]},{"lat":-32.82,"lon":59.35,"b":[{"x":-218.21,"y":270.92,"z":359.03},{"x":-214.99,"y":274.42,"z":358.32},{"x":-210.95,"y":274.41,"z":360.72},{"x":-210.13,"y":270.93,"z":363.82},{"x":-213.32,"y":267.45,"z":364.54},{"x":-217.36,"y":267.43,"z":362.15}]},{"lat":-33.85,"lon":61.52,"b":[{"x":-202.06,"y":278.55,"z":362.63},{"x":-198.8,"y":281.94,"z":361.81},{"x":-194.76,"y":281.83,"z":364.09},{"x":-193.97,"y":278.37,"z":367.17},{"x":-197.19,"y":275,"z":367.99},{"x":-201.24,"y":275.07,"z":365.73}]},{"lat":-34.83,"lon":63.7,"b":[{"x":-185.85,"y":285.72,"z":365.72},{"x":-182.57,"y":288.99,"z":364.79},{"x":-178.55,"y":288.79,"z":366.94},{"x":-177.79,"y":285.34,"z":370},{"x":-181.02,"y":282.09,"z":370.92},{"x":-185.06,"y":282.26,"z":368.79}]},{"lat":-35.76,"lon":65.91,"b":[{"x":-169.65,"y":292.42,"z":368.29},{"x":-166.37,"y":295.57,"z":367.27},{"x":-162.38,"y":295.27,"z":369.29},{"x":-161.65,"y":291.85,"z":372.32},{"x":-164.88,"y":288.71,"z":373.35},{"x":-168.89,"y":288.97,"z":371.34}]},{"lat":-36.63,"lon":68.12,"b":[{"x":-153.53,"y":298.64,"z":370.37},{"x":-150.26,"y":301.67,"z":369.25},{"x":-146.31,"y":301.27,"z":371.15},{"x":-145.61,"y":297.89,"z":374.15},{"x":-148.83,"y":294.87,"z":375.27},{"x":-152.8,"y":295.22,"z":373.39}]},{"lat":-37.44,"lon":70.33,"b":[{"x":-137.55,"y":304.39,"z":371.97},{"x":-134.3,"y":307.29,"z":370.76},{"x":-130.41,"y":306.81,"z":372.55},{"x":-129.74,"y":303.46,"z":375.52},{"x":-132.94,"y":300.56,"z":376.73},{"x":-136.85,"y":301,"z":374.97}]},{"lat":-38.19,"lon":72.54,"b":[{"x":-121.76,"y":309.66,"z":373.12},{"x":-118.55,"y":312.45,"z":371.82},{"x":-114.73,"y":311.88,"z":373.5},{"x":-114.09,"y":308.57,"z":376.44},{"x":-117.25,"y":305.79,"z":377.73},{"x":-121.1,"y":306.31,"z":376.09}]},{"lat":-38.89,"lon":74.74,"b":[{"x":-106.22,"y":314.48,"z":373.84},{"x":-103.06,"y":317.15,"z":372.47},{"x":-99.31,"y":316.5,"z":374.04},{"x":-98.7,"y":313.23,"z":376.94},{"x":-101.81,"y":310.57,"z":378.31},{"x":-105.58,"y":311.17,"z":376.77}]},{"lat":-39.52,"lon":76.92,"b":[{"x":-90.97,"y":318.86,"z":374.16},{"x":-87.86,"y":321.4,"z":372.72},{"x":-84.2,"y":320.68,"z":374.19},{"x":-83.62,"y":317.45,"z":377.06},{"x":-86.67,"y":314.91,"z":378.49},{"x":-90.36,"y":315.59,"z":377.06}]},{"lat":-40.1,"lon":79.08,"b":[{"x":-76.04,"y":322.81,"z":374.1},{"x":-73,"y":325.23,"z":372.6},{"x":-69.43,"y":324.44,"z":373.98},{"x":-68.88,"y":321.26,"z":376.82},{"x":-71.86,"y":318.83,"z":378.31},{"x":-75.46,"y":319.59,"z":376.98}]},{"lat":-10.25,"lon":30,"b":[{"x":-428.17,"y":88.23,"z":242.55},{"x":-427.12,"y":91.86,"z":243.04},{"x":-424.98,"y":92.59,"z":246.49},{"x":-423.9,"y":89.66,"z":249.42},{"x":-424.98,"y":86.04,"z":248.87},{"x":-427.1,"y":85.35,"z":245.45}]},{"lat":-11.38,"lon":31.32,"b":[{"x":-420.92,"y":97.95,"z":251.34},{"x":-419.75,"y":101.65,"z":251.83},{"x":-417.47,"y":102.4,"z":255.3},{"x":-416.37,"y":99.4,"z":258.25},{"x":-417.57,"y":95.71,"z":257.7},{"x":-419.84,"y":95.01,"z":254.27}]},{"lat":-12.54,"lon":32.7,"b":[{"x":-413.07,"y":107.85,"z":260.15},{"x":-411.76,"y":111.62,"z":260.63},{"x":-409.34,"y":112.38,"z":264.11},{"x":-408.23,"y":109.33,"z":267.08},{"x":-409.56,"y":105.57,"z":266.55},{"x":-411.97,"y":104.86,"z":263.11}]},{"lat":-13.73,"lon":34.12,"b":[{"x":-404.59,"y":117.92,"z":268.95},{"x":-403.15,"y":121.76,"z":269.41},{"x":-400.57,"y":122.52,"z":272.89},{"x":-399.46,"y":119.41,"z":275.88},{"x":-400.93,"y":115.59,"z":275.37},{"x":-403.49,"y":114.87,"z":271.93}]},{"lat":-14.94,"lon":35.59,"b":[{"x":-395.47,"y":128.13,"z":277.7},{"x":-393.89,"y":132.02,"z":278.13},{"x":-391.16,"y":132.78,"z":281.6},{"x":-390.04,"y":129.61,"z":284.61},{"x":-391.65,"y":125.74,"z":284.13},{"x":-394.36,"y":125.02,"z":280.69}]},{"lat":-16.16,"lon":37.12,"b":[{"x":-385.7,"y":138.45,"z":286.35},{"x":-383.97,"y":142.38,"z":286.75},{"x":-381.09,"y":143.13,"z":290.2},{"x":-379.97,"y":139.91,"z":293.22},{"x":-381.73,"y":136,"z":292.78},{"x":-384.58,"y":135.28,"z":289.36}]},{"lat":-17.4,"lon":38.7,"b":[{"x":-373.6,"y":149.25,"z":296.83},{"x":-372.8,"y":150.95,"z":296.98},{"x":-371.5,"y":151.27,"z":298.45},{"x":-371.01,"y":149.86,"z":299.76},{"x":-371.83,"y":148.16,"z":299.59},{"x":-373.12,"y":147.86,"z":298.13}]},{"lat":-19.92,"lon":42.02,"b":[{"x":-352.47,"y":169.65,"z":311.31},{"x":-350.29,"y":173.66,"z":311.55},{"x":-346.98,"y":174.32,"z":314.87},{"x":-345.87,"y":170.96,"z":317.91},{"x":-348.07,"y":166.98,"z":317.64},{"x":-351.35,"y":166.33,"z":314.35}]},{"lat":-21.18,"lon":43.76,"b":[{"x":-340.11,"y":179.99,"z":319.14},{"x":-337.79,"y":184,"z":319.32},{"x":-334.35,"y":184.62,"z":322.56},{"x":-333.26,"y":181.22,"z":325.61},{"x":-335.59,"y":177.24,"z":325.41},{"x":-339,"y":176.63,"z":322.19}]},{"lat":-22.44,"lon":45.54,"b":[{"x":-327.15,"y":190.23,"z":326.66},{"x":-324.7,"y":194.23,"z":326.75},{"x":-321.13,"y":194.8,"z":329.92},{"x":-320.05,"y":191.36,"z":332.97},{"x":-322.52,"y":187.39,"z":332.85},{"x":-326.06,"y":186.83,"z":329.7}]},{"lat":-23.69,"lon":47.38,"b":[{"x":-313.63,"y":200.32,"z":333.81},{"x":-311.04,"y":204.3,"z":333.83},{"x":-307.36,"y":204.81,"z":336.9},{"x":-306.3,"y":201.34,"z":339.95},{"x":-308.9,"y":197.39,"z":339.91},{"x":-312.55,"y":196.88,"z":336.86}]},{"lat":-24.92,"lon":49.27,"b":[{"x":-299.58,"y":210.21,"z":340.57},{"x":-296.86,"y":214.15,"z":340.49},{"x":-293.09,"y":214.59,"z":343.47},{"x":-292.05,"y":211.1,"z":346.5},{"x":-294.76,"y":207.19,"z":346.57},{"x":-298.51,"y":206.75,"z":343.61}]},{"lat":-27.33,"lon":53.18,"b":[{"x":-269.57,"y":229.27,"z":353.12},{"x":-267.04,"y":232.59,"z":352.87},{"x":-263.63,"y":232.84,"z":355.27},{"x":-262.77,"y":229.78,"z":357.88},{"x":-265.3,"y":226.49,"z":358.11},{"x":-268.7,"y":226.23,"z":355.74}]},{"lat":-28.49,"lon":55.19,"b":[{"x":-254.77,"y":238.27,"z":358.1},{"x":-251.76,"y":242.03,"z":357.72},{"x":-247.78,"y":242.23,"z":360.35},{"x":-246.82,"y":238.69,"z":363.36},{"x":-249.82,"y":234.97,"z":363.73},{"x":-253.79,"y":234.75,"z":361.12}]},{"lat":-29.62,"lon":57.24,"b":[{"x":-239.16,"y":246.96,"z":362.95},{"x":-236.07,"y":250.63,"z":362.46},{"x":-232.05,"y":250.74,"z":364.97},{"x":-231.13,"y":247.2,"z":367.96},{"x":-234.19,"y":243.56,"z":368.45},{"x":-238.21,"y":243.42,"z":365.96}]},{"lat":-30.71,"lon":59.33,"b":[{"x":-223.32,"y":255.25,"z":367.28},{"x":-220.18,"y":258.83,"z":366.68},{"x":-216.13,"y":258.85,"z":369.06},{"x":-215.24,"y":255.32,"z":372.03},{"x":-218.36,"y":251.77,"z":372.63},{"x":-222.4,"y":251.72,"z":370.27}]},{"lat":-31.75,"lon":61.44,"b":[{"x":-207.33,"y":263.13,"z":371.08},{"x":-204.13,"y":266.61,"z":370.37},{"x":-200.09,"y":266.53,"z":372.63},{"x":-199.23,"y":263.01,"z":375.57},{"x":-202.39,"y":259.56,"z":376.29},{"x":-206.44,"y":259.6,"z":374.05}]},{"lat":-32.75,"lon":63.57,"b":[{"x":-191.24,"y":270.58,"z":374.35},{"x":-188.02,"y":273.95,"z":373.53},{"x":-183.98,"y":273.78,"z":375.66},{"x":-183.17,"y":270.28,"z":378.59},{"x":-186.35,"y":266.93,"z":379.41},{"x":-190.39,"y":267.06,"z":377.3}]},{"lat":-33.69,"lon":65.71,"b":[{"x":-175.14,"y":277.57,"z":377.1},{"x":-171.9,"y":280.83,"z":376.18},{"x":-167.89,"y":280.57,"z":378.18},{"x":-167.11,"y":277.09,"z":381.08},{"x":-170.3,"y":273.85,"z":382.01},{"x":-174.32,"y":274.07,"z":380.03}]},{"lat":-34.59,"lon":67.87,"b":[{"x":-159.08,"y":284.12,"z":379.34},{"x":-155.85,"y":287.26,"z":378.32},{"x":-151.88,"y":286.9,"z":380.2},{"x":-151.13,"y":283.45,"z":383.08},{"x":-154.31,"y":280.33,"z":384.1},{"x":-158.3,"y":280.64,"z":382.25}]},{"lat":-35.43,"lon":70.02,"b":[{"x":-143.13,"y":290.2,"z":381.09},{"x":-139.91,"y":293.22,"z":379.97},{"x":-136,"y":292.78,"z":381.73},{"x":-135.28,"y":289.36,"z":384.58},{"x":-138.45,"y":286.35,"z":385.7},{"x":-142.38,"y":286.75,"z":383.97}]},{"lat":-36.21,"lon":72.18,"b":[{"x":-127.35,"y":295.82,"z":382.37},{"x":-124.15,"y":298.72,"z":381.16},{"x":-120.3,"y":298.2,"z":382.8},{"x":-119.63,"y":294.82,"z":385.63},{"x":-122.76,"y":291.93,"z":386.84},{"x":-126.63,"y":292.41,"z":385.22}]},{"lat":-36.94,"lon":74.33,"b":[{"x":-111.78,"y":301,"z":383.2},{"x":-108.63,"y":303.78,"z":381.91},{"x":-104.85,"y":303.17,"z":383.44},{"x":-104.21,"y":299.83,"z":386.24},{"x":-107.31,"y":297.06,"z":387.53},{"x":-111.1,"y":297.62,"z":386.02}]},{"lat":-37.61,"lon":76.46,"b":[{"x":-96.48,"y":305.74,"z":383.61},{"x":-93.38,"y":308.4,"z":382.24},{"x":-89.69,"y":307.71,"z":383.68},{"x":-89.07,"y":304.42,"z":386.44},{"x":-92.12,"y":301.76,"z":387.8},{"x":-95.84,"y":302.39,"z":386.41}]},{"lat":-38.22,"lon":78.57,"b":[{"x":-81.49,"y":310.05,"z":383.63},{"x":-78.44,"y":312.59,"z":382.2},{"x":-74.84,"y":311.84,"z":383.53},{"x":-74.26,"y":308.59,"z":386.27},{"x":-77.25,"y":306.04,"z":387.7},{"x":-80.87,"y":306.75,"z":386.4}]},{"lat":-38.78,"lon":80.66,"b":[{"x":-66.83,"y":313.95,"z":383.3},{"x":-63.85,"y":316.38,"z":381.8},{"x":-60.34,"y":315.56,"z":383.05},{"x":-59.8,"y":312.36,"z":385.75},{"x":-62.72,"y":309.93,"z":387.24},{"x":-66.25,"y":310.7,"z":386.03}]},{"lat":-8.58,"lon":30.53,"b":[{"x":-427.92,"y":73.91,"z":247.72},{"x":-426.97,"y":77.44,"z":248.28},{"x":-424.84,"y":78.13,"z":251.69},{"x":-423.68,"y":75.23,"z":254.52},{"x":-424.66,"y":71.7,"z":253.91},{"x":-426.77,"y":71.06,"z":250.53}]},{"lat":-9.67,"lon":31.84,"b":[{"x":-420.92,"y":83.32,"z":256.58},{"x":-419.84,"y":86.93,"z":257.13},{"x":-417.58,"y":87.64,"z":260.56},{"x":-416.4,"y":84.68,"z":263.41},{"x":-417.5,"y":81.07,"z":262.8},{"x":-419.75,"y":80.42,"z":259.4}]},{"lat":-10.79,"lon":33.2,"b":[{"x":-413.32,"y":92.93,"z":265.46},{"x":-412.12,"y":96.62,"z":266},{"x":-409.71,"y":97.34,"z":269.45},{"x":-408.52,"y":94.32,"z":272.31},{"x":-409.75,"y":90.64,"z":271.71},{"x":-412.14,"y":89.97,"z":268.3}]},{"lat":-11.94,"lon":34.6,"b":[{"x":-405.12,"y":102.73,"z":274.33},{"x":-403.79,"y":106.49,"z":274.87},{"x":-401.23,"y":107.21,"z":278.31},{"x":-400.03,"y":104.13,"z":281.19},{"x":-401.4,"y":100.39,"z":280.61},{"x":-403.93,"y":99.71,"z":277.2}]},{"lat":-13.11,"lon":36.06,"b":[{"x":-396.3,"y":112.68,"z":283.17},{"x":-394.83,"y":116.5,"z":283.68},{"x":-392.12,"y":117.22,"z":287.12},{"x":-390.91,"y":114.08,"z":290.01},{"x":-392.42,"y":110.29,"z":289.45},{"x":-395.1,"y":109.61,"z":286.05}]},{"lat":-14.3,"lon":37.56,"b":[{"x":-386.84,"y":122.76,"z":291.93},{"x":-385.22,"y":126.63,"z":292.41},{"x":-382.37,"y":127.35,"z":295.82},{"x":-381.16,"y":124.15,"z":298.72},{"x":-382.8,"y":120.3,"z":298.2},{"x":-385.63,"y":119.63,"z":294.82}]},{"lat":-15.5,"lon":39.12,"b":[{"x":-376.05,"y":133.1,"z":301.35},{"x":-374.7,"y":136.1,"z":301.69},{"x":-372.4,"y":136.64,"z":304.29},{"x":-371.47,"y":134.15,"z":306.52},{"x":-372.85,"y":131.16,"z":306.15},{"x":-375.13,"y":130.65,"z":303.58}]},{"lat":-17.95,"lon":42.38,"b":[{"x":-354.53,"y":153.43,"z":317.33},{"x":-352.51,"y":157.33,"z":317.66},{"x":-349.29,"y":157.97,"z":320.89},{"x":-348.11,"y":154.68,"z":323.76},{"x":-350.15,"y":150.8,"z":323.39},{"x":-353.35,"y":150.19,"z":320.19}]},{"lat":-19.18,"lon":44.08,"b":[{"x":-342.57,"y":163.64,"z":325.26},{"x":-340.37,"y":167.63,"z":325.53},{"x":-336.96,"y":168.24,"z":328.76},{"x":-335.78,"y":164.85,"z":331.67},{"x":-337.99,"y":160.89,"z":331.36},{"x":-341.37,"y":160.3,"z":328.17}]},{"lat":-20.41,"lon":45.83,"b":[{"x":-329.95,"y":173.8,"z":332.94},{"x":-327.61,"y":177.79,"z":333.15},{"x":-324.08,"y":178.35,"z":336.29},{"x":-322.91,"y":174.92,"z":339.2},{"x":-325.26,"y":170.96,"z":338.97},{"x":-328.76,"y":170.41,"z":335.86}]},{"lat":-21.64,"lon":47.63,"b":[{"x":-316.75,"y":183.85,"z":340.28},{"x":-314.28,"y":187.82,"z":340.4},{"x":-310.63,"y":188.33,"z":343.46},{"x":-309.49,"y":184.86,"z":346.36},{"x":-311.97,"y":180.92,"z":346.22},{"x":-315.59,"y":180.42,"z":343.19}]},{"lat":-22.86,"lon":49.48,"b":[{"x":-303.02,"y":193.74,"z":347.23},{"x":-300.43,"y":197.68,"z":347.26},{"x":-296.67,"y":198.13,"z":350.22},{"x":-295.55,"y":194.63,"z":353.12},{"x":-298.15,"y":190.72,"z":353.06},{"x":-301.88,"y":190.27,"z":350.13}]},{"lat":-24.06,"lon":51.37,"b":[{"x":-288.06,"y":203.5,"z":354.32},{"x":-285.88,"y":206.65,"z":354.27},{"x":-282.79,"y":206.95,"z":356.56},{"x":-281.91,"y":204.12,"z":358.88},{"x":-284.09,"y":201,"z":358.92},{"x":-287.16,"y":200.69,"z":356.65}]},{"lat":-26.4,"lon":55.27,"b":[{"x":-257.48,"y":222.13,"z":366.48},{"x":-255.76,"y":224.37,"z":366.32},{"x":-253.41,"y":224.51,"z":367.87},{"x":-252.8,"y":222.41,"z":369.56},{"x":-254.52,"y":220.19,"z":369.71},{"x":-256.85,"y":220.04,"z":368.18}]},{"lat":-27.52,"lon":57.27,"b":[{"x":-243.72,"y":230.86,"z":370.44},{"x":-240.72,"y":234.58,"z":370.06},{"x":-236.71,"y":234.72,"z":372.56},{"x":-235.71,"y":231.16,"z":375.4},{"x":-238.69,"y":227.47,"z":375.78},{"x":-242.69,"y":227.3,"z":373.31}]},{"lat":-28.61,"lon":59.3,"b":[{"x":-228.1,"y":239.34,"z":374.98},{"x":-225.03,"y":242.98,"z":374.49},{"x":-220.99,"y":243.03,"z":376.86},{"x":-220.03,"y":239.47,"z":379.69},{"x":-223.08,"y":235.86,"z":380.17},{"x":-227.1,"y":235.78,"z":377.83}]},{"lat":-29.66,"lon":61.36,"b":[{"x":-212.29,"y":247.44,"z":378.99},{"x":-209.17,"y":250.99,"z":378.39},{"x":-205.12,"y":250.95,"z":380.62},{"x":-204.2,"y":247.4,"z":383.44},{"x":-207.29,"y":243.88,"z":384.03},{"x":-211.33,"y":243.88,"z":381.82}]},{"lat":-30.67,"lon":63.43,"b":[{"x":-196.36,"y":255.13,"z":382.46},{"x":-193.2,"y":258.59,"z":381.75},{"x":-189.16,"y":258.46,"z":383.86},{"x":-188.28,"y":254.91,"z":386.65},{"x":-191.4,"y":251.49,"z":387.36},{"x":-195.44,"y":251.58,"z":385.27}]},{"lat":-31.63,"lon":65.53,"b":[{"x":-180.38,"y":262.41,"z":385.4},{"x":-177.2,"y":265.75,"z":384.58},{"x":-173.18,"y":265.53,"z":386.56},{"x":-172.34,"y":262.01,"z":389.33},{"x":-175.48,"y":258.69,"z":390.15},{"x":-179.5,"y":258.86,"z":388.2}]},{"lat":-32.55,"lon":67.63,"b":[{"x":-164.41,"y":269.25,"z":387.82},{"x":-161.23,"y":272.48,"z":386.9},{"x":-157.24,"y":272.17,"z":388.75},{"x":-156.44,"y":268.67,"z":391.5},{"x":-159.59,"y":265.46,"z":392.42},{"x":-163.58,"y":265.72,"z":390.59}]},{"lat":-33.41,"lon":69.73,"b":[{"x":-148.53,"y":275.64,"z":389.73},{"x":-145.34,"y":278.77,"z":388.71},{"x":-141.41,"y":278.37,"z":390.44},{"x":-140.65,"y":274.9,"z":393.17},{"x":-143.79,"y":271.8,"z":394.19},{"x":-147.73,"y":272.14,"z":392.48}]},{"lat":-34.22,"lon":71.84,"b":[{"x":-132.78,"y":281.6,"z":391.16},{"x":-129.61,"y":284.61,"z":390.04},{"x":-125.74,"y":284.13,"z":391.65},{"x":-125.02,"y":280.69,"z":394.36},{"x":-128.13,"y":277.7,"z":395.47},{"x":-132.02,"y":278.13,"z":393.89}]},{"lat":-34.98,"lon":73.93,"b":[{"x":-117.22,"y":287.12,"z":392.12},{"x":-114.08,"y":290.01,"z":390.91},{"x":-110.29,"y":289.45,"z":392.42},{"x":-109.61,"y":286.05,"z":395.1},{"x":-112.68,"y":283.17,"z":396.3},{"x":-116.5,"y":283.68,"z":394.83}]},{"lat":-35.68,"lon":76.02,"b":[{"x":-101.9,"y":292.2,"z":392.65},{"x":-98.81,"y":294.98,"z":391.36},{"x":-95.09,"y":294.34,"z":392.76},{"x":-94.44,"y":290.98,"z":395.41},{"x":-97.48,"y":288.22,"z":396.69},{"x":-101.22,"y":288.8,"z":395.33}]},{"lat":-36.33,"lon":78.08,"b":[{"x":-86.86,"y":296.87,"z":392.77},{"x":-83.82,"y":299.53,"z":391.4},{"x":-80.19,"y":298.82,"z":392.7},{"x":-79.58,"y":295.51,"z":395.33},{"x":-82.57,"y":292.86,"z":396.68},{"x":-86.22,"y":293.51,"z":395.42}]},{"lat":-36.93,"lon":80.12,"b":[{"x":-72.14,"y":301.13,"z":392.51},{"x":-69.16,"y":303.67,"z":391.08},{"x":-65.62,"y":302.9,"z":392.29},{"x":-65.05,"y":299.64,"z":394.88},{"x":-67.97,"y":297.09,"z":396.3},{"x":-71.54,"y":297.81,"z":395.13}]},{"lat":-37.48,"lon":82.14,"b":[{"x":-57.77,"y":304.99,"z":391.9},{"x":-54.85,"y":307.43,"z":390.41},{"x":-51.42,"y":306.6,"z":391.54},{"x":-50.88,"y":303.38,"z":394.11},{"x":-53.74,"y":300.95,"z":395.59},{"x":-57.2,"y":301.73,"z":394.5}]},{"lat":-6.95,"lon":31.04,"b":[{"x":-427.3,"y":59.87,"z":252.55},{"x":-426.43,"y":63.32,"z":253.16},{"x":-424.32,"y":63.96,"z":256.54},{"x":-423.08,"y":61.11,"z":259.26},{"x":-423.97,"y":57.67,"z":258.59},{"x":-426.07,"y":57.08,"z":255.25}]},{"lat":-8,"lon":32.34,"b":[{"x":-420.52,"y":68.98,"z":261.44},{"x":-419.54,"y":72.5,"z":262.05},{"x":-417.29,"y":73.16,"z":265.45},{"x":-416.03,"y":70.25,"z":268.19},{"x":-417.04,"y":66.74,"z":267.52},{"x":-419.28,"y":66.12,"z":264.16}]},{"lat":-9.08,"lon":33.68,"b":[{"x":-413.17,"y":78.29,"z":270.37},{"x":-412.07,"y":81.9,"z":270.98},{"x":-409.68,"y":82.56,"z":274.39},{"x":-408.41,"y":79.59,"z":277.15},{"x":-409.54,"y":76,"z":276.48},{"x":-411.92,"y":75.38,"z":273.11}]},{"lat":-10.19,"lon":35.07,"b":[{"x":-405.24,"y":87.8,"z":279.31},{"x":-404,"y":91.48,"z":279.91},{"x":-401.47,"y":92.15,"z":283.32},{"x":-400.19,"y":89.12,"z":286.09},{"x":-401.45,"y":85.46,"z":285.43},{"x":-403.97,"y":84.83,"z":282.06}]},{"lat":-11.32,"lon":36.5,"b":[{"x":-396.69,"y":97.48,"z":288.22},{"x":-395.33,"y":101.22,"z":288.8},{"x":-392.65,"y":101.9,"z":292.2},{"x":-391.36,"y":98.81,"z":294.98},{"x":-392.76,"y":95.09,"z":294.34},{"x":-395.41,"y":94.44,"z":290.98}]},{"lat":-12.47,"lon":37.98,"b":[{"x":-387.53,"y":107.31,"z":297.06},{"x":-386.02,"y":111.1,"z":297.62},{"x":-383.2,"y":111.78,"z":301},{"x":-381.91,"y":108.63,"z":303.78},{"x":-383.44,"y":104.85,"z":303.17},{"x":-386.24,"y":104.21,"z":299.83}]},{"lat":-13.64,"lon":39.51,"b":[{"x":-377.73,"y":117.25,"z":305.79},{"x":-376.09,"y":121.1,"z":306.31},{"x":-373.12,"y":121.76,"z":309.66},{"x":-371.82,"y":118.55,"z":312.45},{"x":-373.5,"y":114.73,"z":311.88},{"x":-376.44,"y":114.09,"z":308.57}]},{"lat":-16.02,"lon":42.72,"b":[{"x":-354.34,"y":137.72,"z":324.72},{"x":-353.57,"y":139.28,"z":324.89},{"x":-352.28,"y":139.52,"z":326.19},{"x":-351.77,"y":138.21,"z":327.29},{"x":-352.55,"y":136.66,"z":327.11},{"x":-353.83,"y":136.42,"z":325.83}]},{"lat":-17.22,"lon":44.39,"b":[{"x":-344.56,"y":147.42,"z":330.86},{"x":-342.49,"y":151.36,"z":331.24},{"x":-339.11,"y":151.96,"z":334.43},{"x":-337.84,"y":148.59,"z":337.21},{"x":-339.94,"y":144.68,"z":336.81},{"x":-343.28,"y":144.1,"z":333.65}]},{"lat":-18.42,"lon":46.11,"b":[{"x":-332.28,"y":157.46,"z":338.7},{"x":-330.07,"y":161.42,"z":339.01},{"x":-326.56,"y":161.97,"z":342.12},{"x":-325.31,"y":158.56,"z":344.9},{"x":-327.55,"y":154.64,"z":344.57},{"x":-331.02,"y":154.1,"z":341.48}]},{"lat":-19.63,"lon":47.87,"b":[{"x":-319.43,"y":167.43,"z":346.21},{"x":-317.07,"y":171.38,"z":346.44},{"x":-313.46,"y":171.89,"z":349.46},{"x":-312.23,"y":168.44,"z":352.23},{"x":-314.59,"y":164.52,"z":351.98},{"x":-318.18,"y":164.02,"z":348.98}]},{"lat":-20.82,"lon":49.68,"b":[{"x":-306.03,"y":177.28,"z":353.33},{"x":-303.55,"y":181.22,"z":353.48},{"x":-299.82,"y":181.67,"z":356.41},{"x":-298.62,"y":178.18,"z":359.17},{"x":-301.11,"y":174.28,"z":359.01},{"x":-304.8,"y":173.83,"z":356.1}]},{"lat":-22.01,"lon":51.53,"b":[{"x":-292.12,"y":186.96,"z":360.04},{"x":-289.52,"y":190.87,"z":360.09},{"x":-285.71,"y":191.26,"z":362.92},{"x":-284.54,"y":187.75,"z":365.67},{"x":-287.14,"y":183.87,"z":365.6},{"x":-290.92,"y":183.48,"z":362.8}]},{"lat":-23.18,"lon":53.42,"b":[{"x":-277.46,"y":196.47,"z":366.53},{"x":-274.96,"y":200.03,"z":366.49},{"x":-271.39,"y":200.33,"z":368.98},{"x":-270.34,"y":197.07,"z":371.5},{"x":-272.83,"y":193.55,"z":371.53},{"x":-276.38,"y":193.24,"z":369.06}]},{"lat":-24.33,"lon":55.34,"b":[{"x":-262.1,"y":205.74,"z":372.7},{"x":-259.94,"y":208.68,"z":372.59},{"x":-256.91,"y":208.87,"z":374.58},{"x":-256.06,"y":206.14,"z":376.67},{"x":-258.21,"y":203.23,"z":376.78},{"x":-261.23,"y":203.02,"z":374.81}]},{"lat":-25.45,"lon":57.29,"b":[{"x":-244.76,"y":214.8,"z":379.39},{"x":-244.17,"y":215.57,"z":379.33},{"x":-243.35,"y":215.6,"z":379.84},{"x":-243.13,"y":214.87,"z":380.4},{"x":-243.72,"y":214.1,"z":380.45},{"x":-244.54,"y":214.07,"z":379.95}]},{"lat":-26.54,"lon":59.28,"b":[{"x":-232.52,"y":223.26,"z":382.11},{"x":-229.54,"y":226.95,"z":381.74},{"x":-225.52,"y":227.03,"z":384.08},{"x":-224.49,"y":223.46,"z":386.78},{"x":-227.45,"y":219.81,"z":387.14},{"x":-231.46,"y":219.69,"z":384.82}]},{"lat":-27.59,"lon":61.28,"b":[{"x":-216.93,"y":231.55,"z":386.33},{"x":-213.89,"y":235.16,"z":385.85},{"x":-209.85,"y":235.15,"z":388.06},{"x":-208.86,"y":231.58,"z":390.74},{"x":-211.88,"y":228,"z":391.22},{"x":-215.9,"y":227.97,"z":389.03}]},{"lat":-28.61,"lon":63.31,"b":[{"x":-201.18,"y":239.46,"z":390.01},{"x":-198.1,"y":242.98,"z":389.42},{"x":-194.06,"y":242.89,"z":391.5},{"x":-193.12,"y":239.32,"z":394.16},{"x":-196.17,"y":235.84,"z":394.75},{"x":-200.2,"y":235.88,"z":392.69}]},{"lat":-29.59,"lon":65.35,"b":[{"x":-185.36,"y":246.98,"z":393.16},{"x":-182.24,"y":250.4,"z":392.45},{"x":-178.22,"y":250.22,"z":394.4},{"x":-177.32,"y":246.67,"z":397.04},{"x":-180.4,"y":243.28,"z":397.74},{"x":-184.42,"y":243.41,"z":395.81}]},{"lat":-30.52,"lon":67.4,"b":[{"x":-169.52,"y":254.09,"z":395.77},{"x":-166.38,"y":257.41,"z":394.95},{"x":-162.39,"y":257.15,"z":396.78},{"x":-161.54,"y":253.61,"z":399.4},{"x":-164.63,"y":250.32,"z":400.21},{"x":-168.62,"y":250.53,"z":398.41}]},{"lat":-31.4,"lon":69.46,"b":[{"x":-153.73,"y":260.78,"z":397.86},{"x":-150.58,"y":263.99,"z":396.94},{"x":-146.64,"y":263.65,"z":398.65},{"x":-145.83,"y":260.13,"z":401.24},{"x":-148.93,"y":256.95,"z":402.16},{"x":-152.88,"y":257.24,"z":400.48}]},{"lat":-32.23,"lon":71.51,"b":[{"x":-138.04,"y":267.05,"z":399.45},{"x":-134.91,"y":270.15,"z":398.43},{"x":-131.02,"y":269.72,"z":400.02},{"x":-130.26,"y":266.24,"z":402.6},{"x":-133.34,"y":263.16,"z":403.61},{"x":-137.24,"y":263.54,"z":402.05}]},{"lat":-33.02,"lon":73.56,"b":[{"x":-122.52,"y":272.89,"z":400.57},{"x":-119.41,"y":275.88,"z":399.46},{"x":-115.59,"y":275.37,"z":400.93},{"x":-114.87,"y":271.93,"z":403.49},{"x":-117.92,"y":268.95,"z":404.59},{"x":-121.76,"y":269.41,"z":403.15}]},{"lat":-33.75,"lon":75.59,"b":[{"x":-107.21,"y":278.31,"z":401.23},{"x":-104.13,"y":281.19,"z":400.03},{"x":-100.39,"y":280.61,"z":401.4},{"x":-99.71,"y":277.2,"z":403.93},{"x":-102.73,"y":274.33,"z":405.12},{"x":-106.49,"y":274.87,"z":403.79}]},{"lat":-34.43,"lon":77.61,"b":[{"x":-92.15,"y":283.32,"z":401.47},{"x":-89.12,"y":286.09,"z":400.19},{"x":-85.46,"y":285.43,"z":401.45},{"x":-84.83,"y":282.06,"z":403.97},{"x":-87.8,"y":279.31,"z":405.24},{"x":-91.48,"y":279.91,"z":404}]},{"lat":-35.07,"lon":79.61,"b":[{"x":-77.39,"y":287.93,"z":401.31},{"x":-74.41,"y":290.58,"z":399.96},{"x":-70.85,"y":289.86,"z":401.13},{"x":-70.25,"y":286.54,"z":403.62},{"x":-73.17,"y":283.89,"z":404.96},{"x":-76.76,"y":284.56,"z":403.82}]},{"lat":-35.65,"lon":81.59,"b":[{"x":-62.96,"y":292.14,"z":400.79},{"x":-60.04,"y":294.69,"z":399.37},{"x":-56.58,"y":293.91,"z":400.45},{"x":-56.01,"y":290.63,"z":402.92},{"x":-58.88,"y":288.09,"z":404.33},{"x":-62.36,"y":288.82,"z":403.28}]},{"lat":-36.19,"lon":83.53,"b":[{"x":-48.89,"y":295.99,"z":399.94},{"x":-46.03,"y":298.42,"z":398.46},{"x":-42.67,"y":297.59,"z":399.46},{"x":-42.14,"y":294.37,"z":401.9},{"x":-44.94,"y":291.93,"z":403.36},{"x":-48.33,"y":292.72,"z":402.4}]},{"lat":-5.36,"lon":31.53,"b":[{"x":-426.33,"y":46.17,"z":257.03},{"x":-425.55,"y":49.52,"z":257.69},{"x":-423.44,"y":50.11,"z":261.03},{"x":-422.13,"y":47.31,"z":263.65},{"x":-422.95,"y":43.98,"z":262.92},{"x":-425.04,"y":43.43,"z":259.63}]},{"lat":-6.38,"lon":32.82,"b":[{"x":-419.76,"y":54.96,"z":265.95},{"x":-418.87,"y":58.39,"z":266.62},{"x":-416.63,"y":59,"z":269.97},{"x":-415.31,"y":56.14,"z":272.61},{"x":-416.23,"y":52.73,"z":271.88},{"x":-418.45,"y":52.16,"z":268.57}]},{"lat":-7.42,"lon":34.14,"b":[{"x":-412.65,"y":63.96,"z":274.91},{"x":-411.63,"y":67.47,"z":275.58},{"x":-409.26,"y":68.1,"z":278.95},{"x":-407.92,"y":65.18,"z":281.6},{"x":-408.97,"y":61.69,"z":280.87},{"x":-411.32,"y":61.1,"z":277.55}]},{"lat":-8.49,"lon":35.51,"b":[{"x":-404.96,"y":73.17,"z":283.89},{"x":-403.82,"y":76.76,"z":284.56},{"x":-401.31,"y":77.39,"z":287.93},{"x":-399.96,"y":74.41,"z":290.58},{"x":-401.13,"y":70.85,"z":289.86},{"x":-403.62,"y":70.25,"z":286.54}]},{"lat":-9.58,"lon":36.93,"b":[{"x":-396.68,"y":82.57,"z":292.86},{"x":-395.42,"y":86.22,"z":293.51},{"x":-392.77,"y":86.86,"z":296.87},{"x":-391.4,"y":83.82,"z":299.53},{"x":-392.7,"y":80.19,"z":298.82},{"x":-395.33,"y":79.58,"z":295.51}]},{"lat":-10.69,"lon":38.39,"b":[{"x":-387.8,"y":92.12,"z":301.76},{"x":-386.41,"y":95.84,"z":302.39},{"x":-383.61,"y":96.48,"z":305.74},{"x":-382.24,"y":93.38,"z":308.4},{"x":-383.68,"y":89.69,"z":307.71},{"x":-386.44,"y":89.07,"z":304.42}]},{"lat":-11.82,"lon":39.9,"b":[{"x":-378.31,"y":101.81,"z":310.57},{"x":-376.77,"y":105.58,"z":311.17},{"x":-373.84,"y":106.22,"z":314.48},{"x":-372.47,"y":103.06,"z":317.15},{"x":-374.04,"y":99.31,"z":316.5},{"x":-376.94,"y":98.7,"z":313.23}]},{"lat":-12.97,"lon":41.45,"b":[{"x":-368.2,"y":111.6,"z":319.23},{"x":-366.52,"y":115.43,"z":319.8},{"x":-363.44,"y":116.05,"z":323.07},{"x":-362.08,"y":112.83,"z":325.73},{"x":-363.79,"y":109.04,"z":325.12},{"x":-366.83,"y":108.44,"z":321.89}]},{"lat":-14.13,"lon":43.05,"b":[{"x":-355.71,"y":121.81,"z":329.54},{"x":-354.91,"y":123.5,"z":329.77},{"x":-353.5,"y":123.77,"z":331.18},{"x":-352.91,"y":122.33,"z":332.35},{"x":-353.72,"y":120.65,"z":332.1},{"x":-355.11,"y":120.4,"z":330.71}]},{"lat":-15.3,"lon":44.69,"b":[{"x":-346.12,"y":131.37,"z":335.97},{"x":-344.16,"y":135.26,"z":336.43},{"x":-340.82,"y":135.84,"z":339.59},{"x":-339.47,"y":132.51,"z":342.24},{"x":-341.46,"y":128.66,"z":341.74},{"x":-344.76,"y":128.1,"z":338.62}]},{"lat":-16.48,"lon":46.38,"b":[{"x":-334.18,"y":141.27,"z":343.94},{"x":-332.08,"y":145.18,"z":344.35},{"x":-328.61,"y":145.73,"z":347.43},{"x":-327.28,"y":142.35,"z":350.07},{"x":-329.4,"y":138.48,"z":349.64},{"x":-332.83,"y":137.94,"z":346.59}]},{"lat":-17.66,"lon":48.1,"b":[{"x":-321.66,"y":151.13,"z":351.6},{"x":-319.43,"y":155.05,"z":351.93},{"x":-315.84,"y":155.55,"z":354.93},{"x":-314.54,"y":152.13,"z":357.56},{"x":-316.79,"y":148.25,"z":357.2},{"x":-320.33,"y":147.75,"z":354.24}]},{"lat":-18.83,"lon":49.87,"b":[{"x":-308.6,"y":160.9,"z":358.89},{"x":-306.23,"y":164.82,"z":359.14},{"x":-302.55,"y":165.27,"z":362.05},{"x":-301.27,"y":161.81,"z":364.67},{"x":-303.64,"y":157.94,"z":364.4},{"x":-307.29,"y":157.48,"z":361.52}]},{"lat":-20,"lon":51.68,"b":[{"x":-295.03,"y":170.55,"z":365.78},{"x":-292.54,"y":174.45,"z":365.94},{"x":-288.76,"y":174.85,"z":368.74},{"x":-287.51,"y":171.35,"z":371.35},{"x":-290,"y":167.5,"z":371.17},{"x":-293.75,"y":167.09,"z":368.4}]},{"lat":-21.15,"lon":53.53,"b":[{"x":-280.99,"y":180.03,"z":372.23},{"x":-278.38,"y":183.91,"z":372.3},{"x":-274.52,"y":184.24,"z":374.99},{"x":-273.31,"y":180.72,"z":377.58},{"x":-275.92,"y":176.89,"z":377.51},{"x":-279.74,"y":176.54,"z":374.84}]},{"lat":-22.29,"lon":55.41,"b":[{"x":-266.53,"y":189.31,"z":378.22},{"x":-263.82,"y":193.14,"z":378.18},{"x":-259.9,"y":193.41,"z":380.75},{"x":-258.72,"y":189.86,"z":383.33},{"x":-261.43,"y":186.07,"z":383.36},{"x":-265.32,"y":185.78,"z":380.81}]},{"lat":-23.4,"lon":57.32,"b":[{"x":-250.35,"y":198.42,"z":384.58},{"x":-248.52,"y":200.88,"z":384.49},{"x":-245.93,"y":201.01,"z":386.08},{"x":-245.19,"y":198.69,"z":387.75},{"x":-247.01,"y":196.25,"z":387.84},{"x":-249.58,"y":196.11,"z":386.26}]},{"lat":-25.54,"lon":61.21,"b":[{"x":-220.96,"y":215.53,"z":393.26},{"x":-218.21,"y":218.92,"z":392.92},{"x":-214.47,"y":218.96,"z":394.96},{"x":-213.49,"y":215.63,"z":397.31},{"x":-216.22,"y":212.27,"z":397.65},{"x":-219.94,"y":212.2,"z":395.63}]},{"lat":-26.57,"lon":63.19,"b":[{"x":-205.71,"y":223.62,"z":397},{"x":-202.69,"y":227.19,"z":396.52},{"x":-198.67,"y":227.14,"z":398.58},{"x":-197.67,"y":223.57,"z":401.09},{"x":-200.65,"y":220.03,"z":401.57},{"x":-204.66,"y":220.04,"z":399.53}]},{"lat":-27.55,"lon":65.18,"b":[{"x":-190.06,"y":231.35,"z":400.35},{"x":-187.01,"y":234.84,"z":399.76},{"x":-183,"y":234.71,"z":401.69},{"x":-182.04,"y":231.14,"z":404.19},{"x":-185.06,"y":227.69,"z":404.77},{"x":-189.06,"y":227.77,"z":402.87}]},{"lat":-28.5,"lon":67.19,"b":[{"x":-174.38,"y":238.71,"z":403.17},{"x":-171.3,"y":242.1,"z":402.46},{"x":-167.31,"y":241.88,"z":404.26},{"x":-166.41,"y":238.33,"z":406.75},{"x":-169.44,"y":234.97,"z":407.44},{"x":-173.43,"y":235.14,"z":405.66}]},{"lat":-29.4,"lon":69.19,"b":[{"x":-158.71,"y":245.67,"z":405.45},{"x":-155.61,"y":248.96,"z":404.64},{"x":-151.67,"y":248.66,"z":406.32},{"x":-150.81,"y":245.12,"z":408.79},{"x":-153.86,"y":241.86,"z":409.59},{"x":-157.8,"y":242.11,"z":407.94}]},{"lat":-30.25,"lon":71.2,"b":[{"x":-143.11,"y":252.22,"z":407.23},{"x":-140.02,"y":255.41,"z":406.32},{"x":-136.13,"y":255.03,"z":407.87},{"x":-135.32,"y":251.52,"z":410.32},{"x":-138.36,"y":248.36,"z":411.23},{"x":-142.26,"y":248.68,"z":409.7}]},{"lat":-31.06,"lon":73.2,"b":[{"x":-127.66,"y":258.37,"z":408.52},{"x":-124.58,"y":261.45,"z":407.5},{"x":-120.74,"y":260.99,"z":408.95},{"x":-119.99,"y":257.51,"z":411.38},{"x":-123.01,"y":254.46,"z":412.38},{"x":-126.85,"y":254.86,"z":410.96}]},{"lat":-31.82,"lon":75.19,"b":[{"x":-112.38,"y":264.11,"z":409.34},{"x":-109.33,"y":267.08,"z":408.23},{"x":-105.57,"y":266.55,"z":409.56},{"x":-104.86,"y":263.11,"z":411.97},{"x":-107.85,"y":260.15,"z":413.07},{"x":-111.62,"y":260.63,"z":411.76}]},{"lat":-32.53,"lon":77.17,"b":[{"x":-97.34,"y":269.45,"z":409.71},{"x":-94.32,"y":272.31,"z":408.52},{"x":-90.64,"y":271.71,"z":409.75},{"x":-89.97,"y":268.3,"z":412.14},{"x":-92.93,"y":265.46,"z":413.32},{"x":-96.62,"y":266,"z":412.12}]},{"lat":-33.2,"lon":79.13,"b":[{"x":-82.56,"y":274.39,"z":409.68},{"x":-79.59,"y":277.15,"z":408.41},{"x":-76,"y":276.48,"z":409.54},{"x":-75.38,"y":273.11,"z":411.92},{"x":-78.29,"y":270.37,"z":413.17},{"x":-81.9,"y":270.98,"z":412.07}]},{"lat":-33.82,"lon":81.06,"b":[{"x":-68.1,"y":278.95,"z":409.26},{"x":-65.18,"y":281.6,"z":407.92},{"x":-61.69,"y":280.87,"z":408.97},{"x":-61.1,"y":277.55,"z":411.32},{"x":-63.96,"y":274.91,"z":412.65},{"x":-67.47,"y":275.58,"z":411.63}]},{"lat":-34.39,"lon":82.97,"b":[{"x":-53.97,"y":283.14,"z":408.5},{"x":-51.11,"y":285.68,"z":407.09},{"x":-47.72,"y":284.89,"z":408.05},{"x":-47.17,"y":281.62,"z":410.39},{"x":-49.97,"y":279.09,"z":411.78},{"x":-53.38,"y":279.82,"z":410.85}]},{"lat":-34.91,"lon":84.84,"b":[{"x":-40.2,"y":286.97,"z":407.41},{"x":-37.4,"y":289.4,"z":405.95},{"x":-34.12,"y":288.56,"z":406.84},{"x":-33.61,"y":285.35,"z":409.15},{"x":-36.34,"y":282.91,"z":410.59},{"x":-39.65,"y":283.7,"z":409.74}]},{"lat":-3.82,"lon":32.01,"b":[{"x":-425.04,"y":32.81,"z":261.17},{"x":-424.34,"y":36.06,"z":261.89},{"x":-422.25,"y":36.61,"z":265.18},{"x":-420.88,"y":33.87,"z":267.7},{"x":-421.62,"y":30.64,"z":266.93},{"x":-423.69,"y":30.13,"z":263.69}]},{"lat":-4.8,"lon":33.28,"b":[{"x":-418.67,"y":41.28,"z":270.1},{"x":-417.86,"y":44.61,"z":270.83},{"x":-415.64,"y":45.18,"z":274.14},{"x":-414.25,"y":42.38,"z":276.67},{"x":-415.1,"y":39.07,"z":275.89},{"x":-417.3,"y":38.54,"z":272.63}]},{"lat":-5.8,"lon":34.59,"b":[{"x":-411.78,"y":49.97,"z":279.09},{"x":-410.85,"y":53.38,"z":279.82},{"x":-408.5,"y":53.97,"z":283.14},{"x":-407.09,"y":51.11,"z":285.68},{"x":-408.05,"y":47.72,"z":284.89},{"x":-410.39,"y":47.17,"z":281.62}]},{"lat":-6.83,"lon":35.94,"b":[{"x":-404.33,"y":58.88,"z":288.09},{"x":-403.28,"y":62.36,"z":288.82},{"x":-400.79,"y":62.96,"z":292.14},{"x":-399.37,"y":60.04,"z":294.69},{"x":-400.45,"y":56.58,"z":293.91},{"x":-402.92,"y":56.01,"z":290.63}]},{"lat":-7.88,"lon":37.34,"b":[{"x":-396.3,"y":67.97,"z":297.09},{"x":-395.13,"y":71.54,"z":297.81},{"x":-392.51,"y":72.14,"z":301.13},{"x":-391.08,"y":69.16,"z":303.67},{"x":-392.29,"y":65.62,"z":302.9},{"x":-394.88,"y":65.05,"z":299.64}]},{"lat":-8.96,"lon":38.78,"b":[{"x":-387.7,"y":77.25,"z":306.04},{"x":-386.4,"y":80.87,"z":306.75},{"x":-383.63,"y":81.49,"z":310.05},{"x":-382.2,"y":78.44,"z":312.59},{"x":-383.53,"y":74.84,"z":311.84},{"x":-386.27,"y":74.26,"z":308.59}]},{"lat":-10.05,"lon":40.26,"b":[{"x":-378.49,"y":86.67,"z":314.91},{"x":-377.06,"y":90.36,"z":315.59},{"x":-374.16,"y":90.97,"z":318.86},{"x":-372.72,"y":87.86,"z":321.4},{"x":-374.19,"y":84.2,"z":320.68},{"x":-377.06,"y":83.62,"z":317.45}]},{"lat":-11.16,"lon":41.79,"b":[{"x":-368.68,"y":96.22,"z":323.65},{"x":-367.11,"y":99.96,"z":324.3},{"x":-364.07,"y":100.56,"z":327.53},{"x":-362.64,"y":97.39,"z":330.07},{"x":-364.24,"y":93.68,"z":329.38},{"x":-367.25,"y":93.11,"z":326.19}]},{"lat":-12.29,"lon":43.36,"b":[{"x":-356.94,"y":106.11,"z":333.6},{"x":-355.97,"y":108.27,"z":333.95},{"x":-354.16,"y":108.6,"z":335.76},{"x":-353.34,"y":106.76,"z":337.2},{"x":-354.34,"y":104.62,"z":336.84},{"x":-356.13,"y":104.3,"z":335.05}]},{"lat":-13.43,"lon":44.97,"b":[{"x":-347.25,"y":115.56,"z":340.58},{"x":-345.41,"y":119.39,"z":341.13},{"x":-342.1,"y":119.95,"z":344.25},{"x":-340.69,"y":116.67,"z":346.77},{"x":-342.56,"y":112.89,"z":346.18},{"x":-345.83,"y":112.34,"z":343.1}]},{"lat":-14.58,"lon":46.63,"b":[{"x":-335.65,"y":125.29,"z":348.67},{"x":-333.66,"y":129.15,"z":349.17},{"x":-330.24,"y":129.68,"z":352.22},{"x":-328.84,"y":126.35,"z":354.73},{"x":-330.85,"y":122.54,"z":354.2},{"x":-334.23,"y":122.01,"z":351.19}]},{"lat":-15.73,"lon":48.32,"b":[{"x":-323.47,"y":135.01,"z":356.46},{"x":-321.35,"y":138.88,"z":356.9},{"x":-317.81,"y":139.38,"z":359.86},{"x":-316.43,"y":136,"z":362.36},{"x":-318.57,"y":132.17,"z":361.9},{"x":-322.07,"y":131.68,"z":358.97}]},{"lat":-16.88,"lon":50.06,"b":[{"x":-310.75,"y":144.68,"z":363.91},{"x":-308.5,"y":148.56,"z":364.27},{"x":-304.85,"y":149.01,"z":367.14},{"x":-303.5,"y":145.59,"z":369.62},{"x":-305.77,"y":141.76,"z":369.25},{"x":-309.37,"y":141.3,"z":366.41}]},{"lat":-18.02,"lon":51.83,"b":[{"x":-297.52,"y":154.26,"z":370.97},{"x":-295.14,"y":158.13,"z":371.24},{"x":-291.39,"y":158.54,"z":374.01},{"x":-290.07,"y":155.08,"z":376.48},{"x":-292.46,"y":151.25,"z":376.19},{"x":-296.16,"y":150.83,"z":373.45}]},{"lat":-19.16,"lon":53.64,"b":[{"x":-283.81,"y":163.7,"z":377.6},{"x":-281.31,"y":167.56,"z":377.78},{"x":-277.49,"y":167.91,"z":380.44},{"x":-276.2,"y":164.42,"z":382.89},{"x":-278.7,"y":160.61,"z":382.7},{"x":-282.49,"y":160.24,"z":380.07}]},{"lat":-20.28,"lon":55.47,"b":[{"x":-269.67,"y":172.98,"z":383.77},{"x":-267.06,"y":176.81,"z":383.85},{"x":-263.17,"y":177.1,"z":386.4},{"x":-261.92,"y":173.58,"z":388.84},{"x":-264.53,"y":169.8,"z":388.75},{"x":-268.38,"y":169.49,"z":386.23}]},{"lat":-21.38,"lon":57.34,"b":[{"x":-255.15,"y":182.06,"z":389.46},{"x":-252.45,"y":185.85,"z":389.44},{"x":-248.5,"y":186.06,"z":391.86},{"x":-247.3,"y":182.52,"z":394.28},{"x":-250,"y":178.78,"z":394.3},{"x":-253.91,"y":178.53,"z":391.9}]},{"lat":-22.47,"lon":59.23,"b":[{"x":-238.84,"y":190.95,"z":395.53},{"x":-237.09,"y":193.29,"z":395.44},{"x":-234.6,"y":193.39,"z":396.88},{"x":-233.88,"y":191.16,"z":398.39},{"x":-235.61,"y":188.85,"z":398.46},{"x":-238.08,"y":188.74,"z":397.04}]},{"lat":-24.55,"lon":63.08,"b":[{"x":-206.53,"y":207.72,"z":405.19},{"x":-206.09,"y":208.27,"z":405.14},{"x":-205.47,"y":208.27,"z":405.45},{"x":-205.31,"y":207.72,"z":405.81},{"x":-205.76,"y":207.18,"z":405.87},{"x":-206.36,"y":207.18,"z":405.56}]},{"lat":-25.54,"lon":65.02,"b":[{"x":-193.81,"y":215.59,"z":407.3},{"x":-191.33,"y":218.53,"z":406.91},{"x":-188,"y":218.46,"z":408.5},{"x":-187.17,"y":215.49,"z":410.46},{"x":-189.61,"y":212.59,"z":410.84},{"x":-192.93,"y":212.62,"z":409.28}]},{"lat":-26.49,"lon":66.98,"b":[{"x":-178.98,"y":223.16,"z":410},{"x":-175.96,"y":226.61,"z":409.41},{"x":-171.98,"y":226.45,"z":411.19},{"x":-171.02,"y":222.88,"z":413.53},{"x":-174,"y":219.48,"z":414.11},{"x":-177.97,"y":219.59,"z":412.36}]},{"lat":-27.41,"lon":68.94,"b":[{"x":-163.46,"y":230.36,"z":412.49},{"x":-160.42,"y":233.72,"z":411.79},{"x":-156.47,"y":233.47,"z":413.45},{"x":-155.57,"y":229.92,"z":415.78},{"x":-158.56,"y":226.6,"z":416.47},{"x":-162.5,"y":226.8,"z":414.83}]},{"lat":-28.28,"lon":70.9,"b":[{"x":-147.98,"y":237.18,"z":414.47},{"x":-144.94,"y":240.44,"z":413.66},{"x":-141.04,"y":240.11,"z":415.19},{"x":-140.19,"y":236.59,"z":417.51},{"x":-143.18,"y":233.36,"z":418.3},{"x":-147.08,"y":233.63,"z":416.79}]},{"lat":-29.11,"lon":72.86,"b":[{"x":-132.62,"y":243.61,"z":415.94},{"x":-129.58,"y":246.77,"z":415.03},{"x":-125.74,"y":246.37,"z":416.45},{"x":-124.94,"y":242.86,"z":418.75},{"x":-127.92,"y":239.74,"z":419.64},{"x":-131.76,"y":240.08,"z":418.25}]},{"lat":-29.9,"lon":74.81,"b":[{"x":-117.4,"y":249.65,"z":416.93},{"x":-114.38,"y":252.7,"z":415.93},{"x":-110.61,"y":252.23,"z":417.23},{"x":-109.86,"y":248.76,"z":419.51},{"x":-112.83,"y":245.73,"z":420.51},{"x":-116.6,"y":246.15,"z":419.23}]},{"lat":-30.64,"lon":76.74,"b":[{"x":-102.4,"y":255.3,"z":417.47},{"x":-99.4,"y":258.25,"z":416.37},{"x":-95.71,"y":257.7,"z":417.57},{"x":-95.01,"y":254.27,"z":419.84},{"x":-97.95,"y":251.34,"z":420.92},{"x":-101.65,"y":251.83,"z":419.75}]},{"lat":-31.33,"lon":78.66,"b":[{"x":-87.64,"y":260.56,"z":417.58},{"x":-84.68,"y":263.41,"z":416.4},{"x":-81.07,"y":262.8,"z":417.5},{"x":-80.42,"y":259.4,"z":419.75},{"x":-83.32,"y":256.58,"z":420.92},{"x":-86.93,"y":257.13,"z":419.84}]},{"lat":-31.98,"lon":80.55,"b":[{"x":-73.16,"y":265.45,"z":417.29},{"x":-70.25,"y":268.19,"z":416.03},{"x":-66.74,"y":267.52,"z":417.04},{"x":-66.12,"y":264.16,"z":419.28},{"x":-68.98,"y":261.44,"z":420.52},{"x":-72.5,"y":262.05,"z":419.54}]},{"lat":-32.59,"lon":82.43,"b":[{"x":-59,"y":269.97,"z":416.63},{"x":-56.14,"y":272.61,"z":415.31},{"x":-52.73,"y":271.88,"z":416.23},{"x":-52.16,"y":268.57,"z":418.45},{"x":-54.96,"y":265.95,"z":419.76},{"x":-58.39,"y":266.62,"z":418.87}]},{"lat":-33.15,"lon":84.27,"b":[{"x":-45.18,"y":274.14,"z":415.64},{"x":-42.38,"y":276.67,"z":414.25},{"x":-39.07,"y":275.89,"z":415.1},{"x":-38.54,"y":272.63,"z":417.3},{"x":-41.28,"y":270.1,"z":418.67},{"x":-44.61,"y":270.83,"z":417.86}]},{"lat":-33.67,"lon":86.08,"b":[{"x":-31.72,"y":277.96,"z":414.35},{"x":-28.99,"y":280.4,"z":412.9},{"x":-25.78,"y":279.56,"z":413.68},{"x":-25.29,"y":276.36,"z":415.86},{"x":-27.96,"y":273.93,"z":417.29},{"x":-31.19,"y":274.7,"z":416.55}]},{"lat":-2.33,"lon":32.47,"b":[{"x":-423.48,"y":19.81,"z":265},{"x":-422.84,"y":22.96,"z":265.77},{"x":-420.76,"y":23.47,"z":269.01},{"x":-419.33,"y":20.79,"z":271.44},{"x":-420.01,"y":17.67,"z":270.61},{"x":-422.07,"y":17.2,"z":267.42}]},{"lat":-3.26,"lon":33.73,"b":[{"x":-417.29,"y":27.96,"z":273.93},{"x":-416.55,"y":31.19,"z":274.7},{"x":-414.35,"y":31.72,"z":277.96},{"x":-412.9,"y":28.99,"z":280.4},{"x":-413.68,"y":25.78,"z":279.56},{"x":-415.86,"y":25.29,"z":276.36}]},{"lat":-4.23,"lon":35.02,"b":[{"x":-410.59,"y":36.34,"z":282.91},{"x":-409.74,"y":39.65,"z":283.7},{"x":-407.41,"y":40.2,"z":286.97},{"x":-405.95,"y":37.4,"z":289.4},{"x":-406.84,"y":34.12,"z":288.56},{"x":-409.15,"y":33.61,"z":285.35}]},{"lat":-5.22,"lon":36.36,"b":[{"x":-403.36,"y":44.94,"z":291.93},{"x":-402.4,"y":48.33,"z":292.72},{"x":-399.94,"y":48.89,"z":295.99},{"x":-398.46,"y":46.03,"z":298.42},{"x":-399.46,"y":42.67,"z":297.59},{"x":-401.9,"y":42.14,"z":294.37}]},{"lat":-6.23,"lon":37.74,"b":[{"x":-395.59,"y":53.74,"z":300.95},{"x":-394.5,"y":57.2,"z":301.73},{"x":-391.9,"y":57.77,"z":304.99},{"x":-390.41,"y":54.85,"z":307.43},{"x":-391.54,"y":51.42,"z":306.6},{"x":-394.11,"y":50.88,"z":303.38}]},{"lat":-7.27,"lon":39.16,"b":[{"x":-387.24,"y":62.72,"z":309.93},{"x":-386.03,"y":66.25,"z":310.7},{"x":-383.3,"y":66.83,"z":313.95},{"x":-381.8,"y":63.85,"z":316.38},{"x":-383.05,"y":60.34,"z":315.56},{"x":-385.75,"y":59.8,"z":312.36}]},{"lat":-8.33,"lon":40.62,"b":[{"x":-378.31,"y":71.86,"z":318.83},{"x":-376.98,"y":75.46,"z":319.59},{"x":-374.1,"y":76.04,"z":322.81},{"x":-372.6,"y":73,"z":325.23},{"x":-373.98,"y":69.43,"z":324.44},{"x":-376.82,"y":68.88,"z":321.26}]},{"lat":-9.41,"lon":42.12,"b":[{"x":-368.8,"y":81.15,"z":327.63},{"x":-367.33,"y":84.8,"z":328.35},{"x":-364.32,"y":85.38,"z":331.54},{"x":-362.82,"y":82.28,"z":333.96},{"x":-364.33,"y":78.66,"z":333.19},{"x":-367.3,"y":78.1,"z":330.05}]},{"lat":-10.5,"lon":43.66,"b":[{"x":-357.6,"y":90.75,"z":337.4},{"x":-356.57,"y":93.13,"z":337.85},{"x":-354.56,"y":93.49,"z":339.86},{"x":-353.6,"y":91.46,"z":341.41},{"x":-354.65,"y":89.1,"z":340.94},{"x":-356.64,"y":88.75,"z":338.95}]},{"lat":-12.72,"lon":46.87,"b":[{"x":-333.87,"y":110.02,"z":355.55},{"x":-333.61,"y":110.53,"z":355.63},{"x":-333.16,"y":110.6,"z":356.04},{"x":-332.96,"y":110.16,"z":356.36},{"x":-333.22,"y":109.66,"z":356.27},{"x":-333.67,"y":109.59,"z":355.87}]},{"lat":-13.84,"lon":48.54,"b":[{"x":-323.58,"y":119.31,"z":361.96},{"x":-322.33,"y":121.67,"z":362.29},{"x":-320.17,"y":121.97,"z":364.1},{"x":-319.28,"y":119.92,"z":365.55},{"x":-320.54,"y":117.59,"z":365.21},{"x":-322.67,"y":117.29,"z":363.43}]},{"lat":-14.97,"lon":50.23,"b":[{"x":-311.75,"y":128.76,"z":369.02},{"x":-310.06,"y":131.77,"z":369.38},{"x":-307.23,"y":132.13,"z":371.61},{"x":-306.12,"y":129.48,"z":373.46},{"x":-307.82,"y":126.5,"z":373.08},{"x":-310.61,"y":126.14,"z":370.88}]},{"lat":-16.09,"lon":51.97,"b":[{"x":-299.29,"y":138.17,"z":375.86},{"x":-297.22,"y":141.67,"z":376.2},{"x":-293.84,"y":142.04,"z":378.7},{"x":-292.58,"y":138.93,"z":380.83},{"x":-294.66,"y":135.48,"z":380.47},{"x":-297.99,"y":135.1,"z":378}]},{"lat":-17.21,"lon":53.74,"b":[{"x":-286,"y":147.54,"z":382.58},{"x":-283.76,"y":151.13,"z":382.85},{"x":-280.21,"y":151.47,"z":385.32},{"x":-278.95,"y":148.23,"z":387.49},{"x":-281.19,"y":144.69,"z":387.21},{"x":-284.7,"y":144.34,"z":384.77}]},{"lat":-18.31,"lon":55.53,"b":[{"x":-272.42,"y":156.77,"z":388.77},{"x":-269.92,"y":160.58,"z":388.96},{"x":-266.06,"y":160.88,"z":391.48},{"x":-264.76,"y":157.4,"z":393.78},{"x":-267.26,"y":153.64,"z":393.57},{"x":-271.07,"y":153.32,"z":391.08}]},{"lat":-19.41,"lon":57.36,"b":[{"x":-257.77,"y":165.88,"z":394.93},{"x":-255.47,"y":169.22,"z":395.01},{"x":-252.01,"y":169.44,"z":397.13},{"x":-250.89,"y":166.33,"z":399.15},{"x":-253.19,"y":163.04,"z":399.06},{"x":-256.61,"y":162.8,"z":396.97}]},{"lat":-20.48,"lon":59.21,"b":[{"x":-240.47,"y":174.9,"z":401.96},{"x":-239.98,"y":175.57,"z":401.96},{"x":-239.28,"y":175.6,"z":402.36},{"x":-239.06,"y":174.97,"z":402.77},{"x":-239.54,"y":174.3,"z":402.77},{"x":-240.24,"y":174.27,"z":402.37}]},{"lat":-24.51,"lon":66.78,"b":[{"x":-180.83,"y":207.48,"z":417.4},{"x":-179.72,"y":208.8,"z":417.22},{"x":-178.23,"y":208.75,"z":417.88},{"x":-177.85,"y":207.42,"z":418.71},{"x":-178.94,"y":206.12,"z":418.89},{"x":-180.43,"y":206.14,"z":418.23}]},{"lat":-25.44,"lon":68.7,"b":[{"x":-167.96,"y":214.93,"z":418.96},{"x":-164.98,"y":218.34,"z":418.38},{"x":-161.04,"y":218.14,"z":420.01},{"x":-160.09,"y":214.6,"z":422.2},{"x":-163.03,"y":211.23,"z":422.78},{"x":-166.95,"y":211.37,"z":421.17}]},{"lat":-26.33,"lon":70.62,"b":[{"x":-152.63,"y":221.98,"z":421.14},{"x":-149.64,"y":225.3,"z":420.46},{"x":-145.75,"y":225.03,"z":421.96},{"x":-144.85,"y":221.5,"z":424.14},{"x":-147.8,"y":218.22,"z":424.82},{"x":-151.68,"y":218.43,"z":423.33}]},{"lat":-27.18,"lon":72.53,"b":[{"x":-137.38,"y":228.67,"z":422.82},{"x":-134.39,"y":231.89,"z":422.02},{"x":-130.55,"y":231.55,"z":423.41},{"x":-129.71,"y":228.04,"z":425.58},{"x":-132.65,"y":224.85,"z":426.36},{"x":-136.49,"y":225.14,"z":424.99}]},{"lat":-27.99,"lon":74.44,"b":[{"x":-122.26,"y":234.98,"z":424},{"x":-119.28,"y":238.11,"z":423.1},{"x":-115.5,"y":237.69,"z":424.38},{"x":-114.71,"y":234.21,"z":426.53},{"x":-117.65,"y":231.12,"z":427.42},{"x":-121.42,"y":231.47,"z":426.16}]},{"lat":-28.75,"lon":76.33,"b":[{"x":-107.32,"y":240.92,"z":424.71},{"x":-104.35,"y":243.95,"z":423.72},{"x":-100.65,"y":243.47,"z":424.89},{"x":-99.91,"y":240.01,"z":427.03},{"x":-102.83,"y":237.01,"z":428.01},{"x":-106.53,"y":237.44,"z":426.86}]},{"lat":-29.47,"lon":78.21,"b":[{"x":-92.59,"y":246.49,"z":424.98},{"x":-89.66,"y":249.42,"z":423.9},{"x":-86.04,"y":248.87,"z":424.98},{"x":-85.35,"y":245.45,"z":427.1},{"x":-88.23,"y":242.55,"z":428.17},{"x":-91.86,"y":243.04,"z":427.12}]},{"lat":-30.15,"lon":80.07,"b":[{"x":-78.13,"y":251.69,"z":424.84},{"x":-75.23,"y":254.52,"z":423.68},{"x":-71.7,"y":253.91,"z":424.66},{"x":-71.06,"y":250.53,"z":426.77},{"x":-73.91,"y":247.72,"z":427.92},{"x":-77.44,"y":248.28,"z":426.97}]},{"lat":-30.79,"lon":81.91,"b":[{"x":-63.96,"y":256.54,"z":424.32},{"x":-61.11,"y":259.26,"z":423.08},{"x":-57.67,"y":258.59,"z":423.97},{"x":-57.08,"y":255.25,"z":426.07},{"x":-59.87,"y":252.55,"z":427.3},{"x":-63.32,"y":253.16,"z":426.43}]},{"lat":-31.38,"lon":83.72,"b":[{"x":-50.11,"y":261.03,"z":423.44},{"x":-47.31,"y":263.65,"z":422.13},{"x":-43.98,"y":262.92,"z":422.95},{"x":-43.43,"y":259.63,"z":425.04},{"x":-46.17,"y":257.03,"z":426.33},{"x":-49.52,"y":257.69,"z":425.55}]},{"lat":-31.93,"lon":85.5,"b":[{"x":-36.61,"y":265.18,"z":422.25},{"x":-33.87,"y":267.7,"z":420.88},{"x":-30.64,"y":266.93,"z":421.62},{"x":-30.13,"y":263.69,"z":423.69},{"x":-32.81,"y":261.17,"z":425.04},{"x":-36.06,"y":261.89,"z":424.34}]},{"lat":-32.44,"lon":87.24,"b":[{"x":-23.47,"y":269.01,"z":420.76},{"x":-20.79,"y":271.44,"z":419.33},{"x":-17.67,"y":270.61,"z":420.01},{"x":-17.2,"y":267.42,"z":422.07},{"x":-19.81,"y":265,"z":423.48},{"x":-22.96,"y":265.77,"z":422.84}]},{"lat":-0.87,"lon":32.92,"b":[{"x":-421.66,"y":7.19,"z":268.53},{"x":-421.08,"y":10.23,"z":269.34},{"x":-419.01,"y":10.71,"z":272.53},{"x":-417.85,"y":7.66,"z":274.41},{"x":-418.77,"y":4.2,"z":273.07},{"x":-420.51,"y":4.2,"z":270.38}]},{"lat":-1.78,"lon":34.16,"b":[{"x":-415.64,"y":15.03,"z":277.44},{"x":-414.96,"y":18.15,"z":278.26},{"x":-412.78,"y":18.65,"z":281.46},{"x":-411.6,"y":15.56,"z":283.37},{"x":-412.62,"y":12.02,"z":282.05},{"x":-414.48,"y":11.99,"z":279.32}]},{"lat":-2.7,"lon":35.44,"b":[{"x":-409.13,"y":23.1,"z":286.41},{"x":-408.35,"y":26.3,"z":287.24},{"x":-406.04,"y":26.81,"z":290.46},{"x":-404.84,"y":23.68,"z":292.39},{"x":-405.98,"y":20.08,"z":291.09},{"x":-407.95,"y":20.01,"z":288.32}]},{"lat":-3.66,"lon":36.76,"b":[{"x":-402.11,"y":31.38,"z":295.42},{"x":-401.22,"y":34.66,"z":296.25},{"x":-398.78,"y":35.19,"z":299.48},{"x":-397.57,"y":32.01,"z":301.44},{"x":-398.81,"y":28.35,"z":300.16},{"x":-400.91,"y":28.25,"z":297.35}]},{"lat":-4.63,"lon":38.12,"b":[{"x":-394.56,"y":39.87,"z":304.44},{"x":-393.56,"y":43.23,"z":305.27},{"x":-390.98,"y":43.77,"z":308.49},{"x":-389.75,"y":40.55,"z":310.48},{"x":-391.11,"y":36.83,"z":309.23},{"x":-393.34,"y":36.69,"z":306.4}]},{"lat":-5.63,"lon":39.52,"b":[{"x":-386.46,"y":48.56,"z":313.43},{"x":-385.34,"y":51.99,"z":314.26},{"x":-382.63,"y":52.54,"z":317.46},{"x":-381.39,"y":49.28,"z":319.47},{"x":-382.86,"y":45.51,"z":318.26},{"x":-385.23,"y":45.34,"z":315.42}]},{"lat":-6.66,"lon":40.96,"b":[{"x":-377.8,"y":57.42,"z":322.36},{"x":-376.55,"y":60.92,"z":323.18},{"x":-373.71,"y":61.47,"z":326.35},{"x":-372.45,"y":58.17,"z":328.39},{"x":-374.04,"y":54.36,"z":327.23},{"x":-376.55,"y":54.15,"z":324.38}]},{"lat":-7.7,"lon":42.44,"b":[{"x":-368.56,"y":66.43,"z":331.19},{"x":-367.19,"y":69.99,"z":331.99},{"x":-364.22,"y":70.55,"z":335.12},{"x":-362.95,"y":67.21,"z":337.19},{"x":-364.65,"y":63.36,"z":336.09},{"x":-367.3,"y":63.13,"z":333.23}]},{"lat":-8.76,"lon":43.96,"b":[{"x":-358.76,"y":75.58,"z":339.88},{"x":-357.25,"y":79.2,"z":340.65},{"x":-354.15,"y":79.74,"z":343.74},{"x":-352.87,"y":76.37,"z":345.82},{"x":-354.69,"y":72.49,"z":344.79},{"x":-357.48,"y":72.24,"z":341.94}]},{"lat":-9.83,"lon":45.51,"b":[{"x":-347.81,"y":84.92,"z":348.94},{"x":-346.47,"y":87.93,"z":349.53},{"x":-343.82,"y":88.37,"z":352.03},{"x":-342.76,"y":85.58,"z":353.75},{"x":-344.34,"y":82.37,"z":352.97},{"x":-346.76,"y":82.15,"z":350.65}]},{"lat":-10.91,"lon":47.11,"b":[{"x":-335.01,"y":94.53,"z":358.91},{"x":-334.55,"y":95.49,"z":359.08},{"x":-333.69,"y":95.62,"z":359.85},{"x":-333.35,"y":94.73,"z":360.4},{"x":-333.88,"y":93.72,"z":360.17},{"x":-334.67,"y":93.65,"z":359.45}]},{"lat":-23.5,"lon":68.47,"b":[{"x":-171.16,"y":199.41,"z":425.31},{"x":-169.03,"y":201.93,"z":424.97},{"x":-166.15,"y":201.83,"z":426.15},{"x":-165.2,"y":199.32,"z":427.7},{"x":-167.11,"y":196.9,"z":428.08},{"x":-170.19,"y":196.88,"z":426.87}]},{"lat":-24.4,"lon":70.35,"b":[{"x":-157.06,"y":206.69,"z":427.26},{"x":-154.12,"y":210.05,"z":426.69},{"x":-150.23,"y":209.84,"z":428.17},{"x":-148.94,"y":206.44,"z":430.27},{"x":-151.52,"y":203.23,"z":430.9},{"x":-155.75,"y":203.26,"z":429.38}]},{"lat":-25.26,"lon":72.22,"b":[{"x":-141.95,"y":213.6,"z":429.14},{"x":-139,"y":216.88,"z":428.46},{"x":-135.17,"y":216.59,"z":429.83},{"x":-133.88,"y":213.22,"z":431.91},{"x":-136.42,"y":210.11,"z":432.64},{"x":-140.65,"y":210.2,"z":431.24}]},{"lat":-26.09,"lon":74.08,"b":[{"x":-126.94,"y":220.17,"z":430.53},{"x":-124,"y":223.35,"z":429.74},{"x":-120.22,"y":223,"z":431},{"x":-118.95,"y":219.66,"z":433.06},{"x":-121.44,"y":216.65,"z":433.88},{"x":-125.66,"y":216.8,"z":432.61}]},{"lat":-26.87,"lon":75.94,"b":[{"x":-112.09,"y":226.38,"z":431.43},{"x":-109.15,"y":229.47,"z":430.55},{"x":-105.45,"y":229.05,"z":431.69},{"x":-104.19,"y":225.75,"z":433.73},{"x":-106.62,"y":222.83,"z":434.65},{"x":-110.81,"y":223.04,"z":433.49}]},{"lat":-27.62,"lon":77.78,"b":[{"x":-97.42,"y":232.23,"z":431.88},{"x":-94.51,"y":235.23,"z":430.9},{"x":-90.89,"y":234.74,"z":431.95},{"x":-89.64,"y":231.47,"z":433.97},{"x":-92,"y":228.66,"z":434.96},{"x":-96.16,"y":228.93,"z":433.92}]},{"lat":-28.32,"lon":79.61,"b":[{"x":-83,"y":237.72,"z":431.91},{"x":-80.11,"y":240.63,"z":430.84},{"x":-76.58,"y":240.07,"z":431.79},{"x":-75.35,"y":236.85,"z":433.78},{"x":-77.64,"y":234.14,"z":434.85},{"x":-81.75,"y":234.46,"z":433.92}]},{"lat":-28.99,"lon":81.41,"b":[{"x":-68.84,"y":242.87,"z":431.54},{"x":-66,"y":245.67,"z":430.39},{"x":-62.55,"y":245.06,"z":431.25},{"x":-61.34,"y":241.89,"z":433.22},{"x":-63.55,"y":239.28,"z":434.34},{"x":-67.61,"y":239.65,"z":433.53}]},{"lat":-29.61,"lon":83.19,"b":[{"x":-54.98,"y":247.67,"z":430.8},{"x":-52.19,"y":250.38,"z":429.57},{"x":-48.84,"y":249.71,"z":430.36},{"x":-47.64,"y":246.58,"z":432.29},{"x":-49.78,"y":244.07,"z":433.48},{"x":-53.77,"y":244.5,"z":432.76}]},{"lat":-30.2,"lon":84.94,"b":[{"x":-41.45,"y":252.14,"z":429.72},{"x":-38.71,"y":254.75,"z":428.43},{"x":-35.46,"y":254.04,"z":429.14},{"x":-34.28,"y":250.95,"z":431.05},{"x":-36.33,"y":248.53,"z":432.28},{"x":-40.25,"y":249.01,"z":431.66}]},{"lat":-30.74,"lon":86.66,"b":[{"x":-28.26,"y":256.29,"z":428.34},{"x":-25.58,"y":258.8,"z":426.99},{"x":-22.44,"y":258.04,"z":427.63},{"x":-21.28,"y":255,"z":429.51},{"x":-23.24,"y":252.67,"z":430.78},{"x":-27.08,"y":253.2,"z":430.25}]},{"lat":-31.25,"lon":88.35,"b":[{"x":-15.44,"y":260.13,"z":426.68},{"x":-12.83,"y":262.55,"z":425.27},{"x":-9.78,"y":261.74,"z":425.85},{"x":-8.64,"y":258.75,"z":427.7},{"x":-10.52,"y":256.51,"z":429.01},{"x":-14.28,"y":257.08,"z":428.56}]},{"lat":-30.23,"lon":90,"b":[{"x":-1.85,"y":254.55,"z":430.3},{"x":-3.73,"y":252.31,"z":431.6},{"x":-1.88,"y":249.42,"z":433.29},{"x":1.88,"y":249.42,"z":433.29},{"x":3.73,"y":252.31,"z":431.6},{"x":1.85,"y":254.55,"z":430.3}]},{"lat":-28.7,"lon":90,"b":[{"x":-1.88,"y":243.01,"z":436.91},{"x":-3.79,"y":240.65,"z":438.21},{"x":-1.91,"y":237.64,"z":439.86},{"x":1.91,"y":237.64,"z":439.86},{"x":3.79,"y":240.65,"z":438.21},{"x":1.88,"y":243.01,"z":436.91}]},{"lat":-27.12,"lon":90,"b":[{"x":-1.91,"y":230.94,"z":443.41},{"x":-3.85,"y":228.45,"z":444.68},{"x":-1.94,"y":225.33,"z":446.29},{"x":1.94,"y":225.33,"z":446.29},{"x":3.85,"y":228.45,"z":444.68},{"x":1.91,"y":230.94,"z":443.41}]},{"lat":-25.49,"lon":90,"b":[{"x":-1.94,"y":218.33,"z":449.75},{"x":-3.9,"y":215.72,"z":451},{"x":-1.96,"y":212.48,"z":452.55},{"x":1.96,"y":212.48,"z":452.55},{"x":3.9,"y":215.72,"z":451},{"x":1.94,"y":218.33,"z":449.75}]},{"lat":-23.82,"lon":90,"b":[{"x":-1.96,"y":205.19,"z":455.89},{"x":-3.96,"y":202.44,"z":457.11},{"x":-1.99,"y":199.1,"z":458.59},{"x":1.99,"y":199.1,"z":458.59},{"x":3.96,"y":202.44,"z":457.11},{"x":1.96,"y":205.19,"z":455.89}]},{"lat":-22.1,"lon":90,"b":[{"x":-1.57,"y":190.8,"z":462.11},{"x":-3.15,"y":188.53,"z":463.03},{"x":-1.59,"y":185.82,"z":464.14},{"x":1.59,"y":185.82,"z":464.14},{"x":3.15,"y":188.53,"z":463.03},{"x":1.57,"y":190.8,"z":462.11}]},{"lat":-29.73,"lon":88.35,"b":[{"x":-14.39,"y":250.8,"z":432.25},{"x":-10.63,"y":250.23,"z":432.7},{"x":-8.78,"y":247.34,"z":434.4},{"x":-10.69,"y":244.97,"z":435.69},{"x":-14.5,"y":245.54,"z":435.26},{"x":-16.35,"y":248.48,"z":433.52}]},{"lat":-29.19,"lon":86.66,"b":[{"x":-27.3,"y":246.76,"z":433.95},{"x":-23.46,"y":246.23,"z":434.48},{"x":-21.61,"y":243.29,"z":436.23},{"x":-23.6,"y":240.84,"z":437.48},{"x":-27.51,"y":241.36,"z":436.97},{"x":-29.35,"y":244.34,"z":435.18}]},{"lat":-28.16,"lon":88.35,"b":[{"x":-14.61,"y":238.96,"z":438.9},{"x":-10.79,"y":238.4,"z":439.32},{"x":-8.91,"y":235.39,"z":440.98},{"x":-10.85,"y":232.9,"z":442.25},{"x":-14.72,"y":233.46,"z":441.85},{"x":-16.6,"y":236.51,"z":440.15}]},{"lat":-28.61,"lon":84.94,"b":[{"x":-40.58,"y":242.4,"z":435.37},{"x":-36.66,"y":241.92,"z":435.99},{"x":-34.82,"y":238.93,"z":437.77},{"x":-36.9,"y":236.39,"z":438.98},{"x":-40.88,"y":236.86,"z":438.38},{"x":-42.72,"y":239.89,"z":436.55}]},{"lat":-27.59,"lon":86.66,"b":[{"x":-27.72,"y":234.61,"z":440.61},{"x":-23.82,"y":234.09,"z":441.12},{"x":-21.94,"y":231.04,"z":442.82},{"x":-23.96,"y":228.45,"z":444.05},{"x":-27.92,"y":228.96,"z":443.56},{"x":-29.8,"y":232.06,"z":441.82}]},{"lat":-26.55,"lon":88.35,"b":[{"x":-14.83,"y":226.58,"z":445.41},{"x":-10.95,"y":226.03,"z":445.81},{"x":-9.04,"y":222.9,"z":447.42},{"x":-11,"y":220.29,"z":448.66},{"x":-14.94,"y":220.82,"z":448.29},{"x":-16.85,"y":224,"z":446.64}]},{"lat":-28,"lon":83.19,"b":[{"x":-54.21,"y":237.71,"z":436.46},{"x":-50.22,"y":237.28,"z":437.18},{"x":-48.38,"y":234.26,"z":439.01},{"x":-50.54,"y":231.61,"z":440.17},{"x":-54.6,"y":232.03,"z":439.47},{"x":-56.42,"y":235.1,"z":437.59}]},{"lat":-26.98,"lon":84.94,"b":[{"x":-41.2,"y":229.93,"z":442.02},{"x":-37.22,"y":229.46,"z":442.62},{"x":-35.34,"y":226.36,"z":444.36},{"x":-37.45,"y":223.68,"z":445.54},{"x":-41.49,"y":224.14,"z":444.96},{"x":-43.36,"y":227.29,"z":443.17}]},{"lat":-25.95,"lon":86.66,"b":[{"x":-28.13,"y":221.91,"z":447.12},{"x":-24.17,"y":221.4,"z":447.6},{"x":-22.26,"y":218.23,"z":449.25},{"x":-24.31,"y":215.51,"z":450.45},{"x":-28.33,"y":216,"z":449.99},{"x":-30.24,"y":219.22,"z":448.3}]},{"lat":-24.89,"lon":88.35,"b":[{"x":-15.04,"y":213.65,"z":451.75},{"x":-11.1,"y":213.11,"z":452.12},{"x":-9.17,"y":209.88,"z":453.67},{"x":-11.16,"y":207.13,"z":454.88},{"x":-15.15,"y":207.65,"z":454.54},{"x":-17.09,"y":210.93,"z":452.95}]},{"lat":-27.34,"lon":81.41,"b":[{"x":-68.16,"y":232.69,"z":437.21},{"x":-64.11,"y":232.32,"z":438.03},{"x":-62.28,"y":229.24,"z":439.9},{"x":-64.53,"y":226.5,"z":441},{"x":-68.65,"y":226.86,"z":440.19},{"x":-70.46,"y":229.98,"z":438.28}]},{"lat":-26.34,"lon":83.19,"b":[{"x":-55.03,"y":224.93,"z":443.08},{"x":-50.98,"y":224.51,"z":443.79},{"x":-49.1,"y":221.36,"z":445.57},{"x":-51.29,"y":218.58,"z":446.69},{"x":-55.41,"y":218.98,"z":446.01},{"x":-57.27,"y":222.18,"z":444.18}]},{"lat":-25.3,"lon":84.94,"b":[{"x":-41.81,"y":216.9,"z":448.5},{"x":-37.76,"y":216.45,"z":449.08},{"x":-35.85,"y":213.22,"z":450.77},{"x":-37.99,"y":210.41,"z":451.92},{"x":-42.09,"y":210.85,"z":451.35},{"x":-44,"y":214.12,"z":449.62}]},{"lat":-24.25,"lon":86.66,"b":[{"x":-28.53,"y":208.64,"z":453.43},{"x":-24.51,"y":208.15,"z":453.9},{"x":-22.57,"y":204.86,"z":455.48},{"x":-24.64,"y":202.02,"z":456.65},{"x":-28.72,"y":202.49,"z":456.2},{"x":-30.66,"y":205.83,"z":454.57}]},{"lat":-23.19,"lon":88.35,"b":[{"x":-15.24,"y":200.17,"z":457.87},{"x":-11.25,"y":199.65,"z":458.22},{"x":-9.29,"y":196.31,"z":459.7},{"x":-11.31,"y":193.43,"z":460.87},{"x":-15.35,"y":193.92,"z":460.55},{"x":-17.32,"y":197.32,"z":459.03}]},{"lat":-26.65,"lon":79.61,"b":[{"x":-82.42,"y":227.33,"z":437.58},{"x":-78.31,"y":227.01,"z":438.5},{"x":-76.5,"y":223.89,"z":440.41},{"x":-78.82,"y":221.04,"z":441.44},{"x":-82.99,"y":221.35,"z":440.52},{"x":-84.78,"y":224.52,"z":438.57}]},{"lat":-25.65,"lon":81.41,"b":[{"x":-69.19,"y":219.58,"z":443.78},{"x":-65.07,"y":219.22,"z":444.59},{"x":-63.21,"y":216.02,"z":446.41},{"x":-65.47,"y":213.14,"z":447.47},{"x":-69.66,"y":213.49,"z":446.67},{"x":-71.51,"y":216.74,"z":444.81}]},{"lat":-24.62,"lon":83.19,"b":[{"x":-55.83,"y":211.57,"z":449.52},{"x":-51.71,"y":211.16,"z":450.2},{"x":-49.81,"y":207.89,"z":451.93},{"x":-52.02,"y":204.97,"z":453.01},{"x":-56.2,"y":205.36,"z":452.34},{"x":-58.1,"y":208.69,"z":450.57}]},{"lat":-23.58,"lon":84.94,"b":[{"x":-42.39,"y":203.31,"z":454.77},{"x":-38.29,"y":202.86,"z":455.33},{"x":-36.34,"y":199.52,"z":456.96},{"x":-38.5,"y":196.57,"z":458.06},{"x":-42.66,"y":197,"z":457.51},{"x":-44.61,"y":200.39,"z":455.85}]},{"lat":-22.51,"lon":86.66,"b":[{"x":-28.91,"y":194.82,"z":459.51},{"x":-24.83,"y":194.35,"z":459.95},{"x":-22.86,"y":190.95,"z":461.47},{"x":-24.96,"y":187.97,"z":462.58},{"x":-29.09,"y":188.42,"z":462.16},{"x":-31.07,"y":191.87,"z":460.61}]},{"lat":-21.44,"lon":88.35,"b":[{"x":-14.58,"y":184.69,"z":464.37},{"x":-12.27,"y":184.4,"z":464.56},{"x":-11.13,"y":182.43,"z":465.36},{"x":-12.3,"y":180.7,"z":466},{"x":-14.64,"y":180.97,"z":465.83},{"x":-15.79,"y":182.98,"z":465.01}]},{"lat":-25.91,"lon":77.78,"b":[{"x":-96.94,"y":221.61,"z":437.53},{"x":-92.79,"y":221.35,"z":438.57},{"x":-90.99,"y":218.18,"z":440.52},{"x":-93.38,"y":215.24,"z":441.47},{"x":-97.6,"y":215.49,"z":440.43},{"x":-99.37,"y":218.7,"z":438.44}]},{"lat":-24.92,"lon":79.61,"b":[{"x":-83.64,"y":213.89,"z":444.07},{"x":-79.47,"y":213.58,"z":444.99},{"x":-77.62,"y":210.33,"z":446.85},{"x":-79.96,"y":207.35,"z":447.83},{"x":-84.2,"y":207.65,"z":446.92},{"x":-86.03,"y":210.94,"z":445.02}]},{"lat":-23.9,"lon":81.41,"b":[{"x":-70.18,"y":205.89,"z":450.14},{"x":-66,"y":205.54,"z":450.94},{"x":-64.1,"y":202.21,"z":452.7},{"x":-66.39,"y":199.19,"z":453.71},{"x":-70.63,"y":199.53,"z":452.92},{"x":-72.52,"y":202.9,"z":451.12}]},{"lat":-22.86,"lon":83.19,"b":[{"x":-56.6,"y":197.63,"z":455.72},{"x":-52.42,"y":197.24,"z":456.39},{"x":-50.48,"y":193.85,"z":458.06},{"x":-52.72,"y":190.8,"z":459.08},{"x":-56.95,"y":191.17,"z":458.42},{"x":-58.89,"y":194.61,"z":456.72}]},{"lat":-21.8,"lon":84.94,"b":[{"x":-42.95,"y":189.14,"z":460.78},{"x":-38.79,"y":188.72,"z":461.33},{"x":-36.82,"y":185.27,"z":462.88},{"x":-39,"y":182.18,"z":463.93},{"x":-43.21,"y":182.59,"z":463.4},{"x":-45.19,"y":186.09,"z":461.81}]},{"lat":-20.73,"lon":86.66,"b":[{"x":-28.99,"y":179.96,"z":465.53},{"x":-25.45,"y":179.58,"z":465.89},{"x":-23.73,"y":176.57,"z":467.13},{"x":-25.55,"y":173.9,"z":468.03},{"x":-29.14,"y":174.26,"z":467.69},{"x":-30.86,"y":177.32,"z":466.42}]},{"lat":-25.14,"lon":75.94,"b":[{"x":-111.7,"y":215.55,"z":437.04},{"x":-107.5,"y":215.34,"z":438.19},{"x":-105.74,"y":212.13,"z":440.18},{"x":-108.19,"y":209.08,"z":441.04},{"x":-112.44,"y":209.28,"z":439.89},{"x":-114.19,"y":212.53,"z":437.87}]},{"lat":-24.15,"lon":77.78,"b":[{"x":-98.36,"y":207.85,"z":443.92},{"x":-94.14,"y":207.59,"z":444.96},{"x":-92.3,"y":204.3,"z":446.86},{"x":-94.71,"y":201.21,"z":447.75},{"x":-99,"y":201.46,"z":446.72},{"x":-100.81,"y":204.8,"z":444.78}]},{"lat":-23.14,"lon":79.61,"b":[{"x":-84.82,"y":199.86,"z":450.33},{"x":-80.58,"y":199.56,"z":451.25},{"x":-78.69,"y":196.19,"z":453.05},{"x":-81.06,"y":193.07,"z":453.97},{"x":-85.35,"y":193.35,"z":453.06},{"x":-87.23,"y":196.77,"z":451.23}]},{"lat":-22.11,"lon":81.41,"b":[{"x":-71.13,"y":191.61,"z":456.25},{"x":-66.89,"y":191.27,"z":457.04},{"x":-64.95,"y":187.83,"z":458.74},{"x":-67.26,"y":184.68,"z":459.68},{"x":-71.56,"y":185,"z":458.9},{"x":-73.5,"y":188.49,"z":457.17}]},{"lat":-21.06,"lon":83.19,"b":[{"x":-57.34,"y":183.13,"z":461.64},{"x":-53.1,"y":182.75,"z":462.3},{"x":-51.13,"y":179.25,"z":463.89},{"x":-53.38,"y":176.06,"z":464.85},{"x":-57.67,"y":176.41,"z":464.21},{"x":-59.65,"y":179.97,"z":462.59}]},{"lat":-19.99,"lon":84.94,"b":[{"x":-43.49,"y":174.43,"z":466.5},{"x":-39.27,"y":174.03,"z":467.03},{"x":-37.26,"y":170.47,"z":468.5},{"x":-39.46,"y":167.25,"z":469.47},{"x":-43.73,"y":167.63,"z":468.96},{"x":-45.74,"y":171.24,"z":467.46}]},{"lat":-24.32,"lon":74.08,"b":[{"x":-126.65,"y":209.13,"z":436.08},{"x":-122.43,"y":208.98,"z":437.36},{"x":-120.68,"y":205.72,"z":439.37},{"x":-123.19,"y":202.57,"z":440.14},{"x":-127.47,"y":202.71,"z":438.86},{"x":-129.18,"y":206.01,"z":436.81}]},{"lat":-23.35,"lon":75.94,"b":[{"x":-113.3,"y":201.45,"z":443.3},{"x":-109.04,"y":201.26,"z":444.46},{"x":-107.23,"y":197.91,"z":446.39},{"x":-109.7,"y":194.72,"z":447.2},{"x":-114.02,"y":194.91,"z":446.03},{"x":-115.81,"y":198.3,"z":444.07}]},{"lat":-22.35,"lon":77.78,"b":[{"x":-99.72,"y":193.49,"z":450.06},{"x":-95.44,"y":193.24,"z":451.1},{"x":-93.56,"y":189.82,"z":452.93},{"x":-95.98,"y":186.6,"z":453.77},{"x":-100.33,"y":186.83,"z":452.73},{"x":-102.19,"y":190.3,"z":450.86}]},{"lat":-21.32,"lon":79.61,"b":[{"x":-85.95,"y":185.25,"z":456.32},{"x":-81.65,"y":184.96,"z":457.23},{"x":-79.72,"y":181.47,"z":458.96},{"x":-82.1,"y":178.21,"z":459.82},{"x":-86.46,"y":178.48,"z":458.92},{"x":-88.38,"y":182.02,"z":457.16}]},{"lat":-20.27,"lon":81.41,"b":[{"x":-72.04,"y":176.77,"z":462.06},{"x":-67.74,"y":176.44,"z":462.84},{"x":-65.76,"y":172.88,"z":464.46},{"x":-68.09,"y":169.6,"z":465.33},{"x":-72.45,"y":169.9,"z":464.57},{"x":-74.42,"y":173.51,"z":462.92}]},{"lat":-19.21,"lon":83.19,"b":[{"x":-58.04,"y":168.07,"z":467.25},{"x":-53.75,"y":167.72,"z":467.89},{"x":-51.73,"y":164.1,"z":469.39},{"x":-54.01,"y":160.78,"z":470.28},{"x":-58.35,"y":161.11,"z":469.65},{"x":-60.36,"y":164.78,"z":468.12}]},{"lat":-18.12,"lon":84.94,"b":[{"x":-42.27,"y":156.13,"z":473.1},{"x":-41.59,"y":156.07,"z":473.18},{"x":-41.26,"y":155.48,"z":473.4},{"x":-41.62,"y":154.94,"z":473.55},{"x":-42.31,"y":154.99,"z":473.47},{"x":-42.64,"y":155.59,"z":473.24}]},{"lat":-23.47,"lon":72.22,"b":[{"x":-141.74,"y":202.36,"z":434.63},{"x":-137.5,"y":202.27,"z":436.03},{"x":-135.79,"y":198.96,"z":438.07},{"x":-138.34,"y":195.71,"z":438.74},{"x":-142.63,"y":195.8,"z":437.33},{"x":-144.31,"y":199.14,"z":435.26}]},{"lat":-22.5,"lon":74.08,"b":[{"x":-128.42,"y":194.71,"z":442.19},{"x":-124.14,"y":194.57,"z":443.48},{"x":-122.35,"y":191.18,"z":445.44},{"x":-124.87,"y":187.89,"z":446.14},{"x":-129.21,"y":188.03,"z":444.84},{"x":-130.97,"y":191.46,"z":442.86}]},{"lat":-21.51,"lon":75.94,"b":[{"x":-114.83,"y":186.76,"z":449.3},{"x":-110.51,"y":186.57,"z":450.46},{"x":-108.65,"y":183.11,"z":452.33},{"x":-111.13,"y":179.78,"z":453.06},{"x":-115.51,"y":179.96,"z":451.89},{"x":-117.35,"y":183.47,"z":450}]},{"lat":-20.49,"lon":77.78,"b":[{"x":-101.02,"y":178.54,"z":455.91},{"x":-96.67,"y":178.31,"z":456.94},{"x":-94.75,"y":174.76,"z":458.71},{"x":-97.19,"y":171.4,"z":459.46},{"x":-101.59,"y":171.62,"z":458.43},{"x":-103.5,"y":175.21,"z":456.64}]},{"lat":-19.45,"lon":79.61,"b":[{"x":-87.02,"y":170.06,"z":462},{"x":-82.66,"y":169.79,"z":462.9},{"x":-80.69,"y":166.18,"z":464.55},{"x":-83.08,"y":162.79,"z":465.33},{"x":-87.49,"y":163.04,"z":464.43},{"x":-89.46,"y":166.7,"z":462.75}]},{"lat":-18.39,"lon":81.41,"b":[{"x":-72.89,"y":161.36,"z":467.53},{"x":-68.54,"y":161.06,"z":468.29},{"x":-66.52,"y":157.39,"z":469.83},{"x":-68.86,"y":153.98,"z":470.62},{"x":-73.27,"y":154.25,"z":469.86},{"x":-75.29,"y":157.97,"z":468.3}]},{"lat":-17.31,"lon":83.19,"b":[{"x":-57.92,"y":151.09,"z":473.04},{"x":-55.21,"y":150.88,"z":473.44},{"x":-53.93,"y":148.56,"z":474.32},{"x":-55.36,"y":146.41,"z":474.82},{"x":-58.1,"y":146.59,"z":474.44},{"x":-59.38,"y":148.95,"z":473.54}]},{"lat":-22.58,"lon":70.35,"b":[{"x":-156.64,"y":194.69,"z":433.02},{"x":-153.13,"y":194.66,"z":434.29},{"x":-151.73,"y":191.88,"z":436.01},{"x":-153.88,"y":189.09,"z":436.47},{"x":-157.45,"y":189.12,"z":435.19},{"x":-158.81,"y":191.94,"z":433.45}]},{"lat":-21.62,"lon":72.22,"b":[{"x":-143.24,"y":186.78,"z":441.07},{"x":-140.02,"y":186.71,"z":442.13},{"x":-138.7,"y":184.14,"z":443.62},{"x":-140.62,"y":181.59,"z":444.07},{"x":-143.88,"y":181.66,"z":443},{"x":-145.18,"y":184.26,"z":441.49}]},{"lat":-20.64,"lon":74.08,"b":[{"x":-130.11,"y":179.7,"z":448.01},{"x":-125.77,"y":179.56,"z":449.3},{"x":-123.93,"y":176.05,"z":451.2},{"x":-126.46,"y":172.62,"z":451.82},{"x":-130.86,"y":172.75,"z":450.52},{"x":-132.67,"y":176.31,"z":448.6}]},{"lat":-19.63,"lon":75.94,"b":[{"x":-116.29,"y":171.49,"z":454.97},{"x":-111.91,"y":171.31,"z":456.14},{"x":-110,"y":167.72,"z":457.93},{"x":-112.49,"y":164.26,"z":458.58},{"x":-116.92,"y":164.43,"z":457.41},{"x":-118.81,"y":168.06,"z":455.6}]},{"lat":-18.59,"lon":77.78,"b":[{"x":-102.24,"y":163.02,"z":461.41},{"x":-97.84,"y":162.8,"z":462.45},{"x":-95.87,"y":159.15,"z":464.13},{"x":-98.32,"y":155.66,"z":464.8},{"x":-102.77,"y":155.86,"z":463.76},{"x":-104.73,"y":159.56,"z":462.06}]},{"lat":-17.53,"lon":79.61,"b":[{"x":-88.02,"y":154.33,"z":467.3},{"x":-83.61,"y":154.08,"z":468.19},{"x":-81.6,"y":150.36,"z":469.75},{"x":-84,"y":146.84,"z":470.44},{"x":-88.46,"y":147.07,"z":469.55},{"x":-90.47,"y":150.84,"z":467.97}]},{"lat":-16.46,"lon":81.41,"b":[{"x":-73.45,"y":145,"z":472.78},{"x":-69.55,"y":144.75,"z":473.44},{"x":-67.74,"y":141.42,"z":474.71},{"x":-69.82,"y":138.28,"z":475.33},{"x":-73.76,"y":138.51,"z":474.67},{"x":-75.57,"y":141.89,"z":473.38}]},{"lat":-20.7,"lon":70.35,"b":[{"x":-158.31,"y":178.8,"z":439.23},{"x":-155.77,"y":178.78,"z":440.15},{"x":-154.75,"y":176.73,"z":441.33},{"x":-156.28,"y":174.67,"z":441.61},{"x":-158.85,"y":174.69,"z":440.69},{"x":-159.85,"y":176.77,"z":439.49}]},{"lat":-19.73,"lon":72.22,"b":[{"x":-143.95,"y":169.22,"z":447.92},{"x":-143.41,"y":169.21,"z":448.1},{"x":-143.18,"y":168.77,"z":448.34},{"x":-143.5,"y":168.33,"z":448.4},{"x":-144.06,"y":168.34,"z":448.22},{"x":-144.28,"y":168.79,"z":447.98}]},{"lat":-18.72,"lon":74.08,"b":[{"x":-131.7,"y":164.11,"z":453.49},{"x":-127.31,"y":163.98,"z":454.79},{"x":-125.42,"y":160.34,"z":456.61},{"x":-127.95,"y":156.79,"z":457.14},{"x":-132.4,"y":156.91,"z":455.83},{"x":-134.27,"y":160.59,"z":454}]},{"lat":-17.7,"lon":75.94,"b":[{"x":-117.64,"y":155.65,"z":460.29},{"x":-113.21,"y":155.48,"z":461.45},{"x":-111.26,"y":151.78,"z":463.16},{"x":-113.75,"y":148.19,"z":463.71},{"x":-118.23,"y":148.34,"z":462.54},{"x":-120.17,"y":152.1,"z":460.82}]},{"lat":-16.65,"lon":77.78,"b":[{"x":-103.37,"y":146.96,"z":466.53},{"x":-98.92,"y":146.76,"z":467.56},{"x":-96.91,"y":142.99,"z":469.14},{"x":-99.36,"y":139.38,"z":469.71},{"x":-103.86,"y":139.56,"z":468.68},{"x":-105.87,"y":143.37,"z":467.08}]},{"lat":-15.58,"lon":79.61,"b":[{"x":-88.94,"y":138.07,"z":472.18},{"x":-84.48,"y":137.84,"z":473.07},{"x":-82.43,"y":134.02,"z":474.53},{"x":-84.83,"y":130.38,"z":475.11},{"x":-89.34,"y":130.58,"z":474.23},{"x":-91.39,"y":134.45,"z":472.76}]},{"lat":-16.77,"lon":74.08,"b":[{"x":-133.18,"y":147.96,"z":458.58},{"x":-128.73,"y":147.84,"z":459.89},{"x":-126.79,"y":144.09,"z":461.62},{"x":-129.32,"y":140.41,"z":462.05},{"x":-133.82,"y":140.52,"z":460.73},{"x":-135.74,"y":144.31,"z":458.99}]},{"lat":-15.72,"lon":75.94,"b":[{"x":-118.9,"y":139.28,"z":465.18},{"x":-114.41,"y":139.12,"z":466.35},{"x":-112.41,"y":135.31,"z":467.96},{"x":-114.9,"y":131.6,"z":468.41},{"x":-119.43,"y":131.74,"z":467.23},{"x":-121.42,"y":135.6,"z":465.61}]},{"lat":-14.66,"lon":77.78,"b":[{"x":-104.41,"y":130.39,"z":471.2},{"x":-99.9,"y":130.2,"z":472.22},{"x":-97.85,"y":126.33,"z":473.7},{"x":-100.3,"y":122.6,"z":474.17},{"x":-104.85,"y":122.77,"z":473.14},{"x":-106.9,"y":126.68,"z":471.65}]},{"lat":-13.58,"lon":79.61,"b":[{"x":-89.78,"y":121.32,"z":476.6},{"x":-85.27,"y":121.11,"z":477.48},{"x":-83.17,"y":117.2,"z":478.83},{"x":-85.58,"y":113.45,"z":479.3},{"x":-90.13,"y":113.63,"z":478.43},{"x":-92.23,"y":117.59,"z":477.07}]},{"lat":-14.77,"lon":74.08,"b":[{"x":-133.58,"y":129.41,"z":464.08},{"x":-131.28,"y":129.36,"z":464.75},{"x":-130.27,"y":127.39,"z":465.57},{"x":-131.55,"y":125.46,"z":465.74},{"x":-133.87,"y":125.51,"z":465.06},{"x":-134.88,"y":127.49,"z":464.23}]},{"lat":-13.71,"lon":75.94,"b":[{"x":-120.03,"y":122.4,"z":469.61},{"x":-115.5,"y":122.26,"z":470.79},{"x":-113.45,"y":118.35,"z":472.28},{"x":-115.94,"y":114.53,"z":472.62},{"x":-120.51,"y":114.65,"z":471.44},{"x":-122.55,"y":118.61,"z":469.93}]},{"lat":-12.64,"lon":77.78,"b":[{"x":-105.34,"y":113.34,"z":475.38},{"x":-100.79,"y":113.17,"z":476.4},{"x":-98.69,"y":109.21,"z":477.76},{"x":-101.14,"y":105.38,"z":478.11},{"x":-105.72,"y":105.52,"z":477.09},{"x":-107.82,"y":109.52,"z":475.71}]},{"lat":-11.55,"lon":79.61,"b":[{"x":-89.81,"y":102.81,"z":480.95},{"x":-86.76,"y":102.69,"z":481.53},{"x":-85.33,"y":100.02,"z":482.35},{"x":-86.95,"y":97.43,"z":482.59},{"x":-90.02,"y":97.54,"z":482},{"x":-91.45,"y":100.24,"z":481.18}]},{"lat":-11.66,"lon":75.94,"b":[{"x":-120.75,"y":104.54,"z":473.73},{"x":-116.79,"y":104.43,"z":474.75},{"x":-114.98,"y":100.97,"z":475.94},{"x":-117.12,"y":97.57,"z":476.12},{"x":-121.11,"y":97.66,"z":475.1},{"x":-122.93,"y":101.16,"z":473.9}]},{"lat":-10.58,"lon":77.78,"b":[{"x":-106.14,"y":95.86,"z":479.03},{"x":-101.56,"y":95.72,"z":480.05},{"x":-99.42,"y":91.68,"z":481.28},{"x":-101.86,"y":87.75,"z":481.51},{"x":-106.48,"y":87.87,"z":480.48},{"x":-108.62,"y":91.94,"z":479.24}]},{"lat":-9.5,"lon":79.61,"b":[{"x":-89.7,"y":83.83,"z":484.66},{"x":-88.18,"y":83.78,"z":484.95},{"x":-87.46,"y":82.43,"z":485.31},{"x":-88.25,"y":81.13,"z":485.39},{"x":-89.78,"y":81.17,"z":485.1},{"x":-90.5,"y":82.53,"z":484.74}]},{"lat":-8.4,"lon":81.41,"b":[{"x":-74.59,"y":74.35,"z":488.75},{"x":-73.16,"y":74.3,"z":488.98},{"x":-72.47,"y":73.03,"z":489.27},{"x":-73.21,"y":71.79,"z":489.34},{"x":-74.65,"y":71.83,"z":489.12},{"x":-75.34,"y":73.12,"z":488.83}]},{"lat":-9.59,"lon":75.94,"b":[{"x":-120.13,"y":83.97,"z":478.02},{"x":-119.35,"y":83.95,"z":478.22},{"x":-118.98,"y":83.25,"z":478.43},{"x":-119.4,"y":82.57,"z":478.44},{"x":-120.19,"y":82.59,"z":478.24},{"x":-120.56,"y":83.29,"z":478.03}]},{"lat":-8.5,"lon":77.78,"b":[{"x":-106.6,"y":77.58,"z":482.23},{"x":-102.47,"y":77.47,"z":483.14},{"x":-100.52,"y":73.81,"z":484.13},{"x":-102.69,"y":70.22,"z":484.2},{"x":-106.84,"y":70.3,"z":483.29},{"x":-108.8,"y":74,"z":482.3}]},{"lat":-7.41,"lon":79.61,"b":[{"x":-90.35,"y":66.16,"z":487.26},{"x":-88.49,"y":66.11,"z":487.61},{"x":-87.6,"y":64.45,"z":487.99},{"x":-88.57,"y":62.83,"z":488.03},{"x":-90.43,"y":62.87,"z":487.68},{"x":-91.32,"y":64.54,"z":487.3}]},{"lat":-6.32,"lon":81.41,"b":[{"x":-75.86,"y":58.05,"z":490.73},{"x":-72.54,"y":57.95,"z":491.24},{"x":-70.93,"y":54.97,"z":491.82},{"x":-72.63,"y":52.06,"z":491.89},{"x":-75.97,"y":52.13,"z":491.38},{"x":-77.59,"y":55.14,"z":490.8}]},{"lat":-11.14,"lon":50.4,"b":[{"x":-313.6,"y":99.56,"z":376.41},{"x":-310.87,"y":99.8,"z":378.6},{"x":-309.88,"y":96.83,"z":380.19},{"x":-311.64,"y":93.61,"z":379.55},{"x":-314.38,"y":93.4,"z":377.33},{"x":-315.35,"y":96.38,"z":375.78}]},{"lat":-10.05,"lon":48.74,"b":[{"x":-325.79,"y":90.87,"z":368.15},{"x":-322.57,"y":91.17,"z":370.9},{"x":-321.38,"y":87.5,"z":372.81},{"x":-323.46,"y":83.53,"z":371.93},{"x":-326.69,"y":83.29,"z":369.15},{"x":-327.84,"y":86.96,"z":367.28}]},{"lat":-9.15,"lon":50.4,"b":[{"x":-315.63,"y":82.6,"z":378.81},{"x":-312.86,"y":82.81,"z":381.05},{"x":-311.78,"y":79.72,"z":382.59},{"x":-313.51,"y":76.42,"z":381.85},{"x":-316.29,"y":76.25,"z":379.59},{"x":-317.33,"y":79.34,"z":378.08}]},{"lat":-8.96,"lon":47.11,"b":[{"x":-337.22,"y":81.54,"z":359.96},{"x":-334.14,"y":81.82,"z":362.75},{"x":-332.99,"y":78.15,"z":364.62},{"x":-334.96,"y":74.2,"z":363.64},{"x":-338.04,"y":73.97,"z":360.82},{"x":-339.16,"y":77.63,"z":359}]},{"lat":-8.07,"lon":48.74,"b":[{"x":-327.67,"y":73.9,"z":370.28},{"x":-324.44,"y":74.15,"z":373.06},{"x":-323.17,"y":70.39,"z":374.89},{"x":-325.16,"y":66.39,"z":373.89},{"x":-328.4,"y":66.19,"z":371.09},{"x":-329.64,"y":69.95,"z":369.3}]},{"lat":-7.89,"lon":45.51,"b":[{"x":-348.09,"y":72.27,"z":351.5},{"x":-345.15,"y":72.54,"z":354.32},{"x":-344.04,"y":68.87,"z":356.14},{"x":-345.89,"y":64.93,"z":355.08},{"x":-348.83,"y":64.72,"z":352.23},{"x":-349.91,"y":68.38,"z":350.46}]},{"lat":-6.99,"lon":47.11,"b":[{"x":-338.93,"y":64.6,"z":361.78},{"x":-335.85,"y":64.84,"z":364.6},{"x":-334.61,"y":61.08,"z":366.39},{"x":-336.49,"y":57.1,"z":365.31},{"x":-339.58,"y":56.92,"z":362.46},{"x":-340.79,"y":60.67,"z":360.72}]},{"lat":-6.07,"lon":48.74,"b":[{"x":-328.93,"y":55.92,"z":372.32},{"x":-326.33,"y":56.08,"z":374.58},{"x":-325.23,"y":52.99,"z":375.98},{"x":-326.77,"y":49.76,"z":375.09},{"x":-329.37,"y":49.64,"z":372.82},{"x":-330.44,"y":52.72,"z":371.45}]},{"lat":-6.83,"lon":43.96,"b":[{"x":-358.38,"y":63.09,"z":342.81},{"x":-355.59,"y":63.34,"z":345.66},{"x":-354.5,"y":59.68,"z":347.43},{"x":-356.24,"y":55.77,"z":346.3},{"x":-359.03,"y":55.58,"z":343.43},{"x":-360.09,"y":59.23,"z":341.71}]},{"lat":-5.93,"lon":45.51,"b":[{"x":-349.62,"y":55.4,"z":353.04},{"x":-346.68,"y":55.61,"z":355.89},{"x":-345.47,"y":51.87,"z":357.63},{"x":-347.24,"y":47.92,"z":356.46},{"x":-350.18,"y":47.76,"z":353.6},{"x":-351.35,"y":51.5,"z":351.91}]},{"lat":-5.01,"lon":47.11,"b":[{"x":-340.26,"y":47.44,"z":363.19},{"x":-337.17,"y":47.62,"z":366.04},{"x":-335.84,"y":43.79,"z":367.73},{"x":-337.63,"y":39.8,"z":366.54},{"x":-340.72,"y":39.68,"z":363.68},{"x":-342.02,"y":43.49,"z":362.03}]},{"lat":-5.79,"lon":42.44,"b":[{"x":-368.1,"y":54.03,"z":333.96},{"x":-365.45,"y":54.26,"z":336.81},{"x":-364.39,"y":50.61,"z":338.53},{"x":-366.01,"y":46.74,"z":337.33},{"x":-368.66,"y":46.58,"z":334.46},{"x":-369.69,"y":50.22,"z":332.8}]},{"lat":-4.89,"lon":43.96,"b":[{"x":-359.72,"y":46.32,"z":344.09},{"x":-356.92,"y":46.51,"z":346.96},{"x":-355.75,"y":42.78,"z":348.65},{"x":-357.39,"y":38.87,"z":347.42},{"x":-360.19,"y":38.74,"z":344.53},{"x":-361.33,"y":42.46,"z":342.9}]},{"lat":-3.96,"lon":45.51,"b":[{"x":-350.75,"y":38.34,"z":354.18},{"x":-347.81,"y":38.5,"z":357.05},{"x":-346.51,"y":34.68,"z":358.7},{"x":-348.18,"y":30.73,"z":357.44},{"x":-351.12,"y":30.64,"z":354.55},{"x":-352.39,"y":34.43,"z":352.95}]},{"lat":-3.01,"lon":47.11,"b":[{"x":-340.53,"y":28.22,"z":364.97},{"x":-338.95,"y":28.28,"z":366.43},{"x":-338.23,"y":26.3,"z":367.25},{"x":-339.09,"y":24.26,"z":366.59},{"x":-340.67,"y":24.23,"z":365.12},{"x":-341.38,"y":26.21,"z":364.33}]},{"lat":-4.76,"lon":40.96,"b":[{"x":-377.23,"y":45.12,"z":324.97},{"x":-374.72,"y":45.32,"z":327.82},{"x":-373.69,"y":41.69,"z":329.48},{"x":-375.19,"y":37.87,"z":328.24},{"x":-377.7,"y":37.74,"z":325.37},{"x":-378.7,"y":41.35,"z":323.76}]},{"lat":-3.87,"lon":42.44,"b":[{"x":-369.23,"y":37.39,"z":334.98},{"x":-366.58,"y":37.55,"z":337.86},{"x":-365.43,"y":33.84,"z":339.5},{"x":-366.96,"y":29.97,"z":338.21},{"x":-369.6,"y":29.88,"z":335.32},{"x":-370.73,"y":33.57,"z":333.73}]},{"lat":-2.94,"lon":43.96,"b":[{"x":-360.65,"y":29.39,"z":344.98},{"x":-357.85,"y":29.52,"z":347.86},{"x":-356.58,"y":25.73,"z":349.46},{"x":-358.14,"y":21.82,"z":348.14},{"x":-360.93,"y":21.76,"z":345.25},{"x":-362.17,"y":25.53,"z":343.69}]},{"lat":-1.98,"lon":45.51,"b":[{"x":-351.22,"y":20.4,"z":355.21},{"x":-348.85,"y":20.47,"z":357.53},{"x":-347.73,"y":17.36,"z":358.79},{"x":-349,"y":14.19,"z":357.69},{"x":-351.37,"y":14.17,"z":355.37},{"x":-352.46,"y":17.26,"z":354.15}]},{"lat":-3.76,"lon":39.52,"b":[{"x":-385.79,"y":36.39,"z":315.89},{"x":-383.43,"y":36.56,"z":318.73},{"x":-382.42,"y":32.94,"z":320.34},{"x":-383.8,"y":29.18,"z":319.05},{"x":-386.17,"y":29.07,"z":316.19},{"x":-387.15,"y":32.67,"z":314.64}]},{"lat":-2.86,"lon":40.96,"b":[{"x":-378.16,"y":28.63,"z":325.76},{"x":-375.65,"y":28.77,"z":328.63},{"x":-374.53,"y":25.07,"z":330.22},{"x":-375.93,"y":21.26,"z":328.88},{"x":-378.44,"y":21.19,"z":326},{"x":-379.54,"y":24.87,"z":324.47}]},{"lat":-1.94,"lon":42.44,"b":[{"x":-369.95,"y":20.62,"z":335.64},{"x":-367.3,"y":20.72,"z":338.52},{"x":-366.06,"y":16.95,"z":340.08},{"x":-367.49,"y":13.1,"z":338.7},{"x":-370.14,"y":13.07,"z":335.81},{"x":-371.36,"y":16.81,"z":334.3}]},{"lat":-0.98,"lon":43.96,"b":[{"x":-360.82,"y":11.35,"z":345.88},{"x":-358.77,"y":11.4,"z":348},{"x":-357.77,"y":8.58,"z":349.11},{"x":-358.84,"y":5.73,"z":348.07},{"x":-360.89,"y":5.73,"z":345.94},{"x":-361.87,"y":8.53,"z":344.86}]},{"lat":-2.78,"lon":38.12,"b":[{"x":-393.79,"y":27.84,"z":306.75},{"x":-391.56,"y":27.98,"z":309.58},{"x":-390.58,"y":24.38,"z":311.13},{"x":-391.84,"y":20.68,"z":309.8},{"x":-394.07,"y":20.61,"z":306.97},{"x":-395.04,"y":24.17,"z":305.47}]},{"lat":-1.88,"lon":39.52,"b":[{"x":-386.51,"y":20.07,"z":316.47},{"x":-384.14,"y":20.17,"z":319.33},{"x":-383.04,"y":16.5,"z":320.86},{"x":-384.33,"y":12.75,"z":319.49},{"x":-386.69,"y":12.72,"z":316.62},{"x":-387.77,"y":16.36,"z":315.14}]},{"lat":-0.95,"lon":40.96,"b":[{"x":-378.67,"y":12.04,"z":326.2},{"x":-376.16,"y":12.11,"z":329.08},{"x":-374.95,"y":8.37,"z":330.59},{"x":-376.26,"y":4.58,"z":329.17},{"x":-378.76,"y":4.58,"z":326.28},{"x":-379.95,"y":8.3,"z":324.83}]},{"lat":0,"lon":42.44,"b":[{"x":-370.21,"y":3.65,"z":335.96},{"x":-367.66,"y":3.68,"z":338.76},{"x":-366.37,"y":0,"z":340.18},{"x":-367.66,"y":-3.68,"z":338.76},{"x":-370.21,"y":-3.65,"z":335.96},{"x":-371.48,"y":0,"z":334.59}]},{"lat":-1.83,"lon":36.76,"b":[{"x":-401.25,"y":19.49,"z":297.61},{"x":-399.15,"y":19.6,"z":300.41},{"x":-398.18,"y":16.03,"z":301.9},{"x":-399.33,"y":12.39,"z":300.55},{"x":-401.43,"y":12.35,"z":297.74},{"x":-402.38,"y":15.89,"z":296.3}]},{"lat":-0.93,"lon":38.12,"b":[{"x":-394.3,"y":11.71,"z":307.15},{"x":-392.07,"y":11.78,"z":309.98},{"x":-390.99,"y":8.14,"z":311.46},{"x":-392.16,"y":4.46,"z":310.06},{"x":-394.39,"y":4.46,"z":307.22},{"x":-395.45,"y":8.07,"z":305.79}]},{"lat":0,"lon":39.52,"b":[{"x":-386.81,"y":3.68,"z":316.72},{"x":-384.44,"y":3.71,"z":319.58},{"x":-383.25,"y":0,"z":321.04},{"x":-384.44,"y":-3.71,"z":319.58},{"x":-386.81,"y":-3.68,"z":316.72},{"x":-387.98,"y":0,"z":315.31}]},{"lat":0.95,"lon":40.96,"b":[{"x":-378.76,"y":-4.58,"z":326.28},{"x":-376.26,"y":-4.58,"z":329.17},{"x":-374.95,"y":-8.37,"z":330.59},{"x":-376.16,"y":-12.11,"z":329.08},{"x":-378.67,"y":-12.04,"z":326.2},{"x":-379.95,"y":-8.3,"z":324.83}]},{"lat":-0.9,"lon":35.44,"b":[{"x":-408.17,"y":11.37,"z":288.47},{"x":-406.2,"y":11.44,"z":291.24},{"x":-405.25,"y":7.9,"z":292.69},{"x":-406.29,"y":4.33,"z":291.31},{"x":-408.26,"y":4.33,"z":288.54},{"x":-409.2,"y":7.83,"z":287.15}]},{"lat":0,"lon":36.76,"b":[{"x":-401.54,"y":3.57,"z":297.82},{"x":-399.44,"y":3.61,"z":300.63},{"x":-398.38,"y":0,"z":302.06},{"x":-399.44,"y":-3.61,"z":300.63},{"x":-401.54,"y":-3.57,"z":297.82},{"x":-402.58,"y":0,"z":296.45}]},{"lat":0.93,"lon":38.12,"b":[{"x":-394.39,"y":-4.46,"z":307.22},{"x":-392.16,"y":-4.46,"z":310.06},{"x":-390.99,"y":-8.14,"z":311.46},{"x":-392.07,"y":-11.78,"z":309.98},{"x":-394.3,"y":-11.71,"z":307.15},{"x":-395.45,"y":-8.07,"z":305.79}]},{"lat":1.88,"lon":39.52,"b":[{"x":-386.69,"y":-12.72,"z":316.62},{"x":-384.33,"y":-12.75,"z":319.49},{"x":-383.04,"y":-16.5,"z":320.86},{"x":-384.14,"y":-20.17,"z":319.33},{"x":-386.51,"y":-20.07,"z":316.47},{"x":-387.77,"y":-16.36,"z":315.14}]},{"lat":2.86,"lon":40.96,"b":[{"x":-377.55,"y":-23.72,"z":326.9},{"x":-376.73,"y":-23.74,"z":327.86},{"x":-376.26,"y":-25,"z":328.3},{"x":-376.63,"y":-26.23,"z":327.78},{"x":-377.46,"y":-26.18,"z":326.83},{"x":-377.92,"y":-24.94,"z":326.4}]},{"lat":0,"lon":34.16,"b":[{"x":-414.59,"y":3.47,"z":279.39},{"x":-412.73,"y":3.5,"z":282.12},{"x":-411.8,"y":0,"z":283.51},{"x":-412.73,"y":-3.5,"z":282.12},{"x":-414.59,"y":-3.47,"z":279.39},{"x":-415.51,"y":0,"z":278.05}]},{"lat":0.9,"lon":35.44,"b":[{"x":-408.26,"y":-4.33,"z":288.54},{"x":-406.29,"y":-4.33,"z":291.31},{"x":-405.25,"y":-7.9,"z":292.69},{"x":-406.2,"y":-11.44,"z":291.24},{"x":-408.17,"y":-11.37,"z":288.47},{"x":-409.2,"y":-7.83,"z":287.15}]},{"lat":1.83,"lon":36.76,"b":[{"x":-401.43,"y":-12.35,"z":297.74},{"x":-399.33,"y":-12.39,"z":300.55},{"x":-398.18,"y":-16.03,"z":301.9},{"x":-399.15,"y":-19.6,"z":300.41},{"x":-401.25,"y":-19.49,"z":297.61},{"x":-402.38,"y":-15.89,"z":296.3}]},{"lat":2.78,"lon":38.12,"b":[{"x":-394.07,"y":-20.61,"z":306.97},{"x":-391.84,"y":-20.68,"z":309.8},{"x":-390.58,"y":-24.38,"z":311.13},{"x":-391.56,"y":-27.98,"z":309.58},{"x":-393.79,"y":-27.84,"z":306.75},{"x":-395.04,"y":-24.17,"z":305.47}]},{"lat":3.76,"lon":39.52,"b":[{"x":-386.07,"y":-29.34,"z":316.28},{"x":-383.88,"y":-29.43,"z":318.94},{"x":-382.59,"y":-32.93,"z":320.14},{"x":-383.53,"y":-36.29,"z":318.64},{"x":-385.73,"y":-36.13,"z":316},{"x":-386.99,"y":-32.68,"z":314.84}]},{"lat":0.87,"lon":32.92,"b":[{"x":-420.51,"y":-4.2,"z":270.38},{"x":-418.77,"y":-4.2,"z":273.07},{"x":-417.85,"y":-7.66,"z":274.41},{"x":-419.01,"y":-10.71,"z":272.53},{"x":-421.08,"y":-10.23,"z":269.34},{"x":-421.66,"y":-7.19,"z":268.53}]},{"lat":1.78,"lon":34.16,"b":[{"x":-414.48,"y":-11.99,"z":279.32},{"x":-412.62,"y":-12.02,"z":282.05},{"x":-411.6,"y":-15.56,"z":283.37},{"x":-412.78,"y":-18.65,"z":281.46},{"x":-414.96,"y":-18.15,"z":278.26},{"x":-415.64,"y":-15.03,"z":277.44}]},{"lat":2.7,"lon":35.44,"b":[{"x":-407.95,"y":-20.01,"z":288.32},{"x":-405.98,"y":-20.08,"z":291.09},{"x":-404.84,"y":-23.68,"z":292.39},{"x":-406.04,"y":-26.81,"z":290.46},{"x":-408.35,"y":-26.3,"z":287.24},{"x":-409.13,"y":-23.1,"z":286.41}]},{"lat":3.66,"lon":36.76,"b":[{"x":-400.91,"y":-28.25,"z":297.35},{"x":-398.81,"y":-28.35,"z":300.16},{"x":-397.57,"y":-32.01,"z":301.44},{"x":-398.78,"y":-35.19,"z":299.48},{"x":-401.22,"y":-34.66,"z":296.25},{"x":-402.11,"y":-31.38,"z":295.42}]},{"lat":4.63,"lon":38.12,"b":[{"x":-393.34,"y":-36.69,"z":306.4},{"x":-391.11,"y":-36.83,"z":309.23},{"x":-389.75,"y":-40.55,"z":310.48},{"x":-390.98,"y":-43.77,"z":308.49},{"x":-393.56,"y":-43.23,"z":305.27},{"x":-394.56,"y":-39.87,"z":304.44}]},{"lat":5.63,"lon":39.52,"b":[{"x":-384.17,"y":-48.18,"z":316.34},{"x":-383.6,"y":-48.22,"z":317.03},{"x":-383.25,"y":-49.13,"z":317.32},{"x":-383.55,"y":-49.92,"z":316.84},{"x":-384.2,"y":-49.78,"z":316.06},{"x":-384.47,"y":-48.95,"z":315.86}]},{"lat":14.97,"lon":50.23,"b":[{"x":-307.99,"y":-126.89,"z":372.82},{"x":-306.54,"y":-129.42,"z":373.14},{"x":-307.49,"y":-131.68,"z":371.57},{"x":-309.9,"y":-131.38,"z":369.66},{"x":-311.34,"y":-128.81,"z":369.36},{"x":-310.37,"y":-126.58,"z":370.94}]},{"lat":16.88,"lon":50.06,"b":[{"x":-306.72,"y":-144.06,"z":367.62},{"x":-305.99,"y":-145.29,"z":367.74},{"x":-306.43,"y":-146.39,"z":366.94},{"x":-307.6,"y":-146.25,"z":366.01},{"x":-308.33,"y":-145,"z":365.9},{"x":-307.89,"y":-143.91,"z":366.7}]},{"lat":18.83,"lon":49.87,"b":[{"x":-304.83,"y":-160.98,"z":362.15},{"x":-304.55,"y":-161.43,"z":362.18},{"x":-304.7,"y":-161.83,"z":361.88},{"x":-305.13,"y":-161.78,"z":361.54},{"x":-305.41,"y":-161.32,"z":361.51},{"x":-305.26,"y":-160.92,"z":361.82}]},{"lat":13.84,"lon":48.54,"b":[{"x":-320.78,"y":-118.13,"z":364.84},{"x":-319.86,"y":-119.84,"z":365.09},{"x":-320.51,"y":-121.36,"z":364.02},{"x":-322.11,"y":-121.13,"z":362.68},{"x":-323.02,"y":-119.39,"z":362.44},{"x":-322.36,"y":-117.9,"z":363.53}]},{"lat":15.73,"lon":48.32,"b":[{"x":-318.57,"y":-132.17,"z":361.9},{"x":-316.43,"y":-136,"z":362.36},{"x":-317.81,"y":-139.38,"z":359.86},{"x":-321.35,"y":-138.88,"z":356.9},{"x":-323.47,"y":-135.01,"z":356.46},{"x":-322.07,"y":-131.68,"z":358.97}]},{"lat":17.66,"lon":48.1,"b":[{"x":-316.79,"y":-148.25,"z":357.2},{"x":-314.54,"y":-152.13,"z":357.56},{"x":-315.84,"y":-155.55,"z":354.93},{"x":-319.43,"y":-155.05,"z":351.93},{"x":-321.66,"y":-151.13,"z":351.6},{"x":-320.33,"y":-147.75,"z":354.24}]},{"lat":19.63,"lon":47.87,"b":[{"x":-314.59,"y":-164.52,"z":351.98},{"x":-312.23,"y":-168.44,"z":352.23},{"x":-313.46,"y":-171.89,"z":349.46},{"x":-317.07,"y":-171.38,"z":346.44},{"x":-319.43,"y":-167.43,"z":346.21},{"x":-318.18,"y":-164.02,"z":348.98}]},{"lat":21.64,"lon":47.63,"b":[{"x":-311.97,"y":-180.92,"z":346.22},{"x":-309.49,"y":-184.86,"z":346.36},{"x":-310.63,"y":-188.33,"z":343.46},{"x":-314.28,"y":-187.82,"z":340.4},{"x":-316.75,"y":-183.85,"z":340.28},{"x":-315.59,"y":-180.42,"z":343.19}]},{"lat":23.69,"lon":47.38,"b":[{"x":-309.23,"y":-198.41,"z":339.04},{"x":-307.4,"y":-201.2,"z":339.07},{"x":-308.15,"y":-203.65,"z":336.92},{"x":-310.74,"y":-203.29,"z":334.75},{"x":-312.57,"y":-200.48,"z":334.74},{"x":-311.81,"y":-198.05,"z":336.89}]},{"lat":25.76,"lon":47.12,"b":[{"x":-306.29,"y":-216.89,"z":330.36},{"x":-305.95,"y":-217.39,"z":330.35},{"x":-306.07,"y":-217.82,"z":329.95},{"x":-306.53,"y":-217.75,"z":329.56},{"x":-306.87,"y":-217.26,"z":329.57},{"x":-306.75,"y":-216.83,"z":329.97}]},{"lat":16.48,"lon":46.38,"b":[{"x":-329.72,"y":-139.23,"z":349.07},{"x":-328.07,"y":-142.23,"z":349.4},{"x":-329.1,"y":-144.86,"z":347.35},{"x":-331.79,"y":-144.43,"z":344.96},{"x":-333.42,"y":-141.4,"z":344.64},{"x":-332.38,"y":-138.81,"z":346.7}]},{"lat":18.42,"lon":46.11,"b":[{"x":-327.55,"y":-154.64,"z":344.57},{"x":-325.31,"y":-158.56,"z":344.9},{"x":-326.56,"y":-161.97,"z":342.12},{"x":-330.07,"y":-161.42,"z":339.01},{"x":-332.28,"y":-157.46,"z":338.7},{"x":-331.02,"y":-154.1,"z":341.48}]},{"lat":20.41,"lon":45.83,"b":[{"x":-325.26,"y":-170.96,"z":338.97},{"x":-322.91,"y":-174.92,"z":339.2},{"x":-324.08,"y":-178.35,"z":336.29},{"x":-327.61,"y":-177.79,"z":333.15},{"x":-329.95,"y":-173.8,"z":332.94},{"x":-328.76,"y":-170.41,"z":335.86}]},{"lat":22.44,"lon":45.54,"b":[{"x":-322.52,"y":-187.39,"z":332.85},{"x":-320.05,"y":-191.36,"z":332.97},{"x":-321.13,"y":-194.8,"z":329.92},{"x":-324.7,"y":-194.23,"z":326.75},{"x":-327.15,"y":-190.23,"z":326.66},{"x":-326.06,"y":-186.83,"z":329.7}]},{"lat":24.49,"lon":45.24,"b":[{"x":-319.32,"y":-203.86,"z":326.19},{"x":-316.73,"y":-207.83,"z":326.2},{"x":-317.72,"y":-211.26,"z":323.02},{"x":-321.31,"y":-210.68,"z":319.83},{"x":-323.89,"y":-206.68,"z":319.84},{"x":-322.89,"y":-203.29,"z":323.02}]},{"lat":17.22,"lon":44.39,"b":[{"x":-340.67,"y":-146.5,"z":335.33},{"x":-339.71,"y":-148.28,"z":335.52},{"x":-340.29,"y":-149.81,"z":334.25},{"x":-341.83,"y":-149.54,"z":332.8},{"x":-342.77,"y":-147.74,"z":332.63},{"x":-342.19,"y":-146.23,"z":333.89}]},{"lat":19.18,"lon":44.08,"b":[{"x":-338.8,"y":-163.06,"z":329.54},{"x":-338.01,"y":-164.47,"z":329.65},{"x":-338.43,"y":-165.68,"z":328.61},{"x":-339.65,"y":-165.47,"z":327.46},{"x":-340.43,"y":-164.04,"z":327.36},{"x":-340.01,"y":-162.85,"z":328.4}]},{"lat":21.18,"lon":43.76,"b":[{"x":-336.42,"y":-179.66,"z":323.29},{"x":-335.76,"y":-180.8,"z":323.34},{"x":-336.07,"y":-181.77,"z":322.47},{"x":-337.05,"y":-181.59,"z":321.55},{"x":-337.72,"y":-180.45,"z":321.5},{"x":-337.4,"y":-179.49,"z":322.37}]},{"lat":23.21,"lon":43.42,"b":[{"x":-333.31,"y":-195.51,"z":317.24},{"x":-332.19,"y":-197.33,"z":317.29},{"x":-332.64,"y":-198.88,"z":315.84},{"x":-334.22,"y":-198.59,"z":314.35},{"x":-335.34,"y":-196.76,"z":314.32},{"x":-334.88,"y":-195.22,"z":315.76}]},{"lat":14.82,"lon":41.09,"b":[{"x":-363.96,"y":-127.13,"z":318.36},{"x":-363.52,"y":-128.07,"z":318.48},{"x":-363.83,"y":-128.86,"z":317.81},{"x":-364.58,"y":-128.7,"z":317.01},{"x":-365.01,"y":-127.76,"z":316.89},{"x":-364.7,"y":-126.98,"z":317.57}]},{"lat":11.82,"lon":39.9,"b":[{"x":-374.04,"y":-99.31,"z":316.5},{"x":-372.47,"y":-103.06,"z":317.15},{"x":-373.84,"y":-106.22,"z":314.48},{"x":-376.77,"y":-105.58,"z":311.17},{"x":-378.31,"y":-101.81,"z":310.57},{"x":-376.94,"y":-98.7,"z":313.23}]},{"lat":13.64,"lon":39.51,"b":[{"x":-373.5,"y":-114.73,"z":311.88},{"x":-371.82,"y":-118.55,"z":312.45},{"x":-373.12,"y":-121.76,"z":309.66},{"x":-376.09,"y":-121.1,"z":306.31},{"x":-377.73,"y":-117.25,"z":305.79},{"x":-376.44,"y":-114.09,"z":308.57}]},{"lat":15.5,"lon":39.12,"b":[{"x":-372.55,"y":-130.41,"z":306.81},{"x":-370.76,"y":-134.3,"z":307.29},{"x":-371.97,"y":-137.55,"z":304.39},{"x":-374.97,"y":-136.85,"z":301},{"x":-376.73,"y":-132.94,"z":300.56},{"x":-375.52,"y":-129.74,"z":303.46}]},{"lat":17.4,"lon":38.7,"b":[{"x":-371.73,"y":-147.88,"z":299.85},{"x":-370.74,"y":-149.92,"z":300.05},{"x":-371.32,"y":-151.62,"z":298.48},{"x":-372.89,"y":-151.24,"z":296.71},{"x":-373.86,"y":-149.18,"z":296.53},{"x":-373.28,"y":-147.51,"z":298.09}]},{"lat":7.27,"lon":39.16,"b":[{"x":-383.38,"y":-60.97,"z":315.05},{"x":-382.4,"y":-63.72,"z":315.69},{"x":-383.57,"y":-66.07,"z":313.78},{"x":-385.72,"y":-65.61,"z":311.23},{"x":-386.67,"y":-62.84,"z":310.63},{"x":-385.5,"y":-60.54,"z":312.54}]},{"lat":8.96,"lon":38.78,"b":[{"x":-383.53,"y":-74.84,"z":311.84},{"x":-382.2,"y":-78.44,"z":312.59},{"x":-383.63,"y":-81.49,"z":310.05},{"x":-386.4,"y":-80.87,"z":306.75},{"x":-387.7,"y":-77.25,"z":306.04},{"x":-386.27,"y":-74.26,"z":308.59}]},{"lat":10.69,"lon":38.39,"b":[{"x":-383.68,"y":-89.69,"z":307.71},{"x":-382.24,"y":-93.38,"z":308.4},{"x":-383.61,"y":-96.48,"z":305.74},{"x":-386.41,"y":-95.84,"z":302.39},{"x":-387.8,"y":-92.12,"z":301.76},{"x":-386.44,"y":-89.07,"z":304.42}]},{"lat":12.47,"lon":37.98,"b":[{"x":-383.44,"y":-104.85,"z":303.17},{"x":-381.91,"y":-108.63,"z":303.78},{"x":-383.2,"y":-111.78,"z":301},{"x":-386.02,"y":-111.1,"z":297.62},{"x":-387.53,"y":-107.31,"z":297.06},{"x":-386.24,"y":-104.21,"z":299.83}]},{"lat":14.3,"lon":37.56,"b":[{"x":-382.8,"y":-120.3,"z":298.2},{"x":-381.16,"y":-124.15,"z":298.72},{"x":-382.37,"y":-127.35,"z":295.82},{"x":-385.22,"y":-126.63,"z":292.41},{"x":-386.84,"y":-122.76,"z":291.93},{"x":-385.63,"y":-119.63,"z":294.82}]},{"lat":16.16,"lon":37.12,"b":[{"x":-381.73,"y":-136,"z":292.78},{"x":-379.97,"y":-139.91,"z":293.22},{"x":-381.09,"y":-143.13,"z":290.2},{"x":-383.97,"y":-142.38,"z":286.75},{"x":-385.7,"y":-138.45,"z":286.35},{"x":-384.58,"y":-135.28,"z":289.36}]},{"lat":18.07,"lon":36.66,"b":[{"x":-380.39,"y":-152.45,"z":286.35},{"x":-378.85,"y":-155.71,"z":286.65},{"x":-379.69,"y":-158.37,"z":284.06},{"x":-382.08,"y":-157.72,"z":281.21},{"x":-383.6,"y":-154.45,"z":280.95},{"x":-382.76,"y":-151.84,"z":283.52}]},{"lat":21.99,"lon":35.69,"b":[{"x":-376.41,"y":-186.66,"z":271.03},{"x":-376.05,"y":-187.34,"z":271.06},{"x":-376.19,"y":-187.89,"z":270.49},{"x":-376.69,"y":-187.75,"z":269.89},{"x":-377.04,"y":-187.06,"z":269.87},{"x":-376.91,"y":-186.52,"z":270.44}]},{"lat":23.99,"lon":35.17,"b":[{"x":-372.79,"y":-200.74,"z":265.83},{"x":-370.99,"y":-203.96,"z":265.89},{"x":-371.56,"y":-206.5,"z":263.13},{"x":-373.92,"y":-205.79,"z":260.32},{"x":-375.7,"y":-202.57,"z":260.29},{"x":-375.13,"y":-200.06,"z":263.04}]},{"lat":6.23,"lon":37.74,"b":[{"x":-391.54,"y":-51.42,"z":306.6},{"x":-390.41,"y":-54.85,"z":307.43},{"x":-391.9,"y":-57.77,"z":304.99},{"x":-394.5,"y":-57.2,"z":301.73},{"x":-395.59,"y":-53.74,"z":300.95},{"x":-394.11,"y":-50.88,"z":303.38}]},{"lat":7.88,"lon":37.34,"b":[{"x":-392.29,"y":-65.62,"z":302.9},{"x":-391.08,"y":-69.16,"z":303.67},{"x":-392.51,"y":-72.14,"z":301.13},{"x":-395.13,"y":-71.54,"z":297.81},{"x":-396.3,"y":-67.97,"z":297.09},{"x":-394.88,"y":-65.05,"z":299.64}]},{"lat":9.58,"lon":36.93,"b":[{"x":-392.7,"y":-80.19,"z":298.82},{"x":-391.4,"y":-83.82,"z":299.53},{"x":-392.77,"y":-86.86,"z":296.87},{"x":-395.42,"y":-86.22,"z":293.51},{"x":-396.68,"y":-82.57,"z":292.86},{"x":-395.33,"y":-79.58,"z":295.51}]},{"lat":11.32,"lon":36.5,"b":[{"x":-392.76,"y":-95.09,"z":294.34},{"x":-391.36,"y":-98.81,"z":294.98},{"x":-392.65,"y":-101.9,"z":292.2},{"x":-395.33,"y":-101.22,"z":288.8},{"x":-396.69,"y":-97.48,"z":288.22},{"x":-395.41,"y":-94.44,"z":290.98}]},{"lat":13.11,"lon":36.06,"b":[{"x":-392.42,"y":-110.29,"z":289.45},{"x":-390.91,"y":-114.08,"z":290.01},{"x":-392.12,"y":-117.22,"z":287.12},{"x":-394.83,"y":-116.5,"z":283.68},{"x":-396.3,"y":-112.68,"z":283.17},{"x":-395.1,"y":-109.61,"z":286.05}]},{"lat":14.94,"lon":35.59,"b":[{"x":-391.65,"y":-125.74,"z":284.13},{"x":-390.04,"y":-129.61,"z":284.61},{"x":-391.16,"y":-132.78,"z":281.6},{"x":-393.89,"y":-132.02,"z":278.13},{"x":-395.47,"y":-128.13,"z":277.7},{"x":-394.36,"y":-125.02,"z":280.69}]},{"lat":16.81,"lon":35.11,"b":[{"x":-390.44,"y":-141.41,"z":278.37},{"x":-388.71,"y":-145.34,"z":278.77},{"x":-389.73,"y":-148.53,"z":275.64},{"x":-392.48,"y":-147.73,"z":272.14},{"x":-394.19,"y":-143.79,"z":271.8},{"x":-393.17,"y":-140.65,"z":274.9}]},{"lat":18.71,"lon":34.61,"b":[{"x":-388.75,"y":-157.24,"z":272.17},{"x":-386.9,"y":-161.23,"z":272.48},{"x":-387.82,"y":-164.41,"z":269.25},{"x":-390.59,"y":-163.58,"z":265.72},{"x":-392.42,"y":-159.59,"z":265.46},{"x":-391.5,"y":-156.44,"z":268.67}]},{"lat":20.65,"lon":34.09,"b":[{"x":-386.59,"y":-173.29,"z":265.42},{"x":-384.68,"y":-177.17,"z":265.63},{"x":-385.47,"y":-180.24,"z":262.4},{"x":-388.17,"y":-179.39,"z":258.98},{"x":-390.05,"y":-175.51,"z":258.81},{"x":-389.27,"y":-172.48,"z":262.02}]},{"lat":22.62,"lon":33.55,"b":[{"x":-383.86,"y":-189.16,"z":258.46},{"x":-381.75,"y":-193.2,"z":258.59},{"x":-382.46,"y":-196.36,"z":255.13},{"x":-385.27,"y":-195.44,"z":251.58},{"x":-387.36,"y":-191.4,"z":251.49},{"x":-386.65,"y":-188.28,"z":254.91}]},{"lat":24.61,"lon":32.98,"b":[{"x":-380.62,"y":-205.12,"z":250.95},{"x":-378.39,"y":-209.17,"z":250.99},{"x":-378.99,"y":-212.29,"z":247.44},{"x":-381.82,"y":-211.33,"z":243.88},{"x":-384.03,"y":-207.29,"z":243.88},{"x":-383.44,"y":-204.2,"z":247.4}]},{"lat":26.63,"lon":32.39,"b":[{"x":-376.88,"y":-221.13,"z":242.87},{"x":-374.62,"y":-224.99,"z":242.82},{"x":-375.09,"y":-227.92,"z":239.34},{"x":-377.81,"y":-226.97,"z":235.94},{"x":-380.05,"y":-223.12,"z":236.02},{"x":-379.59,"y":-220.21,"z":239.47}]},{"lat":28.65,"lon":31.77,"b":[{"x":-372.58,"y":-236.84,"z":234.56},{"x":-370.19,"y":-240.68,"z":234.43},{"x":-370.56,"y":-243.55,"z":230.87},{"x":-373.29,"y":-242.56,"z":227.47},{"x":-375.66,"y":-238.74,"z":227.63},{"x":-375.3,"y":-235.89,"z":231.16}]},{"lat":30.69,"lon":31.13,"b":[{"x":-367.94,"y":-254.02,"z":223.74},{"x":-366.93,"y":-255.55,"z":223.65},{"x":-367.04,"y":-256.67,"z":222.19},{"x":-368.14,"y":-256.26,"z":220.83},{"x":-369.14,"y":-254.74,"z":220.92},{"x":-369.04,"y":-253.63,"z":222.37}]},{"lat":5.22,"lon":36.36,"b":[{"x":-399.46,"y":-42.67,"z":297.59},{"x":-398.46,"y":-46.03,"z":298.42},{"x":-399.94,"y":-48.89,"z":295.99},{"x":-402.4,"y":-48.33,"z":292.72},{"x":-403.36,"y":-44.94,"z":291.93},{"x":-401.9,"y":-42.14,"z":294.37}]},{"lat":6.83,"lon":35.94,"b":[{"x":-400.45,"y":-56.58,"z":293.91},{"x":-399.37,"y":-60.04,"z":294.69},{"x":-400.79,"y":-62.96,"z":292.14},{"x":-403.28,"y":-62.36,"z":288.82},{"x":-404.33,"y":-58.88,"z":288.09},{"x":-402.92,"y":-56.01,"z":290.63}]},{"lat":8.49,"lon":35.51,"b":[{"x":-401.13,"y":-70.85,"z":289.86},{"x":-399.96,"y":-74.41,"z":290.58},{"x":-401.31,"y":-77.39,"z":287.93},{"x":-403.82,"y":-76.76,"z":284.56},{"x":-404.96,"y":-73.17,"z":283.89},{"x":-403.62,"y":-70.25,"z":286.54}]},{"lat":10.19,"lon":35.07,"b":[{"x":-401.45,"y":-85.46,"z":285.43},{"x":-400.19,"y":-89.12,"z":286.09},{"x":-401.47,"y":-92.15,"z":283.32},{"x":-404,"y":-91.48,"z":279.91},{"x":-405.24,"y":-87.8,"z":279.31},{"x":-403.97,"y":-84.83,"z":282.06}]},{"lat":11.94,"lon":34.6,"b":[{"x":-401.4,"y":-100.39,"z":280.61},{"x":-400.03,"y":-104.13,"z":281.19},{"x":-401.23,"y":-107.21,"z":278.31},{"x":-403.79,"y":-106.49,"z":274.87},{"x":-405.12,"y":-102.73,"z":274.33},{"x":-403.93,"y":-99.71,"z":277.2}]},{"lat":13.73,"lon":34.12,"b":[{"x":-400.93,"y":-115.59,"z":275.37},{"x":-399.46,"y":-119.41,"z":275.88},{"x":-400.57,"y":-122.52,"z":272.89},{"x":-403.15,"y":-121.76,"z":269.41},{"x":-404.59,"y":-117.92,"z":268.95},{"x":-403.49,"y":-114.87,"z":271.93}]},{"lat":15.56,"lon":33.62,"b":[{"x":-400.02,"y":-131.02,"z":269.72},{"x":-398.43,"y":-134.91,"z":270.15},{"x":-399.45,"y":-138.04,"z":267.05},{"x":-402.05,"y":-137.24,"z":263.54},{"x":-403.61,"y":-133.34,"z":263.16},{"x":-402.6,"y":-130.26,"z":266.24}]},{"lat":17.43,"lon":33.1,"b":[{"x":-398.65,"y":-146.64,"z":263.65},{"x":-396.94,"y":-150.58,"z":263.99},{"x":-397.86,"y":-153.73,"z":260.78},{"x":-400.48,"y":-152.88,"z":257.24},{"x":-402.16,"y":-148.93,"z":256.95},{"x":-401.24,"y":-145.83,"z":260.13}]},{"lat":19.33,"lon":32.56,"b":[{"x":-396.78,"y":-162.39,"z":257.15},{"x":-394.95,"y":-166.38,"z":257.41},{"x":-395.77,"y":-169.52,"z":254.09},{"x":-398.41,"y":-168.62,"z":250.53},{"x":-400.21,"y":-164.63,"z":250.32},{"x":-399.4,"y":-161.54,"z":253.61}]},{"lat":21.26,"lon":31.99,"b":[{"x":-394.4,"y":-178.22,"z":250.22},{"x":-392.45,"y":-182.24,"z":250.4},{"x":-393.16,"y":-185.36,"z":246.98},{"x":-395.81,"y":-184.42,"z":243.41},{"x":-397.74,"y":-180.4,"z":243.28},{"x":-397.04,"y":-177.32,"z":246.67}]},{"lat":23.22,"lon":31.4,"b":[{"x":-391.5,"y":-194.06,"z":242.89},{"x":-389.42,"y":-198.1,"z":242.98},{"x":-390.01,"y":-201.18,"z":239.46},{"x":-392.69,"y":-200.2,"z":235.88},{"x":-394.75,"y":-196.17,"z":235.84},{"x":-394.16,"y":-193.12,"z":239.32}]},{"lat":25.2,"lon":30.79,"b":[{"x":-388.06,"y":-209.85,"z":235.15},{"x":-385.85,"y":-213.89,"z":235.16},{"x":-386.33,"y":-216.93,"z":231.55},{"x":-389.03,"y":-215.9,"z":227.97},{"x":-391.22,"y":-211.88,"z":228},{"x":-390.74,"y":-208.86,"z":231.58}]},{"lat":27.2,"lon":30.15,"b":[{"x":-384.08,"y":-225.52,"z":227.03},{"x":-381.74,"y":-229.54,"z":226.95},{"x":-382.11,"y":-232.52,"z":223.26},{"x":-384.82,"y":-231.46,"z":219.69},{"x":-387.14,"y":-227.45,"z":219.81},{"x":-386.78,"y":-224.49,"z":223.46}]},{"lat":29.2,"lon":29.49,"b":[{"x":-379.57,"y":-241.01,"z":218.56},{"x":-377.1,"y":-245,"z":218.39},{"x":-377.36,"y":-247.91,"z":214.63},{"x":-380.08,"y":-246.8,"z":211.07},{"x":-382.53,"y":-242.83,"z":211.26},{"x":-382.28,"y":-239.94,"z":214.99}]},{"lat":31.21,"lon":28.79,"b":[{"x":-374.53,"y":-256.24,"z":209.74},{"x":-371.93,"y":-260.19,"z":209.5},{"x":-372.09,"y":-263.01,"z":205.68},{"x":-374.82,"y":-261.87,"z":202.14},{"x":-377.39,"y":-257.94,"z":202.4},{"x":-377.25,"y":-255.14,"z":206.19}]},{"lat":33.22,"lon":28.07,"b":[{"x":-369.01,"y":-272.15,"z":199.27},{"x":-367.27,"y":-274.65,"z":199.06},{"x":-367.3,"y":-276.4,"z":196.57},{"x":-369.07,"y":-275.65,"z":194.31},{"x":-370.8,"y":-273.16,"z":194.52},{"x":-370.77,"y":-271.42,"z":196.99}]},{"lat":4.23,"lon":35.02,"b":[{"x":-406.84,"y":-34.12,"z":288.56},{"x":-405.95,"y":-37.4,"z":289.4},{"x":-407.41,"y":-40.2,"z":286.97},{"x":-409.74,"y":-39.65,"z":283.7},{"x":-410.59,"y":-36.34,"z":282.91},{"x":-409.15,"y":-33.61,"z":285.35}]},{"lat":5.8,"lon":34.59,"b":[{"x":-408.05,"y":-47.72,"z":284.89},{"x":-407.09,"y":-51.11,"z":285.68},{"x":-408.5,"y":-53.97,"z":283.14},{"x":-410.85,"y":-53.38,"z":279.82},{"x":-411.78,"y":-49.97,"z":279.09},{"x":-410.39,"y":-47.17,"z":281.62}]},{"lat":7.42,"lon":34.14,"b":[{"x":-408.97,"y":-61.69,"z":280.87},{"x":-407.92,"y":-65.18,"z":281.6},{"x":-409.26,"y":-68.1,"z":278.95},{"x":-411.63,"y":-67.47,"z":275.58},{"x":-412.65,"y":-63.96,"z":274.91},{"x":-411.32,"y":-61.1,"z":277.55}]},{"lat":9.08,"lon":33.68,"b":[{"x":-409.54,"y":-76,"z":276.48},{"x":-408.41,"y":-79.59,"z":277.15},{"x":-409.68,"y":-82.56,"z":274.39},{"x":-412.07,"y":-81.9,"z":270.98},{"x":-413.17,"y":-78.29,"z":270.37},{"x":-411.92,"y":-75.38,"z":273.11}]},{"lat":10.79,"lon":33.2,"b":[{"x":-409.75,"y":-90.64,"z":271.71},{"x":-408.52,"y":-94.32,"z":272.31},{"x":-409.71,"y":-97.34,"z":269.45},{"x":-412.12,"y":-96.62,"z":266},{"x":-413.32,"y":-92.93,"z":265.46},{"x":-412.14,"y":-89.97,"z":268.3}]},{"lat":12.54,"lon":32.7,"b":[{"x":-409.56,"y":-105.57,"z":266.55},{"x":-408.23,"y":-109.33,"z":267.08},{"x":-409.34,"y":-112.38,"z":264.11},{"x":-411.76,"y":-111.62,"z":260.63},{"x":-413.07,"y":-107.85,"z":260.15},{"x":-411.97,"y":-104.86,"z":263.11}]},{"lat":14.33,"lon":32.18,"b":[{"x":-408.95,"y":-120.74,"z":260.99},{"x":-407.5,"y":-124.58,"z":261.45},{"x":-408.52,"y":-127.66,"z":258.37},{"x":-410.96,"y":-126.85,"z":254.86},{"x":-412.38,"y":-123.01,"z":254.46},{"x":-411.38,"y":-119.99,"z":257.51}]},{"lat":16.16,"lon":31.64,"b":[{"x":-407.87,"y":-136.13,"z":255.03},{"x":-406.32,"y":-140.02,"z":255.41},{"x":-407.23,"y":-143.11,"z":252.22},{"x":-409.7,"y":-142.26,"z":248.68},{"x":-411.23,"y":-138.36,"z":248.36},{"x":-410.32,"y":-135.32,"z":251.52}]},{"lat":18.03,"lon":31.08,"b":[{"x":-406.32,"y":-151.67,"z":248.66},{"x":-404.64,"y":-155.61,"z":248.96},{"x":-405.45,"y":-158.71,"z":245.67},{"x":-407.94,"y":-157.8,"z":242.11},{"x":-409.59,"y":-153.86,"z":241.86},{"x":-408.79,"y":-150.81,"z":245.12}]},{"lat":19.92,"lon":30.5,"b":[{"x":-404.26,"y":-167.31,"z":241.88},{"x":-402.46,"y":-171.3,"z":242.1},{"x":-403.17,"y":-174.38,"z":238.71},{"x":-405.66,"y":-173.43,"z":235.14},{"x":-407.44,"y":-169.44,"z":234.97},{"x":-406.75,"y":-166.41,"z":238.33}]},{"lat":21.85,"lon":29.89,"b":[{"x":-401.69,"y":-183,"z":234.71},{"x":-399.76,"y":-187.01,"z":234.84},{"x":-400.35,"y":-190.06,"z":231.35},{"x":-402.87,"y":-189.06,"z":227.77},{"x":-404.77,"y":-185.06,"z":227.69},{"x":-404.19,"y":-182.04,"z":231.14}]},{"lat":23.79,"lon":29.26,"b":[{"x":-398.58,"y":-198.67,"z":227.14},{"x":-396.52,"y":-202.69,"z":227.19},{"x":-397,"y":-205.71,"z":223.62},{"x":-399.53,"y":-204.66,"z":220.04},{"x":-401.57,"y":-200.65,"z":220.03},{"x":-401.09,"y":-197.67,"z":223.57}]},{"lat":25.75,"lon":28.6,"b":[{"x":-394.93,"y":-214.26,"z":219.21},{"x":-392.74,"y":-218.28,"z":219.18},{"x":-393.1,"y":-221.24,"z":215.52},{"x":-395.65,"y":-220.15,"z":211.95},{"x":-397.82,"y":-216.14,"z":212.02},{"x":-397.46,"y":-213.21,"z":215.63}]},{"lat":27.73,"lon":27.92,"b":[{"x":-390.73,"y":-229.7,"z":210.92},{"x":-388.41,"y":-233.71,"z":210.81},{"x":-388.67,"y":-236.6,"z":207.09},{"x":-391.23,"y":-235.46,"z":203.52},{"x":-393.53,"y":-231.48,"z":203.67},{"x":-393.28,"y":-228.61,"z":207.35}]},{"lat":29.71,"lon":27.21,"b":[{"x":-386,"y":-244.94,"z":202.31},{"x":-383.56,"y":-248.91,"z":202.12},{"x":-383.7,"y":-251.72,"z":198.34},{"x":-386.28,"y":-250.54,"z":194.79},{"x":-388.7,"y":-246.59,"z":195.01},{"x":-388.57,"y":-243.8,"z":198.75}]},{"lat":31.69,"lon":26.47,"b":[{"x":-380.75,"y":-259.9,"z":193.41},{"x":-378.18,"y":-263.82,"z":193.14},{"x":-378.22,"y":-266.53,"z":189.31},{"x":-380.81,"y":-265.32,"z":185.78},{"x":-383.36,"y":-261.43,"z":186.07},{"x":-383.33,"y":-258.72,"z":189.86}]},{"lat":33.67,"lon":25.69,"b":[{"x":-374.99,"y":-274.74,"z":183.93},{"x":-372.52,"y":-278.29,"z":183.63},{"x":-372.46,"y":-280.68,"z":180.06},{"x":-374.86,"y":-279.53,"z":176.85},{"x":-377.3,"y":-276.02,"z":177.17},{"x":-377.38,"y":-273.62,"z":180.69}]},{"lat":3.26,"lon":33.73,"b":[{"x":-413.68,"y":-25.78,"z":279.56},{"x":-412.9,"y":-28.99,"z":280.4},{"x":-414.35,"y":-31.72,"z":277.96},{"x":-416.55,"y":-31.19,"z":274.7},{"x":-417.29,"y":-27.96,"z":273.93},{"x":-415.86,"y":-25.29,"z":276.36}]},{"lat":4.8,"lon":33.28,"b":[{"x":-415.1,"y":-39.07,"z":275.89},{"x":-414.25,"y":-42.38,"z":276.67},{"x":-415.64,"y":-45.18,"z":274.14},{"x":-417.86,"y":-44.61,"z":270.83},{"x":-418.67,"y":-41.28,"z":270.1},{"x":-417.3,"y":-38.54,"z":272.63}]},{"lat":6.38,"lon":32.82,"b":[{"x":-416.23,"y":-52.73,"z":271.88},{"x":-415.31,"y":-56.14,"z":272.61},{"x":-416.63,"y":-59,"z":269.97},{"x":-418.87,"y":-58.39,"z":266.62},{"x":-419.76,"y":-54.96,"z":265.95},{"x":-418.45,"y":-52.16,"z":268.57}]},{"lat":8,"lon":32.34,"b":[{"x":-417.04,"y":-66.74,"z":267.52},{"x":-416.03,"y":-70.25,"z":268.19},{"x":-417.29,"y":-73.16,"z":265.45},{"x":-419.54,"y":-72.5,"z":262.05},{"x":-420.52,"y":-68.98,"z":261.44},{"x":-419.28,"y":-66.12,"z":264.16}]},{"lat":9.67,"lon":31.84,"b":[{"x":-417.5,"y":-81.07,"z":262.8},{"x":-416.4,"y":-84.68,"z":263.41},{"x":-417.58,"y":-87.64,"z":260.56},{"x":-419.84,"y":-86.93,"z":257.13},{"x":-420.92,"y":-83.32,"z":256.58},{"x":-419.75,"y":-80.42,"z":259.4}]},{"lat":11.38,"lon":31.32,"b":[{"x":-417.57,"y":-95.71,"z":257.7},{"x":-416.37,"y":-99.4,"z":258.25},{"x":-417.47,"y":-102.4,"z":255.3},{"x":-419.75,"y":-101.65,"z":251.83},{"x":-420.92,"y":-97.95,"z":251.34},{"x":-419.84,"y":-95.01,"z":254.27}]},{"lat":13.13,"lon":30.79,"b":[{"x":-417.23,"y":-110.61,"z":252.23},{"x":-415.93,"y":-114.38,"z":252.7},{"x":-416.93,"y":-117.4,"z":249.65},{"x":-419.23,"y":-116.6,"z":246.15},{"x":-420.51,"y":-112.83,"z":245.73},{"x":-419.51,"y":-109.86,"z":248.76}]},{"lat":14.92,"lon":30.23,"b":[{"x":-416.45,"y":-125.74,"z":246.37},{"x":-415.03,"y":-129.58,"z":246.77},{"x":-415.94,"y":-132.62,"z":243.61},{"x":-418.25,"y":-131.76,"z":240.08},{"x":-419.64,"y":-127.92,"z":239.74},{"x":-418.75,"y":-124.94,"z":242.86}]},{"lat":16.75,"lon":29.66,"b":[{"x":-415.19,"y":-141.04,"z":240.11},{"x":-413.66,"y":-144.94,"z":240.44},{"x":-414.47,"y":-147.98,"z":237.18},{"x":-416.79,"y":-147.08,"z":233.63},{"x":-418.3,"y":-143.18,"z":233.36},{"x":-417.51,"y":-140.19,"z":236.59}]},{"lat":18.6,"lon":29.06,"b":[{"x":-413.45,"y":-156.47,"z":233.47},{"x":-411.79,"y":-160.42,"z":233.72},{"x":-412.49,"y":-163.46,"z":230.36},{"x":-414.83,"y":-162.5,"z":226.8},{"x":-416.47,"y":-158.56,"z":226.6},{"x":-415.78,"y":-155.57,"z":229.92}]},{"lat":20.49,"lon":28.44,"b":[{"x":-411.19,"y":-171.98,"z":226.45},{"x":-409.41,"y":-175.96,"z":226.61},{"x":-410,"y":-178.98,"z":223.16},{"x":-412.36,"y":-177.97,"z":219.59},{"x":-414.11,"y":-174,"z":219.48},{"x":-413.53,"y":-171.02,"z":222.88}]},{"lat":22.39,"lon":27.79,"b":[{"x":-408.4,"y":-187.5,"z":219.05},{"x":-406.49,"y":-191.5,"z":219.13},{"x":-406.97,"y":-194.48,"z":215.6},{"x":-409.34,"y":-193.43,"z":212.02},{"x":-411.23,"y":-189.44,"z":211.98},{"x":-410.76,"y":-186.49,"z":215.47}]},{"lat":24.32,"lon":27.12,"b":[{"x":-405.08,"y":-202.97,"z":211.29},{"x":-403.04,"y":-206.99,"z":211.29},{"x":-403.4,"y":-209.92,"z":207.68},{"x":-405.79,"y":-208.81,"z":204.11},{"x":-407.81,"y":-204.82,"z":204.15},{"x":-407.45,"y":-201.92,"z":207.71}]},{"lat":26.26,"lon":26.43,"b":[{"x":-401.21,"y":-218.34,"z":203.19},{"x":-399.04,"y":-222.35,"z":203.12},{"x":-399.29,"y":-225.22,"z":199.44},{"x":-401.69,"y":-224.06,"z":195.87},{"x":-403.84,"y":-220.08,"z":195.98},{"x":-403.6,"y":-217.23,"z":199.62}]},{"lat":28.21,"lon":25.7,"b":[{"x":-396.8,"y":-233.54,"z":194.77},{"x":-394.5,"y":-237.52,"z":194.62},{"x":-394.64,"y":-240.32,"z":190.88},{"x":-397.06,"y":-239.11,"z":187.34},{"x":-399.33,"y":-235.16,"z":187.52},{"x":-399.21,"y":-232.38,"z":191.21}]},{"lat":30.17,"lon":24.94,"b":[{"x":-391.86,"y":-248.5,"z":186.06},{"x":-389.44,"y":-252.45,"z":185.85},{"x":-389.46,"y":-255.15,"z":182.06},{"x":-391.9,"y":-253.91,"z":178.53},{"x":-394.3,"y":-250,"z":178.78},{"x":-394.28,"y":-247.3,"z":182.52}]},{"lat":32.12,"lon":24.16,"b":[{"x":-386.4,"y":-263.17,"z":177.1},{"x":-383.85,"y":-267.06,"z":176.81},{"x":-383.77,"y":-269.67,"z":172.98},{"x":-386.23,"y":-268.38,"z":169.49},{"x":-388.75,"y":-264.53,"z":169.8},{"x":-388.84,"y":-261.92,"z":173.58}]},{"lat":34.06,"lon":23.34,"b":[{"x":-380.42,"y":-278.03,"z":167.09},{"x":-378.32,"y":-281.04,"z":166.82},{"x":-378.18,"y":-283,"z":163.78},{"x":-380.13,"y":-281.96,"z":161.06},{"x":-382.2,"y":-278.99,"z":161.35},{"x":-382.35,"y":-277.02,"z":164.34}]},{"lat":2.33,"lon":32.47,"b":[{"x":-420.01,"y":-17.67,"z":270.61},{"x":-419.33,"y":-20.79,"z":271.44},{"x":-420.76,"y":-23.47,"z":269.01},{"x":-422.84,"y":-22.96,"z":265.77},{"x":-423.48,"y":-19.81,"z":265},{"x":-422.07,"y":-17.2,"z":267.42}]},{"lat":3.82,"lon":32.01,"b":[{"x":-421.62,"y":-30.64,"z":266.93},{"x":-420.88,"y":-33.87,"z":267.7},{"x":-422.25,"y":-36.61,"z":265.18},{"x":-424.34,"y":-36.06,"z":261.89},{"x":-425.04,"y":-32.81,"z":261.17},{"x":-423.69,"y":-30.13,"z":263.69}]},{"lat":5.36,"lon":31.53,"b":[{"x":-422.95,"y":-43.98,"z":262.92},{"x":-422.13,"y":-47.31,"z":263.65},{"x":-423.44,"y":-50.11,"z":261.03},{"x":-425.55,"y":-49.52,"z":257.69},{"x":-426.33,"y":-46.17,"z":257.03},{"x":-425.04,"y":-43.43,"z":259.63}]},{"lat":6.95,"lon":31.04,"b":[{"x":-423.97,"y":-57.67,"z":258.59},{"x":-423.08,"y":-61.11,"z":259.26},{"x":-424.32,"y":-63.96,"z":256.54},{"x":-426.43,"y":-63.32,"z":253.16},{"x":-427.3,"y":-59.87,"z":252.55},{"x":-426.07,"y":-57.08,"z":255.25}]},{"lat":8.58,"lon":30.53,"b":[{"x":-424.66,"y":-71.7,"z":253.91},{"x":-423.68,"y":-75.23,"z":254.52},{"x":-424.84,"y":-78.13,"z":251.69},{"x":-426.97,"y":-77.44,"z":248.28},{"x":-427.92,"y":-73.91,"z":247.72},{"x":-426.77,"y":-71.06,"z":250.53}]},{"lat":10.25,"lon":30,"b":[{"x":-424.98,"y":-86.04,"z":248.87},{"x":-423.9,"y":-89.66,"z":249.42},{"x":-424.98,"y":-92.59,"z":246.49},{"x":-427.12,"y":-91.86,"z":243.04},{"x":-428.17,"y":-88.23,"z":242.55},{"x":-427.1,"y":-85.35,"z":245.45}]},{"lat":11.96,"lon":29.45,"b":[{"x":-424.89,"y":-100.65,"z":243.47},{"x":-423.72,"y":-104.35,"z":243.95},{"x":-424.71,"y":-107.32,"z":240.92},{"x":-426.86,"y":-106.53,"z":237.44},{"x":-428.01,"y":-102.83,"z":237.01},{"x":-427.03,"y":-99.91,"z":240.01}]},{"lat":13.7,"lon":28.88,"b":[{"x":-424.38,"y":-115.5,"z":237.69},{"x":-423.1,"y":-119.28,"z":238.11},{"x":-424,"y":-122.26,"z":234.98},{"x":-426.16,"y":-121.42,"z":231.47},{"x":-427.42,"y":-117.65,"z":231.12},{"x":-426.53,"y":-114.71,"z":234.21}]},{"lat":15.49,"lon":28.29,"b":[{"x":-423.41,"y":-130.55,"z":231.55},{"x":-422.02,"y":-134.39,"z":231.89},{"x":-422.82,"y":-137.38,"z":228.67},{"x":-424.99,"y":-136.49,"z":225.14},{"x":-426.36,"y":-132.65,"z":224.85},{"x":-425.58,"y":-129.71,"z":228.04}]},{"lat":17.3,"lon":27.68,"b":[{"x":-421.96,"y":-145.75,"z":225.03},{"x":-420.46,"y":-149.64,"z":225.3},{"x":-421.14,"y":-152.63,"z":221.98},{"x":-423.33,"y":-151.68,"z":218.43},{"x":-424.82,"y":-147.8,"z":218.22},{"x":-424.14,"y":-144.85,"z":221.5}]},{"lat":19.15,"lon":27.05,"b":[{"x":-420.01,"y":-161.04,"z":218.14},{"x":-418.38,"y":-164.98,"z":218.34},{"x":-418.96,"y":-167.96,"z":214.93},{"x":-421.17,"y":-166.95,"z":211.37},{"x":-422.78,"y":-163.03,"z":211.23},{"x":-422.2,"y":-160.09,"z":214.6}]},{"lat":21.02,"lon":26.39,"b":[{"x":-417.54,"y":-176.39,"z":210.9},{"x":-415.78,"y":-180.36,"z":211.02},{"x":-416.25,"y":-183.3,"z":207.53},{"x":-418.47,"y":-182.24,"z":203.97},{"x":-420.21,"y":-178.29,"z":203.9},{"x":-419.75,"y":-175.38,"z":207.34}]},{"lat":22.91,"lon":25.71,"b":[{"x":-414.54,"y":-191.72,"z":203.31},{"x":-412.65,"y":-195.71,"z":203.35},{"x":-413.01,"y":-198.61,"z":199.78},{"x":-415.24,"y":-197.49,"z":196.22},{"x":-417.1,"y":-193.53,"z":196.23},{"x":-416.76,"y":-190.66,"z":199.75}]},{"lat":24.82,"lon":25,"b":[{"x":-410.99,"y":-206.98,"z":195.38},{"x":-408.98,"y":-210.97,"z":195.35},{"x":-409.22,"y":-213.81,"z":191.72},{"x":-411.47,"y":-212.65,"z":188.17},{"x":-413.46,"y":-208.68,"z":188.24},{"x":-413.23,"y":-205.86,"z":191.83}]},{"lat":26.73,"lon":24.26,"b":[{"x":-406.91,"y":-222.1,"z":187.15},{"x":-404.76,"y":-226.08,"z":187.05},{"x":-404.89,"y":-228.86,"z":183.35},{"x":-407.15,"y":-227.64,"z":179.82},{"x":-409.28,"y":-223.69,"z":179.96},{"x":-409.16,"y":-220.93,"z":183.61}]},{"lat":28.65,"lon":23.5,"b":[{"x":-402.28,"y":-237.03,"z":178.64},{"x":-400.01,"y":-240.98,"z":178.46},{"x":-400.03,"y":-243.68,"z":174.72},{"x":-402.31,"y":-242.41,"z":171.21},{"x":-404.56,"y":-238.5,"z":171.42},{"x":-404.55,"y":-235.81,"z":175.11}]},{"lat":30.58,"lon":22.7,"b":[{"x":-397.14,"y":-251.7,"z":169.87},{"x":-394.74,"y":-255.61,"z":169.63},{"x":-394.65,"y":-258.22,"z":165.85},{"x":-396.95,"y":-256.91,"z":162.36},{"x":-399.32,"y":-253.04,"z":162.63},{"x":-399.42,"y":-250.44,"z":166.36}]},{"lat":32.5,"lon":21.87,"b":[{"x":-391.48,"y":-266.06,"z":160.88},{"x":-388.96,"y":-269.92,"z":160.58},{"x":-388.77,"y":-272.42,"z":156.77},{"x":-391.08,"y":-271.07,"z":153.32},{"x":-393.57,"y":-267.26,"z":153.64},{"x":-393.78,"y":-264.76,"z":157.4}]},{"lat":34.4,"lon":21.01,"b":[{"x":-385.29,"y":-280.5,"z":151.03},{"x":-383.13,"y":-283.61,"z":150.73},{"x":-382.89,"y":-285.57,"z":147.59},{"x":-384.81,"y":-284.43,"z":144.78},{"x":-386.95,"y":-281.36,"z":145.09},{"x":-387.2,"y":-279.39,"z":148.19}]},{"lat":1.41,"lon":31.26,"b":[{"x":-425.85,"y":-9.78,"z":261.74},{"x":-425.27,"y":-12.83,"z":262.55},{"x":-426.68,"y":-15.44,"z":260.13},{"x":-428.56,"y":-14.28,"z":257.08},{"x":-429.01,"y":-10.52,"z":256.51},{"x":-427.7,"y":-8.64,"z":258.75}]},{"lat":2.87,"lon":30.78,"b":[{"x":-427.63,"y":-22.44,"z":258.04},{"x":-426.99,"y":-25.58,"z":258.8},{"x":-428.34,"y":-28.26,"z":256.29},{"x":-430.25,"y":-27.08,"z":253.2},{"x":-430.78,"y":-23.24,"z":252.67},{"x":-429.51,"y":-21.28,"z":255}]},{"lat":4.38,"lon":30.29,"b":[{"x":-429.14,"y":-35.46,"z":254.04},{"x":-428.43,"y":-38.71,"z":254.75},{"x":-429.72,"y":-41.45,"z":252.14},{"x":-431.66,"y":-40.25,"z":249.01},{"x":-432.28,"y":-36.33,"z":248.53},{"x":-431.05,"y":-34.28,"z":250.95}]},{"lat":5.92,"lon":29.79,"b":[{"x":-430.36,"y":-48.84,"z":249.71},{"x":-429.57,"y":-52.19,"z":250.38},{"x":-430.8,"y":-54.98,"z":247.67},{"x":-432.76,"y":-53.77,"z":244.5},{"x":-433.48,"y":-49.78,"z":244.07},{"x":-432.29,"y":-47.64,"z":246.58}]},{"lat":7.51,"lon":29.26,"b":[{"x":-431.25,"y":-62.55,"z":245.06},{"x":-430.39,"y":-66,"z":245.67},{"x":-431.54,"y":-68.84,"z":242.87},{"x":-433.53,"y":-67.61,"z":239.65},{"x":-434.34,"y":-63.55,"z":239.28},{"x":-433.22,"y":-61.34,"z":241.89}]},{"lat":9.14,"lon":28.72,"b":[{"x":-431.79,"y":-76.58,"z":240.07},{"x":-430.84,"y":-80.11,"z":240.63},{"x":-431.91,"y":-83,"z":237.72},{"x":-433.92,"y":-81.75,"z":234.46},{"x":-434.85,"y":-77.64,"z":234.14},{"x":-433.78,"y":-75.35,"z":236.85}]},{"lat":10.81,"lon":28.16,"b":[{"x":-431.95,"y":-90.89,"z":234.74},{"x":-430.9,"y":-94.51,"z":235.23},{"x":-431.88,"y":-97.42,"z":232.23},{"x":-433.92,"y":-96.16,"z":228.93},{"x":-434.96,"y":-92,"z":228.66},{"x":-433.97,"y":-89.64,"z":231.47}]},{"lat":12.52,"lon":27.58,"b":[{"x":-431.69,"y":-105.45,"z":229.05},{"x":-430.55,"y":-109.15,"z":229.47},{"x":-431.43,"y":-112.09,"z":226.38},{"x":-433.49,"y":-110.81,"z":223.04},{"x":-434.65,"y":-106.62,"z":222.83},{"x":-433.73,"y":-104.19,"z":225.75}]},{"lat":14.26,"lon":26.98,"b":[{"x":-431,"y":-120.22,"z":223},{"x":-429.74,"y":-124,"z":223.35},{"x":-430.53,"y":-126.94,"z":220.17},{"x":-432.61,"y":-125.66,"z":216.8},{"x":-433.88,"y":-121.44,"z":216.65},{"x":-433.06,"y":-118.95,"z":219.66}]},{"lat":16.03,"lon":26.36,"b":[{"x":-429.83,"y":-135.17,"z":216.59},{"x":-428.46,"y":-139,"z":216.88},{"x":-429.14,"y":-141.95,"z":213.6},{"x":-431.24,"y":-140.65,"z":210.2},{"x":-432.64,"y":-136.42,"z":210.11},{"x":-431.91,"y":-133.88,"z":213.22}]},{"lat":17.84,"lon":25.72,"b":[{"x":-428.17,"y":-150.23,"z":209.84},{"x":-426.69,"y":-154.12,"z":210.05},{"x":-427.26,"y":-157.06,"z":206.69},{"x":-429.38,"y":-155.75,"z":203.26},{"x":-430.9,"y":-151.52,"z":203.23},{"x":-430.27,"y":-148.94,"z":206.44}]},{"lat":19.67,"lon":25.05,"b":[{"x":-426.01,"y":-165.37,"z":202.74},{"x":-424.4,"y":-169.3,"z":202.88},{"x":-424.86,"y":-172.21,"z":199.43},{"x":-426.99,"y":-170.89,"z":195.98},{"x":-428.65,"y":-166.67,"z":196},{"x":-428.13,"y":-164.07,"z":199.31}]},{"lat":21.52,"lon":24.36,"b":[{"x":-423.32,"y":-180.53,"z":195.3},{"x":-421.58,"y":-184.48,"z":195.37},{"x":-421.93,"y":-187.36,"z":191.85},{"x":-424.07,"y":-186.03,"z":188.38},{"x":-425.86,"y":-181.84,"z":188.45},{"x":-425.45,"y":-179.21,"z":191.85}]},{"lat":23.39,"lon":23.64,"b":[{"x":-420.09,"y":-195.65,"z":187.55},{"x":-418.23,"y":-199.61,"z":187.54},{"x":-418.46,"y":-202.44,"z":183.96},{"x":-420.61,"y":-201.11,"z":180.48},{"x":-422.53,"y":-196.96,"z":180.59},{"x":-422.24,"y":-194.32,"z":184.08}]},{"lat":25.27,"lon":22.89,"b":[{"x":-416.33,"y":-210.67,"z":179.5},{"x":-414.34,"y":-214.63,"z":179.42},{"x":-414.46,"y":-217.39,"z":175.78},{"x":-416.62,"y":-216.06,"z":172.29},{"x":-418.65,"y":-211.97,"z":172.44},{"x":-418.48,"y":-209.34,"z":176.01}]},{"lat":27.16,"lon":22.12,"b":[{"x":-412.03,"y":-225.53,"z":171.17},{"x":-409.91,"y":-229.48,"z":171.03},{"x":-409.91,"y":-232.16,"z":167.34},{"x":-412.08,"y":-230.83,"z":163.84},{"x":-414.23,"y":-226.8,"z":164.03},{"x":-414.19,"y":-224.2,"z":167.68}]},{"lat":29.05,"lon":21.32,"b":[{"x":-407.2,"y":-240.18,"z":162.6},{"x":-404.95,"y":-244.09,"z":162.39},{"x":-404.85,"y":-246.69,"z":158.66},{"x":-407.01,"y":-245.35,"z":155.15},{"x":-409.28,"y":-241.42,"z":155.38},{"x":-409.36,"y":-238.84,"z":159.09}]},{"lat":30.94,"lon":20.48,"b":[{"x":-401.85,"y":-254.55,"z":153.8},{"x":-399.47,"y":-258.42,"z":153.53},{"x":-399.27,"y":-260.92,"z":149.77},{"x":-401.44,"y":-259.59,"z":146.27},{"x":-403.8,"y":-255.74,"z":146.53},{"x":-404.01,"y":-253.21,"z":150.3}]},{"lat":32.83,"lon":19.62,"b":[{"x":-396,"y":-268.59,"z":144.82},{"x":-393.51,"y":-272.4,"z":144.5},{"x":-393.21,"y":-274.8,"z":140.72},{"x":-395.37,"y":-273.47,"z":137.23},{"x":-397.83,"y":-269.73,"z":137.5},{"x":-398.16,"y":-267.26,"z":141.32}]},{"lat":34.7,"lon":18.72,"b":[{"x":-389.46,"y":-283.85,"z":133.13},{"x":-388.62,"y":-285.05,"z":133.01},{"x":-388.49,"y":-285.79,"z":131.8},{"x":-389.19,"y":-285.36,"z":130.68},{"x":-390.01,"y":-284.2,"z":130.77},{"x":-390.15,"y":-283.42,"z":132.01}]},{"lat":84.95,"lon":-180,"b":[{"x":46.68,"y":-497.76,"z":-1.46},{"x":44.06,"y":-498,"z":-2.92},{"x":41.34,"y":-498.24,"z":-1.46},{"x":41.34,"y":-498.24,"z":1.46},{"x":44.06,"y":-498,"z":2.92},{"x":46.68,"y":-497.76,"z":1.46}]},{"lat":86.97,"lon":-180,"b":[{"x":30.45,"y":-499,"z":-2.16},{"x":26.53,"y":-499.21,"z":-4.32},{"x":22.51,"y":-499.42,"z":-2.16},{"x":22.51,"y":-499.42,"z":2.16},{"x":26.53,"y":-499.21,"z":4.32},{"x":30.45,"y":-499,"z":2.16}]},{"lat":88.99,"lon":-180,"b":[{"x":12.82,"y":-499.76,"z":-2.16},{"x":8.85,"y":-499.84,"z":-4.33},{"x":4.86,"y":-499.9,"z":-2.17},{"x":4.86,"y":-499.9,"z":2.17},{"x":8.85,"y":-499.84,"z":4.33},{"x":12.82,"y":-499.76,"z":2.16}]},{"lat":88.99,"lon":0,"b":[{"x":-4.86,"y":-499.9,"z":-2.17},{"x":-8.85,"y":-499.84,"z":-4.33},{"x":-12.82,"y":-499.76,"z":-2.16},{"x":-12.82,"y":-499.76,"z":2.16},{"x":-8.85,"y":-499.84,"z":4.33},{"x":-4.86,"y":-499.9,"z":2.17}]},{"lat":86.97,"lon":0,"b":[{"x":-22.51,"y":-499.42,"z":-2.16},{"x":-26.53,"y":-499.21,"z":-4.32},{"x":-30.45,"y":-499,"z":-2.16},{"x":-30.45,"y":-499,"z":2.16},{"x":-26.53,"y":-499.21,"z":4.32},{"x":-22.51,"y":-499.42,"z":2.16}]},{"lat":84.95,"lon":0,"b":[{"x":-40.09,"y":-498.32,"z":-2.16},{"x":-44.11,"y":-497.96,"z":-4.31},{"x":-47.97,"y":-497.62,"z":-2.15},{"x":-47.97,"y":-497.62,"z":2.15},{"x":-44.11,"y":-497.96,"z":4.31},{"x":-40.09,"y":-498.32,"z":2.16}]},{"lat":82.95,"lon":0,"b":[{"x":-57.52,"y":-496.61,"z":-2.15},{"x":-61.52,"y":-496.12,"z":-4.3},{"x":-65.31,"y":-495.64,"z":-2.14},{"x":-65.31,"y":-495.64,"z":2.14},{"x":-61.52,"y":-496.12,"z":4.3},{"x":-57.52,"y":-496.61,"z":2.15}]},{"lat":80.97,"lon":0,"b":[{"x":-74.73,"y":-494.31,"z":-2.14},{"x":-78.71,"y":-493.68,"z":-4.28},{"x":-82.41,"y":-493.09,"z":-2.13},{"x":-82.41,"y":-493.09,"z":2.13},{"x":-78.71,"y":-493.68,"z":4.28},{"x":-74.73,"y":-494.31,"z":2.14}]},{"lat":79.01,"lon":0,"b":[{"x":-91.68,"y":-491.45,"z":-2.13},{"x":-95.62,"y":-490.69,"z":-4.25},{"x":-99.22,"y":-489.98,"z":-2.12},{"x":-99.22,"y":-489.98,"z":2.12},{"x":-95.62,"y":-490.69,"z":4.25},{"x":-91.68,"y":-491.45,"z":2.13}]},{"lat":77.07,"lon":0,"b":[{"x":-108.31,"y":-488.06,"z":-2.12},{"x":-112.19,"y":-487.17,"z":-4.22},{"x":-115.69,"y":-486.36,"z":-2.1},{"x":-115.69,"y":-486.36,"z":2.1},{"x":-112.19,"y":-487.17,"z":4.22},{"x":-108.31,"y":-488.06,"z":2.12}]},{"lat":75.16,"lon":0,"b":[{"x":-124.57,"y":-484.16,"z":-2.1},{"x":-128.39,"y":-483.15,"z":-4.18},{"x":-131.77,"y":-482.25,"z":-2.08},{"x":-131.77,"y":-482.25,"z":2.08},{"x":-128.39,"y":-483.15,"z":4.18},{"x":-124.57,"y":-484.16,"z":2.1}]},{"lat":73.29,"lon":0,"b":[{"x":-140.42,"y":-479.81,"z":-2.08},{"x":-144.16,"y":-478.69,"z":-4.14},{"x":-147.42,"y":-477.7,"z":-2.06},{"x":-147.42,"y":-477.7,"z":2.06},{"x":-144.16,"y":-478.69,"z":4.14},{"x":-140.42,"y":-479.81,"z":2.08}]},{"lat":71.45,"lon":0,"b":[{"x":-158.38,"y":-474.24,"z":-0.42},{"x":-159.13,"y":-473.99,"z":-0.84},{"x":-159.77,"y":-473.77,"z":-0.42},{"x":-159.77,"y":-473.77,"z":0.42},{"x":-159.13,"y":-473.99,"z":0.84},{"x":-158.38,"y":-474.24,"z":0.42}]},{"lat":80.2,"lon":-160.22,"b":[{"x":79.98,"y":-492.77,"z":-27.54},{"x":81.12,"y":-492.55,"z":-28.15},{"x":81.19,"y":-492.46,"z":-29.4},{"x":80.11,"y":-492.6,"z":-30.05},{"x":78.96,"y":-492.82,"z":-29.43},{"x":78.9,"y":-492.91,"z":-28.17}]},{"lat":78.53,"lon":-154.11,"b":[{"x":89.23,"y":-490.33,"z":-39.4},{"x":92.86,"y":-489.49,"z":-41.36},{"x":93.08,"y":-489.09,"z":-45.39},{"x":89.64,"y":-489.53,"z":-47.5},{"x":85.97,"y":-490.38,"z":-45.52},{"x":85.78,"y":-490.77,"z":-41.46}]},{"lat":76.74,"lon":-149.53,"b":[{"x":98.82,"y":-486.72,"z":-57.68},{"x":99.24,"y":-486.61,"z":-57.91},{"x":99.27,"y":-486.55,"z":-58.39},{"x":98.87,"y":-486.6,"z":-58.64},{"x":98.44,"y":-486.71,"z":-58.41},{"x":98.41,"y":-486.77,"z":-57.93}]},{"lat":83.67,"lon":-164.91,"b":[{"x":53.19,"y":-496.97,"z":-13.24},{"x":54.23,"y":-496.84,"z":-13.79},{"x":54.28,"y":-496.8,"z":-14.92},{"x":53.27,"y":-496.89,"z":-15.5},{"x":52.22,"y":-497.02,"z":-14.93},{"x":52.18,"y":-497.06,"z":-13.8}]},{"lat":82.07,"lon":-155.19,"b":[{"x":62.49,"y":-495.32,"z":-26.78},{"x":64.46,"y":-495.01,"z":-27.84},{"x":64.56,"y":-494.86,"z":-30.01},{"x":62.66,"y":-495.04,"z":-31.12},{"x":60.66,"y":-495.36,"z":-30.04},{"x":60.59,"y":-495.49,"z":-27.86}]},{"lat":80.31,"lon":-148.75,"b":[{"x":71.86,"y":-493.07,"z":-40.9},{"x":74.38,"y":-492.58,"z":-42.25},{"x":74.5,"y":-492.31,"z":-45.05},{"x":72.08,"y":-492.54,"z":-46.49},{"x":69.53,"y":-493.03,"z":-45.12},{"x":69.43,"y":-493.29,"z":-42.31}]},{"lat":78.43,"lon":-144.28,"b":[{"x":81.2,"y":-490.32,"z":-54.04},{"x":85.23,"y":-489.39,"z":-56.21},{"x":85.43,"y":-488.82,"z":-60.72},{"x":81.56,"y":-489.18,"z":-63.08},{"x":77.49,"y":-490.12,"z":-60.89},{"x":77.32,"y":-490.68,"z":-56.35}]},{"lat":76.49,"lon":-141.03,"b":[{"x":90.63,"y":-486.69,"z":-69.66},{"x":94,"y":-485.79,"z":-71.47},{"x":94.17,"y":-485.18,"z":-75.27},{"x":90.93,"y":-485.48,"z":-77.29},{"x":87.52,"y":-486.39,"z":-75.47},{"x":87.39,"y":-487,"z":-71.64}]},{"lat":85.6,"lon":-157.98,"b":[{"x":35.5,"y":-498.56,"z":-10.78},{"x":38.87,"y":-498.27,"z":-12.58},{"x":38.98,"y":-498.15,"z":-16.24},{"x":35.68,"y":-498.34,"z":-18.09},{"x":32.28,"y":-498.63,"z":-16.26},{"x":32.21,"y":-498.74,"z":-12.59}]},{"lat":83.86,"lon":-147.09,"b":[{"x":44.74,"y":-497.32,"z":-24.64},{"x":48.78,"y":-496.82,"z":-26.82},{"x":48.93,"y":-496.54,"z":-31.25},{"x":44.99,"y":-496.77,"z":-33.51},{"x":40.9,"y":-497.27,"z":-31.3},{"x":40.8,"y":-497.54,"z":-26.86}]},{"lat":81.98,"lon":-141.03,"b":[{"x":54.08,"y":-495.43,"z":-39.41},{"x":58.15,"y":-494.79,"z":-41.6},{"x":58.31,"y":-494.37,"z":-46.09},{"x":54.36,"y":-494.6,"z":-48.4},{"x":50.25,"y":-495.25,"z":-46.18},{"x":50.13,"y":-495.66,"z":-41.67}]},{"lat":80.02,"lon":-137.24,"b":[{"x":63.48,"y":-492.9,"z":-54.32},{"x":67.56,"y":-492.11,"z":-56.52},{"x":67.72,"y":-491.54,"z":-61.06},{"x":63.77,"y":-491.77,"z":-63.41},{"x":59.66,"y":-492.57,"z":-61.19},{"x":59.53,"y":-493.13,"z":-56.64}]},{"lat":78,"lon":-134.68,"b":[{"x":72.91,"y":-489.7,"z":-69.34},{"x":76.98,"y":-488.76,"z":-71.53},{"x":77.15,"y":-488.04,"z":-76.1},{"x":73.2,"y":-488.27,"z":-78.5},{"x":69.09,"y":-489.22,"z":-76.29},{"x":68.96,"y":-489.93,"z":-71.69}]},{"lat":75.96,"lon":-132.83,"b":[{"x":82.32,"y":-485.83,"z":-84.39},{"x":86.38,"y":-484.74,"z":-86.56},{"x":86.54,"y":-483.87,"z":-91.15},{"x":82.61,"y":-484.09,"z":-93.59},{"x":78.51,"y":-485.19,"z":-91.4},{"x":78.38,"y":-486.05,"z":-86.79}]},{"lat":87.37,"lon":-141.03,"b":[{"x":17.78,"y":-499.51,"z":-10.1},{"x":21.79,"y":-499.3,"z":-12.26},{"x":21.87,"y":-499.17,"z":-16.63},{"x":17.88,"y":-499.25,"z":-18.84},{"x":13.84,"y":-499.46,"z":-16.64},{"x":13.81,"y":-499.59,"z":-12.27}]},{"lat":85.45,"lon":-132.83,"b":[{"x":26.91,"y":-498.59,"z":-24.71},{"x":30.97,"y":-498.24,"z":-26.9},{"x":31.07,"y":-497.98,"z":-31.34},{"x":27.06,"y":-498.06,"z":-33.6},{"x":22.97,"y":-498.41,"z":-31.37},{"x":22.92,"y":-498.68,"z":-26.92}]},{"lat":83.45,"lon":-129.49,"b":[{"x":36.17,"y":-497.05,"z":-39.54},{"x":40.26,"y":-496.55,"z":-41.75},{"x":40.37,"y":-496.14,"z":-46.26},{"x":36.36,"y":-496.23,"z":-48.56},{"x":32.24,"y":-496.73,"z":-46.31},{"x":32.17,"y":-497.14,"z":-41.8}]},{"lat":81.41,"lon":-127.69,"b":[{"x":45.53,"y":-494.85,"z":-54.54},{"x":49.63,"y":-494.21,"z":-56.77},{"x":49.76,"y":-493.65,"z":-61.32},{"x":45.74,"y":-493.74,"z":-63.67},{"x":41.59,"y":-494.39,"z":-61.42},{"x":41.51,"y":-494.94,"z":-56.85}]},{"lat":79.35,"lon":-126.56,"b":[{"x":54.94,"y":-491.99,"z":-69.66},{"x":59.05,"y":-491.19,"z":-71.89},{"x":59.18,"y":-490.48,"z":-76.48},{"x":55.16,"y":-490.57,"z":-78.87},{"x":51.01,"y":-491.38,"z":-76.62},{"x":50.92,"y":-492.08,"z":-72.01}]},{"lat":77.26,"lon":-125.79,"b":[{"x":64.37,"y":-488.45,"z":-84.85},{"x":68.49,"y":-487.5,"z":-87.05},{"x":68.61,"y":-486.63,"z":-91.67},{"x":64.6,"y":-486.72,"z":-94.09},{"x":60.45,"y":-487.68,"z":-91.87},{"x":60.35,"y":-488.54,"z":-87.23}]},{"lat":75.15,"lon":-125.23,"b":[{"x":73.85,"y":-483.8,"z":-102.14},{"x":76.08,"y":-483.21,"z":-103.32},{"x":76.15,"y":-482.65,"z":-105.84},{"x":73.97,"y":-482.69,"z":-107.18},{"x":71.72,"y":-483.3,"z":-105.98},{"x":71.67,"y":-483.85,"z":-103.46}]},{"lat":88.35,"lon":-90,"b":[{"x":0,"y":-499.83,"z":-10.11},{"x":4,"y":-499.76,"z":-12.27},{"x":4.03,"y":-499.64,"z":-16.64},{"x":0,"y":-499.57,"z":-18.85},{"x":-4.03,"y":-499.64,"z":-16.64},{"x":-4,"y":-499.76,"z":-12.27}]},{"lat":86.5,"lon":-107.17,"b":[{"x":8.98,"y":-499.24,"z":-24.74},{"x":13.03,"y":-499.03,"z":-26.94},{"x":13.08,"y":-498.77,"z":-31.39},{"x":9.03,"y":-498.71,"z":-33.64},{"x":4.96,"y":-498.92,"z":-31.4},{"x":4.96,"y":-499.18,"z":-26.95}]},{"lat":84.53,"lon":-112.39,"b":[{"x":18.12,"y":-498.03,"z":-39.61},{"x":22.21,"y":-497.68,"z":-41.84},{"x":22.28,"y":-497.27,"z":-46.36},{"x":18.21,"y":-497.22,"z":-48.66},{"x":14.1,"y":-497.57,"z":-46.39},{"x":14.07,"y":-497.97,"z":-41.87}]},{"lat":82.5,"lon":-114.87,"b":[{"x":27.39,"y":-496.17,"z":-54.69},{"x":31.51,"y":-495.67,"z":-56.93},{"x":31.59,"y":-495.12,"z":-61.5},{"x":27.51,"y":-495.07,"z":-63.84},{"x":23.36,"y":-495.57,"z":-61.56},{"x":23.32,"y":-496.12,"z":-56.98}]},{"lat":80.43,"lon":-116.31,"b":[{"x":36.75,"y":-493.65,"z":-69.9},{"x":40.89,"y":-493,"z":-72.15},{"x":40.98,"y":-492.29,"z":-76.76},{"x":36.9,"y":-492.24,"z":-79.14},{"x":32.73,"y":-492.89,"z":-76.86},{"x":32.67,"y":-493.6,"z":-72.23}]},{"lat":78.34,"lon":-117.25,"b":[{"x":46.17,"y":-490.44,"z":-85.19},{"x":50.32,"y":-489.64,"z":-87.44},{"x":50.42,"y":-488.78,"z":-92.07},{"x":46.33,"y":-488.72,"z":-94.48},{"x":42.15,"y":-489.53,"z":-92.22},{"x":42.09,"y":-490.39,"z":-87.57}]},{"lat":76.23,"lon":-117.91,"b":[{"x":55.61,"y":-486.55,"z":-100.51},{"x":59.76,"y":-485.59,"z":-102.73},{"x":59.85,"y":-484.57,"z":-107.38},{"x":55.77,"y":-484.51,"z":-109.82},{"x":51.59,"y":-485.47,"z":-107.58},{"x":51.53,"y":-486.49,"z":-102.91}]},{"lat":74.11,"lon":-118.4,"b":[{"x":65.11,"y":-481.06,"z":-119.68},{"x":65.78,"y":-480.88,"z":-120.04},{"x":65.79,"y":-480.69,"z":-120.78},{"x":65.14,"y":-480.68,"z":-121.18},{"x":64.47,"y":-480.86,"z":-120.83},{"x":64.46,"y":-481.05,"z":-120.08}]},{"lat":87.37,"lon":-38.97,"b":[{"x":-17.78,"y":-499.51,"z":-10.1},{"x":-13.81,"y":-499.59,"z":-12.27},{"x":-13.84,"y":-499.46,"z":-16.64},{"x":-17.88,"y":-499.25,"z":-18.84},{"x":-21.87,"y":-499.17,"z":-16.63},{"x":-21.79,"y":-499.3,"z":-12.26}]},{"lat":86.5,"lon":-72.83,"b":[{"x":-8.98,"y":-499.24,"z":-24.74},{"x":-4.96,"y":-499.18,"z":-26.95},{"x":-4.96,"y":-498.92,"z":-31.4},{"x":-9.03,"y":-498.71,"z":-33.64},{"x":-13.08,"y":-498.77,"z":-31.39},{"x":-13.03,"y":-499.03,"z":-26.94}]},{"lat":84.94,"lon":-90,"b":[{"x":0,"y":-498.35,"z":-39.64},{"x":4.08,"y":-498.15,"z":-41.88},{"x":4.1,"y":-497.75,"z":-46.41},{"x":0,"y":-497.55,"z":-48.69},{"x":-4.1,"y":-497.75,"z":-46.41},{"x":-4.08,"y":-498.15,"z":-41.88}]},{"lat":83.11,"lon":-98.78,"b":[{"x":9.14,"y":-496.83,"z":-54.76},{"x":13.26,"y":-496.48,"z":-57.03},{"x":13.3,"y":-495.93,"z":-61.61},{"x":9.18,"y":-495.73,"z":-63.93},{"x":5.04,"y":-496.08,"z":-61.63},{"x":5.04,"y":-496.63,"z":-57.04}]},{"lat":81.15,"lon":-103.89,"b":[{"x":18.41,"y":-494.65,"z":-70.04},{"x":22.56,"y":-494.15,"z":-72.32},{"x":22.62,"y":-493.45,"z":-76.94},{"x":18.49,"y":-493.25,"z":-79.3},{"x":14.31,"y":-493.75,"z":-76.99},{"x":14.29,"y":-494.45,"z":-72.36}]},{"lat":79.13,"lon":-107.17,"b":[{"x":27.78,"y":-491.79,"z":-85.43},{"x":31.95,"y":-491.13,"z":-87.7},{"x":32.01,"y":-490.27,"z":-92.36},{"x":27.88,"y":-490.07,"z":-94.74},{"x":23.68,"y":-490.73,"z":-92.44},{"x":23.65,"y":-491.59,"z":-87.78}]},{"lat":77.07,"lon":-109.45,"b":[{"x":37.2,"y":-488.23,"z":-100.85},{"x":41.38,"y":-487.42,"z":-103.12},{"x":41.45,"y":-486.4,"z":-107.78},{"x":37.31,"y":-486.19,"z":-110.2},{"x":33.1,"y":-487.01,"z":-107.92},{"x":33.06,"y":-488.03,"z":-103.24}]},{"lat":74.97,"lon":-111.12,"b":[{"x":46.7,"y":-483.18,"z":-119.72},{"x":47.78,"y":-482.93,"z":-120.3},{"x":47.79,"y":-482.62,"z":-121.51},{"x":46.72,"y":-482.57,"z":-122.14},{"x":45.64,"y":-482.82,"z":-121.56},{"x":45.62,"y":-483.12,"z":-120.35}]},{"lat":85.6,"lon":-22.02,"b":[{"x":-35.48,"y":-498.57,"z":-10.08},{"x":-31.56,"y":-498.78,"z":-12.24},{"x":-31.64,"y":-498.65,"z":-16.61},{"x":-35.7,"y":-498.3,"z":-18.8},{"x":-39.64,"y":-498.08,"z":-16.59},{"x":-39.5,"y":-498.22,"z":-12.23}]},{"lat":85.45,"lon":-47.17,"b":[{"x":-26.91,"y":-498.59,"z":-24.71},{"x":-22.92,"y":-498.68,"z":-26.92},{"x":-22.97,"y":-498.41,"z":-31.37},{"x":-27.06,"y":-498.06,"z":-33.6},{"x":-31.07,"y":-497.98,"z":-31.34},{"x":-30.97,"y":-498.24,"z":-26.9}]},{"lat":84.53,"lon":-67.61,"b":[{"x":-18.12,"y":-498.03,"z":-39.61},{"x":-14.07,"y":-497.97,"z":-41.87},{"x":-14.1,"y":-497.57,"z":-46.39},{"x":-18.21,"y":-497.22,"z":-48.66},{"x":-22.28,"y":-497.27,"z":-46.36},{"x":-22.21,"y":-497.68,"z":-41.84}]},{"lat":83.11,"lon":-81.22,"b":[{"x":-9.14,"y":-496.83,"z":-54.76},{"x":-5.04,"y":-496.63,"z":-57.04},{"x":-5.04,"y":-496.08,"z":-61.63},{"x":-9.18,"y":-495.73,"z":-63.93},{"x":-13.3,"y":-495.93,"z":-61.61},{"x":-13.26,"y":-496.48,"z":-57.03}]},{"lat":81.41,"lon":-90,"b":[{"x":0,"y":-494.99,"z":-70.09},{"x":4.14,"y":-494.64,"z":-72.39},{"x":4.16,"y":-493.94,"z":-77.02},{"x":0,"y":-493.58,"z":-79.35},{"x":-4.16,"y":-493.94,"z":-77.02},{"x":-4.14,"y":-494.64,"z":-72.39}]},{"lat":79.55,"lon":-95.88,"b":[{"x":9.27,"y":-492.46,"z":-85.54},{"x":13.45,"y":-491.96,"z":-87.85},{"x":13.48,"y":-491.1,"z":-92.51},{"x":9.3,"y":-490.75,"z":-94.87},{"x":5.11,"y":-491.25,"z":-92.54},{"x":5.11,"y":-492.11,"z":-87.87}]},{"lat":77.6,"lon":-100.01,"b":[{"x":18.64,"y":-489.24,"z":-101.06},{"x":22.84,"y":-488.59,"z":-103.36},{"x":22.88,"y":-487.57,"z":-108.04},{"x":18.69,"y":-487.21,"z":-110.43},{"x":14.48,"y":-487.87,"z":-108.11},{"x":14.46,"y":-488.89,"z":-103.42}]},{"lat":75.58,"lon":-103.05,"b":[{"x":28.09,"y":-484.66,"z":-119.48},{"x":29.7,"y":-484.35,"z":-120.35},{"x":29.72,"y":-483.9,"z":-122.14},{"x":28.12,"y":-483.76,"z":-123.07},{"x":26.5,"y":-484.08,"z":-122.19},{"x":26.49,"y":-484.53,"z":-120.39}]},{"lat":73.53,"lon":-105.36,"b":[{"x":37.55,"y":-479.63,"z":-136.13},{"x":38.08,"y":-479.51,"z":-136.42},{"x":38.08,"y":-479.34,"z":-137},{"x":37.56,"y":-479.29,"z":-137.31},{"x":37.03,"y":-479.42,"z":-137.02},{"x":37.02,"y":-479.58,"z":-136.44}]},{"lat":83.67,"lon":-15.09,"b":[{"x":-53.06,"y":-497.01,"z":-10.05},{"x":-49.2,"y":-497.35,"z":-12.21},{"x":-49.33,"y":-497.21,"z":-16.57},{"x":-53.38,"y":-496.72,"z":-18.74},{"x":-57.25,"y":-496.37,"z":-16.53},{"x":-57.06,"y":-496.52,"z":-12.19}]},{"lat":83.86,"lon":-32.91,"b":[{"x":-44.74,"y":-497.32,"z":-24.64},{"x":-40.8,"y":-497.54,"z":-26.86},{"x":-40.9,"y":-497.27,"z":-31.3},{"x":-44.99,"y":-496.77,"z":-33.51},{"x":-48.93,"y":-496.54,"z":-31.25},{"x":-48.78,"y":-496.82,"z":-26.82}]},{"lat":83.45,"lon":-50.51,"b":[{"x":-36.17,"y":-497.05,"z":-39.54},{"x":-32.17,"y":-497.14,"z":-41.8},{"x":-32.24,"y":-496.73,"z":-46.31},{"x":-36.36,"y":-496.23,"z":-48.56},{"x":-40.37,"y":-496.14,"z":-46.26},{"x":-40.26,"y":-496.55,"z":-41.75}]},{"lat":82.5,"lon":-65.13,"b":[{"x":-27.41,"y":-496,"z":-56.4},{"x":-24.87,"y":-495.97,"z":-57.83},{"x":-24.9,"y":-495.62,"z":-60.69},{"x":-27.49,"y":-495.31,"z":-62.11},{"x":-30.04,"y":-495.34,"z":-60.65},{"x":-29.99,"y":-495.69,"z":-57.8}]},{"lat":81.15,"lon":-76.11,"b":[{"x":-18.43,"y":-494.45,"z":-71.6},{"x":-15.7,"y":-494.32,"z":-73.14},{"x":-15.72,"y":-493.85,"z":-76.2},{"x":-18.48,"y":-493.52,"z":-77.72},{"x":-21.21,"y":-493.65,"z":-76.17},{"x":-21.17,"y":-494.12,"z":-73.11}]},{"lat":79.55,"lon":-84.12,"b":[{"x":-9.28,"y":-492.25,"z":-86.83},{"x":-6.27,"y":-492,"z":-88.52},{"x":-6.27,"y":-491.38,"z":-91.89},{"x":-9.3,"y":-491.01,"z":-93.58},{"x":-12.32,"y":-491.27,"z":-91.87},{"x":-12.3,"y":-491.89,"z":-88.5}]},{"lat":77.78,"lon":-90,"b":[{"x":0,"y":-489.58,"z":-101.13},{"x":4.19,"y":-489.08,"z":-103.46},{"x":4.21,"y":-488.06,"z":-108.15},{"x":0,"y":-487.55,"z":-110.51},{"x":-4.21,"y":-488.06,"z":-108.15},{"x":-4.19,"y":-489.08,"z":-103.46}]},{"lat":75.9,"lon":-94.42,"b":[{"x":9.37,"y":-486.01,"z":-116.75},{"x":13.58,"y":-485.34,"z":-119.06},{"x":13.61,"y":-484.17,"z":-123.75},{"x":9.39,"y":-483.65,"z":-126.13},{"x":5.16,"y":-484.32,"z":-123.8},{"x":5.16,"y":-485.5,"z":-119.1}]},{"lat":73.94,"lon":-97.82,"b":[{"x":18.8,"y":-481.36,"z":-133.7},{"x":21.78,"y":-480.78,"z":-135.32},{"x":21.8,"y":-479.84,"z":-138.61},{"x":18.82,"y":-479.48,"z":-140.3},{"x":15.84,"y":-480.06,"z":-138.68},{"x":15.83,"y":-481,"z":-135.38}]},{"lat":71.93,"lon":-100.5,"b":[{"x":28.26,"y":-475.56,"z":-151.74},{"x":28.9,"y":-475.42,"z":-152.08},{"x":28.91,"y":-475.19,"z":-152.79},{"x":28.27,"y":-475.11,"z":-153.15},{"x":27.62,"y":-475.26,"z":-152.81},{"x":27.62,"y":-475.48,"z":-152.11}]},{"lat":81.71,"lon":-11.43,"b":[{"x":-70.44,"y":-494.85,"z":-10},{"x":-66.65,"y":-495.32,"z":-12.16},{"x":-66.84,"y":-495.17,"z":-16.5},{"x":-70.86,"y":-494.53,"z":-18.66},{"x":-74.65,"y":-494.05,"z":-16.45},{"x":-74.41,"y":-494.22,"z":-12.14}]},{"lat":82.07,"lon":-24.81,"b":[{"x":-62.39,"y":-495.42,"z":-24.55},{"x":-58.52,"y":-495.77,"z":-26.76},{"x":-58.67,"y":-495.49,"z":-31.19},{"x":-62.74,"y":-494.85,"z":-33.38},{"x":-66.61,"y":-494.49,"z":-31.12},{"x":-66.41,"y":-494.78,"z":-26.71}]},{"lat":81.98,"lon":-38.97,"b":[{"x":-54.12,"y":-495.34,"z":-40.68},{"x":-51.3,"y":-495.5,"z":-42.3},{"x":-51.39,"y":-495.21,"z":-45.52},{"x":-54.32,"y":-494.75,"z":-47.11},{"x":-57.14,"y":-494.58,"z":-45.46},{"x":-57.03,"y":-494.88,"z":-42.25}]},{"lat":81.41,"lon":-52.31,"b":[{"x":-45.62,"y":-494.48,"z":-58.23},{"x":-44.87,"y":-494.5,"z":-58.66},{"x":-44.88,"y":-494.39,"z":-59.52},{"x":-45.66,"y":-494.27,"z":-59.94},{"x":-46.41,"y":-494.25,"z":-59.5},{"x":-46.39,"y":-494.36,"z":-58.65}]},{"lat":80.43,"lon":-63.69,"b":[{"x":-36.81,"y":-493.23,"z":-73.06},{"x":-35.54,"y":-493.22,"z":-73.79},{"x":-35.55,"y":-493,"z":-75.24},{"x":-36.85,"y":-492.79,"z":-75.95},{"x":-38.13,"y":-492.81,"z":-75.21},{"x":-38.1,"y":-493.03,"z":-73.77}]},{"lat":79.13,"lon":-72.83,"b":[{"x":-27.83,"y":-491.15,"z":-89.33},{"x":-27.16,"y":-491.12,"z":-89.71},{"x":-27.17,"y":-490.98,"z":-90.46},{"x":-27.84,"y":-490.88,"z":-90.83},{"x":-28.51,"y":-490.91,"z":-90.44},{"x":-28.5,"y":-491.05,"z":-89.69}]},{"lat":77.6,"lon":-79.99,"b":[{"x":-18.64,"y":-489.23,"z":-101.14},{"x":-14.54,"y":-488.88,"z":-103.46},{"x":-14.55,"y":-487.88,"z":-108.07},{"x":-18.69,"y":-487.23,"z":-110.35},{"x":-22.8,"y":-487.58,"z":-108},{"x":-22.76,"y":-488.58,"z":-103.4}]},{"lat":75.9,"lon":-85.58,"b":[{"x":-9.37,"y":-486.01,"z":-116.75},{"x":-5.16,"y":-485.5,"z":-119.1},{"x":-5.16,"y":-484.32,"z":-123.8},{"x":-9.39,"y":-483.65,"z":-126.13},{"x":-13.61,"y":-484.17,"z":-123.75},{"x":-13.58,"y":-485.34,"z":-119.06}]},{"lat":74.08,"lon":-90,"b":[{"x":0,"y":-481.8,"z":-133.42},{"x":3.32,"y":-481.28,"z":-135.25},{"x":3.33,"y":-480.23,"z":-138.93},{"x":0,"y":-479.7,"z":-140.77},{"x":-3.33,"y":-480.23,"z":-138.93},{"x":-3.32,"y":-481.28,"z":-135.25}]},{"lat":79.75,"lon":-9.19,"b":[{"x":-87.56,"y":-492.11,"z":-9.95},{"x":-83.86,"y":-492.7,"z":-12.09},{"x":-84.1,"y":-492.54,"z":-16.41},{"x":-88.08,"y":-491.76,"z":-18.56},{"x":-91.78,"y":-491.16,"z":-16.36},{"x":-91.49,"y":-491.34,"z":-12.07}]},{"lat":80.2,"lon":-19.78,"b":[{"x":-79.81,"y":-492.92,"z":-24.42},{"x":-76.02,"y":-493.4,"z":-26.63},{"x":-76.22,"y":-493.11,"z":-31.04},{"x":-80.25,"y":-492.33,"z":-33.21},{"x":-84.04,"y":-491.84,"z":-30.95},{"x":-83.8,"y":-492.14,"z":-26.57}]},{"lat":80.31,"lon":-31.25,"b":[{"x":-71.93,"y":-492.94,"z":-42.56},{"x":-70.96,"y":-493.03,"z":-43.13},{"x":-71,"y":-492.93,"z":-44.25},{"x":-72.02,"y":-492.73,"z":-44.8},{"x":-72.99,"y":-492.64,"z":-44.22},{"x":-72.94,"y":-492.75,"z":-43.11}]},{"lat":80.02,"lon":-42.76,"b":[{"x":-63.58,"y":-492.63,"z":-56.91},{"x":-61.88,"y":-492.73,"z":-57.9},{"x":-61.93,"y":-492.49,"z":-59.85},{"x":-63.7,"y":-492.15,"z":-60.81},{"x":-65.4,"y":-492.05,"z":-59.8},{"x":-65.33,"y":-492.29,"z":-57.85}]},{"lat":77.07,"lon":-70.55,"b":[{"x":-37.24,"y":-487.75,"z":-103.31},{"x":-35.27,"y":-487.65,"z":-104.44},{"x":-35.29,"y":-487.17,"z":-106.66},{"x":-37.29,"y":-486.78,"z":-107.74},{"x":-39.25,"y":-486.88,"z":-106.6},{"x":-39.22,"y":-487.36,"z":-104.38}]},{"lat":75.58,"lon":-76.95,"b":[{"x":-28.07,"y":-485.33,"z":-116.58},{"x":-23.88,"y":-484.97,"z":-118.97},{"x":-23.9,"y":-483.79,"z":-123.66},{"x":-28.13,"y":-482.97,"z":-125.95},{"x":-32.32,"y":-483.33,"z":-123.54},{"x":-32.27,"y":-484.51,"z":-118.86}]},{"lat":73.94,"lon":-82.18,"b":[{"x":-18.81,"y":-481.01,"z":-135.04},{"x":-17.04,"y":-480.79,"z":-136.04},{"x":-17.04,"y":-480.23,"z":-138},{"x":-18.82,"y":-479.89,"z":-138.97},{"x":-20.59,"y":-480.11,"z":-137.97},{"x":-20.58,"y":-480.67,"z":-136}]},{"lat":77.8,"lon":-7.68,"b":[{"x":-104.37,"y":-488.82,"z":-9.88},{"x":-100.77,"y":-489.52,"z":-12.01},{"x":-101.05,"y":-489.34,"z":-16.3},{"x":-104.98,"y":-488.44,"z":-18.43},{"x":-108.58,"y":-487.73,"z":-16.24},{"x":-108.25,"y":-487.93,"z":-11.98}]},{"lat":78.31,"lon":-16.39,"b":[{"x":-96.94,"y":-489.84,"z":-24.27},{"x":-93.24,"y":-490.44,"z":-26.47},{"x":-93.48,"y":-490.14,"z":-30.85},{"x":-97.47,"y":-489.23,"z":-33},{"x":-101.16,"y":-488.62,"z":-30.75},{"x":-100.87,"y":-488.94,"z":-26.4}]},{"lat":78.53,"lon":-25.89,"b":[{"x":-89.21,"y":-490.36,"z":-39},{"x":-85.42,"y":-490.84,"z":-41.26},{"x":-85.63,"y":-490.41,"z":-45.73},{"x":-89.66,"y":-489.49,"z":-47.9},{"x":-93.44,"y":-489,"z":-45.59},{"x":-93.19,"y":-489.44,"z":-41.15}]},{"lat":78.43,"lon":-35.72,"b":[{"x":-81.32,"y":-490.02,"z":-56.85},{"x":-79.87,"y":-490.16,"z":-57.72},{"x":-79.93,"y":-489.95,"z":-59.42},{"x":-81.46,"y":-489.59,"z":-60.24},{"x":-82.91,"y":-489.46,"z":-59.36},{"x":-82.84,"y":-489.67,"z":-57.67}]},{"lat":78,"lon":-45.32,"b":[{"x":-73.05,"y":-489.18,"z":-73.17},{"x":-72.42,"y":-489.22,"z":-73.55},{"x":-72.44,"y":-489.1,"z":-74.28},{"x":-73.1,"y":-488.95,"z":-74.64},{"x":-73.73,"y":-488.91,"z":-74.25},{"x":-73.71,"y":-489.03,"z":-73.52}]},{"lat":74.97,"lon":-68.88,"b":[{"x":-46.65,"y":-483.97,"z":-116.26},{"x":-42.51,"y":-483.77,"z":-118.67},{"x":-42.55,"y":-482.59,"z":-123.35},{"x":-46.75,"y":-481.62,"z":-125.6},{"x":-50.89,"y":-481.83,"z":-123.16},{"x":-50.83,"y":-483.01,"z":-118.49}]},{"lat":73.53,"lon":-74.64,"b":[{"x":-37.55,"y":-479.72,"z":-135.8},{"x":-36.73,"y":-479.65,"z":-136.28},{"x":-36.73,"y":-479.38,"z":-137.19},{"x":-37.56,"y":-479.19,"z":-137.64},{"x":-38.38,"y":-479.27,"z":-137.16},{"x":-38.37,"y":-479.53,"z":-136.24}]},{"lat":75.88,"lon":-6.59,"b":[{"x":-120.82,"y":-485.02,"z":-9.8},{"x":-117.32,"y":-485.83,"z":-11.92},{"x":-117.65,"y":-485.63,"z":-16.18},{"x":-121.51,"y":-484.6,"z":-18.29},{"x":-125,"y":-483.79,"z":-16.11},{"x":-124.63,"y":-484.01,"z":-11.89}]},{"lat":76.4,"lon":-13.98,"b":[{"x":-113.72,"y":-486.23,"z":-24.09},{"x":-110.12,"y":-486.94,"z":-26.28},{"x":-110.41,"y":-486.63,"z":-30.63},{"x":-114.33,"y":-485.58,"z":-32.76},{"x":-117.91,"y":-484.87,"z":-30.51},{"x":-117.59,"y":-485.2,"z":-26.2}]},{"lat":76.7,"lon":-22.02,"b":[{"x":-106.32,"y":-486.95,"z":-38.89},{"x":-102.76,"y":-487.53,"z":-41.06},{"x":-103,"y":-487.1,"z":-45.34},{"x":-106.83,"y":-486.08,"z":-47.41},{"x":-110.37,"y":-485.5,"z":-45.18},{"x":-110.1,"y":-485.94,"z":-40.94}]},{"lat":76.74,"lon":-30.47,"b":[{"x":-98.81,"y":-486.74,"z":-57.48},{"x":-98.23,"y":-486.82,"z":-57.83},{"x":-98.26,"y":-486.73,"z":-58.52},{"x":-98.87,"y":-486.57,"z":-58.84},{"x":-99.45,"y":-486.49,"z":-58.48},{"x":-99.41,"y":-486.58,"z":-57.81}]},{"lat":74.11,"lon":-61.6,"b":[{"x":-65.07,"y":-481.55,"z":-117.56},{"x":-62.55,"y":-481.51,"z":-119.07},{"x":-62.59,"y":-480.79,"z":-121.94},{"x":-65.16,"y":-480.1,"z":-123.29},{"x":-67.67,"y":-480.14,"z":-121.77},{"x":-67.62,"y":-480.87,"z":-118.91}]},{"lat":72.86,"lon":-67.61,"b":[{"x":-56.09,"y":-478.63,"z":-133.07},{"x":-53.28,"y":-478.48,"z":-134.73},{"x":-53.31,"y":-477.58,"z":-137.9},{"x":-56.16,"y":-476.82,"z":-139.39},{"x":-58.96,"y":-476.97,"z":-137.72},{"x":-58.92,"y":-477.87,"z":-134.57}]},{"lat":71.44,"lon":-72.83,"b":[{"x":-46.96,"y":-474.48,"z":-150.44},{"x":-45.54,"y":-474.35,"z":-151.26},{"x":-45.55,"y":-473.85,"z":-152.84},{"x":-46.98,"y":-473.47,"z":-153.59},{"x":-48.4,"y":-473.59,"z":-152.76},{"x":-48.39,"y":-474.1,"z":-151.19}]},{"lat":73.98,"lon":-5.77,"b":[{"x":-136.86,"y":-480.74,"z":-9.72},{"x":-133.48,"y":-481.64,"z":-11.82},{"x":-133.85,"y":-481.42,"z":-16.04},{"x":-137.64,"y":-480.28,"z":-18.12},{"x":-141,"y":-479.37,"z":-15.96},{"x":-140.6,"y":-479.62,"z":-11.78}]},{"lat":74.52,"lon":-12.17,"b":[{"x":-130.1,"y":-482.12,"z":-23.89},{"x":-126.62,"y":-482.93,"z":-26.06},{"x":-126.95,"y":-482.59,"z":-30.38},{"x":-130.79,"y":-481.43,"z":-32.48},{"x":-134.26,"y":-480.62,"z":-30.24},{"x":-133.9,"y":-480.97,"z":-25.97}]},{"lat":74.86,"lon":-19.12,"b":[{"x":-123.27,"y":-482.76,"z":-41.56},{"x":-122.27,"y":-482.96,"z":-42.19},{"x":-122.35,"y":-482.83,"z":-43.41},{"x":-123.43,"y":-482.5,"z":-43.99},{"x":-124.42,"y":-482.3,"z":-43.35},{"x":-124.33,"y":-482.44,"z":-42.15}]},{"lat":71.98,"lon":-61.22,"b":[{"x":-74.45,"y":-476.01,"z":-133.55},{"x":-72.66,"y":-475.98,"z":-134.63},{"x":-72.69,"y":-475.39,"z":-136.66},{"x":-74.5,"y":-474.84,"z":-137.6},{"x":-76.27,"y":-474.88,"z":-136.51},{"x":-76.24,"y":-475.46,"z":-134.49}]},{"lat":70.74,"lon":-66.61,"b":[{"x":-65.44,"y":-473.21,"z":-147.36},{"x":-61.87,"y":-473.02,"z":-149.5},{"x":-61.89,"y":-471.73,"z":-153.51},{"x":-65.5,"y":-470.64,"z":-155.36},{"x":-69.07,"y":-470.83,"z":-153.21},{"x":-69.03,"y":-472.12,"z":-149.22}]},{"lat":69.35,"lon":-71.37,"b":[{"x":-56.33,"y":-468.1,"z":-166.4},{"x":-55.7,"y":-468.05,"z":-166.78},{"x":-55.7,"y":-467.8,"z":-167.47},{"x":-56.33,"y":-467.61,"z":-167.8},{"x":-56.96,"y":-467.66,"z":-167.42},{"x":-56.96,"y":-467.91,"z":-166.73}]},{"lat":72.12,"lon":-5.14,"b":[{"x":-152.52,"y":-476,"z":-10.21},{"x":-149.73,"y":-476.84,"z":-12},{"x":-150.08,"y":-476.63,"z":-15.58},{"x":-153.25,"y":-475.56,"z":-17.34},{"x":-156.03,"y":-474.72,"z":-15.5},{"x":-155.65,"y":-474.95,"z":-11.96}]},{"lat":72.65,"lon":-10.78,"b":[{"x":-146.16,"y":-477.47,"z":-24.79},{"x":-143.7,"y":-478.13,"z":-26.37},{"x":-143.96,"y":-477.87,"z":-29.5},{"x":-146.72,"y":-476.93,"z":-31.02},{"x":-149.16,"y":-476.27,"z":-29.39},{"x":-148.87,"y":-476.55,"z":-26.3}]},{"lat":68.62,"lon":-65.8,"b":[{"x":-74.72,"y":-466.39,"z":-163.86},{"x":-72.56,"y":-466.27,"z":-165.17},{"x":-72.56,"y":-465.4,"z":-167.59},{"x":-74.74,"y":-464.67,"z":-168.68},{"x":-76.89,"y":-464.79,"z":-167.36},{"x":-76.88,"y":-465.65,"z":-164.96}]},{"lat":66.5,"lon":-65.13,"b":[{"x":-83.84,"y":-459.53,"z":-178.18},{"x":-81.39,"y":-459.39,"z":-179.68},{"x":-81.39,"y":-458.32,"z":-182.38},{"x":-83.83,"y":-457.41,"z":-183.57},{"x":-86.26,"y":-457.56,"z":-182.07},{"x":-86.27,"y":-458.61,"z":-179.38}]},{"lat":65.61,"lon":-60.47,"b":[{"x":-101.78,"y":-455.79,"z":-178.53},{"x":-100.77,"y":-455.77,"z":-179.16},{"x":-100.77,"y":-455.32,"z":-180.28},{"x":-101.77,"y":-454.91,"z":-180.77},{"x":-102.77,"y":-454.94,"z":-180.13},{"x":-102.77,"y":-455.38,"z":-179.01}]},{"lat":64.39,"lon":-64.57,"b":[{"x":-92.78,"y":-451.13,"z":-194.56},{"x":-92.24,"y":-451.1,"z":-194.9},{"x":-92.23,"y":-450.85,"z":-195.49},{"x":-92.77,"y":-450.62,"z":-195.75},{"x":-93.31,"y":-450.66,"z":-195.41},{"x":-93.32,"y":-450.91,"z":-194.82}]},{"lat":64.6,"lon":-56.2,"b":[{"x":-119.31,"y":-451.91,"z":-177.56},{"x":-118.74,"y":-451.92,"z":-177.92},{"x":-118.74,"y":-451.67,"z":-178.56},{"x":-119.3,"y":-451.41,"z":-178.83},{"x":-119.86,"y":-451.41,"z":-178.46},{"x":-119.86,"y":-451.66,"z":-177.83}]},{"lat":55.62,"lon":-69.31,"b":[{"x":-99.81,"y":-413.57,"z":-262.62},{"x":-98.3,"y":-413.36,"z":-263.51},{"x":-98.23,"y":-412.43,"z":-264.99},{"x":-99.67,"y":-411.72,"z":-265.55},{"x":-101.17,"y":-411.93,"z":-264.66},{"x":-101.25,"y":-412.85,"z":-263.2}]},{"lat":54.24,"lon":-71.98,"b":[{"x":-90.5,"y":-407.4,"z":-275.28},{"x":-87.78,"y":-406.95,"z":-276.83},{"x":-87.66,"y":-405.23,"z":-279.38},{"x":-90.24,"y":-403.98,"z":-280.36},{"x":-92.93,"y":-404.44,"z":-278.82},{"x":-93.07,"y":-406.14,"z":-276.29}]},{"lat":52.81,"lon":-74.46,"b":[{"x":-81.03,"y":-399.16,"z":-289.96},{"x":-79.73,"y":-398.9,"z":-290.68},{"x":-79.67,"y":-398.05,"z":-291.86},{"x":-80.91,"y":-397.46,"z":-292.32},{"x":-82.2,"y":-397.72,"z":-291.61},{"x":-82.27,"y":-398.56,"z":-290.43}]},{"lat":54.97,"lon":-65.95,"b":[{"x":-117.03,"y":-410.25,"z":-260.71},{"x":-115.69,"y":-410.1,"z":-261.54},{"x":-115.62,"y":-409.28,"z":-262.86},{"x":-116.88,"y":-408.6,"z":-263.35},{"x":-118.21,"y":-408.75,"z":-262.52},{"x":-118.29,"y":-409.57,"z":-261.2}]},{"lat":53.68,"lon":-68.68,"b":[{"x":-107.82,"y":-404.44,"z":-273.4},{"x":-105.24,"y":-404.08,"z":-274.94},{"x":-105.1,"y":-402.44,"z":-277.39},{"x":-107.53,"y":-401.18,"z":-278.29},{"x":-110.08,"y":-401.54,"z":-276.76},{"x":-110.24,"y":-403.16,"z":-274.33}]},{"lat":52.33,"lon":-71.23,"b":[{"x":-98.55,"y":-398.33,"z":-285.57},{"x":-94.54,"y":-397.65,"z":-287.87},{"x":-94.33,"y":-395.03,"z":-291.52},{"x":-98.08,"y":-393.12,"z":-292.86},{"x":-102.04,"y":-393.79,"z":-290.6},{"x":-102.29,"y":-396.38,"z":-286.96}]},{"lat":50.94,"lon":-73.6,"b":[{"x":-89.14,"y":-390.64,"z":-298.98},{"x":-85.51,"y":-389.93,"z":-300.96},{"x":-85.32,"y":-387.5,"z":-304.14},{"x":-88.71,"y":-385.81,"z":-305.32},{"x":-92.29,"y":-386.52,"z":-303.36},{"x":-92.53,"y":-388.92,"z":-300.19}]},{"lat":49.53,"lon":-75.81,"b":[{"x":-79.6,"y":-381.07,"z":-313.73},{"x":-78.56,"y":-380.84,"z":-314.28},{"x":-78.51,"y":-380.12,"z":-315.15},{"x":-79.48,"y":-379.65,"z":-315.48},{"x":-80.51,"y":-379.88,"z":-314.95},{"x":-80.58,"y":-380.58,"z":-314.07}]},{"lat":50.46,"lon":-70.55,"b":[{"x":-106.25,"y":-388.19,"z":-296.56},{"x":-102.29,"y":-387.52,"z":-298.83},{"x":-102.03,"y":-384.86,"z":-302.33},{"x":-105.7,"y":-382.9,"z":-303.56},{"x":-109.6,"y":-383.57,"z":-301.32},{"x":-109.9,"y":-386.2,"z":-297.82}]},{"lat":49.12,"lon":-72.83,"b":[{"x":-96.88,"y":-380.69,"z":-309.23},{"x":-92.91,"y":-379.9,"z":-311.4},{"x":-92.66,"y":-377.18,"z":-314.78},{"x":-96.32,"y":-375.27,"z":-315.96},{"x":-100.24,"y":-376.04,"z":-313.82},{"x":-100.54,"y":-378.73,"z":-310.46}]},{"lat":47.75,"lon":-74.96,"b":[{"x":-87.3,"y":-370.67,"z":-323.99},{"x":-86.45,"y":-370.48,"z":-324.43},{"x":-86.4,"y":-369.88,"z":-325.12},{"x":-87.19,"y":-369.48,"z":-325.37},{"x":-88.03,"y":-369.67,"z":-324.93},{"x":-88.09,"y":-370.26,"z":-324.24}]},{"lat":49.91,"lon":-67.61,"b":[{"x":-122.78,"y":-383.46,"z":-296.4},{"x":-121.32,"y":-383.25,"z":-297.27},{"x":-121.21,"y":-382.26,"z":-298.58},{"x":-122.51,"y":-381.46,"z":-299.08},{"x":-123.93,"y":-381.64,"z":-298.27},{"x":-124.09,"y":-382.66,"z":-296.9}]},{"lat":48.63,"lon":-69.94,"b":[{"x":-113.65,"y":-377.88,"z":-306.95},{"x":-109.74,"y":-377.21,"z":-309.2},{"x":-109.44,"y":-374.52,"z":-312.56},{"x":-112.89,"y":-372.39,"z":-313.87},{"x":-116.66,"y":-372.94,"z":-311.84},{"x":-117.12,"y":-375.74,"z":-308.28}]},{"lat":47.33,"lon":-72.13,"b":[{"x":-104.3,"y":-370.33,"z":-319.24},{"x":-100.38,"y":-369.55,"z":-321.39},{"x":-100.09,"y":-366.8,"z":-324.61},{"x":-103.52,"y":-364.69,"z":-325.92},{"x":-107.26,"y":-365.3,"z":-324.01},{"x":-107.75,"y":-368.2,"z":-320.56}]},{"lat":46,"lon":-74.18,"b":[{"x":-94.77,"y":-360.77,"z":-332.92},{"x":-93.23,"y":-360.43,"z":-333.72},{"x":-93.12,"y":-359.33,"z":-334.94},{"x":-94.46,"y":-358.5,"z":-335.45},{"x":-95.92,"y":-358.77,"z":-334.75},{"x":-96.12,"y":-359.93,"z":-333.44}]},{"lat":72.12,"lon":5.14,"b":[{"x":-152.46,"y":-476.03,"z":9.62},{"x":-156.11,"y":-474.8,"z":11.66},{"x":-156.55,"y":-474.53,"z":15.8},{"x":-153.31,"y":-475.51,"z":17.94},{"x":-149.6,"y":-476.77,"z":15.89},{"x":-149.2,"y":-477.01,"z":11.7}]},{"lat":70.82,"lon":9.67,"b":[{"x":-161.79,"y":-472.36,"z":25.91},{"x":-163.24,"y":-471.82,"z":26.73},{"x":-163.41,"y":-471.66,"z":28.4},{"x":-162.12,"y":-472.05,"z":29.29},{"x":-160.65,"y":-472.6,"z":28.47},{"x":-160.49,"y":-472.75,"z":26.77}]},{"lat":73.98,"lon":5.77,"b":[{"x":-136.86,"y":-480.74,"z":9.72},{"x":-140.6,"y":-479.62,"z":11.78},{"x":-141,"y":-479.37,"z":15.96},{"x":-137.64,"y":-480.28,"z":18.12},{"x":-133.85,"y":-481.42,"z":16.04},{"x":-133.48,"y":-481.64,"z":11.82}]},{"lat":72.65,"lon":10.78,"b":[{"x":-146.05,"y":-477.54,"z":23.66},{"x":-149.76,"y":-476.29,"z":25.72},{"x":-150.15,"y":-475.91,"z":29.95},{"x":-146.81,"y":-476.81,"z":32.16},{"x":-143.05,"y":-478.09,"z":30.1},{"x":-142.69,"y":-478.44,"z":25.82}]},{"lat":71.2,"lon":15.09,"b":[{"x":-155.23,"y":-473.67,"z":38.6},{"x":-158.11,"y":-472.58,"z":40.2},{"x":-158.4,"y":-472.19,"z":43.55},{"x":-155.8,"y":-472.88,"z":45.33},{"x":-152.88,"y":-473.99,"z":43.73},{"x":-152.61,"y":-474.37,"z":40.34}]},{"lat":75.88,"lon":6.59,"b":[{"x":-120.82,"y":-485.02,"z":9.8},{"x":-124.63,"y":-484.01,"z":11.89},{"x":-125,"y":-483.79,"z":16.11},{"x":-121.51,"y":-484.6,"z":18.29},{"x":-117.65,"y":-485.63,"z":16.18},{"x":-117.32,"y":-485.83,"z":11.92}]},{"lat":74.52,"lon":12.17,"b":[{"x":-130.1,"y":-482.12,"z":23.89},{"x":-133.9,"y":-480.97,"z":25.97},{"x":-134.26,"y":-480.62,"z":30.24},{"x":-130.79,"y":-481.43,"z":32.48},{"x":-126.95,"y":-482.59,"z":30.38},{"x":-126.62,"y":-482.93,"z":26.06}]},{"lat":73.03,"lon":16.88,"b":[{"x":-139.32,"y":-478.62,"z":38.07},{"x":-143.08,"y":-477.34,"z":40.14},{"x":-143.43,"y":-476.85,"z":44.45},{"x":-139.98,"y":-477.65,"z":46.74},{"x":-136.17,"y":-478.95,"z":44.66},{"x":-135.85,"y":-479.43,"z":40.3}]},{"lat":71.43,"lon":20.84,"b":[{"x":-148.55,"y":-474.34,"z":53.77},{"x":-151.01,"y":-473.41,"z":55.12},{"x":-151.22,"y":-472.99,"z":57.99},{"x":-148.96,"y":-473.51,"z":59.54},{"x":-146.47,"y":-474.46,"z":58.18},{"x":-146.27,"y":-474.87,"z":55.28}]},{"lat":77.8,"lon":7.68,"b":[{"x":-104.37,"y":-488.82,"z":9.88},{"x":-108.25,"y":-487.93,"z":11.98},{"x":-108.58,"y":-487.73,"z":16.24},{"x":-104.98,"y":-488.44,"z":18.43},{"x":-101.05,"y":-489.34,"z":16.3},{"x":-100.77,"y":-489.52,"z":12.01}]},{"lat":76.4,"lon":13.98,"b":[{"x":-113.72,"y":-486.23,"z":24.09},{"x":-117.59,"y":-485.2,"z":26.2},{"x":-117.91,"y":-484.87,"z":30.51},{"x":-114.33,"y":-485.58,"z":32.76},{"x":-110.41,"y":-486.63,"z":30.63},{"x":-110.12,"y":-486.94,"z":26.28}]},{"lat":74.86,"lon":19.12,"b":[{"x":-123.03,"y":-483.03,"z":38.42},{"x":-126.87,"y":-481.87,"z":40.52},{"x":-127.19,"y":-481.39,"z":44.88},{"x":-123.63,"y":-482.1,"z":47.18},{"x":-119.73,"y":-483.29,"z":45.06},{"x":-119.45,"y":-483.75,"z":40.67}]},{"lat":73.21,"lon":23.34,"b":[{"x":-132.26,"y":-479.22,"z":52.82},{"x":-136.08,"y":-477.92,"z":54.9},{"x":-136.38,"y":-477.3,"z":59.29},{"x":-132.83,"y":-478,"z":61.64},{"x":-128.97,"y":-479.33,"z":59.55},{"x":-128.7,"y":-479.93,"z":55.12}]},{"lat":71.49,"lon":26.82,"b":[{"x":-141.52,"y":-474.48,"z":69.28},{"x":-143.54,"y":-473.71,"z":70.38},{"x":-143.69,"y":-473.31,"z":72.73},{"x":-141.81,"y":-473.68,"z":74.02},{"x":-139.76,"y":-474.45,"z":72.92},{"x":-139.63,"y":-474.85,"z":70.54}]},{"lat":79.75,"lon":9.19,"b":[{"x":-87.56,"y":-492.11,"z":9.95},{"x":-91.49,"y":-491.34,"z":12.07},{"x":-91.78,"y":-491.16,"z":16.36},{"x":-88.08,"y":-491.76,"z":18.56},{"x":-84.1,"y":-492.54,"z":16.41},{"x":-83.86,"y":-492.7,"z":12.09}]},{"lat":78.31,"lon":16.39,"b":[{"x":-96.94,"y":-489.84,"z":24.27},{"x":-100.87,"y":-488.94,"z":26.4},{"x":-101.16,"y":-488.62,"z":30.75},{"x":-97.47,"y":-489.23,"z":33},{"x":-93.48,"y":-490.14,"z":30.85},{"x":-93.24,"y":-490.44,"z":26.47}]},{"lat":76.7,"lon":22.02,"b":[{"x":-106.31,"y":-486.96,"z":38.73},{"x":-110.23,"y":-485.91,"z":40.86},{"x":-110.51,"y":-485.46,"z":45.26},{"x":-106.83,"y":-486.06,"z":47.56},{"x":-102.86,"y":-487.12,"z":45.42},{"x":-102.62,"y":-487.56,"z":40.99}]},{"lat":74.99,"lon":26.47,"b":[{"x":-115.64,"y":-483.45,"z":53.28},{"x":-119.54,"y":-482.26,"z":55.4},{"x":-119.81,"y":-481.66,"z":59.83},{"x":-116.15,"y":-482.26,"z":62.19},{"x":-112.2,"y":-483.46,"z":60.06},{"x":-111.96,"y":-484.05,"z":55.59}]},{"lat":73.2,"lon":30.02,"b":[{"x":-124.89,"y":-479.3,"z":67.87},{"x":-128.75,"y":-477.98,"z":69.95},{"x":-129,"y":-477.23,"z":74.41},{"x":-125.36,"y":-477.82,"z":76.82},{"x":-121.45,"y":-479.16,"z":74.72},{"x":-121.23,"y":-479.9,"z":70.22}]},{"lat":71.34,"lon":32.91,"b":[{"x":-134.02,"y":-474.53,"z":82.43},{"x":-137.84,"y":-473.07,"z":84.48},{"x":-138.07,"y":-472.18,"z":88.94},{"x":-134.45,"y":-472.76,"z":91.39},{"x":-130.58,"y":-474.23,"z":89.34},{"x":-130.38,"y":-475.11,"z":84.83}]},{"lat":69.45,"lon":35.29,"b":[{"x":-143.17,"y":-468.4,"z":100.43},{"x":-143.98,"y":-468.06,"z":100.86},{"x":-144.02,"y":-467.84,"z":101.81},{"x":-143.25,"y":-467.96,"z":102.34},{"x":-142.44,"y":-468.3,"z":101.92},{"x":-142.4,"y":-468.52,"z":100.95}]},{"lat":81.71,"lon":11.43,"b":[{"x":-70.44,"y":-494.85,"z":10},{"x":-74.41,"y":-494.22,"z":12.14},{"x":-74.65,"y":-494.05,"z":16.45},{"x":-70.86,"y":-494.53,"z":18.66},{"x":-66.84,"y":-495.17,"z":16.5},{"x":-66.65,"y":-495.32,"z":12.16}]},{"lat":80.2,"lon":19.78,"b":[{"x":-79.81,"y":-492.92,"z":24.42},{"x":-83.8,"y":-492.14,"z":26.57},{"x":-84.04,"y":-491.84,"z":30.95},{"x":-80.25,"y":-492.33,"z":33.21},{"x":-76.22,"y":-493.11,"z":31.04},{"x":-76.02,"y":-493.4,"z":26.63}]},{"lat":78.53,"lon":25.89,"b":[{"x":-89.21,"y":-490.36,"z":39},{"x":-93.19,"y":-489.44,"z":41.15},{"x":-93.44,"y":-489,"z":45.59},{"x":-89.66,"y":-489.49,"z":47.9},{"x":-85.63,"y":-490.41,"z":45.73},{"x":-85.42,"y":-490.84,"z":41.26}]},{"lat":76.74,"lon":30.47,"b":[{"x":-98.6,"y":-487.16,"z":53.69},{"x":-102.57,"y":-486.1,"z":55.84},{"x":-102.81,"y":-485.51,"z":60.31},{"x":-99.04,"y":-486,"z":62.67},{"x":-95.02,"y":-487.07,"z":60.51},{"x":-94.82,"y":-487.65,"z":56}]},{"lat":74.87,"lon":33.99,"b":[{"x":-107.94,"y":-483.32,"z":68.43},{"x":-111.89,"y":-482.11,"z":70.56},{"x":-112.11,"y":-481.38,"z":75.06},{"x":-108.36,"y":-481.85,"z":77.47},{"x":-104.37,"y":-483.07,"z":75.33},{"x":-104.17,"y":-483.8,"z":70.8}]},{"lat":72.96,"lon":36.75,"b":[{"x":-117.2,"y":-478.83,"z":83.17},{"x":-121.11,"y":-477.48,"z":85.27},{"x":-121.32,"y":-476.6,"z":89.78},{"x":-117.59,"y":-477.07,"z":92.23},{"x":-113.63,"y":-478.43,"z":90.13},{"x":-113.45,"y":-479.3,"z":85.58}]},{"lat":71,"lon":38.97,"b":[{"x":-126.36,"y":-473.57,"z":98.5},{"x":-129.68,"y":-472.3,"z":100.26},{"x":-129.84,"y":-471.42,"z":104.12},{"x":-126.66,"y":-471.81,"z":106.25},{"x":-123.3,"y":-473.09,"z":104.5},{"x":-123.16,"y":-473.97,"z":100.6}]},{"lat":69.03,"lon":40.79,"b":[{"x":-135.42,"y":-467.3,"z":115.15},{"x":-136.92,"y":-466.67,"z":115.94},{"x":-136.98,"y":-466.21,"z":117.7},{"x":-135.53,"y":-466.38,"z":118.69},{"x":-134.02,"y":-467.02,"z":117.91},{"x":-133.97,"y":-467.48,"z":116.13}]},{"lat":83.67,"lon":15.09,"b":[{"x":-53.06,"y":-497.01,"z":10.05},{"x":-57.06,"y":-496.52,"z":12.19},{"x":-57.25,"y":-496.37,"z":16.53},{"x":-53.38,"y":-496.72,"z":18.74},{"x":-49.33,"y":-497.21,"z":16.57},{"x":-49.2,"y":-497.35,"z":12.21}]},{"lat":82.07,"lon":24.81,"b":[{"x":-62.39,"y":-495.42,"z":24.55},{"x":-66.41,"y":-494.78,"z":26.71},{"x":-66.61,"y":-494.49,"z":31.12},{"x":-62.74,"y":-494.85,"z":33.38},{"x":-58.67,"y":-495.49,"z":31.19},{"x":-58.52,"y":-495.77,"z":26.76}]},{"lat":80.31,"lon":31.25,"b":[{"x":-71.78,"y":-493.19,"z":39.23},{"x":-75.81,"y":-492.41,"z":41.4},{"x":-76.01,"y":-491.98,"z":45.87},{"x":-72.14,"y":-492.34,"z":48.18},{"x":-68.07,"y":-493.13,"z":45.98},{"x":-67.91,"y":-493.55,"z":41.49}]},{"lat":78.43,"lon":35.72,"b":[{"x":-81.2,"y":-490.32,"z":54.04},{"x":-85.23,"y":-489.39,"z":56.21},{"x":-85.43,"y":-488.82,"z":60.72},{"x":-81.56,"y":-489.18,"z":63.08},{"x":-77.49,"y":-490.12,"z":60.89},{"x":-77.32,"y":-490.68,"z":56.35}]},{"lat":76.49,"lon":38.97,"b":[{"x":-90.6,"y":-486.79,"z":68.93},{"x":-94.62,"y":-485.72,"z":71.09},{"x":-94.81,"y":-484.99,"z":75.62},{"x":-90.96,"y":-485.35,"z":78.03},{"x":-86.9,"y":-486.44,"z":75.85},{"x":-86.73,"y":-487.16,"z":71.29}]},{"lat":74.51,"lon":41.43,"b":[{"x":-99.95,"y":-482.61,"z":83.83},{"x":-103.94,"y":-481.39,"z":85.96},{"x":-104.13,"y":-480.51,"z":90.51},{"x":-100.29,"y":-480.86,"z":92.96},{"x":-96.25,"y":-482.09,"z":90.82},{"x":-96.1,"y":-482.96,"z":86.24}]},{"lat":72.49,"lon":43.35,"b":[{"x":-109.21,"y":-477.76,"z":98.69},{"x":-113.17,"y":-476.4,"z":100.79},{"x":-113.34,"y":-475.38,"z":105.34},{"x":-109.52,"y":-475.71,"z":107.82},{"x":-105.52,"y":-477.09,"z":105.72},{"x":-105.38,"y":-478.11,"z":101.14}]},{"lat":70.46,"lon":44.88,"b":[{"x":-118.35,"y":-472.28,"z":113.45},{"x":-122.26,"y":-470.79,"z":115.5},{"x":-122.4,"y":-469.61,"z":120.03},{"x":-118.61,"y":-469.93,"z":122.55},{"x":-114.65,"y":-471.44,"z":120.51},{"x":-114.53,"y":-472.62,"z":115.94}]},{"lat":68.42,"lon":46.13,"b":[{"x":-127.34,"y":-466,"z":128.69},{"x":-130.65,"y":-464.61,"z":130.4},{"x":-130.74,"y":-463.48,"z":134.26},{"x":-127.52,"y":-463.74,"z":136.44},{"x":-124.17,"y":-465.14,"z":134.75},{"x":-124.09,"y":-466.27,"z":130.85}]},{"lat":85.6,"lon":22.02,"b":[{"x":-35.48,"y":-498.57,"z":10.08},{"x":-39.5,"y":-498.22,"z":12.23},{"x":-39.64,"y":-498.08,"z":16.59},{"x":-35.7,"y":-498.3,"z":18.8},{"x":-31.64,"y":-498.65,"z":16.61},{"x":-31.56,"y":-498.78,"z":12.24}]},{"lat":83.86,"lon":32.91,"b":[{"x":-44.74,"y":-497.32,"z":24.64},{"x":-48.78,"y":-496.82,"z":26.82},{"x":-48.93,"y":-496.54,"z":31.25},{"x":-44.99,"y":-496.77,"z":33.51},{"x":-40.9,"y":-497.27,"z":31.3},{"x":-40.8,"y":-497.54,"z":26.86}]},{"lat":81.98,"lon":38.97,"b":[{"x":-54.08,"y":-495.43,"z":39.41},{"x":-58.15,"y":-494.79,"z":41.6},{"x":-58.31,"y":-494.37,"z":46.09},{"x":-54.36,"y":-494.6,"z":48.4},{"x":-50.25,"y":-495.25,"z":46.18},{"x":-50.13,"y":-495.66,"z":41.67}]},{"lat":80.02,"lon":42.76,"b":[{"x":-63.48,"y":-492.9,"z":54.32},{"x":-67.56,"y":-492.11,"z":56.52},{"x":-67.72,"y":-491.54,"z":61.06},{"x":-63.77,"y":-491.77,"z":63.41},{"x":-59.66,"y":-492.57,"z":61.19},{"x":-59.53,"y":-493.13,"z":56.64}]},{"lat":78,"lon":45.32,"b":[{"x":-72.91,"y":-489.7,"z":69.34},{"x":-76.98,"y":-488.76,"z":71.53},{"x":-77.15,"y":-488.04,"z":76.1},{"x":-73.2,"y":-488.27,"z":78.5},{"x":-69.09,"y":-489.22,"z":76.29},{"x":-68.96,"y":-489.93,"z":71.69}]},{"lat":75.96,"lon":47.17,"b":[{"x":-82.32,"y":-485.83,"z":84.39},{"x":-86.38,"y":-484.74,"z":86.56},{"x":-86.54,"y":-483.87,"z":91.15},{"x":-82.61,"y":-484.09,"z":93.59},{"x":-78.51,"y":-485.19,"z":91.4},{"x":-78.38,"y":-486.05,"z":86.79}]},{"lat":73.89,"lon":48.56,"b":[{"x":-91.68,"y":-481.28,"z":99.42},{"x":-95.72,"y":-480.05,"z":101.56},{"x":-95.86,"y":-479.03,"z":106.14},{"x":-91.94,"y":-479.24,"z":108.62},{"x":-87.87,"y":-480.48,"z":106.48},{"x":-87.75,"y":-481.51,"z":101.86}]},{"lat":71.81,"lon":49.64,"b":[{"x":-100.95,"y":-476.08,"z":114.36},{"x":-104.95,"y":-474.71,"z":116.46},{"x":-105.07,"y":-473.53,"z":121.03},{"x":-101.17,"y":-473.73,"z":123.54},{"x":-97.13,"y":-475.12,"z":121.45},{"x":-97.03,"y":-476.29,"z":116.84}]},{"lat":69.72,"lon":50.51,"b":[{"x":-110.08,"y":-470.24,"z":129.16},{"x":-114.04,"y":-468.73,"z":131.2},{"x":-114.14,"y":-467.41,"z":135.75},{"x":-110.26,"y":-467.59,"z":138.29},{"x":-106.27,"y":-469.11,"z":136.25},{"x":-106.19,"y":-470.44,"z":131.67}]},{"lat":67.64,"lon":51.22,"b":[{"x":-119.06,"y":-463.71,"z":143.96},{"x":-122.78,"y":-462.15,"z":145.85},{"x":-122.84,"y":-460.75,"z":150.15},{"x":-119.17,"y":-460.91,"z":152.6},{"x":-115.41,"y":-462.48,"z":150.72},{"x":-115.36,"y":-463.89,"z":146.39}]},{"lat":87.37,"lon":38.97,"b":[{"x":-17.78,"y":-499.51,"z":10.1},{"x":-21.79,"y":-499.3,"z":12.26},{"x":-21.87,"y":-499.17,"z":16.63},{"x":-17.88,"y":-499.25,"z":18.84},{"x":-13.84,"y":-499.46,"z":16.64},{"x":-13.81,"y":-499.59,"z":12.27}]},{"lat":85.45,"lon":47.17,"b":[{"x":-26.91,"y":-498.59,"z":24.71},{"x":-30.97,"y":-498.24,"z":26.9},{"x":-31.07,"y":-497.98,"z":31.34},{"x":-27.06,"y":-498.06,"z":33.6},{"x":-22.97,"y":-498.41,"z":31.37},{"x":-22.92,"y":-498.68,"z":26.92}]},{"lat":83.45,"lon":50.51,"b":[{"x":-36.17,"y":-497.05,"z":39.54},{"x":-40.26,"y":-496.55,"z":41.75},{"x":-40.37,"y":-496.14,"z":46.26},{"x":-36.36,"y":-496.23,"z":48.56},{"x":-32.24,"y":-496.73,"z":46.31},{"x":-32.17,"y":-497.14,"z":41.8}]},{"lat":81.41,"lon":52.31,"b":[{"x":-45.53,"y":-494.85,"z":54.54},{"x":-49.63,"y":-494.21,"z":56.77},{"x":-49.76,"y":-493.65,"z":61.32},{"x":-45.74,"y":-493.74,"z":63.67},{"x":-41.59,"y":-494.39,"z":61.42},{"x":-41.51,"y":-494.94,"z":56.85}]},{"lat":79.35,"lon":53.44,"b":[{"x":-54.94,"y":-491.99,"z":69.66},{"x":-59.05,"y":-491.19,"z":71.89},{"x":-59.18,"y":-490.48,"z":76.48},{"x":-55.16,"y":-490.57,"z":78.87},{"x":-51.01,"y":-491.38,"z":76.62},{"x":-50.92,"y":-492.08,"z":72.01}]},{"lat":77.26,"lon":54.21,"b":[{"x":-64.37,"y":-488.45,"z":84.85},{"x":-68.49,"y":-487.5,"z":87.05},{"x":-68.61,"y":-486.63,"z":91.67},{"x":-64.6,"y":-486.72,"z":94.09},{"x":-60.45,"y":-487.68,"z":91.87},{"x":-60.35,"y":-488.54,"z":87.23}]},{"lat":75.15,"lon":54.77,"b":[{"x":-73.79,"y":-484.22,"z":100.02},{"x":-77.89,"y":-483.13,"z":102.21},{"x":-78.01,"y":-482.1,"z":106.83},{"x":-74.01,"y":-482.18,"z":109.29},{"x":-69.87,"y":-483.29,"z":107.1},{"x":-69.78,"y":-484.31,"z":102.45}]},{"lat":73.04,"lon":55.19,"b":[{"x":-83.16,"y":-479.32,"z":115.14},{"x":-87.23,"y":-478.08,"z":117.29},{"x":-87.34,"y":-476.9,"z":121.89},{"x":-83.34,"y":-476.97,"z":124.39},{"x":-79.23,"y":-478.23,"z":122.24},{"x":-79.15,"y":-479.4,"z":117.6}]},{"lat":70.92,"lon":55.52,"b":[{"x":-92.42,"y":-473.76,"z":130.13},{"x":-96.46,"y":-472.37,"z":132.22},{"x":-96.55,"y":-471.05,"z":136.81},{"x":-92.58,"y":-471.1,"z":139.33},{"x":-88.5,"y":-472.5,"z":137.24},{"x":-88.43,"y":-473.83,"z":132.62}]},{"lat":68.8,"lon":55.79,"b":[{"x":-101.56,"y":-467.55,"z":144.93},{"x":-105.55,"y":-466.03,"z":146.96},{"x":-105.61,"y":-464.56,"z":151.5},{"x":-101.66,"y":-464.6,"z":154.05},{"x":-97.64,"y":-466.13,"z":152.02},{"x":-97.59,"y":-467.61,"z":147.45}]},{"lat":66.7,"lon":56.01,"b":[{"x":-110.56,"y":-459.7,"z":162.55},{"x":-111.83,"y":-459.17,"z":163.18},{"x":-111.84,"y":-458.65,"z":164.63},{"x":-110.58,"y":-458.66,"z":165.45},{"x":-109.3,"y":-459.19,"z":164.83},{"x":-109.29,"y":-459.71,"z":163.37}]},{"lat":88.35,"lon":90,"b":[{"x":0,"y":-499.83,"z":10.11},{"x":-4,"y":-499.76,"z":12.27},{"x":-4.03,"y":-499.64,"z":16.64},{"x":0,"y":-499.57,"z":18.85},{"x":4.03,"y":-499.64,"z":16.64},{"x":4,"y":-499.76,"z":12.27}]},{"lat":86.5,"lon":72.83,"b":[{"x":-8.98,"y":-499.24,"z":24.74},{"x":-13.03,"y":-499.03,"z":26.94},{"x":-13.08,"y":-498.77,"z":31.39},{"x":-9.03,"y":-498.71,"z":33.64},{"x":-4.96,"y":-498.92,"z":31.4},{"x":-4.96,"y":-499.18,"z":26.95}]},{"lat":84.53,"lon":67.61,"b":[{"x":-18.12,"y":-498.03,"z":39.61},{"x":-22.21,"y":-497.68,"z":41.84},{"x":-22.28,"y":-497.27,"z":46.36},{"x":-18.21,"y":-497.22,"z":48.66},{"x":-14.1,"y":-497.57,"z":46.39},{"x":-14.07,"y":-497.97,"z":41.87}]},{"lat":82.5,"lon":65.13,"b":[{"x":-27.39,"y":-496.17,"z":54.69},{"x":-31.51,"y":-495.67,"z":56.93},{"x":-31.59,"y":-495.12,"z":61.5},{"x":-27.51,"y":-495.07,"z":63.84},{"x":-23.36,"y":-495.57,"z":61.56},{"x":-23.32,"y":-496.12,"z":56.98}]},{"lat":80.43,"lon":63.69,"b":[{"x":-36.75,"y":-493.65,"z":69.9},{"x":-40.89,"y":-493,"z":72.15},{"x":-40.98,"y":-492.29,"z":76.76},{"x":-36.9,"y":-492.24,"z":79.14},{"x":-32.73,"y":-492.89,"z":76.86},{"x":-32.67,"y":-493.6,"z":72.23}]},{"lat":78.34,"lon":62.75,"b":[{"x":-46.17,"y":-490.44,"z":85.19},{"x":-50.32,"y":-489.64,"z":87.44},{"x":-50.42,"y":-488.78,"z":92.07},{"x":-46.33,"y":-488.72,"z":94.48},{"x":-42.15,"y":-489.53,"z":92.22},{"x":-42.09,"y":-490.39,"z":87.57}]},{"lat":76.23,"lon":62.09,"b":[{"x":-55.61,"y":-486.55,"z":100.51},{"x":-59.76,"y":-485.59,"z":102.73},{"x":-59.85,"y":-484.57,"z":107.38},{"x":-55.77,"y":-484.51,"z":109.82},{"x":-51.59,"y":-485.47,"z":107.58},{"x":-51.53,"y":-486.49,"z":102.91}]},{"lat":74.11,"lon":61.6,"b":[{"x":-65.03,"y":-481.96,"z":115.77},{"x":-69.17,"y":-480.86,"z":117.97},{"x":-69.25,"y":-479.68,"z":122.61},{"x":-65.18,"y":-479.61,"z":125.08},{"x":-61.02,"y":-480.73,"z":122.88},{"x":-60.95,"y":-481.9,"z":118.22}]},{"lat":71.98,"lon":61.22,"b":[{"x":-74.4,"y":-476.7,"z":130.94},{"x":-78.51,"y":-475.44,"z":133.08},{"x":-78.58,"y":-474.12,"z":137.7},{"x":-74.52,"y":-474.04,"z":140.19},{"x":-70.38,"y":-475.3,"z":138.05},{"x":-70.33,"y":-476.63,"z":133.41}]},{"lat":69.85,"lon":60.92,"b":[{"x":-83.67,"y":-470.77,"z":145.93},{"x":-87.74,"y":-469.38,"z":148.02},{"x":-87.79,"y":-467.9,"z":152.59},{"x":-83.75,"y":-467.81,"z":155.11},{"x":-79.65,"y":-469.21,"z":153.03},{"x":-79.61,"y":-470.69,"z":148.42}]},{"lat":67.72,"lon":60.67,"b":[{"x":-92.83,"y":-463.07,"z":164.07},{"x":-93.88,"y":-462.68,"z":164.59},{"x":-93.88,"y":-462.26,"z":165.76},{"x":-92.84,"y":-462.23,"z":166.42},{"x":-91.79,"y":-462.63,"z":165.9},{"x":-91.79,"y":-463.05,"z":164.72}]},{"lat":87.37,"lon":141.03,"b":[{"x":17.78,"y":-499.51,"z":10.1},{"x":13.81,"y":-499.59,"z":12.27},{"x":13.84,"y":-499.46,"z":16.64},{"x":17.88,"y":-499.25,"z":18.84},{"x":21.87,"y":-499.17,"z":16.63},{"x":21.79,"y":-499.3,"z":12.26}]},{"lat":86.5,"lon":107.17,"b":[{"x":8.98,"y":-499.24,"z":24.74},{"x":4.96,"y":-499.18,"z":26.95},{"x":4.96,"y":-498.92,"z":31.4},{"x":9.03,"y":-498.71,"z":33.64},{"x":13.08,"y":-498.77,"z":31.39},{"x":13.03,"y":-499.03,"z":26.94}]},{"lat":84.94,"lon":90,"b":[{"x":0,"y":-498.35,"z":39.64},{"x":-4.08,"y":-498.15,"z":41.88},{"x":-4.1,"y":-497.75,"z":46.41},{"x":0,"y":-497.55,"z":48.69},{"x":4.1,"y":-497.75,"z":46.41},{"x":4.08,"y":-498.15,"z":41.88}]},{"lat":83.11,"lon":81.22,"b":[{"x":-9.14,"y":-496.83,"z":54.76},{"x":-13.26,"y":-496.48,"z":57.03},{"x":-13.3,"y":-495.93,"z":61.61},{"x":-9.18,"y":-495.73,"z":63.93},{"x":-5.04,"y":-496.08,"z":61.63},{"x":-5.04,"y":-496.63,"z":57.04}]},{"lat":81.15,"lon":76.11,"b":[{"x":-18.41,"y":-494.65,"z":70.04},{"x":-22.56,"y":-494.15,"z":72.32},{"x":-22.62,"y":-493.45,"z":76.94},{"x":-18.49,"y":-493.25,"z":79.3},{"x":-14.31,"y":-493.75,"z":76.99},{"x":-14.29,"y":-494.45,"z":72.36}]},{"lat":79.13,"lon":72.83,"b":[{"x":-27.78,"y":-491.79,"z":85.43},{"x":-31.95,"y":-491.13,"z":87.7},{"x":-32.01,"y":-490.27,"z":92.36},{"x":-27.88,"y":-490.07,"z":94.74},{"x":-23.68,"y":-490.73,"z":92.44},{"x":-23.65,"y":-491.59,"z":87.78}]},{"lat":77.07,"lon":70.55,"b":[{"x":-37.2,"y":-488.23,"z":100.85},{"x":-41.38,"y":-487.42,"z":103.12},{"x":-41.45,"y":-486.4,"z":107.78},{"x":-37.31,"y":-486.19,"z":110.2},{"x":-33.1,"y":-487.01,"z":107.92},{"x":-33.06,"y":-488.03,"z":103.24}]},{"lat":74.97,"lon":68.88,"b":[{"x":-46.65,"y":-483.97,"z":116.26},{"x":-50.83,"y":-483.01,"z":118.49},{"x":-50.89,"y":-481.83,"z":123.16},{"x":-46.75,"y":-481.62,"z":125.6},{"x":-42.55,"y":-482.59,"z":123.35},{"x":-42.51,"y":-483.77,"z":118.67}]},{"lat":72.86,"lon":67.61,"b":[{"x":-56.1,"y":-478.46,"z":133.7},{"x":-58.37,"y":-477.86,"z":134.9},{"x":-58.4,"y":-477.13,"z":137.43},{"x":-56.15,"y":-477.01,"z":138.77},{"x":-53.87,"y":-477.62,"z":137.57},{"x":-53.85,"y":-478.35,"z":135.03}]},{"lat":70.74,"lon":66.61,"b":[{"x":-65.44,"y":-473.2,"z":147.4},{"x":-68.99,"y":-472.12,"z":149.24},{"x":-69.03,"y":-470.85,"z":153.19},{"x":-65.5,"y":-470.65,"z":155.32},{"x":-61.93,"y":-471.74,"z":153.49},{"x":-61.91,"y":-473.01,"z":149.52}]},{"lat":68.62,"lon":65.8,"b":[{"x":-74.71,"y":-466.74,"z":162.8},{"x":-77.83,"y":-465.68,"z":164.38},{"x":-77.84,"y":-464.45,"z":167.83},{"x":-74.74,"y":-464.26,"z":169.73},{"x":-71.61,"y":-465.33,"z":168.16},{"x":-71.6,"y":-466.57,"z":164.68}]},{"lat":85.6,"lon":157.98,"b":[{"x":35.48,"y":-498.57,"z":10.08},{"x":31.56,"y":-498.78,"z":12.24},{"x":31.64,"y":-498.65,"z":16.61},{"x":35.7,"y":-498.3,"z":18.8},{"x":39.64,"y":-498.08,"z":16.59},{"x":39.5,"y":-498.22,"z":12.23}]},{"lat":85.45,"lon":132.83,"b":[{"x":26.91,"y":-498.59,"z":24.71},{"x":22.92,"y":-498.68,"z":26.92},{"x":22.97,"y":-498.41,"z":31.37},{"x":27.06,"y":-498.06,"z":33.6},{"x":31.07,"y":-497.98,"z":31.34},{"x":30.97,"y":-498.24,"z":26.9}]},{"lat":84.53,"lon":112.39,"b":[{"x":18.12,"y":-498.03,"z":39.61},{"x":14.07,"y":-497.97,"z":41.87},{"x":14.1,"y":-497.57,"z":46.39},{"x":18.21,"y":-497.22,"z":48.66},{"x":22.28,"y":-497.27,"z":46.36},{"x":22.21,"y":-497.68,"z":41.84}]},{"lat":83.11,"lon":98.78,"b":[{"x":9.14,"y":-496.83,"z":54.76},{"x":5.04,"y":-496.63,"z":57.04},{"x":5.04,"y":-496.08,"z":61.63},{"x":9.18,"y":-495.73,"z":63.93},{"x":13.3,"y":-495.93,"z":61.61},{"x":13.26,"y":-496.48,"z":57.03}]},{"lat":81.41,"lon":90,"b":[{"x":0,"y":-494.99,"z":70.09},{"x":-4.14,"y":-494.64,"z":72.39},{"x":-4.16,"y":-493.94,"z":77.02},{"x":0,"y":-493.58,"z":79.35},{"x":4.16,"y":-493.94,"z":77.02},{"x":4.14,"y":-494.64,"z":72.39}]},{"lat":79.55,"lon":84.12,"b":[{"x":-9.27,"y":-492.46,"z":85.54},{"x":-13.45,"y":-491.96,"z":87.85},{"x":-13.48,"y":-491.1,"z":92.51},{"x":-9.3,"y":-490.75,"z":94.87},{"x":-5.11,"y":-491.25,"z":92.54},{"x":-5.11,"y":-492.11,"z":87.87}]},{"lat":77.6,"lon":79.99,"b":[{"x":-18.64,"y":-489.24,"z":101.06},{"x":-22.84,"y":-488.59,"z":103.36},{"x":-22.88,"y":-487.57,"z":108.04},{"x":-18.69,"y":-487.21,"z":110.43},{"x":-14.48,"y":-487.87,"z":108.11},{"x":-14.46,"y":-488.89,"z":103.42}]},{"lat":75.58,"lon":76.95,"b":[{"x":-28.07,"y":-485.33,"z":116.58},{"x":-32.27,"y":-484.51,"z":118.86},{"x":-32.32,"y":-483.33,"z":123.54},{"x":-28.13,"y":-482.97,"z":125.95},{"x":-23.9,"y":-483.79,"z":123.66},{"x":-23.88,"y":-484.97,"z":118.97}]},{"lat":73.53,"lon":74.64,"b":[{"x":-37.51,"y":-480.71,"z":132.04},{"x":-41.72,"y":-479.74,"z":134.28},{"x":-41.76,"y":-478.4,"z":138.95},{"x":-37.58,"y":-478.04,"z":141.38},{"x":-33.35,"y":-479.01,"z":139.13},{"x":-33.33,"y":-480.34,"z":134.45}]},{"lat":71.44,"lon":72.83,"b":[{"x":-46.95,"y":-475.06,"z":148.48},{"x":-50.13,"y":-474.21,"z":150.15},{"x":-50.15,"y":-473.08,"z":153.67},{"x":-46.98,"y":-472.8,"z":155.52},{"x":-43.79,"y":-473.65,"z":153.86},{"x":-43.77,"y":-474.78,"z":150.33}]},{"lat":83.67,"lon":164.91,"b":[{"x":53.1,"y":-496.99,"z":11.13},{"x":50.21,"y":-497.25,"z":12.75},{"x":50.31,"y":-497.15,"z":16.01},{"x":53.34,"y":-496.78,"z":17.65},{"x":56.24,"y":-496.51,"z":15.99},{"x":56.1,"y":-496.62,"z":12.73}]},{"lat":83.86,"lon":147.09,"b":[{"x":44.74,"y":-497.32,"z":24.64},{"x":40.8,"y":-497.54,"z":26.86},{"x":40.9,"y":-497.27,"z":31.3},{"x":44.99,"y":-496.77,"z":33.51},{"x":48.93,"y":-496.54,"z":31.25},{"x":48.78,"y":-496.82,"z":26.82}]},{"lat":83.45,"lon":129.49,"b":[{"x":36.17,"y":-497.05,"z":39.54},{"x":32.17,"y":-497.14,"z":41.8},{"x":32.24,"y":-496.73,"z":46.31},{"x":36.36,"y":-496.23,"z":48.56},{"x":40.37,"y":-496.14,"z":46.26},{"x":40.26,"y":-496.55,"z":41.75}]},{"lat":82.5,"lon":114.87,"b":[{"x":27.39,"y":-496.17,"z":54.69},{"x":23.32,"y":-496.12,"z":56.98},{"x":23.36,"y":-495.57,"z":61.56},{"x":27.51,"y":-495.07,"z":63.84},{"x":31.59,"y":-495.12,"z":61.5},{"x":31.51,"y":-495.67,"z":56.93}]},{"lat":81.15,"lon":103.89,"b":[{"x":18.41,"y":-494.65,"z":70.04},{"x":14.29,"y":-494.45,"z":72.36},{"x":14.31,"y":-493.75,"z":76.99},{"x":18.49,"y":-493.25,"z":79.3},{"x":22.62,"y":-493.45,"z":76.94},{"x":22.56,"y":-494.15,"z":72.32}]},{"lat":79.55,"lon":95.88,"b":[{"x":9.27,"y":-492.46,"z":85.54},{"x":5.11,"y":-492.11,"z":87.87},{"x":5.11,"y":-491.25,"z":92.54},{"x":9.3,"y":-490.75,"z":94.87},{"x":13.48,"y":-491.1,"z":92.51},{"x":13.45,"y":-491.96,"z":87.85}]},{"lat":77.78,"lon":90,"b":[{"x":0,"y":-489.58,"z":101.13},{"x":-4.19,"y":-489.08,"z":103.46},{"x":-4.21,"y":-488.06,"z":108.15},{"x":0,"y":-487.55,"z":110.51},{"x":4.21,"y":-488.06,"z":108.15},{"x":4.19,"y":-489.08,"z":103.46}]},{"lat":75.9,"lon":85.58,"b":[{"x":-9.37,"y":-486.01,"z":116.75},{"x":-13.58,"y":-485.34,"z":119.06},{"x":-13.61,"y":-484.17,"z":123.75},{"x":-9.39,"y":-483.65,"z":126.13},{"x":-5.16,"y":-484.32,"z":123.8},{"x":-5.16,"y":-485.5,"z":119.1}]},{"lat":73.94,"lon":82.18,"b":[{"x":-18.8,"y":-481.72,"z":132.32},{"x":-23.02,"y":-480.9,"z":134.61},{"x":-23.05,"y":-479.57,"z":139.29},{"x":-18.83,"y":-479.05,"z":141.68},{"x":-14.59,"y":-479.87,"z":139.38},{"x":-14.58,"y":-481.21,"z":134.69}]},{"lat":71.93,"lon":79.5,"b":[{"x":-28.24,"y":-476.74,"z":147.78},{"x":-32.47,"y":-475.77,"z":150.03},{"x":-32.49,"y":-474.28,"z":154.67},{"x":-28.27,"y":-473.76,"z":157.08},{"x":-24.03,"y":-474.73,"z":154.83},{"x":-24.02,"y":-476.22,"z":150.17}]},{"lat":69.89,"lon":77.33,"b":[{"x":-37.68,"y":-470.44,"z":164.96},{"x":-40.16,"y":-469.78,"z":166.26},{"x":-40.16,"y":-468.81,"z":168.97},{"x":-37.69,"y":-468.5,"z":170.39},{"x":-35.2,"y":-469.16,"z":169.1},{"x":-35.19,"y":-470.13,"z":166.38}]},{"lat":82.07,"lon":155.19,"b":[{"x":62.39,"y":-495.42,"z":24.55},{"x":58.52,"y":-495.77,"z":26.76},{"x":58.67,"y":-495.49,"z":31.19},{"x":62.74,"y":-494.85,"z":33.38},{"x":66.61,"y":-494.49,"z":31.12},{"x":66.41,"y":-494.78,"z":26.71}]},{"lat":81.98,"lon":141.03,"b":[{"x":54.08,"y":-495.43,"z":39.41},{"x":50.13,"y":-495.66,"z":41.67},{"x":50.25,"y":-495.25,"z":46.18},{"x":54.36,"y":-494.6,"z":48.4},{"x":58.31,"y":-494.37,"z":46.09},{"x":58.15,"y":-494.79,"z":41.6}]},{"lat":81.41,"lon":127.69,"b":[{"x":45.53,"y":-494.85,"z":54.54},{"x":41.51,"y":-494.94,"z":56.85},{"x":41.59,"y":-494.39,"z":61.42},{"x":45.74,"y":-493.74,"z":63.67},{"x":49.76,"y":-493.65,"z":61.32},{"x":49.63,"y":-494.21,"z":56.77}]},{"lat":80.43,"lon":116.31,"b":[{"x":36.75,"y":-493.65,"z":69.9},{"x":32.67,"y":-493.6,"z":72.23},{"x":32.73,"y":-492.89,"z":76.86},{"x":36.9,"y":-492.24,"z":79.14},{"x":40.98,"y":-492.29,"z":76.76},{"x":40.89,"y":-493,"z":72.15}]},{"lat":79.13,"lon":107.17,"b":[{"x":27.78,"y":-491.79,"z":85.43},{"x":23.65,"y":-491.59,"z":87.78},{"x":23.68,"y":-490.73,"z":92.44},{"x":27.88,"y":-490.07,"z":94.74},{"x":32.01,"y":-490.27,"z":92.36},{"x":31.95,"y":-491.13,"z":87.7}]},{"lat":77.6,"lon":100.01,"b":[{"x":18.64,"y":-489.24,"z":101.06},{"x":14.46,"y":-488.89,"z":103.42},{"x":14.48,"y":-487.87,"z":108.11},{"x":18.69,"y":-487.21,"z":110.43},{"x":22.88,"y":-487.57,"z":108.04},{"x":22.84,"y":-488.59,"z":103.36}]},{"lat":75.9,"lon":94.42,"b":[{"x":9.37,"y":-486.01,"z":116.75},{"x":5.16,"y":-485.5,"z":119.1},{"x":5.16,"y":-484.32,"z":123.8},{"x":9.39,"y":-483.65,"z":126.13},{"x":13.61,"y":-484.17,"z":123.75},{"x":13.58,"y":-485.34,"z":119.06}]},{"lat":74.08,"lon":90,"b":[{"x":0,"y":-482.06,"z":132.41},{"x":-4.23,"y":-481.4,"z":134.75},{"x":-4.24,"y":-480.06,"z":139.43},{"x":0,"y":-479.39,"z":141.78},{"x":4.24,"y":-480.06,"z":139.43},{"x":4.23,"y":-481.4,"z":134.75}]},{"lat":72.19,"lon":86.46,"b":[{"x":-9.43,"y":-477.42,"z":147.99},{"x":-13.67,"y":-476.6,"z":150.29},{"x":-13.68,"y":-475.1,"z":154.94},{"x":-9.44,"y":-474.43,"z":157.3},{"x":-5.19,"y":-475.25,"z":155},{"x":-5.19,"y":-476.75,"z":150.34}]},{"lat":70.23,"lon":83.59,"b":[{"x":-18.87,"y":-472.08,"z":163.41},{"x":-23.11,"y":-471.1,"z":165.66},{"x":-23.12,"y":-469.46,"z":170.27},{"x":-18.88,"y":-468.78,"z":172.64},{"x":-14.64,"y":-469.76,"z":170.39},{"x":-14.63,"y":-471.41,"z":165.77}]},{"lat":68.24,"lon":81.22,"b":[{"x":-28.3,"y":-465.02,"z":181.44},{"x":-29.92,"y":-464.59,"z":182.28},{"x":-29.92,"y":-463.9,"z":184.03},{"x":-28.3,"y":-463.64,"z":184.93},{"x":-26.68,"y":-464.07,"z":184.1},{"x":-26.68,"y":-464.76,"z":182.35}]},{"lat":80.2,"lon":160.22,"b":[{"x":79.91,"y":-492.83,"z":26.22},{"x":77.68,"y":-493.11,"z":27.52},{"x":77.79,"y":-492.95,"z":30.11},{"x":80.17,"y":-492.49,"z":31.39},{"x":82.4,"y":-492.2,"z":30.06},{"x":82.26,"y":-492.38,"z":27.48}]},{"lat":80.31,"lon":148.75,"b":[{"x":71.78,"y":-493.19,"z":39.23},{"x":67.91,"y":-493.55,"z":41.49},{"x":68.07,"y":-493.13,"z":45.98},{"x":72.14,"y":-492.34,"z":48.18},{"x":76.01,"y":-491.98,"z":45.87},{"x":75.81,"y":-492.41,"z":41.4}]},{"lat":80.02,"lon":137.24,"b":[{"x":63.48,"y":-492.9,"z":54.32},{"x":59.53,"y":-493.13,"z":56.64},{"x":59.66,"y":-492.57,"z":61.19},{"x":63.77,"y":-491.77,"z":63.41},{"x":67.72,"y":-491.54,"z":61.06},{"x":67.56,"y":-492.11,"z":56.52}]},{"lat":79.35,"lon":126.56,"b":[{"x":54.94,"y":-491.99,"z":69.66},{"x":50.92,"y":-492.08,"z":72.01},{"x":51.01,"y":-491.38,"z":76.62},{"x":55.16,"y":-490.57,"z":78.87},{"x":59.18,"y":-490.48,"z":76.48},{"x":59.05,"y":-491.19,"z":71.89}]},{"lat":78.34,"lon":117.25,"b":[{"x":46.17,"y":-490.44,"z":85.19},{"x":42.09,"y":-490.39,"z":87.57},{"x":42.15,"y":-489.53,"z":92.22},{"x":46.33,"y":-488.72,"z":94.48},{"x":50.42,"y":-488.78,"z":92.07},{"x":50.32,"y":-489.64,"z":87.44}]},{"lat":77.07,"lon":109.45,"b":[{"x":37.2,"y":-488.23,"z":100.85},{"x":33.06,"y":-488.03,"z":103.24},{"x":33.1,"y":-487.01,"z":107.92},{"x":37.31,"y":-486.19,"z":110.2},{"x":41.45,"y":-486.4,"z":107.78},{"x":41.38,"y":-487.42,"z":103.12}]},{"lat":75.58,"lon":103.05,"b":[{"x":28.07,"y":-485.33,"z":116.58},{"x":23.88,"y":-484.97,"z":118.97},{"x":23.9,"y":-483.79,"z":123.66},{"x":28.13,"y":-482.97,"z":125.95},{"x":32.32,"y":-483.33,"z":123.54},{"x":32.27,"y":-484.51,"z":118.86}]},{"lat":73.94,"lon":97.82,"b":[{"x":18.8,"y":-481.72,"z":132.32},{"x":14.58,"y":-481.21,"z":134.69},{"x":14.59,"y":-479.87,"z":139.38},{"x":18.83,"y":-479.05,"z":141.68},{"x":23.05,"y":-479.57,"z":139.29},{"x":23.02,"y":-480.9,"z":134.61}]},{"lat":72.19,"lon":93.54,"b":[{"x":9.43,"y":-477.42,"z":147.99},{"x":5.19,"y":-476.75,"z":150.34},{"x":5.19,"y":-475.25,"z":155},{"x":9.44,"y":-474.43,"z":157.3},{"x":13.68,"y":-475.1,"z":154.94},{"x":13.67,"y":-476.6,"z":150.29}]},{"lat":70.35,"lon":90,"b":[{"x":0,"y":-472.42,"z":163.52},{"x":-4.25,"y":-471.59,"z":165.83},{"x":-4.25,"y":-469.94,"z":170.45},{"x":0,"y":-469.12,"z":172.76},{"x":4.25,"y":-469.94,"z":170.45},{"x":4.25,"y":-471.59,"z":165.83}]},{"lat":68.44,"lon":87.05,"b":[{"x":-9.45,"y":-466.73,"z":178.86},{"x":-13.69,"y":-465.75,"z":181.11},{"x":-13.69,"y":-463.95,"z":185.68},{"x":-9.44,"y":-463.13,"z":187.99},{"x":-5.2,"y":-464.1,"z":185.74},{"x":-5.2,"y":-465.9,"z":181.17}]},{"lat":78.31,"lon":163.61,"b":[{"x":97.02,"y":-489.78,"z":25.47},{"x":94.34,"y":-490.22,"z":27.06},{"x":94.52,"y":-490,"z":30.23},{"x":97.4,"y":-489.34,"z":31.79},{"x":100.07,"y":-488.9,"z":30.15},{"x":99.86,"y":-489.13,"z":27.01}]},{"lat":78.53,"lon":154.11,"b":[{"x":89.21,"y":-490.36,"z":39},{"x":85.42,"y":-490.84,"z":41.26},{"x":85.63,"y":-490.41,"z":45.73},{"x":89.66,"y":-489.49,"z":47.9},{"x":93.44,"y":-489,"z":45.59},{"x":93.19,"y":-489.44,"z":41.15}]},{"lat":78.43,"lon":144.28,"b":[{"x":81.2,"y":-490.32,"z":54.04},{"x":77.32,"y":-490.68,"z":56.35},{"x":77.49,"y":-490.12,"z":60.89},{"x":81.56,"y":-489.18,"z":63.08},{"x":85.43,"y":-488.82,"z":60.72},{"x":85.23,"y":-489.39,"z":56.21}]},{"lat":78,"lon":134.68,"b":[{"x":72.91,"y":-489.7,"z":69.34},{"x":68.96,"y":-489.93,"z":71.69},{"x":69.09,"y":-489.22,"z":76.29},{"x":73.2,"y":-488.27,"z":78.5},{"x":77.15,"y":-488.04,"z":76.1},{"x":76.98,"y":-488.76,"z":71.53}]},{"lat":77.26,"lon":125.79,"b":[{"x":64.37,"y":-488.45,"z":84.85},{"x":60.35,"y":-488.54,"z":87.23},{"x":60.45,"y":-487.68,"z":91.87},{"x":64.6,"y":-486.72,"z":94.09},{"x":68.61,"y":-486.63,"z":91.67},{"x":68.49,"y":-487.5,"z":87.05}]},{"lat":76.23,"lon":117.91,"b":[{"x":55.61,"y":-486.55,"z":100.51},{"x":51.53,"y":-486.49,"z":102.91},{"x":51.59,"y":-485.47,"z":107.58},{"x":55.77,"y":-484.51,"z":109.82},{"x":59.85,"y":-484.57,"z":107.38},{"x":59.76,"y":-485.59,"z":102.73}]},{"lat":74.97,"lon":111.12,"b":[{"x":46.65,"y":-483.97,"z":116.26},{"x":42.51,"y":-483.77,"z":118.67},{"x":42.55,"y":-482.59,"z":123.35},{"x":46.75,"y":-481.62,"z":125.6},{"x":50.89,"y":-481.83,"z":123.16},{"x":50.83,"y":-483.01,"z":118.49}]},{"lat":73.53,"lon":105.36,"b":[{"x":37.51,"y":-480.71,"z":132.04},{"x":33.33,"y":-480.34,"z":134.45},{"x":33.35,"y":-479.01,"z":139.13},{"x":37.58,"y":-478.04,"z":141.38},{"x":41.76,"y":-478.4,"z":138.95},{"x":41.72,"y":-479.74,"z":134.28}]},{"lat":71.93,"lon":100.5,"b":[{"x":28.24,"y":-476.74,"z":147.78},{"x":24.02,"y":-476.22,"z":150.17},{"x":24.03,"y":-474.73,"z":154.83},{"x":28.27,"y":-473.76,"z":157.08},{"x":32.49,"y":-474.28,"z":154.67},{"x":32.47,"y":-475.77,"z":150.03}]},{"lat":70.23,"lon":96.41,"b":[{"x":18.87,"y":-472.08,"z":163.41},{"x":14.63,"y":-471.41,"z":165.77},{"x":14.64,"y":-469.76,"z":170.39},{"x":18.88,"y":-468.78,"z":172.64},{"x":23.12,"y":-469.46,"z":170.27},{"x":23.11,"y":-471.1,"z":165.66}]},{"lat":68.44,"lon":92.95,"b":[{"x":9.45,"y":-466.73,"z":178.86},{"x":5.2,"y":-465.9,"z":181.17},{"x":5.2,"y":-464.1,"z":185.74},{"x":9.44,"y":-463.13,"z":187.99},{"x":13.69,"y":-463.95,"z":185.68},{"x":13.69,"y":-465.75,"z":181.11}]},{"lat":66.6,"lon":90,"b":[{"x":0,"y":-459.11,"z":198.01},{"x":-0.57,"y":-458.98,"z":198.31},{"x":-0.57,"y":-458.72,"z":198.91},{"x":0,"y":-458.59,"z":199.2},{"x":0.57,"y":-458.72,"z":198.91},{"x":0.57,"y":-458.98,"z":198.31}]},{"lat":76.7,"lon":157.98,"b":[{"x":106.31,"y":-486.96,"z":38.73},{"x":102.62,"y":-487.56,"z":40.99},{"x":102.86,"y":-487.12,"z":45.42},{"x":106.83,"y":-486.06,"z":47.56},{"x":110.51,"y":-485.46,"z":45.26},{"x":110.23,"y":-485.91,"z":40.86}]},{"lat":76.74,"lon":149.53,"b":[{"x":98.6,"y":-487.16,"z":53.69},{"x":94.82,"y":-487.65,"z":56},{"x":95.02,"y":-487.07,"z":60.51},{"x":99.04,"y":-486,"z":62.67},{"x":102.81,"y":-485.51,"z":60.31},{"x":102.57,"y":-486.1,"z":55.84}]},{"lat":76.49,"lon":141.03,"b":[{"x":90.6,"y":-486.79,"z":68.93},{"x":86.73,"y":-487.16,"z":71.29},{"x":86.9,"y":-486.44,"z":75.85},{"x":90.96,"y":-485.35,"z":78.03},{"x":94.81,"y":-484.99,"z":75.62},{"x":94.62,"y":-485.72,"z":71.09}]},{"lat":75.96,"lon":132.83,"b":[{"x":82.32,"y":-485.83,"z":84.39},{"x":78.38,"y":-486.05,"z":86.79},{"x":78.51,"y":-485.19,"z":91.4},{"x":82.61,"y":-484.09,"z":93.59},{"x":86.54,"y":-483.87,"z":91.15},{"x":86.38,"y":-484.74,"z":86.56}]},{"lat":75.15,"lon":125.23,"b":[{"x":73.79,"y":-484.22,"z":100.02},{"x":69.78,"y":-484.31,"z":102.45},{"x":69.87,"y":-483.29,"z":107.1},{"x":74.01,"y":-482.18,"z":109.29},{"x":78.01,"y":-482.1,"z":106.83},{"x":77.89,"y":-483.13,"z":102.21}]},{"lat":74.11,"lon":118.4,"b":[{"x":65.03,"y":-481.96,"z":115.77},{"x":60.95,"y":-481.9,"z":118.22},{"x":61.02,"y":-480.73,"z":122.88},{"x":65.18,"y":-479.61,"z":125.08},{"x":69.25,"y":-479.68,"z":122.61},{"x":69.17,"y":-480.86,"z":117.97}]},{"lat":72.86,"lon":112.39,"b":[{"x":56.07,"y":-479.02,"z":131.58},{"x":51.94,"y":-478.81,"z":134.02},{"x":51.97,"y":-477.48,"z":138.68},{"x":56.16,"y":-476.36,"z":140.88},{"x":60.29,"y":-476.58,"z":138.41},{"x":60.24,"y":-477.91,"z":133.77}]},{"lat":71.44,"lon":107.17,"b":[{"x":46.94,"y":-475.4,"z":147.36},{"x":42.76,"y":-475.03,"z":149.79},{"x":42.78,"y":-473.54,"z":154.44},{"x":46.99,"y":-472.41,"z":156.64},{"x":51.16,"y":-472.79,"z":154.19},{"x":51.13,"y":-474.28,"z":149.56}]},{"lat":69.89,"lon":102.67,"b":[{"x":37.67,"y":-471.07,"z":163.06},{"x":33.45,"y":-470.55,"z":165.46},{"x":33.46,"y":-468.9,"z":170.08},{"x":37.68,"y":-467.78,"z":172.27},{"x":41.89,"y":-468.31,"z":169.86},{"x":41.88,"y":-469.95,"z":165.26}]},{"lat":68.24,"lon":98.78,"b":[{"x":28.3,"y":-466.06,"z":178.61},{"x":24.06,"y":-465.39,"z":180.97},{"x":24.06,"y":-463.59,"z":185.53},{"x":28.29,"y":-462.47,"z":187.72},{"x":32.52,"y":-463.15,"z":185.35},{"x":32.52,"y":-464.94,"z":180.8}]},{"lat":74.86,"lon":160.88,"b":[{"x":123.03,"y":-483.03,"z":38.42},{"x":119.45,"y":-483.75,"z":40.67},{"x":119.73,"y":-483.29,"z":45.06},{"x":123.63,"y":-482.1,"z":47.18},{"x":127.19,"y":-481.39,"z":44.88},{"x":126.87,"y":-481.87,"z":40.52}]},{"lat":74.99,"lon":153.53,"b":[{"x":115.64,"y":-483.45,"z":53.28},{"x":111.96,"y":-484.05,"z":55.59},{"x":112.2,"y":-483.46,"z":60.06},{"x":116.15,"y":-482.26,"z":62.19},{"x":119.81,"y":-481.66,"z":59.83},{"x":119.54,"y":-482.26,"z":55.4}]},{"lat":74.87,"lon":146.01,"b":[{"x":107.94,"y":-483.32,"z":68.43},{"x":104.17,"y":-483.8,"z":70.8},{"x":104.37,"y":-483.07,"z":75.33},{"x":108.36,"y":-481.85,"z":77.47},{"x":112.11,"y":-481.38,"z":75.06},{"x":111.89,"y":-482.11,"z":70.56}]},{"lat":74.51,"lon":138.57,"b":[{"x":99.95,"y":-482.61,"z":83.83},{"x":96.1,"y":-482.96,"z":86.24},{"x":96.25,"y":-482.09,"z":90.82},{"x":100.29,"y":-480.86,"z":92.96},{"x":104.13,"y":-480.51,"z":90.51},{"x":103.94,"y":-481.39,"z":85.96}]},{"lat":73.89,"lon":131.44,"b":[{"x":91.68,"y":-481.28,"z":99.42},{"x":87.75,"y":-481.51,"z":101.86},{"x":87.87,"y":-480.48,"z":106.48},{"x":91.94,"y":-479.24,"z":108.62},{"x":95.86,"y":-479.03,"z":106.14},{"x":95.72,"y":-480.05,"z":101.56}]},{"lat":73.04,"lon":124.81,"b":[{"x":83.16,"y":-479.32,"z":115.14},{"x":79.15,"y":-479.4,"z":117.6},{"x":79.23,"y":-478.23,"z":122.24},{"x":83.34,"y":-476.97,"z":124.39},{"x":87.34,"y":-476.9,"z":121.89},{"x":87.23,"y":-478.08,"z":117.29}]},{"lat":71.98,"lon":118.78,"b":[{"x":74.4,"y":-476.7,"z":130.94},{"x":70.33,"y":-476.63,"z":133.41},{"x":70.38,"y":-475.3,"z":138.05},{"x":74.52,"y":-474.04,"z":140.19},{"x":78.58,"y":-474.12,"z":137.7},{"x":78.51,"y":-475.44,"z":133.08}]},{"lat":70.74,"lon":113.39,"b":[{"x":65.44,"y":-473.4,"z":146.74},{"x":61.31,"y":-473.18,"z":149.21},{"x":61.34,"y":-471.69,"z":153.84},{"x":65.51,"y":-470.43,"z":155.98},{"x":69.62,"y":-470.65,"z":153.49},{"x":69.58,"y":-472.14,"z":148.88}]},{"lat":69.35,"lon":108.63,"b":[{"x":56.3,"y":-469.41,"z":162.48},{"x":52.13,"y":-469.04,"z":164.93},{"x":52.14,"y":-467.4,"z":169.53},{"x":56.33,"y":-466.13,"z":171.66},{"x":60.48,"y":-466.51,"z":169.2},{"x":60.47,"y":-468.15,"z":164.62}]},{"lat":67.83,"lon":104.44,"b":[{"x":47.03,"y":-464.74,"z":178.1},{"x":42.83,"y":-464.22,"z":180.51},{"x":42.83,"y":-462.42,"z":185.07},{"x":47.02,"y":-461.16,"z":187.19},{"x":51.21,"y":-461.69,"z":184.77},{"x":51.22,"y":-463.48,"z":180.23}]},{"lat":66.22,"lon":100.77,"b":[{"x":37.66,"y":-458.23,"z":196.39},{"x":36.12,"y":-457.98,"z":197.26},{"x":36.11,"y":-457.27,"z":198.9},{"x":37.65,"y":-456.81,"z":199.67},{"x":39.19,"y":-457.06,"z":198.8},{"x":39.2,"y":-457.77,"z":197.17}]},{"lat":72.65,"lon":169.22,"b":[{"x":146.15,"y":-477.48,"z":24.64},{"x":143.56,"y":-478.17,"z":26.3},{"x":143.84,"y":-477.9,"z":29.58},{"x":146.73,"y":-476.91,"z":31.17},{"x":149.3,"y":-476.22,"z":29.47},{"x":148.99,"y":-476.51,"z":26.22}]},{"lat":73.03,"lon":163.12,"b":[{"x":139.32,"y":-478.62,"z":38.07},{"x":135.85,"y":-479.43,"z":40.3},{"x":136.17,"y":-478.95,"z":44.66},{"x":139.98,"y":-477.65,"z":46.74},{"x":143.43,"y":-476.85,"z":44.45},{"x":143.08,"y":-477.34,"z":40.14}]},{"lat":73.21,"lon":156.66,"b":[{"x":132.26,"y":-479.22,"z":52.82},{"x":128.7,"y":-479.93,"z":55.12},{"x":128.97,"y":-479.33,"z":59.55},{"x":132.83,"y":-478,"z":61.64},{"x":136.38,"y":-477.3,"z":59.29},{"x":136.08,"y":-477.92,"z":54.9}]},{"lat":73.2,"lon":149.98,"b":[{"x":124.89,"y":-479.3,"z":67.87},{"x":121.23,"y":-479.9,"z":70.22},{"x":121.45,"y":-479.16,"z":74.72},{"x":125.36,"y":-477.82,"z":76.82},{"x":129,"y":-477.23,"z":74.41},{"x":128.75,"y":-477.98,"z":69.95}]},{"lat":72.96,"lon":143.25,"b":[{"x":117.2,"y":-478.83,"z":83.17},{"x":113.45,"y":-479.3,"z":85.58},{"x":113.63,"y":-478.43,"z":90.13},{"x":117.59,"y":-477.07,"z":92.23},{"x":121.32,"y":-476.6,"z":89.78},{"x":121.11,"y":-477.48,"z":85.27}]},{"lat":72.49,"lon":136.65,"b":[{"x":109.21,"y":-477.76,"z":98.69},{"x":105.38,"y":-478.11,"z":101.14},{"x":105.52,"y":-477.09,"z":105.72},{"x":109.52,"y":-475.71,"z":107.82},{"x":113.34,"y":-475.38,"z":105.34},{"x":113.17,"y":-476.4,"z":100.79}]},{"lat":71.81,"lon":130.36,"b":[{"x":100.95,"y":-476.08,"z":114.36},{"x":97.03,"y":-476.29,"z":116.84},{"x":97.13,"y":-475.12,"z":121.45},{"x":101.17,"y":-473.73,"z":123.54},{"x":105.07,"y":-473.53,"z":121.03},{"x":104.95,"y":-474.71,"z":116.46}]},{"lat":70.92,"lon":124.48,"b":[{"x":92.42,"y":-473.76,"z":130.13},{"x":88.43,"y":-473.83,"z":132.62},{"x":88.5,"y":-472.5,"z":137.24},{"x":92.58,"y":-471.1,"z":139.33},{"x":96.55,"y":-471.05,"z":136.81},{"x":96.46,"y":-472.37,"z":132.22}]},{"lat":69.85,"lon":119.08,"b":[{"x":83.67,"y":-470.77,"z":145.93},{"x":79.61,"y":-470.69,"z":148.42},{"x":79.65,"y":-469.21,"z":153.03},{"x":83.75,"y":-467.81,"z":155.11},{"x":87.79,"y":-467.9,"z":152.59},{"x":87.74,"y":-469.38,"z":148.02}]},{"lat":68.62,"lon":114.2,"b":[{"x":74.7,"y":-467.11,"z":161.69},{"x":70.59,"y":-466.89,"z":164.17},{"x":70.61,"y":-465.25,"z":168.75},{"x":74.73,"y":-463.85,"z":170.82},{"x":78.82,"y":-464.08,"z":168.32},{"x":78.81,"y":-465.71,"z":163.77}]},{"lat":67.25,"lon":109.83,"b":[{"x":65.57,"y":-462.09,"z":179.22},{"x":63.13,"y":-461.86,"z":180.67},{"x":63.13,"y":-460.81,"z":183.34},{"x":65.57,"y":-459.99,"z":184.55},{"x":68,"y":-460.21,"z":183.1},{"x":68.01,"y":-461.26,"z":180.44}]},{"lat":71.2,"lon":164.91,"b":[{"x":155.29,"y":-473.6,"z":39.28},{"x":153.2,"y":-474.16,"z":40.67},{"x":153.42,"y":-473.85,"z":43.36},{"x":155.74,"y":-472.98,"z":44.64},{"x":157.82,"y":-472.42,"z":43.22},{"x":157.58,"y":-472.74,"z":40.56}]},{"lat":71.43,"lon":159.16,"b":[{"x":148.43,"y":-474.52,"z":52.3},{"x":144.98,"y":-475.32,"z":54.59},{"x":145.28,"y":-474.71,"z":58.98},{"x":149.06,"y":-473.28,"z":61.03},{"x":152.47,"y":-472.48,"z":58.69},{"x":152.15,"y":-473.11,"z":54.35}]},{"lat":71.49,"lon":153.18,"b":[{"x":141.38,"y":-474.79,"z":67.23},{"x":137.84,"y":-475.49,"z":69.58},{"x":138.09,"y":-474.74,"z":74.03},{"x":141.92,"y":-473.29,"z":76.09},{"x":145.43,"y":-472.6,"z":73.69},{"x":145.15,"y":-473.36,"z":69.28}]},{"lat":71.34,"lon":147.09,"b":[{"x":134.02,"y":-474.53,"z":82.43},{"x":130.38,"y":-475.11,"z":84.83},{"x":130.58,"y":-474.23,"z":89.34},{"x":134.45,"y":-472.76,"z":91.39},{"x":138.07,"y":-472.18,"z":88.94},{"x":137.84,"y":-473.07,"z":84.48}]},{"lat":71,"lon":141.03,"b":[{"x":126.33,"y":-473.7,"z":97.85},{"x":122.6,"y":-474.17,"z":100.3},{"x":122.77,"y":-473.14,"z":104.85},{"x":126.68,"y":-471.65,"z":106.9},{"x":130.39,"y":-471.2,"z":104.41},{"x":130.2,"y":-472.22,"z":99.9}]},{"lat":70.46,"lon":135.12,"b":[{"x":118.35,"y":-472.28,"z":113.45},{"x":114.53,"y":-472.62,"z":115.94},{"x":114.65,"y":-471.44,"z":120.51},{"x":118.61,"y":-469.93,"z":122.55},{"x":122.4,"y":-469.61,"z":120.03},{"x":122.26,"y":-470.79,"z":115.5}]},{"lat":69.72,"lon":129.49,"b":[{"x":110.08,"y":-470.24,"z":129.16},{"x":106.19,"y":-470.44,"z":131.67},{"x":106.27,"y":-469.11,"z":136.25},{"x":110.26,"y":-467.59,"z":138.29},{"x":114.14,"y":-467.41,"z":135.75},{"x":114.04,"y":-468.73,"z":131.2}]},{"lat":68.8,"lon":124.21,"b":[{"x":101.56,"y":-467.55,"z":144.93},{"x":97.59,"y":-467.61,"z":147.45},{"x":97.64,"y":-466.13,"z":152.02},{"x":101.66,"y":-464.6,"z":154.05},{"x":105.61,"y":-464.56,"z":151.5},{"x":105.55,"y":-466.03,"z":146.96}]},{"lat":67.72,"lon":119.33,"b":[{"x":92.82,"y":-463.59,"z":162.52},{"x":90.41,"y":-463.54,"z":164.02},{"x":90.42,"y":-462.57,"z":166.75},{"x":92.84,"y":-461.65,"z":167.95},{"x":95.24,"y":-461.71,"z":166.43},{"x":95.22,"y":-462.68,"z":163.73}]},{"lat":66.5,"lon":114.87,"b":[{"x":83.85,"y":-459.09,"z":179.36},{"x":82.46,"y":-459.01,"z":180.21},{"x":82.46,"y":-458.41,"z":181.74},{"x":83.84,"y":-457.89,"z":182.41},{"x":85.22,"y":-457.98,"z":181.56},{"x":85.22,"y":-458.58,"z":180.04}]},{"lat":69.77,"lon":155.8,"b":[{"x":157.48,"y":-469.66,"z":67.62},{"x":154.91,"y":-470.25,"z":69.37},{"x":155.12,"y":-469.68,"z":72.68},{"x":157.91,"y":-468.51,"z":74.18},{"x":160.45,"y":-467.93,"z":72.39},{"x":160.23,"y":-468.51,"z":69.13}]},{"lat":69.7,"lon":150.27,"b":[{"x":150.36,"y":-469.75,"z":81.6},{"x":146.84,"y":-470.44,"z":84},{"x":147.07,"y":-469.55,"z":88.46},{"x":150.84,"y":-467.97,"z":90.47},{"x":154.33,"y":-467.3,"z":88.02},{"x":154.08,"y":-468.19,"z":83.61}]},{"lat":69.45,"lon":144.71,"b":[{"x":142.99,"y":-469.14,"z":96.91},{"x":139.38,"y":-469.71,"z":99.36},{"x":139.56,"y":-468.68,"z":103.86},{"x":143.37,"y":-467.08,"z":105.87},{"x":146.96,"y":-466.53,"z":103.37},{"x":146.76,"y":-467.56,"z":98.92}]},{"lat":69.03,"lon":139.21,"b":[{"x":135.31,"y":-467.96,"z":112.41},{"x":131.6,"y":-468.41,"z":114.9},{"x":131.74,"y":-467.23,"z":119.43},{"x":135.6,"y":-465.61,"z":121.42},{"x":139.28,"y":-465.18,"z":118.9},{"x":139.12,"y":-466.35,"z":114.41}]},{"lat":68.42,"lon":133.87,"b":[{"x":127.32,"y":-466.17,"z":128.05},{"x":123.53,"y":-466.49,"z":130.57},{"x":123.63,"y":-465.17,"z":135.11},{"x":127.53,"y":-463.54,"z":137.09},{"x":131.29,"y":-463.24,"z":134.54},{"x":131.18,"y":-464.55,"z":130.04}]},{"lat":67.64,"lon":128.78,"b":[{"x":119.08,"y":-463.33,"z":145.22},{"x":116.46,"y":-463.45,"z":146.94},{"x":116.5,"y":-462.46,"z":150.02},{"x":119.17,"y":-461.34,"z":151.35},{"x":121.77,"y":-461.23,"z":149.61},{"x":121.73,"y":-462.22,"z":146.56}]},{"lat":66.7,"lon":123.99,"b":[{"x":110.57,"y":-459.59,"z":162.88},{"x":109.58,"y":-459.6,"z":163.51},{"x":109.59,"y":-459.19,"z":164.64},{"x":110.58,"y":-458.78,"z":165.13},{"x":111.56,"y":-458.78,"z":164.49},{"x":111.55,"y":-459.18,"z":163.37}]},{"lat":67.54,"lon":142.71,"b":[{"x":151.83,"y":-462.86,"z":112.49},{"x":149.24,"y":-463.26,"z":114.3},{"x":149.35,"y":-462.41,"z":117.54},{"x":152.06,"y":-461.17,"z":118.94},{"x":154.63,"y":-460.78,"z":117.11},{"x":154.51,"y":-461.63,"z":113.91}]},{"lat":67.04,"lon":137.69,"b":[{"x":144.15,"y":-461.09,"z":128.72},{"x":142.06,"y":-461.34,"z":130.16},{"x":142.12,"y":-460.59,"z":132.73},{"x":144.28,"y":-459.59,"z":133.83},{"x":146.36,"y":-459.36,"z":132.37},{"x":146.3,"y":-460.11,"z":129.83}]},{"lat":66.38,"lon":132.83,"b":[{"x":136.17,"y":-458.6,"z":145.32},{"x":134.83,"y":-458.7,"z":146.23},{"x":134.85,"y":-458.18,"z":147.83},{"x":136.21,"y":-457.56,"z":148.51},{"x":137.54,"y":-457.46,"z":147.59},{"x":137.52,"y":-457.98,"z":146}]},{"lat":-19.67,"lon":-154.95,"b":[{"x":426.63,"y":168.75,"z":-198.74},{"x":426.92,"y":168,"z":-198.75},{"x":426.83,"y":167.53,"z":-199.34},{"x":426.45,"y":167.76,"z":-199.95},{"x":426.16,"y":168.47,"z":-199.97},{"x":426.25,"y":168.99,"z":-199.36}]},{"lat":-58.4,"lon":163.46,"b":[{"x":250.22,"y":426.43,"z":74.38},{"x":250.97,"y":426.12,"z":73.62},{"x":251.88,"y":425.55,"z":73.79},{"x":252.04,"y":425.29,"z":74.74},{"x":251.28,"y":425.6,"z":75.52},{"x":250.37,"y":426.17,"z":75.33}]},{"lat":-58.46,"lon":160.12,"b":[{"x":243.75,"y":427.45,"z":88.48},{"x":245.64,"y":426.76,"z":86.6},{"x":247.87,"y":425.37,"z":87.05},{"x":248.23,"y":424.67,"z":89.41},{"x":246.32,"y":425.38,"z":91.32},{"x":244.07,"y":426.77,"z":90.84}]},{"lat":-56.87,"lon":162.1,"b":[{"x":256.67,"y":420.86,"z":83.34},{"x":259.42,"y":419.72,"z":80.51},{"x":262.72,"y":417.53,"z":81.15},{"x":263.32,"y":416.46,"z":84.66},{"x":260.55,"y":417.61,"z":87.54},{"x":257.2,"y":419.81,"z":86.86}]},{"lat":-56.87,"lon":158.83,"b":[{"x":251.34,"y":420.92,"z":97.95},{"x":254.27,"y":419.84,"z":95.01},{"x":257.7,"y":417.57,"z":95.71},{"x":258.25,"y":416.37,"z":99.4},{"x":255.3,"y":417.47,"z":102.4},{"x":251.83,"y":419.75,"z":101.65}]},{"lat":-55.29,"lon":160.8,"b":[{"x":265.46,"y":413.32,"z":92.93},{"x":268.3,"y":412.14,"z":89.97},{"x":271.71,"y":409.75,"z":90.64},{"x":272.31,"y":408.52,"z":94.32},{"x":269.45,"y":409.71,"z":97.34},{"x":266,"y":412.12,"z":96.62}]},{"lat":-55.23,"lon":157.61,"b":[{"x":260.15,"y":413.07,"z":107.85},{"x":263.11,"y":411.97,"z":104.86},{"x":266.55,"y":409.56,"z":105.57},{"x":267.08,"y":408.23,"z":109.33},{"x":264.11,"y":409.34,"z":112.38},{"x":260.63,"y":411.76,"z":111.62}]},{"lat":-53.64,"lon":159.58,"b":[{"x":275.17,"y":404.53,"z":102.9},{"x":277.34,"y":403.63,"z":100.61},{"x":279.93,"y":401.7,"z":101.12},{"x":280.37,"y":400.66,"z":103.96},{"x":278.19,"y":401.58,"z":106.3},{"x":275.57,"y":403.52,"z":105.75}]},{"lat":-53.53,"lon":156.46,"b":[{"x":269.95,"y":403.88,"z":118.14},{"x":272.07,"y":403.09,"z":115.95},{"x":274.54,"y":401.27,"z":116.47},{"x":274.9,"y":400.21,"z":119.2},{"x":272.76,"y":401.01,"z":121.42},{"x":270.28,"y":402.85,"z":120.87}]},{"lat":-51.94,"lon":158.42,"b":[{"x":284.52,"y":395.27,"z":112.96},{"x":286.27,"y":394.55,"z":111.09},{"x":288.34,"y":392.92,"z":111.5},{"x":288.68,"y":392,"z":113.81},{"x":286.92,"y":392.74,"z":115.72},{"x":284.83,"y":394.38,"z":115.28}]},{"lat":-56.74,"lon":139.16,"b":[{"x":205.71,"y":419.13,"z":178.82},{"x":207.4,"y":418.9,"z":177.39},{"x":209.15,"y":417.82,"z":177.89},{"x":209.21,"y":416.96,"z":179.84},{"x":207.49,"y":417.19,"z":181.29},{"x":205.74,"y":418.28,"z":180.77}]},{"lat":-56.09,"lon":135.75,"b":[{"x":196.23,"y":417.1,"z":193.53},{"x":199.75,"y":416.76,"z":190.66},{"x":203.31,"y":414.54,"z":191.72},{"x":203.35,"y":412.65,"z":195.71},{"x":199.78,"y":413.01,"z":198.61},{"x":196.22,"y":415.24,"z":197.49}]},{"lat":-54.88,"lon":138.53,"b":[{"x":215.02,"y":409.3,"z":190.33},{"x":215.55,"y":409.23,"z":189.88},{"x":216.1,"y":408.87,"z":190.03},{"x":216.11,"y":408.58,"z":190.64},{"x":215.57,"y":408.65,"z":191.1},{"x":215.03,"y":409.02,"z":190.94}]},{"lat":-53.58,"lon":141.19,"b":[{"x":230.57,"y":402.83,"z":185.86},{"x":231.25,"y":402.72,"z":185.26},{"x":231.95,"y":402.23,"z":185.45},{"x":231.98,"y":401.85,"z":186.24},{"x":231.29,"y":401.96,"z":186.84},{"x":230.59,"y":402.46,"z":186.65}]},{"lat":-52.22,"lon":143.7,"b":[{"x":245.45,"y":396.19,"z":180.97},{"x":246.79,"y":395.92,"z":179.76},{"x":248.18,"y":394.88,"z":180.11},{"x":248.25,"y":394.11,"z":181.69},{"x":246.91,"y":394.39,"z":182.92},{"x":245.5,"y":395.44,"z":182.55}]},{"lat":-55.35,"lon":132.43,"b":[{"x":188.24,"y":413.46,"z":208.68},{"x":191.83,"y":413.23,"z":205.86},{"x":195.38,"y":410.99,"z":206.98},{"x":195.35,"y":408.98,"z":210.97},{"x":191.72,"y":409.22,"z":213.81},{"x":188.17,"y":411.47,"z":212.65}]},{"lat":-54.2,"lon":135.25,"b":[{"x":204.79,"y":407.4,"z":205.02},{"x":207.71,"y":407.11,"z":202.63},{"x":210.65,"y":405.16,"z":203.5},{"x":210.66,"y":403.48,"z":206.8},{"x":207.69,"y":403.78,"z":209.21},{"x":204.76,"y":405.74,"z":208.29}]},{"lat":-52.97,"lon":137.95,"b":[{"x":220.61,"y":401.18,"z":200.81},{"x":223.58,"y":400.78,"z":198.31},{"x":226.58,"y":398.67,"z":199.15},{"x":226.62,"y":396.94,"z":202.53},{"x":223.62,"y":397.34,"z":205.06},{"x":220.61,"y":399.47,"z":204.18}]},{"lat":-51.66,"lon":140.53,"b":[{"x":236.22,"y":394.47,"z":196.28},{"x":239.33,"y":393.95,"z":193.55},{"x":242.52,"y":391.57,"z":194.39},{"x":242.6,"y":389.71,"z":198},{"x":239.46,"y":390.25,"z":200.75},{"x":236.26,"y":392.63,"z":199.87}]},{"lat":-50.29,"lon":142.98,"b":[{"x":252,"y":386.97,"z":191.53},{"x":254.94,"y":386.36,"z":188.86},{"x":257.97,"y":383.97,"z":189.61},{"x":258.08,"y":382.16,"z":193.08},{"x":255.12,"y":382.77,"z":195.78},{"x":252.08,"y":385.19,"z":194.99}]},{"lat":-54.51,"lon":129.21,"b":[{"x":179.96,"y":409.28,"z":223.69},{"x":183.61,"y":409.16,"z":220.93},{"x":187.15,"y":406.91,"z":222.1},{"x":187.05,"y":404.76,"z":226.08},{"x":183.35,"y":404.89,"z":228.86},{"x":179.82,"y":407.15,"z":227.64}]},{"lat":-53.42,"lon":132.05,"b":[{"x":195.98,"y":403.84,"z":220.08},{"x":199.62,"y":403.6,"z":217.23},{"x":203.19,"y":401.21,"z":218.34},{"x":203.12,"y":399.04,"z":222.35},{"x":199.44,"y":399.29,"z":225.22},{"x":195.87,"y":401.69,"z":224.06}]},{"lat":-52.26,"lon":134.78,"b":[{"x":212.02,"y":397.82,"z":216.14},{"x":215.63,"y":397.46,"z":213.21},{"x":219.21,"y":394.93,"z":214.26},{"x":219.18,"y":392.74,"z":218.28},{"x":215.52,"y":393.1,"z":221.24},{"x":211.95,"y":395.65,"z":220.15}]},{"lat":-51.01,"lon":137.41,"b":[{"x":228,"y":391.22,"z":211.88},{"x":231.58,"y":390.74,"z":208.86},{"x":235.15,"y":388.06,"z":209.85},{"x":235.16,"y":385.85,"z":213.89},{"x":231.55,"y":386.33,"z":216.93},{"x":227.97,"y":389.03,"z":215.9}]},{"lat":-49.69,"lon":139.92,"b":[{"x":244.26,"y":383.74,"z":207.39},{"x":247.4,"y":383.21,"z":204.63},{"x":250.58,"y":380.7,"z":205.46},{"x":250.61,"y":378.7,"z":209.07},{"x":247.44,"y":379.24,"z":211.86},{"x":244.26,"y":381.77,"z":211}]},{"lat":-48.32,"lon":142.31,"b":[{"x":261.69,"y":374.57,"z":202.93},{"x":263.08,"y":374.29,"z":201.66},{"x":264.49,"y":373.1,"z":202},{"x":264.52,"y":372.19,"z":203.63},{"x":263.12,"y":372.48,"z":204.92},{"x":261.7,"y":373.67,"z":204.56}]},{"lat":-53.59,"lon":126.11,"b":[{"x":171.42,"y":404.56,"z":238.5},{"x":175.11,"y":404.55,"z":235.81},{"x":178.64,"y":402.28,"z":237.03},{"x":178.46,"y":400.01,"z":240.98},{"x":174.72,"y":400.03,"z":243.68},{"x":171.21,"y":402.31,"z":242.41}]},{"lat":-52.56,"lon":128.95,"b":[{"x":187.52,"y":399.33,"z":235.16},{"x":191.21,"y":399.21,"z":232.38},{"x":194.77,"y":396.8,"z":233.54},{"x":194.62,"y":394.5,"z":237.52},{"x":190.88,"y":394.64,"z":240.32},{"x":187.34,"y":397.06,"z":239.11}]},{"lat":-51.46,"lon":131.7,"b":[{"x":203.67,"y":393.53,"z":231.48},{"x":207.35,"y":393.28,"z":228.61},{"x":210.92,"y":390.73,"z":229.7},{"x":210.81,"y":388.41,"z":233.71},{"x":207.09,"y":388.67,"z":236.6},{"x":203.52,"y":391.23,"z":235.46}]},{"lat":-50.27,"lon":134.35,"b":[{"x":219.81,"y":387.14,"z":227.45},{"x":223.46,"y":386.78,"z":224.49},{"x":227.03,"y":384.08,"z":225.52},{"x":226.95,"y":381.74,"z":229.54},{"x":223.26,"y":382.11,"z":232.52},{"x":219.69,"y":384.82,"z":231.46}]},{"lat":-49.01,"lon":136.9,"b":[{"x":235.86,"y":380.17,"z":223.08},{"x":239.47,"y":379.69,"z":220.03},{"x":243.03,"y":376.86,"z":220.99},{"x":242.98,"y":374.49,"z":225.03},{"x":239.34,"y":374.98,"z":228.1},{"x":235.78,"y":377.83,"z":227.1}]},{"lat":-47.69,"lon":139.34,"b":[{"x":252.79,"y":371.81,"z":218.63},{"x":255.32,"y":371.38,"z":216.4},{"x":257.84,"y":369.26,"z":217.04},{"x":257.83,"y":367.56,"z":219.93},{"x":255.27,"y":367.99,"z":222.17},{"x":252.75,"y":370.12,"z":221.51}]},{"lat":-46.31,"lon":141.68,"b":[{"x":270,"y":362.35,"z":213.95},{"x":270.96,"y":362.15,"z":213.07},{"x":271.93,"y":361.3,"z":213.29},{"x":271.93,"y":360.63,"z":214.41},{"x":270.96,"y":360.83,"z":215.3},{"x":270,"y":361.69,"z":215.07}]},{"lat":-43.39,"lon":146.02,"b":[{"x":300.68,"y":344.09,"z":202.91},{"x":301.27,"y":343.93,"z":202.32},{"x":301.87,"y":343.33,"z":202.44},{"x":301.88,"y":342.89,"z":203.16},{"x":301.29,"y":343.05,"z":203.76},{"x":300.69,"y":343.66,"z":203.64}]},{"lat":-52.58,"lon":123.15,"b":[{"x":162.63,"y":399.32,"z":253.04},{"x":166.36,"y":399.42,"z":250.44},{"x":169.87,"y":397.14,"z":251.7},{"x":169.63,"y":394.74,"z":255.61},{"x":165.85,"y":394.65,"z":258.22},{"x":162.36,"y":396.95,"z":256.91}]},{"lat":-51.62,"lon":125.96,"b":[{"x":178.78,"y":394.3,"z":250},{"x":182.52,"y":394.28,"z":247.3},{"x":186.06,"y":391.86,"z":248.5},{"x":185.85,"y":389.44,"z":252.45},{"x":182.06,"y":389.46,"z":255.15},{"x":178.53,"y":391.9,"z":253.91}]},{"lat":-50.57,"lon":128.71,"b":[{"x":195.01,"y":388.7,"z":246.59},{"x":198.75,"y":388.57,"z":243.8},{"x":202.31,"y":386,"z":244.94},{"x":202.12,"y":383.56,"z":248.91},{"x":198.34,"y":383.7,"z":251.72},{"x":194.79,"y":386.28,"z":250.54}]},{"lat":-49.45,"lon":131.37,"b":[{"x":211.26,"y":382.53,"z":242.83},{"x":214.99,"y":382.28,"z":239.94},{"x":218.56,"y":379.57,"z":241.01},{"x":218.39,"y":377.1,"z":245},{"x":214.63,"y":377.36,"z":247.91},{"x":211.07,"y":380.08,"z":246.8}]},{"lat":-48.25,"lon":133.94,"b":[{"x":227.47,"y":375.78,"z":238.69},{"x":231.16,"y":375.4,"z":235.71},{"x":234.72,"y":372.56,"z":236.71},{"x":234.58,"y":370.06,"z":240.72},{"x":230.86,"y":370.44,"z":243.72},{"x":227.3,"y":373.31,"z":242.69}]},{"lat":-46.98,"lon":136.42,"b":[{"x":243.56,"y":368.45,"z":234.19},{"x":247.2,"y":367.96,"z":231.13},{"x":250.74,"y":364.97,"z":232.05},{"x":250.63,"y":362.46,"z":236.07},{"x":246.96,"y":362.95,"z":239.16},{"x":243.42,"y":365.96,"z":238.21}]},{"lat":-42.83,"lon":143.26,"b":[{"x":290.47,"y":343.15,"z":218.63},{"x":293.84,"y":342.34,"z":215.37},{"x":297.17,"y":339.01,"z":216.07},{"x":297.14,"y":336.47,"z":220.05},{"x":293.75,"y":337.27,"z":223.34},{"x":290.41,"y":340.62,"z":222.62}]},{"lat":-51.51,"lon":120.32,"b":[{"x":153.64,"y":393.57,"z":267.26},{"x":157.4,"y":393.78,"z":264.76},{"x":160.88,"y":391.48,"z":266.06},{"x":160.58,"y":388.96,"z":269.92},{"x":156.77,"y":388.77,"z":272.42},{"x":153.32,"y":391.08,"z":271.07}]},{"lat":-50.6,"lon":123.1,"b":[{"x":169.8,"y":388.75,"z":264.53},{"x":173.58,"y":388.84,"z":261.92},{"x":177.1,"y":386.4,"z":263.17},{"x":176.81,"y":383.85,"z":267.06},{"x":172.98,"y":383.77,"z":269.67},{"x":169.49,"y":386.23,"z":268.38}]},{"lat":-49.62,"lon":125.82,"b":[{"x":186.07,"y":383.36,"z":261.43},{"x":189.86,"y":383.33,"z":258.72},{"x":193.41,"y":380.75,"z":259.9},{"x":193.14,"y":378.18,"z":263.82},{"x":189.31,"y":378.22,"z":266.53},{"x":185.78,"y":380.81,"z":265.32}]},{"lat":-48.55,"lon":128.48,"b":[{"x":202.4,"y":377.39,"z":257.94},{"x":206.19,"y":377.25,"z":255.14},{"x":209.74,"y":374.53,"z":256.24},{"x":209.5,"y":371.93,"z":260.19},{"x":205.68,"y":372.09,"z":263.01},{"x":202.14,"y":374.82,"z":261.87}]},{"lat":-47.4,"lon":131.06,"b":[{"x":218.73,"y":370.85,"z":254.07},{"x":222.49,"y":370.59,"z":251.17},{"x":226.04,"y":367.73,"z":252.2},{"x":225.82,"y":365.11,"z":256.17},{"x":222.02,"y":365.38,"z":259.09},{"x":218.48,"y":368.26,"z":258.02}]},{"lat":-46.19,"lon":133.56,"b":[{"x":234.97,"y":363.73,"z":249.82},{"x":238.69,"y":363.36,"z":246.82},{"x":242.23,"y":360.35,"z":247.78},{"x":242.03,"y":357.72,"z":251.76},{"x":238.27,"y":358.1,"z":254.77},{"x":234.75,"y":361.12,"z":253.79}]},{"lat":-44.91,"lon":135.97,"b":[{"x":251.12,"y":356,"z":245.2},{"x":254.73,"y":355.52,"z":242.16},{"x":258.17,"y":352.43,"z":243.03},{"x":257.99,"y":349.82,"z":246.95},{"x":254.36,"y":350.31,"z":250.01},{"x":250.93,"y":353.41,"z":249.12}]},{"lat":-42.19,"lon":140.51,"b":[{"x":284.13,"y":337.51,"z":235.17},{"x":285.98,"y":337.14,"z":233.46},{"x":287.76,"y":335.35,"z":233.84},{"x":287.69,"y":333.94,"z":235.95},{"x":285.83,"y":334.31,"z":237.67},{"x":284.04,"y":336.11,"z":237.28}]},{"lat":-50.37,"lon":117.63,"b":[{"x":144.48,"y":387.35,"z":281.11},{"x":148.26,"y":387.65,"z":278.71},{"x":151.71,"y":385.33,"z":280.06},{"x":151.35,"y":382.7,"z":283.84},{"x":147.52,"y":382.41,"z":286.23},{"x":144.1,"y":384.74,"z":284.85}]},{"lat":-49.52,"lon":120.37,"b":[{"x":160.61,"y":382.7,"z":278.7},{"x":164.42,"y":382.89,"z":276.2},{"x":167.91,"y":380.44,"z":277.49},{"x":167.56,"y":377.78,"z":281.31},{"x":163.7,"y":377.6,"z":283.81},{"x":160.24,"y":380.07,"z":282.49}]},{"lat":-48.59,"lon":123.06,"b":[{"x":176.89,"y":377.51,"z":275.92},{"x":180.72,"y":377.58,"z":273.31},{"x":184.24,"y":374.99,"z":274.52},{"x":183.91,"y":372.3,"z":278.38},{"x":180.03,"y":372.23,"z":280.99},{"x":176.54,"y":374.84,"z":279.74}]},{"lat":-47.58,"lon":125.69,"b":[{"x":193.26,"y":371.74,"z":272.73},{"x":197.1,"y":371.71,"z":270.02},{"x":200.64,"y":368.97,"z":271.16},{"x":200.32,"y":366.26,"z":275.05},{"x":196.44,"y":366.3,"z":277.77},{"x":192.93,"y":369.05,"z":276.59}]},{"lat":-46.49,"lon":128.27,"b":[{"x":209.66,"y":365.41,"z":269.15},{"x":213.49,"y":365.26,"z":266.34},{"x":217.03,"y":362.38,"z":267.4},{"x":216.72,"y":359.64,"z":271.31},{"x":212.86,"y":359.81,"z":274.14},{"x":209.34,"y":362.7,"z":273.04}]},{"lat":-45.33,"lon":130.77,"b":[{"x":226.02,"y":358.5,"z":265.16},{"x":229.82,"y":358.23,"z":262.25},{"x":233.34,"y":355.22,"z":263.23},{"x":233.06,"y":352.46,"z":267.16},{"x":229.23,"y":352.74,"z":270.09},{"x":225.72,"y":355.77,"z":269.08}]},{"lat":-44.1,"lon":133.2,"b":[{"x":242.27,"y":351.04,"z":260.77},{"x":246.02,"y":350.65,"z":257.76},{"x":249.51,"y":347.5,"z":258.66},{"x":249.24,"y":344.72,"z":262.61},{"x":245.46,"y":345.12,"z":265.63},{"x":241.98,"y":348.28,"z":264.7}]},{"lat":-42.82,"lon":135.55,"b":[{"x":261.12,"y":340.45,"z":256.69},{"x":261.85,"y":340.35,"z":256.08},{"x":262.53,"y":339.7,"z":256.24},{"x":262.48,"y":339.15,"z":257.02},{"x":261.75,"y":339.25,"z":257.63},{"x":261.07,"y":339.9,"z":257.47}]},{"lat":-40.09,"lon":139.98,"b":[{"x":291.75,"y":323.22,"z":245.72},{"x":293.01,"y":322.96,"z":244.55},{"x":294.19,"y":321.71,"z":244.79},{"x":294.11,"y":320.7,"z":246.2},{"x":292.85,"y":320.95,"z":247.37},{"x":291.67,"y":322.21,"z":247.13}]},{"lat":-38.66,"lon":142.07,"b":[{"x":306.44,"y":313.99,"z":239.71},{"x":308,"y":313.62,"z":238.19},{"x":309.47,"y":311.97,"z":238.45},{"x":309.37,"y":310.69,"z":240.25},{"x":307.81,"y":311.05,"z":241.78},{"x":306.34,"y":312.71,"z":241.51}]},{"lat":-49.19,"lon":115.09,"b":[{"x":135.18,"y":380.67,"z":294.54},{"x":138.97,"y":381.06,"z":292.25},{"x":142.38,"y":378.73,"z":293.64},{"x":141.97,"y":375.99,"z":297.34},{"x":138.14,"y":375.61,"z":299.61},{"x":134.76,"y":377.96,"z":298.19}]},{"lat":-48.38,"lon":117.76,"b":[{"x":151.25,"y":376.19,"z":292.46},{"x":155.08,"y":376.48,"z":290.07},{"x":158.54,"y":374.01,"z":291.39},{"x":158.13,"y":371.24,"z":295.14},{"x":154.26,"y":370.97,"z":297.52},{"x":150.83,"y":373.45,"z":296.16}]},{"lat":-47.5,"lon":120.41,"b":[{"x":167.5,"y":371.17,"z":290},{"x":171.35,"y":371.35,"z":287.51},{"x":174.85,"y":368.74,"z":288.76},{"x":174.45,"y":365.94,"z":292.54},{"x":170.55,"y":365.78,"z":295.03},{"x":167.09,"y":368.4,"z":293.75}]},{"lat":-46.54,"lon":123.01,"b":[{"x":183.87,"y":365.6,"z":287.14},{"x":187.75,"y":365.67,"z":284.54},{"x":191.26,"y":362.92,"z":285.71},{"x":190.87,"y":360.09,"z":289.52},{"x":186.96,"y":360.04,"z":292.12},{"x":183.48,"y":362.8,"z":290.92}]},{"lat":-45.51,"lon":125.57,"b":[{"x":200.31,"y":359.47,"z":283.86},{"x":204.19,"y":359.42,"z":281.15},{"x":207.71,"y":356.53,"z":282.25},{"x":207.33,"y":353.68,"z":286.08},{"x":203.42,"y":353.75,"z":288.8},{"x":199.93,"y":356.64,"z":287.68}]},{"lat":-44.4,"lon":128.07,"b":[{"x":216.75,"y":352.77,"z":280.17},{"x":220.61,"y":352.61,"z":277.34},{"x":224.12,"y":349.58,"z":278.36},{"x":223.75,"y":346.71,"z":282.22},{"x":219.86,"y":346.89,"z":285.04},{"x":216.37,"y":349.92,"z":284.01}]},{"lat":-43.23,"lon":130.5,"b":[{"x":233.11,"y":345.52,"z":276.04},{"x":236.94,"y":345.24,"z":273.12},{"x":240.42,"y":342.08,"z":274.05},{"x":240.06,"y":339.19,"z":277.92},{"x":236.21,"y":339.47,"z":280.86},{"x":232.74,"y":342.64,"z":279.9}]},{"lat":-41.99,"lon":132.86,"b":[{"x":252.17,"y":335.07,"z":272.24},{"x":252.85,"y":335,"z":271.7},{"x":253.47,"y":334.41,"z":271.85},{"x":253.41,"y":333.89,"z":272.55},{"x":252.72,"y":333.96,"z":273.09},{"x":252.11,"y":334.56,"z":272.94}]},{"lat":-37.97,"lon":139.48,"b":[{"x":298.26,"y":309.12,"z":255.83},{"x":299.71,"y":308.83,"z":254.48},{"x":301.03,"y":307.34,"z":254.72},{"x":300.9,"y":306.13,"z":256.32},{"x":299.45,"y":306.42,"z":257.67},{"x":298.13,"y":307.92,"z":257.43}]},{"lat":-36.56,"lon":141.52,"b":[{"x":313.75,"y":298.56,"z":249.8},{"x":314.45,"y":298.4,"z":249.11},{"x":315.1,"y":297.63,"z":249.21},{"x":315.03,"y":297.03,"z":250.01},{"x":314.33,"y":297.19,"z":250.71},{"x":313.68,"y":297.96,"z":250.6}]},{"lat":-47.95,"lon":112.68,"b":[{"x":125.79,"y":373.57,"z":307.5},{"x":129.57,"y":374.05,"z":305.34},{"x":132.94,"y":371.7,"z":306.76},{"x":132.49,"y":368.86,"z":310.36},{"x":128.66,"y":368.4,"z":312.5},{"x":125.33,"y":370.77,"z":311.06}]},{"lat":-47.2,"lon":115.29,"b":[{"x":141.76,"y":369.25,"z":305.77},{"x":145.59,"y":369.62,"z":303.5},{"x":149.01,"y":367.14,"z":304.85},{"x":148.56,"y":364.27,"z":308.5},{"x":144.68,"y":363.91,"z":310.75},{"x":141.3,"y":366.41,"z":309.37}]},{"lat":-46.36,"lon":117.88,"b":[{"x":157.94,"y":364.4,"z":303.64},{"x":161.81,"y":364.67,"z":301.27},{"x":165.27,"y":362.05,"z":302.55},{"x":164.82,"y":359.14,"z":306.23},{"x":160.9,"y":358.89,"z":308.6},{"x":157.48,"y":361.52,"z":307.29}]},{"lat":-45.45,"lon":120.45,"b":[{"x":174.28,"y":359.01,"z":301.11},{"x":178.18,"y":359.17,"z":298.62},{"x":181.67,"y":356.41,"z":299.82},{"x":181.22,"y":353.48,"z":303.55},{"x":177.28,"y":353.33,"z":306.03},{"x":173.83,"y":356.1,"z":304.8}]},{"lat":-44.47,"lon":122.98,"b":[{"x":190.72,"y":353.06,"z":298.15},{"x":194.63,"y":353.12,"z":295.55},{"x":198.13,"y":350.22,"z":296.67},{"x":197.68,"y":347.26,"z":300.43},{"x":193.74,"y":347.23,"z":303.02},{"x":190.27,"y":350.13,"z":301.88}]},{"lat":-43.41,"lon":125.46,"b":[{"x":207.19,"y":346.57,"z":294.76},{"x":211.1,"y":346.5,"z":292.05},{"x":214.59,"y":343.47,"z":293.09},{"x":214.15,"y":340.49,"z":296.86},{"x":210.21,"y":340.57,"z":299.58},{"x":206.75,"y":343.61,"z":298.51}]},{"lat":-42.29,"lon":127.88,"b":[{"x":223.63,"y":339.52,"z":290.93},{"x":227.52,"y":339.34,"z":288.11},{"x":230.99,"y":336.17,"z":289.06},{"x":230.55,"y":333.17,"z":292.85},{"x":226.64,"y":333.36,"z":295.68},{"x":223.18,"y":336.54,"z":294.71}]},{"lat":-41.1,"lon":130.24,"b":[{"x":242.39,"y":329.65,"z":287.31},{"x":243.53,"y":329.56,"z":286.45},{"x":244.54,"y":328.59,"z":286.7},{"x":244.41,"y":327.7,"z":287.83},{"x":243.27,"y":327.79,"z":288.69},{"x":242.26,"y":328.76,"z":288.43}]},{"lat":-37.23,"lon":136.92,"b":[{"x":290.36,"y":302.95,"z":271.83},{"x":290.85,"y":302.87,"z":271.4},{"x":291.28,"y":302.39,"z":271.48},{"x":291.23,"y":301.98,"z":271.99},{"x":290.74,"y":302.06,"z":272.43},{"x":290.31,"y":302.55,"z":272.34}]},{"lat":-35.85,"lon":139,"b":[{"x":302.67,"y":296.5,"z":265.33},{"x":306.21,"y":295.8,"z":262.03},{"x":309.33,"y":292.07,"z":262.54},{"x":308.93,"y":289.03,"z":266.35},{"x":305.39,"y":289.72,"z":269.66},{"x":302.25,"y":293.46,"z":269.15}]},{"lat":-46.69,"lon":110.41,"b":[{"x":116.34,"y":366.09,"z":319.97},{"x":120.11,"y":366.64,"z":317.93},{"x":123.43,"y":364.28,"z":319.37},{"x":122.94,"y":361.35,"z":322.87},{"x":119.12,"y":360.82,"z":324.88},{"x":115.85,"y":363.2,"z":323.42}]},{"lat":-45.97,"lon":112.95,"b":[{"x":132.17,"y":361.9,"z":318.57},{"x":136,"y":362.36,"z":316.43},{"x":139.38,"y":359.86,"z":317.81},{"x":138.88,"y":356.9,"z":321.35},{"x":135.01,"y":356.46,"z":323.47},{"x":131.68,"y":358.97,"z":322.07}]},{"lat":-45.18,"lon":115.48,"b":[{"x":148.25,"y":357.2,"z":316.79},{"x":152.13,"y":357.56,"z":314.54},{"x":155.55,"y":354.93,"z":315.84},{"x":155.05,"y":351.93,"z":319.43},{"x":151.13,"y":351.6,"z":321.66},{"x":147.75,"y":354.24,"z":320.33}]},{"lat":-44.31,"lon":118,"b":[{"x":164.52,"y":351.98,"z":314.59},{"x":168.44,"y":352.23,"z":312.23},{"x":171.89,"y":349.46,"z":313.46},{"x":171.38,"y":346.44,"z":317.07},{"x":167.43,"y":346.21,"z":319.43},{"x":164.02,"y":348.98,"z":318.18}]},{"lat":-43.38,"lon":120.49,"b":[{"x":180.92,"y":346.22,"z":311.97},{"x":184.86,"y":346.36,"z":309.49},{"x":188.33,"y":343.46,"z":310.63},{"x":187.82,"y":340.4,"z":314.28},{"x":183.85,"y":340.28,"z":316.75},{"x":180.42,"y":343.19,"z":315.59}]},{"lat":-42.37,"lon":122.94,"b":[{"x":197.39,"y":339.91,"z":308.9},{"x":201.34,"y":339.95,"z":306.3},{"x":204.81,"y":336.9,"z":307.36},{"x":204.3,"y":333.83,"z":311.04},{"x":200.32,"y":333.81,"z":313.63},{"x":196.88,"y":336.86,"z":312.55}]},{"lat":-41.29,"lon":125.35,"b":[{"x":213.86,"y":333.06,"z":305.38},{"x":217.8,"y":332.98,"z":302.66},{"x":221.25,"y":329.81,"z":303.64},{"x":220.74,"y":326.71,"z":307.33},{"x":216.78,"y":326.81,"z":310.04},{"x":213.35,"y":329.98,"z":309.05}]},{"lat":-40.16,"lon":127.7,"b":[{"x":230.57,"y":325.38,"z":301.48},{"x":234.13,"y":325.21,"z":298.91},{"x":237.25,"y":322.2,"z":299.71},{"x":236.78,"y":319.37,"z":303.09},{"x":233.2,"y":319.55,"z":305.66},{"x":230.1,"y":322.56,"z":304.85}]},{"lat":-35.09,"lon":136.51,"b":[{"x":293.82,"y":290.89,"z":281.02},{"x":297.27,"y":290.31,"z":277.97},{"x":300.24,"y":286.78,"z":278.45},{"x":299.76,"y":283.81,"z":281.99},{"x":296.31,"y":284.38,"z":285.05},{"x":293.34,"y":287.92,"z":284.56}]},{"lat":-33.72,"lon":138.54,"b":[{"x":311.36,"y":277.96,"z":275.28},{"x":311.74,"y":277.89,"z":274.92},{"x":312.07,"y":277.48,"z":274.97},{"x":312.01,"y":277.14,"z":275.37},{"x":311.63,"y":277.21,"z":275.73},{"x":311.31,"y":277.63,"z":275.68}]},{"lat":-45.39,"lon":108.27,"b":[{"x":106.86,"y":358.27,"z":331.9},{"x":110.61,"y":358.89,"z":330},{"x":113.88,"y":356.51,"z":331.46},{"x":113.36,"y":353.5,"z":334.85},{"x":109.57,"y":352.91,"z":336.72},{"x":106.35,"y":355.3,"z":335.24}]},{"lat":-44.71,"lon":110.74,"b":[{"x":122.54,"y":354.2,"z":330.85},{"x":126.35,"y":354.73,"z":328.84},{"x":129.68,"y":352.22,"z":330.24},{"x":129.15,"y":349.17,"z":333.66},{"x":125.29,"y":348.67,"z":335.65},{"x":122.01,"y":351.19,"z":334.23}]},{"lat":-43.96,"lon":113.21,"b":[{"x":138.48,"y":349.64,"z":329.4},{"x":142.35,"y":350.07,"z":327.28},{"x":145.73,"y":347.43,"z":328.61},{"x":145.18,"y":344.35,"z":332.08},{"x":141.27,"y":343.94,"z":334.18},{"x":137.94,"y":346.59,"z":332.83}]},{"lat":-43.14,"lon":115.67,"b":[{"x":154.64,"y":344.57,"z":327.55},{"x":158.56,"y":344.9,"z":325.31},{"x":161.97,"y":342.12,"z":326.56},{"x":161.42,"y":339.01,"z":330.07},{"x":157.46,"y":338.7,"z":332.28},{"x":154.1,"y":341.48,"z":331.02}]},{"lat":-42.24,"lon":118.11,"b":[{"x":170.96,"y":338.97,"z":325.26},{"x":174.92,"y":339.2,"z":322.91},{"x":178.35,"y":336.29,"z":324.08},{"x":177.79,"y":333.15,"z":327.61},{"x":173.8,"y":332.94,"z":329.95},{"x":170.41,"y":335.86,"z":328.76}]},{"lat":-41.28,"lon":120.52,"b":[{"x":187.39,"y":332.85,"z":322.52},{"x":191.36,"y":332.97,"z":320.05},{"x":194.8,"y":329.92,"z":321.13},{"x":194.23,"y":326.75,"z":324.7},{"x":190.23,"y":326.66,"z":327.15},{"x":186.83,"y":329.7,"z":326.06}]},{"lat":-40.25,"lon":122.9,"b":[{"x":204.38,"y":325.72,"z":319.48},{"x":207.75,"y":325.73,"z":317.29},{"x":210.66,"y":323.03,"z":318.12},{"x":210.17,"y":320.33,"z":321.17},{"x":206.77,"y":320.34,"z":323.36},{"x":203.89,"y":323.03,"z":322.51}]},{"lat":-39.16,"lon":125.24,"b":[{"x":222.02,"y":317.36,"z":316.14},{"x":223.97,"y":317.31,"z":314.81},{"x":225.65,"y":315.69,"z":315.25},{"x":225.36,"y":314.11,"z":317.02},{"x":223.4,"y":314.17,"z":318.35},{"x":221.74,"y":315.79,"z":317.9}]},{"lat":-38.02,"lon":127.54,"b":[{"x":236.64,"y":311.26,"z":311.51},{"x":240.54,"y":311.06,"z":308.71},{"x":243.87,"y":307.66,"z":309.5},{"x":243.28,"y":304.47,"z":313.1},{"x":239.37,"y":304.69,"z":315.89},{"x":236.06,"y":308.08,"z":315.09}]},{"lat":-36.81,"lon":129.77,"b":[{"x":255.29,"y":300.44,"z":307.47},{"x":256.23,"y":300.37,"z":306.76},{"x":257.02,"y":299.51,"z":306.93},{"x":256.88,"y":298.74,"z":307.81},{"x":255.94,"y":298.81,"z":308.51},{"x":255.15,"y":299.67,"z":308.34}]},{"lat":-34.27,"lon":134.07,"b":[{"x":284.97,"y":284.36,"z":296.42},{"x":287.81,"y":283.97,"z":294.03},{"x":290.2,"y":281.13,"z":294.42},{"x":289.74,"y":278.68,"z":297.19},{"x":286.9,"y":279.07,"z":299.57},{"x":284.52,"y":281.91,"z":299.18}]},{"lat":-32.95,"lon":136.13,"b":[{"x":301.95,"y":272.56,"z":290.72},{"x":302.57,"y":272.46,"z":290.18},{"x":303.08,"y":271.81,"z":290.25},{"x":302.98,"y":271.26,"z":290.86},{"x":302.36,"y":271.36,"z":291.41},{"x":301.85,"y":272.01,"z":291.34}]},{"lat":-44.08,"lon":106.26,"b":[{"x":97.4,"y":350.15,"z":343.28},{"x":101.11,"y":350.83,"z":341.51},{"x":104.33,"y":348.43,"z":342.99},{"x":103.79,"y":345.36,"z":346.26},{"x":100.03,"y":344.71,"z":348},{"x":96.87,"y":347.12,"z":346.51}]},{"lat":-43.43,"lon":108.65,"b":[{"x":112.89,"y":346.18,"z":342.56},{"x":116.67,"y":346.77,"z":340.69},{"x":119.95,"y":344.25,"z":342.1},{"x":119.39,"y":341.13,"z":345.41},{"x":115.56,"y":340.58,"z":347.25},{"x":112.34,"y":343.1,"z":345.83}]},{"lat":-42.71,"lon":111.05,"b":[{"x":128.66,"y":341.74,"z":341.46},{"x":132.51,"y":342.24,"z":339.47},{"x":135.84,"y":339.59,"z":340.82},{"x":135.26,"y":336.43,"z":344.16},{"x":131.37,"y":335.97,"z":346.12},{"x":128.1,"y":338.62,"z":344.76}]},{"lat":-41.93,"lon":113.45,"b":[{"x":144.68,"y":336.81,"z":339.94},{"x":148.59,"y":337.21,"z":337.84},{"x":151.96,"y":334.43,"z":339.11},{"x":151.36,"y":331.24,"z":342.49},{"x":147.42,"y":330.86,"z":344.56},{"x":144.1,"y":333.65,"z":343.28}]},{"lat":-41.08,"lon":115.84,"b":[{"x":160.89,"y":331.36,"z":337.99},{"x":164.85,"y":331.67,"z":335.78},{"x":168.24,"y":328.76,"z":336.96},{"x":167.63,"y":325.53,"z":340.37},{"x":163.64,"y":325.26,"z":342.57},{"x":160.3,"y":328.17,"z":341.37}]},{"lat":-40.16,"lon":118.21,"b":[{"x":177.24,"y":325.41,"z":335.59},{"x":181.22,"y":325.61,"z":333.26},{"x":184.62,"y":322.56,"z":334.35},{"x":184,"y":319.32,"z":337.79},{"x":179.99,"y":319.14,"z":340.11},{"x":176.63,"y":322.19,"z":339}]},{"lat":-35.87,"lon":127.38,"b":[{"x":243.22,"y":295.83,"z":321.34},{"x":246.49,"y":295.65,"z":319},{"x":249.22,"y":292.71,"z":319.59},{"x":248.66,"y":289.96,"z":322.52},{"x":245.38,"y":290.16,"z":324.84},{"x":242.67,"y":293.09,"z":324.25}]},{"lat":-34.66,"lon":129.56,"b":[{"x":261.25,"y":285.1,"z":316.94},{"x":262.05,"y":285.03,"z":316.34},{"x":262.71,"y":284.28,"z":316.46},{"x":262.57,"y":283.6,"z":317.19},{"x":261.77,"y":283.67,"z":317.79},{"x":261.11,"y":284.42,"z":317.66}]},{"lat":-33.41,"lon":131.68,"b":[{"x":275.56,"y":277.63,"z":311.34},{"x":277.95,"y":277.36,"z":309.44},{"x":279.91,"y":275.03,"z":309.76},{"x":279.48,"y":272.96,"z":311.97},{"x":277.09,"y":273.23,"z":313.86},{"x":275.14,"y":275.56,"z":313.54}]},{"lat":-42.76,"lon":104.37,"b":[{"x":87.99,"y":341.78,"z":354.1},{"x":91.66,"y":342.5,"z":352.46},{"x":94.82,"y":340.1,"z":353.95},{"x":94.26,"y":336.96,"z":357.09},{"x":90.55,"y":336.27,"z":358.69},{"x":87.44,"y":338.68,"z":357.19}]},{"lat":-42.13,"lon":106.68,"b":[{"x":103.26,"y":337.89,"z":353.7},{"x":107.01,"y":338.54,"z":351.96},{"x":110.23,"y":336.01,"z":353.39},{"x":109.65,"y":332.83,"z":356.56},{"x":105.86,"y":332.22,"z":358.27},{"x":102.69,"y":334.76,"z":356.84}]},{"lat":-41.45,"lon":109.01,"b":[{"x":118.83,"y":333.55,"z":352.92},{"x":122.66,"y":334.11,"z":351.07},{"x":125.94,"y":331.46,"z":352.43},{"x":125.33,"y":328.24,"z":355.64},{"x":121.47,"y":327.71,"z":357.46},{"x":118.25,"y":330.37,"z":356.1}]},{"lat":-40.7,"lon":111.34,"b":[{"x":134.68,"y":328.74,"z":351.74},{"x":138.57,"y":329.21,"z":349.78},{"x":141.89,"y":326.42,"z":351.06},{"x":141.26,"y":323.17,"z":354.31},{"x":137.34,"y":322.73,"z":356.24},{"x":134.07,"y":325.52,"z":354.96}]},{"lat":-39.88,"lon":113.67,"b":[{"x":150.75,"y":323.44,"z":350.13},{"x":154.69,"y":323.81,"z":348.06},{"x":158.04,"y":320.9,"z":349.25},{"x":157.39,"y":317.61,"z":352.53},{"x":153.42,"y":317.27,"z":354.58},{"x":150.12,"y":320.18,"z":353.38}]},{"lat":-39,"lon":116,"b":[{"x":166.98,"y":317.64,"z":348.07},{"x":170.96,"y":317.91,"z":345.87},{"x":174.32,"y":314.87,"z":346.98},{"x":173.66,"y":311.55,"z":350.29},{"x":169.65,"y":311.31,"z":352.47},{"x":166.33,"y":314.35,"z":351.35}]},{"lat":-38.06,"lon":118.3,"b":[{"x":185.32,"y":309.47,"z":346.19},{"x":186.93,"y":309.54,"z":345.26},{"x":188.29,"y":308.27,"z":345.66},{"x":188.01,"y":306.93,"z":347},{"x":186.39,"y":306.87,"z":347.93},{"x":185.06,"y":308.14,"z":347.52}]},{"lat":-37.06,"lon":120.59,"b":[{"x":201.01,"y":303.25,"z":342.91},{"x":203.45,"y":303.29,"z":341.42},{"x":205.48,"y":301.29,"z":341.98},{"x":205.05,"y":299.25,"z":344.02},{"x":202.6,"y":299.23,"z":345.49},{"x":200.59,"y":301.22,"z":344.93}]},{"lat":-33.72,"lon":127.23,"b":[{"x":250.76,"y":278.48,"z":330.97},{"x":251.79,"y":278.42,"z":330.24},{"x":252.62,"y":277.48,"z":330.4},{"x":252.42,"y":276.6,"z":331.29},{"x":251.4,"y":276.66,"z":332.01},{"x":250.57,"y":277.6,"z":331.85}]},{"lat":-32.51,"lon":129.35,"b":[{"x":267.02,"y":269.13,"z":325.97},{"x":267.44,"y":269.09,"z":325.66},{"x":267.78,"y":268.69,"z":325.71},{"x":267.69,"y":268.33,"z":326.08},{"x":267.27,"y":268.37,"z":326.39},{"x":266.94,"y":268.77,"z":326.34}]},{"lat":-31.27,"lon":131.43,"b":[{"x":281.21,"y":261.43,"z":320.21},{"x":283.15,"y":261.21,"z":318.66},{"x":284.7,"y":259.26,"z":318.87},{"x":284.3,"y":257.54,"z":320.62},{"x":282.36,"y":257.76,"z":322.15},{"x":280.81,"y":259.7,"z":321.95}]},{"lat":-41.43,"lon":102.59,"b":[{"x":78.66,"y":333.19,"z":364.33},{"x":82.28,"y":333.96,"z":362.82},{"x":85.38,"y":331.54,"z":364.32},{"x":84.8,"y":328.35,"z":367.33},{"x":81.15,"y":327.63,"z":368.8},{"x":78.1,"y":330.05,"z":367.3}]},{"lat":-40.83,"lon":104.83,"b":[{"x":93.68,"y":329.38,"z":364.24},{"x":97.39,"y":330.07,"z":362.64},{"x":100.56,"y":327.53,"z":364.07},{"x":99.96,"y":324.3,"z":367.11},{"x":96.22,"y":323.65,"z":368.68},{"x":93.11,"y":326.19,"z":367.25}]},{"lat":-40.17,"lon":107.08,"b":[{"x":109.04,"y":325.12,"z":363.79},{"x":112.83,"y":325.73,"z":362.08},{"x":116.05,"y":323.07,"z":363.44},{"x":115.43,"y":319.8,"z":366.52},{"x":111.6,"y":319.23,"z":368.2},{"x":108.44,"y":321.89,"z":366.83}]},{"lat":-39.45,"lon":109.35,"b":[{"x":124.68,"y":320.42,"z":362.93},{"x":128.55,"y":320.94,"z":361.11},{"x":131.81,"y":318.15,"z":362.4},{"x":131.16,"y":314.85,"z":365.51},{"x":127.27,"y":314.36,"z":367.3},{"x":124.06,"y":317.14,"z":366.01}]},{"lat":-38.67,"lon":111.62,"b":[{"x":140.57,"y":315.24,"z":361.66},{"x":144.5,"y":315.67,"z":359.72},{"x":147.79,"y":312.76,"z":360.93},{"x":147.12,"y":309.42,"z":364.07},{"x":143.17,"y":309.02,"z":365.98},{"x":139.92,"y":311.93,"z":364.77}]},{"lat":-37.82,"lon":113.89,"b":[{"x":156.65,"y":309.58,"z":359.93},{"x":160.63,"y":309.92,"z":357.88},{"x":163.94,"y":306.88,"z":358.99},{"x":163.24,"y":303.5,"z":362.16},{"x":159.25,"y":303.2,"z":364.19},{"x":155.98,"y":306.23,"z":363.07}]},{"lat":-36.92,"lon":116.15,"b":[{"x":172.87,"y":303.43,"z":357.73},{"x":176.88,"y":303.67,"z":355.56},{"x":180.2,"y":300.5,"z":356.58},{"x":179.48,"y":297.11,"z":359.78},{"x":175.45,"y":296.9,"z":361.93},{"x":172.17,"y":300.05,"z":360.91}]},{"lat":-35.95,"lon":118.4,"b":[{"x":189.16,"y":296.78,"z":355.05},{"x":193.19,"y":296.93,"z":352.75},{"x":196.51,"y":293.64,"z":353.67},{"x":195.75,"y":290.22,"z":356.89},{"x":191.71,"y":290.11,"z":359.17},{"x":188.44,"y":293.39,"z":358.25}]},{"lat":-40.1,"lon":100.92,"b":[{"x":69.43,"y":324.44,"z":373.98},{"x":73,"y":325.23,"z":372.6},{"x":76.04,"y":322.81,"z":374.1},{"x":75.46,"y":319.59,"z":376.98},{"x":71.86,"y":318.83,"z":378.31},{"x":68.88,"y":321.26,"z":376.82}]},{"lat":-39.52,"lon":103.08,"b":[{"x":84.2,"y":320.68,"z":374.19},{"x":87.86,"y":321.4,"z":372.72},{"x":90.97,"y":318.86,"z":374.16},{"x":90.36,"y":315.59,"z":377.06},{"x":86.67,"y":314.91,"z":378.49},{"x":83.62,"y":317.45,"z":377.06}]},{"lat":-38.89,"lon":105.26,"b":[{"x":99.31,"y":316.5,"z":374.04},{"x":103.06,"y":317.15,"z":372.47},{"x":106.22,"y":314.48,"z":373.84},{"x":105.58,"y":311.17,"z":376.77},{"x":101.81,"y":310.57,"z":378.31},{"x":98.7,"y":313.23,"z":376.94}]},{"lat":-38.19,"lon":107.46,"b":[{"x":114.73,"y":311.88,"z":373.5},{"x":118.55,"y":312.45,"z":371.82},{"x":121.76,"y":309.66,"z":373.12},{"x":121.1,"y":306.31,"z":376.09},{"x":117.25,"y":305.79,"z":377.73},{"x":114.09,"y":308.57,"z":376.44}]},{"lat":-37.44,"lon":109.67,"b":[{"x":130.41,"y":306.81,"z":372.55},{"x":134.3,"y":307.29,"z":370.76},{"x":137.55,"y":304.39,"z":371.97},{"x":136.85,"y":301,"z":374.97},{"x":132.94,"y":300.56,"z":376.73},{"x":129.74,"y":303.46,"z":375.52}]},{"lat":-36.63,"lon":111.88,"b":[{"x":146.31,"y":301.27,"z":371.15},{"x":150.26,"y":301.67,"z":369.25},{"x":153.53,"y":298.64,"z":370.37},{"x":152.8,"y":295.22,"z":373.39},{"x":148.83,"y":294.87,"z":375.27},{"x":145.61,"y":297.89,"z":374.15}]},{"lat":-35.76,"lon":114.09,"b":[{"x":162.38,"y":295.27,"z":369.29},{"x":166.37,"y":295.57,"z":367.27},{"x":169.65,"y":292.42,"z":368.29},{"x":168.89,"y":288.97,"z":371.34},{"x":164.88,"y":288.71,"z":373.35},{"x":161.65,"y":291.85,"z":372.32}]},{"lat":-34.83,"lon":116.3,"b":[{"x":178.55,"y":288.79,"z":366.94},{"x":182.57,"y":288.99,"z":364.79},{"x":185.85,"y":285.72,"z":365.72},{"x":185.06,"y":282.26,"z":368.79},{"x":181.02,"y":282.09,"z":370.92},{"x":177.79,"y":285.34,"z":370}]},{"lat":-33.85,"lon":118.48,"b":[{"x":194.76,"y":281.83,"z":364.09},{"x":198.8,"y":281.94,"z":361.81},{"x":202.06,"y":278.55,"z":362.63},{"x":201.24,"y":275.07,"z":365.73},{"x":197.19,"y":275,"z":367.99},{"x":193.97,"y":278.37,"z":367.17}]},{"lat":-32.82,"lon":120.65,"b":[{"x":211.96,"y":273.34,"z":360.97},{"x":214.74,"y":273.35,"z":359.32},{"x":216.96,"y":270.94,"z":359.81},{"x":216.37,"y":268.54,"z":361.95},{"x":213.59,"y":268.55,"z":363.59},{"x":211.4,"y":270.94,"z":363.1}]},{"lat":-38.78,"lon":99.34,"b":[{"x":60.34,"y":315.56,"z":383.05},{"x":63.85,"y":316.38,"z":381.8},{"x":66.83,"y":313.95,"z":383.3},{"x":66.25,"y":310.7,"z":386.03},{"x":62.72,"y":309.93,"z":387.24},{"x":59.8,"y":312.36,"z":385.75}]},{"lat":-38.22,"lon":101.43,"b":[{"x":74.84,"y":311.84,"z":383.53},{"x":78.44,"y":312.59,"z":382.2},{"x":81.49,"y":310.05,"z":383.63},{"x":80.87,"y":306.75,"z":386.4},{"x":77.25,"y":306.04,"z":387.7},{"x":74.26,"y":308.59,"z":386.27}]},{"lat":-37.61,"lon":103.54,"b":[{"x":89.69,"y":307.71,"z":383.68},{"x":93.38,"y":308.4,"z":382.24},{"x":96.48,"y":305.74,"z":383.61},{"x":95.84,"y":302.39,"z":386.41},{"x":92.12,"y":301.76,"z":387.8},{"x":89.07,"y":304.42,"z":386.44}]},{"lat":-36.94,"lon":105.67,"b":[{"x":104.85,"y":303.17,"z":383.44},{"x":108.63,"y":303.78,"z":381.91},{"x":111.78,"y":301,"z":383.2},{"x":111.1,"y":297.62,"z":386.02},{"x":107.31,"y":297.06,"z":387.53},{"x":104.21,"y":299.83,"z":386.24}]},{"lat":-36.21,"lon":107.82,"b":[{"x":120.3,"y":298.2,"z":382.8},{"x":124.15,"y":298.72,"z":381.16},{"x":127.35,"y":295.82,"z":382.37},{"x":126.63,"y":292.41,"z":385.22},{"x":122.76,"y":291.93,"z":386.84},{"x":119.63,"y":294.82,"z":385.63}]},{"lat":-35.43,"lon":109.98,"b":[{"x":136,"y":292.78,"z":381.73},{"x":139.91,"y":293.22,"z":379.97},{"x":143.13,"y":290.2,"z":381.09},{"x":142.38,"y":286.75,"z":383.97},{"x":138.45,"y":286.35,"z":385.7},{"x":135.28,"y":289.36,"z":384.58}]},{"lat":-34.59,"lon":112.13,"b":[{"x":151.88,"y":286.9,"z":380.2},{"x":155.85,"y":287.26,"z":378.32},{"x":159.08,"y":284.12,"z":379.34},{"x":158.3,"y":280.64,"z":382.25},{"x":154.31,"y":280.33,"z":384.1},{"x":151.13,"y":283.45,"z":383.08}]},{"lat":-33.69,"lon":114.29,"b":[{"x":167.89,"y":280.57,"z":378.18},{"x":171.9,"y":280.83,"z":376.18},{"x":175.14,"y":277.57,"z":377.1},{"x":174.32,"y":274.07,"z":380.03},{"x":170.3,"y":273.85,"z":382.01},{"x":167.11,"y":277.09,"z":381.08}]},{"lat":-32.75,"lon":116.43,"b":[{"x":183.98,"y":273.78,"z":375.66},{"x":188.02,"y":273.95,"z":373.53},{"x":191.24,"y":270.58,"z":374.35},{"x":190.39,"y":267.06,"z":377.3},{"x":186.35,"y":266.93,"z":379.41},{"x":183.17,"y":270.28,"z":378.59}]},{"lat":-31.75,"lon":118.56,"b":[{"x":200.09,"y":266.53,"z":372.63},{"x":204.13,"y":266.61,"z":370.37},{"x":207.33,"y":263.13,"z":371.08},{"x":206.44,"y":259.6,"z":374.05},{"x":202.39,"y":259.56,"z":376.29},{"x":199.23,"y":263.01,"z":375.57}]},{"lat":-30.71,"lon":120.67,"b":[{"x":216.22,"y":258.75,"z":369.08},{"x":220.15,"y":258.74,"z":366.76},{"x":223.22,"y":255.25,"z":367.35},{"x":222.32,"y":251.81,"z":370.26},{"x":218.39,"y":251.86,"z":372.56},{"x":215.35,"y":255.32,"z":371.97}]},{"lat":-37.48,"lon":97.86,"b":[{"x":51.42,"y":306.6,"z":391.54},{"x":54.85,"y":307.43,"z":390.41},{"x":57.77,"y":304.99,"z":391.9},{"x":57.2,"y":301.73,"z":394.5},{"x":53.74,"y":300.95,"z":395.59},{"x":50.88,"y":303.38,"z":394.11}]},{"lat":-36.93,"lon":99.88,"b":[{"x":65.62,"y":302.9,"z":392.29},{"x":69.16,"y":303.67,"z":391.08},{"x":72.14,"y":301.13,"z":392.51},{"x":71.54,"y":297.81,"z":395.13},{"x":67.97,"y":297.09,"z":396.3},{"x":65.05,"y":299.64,"z":394.88}]},{"lat":-36.33,"lon":101.92,"b":[{"x":80.19,"y":298.82,"z":392.7},{"x":83.82,"y":299.53,"z":391.4},{"x":86.86,"y":296.87,"z":392.77},{"x":86.22,"y":293.51,"z":395.42},{"x":82.57,"y":292.86,"z":396.68},{"x":79.58,"y":295.51,"z":395.33}]},{"lat":-35.68,"lon":103.98,"b":[{"x":95.09,"y":294.34,"z":392.76},{"x":98.81,"y":294.98,"z":391.36},{"x":101.9,"y":292.2,"z":392.65},{"x":101.22,"y":288.8,"z":395.33},{"x":97.48,"y":288.22,"z":396.69},{"x":94.44,"y":290.98,"z":395.41}]},{"lat":-34.98,"lon":106.07,"b":[{"x":110.29,"y":289.45,"z":392.42},{"x":114.08,"y":290.01,"z":390.91},{"x":117.22,"y":287.12,"z":392.12},{"x":116.5,"y":283.68,"z":394.83},{"x":112.68,"y":283.17,"z":396.3},{"x":109.61,"y":286.05,"z":395.1}]},{"lat":-34.22,"lon":108.16,"b":[{"x":125.74,"y":284.13,"z":391.65},{"x":129.61,"y":284.61,"z":390.04},{"x":132.78,"y":281.6,"z":391.16},{"x":132.02,"y":278.13,"z":393.89},{"x":128.13,"y":277.7,"z":395.47},{"x":125.02,"y":280.69,"z":394.36}]},{"lat":-33.41,"lon":110.27,"b":[{"x":141.41,"y":278.37,"z":390.44},{"x":145.34,"y":278.77,"z":388.71},{"x":148.53,"y":275.64,"z":389.73},{"x":147.73,"y":272.14,"z":392.48},{"x":143.79,"y":271.8,"z":394.19},{"x":140.65,"y":274.9,"z":393.17}]},{"lat":-32.55,"lon":112.37,"b":[{"x":157.24,"y":272.17,"z":388.75},{"x":161.23,"y":272.48,"z":386.9},{"x":164.41,"y":269.25,"z":387.82},{"x":163.58,"y":265.72,"z":390.59},{"x":159.59,"y":265.46,"z":392.42},{"x":156.44,"y":268.67,"z":391.5}]},{"lat":-31.63,"lon":114.47,"b":[{"x":173.18,"y":265.53,"z":386.56},{"x":177.2,"y":265.75,"z":384.58},{"x":180.38,"y":262.41,"z":385.4},{"x":179.5,"y":258.86,"z":388.2},{"x":175.48,"y":258.69,"z":390.15},{"x":172.34,"y":262.01,"z":389.33}]},{"lat":-30.67,"lon":116.57,"b":[{"x":189.16,"y":258.46,"z":383.86},{"x":193.2,"y":258.59,"z":381.75},{"x":196.36,"y":255.13,"z":382.46},{"x":195.44,"y":251.58,"z":385.27},{"x":191.4,"y":251.49,"z":387.36},{"x":188.28,"y":254.91,"z":386.65}]},{"lat":-29.66,"lon":118.64,"b":[{"x":205.12,"y":250.95,"z":380.62},{"x":209.17,"y":250.99,"z":378.39},{"x":212.29,"y":247.44,"z":378.99},{"x":211.33,"y":243.88,"z":381.82},{"x":207.29,"y":243.88,"z":384.03},{"x":204.2,"y":247.4,"z":383.44}]},{"lat":-28.61,"lon":120.7,"b":[{"x":220.99,"y":243.03,"z":376.86},{"x":225.03,"y":242.98,"z":374.49},{"x":228.1,"y":239.34,"z":374.98},{"x":227.1,"y":235.78,"z":377.83},{"x":223.08,"y":235.86,"z":380.17},{"x":220.03,"y":239.47,"z":379.69}]},{"lat":-36.19,"lon":96.47,"b":[{"x":42.67,"y":297.59,"z":399.46},{"x":46.03,"y":298.42,"z":398.46},{"x":48.89,"y":295.99,"z":399.94},{"x":48.33,"y":292.72,"z":402.4},{"x":44.94,"y":291.93,"z":403.36},{"x":42.14,"y":294.37,"z":401.9}]},{"lat":-35.65,"lon":98.41,"b":[{"x":56.58,"y":293.91,"z":400.45},{"x":60.04,"y":294.69,"z":399.37},{"x":62.96,"y":292.14,"z":400.79},{"x":62.36,"y":288.82,"z":403.28},{"x":58.88,"y":288.09,"z":404.33},{"x":56.01,"y":290.63,"z":402.92}]},{"lat":-35.07,"lon":100.39,"b":[{"x":70.85,"y":289.86,"z":401.13},{"x":74.41,"y":290.58,"z":399.96},{"x":77.39,"y":287.93,"z":401.31},{"x":76.76,"y":284.56,"z":403.82},{"x":73.17,"y":283.89,"z":404.96},{"x":70.25,"y":286.54,"z":403.62}]},{"lat":-34.43,"lon":102.39,"b":[{"x":85.46,"y":285.43,"z":401.45},{"x":89.12,"y":286.09,"z":400.19},{"x":92.15,"y":283.32,"z":401.47},{"x":91.48,"y":279.91,"z":404},{"x":87.8,"y":279.31,"z":405.24},{"x":84.83,"y":282.06,"z":403.97}]},{"lat":-33.75,"lon":104.41,"b":[{"x":100.39,"y":280.61,"z":401.4},{"x":104.13,"y":281.19,"z":400.03},{"x":107.21,"y":278.31,"z":401.23},{"x":106.49,"y":274.87,"z":403.79},{"x":102.73,"y":274.33,"z":405.12},{"x":99.71,"y":277.2,"z":403.93}]},{"lat":-33.02,"lon":106.44,"b":[{"x":115.59,"y":275.37,"z":400.93},{"x":119.41,"y":275.88,"z":399.46},{"x":122.52,"y":272.89,"z":400.57},{"x":121.76,"y":269.41,"z":403.15},{"x":117.92,"y":268.95,"z":404.59},{"x":114.87,"y":271.93,"z":403.49}]},{"lat":-32.23,"lon":108.49,"b":[{"x":131.02,"y":269.72,"z":400.02},{"x":134.91,"y":270.15,"z":398.43},{"x":138.04,"y":267.05,"z":399.45},{"x":137.24,"y":263.54,"z":402.05},{"x":133.34,"y":263.16,"z":403.61},{"x":130.26,"y":266.24,"z":402.6}]},{"lat":-31.4,"lon":110.54,"b":[{"x":146.64,"y":263.65,"z":398.65},{"x":150.58,"y":263.99,"z":396.94},{"x":153.73,"y":260.78,"z":397.86},{"x":152.88,"y":257.24,"z":400.48},{"x":148.93,"y":256.95,"z":402.16},{"x":145.83,"y":260.13,"z":401.24}]},{"lat":-30.52,"lon":112.6,"b":[{"x":162.39,"y":257.15,"z":396.78},{"x":166.38,"y":257.41,"z":394.95},{"x":169.52,"y":254.09,"z":395.77},{"x":168.62,"y":250.53,"z":398.41},{"x":164.63,"y":250.32,"z":400.21},{"x":161.54,"y":253.61,"z":399.4}]},{"lat":-29.59,"lon":114.65,"b":[{"x":178.22,"y":250.22,"z":394.4},{"x":182.24,"y":250.4,"z":392.45},{"x":185.36,"y":246.98,"z":393.16},{"x":184.42,"y":243.41,"z":395.81},{"x":180.4,"y":243.28,"z":397.74},{"x":177.32,"y":246.67,"z":397.04}]},{"lat":-28.61,"lon":116.69,"b":[{"x":194.06,"y":242.89,"z":391.5},{"x":198.1,"y":242.98,"z":389.42},{"x":201.18,"y":239.46,"z":390.01},{"x":200.2,"y":235.88,"z":392.69},{"x":196.17,"y":235.84,"z":394.75},{"x":193.12,"y":239.32,"z":394.16}]},{"lat":-27.59,"lon":118.72,"b":[{"x":209.85,"y":235.15,"z":388.06},{"x":213.89,"y":235.16,"z":385.85},{"x":216.93,"y":231.55,"z":386.33},{"x":215.9,"y":227.97,"z":389.03},{"x":211.88,"y":228,"z":391.22},{"x":208.86,"y":231.58,"z":390.74}]},{"lat":-26.54,"lon":120.72,"b":[{"x":227.8,"y":224.27,"z":384.43},{"x":228.77,"y":224.25,"z":383.86},{"x":229.49,"y":223.36,"z":383.95},{"x":229.24,"y":222.5,"z":384.61},{"x":228.27,"y":222.53,"z":385.17},{"x":227.55,"y":223.41,"z":385.08}]},{"lat":-34.91,"lon":95.16,"b":[{"x":34.12,"y":288.56,"z":406.84},{"x":37.4,"y":289.4,"z":405.95},{"x":40.2,"y":286.97,"z":407.41},{"x":39.65,"y":283.7,"z":409.74},{"x":36.34,"y":282.91,"z":410.59},{"x":33.61,"y":285.35,"z":409.15}]},{"lat":-34.39,"lon":97.03,"b":[{"x":47.72,"y":284.89,"z":408.05},{"x":51.11,"y":285.68,"z":407.09},{"x":53.97,"y":283.14,"z":408.5},{"x":53.38,"y":279.82,"z":410.85},{"x":49.97,"y":279.09,"z":411.78},{"x":47.17,"y":281.62,"z":410.39}]},{"lat":-33.82,"lon":98.94,"b":[{"x":61.69,"y":280.87,"z":408.97},{"x":65.18,"y":281.6,"z":407.92},{"x":68.1,"y":278.95,"z":409.26},{"x":67.47,"y":275.58,"z":411.63},{"x":63.96,"y":274.91,"z":412.65},{"x":61.1,"y":277.55,"z":411.32}]},{"lat":-33.2,"lon":100.87,"b":[{"x":76,"y":276.48,"z":409.54},{"x":79.59,"y":277.15,"z":408.41},{"x":82.56,"y":274.39,"z":409.68},{"x":81.9,"y":270.98,"z":412.07},{"x":78.29,"y":270.37,"z":413.17},{"x":75.38,"y":273.11,"z":411.92}]},{"lat":-32.53,"lon":102.83,"b":[{"x":90.64,"y":271.71,"z":409.75},{"x":94.32,"y":272.31,"z":408.52},{"x":97.34,"y":269.45,"z":409.71},{"x":96.62,"y":266,"z":412.12},{"x":92.93,"y":265.46,"z":413.32},{"x":89.97,"y":268.3,"z":412.14}]},{"lat":-31.82,"lon":104.81,"b":[{"x":105.57,"y":266.55,"z":409.56},{"x":109.33,"y":267.08,"z":408.23},{"x":112.38,"y":264.11,"z":409.34},{"x":111.62,"y":260.63,"z":411.76},{"x":107.85,"y":260.15,"z":413.07},{"x":104.86,"y":263.11,"z":411.97}]},{"lat":-31.06,"lon":106.8,"b":[{"x":120.74,"y":260.99,"z":408.95},{"x":124.58,"y":261.45,"z":407.5},{"x":127.66,"y":258.37,"z":408.52},{"x":126.85,"y":254.86,"z":410.96},{"x":123.01,"y":254.46,"z":412.38},{"x":119.99,"y":257.51,"z":411.38}]},{"lat":-30.25,"lon":108.8,"b":[{"x":136.13,"y":255.03,"z":407.87},{"x":140.02,"y":255.41,"z":406.32},{"x":143.11,"y":252.22,"z":407.23},{"x":142.26,"y":248.68,"z":409.7},{"x":138.36,"y":248.36,"z":411.23},{"x":135.32,"y":251.52,"z":410.32}]},{"lat":-29.4,"lon":110.81,"b":[{"x":151.67,"y":248.66,"z":406.32},{"x":155.61,"y":248.96,"z":404.64},{"x":158.71,"y":245.67,"z":405.45},{"x":157.8,"y":242.11,"z":407.94},{"x":153.86,"y":241.86,"z":409.59},{"x":150.81,"y":245.12,"z":408.79}]},{"lat":-28.5,"lon":112.81,"b":[{"x":167.31,"y":241.88,"z":404.26},{"x":171.3,"y":242.1,"z":402.46},{"x":174.38,"y":238.71,"z":403.17},{"x":173.43,"y":235.14,"z":405.66},{"x":169.44,"y":234.97,"z":407.44},{"x":166.41,"y":238.33,"z":406.75}]},{"lat":-27.55,"lon":114.82,"b":[{"x":183,"y":234.71,"z":401.69},{"x":187.01,"y":234.84,"z":399.76},{"x":190.06,"y":231.35,"z":400.35},{"x":189.06,"y":227.77,"z":402.87},{"x":185.06,"y":227.69,"z":404.77},{"x":182.04,"y":231.14,"z":404.19}]},{"lat":-26.57,"lon":116.81,"b":[{"x":198.67,"y":227.14,"z":398.58},{"x":202.69,"y":227.19,"z":396.52},{"x":205.71,"y":223.62,"z":397},{"x":204.66,"y":220.04,"z":399.53},{"x":200.65,"y":220.03,"z":401.57},{"x":197.67,"y":223.57,"z":401.09}]},{"lat":-25.54,"lon":118.79,"b":[{"x":214.39,"y":219.05,"z":394.95},{"x":218.24,"y":219.02,"z":392.85},{"x":221.06,"y":215.53,"z":393.2},{"x":220.02,"y":212.11,"z":395.64},{"x":216.19,"y":212.18,"z":397.71},{"x":213.39,"y":215.63,"z":397.37}]},{"lat":-24.49,"lon":120.75,"b":[{"x":231.89,"y":208.17,"z":390.98},{"x":232.9,"y":208.14,"z":390.4},{"x":233.62,"y":207.21,"z":390.47},{"x":233.33,"y":206.32,"z":391.11},{"x":232.34,"y":206.35,"z":391.68},{"x":231.62,"y":207.27,"z":391.62}]},{"lat":-33.67,"lon":93.92,"b":[{"x":25.78,"y":279.56,"z":413.68},{"x":28.99,"y":280.4,"z":412.9},{"x":31.72,"y":277.96,"z":414.35},{"x":31.19,"y":274.7,"z":416.55},{"x":27.96,"y":273.93,"z":417.29},{"x":25.29,"y":276.36,"z":415.86}]},{"lat":-33.15,"lon":95.73,"b":[{"x":39.07,"y":275.89,"z":415.1},{"x":42.38,"y":276.67,"z":414.25},{"x":45.18,"y":274.14,"z":415.64},{"x":44.61,"y":270.83,"z":417.86},{"x":41.28,"y":270.1,"z":418.67},{"x":38.54,"y":272.63,"z":417.3}]},{"lat":-32.59,"lon":97.57,"b":[{"x":52.73,"y":271.88,"z":416.23},{"x":56.14,"y":272.61,"z":415.31},{"x":59,"y":269.97,"z":416.63},{"x":58.39,"y":266.62,"z":418.87},{"x":54.96,"y":265.95,"z":419.76},{"x":52.16,"y":268.57,"z":418.45}]},{"lat":-31.98,"lon":99.45,"b":[{"x":66.74,"y":267.52,"z":417.04},{"x":70.25,"y":268.19,"z":416.03},{"x":73.16,"y":265.45,"z":417.29},{"x":72.5,"y":262.05,"z":419.54},{"x":68.98,"y":261.44,"z":420.52},{"x":66.12,"y":264.16,"z":419.28}]},{"lat":-31.33,"lon":101.34,"b":[{"x":81.07,"y":262.8,"z":417.5},{"x":84.68,"y":263.41,"z":416.4},{"x":87.64,"y":260.56,"z":417.58},{"x":86.93,"y":257.13,"z":419.84},{"x":83.32,"y":256.58,"z":420.92},{"x":80.42,"y":259.4,"z":419.75}]},{"lat":-30.64,"lon":103.26,"b":[{"x":95.71,"y":257.7,"z":417.57},{"x":99.4,"y":258.25,"z":416.37},{"x":102.4,"y":255.3,"z":417.47},{"x":101.65,"y":251.83,"z":419.75},{"x":97.95,"y":251.34,"z":420.92},{"x":95.01,"y":254.27,"z":419.84}]},{"lat":-29.9,"lon":105.19,"b":[{"x":110.61,"y":252.23,"z":417.23},{"x":114.38,"y":252.7,"z":415.93},{"x":117.4,"y":249.65,"z":416.93},{"x":116.6,"y":246.15,"z":419.23},{"x":112.83,"y":245.73,"z":420.51},{"x":109.86,"y":248.76,"z":419.51}]},{"lat":-29.11,"lon":107.14,"b":[{"x":125.74,"y":246.37,"z":416.45},{"x":129.58,"y":246.77,"z":415.03},{"x":132.62,"y":243.61,"z":415.94},{"x":131.76,"y":240.08,"z":418.25},{"x":127.92,"y":239.74,"z":419.64},{"x":124.94,"y":242.86,"z":418.75}]},{"lat":-28.28,"lon":109.1,"b":[{"x":141.04,"y":240.11,"z":415.19},{"x":144.94,"y":240.44,"z":413.66},{"x":147.98,"y":237.18,"z":414.47},{"x":147.08,"y":233.63,"z":416.79},{"x":143.18,"y":233.36,"z":418.3},{"x":140.19,"y":236.59,"z":417.51}]},{"lat":-27.41,"lon":111.06,"b":[{"x":156.47,"y":233.47,"z":413.45},{"x":160.42,"y":233.72,"z":411.79},{"x":163.46,"y":230.36,"z":412.49},{"x":162.5,"y":226.8,"z":414.83},{"x":158.56,"y":226.6,"z":416.47},{"x":155.57,"y":229.92,"z":415.78}]},{"lat":-26.49,"lon":113.02,"b":[{"x":171.98,"y":226.45,"z":411.19},{"x":175.96,"y":226.61,"z":409.41},{"x":178.98,"y":223.16,"z":410},{"x":177.97,"y":219.59,"z":412.36},{"x":174,"y":219.48,"z":414.11},{"x":171.02,"y":222.88,"z":413.53}]},{"lat":-25.54,"lon":114.98,"b":[{"x":187.5,"y":219.05,"z":408.4},{"x":191.5,"y":219.13,"z":406.49},{"x":194.48,"y":215.6,"z":406.97},{"x":193.43,"y":212.02,"z":409.34},{"x":189.44,"y":211.98,"z":411.23},{"x":186.49,"y":215.47,"z":410.76}]},{"lat":-24.55,"lon":116.92,"b":[{"x":202.97,"y":211.29,"z":405.08},{"x":206.99,"y":211.29,"z":403.04},{"x":209.92,"y":207.68,"z":403.4},{"x":208.81,"y":204.11,"z":405.79},{"x":204.82,"y":204.15,"z":407.81},{"x":201.92,"y":207.71,"z":407.45}]},{"lat":-22.47,"lon":120.77,"b":[{"x":234.78,"y":193.16,"z":396.89},{"x":237.02,"y":193.07,"z":395.6},{"x":238.59,"y":190.97,"z":395.68},{"x":237.91,"y":188.97,"z":397.04},{"x":235.69,"y":189.07,"z":398.32},{"x":234.12,"y":191.15,"z":398.25}]},{"lat":-32.44,"lon":92.76,"b":[{"x":17.67,"y":270.61,"z":420.01},{"x":20.79,"y":271.44,"z":419.33},{"x":23.47,"y":269.01,"z":420.76},{"x":22.96,"y":265.77,"z":422.84},{"x":19.81,"y":265,"z":423.48},{"x":17.2,"y":267.42,"z":422.07}]},{"lat":-31.93,"lon":94.5,"b":[{"x":30.64,"y":266.93,"z":421.62},{"x":33.87,"y":267.7,"z":420.88},{"x":36.61,"y":265.18,"z":422.25},{"x":36.06,"y":261.89,"z":424.34},{"x":32.81,"y":261.17,"z":425.04},{"x":30.13,"y":263.69,"z":423.69}]},{"lat":-31.38,"lon":96.28,"b":[{"x":43.98,"y":262.92,"z":422.95},{"x":47.31,"y":263.65,"z":422.13},{"x":50.11,"y":261.03,"z":423.44},{"x":49.52,"y":257.69,"z":425.55},{"x":46.17,"y":257.03,"z":426.33},{"x":43.43,"y":259.63,"z":425.04}]},{"lat":-30.79,"lon":98.09,"b":[{"x":57.67,"y":258.59,"z":423.97},{"x":61.11,"y":259.26,"z":423.08},{"x":63.96,"y":256.54,"z":424.32},{"x":63.32,"y":253.16,"z":426.43},{"x":59.87,"y":252.55,"z":427.3},{"x":57.08,"y":255.25,"z":426.07}]},{"lat":-30.15,"lon":99.93,"b":[{"x":71.7,"y":253.91,"z":424.66},{"x":75.23,"y":254.52,"z":423.68},{"x":78.13,"y":251.69,"z":424.84},{"x":77.44,"y":248.28,"z":426.97},{"x":73.91,"y":247.72,"z":427.92},{"x":71.06,"y":250.53,"z":426.77}]},{"lat":-29.47,"lon":101.79,"b":[{"x":86.04,"y":248.87,"z":424.98},{"x":89.66,"y":249.42,"z":423.9},{"x":92.59,"y":246.49,"z":424.98},{"x":91.86,"y":243.04,"z":427.12},{"x":88.23,"y":242.55,"z":428.17},{"x":85.35,"y":245.45,"z":427.1}]},{"lat":-28.75,"lon":103.67,"b":[{"x":100.65,"y":243.47,"z":424.89},{"x":104.35,"y":243.95,"z":423.72},{"x":107.32,"y":240.92,"z":424.71},{"x":106.53,"y":237.44,"z":426.86},{"x":102.83,"y":237.01,"z":428.01},{"x":99.91,"y":240.01,"z":427.03}]},{"lat":-27.99,"lon":105.56,"b":[{"x":115.5,"y":237.69,"z":424.38},{"x":119.28,"y":238.11,"z":423.1},{"x":122.26,"y":234.98,"z":424},{"x":121.42,"y":231.47,"z":426.16},{"x":117.65,"y":231.12,"z":427.42},{"x":114.71,"y":234.21,"z":426.53}]},{"lat":-27.18,"lon":107.47,"b":[{"x":130.55,"y":231.55,"z":423.41},{"x":134.39,"y":231.89,"z":422.02},{"x":137.38,"y":228.67,"z":422.82},{"x":136.49,"y":225.14,"z":424.99},{"x":132.65,"y":224.85,"z":426.36},{"x":129.71,"y":228.04,"z":425.58}]},{"lat":-26.33,"lon":109.38,"b":[{"x":145.75,"y":225.03,"z":421.96},{"x":149.64,"y":225.3,"z":420.46},{"x":152.63,"y":221.98,"z":421.14},{"x":151.68,"y":218.43,"z":423.33},{"x":147.8,"y":218.22,"z":424.82},{"x":144.85,"y":221.5,"z":424.14}]},{"lat":-25.44,"lon":111.3,"b":[{"x":161.04,"y":218.14,"z":420.01},{"x":164.98,"y":218.34,"z":418.38},{"x":167.96,"y":214.93,"z":418.96},{"x":166.95,"y":211.37,"z":421.17},{"x":163.03,"y":211.23,"z":422.78},{"x":160.09,"y":214.6,"z":422.2}]},{"lat":-24.51,"lon":113.22,"b":[{"x":176.39,"y":210.9,"z":417.54},{"x":180.36,"y":211.02,"z":415.78},{"x":183.3,"y":207.53,"z":416.25},{"x":182.24,"y":203.97,"z":418.47},{"x":178.29,"y":203.9,"z":420.21},{"x":175.38,"y":207.34,"z":419.75}]},{"lat":-23.55,"lon":115.13,"b":[{"x":191.72,"y":203.31,"z":414.54},{"x":195.71,"y":203.35,"z":412.65},{"x":198.61,"y":199.78,"z":413.01},{"x":197.49,"y":196.22,"z":415.24},{"x":193.53,"y":196.23,"z":417.1},{"x":190.66,"y":199.75,"z":416.76}]},{"lat":-22.56,"lon":117.03,"b":[{"x":209.2,"y":192.6,"z":411.24},{"x":210.1,"y":192.59,"z":410.79},{"x":210.74,"y":191.78,"z":410.84},{"x":210.47,"y":190.98,"z":411.35},{"x":209.59,"y":191,"z":411.79},{"x":208.95,"y":191.8,"z":411.74}]},{"lat":-31.25,"lon":91.65,"b":[{"x":9.78,"y":261.74,"z":425.85},{"x":12.83,"y":262.55,"z":425.27},{"x":15.44,"y":260.13,"z":426.68},{"x":14.28,"y":257.08,"z":428.56},{"x":10.52,"y":256.51,"z":429.01},{"x":8.64,"y":258.75,"z":427.7}]},{"lat":-30.74,"lon":93.34,"b":[{"x":22.44,"y":258.04,"z":427.63},{"x":25.58,"y":258.8,"z":426.99},{"x":28.26,"y":256.29,"z":428.34},{"x":27.08,"y":253.2,"z":430.25},{"x":23.24,"y":252.67,"z":430.78},{"x":21.28,"y":255,"z":429.51}]},{"lat":-30.2,"lon":95.06,"b":[{"x":35.46,"y":254.04,"z":429.14},{"x":38.71,"y":254.75,"z":428.43},{"x":41.45,"y":252.14,"z":429.72},{"x":40.25,"y":249.01,"z":431.66},{"x":36.33,"y":248.53,"z":432.28},{"x":34.28,"y":250.95,"z":431.05}]},{"lat":-29.61,"lon":96.81,"b":[{"x":48.84,"y":249.71,"z":430.36},{"x":52.19,"y":250.38,"z":429.57},{"x":54.98,"y":247.67,"z":430.8},{"x":53.77,"y":244.5,"z":432.76},{"x":49.78,"y":244.07,"z":433.48},{"x":47.64,"y":246.58,"z":432.29}]},{"lat":-28.99,"lon":98.59,"b":[{"x":62.55,"y":245.06,"z":431.25},{"x":66,"y":245.67,"z":430.39},{"x":68.84,"y":242.87,"z":431.54},{"x":67.61,"y":239.65,"z":433.53},{"x":63.55,"y":239.28,"z":434.34},{"x":61.34,"y":241.89,"z":433.22}]},{"lat":-28.32,"lon":100.39,"b":[{"x":76.58,"y":240.07,"z":431.79},{"x":80.11,"y":240.63,"z":430.84},{"x":83,"y":237.72,"z":431.91},{"x":81.75,"y":234.46,"z":433.92},{"x":77.64,"y":234.14,"z":434.85},{"x":75.35,"y":236.85,"z":433.78}]},{"lat":-27.62,"lon":102.22,"b":[{"x":90.89,"y":234.74,"z":431.95},{"x":94.51,"y":235.23,"z":430.9},{"x":97.42,"y":232.23,"z":431.88},{"x":96.16,"y":228.93,"z":433.92},{"x":92,"y":228.66,"z":434.96},{"x":89.64,"y":231.47,"z":433.97}]},{"lat":-26.87,"lon":104.06,"b":[{"x":105.45,"y":229.05,"z":431.69},{"x":109.15,"y":229.47,"z":430.55},{"x":112.09,"y":226.38,"z":431.43},{"x":110.81,"y":223.04,"z":433.49},{"x":106.62,"y":222.83,"z":434.65},{"x":104.19,"y":225.75,"z":433.73}]},{"lat":-26.09,"lon":105.92,"b":[{"x":120.22,"y":223,"z":431},{"x":124,"y":223.35,"z":429.74},{"x":126.94,"y":220.17,"z":430.53},{"x":125.66,"y":216.8,"z":432.61},{"x":121.44,"y":216.65,"z":433.88},{"x":118.95,"y":219.66,"z":433.06}]},{"lat":-25.26,"lon":107.78,"b":[{"x":135.17,"y":216.59,"z":429.83},{"x":139,"y":216.88,"z":428.46},{"x":141.95,"y":213.6,"z":429.14},{"x":140.65,"y":210.2,"z":431.24},{"x":136.42,"y":210.11,"z":432.64},{"x":133.88,"y":213.22,"z":431.91}]},{"lat":-24.4,"lon":109.65,"b":[{"x":150.23,"y":209.84,"z":428.17},{"x":154.12,"y":210.05,"z":426.69},{"x":157.06,"y":206.69,"z":427.26},{"x":155.75,"y":203.26,"z":429.38},{"x":151.52,"y":203.23,"z":430.9},{"x":148.94,"y":206.44,"z":430.27}]},{"lat":-23.5,"lon":111.53,"b":[{"x":165.37,"y":202.74,"z":426.01},{"x":169.3,"y":202.88,"z":424.4},{"x":172.21,"y":199.43,"z":424.86},{"x":170.89,"y":195.98,"z":426.99},{"x":166.67,"y":196,"z":428.65},{"x":164.07,"y":199.31,"z":428.13}]},{"lat":-22.56,"lon":113.4,"b":[{"x":180.92,"y":194.84,"z":423.37},{"x":184.34,"y":194.9,"z":421.87},{"x":186.83,"y":191.85,"z":422.17},{"x":185.68,"y":188.84,"z":424.03},{"x":182.05,"y":188.9,"z":425.58},{"x":179.77,"y":191.85,"z":425.22}]},{"lat":-17.47,"lon":122.62,"b":[{"x":256.3,"y":151.24,"z":401.76},{"x":257.51,"y":151.15,"z":401.01},{"x":258.3,"y":149.98,"z":400.95},{"x":257.88,"y":148.88,"z":401.63},{"x":256.68,"y":148.96,"z":402.37},{"x":255.88,"y":150.14,"z":402.44}]},{"lat":5.92,"lon":150.21,"b":[{"x":431.94,"y":-49.72,"z":246.83},{"x":432.5,"y":-50.73,"z":245.64},{"x":432.16,"y":-52.61,"z":245.85},{"x":431.23,"y":-53.19,"z":247.35},{"x":430.66,"y":-51.87,"z":248.63},{"x":431.03,"y":-50.28,"z":248.31}]},{"lat":45.36,"lon":167.49,"b":[{"x":344.24,"y":-354.49,"z":76.22},{"x":343.79,"y":-355.28,"z":74.52},{"x":342.54,"y":-356.51,"z":74.41},{"x":341.64,"y":-357.06,"z":75.87},{"x":341.97,"y":-356.4,"z":77.46},{"x":343.33,"y":-355.05,"z":77.7}]},{"lat":47,"lon":168.67,"b":[{"x":335.93,"y":-364.16,"z":67.1},{"x":335.32,"y":-365.11,"z":64.96},{"x":333.73,"y":-366.58,"z":64.84},{"x":332.6,"y":-367.28,"z":66.67},{"x":333.04,"y":-366.52,"z":68.65},{"x":334.78,"y":-364.87,"z":68.95}]},{"lat":2.92,"lon":150.77,"b":[{"x":435.55,"y":-25.67,"z":244.2},{"x":435.61,"y":-25.22,"z":244.13},{"x":435.81,"y":-25.01,"z":243.79},{"x":435.96,"y":-25.24,"z":243.51},{"x":435.9,"y":-25.7,"z":243.57},{"x":435.69,"y":-25.91,"z":243.91}]},{"lat":6.01,"lon":151.83,"b":[{"x":437.36,"y":-53.35,"z":236.3},{"x":437.74,"y":-51.24,"z":236.08},{"x":438.7,"y":-50.27,"z":234.48},{"x":439.32,"y":-51.41,"z":233.08},{"x":438.94,"y":-53.55,"z":233.3},{"x":437.96,"y":-54.52,"z":234.92}]},{"lat":4.51,"lon":152.93,"b":[{"x":443.31,"y":-39.87,"z":227.75},{"x":443.48,"y":-38.73,"z":227.61},{"x":443.98,"y":-38.19,"z":226.72},{"x":444.32,"y":-38.79,"z":225.96},{"x":444.15,"y":-39.95,"z":226.09},{"x":443.64,"y":-40.49,"z":226.99}]},{"lat":6.19,"lon":155.22,"b":[{"x":450.82,"y":-54.46,"z":209.23},{"x":451.01,"y":-53.32,"z":209.12},{"x":451.49,"y":-52.79,"z":208.21},{"x":451.79,"y":-53.4,"z":207.4},{"x":451.6,"y":-54.56,"z":207.51},{"x":451.11,"y":-55.09,"z":208.43}]},{"lat":7.96,"lon":157.66,"b":[{"x":457.79,"y":-69.47,"z":188.66},{"x":457.9,"y":-68.9,"z":188.61},{"x":458.12,"y":-68.64,"z":188.15},{"x":458.25,"y":-68.95,"z":187.73},{"x":458.15,"y":-69.52,"z":187.77},{"x":457.91,"y":-69.78,"z":188.24}]},{"lat":8.06,"lon":159.52,"b":[{"x":463.47,"y":-70.41,"z":173.84},{"x":463.61,"y":-69.68,"z":173.78},{"x":463.88,"y":-69.34,"z":173.18},{"x":464.03,"y":-69.74,"z":172.62},{"x":463.9,"y":-70.48,"z":172.67},{"x":463.62,"y":-70.82,"z":173.28}]},{"lat":9.8,"lon":160.25,"b":[{"x":463.11,"y":-85.77,"z":167.76},{"x":463.43,"y":-84.21,"z":167.67},{"x":464.02,"y":-83.5,"z":166.38},{"x":464.3,"y":-84.36,"z":165.17},{"x":463.98,"y":-85.93,"z":165.26},{"x":463.38,"y":-86.64,"z":166.56}]},{"lat":20.88,"lon":165.2,"b":[{"x":451.2,"y":-178.67,"z":120.31},{"x":451.65,"y":-177.52,"z":120.31},{"x":452.11,"y":-177.03,"z":119.3},{"x":452.11,"y":-177.7,"z":118.29},{"x":451.66,"y":-178.86,"z":118.28},{"x":451.2,"y":-179.34,"z":119.3}]},{"lat":22.79,"lon":166.13,"b":[{"x":447.23,"y":-193.97,"z":111.09},{"x":447.52,"y":-193.31,"z":111.1},{"x":447.79,"y":-193.03,"z":110.51},{"x":447.77,"y":-193.41,"z":109.9},{"x":447.48,"y":-194.08,"z":109.89},{"x":447.21,"y":-194.36,"z":110.49}]},{"lat":17.78,"lon":178.86,"b":[{"x":475.74,"y":-153.38,"z":10.76},{"x":476.21,"y":-151.93,"z":10.76},{"x":476.46,"y":-151.21,"z":9.43},{"x":476.25,"y":-151.94,"z":8.11},{"x":475.79,"y":-153.4,"z":8.11},{"x":475.53,"y":-154.12,"z":9.44}]},{"lat":35.99,"lon":173.56,"b":[{"x":401.34,"y":-294.44,"z":46.92},{"x":402.36,"y":-293.03,"z":46.98},{"x":403,"y":-292.4,"z":45.44},{"x":402.59,"y":-293.19,"z":43.85},{"x":401.56,"y":-294.61,"z":43.82},{"x":400.94,"y":-295.23,"z":45.35}]},{"lat":13.94,"lon":-172.29,"b":[{"x":480.87,"y":-120.78,"z":-64.54},{"x":481.03,"y":-120.11,"z":-64.53},{"x":481.04,"y":-119.76,"z":-65.11},{"x":480.88,"y":-120.08,"z":-65.71},{"x":480.72,"y":-120.74,"z":-65.72},{"x":480.71,"y":-121.1,"z":-65.14}]},{"lat":43.96,"lon":169.01,"b":[{"x":353.08,"y":-347.2,"z":69.12},{"x":353.45,"y":-346.81,"z":69.16},{"x":353.7,"y":-346.66,"z":68.67},{"x":353.56,"y":-346.91,"z":68.14},{"x":353.18,"y":-347.3,"z":68.12},{"x":352.94,"y":-347.44,"z":68.6}]},{"lat":40.98,"lon":171.95,"b":[{"x":373.49,"y":-328.09,"z":53.41},{"x":373.89,"y":-327.63,"z":53.44},{"x":374.14,"y":-327.43,"z":52.89},{"x":373.98,"y":-327.7,"z":52.31},{"x":373.58,"y":-328.17,"z":52.29},{"x":373.33,"y":-328.36,"z":52.84}]},{"lat":37.78,"lon":174.76,"b":[{"x":392.79,"y":-307,"z":37.83},{"x":394.01,"y":-305.42,"z":37.88},{"x":394.74,"y":-304.7,"z":36.1},{"x":394.22,"y":-305.58,"z":34.27},{"x":392.99,"y":-307.16,"z":34.23},{"x":392.28,"y":-307.86,"z":36.01}]},{"lat":45.62,"lon":170.21,"b":[{"x":342.81,"y":-358.38,"z":63.09},{"x":345.66,"y":-355.59,"z":63.34},{"x":347.43,"y":-354.5,"z":59.68},{"x":346.3,"y":-356.24,"z":55.77},{"x":343.43,"y":-359.03,"z":55.58},{"x":341.71,"y":-360.09,"z":59.23}]},{"lat":44.19,"lon":171.71,"b":[{"x":353.36,"y":-349.41,"z":54.71},{"x":355.68,"y":-347.02,"z":54.88},{"x":357.1,"y":-346.04,"z":51.83},{"x":356.15,"y":-347.47,"z":48.62},{"x":353.82,"y":-349.86,"z":48.5},{"x":352.44,"y":-350.82,"z":51.53}]},{"lat":42.69,"lon":173.18,"b":[{"x":363.32,"y":-340.17,"z":47.17},{"x":365.96,"y":-337.3,"z":47.34},{"x":367.53,"y":-336.07,"z":43.78},{"x":366.43,"y":-337.73,"z":40.07},{"x":363.77,"y":-340.6,"z":39.96},{"x":362.24,"y":-341.81,"z":43.51}]},{"lat":41.14,"lon":174.61,"b":[{"x":374.44,"y":-329.31,"z":36.43},{"x":375.23,"y":-328.41,"z":36.47},{"x":375.68,"y":-328.01,"z":35.38},{"x":375.34,"y":-328.51,"z":34.27},{"x":374.56,"y":-329.41,"z":34.24},{"x":374.11,"y":-329.8,"z":35.32}]},{"lat":39.53,"lon":176.01,"b":[{"x":383.1,"y":-319.71,"z":30.76},{"x":385.9,"y":-316.32,"z":30.87},{"x":387.48,"y":-314.75,"z":26.89},{"x":386.23,"y":-316.59,"z":22.83},{"x":383.43,"y":-319.99,"z":22.77},{"x":381.88,"y":-321.53,"z":26.73}]},{"lat":37.87,"lon":177.38,"b":[{"x":394.09,"y":-307.14,"z":18.6},{"x":394.46,"y":-306.66,"z":18.61},{"x":394.66,"y":-306.43,"z":18.07},{"x":394.49,"y":-306.69,"z":17.52},{"x":394.12,"y":-307.16,"z":17.52},{"x":393.93,"y":-307.38,"z":18.06}]},{"lat":39.59,"lon":178.67,"b":[{"x":385,"y":-318.86,"z":9.52},{"x":385.4,"y":-318.38,"z":9.53},{"x":385.61,"y":-318.14,"z":8.95},{"x":385.41,"y":-318.39,"z":8.38},{"x":385.01,"y":-318.88,"z":8.38},{"x":384.81,"y":-319.11,"z":8.95}]},{"lat":3.66,"lon":143.24,"b":[{"x":400.19,"y":-30.48,"z":298.15},{"x":399.39,"y":-30.53,"z":299.22},{"x":398.91,"y":-31.93,"z":299.71},{"x":399.38,"y":-33.15,"z":298.96},{"x":400.31,"y":-32.95,"z":297.72},{"x":400.65,"y":-31.69,"z":297.4}]},{"lat":4.63,"lon":141.88,"b":[{"x":393.34,"y":-36.69,"z":306.4},{"x":391.11,"y":-36.83,"z":309.23},{"x":389.75,"y":-40.55,"z":310.48},{"x":390.98,"y":-43.77,"z":308.49},{"x":393.56,"y":-43.23,"z":305.27},{"x":394.56,"y":-39.87,"z":304.44}]},{"lat":5.63,"lon":140.48,"b":[{"x":385.23,"y":-45.34,"z":315.42},{"x":382.86,"y":-45.51,"z":318.26},{"x":381.39,"y":-49.28,"z":319.47},{"x":382.63,"y":-52.54,"z":317.46},{"x":385.34,"y":-51.99,"z":314.26},{"x":386.46,"y":-48.56,"z":313.43}]},{"lat":6.66,"lon":139.04,"b":[{"x":376.39,"y":-54.56,"z":324.5},{"x":374.15,"y":-54.74,"z":327.05},{"x":372.73,"y":-58.15,"z":328.09},{"x":373.85,"y":-61.1,"z":326.27},{"x":376.39,"y":-60.6,"z":323.43},{"x":377.5,"y":-57.47,"z":322.7}]},{"lat":12.01,"lon":131.26,"b":[{"x":322.93,"y":-103.27,"z":367.47},{"x":322.33,"y":-103.33,"z":367.99},{"x":321.92,"y":-104.06,"z":368.13},{"x":322.17,"y":-104.71,"z":367.73},{"x":322.82,"y":-104.62,"z":367.19},{"x":323.18,"y":-103.91,"z":367.07}]},{"lat":14.2,"lon":127.9,"b":[{"x":298.08,"y":-122.08,"z":382.4},{"x":297.55,"y":-122.13,"z":382.8},{"x":297.19,"y":-122.72,"z":382.89},{"x":297.4,"y":-123.25,"z":382.56},{"x":297.95,"y":-123.18,"z":382.15},{"x":298.28,"y":-122.61,"z":382.08}]},{"lat":15.3,"lon":126.17,"b":[{"x":286.76,"y":-128.36,"z":388.88},{"x":283.44,"y":-128.63,"z":391.22},{"x":281.22,"y":-132.17,"z":391.64},{"x":282.45,"y":-135.39,"z":389.65},{"x":285.89,"y":-135.04,"z":387.26},{"x":287.99,"y":-131.56,"z":386.9}]},{"lat":16.39,"lon":124.41,"b":[{"x":271.98,"y":-139.59,"z":395.61},{"x":270.54,"y":-139.7,"z":396.56},{"x":269.59,"y":-141.16,"z":396.69},{"x":270.11,"y":-142.51,"z":395.86},{"x":271.57,"y":-142.38,"z":394.9},{"x":272.49,"y":-140.93,"z":394.79}]},{"lat":17.47,"lon":122.62,"b":[{"x":258.23,"y":-148.34,"z":401.59},{"x":256.48,"y":-148.45,"z":402.67},{"x":255.33,"y":-150.17,"z":402.76},{"x":255.94,"y":-151.77,"z":401.78},{"x":257.7,"y":-151.65,"z":400.69},{"x":258.84,"y":-149.94,"z":400.6}]},{"lat":20.6,"lon":117.13,"b":[{"x":213.99,"y":-175.16,"z":416.55},{"x":213.15,"y":-175.19,"z":416.96},{"x":212.61,"y":-175.92,"z":416.93},{"x":212.88,"y":-176.64,"z":416.49},{"x":213.7,"y":-176.62,"z":416.08},{"x":214.26,"y":-175.87,"z":416.1}]},{"lat":21.59,"lon":115.27,"b":[{"x":198.84,"y":-183.54,"z":420.44},{"x":198.28,"y":-183.55,"z":420.69},{"x":197.93,"y":-184.02,"z":420.65},{"x":198.11,"y":-184.48,"z":420.37},{"x":198.64,"y":-184.48,"z":420.12},{"x":199.02,"y":-184,"z":420.15}]},{"lat":2.78,"lon":141.88,"b":[{"x":393.07,"y":-23.72,"z":308.1},{"x":393.22,"y":-24.27,"z":307.87},{"x":393.03,"y":-24.82,"z":308.07},{"x":392.69,"y":-24.84,"z":308.49},{"x":392.54,"y":-24.3,"z":308.73},{"x":392.73,"y":-23.73,"z":308.53}]},{"lat":3.76,"lon":140.48,"b":[{"x":386.17,"y":-29.07,"z":316.19},{"x":387.15,"y":-32.67,"z":314.64},{"x":385.79,"y":-36.39,"z":315.89},{"x":383.43,"y":-36.56,"z":318.73},{"x":382.42,"y":-32.94,"z":320.34},{"x":383.8,"y":-29.18,"z":319.05}]},{"lat":2.86,"lon":139.04,"b":[{"x":378.35,"y":-21.43,"z":326.09},{"x":379.38,"y":-24.87,"z":324.65},{"x":378.09,"y":-28.4,"z":325.86},{"x":375.74,"y":-28.53,"z":328.55},{"x":374.69,"y":-25.06,"z":330.04},{"x":376.01,"y":-21.5,"z":328.79}]},{"lat":4.76,"lon":139.04,"b":[{"x":377.7,"y":-37.74,"z":325.37},{"x":378.7,"y":-41.35,"z":323.76},{"x":377.23,"y":-45.12,"z":324.97},{"x":374.72,"y":-45.32,"z":327.82},{"x":373.69,"y":-41.69,"z":329.48},{"x":375.19,"y":-37.87,"z":328.24}]},{"lat":1.94,"lon":137.56,"b":[{"x":369.38,"y":-15.21,"z":336.59},{"x":369.92,"y":-16.85,"z":335.93},{"x":369.3,"y":-18.52,"z":336.52},{"x":368.14,"y":-18.56,"z":337.78},{"x":367.6,"y":-16.91,"z":338.46},{"x":368.22,"y":-15.23,"z":337.86}]},{"lat":3.87,"lon":137.56,"b":[{"x":369.6,"y":-29.88,"z":335.32},{"x":370.73,"y":-33.57,"z":333.73},{"x":369.23,"y":-37.39,"z":334.98},{"x":366.58,"y":-37.55,"z":337.86},{"x":365.43,"y":-33.84,"z":339.5},{"x":366.96,"y":-29.97,"z":338.21}]},{"lat":5.79,"lon":137.56,"b":[{"x":367.51,"y":-49.46,"z":335.37},{"x":367.77,"y":-50.37,"z":334.95},{"x":367.37,"y":-51.33,"z":335.24},{"x":366.7,"y":-51.38,"z":335.96},{"x":366.44,"y":-50.47,"z":336.39},{"x":366.84,"y":-49.5,"z":336.09}]},{"lat":0.98,"lon":136.04,"b":[{"x":360.12,"y":-7.9,"z":346.75},{"x":360.35,"y":-8.55,"z":346.5},{"x":360.1,"y":-9.2,"z":346.74},{"x":359.63,"y":-9.21,"z":347.23},{"x":359.4,"y":-8.56,"z":347.49},{"x":359.64,"y":-7.9,"z":347.25}]},{"lat":2.94,"lon":136.04,"b":[{"x":359.81,"y":-24.74,"z":346.28},{"x":360.09,"y":-25.61,"z":345.92},{"x":359.74,"y":-26.51,"z":346.22},{"x":359.09,"y":-26.54,"z":346.89},{"x":358.8,"y":-25.66,"z":347.26},{"x":359.16,"y":-24.75,"z":346.95}]},{"lat":4.89,"lon":136.04,"b":[{"x":359.3,"y":-40.96,"z":345.25},{"x":359.79,"y":-42.55,"z":344.55},{"x":359.1,"y":-44.21,"z":345.06},{"x":357.9,"y":-44.29,"z":346.29},{"x":357.39,"y":-42.69,"z":347.01},{"x":358.1,"y":-41.01,"z":346.48}]},{"lat":1.98,"lon":134.49,"b":[{"x":350.84,"y":-15.56,"z":355.86},{"x":351.44,"y":-17.28,"z":355.19},{"x":350.75,"y":-19.03,"z":355.78},{"x":349.44,"y":-19.07,"z":357.07},{"x":348.81,"y":-17.34,"z":357.76},{"x":349.52,"y":-15.58,"z":357.15}]},{"lat":3.96,"lon":134.49,"b":[{"x":350.77,"y":-31.51,"z":354.84},{"x":351.76,"y":-34.46,"z":353.59},{"x":350.48,"y":-37.5,"z":354.55},{"x":348.19,"y":-37.62,"z":356.78},{"x":347.18,"y":-34.66,"z":358.06},{"x":348.48,"y":-31.58,"z":357.08}]},{"lat":5.93,"lon":134.49,"b":[{"x":348.73,"y":-51.16,"z":354.63},{"x":348.89,"y":-51.67,"z":354.4},{"x":348.65,"y":-52.19,"z":354.55},{"x":348.26,"y":-52.22,"z":354.94},{"x":348.1,"y":-51.72,"z":355.17},{"x":348.33,"y":-51.19,"z":355.01}]},{"lat":1,"lon":132.89,"b":[{"x":341.24,"y":-6.23,"z":365.33},{"x":342.2,"y":-8.74,"z":364.39},{"x":341.18,"y":-11.27,"z":365.27},{"x":339.19,"y":-11.31,"z":367.11},{"x":338.22,"y":-8.78,"z":368.08},{"x":339.25,"y":-6.23,"z":367.18}]},{"lat":3.01,"lon":132.89,"b":[{"x":340.97,"y":-23.49,"z":364.88},{"x":341.94,"y":-26.19,"z":363.79},{"x":340.78,"y":-28.94,"z":364.67},{"x":338.62,"y":-29.02,"z":366.66},{"x":337.63,"y":-26.31,"z":367.78},{"x":338.82,"y":-23.53,"z":366.88}]},{"lat":0,"lon":131.26,"b":[{"x":330.05,"y":0.75,"z":375.57},{"x":330.35,"y":0,"z":375.31},{"x":330.05,"y":-0.75,"z":375.57},{"x":329.44,"y":-0.75,"z":376.1},{"x":329.13,"y":0,"z":376.38},{"x":329.44,"y":0.75,"z":376.1}]},{"lat":2.03,"lon":131.26,"b":[{"x":329.86,"y":-16.96,"z":375.35},{"x":330.14,"y":-17.7,"z":375.07},{"x":329.82,"y":-18.45,"z":375.31},{"x":329.21,"y":-18.47,"z":375.85},{"x":328.92,"y":-17.72,"z":376.14},{"x":329.25,"y":-16.96,"z":375.89}]},{"lat":4.05,"lon":131.26,"b":[{"x":329.15,"y":-34.85,"z":374.75},{"x":329.33,"y":-35.34,"z":374.55},{"x":329.1,"y":-35.84,"z":374.7},{"x":328.69,"y":-35.86,"z":375.05},{"x":328.51,"y":-35.37,"z":375.26},{"x":328.74,"y":-34.86,"z":375.1}]},{"lat":8.07,"lon":131.26,"b":[{"x":326.93,"y":-69.26,"z":371.88},{"x":327.22,"y":-70.13,"z":371.47},{"x":326.77,"y":-71.05,"z":371.7},{"x":326.01,"y":-71.11,"z":372.34},{"x":325.72,"y":-70.23,"z":372.77},{"x":326.18,"y":-69.3,"z":372.54}]},{"lat":3.07,"lon":129.6,"b":[{"x":319.02,"y":-25.01,"z":384.14},{"x":319.7,"y":-26.78,"z":383.45},{"x":318.89,"y":-28.58,"z":384},{"x":317.38,"y":-28.63,"z":385.25},{"x":316.67,"y":-26.85,"z":385.95},{"x":317.5,"y":-25.04,"z":385.4}]},{"lat":0,"lon":127.9,"b":[{"x":307.64,"y":1.23,"z":394.12},{"x":308.17,"y":0,"z":393.71},{"x":307.64,"y":-1.23,"z":394.12},{"x":306.56,"y":-1.24,"z":394.96},{"x":306.02,"y":0,"z":395.38},{"x":306.56,"y":1.24,"z":394.96}]},{"lat":2.07,"lon":127.9,"b":[{"x":307.16,"y":-17.52,"z":394.12},{"x":307.39,"y":-18.06,"z":393.92},{"x":307.14,"y":-18.6,"z":394.09},{"x":306.66,"y":-18.61,"z":394.46},{"x":306.43,"y":-18.07,"z":394.66},{"x":306.68,"y":-17.52,"z":394.49}]},{"lat":-9.32,"lon":126.17,"b":[{"x":291.56,"y":82.07,"z":397.78},{"x":292.19,"y":80.92,"z":397.56},{"x":291.78,"y":79.82,"z":398.08},{"x":290.73,"y":79.87,"z":398.84},{"x":290.1,"y":81.03,"z":399.07},{"x":290.52,"y":82.13,"z":398.53}]},{"lat":-7.27,"lon":126.17,"b":[{"x":294.01,"y":66.82,"z":398.78},{"x":295.93,"y":63.16,"z":397.96},{"x":294.56,"y":59.62,"z":399.52},{"x":291.24,"y":59.74,"z":401.93},{"x":289.3,"y":63.44,"z":402.76},{"x":290.7,"y":66.98,"z":401.17}]},{"lat":3.13,"lon":126.17,"b":[{"x":294.83,"y":-26.87,"z":402.92},{"x":295.01,"y":-27.3,"z":402.76},{"x":294.8,"y":-27.74,"z":402.88},{"x":294.4,"y":-27.75,"z":403.17},{"x":294.22,"y":-27.32,"z":403.33},{"x":294.43,"y":-26.88,"z":403.21}]},{"lat":9.32,"lon":126.17,"b":[{"x":292.22,"y":-78.98,"z":397.9},{"x":292.92,"y":-80.87,"z":397.01},{"x":291.84,"y":-82.84,"z":397.4},{"x":290.05,"y":-82.95,"z":398.68},{"x":289.33,"y":-81.06,"z":399.59},{"x":290.42,"y":-79.07,"z":399.2}]},{"lat":-12.44,"lon":124.41,"b":[{"x":276.21,"y":108.55,"z":402.38},{"x":276.76,"y":107.63,"z":402.25},{"x":276.43,"y":106.76,"z":402.7},{"x":275.55,"y":106.81,"z":403.29},{"x":275,"y":107.74,"z":403.42},{"x":275.33,"y":108.61,"z":402.96}]},{"lat":-10.41,"lon":124.41,"b":[{"x":278.27,"y":91.44,"z":405.2},{"x":278.9,"y":90.33,"z":405.01},{"x":278.49,"y":89.26,"z":405.52},{"x":277.44,"y":89.31,"z":406.23},{"x":276.8,"y":90.43,"z":406.42},{"x":277.22,"y":91.5,"z":405.9}]},{"lat":-8.36,"lon":124.41,"b":[{"x":279.9,"y":73.71,"z":407.68},{"x":280.45,"y":72.69,"z":407.48},{"x":280.06,"y":71.71,"z":407.92},{"x":279.11,"y":71.75,"z":408.57},{"x":278.55,"y":72.77,"z":408.77},{"x":278.95,"y":73.75,"z":408.32}]},{"lat":-6.29,"lon":124.41,"b":[{"x":281.77,"y":57.18,"z":409},{"x":283.06,"y":54.73,"z":408.45},{"x":282.08,"y":52.33,"z":409.44},{"x":279.79,"y":52.39,"z":411},{"x":278.49,"y":54.87,"z":411.56},{"x":279.49,"y":57.27,"z":410.55}]},{"lat":0,"lon":124.41,"b":[{"x":282.97,"y":0.99,"z":412.19},{"x":283.43,"y":0,"z":411.88},{"x":282.97,"y":-0.99,"z":412.19},{"x":282.05,"y":-1,"z":412.83},{"x":281.58,"y":0,"z":413.14},{"x":282.05,"y":1,"z":412.83}]},{"lat":2.11,"lon":124.41,"b":[{"x":282.54,"y":-17.92,"z":412.11},{"x":282.74,"y":-18.36,"z":411.96},{"x":282.52,"y":-18.8,"z":412.09},{"x":282.11,"y":-18.81,"z":412.37},{"x":281.92,"y":-18.37,"z":412.52},{"x":282.13,"y":-17.93,"z":412.4}]},{"lat":8.36,"lon":124.41,"b":[{"x":279.87,"y":-72.08,"z":408},{"x":280.12,"y":-72.71,"z":407.72},{"x":279.76,"y":-73.36,"z":407.84},{"x":279.15,"y":-73.39,"z":408.26},{"x":278.9,"y":-72.76,"z":408.54},{"x":279.26,"y":-72.1,"z":408.41}]},{"lat":10.41,"lon":124.41,"b":[{"x":279.15,"y":-88.06,"z":405.3},{"x":279.99,"y":-90.26,"z":404.24},{"x":278.68,"y":-92.55,"z":404.63},{"x":276.52,"y":-92.67,"z":406.08},{"x":275.66,"y":-90.48,"z":407.16},{"x":276.98,"y":-88.17,"z":406.77}]},{"lat":-13.53,"lon":122.62,"b":[{"x":262.53,"y":118.24,"z":408.74},{"x":263.38,"y":116.88,"z":408.58},{"x":262.88,"y":115.58,"z":409.27},{"x":261.52,"y":115.65,"z":410.12},{"x":260.67,"y":117.03,"z":410.27},{"x":261.18,"y":118.32,"z":409.58}]},{"lat":-11.51,"lon":122.62,"b":[{"x":264.68,"y":101.23,"z":411.9},{"x":265.62,"y":99.67,"z":411.68},{"x":265.03,"y":98.16,"z":412.42},{"x":263.49,"y":98.23,"z":413.39},{"x":262.55,"y":99.81,"z":413.61},{"x":263.15,"y":101.31,"z":412.86}]},{"lat":-9.46,"lon":122.62,"b":[{"x":266.1,"y":82.75,"z":415.13},{"x":266.45,"y":82.13,"z":415.02},{"x":266.21,"y":81.53,"z":415.3},{"x":265.61,"y":81.56,"z":415.67},{"x":265.26,"y":82.18,"z":415.78},{"x":265.51,"y":82.77,"z":415.5}]},{"lat":-7.38,"lon":122.62,"b":[{"x":268.06,"y":66.12,"z":416.81},{"x":269.13,"y":64.18,"z":416.43},{"x":268.33,"y":62.28,"z":417.22},{"x":266.46,"y":62.33,"z":418.41},{"x":265.39,"y":64.29,"z":418.8},{"x":266.2,"y":66.19,"z":417.99}]},{"lat":-1.06,"lon":122.62,"b":[{"x":269.82,"y":9.99,"z":420.81},{"x":270.18,"y":9.25,"z":420.6},{"x":269.83,"y":8.51,"z":420.83},{"x":269.13,"y":8.51,"z":421.29},{"x":268.76,"y":9.26,"z":421.5},{"x":269.11,"y":10,"z":421.26}]},{"lat":1.06,"lon":122.62,"b":[{"x":269.94,"y":-8.28,"z":420.76},{"x":270.39,"y":-9.25,"z":420.46},{"x":269.92,"y":-10.21,"z":420.73},{"x":269,"y":-10.22,"z":421.32},{"x":268.54,"y":-9.26,"z":421.64},{"x":269.02,"y":-8.28,"z":421.35}]},{"lat":3.18,"lon":122.62,"b":[{"x":269.63,"y":-26.68,"z":420.2},{"x":270.09,"y":-27.7,"z":419.84},{"x":269.56,"y":-28.75,"z":420.1},{"x":268.57,"y":-28.76,"z":420.73},{"x":268.1,"y":-27.73,"z":421.1},{"x":268.63,"y":-26.68,"z":420.83}]},{"lat":5.29,"lon":122.62,"b":[{"x":269.48,"y":-43.91,"z":418.81},{"x":270.4,"y":-46.02,"z":418},{"x":269.27,"y":-48.17,"z":418.48},{"x":267.22,"y":-48.23,"z":419.79},{"x":266.29,"y":-46.11,"z":420.62},{"x":267.43,"y":-43.95,"z":420.13}]},{"lat":-16.59,"lon":120.81,"b":[{"x":246.45,"y":145.4,"z":409.96},{"x":248.36,"y":142.57,"z":409.8},{"x":247.31,"y":139.88,"z":411.36},{"x":244.33,"y":140.03,"z":413.08},{"x":242.42,"y":142.9,"z":413.23},{"x":243.5,"y":145.57,"z":411.66}]},{"lat":-14.61,"lon":120.81,"b":[{"x":248.78,"y":128.6,"z":414.15},{"x":250.48,"y":125.97,"z":413.93},{"x":249.48,"y":123.45,"z":415.29},{"x":246.76,"y":123.58,"z":416.87},{"x":245.06,"y":126.24,"z":417.08},{"x":246.08,"y":128.74,"z":415.71}]},{"lat":-12.6,"lon":120.81,"b":[{"x":250.55,"y":110.58,"z":418.28},{"x":251.56,"y":108.95,"z":418.11},{"x":250.92,"y":107.38,"z":418.89},{"x":249.26,"y":107.45,"z":419.87},{"x":248.25,"y":109.09,"z":420.04},{"x":248.9,"y":110.66,"z":419.25}]},{"lat":0,"lon":120.81,"b":[{"x":256.68,"y":1.23,"z":429.05},{"x":257.28,"y":0,"z":428.7},{"x":256.68,"y":-1.23,"z":429.05},{"x":255.47,"y":-1.24,"z":429.77},{"x":254.87,"y":0,"z":430.13},{"x":255.47,"y":1.24,"z":429.77}]},{"lat":2.13,"lon":120.81,"b":[{"x":257.78,"y":-14.83,"z":428.09},{"x":259.54,"y":-18.58,"z":426.88},{"x":257.63,"y":-22.35,"z":427.85},{"x":253.95,"y":-22.39,"z":430.04},{"x":252.17,"y":-18.63,"z":431.27},{"x":254.09,"y":-14.84,"z":430.28}]},{"lat":4.26,"lon":120.81,"b":[{"x":256.1,"y":-35.75,"z":427.91},{"x":256.72,"y":-37.11,"z":427.42},{"x":255.99,"y":-38.5,"z":427.73},{"x":254.64,"y":-38.52,"z":428.54},{"x":254.01,"y":-37.16,"z":429.03},{"x":254.74,"y":-35.77,"z":428.71}]},{"lat":8.47,"lon":120.81,"b":[{"x":253.89,"y":-72.6,"z":424.55},{"x":254.33,"y":-73.63,"z":424.11},{"x":253.73,"y":-74.69,"z":424.29},{"x":252.68,"y":-74.73,"z":424.9},{"x":252.23,"y":-73.7,"z":425.35},{"x":252.84,"y":-72.63,"z":425.17}]},{"lat":-9.56,"lon":118.98,"b":[{"x":239.34,"y":84.11,"z":430.83},{"x":239.99,"y":83.01,"z":430.69},{"x":239.52,"y":81.94,"z":431.15},{"x":238.4,"y":81.97,"z":431.77},{"x":237.75,"y":83.07,"z":431.91},{"x":238.23,"y":84.14,"z":431.44}]},{"lat":-5.35,"lon":118.98,"b":[{"x":241.55,"y":47.35,"z":435.2},{"x":241.97,"y":46.57,"z":435.04},{"x":241.62,"y":45.8,"z":435.32},{"x":240.83,"y":45.81,"z":435.76},{"x":240.4,"y":46.59,"z":435.91},{"x":240.76,"y":47.37,"z":435.63}]},{"lat":-1.07,"lon":118.98,"b":[{"x":242.73,"y":10.44,"z":436.98},{"x":243.28,"y":9.35,"z":436.69},{"x":242.75,"y":8.26,"z":437.01},{"x":241.66,"y":8.26,"z":437.62},{"x":241.1,"y":9.36,"z":437.9},{"x":241.64,"y":10.45,"z":437.58}]},{"lat":3.21,"lon":118.98,"b":[{"x":243.01,"y":-25.81,"z":436.16},{"x":244.05,"y":-28,"z":435.44},{"x":242.89,"y":-30.22,"z":435.94},{"x":240.67,"y":-30.24,"z":437.17},{"x":239.62,"y":-28.04,"z":437.89},{"x":240.79,"y":-25.82,"z":437.38}]},{"lat":9.56,"lon":118.98,"b":[{"x":239.41,"y":-82.13,"z":431.18},{"x":239.8,"y":-83.02,"z":430.79},{"x":239.27,"y":-83.93,"z":430.91},{"x":238.34,"y":-83.96,"z":431.42},{"x":237.94,"y":-83.07,"z":431.81},{"x":238.48,"y":-82.15,"z":431.69}]},{"lat":-6.43,"lon":117.13,"b":[{"x":227.23,"y":57.4,"z":441.63},{"x":228.03,"y":55.99,"z":441.4},{"x":227.38,"y":54.59,"z":441.91},{"x":225.92,"y":54.61,"z":442.66},{"x":225.12,"y":56.03,"z":442.89},{"x":225.78,"y":57.43,"z":442.37}]},{"lat":-4.3,"lon":117.13,"b":[{"x":229.34,"y":41.62,"z":442.26},{"x":231.63,"y":37.43,"z":441.44},{"x":229.63,"y":33.25,"z":442.81},{"x":225.32,"y":33.28,"z":445.02},{"x":223.02,"y":37.5,"z":445.84},{"x":225.04,"y":41.67,"z":444.45}]},{"lat":-2.15,"lon":117.13,"b":[{"x":229.79,"y":22.74,"z":443.4},{"x":231.89,"y":18.75,"z":442.49},{"x":229.93,"y":14.78,"z":443.66},{"x":225.84,"y":14.78,"z":445.75},{"x":223.73,"y":18.79,"z":446.67},{"x":225.71,"y":22.77,"z":445.49}]},{"lat":0,"lon":117.13,"b":[{"x":230,"y":3.96,"z":443.85},{"x":232.02,"y":0,"z":442.82},{"x":230,"y":-3.96,"z":443.85},{"x":225.95,"y":-3.97,"z":445.93},{"x":223.92,"y":0,"z":446.97},{"x":225.95,"y":3.97,"z":445.93}]},{"lat":2.15,"lon":117.13,"b":[{"x":228.42,"y":-17.72,"z":444.4},{"x":228.94,"y":-18.77,"z":444.09},{"x":228.38,"y":-19.83,"z":444.33},{"x":227.3,"y":-19.83,"z":444.88},{"x":226.77,"y":-18.78,"z":445.19},{"x":227.33,"y":-17.72,"z":444.95}]},{"lat":8.55,"lon":117.13,"b":[{"x":225.99,"y":-73.47,"z":439.9},{"x":226.36,"y":-74.31,"z":439.57},{"x":225.87,"y":-75.15,"z":439.68},{"x":224.99,"y":-75.17,"z":440.12},{"x":224.61,"y":-74.34,"z":440.46},{"x":225.1,"y":-73.49,"z":440.35}]},{"lat":-3.24,"lon":115.27,"b":[{"x":215.18,"y":32.42,"z":450.07},{"x":217.48,"y":28.2,"z":449.25},{"x":215.39,"y":23.99,"z":450.5},{"x":210.98,"y":24,"z":452.58},{"x":208.67,"y":28.24,"z":453.41},{"x":210.78,"y":32.44,"z":452.15}]},{"lat":-1.08,"lon":115.27,"b":[{"x":215.55,"y":13.65,"z":450.85},{"x":217.79,"y":9.41,"z":449.89},{"x":215.62,"y":5.18,"z":451},{"x":211.21,"y":5.18,"z":453.08},{"x":208.97,"y":9.43,"z":454.05},{"x":211.14,"y":13.66,"z":452.93}]},{"lat":1.08,"lon":115.27,"b":[{"x":215.62,"y":-5.18,"z":451},{"x":217.79,"y":-9.41,"z":449.89},{"x":215.55,"y":-13.65,"z":450.85},{"x":211.14,"y":-13.66,"z":452.93},{"x":208.97,"y":-9.43,"z":454.05},{"x":211.21,"y":-5.18,"z":453.08}]},{"lat":3.24,"lon":115.27,"b":[{"x":215.39,"y":-23.99,"z":450.5},{"x":217.48,"y":-28.2,"z":449.25},{"x":215.18,"y":-32.42,"z":450.07},{"x":210.78,"y":-32.44,"z":452.15},{"x":208.67,"y":-28.24,"z":453.41},{"x":210.98,"y":-24,"z":452.58}]},{"lat":-2.16,"lon":113.4,"b":[{"x":200.41,"y":22.71,"z":457.43},{"x":202.52,"y":18.86,"z":456.68},{"x":200.53,"y":15,"z":457.69},{"x":196.44,"y":15.01,"z":459.47},{"x":194.34,"y":18.87,"z":460.22},{"x":196.33,"y":22.73,"z":459.2}]},{"lat":0,"lon":113.4,"b":[{"x":200.81,"y":4.24,"z":457.79},{"x":203.06,"y":0,"z":456.82},{"x":200.81,"y":-4.24,"z":457.79},{"x":196.32,"y":-4.25,"z":459.74},{"x":194.07,"y":0,"z":460.71},{"x":196.32,"y":4.25,"z":459.74}]},{"lat":2.16,"lon":113.4,"b":[{"x":200.74,"y":-14.62,"z":457.61},{"x":202.91,"y":-18.86,"z":456.5},{"x":200.61,"y":-23.09,"z":457.32},{"x":196.12,"y":-23.1,"z":459.26},{"x":193.93,"y":-18.87,"z":460.38},{"x":196.24,"y":-14.63,"z":459.56}]},{"lat":8.59,"lon":113.4,"b":[{"x":197.86,"y":-72.17,"z":453.42},{"x":199.05,"y":-74.66,"z":452.49},{"x":197.55,"y":-77.15,"z":452.73},{"x":194.86,"y":-77.17,"z":453.89},{"x":193.66,"y":-74.7,"z":454.82},{"x":195.15,"y":-72.19,"z":454.59}]},{"lat":-21.65,"lon":111.53,"b":[{"x":171.83,"y":187.15,"z":430.57},{"x":173.95,"y":184.41,"z":430.9},{"x":172.65,"y":181.66,"z":432.59},{"x":169.21,"y":181.67,"z":433.94},{"x":167.11,"y":184.44,"z":433.59},{"x":168.44,"y":187.16,"z":431.91}]},{"lat":-19.75,"lon":111.53,"b":[{"x":172.92,"y":169.46,"z":437.46},{"x":173.27,"y":168.99,"z":437.5},{"x":173.05,"y":168.51,"z":437.78},{"x":172.47,"y":168.51,"z":438},{"x":172.12,"y":168.99,"z":437.96},{"x":172.35,"y":169.46,"z":437.68}]},{"lat":-1.08,"lon":111.53,"b":[{"x":185.36,"y":13.08,"z":464.11},{"x":187.34,"y":9.45,"z":463.4},{"x":185.41,"y":5.8,"z":464.24},{"x":181.5,"y":5.8,"z":465.78},{"x":179.52,"y":9.45,"z":466.49},{"x":181.45,"y":13.09,"z":465.65}]},{"lat":1.08,"lon":111.53,"b":[{"x":185.74,"y":-5.2,"z":464.1},{"x":187.99,"y":-9.44,"z":463.13},{"x":185.68,"y":-13.69,"z":463.95},{"x":181.11,"y":-13.69,"z":465.75},{"x":178.86,"y":-9.45,"z":466.73},{"x":181.17,"y":-5.2,"z":465.9}]},{"lat":3.25,"lon":111.53,"b":[{"x":184.91,"y":-25.19,"z":463.8},{"x":186.52,"y":-28.3,"z":462.97},{"x":184.78,"y":-31.4,"z":463.47},{"x":181.44,"y":-31.4,"z":464.79},{"x":179.83,"y":-28.3,"z":465.61},{"x":181.56,"y":-25.19,"z":465.12}]},{"lat":7.54,"lon":111.53,"b":[{"x":183.84,"y":-62.27,"z":460.71},{"x":185.48,"y":-65.56,"z":459.6},{"x":183.52,"y":-68.85,"z":459.91},{"x":179.93,"y":-68.85,"z":461.32},{"x":178.29,"y":-65.57,"z":462.43},{"x":180.24,"y":-62.27,"z":462.13}]},{"lat":-22.58,"lon":109.65,"b":[{"x":156.92,"y":195.24,"z":432.66},{"x":159.53,"y":191.93,"z":433.18},{"x":157.88,"y":188.55,"z":435.27},{"x":153.59,"y":188.52,"z":436.81},{"x":151.01,"y":191.87,"z":436.25},{"x":152.69,"y":195.21,"z":434.19}]},{"lat":-20.7,"lon":109.65,"b":[{"x":158.1,"y":178.37,"z":439.49},{"x":159.31,"y":176.77,"z":439.7},{"x":158.52,"y":175.13,"z":440.64},{"x":156.5,"y":175.12,"z":441.37},{"x":155.29,"y":176.74,"z":441.15},{"x":156.1,"y":178.35,"z":440.21}]},{"lat":-18.79,"lon":109.65,"b":[{"x":160.75,"y":164.17,"z":444.01},{"x":163.06,"y":161.01,"z":444.32},{"x":161.5,"y":157.79,"z":446.04},{"x":157.62,"y":157.76,"z":447.44},{"x":155.33,"y":160.95,"z":447.1},{"x":156.91,"y":164.14,"z":445.39}]},{"lat":-14.82,"lon":109.65,"b":[{"x":162.83,"y":128.39,"z":454.96},{"x":163.18,"y":127.88,"z":454.98},{"x":162.92,"y":127.37,"z":455.22},{"x":162.32,"y":127.36,"z":455.43},{"x":161.98,"y":127.88,"z":455.41},{"x":162.24,"y":128.39,"z":455.17}]},{"lat":-12.78,"lon":109.65,"b":[{"x":164.68,"y":111.94,"z":458.6},{"x":165.57,"y":110.58,"z":458.61},{"x":164.9,"y":109.19,"z":459.19},{"x":163.32,"y":109.18,"z":459.75},{"x":162.43,"y":110.56,"z":459.74},{"x":163.11,"y":111.93,"z":459.17}]},{"lat":0,"lon":109.65,"b":[{"x":169.96,"y":3.34,"z":470.14},{"x":171.78,"y":0,"z":469.49},{"x":169.96,"y":-3.34,"z":470.14},{"x":166.33,"y":-3.34,"z":471.44},{"x":164.52,"y":0,"z":472.08},{"x":166.33,"y":3.34,"z":471.44}]},{"lat":8.6,"lon":109.65,"b":[{"x":166.79,"y":-73.89,"z":465.51},{"x":167.22,"y":-74.74,"z":465.22},{"x":166.71,"y":-75.58,"z":465.27},{"x":165.77,"y":-75.58,"z":465.61},{"x":165.34,"y":-74.73,"z":465.89},{"x":165.85,"y":-73.89,"z":465.85}]},{"lat":-23.47,"lon":107.78,"b":[{"x":141.74,"y":202.36,"z":434.63},{"x":144.31,"y":199.14,"z":435.26},{"x":142.63,"y":195.8,"z":437.33},{"x":138.34,"y":195.71,"z":438.74},{"x":135.79,"y":198.96,"z":438.07},{"x":137.5,"y":202.27,"z":436.03}]},{"lat":-21.62,"lon":107.78,"b":[{"x":143.56,"y":187.41,"z":440.68},{"x":145.99,"y":184.27,"z":441.21},{"x":144.37,"y":181.01,"z":443.09},{"x":140.28,"y":180.93,"z":444.43},{"x":137.88,"y":184.11,"z":443.88},{"x":139.54,"y":187.33,"z":442.01}]},{"lat":-15.81,"lon":107.78,"b":[{"x":148.31,"y":138.99,"z":456.76},{"x":150.23,"y":136.23,"z":456.96},{"x":148.82,"y":133.38,"z":458.26},{"x":145.48,"y":133.34,"z":459.34},{"x":143.59,"y":136.13,"z":459.12},{"x":145.01,"y":138.94,"z":457.83}]},{"lat":-13.79,"lon":107.78,"b":[{"x":150.23,"y":123.02,"z":460.68},{"x":152.8,"y":119.17,"z":460.84},{"x":150.84,"y":115.24,"z":462.49},{"x":146.3,"y":115.18,"z":463.96},{"x":143.76,"y":119.05,"z":463.77},{"x":145.73,"y":122.95,"z":462.14}]},{"lat":-11.73,"lon":107.78,"b":[{"x":151.5,"y":105.61,"z":464.56},{"x":154.05,"y":101.66,"z":464.6},{"x":152.02,"y":97.64,"z":466.13},{"x":147.45,"y":97.59,"z":467.61},{"x":144.93,"y":101.56,"z":467.55},{"x":146.96,"y":105.55,"z":466.03}]},{"lat":3.24,"lon":107.78,"b":[{"x":153.17,"y":-26.98,"z":475.16},{"x":153.86,"y":-28.27,"z":474.87},{"x":153.13,"y":-29.55,"z":475.02},{"x":151.71,"y":-29.54,"z":475.48},{"x":151.03,"y":-28.26,"z":475.77},{"x":151.76,"y":-26.98,"z":475.62}]},{"lat":7.53,"lon":107.78,"b":[{"x":153.31,"y":-62.23,"z":471.76},{"x":154.99,"y":-65.5,"z":470.76},{"x":153.04,"y":-68.74,"z":470.94},{"x":149.42,"y":-68.7,"z":472.11},{"x":147.73,"y":-65.45,"z":473.1},{"x":149.67,"y":-62.2,"z":472.93}]},{"lat":-24.32,"lon":105.92,"b":[{"x":126.65,"y":209.13,"z":436.08},{"x":129.18,"y":206.01,"z":436.81},{"x":127.47,"y":202.71,"z":438.86},{"x":123.19,"y":202.57,"z":440.14},{"x":120.68,"y":205.72,"z":439.37},{"x":122.43,"y":208.98,"z":437.36}]},{"lat":-22.5,"lon":105.92,"b":[{"x":128.42,"y":194.71,"z":442.19},{"x":130.97,"y":191.46,"z":442.86},{"x":129.21,"y":188.03,"z":444.84},{"x":124.87,"y":187.89,"z":446.14},{"x":122.35,"y":191.18,"z":445.44},{"x":124.14,"y":194.57,"z":443.48}]},{"lat":-20.64,"lon":105.92,"b":[{"x":130.11,"y":179.7,"z":448.01},{"x":132.67,"y":176.31,"z":448.6},{"x":130.86,"y":172.75,"z":450.52},{"x":126.46,"y":172.62,"z":451.82},{"x":123.93,"y":176.05,"z":451.2},{"x":125.77,"y":179.56,"z":449.3}]},{"lat":-18.72,"lon":105.92,"b":[{"x":130.68,"y":162.11,"z":454.54},{"x":131.82,"y":160.54,"z":454.77},{"x":130.99,"y":158.9,"z":455.58},{"x":129,"y":158.85,"z":456.17},{"x":127.87,"y":160.43,"z":455.93},{"x":128.72,"y":162.06,"z":455.12}]},{"lat":-16.77,"lon":105.92,"b":[{"x":133.18,"y":147.96,"z":458.58},{"x":135.74,"y":144.31,"z":458.99},{"x":133.82,"y":140.52,"z":460.73},{"x":129.32,"y":140.41,"z":462.05},{"x":126.79,"y":144.09,"z":461.62},{"x":128.73,"y":147.84,"z":459.89}]},{"lat":-14.77,"lon":105.92,"b":[{"x":134.54,"y":131.29,"z":463.24},{"x":137.09,"y":127.53,"z":463.54},{"x":135.11,"y":123.63,"z":465.17},{"x":130.57,"y":123.53,"z":466.49},{"x":128.05,"y":127.32,"z":466.17},{"x":130.04,"y":131.18,"z":464.55}]},{"lat":-12.73,"lon":105.92,"b":[{"x":135.75,"y":114.14,"z":467.41},{"x":138.29,"y":110.26,"z":467.59},{"x":136.25,"y":106.27,"z":469.11},{"x":131.67,"y":106.19,"z":470.44},{"x":129.16,"y":110.08,"z":470.24},{"x":131.2,"y":114.04,"z":468.73}]},{"lat":-10.66,"lon":105.92,"b":[{"x":136.81,"y":96.55,"z":471.05},{"x":139.33,"y":92.58,"z":471.1},{"x":137.24,"y":88.5,"z":472.5},{"x":132.62,"y":88.43,"z":473.83},{"x":130.13,"y":92.42,"z":473.76},{"x":132.22,"y":96.46,"z":472.37}]},{"lat":-8.57,"lon":105.92,"b":[{"x":136.34,"y":75.95,"z":474.98},{"x":137.23,"y":74.5,"z":474.96},{"x":136.46,"y":73.01,"z":475.41},{"x":134.8,"y":73,"z":475.88},{"x":133.92,"y":74.45,"z":475.91},{"x":134.69,"y":75.92,"z":475.46}]},{"lat":2.16,"lon":105.92,"b":[{"x":137.92,"y":-17.19,"z":480.26},{"x":138.8,"y":-18.82,"z":479.94},{"x":137.88,"y":-20.44,"z":480.14},{"x":136.09,"y":-20.43,"z":480.65},{"x":135.21,"y":-18.81,"z":480.97},{"x":136.12,"y":-17.19,"z":480.77}]},{"lat":4.31,"lon":105.92,"b":[{"x":138.01,"y":-35.3,"z":479.23},{"x":139.22,"y":-37.57,"z":478.7},{"x":137.91,"y":-39.81,"z":478.9},{"x":135.41,"y":-39.79,"z":479.62},{"x":134.21,"y":-37.53,"z":480.14},{"x":135.5,"y":-35.29,"z":479.94}]},{"lat":6.45,"lon":105.92,"b":[{"x":137.4,"y":-54.16,"z":477.64},{"x":138.44,"y":-56.15,"z":477.11},{"x":137.27,"y":-58.1,"z":477.22},{"x":135.07,"y":-58.08,"z":477.85},{"x":134.03,"y":-56.1,"z":478.38},{"x":135.19,"y":-54.14,"z":478.28}]},{"lat":-25.14,"lon":104.06,"b":[{"x":111.7,"y":215.55,"z":437.04},{"x":114.19,"y":212.53,"z":437.87},{"x":112.44,"y":209.28,"z":439.89},{"x":108.19,"y":209.08,"z":441.04},{"x":105.74,"y":212.13,"z":440.18},{"x":107.5,"y":215.34,"z":438.19}]},{"lat":-23.35,"lon":104.06,"b":[{"x":113.3,"y":201.45,"z":443.3},{"x":115.81,"y":198.3,"z":444.07},{"x":114.02,"y":194.91,"z":446.03},{"x":109.7,"y":194.72,"z":447.2},{"x":107.23,"y":197.91,"z":446.39},{"x":109.04,"y":201.26,"z":444.46}]},{"lat":-21.51,"lon":104.06,"b":[{"x":114.83,"y":186.76,"z":449.3},{"x":117.35,"y":183.47,"z":450},{"x":115.51,"y":179.96,"z":451.89},{"x":111.13,"y":179.78,"z":453.06},{"x":108.65,"y":183.11,"z":452.33},{"x":110.51,"y":186.57,"z":450.46}]},{"lat":-19.63,"lon":104.06,"b":[{"x":116.29,"y":171.49,"z":454.97},{"x":118.81,"y":168.06,"z":455.6},{"x":116.92,"y":164.43,"z":457.41},{"x":112.49,"y":164.26,"z":458.58},{"x":110,"y":167.72,"z":457.93},{"x":111.91,"y":171.31,"z":456.14}]},{"lat":-17.7,"lon":104.06,"b":[{"x":117.64,"y":155.65,"z":460.29},{"x":120.17,"y":152.1,"z":460.82},{"x":118.23,"y":148.34,"z":462.54},{"x":113.75,"y":148.19,"z":463.71},{"x":111.26,"y":151.78,"z":463.16},{"x":113.21,"y":155.48,"z":461.45}]},{"lat":-15.72,"lon":104.06,"b":[{"x":118.9,"y":139.28,"z":465.18},{"x":121.42,"y":135.6,"z":465.61},{"x":119.43,"y":131.74,"z":467.23},{"x":114.9,"y":131.6,"z":468.41},{"x":112.41,"y":135.31,"z":467.96},{"x":114.41,"y":139.12,"z":466.35}]},{"lat":-13.71,"lon":104.06,"b":[{"x":120.03,"y":122.4,"z":469.61},{"x":122.55,"y":118.61,"z":469.93},{"x":120.51,"y":114.65,"z":471.44},{"x":115.94,"y":114.53,"z":472.62},{"x":113.45,"y":118.35,"z":472.28},{"x":115.5,"y":122.26,"z":470.79}]},{"lat":-11.66,"lon":104.06,"b":[{"x":121.03,"y":105.07,"z":473.53},{"x":123.54,"y":101.17,"z":473.73},{"x":121.45,"y":97.13,"z":475.12},{"x":116.84,"y":97.03,"z":476.29},{"x":114.36,"y":100.95,"z":476.08},{"x":116.46,"y":104.95,"z":474.71}]},{"lat":-1.08,"lon":104.06,"b":[{"x":122.11,"y":10.59,"z":484.72},{"x":122.79,"y":9.38,"z":484.57},{"x":122.12,"y":8.17,"z":484.76},{"x":120.77,"y":8.17,"z":485.1},{"x":120.1,"y":9.38,"z":485.24},{"x":120.76,"y":10.59,"z":485.05}]},{"lat":1.08,"lon":104.06,"b":[{"x":122.47,"y":-7.53,"z":484.67},{"x":123.5,"y":-9.39,"z":484.37},{"x":122.46,"y":-11.23,"z":484.6},{"x":120.4,"y":-11.22,"z":485.11},{"x":119.39,"y":-9.38,"z":485.4},{"x":120.42,"y":-7.53,"z":485.18}]},{"lat":3.22,"lon":104.06,"b":[{"x":123.66,"y":-23.9,"z":483.79},{"x":125.95,"y":-28.13,"z":482.97},{"x":123.54,"y":-32.32,"z":483.33},{"x":118.86,"y":-32.27,"z":484.51},{"x":116.58,"y":-28.07,"z":485.33},{"x":118.97,"y":-23.88,"z":484.97}]},{"lat":5.36,"lon":104.06,"b":[{"x":122.56,"y":-43.92,"z":482.69},{"x":124.07,"y":-46.74,"z":482.04},{"x":122.43,"y":-49.52,"z":482.18},{"x":119.3,"y":-49.47,"z":482.97},{"x":117.8,"y":-46.67,"z":483.62},{"x":119.42,"y":-43.89,"z":483.48}]},{"lat":-25.91,"lon":102.22,"b":[{"x":96.94,"y":221.61,"z":437.53},{"x":99.37,"y":218.7,"z":438.44},{"x":97.6,"y":215.49,"z":440.43},{"x":93.38,"y":215.24,"z":441.47},{"x":90.99,"y":218.18,"z":440.52},{"x":92.79,"y":221.35,"z":438.57}]},{"lat":-24.15,"lon":102.22,"b":[{"x":98.36,"y":207.85,"z":443.92},{"x":100.81,"y":204.8,"z":444.78},{"x":99,"y":201.46,"z":446.72},{"x":94.71,"y":201.21,"z":447.75},{"x":92.3,"y":204.3,"z":446.86},{"x":94.14,"y":207.59,"z":444.96}]},{"lat":-22.35,"lon":102.22,"b":[{"x":99.72,"y":193.49,"z":450.06},{"x":102.19,"y":190.3,"z":450.86},{"x":100.33,"y":186.83,"z":452.73},{"x":95.98,"y":186.6,"z":453.77},{"x":93.56,"y":189.82,"z":452.93},{"x":95.44,"y":193.24,"z":451.1}]},{"lat":-20.49,"lon":102.22,"b":[{"x":101.02,"y":178.54,"z":455.91},{"x":103.5,"y":175.21,"z":456.64},{"x":101.59,"y":171.62,"z":458.43},{"x":97.19,"y":171.4,"z":459.46},{"x":94.75,"y":174.76,"z":458.71},{"x":96.67,"y":178.31,"z":456.94}]},{"lat":-18.59,"lon":102.22,"b":[{"x":102.24,"y":163.02,"z":461.41},{"x":104.73,"y":159.56,"z":462.06},{"x":102.77,"y":155.86,"z":463.76},{"x":98.32,"y":155.66,"z":464.8},{"x":95.87,"y":159.15,"z":464.13},{"x":97.84,"y":162.8,"z":462.45}]},{"lat":-16.65,"lon":102.22,"b":[{"x":103.37,"y":146.96,"z":466.53},{"x":105.87,"y":143.37,"z":467.08},{"x":103.86,"y":139.56,"z":468.68},{"x":99.36,"y":139.38,"z":469.71},{"x":96.91,"y":142.99,"z":469.14},{"x":98.92,"y":146.76,"z":467.56}]},{"lat":-14.66,"lon":102.22,"b":[{"x":104.41,"y":130.39,"z":471.2},{"x":106.9,"y":126.68,"z":471.65},{"x":104.85,"y":122.77,"z":473.14},{"x":100.3,"y":122.6,"z":474.17},{"x":97.85,"y":126.33,"z":473.7},{"x":99.9,"y":130.2,"z":472.22}]},{"lat":-12.64,"lon":102.22,"b":[{"x":105.09,"y":112.88,"z":475.55},{"x":107.29,"y":109.5,"z":475.84},{"x":105.44,"y":105.97,"z":477.06},{"x":101.38,"y":105.84,"z":477.96},{"x":99.22,"y":109.24,"z":477.66},{"x":101.07,"y":112.74,"z":476.45}]},{"lat":-6.4,"lon":102.22,"b":[{"x":105.57,"y":56.47,"z":485.44},{"x":106.02,"y":55.72,"z":485.42},{"x":105.61,"y":54.95,"z":485.6},{"x":104.74,"y":54.93,"z":485.79},{"x":104.3,"y":55.69,"z":485.8},{"x":104.71,"y":56.46,"z":485.62}]},{"lat":-4.27,"lon":102.22,"b":[{"x":107.78,"y":41.45,"z":486.4},{"x":110.2,"y":37.31,"z":486.19},{"x":107.92,"y":33.1,"z":487.01},{"x":103.24,"y":33.06,"z":488.03},{"x":100.85,"y":37.2,"z":488.23},{"x":103.12,"y":41.38,"z":487.42}]},{"lat":-2.14,"lon":102.22,"b":[{"x":107.27,"y":21.46,"z":487.83},{"x":108.85,"y":18.69,"z":487.59},{"x":107.31,"y":15.9,"z":488.03},{"x":104.21,"y":15.89,"z":488.7},{"x":102.64,"y":18.65,"z":488.94},{"x":104.17,"y":21.43,"z":488.5}]},{"lat":0,"lon":102.22,"b":[{"x":107.96,"y":3.87,"z":488.11},{"x":110.13,"y":0,"z":487.64},{"x":107.96,"y":-3.87,"z":488.11},{"x":103.65,"y":-3.86,"z":489.05},{"x":101.51,"y":0,"z":489.51},{"x":103.65,"y":3.86,"z":489.05}]},{"lat":2.14,"lon":102.22,"b":[{"x":108.11,"y":-14.48,"z":487.87},{"x":110.43,"y":-18.69,"z":487.21},{"x":108.04,"y":-22.88,"z":487.57},{"x":103.36,"y":-22.84,"z":488.59},{"x":101.06,"y":-18.64,"z":489.24},{"x":103.42,"y":-14.46,"z":488.89}]},{"lat":4.27,"lon":102.22,"b":[{"x":106.23,"y":-36.04,"z":487.22},{"x":106.9,"y":-37.28,"z":486.98},{"x":106.19,"y":-38.5,"z":487.05},{"x":104.81,"y":-38.48,"z":487.35},{"x":104.15,"y":-37.25,"z":487.58},{"x":104.85,"y":-36.03,"z":487.52}]},{"lat":-26.65,"lon":100.39,"b":[{"x":82.42,"y":227.33,"z":437.58},{"x":84.78,"y":224.52,"z":438.57},{"x":82.99,"y":221.35,"z":440.52},{"x":78.82,"y":221.04,"z":441.44},{"x":76.5,"y":223.89,"z":440.41},{"x":78.31,"y":227.01,"z":438.5}]},{"lat":-24.92,"lon":100.39,"b":[{"x":83.64,"y":213.89,"z":444.07},{"x":86.03,"y":210.94,"z":445.02},{"x":84.2,"y":207.65,"z":446.92},{"x":79.96,"y":207.35,"z":447.83},{"x":77.62,"y":210.33,"z":446.85},{"x":79.47,"y":213.58,"z":444.99}]},{"lat":-23.14,"lon":100.39,"b":[{"x":84.82,"y":199.86,"z":450.33},{"x":87.23,"y":196.77,"z":451.23},{"x":85.35,"y":193.35,"z":453.06},{"x":81.06,"y":193.07,"z":453.97},{"x":78.69,"y":196.19,"z":453.05},{"x":80.58,"y":199.56,"z":451.25}]},{"lat":-21.32,"lon":100.39,"b":[{"x":85.95,"y":185.25,"z":456.32},{"x":88.38,"y":182.02,"z":457.16},{"x":86.46,"y":178.48,"z":458.92},{"x":82.1,"y":178.21,"z":459.82},{"x":79.72,"y":181.47,"z":458.96},{"x":81.65,"y":184.96,"z":457.23}]},{"lat":-19.45,"lon":100.39,"b":[{"x":87.02,"y":170.06,"z":462},{"x":89.46,"y":166.7,"z":462.75},{"x":87.49,"y":163.04,"z":464.43},{"x":83.08,"y":162.79,"z":465.33},{"x":80.69,"y":166.18,"z":464.55},{"x":82.66,"y":169.79,"z":462.9}]},{"lat":-17.53,"lon":100.39,"b":[{"x":88.02,"y":154.33,"z":467.3},{"x":90.47,"y":150.84,"z":467.97},{"x":88.46,"y":147.07,"z":469.55},{"x":84,"y":146.84,"z":470.44},{"x":81.6,"y":150.36,"z":469.75},{"x":83.61,"y":154.08,"z":468.19}]},{"lat":-15.58,"lon":100.39,"b":[{"x":88.94,"y":138.07,"z":472.18},{"x":91.39,"y":134.45,"z":472.76},{"x":89.34,"y":130.58,"z":474.23},{"x":84.83,"y":130.38,"z":475.11},{"x":82.43,"y":134.02,"z":474.53},{"x":84.48,"y":137.84,"z":473.07}]},{"lat":-13.58,"lon":100.39,"b":[{"x":89.76,"y":121.29,"z":476.61},{"x":92.19,"y":117.59,"z":477.08},{"x":90.11,"y":113.66,"z":478.42},{"x":85.6,"y":113.48,"z":479.29},{"x":83.21,"y":117.2,"z":478.82},{"x":85.29,"y":121.08,"z":477.49}]},{"lat":-11.55,"lon":100.39,"b":[{"x":88.87,"y":101.05,"z":481.53},{"x":89.43,"y":100.18,"z":481.61},{"x":88.94,"y":99.26,"z":481.89},{"x":87.9,"y":99.22,"z":482.09},{"x":87.35,"y":100.1,"z":482.01},{"x":87.83,"y":101.01,"z":481.73}]},{"lat":-7.41,"lon":100.39,"b":[{"x":90.72,"y":66.86,"z":487.08},{"x":92.11,"y":64.56,"z":487.13},{"x":90.84,"y":62.19,"z":487.68},{"x":88.19,"y":62.13,"z":488.17},{"x":86.82,"y":64.43,"z":488.12},{"x":88.08,"y":66.78,"z":487.58}]},{"lat":-5.31,"lon":100.39,"b":[{"x":90.73,"y":47.93,"z":489.32},{"x":91.7,"y":46.29,"z":489.3},{"x":90.79,"y":44.61,"z":489.62},{"x":88.92,"y":44.58,"z":489.97},{"x":87.96,"y":46.23,"z":489.99},{"x":88.87,"y":47.9,"z":489.67}]},{"lat":-1.06,"lon":100.39,"b":[{"x":92.47,"y":13.4,"z":491.11},{"x":94.79,"y":9.3,"z":490.76},{"x":92.5,"y":5.19,"z":491.26},{"x":87.92,"y":5.19,"z":492.1},{"x":85.63,"y":9.27,"z":492.45},{"x":87.89,"y":13.37,"z":491.95}]},{"lat":1.06,"lon":100.39,"b":[{"x":91.48,"y":-7.01,"z":491.46},{"x":92.75,"y":-9.3,"z":491.18},{"x":91.46,"y":-11.58,"z":491.38},{"x":88.92,"y":-11.56,"z":491.85},{"x":87.66,"y":-9.28,"z":492.12},{"x":88.93,"y":-7.01,"z":491.93}]},{"lat":-27.34,"lon":98.59,"b":[{"x":68.16,"y":232.69,"z":437.21},{"x":70.46,"y":229.98,"z":438.28},{"x":68.65,"y":226.86,"z":440.19},{"x":64.53,"y":226.5,"z":441},{"x":62.28,"y":229.24,"z":439.9},{"x":64.11,"y":232.32,"z":438.03}]},{"lat":-25.65,"lon":98.59,"b":[{"x":69.19,"y":219.58,"z":443.78},{"x":71.51,"y":216.74,"z":444.81},{"x":69.66,"y":213.49,"z":446.67},{"x":65.47,"y":213.14,"z":447.47},{"x":63.21,"y":216.02,"z":446.41},{"x":65.07,"y":219.22,"z":444.59}]},{"lat":-23.9,"lon":98.59,"b":[{"x":70.18,"y":205.89,"z":450.14},{"x":72.52,"y":202.9,"z":451.12},{"x":70.63,"y":199.53,"z":452.92},{"x":66.39,"y":199.19,"z":453.71},{"x":64.1,"y":202.21,"z":452.7},{"x":66,"y":205.54,"z":450.94}]},{"lat":-22.11,"lon":98.59,"b":[{"x":71.13,"y":191.61,"z":456.25},{"x":73.5,"y":188.49,"z":457.17},{"x":71.56,"y":185,"z":458.9},{"x":67.26,"y":184.68,"z":459.68},{"x":64.95,"y":187.83,"z":458.74},{"x":66.89,"y":191.27,"z":457.04}]},{"lat":-20.27,"lon":98.59,"b":[{"x":72.04,"y":176.77,"z":462.06},{"x":74.42,"y":173.51,"z":462.92},{"x":72.45,"y":169.9,"z":464.57},{"x":68.09,"y":169.6,"z":465.33},{"x":65.76,"y":172.88,"z":464.46},{"x":67.74,"y":176.44,"z":462.84}]},{"lat":-18.39,"lon":98.59,"b":[{"x":72.89,"y":161.36,"z":467.53},{"x":75.29,"y":157.97,"z":468.3},{"x":73.27,"y":154.25,"z":469.86},{"x":68.86,"y":153.98,"z":470.62},{"x":66.52,"y":157.39,"z":469.83},{"x":68.54,"y":161.06,"z":468.29}]},{"lat":-16.46,"lon":98.59,"b":[{"x":73.69,"y":145.43,"z":472.6},{"x":76.09,"y":141.92,"z":473.29},{"x":74.03,"y":138.09,"z":474.74},{"x":69.58,"y":137.84,"z":475.49},{"x":67.23,"y":141.38,"z":474.79},{"x":69.28,"y":145.15,"z":473.36}]},{"lat":-14.5,"lon":98.59,"b":[{"x":74.32,"y":128.85,"z":477.29},{"x":76.64,"y":125.36,"z":477.85},{"x":74.62,"y":121.6,"z":479.14},{"x":70.31,"y":121.38,"z":479.85},{"x":68.05,"y":124.9,"z":479.27},{"x":70.05,"y":128.61,"z":478}]},{"lat":-12.5,"lon":98.59,"b":[{"x":73.81,"y":109.8,"z":482.14},{"x":74.8,"y":108.26,"z":482.34},{"x":73.92,"y":106.61,"z":482.84},{"x":72.05,"y":106.53,"z":483.14},{"x":71.08,"y":108.08,"z":482.94},{"x":71.96,"y":109.71,"z":482.44}]},{"lat":-10.46,"lon":98.59,"b":[{"x":74.19,"y":92.16,"z":485.77},{"x":75.01,"y":90.86,"z":485.89},{"x":74.27,"y":89.48,"z":486.26},{"x":72.72,"y":89.42,"z":486.5},{"x":71.92,"y":90.73,"z":486.38},{"x":72.65,"y":92.1,"z":486.01}]},{"lat":-8.4,"lon":98.59,"b":[{"x":75.34,"y":75.74,"z":488.4},{"x":76.9,"y":73.16,"z":488.55},{"x":75.46,"y":70.47,"z":489.17},{"x":72.46,"y":70.39,"z":489.63},{"x":70.92,"y":72.97,"z":489.48},{"x":72.35,"y":75.63,"z":488.87}]},{"lat":-4.22,"lon":98.59,"b":[{"x":75.04,"y":37.83,"z":492.86},{"x":75.62,"y":36.85,"z":492.85},{"x":75.07,"y":35.85,"z":493.01},{"x":73.95,"y":35.83,"z":493.18},{"x":73.39,"y":36.81,"z":493.19},{"x":73.93,"y":37.81,"z":493.03}]},{"lat":-2.12,"lon":98.59,"b":[{"x":76.78,"y":22.32,"z":493.49},{"x":78.97,"y":18.49,"z":493.3},{"x":76.83,"y":14.61,"z":493.77},{"x":72.52,"y":14.59,"z":494.42},{"x":70.37,"y":18.42,"z":494.61},{"x":72.48,"y":22.27,"z":494.14}]},{"lat":2.12,"lon":98.59,"b":[{"x":75.05,"y":-17.75,"z":494},{"x":75.44,"y":-18.46,"z":493.91},{"x":75.04,"y":-19.16,"z":493.95},{"x":74.25,"y":-19.15,"z":494.07},{"x":73.87,"y":-18.45,"z":494.15},{"x":74.26,"y":-17.75,"z":494.12}]},{"lat":-28,"lon":96.81,"b":[{"x":54.21,"y":237.71,"z":436.46},{"x":56.42,"y":235.1,"z":437.59},{"x":54.6,"y":232.03,"z":439.47},{"x":50.54,"y":231.61,"z":440.17},{"x":48.38,"y":234.26,"z":439.01},{"x":50.22,"y":237.28,"z":437.18}]},{"lat":-26.34,"lon":96.81,"b":[{"x":55.03,"y":224.93,"z":443.08},{"x":57.27,"y":222.18,"z":444.18},{"x":55.41,"y":218.98,"z":446.01},{"x":51.29,"y":218.58,"z":446.69},{"x":49.1,"y":221.36,"z":445.57},{"x":50.98,"y":224.51,"z":443.79}]},{"lat":-24.62,"lon":96.81,"b":[{"x":55.83,"y":211.57,"z":449.52},{"x":58.1,"y":208.69,"z":450.57},{"x":56.2,"y":205.36,"z":452.34},{"x":52.02,"y":204.97,"z":453.01},{"x":49.81,"y":207.89,"z":451.93},{"x":51.71,"y":211.16,"z":450.2}]},{"lat":-22.86,"lon":96.81,"b":[{"x":56.6,"y":197.63,"z":455.72},{"x":58.89,"y":194.61,"z":456.72},{"x":56.95,"y":191.17,"z":458.42},{"x":52.72,"y":190.8,"z":459.08},{"x":50.48,"y":193.85,"z":458.06},{"x":52.42,"y":197.24,"z":456.39}]},{"lat":-21.06,"lon":96.81,"b":[{"x":57.34,"y":183.13,"z":461.64},{"x":59.65,"y":179.97,"z":462.59},{"x":57.67,"y":176.41,"z":464.21},{"x":53.38,"y":176.06,"z":464.85},{"x":51.13,"y":179.25,"z":463.89},{"x":53.1,"y":182.75,"z":462.3}]},{"lat":-19.21,"lon":96.81,"b":[{"x":58.04,"y":168.07,"z":467.25},{"x":60.36,"y":164.78,"z":468.12},{"x":58.35,"y":161.11,"z":469.65},{"x":54.01,"y":160.78,"z":470.28},{"x":51.73,"y":164.1,"z":469.39},{"x":53.75,"y":167.72,"z":467.89}]},{"lat":-17.31,"lon":96.81,"b":[{"x":58.67,"y":152.44,"z":472.5},{"x":60.99,"y":149.05,"z":473.28},{"x":58.96,"y":145.31,"z":474.7},{"x":54.6,"y":145.02,"z":475.31},{"x":52.33,"y":148.43,"z":474.51},{"x":54.36,"y":152.12,"z":473.12}]},{"lat":-5.24,"lon":96.81,"b":[{"x":59.8,"y":46.97,"z":494.15},{"x":60.56,"y":45.67,"z":494.18},{"x":59.83,"y":44.34,"z":494.39},{"x":58.36,"y":44.31,"z":494.57},{"x":57.62,"y":45.61,"z":494.54},{"x":58.34,"y":46.93,"z":494.33}]},{"lat":-3.15,"lon":96.81,"b":[{"x":60.13,"y":29.09,"z":495.48},{"x":61.05,"y":27.48,"z":495.46},{"x":60.15,"y":25.85,"z":495.66},{"x":58.35,"y":25.83,"z":495.88},{"x":57.45,"y":27.43,"z":495.9},{"x":58.33,"y":29.05,"z":495.7}]},{"lat":-28.61,"lon":95.06,"b":[{"x":40.58,"y":242.4,"z":435.37},{"x":42.72,"y":239.89,"z":436.55},{"x":40.88,"y":236.86,"z":438.38},{"x":36.9,"y":236.39,"z":438.98},{"x":34.82,"y":238.93,"z":437.77},{"x":36.66,"y":241.92,"z":435.99}]},{"lat":-26.98,"lon":95.06,"b":[{"x":41.2,"y":229.93,"z":442.02},{"x":43.36,"y":227.29,"z":443.17},{"x":41.49,"y":224.14,"z":444.96},{"x":37.45,"y":223.68,"z":445.54},{"x":35.34,"y":226.36,"z":444.36},{"x":37.22,"y":229.46,"z":442.62}]},{"lat":-25.3,"lon":95.06,"b":[{"x":41.81,"y":216.9,"z":448.5},{"x":44,"y":214.12,"z":449.62},{"x":42.09,"y":210.85,"z":451.35},{"x":37.99,"y":210.41,"z":451.92},{"x":35.85,"y":213.22,"z":450.77},{"x":37.76,"y":216.45,"z":449.08}]},{"lat":-23.58,"lon":95.06,"b":[{"x":42.39,"y":203.31,"z":454.77},{"x":44.61,"y":200.39,"z":455.85},{"x":42.66,"y":197,"z":457.51},{"x":38.5,"y":196.57,"z":458.06},{"x":36.34,"y":199.52,"z":456.96},{"x":38.29,"y":202.86,"z":455.33}]},{"lat":-21.8,"lon":95.06,"b":[{"x":42.95,"y":189.14,"z":460.78},{"x":45.19,"y":186.09,"z":461.81},{"x":43.21,"y":182.59,"z":463.4},{"x":39,"y":182.18,"z":463.93},{"x":36.82,"y":185.27,"z":462.88},{"x":38.79,"y":188.72,"z":461.33}]},{"lat":-19.99,"lon":95.06,"b":[{"x":43.49,"y":174.43,"z":466.5},{"x":45.74,"y":171.24,"z":467.46},{"x":43.73,"y":167.63,"z":468.96},{"x":39.46,"y":167.25,"z":469.47},{"x":37.26,"y":170.47,"z":468.5},{"x":39.27,"y":174.03,"z":467.03}]},{"lat":-18.12,"lon":95.06,"b":[{"x":43.93,"y":159.09,"z":471.91},{"x":46.15,"y":155.86,"z":472.77},{"x":44.15,"y":152.24,"z":474.14},{"x":39.95,"y":151.9,"z":474.62},{"x":37.79,"y":155.15,"z":473.75},{"x":39.78,"y":158.72,"z":472.4}]},{"lat":-16.22,"lon":95.06,"b":[{"x":44.32,"y":143.19,"z":476.94},{"x":46.47,"y":139.96,"z":477.69},{"x":44.52,"y":136.39,"z":478.91},{"x":40.43,"y":136.09,"z":479.35},{"x":38.34,"y":139.34,"z":478.59},{"x":40.28,"y":142.87,"z":477.4}]},{"lat":-29.19,"lon":93.34,"b":[{"x":27.3,"y":246.76,"z":433.95},{"x":29.35,"y":244.34,"z":435.18},{"x":27.51,"y":241.36,"z":436.97},{"x":23.6,"y":240.84,"z":437.48},{"x":21.61,"y":243.29,"z":436.23},{"x":23.46,"y":246.23,"z":434.48}]},{"lat":-27.59,"lon":93.34,"b":[{"x":27.72,"y":234.61,"z":440.61},{"x":29.8,"y":232.06,"z":441.82},{"x":27.92,"y":228.96,"z":443.56},{"x":23.96,"y":228.45,"z":444.05},{"x":21.94,"y":231.04,"z":442.82},{"x":23.82,"y":234.09,"z":441.12}]},{"lat":-25.95,"lon":93.34,"b":[{"x":28.13,"y":221.91,"z":447.12},{"x":30.24,"y":219.22,"z":448.3},{"x":28.33,"y":216,"z":449.99},{"x":24.31,"y":215.51,"z":450.45},{"x":22.26,"y":218.23,"z":449.25},{"x":24.17,"y":221.4,"z":447.6}]},{"lat":-24.25,"lon":93.34,"b":[{"x":28.53,"y":208.64,"z":453.43},{"x":30.66,"y":205.83,"z":454.57},{"x":28.72,"y":202.49,"z":456.2},{"x":24.64,"y":202.02,"z":456.65},{"x":22.57,"y":204.86,"z":455.48},{"x":24.51,"y":208.15,"z":453.9}]},{"lat":-22.51,"lon":93.34,"b":[{"x":28.91,"y":194.82,"z":459.51},{"x":31.07,"y":191.87,"z":460.61},{"x":29.09,"y":188.42,"z":462.16},{"x":24.96,"y":187.97,"z":462.58},{"x":22.86,"y":190.95,"z":461.47},{"x":24.83,"y":194.35,"z":459.95}]},{"lat":-20.73,"lon":93.34,"b":[{"x":29.28,"y":180.46,"z":465.31},{"x":31.46,"y":177.37,"z":466.36},{"x":29.45,"y":173.81,"z":467.83},{"x":25.27,"y":173.39,"z":468.23},{"x":23.15,"y":176.5,"z":467.18},{"x":25.15,"y":180.01,"z":465.73}]},{"lat":-18.9,"lon":93.34,"b":[{"x":27.84,"y":162.42,"z":472.05},{"x":28.12,"y":162.02,"z":472.18},{"x":27.86,"y":161.56,"z":472.35},{"x":27.33,"y":161.51,"z":472.4},{"x":27.06,"y":161.92,"z":472.27},{"x":27.32,"y":162.37,"z":472.1}]},{"lat":-29.73,"lon":91.65,"b":[{"x":14.39,"y":250.8,"z":432.25},{"x":16.35,"y":248.48,"z":433.52},{"x":14.5,"y":245.54,"z":435.26},{"x":10.69,"y":244.97,"z":435.69},{"x":8.78,"y":247.34,"z":434.4},{"x":10.63,"y":250.23,"z":432.7}]},{"lat":-28.16,"lon":91.65,"b":[{"x":14.61,"y":238.96,"z":438.9},{"x":16.6,"y":236.51,"z":440.15},{"x":14.72,"y":233.46,"z":441.85},{"x":10.85,"y":232.9,"z":442.25},{"x":8.91,"y":235.39,"z":440.98},{"x":10.79,"y":238.4,"z":439.32}]},{"lat":-26.55,"lon":91.65,"b":[{"x":14.83,"y":226.58,"z":445.41},{"x":16.85,"y":224,"z":446.64},{"x":14.94,"y":220.82,"z":448.29},{"x":11,"y":220.29,"z":448.66},{"x":9.04,"y":222.9,"z":447.42},{"x":10.95,"y":226.03,"z":445.81}]},{"lat":-24.89,"lon":91.65,"b":[{"x":15.04,"y":213.65,"z":451.75},{"x":17.09,"y":210.93,"z":452.95},{"x":15.15,"y":207.65,"z":454.54},{"x":11.16,"y":207.13,"z":454.88},{"x":9.17,"y":209.88,"z":453.67},{"x":11.1,"y":213.11,"z":452.12}]},{"lat":-23.19,"lon":91.65,"b":[{"x":15.24,"y":200.17,"z":457.87},{"x":17.32,"y":197.32,"z":459.03},{"x":15.35,"y":193.92,"z":460.55},{"x":11.31,"y":193.43,"z":460.87},{"x":9.29,"y":196.31,"z":459.7},{"x":11.25,"y":199.65,"z":458.22}]},{"lat":-21.44,"lon":91.65,"b":[{"x":14.01,"y":183.71,"z":464.8},{"x":14.61,"y":182.85,"z":465.11},{"x":14.04,"y":181.85,"z":465.53},{"x":12.87,"y":181.71,"z":465.61},{"x":12.28,"y":182.57,"z":465.29},{"x":12.85,"y":183.56,"z":464.89}]},{"lat":4.23,"lon":144.98,"b":[{"x":407.82,"y":-35.91,"z":287.01},{"x":408.62,"y":-35.73,"z":285.89},{"x":409.12,"y":-36.68,"z":285.04},{"x":408.83,"y":-37.83,"z":285.32},{"x":408.02,"y":-38.02,"z":286.45},{"x":407.51,"y":-37.05,"z":287.3}]},{"lat":5.22,"lon":143.64,"b":[{"x":399.46,"y":-42.67,"z":297.59},{"x":401.9,"y":-42.14,"z":294.37},{"x":403.36,"y":-44.94,"z":291.93},{"x":402.4,"y":-48.33,"z":292.72},{"x":399.94,"y":-48.89,"z":295.99},{"x":398.46,"y":-46.03,"z":298.42}]},{"lat":5.8,"lon":145.41,"b":[{"x":408.05,"y":-47.72,"z":284.89},{"x":410.39,"y":-47.17,"z":281.62},{"x":411.78,"y":-49.97,"z":279.09},{"x":410.85,"y":-53.38,"z":279.82},{"x":408.5,"y":-53.97,"z":283.14},{"x":407.09,"y":-51.11,"z":285.68}]},{"lat":6.38,"lon":147.18,"b":[{"x":416.64,"y":-53.55,"z":271.12},{"x":418.2,"y":-53.15,"z":268.78},{"x":419.13,"y":-55.13,"z":266.93},{"x":418.5,"y":-57.55,"z":267.41},{"x":416.92,"y":-57.98,"z":269.77},{"x":415.98,"y":-55.96,"z":271.63}]},{"lat":6.23,"lon":142.26,"b":[{"x":391.54,"y":-51.42,"z":306.6},{"x":394.11,"y":-50.88,"z":303.38},{"x":395.59,"y":-53.74,"z":300.95},{"x":394.5,"y":-57.2,"z":301.73},{"x":391.9,"y":-57.77,"z":304.99},{"x":390.41,"y":-54.85,"z":307.43}]},{"lat":6.83,"lon":144.06,"b":[{"x":400.45,"y":-56.58,"z":293.91},{"x":402.92,"y":-56.01,"z":290.63},{"x":404.33,"y":-58.88,"z":288.09},{"x":403.28,"y":-62.36,"z":288.82},{"x":400.79,"y":-62.96,"z":292.14},{"x":399.37,"y":-60.04,"z":294.69}]},{"lat":7.42,"lon":145.86,"b":[{"x":408.97,"y":-61.69,"z":280.87},{"x":411.32,"y":-61.1,"z":277.55},{"x":412.65,"y":-63.96,"z":274.91},{"x":411.63,"y":-67.47,"z":275.58},{"x":409.26,"y":-68.1,"z":278.95},{"x":407.92,"y":-65.18,"z":281.6}]},{"lat":8,"lon":147.66,"b":[{"x":417.48,"y":-67.68,"z":266.63},{"x":418.97,"y":-67.27,"z":264.38},{"x":419.8,"y":-69.18,"z":262.56},{"x":419.15,"y":-71.54,"z":262.97},{"x":417.64,"y":-71.98,"z":265.25},{"x":416.8,"y":-70.03,"z":267.08}]},{"lat":7.27,"lon":140.84,"b":[{"x":383.05,"y":-60.34,"z":315.56},{"x":385.75,"y":-59.8,"z":312.36},{"x":387.24,"y":-62.72,"z":309.93},{"x":386.03,"y":-66.25,"z":310.7},{"x":383.3,"y":-66.83,"z":313.95},{"x":381.8,"y":-63.85,"z":316.38}]},{"lat":7.88,"lon":142.66,"b":[{"x":392.3,"y":-65.65,"z":302.88},{"x":394.88,"y":-65.08,"z":299.64},{"x":396.28,"y":-67.98,"z":297.12},{"x":395.12,"y":-71.51,"z":297.83},{"x":392.52,"y":-72.11,"z":301.12},{"x":391.1,"y":-69.15,"z":303.64}]},{"lat":8.49,"lon":144.49,"b":[{"x":402.28,"y":-73.26,"z":287.73},{"x":402.73,"y":-73.15,"z":287.13},{"x":402.97,"y":-73.67,"z":286.66},{"x":402.77,"y":-74.32,"z":286.78},{"x":402.32,"y":-74.43,"z":287.38},{"x":402.07,"y":-73.9,"z":287.86}]},{"lat":9.08,"lon":146.32,"b":[{"x":410.67,"y":-78.49,"z":274.19},{"x":411.03,"y":-78.39,"z":273.68},{"x":411.22,"y":-78.84,"z":273.26},{"x":411.05,"y":-79.38,"z":273.35},{"x":410.69,"y":-79.49,"z":273.87},{"x":410.49,"y":-79.03,"z":274.29}]},{"lat":9.67,"lon":148.16,"b":[{"x":417.57,"y":-81.23,"z":262.65},{"x":419.7,"y":-80.61,"z":259.43},{"x":420.8,"y":-83.35,"z":256.76},{"x":419.78,"y":-86.78,"z":257.28},{"x":417.64,"y":-87.44,"z":260.53},{"x":416.52,"y":-84.64,"z":263.23}]},{"lat":10.25,"lon":150,"b":[{"x":425.6,"y":-87.62,"z":247.31},{"x":426.57,"y":-87.3,"z":245.75},{"x":427.05,"y":-88.62,"z":244.42},{"x":426.58,"y":-90.27,"z":244.65},{"x":425.6,"y":-90.61,"z":246.22},{"x":425.11,"y":-89.27,"z":247.56}]},{"lat":8.33,"lon":139.38,"b":[{"x":374.57,"y":-70.58,"z":323.54},{"x":376.32,"y":-70.23,"z":321.58},{"x":377.25,"y":-72.08,"z":320.08},{"x":376.42,"y":-74.3,"z":320.54},{"x":374.65,"y":-74.66,"z":322.53},{"x":373.72,"y":-72.78,"z":324.03}]},{"lat":8.96,"lon":141.22,"b":[{"x":383.76,"y":-75.29,"z":311.46},{"x":386.08,"y":-74.8,"z":308.7},{"x":387.3,"y":-77.34,"z":306.54},{"x":386.19,"y":-80.42,"z":307.14},{"x":383.84,"y":-80.94,"z":309.94},{"x":382.62,"y":-78.35,"z":312.1}]},{"lat":9.58,"lon":143.07,"b":[{"x":393.42,"y":-81.71,"z":297.5},{"x":394.72,"y":-81.41,"z":295.87},{"x":395.38,"y":-82.88,"z":294.57},{"x":394.76,"y":-84.68,"z":294.89},{"x":393.45,"y":-84.99,"z":296.54},{"x":392.78,"y":-83.5,"z":297.85}]},{"lat":12.47,"lon":142.02,"b":[{"x":384.07,"y":-106.3,"z":301.91},{"x":385.57,"y":-105.95,"z":300.12},{"x":386.26,"y":-107.61,"z":298.64},{"x":385.45,"y":-109.65,"z":298.94},{"x":383.94,"y":-110.01,"z":300.75},{"x":383.25,"y":-108.32,"z":302.24}]},{"lat":13.11,"lon":143.94,"b":[{"x":393.41,"y":-112.69,"z":287.25},{"x":394,"y":-112.54,"z":286.49},{"x":394.27,"y":-113.23,"z":285.85},{"x":393.94,"y":-114.08,"z":285.96},{"x":393.34,"y":-114.24,"z":286.73},{"x":393.07,"y":-113.54,"z":287.38}]},{"lat":14.3,"lon":142.44,"b":[{"x":382.8,"y":-120.3,"z":298.2},{"x":385.63,"y":-119.63,"z":294.82},{"x":386.84,"y":-122.76,"z":291.93},{"x":385.22,"y":-126.63,"z":292.41},{"x":382.37,"y":-127.35,"z":295.82},{"x":381.16,"y":-124.15,"z":298.72}]},{"lat":14.94,"lon":144.41,"b":[{"x":392.15,"y":-127.06,"z":282.89},{"x":393.72,"y":-126.64,"z":280.9},{"x":394.37,"y":-128.45,"z":279.16},{"x":393.45,"y":-130.7,"z":279.41},{"x":391.86,"y":-131.14,"z":281.43},{"x":391.22,"y":-129.3,"z":283.17}]},{"lat":12.72,"lon":133.13,"b":[{"x":331.98,"y":-107.04,"z":358.15},{"x":335.15,"y":-106.55,"z":355.34},{"x":336.55,"y":-109.6,"z":353.07},{"x":334.77,"y":-113.18,"z":353.63},{"x":331.57,"y":-113.68,"z":356.48},{"x":330.18,"y":-110.58,"z":358.73}]},{"lat":13.43,"lon":135.03,"b":[{"x":342.56,"y":-112.89,"z":346.18},{"x":345.83,"y":-112.34,"z":343.1},{"x":347.25,"y":-115.56,"z":340.58},{"x":345.41,"y":-119.39,"z":341.13},{"x":342.1,"y":-119.95,"z":344.25},{"x":340.69,"y":-116.67,"z":346.77}]},{"lat":14.13,"lon":136.95,"b":[{"x":354.12,"y":-121.58,"z":331.36},{"x":354.61,"y":-121.49,"z":330.88},{"x":354.82,"y":-121.98,"z":330.47},{"x":354.54,"y":-122.57,"z":330.55},{"x":354.05,"y":-122.66,"z":331.04},{"x":353.84,"y":-122.16,"z":331.45}]},{"lat":16.16,"lon":142.88,"b":[{"x":381.73,"y":-136,"z":292.78},{"x":384.58,"y":-135.28,"z":289.36},{"x":385.7,"y":-138.45,"z":286.35},{"x":383.97,"y":-142.38,"z":286.75},{"x":381.09,"y":-143.13,"z":290.2},{"x":379.97,"y":-139.91,"z":293.22}]},{"lat":16.81,"lon":144.89,"b":[{"x":390.44,"y":-141.41,"z":278.37},{"x":393.17,"y":-140.65,"z":274.9},{"x":394.19,"y":-143.79,"z":271.8},{"x":392.48,"y":-147.73,"z":272.14},{"x":389.73,"y":-148.53,"z":275.64},{"x":388.71,"y":-145.34,"z":278.77}]},{"lat":13.84,"lon":131.46,"b":[{"x":319.97,"y":-116.34,"z":366.09},{"x":323.42,"y":-115.85,"z":363.2},{"x":324.88,"y":-119.12,"z":360.82},{"x":322.87,"y":-122.94,"z":361.35},{"x":319.37,"y":-123.43,"z":364.28},{"x":317.93,"y":-120.11,"z":366.64}]},{"lat":14.58,"lon":133.37,"b":[{"x":330.85,"y":-122.54,"z":354.2},{"x":334.23,"y":-122.01,"z":351.19},{"x":335.65,"y":-125.29,"z":348.67},{"x":333.66,"y":-129.15,"z":349.17},{"x":330.24,"y":-129.68,"z":352.22},{"x":328.84,"y":-126.35,"z":354.73}]},{"lat":15.3,"lon":135.31,"b":[{"x":341.66,"y":-129.13,"z":341.37},{"x":344.49,"y":-128.65,"z":338.7},{"x":345.65,"y":-131.46,"z":336.42},{"x":343.97,"y":-134.79,"z":336.82},{"x":341.11,"y":-135.29,"z":339.53},{"x":339.95,"y":-132.43,"z":341.8}]},{"lat":16.02,"lon":137.28,"b":[{"x":352.92,"y":-137.56,"z":326.37},{"x":353.32,"y":-137.48,"z":325.97},{"x":353.48,"y":-137.89,"z":325.62},{"x":353.24,"y":-138.38,"z":325.67},{"x":352.83,"y":-138.46,"z":326.08},{"x":352.67,"y":-138.04,"z":326.43}]},{"lat":17.4,"lon":141.3,"b":[{"x":371.6,"y":-147.53,"z":300.16},{"x":373.48,"y":-147.09,"z":298.05},{"x":374.18,"y":-149.11,"z":296.16},{"x":373,"y":-151.59,"z":296.38},{"x":371.11,"y":-152.04,"z":298.52},{"x":370.41,"y":-150,"z":300.41}]},{"lat":18.07,"lon":143.34,"b":[{"x":380.2,"y":-151.88,"z":286.9},{"x":383.08,"y":-151.13,"z":283.45},{"x":384.1,"y":-154.31,"z":280.33},{"x":382.25,"y":-158.3,"z":280.64},{"x":379.34,"y":-159.08,"z":284.12},{"x":378.32,"y":-155.85,"z":287.26}]},{"lat":18.71,"lon":145.39,"b":[{"x":388.75,"y":-157.24,"z":272.17},{"x":391.5,"y":-156.44,"z":268.67},{"x":392.42,"y":-159.59,"z":265.46},{"x":390.59,"y":-163.58,"z":265.72},{"x":387.82,"y":-164.41,"z":269.25},{"x":386.9,"y":-161.23,"z":272.48}]},{"lat":14.97,"lon":129.77,"b":[{"x":307.95,"y":-126.8,"z":372.88},{"x":310.43,"y":-126.48,"z":370.93},{"x":311.43,"y":-128.8,"z":369.28},{"x":309.94,"y":-131.47,"z":369.6},{"x":307.43,"y":-131.79,"z":371.58},{"x":306.44,"y":-129.44,"z":373.21}]},{"lat":15.73,"lon":131.68,"b":[{"x":318.57,"y":-132.17,"z":361.9},{"x":322.07,"y":-131.68,"z":358.97},{"x":323.47,"y":-135.01,"z":356.46},{"x":321.35,"y":-138.88,"z":356.9},{"x":317.81,"y":-139.38,"z":359.86},{"x":316.43,"y":-136,"z":362.36}]},{"lat":16.48,"lon":133.62,"b":[{"x":329.4,"y":-138.48,"z":349.64},{"x":332.83,"y":-137.94,"z":346.59},{"x":334.18,"y":-141.27,"z":343.94},{"x":332.08,"y":-145.18,"z":344.35},{"x":328.61,"y":-145.73,"z":347.43},{"x":327.28,"y":-142.35,"z":350.07}]},{"lat":17.22,"lon":135.61,"b":[{"x":339.94,"y":-144.68,"z":336.81},{"x":343.28,"y":-144.1,"z":333.65},{"x":344.56,"y":-147.42,"z":330.86},{"x":342.49,"y":-151.36,"z":331.24},{"x":339.11,"y":-151.96,"z":334.43},{"x":337.84,"y":-148.59,"z":337.21}]},{"lat":17.95,"lon":137.62,"b":[{"x":350.13,"y":-150.75,"z":323.44},{"x":353.38,"y":-150.12,"z":320.18},{"x":354.58,"y":-153.42,"z":317.27},{"x":352.53,"y":-157.39,"z":317.61},{"x":349.25,"y":-158.04,"z":320.9},{"x":348.06,"y":-154.69,"z":323.81}]},{"lat":18.66,"lon":139.67,"b":[{"x":359.93,"y":-156.65,"z":309.58},{"x":363.07,"y":-155.98,"z":306.23},{"x":364.19,"y":-159.25,"z":303.2},{"x":362.16,"y":-163.24,"z":303.5},{"x":358.99,"y":-163.94,"z":306.88},{"x":357.88,"y":-160.63,"z":309.92}]},{"lat":19.35,"lon":141.73,"b":[{"x":369.29,"y":-162.38,"z":295.27},{"x":372.32,"y":-161.65,"z":291.85},{"x":373.35,"y":-164.88,"z":288.71},{"x":371.34,"y":-168.89,"z":288.97},{"x":368.29,"y":-169.65,"z":292.42},{"x":367.27,"y":-166.37,"z":295.57}]},{"lat":20.01,"lon":143.81,"b":[{"x":378.18,"y":-167.89,"z":280.57},{"x":381.08,"y":-167.11,"z":277.09},{"x":382.01,"y":-170.3,"z":273.85},{"x":380.03,"y":-174.32,"z":274.07},{"x":377.1,"y":-175.14,"z":277.57},{"x":376.18,"y":-171.9,"z":280.83}]},{"lat":20.65,"lon":145.91,"b":[{"x":386.56,"y":-173.18,"z":265.53},{"x":389.33,"y":-172.34,"z":262.01},{"x":390.15,"y":-175.48,"z":258.69},{"x":388.2,"y":-179.5,"z":258.86},{"x":385.4,"y":-180.38,"z":262.41},{"x":384.58,"y":-177.2,"z":265.75}]},{"lat":21.26,"lon":148.01,"b":[{"x":394.4,"y":-178.22,"z":250.22},{"x":397.04,"y":-177.32,"z":246.67},{"x":397.74,"y":-180.4,"z":243.28},{"x":395.81,"y":-184.42,"z":243.41},{"x":393.16,"y":-185.36,"z":246.98},{"x":392.45,"y":-182.24,"z":250.4}]},{"lat":21.85,"lon":150.11,"b":[{"x":402.26,"y":-185.59,"z":231.8},{"x":402.64,"y":-185.44,"z":231.26},{"x":402.73,"y":-185.9,"z":230.73},{"x":402.44,"y":-186.51,"z":230.75},{"x":402.06,"y":-186.66,"z":231.29},{"x":401.97,"y":-186.2,"z":231.82}]},{"lat":16.09,"lon":128.03,"b":[{"x":294.59,"y":-135.31,"z":380.59},{"x":298.11,"y":-134.9,"z":377.98},{"x":299.48,"y":-138.15,"z":375.71},{"x":297.29,"y":-141.85,"z":376.07},{"x":293.72,"y":-142.25,"z":378.72},{"x":292.39,"y":-138.95,"z":380.96}]},{"lat":16.88,"lon":129.94,"b":[{"x":305.77,"y":-141.76,"z":369.25},{"x":309.37,"y":-141.3,"z":366.41},{"x":310.75,"y":-144.68,"z":363.91},{"x":308.5,"y":-148.56,"z":364.27},{"x":304.85,"y":-149.01,"z":367.14},{"x":303.5,"y":-145.59,"z":369.62}]},{"lat":17.66,"lon":131.9,"b":[{"x":316.79,"y":-148.25,"z":357.2},{"x":320.33,"y":-147.75,"z":354.24},{"x":321.66,"y":-151.13,"z":351.6},{"x":319.43,"y":-155.05,"z":351.93},{"x":315.84,"y":-155.55,"z":354.93},{"x":314.54,"y":-152.13,"z":357.56}]},{"lat":18.42,"lon":133.89,"b":[{"x":327.55,"y":-154.64,"z":344.57},{"x":331.02,"y":-154.1,"z":341.48},{"x":332.28,"y":-157.46,"z":338.7},{"x":330.07,"y":-161.42,"z":339.01},{"x":326.56,"y":-161.97,"z":342.12},{"x":325.31,"y":-158.56,"z":344.9}]},{"lat":19.18,"lon":135.92,"b":[{"x":337.99,"y":-160.89,"z":331.36},{"x":341.37,"y":-160.3,"z":328.17},{"x":342.57,"y":-163.64,"z":325.26},{"x":340.37,"y":-167.63,"z":325.53},{"x":336.96,"y":-168.24,"z":328.76},{"x":335.78,"y":-164.85,"z":331.67}]},{"lat":19.92,"lon":137.98,"b":[{"x":348.07,"y":-166.98,"z":317.64},{"x":351.35,"y":-166.33,"z":314.35},{"x":352.47,"y":-169.65,"z":311.31},{"x":350.29,"y":-173.66,"z":311.55},{"x":346.98,"y":-174.32,"z":314.87},{"x":345.87,"y":-170.96,"z":317.91}]},{"lat":20.63,"lon":140.07,"b":[{"x":357.73,"y":-172.87,"z":303.43},{"x":360.91,"y":-172.17,"z":300.05},{"x":361.93,"y":-175.45,"z":296.9},{"x":359.78,"y":-179.48,"z":297.11},{"x":356.58,"y":-180.2,"z":300.5},{"x":355.56,"y":-176.88,"z":303.67}]},{"lat":21.32,"lon":142.18,"b":[{"x":366.94,"y":-178.55,"z":288.79},{"x":370,"y":-177.79,"z":285.34},{"x":370.92,"y":-181.02,"z":282.09},{"x":368.79,"y":-185.06,"z":282.26},{"x":365.72,"y":-185.85,"z":285.72},{"x":364.79,"y":-182.57,"z":288.99}]},{"lat":21.99,"lon":144.31,"b":[{"x":375.66,"y":-183.98,"z":273.78},{"x":378.59,"y":-183.17,"z":270.28},{"x":379.41,"y":-186.35,"z":266.93},{"x":377.3,"y":-190.39,"z":267.06},{"x":374.35,"y":-191.24,"z":270.58},{"x":373.53,"y":-188.02,"z":273.95}]},{"lat":22.62,"lon":146.45,"b":[{"x":383.86,"y":-189.16,"z":258.46},{"x":386.65,"y":-188.28,"z":254.91},{"x":387.36,"y":-191.4,"z":251.49},{"x":385.27,"y":-195.44,"z":251.58},{"x":382.46,"y":-196.36,"z":255.13},{"x":381.75,"y":-193.2,"z":258.59}]},{"lat":23.22,"lon":148.6,"b":[{"x":391.5,"y":-194.06,"z":242.89},{"x":394.16,"y":-193.12,"z":239.32},{"x":394.75,"y":-196.17,"z":235.84},{"x":392.69,"y":-200.2,"z":235.88},{"x":390.01,"y":-201.18,"z":239.46},{"x":389.42,"y":-198.1,"z":242.98}]},{"lat":23.79,"lon":150.74,"b":[{"x":398.68,"y":-199.23,"z":226.49},{"x":400.73,"y":-198.42,"z":223.58},{"x":401.11,"y":-200.84,"z":220.71},{"x":399.46,"y":-204.1,"z":220.71},{"x":397.4,"y":-204.96,"z":223.62},{"x":397.01,"y":-202.51,"z":226.53}]},{"lat":17.21,"lon":126.26,"b":[{"x":281.11,"y":-144.48,"z":387.35},{"x":284.85,"y":-144.1,"z":384.74},{"x":286.23,"y":-147.52,"z":382.41},{"x":283.84,"y":-151.35,"z":382.7},{"x":280.06,"y":-151.71,"z":385.33},{"x":278.71,"y":-148.26,"z":387.65}]},{"lat":18.02,"lon":128.17,"b":[{"x":292.46,"y":-151.25,"z":376.19},{"x":296.16,"y":-150.83,"z":373.45},{"x":297.52,"y":-154.26,"z":370.97},{"x":295.14,"y":-158.13,"z":371.24},{"x":291.39,"y":-158.54,"z":374.01},{"x":290.07,"y":-155.08,"z":376.48}]},{"lat":18.83,"lon":130.13,"b":[{"x":303.64,"y":-157.94,"z":364.4},{"x":307.29,"y":-157.48,"z":361.52},{"x":308.6,"y":-160.9,"z":358.89},{"x":306.23,"y":-164.82,"z":359.14},{"x":302.55,"y":-165.27,"z":362.05},{"x":301.27,"y":-161.81,"z":364.67}]},{"lat":19.63,"lon":132.13,"b":[{"x":314.59,"y":-164.52,"z":351.98},{"x":318.18,"y":-164.02,"z":348.98},{"x":319.43,"y":-167.43,"z":346.21},{"x":317.07,"y":-171.38,"z":346.44},{"x":313.46,"y":-171.89,"z":349.46},{"x":312.23,"y":-168.44,"z":352.23}]},{"lat":20.41,"lon":134.17,"b":[{"x":325.26,"y":-170.96,"z":338.97},{"x":328.76,"y":-170.41,"z":335.86},{"x":329.95,"y":-173.8,"z":332.94},{"x":327.61,"y":-177.79,"z":333.15},{"x":324.08,"y":-178.35,"z":336.29},{"x":322.91,"y":-174.92,"z":339.2}]},{"lat":21.18,"lon":136.24,"b":[{"x":335.59,"y":-177.24,"z":325.41},{"x":339,"y":-176.63,"z":322.19},{"x":340.11,"y":-179.99,"z":319.14},{"x":337.79,"y":-184,"z":319.32},{"x":334.35,"y":-184.62,"z":322.56},{"x":333.26,"y":-181.22,"z":325.61}]},{"lat":21.92,"lon":138.36,"b":[{"x":345.54,"y":-183.31,"z":311.33},{"x":348.85,"y":-182.65,"z":308.01},{"x":349.87,"y":-185.97,"z":304.85},{"x":347.57,"y":-190,"z":304.99},{"x":344.23,"y":-190.69,"z":308.33},{"x":343.22,"y":-187.32,"z":311.5}]},{"lat":22.64,"lon":140.49,"b":[{"x":355.05,"y":-189.16,"z":296.78},{"x":358.25,"y":-188.44,"z":293.39},{"x":359.17,"y":-191.71,"z":290.11},{"x":356.89,"y":-195.75,"z":290.22},{"x":353.67,"y":-196.51,"z":293.64},{"x":352.75,"y":-193.19,"z":296.93}]},{"lat":23.33,"lon":142.65,"b":[{"x":364.09,"y":-194.76,"z":281.83},{"x":367.17,"y":-193.97,"z":278.37},{"x":367.99,"y":-197.19,"z":275},{"x":365.73,"y":-201.24,"z":275.07},{"x":362.63,"y":-202.06,"z":278.55},{"x":361.81,"y":-198.8,"z":281.94}]},{"lat":23.99,"lon":144.83,"b":[{"x":372.63,"y":-200.09,"z":266.53},{"x":375.57,"y":-199.23,"z":263.01},{"x":376.29,"y":-202.39,"z":259.56},{"x":374.05,"y":-206.44,"z":259.6},{"x":371.08,"y":-207.33,"z":263.13},{"x":370.37,"y":-204.13,"z":266.61}]},{"lat":24.61,"lon":147.02,"b":[{"x":380.62,"y":-205.12,"z":250.95},{"x":383.44,"y":-204.2,"z":247.4},{"x":384.03,"y":-207.29,"z":243.88},{"x":381.82,"y":-211.33,"z":243.88},{"x":378.99,"y":-212.29,"z":247.44},{"x":378.39,"y":-209.17,"z":250.99}]},{"lat":25.2,"lon":149.21,"b":[{"x":388.06,"y":-209.85,"z":235.15},{"x":390.74,"y":-208.86,"z":231.58},{"x":391.22,"y":-211.88,"z":228},{"x":389.03,"y":-215.9,"z":227.97},{"x":386.33,"y":-216.93,"z":231.55},{"x":385.85,"y":-213.89,"z":235.16}]},{"lat":25.75,"lon":151.4,"b":[{"x":394.93,"y":-214.26,"z":219.21},{"x":397.46,"y":-213.21,"z":215.63},{"x":397.82,"y":-216.14,"z":212.02},{"x":395.65,"y":-220.15,"z":211.95},{"x":393.1,"y":-221.24,"z":215.52},{"x":392.74,"y":-218.28,"z":219.18}]},{"lat":26.26,"lon":153.57,"b":[{"x":401.46,"y":-220.54,"z":200.43},{"x":402.04,"y":-220.27,"z":199.57},{"x":402.09,"y":-220.96,"z":198.69},{"x":401.57,"y":-221.92,"z":198.66},{"x":400.99,"y":-222.2,"z":199.53},{"x":400.93,"y":-221.51,"z":200.42}]},{"lat":18.31,"lon":124.47,"b":[{"x":267.26,"y":-153.64,"z":393.57},{"x":271.07,"y":-153.32,"z":391.08},{"x":272.42,"y":-156.77,"z":388.77},{"x":269.92,"y":-160.58,"z":388.96},{"x":266.06,"y":-160.88,"z":391.48},{"x":264.76,"y":-157.4,"z":393.78}]},{"lat":19.16,"lon":126.36,"b":[{"x":278.7,"y":-160.61,"z":382.7},{"x":282.49,"y":-160.24,"z":380.07},{"x":283.81,"y":-163.7,"z":377.6},{"x":281.31,"y":-167.56,"z":377.78},{"x":277.49,"y":-167.91,"z":380.44},{"x":276.2,"y":-164.42,"z":382.89}]},{"lat":20,"lon":128.32,"b":[{"x":290,"y":-167.5,"z":371.17},{"x":293.75,"y":-167.09,"z":368.4},{"x":295.03,"y":-170.55,"z":365.78},{"x":292.54,"y":-174.45,"z":365.94},{"x":288.76,"y":-174.85,"z":368.74},{"x":287.51,"y":-171.35,"z":371.35}]},{"lat":20.82,"lon":130.32,"b":[{"x":301.11,"y":-174.28,"z":359.01},{"x":304.8,"y":-173.83,"z":356.1},{"x":306.03,"y":-177.28,"z":353.33},{"x":303.55,"y":-181.22,"z":353.48},{"x":299.82,"y":-181.67,"z":356.41},{"x":298.62,"y":-178.18,"z":359.17}]},{"lat":21.64,"lon":132.37,"b":[{"x":311.97,"y":-180.92,"z":346.22},{"x":315.59,"y":-180.42,"z":343.19},{"x":316.75,"y":-183.85,"z":340.28},{"x":314.28,"y":-187.82,"z":340.4},{"x":310.63,"y":-188.33,"z":343.46},{"x":309.49,"y":-184.86,"z":346.36}]},{"lat":22.44,"lon":134.46,"b":[{"x":322.52,"y":-187.39,"z":332.85},{"x":326.06,"y":-186.83,"z":329.7},{"x":327.15,"y":-190.23,"z":326.66},{"x":324.7,"y":-194.23,"z":326.75},{"x":321.13,"y":-194.8,"z":329.92},{"x":320.05,"y":-191.36,"z":332.97}]},{"lat":23.21,"lon":136.58,"b":[{"x":332.72,"y":-193.66,"z":318.93},{"x":336.16,"y":-193.04,"z":315.68},{"x":337.18,"y":-196.4,"z":312.51},{"x":334.74,"y":-200.42,"z":312.58},{"x":331.27,"y":-201.05,"z":315.85},{"x":330.27,"y":-197.66,"z":319.03}]},{"lat":23.96,"lon":138.75,"b":[{"x":342.52,"y":-199.69,"z":304.51},{"x":345.85,"y":-199,"z":301.17},{"x":346.77,"y":-202.32,"z":297.89},{"x":344.35,"y":-206.35,"z":297.93},{"x":340.99,"y":-207.06,"z":301.29},{"x":340.08,"y":-203.71,"z":304.58}]},{"lat":24.68,"lon":140.94,"b":[{"x":351.86,"y":-205.46,"z":289.65},{"x":355.09,"y":-204.71,"z":286.24},{"x":355.91,"y":-207.97,"z":282.85},{"x":353.5,"y":-212.01,"z":282.86},{"x":350.26,"y":-212.79,"z":286.29},{"x":349.44,"y":-209.5,"z":289.7}]},{"lat":25.36,"lon":143.15,"b":[{"x":360.72,"y":-210.95,"z":274.41},{"x":363.82,"y":-210.13,"z":270.93},{"x":364.54,"y":-213.32,"z":267.45},{"x":362.15,"y":-217.36,"z":267.43},{"x":359.03,"y":-218.21,"z":270.92},{"x":358.32,"y":-214.99,"z":274.42}]},{"lat":26.01,"lon":145.37,"b":[{"x":369.06,"y":-216.13,"z":258.85},{"x":372.03,"y":-215.24,"z":255.32},{"x":372.63,"y":-218.36,"z":251.77},{"x":370.27,"y":-222.4,"z":251.72},{"x":367.28,"y":-223.32,"z":255.25},{"x":366.68,"y":-220.18,"z":258.83}]},{"lat":26.63,"lon":147.61,"b":[{"x":376.86,"y":-220.99,"z":243.03},{"x":379.69,"y":-220.03,"z":239.47},{"x":380.17,"y":-223.08,"z":235.86},{"x":377.83,"y":-227.1,"z":235.78},{"x":374.98,"y":-228.1,"z":239.34},{"x":374.49,"y":-225.03,"z":242.98}]},{"lat":27.2,"lon":149.85,"b":[{"x":384.08,"y":-225.52,"z":227.03},{"x":386.78,"y":-224.49,"z":223.46},{"x":387.14,"y":-227.45,"z":219.81},{"x":384.82,"y":-231.46,"z":219.69},{"x":382.11,"y":-232.52,"z":223.26},{"x":381.74,"y":-229.54,"z":226.95}]},{"lat":27.73,"lon":152.08,"b":[{"x":390.73,"y":-229.7,"z":210.92},{"x":393.28,"y":-228.61,"z":207.35},{"x":393.53,"y":-231.48,"z":203.67},{"x":391.23,"y":-235.46,"z":203.52},{"x":388.67,"y":-236.6,"z":207.09},{"x":388.41,"y":-233.71,"z":210.81}]},{"lat":19.41,"lon":122.64,"b":[{"x":253.04,"y":-162.63,"z":399.32},{"x":256.91,"y":-162.36,"z":396.95},{"x":258.22,"y":-165.85,"z":394.65},{"x":255.61,"y":-169.63,"z":394.74},{"x":251.7,"y":-169.87,"z":397.14},{"x":250.44,"y":-166.36,"z":399.42}]},{"lat":20.28,"lon":124.53,"b":[{"x":264.53,"y":-169.8,"z":388.75},{"x":268.38,"y":-169.49,"z":386.23},{"x":269.67,"y":-172.98,"z":383.77},{"x":267.06,"y":-176.81,"z":383.85},{"x":263.17,"y":-177.1,"z":386.4},{"x":261.92,"y":-173.58,"z":388.84}]},{"lat":21.15,"lon":126.47,"b":[{"x":275.92,"y":-176.89,"z":377.51},{"x":279.74,"y":-176.54,"z":374.84},{"x":280.99,"y":-180.03,"z":372.23},{"x":278.38,"y":-183.91,"z":372.3},{"x":274.52,"y":-184.24,"z":374.99},{"x":273.31,"y":-180.72,"z":377.58}]},{"lat":22.01,"lon":128.47,"b":[{"x":287.14,"y":-183.87,"z":365.6},{"x":290.92,"y":-183.48,"z":362.8},{"x":292.12,"y":-186.96,"z":360.04},{"x":289.52,"y":-190.87,"z":360.09},{"x":285.71,"y":-191.26,"z":362.92},{"x":284.54,"y":-187.75,"z":365.67}]},{"lat":22.86,"lon":130.52,"b":[{"x":298.15,"y":-190.72,"z":353.06},{"x":301.88,"y":-190.27,"z":350.13},{"x":303.02,"y":-193.74,"z":347.23},{"x":300.43,"y":-197.68,"z":347.26},{"x":296.67,"y":-198.13,"z":350.22},{"x":295.55,"y":-194.63,"z":353.12}]},{"lat":23.69,"lon":132.62,"b":[{"x":308.9,"y":-197.39,"z":339.91},{"x":312.55,"y":-196.88,"z":336.86},{"x":313.63,"y":-200.32,"z":333.81},{"x":311.04,"y":-204.3,"z":333.83},{"x":307.36,"y":-204.81,"z":336.9},{"x":306.3,"y":-201.34,"z":339.95}]},{"lat":24.49,"lon":134.76,"b":[{"x":319.32,"y":-203.86,"z":326.19},{"x":322.89,"y":-203.29,"z":323.02},{"x":323.89,"y":-206.68,"z":319.84},{"x":321.31,"y":-210.68,"z":319.83},{"x":317.72,"y":-211.26,"z":323.02},{"x":316.73,"y":-207.83,"z":326.2}]},{"lat":25.27,"lon":136.94,"b":[{"x":329.37,"y":-210.08,"z":311.93},{"x":332.84,"y":-209.45,"z":308.66},{"x":333.75,"y":-212.79,"z":305.37},{"x":331.19,"y":-216.81,"z":305.33},{"x":327.7,"y":-217.46,"z":308.62},{"x":326.79,"y":-214.08,"z":311.92}]},{"lat":26.02,"lon":139.15,"b":[{"x":339,"y":-216.04,"z":297.2},{"x":342.36,"y":-215.33,"z":293.84},{"x":343.18,"y":-218.62,"z":290.44},{"x":340.63,"y":-222.64,"z":290.38},{"x":337.25,"y":-223.37,"z":293.75},{"x":336.44,"y":-220.05,"z":297.17}]},{"lat":26.74,"lon":141.4,"b":[{"x":348.17,"y":-221.7,"z":282.05},{"x":351.41,"y":-220.92,"z":278.61},{"x":352.13,"y":-224.14,"z":275.12},{"x":349.59,"y":-228.17,"z":275.03},{"x":346.33,"y":-228.97,"z":278.47},{"x":345.62,"y":-225.72,"z":281.99}]},{"lat":27.42,"lon":143.66,"b":[{"x":356.83,"y":-227.04,"z":266.54},{"x":359.95,"y":-226.19,"z":263.05},{"x":360.56,"y":-229.34,"z":259.47},{"x":358.05,"y":-233.36,"z":259.36},{"x":354.91,"y":-234.24,"z":262.85},{"x":354.3,"y":-231.07,"z":266.45}]},{"lat":28.06,"lon":145.94,"b":[{"x":364.97,"y":-232.05,"z":250.74},{"x":367.96,"y":-231.13,"z":247.2},{"x":368.45,"y":-234.19,"z":243.56},{"x":365.96,"y":-238.21,"z":243.42},{"x":362.95,"y":-239.16,"z":246.96},{"x":362.46,"y":-236.07,"z":250.63}]},{"lat":28.65,"lon":148.23,"b":[{"x":372.56,"y":-236.71,"z":234.72},{"x":375.4,"y":-235.71,"z":231.16},{"x":375.78,"y":-238.69,"z":227.47},{"x":373.31,"y":-242.69,"z":227.3},{"x":370.44,"y":-243.72,"z":230.86},{"x":370.06,"y":-240.72,"z":234.58}]},{"lat":29.2,"lon":150.51,"b":[{"x":379.57,"y":-241.01,"z":218.56},{"x":382.28,"y":-239.94,"z":214.99},{"x":382.53,"y":-242.83,"z":211.26},{"x":380.08,"y":-246.8,"z":211.07},{"x":377.36,"y":-247.91,"z":214.63},{"x":377.1,"y":-245,"z":218.39}]},{"lat":29.71,"lon":152.79,"b":[{"x":386,"y":-244.94,"z":202.31},{"x":388.57,"y":-243.8,"z":198.75},{"x":388.7,"y":-246.59,"z":195.01},{"x":386.28,"y":-250.54,"z":194.79},{"x":383.7,"y":-251.72,"z":198.34},{"x":383.56,"y":-248.91,"z":202.12}]},{"lat":20.48,"lon":120.79,"b":[{"x":238.83,"y":-172.33,"z":403.99},{"x":241.73,"y":-172.17,"z":402.33},{"x":242.66,"y":-174.78,"z":400.64},{"x":240.67,"y":-177.55,"z":400.63},{"x":237.74,"y":-177.68,"z":402.31},{"x":236.84,"y":-175.06,"z":403.99}]},{"lat":21.38,"lon":122.66,"b":[{"x":250,"y":-178.78,"z":394.3},{"x":253.91,"y":-178.53,"z":391.9},{"x":255.15,"y":-182.06,"z":389.46},{"x":252.45,"y":-185.85,"z":389.44},{"x":248.5,"y":-186.06,"z":391.86},{"x":247.3,"y":-182.52,"z":394.28}]},{"lat":22.29,"lon":124.59,"b":[{"x":261.43,"y":-186.07,"z":383.36},{"x":265.32,"y":-185.78,"z":380.81},{"x":266.53,"y":-189.31,"z":378.22},{"x":263.82,"y":-193.14,"z":378.18},{"x":259.9,"y":-193.41,"z":380.75},{"x":258.72,"y":-189.86,"z":383.33}]},{"lat":23.18,"lon":126.58,"b":[{"x":272.73,"y":-193.26,"z":371.74},{"x":276.59,"y":-192.93,"z":369.05},{"x":277.77,"y":-196.44,"z":366.3},{"x":275.05,"y":-200.32,"z":366.26},{"x":271.16,"y":-200.64,"z":368.97},{"x":270.02,"y":-197.1,"z":371.71}]},{"lat":24.06,"lon":128.63,"b":[{"x":283.86,"y":-200.31,"z":359.47},{"x":287.68,"y":-199.93,"z":356.64},{"x":288.8,"y":-203.42,"z":353.75},{"x":286.08,"y":-207.33,"z":353.68},{"x":282.25,"y":-207.71,"z":356.53},{"x":281.15,"y":-204.19,"z":359.42}]},{"lat":24.92,"lon":130.73,"b":[{"x":294.76,"y":-207.19,"z":346.57},{"x":298.51,"y":-206.75,"z":343.61},{"x":299.58,"y":-210.21,"z":340.57},{"x":296.86,"y":-214.15,"z":340.49},{"x":293.09,"y":-214.59,"z":343.47},{"x":292.05,"y":-211.1,"z":346.5}]},{"lat":25.76,"lon":132.88,"b":[{"x":305.38,"y":-213.86,"z":333.06},{"x":309.05,"y":-213.35,"z":329.98},{"x":310.04,"y":-216.78,"z":326.81},{"x":307.33,"y":-220.74,"z":326.71},{"x":303.64,"y":-221.25,"z":329.81},{"x":302.66,"y":-217.8,"z":332.98}]},{"lat":26.58,"lon":135.08,"b":[{"x":315.65,"y":-220.29,"z":319},{"x":319.24,"y":-219.71,"z":315.81},{"x":320.14,"y":-223.09,"z":312.51},{"x":317.45,"y":-227.06,"z":312.39},{"x":313.84,"y":-227.65,"z":315.6},{"x":312.94,"y":-224.25,"z":318.9}]},{"lat":27.36,"lon":137.31,"b":[{"x":325.53,"y":-226.44,"z":304.42},{"x":329.02,"y":-225.79,"z":301.14},{"x":329.84,"y":-229.1,"z":297.72},{"x":327.15,"y":-233.1,"z":297.59},{"x":323.64,"y":-233.76,"z":300.89},{"x":322.84,"y":-230.42,"z":304.31}]},{"lat":28.11,"lon":139.58,"b":[{"x":334.98,"y":-232.28,"z":289.4},{"x":338.36,"y":-231.56,"z":286.02},{"x":339.08,"y":-234.81,"z":282.51},{"x":336.41,"y":-238.8,"z":282.35},{"x":333.01,"y":-239.55,"z":285.73},{"x":332.3,"y":-236.28,"z":289.26}]},{"lat":28.82,"lon":141.88,"b":[{"x":343.96,"y":-237.8,"z":273.97},{"x":347.22,"y":-237,"z":270.53},{"x":347.83,"y":-240.17,"z":266.93},{"x":345.17,"y":-244.17,"z":266.75},{"x":341.89,"y":-244.99,"z":270.2},{"x":341.29,"y":-241.8,"z":273.82}]},{"lat":29.49,"lon":144.2,"b":[{"x":352.42,"y":-242.97,"z":258.23},{"x":355.56,"y":-242.09,"z":254.73},{"x":356.05,"y":-245.18,"z":251.06},{"x":353.42,"y":-249.17,"z":250.86},{"x":350.27,"y":-250.07,"z":254.35},{"x":349.77,"y":-246.97,"z":258.05}]},{"lat":30.11,"lon":146.53,"b":[{"x":360.35,"y":-247.78,"z":242.23},{"x":363.36,"y":-246.82,"z":238.69},{"x":363.73,"y":-249.82,"z":234.97},{"x":361.12,"y":-253.79,"z":234.75},{"x":358.1,"y":-254.77,"z":238.27},{"x":357.72,"y":-251.76,"z":242.03}]},{"lat":30.69,"lon":148.87,"b":[{"x":367.73,"y":-252.2,"z":226.04},{"x":370.59,"y":-251.17,"z":222.49},{"x":370.85,"y":-254.07,"z":218.73},{"x":368.26,"y":-258.02,"z":218.48},{"x":365.38,"y":-259.09,"z":222.02},{"x":365.11,"y":-256.17,"z":225.82}]},{"lat":31.21,"lon":151.21,"b":[{"x":374.53,"y":-256.24,"z":209.74},{"x":377.25,"y":-255.14,"z":206.19},{"x":377.39,"y":-257.94,"z":202.4},{"x":374.82,"y":-261.87,"z":202.14},{"x":372.09,"y":-263.01,"z":205.68},{"x":371.93,"y":-260.19,"z":209.5}]},{"lat":31.69,"lon":153.53,"b":[{"x":380.83,"y":-261.97,"z":190.56},{"x":381.48,"y":-261.68,"z":189.67},{"x":381.49,"y":-262.35,"z":188.72},{"x":380.85,"y":-263.33,"z":188.65},{"x":380.2,"y":-263.63,"z":189.54},{"x":380.19,"y":-262.95,"z":190.5}]},{"lat":21.53,"lon":118.92,"b":[{"x":223.69,"y":-179.96,"z":409.28},{"x":227.64,"y":-179.82,"z":407.15},{"x":228.86,"y":-183.35,"z":404.89},{"x":226.08,"y":-187.05,"z":404.76},{"x":222.1,"y":-187.15,"z":406.91},{"x":220.93,"y":-183.61,"z":409.16}]},{"lat":22.47,"lon":120.77,"b":[{"x":235.16,"y":-187.52,"z":399.33},{"x":239.11,"y":-187.34,"z":397.06},{"x":240.32,"y":-190.88,"z":394.64},{"x":237.52,"y":-194.62,"z":394.5},{"x":233.54,"y":-194.77,"z":396.8},{"x":232.38,"y":-191.21,"z":399.21}]},{"lat":23.4,"lon":122.68,"b":[{"x":246.59,"y":-195.01,"z":388.7},{"x":250.54,"y":-194.79,"z":386.28},{"x":251.72,"y":-198.34,"z":383.7},{"x":248.91,"y":-202.12,"z":383.56},{"x":244.94,"y":-202.31,"z":386},{"x":243.8,"y":-198.75,"z":388.57}]},{"lat":24.33,"lon":124.66,"b":[{"x":257.94,"y":-202.4,"z":377.39},{"x":261.87,"y":-202.14,"z":374.82},{"x":263.01,"y":-205.68,"z":372.09},{"x":260.19,"y":-209.5,"z":371.93},{"x":256.24,"y":-209.74,"z":374.53},{"x":255.14,"y":-206.19,"z":377.25}]},{"lat":25.24,"lon":126.7,"b":[{"x":269.15,"y":-209.66,"z":365.41},{"x":273.04,"y":-209.34,"z":362.7},{"x":274.14,"y":-212.86,"z":359.81},{"x":271.31,"y":-216.72,"z":359.64},{"x":267.4,"y":-217.03,"z":362.38},{"x":266.34,"y":-213.49,"z":365.26}]},{"lat":26.14,"lon":128.8,"b":[{"x":280.17,"y":-216.75,"z":352.77},{"x":284.01,"y":-216.37,"z":349.92},{"x":285.04,"y":-219.86,"z":346.89},{"x":282.22,"y":-223.75,"z":346.71},{"x":278.36,"y":-224.12,"z":349.58},{"x":277.34,"y":-220.61,"z":352.61}]},{"lat":27.02,"lon":130.95,"b":[{"x":290.93,"y":-223.63,"z":339.52},{"x":294.71,"y":-223.18,"z":336.54},{"x":295.68,"y":-226.64,"z":333.36},{"x":292.85,"y":-230.55,"z":333.17},{"x":289.06,"y":-230.99,"z":336.17},{"x":288.11,"y":-227.52,"z":339.34}]},{"lat":27.87,"lon":133.16,"b":[{"x":301.39,"y":-230.26,"z":325.67},{"x":305.09,"y":-229.75,"z":322.57},{"x":305.99,"y":-233.15,"z":319.27},{"x":303.17,"y":-237.08,"z":319.06},{"x":299.45,"y":-237.59,"z":322.18},{"x":298.57,"y":-234.17,"z":325.48}]},{"lat":28.69,"lon":135.41,"b":[{"x":311.5,"y":-236.61,"z":311.29},{"x":315.11,"y":-236.03,"z":308.08},{"x":315.92,"y":-239.37,"z":304.66},{"x":313.11,"y":-243.31,"z":304.44},{"x":309.48,"y":-243.9,"z":307.66},{"x":308.68,"y":-240.54,"z":311.08}]},{"lat":29.47,"lon":137.7,"b":[{"x":321.21,"y":-242.65,"z":296.42},{"x":324.72,"y":-241.99,"z":293.12},{"x":325.43,"y":-245.26,"z":289.59},{"x":322.62,"y":-249.21,"z":289.35},{"x":319.1,"y":-249.88,"z":292.66},{"x":318.39,"y":-246.6,"z":296.2}]},{"lat":30.21,"lon":140.03,"b":[{"x":330.47,"y":-248.36,"z":281.12},{"x":333.86,"y":-247.62,"z":277.74},{"x":334.47,"y":-250.81,"z":274.12},{"x":331.68,"y":-254.76,"z":273.87},{"x":328.27,"y":-255.52,"z":277.25},{"x":327.66,"y":-252.31,"z":280.89}]},{"lat":30.91,"lon":142.39,"b":[{"x":339.24,"y":-253.7,"z":265.46},{"x":342.52,"y":-252.88,"z":262.02},{"x":343.02,"y":-255.98,"z":258.32},{"x":340.24,"y":-259.93,"z":258.05},{"x":336.95,"y":-260.77,"z":261.5},{"x":336.45,"y":-257.65,"z":265.21}]},{"lat":31.57,"lon":144.76,"b":[{"x":347.5,"y":-258.66,"z":249.51},{"x":350.65,"y":-257.76,"z":246.02},{"x":351.04,"y":-260.77,"z":242.27},{"x":348.28,"y":-264.7,"z":241.98},{"x":345.12,"y":-265.63,"z":245.46},{"x":344.72,"y":-262.61,"z":249.24}]},{"lat":32.17,"lon":147.15,"b":[{"x":355.22,"y":-263.23,"z":233.34},{"x":358.23,"y":-262.25,"z":229.82},{"x":358.5,"y":-265.16,"z":226.02},{"x":355.77,"y":-269.08,"z":225.72},{"x":352.74,"y":-270.09,"z":229.23},{"x":352.46,"y":-267.16,"z":233.06}]},{"lat":32.72,"lon":149.55,"b":[{"x":362.38,"y":-267.4,"z":217.03},{"x":365.26,"y":-266.34,"z":213.49},{"x":365.41,"y":-269.15,"z":209.66},{"x":362.7,"y":-273.04,"z":209.34},{"x":359.81,"y":-274.14,"z":212.86},{"x":359.64,"y":-271.31,"z":216.72}]},{"lat":33.22,"lon":151.93,"b":[{"x":369.01,"y":-271.98,"z":199.51},{"x":370.94,"y":-271.17,"z":197.01},{"x":370.96,"y":-273.09,"z":194.3},{"x":369.07,"y":-275.81,"z":194.06},{"x":367.12,"y":-276.64,"z":196.55},{"x":367.09,"y":-274.72,"z":199.28}]},{"lat":22.56,"lon":117.03,"b":[{"x":208.68,"y":-188.24,"z":413.46},{"x":212.65,"y":-188.17,"z":411.47},{"x":213.81,"y":-191.72,"z":409.22},{"x":210.97,"y":-195.35,"z":408.98},{"x":206.98,"y":-195.38,"z":410.99},{"x":205.86,"y":-191.83,"z":413.23}]},{"lat":23.52,"lon":118.85,"b":[{"x":220.08,"y":-195.98,"z":403.84},{"x":224.06,"y":-195.87,"z":401.69},{"x":225.22,"y":-199.44,"z":399.29},{"x":222.35,"y":-203.12,"z":399.04},{"x":218.34,"y":-203.19,"z":401.21},{"x":217.23,"y":-199.62,"z":403.6}]},{"lat":24.49,"lon":120.75,"b":[{"x":231.48,"y":-203.67,"z":393.53},{"x":235.46,"y":-203.52,"z":391.23},{"x":236.6,"y":-207.09,"z":388.67},{"x":233.71,"y":-210.81,"z":388.41},{"x":229.7,"y":-210.92,"z":390.73},{"x":228.61,"y":-207.35,"z":393.28}]},{"lat":25.45,"lon":122.71,"b":[{"x":242.83,"y":-211.26,"z":382.53},{"x":246.8,"y":-211.07,"z":380.08},{"x":247.91,"y":-214.63,"z":377.36},{"x":245,"y":-218.39,"z":377.1},{"x":241.01,"y":-218.56,"z":379.57},{"x":239.94,"y":-214.99,"z":382.28}]},{"lat":26.4,"lon":124.73,"b":[{"x":254.07,"y":-218.73,"z":370.85},{"x":258.02,"y":-218.48,"z":368.26},{"x":259.09,"y":-222.02,"z":365.38},{"x":256.17,"y":-225.82,"z":365.11},{"x":252.2,"y":-226.04,"z":367.73},{"x":251.17,"y":-222.49,"z":370.59}]},{"lat":27.33,"lon":126.82,"b":[{"x":265.16,"y":-226.02,"z":358.5},{"x":269.08,"y":-225.72,"z":355.77},{"x":270.09,"y":-229.23,"z":352.74},{"x":267.16,"y":-233.06,"z":352.46},{"x":263.23,"y":-233.34,"z":355.22},{"x":262.25,"y":-229.82,"z":358.23}]},{"lat":28.24,"lon":128.97,"b":[{"x":276.04,"y":-233.11,"z":345.52},{"x":279.9,"y":-232.74,"z":342.64},{"x":280.86,"y":-236.21,"z":339.47},{"x":277.92,"y":-240.06,"z":339.19},{"x":274.05,"y":-240.42,"z":342.08},{"x":273.12,"y":-236.94,"z":345.24}]},{"lat":29.13,"lon":131.18,"b":[{"x":286.66,"y":-239.95,"z":331.92},{"x":290.45,"y":-239.51,"z":328.92},{"x":291.33,"y":-242.93,"z":325.62},{"x":288.4,"y":-246.8,"z":325.32},{"x":284.59,"y":-247.24,"z":328.33},{"x":283.73,"y":-243.8,"z":331.63}]},{"lat":29.99,"lon":133.45,"b":[{"x":296.96,"y":-246.51,"z":317.76},{"x":300.67,"y":-246,"z":314.64},{"x":301.47,"y":-249.36,"z":311.22},{"x":298.54,"y":-253.24,"z":310.9},{"x":294.81,"y":-253.75,"z":314.03},{"x":294.02,"y":-250.38,"z":317.46}]},{"lat":30.81,"lon":135.76,"b":[{"x":306.88,"y":-252.75,"z":303.08},{"x":310.51,"y":-252.16,"z":299.86},{"x":311.22,"y":-255.45,"z":296.32},{"x":308.29,"y":-259.34,"z":296},{"x":304.65,"y":-259.94,"z":299.23},{"x":303.95,"y":-256.64,"z":302.77}]},{"lat":31.59,"lon":138.11,"b":[{"x":316.4,"y":-258.65,"z":287.94},{"x":319.92,"y":-257.98,"z":284.63},{"x":320.53,"y":-261.19,"z":281},{"x":317.61,"y":-265.08,"z":280.66},{"x":314.08,"y":-265.76,"z":283.97},{"x":313.47,"y":-262.55,"z":287.61}]},{"lat":32.33,"lon":140.5,"b":[{"x":325.46,"y":-264.18,"z":272.4},{"x":328.87,"y":-263.42,"z":269.02},{"x":329.37,"y":-266.54,"z":265.31},{"x":326.47,"y":-270.43,"z":264.96},{"x":323.05,"y":-271.21,"z":268.34},{"x":322.54,"y":-268.07,"z":272.07}]},{"lat":33.01,"lon":142.92,"b":[{"x":334.03,"y":-269.32,"z":256.54},{"x":337.32,"y":-268.47,"z":253.1},{"x":337.71,"y":-271.5,"z":249.32},{"x":334.82,"y":-275.38,"z":248.96},{"x":331.52,"y":-276.24,"z":252.4},{"x":331.12,"y":-273.21,"z":256.19}]},{"lat":33.65,"lon":145.36,"b":[{"x":342.08,"y":-274.05,"z":240.42},{"x":345.24,"y":-273.12,"z":236.94},{"x":345.52,"y":-276.04,"z":233.11},{"x":342.64,"y":-279.9,"z":232.74},{"x":339.47,"y":-280.86,"z":236.21},{"x":339.19,"y":-277.92,"z":240.06}]},{"lat":34.23,"lon":147.8,"b":[{"x":349.58,"y":-278.36,"z":224.12},{"x":352.61,"y":-277.34,"z":220.61},{"x":352.77,"y":-280.17,"z":216.75},{"x":349.92,"y":-284.01,"z":216.37},{"x":346.89,"y":-285.04,"z":219.86},{"x":346.71,"y":-282.22,"z":223.75}]},{"lat":34.75,"lon":150.25,"b":[{"x":356.53,"y":-282.25,"z":207.71},{"x":359.42,"y":-281.15,"z":204.19},{"x":359.47,"y":-283.86,"z":200.31},{"x":356.64,"y":-287.68,"z":199.93},{"x":353.75,"y":-288.8,"z":203.42},{"x":353.68,"y":-286.08,"z":207.33}]},{"lat":23.55,"lon":115.13,"b":[{"x":193.53,"y":-196.23,"z":417.1},{"x":197.49,"y":-196.22,"z":415.24},{"x":198.61,"y":-199.78,"z":413.01},{"x":195.71,"y":-203.35,"z":412.65},{"x":191.72,"y":-203.31,"z":414.54},{"x":190.66,"y":-199.75,"z":416.76}]},{"lat":24.55,"lon":116.92,"b":[{"x":204.82,"y":-204.15,"z":407.81},{"x":208.81,"y":-204.11,"z":405.79},{"x":209.92,"y":-207.68,"z":403.4},{"x":206.99,"y":-211.29,"z":403.04},{"x":202.97,"y":-211.29,"z":405.08},{"x":201.92,"y":-207.71,"z":407.45}]},{"lat":25.54,"lon":118.79,"b":[{"x":216.14,"y":-212.02,"z":397.82},{"x":220.15,"y":-211.95,"z":395.65},{"x":221.24,"y":-215.52,"z":393.1},{"x":218.28,"y":-219.18,"z":392.74},{"x":214.26,"y":-219.21,"z":394.93},{"x":213.21,"y":-215.63,"z":397.46}]},{"lat":26.54,"lon":120.72,"b":[{"x":227.45,"y":-219.81,"z":387.14},{"x":231.46,"y":-219.69,"z":384.82},{"x":232.52,"y":-223.26,"z":382.11},{"x":229.54,"y":-226.95,"z":381.74},{"x":225.52,"y":-227.03,"z":384.08},{"x":224.49,"y":-223.46,"z":386.78}]},{"lat":27.52,"lon":122.73,"b":[{"x":238.69,"y":-227.47,"z":375.78},{"x":242.69,"y":-227.3,"z":373.31},{"x":243.72,"y":-230.86,"z":370.44},{"x":240.72,"y":-234.58,"z":370.06},{"x":236.71,"y":-234.72,"z":372.56},{"x":235.71,"y":-231.16,"z":375.4}]},{"lat":28.49,"lon":124.81,"b":[{"x":249.82,"y":-234.97,"z":363.73},{"x":253.79,"y":-234.75,"z":361.12},{"x":254.77,"y":-238.27,"z":358.1},{"x":251.76,"y":-242.03,"z":357.72},{"x":247.78,"y":-242.23,"z":360.35},{"x":246.82,"y":-238.69,"z":363.36}]},{"lat":29.44,"lon":126.95,"b":[{"x":260.77,"y":-242.27,"z":351.04},{"x":264.7,"y":-241.98,"z":348.28},{"x":265.63,"y":-245.46,"z":345.12},{"x":262.61,"y":-249.24,"z":344.72},{"x":258.66,"y":-249.51,"z":347.5},{"x":257.76,"y":-246.02,"z":350.65}]},{"lat":30.37,"lon":129.16,"b":[{"x":271.5,"y":-249.32,"z":337.71},{"x":275.38,"y":-248.96,"z":334.82},{"x":276.24,"y":-252.4,"z":331.52},{"x":273.21,"y":-256.19,"z":331.12},{"x":269.32,"y":-256.54,"z":334.03},{"x":268.47,"y":-253.1,"z":337.32}]},{"lat":31.27,"lon":131.43,"b":[{"x":281.95,"y":-256.09,"z":323.79},{"x":285.76,"y":-255.66,"z":320.78},{"x":286.55,"y":-259.03,"z":317.35},{"x":283.51,"y":-262.84,"z":316.95},{"x":279.69,"y":-263.27,"z":319.97},{"x":278.92,"y":-259.89,"z":323.39}]},{"lat":32.13,"lon":133.75,"b":[{"x":292.18,"y":-263.02,"z":308.84},{"x":295.37,"y":-262.58,"z":306.16},{"x":295.97,"y":-265.41,"z":303.12},{"x":293.37,"y":-268.68,"z":302.77},{"x":290.17,"y":-269.12,"z":305.46},{"x":289.57,"y":-266.29,"z":308.49}]},{"lat":32.95,"lon":136.13,"b":[{"x":301.81,"y":-268.64,"z":294.38},{"x":305.44,"y":-268.05,"z":291.16},{"x":306.05,"y":-271.27,"z":287.52},{"x":303.02,"y":-275.09,"z":287.1},{"x":299.37,"y":-275.69,"z":290.33},{"x":298.77,"y":-272.46,"z":293.97}]},{"lat":33.72,"lon":138.54,"b":[{"x":311.22,"y":-274.91,"z":278.38},{"x":314.15,"y":-274.34,"z":275.63},{"x":314.57,"y":-276.94,"z":272.54},{"x":312.06,"y":-280.11,"z":272.18},{"x":309.12,"y":-280.69,"z":274.93},{"x":308.7,"y":-278.08,"z":278.04}]},{"lat":34.44,"lon":141,"b":[{"x":319.97,"y":-279.69,"z":263.27},{"x":323.39,"y":-278.92,"z":259.89},{"x":323.79,"y":-281.95,"z":256.09},{"x":320.78,"y":-285.76,"z":255.66},{"x":317.35,"y":-286.55,"z":259.03},{"x":316.95,"y":-283.51,"z":262.84}]},{"lat":35.11,"lon":143.48,"b":[{"x":328.33,"y":-284.59,"z":247.24},{"x":331.63,"y":-283.73,"z":243.8},{"x":331.92,"y":-286.66,"z":239.95},{"x":328.92,"y":-290.45,"z":239.51},{"x":325.62,"y":-291.33,"z":242.93},{"x":325.32,"y":-288.4,"z":246.8}]},{"lat":35.73,"lon":145.98,"b":[{"x":336.17,"y":-289.06,"z":230.99},{"x":339.34,"y":-288.11,"z":227.52},{"x":339.52,"y":-290.93,"z":223.63},{"x":336.54,"y":-294.71,"z":223.18},{"x":333.36,"y":-295.68,"z":226.64},{"x":333.17,"y":-292.85,"z":230.55}]},{"lat":36.28,"lon":148.48,"b":[{"x":343.47,"y":-293.09,"z":214.59},{"x":346.5,"y":-292.05,"z":211.1},{"x":346.57,"y":-294.76,"z":207.19},{"x":343.61,"y":-298.51,"z":206.75},{"x":340.57,"y":-299.58,"z":210.21},{"x":340.49,"y":-296.86,"z":214.15}]},{"lat":24.51,"lon":113.22,"b":[{"x":179.18,"y":-206.92,"z":418.41},{"x":179.78,"y":-206.93,"z":418.15},{"x":179.94,"y":-207.47,"z":417.81},{"x":179.49,"y":-208,"z":417.74},{"x":178.89,"y":-207.98,"z":418.01},{"x":178.74,"y":-207.44,"z":418.34}]},{"lat":25.54,"lon":114.98,"b":[{"x":189.44,"y":-211.98,"z":411.23},{"x":193.43,"y":-212.02,"z":409.34},{"x":194.48,"y":-215.6,"z":406.97},{"x":191.5,"y":-219.13,"z":406.49},{"x":187.5,"y":-219.05,"z":408.4},{"x":186.49,"y":-215.47,"z":410.76}]},{"lat":26.57,"lon":116.81,"b":[{"x":200.65,"y":-220.03,"z":401.57},{"x":204.66,"y":-220.04,"z":399.53},{"x":205.71,"y":-223.62,"z":397},{"x":202.69,"y":-227.19,"z":396.52},{"x":198.67,"y":-227.14,"z":398.58},{"x":197.67,"y":-223.57,"z":401.09}]},{"lat":27.59,"lon":118.72,"b":[{"x":211.88,"y":-228,"z":391.22},{"x":215.9,"y":-227.97,"z":389.03},{"x":216.93,"y":-231.55,"z":386.33},{"x":213.89,"y":-235.16,"z":385.85},{"x":209.85,"y":-235.15,"z":388.06},{"x":208.86,"y":-231.58,"z":390.74}]},{"lat":28.61,"lon":120.7,"b":[{"x":223.08,"y":-235.86,"z":380.17},{"x":227.1,"y":-235.78,"z":377.83},{"x":228.1,"y":-239.34,"z":374.98},{"x":225.03,"y":-242.98,"z":374.49},{"x":220.99,"y":-243.03,"z":376.86},{"x":220.03,"y":-239.47,"z":379.69}]},{"lat":29.62,"lon":122.76,"b":[{"x":234.19,"y":-243.56,"z":368.45},{"x":238.21,"y":-243.42,"z":365.96},{"x":239.16,"y":-246.96,"z":362.95},{"x":236.07,"y":-250.63,"z":362.46},{"x":232.05,"y":-250.74,"z":364.97},{"x":231.13,"y":-247.2,"z":367.96}]},{"lat":30.61,"lon":124.88,"b":[{"x":245.18,"y":-251.06,"z":356.05},{"x":249.17,"y":-250.86,"z":353.42},{"x":250.07,"y":-254.35,"z":350.27},{"x":246.97,"y":-258.05,"z":349.77},{"x":242.97,"y":-258.23,"z":352.42},{"x":242.09,"y":-254.73,"z":355.56}]},{"lat":31.58,"lon":127.09,"b":[{"x":255.98,"y":-258.32,"z":343.02},{"x":259.93,"y":-258.05,"z":340.24},{"x":260.77,"y":-261.5,"z":336.95},{"x":257.65,"y":-265.21,"z":336.45},{"x":253.7,"y":-265.46,"z":339.24},{"x":252.88,"y":-262.02,"z":342.52}]},{"lat":32.51,"lon":129.35,"b":[{"x":267.19,"y":-268,"z":326.75},{"x":268.02,"y":-267.92,"z":326.13},{"x":268.19,"y":-268.65,"z":325.39},{"x":267.52,"y":-269.45,"z":325.28},{"x":266.68,"y":-269.52,"z":325.91},{"x":266.51,"y":-268.8,"z":326.65}]},{"lat":35.09,"lon":136.51,"b":[{"x":296.67,"y":-286.37,"z":282.75},{"x":297.84,"y":-286.18,"z":281.71},{"x":298,"y":-287.19,"z":280.51},{"x":297,"y":-288.39,"z":280.34},{"x":295.82,"y":-288.59,"z":281.38},{"x":295.66,"y":-287.58,"z":282.58}]},{"lat":35.85,"lon":139,"b":[{"x":305.62,"y":-291.24,"z":267.81},{"x":307.43,"y":-290.89,"z":266.13},{"x":307.63,"y":-292.44,"z":264.19},{"x":306.04,"y":-294.34,"z":263.92},{"x":304.23,"y":-294.7,"z":265.61},{"x":304.02,"y":-293.15,"z":267.55}]},{"lat":36.56,"lon":141.52,"b":[{"x":314.03,"y":-294.81,"z":253.75},{"x":317.46,"y":-294.02,"z":250.38},{"x":317.76,"y":-296.96,"z":246.51},{"x":314.64,"y":-300.67,"z":246},{"x":311.22,"y":-301.47,"z":249.36},{"x":310.9,"y":-298.54,"z":253.24}]},{"lat":37.21,"lon":144.07,"b":[{"x":322.18,"y":-299.45,"z":237.59},{"x":325.48,"y":-298.57,"z":234.17},{"x":325.67,"y":-301.39,"z":230.26},{"x":322.57,"y":-305.09,"z":229.75},{"x":319.27,"y":-305.99,"z":233.15},{"x":319.06,"y":-303.17,"z":237.08}]},{"lat":37.79,"lon":146.63,"b":[{"x":329.81,"y":-303.64,"z":221.25},{"x":332.98,"y":-302.66,"z":217.8},{"x":333.06,"y":-305.38,"z":213.86},{"x":329.98,"y":-309.05,"z":213.35},{"x":326.81,"y":-310.04,"z":216.78},{"x":326.71,"y":-307.33,"z":220.74}]},{"lat":38.32,"lon":149.2,"b":[{"x":336.93,"y":-309.03,"z":202.34},{"x":338.08,"y":-308.63,"z":201.04},{"x":338.06,"y":-309.6,"z":199.56},{"x":336.92,"y":-310.97,"z":199.37},{"x":335.77,"y":-311.38,"z":200.66},{"x":335.78,"y":-310.41,"z":202.15}]},{"lat":27.55,"lon":114.82,"b":[{"x":185.09,"y":-227.78,"z":404.71},{"x":188.99,"y":-227.87,"z":402.85},{"x":189.96,"y":-231.35,"z":400.4},{"x":186.99,"y":-234.75,"z":399.83},{"x":183.08,"y":-234.62,"z":401.71},{"x":182.15,"y":-231.14,"z":404.14}]},{"lat":28.61,"lon":116.69,"b":[{"x":196.17,"y":-235.84,"z":394.75},{"x":200.2,"y":-235.88,"z":392.69},{"x":201.18,"y":-239.46,"z":390.01},{"x":198.1,"y":-242.98,"z":389.42},{"x":194.06,"y":-242.89,"z":391.5},{"x":193.12,"y":-239.32,"z":394.16}]},{"lat":29.66,"lon":118.64,"b":[{"x":207.29,"y":-243.88,"z":384.03},{"x":211.33,"y":-243.88,"z":381.82},{"x":212.29,"y":-247.44,"z":378.99},{"x":209.17,"y":-250.99,"z":378.39},{"x":205.12,"y":-250.95,"z":380.62},{"x":204.2,"y":-247.4,"z":383.44}]},{"lat":30.71,"lon":120.67,"b":[{"x":218.36,"y":-251.77,"z":372.63},{"x":222.4,"y":-251.72,"z":370.27},{"x":223.32,"y":-255.25,"z":367.28},{"x":220.18,"y":-258.83,"z":366.68},{"x":216.13,"y":-258.85,"z":369.06},{"x":215.24,"y":-255.32,"z":372.03}]},{"lat":31.74,"lon":122.78,"b":[{"x":229.34,"y":-259.47,"z":360.56},{"x":233.36,"y":-259.36,"z":358.05},{"x":234.24,"y":-262.85,"z":354.91},{"x":231.07,"y":-266.45,"z":354.3},{"x":227.04,"y":-266.54,"z":356.83},{"x":226.19,"y":-263.05,"z":359.95}]},{"lat":32.74,"lon":124.97,"b":[{"x":240.29,"y":-267.4,"z":347.4},{"x":243.75,"y":-267.24,"z":345.1},{"x":244.46,"y":-270.23,"z":342.26},{"x":241.7,"y":-273.36,"z":341.73},{"x":238.23,"y":-273.5,"z":344.05},{"x":237.54,"y":-270.52,"z":346.88}]},{"lat":38.66,"lon":142.07,"b":[{"x":307.8,"y":-311,"z":241.85},{"x":309.43,"y":-310.62,"z":240.26},{"x":309.52,"y":-311.96,"z":238.4},{"x":308.01,"y":-313.67,"z":238.12},{"x":306.39,"y":-314.05,"z":239.7},{"x":306.28,"y":-312.72,"z":241.57}]},{"lat":39.29,"lon":144.68,"b":[{"x":315.75,"y":-316.22,"z":224.27},{"x":316.22,"y":-316.09,"z":223.78},{"x":316.23,"y":-316.48,"z":223.22},{"x":315.78,"y":-316.99,"z":223.13},{"x":315.3,"y":-317.12,"z":223.62},{"x":315.29,"y":-316.73,"z":224.19}]},{"lat":29.59,"lon":114.65,"b":[{"x":181.06,"y":-245.81,"z":395.94},{"x":182.25,"y":-245.85,"z":395.37},{"x":182.52,"y":-246.9,"z":394.59},{"x":181.6,"y":-247.91,"z":394.38},{"x":180.42,"y":-247.85,"z":394.96},{"x":180.16,"y":-246.81,"z":395.74}]},{"lat":30.67,"lon":116.57,"b":[{"x":191.4,"y":-251.49,"z":387.36},{"x":195.44,"y":-251.58,"z":385.27},{"x":196.36,"y":-255.13,"z":382.46},{"x":193.2,"y":-258.59,"z":381.75},{"x":189.16,"y":-258.46,"z":383.86},{"x":188.28,"y":-254.91,"z":386.65}]},{"lat":31.75,"lon":118.56,"b":[{"x":202.39,"y":-259.56,"z":376.29},{"x":206.44,"y":-259.6,"z":374.05},{"x":207.33,"y":-263.13,"z":371.08},{"x":204.13,"y":-266.61,"z":370.37},{"x":200.09,"y":-266.53,"z":372.63},{"x":199.23,"y":-263.01,"z":375.57}]},{"lat":32.82,"lon":120.65,"b":[{"x":213.32,"y":-267.45,"z":364.54},{"x":217.36,"y":-267.43,"z":362.15},{"x":218.21,"y":-270.92,"z":359.03},{"x":214.99,"y":-274.42,"z":358.32},{"x":210.95,"y":-274.41,"z":360.72},{"x":210.13,"y":-270.93,"z":363.82}]},{"lat":33.86,"lon":122.81,"b":[{"x":224.23,"y":-275.45,"z":351.82},{"x":227.86,"y":-275.38,"z":349.53},{"x":228.58,"y":-278.48,"z":346.59},{"x":225.65,"y":-281.66,"z":345.94},{"x":222.02,"y":-281.71,"z":348.24},{"x":221.32,"y":-278.61,"z":351.17}]},{"lat":41.35,"lon":145.34,"b":[{"x":308.67,"y":-329.14,"z":215.29},{"x":310.17,"y":-328.73,"z":213.75},{"x":310.18,"y":-329.9,"z":211.93},{"x":308.69,"y":-331.48,"z":211.64},{"x":307.19,"y":-331.9,"z":213.16},{"x":307.17,"y":-330.73,"z":214.99}]},{"lat":41.88,"lon":148.04,"b":[{"x":315.84,"y":-332.17,"z":199.63},{"x":317.88,"y":-331.53,"z":197.44},{"x":317.82,"y":-333.11,"z":194.87},{"x":315.73,"y":-335.32,"z":194.47},{"x":313.7,"y":-335.97,"z":196.63},{"x":313.74,"y":-334.4,"z":199.22}]},{"lat":32.75,"lon":116.43,"b":[{"x":186.47,"y":-267.44,"z":379},{"x":189.93,"y":-267.55,"z":377.2},{"x":190.66,"y":-270.56,"z":374.67},{"x":187.9,"y":-273.45,"z":373.97},{"x":184.45,"y":-273.3,"z":375.79},{"x":183.74,"y":-270.3,"z":378.3}]},{"lat":33.85,"lon":118.48,"b":[{"x":197.19,"y":-275,"z":367.99},{"x":201.24,"y":-275.07,"z":365.73},{"x":202.06,"y":-278.55,"z":362.63},{"x":198.8,"y":-281.94,"z":361.81},{"x":194.76,"y":-281.83,"z":364.09},{"x":193.97,"y":-278.37,"z":367.17}]},{"lat":34.93,"lon":120.62,"b":[{"x":208.62,"y":-285.7,"z":353.32},{"x":209.35,"y":-285.7,"z":352.89},{"x":209.48,"y":-286.32,"z":352.31},{"x":208.9,"y":-286.93,"z":352.16},{"x":208.17,"y":-286.92,"z":352.6},{"x":208.04,"y":-286.31,"z":353.18}]},{"lat":43.39,"lon":146.02,"b":[{"x":301.29,"y":-341.73,"z":205.88},{"x":303.61,"y":-341.09,"z":203.51},{"x":303.56,"y":-342.81,"z":200.68},{"x":301.21,"y":-345.16,"z":200.2},{"x":298.89,"y":-345.81,"z":202.53},{"x":298.92,"y":-344.1,"z":205.38}]},{"lat":34.83,"lon":116.3,"b":[{"x":181.25,"y":-283.08,"z":370.07},{"x":184.14,"y":-283.2,"z":368.55},{"x":184.7,"y":-285.68,"z":366.35},{"x":182.36,"y":-288.02,"z":365.69},{"x":179.48,"y":-287.87,"z":367.23},{"x":178.94,"y":-285.41,"z":369.41}]},{"lat":-53.46,"lon":-59.73,"b":[{"x":-150.26,"y":403.6,"z":-253.9},{"x":-147.16,"y":403.43,"z":-255.99},{"x":-146.95,"y":401.49,"z":-259.14},{"x":-149.83,"y":399.71,"z":-260.24},{"x":-152.92,"y":399.87,"z":-258.18},{"x":-153.14,"y":401.82,"z":-255}]},{"lat":-52.33,"lon":-62.51,"b":[{"x":-141.32,"y":398.16,"z":-267.26},{"x":-137.5,"y":397.83,"z":-269.73},{"x":-137.23,"y":395.37,"z":-273.47},{"x":-140.72,"y":393.21,"z":-274.8},{"x":-144.5,"y":393.51,"z":-272.4},{"x":-144.82,"y":396,"z":-268.59}]},{"lat":-51.14,"lon":-65.13,"b":[{"x":-132.2,"y":391.84,"z":-280.92},{"x":-128.34,"y":391.39,"z":-283.33},{"x":-128.05,"y":388.84,"z":-286.95},{"x":-131.53,"y":386.68,"z":-288.28},{"x":-135.32,"y":387.08,"z":-286},{"x":-135.69,"y":389.68,"z":-282.26}]},{"lat":-49.91,"lon":-67.61,"b":[{"x":-122.96,"y":385.07,"z":-294.17},{"x":-119.07,"y":384.5,"z":-296.5},{"x":-118.77,"y":381.87,"z":-299.99},{"x":-122.24,"y":379.73,"z":-301.32},{"x":-126.02,"y":380.21,"z":-299.16},{"x":-126.44,"y":382.91,"z":-295.5}]},{"lat":-48.63,"lon":-69.94,"b":[{"x":-113.64,"y":377.77,"z":-307.1},{"x":-109.9,"y":377.13,"z":-309.25},{"x":-109.61,"y":374.55,"z":-312.46},{"x":-112.91,"y":372.51,"z":-313.72},{"x":-116.52,"y":373.04,"z":-311.78},{"x":-116.96,"y":375.72,"z":-308.37}]},{"lat":-47.33,"lon":-72.13,"b":[{"x":-104.3,"y":370.33,"z":-319.24},{"x":-100.38,"y":369.55,"z":-321.39},{"x":-100.09,"y":366.8,"z":-324.61},{"x":-103.52,"y":364.69,"z":-325.92},{"x":-107.26,"y":365.3,"z":-324.01},{"x":-107.75,"y":368.2,"z":-320.56}]},{"lat":-46,"lon":-74.18,"b":[{"x":-94.95,"y":362.41,"z":-331.03},{"x":-91.06,"y":361.55,"z":-333.05},{"x":-90.78,"y":358.78,"z":-336.11},{"x":-94.15,"y":356.7,"z":-337.4},{"x":-97.83,"y":357.37,"z":-335.64},{"x":-98.34,"y":360.31,"z":-332.33}]},{"lat":-44.66,"lon":-76.11,"b":[{"x":-85.63,"y":354.25,"z":-342.22},{"x":-81.73,"y":353.3,"z":-344.15},{"x":-81.46,"y":350.47,"z":-347.09},{"x":-84.82,"y":348.39,"z":-348.37},{"x":-88.49,"y":349.11,"z":-346.74},{"x":-89.03,"y":352.15,"z":-343.51}]},{"lat":-43.32,"lon":-77.92,"b":[{"x":-76.37,"y":345.82,"z":-352.87},{"x":-72.49,"y":344.79,"z":-354.69},{"x":-72.24,"y":341.94,"z":-357.48},{"x":-75.58,"y":339.88,"z":-358.76},{"x":-79.2,"y":340.65,"z":-357.25},{"x":-79.74,"y":343.74,"z":-354.15}]},{"lat":-41.97,"lon":-79.62,"b":[{"x":-67.21,"y":337.19,"z":-362.95},{"x":-63.36,"y":336.09,"z":-364.65},{"x":-63.13,"y":333.23,"z":-367.3},{"x":-66.43,"y":331.19,"z":-368.56},{"x":-69.99,"y":331.99,"z":-367.19},{"x":-70.55,"y":335.12,"z":-364.22}]},{"lat":-40.62,"lon":-81.22,"b":[{"x":-58.17,"y":328.39,"z":-372.45},{"x":-54.36,"y":327.23,"z":-374.04},{"x":-54.15,"y":324.38,"z":-376.55},{"x":-57.42,"y":322.36,"z":-377.8},{"x":-60.92,"y":323.18,"z":-376.55},{"x":-61.47,"y":326.35,"z":-373.71}]},{"lat":-39.29,"lon":-82.71,"b":[{"x":-49.28,"y":319.47,"z":-381.39},{"x":-45.51,"y":318.26,"z":-382.86},{"x":-45.34,"y":315.42,"z":-385.23},{"x":-48.56,"y":313.43,"z":-386.46},{"x":-51.99,"y":314.26,"z":-385.34},{"x":-52.54,"y":317.46,"z":-382.63}]},{"lat":-37.97,"lon":-84.12,"b":[{"x":-40.55,"y":310.48,"z":-389.75},{"x":-36.83,"y":309.23,"z":-391.11},{"x":-36.69,"y":306.4,"z":-393.34},{"x":-39.87,"y":304.44,"z":-394.56},{"x":-43.23,"y":305.27,"z":-393.56},{"x":-43.77,"y":308.49,"z":-390.98}]},{"lat":-36.68,"lon":-85.44,"b":[{"x":-32.01,"y":301.44,"z":-397.57},{"x":-28.35,"y":300.16,"z":-398.81},{"x":-28.25,"y":297.35,"z":-400.91},{"x":-31.38,"y":295.42,"z":-402.11},{"x":-34.66,"y":296.25,"z":-401.22},{"x":-35.19,"y":299.48,"z":-398.78}]},{"lat":-35.4,"lon":-86.68,"b":[{"x":-23.68,"y":292.39,"z":-404.84},{"x":-20.08,"y":291.09,"z":-405.98},{"x":-20.01,"y":288.32,"z":-407.95},{"x":-23.1,"y":286.41,"z":-409.13},{"x":-26.3,"y":287.24,"z":-408.35},{"x":-26.81,"y":290.46,"z":-406.04}]},{"lat":-34.14,"lon":-87.85,"b":[{"x":-15.56,"y":283.37,"z":-411.6},{"x":-12.02,"y":282.05,"z":-412.62},{"x":-11.99,"y":279.32,"z":-414.48},{"x":-15.03,"y":277.44,"z":-415.64},{"x":-18.15,"y":278.26,"z":-414.96},{"x":-18.65,"y":281.46,"z":-412.78}]},{"lat":-32.92,"lon":-88.96,"b":[{"x":-7.66,"y":274.41,"z":-417.85},{"x":-4.2,"y":273.07,"z":-418.77},{"x":-4.2,"y":270.38,"z":-420.51},{"x":-7.19,"y":268.53,"z":-421.66},{"x":-10.23,"y":269.34,"z":-421.08},{"x":-10.71,"y":272.53,"z":-419.01}]},{"lat":-64.51,"lon":-14.51,"b":[{"x":-208.07,"y":451.68,"z":-51.5},{"x":-210,"y":450.66,"z":-52.63},{"x":-210.24,"y":450.26,"z":-55.05},{"x":-208.54,"y":450.88,"z":-56.39},{"x":-206.58,"y":451.92,"z":-55.27},{"x":-206.35,"y":452.32,"z":-52.81}]},{"lat":-63.04,"lon":-17.28,"b":[{"x":-216.37,"y":445.78,"z":-66.75},{"x":-216.82,"y":445.52,"z":-67.02},{"x":-216.88,"y":445.4,"z":-67.61},{"x":-216.47,"y":445.55,"z":-67.94},{"x":-216,"y":445.82,"z":-67.67},{"x":-215.95,"y":445.93,"z":-67.07}]},{"lat":-66.19,"lon":-15.72,"b":[{"x":-194.15,"y":457.63,"z":-53.47},{"x":-195.12,"y":457.15,"z":-54.03},{"x":-195.23,"y":456.96,"z":-55.22},{"x":-194.37,"y":457.25,"z":-55.87},{"x":-193.39,"y":457.74,"z":-55.32},{"x":-193.28,"y":457.92,"z":-54.11}]},{"lat":-64.68,"lon":-18.63,"b":[{"x":-202.21,"y":452.7,"z":-64.1},{"x":-205.54,"y":450.94,"z":-66},{"x":-205.89,"y":450.14,"z":-70.18},{"x":-202.9,"y":451.12,"z":-72.52},{"x":-199.53,"y":452.92,"z":-70.63},{"x":-199.19,"y":453.71,"z":-66.39}]},{"lat":-64.75,"lon":-22.88,"b":[{"x":-196.41,"y":452.5,"z":-81.51},{"x":-197.56,"y":451.88,"z":-82.15},{"x":-197.66,"y":451.57,"z":-83.59},{"x":-196.61,"y":451.88,"z":-84.41},{"x":-195.45,"y":452.5,"z":-83.77},{"x":-195.35,"y":452.81,"z":-82.31}]},{"lat":-69.77,"lon":-24.2,"b":[{"x":-157.57,"y":469.47,"z":-68.82},{"x":-159.3,"y":468.74,"z":-69.78},{"x":-159.44,"y":468.38,"z":-71.84},{"x":-157.84,"y":468.75,"z":-72.97},{"x":-156.08,"y":469.49,"z":-72.02},{"x":-155.95,"y":469.84,"z":-69.93}]},{"lat":-68.04,"lon":-27.07,"b":[{"x":-166.4,"y":463.96,"z":-83.81},{"x":-167.43,"y":463.49,"z":-84.38},{"x":-167.51,"y":463.23,"z":-85.63},{"x":-166.55,"y":463.45,"z":-86.32},{"x":-165.5,"y":463.93,"z":-85.76},{"x":-165.43,"y":464.19,"z":-84.5}]},{"lat":-74.86,"lon":-19.12,"b":[{"x":-123.26,"y":482.76,"z":-41.53},{"x":-124.36,"y":482.43,"z":-42.13},{"x":-124.45,"y":482.29,"z":-43.37},{"x":-123.43,"y":482.5,"z":-44.03},{"x":-122.32,"y":482.83,"z":-43.43},{"x":-122.24,"y":482.96,"z":-42.17}]},{"lat":-73.21,"lon":-23.34,"b":[{"x":-132.33,"y":479.11,"z":-53.71},{"x":-135.36,"y":478.08,"z":-55.37},{"x":-135.6,"y":477.59,"z":-58.86},{"x":-132.78,"y":478.14,"z":-60.73},{"x":-129.71,"y":479.2,"z":-59.07},{"x":-129.49,"y":479.67,"z":-55.54}]},{"lat":-71.49,"lon":-26.82,"b":[{"x":-141.43,"y":474.69,"z":-67.85},{"x":-144.66,"y":473.46,"z":-69.61},{"x":-144.9,"y":472.82,"z":-73.39},{"x":-141.88,"y":473.41,"z":-75.45},{"x":-138.6,"y":474.65,"z":-73.69},{"x":-138.39,"y":475.29,"z":-69.87}]},{"lat":-69.7,"lon":-29.73,"b":[{"x":-150.36,"y":469.75,"z":-81.6},{"x":-154.08,"y":468.19,"z":-83.61},{"x":-154.33,"y":467.3,"z":-88.02},{"x":-150.84,"y":467.97,"z":-90.47},{"x":-147.07,"y":469.55,"z":-88.46},{"x":-146.84,"y":470.44,"z":-84}]},{"lat":-67.87,"lon":-32.18,"b":[{"x":-159.24,"y":463.75,"z":-97.61},{"x":-161.47,"y":462.73,"z":-98.8},{"x":-161.6,"y":462.11,"z":-101.48},{"x":-159.5,"y":462.5,"z":-102.99},{"x":-157.25,"y":463.53,"z":-101.8},{"x":-157.12,"y":464.16,"z":-99.1}]},{"lat":-66.02,"lon":-34.27,"b":[{"x":-167.88,"y":457.15,"z":-113.19},{"x":-168.87,"y":456.65,"z":-113.72},{"x":-168.92,"y":456.33,"z":-114.93},{"x":-167.97,"y":456.5,"z":-115.63},{"x":-166.96,"y":457,"z":-115.11},{"x":-166.92,"y":457.33,"z":-113.88}]},{"lat":-76.7,"lon":-22.02,"b":[{"x":-106.39,"y":486.86,"z":-39.99},{"x":-109.19,"y":486.11,"z":-41.51},{"x":-109.39,"y":485.78,"z":-44.64},{"x":-106.77,"y":486.21,"z":-46.29},{"x":-103.93,"y":486.97,"z":-44.76},{"x":-103.76,"y":487.29,"z":-41.6}]},{"lat":-74.99,"lon":-26.47,"b":[{"x":-115.64,"y":483.45,"z":-53.28},{"x":-119.54,"y":482.26,"z":-55.4},{"x":-119.81,"y":481.66,"z":-59.83},{"x":-116.15,"y":482.26,"z":-62.19},{"x":-112.2,"y":483.46,"z":-60.06},{"x":-111.96,"y":484.05,"z":-55.59}]},{"lat":-73.2,"lon":-30.02,"b":[{"x":-124.89,"y":479.3,"z":-67.87},{"x":-128.75,"y":477.98,"z":-69.95},{"x":-129,"y":477.23,"z":-74.41},{"x":-125.36,"y":477.82,"z":-76.82},{"x":-121.45,"y":479.16,"z":-74.72},{"x":-121.23,"y":479.9,"z":-70.22}]},{"lat":-71.34,"lon":-32.91,"b":[{"x":-134.02,"y":474.53,"z":-82.43},{"x":-137.84,"y":473.07,"z":-84.48},{"x":-138.07,"y":472.18,"z":-88.94},{"x":-134.45,"y":472.76,"z":-91.39},{"x":-130.58,"y":474.23,"z":-89.34},{"x":-130.38,"y":475.11,"z":-84.83}]},{"lat":-69.45,"lon":-35.29,"b":[{"x":-142.99,"y":469.14,"z":-96.91},{"x":-146.76,"y":467.56,"z":-98.92},{"x":-146.96,"y":466.53,"z":-103.37},{"x":-143.37,"y":467.08,"z":-105.87},{"x":-139.56,"y":468.68,"z":-103.86},{"x":-139.38,"y":469.71,"z":-99.36}]},{"lat":-67.54,"lon":-37.29,"b":[{"x":-151.78,"y":463.16,"z":-111.26},{"x":-155.48,"y":461.45,"z":-113.21},{"x":-155.65,"y":460.29,"z":-117.64},{"x":-152.1,"y":460.82,"z":-120.17},{"x":-148.34,"y":462.54,"z":-118.23},{"x":-148.19,"y":463.71,"z":-113.75}]},{"lat":-65.61,"lon":-38.97,"b":[{"x":-160.4,"y":456.19,"z":-126.92},{"x":-162.81,"y":454.99,"z":-128.17},{"x":-162.89,"y":454.13,"z":-131.08},{"x":-160.56,"y":454.47,"z":-132.78},{"x":-158.12,"y":455.68,"z":-131.54},{"x":-158.04,"y":456.55,"z":-128.59}]},{"lat":-63.68,"lon":-40.42,"b":[{"x":-168.73,"y":448.71,"z":-141.97},{"x":-170.16,"y":447.94,"z":-142.7},{"x":-170.19,"y":447.37,"z":-144.44},{"x":-168.8,"y":447.56,"z":-145.48},{"x":-167.35,"y":448.34,"z":-144.77},{"x":-167.32,"y":448.91,"z":-143}]},{"lat":-61.75,"lon":-41.67,"b":[{"x":-176.75,"y":440.83,"z":-156.23},{"x":-177.62,"y":440.33,"z":-156.66},{"x":-177.63,"y":439.94,"z":-157.74},{"x":-176.77,"y":440.05,"z":-158.39},{"x":-175.89,"y":440.56,"z":-157.96},{"x":-175.88,"y":440.95,"z":-156.88}]},{"lat":-59.84,"lon":-42.76,"b":[{"x":-184.46,"y":432.54,"z":-169.9},{"x":-184.97,"y":432.23,"z":-170.15},{"x":-184.97,"y":431.97,"z":-170.8},{"x":-184.45,"y":432.04,"z":-171.2},{"x":-183.93,"y":432.36,"z":-170.95},{"x":-183.93,"y":432.61,"z":-170.3}]},{"lat":-81.71,"lon":-11.43,"b":[{"x":-70.62,"y":494.79,"z":-13.37},{"x":-71.47,"y":494.66,"z":-13.83},{"x":-71.52,"y":494.62,"z":-14.76},{"x":-70.71,"y":494.72,"z":-15.23},{"x":-69.85,"y":494.86,"z":-14.76},{"x":-69.81,"y":494.89,"z":-13.84}]},{"lat":-80.2,"lon":-19.78,"b":[{"x":-79.87,"y":492.86,"z":-25.51},{"x":-82.86,"y":492.28,"z":-27.12},{"x":-83.04,"y":492.06,"z":-30.41},{"x":-80.2,"y":492.42,"z":-32.11},{"x":-77.17,"y":493.01,"z":-30.48},{"x":-77.03,"y":493.23,"z":-27.17}]},{"lat":-78.53,"lon":-25.89,"b":[{"x":-89.21,"y":490.36,"z":-39},{"x":-93.19,"y":489.44,"z":-41.15},{"x":-93.44,"y":489,"z":-45.59},{"x":-89.66,"y":489.49,"z":-47.9},{"x":-85.63,"y":490.41,"z":-45.73},{"x":-85.42,"y":490.84,"z":-41.26}]},{"lat":-76.74,"lon":-30.47,"b":[{"x":-98.6,"y":487.16,"z":-53.69},{"x":-102.57,"y":486.1,"z":-55.84},{"x":-102.81,"y":485.51,"z":-60.31},{"x":-99.04,"y":486,"z":-62.67},{"x":-95.02,"y":487.07,"z":-60.51},{"x":-94.82,"y":487.65,"z":-56}]},{"lat":-74.87,"lon":-33.99,"b":[{"x":-107.94,"y":483.32,"z":-68.43},{"x":-111.89,"y":482.11,"z":-70.56},{"x":-112.11,"y":481.38,"z":-75.06},{"x":-108.36,"y":481.85,"z":-77.47},{"x":-104.37,"y":483.07,"z":-75.33},{"x":-104.17,"y":483.8,"z":-70.8}]},{"lat":-72.96,"lon":-36.75,"b":[{"x":-117.2,"y":478.83,"z":-83.17},{"x":-121.11,"y":477.48,"z":-85.27},{"x":-121.32,"y":476.6,"z":-89.78},{"x":-117.59,"y":477.07,"z":-92.23},{"x":-113.63,"y":478.43,"z":-90.13},{"x":-113.45,"y":479.3,"z":-85.58}]},{"lat":-71,"lon":-38.97,"b":[{"x":-126.33,"y":473.7,"z":-97.85},{"x":-130.2,"y":472.22,"z":-99.9},{"x":-130.39,"y":471.2,"z":-104.41},{"x":-126.68,"y":471.65,"z":-106.9},{"x":-122.77,"y":473.14,"z":-104.85},{"x":-122.6,"y":474.17,"z":-100.3}]},{"lat":-69.03,"lon":-40.79,"b":[{"x":-135.31,"y":467.96,"z":-112.41},{"x":-139.12,"y":466.35,"z":-114.41},{"x":-139.28,"y":465.18,"z":-118.9},{"x":-135.6,"y":465.61,"z":-121.42},{"x":-131.74,"y":467.23,"z":-119.43},{"x":-131.6,"y":468.41,"z":-114.9}]},{"lat":-67.04,"lon":-42.31,"b":[{"x":-144.09,"y":461.62,"z":-126.79},{"x":-147.84,"y":459.89,"z":-128.73},{"x":-147.96,"y":458.58,"z":-133.18},{"x":-144.31,"y":458.99,"z":-135.74},{"x":-140.52,"y":460.73,"z":-133.82},{"x":-140.41,"y":462.05,"z":-129.32}]},{"lat":-65.05,"lon":-43.58,"b":[{"x":-152.64,"y":454.71,"z":-140.95},{"x":-156.33,"y":452.88,"z":-142.81},{"x":-156.4,"y":451.44,"z":-147.22},{"x":-152.79,"y":451.82,"z":-149.81},{"x":-149.07,"y":453.67,"z":-147.96},{"x":-149,"y":455.12,"z":-143.51}]},{"lat":-63.07,"lon":-44.68,"b":[{"x":-160.95,"y":447.28,"z":-154.82},{"x":-164.55,"y":445.34,"z":-156.61},{"x":-164.58,"y":443.78,"z":-160.95},{"x":-161.01,"y":444.13,"z":-163.56},{"x":-157.36,"y":446.08,"z":-161.8},{"x":-157.34,"y":447.66,"z":-157.41}]},{"lat":-61.1,"lon":-45.62,"b":[{"x":-168.97,"y":439.21,"z":-168.75},{"x":-172.17,"y":437.37,"z":-170.3},{"x":-172.16,"y":435.84,"z":-174.2},{"x":-168.94,"y":436.13,"z":-176.59},{"x":-165.7,"y":437.98,"z":-175.07},{"x":-165.71,"y":439.53,"z":-171.13}]},{"lat":-82.07,"lon":-24.81,"b":[{"x":-62.47,"y":495.34,"z":-26.39},{"x":-64.8,"y":494.97,"z":-27.64},{"x":-64.92,"y":494.8,"z":-30.2},{"x":-62.67,"y":495.01,"z":-31.51},{"x":-60.31,"y":495.38,"z":-30.24},{"x":-60.22,"y":495.54,"z":-27.67}]},{"lat":-80.31,"lon":-31.25,"b":[{"x":-71.78,"y":493.19,"z":-39.23},{"x":-75.81,"y":492.41,"z":-41.4},{"x":-76.01,"y":491.98,"z":-45.87},{"x":-72.14,"y":492.34,"z":-48.18},{"x":-68.07,"y":493.13,"z":-45.98},{"x":-67.91,"y":493.55,"z":-41.49}]},{"lat":-78.43,"lon":-35.72,"b":[{"x":-81.2,"y":490.32,"z":-54.04},{"x":-85.23,"y":489.39,"z":-56.21},{"x":-85.43,"y":488.82,"z":-60.72},{"x":-81.56,"y":489.18,"z":-63.08},{"x":-77.49,"y":490.12,"z":-60.89},{"x":-77.32,"y":490.68,"z":-56.35}]},{"lat":-76.49,"lon":-38.97,"b":[{"x":-90.6,"y":486.79,"z":-68.93},{"x":-94.62,"y":485.72,"z":-71.09},{"x":-94.81,"y":484.99,"z":-75.62},{"x":-90.96,"y":485.35,"z":-78.03},{"x":-86.9,"y":486.44,"z":-75.85},{"x":-86.73,"y":487.16,"z":-71.29}]},{"lat":-74.51,"lon":-41.43,"b":[{"x":-99.95,"y":482.61,"z":-83.83},{"x":-103.94,"y":481.39,"z":-85.96},{"x":-104.13,"y":480.51,"z":-90.51},{"x":-100.29,"y":480.86,"z":-92.96},{"x":-96.25,"y":482.09,"z":-90.82},{"x":-96.1,"y":482.96,"z":-86.24}]},{"lat":-72.49,"lon":-43.35,"b":[{"x":-109.21,"y":477.76,"z":-98.69},{"x":-113.17,"y":476.4,"z":-100.79},{"x":-113.34,"y":475.38,"z":-105.34},{"x":-109.52,"y":475.71,"z":-107.82},{"x":-105.52,"y":477.09,"z":-105.72},{"x":-105.38,"y":478.11,"z":-101.14}]},{"lat":-70.46,"lon":-44.88,"b":[{"x":-118.35,"y":472.28,"z":-113.45},{"x":-122.26,"y":470.79,"z":-115.5},{"x":-122.4,"y":469.61,"z":-120.03},{"x":-118.61,"y":469.93,"z":-122.55},{"x":-114.65,"y":471.44,"z":-120.51},{"x":-114.53,"y":472.62,"z":-115.94}]},{"lat":-68.42,"lon":-46.13,"b":[{"x":-127.32,"y":466.17,"z":-128.05},{"x":-131.18,"y":464.55,"z":-130.04},{"x":-131.29,"y":463.24,"z":-134.54},{"x":-127.53,"y":463.54,"z":-137.09},{"x":-123.63,"y":465.17,"z":-135.11},{"x":-123.53,"y":466.49,"z":-130.57}]},{"lat":-66.38,"lon":-47.17,"b":[{"x":-136.1,"y":459.48,"z":-142.42},{"x":-139.89,"y":457.74,"z":-144.35},{"x":-139.96,"y":456.28,"z":-148.8},{"x":-136.23,"y":456.56,"z":-151.38},{"x":-132.4,"y":458.32,"z":-149.48},{"x":-132.33,"y":459.78,"z":-144.98}]},{"lat":-64.35,"lon":-48.05,"b":[{"x":-144.64,"y":452.22,"z":-156.53},{"x":-148.37,"y":450.37,"z":-158.38},{"x":-148.4,"y":448.79,"z":-162.77},{"x":-144.7,"y":449.04,"z":-165.37},{"x":-140.94,"y":450.9,"z":-163.55},{"x":-140.91,"y":452.5,"z":-159.11}]},{"lat":-62.33,"lon":-48.8,"b":[{"x":-152.93,"y":444.43,"z":-170.36},{"x":-156.54,"y":442.5,"z":-172.1},{"x":-156.53,"y":440.82,"z":-176.39},{"x":-152.9,"y":441.04,"z":-178.98},{"x":-149.25,"y":442.98,"z":-177.27},{"x":-149.27,"y":444.68,"z":-172.93}]},{"lat":-81.98,"lon":-38.97,"b":[{"x":-54.08,"y":495.43,"z":-39.41},{"x":-58.15,"y":494.79,"z":-41.6},{"x":-58.31,"y":494.37,"z":-46.09},{"x":-54.36,"y":494.6,"z":-48.4},{"x":-50.25,"y":495.25,"z":-46.18},{"x":-50.13,"y":495.66,"z":-41.67}]},{"lat":-80.02,"lon":-42.76,"b":[{"x":-63.48,"y":492.9,"z":-54.32},{"x":-67.56,"y":492.11,"z":-56.52},{"x":-67.72,"y":491.54,"z":-61.06},{"x":-63.77,"y":491.77,"z":-63.41},{"x":-59.66,"y":492.57,"z":-61.19},{"x":-59.53,"y":493.13,"z":-56.64}]},{"lat":-78,"lon":-45.32,"b":[{"x":-72.91,"y":489.7,"z":-69.34},{"x":-76.98,"y":488.76,"z":-71.53},{"x":-77.15,"y":488.04,"z":-76.1},{"x":-73.2,"y":488.27,"z":-78.5},{"x":-69.09,"y":489.22,"z":-76.29},{"x":-68.96,"y":489.93,"z":-71.69}]},{"lat":-75.96,"lon":-47.17,"b":[{"x":-82.32,"y":485.83,"z":-84.39},{"x":-86.38,"y":484.74,"z":-86.56},{"x":-86.54,"y":483.87,"z":-91.15},{"x":-82.61,"y":484.09,"z":-93.59},{"x":-78.51,"y":485.19,"z":-91.4},{"x":-78.38,"y":486.05,"z":-86.79}]},{"lat":-73.89,"lon":-48.56,"b":[{"x":-91.68,"y":481.28,"z":-99.42},{"x":-95.72,"y":480.05,"z":-101.56},{"x":-95.86,"y":479.03,"z":-106.14},{"x":-91.94,"y":479.24,"z":-108.62},{"x":-87.87,"y":480.48,"z":-106.48},{"x":-87.75,"y":481.51,"z":-101.86}]},{"lat":-71.81,"lon":-49.64,"b":[{"x":-100.95,"y":476.08,"z":-114.36},{"x":-104.95,"y":474.71,"z":-116.46},{"x":-105.07,"y":473.53,"z":-121.03},{"x":-101.17,"y":473.73,"z":-123.54},{"x":-97.13,"y":475.12,"z":-121.45},{"x":-97.03,"y":476.29,"z":-116.84}]},{"lat":-69.72,"lon":-50.51,"b":[{"x":-110.11,"y":469.95,"z":-130.22},{"x":-113.15,"y":468.79,"z":-131.79},{"x":-113.22,"y":467.78,"z":-135.28},{"x":-110.25,"y":467.92,"z":-137.23},{"x":-107.18,"y":469.09,"z":-135.67},{"x":-107.12,"y":470.1,"z":-132.15}]},{"lat":-67.64,"lon":-51.22,"b":[{"x":-119.06,"y":463.67,"z":-144.08},{"x":-122.68,"y":462.15,"z":-145.92},{"x":-122.74,"y":460.8,"z":-150.1},{"x":-119.17,"y":460.95,"z":-152.48},{"x":-115.52,"y":462.48,"z":-150.66},{"x":-115.46,"y":463.84,"z":-146.44}]},{"lat":-65.56,"lon":-51.81,"b":[{"x":-127.83,"y":456.44,"z":-158.93},{"x":-130.95,"y":455.01,"z":-160.48},{"x":-130.98,"y":453.71,"z":-164.09},{"x":-127.88,"y":453.83,"z":-166.19},{"x":-124.73,"y":455.26,"z":-164.66},{"x":-124.71,"y":456.57,"z":-161.01}]},{"lat":-63.5,"lon":-52.31,"b":[{"x":-136.38,"y":447.84,"z":-175.55},{"x":-137.22,"y":447.43,"z":-175.96},{"x":-137.22,"y":447.04,"z":-176.93},{"x":-136.37,"y":447.07,"z":-177.51},{"x":-135.52,"y":447.49,"z":-177.11},{"x":-135.53,"y":447.87,"z":-176.13}]},{"lat":-81.41,"lon":-52.31,"b":[{"x":-45.54,"y":494.81,"z":-54.95},{"x":-49.28,"y":494.22,"z":-56.97},{"x":-49.39,"y":493.71,"z":-61.12},{"x":-45.73,"y":493.8,"z":-63.26},{"x":-41.95,"y":494.39,"z":-61.21},{"x":-41.88,"y":494.9,"z":-57.04}]},{"lat":-79.35,"lon":-53.44,"b":[{"x":-54.94,"y":491.99,"z":-69.66},{"x":-59.05,"y":491.19,"z":-71.89},{"x":-59.18,"y":490.48,"z":-76.48},{"x":-55.16,"y":490.57,"z":-78.87},{"x":-51.01,"y":491.38,"z":-76.62},{"x":-50.92,"y":492.08,"z":-72.01}]},{"lat":-77.26,"lon":-54.21,"b":[{"x":-64.37,"y":488.45,"z":-84.85},{"x":-68.49,"y":487.5,"z":-87.05},{"x":-68.61,"y":486.63,"z":-91.67},{"x":-64.6,"y":486.72,"z":-94.09},{"x":-60.45,"y":487.68,"z":-91.87},{"x":-60.35,"y":488.54,"z":-87.23}]},{"lat":-75.15,"lon":-54.77,"b":[{"x":-73.79,"y":484.22,"z":-100.02},{"x":-77.89,"y":483.13,"z":-102.21},{"x":-78.01,"y":482.1,"z":-106.83},{"x":-74.01,"y":482.18,"z":-109.29},{"x":-69.87,"y":483.29,"z":-107.1},{"x":-69.78,"y":484.31,"z":-102.45}]},{"lat":-73.04,"lon":-55.19,"b":[{"x":-83.2,"y":478.95,"z":-116.75},{"x":-85.85,"y":478.14,"z":-118.15},{"x":-85.92,"y":477.37,"z":-121.15},{"x":-83.32,"y":477.42,"z":-122.78},{"x":-80.64,"y":478.23,"z":-121.38},{"x":-80.59,"y":479,"z":-118.36}]},{"lat":-70.92,"lon":-55.52,"b":[{"x":-92.51,"y":472.75,"z":-133.92},{"x":-93.23,"y":472.5,"z":-134.29},{"x":-93.25,"y":472.26,"z":-135.11},{"x":-92.54,"y":472.27,"z":-135.56},{"x":-91.81,"y":472.52,"z":-135.19},{"x":-91.8,"y":472.76,"z":-134.36}]},{"lat":-82.5,"lon":-65.13,"b":[{"x":-27.41,"y":496.01,"z":-56.31},{"x":-30.06,"y":495.69,"z":-57.76},{"x":-30.12,"y":495.33,"z":-60.7},{"x":-27.49,"y":495.3,"z":-62.2},{"x":-24.83,"y":495.62,"z":-60.73},{"x":-24.8,"y":495.98,"z":-57.79}]},{"lat":-80.43,"lon":-63.69,"b":[{"x":-36.78,"y":493.45,"z":-71.38},{"x":-39.59,"y":493.01,"z":-72.91},{"x":-39.65,"y":492.53,"z":-76.03},{"x":-36.88,"y":492.5,"z":-77.64},{"x":-34.05,"y":492.94,"z":-76.1},{"x":-34.01,"y":493.42,"z":-72.96}]},{"lat":-78.34,"lon":-62.75,"b":[{"x":-46.17,"y":490.44,"z":-85.19},{"x":-50.32,"y":489.64,"z":-87.44},{"x":-50.42,"y":488.78,"z":-92.07},{"x":-46.33,"y":488.72,"z":-94.48},{"x":-42.15,"y":489.53,"z":-92.22},{"x":-42.09,"y":490.39,"z":-87.57}]},{"lat":-76.23,"lon":-62.09,"b":[{"x":-55.64,"y":486.29,"z":-101.84},{"x":-58.6,"y":485.6,"z":-103.42},{"x":-58.67,"y":484.87,"z":-106.74},{"x":-55.75,"y":484.83,"z":-108.49},{"x":-52.77,"y":485.52,"z":-106.89},{"x":-52.72,"y":486.25,"z":-103.56}]},{"lat":-55.4,"lon":-59.81,"b":[{"x":-142.81,"y":412.07,"z":-244.5},{"x":-143.63,"y":411.59,"z":-244.84},{"x":-143.58,"y":411.06,"z":-245.75},{"x":-142.7,"y":411.02,"z":-246.34},{"x":-141.87,"y":411.5,"z":-246.01},{"x":-141.92,"y":412.03,"z":-245.09}]},{"lat":-81.15,"lon":-76.11,"b":[{"x":-18.42,"y":494.6,"z":-70.41},{"x":-22.23,"y":494.14,"z":-72.5},{"x":-22.29,"y":493.5,"z":-76.76},{"x":-18.48,"y":493.31,"z":-78.93},{"x":-14.64,"y":493.77,"z":-76.8},{"x":-14.63,"y":494.42,"z":-72.54}]},{"lat":-79.13,"lon":-72.83,"b":[{"x":-27.82,"y":491.24,"z":-88.79},{"x":-28.98,"y":491.06,"z":-89.42},{"x":-28.99,"y":490.82,"z":-90.71},{"x":-27.85,"y":490.76,"z":-91.37},{"x":-26.68,"y":490.95,"z":-90.73},{"x":-26.67,"y":491.19,"z":-89.44}]},{"lat":-77.07,"lon":-70.55,"b":[{"x":-37.24,"y":487.7,"z":-103.56},{"x":-38.99,"y":487.36,"z":-104.51},{"x":-39.02,"y":486.93,"z":-106.47},{"x":-37.29,"y":486.84,"z":-107.49},{"x":-35.52,"y":487.19,"z":-106.53},{"x":-35.5,"y":487.61,"z":-104.57}]},{"lat":-66.5,"lon":-65.13,"b":[{"x":-83.83,"y":460.13,"z":-176.56},{"x":-87.71,"y":458.67,"z":-178.48},{"x":-87.7,"y":456.98,"z":-182.77},{"x":-83.82,"y":456.74,"z":-185.16},{"x":-79.92,"y":458.2,"z":-183.26},{"x":-79.93,"y":459.9,"z":-178.95}]},{"lat":-64.39,"lon":-64.57,"b":[{"x":-92.79,"y":451.39,"z":-193.93},{"x":-93.89,"y":450.94,"z":-194.46},{"x":-93.88,"y":450.41,"z":-195.68},{"x":-92.76,"y":450.34,"z":-196.37},{"x":-91.65,"y":450.8,"z":-195.85},{"x":-91.66,"y":451.33,"z":-194.62}]},{"lat":-58.21,"lon":-63.34,"b":[{"x":-118.27,"y":426.29,"z":-232.89},{"x":-120.53,"y":425.13,"z":-233.86},{"x":-120.43,"y":423.8,"z":-236.31},{"x":-118.09,"y":423.62,"z":-237.81},{"x":-115.82,"y":424.77,"z":-236.86},{"x":-115.9,"y":426.12,"z":-234.39}]},{"lat":-56.21,"lon":-63.03,"b":[{"x":-126.28,"y":417.7,"z":-243.94},{"x":-129.81,"y":415.77,"z":-245.38},{"x":-129.61,"y":413.58,"z":-249.18},{"x":-125.91,"y":413.27,"z":-251.56},{"x":-122.37,"y":415.18,"z":-250.16},{"x":-122.54,"y":417.41,"z":-246.34}]},{"lat":-54.25,"lon":-62.75,"b":[{"x":-133.96,"y":408.12,"z":-255.78},{"x":-137.55,"y":406.04,"z":-257.18},{"x":-137.3,"y":403.67,"z":-261.02},{"x":-133.48,"y":403.34,"z":-263.49},{"x":-129.86,"y":405.39,"z":-262.14},{"x":-130.09,"y":407.8,"z":-258.27}]},{"lat":-81.41,"lon":-90,"b":[{"x":0,"y":494.68,"z":-72.48},{"x":-2,"y":494.51,"z":-73.59},{"x":-2.01,"y":494.17,"z":-75.82},{"x":0,"y":494,"z":-76.94},{"x":2.01,"y":494.17,"z":-75.82},{"x":2,"y":494.51,"z":-73.59}]},{"lat":-79.55,"lon":-84.12,"b":[{"x":-9.28,"y":492.15,"z":-87.5},{"x":-11.7,"y":491.85,"z":-88.84},{"x":-11.72,"y":491.36,"z":-91.54},{"x":-9.3,"y":491.15,"z":-92.91},{"x":-6.87,"y":491.45,"z":-91.56},{"x":-6.87,"y":491.94,"z":-88.85}]},{"lat":-77.6,"lon":-79.99,"b":[{"x":-18.65,"y":489.04,"z":-102.1},{"x":-21.91,"y":488.53,"z":-103.89},{"x":-21.94,"y":487.74,"z":-107.53},{"x":-18.69,"y":487.46,"z":-109.39},{"x":-15.41,"y":487.98,"z":-107.58},{"x":-15.4,"y":488.77,"z":-103.94}]},{"lat":-71.44,"lon":-72.83,"b":[{"x":-46.96,"y":474.54,"z":-150.23},{"x":-48.57,"y":474.11,"z":-151.08},{"x":-48.58,"y":473.54,"z":-152.85},{"x":-46.98,"y":473.4,"z":-153.79},{"x":-45.37,"y":473.83,"z":-152.95},{"x":-45.36,"y":474.4,"z":-151.17}]},{"lat":-69.35,"lon":-71.37,"b":[{"x":-56.3,"y":469.41,"z":-162.48},{"x":-60.47,"y":468.15,"z":-164.62},{"x":-60.48,"y":466.51,"z":-169.2},{"x":-56.33,"y":466.13,"z":-171.66},{"x":-52.14,"y":467.4,"z":-169.53},{"x":-52.13,"y":469.04,"z":-164.93}]},{"lat":-67.25,"lon":-70.17,"b":[{"x":-65.57,"y":462.78,"z":-177.35},{"x":-69.7,"y":461.38,"z":-179.42},{"x":-69.69,"y":459.6,"z":-183.93},{"x":-65.56,"y":459.21,"z":-186.4},{"x":-61.41,"y":460.61,"z":-184.34},{"x":-61.41,"y":462.4,"z":-179.81}]},{"lat":-65.15,"lon":-69.18,"b":[{"x":-74.7,"y":455.52,"z":-191.93},{"x":-78.74,"y":454.01,"z":-193.9},{"x":-78.71,"y":452.11,"z":-198.3},{"x":-74.64,"y":451.72,"z":-200.74},{"x":-70.57,"y":453.23,"z":-198.79},{"x":-70.6,"y":455.14,"z":-194.38}]},{"lat":-63.07,"lon":-68.33,"b":[{"x":-83.65,"y":447.24,"z":-207.16},{"x":-86.66,"y":446.01,"z":-208.58},{"x":-86.61,"y":444.48,"z":-211.84},{"x":-83.55,"y":444.17,"z":-213.69},{"x":-80.52,"y":445.4,"z":-212.29},{"x":-80.56,"y":446.95,"z":-209.01}]},{"lat":-56.95,"lon":-66.43,"b":[{"x":-109.18,"y":421.38,"z":-245.85},{"x":-112.97,"y":419.45,"z":-247.43},{"x":-112.79,"y":417.12,"z":-251.43},{"x":-108.83,"y":416.69,"z":-253.88},{"x":-105.02,"y":418.6,"z":-252.33},{"x":-105.18,"y":420.96,"z":-248.31}]},{"lat":-54.97,"lon":-65.95,"b":[{"x":-117.15,"y":411.81,"z":-258.1},{"x":-120.86,"y":409.81,"z":-259.56},{"x":-120.63,"y":407.41,"z":-263.43},{"x":-116.72,"y":406.97,"z":-265.86},{"x":-112.99,"y":408.94,"z":-264.44},{"x":-113.2,"y":411.38,"z":-260.54}]},{"lat":-53.04,"lon":-65.52,"b":[{"x":-124.83,"y":401.94,"z":-269.79},{"x":-128.44,"y":399.89,"z":-271.14},{"x":-128.17,"y":397.43,"z":-274.88},{"x":-124.31,"y":396.98,"z":-277.29},{"x":-120.68,"y":399,"z":-275.98},{"x":-120.92,"y":401.5,"z":-272.22}]},{"lat":-79.55,"lon":-95.88,"b":[{"x":9.28,"y":492.08,"z":-87.91},{"x":7.23,"y":491.91,"z":-89.06},{"x":7.23,"y":491.49,"z":-91.35},{"x":9.3,"y":491.24,"z":-92.5},{"x":11.35,"y":491.41,"z":-91.34},{"x":11.34,"y":491.83,"z":-89.04}]},{"lat":-77.78,"lon":-90,"b":[{"x":0,"y":489.09,"z":-103.68},{"x":-1.92,"y":488.86,"z":-104.74},{"x":-1.92,"y":488.39,"z":-106.89},{"x":0,"y":488.16,"z":-107.96},{"x":1.92,"y":488.39,"z":-106.89},{"x":1.92,"y":488.86,"z":-104.74}]},{"lat":-75.9,"lon":-85.58,"b":[{"x":-9.38,"y":485.42,"z":-119.31},{"x":-11.3,"y":485.12,"z":-120.36},{"x":-11.31,"y":484.59,"z":-122.5},{"x":-9.39,"y":484.35,"z":-123.58},{"x":-7.46,"y":484.66,"z":-122.52},{"x":-7.46,"y":485.19,"z":-120.38}]},{"lat":-73.94,"lon":-82.18,"b":[{"x":-18.81,"y":480.84,"z":-135.67},{"x":-20.02,"y":480.61,"z":-136.33},{"x":-20.03,"y":480.23,"z":-137.66},{"x":-18.82,"y":480.08,"z":-138.35},{"x":-17.61,"y":480.32,"z":-137.69},{"x":-17.61,"y":480.7,"z":-136.35}]},{"lat":-71.93,"lon":-79.5,"b":[{"x":-28.24,"y":476.59,"z":-148.27},{"x":-32.02,"y":475.72,"z":-150.29},{"x":-32.04,"y":474.39,"z":-154.44},{"x":-28.27,"y":473.93,"z":-156.59},{"x":-24.48,"y":474.8,"z":-154.57},{"x":-24.48,"y":476.13,"z":-150.41}]},{"lat":-69.89,"lon":-77.33,"b":[{"x":-37.67,"y":470.65,"z":-164.34},{"x":-40.72,"y":469.83,"z":-165.93},{"x":-40.73,"y":468.65,"z":-169.26},{"x":-37.69,"y":468.27,"z":-171.01},{"x":-34.63,"y":469.08,"z":-169.42},{"x":-34.63,"y":470.27,"z":-166.08}]},{"lat":-67.83,"lon":-75.56,"b":[{"x":-47.04,"y":463.92,"z":-180.31},{"x":-49.2,"y":463.27,"z":-181.42},{"x":-49.2,"y":462.35,"z":-183.76},{"x":-47.03,"y":462.07,"z":-185.01},{"x":-44.86,"y":462.72,"z":-183.92},{"x":-44.86,"y":463.65,"z":-181.56}]},{"lat":-65.77,"lon":-74.08,"b":[{"x":-56.3,"y":457.09,"z":-194.53},{"x":-58.89,"y":456.22,"z":-195.81},{"x":-58.87,"y":455.01,"z":-198.6},{"x":-56.27,"y":454.68,"z":-200.11},{"x":-53.67,"y":455.55,"z":-198.84},{"x":-53.68,"y":456.76,"z":-196.04}]},{"lat":-63.7,"lon":-72.83,"b":[{"x":-65.41,"y":448.94,"z":-210.09},{"x":-66.84,"y":448.41,"z":-210.78},{"x":-66.82,"y":447.7,"z":-212.3},{"x":-65.38,"y":447.51,"z":-213.14},{"x":-63.94,"y":448.04,"z":-212.47},{"x":-63.96,"y":448.76,"z":-210.94}]},{"lat":-61.65,"lon":-71.76,"b":[{"x":-74.34,"y":440.63,"z":-224.26},{"x":-75.5,"y":440.16,"z":-224.79},{"x":-75.47,"y":439.54,"z":-226.01},{"x":-74.3,"y":439.38,"z":-226.7},{"x":-73.14,"y":439.85,"z":-226.18},{"x":-73.16,"y":440.47,"z":-224.95}]},{"lat":-59.61,"lon":-70.83,"b":[{"x":-83.13,"y":433.41,"z":-234.89},{"x":-86.89,"y":431.76,"z":-236.56},{"x":-86.78,"y":429.61,"z":-240.49},{"x":-82.92,"y":429.09,"z":-242.76},{"x":-79.15,"y":430.72,"z":-241.12},{"x":-79.24,"y":432.89,"z":-237.17}]},{"lat":-57.6,"lon":-70.02,"b":[{"x":-91.65,"y":424.48,"z":-247.66},{"x":-95.55,"y":422.65,"z":-249.32},{"x":-95.39,"y":420.29,"z":-253.34},{"x":-91.36,"y":419.74,"z":-255.73},{"x":-87.45,"y":421.55,"z":-254.11},{"x":-87.58,"y":423.94,"z":-250.07}]},{"lat":-55.62,"lon":-69.31,"b":[{"x":-99.91,"y":415.06,"z":-260.13},{"x":-103.73,"y":413.15,"z":-261.68},{"x":-103.53,"y":410.71,"z":-265.57},{"x":-99.54,"y":410.15,"z":-267.94},{"x":-95.71,"y":412.04,"z":-266.44},{"x":-95.88,"y":414.51,"z":-262.52}]},{"lat":-53.68,"lon":-68.68,"b":[{"x":-107.89,"y":405.31,"z":-272.05},{"x":-111.62,"y":403.34,"z":-273.48},{"x":-111.38,"y":400.83,"z":-277.23},{"x":-107.44,"y":400.27,"z":-279.59},{"x":-103.69,"y":402.22,"z":-278.2},{"x":-103.91,"y":404.75,"z":-274.42}]},{"lat":-51.77,"lon":-68.11,"b":[{"x":-115.58,"y":395.29,"z":-283.4},{"x":-119.21,"y":393.27,"z":-284.71},{"x":-118.92,"y":390.72,"z":-288.32},{"x":-115.04,"y":390.15,"z":-290.65},{"x":-111.39,"y":392.14,"z":-289.39},{"x":-111.64,"y":394.73,"z":-285.75}]},{"lat":-79.13,"lon":-107.17,"b":[{"x":27.83,"y":491.11,"z":-89.58},{"x":27.39,"y":491.09,"z":-89.83},{"x":27.39,"y":491,"z":-90.33},{"x":27.84,"y":490.93,"z":-90.57},{"x":28.28,"y":490.95,"z":-90.32},{"x":28.27,"y":491.04,"z":-89.82}]},{"lat":-77.6,"lon":-100.01,"b":[{"x":18.67,"y":488.5,"z":-104.91},{"x":17.92,"y":488.43,"z":-105.33},{"x":17.92,"y":488.25,"z":-106.17},{"x":18.68,"y":488.13,"z":-106.58},{"x":19.42,"y":488.2,"z":-106.16},{"x":19.42,"y":488.38,"z":-105.32}]},{"lat":-75.9,"lon":-94.42,"b":[{"x":9.38,"y":485.35,"z":-119.64},{"x":7.76,"y":485.15,"z":-120.55},{"x":7.76,"y":484.7,"z":-122.35},{"x":9.39,"y":484.44,"z":-123.24},{"x":11,"y":484.64,"z":-122.33},{"x":10.99,"y":485.09,"z":-120.53}]},{"lat":-74.08,"lon":-90,"b":[{"x":0,"y":481.43,"z":-134.84},{"x":-2.04,"y":481.11,"z":-135.97},{"x":-2.04,"y":480.46,"z":-138.23},{"x":0,"y":480.14,"z":-139.36},{"x":2.04,"y":480.46,"z":-138.23},{"x":2.04,"y":481.11,"z":-135.97}]},{"lat":-72.19,"lon":-86.46,"b":[{"x":-9.43,"y":477.03,"z":-149.28},{"x":-12.5,"y":476.44,"z":-150.95},{"x":-12.5,"y":475.36,"z":-154.32},{"x":-9.44,"y":474.87,"z":-156.02},{"x":-6.36,"y":475.47,"z":-154.35},{"x":-6.36,"y":476.55,"z":-150.98}]},{"lat":-70.23,"lon":-83.59,"b":[{"x":-18.88,"y":471.91,"z":-163.9},{"x":-22.66,"y":471.04,"z":-165.92},{"x":-22.67,"y":469.57,"z":-170.04},{"x":-18.88,"y":468.97,"z":-172.15},{"x":-15.09,"y":469.84,"z":-170.14},{"x":-15.09,"y":471.31,"z":-166.01}]},{"lat":-68.24,"lon":-81.22,"b":[{"x":-28.3,"y":464.84,"z":-181.93},{"x":-29.47,"y":464.53,"z":-182.54},{"x":-29.47,"y":464.03,"z":-183.8},{"x":-28.3,"y":463.84,"z":-184.45},{"x":-27.13,"y":464.15,"z":-183.85},{"x":-27.13,"y":464.65,"z":-182.59}]},{"lat":-64.2,"lon":-77.55,"b":[{"x":-46.92,"y":451.14,"z":-210.3},{"x":-49,"y":450.44,"z":-211.32},{"x":-48.98,"y":449.4,"z":-213.52},{"x":-46.89,"y":449.06,"z":-214.7},{"x":-44.8,"y":449.76,"z":-213.69},{"x":-44.81,"y":450.8,"z":-211.49}]},{"lat":-62.17,"lon":-76.11,"b":[{"x":-56.04,"y":443.19,"z":-224.5},{"x":-58.02,"y":442.46,"z":-225.43},{"x":-57.99,"y":441.4,"z":-227.5},{"x":-55.98,"y":441.08,"z":-228.64},{"x":-53.99,"y":441.8,"z":-227.71},{"x":-54.02,"y":442.86,"z":-225.64}]},{"lat":-60.16,"lon":-74.87,"b":[{"x":-65.02,"y":435.91,"z":-235.95},{"x":-69.07,"y":434.28,"z":-237.8},{"x":-68.97,"y":431.99,"z":-241.97},{"x":-64.84,"y":431.31,"z":-244.31},{"x":-60.78,"y":432.92,"z":-242.5},{"x":-60.85,"y":435.23,"z":-238.31}]},{"lat":-58.16,"lon":-73.78,"b":[{"x":-73.77,"y":427.08,"z":-249.17},{"x":-77.76,"y":425.35,"z":-250.91},{"x":-77.62,"y":422.96,"z":-254.96},{"x":-73.53,"y":422.28,"z":-257.28},{"x":-69.53,"y":423.99,"z":-255.58},{"x":-69.64,"y":426.39,"z":-251.52}]},{"lat":-56.18,"lon":-72.83,"b":[{"x":-82.29,"y":417.83,"z":-261.87},{"x":-86.2,"y":416.01,"z":-263.49},{"x":-86.03,"y":413.55,"z":-267.4},{"x":-81.98,"y":412.87,"z":-269.72},{"x":-78.06,"y":414.65,"z":-268.13},{"x":-78.2,"y":417.15,"z":-264.2}]},{"lat":-54.24,"lon":-71.98,"b":[{"x":-90.56,"y":408.22,"z":-274.01},{"x":-94.39,"y":406.34,"z":-275.51},{"x":-94.18,"y":403.8,"z":-279.29},{"x":-90.17,"y":403.13,"z":-281.58},{"x":-86.33,"y":404.98,"z":-280.11},{"x":-86.5,"y":407.54,"z":-276.32}]},{"lat":-52.33,"lon":-71.23,"b":[{"x":-98.55,"y":398.33,"z":-285.57},{"x":-102.29,"y":396.38,"z":-286.96},{"x":-102.04,"y":393.79,"z":-290.6},{"x":-98.08,"y":393.12,"z":-292.86},{"x":-94.33,"y":395.03,"z":-291.52},{"x":-94.54,"y":397.65,"z":-287.87}]},{"lat":-50.46,"lon":-70.55,"b":[{"x":-106.25,"y":388.19,"z":-296.56},{"x":-109.9,"y":386.2,"z":-297.82},{"x":-109.6,"y":383.57,"z":-301.32},{"x":-105.7,"y":382.9,"z":-303.56},{"x":-102.03,"y":384.86,"z":-302.33},{"x":-102.29,"y":387.52,"z":-298.83}]},{"lat":-75.58,"lon":-103.05,"b":[{"x":28.09,"y":484.72,"z":-119.22},{"x":26.26,"y":484.57,"z":-120.27},{"x":26.27,"y":484.05,"z":-122.32},{"x":28.12,"y":483.69,"z":-123.32},{"x":29.95,"y":483.85,"z":-122.27},{"x":29.93,"y":484.37,"z":-120.22}]},{"lat":-73.94,"lon":-97.82,"b":[{"x":18.81,"y":480.69,"z":-136.26},{"x":18.14,"y":480.61,"z":-136.64},{"x":18.14,"y":480.39,"z":-137.39},{"x":18.82,"y":480.26,"z":-137.76},{"x":19.5,"y":480.34,"z":-137.38},{"x":19.49,"y":480.56,"z":-136.63}]},{"lat":-72.19,"lon":-93.54,"b":[{"x":9.43,"y":476.63,"z":-150.66},{"x":7.61,"y":476.34,"z":-151.67},{"x":7.61,"y":475.7,"z":-153.67},{"x":9.44,"y":475.34,"z":-154.66},{"x":11.26,"y":475.63,"z":-153.65},{"x":11.25,"y":476.27,"z":-151.65}]},{"lat":-70.35,"lon":-90,"b":[{"x":0,"y":471.06,"z":-167.59},{"x":-0.53,"y":470.96,"z":-167.88},{"x":-0.53,"y":470.75,"z":-168.46},{"x":0,"y":470.65,"z":-168.75},{"x":0.53,"y":470.75,"z":-168.46},{"x":0.53,"y":470.96,"z":-167.88}]},{"lat":-68.44,"lon":-87.05,"b":[{"x":-9.45,"y":465.47,"z":-182.27},{"x":-10.55,"y":465.22,"z":-182.86},{"x":-10.55,"y":464.75,"z":-184.04},{"x":-9.45,"y":464.54,"z":-184.64},{"x":-8.35,"y":464.79,"z":-184.05},{"x":-8.35,"y":465.26,"z":-182.87}]},{"lat":-66.5,"lon":-84.57,"b":[{"x":-18.87,"y":459.82,"z":-195.31},{"x":-21.82,"y":459.04,"z":-196.83},{"x":-21.81,"y":457.69,"z":-199.96},{"x":-18.86,"y":457.11,"z":-201.57},{"x":-15.91,"y":457.89,"z":-200.05},{"x":-15.91,"y":459.25,"z":-196.92}]},{"lat":-64.53,"lon":-82.46,"b":[{"x":-28.23,"y":452.18,"z":-211.42},{"x":-29.84,"y":451.7,"z":-212.23},{"x":-29.83,"y":450.9,"z":-213.92},{"x":-28.21,"y":450.59,"z":-214.8},{"x":-26.6,"y":451.07,"z":-214},{"x":-26.61,"y":451.86,"z":-212.3}]},{"lat":-58.6,"lon":-77.69,"b":[{"x":-55.57,"y":428.35,"z":-251.74},{"x":-58.29,"y":427.27,"z":-252.95},{"x":-58.22,"y":425.66,"z":-255.68},{"x":-55.44,"y":425.11,"z":-257.19},{"x":-52.72,"y":426.18,"z":-255.99},{"x":-52.77,"y":427.8,"z":-253.26}]},{"lat":-56.65,"lon":-76.49,"b":[{"x":-64.31,"y":419.19,"z":-264.75},{"x":-66.84,"y":418.11,"z":-265.83},{"x":-66.76,"y":416.53,"z":-268.32},{"x":-64.15,"y":416.02,"z":-269.75},{"x":-61.62,"y":417.08,"z":-268.69},{"x":-61.69,"y":418.67,"z":-266.18}]},{"lat":-54.71,"lon":-75.41,"b":[{"x":-72.88,"y":410.66,"z":-275.64},{"x":-76.8,"y":408.87,"z":-277.23},{"x":-76.62,"y":406.31,"z":-281.02},{"x":-72.56,"y":405.51,"z":-283.24},{"x":-68.63,"y":407.26,"z":-281.69},{"x":-68.77,"y":409.85,"z":-277.88}]},{"lat":-52.81,"lon":-74.46,"b":[{"x":-81.15,"y":400.91,"z":-287.43},{"x":-84.99,"y":399.05,"z":-288.89},{"x":-84.78,"y":396.43,"z":-292.55},{"x":-80.76,"y":395.64,"z":-294.74},{"x":-76.92,"y":397.46,"z":-293.31},{"x":-77.09,"y":400.11,"z":-289.65}]},{"lat":-50.94,"lon":-73.6,"b":[{"x":-89.16,"y":390.9,"z":-298.63},{"x":-92.91,"y":388.99,"z":-299.97},{"x":-92.65,"y":386.33,"z":-303.48},{"x":-88.69,"y":385.54,"z":-305.65},{"x":-84.93,"y":387.42,"z":-304.34},{"x":-85.14,"y":390.11,"z":-300.82}]},{"lat":-49.12,"lon":-72.83,"b":[{"x":-96.88,"y":380.69,"z":-309.23},{"x":-100.54,"y":378.73,"z":-310.46},{"x":-100.24,"y":376.04,"z":-313.82},{"x":-96.32,"y":375.27,"z":-315.96},{"x":-92.66,"y":377.18,"z":-314.78},{"x":-92.91,"y":379.9,"z":-311.4}]},{"lat":-76.23,"lon":-117.91,"b":[{"x":55.64,"y":486.26,"z":-101.96},{"x":52.83,"y":486.22,"z":-103.62},{"x":52.88,"y":485.52,"z":-106.82},{"x":55.75,"y":484.86,"z":-108.36},{"x":58.55,"y":484.9,"z":-106.68},{"x":58.49,"y":485.6,"z":-103.49}]},{"lat":-74.97,"lon":-111.12,"b":[{"x":46.67,"y":483.67,"z":-117.59},{"x":43.71,"y":483.52,"z":-119.32},{"x":43.74,"y":482.68,"z":-122.66},{"x":46.74,"y":481.99,"z":-124.27},{"x":49.7,"y":482.14,"z":-122.52},{"x":49.65,"y":482.98,"z":-119.19}]},{"lat":-73.53,"lon":-105.36,"b":[{"x":37.55,"y":479.63,"z":-136.14},{"x":37.03,"y":479.58,"z":-136.44},{"x":37.03,"y":479.42,"z":-137.02},{"x":37.56,"y":479.3,"z":-137.3},{"x":38.08,"y":479.34,"z":-137},{"x":38.07,"y":479.51,"z":-136.42}]},{"lat":-71.93,"lon":-100.5,"b":[{"x":28.26,"y":475.97,"z":-150.36},{"x":26.37,"y":475.74,"z":-151.43},{"x":26.38,"y":475.07,"z":-153.51},{"x":28.27,"y":474.64,"z":-154.52},{"x":30.15,"y":474.87,"z":-153.44},{"x":30.14,"y":475.54,"z":-151.37}]},{"lat":-70.23,"lon":-96.41,"b":[{"x":18.88,"y":471.28,"z":-165.81},{"x":16.83,"y":470.95,"z":-166.95},{"x":16.83,"y":470.16,"z":-169.18},{"x":18.88,"y":469.69,"z":-170.27},{"x":20.93,"y":470.01,"z":-169.13},{"x":20.93,"y":470.81,"z":-166.9}]},{"lat":-68.44,"lon":-92.95,"b":[{"x":9.45,"y":466.55,"z":-179.36},{"x":5.65,"y":465.81,"z":-181.42},{"x":5.65,"y":464.2,"z":-185.49},{"x":9.45,"y":463.33,"z":-187.5},{"x":13.23,"y":464.07,"z":-185.44},{"x":13.24,"y":465.68,"z":-181.37}]},{"lat":-66.6,"lon":-90,"b":[{"x":0,"y":460.71,"z":-194.07},{"x":-4.25,"y":459.74,"z":-196.32},{"x":-4.24,"y":457.79,"z":-200.81},{"x":0,"y":456.82,"z":-203.06},{"x":4.24,"y":457.79,"z":-200.81},{"x":4.25,"y":459.74,"z":-196.32}]},{"lat":-64.7,"lon":-87.47,"b":[{"x":-9.42,"y":453.2,"z":-210.88},{"x":-11.84,"y":452.56,"z":-212.12},{"x":-11.84,"y":451.37,"z":-214.64},{"x":-9.42,"y":450.82,"z":-215.92},{"x":-7,"y":451.45,"z":-214.68},{"x":-7,"y":452.64,"z":-212.16}]},{"lat":-62.79,"lon":-85.29,"b":[{"x":-18.78,"y":445.1,"z":-226.97},{"x":-19.65,"y":444.84,"z":-227.4},{"x":-19.64,"y":444.39,"z":-228.29},{"x":-18.77,"y":444.19,"z":-228.74},{"x":-17.91,"y":444.44,"z":-228.32},{"x":-17.91,"y":444.9,"z":-227.43}]},{"lat":-55.09,"lon":-78.96,"b":[{"x":-54.83,"y":410.63,"z":-279.92},{"x":-55.76,"y":410.24,"z":-280.31},{"x":-55.73,"y":409.64,"z":-281.19},{"x":-54.78,"y":409.43,"z":-281.69},{"x":-53.85,"y":409.81,"z":-281.31},{"x":-53.87,"y":410.41,"z":-280.42}]},{"lat":-53.21,"lon":-77.79,"b":[{"x":-63.45,"y":403.01,"z":-288.93},{"x":-67.38,"y":401.25,"z":-290.48},{"x":-67.2,"y":398.61,"z":-294.15},{"x":-63.14,"y":397.7,"z":-296.27},{"x":-59.22,"y":399.42,"z":-294.76},{"x":-59.35,"y":402.09,"z":-291.08}]},{"lat":-51.35,"lon":-76.75,"b":[{"x":-71.74,"y":393.16,"z":-300.35},{"x":-75.58,"y":391.34,"z":-301.78},{"x":-75.37,"y":388.64,"z":-305.3},{"x":-71.35,"y":387.75,"z":-307.4},{"x":-67.51,"y":389.53,"z":-306},{"x":-67.68,"y":392.25,"z":-302.47}]},{"lat":-49.53,"lon":-75.81,"b":[{"x":-79.76,"y":383.07,"z":-311.17},{"x":-83.52,"y":381.2,"z":-312.48},{"x":-83.26,"y":378.47,"z":-315.85},{"x":-79.3,"y":377.59,"z":-317.92},{"x":-75.54,"y":379.42,"z":-316.65},{"x":-75.75,"y":382.18,"z":-313.27}]},{"lat":-47.75,"lon":-74.96,"b":[{"x":-87.5,"y":372.81,"z":-321.38},{"x":-91.17,"y":370.9,"z":-322.57},{"x":-90.87,"y":368.15,"z":-325.79},{"x":-86.96,"y":367.28,"z":-327.84},{"x":-83.29,"y":369.15,"z":-326.69},{"x":-83.53,"y":371.93,"z":-323.46}]},{"lat":-74.11,"lon":-118.4,"b":[{"x":65.09,"y":481.3,"z":-118.65},{"x":63.53,"y":481.28,"z":-119.58},{"x":63.55,"y":480.83,"z":-121.37},{"x":65.15,"y":480.4,"z":-122.21},{"x":66.71,"y":480.43,"z":-121.26},{"x":66.68,"y":480.88,"z":-119.49}]},{"lat":-72.86,"lon":-112.39,"b":[{"x":56.11,"y":478.19,"z":-134.74},{"x":54.78,"y":478.12,"z":-135.53},{"x":54.8,"y":477.69,"z":-137.03},{"x":56.14,"y":477.33,"z":-137.73},{"x":57.47,"y":477.4,"z":-136.94},{"x":57.45,"y":477.83,"z":-135.45}]},{"lat":-71.44,"lon":-107.17,"b":[{"x":46.94,"y":475.27,"z":-147.77},{"x":43.13,"y":474.94,"z":-149.99},{"x":43.15,"y":473.58,"z":-154.22},{"x":46.99,"y":472.56,"z":-156.22},{"x":50.79,"y":472.9,"z":-153.99},{"x":50.76,"y":474.25,"z":-149.78}]},{"lat":-69.89,"lon":-102.67,"b":[{"x":37.68,"y":470.45,"z":-164.92},{"x":35.16,"y":470.14,"z":-166.36},{"x":35.16,"y":469.16,"z":-169.12},{"x":37.69,"y":468.48,"z":-170.43},{"x":40.2,"y":468.8,"z":-168.99},{"x":40.2,"y":469.78,"z":-166.24}]},{"lat":-68.24,"lon":-98.78,"b":[{"x":28.3,"y":465.17,"z":-181.02},{"x":26.3,"y":464.85,"z":-182.15},{"x":26.3,"y":464,"z":-184.31},{"x":28.3,"y":463.47,"z":-185.34},{"x":30.3,"y":463.79,"z":-184.22},{"x":30.31,"y":464.64,"z":-182.06}]},{"lat":-66.5,"lon":-95.43,"b":[{"x":18.87,"y":460.22,"z":-194.33},{"x":15.01,"y":459.47,"z":-196.44},{"x":15,"y":457.69,"z":-200.53},{"x":18.86,"y":456.68,"z":-202.52},{"x":22.72,"y":457.43,"z":-200.42},{"x":22.73,"y":459.2,"z":-196.33}]},{"lat":-64.7,"lon":-92.53,"b":[{"x":9.43,"y":454.05,"z":-208.97},{"x":5.18,"y":453.08,"z":-211.21},{"x":5.18,"y":451,"z":-215.62},{"x":9.41,"y":449.89,"z":-217.79},{"x":13.65,"y":450.85,"z":-215.55},{"x":13.66,"y":452.93,"z":-211.14}]},{"lat":-51.68,"lon":-79.99,"b":[{"x":-53.93,"y":392.62,"z":-304.85},{"x":-54.46,"y":392.39,"z":-305.05},{"x":-54.44,"y":392.02,"z":-305.52},{"x":-53.89,"y":391.89,"z":-305.79},{"x":-53.37,"y":392.11,"z":-305.59},{"x":-53.39,"y":392.48,"z":-305.12}]},{"lat":-49.87,"lon":-78.87,"b":[{"x":-62.35,"y":385.01,"z":-312.74},{"x":-66.19,"y":383.23,"z":-314.14},{"x":-65.99,"y":380.47,"z":-317.52},{"x":-61.99,"y":379.48,"z":-319.51},{"x":-58.15,"y":381.22,"z":-318.15},{"x":-58.3,"y":384,"z":-314.76}]},{"lat":-48.09,"lon":-77.87,"b":[{"x":-70.39,"y":374.89,"z":-323.17},{"x":-74.15,"y":373.06,"z":-324.44},{"x":-73.9,"y":370.28,"z":-327.67},{"x":-69.95,"y":369.3,"z":-329.64},{"x":-66.19,"y":371.09,"z":-328.4},{"x":-66.39,"y":373.89,"z":-325.16}]},{"lat":-46.36,"lon":-76.95,"b":[{"x":-78.15,"y":364.62,"z":-332.99},{"x":-81.82,"y":362.75,"z":-334.14},{"x":-81.54,"y":359.96,"z":-337.22},{"x":-77.63,"y":359,"z":-339.16},{"x":-73.97,"y":360.82,"z":-338.04},{"x":-74.2,"y":363.64,"z":-334.96}]},{"lat":-73.04,"lon":-124.81,"b":[{"x":83.21,"y":478.82,"z":-117.29},{"x":81.07,"y":478.87,"z":-118.61},{"x":81.11,"y":478.24,"z":-121.09},{"x":83.31,"y":477.56,"z":-122.24},{"x":85.45,"y":477.53,"z":-120.91},{"x":85.39,"y":478.16,"z":-118.44}]},{"lat":-71.98,"lon":-118.78,"b":[{"x":74.42,"y":476.35,"z":-132.26},{"x":71.51,"y":476.3,"z":-134.03},{"x":71.55,"y":475.35,"z":-137.35},{"x":74.51,"y":474.45,"z":-138.88},{"x":77.41,"y":474.5,"z":-137.09},{"x":77.36,"y":475.45,"z":-133.79}]},{"lat":-70.74,"lon":-113.39,"b":[{"x":65.44,"y":473.2,"z":-147.4},{"x":61.91,"y":473.01,"z":-149.52},{"x":61.93,"y":471.74,"z":-153.49},{"x":65.5,"y":470.65,"z":-155.32},{"x":69.03,"y":470.85,"z":-153.19},{"x":69,"y":472.12,"z":-149.24}]},{"lat":-69.35,"lon":-108.63,"b":[{"x":56.3,"y":469.37,"z":-162.6},{"x":52.24,"y":469.01,"z":-164.99},{"x":52.25,"y":467.41,"z":-169.47},{"x":56.33,"y":466.18,"z":-171.55},{"x":60.37,"y":466.54,"z":-169.15},{"x":60.36,"y":468.14,"z":-164.69}]},{"lat":-67.83,"lon":-104.44,"b":[{"x":47.04,"y":464.02,"z":-180.06},{"x":44.64,"y":463.72,"z":-181.44},{"x":44.63,"y":462.69,"z":-184.05},{"x":47.03,"y":461.97,"z":-185.26},{"x":49.43,"y":462.27,"z":-183.87},{"x":49.43,"y":463.29,"z":-181.28}]},{"lat":-66.22,"lon":-100.77,"b":[{"x":37.67,"y":459.4,"z":-193.52},{"x":33.44,"y":458.73,"z":-195.88},{"x":33.43,"y":456.78,"z":-200.37},{"x":37.63,"y":455.52,"z":-202.48},{"x":41.84,"y":456.2,"z":-200.12},{"x":41.86,"y":458.14,"z":-195.64}]},{"lat":-64.53,"lon":-97.54,"b":[{"x":28.24,"y":453.41,"z":-208.67},{"x":24,"y":452.58,"z":-210.98},{"x":23.99,"y":450.5,"z":-215.39},{"x":28.2,"y":449.25,"z":-217.48},{"x":32.42,"y":450.07,"z":-215.18},{"x":32.44,"y":452.15,"z":-210.78}]},{"lat":-62.79,"lon":-94.71,"b":[{"x":18.79,"y":446.78,"z":-223.49},{"x":14.56,"y":445.82,"z":-225.73},{"x":14.55,"y":443.61,"z":-230.05},{"x":18.75,"y":442.37,"z":-232.12},{"x":22.97,"y":443.33,"z":-229.9},{"x":23,"y":445.53,"z":-225.59}]},{"lat":-55.54,"lon":-86.28,"b":[{"x":-18.38,"y":413.12,"z":-281.01},{"x":-19.77,"y":412.63,"z":-281.63},{"x":-19.75,"y":411.74,"z":-282.93},{"x":-18.35,"y":411.34,"z":-283.6},{"x":-16.96,"y":411.82,"z":-282.99},{"x":-16.97,"y":412.71,"z":-281.69}]},{"lat":-53.72,"lon":-84.7,"b":[{"x":-27.37,"y":405.69,"z":-290.85},{"x":-31.43,"y":404.15,"z":-292.58},{"x":-31.34,"y":401.47,"z":-296.26},{"x":-27.24,"y":400.31,"z":-298.22},{"x":-23.2,"y":401.82,"z":-296.53},{"x":-23.24,"y":404.51,"z":-292.84}]},{"lat":-51.91,"lon":-83.29,"b":[{"x":-36.15,"y":396.23,"z":-302.69},{"x":-40.14,"y":394.61,"z":-304.3},{"x":-40.02,"y":391.87,"z":-307.84},{"x":-35.95,"y":390.74,"z":-309.77},{"x":-31.98,"y":392.33,"z":-308.2},{"x":-32.05,"y":395.08,"z":-304.66}]},{"lat":-50.13,"lon":-82,"b":[{"x":-44.71,"y":386.49,"z":-313.94},{"x":-48.62,"y":384.8,"z":-315.42},{"x":-48.47,"y":382.02,"z":-318.81},{"x":-44.44,"y":380.92,"z":-320.72},{"x":-40.54,"y":382.56,"z":-319.27},{"x":-40.64,"y":385.36,"z":-315.88}]},{"lat":-48.37,"lon":-80.84,"b":[{"x":-53.02,"y":376.52,"z":-324.58},{"x":-56.86,"y":374.78,"z":-325.94},{"x":-56.67,"y":371.97,"z":-329.18},{"x":-52.69,"y":370.89,"z":-331.06},{"x":-48.86,"y":372.59,"z":-329.73},{"x":-49,"y":375.42,"z":-326.49}]},{"lat":-46.65,"lon":-79.78,"b":[{"x":-61.08,"y":366.39,"z":-334.61},{"x":-64.84,"y":364.6,"z":-335.85},{"x":-64.6,"y":361.78,"z":-338.93},{"x":-60.67,"y":360.72,"z":-340.79},{"x":-56.92,"y":362.46,"z":-339.58},{"x":-57.1,"y":365.31,"z":-336.49}]},{"lat":-44.96,"lon":-78.81,"b":[{"x":-68.87,"y":356.14,"z":-344.04},{"x":-72.54,"y":354.32,"z":-345.15},{"x":-72.27,"y":351.5,"z":-348.09},{"x":-68.38,"y":350.46,"z":-349.91},{"x":-64.72,"y":352.23,"z":-348.83},{"x":-64.93,"y":355.08,"z":-345.89}]},{"lat":-70.92,"lon":-124.48,"b":[{"x":92.5,"y":472.87,"z":-133.46},{"x":91.39,"y":472.89,"z":-134.15},{"x":91.41,"y":472.52,"z":-135.43},{"x":92.54,"y":472.13,"z":-136.01},{"x":93.64,"y":472.12,"z":-135.31},{"x":93.62,"y":472.49,"z":-134.04}]},{"lat":-68.62,"lon":-114.2,"b":[{"x":74.72,"y":466.44,"z":-163.7},{"x":72.41,"y":466.31,"z":-165.1},{"x":72.41,"y":465.39,"z":-167.68},{"x":74.74,"y":464.6,"z":-168.84},{"x":77.04,"y":464.74,"z":-167.43},{"x":77.03,"y":465.65,"z":-164.87}]},{"lat":-67.25,"lon":-109.83,"b":[{"x":65.57,"y":462.38,"z":-178.45},{"x":62.42,"y":462.09,"z":-180.31},{"x":62.41,"y":460.73,"z":-183.76},{"x":65.56,"y":459.67,"z":-185.32},{"x":68.7,"y":459.96,"z":-183.44},{"x":68.71,"y":461.31,"z":-180.02}]},{"lat":-65.77,"lon":-105.92,"b":[{"x":56.3,"y":457.78,"z":-192.83},{"x":52.11,"y":457.25,"z":-195.25},{"x":52.09,"y":455.32,"z":-199.73},{"x":56.25,"y":453.92,"z":-201.77},{"x":60.42,"y":454.46,"z":-199.35},{"x":60.45,"y":456.38,"z":-194.89}]},{"lat":-64.2,"lon":-102.45,"b":[{"x":46.93,"y":452.13,"z":-208.08},{"x":42.72,"y":451.45,"z":-210.45},{"x":42.69,"y":449.37,"z":-214.85},{"x":46.86,"y":447.99,"z":-216.87},{"x":51.05,"y":448.67,"z":-214.51},{"x":51.09,"y":450.73,"z":-210.12}]},{"lat":-62.55,"lon":-99.36,"b":[{"x":37.5,"y":445.84,"z":-223.02},{"x":33.28,"y":445.02,"z":-225.32},{"x":33.25,"y":442.81,"z":-229.63},{"x":37.43,"y":441.44,"z":-231.63},{"x":41.62,"y":442.26,"z":-229.34},{"x":41.67,"y":444.45,"z":-225.04}]},{"lat":-60.86,"lon":-96.61,"b":[{"x":28.06,"y":438.95,"z":-237.6},{"x":23.84,"y":437.99,"z":-239.82},{"x":23.81,"y":435.66,"z":-244.03},{"x":27.98,"y":434.3,"z":-246.01},{"x":32.18,"y":435.26,"z":-243.8},{"x":32.23,"y":437.58,"z":-239.6}]},{"lat":-59.12,"lon":-94.16,"b":[{"x":18.61,"y":429.77,"z":-254.8},{"x":17.49,"y":429.48,"z":-255.37},{"x":17.48,"y":428.83,"z":-256.47},{"x":18.6,"y":428.47,"z":-256.99},{"x":19.72,"y":428.76,"z":-256.43},{"x":19.73,"y":429.41,"z":-255.33}]},{"lat":-57.37,"lon":-91.97,"b":[{"x":9.26,"y":421.68,"z":-268.47},{"x":8.21,"y":421.38,"z":-268.98},{"x":8.21,"y":420.74,"z":-269.97},{"x":9.25,"y":420.41,"z":-270.45},{"x":10.29,"y":420.71,"z":-269.95},{"x":10.3,"y":421.34,"z":-268.96}]},{"lat":-55.59,"lon":-90,"b":[{"x":0,"y":415.09,"z":-278.61},{"x":-4.14,"y":413.77,"z":-280.54},{"x":-4.12,"y":411.14,"z":-284.37},{"x":0,"y":409.85,"z":-286.27},{"x":4.12,"y":411.14,"z":-284.37},{"x":4.14,"y":413.77,"z":-280.54}]},{"lat":-53.82,"lon":-88.23,"b":[{"x":-9.14,"y":406.23,"z":-291.24},{"x":-13.23,"y":404.81,"z":-293.05},{"x":-13.19,"y":402.12,"z":-296.74},{"x":-9.09,"y":400.84,"z":-298.62},{"x":-5.01,"y":402.23,"z":-296.83},{"x":-5.01,"y":404.93,"z":-293.14}]},{"lat":-52.06,"lon":-86.63,"b":[{"x":-18.11,"y":397.01,"z":-303.29},{"x":-22.15,"y":395.5,"z":-304.99},{"x":-22.08,"y":392.75,"z":-308.53},{"x":-18.01,"y":391.5,"z":-310.37},{"x":-13.99,"y":392.98,"z":-308.71},{"x":-14.01,"y":395.73,"z":-305.16}]},{"lat":-50.3,"lon":-85.18,"b":[{"x":-26.89,"y":387.48,"z":-314.75},{"x":-30.87,"y":385.9,"z":-316.32},{"x":-30.76,"y":383.1,"z":-319.71},{"x":-26.73,"y":381.88,"z":-321.53},{"x":-22.77,"y":383.43,"z":-319.99},{"x":-22.83,"y":386.23,"z":-316.59}]},{"lat":-48.57,"lon":-83.87,"b":[{"x":-35.46,"y":377.7,"z":-325.6},{"x":-39.37,"y":376.06,"z":-327.05},{"x":-39.23,"y":373.23,"z":-330.29},{"x":-35.23,"y":372.04,"z":-332.08},{"x":-31.34,"y":373.65,"z":-330.66},{"x":-31.43,"y":376.48,"z":-327.42}]},{"lat":-46.87,"lon":-82.66,"b":[{"x":-43.79,"y":367.73,"z":-335.84},{"x":-47.62,"y":366.04,"z":-337.17},{"x":-47.44,"y":363.19,"z":-340.26},{"x":-43.49,"y":362.03,"z":-342.02},{"x":-39.68,"y":363.68,"z":-340.72},{"x":-39.8,"y":366.54,"z":-337.63}]},{"lat":-45.2,"lon":-81.56,"b":[{"x":-51.87,"y":357.63,"z":-345.47},{"x":-55.61,"y":355.89,"z":-346.68},{"x":-55.4,"y":353.04,"z":-349.62},{"x":-51.5,"y":351.91,"z":-351.35},{"x":-47.76,"y":353.6,"z":-350.18},{"x":-47.92,"y":356.46,"z":-347.24}]},{"lat":-43.56,"lon":-80.55,"b":[{"x":-59.68,"y":347.43,"z":-354.5},{"x":-63.34,"y":345.66,"z":-355.59},{"x":-63.09,"y":342.81,"z":-358.38},{"x":-59.23,"y":341.71,"z":-360.09},{"x":-55.58,"y":343.43,"z":-359.03},{"x":-55.77,"y":346.3,"z":-356.24}]},{"lat":-69.72,"lon":-129.49,"b":[{"x":110.13,"y":469.74,"z":-131},{"x":107.8,"y":469.86,"z":-132.5},{"x":107.85,"y":469.07,"z":-135.24},{"x":110.24,"y":468.16,"z":-136.46},{"x":112.56,"y":468.05,"z":-134.94},{"x":112.5,"y":468.84,"z":-132.22}]},{"lat":-68.8,"lon":-124.21,"b":[{"x":101.56,"y":467.45,"z":-145.26},{"x":97.88,"y":467.51,"z":-147.6},{"x":97.92,"y":466.13,"z":-151.84},{"x":101.66,"y":464.72,"z":-153.72},{"x":105.32,"y":464.68,"z":-151.36},{"x":105.27,"y":466.04,"z":-147.14}]},{"lat":-67.72,"lon":-119.33,"b":[{"x":92.8,"y":464.21,"z":-160.68},{"x":88.76,"y":464.12,"z":-163.2},{"x":88.78,"y":462.49,"z":-167.75},{"x":92.84,"y":460.96,"z":-169.76},{"x":96.85,"y":461.06,"z":-167.23},{"x":96.83,"y":462.68,"z":-162.7}]},{"lat":-66.5,"lon":-114.87,"b":[{"x":83.83,"y":460.21,"z":-176.36},{"x":79.74,"y":459.97,"z":-178.86},{"x":79.74,"y":458.19,"z":-183.37},{"x":83.82,"y":456.66,"z":-185.36},{"x":87.88,"y":456.91,"z":-182.85},{"x":87.89,"y":458.67,"z":-178.37}]},{"lat":-65.15,"lon":-110.82,"b":[{"x":74.7,"y":455.54,"z":-191.89},{"x":70.56,"y":455.15,"z":-194.36},{"x":70.54,"y":453.23,"z":-198.82},{"x":74.64,"y":451.7,"z":-200.78},{"x":78.74,"y":452.1,"z":-198.31},{"x":78.78,"y":454.01,"z":-193.88}]},{"lat":-63.7,"lon":-107.17,"b":[{"x":65.43,"y":450.23,"z":-207.21},{"x":61.26,"y":449.69,"z":-209.63},{"x":61.22,"y":447.63,"z":-214.01},{"x":65.33,"y":446.11,"z":-215.96},{"x":69.47,"y":446.65,"z":-213.54},{"x":69.53,"y":448.7,"z":-209.17}]},{"lat":-62.17,"lon":-103.89,"b":[{"x":56.06,"y":444.28,"z":-222.24},{"x":51.87,"y":443.6,"z":-224.61},{"x":51.82,"y":441.4,"z":-228.91},{"x":55.94,"y":439.9,"z":-230.83},{"x":60.1,"y":440.58,"z":-228.47},{"x":60.17,"y":442.76,"z":-224.19}]},{"lat":-60.57,"lon":-100.93,"b":[{"x":46.63,"y":437.73,"z":-236.94},{"x":42.43,"y":436.91,"z":-239.23},{"x":42.38,"y":434.59,"z":-243.43},{"x":46.51,"y":433.1,"z":-245.32},{"x":50.68,"y":433.91,"z":-243.05},{"x":50.75,"y":436.22,"z":-238.86}]},{"lat":-58.93,"lon":-98.27,"b":[{"x":37.19,"y":430.6,"z":-251.23},{"x":32.99,"y":429.65,"z":-253.44},{"x":32.95,"y":427.22,"z":-257.53},{"x":37.07,"y":425.75,"z":-259.4},{"x":41.24,"y":426.69,"z":-257.21},{"x":41.31,"y":429.12,"z":-253.13}]},{"lat":-57.24,"lon":-95.88,"b":[{"x":27.77,"y":422.95,"z":-265.08},{"x":23.58,"y":421.87,"z":-267.19},{"x":23.55,"y":419.34,"z":-271.15},{"x":27.66,"y":417.89,"z":-273},{"x":31.81,"y":418.95,"z":-270.9},{"x":31.89,"y":421.48,"z":-266.95}]},{"lat":-55.54,"lon":-93.72,"b":[{"x":18.4,"y":414.81,"z":-278.42},{"x":14.25,"y":413.61,"z":-280.44},{"x":14.22,"y":410.99,"z":-284.27},{"x":18.32,"y":409.57,"z":-286.08},{"x":22.45,"y":410.74,"z":-284.09},{"x":22.51,"y":413.36,"z":-280.27}]},{"lat":-53.82,"lon":-91.77,"b":[{"x":9.14,"y":406.23,"z":-291.24},{"x":5.01,"y":404.93,"z":-293.14},{"x":5.01,"y":402.23,"z":-296.83},{"x":9.09,"y":400.84,"z":-298.62},{"x":13.19,"y":402.12,"z":-296.74},{"x":13.23,"y":404.81,"z":-293.05}]},{"lat":-52.1,"lon":-90,"b":[{"x":0,"y":397.27,"z":-303.49},{"x":-4.08,"y":395.87,"z":-305.27},{"x":-4.05,"y":393.12,"z":-308.82},{"x":0,"y":391.76,"z":-310.58},{"x":4.05,"y":393.12,"z":-308.82},{"x":4.08,"y":395.87,"z":-305.27}]},{"lat":-50.39,"lon":-88.39,"b":[{"x":-8.98,"y":387.98,"z":-315.15},{"x":-13,"y":386.5,"z":-316.82},{"x":-12.95,"y":383.7,"z":-320.21},{"x":-8.92,"y":382.37,"z":-321.94},{"x":-4.92,"y":383.81,"z":-320.31},{"x":-4.92,"y":386.62,"z":-316.91}]},{"lat":-48.7,"lon":-86.92,"b":[{"x":-17.76,"y":378.42,"z":-326.21},{"x":-21.72,"y":376.87,"z":-327.76},{"x":-21.64,"y":374.03,"z":-331},{"x":-17.65,"y":372.74,"z":-332.7},{"x":-13.71,"y":374.24,"z":-331.19},{"x":-13.74,"y":377.09,"z":-327.94}]},{"lat":-47.02,"lon":-85.58,"b":[{"x":-26.34,"y":368.64,"z":-336.67},{"x":-30.23,"y":367.04,"z":-338.09},{"x":-30.11,"y":364.18,"z":-341.18},{"x":-26.16,"y":362.91,"z":-342.85},{"x":-22.29,"y":364.47,"z":-341.46},{"x":-22.35,"y":367.34,"z":-338.37}]},{"lat":-45.37,"lon":-84.35,"b":[{"x":-34.68,"y":358.7,"z":-346.51},{"x":-38.5,"y":357.05,"z":-347.81},{"x":-38.34,"y":354.18,"z":-350.75},{"x":-34.43,"y":352.95,"z":-352.39},{"x":-30.64,"y":354.55,"z":-351.12},{"x":-30.73,"y":357.44,"z":-348.18}]},{"lat":-43.75,"lon":-83.22,"b":[{"x":-42.78,"y":348.65,"z":-355.75},{"x":-46.51,"y":346.96,"z":-356.92},{"x":-46.32,"y":344.09,"z":-359.72},{"x":-42.46,"y":342.9,"z":-361.33},{"x":-38.74,"y":344.53,"z":-360.19},{"x":-38.87,"y":347.42,"z":-357.39}]},{"lat":-42.17,"lon":-82.18,"b":[{"x":-50.61,"y":338.53,"z":-364.39},{"x":-54.26,"y":336.81,"z":-365.45},{"x":-54.03,"y":333.96,"z":-368.1},{"x":-50.22,"y":332.8,"z":-369.69},{"x":-46.58,"y":334.46,"z":-368.66},{"x":-46.74,"y":337.33,"z":-366.01}]},{"lat":-69.66,"lon":-161.19,"b":[{"x":164.2,"y":469.24,"z":-52.92},{"x":161.8,"y":469.88,"z":-54.57},{"x":162.04,"y":469.43,"z":-57.71},{"x":164.69,"y":468.32,"z":-59.16},{"x":167.07,"y":467.69,"z":-57.48},{"x":166.82,"y":468.15,"z":-54.38}]},{"lat":-69.77,"lon":-155.8,"b":[{"x":157.39,"y":469.83,"z":-66.52},{"x":153.98,"y":470.62,"z":-68.86},{"x":154.25,"y":469.86,"z":-73.27},{"x":157.97,"y":468.3,"z":-75.29},{"x":161.36,"y":467.53,"z":-72.89},{"x":161.06,"y":468.29,"z":-68.54}]},{"lat":-69.7,"lon":-150.27,"b":[{"x":150.39,"y":469.66,"z":-82.07},{"x":147.25,"y":470.28,"z":-84.22},{"x":147.45,"y":469.49,"z":-88.2},{"x":150.82,"y":468.07,"z":-89.99},{"x":153.93,"y":467.47,"z":-87.81},{"x":153.71,"y":468.27,"z":-83.87}]},{"lat":-69.45,"lon":-144.71,"b":[{"x":143.05,"y":468.89,"z":-98.11},{"x":140.41,"y":469.31,"z":-99.9},{"x":140.54,"y":468.55,"z":-103.2},{"x":143.33,"y":467.38,"z":-104.67},{"x":145.96,"y":466.97,"z":-102.84},{"x":145.81,"y":467.73,"z":-99.58}]},{"lat":-69.03,"lon":-139.21,"b":[{"x":135.4,"y":467.4,"z":-114.75},{"x":133.62,"y":467.61,"z":-115.95},{"x":133.68,"y":467.05,"z":-118.13},{"x":135.54,"y":466.27,"z":-119.09},{"x":137.31,"y":466.06,"z":-117.87},{"x":137.24,"y":466.62,"z":-115.71}]},{"lat":-68.42,"lon":-133.87,"b":[{"x":127.33,"y":466.12,"z":-128.25},{"x":123.7,"y":466.43,"z":-130.66},{"x":123.8,"y":465.16,"z":-135},{"x":127.52,"y":463.6,"z":-136.89},{"x":131.12,"y":463.31,"z":-134.45},{"x":131.02,"y":464.57,"z":-130.15}]},{"lat":-67.64,"lon":-128.78,"b":[{"x":119.05,"y":463.77,"z":-143.76},{"x":115.18,"y":463.96,"z":-146.3},{"x":115.24,"y":462.49,"z":-150.84},{"x":119.17,"y":460.84,"z":-152.8},{"x":123.02,"y":460.68,"z":-150.23},{"x":122.95,"y":462.14,"z":-145.73}]},{"lat":-66.7,"lon":-123.99,"b":[{"x":110.52,"y":460.73,"z":-159.48},{"x":106.58,"y":460.77,"z":-162.02},{"x":106.6,"y":459.15,"z":-166.54},{"x":110.57,"y":457.5,"z":-168.49},{"x":114.49,"y":457.48,"z":-165.93},{"x":114.46,"y":459.09,"z":-161.44}]},{"lat":-65.61,"lon":-119.53,"b":[{"x":101.76,"y":457.04,"z":-175.15},{"x":97.75,"y":456.94,"z":-177.68},{"x":97.74,"y":455.17,"z":-182.17},{"x":101.74,"y":453.52,"z":-184.09},{"x":105.72,"y":453.64,"z":-181.54},{"x":105.73,"y":455.39,"z":-177.09}]},{"lat":-64.39,"lon":-115.43,"b":[{"x":92.79,"y":452.71,"z":-190.7},{"x":88.73,"y":452.46,"z":-193.21},{"x":88.69,"y":450.55,"z":-197.64},{"x":92.72,"y":448.9,"z":-199.54},{"x":96.75,"y":449.16,"z":-197.02},{"x":96.79,"y":451.06,"z":-192.62}]},{"lat":-63.07,"lon":-111.67,"b":[{"x":83.65,"y":447.73,"z":-206.06},{"x":79.55,"y":447.34,"z":-208.53},{"x":79.49,"y":445.28,"z":-212.9},{"x":83.53,"y":443.64,"z":-214.77},{"x":87.61,"y":444.05,"z":-212.3},{"x":87.68,"y":446.08,"z":-207.95}]},{"lat":-61.65,"lon":-108.24,"b":[{"x":74.38,"y":442.12,"z":-221.16},{"x":70.24,"y":441.58,"z":-223.58},{"x":70.17,"y":439.4,"z":-227.87},{"x":74.23,"y":437.77,"z":-229.71},{"x":78.34,"y":438.32,"z":-227.3},{"x":78.42,"y":440.48,"z":-223.03}]},{"lat":-60.16,"lon":-105.13,"b":[{"x":65.02,"y":435.91,"z":-235.95},{"x":60.85,"y":435.23,"z":-238.31},{"x":60.78,"y":432.92,"z":-242.5},{"x":64.84,"y":431.31,"z":-244.31},{"x":68.97,"y":431.99,"z":-241.97},{"x":69.07,"y":434.28,"z":-237.8}]},{"lat":-58.6,"lon":-102.31,"b":[{"x":55.59,"y":429.12,"z":-250.37},{"x":51.42,"y":428.31,"z":-252.65},{"x":51.34,"y":425.89,"z":-256.72},{"x":55.41,"y":424.29,"z":-258.51},{"x":59.55,"y":425.11,"z":-256.25},{"x":59.65,"y":427.51,"z":-252.18}]},{"lat":-57,"lon":-99.74,"b":[{"x":46.15,"y":421.79,"z":-264.35},{"x":41.98,"y":420.85,"z":-266.54},{"x":41.91,"y":418.33,"z":-270.5},{"x":45.97,"y":416.76,"z":-272.26},{"x":50.11,"y":417.69,"z":-270.09},{"x":50.22,"y":420.2,"z":-266.14}]},{"lat":-55.37,"lon":-97.41,"b":[{"x":36.73,"y":413.97,"z":-277.86},{"x":32.58,"y":412.9,"z":-279.95},{"x":32.51,"y":410.29,"z":-283.78},{"x":36.57,"y":408.75,"z":-285.51},{"x":40.69,"y":409.8,"z":-283.44},{"x":40.8,"y":412.4,"z":-279.62}]},{"lat":-53.72,"lon":-95.3,"b":[{"x":27.37,"y":405.69,"z":-290.85},{"x":23.24,"y":404.51,"z":-292.84},{"x":23.2,"y":401.82,"z":-296.53},{"x":27.24,"y":400.31,"z":-298.22},{"x":31.34,"y":401.47,"z":-296.26},{"x":31.43,"y":404.15,"z":-292.58}]},{"lat":-52.06,"lon":-93.37,"b":[{"x":18.11,"y":397.01,"z":-303.29},{"x":14.01,"y":395.73,"z":-305.16},{"x":13.99,"y":392.98,"z":-308.71},{"x":18.01,"y":391.5,"z":-310.37},{"x":22.08,"y":392.75,"z":-308.53},{"x":22.15,"y":395.5,"z":-304.99}]},{"lat":-50.39,"lon":-91.61,"b":[{"x":8.98,"y":387.98,"z":-315.15},{"x":4.92,"y":386.62,"z":-316.91},{"x":4.92,"y":383.81,"z":-320.31},{"x":8.92,"y":382.37,"z":-321.94},{"x":12.95,"y":383.7,"z":-320.21},{"x":13,"y":386.5,"z":-316.82}]},{"lat":-48.74,"lon":-90,"b":[{"x":0,"y":378.66,"z":-326.42},{"x":-4,"y":377.22,"z":-328.06},{"x":-3.97,"y":374.37,"z":-331.3},{"x":0,"y":372.97,"z":-332.91},{"x":3.97,"y":374.37,"z":-331.3},{"x":4,"y":377.22,"z":-328.06}]},{"lat":-47.1,"lon":-88.52,"b":[{"x":-8.79,"y":369.1,"z":-337.08},{"x":-12.73,"y":367.59,"z":-338.6},{"x":-12.67,"y":364.72,"z":-341.69},{"x":-8.73,"y":363.35,"z":-343.27},{"x":-4.82,"y":364.82,"z":-341.78},{"x":-4.82,"y":367.69,"z":-338.69}]},{"lat":-45.48,"lon":-87.17,"b":[{"x":-17.37,"y":359.35,"z":-347.14},{"x":-21.24,"y":357.79,"z":-348.53},{"x":-21.15,"y":354.91,"z":-351.47},{"x":-17.25,"y":353.58,"z":-353.02},{"x":-13.4,"y":355.09,"z":-351.66},{"x":-13.43,"y":357.98,"z":-348.72}]},{"lat":-43.88,"lon":-85.92,"b":[{"x":-25.73,"y":349.46,"z":-356.58},{"x":-29.52,"y":347.86,"z":-357.85},{"x":-29.39,"y":344.98,"z":-360.65},{"x":-25.53,"y":343.69,"z":-362.17},{"x":-21.76,"y":345.25,"z":-360.93},{"x":-21.82,"y":348.14,"z":-358.14}]},{"lat":-42.32,"lon":-84.77,"b":[{"x":-33.84,"y":339.5,"z":-365.43},{"x":-37.55,"y":337.86,"z":-366.58},{"x":-37.39,"y":334.98,"z":-369.23},{"x":-33.57,"y":333.73,"z":-370.73},{"x":-29.88,"y":335.32,"z":-369.6},{"x":-29.97,"y":338.21,"z":-366.96}]},{"lat":-40.79,"lon":-83.7,"b":[{"x":-41.69,"y":329.48,"z":-373.69},{"x":-45.32,"y":327.82,"z":-374.72},{"x":-45.12,"y":324.97,"z":-377.23},{"x":-41.35,"y":323.76,"z":-378.7},{"x":-37.74,"y":325.37,"z":-377.7},{"x":-37.87,"y":328.24,"z":-375.19}]},{"lat":-66.76,"lon":-176.14,"b":[{"x":196.38,"y":459.66,"z":-9.86},{"x":193.91,"y":460.66,"z":-11.59},{"x":194.34,"y":460.39,"z":-15.05},{"x":197.25,"y":459.09,"z":-16.74},{"x":199.7,"y":458.09,"z":-14.96},{"x":199.25,"y":458.39,"z":-11.54}]},{"lat":-67.92,"lon":-162.87,"b":[{"x":179.25,"y":463.89,"z":-51.13},{"x":176.06,"y":464.85,"z":-53.38},{"x":176.41,"y":464.21,"z":-57.67},{"x":179.97,"y":462.59,"z":-59.65},{"x":183.13,"y":461.64,"z":-57.34},{"x":182.75,"y":462.3,"z":-53.1}]},{"lat":-68.05,"lon":-157.98,"b":[{"x":172.88,"y":464.46,"z":-65.76},{"x":169.6,"y":465.33,"z":-68.09},{"x":169.9,"y":464.57,"z":-72.45},{"x":173.51,"y":462.92,"z":-74.42},{"x":176.77,"y":462.06,"z":-72.04},{"x":176.44,"y":462.84,"z":-67.74}]},{"lat":-68.04,"lon":-152.93,"b":[{"x":166.18,"y":464.55,"z":-80.69},{"x":162.79,"y":465.33,"z":-83.08},{"x":163.04,"y":464.43,"z":-87.49},{"x":166.7,"y":462.75,"z":-89.46},{"x":170.06,"y":462,"z":-87.02},{"x":169.79,"y":462.9,"z":-82.66}]},{"lat":-67.87,"lon":-147.82,"b":[{"x":159.15,"y":464.13,"z":-95.87},{"x":155.66,"y":464.8,"z":-98.32},{"x":155.86,"y":463.76,"z":-102.77},{"x":159.56,"y":462.06,"z":-104.73},{"x":163.02,"y":461.41,"z":-102.24},{"x":162.8,"y":462.45,"z":-97.84}]},{"lat":-67.54,"lon":-142.71,"b":[{"x":151.78,"y":463.16,"z":-111.26},{"x":148.19,"y":463.71,"z":-113.75},{"x":148.34,"y":462.54,"z":-118.23},{"x":152.1,"y":460.82,"z":-120.17},{"x":155.65,"y":460.29,"z":-117.64},{"x":155.48,"y":461.45,"z":-113.21}]},{"lat":-67.04,"lon":-137.69,"b":[{"x":144.09,"y":461.62,"z":-126.79},{"x":140.41,"y":462.05,"z":-129.32},{"x":140.52,"y":460.73,"z":-133.82},{"x":144.31,"y":458.99,"z":-135.74},{"x":147.96,"y":458.58,"z":-133.18},{"x":147.84,"y":459.89,"z":-128.73}]},{"lat":-66.38,"lon":-132.83,"b":[{"x":136.1,"y":459.48,"z":-142.42},{"x":132.33,"y":459.78,"z":-144.98},{"x":132.4,"y":458.32,"z":-149.48},{"x":136.23,"y":456.56,"z":-151.38},{"x":139.96,"y":456.28,"z":-148.8},{"x":139.89,"y":457.74,"z":-144.35}]},{"lat":-65.56,"lon":-128.19,"b":[{"x":127.82,"y":456.72,"z":-158.09},{"x":123.98,"y":456.88,"z":-160.65},{"x":124,"y":455.28,"z":-165.14},{"x":127.87,"y":453.52,"z":-167.02},{"x":131.68,"y":453.37,"z":-164.44},{"x":131.66,"y":454.97,"z":-159.99}]},{"lat":-64.6,"lon":-123.8,"b":[{"x":119.29,"y":453.34,"z":-173.73},{"x":115.37,"y":453.36,"z":-176.29},{"x":115.36,"y":451.61,"z":-180.74},{"x":119.26,"y":449.84,"z":-182.6},{"x":123.14,"y":449.84,"z":-180.02},{"x":123.16,"y":451.58,"z":-175.61}]},{"lat":-63.51,"lon":-119.7,"b":[{"x":110.52,"y":449.32,"z":-189.27},{"x":106.54,"y":449.2,"z":-191.81},{"x":106.5,"y":447.3,"z":-196.22},{"x":110.43,"y":445.54,"z":-198.04},{"x":114.37,"y":445.68,"z":-195.49},{"x":114.42,"y":447.55,"z":-191.12}]},{"lat":-62.31,"lon":-115.9,"b":[{"x":101.54,"y":444.67,"z":-204.65},{"x":97.51,"y":444.41,"z":-207.16},{"x":97.45,"y":442.37,"z":-211.5},{"x":101.4,"y":440.62,"z":-213.3},{"x":105.4,"y":440.89,"z":-210.79},{"x":105.48,"y":442.91,"z":-206.47}]},{"lat":-61,"lon":-112.39,"b":[{"x":92.41,"y":439.4,"z":-219.8},{"x":88.33,"y":438.99,"z":-222.27},{"x":88.24,"y":436.83,"z":-226.53},{"x":92.22,"y":435.08,"z":-228.3},{"x":96.26,"y":435.5,"z":-225.84},{"x":96.36,"y":437.64,"z":-221.6}]},{"lat":-59.61,"lon":-109.17,"b":[{"x":83.13,"y":433.53,"z":-234.66},{"x":79.02,"y":432.98,"z":-237.08},{"x":78.93,"y":430.69,"z":-241.25},{"x":82.91,"y":428.96,"z":-242.98},{"x":86.99,"y":429.51,"z":-240.58},{"x":87.11,"y":431.78,"z":-236.43}]},{"lat":-58.16,"lon":-106.22,"b":[{"x":73.77,"y":427.08,"z":-249.17},{"x":69.64,"y":426.39,"z":-251.52},{"x":69.53,"y":423.99,"z":-255.58},{"x":73.53,"y":422.28,"z":-257.28},{"x":77.62,"y":422.96,"z":-254.96},{"x":77.76,"y":425.35,"z":-250.91}]},{"lat":-56.65,"lon":-103.51,"b":[{"x":64.35,"y":420.08,"z":-263.28},{"x":60.21,"y":419.27,"z":-265.54},{"x":60.1,"y":416.76,"z":-269.49},{"x":64.1,"y":415.08,"z":-271.16},{"x":68.2,"y":415.88,"z":-268.91},{"x":68.34,"y":418.37,"z":-264.98}]},{"lat":-55.09,"lon":-101.04,"b":[{"x":54.91,"y":412.58,"z":-276.93},{"x":50.78,"y":411.64,"z":-279.1},{"x":50.67,"y":409.04,"z":-282.92},{"x":54.67,"y":407.39,"z":-284.56},{"x":58.77,"y":408.31,"z":-282.41},{"x":58.91,"y":410.9,"z":-278.6}]},{"lat":-53.51,"lon":-98.78,"b":[{"x":45.5,"y":404.61,"z":-290.08},{"x":41.38,"y":403.56,"z":-292.15},{"x":41.29,"y":400.88,"z":-295.83},{"x":45.28,"y":399.26,"z":-297.44},{"x":49.37,"y":400.29,"z":-295.39},{"x":49.5,"y":402.96,"z":-291.72}]},{"lat":-51.91,"lon":-96.71,"b":[{"x":36.15,"y":396.23,"z":-302.69},{"x":32.05,"y":395.08,"z":-304.66},{"x":31.98,"y":392.33,"z":-308.2},{"x":35.95,"y":390.74,"z":-309.77},{"x":40.02,"y":391.87,"z":-307.84},{"x":40.14,"y":394.61,"z":-304.3}]},{"lat":-50.3,"lon":-94.82,"b":[{"x":26.89,"y":387.48,"z":-314.75},{"x":22.83,"y":386.23,"z":-316.59},{"x":22.77,"y":383.43,"z":-319.99},{"x":26.73,"y":381.88,"z":-321.53},{"x":30.76,"y":383.1,"z":-319.71},{"x":30.87,"y":385.9,"z":-316.32}]},{"lat":-48.7,"lon":-93.08,"b":[{"x":17.76,"y":378.42,"z":-326.21},{"x":13.74,"y":377.09,"z":-327.94},{"x":13.71,"y":374.24,"z":-331.19},{"x":17.65,"y":372.74,"z":-332.7},{"x":21.64,"y":374.03,"z":-331},{"x":21.72,"y":376.87,"z":-327.76}]},{"lat":-47.1,"lon":-91.48,"b":[{"x":8.79,"y":369.1,"z":-337.08},{"x":4.82,"y":367.69,"z":-338.69},{"x":4.82,"y":364.82,"z":-341.78},{"x":8.73,"y":363.35,"z":-343.27},{"x":12.67,"y":364.72,"z":-341.69},{"x":12.73,"y":367.59,"z":-338.6}]},{"lat":-45.51,"lon":-90,"b":[{"x":0,"y":359.56,"z":-347.35},{"x":-3.91,"y":358.1,"z":-348.83},{"x":-3.88,"y":355.21,"z":-351.77},{"x":0,"y":353.79,"z":-353.23},{"x":3.88,"y":355.21,"z":-351.77},{"x":3.91,"y":358.1,"z":-348.83}]},{"lat":-43.95,"lon":-88.64,"b":[{"x":-8.59,"y":349.88,"z":-357},{"x":-12.43,"y":348.36,"z":-358.37},{"x":-12.37,"y":345.47,"z":-361.16},{"x":-8.52,"y":344.09,"z":-362.59},{"x":-4.71,"y":345.56,"z":-361.25},{"x":-4.71,"y":348.45,"z":-358.46}]},{"lat":-42.41,"lon":-87.38,"b":[{"x":-16.95,"y":340.08,"z":-366.06},{"x":-20.72,"y":338.52,"z":-367.3},{"x":-20.62,"y":335.64,"z":-369.95},{"x":-16.81,"y":334.3,"z":-371.36},{"x":-13.07,"y":335.81,"z":-370.14},{"x":-13.1,"y":338.7,"z":-367.49}]},{"lat":-40.9,"lon":-86.21,"b":[{"x":-25.07,"y":330.22,"z":-374.53},{"x":-28.77,"y":328.63,"z":-375.65},{"x":-28.63,"y":325.76,"z":-378.16},{"x":-24.87,"y":324.47,"z":-379.54},{"x":-21.19,"y":326,"z":-378.44},{"x":-21.26,"y":328.88,"z":-375.93}]},{"lat":-39.42,"lon":-85.13,"b":[{"x":-32.94,"y":320.34,"z":-382.42},{"x":-36.56,"y":318.73,"z":-383.43},{"x":-36.39,"y":315.89,"z":-385.79},{"x":-32.67,"y":314.64,"z":-387.15},{"x":-29.07,"y":316.19,"z":-386.17},{"x":-29.18,"y":319.05,"z":-383.8}]},{"lat":-65.06,"lon":-176.44,"b":[{"x":210.17,"y":453.51,"z":-11.2},{"x":208.84,"y":454.1,"z":-12.16},{"x":209.09,"y":453.93,"z":-14.08},{"x":210.68,"y":453.16,"z":-15.02},{"x":211.99,"y":452.59,"z":-14.03},{"x":211.73,"y":452.77,"z":-12.14}]},{"lat":-65.53,"lon":-172.62,"b":[{"x":204.97,"y":455.4,"z":-23.39},{"x":202.71,"y":456.33,"z":-25.04},{"x":203.08,"y":455.97,"z":-28.28},{"x":205.74,"y":454.68,"z":-29.83},{"x":207.97,"y":453.77,"z":-28.13},{"x":207.58,"y":454.14,"z":-24.93}]},{"lat":-66.19,"lon":-164.28,"b":[{"x":194.07,"y":457.74,"z":-52.69},{"x":192.63,"y":458.23,"z":-53.75},{"x":192.81,"y":457.92,"z":-55.75},{"x":194.43,"y":457.11,"z":-56.66},{"x":195.86,"y":456.64,"z":-55.58},{"x":195.67,"y":456.96,"z":-53.61}]},{"lat":-66.36,"lon":-159.81,"b":[{"x":187.86,"y":458.68,"z":-65.3},{"x":184.96,"y":459.55,"z":-67.42},{"x":185.26,"y":458.83,"z":-71.37},{"x":188.47,"y":457.24,"z":-73.15},{"x":191.34,"y":456.39,"z":-70.98},{"x":191.03,"y":457.12,"z":-67.08}]},{"lat":-66.39,"lon":-155.19,"b":[{"x":181.47,"y":458.96,"z":-79.72},{"x":178.21,"y":459.82,"z":-82.1},{"x":178.48,"y":458.92,"z":-86.46},{"x":182.02,"y":457.16,"z":-88.38},{"x":185.25,"y":456.32,"z":-85.95},{"x":184.96,"y":457.23,"z":-81.65}]},{"lat":-66.28,"lon":-150.48,"b":[{"x":174.76,"y":458.71,"z":-94.75},{"x":171.4,"y":459.46,"z":-97.19},{"x":171.62,"y":458.43,"z":-101.59},{"x":175.21,"y":456.64,"z":-103.5},{"x":178.54,"y":455.91,"z":-101.02},{"x":178.31,"y":456.94,"z":-96.67}]},{"lat":-66.02,"lon":-145.73,"b":[{"x":167.72,"y":457.93,"z":-110},{"x":164.26,"y":458.58,"z":-112.49},{"x":164.43,"y":457.41,"z":-116.92},{"x":168.06,"y":455.6,"z":-118.81},{"x":171.49,"y":454.97,"z":-116.29},{"x":171.31,"y":456.14,"z":-111.91}]},{"lat":-65.61,"lon":-141.03,"b":[{"x":160.34,"y":456.61,"z":-125.42},{"x":156.79,"y":457.14,"z":-127.95},{"x":156.91,"y":455.83,"z":-132.4},{"x":160.59,"y":454,"z":-134.27},{"x":164.11,"y":453.49,"z":-131.7},{"x":163.98,"y":454.79,"z":-127.31}]},{"lat":-65.05,"lon":-136.42,"b":[{"x":152.64,"y":454.71,"z":-140.95},{"x":149,"y":455.12,"z":-143.51},{"x":149.07,"y":453.67,"z":-147.96},{"x":152.79,"y":451.82,"z":-149.81},{"x":156.4,"y":451.44,"z":-147.22},{"x":156.33,"y":452.88,"z":-142.81}]},{"lat":-64.35,"lon":-131.95,"b":[{"x":144.64,"y":452.22,"z":-156.53},{"x":140.91,"y":452.5,"z":-159.11},{"x":140.94,"y":450.9,"z":-163.55},{"x":144.7,"y":449.04,"z":-165.37},{"x":148.4,"y":448.79,"z":-162.77},{"x":148.37,"y":450.37,"z":-158.38}]},{"lat":-63.5,"lon":-127.69,"b":[{"x":136.36,"y":449.12,"z":-172.11},{"x":132.55,"y":449.26,"z":-174.69},{"x":132.54,"y":447.53,"z":-179.11},{"x":136.33,"y":445.66,"z":-180.9},{"x":140.11,"y":445.54,"z":-178.3},{"x":140.12,"y":447.26,"z":-173.93}]},{"lat":-62.53,"lon":-123.65,"b":[{"x":127.81,"y":445.41,"z":-187.62},{"x":123.93,"y":445.41,"z":-190.19},{"x":123.88,"y":443.53,"z":-194.57},{"x":127.71,"y":441.67,"z":-196.32},{"x":131.56,"y":441.68,"z":-193.74},{"x":131.61,"y":443.54,"z":-189.41}]},{"lat":-61.44,"lon":-119.85,"b":[{"x":119.04,"y":441.07,"z":-202.99},{"x":115.09,"y":440.94,"z":-205.55},{"x":115.02,"y":438.92,"z":-209.86},{"x":118.87,"y":437.07,"z":-211.58},{"x":122.78,"y":437.22,"z":-209.03},{"x":122.87,"y":439.21,"z":-204.75}]},{"lat":-60.24,"lon":-116.31,"b":[{"x":110.06,"y":436.13,"z":-218.17},{"x":106.06,"y":435.86,"z":-220.68},{"x":105.96,"y":433.71,"z":-224.92},{"x":109.84,"y":431.86,"z":-226.61},{"x":113.8,"y":432.15,"z":-224.1},{"x":113.92,"y":434.27,"z":-219.89}]},{"lat":-58.96,"lon":-113.02,"b":[{"x":100.92,"y":430.6,"z":-233.08},{"x":96.88,"y":430.18,"z":-235.54},{"x":96.76,"y":427.91,"z":-239.69},{"x":100.66,"y":426.08,"z":-241.35},{"x":104.66,"y":426.5,"z":-238.89},{"x":104.8,"y":428.75,"z":-234.77}]},{"lat":-57.6,"lon":-109.98,"b":[{"x":91.65,"y":424.48,"z":-247.66},{"x":87.58,"y":423.94,"z":-250.07},{"x":87.45,"y":421.55,"z":-254.11},{"x":91.36,"y":419.74,"z":-255.73},{"x":95.39,"y":420.29,"z":-253.34},{"x":95.55,"y":422.65,"z":-249.32}]},{"lat":-56.18,"lon":-107.17,"b":[{"x":82.29,"y":417.83,"z":-261.87},{"x":78.2,"y":417.15,"z":-264.2},{"x":78.06,"y":414.65,"z":-268.13},{"x":81.98,"y":412.87,"z":-269.72},{"x":86.03,"y":413.55,"z":-267.4},{"x":86.2,"y":416.01,"z":-263.49}]},{"lat":-54.71,"lon":-104.59,"b":[{"x":72.88,"y":410.66,"z":-275.64},{"x":68.77,"y":409.85,"z":-277.88},{"x":68.63,"y":407.26,"z":-281.69},{"x":72.56,"y":405.51,"z":-283.24},{"x":76.62,"y":406.31,"z":-281.02},{"x":76.8,"y":408.87,"z":-277.23}]},{"lat":-53.21,"lon":-102.21,"b":[{"x":63.45,"y":403.01,"z":-288.93},{"x":59.35,"y":402.09,"z":-291.08},{"x":59.22,"y":399.42,"z":-294.76},{"x":63.14,"y":397.7,"z":-296.27},{"x":67.2,"y":398.61,"z":-294.15},{"x":67.38,"y":401.25,"z":-290.48}]},{"lat":-51.68,"lon":-100.01,"b":[{"x":54.05,"y":394.94,"z":-301.71},{"x":49.96,"y":393.91,"z":-303.76},{"x":49.84,"y":391.17,"z":-307.29},{"x":53.76,"y":389.48,"z":-308.78},{"x":57.8,"y":390.5,"z":-306.76},{"x":57.97,"y":393.22,"z":-303.23}]},{"lat":-50.13,"lon":-98,"b":[{"x":44.71,"y":386.49,"z":-313.94},{"x":40.64,"y":385.36,"z":-315.88},{"x":40.54,"y":382.56,"z":-319.27},{"x":44.44,"y":380.92,"z":-320.72},{"x":48.47,"y":382.02,"z":-318.81},{"x":48.62,"y":384.8,"z":-315.42}]},{"lat":-48.57,"lon":-96.13,"b":[{"x":35.46,"y":377.7,"z":-325.6},{"x":31.43,"y":376.48,"z":-327.42},{"x":31.34,"y":373.65,"z":-330.66},{"x":35.23,"y":372.04,"z":-332.08},{"x":39.23,"y":373.23,"z":-330.29},{"x":39.37,"y":376.06,"z":-327.05}]},{"lat":-47.02,"lon":-94.42,"b":[{"x":26.34,"y":368.64,"z":-336.67},{"x":22.35,"y":367.34,"z":-338.37},{"x":22.29,"y":364.47,"z":-341.46},{"x":26.16,"y":362.91,"z":-342.85},{"x":30.11,"y":364.18,"z":-341.18},{"x":30.23,"y":367.04,"z":-338.09}]},{"lat":-45.48,"lon":-92.83,"b":[{"x":17.37,"y":359.35,"z":-347.14},{"x":13.43,"y":357.98,"z":-348.72},{"x":13.4,"y":355.09,"z":-351.66},{"x":17.25,"y":353.58,"z":-353.02},{"x":21.15,"y":354.91,"z":-351.47},{"x":21.24,"y":357.79,"z":-348.53}]},{"lat":-43.95,"lon":-91.36,"b":[{"x":8.59,"y":349.88,"z":-357},{"x":4.71,"y":348.45,"z":-358.46},{"x":4.71,"y":345.56,"z":-361.25},{"x":8.52,"y":344.09,"z":-362.59},{"x":12.37,"y":345.47,"z":-361.16},{"x":12.43,"y":348.36,"z":-358.37}]},{"lat":-42.44,"lon":-90,"b":[{"x":0,"y":340.28,"z":-366.27},{"x":-3.82,"y":338.81,"z":-367.61},{"x":-3.78,"y":335.91,"z":-370.25},{"x":0,"y":334.49,"z":-371.57},{"x":3.78,"y":335.91,"z":-370.25},{"x":3.82,"y":338.81,"z":-367.61}]},{"lat":-40.95,"lon":-88.74,"b":[{"x":-8.37,"y":330.59,"z":-374.95},{"x":-12.11,"y":329.08,"z":-376.16},{"x":-12.04,"y":326.2,"z":-378.67},{"x":-8.3,"y":324.83,"z":-379.95},{"x":-4.58,"y":326.28,"z":-378.76},{"x":-4.58,"y":329.17,"z":-376.26}]},{"lat":-39.49,"lon":-87.56,"b":[{"x":-16.5,"y":320.86,"z":-383.04},{"x":-20.17,"y":319.33,"z":-384.14},{"x":-20.07,"y":316.47,"z":-386.51},{"x":-16.36,"y":315.14,"z":-387.77},{"x":-12.72,"y":316.62,"z":-386.69},{"x":-12.75,"y":319.49,"z":-384.33}]},{"lat":-38.07,"lon":-86.46,"b":[{"x":-24.38,"y":311.13,"z":-390.58},{"x":-27.98,"y":309.58,"z":-391.56},{"x":-27.84,"y":306.75,"z":-393.79},{"x":-24.17,"y":305.47,"z":-395.04},{"x":-20.61,"y":306.97,"z":-394.07},{"x":-20.68,"y":309.8,"z":-391.84}]},{"lat":-63.85,"lon":-173.17,"b":[{"x":218.67,"y":448.91,"z":-25.51},{"x":218.18,"y":449.13,"z":-25.88},{"x":218.27,"y":449.04,"z":-26.6},{"x":218.85,"y":448.74,"z":-26.94},{"x":219.33,"y":448.53,"z":-26.56},{"x":219.24,"y":448.62,"z":-25.85}]},{"lat":-64.51,"lon":-165.49,"b":[{"x":208.03,"y":451.74,"z":-51.13},{"x":206.05,"y":452.47,"z":-52.63},{"x":206.31,"y":452.01,"z":-55.47},{"x":208.57,"y":450.81,"z":-56.76},{"x":210.53,"y":450.09,"z":-55.22},{"x":210.25,"y":450.56,"z":-52.43}]},{"lat":-64.68,"lon":-161.37,"b":[{"x":202.29,"y":452.57,"z":-64.88},{"x":199.83,"y":453.39,"z":-66.75},{"x":200.11,"y":452.75,"z":-70.19},{"x":202.85,"y":451.28,"z":-71.73},{"x":205.27,"y":450.48,"z":-69.83},{"x":204.99,"y":451.13,"z":-66.43}]},{"lat":-64.75,"lon":-157.12,"b":[{"x":196.19,"y":453.05,"z":-78.69},{"x":193.07,"y":453.97,"z":-81.06},{"x":193.35,"y":453.06,"z":-85.35},{"x":196.77,"y":451.23,"z":-87.23},{"x":199.86,"y":450.33,"z":-84.82},{"x":199.56,"y":451.25,"z":-80.58}]},{"lat":-64.68,"lon":-152.76,"b":[{"x":189.82,"y":452.93,"z":-93.56},{"x":186.6,"y":453.77,"z":-95.98},{"x":186.83,"y":452.73,"z":-100.33},{"x":190.3,"y":450.86,"z":-102.19},{"x":193.49,"y":450.06,"z":-99.72},{"x":193.24,"y":451.1,"z":-95.44}]},{"lat":-64.49,"lon":-148.35,"b":[{"x":183.11,"y":452.33,"z":-108.65},{"x":179.78,"y":453.06,"z":-111.13},{"x":179.96,"y":451.89,"z":-115.51},{"x":183.47,"y":450,"z":-117.35},{"x":186.76,"y":449.3,"z":-114.83},{"x":186.57,"y":450.46,"z":-110.51}]},{"lat":-64.15,"lon":-143.94,"b":[{"x":176.05,"y":451.2,"z":-123.93},{"x":172.62,"y":451.82,"z":-126.46},{"x":172.75,"y":450.52,"z":-130.86},{"x":176.31,"y":448.6,"z":-132.67},{"x":179.7,"y":448.01,"z":-130.11},{"x":179.56,"y":449.3,"z":-125.77}]},{"lat":-63.68,"lon":-139.58,"b":[{"x":168.66,"y":449.52,"z":-139.34},{"x":165.14,"y":450.03,"z":-141.9},{"x":165.21,"y":448.59,"z":-146.31},{"x":168.82,"y":446.65,"z":-148.09},{"x":172.3,"y":446.18,"z":-145.5},{"x":172.22,"y":447.61,"z":-141.15}]},{"lat":-63.07,"lon":-135.32,"b":[{"x":160.95,"y":447.28,"z":-154.82},{"x":157.34,"y":447.66,"z":-157.41},{"x":157.36,"y":446.08,"z":-161.8},{"x":161.01,"y":444.13,"z":-163.56},{"x":164.58,"y":443.78,"z":-160.95},{"x":164.55,"y":445.34,"z":-156.61}]},{"lat":-62.33,"lon":-131.2,"b":[{"x":152.93,"y":444.44,"z":-170.32},{"x":149.24,"y":444.7,"z":-172.92},{"x":149.22,"y":442.98,"z":-177.29},{"x":152.9,"y":441.02,"z":-179.02},{"x":156.56,"y":440.8,"z":-176.4},{"x":156.57,"y":442.5,"z":-172.08}]},{"lat":-61.46,"lon":-127.26,"b":[{"x":144.63,"y":441.02,"z":-185.77},{"x":140.86,"y":441.14,"z":-188.37},{"x":140.81,"y":439.28,"z":-192.7},{"x":144.52,"y":437.32,"z":-194.39},{"x":148.25,"y":437.23,"z":-191.79},{"x":148.31,"y":439.06,"z":-187.5}]},{"lat":-60.48,"lon":-123.51,"b":[{"x":136.08,"y":436.99,"z":-201.11},{"x":132.24,"y":436.98,"z":-203.7},{"x":132.15,"y":434.98,"z":-207.97},{"x":135.89,"y":433.03,"z":-209.63},{"x":139.7,"y":433.07,"z":-207.04},{"x":139.79,"y":435.03,"z":-202.81}]},{"lat":-59.39,"lon":-119.98,"b":[{"x":127.3,"y":432.37,"z":-216.28},{"x":123.39,"y":432.22,"z":-218.84},{"x":123.27,"y":430.09,"z":-223.04},{"x":127.05,"y":428.15,"z":-224.66},{"x":130.91,"y":428.32,"z":-222.11},{"x":131.04,"y":430.41,"z":-217.94}]},{"lat":-58.21,"lon":-116.66,"b":[{"x":118.32,"y":427.16,"z":-231.22},{"x":114.36,"y":426.87,"z":-233.73},{"x":114.22,"y":424.62,"z":-237.85},{"x":118.01,"y":422.7,"z":-239.43},{"x":121.93,"y":423,"z":-236.93},{"x":122.09,"y":425.22,"z":-232.83}]},{"lat":-56.95,"lon":-113.57,"b":[{"x":109.18,"y":421.38,"z":-245.85},{"x":105.18,"y":420.96,"z":-248.31},{"x":105.02,"y":418.6,"z":-252.33},{"x":108.83,"y":416.69,"z":-253.88},{"x":112.79,"y":417.12,"z":-251.43},{"x":112.97,"y":419.45,"z":-247.43}]},{"lat":-55.62,"lon":-110.69,"b":[{"x":99.91,"y":415.06,"z":-260.13},{"x":95.88,"y":414.51,"z":-262.52},{"x":95.71,"y":412.04,"z":-266.44},{"x":99.54,"y":410.15,"z":-267.94},{"x":103.53,"y":410.71,"z":-265.57},{"x":103.73,"y":413.15,"z":-261.68}]},{"lat":-54.24,"lon":-108.02,"b":[{"x":90.56,"y":408.22,"z":-274.01},{"x":86.5,"y":407.54,"z":-276.32},{"x":86.33,"y":404.98,"z":-280.11},{"x":90.17,"y":403.13,"z":-281.58},{"x":94.18,"y":403.8,"z":-279.29},{"x":94.39,"y":406.34,"z":-275.51}]},{"lat":-52.81,"lon":-105.54,"b":[{"x":81.15,"y":400.91,"z":-287.43},{"x":77.09,"y":400.11,"z":-289.65},{"x":76.92,"y":397.46,"z":-293.31},{"x":80.76,"y":395.64,"z":-294.74},{"x":84.78,"y":396.43,"z":-292.55},{"x":84.99,"y":399.05,"z":-288.89}]},{"lat":-51.35,"lon":-103.25,"b":[{"x":71.74,"y":393.16,"z":-300.35},{"x":67.68,"y":392.25,"z":-302.47},{"x":67.51,"y":389.53,"z":-306},{"x":71.35,"y":387.75,"z":-307.4},{"x":75.37,"y":388.64,"z":-305.3},{"x":75.58,"y":391.34,"z":-301.78}]},{"lat":-49.87,"lon":-101.13,"b":[{"x":62.35,"y":385.01,"z":-312.74},{"x":58.3,"y":384,"z":-314.76},{"x":58.15,"y":381.22,"z":-318.15},{"x":61.99,"y":379.48,"z":-319.51},{"x":65.99,"y":380.47,"z":-317.52},{"x":66.19,"y":383.23,"z":-314.14}]},{"lat":-48.37,"lon":-99.16,"b":[{"x":53.02,"y":376.52,"z":-324.58},{"x":49,"y":375.42,"z":-326.49},{"x":48.86,"y":372.59,"z":-329.73},{"x":52.69,"y":370.89,"z":-331.06},{"x":56.67,"y":371.97,"z":-329.18},{"x":56.86,"y":374.78,"z":-325.94}]},{"lat":-46.87,"lon":-97.34,"b":[{"x":43.79,"y":367.73,"z":-335.84},{"x":39.8,"y":366.54,"z":-337.63},{"x":39.68,"y":363.68,"z":-340.72},{"x":43.49,"y":362.03,"z":-342.02},{"x":47.44,"y":363.19,"z":-340.26},{"x":47.62,"y":366.04,"z":-337.17}]},{"lat":-45.37,"lon":-95.65,"b":[{"x":34.68,"y":358.7,"z":-346.51},{"x":30.73,"y":357.44,"z":-348.18},{"x":30.64,"y":354.55,"z":-351.12},{"x":34.43,"y":352.95,"z":-352.39},{"x":38.34,"y":354.18,"z":-350.75},{"x":38.5,"y":357.05,"z":-347.81}]},{"lat":-43.88,"lon":-94.08,"b":[{"x":25.73,"y":349.46,"z":-356.58},{"x":21.82,"y":348.14,"z":-358.14},{"x":21.76,"y":345.25,"z":-360.93},{"x":25.53,"y":343.69,"z":-362.17},{"x":29.39,"y":344.98,"z":-360.65},{"x":29.52,"y":347.86,"z":-357.85}]},{"lat":-42.41,"lon":-92.62,"b":[{"x":16.95,"y":340.08,"z":-366.06},{"x":13.1,"y":338.7,"z":-367.49},{"x":13.07,"y":335.81,"z":-370.14},{"x":16.81,"y":334.3,"z":-371.36},{"x":20.62,"y":335.64,"z":-369.95},{"x":20.72,"y":338.52,"z":-367.3}]},{"lat":-40.95,"lon":-91.26,"b":[{"x":8.37,"y":330.59,"z":-374.95},{"x":4.58,"y":329.17,"z":-376.26},{"x":4.58,"y":326.28,"z":-378.76},{"x":8.3,"y":324.83,"z":-379.95},{"x":12.04,"y":326.2,"z":-378.67},{"x":12.11,"y":329.08,"z":-376.16}]},{"lat":-39.52,"lon":-90,"b":[{"x":0,"y":321.04,"z":-383.25},{"x":-3.71,"y":319.58,"z":-384.44},{"x":-3.68,"y":316.72,"z":-386.81},{"x":0,"y":315.31,"z":-387.98},{"x":3.68,"y":316.72,"z":-386.81},{"x":3.71,"y":319.58,"z":-384.44}]},{"lat":-38.12,"lon":-88.82,"b":[{"x":-8.14,"y":311.46,"z":-390.99},{"x":-11.78,"y":309.98,"z":-392.07},{"x":-11.71,"y":307.15,"z":-394.3},{"x":-8.07,"y":305.79,"z":-395.45},{"x":-4.46,"y":307.22,"z":-394.39},{"x":-4.46,"y":310.06,"z":-392.16}]},{"lat":-36.74,"lon":-87.72,"b":[{"x":-16.03,"y":301.9,"z":-398.18},{"x":-19.6,"y":300.41,"z":-399.15},{"x":-19.49,"y":297.61,"z":-401.25},{"x":-15.89,"y":296.3,"z":-402.38},{"x":-12.35,"y":297.74,"z":-401.43},{"x":-12.39,"y":300.55,"z":-399.33}]},{"lat":-62.58,"lon":-170.16,"b":[{"x":226.77,"y":443.93,"z":-38.55},{"x":226.24,"y":444.17,"z":-38.96},{"x":226.33,"y":444.05,"z":-39.76},{"x":226.95,"y":443.7,"z":-40.12},{"x":227.47,"y":443.47,"z":-39.7},{"x":227.38,"y":443.59,"z":-38.92}]},{"lat":-63.04,"lon":-162.72,"b":[{"x":216.22,"y":446.05,"z":-65.24},{"x":214.75,"y":446.59,"z":-66.39},{"x":214.93,"y":446.18,"z":-68.52},{"x":216.58,"y":445.23,"z":-69.46},{"x":218.03,"y":444.71,"z":-68.28},{"x":217.84,"y":445.12,"z":-66.19}]},{"lat":-63.13,"lon":-158.78,"b":[{"x":210.33,"y":446.85,"z":-77.62},{"x":207.35,"y":447.83,"z":-79.96},{"x":207.65,"y":446.92,"z":-84.2},{"x":210.94,"y":445.02,"z":-86.03},{"x":213.89,"y":444.07,"z":-83.64},{"x":213.58,"y":444.99,"z":-79.47}]},{"lat":-63.1,"lon":-154.74,"b":[{"x":204.3,"y":446.86,"z":-92.3},{"x":201.21,"y":447.75,"z":-94.71},{"x":201.46,"y":446.72,"z":-99},{"x":204.8,"y":444.78,"z":-100.81},{"x":207.85,"y":443.92,"z":-98.36},{"x":207.59,"y":444.96,"z":-94.14}]},{"lat":-62.95,"lon":-150.63,"b":[{"x":197.91,"y":446.39,"z":-107.23},{"x":194.72,"y":447.2,"z":-109.7},{"x":194.91,"y":446.03,"z":-114.02},{"x":198.3,"y":444.07,"z":-115.81},{"x":201.45,"y":443.3,"z":-113.3},{"x":201.26,"y":444.46,"z":-109.04}]},{"lat":-62.68,"lon":-146.5,"b":[{"x":191.18,"y":445.44,"z":-122.35},{"x":187.89,"y":446.14,"z":-124.87},{"x":188.03,"y":444.84,"z":-129.21},{"x":191.46,"y":442.86,"z":-130.97},{"x":194.71,"y":442.19,"z":-128.42},{"x":194.57,"y":443.48,"z":-124.14}]},{"lat":-62.28,"lon":-142.39,"b":[{"x":184.1,"y":443.96,"z":-137.61},{"x":180.72,"y":444.55,"z":-140.17},{"x":180.8,"y":443.12,"z":-144.52},{"x":184.27,"y":441.12,"z":-146.26},{"x":187.62,"y":440.56,"z":-143.67},{"x":187.54,"y":441.97,"z":-139.38}]},{"lat":-61.75,"lon":-138.33,"b":[{"x":176.69,"y":441.94,"z":-152.97},{"x":173.21,"y":442.41,"z":-155.56},{"x":173.24,"y":440.85,"z":-159.91},{"x":176.76,"y":438.83,"z":-161.61},{"x":180.2,"y":438.38,"z":-159},{"x":180.17,"y":439.93,"z":-154.71}]},{"lat":-61.1,"lon":-134.38,"b":[{"x":168.97,"y":439.35,"z":-168.37},{"x":165.39,"y":439.71,"z":-170.98},{"x":165.38,"y":438.01,"z":-175.3},{"x":168.93,"y":435.97,"z":-176.97},{"x":172.47,"y":435.65,"z":-174.34},{"x":172.48,"y":437.33,"z":-170.07}]},{"lat":-60.33,"lon":-130.55,"b":[{"x":160.94,"y":436.2,"z":-183.74},{"x":157.28,"y":436.42,"z":-186.35},{"x":157.22,"y":434.59,"z":-190.64},{"x":160.81,"y":432.55,"z":-192.27},{"x":164.43,"y":432.35,"z":-189.65},{"x":164.49,"y":434.16,"z":-185.41}]},{"lat":-59.45,"lon":-126.89,"b":[{"x":152.63,"y":432.46,"z":-199.03},{"x":148.89,"y":432.55,"z":-201.64},{"x":148.79,"y":430.59,"z":-205.87},{"x":152.42,"y":428.55,"z":-207.46},{"x":156.11,"y":428.48,"z":-204.85},{"x":156.22,"y":430.42,"z":-200.66}]},{"lat":-58.46,"lon":-123.39,"b":[{"x":144.06,"y":428.14,"z":-214.17},{"x":140.26,"y":428.1,"z":-216.76},{"x":140.12,"y":426.01,"z":-220.93},{"x":143.78,"y":423.98,"z":-222.48},{"x":147.54,"y":424.04,"z":-219.89},{"x":147.69,"y":426.11,"z":-215.76}]},{"lat":-57.38,"lon":-120.09,"b":[{"x":135.27,"y":423.25,"z":-229.1},{"x":131.41,"y":423.08,"z":-231.65},{"x":131.25,"y":420.86,"z":-235.75},{"x":134.93,"y":418.85,"z":-237.25},{"x":138.75,"y":419.04,"z":-234.71},{"x":138.93,"y":421.22,"z":-230.65}]},{"lat":-56.21,"lon":-116.97,"b":[{"x":126.29,"y":417.8,"z":-243.76},{"x":122.38,"y":417.5,"z":-246.27},{"x":122.19,"y":415.17,"z":-250.27},{"x":125.9,"y":413.17,"z":-251.73},{"x":129.77,"y":413.49,"z":-249.24},{"x":129.98,"y":415.78,"z":-245.27}]},{"lat":-54.97,"lon":-114.05,"b":[{"x":117.15,"y":411.81,"z":-258.1},{"x":113.2,"y":411.38,"z":-260.54},{"x":112.99,"y":408.94,"z":-264.44},{"x":116.72,"y":406.97,"z":-265.86},{"x":120.63,"y":407.41,"z":-263.43},{"x":120.86,"y":409.81,"z":-259.56}]},{"lat":-53.68,"lon":-111.32,"b":[{"x":107.89,"y":405.31,"z":-272.05},{"x":103.91,"y":404.75,"z":-274.42},{"x":103.69,"y":402.22,"z":-278.2},{"x":107.44,"y":400.27,"z":-279.59},{"x":111.38,"y":400.83,"z":-277.23},{"x":111.62,"y":403.34,"z":-273.48}]},{"lat":-52.33,"lon":-108.77,"b":[{"x":98.55,"y":398.33,"z":-285.57},{"x":94.54,"y":397.65,"z":-287.87},{"x":94.33,"y":395.03,"z":-291.52},{"x":98.08,"y":393.12,"z":-292.86},{"x":102.04,"y":393.79,"z":-290.6},{"x":102.29,"y":396.38,"z":-286.96}]},{"lat":-50.94,"lon":-106.4,"b":[{"x":89.16,"y":390.9,"z":-298.63},{"x":85.14,"y":390.11,"z":-300.82},{"x":84.93,"y":387.42,"z":-304.34},{"x":88.69,"y":385.54,"z":-305.65},{"x":92.65,"y":386.33,"z":-303.48},{"x":92.91,"y":388.99,"z":-299.97}]},{"lat":-49.53,"lon":-104.19,"b":[{"x":79.76,"y":383.07,"z":-311.17},{"x":75.75,"y":382.18,"z":-313.27},{"x":75.54,"y":379.42,"z":-316.65},{"x":79.3,"y":377.59,"z":-317.92},{"x":83.26,"y":378.47,"z":-315.85},{"x":83.52,"y":381.2,"z":-312.48}]},{"lat":-48.09,"lon":-102.13,"b":[{"x":70.39,"y":374.89,"z":-323.17},{"x":66.39,"y":373.89,"z":-325.16},{"x":66.19,"y":371.09,"z":-328.4},{"x":69.95,"y":369.3,"z":-329.64},{"x":73.9,"y":370.28,"z":-327.67},{"x":74.15,"y":373.06,"z":-324.44}]},{"lat":-46.65,"lon":-100.22,"b":[{"x":61.08,"y":366.39,"z":-334.61},{"x":57.1,"y":365.31,"z":-336.49},{"x":56.92,"y":362.46,"z":-339.58},{"x":60.67,"y":360.72,"z":-340.79},{"x":64.6,"y":361.78,"z":-338.93},{"x":64.84,"y":364.6,"z":-335.85}]},{"lat":-45.2,"lon":-98.44,"b":[{"x":51.87,"y":357.63,"z":-345.47},{"x":47.92,"y":356.46,"z":-347.24},{"x":47.76,"y":353.6,"z":-350.18},{"x":51.5,"y":351.91,"z":-351.35},{"x":55.4,"y":353.04,"z":-349.62},{"x":55.61,"y":355.89,"z":-346.68}]},{"lat":-43.75,"lon":-96.78,"b":[{"x":42.78,"y":348.65,"z":-355.75},{"x":38.87,"y":347.42,"z":-357.39},{"x":38.74,"y":344.53,"z":-360.19},{"x":42.46,"y":342.9,"z":-361.33},{"x":46.32,"y":344.09,"z":-359.72},{"x":46.51,"y":346.96,"z":-356.92}]},{"lat":-42.32,"lon":-95.23,"b":[{"x":33.84,"y":339.5,"z":-365.43},{"x":29.97,"y":338.21,"z":-366.96},{"x":29.88,"y":335.32,"z":-369.6},{"x":33.57,"y":333.73,"z":-370.73},{"x":37.39,"y":334.98,"z":-369.23},{"x":37.55,"y":337.86,"z":-366.58}]},{"lat":-40.9,"lon":-93.79,"b":[{"x":25.07,"y":330.22,"z":-374.53},{"x":21.26,"y":328.88,"z":-375.93},{"x":21.19,"y":326,"z":-378.44},{"x":24.87,"y":324.47,"z":-379.54},{"x":28.63,"y":325.76,"z":-378.16},{"x":28.77,"y":328.63,"z":-375.65}]},{"lat":-39.49,"lon":-92.44,"b":[{"x":16.5,"y":320.86,"z":-383.04},{"x":12.75,"y":319.49,"z":-384.33},{"x":12.72,"y":316.62,"z":-386.69},{"x":16.36,"y":315.14,"z":-387.77},{"x":20.07,"y":316.47,"z":-386.51},{"x":20.17,"y":319.33,"z":-384.14}]},{"lat":-38.12,"lon":-91.18,"b":[{"x":8.14,"y":311.46,"z":-390.99},{"x":4.46,"y":310.06,"z":-392.16},{"x":4.46,"y":307.22,"z":-394.39},{"x":8.07,"y":305.79,"z":-395.45},{"x":11.71,"y":307.15,"z":-394.3},{"x":11.78,"y":309.98,"z":-392.07}]},{"lat":-36.76,"lon":-90,"b":[{"x":0,"y":302.06,"z":-398.38},{"x":-3.61,"y":300.63,"z":-399.44},{"x":-3.57,"y":297.82,"z":-401.54},{"x":0,"y":296.45,"z":-402.58},{"x":3.57,"y":297.82,"z":-401.54},{"x":3.61,"y":300.63,"z":-399.44}]},{"lat":-35.44,"lon":-88.89,"b":[{"x":-7.9,"y":292.69,"z":-405.25},{"x":-11.44,"y":291.24,"z":-406.2},{"x":-11.37,"y":288.47,"z":-408.17},{"x":-7.83,"y":287.15,"z":-409.2},{"x":-4.33,"y":288.54,"z":-408.26},{"x":-4.33,"y":291.31,"z":-406.29}]},{"lat":-61.44,"lon":-163.88,"b":[{"x":229.24,"y":439.9,"z":-62.28},{"x":226.5,"y":441,"z":-64.53},{"x":226.86,"y":440.19,"z":-68.65},{"x":229.98,"y":438.28,"z":-70.46},{"x":232.69,"y":437.21,"z":-68.16},{"x":232.32,"y":438.03,"z":-64.11}]},{"lat":-61.54,"lon":-160.22,"b":[{"x":223.89,"y":440.41,"z":-76.5},{"x":221.04,"y":441.44,"z":-78.82},{"x":221.35,"y":440.52,"z":-82.99},{"x":224.52,"y":438.57,"z":-84.78},{"x":227.33,"y":437.58,"z":-82.42},{"x":227.01,"y":438.5,"z":-78.31}]},{"lat":-61.53,"lon":-156.46,"b":[{"x":218.18,"y":440.52,"z":-90.99},{"x":215.24,"y":441.47,"z":-93.38},{"x":215.49,"y":440.43,"z":-97.6},{"x":218.7,"y":438.44,"z":-99.37},{"x":221.61,"y":437.53,"z":-96.94},{"x":221.35,"y":438.57,"z":-92.79}]},{"lat":-61.42,"lon":-152.63,"b":[{"x":212.13,"y":440.18,"z":-105.74},{"x":209.08,"y":441.04,"z":-108.19},{"x":209.28,"y":439.89,"z":-112.44},{"x":212.53,"y":437.87,"z":-114.19},{"x":215.55,"y":437.04,"z":-111.7},{"x":215.34,"y":438.19,"z":-107.5}]},{"lat":-61.2,"lon":-148.75,"b":[{"x":205.73,"y":439.33,"z":-120.84},{"x":202.69,"y":440.07,"z":-123.25},{"x":202.83,"y":438.83,"z":-127.38},{"x":206.01,"y":436.86,"z":-129.03},{"x":209.01,"y":436.16,"z":-126.58},{"x":208.87,"y":437.39,"z":-122.52}]},{"lat":-60.86,"lon":-144.87,"b":[{"x":198.97,"y":438.04,"z":-135.9},{"x":195.8,"y":438.69,"z":-138.39},{"x":195.89,"y":437.31,"z":-142.56},{"x":199.14,"y":435.3,"z":-144.2},{"x":202.27,"y":434.68,"z":-141.69},{"x":202.18,"y":436.05,"z":-137.57}]},{"lat":-60.41,"lon":-141.03,"b":[{"x":191.87,"y":436.25,"z":-151.01},{"x":188.52,"y":436.81,"z":-153.59},{"x":188.55,"y":435.27,"z":-157.88},{"x":191.93,"y":433.18,"z":-159.53},{"x":195.24,"y":432.66,"z":-156.92},{"x":195.21,"y":434.19,"z":-152.69}]},{"lat":-59.84,"lon":-137.24,"b":[{"x":184.43,"y":433.9,"z":-166.28},{"x":180.99,"y":434.34,"z":-168.89},{"x":180.97,"y":432.66,"z":-173.16},{"x":184.4,"y":430.56,"z":-174.77},{"x":187.8,"y":430.16,"z":-172.14},{"x":187.82,"y":431.81,"z":-167.92}]},{"lat":-59.15,"lon":-133.56,"b":[{"x":176.68,"y":430.99,"z":-181.55},{"x":173.15,"y":431.31,"z":-184.17},{"x":173.09,"y":429.5,"z":-188.41},{"x":176.55,"y":427.4,"z":-189.98},{"x":180.04,"y":427.11,"z":-187.35},{"x":180.11,"y":428.89,"z":-183.16}]},{"lat":-58.36,"lon":-129.99,"b":[{"x":168.64,"y":427.53,"z":-196.76},{"x":165.02,"y":427.72,"z":-199.38},{"x":164.91,"y":425.78,"z":-203.58},{"x":168.41,"y":423.68,"z":-205.1},{"x":171.98,"y":423.51,"z":-202.47},{"x":172.1,"y":425.42,"z":-198.33}]},{"lat":-57.46,"lon":-126.56,"b":[{"x":160.31,"y":423.5,"z":-211.85},{"x":156.62,"y":423.57,"z":-214.46},{"x":156.47,"y":421.5,"z":-218.59},{"x":160.01,"y":419.4,"z":-220.07},{"x":163.65,"y":419.36,"z":-217.46},{"x":163.81,"y":421.39,"z":-213.37}]},{"lat":-56.47,"lon":-123.29,"b":[{"x":151.74,"y":418.91,"z":-226.75},{"x":147.98,"y":418.85,"z":-229.34},{"x":147.8,"y":416.67,"z":-233.4},{"x":151.36,"y":414.58,"z":-234.83},{"x":155.08,"y":414.66,"z":-232.26},{"x":155.27,"y":416.81,"z":-228.23}]},{"lat":-55.4,"lon":-120.19,"b":[{"x":142.94,"y":413.78,"z":-241.42},{"x":139.13,"y":413.59,"z":-243.96},{"x":138.92,"y":411.29,"z":-247.93},{"x":142.51,"y":409.22,"z":-249.33},{"x":146.28,"y":409.42,"z":-246.79},{"x":146.51,"y":411.69,"z":-242.85}]},{"lat":-54.25,"lon":-117.25,"b":[{"x":133.96,"y":408.12,"z":-255.78},{"x":130.09,"y":407.8,"z":-258.27},{"x":129.86,"y":405.39,"z":-262.14},{"x":133.48,"y":403.34,"z":-263.49},{"x":137.3,"y":403.67,"z":-261.02},{"x":137.55,"y":406.04,"z":-257.18}]},{"lat":-53.04,"lon":-114.48,"b":[{"x":124.83,"y":401.94,"z":-269.79},{"x":120.92,"y":401.5,"z":-272.22},{"x":120.68,"y":399,"z":-275.98},{"x":124.31,"y":396.98,"z":-277.29},{"x":128.17,"y":397.43,"z":-274.88},{"x":128.44,"y":399.89,"z":-271.14}]},{"lat":-51.77,"lon":-111.89,"b":[{"x":115.58,"y":395.29,"z":-283.4},{"x":111.64,"y":394.73,"z":-285.75},{"x":111.39,"y":392.14,"z":-289.39},{"x":115.04,"y":390.15,"z":-290.65},{"x":118.92,"y":390.72,"z":-288.32},{"x":119.21,"y":393.27,"z":-284.71}]},{"lat":-50.46,"lon":-109.45,"b":[{"x":106.25,"y":388.19,"z":-296.56},{"x":102.29,"y":387.52,"z":-298.83},{"x":102.03,"y":384.86,"z":-302.33},{"x":105.7,"y":382.9,"z":-303.56},{"x":109.6,"y":383.57,"z":-301.32},{"x":109.9,"y":386.2,"z":-297.82}]},{"lat":-49.12,"lon":-107.17,"b":[{"x":96.88,"y":380.69,"z":-309.23},{"x":92.91,"y":379.9,"z":-311.4},{"x":92.66,"y":377.18,"z":-314.78},{"x":96.32,"y":375.27,"z":-315.96},{"x":100.24,"y":376.04,"z":-313.82},{"x":100.54,"y":378.73,"z":-310.46}]},{"lat":-47.75,"lon":-105.04,"b":[{"x":87.5,"y":372.81,"z":-321.38},{"x":83.53,"y":371.93,"z":-323.46},{"x":83.29,"y":369.15,"z":-326.69},{"x":86.96,"y":367.28,"z":-327.84},{"x":90.87,"y":368.15,"z":-325.79},{"x":91.17,"y":370.9,"z":-322.57}]},{"lat":-46.36,"lon":-103.05,"b":[{"x":78.15,"y":364.62,"z":-332.99},{"x":74.2,"y":363.64,"z":-334.96},{"x":73.97,"y":360.82,"z":-338.04},{"x":77.63,"y":359,"z":-339.16},{"x":81.54,"y":359.96,"z":-337.22},{"x":81.82,"y":362.75,"z":-334.14}]},{"lat":-44.96,"lon":-101.19,"b":[{"x":68.87,"y":356.14,"z":-344.04},{"x":64.93,"y":355.08,"z":-345.89},{"x":64.72,"y":352.23,"z":-348.83},{"x":68.38,"y":350.46,"z":-349.91},{"x":72.27,"y":351.5,"z":-348.09},{"x":72.54,"y":354.32,"z":-345.15}]},{"lat":-43.56,"lon":-99.45,"b":[{"x":59.68,"y":347.43,"z":-354.5},{"x":55.77,"y":346.3,"z":-356.24},{"x":55.58,"y":343.43,"z":-359.03},{"x":59.23,"y":341.71,"z":-360.09},{"x":63.09,"y":342.81,"z":-358.38},{"x":63.34,"y":345.66,"z":-355.59}]},{"lat":-42.17,"lon":-97.82,"b":[{"x":50.61,"y":338.53,"z":-364.39},{"x":46.74,"y":337.33,"z":-366.01},{"x":46.58,"y":334.46,"z":-368.66},{"x":50.22,"y":332.8,"z":-369.69},{"x":54.03,"y":333.96,"z":-368.1},{"x":54.26,"y":336.81,"z":-365.45}]},{"lat":-40.79,"lon":-96.3,"b":[{"x":41.69,"y":329.48,"z":-373.69},{"x":37.87,"y":328.24,"z":-375.19},{"x":37.74,"y":325.37,"z":-377.7},{"x":41.35,"y":323.76,"z":-378.7},{"x":45.12,"y":324.97,"z":-377.23},{"x":45.32,"y":327.82,"z":-374.72}]},{"lat":-39.42,"lon":-94.87,"b":[{"x":32.94,"y":320.34,"z":-382.42},{"x":29.18,"y":319.05,"z":-383.8},{"x":29.07,"y":316.19,"z":-386.17},{"x":32.67,"y":314.64,"z":-387.15},{"x":36.39,"y":315.89,"z":-385.79},{"x":36.56,"y":318.73,"z":-383.43}]},{"lat":-38.07,"lon":-93.54,"b":[{"x":24.38,"y":311.13,"z":-390.58},{"x":20.68,"y":309.8,"z":-391.84},{"x":20.61,"y":306.97,"z":-394.07},{"x":24.17,"y":305.47,"z":-395.04},{"x":27.84,"y":306.75,"z":-393.79},{"x":27.98,"y":309.58,"z":-391.56}]},{"lat":-36.74,"lon":-92.28,"b":[{"x":16.03,"y":301.9,"z":-398.18},{"x":12.39,"y":300.55,"z":-399.33},{"x":12.35,"y":297.74,"z":-401.43},{"x":15.89,"y":296.3,"z":-402.38},{"x":19.49,"y":297.61,"z":-401.25},{"x":19.6,"y":300.41,"z":-399.15}]},{"lat":-35.44,"lon":-91.11,"b":[{"x":7.9,"y":292.69,"z":-405.25},{"x":4.33,"y":291.31,"z":-406.29},{"x":4.33,"y":288.54,"z":-408.26},{"x":7.83,"y":287.15,"z":-409.2},{"x":11.37,"y":288.47,"z":-408.17},{"x":11.44,"y":291.24,"z":-406.2}]},{"lat":-34.16,"lon":-90,"b":[{"x":0,"y":283.51,"z":-411.8},{"x":-3.5,"y":282.12,"z":-412.73},{"x":-3.47,"y":279.39,"z":-414.59},{"x":0,"y":278.05,"z":-415.51},{"x":3.47,"y":279.39,"z":-414.59},{"x":3.5,"y":282.12,"z":-412.73}]},{"lat":-59.87,"lon":-164.91,"b":[{"x":242.13,"y":432.77,"z":-63.66},{"x":241.04,"y":433.25,"z":-64.59},{"x":241.19,"y":432.9,"z":-66.3},{"x":242.55,"y":432.07,"z":-66.81},{"x":243.72,"y":431.59,"z":-65.62},{"x":243.47,"y":431.95,"z":-64.17}]},{"lat":-59.98,"lon":-161.49,"b":[{"x":236.85,"y":433.78,"z":-75.35},{"x":234.14,"y":434.85,"z":-77.64},{"x":234.46,"y":433.92,"z":-81.75},{"x":237.72,"y":431.91,"z":-83},{"x":240.63,"y":430.84,"z":-80.11},{"x":240.07,"y":431.79,"z":-76.58}]},{"lat":-60,"lon":-157.98,"b":[{"x":231.47,"y":433.97,"z":-89.64},{"x":228.66,"y":434.96,"z":-92},{"x":228.93,"y":433.92,"z":-96.16},{"x":232.23,"y":431.88,"z":-97.42},{"x":235.23,"y":430.9,"z":-94.51},{"x":234.74,"y":431.95,"z":-90.89}]},{"lat":-59.92,"lon":-154.39,"b":[{"x":225.75,"y":433.73,"z":-104.19},{"x":222.83,"y":434.65,"z":-106.62},{"x":223.04,"y":433.49,"z":-110.81},{"x":226.38,"y":431.43,"z":-112.09},{"x":229.47,"y":430.55,"z":-109.15},{"x":229.05,"y":431.69,"z":-105.45}]},{"lat":-59.74,"lon":-150.75,"b":[{"x":219.71,"y":432.78,"z":-119.92},{"x":217.39,"y":433.42,"z":-121.83},{"x":217.5,"y":432.43,"z":-125.08},{"x":220.1,"y":430.83,"z":-126.07},{"x":222.55,"y":430.23,"z":-123.8},{"x":222.27,"y":431.19,"z":-120.9}]},{"lat":-57.94,"lon":-136.29,"b":[{"x":191.84,"y":424.7,"z":-181.05},{"x":189.93,"y":424.93,"z":-182.53},{"x":189.89,"y":423.93,"z":-184.89},{"x":191.84,"y":422.72,"z":-185.63},{"x":193.82,"y":422.53,"z":-184.02},{"x":193.78,"y":423.5,"z":-181.79}]},{"lat":-57.23,"lon":-132.83,"b":[{"x":184.07,"y":422.03,"z":-194.81},{"x":180.99,"y":422.28,"z":-197.14},{"x":180.88,"y":420.59,"z":-200.8},{"x":183.97,"y":418.69,"z":-201.98},{"x":187.14,"y":418.48,"z":-199.48},{"x":187.14,"y":420.13,"z":-195.98}]},{"lat":-56.41,"lon":-129.49,"b":[{"x":176.01,"y":418.48,"z":-209.34},{"x":172.44,"y":418.65,"z":-211.97},{"x":172.29,"y":416.62,"z":-216.06},{"x":175.78,"y":414.46,"z":-217.39},{"x":179.42,"y":414.34,"z":-214.63},{"x":179.5,"y":416.33,"z":-210.67}]},{"lat":-55.51,"lon":-126.28,"b":[{"x":167.68,"y":414.19,"z":-224.2},{"x":164.03,"y":414.23,"z":-226.8},{"x":163.84,"y":412.08,"z":-230.83},{"x":167.34,"y":409.91,"z":-232.16},{"x":171.03,"y":409.91,"z":-229.48},{"x":171.17,"y":412.03,"z":-225.53}]},{"lat":-54.52,"lon":-123.2,"b":[{"x":159.09,"y":409.36,"z":-238.84},{"x":155.38,"y":409.28,"z":-241.42},{"x":155.15,"y":407.01,"z":-245.35},{"x":158.66,"y":404.85,"z":-246.69},{"x":162.39,"y":404.95,"z":-244.09},{"x":162.6,"y":407.2,"z":-240.18}]},{"lat":-53.46,"lon":-120.27,"b":[{"x":150.3,"y":404.01,"z":-253.21},{"x":146.53,"y":403.8,"z":-255.74},{"x":146.27,"y":401.44,"z":-259.59},{"x":149.77,"y":399.27,"z":-260.92},{"x":153.53,"y":399.47,"z":-258.42},{"x":153.8,"y":401.85,"z":-254.55}]},{"lat":-52.33,"lon":-117.49,"b":[{"x":141.32,"y":398.16,"z":-267.26},{"x":137.5,"y":397.83,"z":-269.73},{"x":137.23,"y":395.37,"z":-273.47},{"x":140.72,"y":393.21,"z":-274.8},{"x":144.5,"y":393.51,"z":-272.4},{"x":144.82,"y":396,"z":-268.59}]},{"lat":-51.14,"lon":-114.87,"b":[{"x":132.2,"y":391.84,"z":-280.92},{"x":128.34,"y":391.39,"z":-283.33},{"x":128.05,"y":388.84,"z":-286.95},{"x":131.53,"y":386.68,"z":-288.28},{"x":135.32,"y":387.08,"z":-286},{"x":135.69,"y":389.68,"z":-282.26}]},{"lat":-49.91,"lon":-112.39,"b":[{"x":122.96,"y":385.07,"z":-294.17},{"x":119.07,"y":384.5,"z":-296.5},{"x":118.77,"y":381.87,"z":-299.99},{"x":122.24,"y":379.73,"z":-301.32},{"x":126.02,"y":380.21,"z":-299.16},{"x":126.44,"y":382.91,"z":-295.5}]},{"lat":-48.63,"lon":-110.06,"b":[{"x":113.65,"y":377.88,"z":-306.95},{"x":109.74,"y":377.21,"z":-309.2},{"x":109.44,"y":374.52,"z":-312.56},{"x":112.89,"y":372.39,"z":-313.87},{"x":116.66,"y":372.94,"z":-311.84},{"x":117.12,"y":375.74,"z":-308.28}]},{"lat":-47.33,"lon":-107.87,"b":[{"x":104.3,"y":370.33,"z":-319.24},{"x":100.38,"y":369.55,"z":-321.39},{"x":100.09,"y":366.8,"z":-324.61},{"x":103.52,"y":364.69,"z":-325.92},{"x":107.26,"y":365.3,"z":-324.01},{"x":107.75,"y":368.2,"z":-320.56}]},{"lat":-46,"lon":-105.82,"b":[{"x":94.95,"y":362.44,"z":-331},{"x":91.03,"y":361.57,"z":-333.04},{"x":90.75,"y":358.77,"z":-336.13},{"x":94.15,"y":356.67,"z":-337.42},{"x":97.86,"y":357.35,"z":-335.65},{"x":98.37,"y":360.32,"z":-332.31}]},{"lat":-44.66,"lon":-103.89,"b":[{"x":85.63,"y":354.25,"z":-342.22},{"x":81.73,"y":353.3,"z":-344.15},{"x":81.46,"y":350.47,"z":-347.09},{"x":84.82,"y":348.39,"z":-348.37},{"x":88.49,"y":349.11,"z":-346.74},{"x":89.03,"y":352.15,"z":-343.51}]},{"lat":-43.32,"lon":-102.08,"b":[{"x":76.37,"y":345.82,"z":-352.87},{"x":72.49,"y":344.79,"z":-354.69},{"x":72.24,"y":341.94,"z":-357.48},{"x":75.58,"y":339.88,"z":-358.76},{"x":79.2,"y":340.65,"z":-357.25},{"x":79.74,"y":343.74,"z":-354.15}]},{"lat":-41.97,"lon":-100.38,"b":[{"x":67.21,"y":337.19,"z":-362.95},{"x":63.36,"y":336.09,"z":-364.65},{"x":63.13,"y":333.23,"z":-367.3},{"x":66.43,"y":331.19,"z":-368.56},{"x":69.99,"y":331.99,"z":-367.19},{"x":70.55,"y":335.12,"z":-364.22}]},{"lat":-40.62,"lon":-98.78,"b":[{"x":58.17,"y":328.39,"z":-372.45},{"x":54.36,"y":327.23,"z":-374.04},{"x":54.15,"y":324.38,"z":-376.55},{"x":57.42,"y":322.36,"z":-377.8},{"x":60.92,"y":323.18,"z":-376.55},{"x":61.47,"y":326.35,"z":-373.71}]},{"lat":-39.29,"lon":-97.29,"b":[{"x":49.28,"y":319.47,"z":-381.39},{"x":45.51,"y":318.26,"z":-382.86},{"x":45.34,"y":315.42,"z":-385.23},{"x":48.56,"y":313.43,"z":-386.46},{"x":51.99,"y":314.26,"z":-385.34},{"x":52.54,"y":317.46,"z":-382.63}]},{"lat":-37.97,"lon":-95.88,"b":[{"x":40.55,"y":310.48,"z":-389.75},{"x":36.83,"y":309.23,"z":-391.11},{"x":36.69,"y":306.4,"z":-393.34},{"x":39.87,"y":304.44,"z":-394.56},{"x":43.23,"y":305.27,"z":-393.56},{"x":43.77,"y":308.49,"z":-390.98}]},{"lat":-36.68,"lon":-94.56,"b":[{"x":32.01,"y":301.44,"z":-397.57},{"x":28.35,"y":300.16,"z":-398.81},{"x":28.25,"y":297.35,"z":-400.91},{"x":31.38,"y":295.42,"z":-402.11},{"x":34.66,"y":296.25,"z":-401.22},{"x":35.19,"y":299.48,"z":-398.78}]},{"lat":-35.4,"lon":-93.32,"b":[{"x":23.68,"y":292.39,"z":-404.84},{"x":20.08,"y":291.09,"z":-405.98},{"x":20.01,"y":288.32,"z":-407.95},{"x":23.1,"y":286.41,"z":-409.13},{"x":26.3,"y":287.24,"z":-408.35},{"x":26.81,"y":290.46,"z":-406.04}]},{"lat":-34.14,"lon":-92.15,"b":[{"x":15.56,"y":283.37,"z":-411.6},{"x":12.02,"y":282.05,"z":-412.62},{"x":11.99,"y":279.32,"z":-414.48},{"x":15.03,"y":277.44,"z":-415.64},{"x":18.15,"y":278.26,"z":-414.96},{"x":18.65,"y":281.46,"z":-412.78}]},{"lat":-32.92,"lon":-91.04,"b":[{"x":7.66,"y":274.41,"z":-417.85},{"x":4.2,"y":273.07,"z":-418.77},{"x":4.2,"y":270.38,"z":-420.51},{"x":7.19,"y":268.53,"z":-421.66},{"x":10.23,"y":269.34,"z":-421.08},{"x":10.71,"y":272.53,"z":-419.01}]},{"lat":-51.64,"lon":-7.48,"b":[{"x":-308,"y":391.62,"z":-41.78},{"x":-306.67,"y":392.68,"z":-41.56},{"x":-306.33,"y":393.09,"z":-40.17},{"x":-307.14,"y":392.59,"z":-38.87},{"x":-308.3,"y":391.67,"z":-38.92},{"x":-308.82,"y":391.11,"z":-40.45}]},{"lat":-53.08,"lon":-6.09,"b":[{"x":-299.09,"y":399.23,"z":-33.66},{"x":-297.36,"y":400.54,"z":-33.38},{"x":-296.91,"y":401.02,"z":-31.61},{"x":-297.95,"y":400.37,"z":-29.92},{"x":-299.45,"y":399.24,"z":-29.98},{"x":-300.15,"y":398.58,"z":-31.95}]},{"lat":-54.47,"lon":-4.65,"b":[{"x":-289.93,"y":406.58,"z":-24.76},{"x":-288.75,"y":407.43,"z":-24.58},{"x":-288.44,"y":407.72,"z":-23.4},{"x":-289.14,"y":407.28,"z":-22.27},{"x":-290.16,"y":406.56,"z":-22.29},{"x":-290.64,"y":406.14,"z":-23.61}]},{"lat":-55.8,"lon":-3.16,"b":[{"x":-281.23,"y":412.98,"z":-17.77},{"x":-278.92,"y":414.57,"z":-17.42},{"x":-278.32,"y":415.05,"z":-15.16},{"x":-279.68,"y":414.21,"z":-12.96},{"x":-281.66,"y":412.87,"z":-12.98},{"x":-282.61,"y":412.13,"z":-15.54}]},{"lat":-57.07,"lon":-1.61,"b":[{"x":-271.88,"y":419.53,"z":-8.26},{"x":-271.22,"y":419.95,"z":-8.17},{"x":-271.05,"y":420.07,"z":-7.54},{"x":-271.44,"y":419.84,"z":-6.92},{"x":-271.99,"y":419.48,"z":-6.92},{"x":-272.26,"y":419.29,"z":-7.64}]},{"lat":-28.99,"lon":-81.41,"b":[{"x":-67.84,"y":242.71,"z":-431.8},{"x":-65.81,"y":244.71,"z":-430.98},{"x":-63.35,"y":244.28,"z":-431.59},{"x":-62.48,"y":242.01,"z":-433},{"x":-64.06,"y":240.14,"z":-433.8},{"x":-66.96,"y":240.41,"z":-433.22}]},{"lat":-29.61,"lon":-83.19,"b":[{"x":-54.22,"y":247.54,"z":-430.98},{"x":-52.05,"y":249.64,"z":-430.03},{"x":-49.45,"y":249.12,"z":-430.64},{"x":-48.52,"y":246.69,"z":-432.14},{"x":-50.18,"y":244.73,"z":-433.06},{"x":-53.28,"y":245.07,"z":-432.51}]},{"lat":-30.2,"lon":-84.94,"b":[{"x":-41.42,"y":252.14,"z":-429.73},{"x":-38.71,"y":254.73,"z":-428.45},{"x":-35.48,"y":254.01,"z":-429.15},{"x":-34.31,"y":250.95,"z":-431.04},{"x":-36.35,"y":248.55,"z":-432.26},{"x":-40.23,"y":249.03,"z":-431.65}]},{"lat":-30.74,"lon":-86.66,"b":[{"x":-28.15,"y":256.26,"z":-428.36},{"x":-25.57,"y":258.69,"z":-427.06},{"x":-22.53,"y":257.95,"z":-427.67},{"x":-21.41,"y":255.02,"z":-429.49},{"x":-23.31,"y":252.77,"z":-430.71},{"x":-27.01,"y":253.28,"z":-430.2}]},{"lat":-31.25,"lon":-88.35,"b":[{"x":-15.44,"y":260.13,"z":-426.68},{"x":-12.83,"y":262.55,"z":-425.27},{"x":-9.78,"y":261.74,"z":-425.85},{"x":-8.64,"y":258.75,"z":-427.7},{"x":-10.52,"y":256.51,"z":-429.01},{"x":-14.28,"y":257.08,"z":-428.56}]},{"lat":-51.83,"lon":-10.12,"b":[{"x":-305.11,"y":392.49,"z":-53.21},{"x":-305.42,"y":392.07,"z":-54.5},{"x":-304.51,"y":392.63,"z":-55.59},{"x":-303.28,"y":393.61,"z":-55.38},{"x":-302.99,"y":394.01,"z":-54.08},{"x":-303.9,"y":393.46,"z":-53}]},{"lat":-53.32,"lon":-8.76,"b":[{"x":-297.46,"y":399.54,"z":-42.82},{"x":-298.25,"y":398.59,"z":-46},{"x":-295.95,"y":399.99,"z":-48.71},{"x":-292.85,"y":402.33,"z":-48.17},{"x":-292.1,"y":403.24,"z":-44.97},{"x":-294.41,"y":401.85,"z":-42.32}]},{"lat":-47.58,"lon":-54.31,"b":[{"x":-199.51,"y":369.01,"z":-271.98},{"x":-199.28,"y":367.09,"z":-274.72},{"x":-196.55,"y":367.12,"z":-276.64},{"x":-194.07,"y":369.07,"z":-275.81},{"x":-194.3,"y":370.96,"z":-273.09},{"x":-197.01,"y":370.94,"z":-271.17}]},{"lat":-45.45,"lon":-59.55,"b":[{"x":-178.17,"y":356.34,"z":-302.11},{"x":-178.13,"y":356.02,"z":-302.51},{"x":-177.7,"y":356.01,"z":-302.77},{"x":-177.33,"y":356.3,"z":-302.64},{"x":-177.38,"y":356.62,"z":-302.24},{"x":-177.8,"y":356.63,"z":-301.98}]},{"lat":-44.31,"lon":-62,"b":[{"x":-169.01,"y":349.34,"z":-315.24},{"x":-168.87,"y":348.53,"z":-316.21},{"x":-167.81,"y":348.46,"z":-316.84},{"x":-166.9,"y":349.21,"z":-316.5},{"x":-167.03,"y":350.01,"z":-315.54},{"x":-168.08,"y":350.08,"z":-314.91}]},{"lat":-35.68,"lon":-76.02,"b":[{"x":-99.82,"y":291.89,"z":-393.45},{"x":-99.52,"y":290.37,"z":-394.65},{"x":-97.85,"y":290.11,"z":-395.26},{"x":-96.49,"y":291.34,"z":-394.69},{"x":-96.78,"y":292.84,"z":-393.5},{"x":-98.44,"y":293.13,"z":-392.88}]},{"lat":-34.43,"lon":-77.61,"b":[{"x":-91.07,"y":283.15,"z":-401.86},{"x":-90.59,"y":280.74,"z":-403.65},{"x":-87.99,"y":280.32,"z":-404.52},{"x":-85.89,"y":282.26,"z":-403.62},{"x":-86.34,"y":284.64,"z":-401.85},{"x":-88.92,"y":285.1,"z":-400.95}]},{"lat":-33.2,"lon":-79.13,"b":[{"x":-81.01,"y":274.13,"z":-410.19},{"x":-80.63,"y":272.18,"z":-411.56},{"x":-78.57,"y":271.83,"z":-412.19},{"x":-76.9,"y":273.4,"z":-411.47},{"x":-77.26,"y":275.32,"z":-410.11},{"x":-79.31,"y":275.71,"z":-409.46}]},{"lat":-31.98,"lon":-80.55,"b":[{"x":-71.25,"y":265.12,"z":-417.86},{"x":-70.95,"y":263.54,"z":-418.9},{"x":-69.31,"y":263.26,"z":-419.36},{"x":-67.99,"y":264.52,"z":-418.78},{"x":-68.27,"y":266.08,"z":-417.74},{"x":-69.9,"y":266.39,"z":-417.27}]},{"lat":-30.79,"lon":-81.91,"b":[{"x":-63.53,"y":256.46,"z":-424.44},{"x":-62.97,"y":253.5,"z":-426.29},{"x":-59.95,"y":252.96,"z":-427.04},{"x":-57.5,"y":255.33,"z":-425.97},{"x":-58.02,"y":258.25,"z":-424.13},{"x":-61.03,"y":258.84,"z":-423.35}]},{"lat":-54.75,"lon":-7.34,"b":[{"x":-287.75,"y":407.35,"z":-35.06},{"x":-288.3,"y":406.77,"z":-37.22},{"x":-286.7,"y":407.73,"z":-39.05},{"x":-284.55,"y":409.26,"z":-38.69},{"x":-284.04,"y":409.82,"z":-36.52},{"x":-285.63,"y":408.87,"z":-34.72}]},{"lat":-48.59,"lon":-56.94,"b":[{"x":-184.24,"y":374.99,"z":-274.52},{"x":-183.91,"y":372.3,"z":-278.38},{"x":-180.03,"y":372.23,"z":-280.99},{"x":-176.54,"y":374.84,"z":-279.74},{"x":-176.89,"y":377.51,"z":-275.92},{"x":-180.72,"y":377.58,"z":-273.31}]},{"lat":-47.5,"lon":-59.59,"b":[{"x":-171.95,"y":368.67,"z":-290.68},{"x":-171.85,"y":367.97,"z":-291.62},{"x":-170.87,"y":367.93,"z":-292.25},{"x":-170,"y":368.59,"z":-291.92},{"x":-170.1,"y":369.28,"z":-290.99},{"x":-171.07,"y":369.33,"z":-290.36}]},{"lat":-45.18,"lon":-64.52,"b":[{"x":-154.65,"y":354.86,"z":-316.38},{"x":-154.26,"y":352.56,"z":-319.13},{"x":-151.25,"y":352.3,"z":-320.85},{"x":-148.65,"y":354.33,"z":-319.83},{"x":-149.04,"y":356.61,"z":-317.11},{"x":-152.02,"y":356.89,"z":-315.38}]},{"lat":-43.96,"lon":-66.79,"b":[{"x":-142.42,"y":347.13,"z":-330.46},{"x":-142.34,"y":346.66,"z":-330.99},{"x":-141.74,"y":346.6,"z":-331.31},{"x":-141.23,"y":347,"z":-331.11},{"x":-141.31,"y":347.46,"z":-330.58},{"x":-141.9,"y":347.53,"z":-330.26}]},{"lat":-41.45,"lon":-70.99,"b":[{"x":-123.97,"y":331.21,"z":-353.4},{"x":-123.68,"y":329.63,"z":-354.98},{"x":-121.78,"y":329.37,"z":-355.88},{"x":-120.19,"y":330.68,"z":-355.21},{"x":-120.48,"y":332.24,"z":-353.64},{"x":-122.36,"y":332.52,"z":-352.73}]},{"lat":-40.17,"lon":-72.92,"b":[{"x":-112.73,"y":322.61,"z":-364.97},{"x":-112.65,"y":322.17,"z":-365.39},{"x":-112.14,"y":322.09,"z":-365.61},{"x":-111.71,"y":322.45,"z":-365.43},{"x":-111.79,"y":322.88,"z":-365.02},{"x":-112.3,"y":322.96,"z":-364.79}]},{"lat":-38.89,"lon":-74.74,"b":[{"x":-103.62,"y":314.08,"z":-374.95},{"x":-103.42,"y":313.05,"z":-375.87},{"x":-102.24,"y":312.86,"z":-376.36},{"x":-101.27,"y":313.69,"z":-375.93},{"x":-101.46,"y":314.71,"z":-375.02},{"x":-102.63,"y":314.92,"z":-374.53}]},{"lat":-37.61,"lon":-76.46,"b":[{"x":-94.99,"y":305.49,"z":-384.21},{"x":-94.6,"y":303.48,"z":-385.88},{"x":-92.37,"y":303.1,"z":-386.72},{"x":-90.54,"y":304.7,"z":-385.91},{"x":-90.91,"y":306.68,"z":-384.25},{"x":-93.12,"y":307.08,"z":-383.39}]},{"lat":-36.33,"lon":-78.08,"b":[{"x":-86.86,"y":296.87,"z":-392.77},{"x":-86.22,"y":293.51,"z":-395.42},{"x":-82.57,"y":292.86,"z":-396.68},{"x":-79.58,"y":295.51,"z":-395.33},{"x":-80.19,"y":298.82,"z":-392.7},{"x":-83.82,"y":299.53,"z":-391.4}]},{"lat":-35.07,"lon":-79.61,"b":[{"x":-77.39,"y":287.93,"z":-401.31},{"x":-76.76,"y":284.56,"z":-403.82},{"x":-73.17,"y":283.89,"z":-404.96},{"x":-70.25,"y":286.54,"z":-403.62},{"x":-70.85,"y":289.86,"z":-401.13},{"x":-74.41,"y":290.58,"z":-399.96}]},{"lat":-33.82,"lon":-81.06,"b":[{"x":-68.1,"y":278.95,"z":-409.26},{"x":-67.47,"y":275.58,"z":-411.63},{"x":-63.96,"y":274.91,"z":-412.65},{"x":-61.1,"y":277.55,"z":-411.32},{"x":-61.69,"y":280.87,"z":-408.97},{"x":-65.18,"y":281.6,"z":-407.92}]},{"lat":-32.59,"lon":-82.43,"b":[{"x":-59,"y":269.97,"z":-416.63},{"x":-58.39,"y":266.62,"z":-418.87},{"x":-54.96,"y":265.95,"z":-419.76},{"x":-52.16,"y":268.57,"z":-418.45},{"x":-52.73,"y":271.88,"z":-416.23},{"x":-56.14,"y":272.61,"z":-415.31}]},{"lat":-31.38,"lon":-83.72,"b":[{"x":-50.11,"y":261.03,"z":-423.44},{"x":-49.52,"y":257.69,"z":-425.55},{"x":-46.17,"y":257.03,"z":-426.33},{"x":-43.43,"y":259.63,"z":-425.04},{"x":-43.98,"y":262.92,"z":-422.95},{"x":-47.31,"y":263.65,"z":-422.13}]},{"lat":-56.13,"lon":-5.86,"b":[{"x":-278.18,"y":414.54,"z":-27.33},{"x":-278.53,"y":414.21,"z":-28.68},{"x":-277.51,"y":414.82,"z":-29.83},{"x":-276.14,"y":415.75,"z":-29.61},{"x":-275.81,"y":416.06,"z":-28.25},{"x":-276.83,"y":415.46,"z":-27.13}]},{"lat":-50.6,"lon":-56.9,"b":[{"x":-175.2,"y":386.4,"z":-264.5},{"x":-175.06,"y":385.12,"z":-266.45},{"x":-173.14,"y":385.08,"z":-267.75},{"x":-171.39,"y":386.31,"z":-267.11},{"x":-171.55,"y":387.57,"z":-265.18},{"x":-173.44,"y":387.62,"z":-263.88}]},{"lat":-49.52,"lon":-59.63,"b":[{"x":-164.49,"y":380.34,"z":-279.77},{"x":-164.45,"y":380.06,"z":-280.18},{"x":-164.04,"y":380.04,"z":-280.45},{"x":-163.67,"y":380.3,"z":-280.31},{"x":-163.71,"y":380.59,"z":-279.9},{"x":-164.12,"y":380.61,"z":-279.63}]},{"lat":-48.38,"lon":-62.24,"b":[{"x":-155.13,"y":373.83,"z":-293.56},{"x":-155.08,"y":373.5,"z":-293.99},{"x":-154.63,"y":373.47,"z":-294.27},{"x":-154.23,"y":373.76,"z":-294.11},{"x":-154.28,"y":374.08,"z":-293.68},{"x":-154.73,"y":374.12,"z":-293.4}]},{"lat":-47.2,"lon":-64.71,"b":[{"x":-146.49,"y":366.95,"z":-306.37},{"x":-146.34,"y":365.94,"z":-307.64},{"x":-144.98,"y":365.82,"z":-308.42},{"x":-143.81,"y":366.69,"z":-307.94},{"x":-143.97,"y":367.68,"z":-306.69},{"x":-145.3,"y":367.81,"z":-305.9}]},{"lat":-45.97,"lon":-67.05,"b":[{"x":-139.38,"y":359.86,"z":-317.81},{"x":-138.88,"y":356.9,"z":-321.35},{"x":-135.01,"y":356.46,"z":-323.47},{"x":-131.68,"y":358.97,"z":-322.07},{"x":-132.17,"y":361.9,"z":-318.57},{"x":-136,"y":362.36,"z":-316.43}]},{"lat":-44.71,"lon":-69.26,"b":[{"x":-129.68,"y":352.22,"z":-330.24},{"x":-129.15,"y":349.17,"z":-333.66},{"x":-125.29,"y":348.67,"z":-335.65},{"x":-122.01,"y":351.19,"z":-334.23},{"x":-122.54,"y":354.2,"z":-330.85},{"x":-126.35,"y":354.73,"z":-328.84}]},{"lat":-43.43,"lon":-71.35,"b":[{"x":-119.95,"y":344.25,"z":-342.1},{"x":-119.39,"y":341.13,"z":-345.41},{"x":-115.56,"y":340.58,"z":-347.25},{"x":-112.34,"y":343.1,"z":-345.83},{"x":-112.89,"y":346.18,"z":-342.56},{"x":-116.67,"y":346.77,"z":-340.69}]},{"lat":-42.13,"lon":-73.32,"b":[{"x":-110.23,"y":336.01,"z":-353.39},{"x":-109.65,"y":332.83,"z":-356.56},{"x":-105.86,"y":332.22,"z":-358.27},{"x":-102.69,"y":334.76,"z":-356.84},{"x":-103.26,"y":337.89,"z":-353.7},{"x":-107.01,"y":338.54,"z":-351.96}]},{"lat":-40.83,"lon":-75.17,"b":[{"x":-100.56,"y":327.53,"z":-364.07},{"x":-99.96,"y":324.3,"z":-367.11},{"x":-96.22,"y":323.65,"z":-368.68},{"x":-93.11,"y":326.19,"z":-367.25},{"x":-93.68,"y":329.38,"z":-364.24},{"x":-97.39,"y":330.07,"z":-362.64}]},{"lat":-39.52,"lon":-76.92,"b":[{"x":-90.97,"y":318.86,"z":-374.16},{"x":-90.36,"y":315.59,"z":-377.06},{"x":-86.67,"y":314.91,"z":-378.49},{"x":-83.62,"y":317.45,"z":-377.06},{"x":-84.2,"y":320.68,"z":-374.19},{"x":-87.86,"y":321.4,"z":-372.72}]},{"lat":-38.22,"lon":-78.57,"b":[{"x":-81.49,"y":310.05,"z":-383.63},{"x":-80.87,"y":306.75,"z":-386.4},{"x":-77.25,"y":306.04,"z":-387.7},{"x":-74.26,"y":308.59,"z":-386.27},{"x":-74.84,"y":311.84,"z":-383.53},{"x":-78.44,"y":312.59,"z":-382.2}]},{"lat":-36.93,"lon":-80.12,"b":[{"x":-72.14,"y":301.13,"z":-392.51},{"x":-71.54,"y":297.81,"z":-395.13},{"x":-67.97,"y":297.09,"z":-396.3},{"x":-65.05,"y":299.64,"z":-394.88},{"x":-65.62,"y":302.9,"z":-392.29},{"x":-69.16,"y":303.67,"z":-391.08}]},{"lat":-35.65,"lon":-81.59,"b":[{"x":-62.96,"y":292.14,"z":-400.79},{"x":-62.36,"y":288.82,"z":-403.28},{"x":-58.88,"y":288.09,"z":-404.33},{"x":-56.01,"y":290.63,"z":-402.92},{"x":-56.58,"y":293.91,"z":-400.45},{"x":-60.04,"y":294.69,"z":-399.37}]},{"lat":-34.39,"lon":-82.97,"b":[{"x":-53.97,"y":283.14,"z":-408.5},{"x":-53.38,"y":279.82,"z":-410.85},{"x":-49.97,"y":279.09,"z":-411.78},{"x":-47.17,"y":281.62,"z":-410.39},{"x":-47.72,"y":284.89,"z":-408.05},{"x":-51.11,"y":285.68,"z":-407.09}]},{"lat":-33.15,"lon":-84.27,"b":[{"x":-45.18,"y":274.14,"z":-415.64},{"x":-44.61,"y":270.83,"z":-417.86},{"x":-41.28,"y":270.1,"z":-418.67},{"x":-38.54,"y":272.63,"z":-417.3},{"x":-39.07,"y":275.89,"z":-415.1},{"x":-42.38,"y":276.67,"z":-414.25}]},{"lat":-31.93,"lon":-85.5,"b":[{"x":-36.61,"y":265.18,"z":-422.25},{"x":-36.06,"y":261.89,"z":-424.34},{"x":-32.81,"y":261.17,"z":-425.04},{"x":-30.13,"y":263.69,"z":-423.69},{"x":-30.64,"y":266.93,"z":-421.62},{"x":-33.87,"y":267.7,"z":-420.88}]},{"lat":-57.45,"lon":-4.32,"b":[{"x":-270.25,"y":420.23,"z":-18.06},{"x":-270.95,"y":419.66,"z":-20.72},{"x":-268.89,"y":420.87,"z":-22.98},{"x":-266.14,"y":422.63,"z":-22.55},{"x":-265.49,"y":423.17,"z":-19.88},{"x":-267.55,"y":421.98,"z":-17.66}]},{"lat":-57.79,"lon":-7.18,"b":[{"x":-264.94,"y":422.75,"z":-32.79},{"x":-265.09,"y":422.61,"z":-33.43},{"x":-264.6,"y":422.88,"z":-33.97},{"x":-263.95,"y":423.29,"z":-33.86},{"x":-263.81,"y":423.43,"z":-33.22},{"x":-264.3,"y":423.16,"z":-32.69}]},{"lat":-52.58,"lon":-56.85,"b":[{"x":-169.74,"y":397.14,"z":-251.8},{"x":-169.51,"y":394.82,"z":-255.57},{"x":-165.86,"y":394.73,"z":-258.08},{"x":-162.5,"y":396.95,"z":-256.82},{"x":-162.76,"y":399.24,"z":-253.08},{"x":-166.35,"y":399.34,"z":-250.58}]},{"lat":-51.51,"lon":-59.68,"b":[{"x":-160.88,"y":391.48,"z":-266.06},{"x":-160.58,"y":388.96,"z":-269.92},{"x":-156.77,"y":388.77,"z":-272.42},{"x":-153.32,"y":391.08,"z":-271.07},{"x":-153.64,"y":393.57,"z":-267.26},{"x":-157.4,"y":393.78,"z":-264.76}]},{"lat":-50.37,"lon":-62.37,"b":[{"x":-151.47,"y":385.32,"z":-280.21},{"x":-151.13,"y":382.85,"z":-283.76},{"x":-147.54,"y":382.58,"z":-286},{"x":-144.34,"y":384.77,"z":-284.7},{"x":-144.69,"y":387.21,"z":-281.19},{"x":-148.24,"y":387.49,"z":-278.94}]},{"lat":-49.19,"lon":-64.91,"b":[{"x":-139.48,"y":378.49,"z":-295.41},{"x":-139.38,"y":377.83,"z":-296.3},{"x":-138.46,"y":377.74,"z":-296.85},{"x":-137.65,"y":378.3,"z":-296.51},{"x":-137.75,"y":378.96,"z":-295.63},{"x":-138.66,"y":379.05,"z":-295.08}]},{"lat":-47.95,"lon":-67.32,"b":[{"x":-132.91,"y":371.69,"z":-306.77},{"x":-132.46,"y":368.88,"z":-310.35},{"x":-128.66,"y":368.43,"z":-312.47},{"x":-125.37,"y":370.77,"z":-311.04},{"x":-125.82,"y":373.55,"z":-307.51},{"x":-129.57,"y":374.02,"z":-305.37}]},{"lat":-46.69,"lon":-69.59,"b":[{"x":-123.4,"y":364.27,"z":-319.39},{"x":-122.91,"y":361.37,"z":-322.86},{"x":-119.13,"y":360.85,"z":-324.85},{"x":-115.88,"y":363.2,"z":-323.4},{"x":-116.37,"y":366.07,"z":-319.98},{"x":-120.1,"y":366.62,"z":-317.96}]},{"lat":-45.39,"lon":-71.73,"b":[{"x":-113.88,"y":356.51,"z":-331.46},{"x":-113.36,"y":353.5,"z":-334.85},{"x":-109.57,"y":352.91,"z":-336.72},{"x":-106.35,"y":355.3,"z":-335.24},{"x":-106.86,"y":358.27,"z":-331.9},{"x":-110.61,"y":358.89,"z":-330}]},{"lat":-44.08,"lon":-73.74,"b":[{"x":-104.33,"y":348.43,"z":-342.99},{"x":-103.79,"y":345.36,"z":-346.26},{"x":-100.03,"y":344.71,"z":-348},{"x":-96.87,"y":347.12,"z":-346.51},{"x":-97.4,"y":350.15,"z":-343.28},{"x":-101.11,"y":350.83,"z":-341.51}]},{"lat":-42.76,"lon":-75.63,"b":[{"x":-94.82,"y":340.1,"z":-353.95},{"x":-94.26,"y":336.96,"z":-357.09},{"x":-90.55,"y":336.27,"z":-358.69},{"x":-87.44,"y":338.68,"z":-357.19},{"x":-87.99,"y":341.78,"z":-354.1},{"x":-91.66,"y":342.5,"z":-352.46}]},{"lat":-41.43,"lon":-77.41,"b":[{"x":-85.38,"y":331.54,"z":-364.32},{"x":-84.8,"y":328.35,"z":-367.33},{"x":-81.15,"y":327.63,"z":-368.8},{"x":-78.1,"y":330.05,"z":-367.3},{"x":-78.66,"y":333.19,"z":-364.33},{"x":-82.28,"y":333.96,"z":-362.82}]},{"lat":-40.1,"lon":-79.08,"b":[{"x":-76.04,"y":322.81,"z":-374.1},{"x":-75.46,"y":319.59,"z":-376.98},{"x":-71.86,"y":318.83,"z":-378.31},{"x":-68.88,"y":321.26,"z":-376.82},{"x":-69.43,"y":324.44,"z":-373.98},{"x":-73,"y":325.23,"z":-372.6}]},{"lat":-38.78,"lon":-80.66,"b":[{"x":-66.83,"y":313.95,"z":-383.3},{"x":-66.25,"y":310.7,"z":-386.03},{"x":-62.72,"y":309.93,"z":-387.24},{"x":-59.8,"y":312.36,"z":-385.75},{"x":-60.34,"y":315.56,"z":-383.05},{"x":-63.85,"y":316.38,"z":-381.8}]},{"lat":-37.48,"lon":-82.14,"b":[{"x":-57.77,"y":304.99,"z":-391.9},{"x":-57.2,"y":301.73,"z":-394.5},{"x":-53.74,"y":300.95,"z":-395.59},{"x":-50.88,"y":303.38,"z":-394.11},{"x":-51.42,"y":306.6,"z":-391.54},{"x":-54.85,"y":307.43,"z":-390.41}]},{"lat":-36.19,"lon":-83.53,"b":[{"x":-48.89,"y":295.99,"z":-399.94},{"x":-48.33,"y":292.72,"z":-402.4},{"x":-44.94,"y":291.93,"z":-403.36},{"x":-42.14,"y":294.37,"z":-401.9},{"x":-42.67,"y":297.59,"z":-399.46},{"x":-46.03,"y":298.42,"z":-398.46}]},{"lat":-34.91,"lon":-84.84,"b":[{"x":-40.2,"y":286.97,"z":-407.41},{"x":-39.65,"y":283.7,"z":-409.74},{"x":-36.34,"y":282.91,"z":-410.59},{"x":-33.61,"y":285.35,"z":-409.15},{"x":-34.12,"y":288.56,"z":-406.84},{"x":-37.4,"y":289.4,"z":-405.95}]},{"lat":-33.67,"lon":-86.08,"b":[{"x":-31.72,"y":277.96,"z":-414.35},{"x":-31.19,"y":274.7,"z":-416.55},{"x":-27.96,"y":273.93,"z":-417.29},{"x":-25.29,"y":276.36,"z":-415.86},{"x":-25.78,"y":279.56,"z":-413.68},{"x":-28.99,"y":280.4,"z":-412.9}]},{"lat":-32.44,"lon":-87.24,"b":[{"x":-23.47,"y":269.01,"z":-420.76},{"x":-22.96,"y":265.77,"z":-422.84},{"x":-19.81,"y":265,"z":-423.48},{"x":-17.2,"y":267.42,"z":-422.07},{"x":-17.67,"y":270.61,"z":-420.01},{"x":-20.79,"y":271.44,"z":-419.33}]},{"lat":31.29,"lon":18.24,"b":[{"x":-403.88,"y":-260.89,"z":136.95},{"x":-403.58,"y":-263.12,"z":133.51},{"x":-405.43,"y":-261.9,"z":130.25},{"x":-407.6,"y":-258.41,"z":130.45},{"x":-407.89,"y":-256.17,"z":133.94},{"x":-406.02,"y":-257.42,"z":137.18}]},{"lat":29.4,"lon":19.13,"b":[{"x":-409.42,"y":-246.79,"z":146.28},{"x":-409.22,"y":-249.33,"z":142.51},{"x":-411.29,"y":-247.93,"z":138.92},{"x":-413.59,"y":-243.96,"z":139.13},{"x":-413.78,"y":-241.42,"z":142.94},{"x":-411.69,"y":-242.85,"z":146.51}]},{"lat":29.71,"lon":16.88,"b":[{"x":-414.34,"y":-248.65,"z":128.26},{"x":-414.16,"y":-250.11,"z":125.99},{"x":-415.32,"y":-249.25,"z":123.83},{"x":-416.69,"y":-246.91,"z":123.93},{"x":-416.87,"y":-245.44,"z":126.22},{"x":-415.69,"y":-246.33,"z":128.38}]},{"lat":27.5,"lon":19.99,"b":[{"x":-414.66,"y":-232.26,"z":155.08},{"x":-414.58,"y":-234.83,"z":151.36},{"x":-416.67,"y":-233.4,"z":147.8},{"x":-418.85,"y":-229.34,"z":147.98},{"x":-418.91,"y":-226.75,"z":151.74},{"x":-416.81,"y":-228.23,"z":155.27}]},{"lat":27.81,"lon":17.79,"b":[{"x":-419.04,"y":-234.71,"z":138.75},{"x":-418.85,"y":-237.25,"z":134.93},{"x":-420.86,"y":-235.75,"z":131.25},{"x":-423.08,"y":-231.65,"z":131.41},{"x":-423.25,"y":-229.1,"z":135.27},{"x":-421.22,"y":-230.65,"z":138.93}]},{"lat":28.08,"lon":15.54,"b":[{"x":-423.94,"y":-236.2,"z":120.17},{"x":-423.78,"y":-237.52,"z":118.1},{"x":-424.8,"y":-236.69,"z":116.1},{"x":-425.99,"y":-234.51,"z":116.17},{"x":-426.14,"y":-233.19,"z":118.26},{"x":-425.11,"y":-234.04,"z":120.25}]},{"lat":25.6,"lon":20.81,"b":[{"x":-419.36,"y":-217.46,"z":163.65},{"x":-419.4,"y":-220.07,"z":160.01},{"x":-421.5,"y":-218.59,"z":156.47},{"x":-423.57,"y":-214.46,"z":156.62},{"x":-423.5,"y":-211.85,"z":160.31},{"x":-421.39,"y":-213.37,"z":163.81}]},{"lat":25.9,"lon":18.67,"b":[{"x":-424.04,"y":-219.89,"z":147.54},{"x":-423.98,"y":-222.48,"z":143.78},{"x":-426.01,"y":-220.93,"z":140.12},{"x":-428.1,"y":-216.76,"z":140.26},{"x":-428.14,"y":-214.17,"z":144.06},{"x":-426.11,"y":-215.76,"z":147.69}]},{"lat":26.17,"lon":16.47,"b":[{"x":-428.32,"y":-222.11,"z":130.91},{"x":-428.15,"y":-224.66,"z":127.05},{"x":-430.09,"y":-223.04,"z":123.27},{"x":-432.22,"y":-218.84,"z":123.39},{"x":-432.37,"y":-216.28,"z":127.3},{"x":-430.41,"y":-217.94,"z":131.04}]},{"lat":23.7,"lon":21.6,"b":[{"x":-423.51,"y":-202.47,"z":171.98},{"x":-423.68,"y":-205.1,"z":168.41},{"x":-425.78,"y":-203.58,"z":164.91},{"x":-427.72,"y":-199.38,"z":165.02},{"x":-427.53,"y":-196.76,"z":168.64},{"x":-425.42,"y":-198.33,"z":172.1}]},{"lat":23.99,"lon":19.51,"b":[{"x":-428.48,"y":-204.85,"z":156.11},{"x":-428.55,"y":-207.46,"z":152.42},{"x":-430.59,"y":-205.87,"z":148.79},{"x":-432.55,"y":-201.64,"z":148.89},{"x":-432.46,"y":-199.03,"z":152.63},{"x":-430.42,"y":-200.66,"z":156.22}]},{"lat":24.26,"lon":17.36,"b":[{"x":-433.07,"y":-207.04,"z":139.7},{"x":-433.03,"y":-209.63,"z":135.89},{"x":-434.98,"y":-207.97,"z":132.15},{"x":-436.98,"y":-203.7,"z":132.24},{"x":-436.99,"y":-201.11,"z":136.08},{"x":-435.03,"y":-202.81,"z":139.79}]},{"lat":24.5,"lon":15.16,"b":[{"x":-437.23,"y":-209.01,"z":122.75},{"x":-437.08,"y":-211.55,"z":118.87},{"x":-438.93,"y":-209.84,"z":115.05},{"x":-440.93,"y":-205.56,"z":115.13},{"x":-441.06,"y":-203.03,"z":119.04},{"x":-439.21,"y":-204.77,"z":122.83}]},{"lat":21.81,"lon":22.37,"b":[{"x":-427.11,"y":-187.35,"z":180.04},{"x":-427.4,"y":-189.98,"z":176.55},{"x":-429.5,"y":-188.41,"z":173.09},{"x":-431.31,"y":-184.17,"z":173.15},{"x":-430.99,"y":-181.55,"z":176.68},{"x":-428.89,"y":-183.16,"z":180.11}]},{"lat":22.09,"lon":20.32,"b":[{"x":-432.35,"y":-189.65,"z":164.43},{"x":-432.55,"y":-192.27,"z":160.81},{"x":-434.59,"y":-190.64,"z":157.22},{"x":-436.42,"y":-186.35,"z":157.28},{"x":-436.2,"y":-183.74,"z":160.94},{"x":-434.16,"y":-185.41,"z":164.49}]},{"lat":22.35,"lon":18.22,"b":[{"x":-437.23,"y":-191.79,"z":148.25},{"x":-437.32,"y":-194.39,"z":144.52},{"x":-439.28,"y":-192.7,"z":140.81},{"x":-441.14,"y":-188.37,"z":140.86},{"x":-441.02,"y":-185.77,"z":144.63},{"x":-439.06,"y":-187.5,"z":148.31}]},{"lat":22.58,"lon":16.07,"b":[{"x":-441.68,"y":-193.74,"z":131.56},{"x":-441.67,"y":-196.32,"z":127.71},{"x":-443.53,"y":-194.57,"z":123.88},{"x":-445.41,"y":-190.19,"z":123.93},{"x":-445.41,"y":-187.62,"z":127.81},{"x":-443.54,"y":-189.41,"z":131.61}]},{"lat":22.79,"lon":13.87,"b":[{"x":-447.19,"y":-194.02,"z":111.2},{"x":-447.16,"y":-194.48,"z":110.49},{"x":-447.48,"y":-194.15,"z":109.79},{"x":-447.82,"y":-193.36,"z":109.8},{"x":-447.84,"y":-192.91,"z":110.51},{"x":-447.52,"y":-193.24,"z":111.2}]},{"lat":19.94,"lon":23.11,"b":[{"x":-430.16,"y":-172.14,"z":187.8},{"x":-430.56,"y":-174.77,"z":184.4},{"x":-432.66,"y":-173.16,"z":180.97},{"x":-434.34,"y":-168.89,"z":180.99},{"x":-433.9,"y":-166.28,"z":184.43},{"x":-431.81,"y":-167.92,"z":187.82}]},{"lat":20.21,"lon":21.11,"b":[{"x":-435.65,"y":-174.34,"z":172.47},{"x":-435.97,"y":-176.97,"z":168.93},{"x":-438.01,"y":-175.3,"z":165.38},{"x":-439.71,"y":-170.98,"z":165.39},{"x":-439.35,"y":-168.37,"z":168.97},{"x":-437.33,"y":-170.07,"z":172.48}]},{"lat":20.45,"lon":19.06,"b":[{"x":-440.8,"y":-176.4,"z":156.56},{"x":-441.02,"y":-179.02,"z":152.9},{"x":-442.98,"y":-177.29,"z":149.22},{"x":-444.7,"y":-172.92,"z":149.24},{"x":-444.44,"y":-170.32,"z":152.93},{"x":-442.5,"y":-172.08,"z":156.57}]},{"lat":20.68,"lon":16.95,"b":[{"x":-445.54,"y":-178.3,"z":140.11},{"x":-445.66,"y":-180.9,"z":136.33},{"x":-447.53,"y":-179.11,"z":132.54},{"x":-449.26,"y":-174.69,"z":132.55},{"x":-449.12,"y":-172.11,"z":136.36},{"x":-447.26,"y":-173.93,"z":140.12}]},{"lat":20.88,"lon":14.8,"b":[{"x":-449.84,"y":-180.02,"z":123.14},{"x":-449.84,"y":-182.6,"z":119.26},{"x":-451.61,"y":-180.74,"z":115.36},{"x":-453.36,"y":-176.29,"z":115.37},{"x":-453.34,"y":-173.73,"z":119.29},{"x":-451.58,"y":-175.61,"z":123.16}]},{"lat":18.09,"lon":23.82,"b":[{"x":-432.66,"y":-156.92,"z":195.24},{"x":-433.18,"y":-159.53,"z":191.93},{"x":-435.27,"y":-157.88,"z":188.55},{"x":-436.81,"y":-153.59,"z":188.52},{"x":-436.25,"y":-151.01,"z":191.87},{"x":-434.19,"y":-152.69,"z":195.21}]},{"lat":18.34,"lon":21.87,"b":[{"x":-438.38,"y":-159,"z":180.2},{"x":-438.83,"y":-161.61,"z":176.76},{"x":-440.85,"y":-159.91,"z":173.24},{"x":-442.41,"y":-155.56,"z":173.21},{"x":-441.94,"y":-152.97,"z":176.69},{"x":-439.93,"y":-154.71,"z":180.17}]},{"lat":18.57,"lon":19.86,"b":[{"x":-443.78,"y":-160.95,"z":164.58},{"x":-444.13,"y":-163.56,"z":161.01},{"x":-446.08,"y":-161.8,"z":157.36},{"x":-447.66,"y":-157.41,"z":157.34},{"x":-447.28,"y":-154.82,"z":160.95},{"x":-445.34,"y":-156.61,"z":164.55}]},{"lat":18.78,"lon":17.8,"b":[{"x":-448.79,"y":-162.77,"z":148.4},{"x":-449.04,"y":-165.37,"z":144.7},{"x":-450.9,"y":-163.55,"z":140.94},{"x":-452.5,"y":-159.11,"z":140.91},{"x":-452.22,"y":-156.53,"z":144.64},{"x":-450.37,"y":-158.38,"z":148.37}]},{"lat":18.98,"lon":15.69,"b":[{"x":-453.37,"y":-164.44,"z":131.68},{"x":-453.52,"y":-167.02,"z":127.87},{"x":-455.28,"y":-165.14,"z":124},{"x":-456.88,"y":-160.65,"z":123.98},{"x":-456.72,"y":-158.09,"z":127.82},{"x":-454.97,"y":-159.99,"z":131.66}]},{"lat":19.15,"lon":13.54,"b":[{"x":-457.48,"y":-165.93,"z":114.49},{"x":-457.5,"y":-168.49,"z":110.57},{"x":-459.15,"y":-166.54,"z":106.6},{"x":-460.77,"y":-162.02,"z":106.58},{"x":-460.73,"y":-159.48,"z":110.52},{"x":-459.09,"y":-161.44,"z":114.46}]},{"lat":16.27,"lon":24.51,"b":[{"x":-434.63,"y":-141.74,"z":202.36},{"x":-435.26,"y":-144.31,"z":199.14},{"x":-437.33,"y":-142.63,"z":195.8},{"x":-438.74,"y":-138.34,"z":195.71},{"x":-438.07,"y":-135.79,"z":198.96},{"x":-436.03,"y":-137.5,"z":202.27}]},{"lat":16.49,"lon":22.6,"b":[{"x":-440.56,"y":-143.67,"z":187.62},{"x":-441.12,"y":-146.26,"z":184.27},{"x":-443.12,"y":-144.52,"z":180.8},{"x":-444.55,"y":-140.17,"z":180.72},{"x":-443.96,"y":-137.61,"z":184.1},{"x":-441.97,"y":-139.38,"z":187.54}]},{"lat":16.71,"lon":20.64,"b":[{"x":-446.18,"y":-145.5,"z":172.3},{"x":-446.65,"y":-148.09,"z":168.82},{"x":-448.59,"y":-146.31,"z":165.21},{"x":-450.03,"y":-141.9,"z":165.14},{"x":-449.52,"y":-139.34,"z":168.66},{"x":-447.61,"y":-141.15,"z":172.22}]},{"lat":16.91,"lon":18.62,"b":[{"x":-451.44,"y":-147.22,"z":156.4},{"x":-451.82,"y":-149.81,"z":152.79},{"x":-453.67,"y":-147.96,"z":149.07},{"x":-455.12,"y":-143.51,"z":149},{"x":-454.71,"y":-140.95,"z":152.64},{"x":-452.88,"y":-142.81,"z":156.33}]},{"lat":17.09,"lon":16.56,"b":[{"x":-456.28,"y":-148.8,"z":139.96},{"x":-456.56,"y":-151.38,"z":136.23},{"x":-458.32,"y":-149.48,"z":132.4},{"x":-459.78,"y":-144.98,"z":132.33},{"x":-459.48,"y":-142.42,"z":136.1},{"x":-457.74,"y":-144.35,"z":139.89}]},{"lat":17.25,"lon":14.45,"b":[{"x":-460.68,"y":-150.23,"z":123.02},{"x":-460.84,"y":-152.8,"z":119.17},{"x":-462.49,"y":-150.84,"z":115.24},{"x":-463.96,"y":-146.3,"z":115.18},{"x":-463.77,"y":-143.76,"z":119.05},{"x":-462.14,"y":-145.73,"z":122.95}]},{"lat":17.4,"lon":12.3,"b":[{"x":-464.72,"y":-151.3,"z":105.21},{"x":-464.76,"y":-153.6,"z":101.66},{"x":-466.13,"y":-151.77,"z":98.03},{"x":-467.47,"y":-147.65,"z":97.99},{"x":-467.41,"y":-145.38,"z":101.57},{"x":-466.05,"y":-147.21,"z":105.16}]},{"lat":14.47,"lon":25.17,"b":[{"x":-436.08,"y":-126.65,"z":209.13},{"x":-436.81,"y":-129.18,"z":206.01},{"x":-438.86,"y":-127.47,"z":202.71},{"x":-440.14,"y":-123.19,"z":202.57},{"x":-439.37,"y":-120.68,"z":205.72},{"x":-437.36,"y":-122.43,"z":208.98}]},{"lat":14.68,"lon":23.31,"b":[{"x":-442.19,"y":-128.42,"z":194.71},{"x":-442.86,"y":-130.97,"z":191.46},{"x":-444.84,"y":-129.21,"z":188.03},{"x":-446.14,"y":-124.87,"z":187.89},{"x":-445.44,"y":-122.35,"z":191.18},{"x":-443.48,"y":-124.14,"z":194.57}]},{"lat":14.87,"lon":21.39,"b":[{"x":-448.01,"y":-130.11,"z":179.7},{"x":-448.6,"y":-132.67,"z":176.31},{"x":-450.52,"y":-130.86,"z":172.75},{"x":-451.82,"y":-126.46,"z":172.62},{"x":-451.2,"y":-123.93,"z":176.05},{"x":-449.3,"y":-125.77,"z":179.56}]},{"lat":15.05,"lon":19.42,"b":[{"x":-453.49,"y":-131.7,"z":164.11},{"x":-454,"y":-134.27,"z":160.59},{"x":-455.83,"y":-132.4,"z":156.91},{"x":-457.14,"y":-127.95,"z":156.79},{"x":-456.61,"y":-125.42,"z":160.34},{"x":-454.79,"y":-127.31,"z":163.98}]},{"lat":15.22,"lon":17.4,"b":[{"x":-458.58,"y":-133.18,"z":147.96},{"x":-458.99,"y":-135.74,"z":144.31},{"x":-460.73,"y":-133.82,"z":140.52},{"x":-462.05,"y":-129.32,"z":140.41},{"x":-461.62,"y":-126.79,"z":144.09},{"x":-459.89,"y":-128.73,"z":147.84}]},{"lat":15.38,"lon":15.33,"b":[{"x":-463.24,"y":-134.54,"z":131.29},{"x":-463.54,"y":-137.09,"z":127.53},{"x":-465.17,"y":-135.11,"z":123.63},{"x":-466.49,"y":-130.57,"z":123.53},{"x":-466.17,"y":-128.05,"z":127.32},{"x":-464.55,"y":-130.04,"z":131.18}]},{"lat":15.51,"lon":13.22,"b":[{"x":-467.41,"y":-135.75,"z":114.14},{"x":-467.59,"y":-138.29,"z":110.26},{"x":-469.11,"y":-136.25,"z":106.27},{"x":-470.44,"y":-131.67,"z":106.19},{"x":-470.24,"y":-129.16,"z":110.08},{"x":-468.73,"y":-131.2,"z":114.04}]},{"lat":12.7,"lon":25.81,"b":[{"x":-437.04,"y":-111.7,"z":215.55},{"x":-437.87,"y":-114.19,"z":212.53},{"x":-439.89,"y":-112.44,"z":209.28},{"x":-441.04,"y":-108.19,"z":209.08},{"x":-440.18,"y":-105.74,"z":212.13},{"x":-438.19,"y":-107.5,"z":215.34}]},{"lat":12.89,"lon":23.99,"b":[{"x":-443.3,"y":-113.3,"z":201.45},{"x":-444.07,"y":-115.81,"z":198.3},{"x":-446.03,"y":-114.02,"z":194.91},{"x":-447.2,"y":-109.7,"z":194.72},{"x":-446.39,"y":-107.23,"z":197.91},{"x":-444.46,"y":-109.04,"z":201.26}]},{"lat":13.06,"lon":22.11,"b":[{"x":-449.3,"y":-114.83,"z":186.76},{"x":-450,"y":-117.35,"z":183.47},{"x":-451.89,"y":-115.51,"z":179.96},{"x":-453.06,"y":-111.13,"z":179.78},{"x":-452.33,"y":-108.65,"z":183.11},{"x":-450.46,"y":-110.51,"z":186.57}]},{"lat":13.23,"lon":20.18,"b":[{"x":-454.97,"y":-116.29,"z":171.49},{"x":-455.6,"y":-118.81,"z":168.06},{"x":-457.41,"y":-116.92,"z":164.43},{"x":-458.58,"y":-112.49,"z":164.26},{"x":-457.93,"y":-110,"z":167.72},{"x":-456.14,"y":-111.91,"z":171.31}]},{"lat":13.38,"lon":18.21,"b":[{"x":-460.29,"y":-117.64,"z":155.65},{"x":-460.82,"y":-120.17,"z":152.1},{"x":-462.54,"y":-118.23,"z":148.34},{"x":-463.71,"y":-113.75,"z":148.19},{"x":-463.16,"y":-111.26,"z":151.78},{"x":-461.45,"y":-113.21,"z":155.48}]},{"lat":13.52,"lon":16.18,"b":[{"x":-465.18,"y":-118.9,"z":139.28},{"x":-465.61,"y":-121.42,"z":135.6},{"x":-467.23,"y":-119.43,"z":131.74},{"x":-468.41,"y":-114.9,"z":131.6},{"x":-467.96,"y":-112.41,"z":135.31},{"x":-466.35,"y":-114.41,"z":139.12}]},{"lat":13.65,"lon":14.12,"b":[{"x":-469.61,"y":-120.03,"z":122.4},{"x":-469.93,"y":-122.55,"z":118.61},{"x":-471.44,"y":-120.51,"z":114.65},{"x":-472.62,"y":-115.94,"z":114.53},{"x":-472.28,"y":-113.45,"z":118.35},{"x":-470.79,"y":-115.5,"z":122.26}]},{"lat":10.97,"lon":26.43,"b":[{"x":-437.53,"y":-96.94,"z":221.61},{"x":-438.44,"y":-99.37,"z":218.7},{"x":-440.43,"y":-97.6,"z":215.49},{"x":-441.47,"y":-93.38,"z":215.24},{"x":-440.52,"y":-90.99,"z":218.18},{"x":-438.57,"y":-92.79,"z":221.35}]},{"lat":11.13,"lon":24.65,"b":[{"x":-443.92,"y":-98.36,"z":207.85},{"x":-444.78,"y":-100.81,"z":204.8},{"x":-446.72,"y":-99,"z":201.46},{"x":-447.75,"y":-94.71,"z":201.21},{"x":-446.86,"y":-92.3,"z":204.3},{"x":-444.96,"y":-94.14,"z":207.59}]},{"lat":11.29,"lon":22.81,"b":[{"x":-450.06,"y":-99.72,"z":193.49},{"x":-450.86,"y":-102.19,"z":190.3},{"x":-452.73,"y":-100.33,"z":186.83},{"x":-453.77,"y":-95.98,"z":186.6},{"x":-452.93,"y":-93.56,"z":189.82},{"x":-451.1,"y":-95.44,"z":193.24}]},{"lat":11.43,"lon":20.93,"b":[{"x":-455.91,"y":-101.02,"z":178.54},{"x":-456.64,"y":-103.5,"z":175.21},{"x":-458.43,"y":-101.59,"z":171.62},{"x":-459.46,"y":-97.19,"z":171.4},{"x":-458.71,"y":-94.75,"z":174.76},{"x":-456.94,"y":-96.67,"z":178.31}]},{"lat":11.57,"lon":18.99,"b":[{"x":-461.41,"y":-102.24,"z":163.02},{"x":-462.06,"y":-104.73,"z":159.56},{"x":-463.76,"y":-102.77,"z":155.86},{"x":-464.8,"y":-98.32,"z":155.66},{"x":-464.13,"y":-95.87,"z":159.15},{"x":-462.45,"y":-97.84,"z":162.8}]},{"lat":11.7,"lon":17.01,"b":[{"x":-466.53,"y":-103.37,"z":146.96},{"x":-467.08,"y":-105.87,"z":143.37},{"x":-468.68,"y":-103.86,"z":139.56},{"x":-469.71,"y":-99.36,"z":139.38},{"x":-469.14,"y":-96.91,"z":142.99},{"x":-467.56,"y":-98.92,"z":146.76}]},{"lat":11.81,"lon":14.98,"b":[{"x":-471.2,"y":-104.41,"z":130.39},{"x":-471.65,"y":-106.9,"z":126.68},{"x":-473.14,"y":-104.85,"z":122.77},{"x":-474.17,"y":-100.3,"z":122.6},{"x":-473.7,"y":-97.85,"z":126.33},{"x":-472.22,"y":-99.9,"z":130.2}]},{"lat":9.28,"lon":27.03,"b":[{"x":-437.58,"y":-82.42,"z":227.33},{"x":-438.57,"y":-84.78,"z":224.52},{"x":-440.52,"y":-82.99,"z":221.35},{"x":-441.44,"y":-78.82,"z":221.04},{"x":-440.41,"y":-76.5,"z":223.89},{"x":-438.5,"y":-78.31,"z":227.01}]},{"lat":9.42,"lon":25.29,"b":[{"x":-444.07,"y":-83.64,"z":213.89},{"x":-445.02,"y":-86.03,"z":210.94},{"x":-446.92,"y":-84.2,"z":207.65},{"x":-447.83,"y":-79.96,"z":207.35},{"x":-446.85,"y":-77.62,"z":210.33},{"x":-444.99,"y":-79.47,"z":213.58}]},{"lat":9.55,"lon":23.49,"b":[{"x":-450.33,"y":-84.82,"z":199.86},{"x":-451.23,"y":-87.23,"z":196.77},{"x":-453.06,"y":-85.35,"z":193.35},{"x":-453.97,"y":-81.06,"z":193.07},{"x":-453.05,"y":-78.69,"z":196.19},{"x":-451.25,"y":-80.58,"z":199.56}]},{"lat":9.68,"lon":21.64,"b":[{"x":-456.32,"y":-85.95,"z":185.25},{"x":-457.16,"y":-88.38,"z":182.02},{"x":-458.92,"y":-86.46,"z":178.48},{"x":-459.82,"y":-82.1,"z":178.21},{"x":-458.96,"y":-79.72,"z":181.47},{"x":-457.23,"y":-81.65,"z":184.96}]},{"lat":9.8,"lon":19.75,"b":[{"x":-462,"y":-87.02,"z":170.06},{"x":-462.75,"y":-89.46,"z":166.7},{"x":-464.43,"y":-87.49,"z":163.04},{"x":-465.33,"y":-83.08,"z":162.79},{"x":-464.55,"y":-80.69,"z":166.18},{"x":-462.9,"y":-82.66,"z":169.79}]},{"lat":9.91,"lon":17.81,"b":[{"x":-467.3,"y":-88.02,"z":154.33},{"x":-467.97,"y":-90.47,"z":150.84},{"x":-469.55,"y":-88.46,"z":147.07},{"x":-470.44,"y":-84,"z":146.84},{"x":-469.75,"y":-81.6,"z":150.36},{"x":-468.19,"y":-83.61,"z":154.08}]},{"lat":10.01,"lon":15.82,"b":[{"x":-472.18,"y":-88.94,"z":138.07},{"x":-472.76,"y":-91.39,"z":134.45},{"x":-474.23,"y":-89.34,"z":130.58},{"x":-475.11,"y":-84.83,"z":130.38},{"x":-474.53,"y":-82.43,"z":134.02},{"x":-473.07,"y":-84.48,"z":137.84}]},{"lat":10.1,"lon":13.8,"b":[{"x":-476.78,"y":-89.52,"z":120.84},{"x":-477.19,"y":-91.67,"z":117.57},{"x":-478.38,"y":-89.83,"z":114.1},{"x":-479.15,"y":-85.84,"z":113.94},{"x":-478.73,"y":-83.73,"z":117.23},{"x":-477.55,"y":-85.57,"z":120.66}]},{"lat":7.63,"lon":27.61,"b":[{"x":-437.21,"y":-68.16,"z":232.69},{"x":-438.28,"y":-70.46,"z":229.98},{"x":-440.19,"y":-68.65,"z":226.86},{"x":-441,"y":-64.53,"z":226.5},{"x":-439.9,"y":-62.28,"z":229.24},{"x":-438.03,"y":-64.11,"z":232.32}]},{"lat":7.74,"lon":25.9,"b":[{"x":-443.78,"y":-69.19,"z":219.58},{"x":-444.81,"y":-71.51,"z":216.74},{"x":-446.67,"y":-69.66,"z":213.49},{"x":-447.47,"y":-65.47,"z":213.14},{"x":-446.41,"y":-63.21,"z":216.02},{"x":-444.59,"y":-65.07,"z":219.22}]},{"lat":7.85,"lon":24.14,"b":[{"x":-450.14,"y":-70.18,"z":205.89},{"x":-451.12,"y":-72.52,"z":202.9},{"x":-452.92,"y":-70.63,"z":199.53},{"x":-453.71,"y":-66.39,"z":199.19},{"x":-452.7,"y":-64.1,"z":202.21},{"x":-450.94,"y":-66,"z":205.54}]},{"lat":7.96,"lon":22.34,"b":[{"x":-456.25,"y":-71.13,"z":191.61},{"x":-457.17,"y":-73.5,"z":188.49},{"x":-458.9,"y":-71.56,"z":185},{"x":-459.68,"y":-67.26,"z":184.68},{"x":-458.74,"y":-64.95,"z":187.83},{"x":-457.04,"y":-66.89,"z":191.27}]},{"lat":8.06,"lon":20.48,"b":[{"x":-462.06,"y":-72.04,"z":176.77},{"x":-462.92,"y":-74.42,"z":173.51},{"x":-464.57,"y":-72.45,"z":169.9},{"x":-465.33,"y":-68.09,"z":169.6},{"x":-464.46,"y":-65.76,"z":172.88},{"x":-462.84,"y":-67.74,"z":176.44}]},{"lat":8.15,"lon":18.58,"b":[{"x":-467.53,"y":-72.89,"z":161.36},{"x":-468.3,"y":-75.29,"z":157.97},{"x":-469.86,"y":-73.27,"z":154.25},{"x":-470.62,"y":-68.86,"z":153.98},{"x":-469.83,"y":-66.52,"z":157.39},{"x":-468.29,"y":-68.54,"z":161.06}]},{"lat":8.24,"lon":16.64,"b":[{"x":-472.6,"y":-73.69,"z":145.43},{"x":-473.29,"y":-76.09,"z":141.92},{"x":-474.74,"y":-74.03,"z":138.09},{"x":-475.49,"y":-69.58,"z":137.84},{"x":-474.79,"y":-67.23,"z":141.38},{"x":-473.36,"y":-69.28,"z":145.15}]},{"lat":8.32,"lon":14.65,"b":[{"x":-477.23,"y":-74.41,"z":129},{"x":-477.82,"y":-76.82,"z":125.36},{"x":-479.16,"y":-74.72,"z":121.45},{"x":-479.9,"y":-70.22,"z":121.23},{"x":-479.3,"y":-67.87,"z":124.89},{"x":-477.98,"y":-69.95,"z":128.75}]},{"lat":6.01,"lon":28.17,"b":[{"x":-436.46,"y":-54.21,"z":237.71},{"x":-437.59,"y":-56.42,"z":235.1},{"x":-439.47,"y":-54.6,"z":232.03},{"x":-440.17,"y":-50.54,"z":231.61},{"x":-439.01,"y":-48.38,"z":234.26},{"x":-437.18,"y":-50.22,"z":237.28}]},{"lat":6.1,"lon":26.5,"b":[{"x":-443.08,"y":-55.03,"z":224.93},{"x":-444.18,"y":-57.27,"z":222.18},{"x":-446.01,"y":-55.41,"z":218.98},{"x":-446.69,"y":-51.29,"z":218.58},{"x":-445.57,"y":-49.1,"z":221.36},{"x":-443.79,"y":-50.98,"z":224.51}]},{"lat":6.19,"lon":24.78,"b":[{"x":-449.52,"y":-55.83,"z":211.57},{"x":-450.57,"y":-58.1,"z":208.69},{"x":-452.34,"y":-56.2,"z":205.36},{"x":-453.01,"y":-52.02,"z":204.97},{"x":-451.93,"y":-49.81,"z":207.89},{"x":-450.2,"y":-51.71,"z":211.16}]},{"lat":6.28,"lon":23.01,"b":[{"x":-455.72,"y":-56.6,"z":197.63},{"x":-456.72,"y":-58.89,"z":194.61},{"x":-458.42,"y":-56.95,"z":191.17},{"x":-459.08,"y":-52.72,"z":190.8},{"x":-458.06,"y":-50.48,"z":193.85},{"x":-456.39,"y":-52.42,"z":197.24}]},{"lat":6.36,"lon":21.19,"b":[{"x":-461.64,"y":-57.34,"z":183.13},{"x":-462.59,"y":-59.65,"z":179.97},{"x":-464.21,"y":-57.67,"z":176.41},{"x":-464.85,"y":-53.38,"z":176.06},{"x":-463.89,"y":-51.13,"z":179.25},{"x":-462.3,"y":-53.1,"z":182.75}]},{"lat":6.43,"lon":19.33,"b":[{"x":-467.25,"y":-58.04,"z":168.07},{"x":-468.12,"y":-60.36,"z":164.78},{"x":-469.65,"y":-58.35,"z":161.11},{"x":-470.28,"y":-54.01,"z":160.78},{"x":-469.39,"y":-51.73,"z":164.1},{"x":-467.89,"y":-53.75,"z":167.72}]},{"lat":6.5,"lon":17.43,"b":[{"x":-472.48,"y":-58.69,"z":152.47},{"x":-473.28,"y":-61.03,"z":149.06},{"x":-474.71,"y":-58.98,"z":145.28},{"x":-475.32,"y":-54.59,"z":144.98},{"x":-474.52,"y":-52.3,"z":148.43},{"x":-473.11,"y":-54.35,"z":152.15}]},{"lat":6.57,"lon":15.48,"b":[{"x":-477.3,"y":-59.29,"z":136.38},{"x":-478,"y":-61.64,"z":132.83},{"x":-479.33,"y":-59.55,"z":128.97},{"x":-479.93,"y":-55.12,"z":128.7},{"x":-479.22,"y":-52.82,"z":132.26},{"x":-477.92,"y":-54.9,"z":136.08}]},{"lat":6.63,"lon":13.5,"b":[{"x":-481.66,"y":-59.83,"z":119.81},{"x":-482.26,"y":-62.19,"z":116.15},{"x":-483.46,"y":-60.06,"z":112.2},{"x":-484.05,"y":-55.59,"z":111.96},{"x":-483.45,"y":-53.28,"z":115.64},{"x":-482.26,"y":-55.4,"z":119.54}]},{"lat":4.44,"lon":28.71,"b":[{"x":-435.37,"y":-40.58,"z":242.4},{"x":-436.55,"y":-42.72,"z":239.89},{"x":-438.38,"y":-40.88,"z":236.86},{"x":-438.98,"y":-36.9,"z":236.39},{"x":-437.77,"y":-34.82,"z":238.93},{"x":-435.99,"y":-36.66,"z":241.92}]},{"lat":4.51,"lon":27.07,"b":[{"x":-442.02,"y":-41.2,"z":229.93},{"x":-443.17,"y":-43.36,"z":227.29},{"x":-444.96,"y":-41.49,"z":224.14},{"x":-445.54,"y":-37.45,"z":223.68},{"x":-444.36,"y":-35.34,"z":226.36},{"x":-442.62,"y":-37.22,"z":229.46}]},{"lat":4.58,"lon":25.39,"b":[{"x":-448.5,"y":-41.81,"z":216.9},{"x":-449.62,"y":-44,"z":214.12},{"x":-451.35,"y":-42.09,"z":210.85},{"x":-451.92,"y":-37.99,"z":210.41},{"x":-450.77,"y":-35.85,"z":213.22},{"x":-449.08,"y":-37.76,"z":216.45}]},{"lat":4.64,"lon":23.66,"b":[{"x":-454.77,"y":-42.39,"z":203.31},{"x":-455.85,"y":-44.61,"z":200.39},{"x":-457.51,"y":-42.66,"z":197},{"x":-458.06,"y":-38.5,"z":196.57},{"x":-456.96,"y":-36.34,"z":199.52},{"x":-455.33,"y":-38.29,"z":202.86}]},{"lat":4.7,"lon":21.88,"b":[{"x":-460.78,"y":-42.95,"z":189.14},{"x":-461.81,"y":-45.19,"z":186.09},{"x":-463.4,"y":-43.21,"z":182.59},{"x":-463.93,"y":-39,"z":182.18},{"x":-462.88,"y":-36.82,"z":185.27},{"x":-461.33,"y":-38.79,"z":188.72}]},{"lat":4.76,"lon":20.06,"b":[{"x":-466.5,"y":-43.49,"z":174.43},{"x":-467.46,"y":-45.74,"z":171.24},{"x":-468.96,"y":-43.73,"z":167.63},{"x":-469.47,"y":-39.46,"z":167.25},{"x":-468.5,"y":-37.26,"z":170.47},{"x":-467.03,"y":-39.27,"z":174.03}]},{"lat":4.81,"lon":18.19,"b":[{"x":-471.87,"y":-43.99,"z":159.18},{"x":-472.76,"y":-46.26,"z":155.87},{"x":-474.17,"y":-44.21,"z":152.15},{"x":-474.66,"y":-39.9,"z":151.8},{"x":-473.76,"y":-37.68,"z":155.14},{"x":-472.38,"y":-39.72,"z":158.81}]},{"lat":4.86,"lon":16.28,"b":[{"x":-476.85,"y":-44.45,"z":143.43},{"x":-477.65,"y":-46.74,"z":139.98},{"x":-478.95,"y":-44.66,"z":136.17},{"x":-479.43,"y":-40.3,"z":135.85},{"x":-478.62,"y":-38.07,"z":139.32},{"x":-477.34,"y":-40.14,"z":143.08}]},{"lat":4.91,"lon":14.34,"b":[{"x":-481.39,"y":-44.88,"z":127.19},{"x":-482.1,"y":-47.18,"z":123.63},{"x":-483.29,"y":-45.06,"z":119.73},{"x":-483.75,"y":-40.67,"z":119.45},{"x":-483.03,"y":-38.42,"z":123.03},{"x":-481.87,"y":-40.52,"z":126.87}]},{"lat":4.95,"lon":12.36,"b":[{"x":-485.56,"y":-45.07,"z":110.16},{"x":-486.11,"y":-47.17,"z":106.81},{"x":-487.07,"y":-45.22,"z":103.19},{"x":-487.48,"y":-41.18,"z":102.97},{"x":-486.93,"y":-39.12,"z":106.34},{"x":-485.98,"y":-41.06,"z":109.91}]},{"lat":2.92,"lon":29.23,"b":[{"x":-433.95,"y":-27.3,"z":246.76},{"x":-435.18,"y":-29.35,"z":244.34},{"x":-436.97,"y":-27.51,"z":241.36},{"x":-437.48,"y":-23.6,"z":240.84},{"x":-436.23,"y":-21.61,"z":243.29},{"x":-434.48,"y":-23.46,"z":246.23}]},{"lat":2.96,"lon":27.63,"b":[{"x":-440.61,"y":-27.72,"z":234.61},{"x":-441.82,"y":-29.8,"z":232.06},{"x":-443.56,"y":-27.92,"z":228.96},{"x":-444.05,"y":-23.96,"z":228.45},{"x":-442.82,"y":-21.94,"z":231.04},{"x":-441.12,"y":-23.82,"z":234.09}]},{"lat":3.01,"lon":25.98,"b":[{"x":-447.12,"y":-28.13,"z":221.91},{"x":-448.3,"y":-30.24,"z":219.22},{"x":-449.99,"y":-28.33,"z":216},{"x":-450.45,"y":-24.31,"z":215.51},{"x":-449.25,"y":-22.26,"z":218.23},{"x":-447.6,"y":-24.17,"z":221.4}]},{"lat":3.05,"lon":24.29,"b":[{"x":-453.43,"y":-28.53,"z":208.64},{"x":-454.57,"y":-30.66,"z":205.83},{"x":-456.2,"y":-28.72,"z":202.49},{"x":-456.65,"y":-24.64,"z":202.02},{"x":-455.48,"y":-22.57,"z":204.86},{"x":-453.9,"y":-24.51,"z":208.15}]},{"lat":3.09,"lon":22.55,"b":[{"x":-459.51,"y":-28.91,"z":194.82},{"x":-460.61,"y":-31.07,"z":191.87},{"x":-462.16,"y":-29.09,"z":188.42},{"x":-462.58,"y":-24.96,"z":187.97},{"x":-461.47,"y":-22.86,"z":190.95},{"x":-459.95,"y":-24.83,"z":194.35}]},{"lat":3.13,"lon":20.76,"b":[{"x":-465.31,"y":-29.28,"z":180.46},{"x":-466.36,"y":-31.46,"z":177.37},{"x":-467.83,"y":-29.45,"z":173.81},{"x":-468.23,"y":-25.27,"z":173.39},{"x":-467.18,"y":-23.15,"z":176.5},{"x":-465.73,"y":-25.15,"z":180.01}]},{"lat":3.16,"lon":18.93,"b":[{"x":-470.8,"y":-29.62,"z":165.56},{"x":-471.77,"y":-31.82,"z":162.35},{"x":-473.15,"y":-29.78,"z":158.68},{"x":-473.53,"y":-25.55,"z":158.29},{"x":-472.55,"y":-23.41,"z":161.53},{"x":-471.2,"y":-25.44,"z":165.14}]},{"lat":3.2,"lon":17.06,"b":[{"x":-475.91,"y":-29.95,"z":150.15},{"x":-476.81,"y":-32.16,"z":146.81},{"x":-478.09,"y":-30.1,"z":143.05},{"x":-478.44,"y":-25.82,"z":142.69},{"x":-477.54,"y":-23.66,"z":146.05},{"x":-476.29,"y":-25.72,"z":149.76}]},{"lat":3.23,"lon":15.15,"b":[{"x":-480.62,"y":-30.24,"z":134.26},{"x":-481.43,"y":-32.48,"z":130.79},{"x":-482.59,"y":-30.38,"z":126.95},{"x":-482.93,"y":-26.06,"z":126.62},{"x":-482.12,"y":-23.89,"z":130.1},{"x":-480.97,"y":-25.97,"z":133.9}]},{"lat":3.26,"lon":13.21,"b":[{"x":-484.87,"y":-30.51,"z":117.91},{"x":-485.58,"y":-32.76,"z":114.33},{"x":-486.63,"y":-30.63,"z":110.41},{"x":-486.94,"y":-26.28,"z":110.12},{"x":-486.23,"y":-24.09,"z":113.72},{"x":-485.2,"y":-26.2,"z":117.59}]},{"lat":3.28,"lon":11.23,"b":[{"x":-488.64,"y":-30.71,"z":101.09},{"x":-489.23,"y":-32.93,"z":97.46},{"x":-490.13,"y":-30.81,"z":93.55},{"x":-490.43,"y":-26.51,"z":93.31},{"x":-489.84,"y":-24.35,"z":96.94},{"x":-488.95,"y":-26.44,"z":100.81}]},{"lat":1.44,"lon":29.74,"b":[{"x":-432.25,"y":-14.39,"z":250.8},{"x":-433.52,"y":-16.35,"z":248.48},{"x":-435.26,"y":-14.5,"z":245.54},{"x":-435.69,"y":-10.69,"z":244.97},{"x":-434.4,"y":-8.78,"z":247.34},{"x":-432.7,"y":-10.63,"z":250.23}]},{"lat":1.46,"lon":28.17,"b":[{"x":-438.9,"y":-14.61,"z":238.96},{"x":-440.15,"y":-16.6,"z":236.51},{"x":-441.85,"y":-14.72,"z":233.46},{"x":-442.25,"y":-10.85,"z":232.9},{"x":-440.98,"y":-8.91,"z":235.39},{"x":-439.32,"y":-10.79,"z":238.4}]},{"lat":1.48,"lon":26.56,"b":[{"x":-445.41,"y":-14.83,"z":226.58},{"x":-446.64,"y":-16.85,"z":224},{"x":-448.29,"y":-14.94,"z":220.82},{"x":-448.66,"y":-11,"z":220.29},{"x":-447.42,"y":-9.04,"z":222.9},{"x":-445.81,"y":-10.95,"z":226.03}]},{"lat":1.5,"lon":24.9,"b":[{"x":-451.75,"y":-15.04,"z":213.65},{"x":-452.95,"y":-17.09,"z":210.93},{"x":-454.54,"y":-15.15,"z":207.65},{"x":-454.88,"y":-11.16,"z":207.13},{"x":-453.67,"y":-9.17,"z":209.88},{"x":-452.12,"y":-11.1,"z":213.11}]},{"lat":1.52,"lon":23.19,"b":[{"x":-457.87,"y":-15.24,"z":200.17},{"x":-459.03,"y":-17.32,"z":197.32},{"x":-460.55,"y":-15.35,"z":193.92},{"x":-460.87,"y":-11.31,"z":193.43},{"x":-459.7,"y":-9.29,"z":196.31},{"x":-458.22,"y":-11.25,"z":199.65}]},{"lat":1.54,"lon":21.44,"b":[{"x":-463.74,"y":-15.44,"z":186.15},{"x":-464.85,"y":-17.54,"z":183.17},{"x":-466.29,"y":-15.54,"z":179.66},{"x":-466.58,"y":-11.45,"z":179.19},{"x":-465.46,"y":-9.41,"z":182.2},{"x":-464.06,"y":-11.4,"z":185.66}]},{"lat":1.56,"lon":19.65,"b":[{"x":-469.31,"y":-15.62,"z":171.6},{"x":-470.36,"y":-17.75,"z":168.49},{"x":-471.71,"y":-15.72,"z":164.88},{"x":-471.98,"y":-11.58,"z":164.44},{"x":-470.92,"y":-9.52,"z":167.58},{"x":-469.6,"y":-11.53,"z":171.13}]},{"lat":1.58,"lon":17.81,"b":[{"x":-474.53,"y":-15.8,"z":156.55},{"x":-475.51,"y":-17.94,"z":153.31},{"x":-476.77,"y":-15.89,"z":149.6},{"x":-477.01,"y":-11.7,"z":149.2},{"x":-476.03,"y":-9.62,"z":152.46},{"x":-474.8,"y":-11.66,"z":156.11}]},{"lat":1.59,"lon":15.94,"b":[{"x":-479.37,"y":-15.96,"z":141},{"x":-480.28,"y":-18.12,"z":137.64},{"x":-481.42,"y":-16.04,"z":133.85},{"x":-481.64,"y":-11.82,"z":133.48},{"x":-480.74,"y":-9.72,"z":136.86},{"x":-479.62,"y":-11.78,"z":140.6}]},{"lat":1.61,"lon":14.03,"b":[{"x":-483.79,"y":-16.11,"z":125},{"x":-484.6,"y":-18.29,"z":121.51},{"x":-485.63,"y":-16.18,"z":117.65},{"x":-485.83,"y":-11.92,"z":117.32},{"x":-485.02,"y":-9.8,"z":120.82},{"x":-484.01,"y":-11.89,"z":124.63}]},{"lat":1.62,"lon":12.09,"b":[{"x":-487.73,"y":-16.24,"z":108.58},{"x":-488.44,"y":-18.43,"z":104.98},{"x":-489.34,"y":-16.3,"z":101.05},{"x":-489.52,"y":-12.01,"z":100.77},{"x":-488.82,"y":-9.88,"z":104.37},{"x":-487.93,"y":-11.98,"z":108.25}]},{"lat":1.63,"lon":10.12,"b":[{"x":-491.17,"y":-16.34,"z":91.74},{"x":-491.76,"y":-18.52,"z":88.08},{"x":-492.53,"y":-16.39,"z":84.13},{"x":-492.69,"y":-12.11,"z":83.89},{"x":-492.11,"y":-9.99,"z":87.56},{"x":-491.35,"y":-12.09,"z":91.46}]},{"lat":0,"lon":30.23,"b":[{"x":-430.3,"y":-1.85,"z":254.55},{"x":-431.6,"y":-3.73,"z":252.31},{"x":-433.29,"y":-1.88,"z":249.42},{"x":-433.29,"y":1.88,"z":249.42},{"x":-431.6,"y":3.73,"z":252.31},{"x":-430.3,"y":1.85,"z":254.55}]},{"lat":0,"lon":28.7,"b":[{"x":-436.91,"y":-1.88,"z":243.01},{"x":-438.21,"y":-3.79,"z":240.65},{"x":-439.86,"y":-1.91,"z":237.64},{"x":-439.86,"y":1.91,"z":237.64},{"x":-438.21,"y":3.79,"z":240.65},{"x":-436.91,"y":1.88,"z":243.01}]},{"lat":0,"lon":27.12,"b":[{"x":-443.41,"y":-1.91,"z":230.94},{"x":-444.68,"y":-3.85,"z":228.45},{"x":-446.29,"y":-1.94,"z":225.33},{"x":-446.29,"y":1.94,"z":225.33},{"x":-444.68,"y":3.85,"z":228.45},{"x":-443.41,"y":1.91,"z":230.94}]},{"lat":0,"lon":25.49,"b":[{"x":-449.75,"y":-1.94,"z":218.33},{"x":-451,"y":-3.9,"z":215.72},{"x":-452.55,"y":-1.96,"z":212.48},{"x":-452.55,"y":1.96,"z":212.48},{"x":-451,"y":3.9,"z":215.72},{"x":-449.75,"y":1.94,"z":218.33}]},{"lat":0,"lon":23.82,"b":[{"x":-455.89,"y":-1.96,"z":205.19},{"x":-457.11,"y":-3.96,"z":202.44},{"x":-458.59,"y":-1.99,"z":199.1},{"x":-458.59,"y":1.99,"z":199.1},{"x":-457.11,"y":3.96,"z":202.44},{"x":-455.89,"y":1.96,"z":205.19}]},{"lat":0,"lon":22.1,"b":[{"x":-461.8,"y":-1.99,"z":191.52},{"x":-462.97,"y":-4.01,"z":188.64},{"x":-464.38,"y":-2.02,"z":185.19},{"x":-464.38,"y":2.02,"z":185.19},{"x":-462.97,"y":4.01,"z":188.64},{"x":-461.8,"y":1.99,"z":191.52}]},{"lat":0,"lon":20.35,"b":[{"x":-467.44,"y":-2.02,"z":177.32},{"x":-468.55,"y":-4.06,"z":174.31},{"x":-469.88,"y":-2.04,"z":170.76},{"x":-469.88,"y":2.04,"z":170.76},{"x":-468.55,"y":4.06,"z":174.31},{"x":-467.44,"y":2.02,"z":177.32}]},{"lat":0,"lon":18.55,"b":[{"x":-472.75,"y":-2.04,"z":162.61},{"x":-473.81,"y":-4.1,"z":159.48},{"x":-475.03,"y":-2.06,"z":155.83},{"x":-475.03,"y":2.06,"z":155.83},{"x":-473.81,"y":4.1,"z":159.48},{"x":-472.75,"y":2.04,"z":162.61}]},{"lat":0,"lon":16.71,"b":[{"x":-477.7,"y":-2.06,"z":147.42},{"x":-478.69,"y":-4.14,"z":144.16},{"x":-479.81,"y":-2.08,"z":140.42},{"x":-479.81,"y":2.08,"z":140.42},{"x":-478.69,"y":4.14,"z":144.16},{"x":-477.7,"y":2.06,"z":147.42}]},{"lat":0,"lon":14.84,"b":[{"x":-482.25,"y":-2.08,"z":131.77},{"x":-483.15,"y":-4.18,"z":128.39},{"x":-484.16,"y":-2.1,"z":124.57},{"x":-484.16,"y":2.1,"z":124.57},{"x":-483.15,"y":4.18,"z":128.39},{"x":-482.25,"y":2.08,"z":131.77}]},{"lat":0,"lon":12.93,"b":[{"x":-486.36,"y":-2.1,"z":115.69},{"x":-487.17,"y":-4.22,"z":112.19},{"x":-488.06,"y":-2.12,"z":108.31},{"x":-488.06,"y":2.12,"z":108.31},{"x":-487.17,"y":4.22,"z":112.19},{"x":-486.36,"y":2.1,"z":115.69}]},{"lat":0,"lon":10.99,"b":[{"x":-489.98,"y":-2.12,"z":99.22},{"x":-490.69,"y":-4.25,"z":95.62},{"x":-491.45,"y":-2.13,"z":91.68},{"x":-491.45,"y":2.13,"z":91.68},{"x":-490.69,"y":4.25,"z":95.62},{"x":-489.98,"y":2.12,"z":99.22}]},{"lat":0,"lon":9.03,"b":[{"x":-493.65,"y":-0.46,"z":79.32},{"x":-493.78,"y":-0.92,"z":78.53},{"x":-493.91,"y":-0.46,"z":77.67},{"x":-493.91,"y":0.46,"z":77.67},{"x":-493.78,"y":0.92,"z":78.53},{"x":-493.65,"y":0.46,"z":79.32}]},{"lat":-31.25,"lon":-91.65,"b":[{"x":8.64,"y":258.75,"z":-427.7},{"x":10.52,"y":256.51,"z":-429.01},{"x":14.28,"y":257.08,"z":-428.56},{"x":15.44,"y":260.13,"z":-426.68},{"x":12.83,"y":262.55,"z":-425.27},{"x":9.78,"y":261.74,"z":-425.85}]},{"lat":-30.74,"lon":-93.34,"b":[{"x":21.28,"y":255,"z":-429.51},{"x":23.24,"y":252.67,"z":-430.78},{"x":27.08,"y":253.2,"z":-430.25},{"x":28.26,"y":256.29,"z":-428.34},{"x":25.58,"y":258.8,"z":-426.99},{"x":22.44,"y":258.04,"z":-427.63}]},{"lat":-30.2,"lon":-95.06,"b":[{"x":34.28,"y":250.95,"z":-431.05},{"x":36.33,"y":248.53,"z":-432.28},{"x":40.25,"y":249.01,"z":-431.66},{"x":41.45,"y":252.14,"z":-429.72},{"x":38.71,"y":254.75,"z":-428.43},{"x":35.46,"y":254.04,"z":-429.14}]},{"lat":-29.61,"lon":-96.81,"b":[{"x":47.64,"y":246.58,"z":-432.29},{"x":49.78,"y":244.07,"z":-433.48},{"x":53.77,"y":244.5,"z":-432.76},{"x":54.98,"y":247.67,"z":-430.8},{"x":52.19,"y":250.38,"z":-429.57},{"x":48.84,"y":249.71,"z":-430.36}]},{"lat":-28.99,"lon":-98.59,"b":[{"x":61.34,"y":241.89,"z":-433.22},{"x":63.55,"y":239.28,"z":-434.34},{"x":67.61,"y":239.65,"z":-433.53},{"x":68.84,"y":242.87,"z":-431.54},{"x":66,"y":245.67,"z":-430.39},{"x":62.55,"y":245.06,"z":-431.25}]},{"lat":-28.32,"lon":-100.39,"b":[{"x":75.35,"y":236.85,"z":-433.78},{"x":77.64,"y":234.14,"z":-434.85},{"x":81.75,"y":234.46,"z":-433.92},{"x":83,"y":237.72,"z":-431.91},{"x":80.11,"y":240.63,"z":-430.84},{"x":76.58,"y":240.07,"z":-431.79}]},{"lat":-27.62,"lon":-102.22,"b":[{"x":89.64,"y":231.47,"z":-433.97},{"x":92,"y":228.66,"z":-434.96},{"x":96.16,"y":228.93,"z":-433.92},{"x":97.42,"y":232.23,"z":-431.88},{"x":94.51,"y":235.23,"z":-430.9},{"x":90.89,"y":234.74,"z":-431.95}]},{"lat":-26.87,"lon":-104.06,"b":[{"x":104.19,"y":225.75,"z":-433.73},{"x":106.62,"y":222.83,"z":-434.65},{"x":110.81,"y":223.04,"z":-433.49},{"x":112.09,"y":226.38,"z":-431.43},{"x":109.15,"y":229.47,"z":-430.55},{"x":105.45,"y":229.05,"z":-431.69}]},{"lat":-26.09,"lon":-105.92,"b":[{"x":118.95,"y":219.66,"z":-433.06},{"x":121.44,"y":216.65,"z":-433.88},{"x":125.66,"y":216.8,"z":-432.61},{"x":126.94,"y":220.17,"z":-430.53},{"x":124,"y":223.35,"z":-429.74},{"x":120.22,"y":223,"z":-431}]},{"lat":-25.26,"lon":-107.78,"b":[{"x":133.88,"y":213.22,"z":-431.91},{"x":136.42,"y":210.11,"z":-432.64},{"x":140.65,"y":210.2,"z":-431.24},{"x":141.95,"y":213.6,"z":-429.14},{"x":139,"y":216.88,"z":-428.46},{"x":135.17,"y":216.59,"z":-429.83}]},{"lat":-23.5,"lon":-111.53,"b":[{"x":167.49,"y":199.34,"z":-426.84},{"x":167.98,"y":198.71,"z":-426.94},{"x":168.77,"y":198.71,"z":-426.63},{"x":169.02,"y":199.36,"z":-426.23},{"x":168.47,"y":200.01,"z":-426.14},{"x":167.74,"y":199.98,"z":-426.45}]},{"lat":-30.23,"lon":-90,"b":[{"x":1.59,"y":254.15,"z":-430.54},{"x":3.2,"y":252.23,"z":-431.66},{"x":1.61,"y":249.75,"z":-433.11},{"x":-1.61,"y":249.75,"z":-433.11},{"x":-3.2,"y":252.23,"z":-431.66},{"x":-1.59,"y":254.15,"z":-430.54}]},{"lat":-28.7,"lon":-90,"b":[{"x":0.4,"y":240.71,"z":-438.23},{"x":0.82,"y":240.21,"z":-438.51},{"x":0.41,"y":239.56,"z":-438.86},{"x":-0.41,"y":239.56,"z":-438.86},{"x":-0.82,"y":240.21,"z":-438.51},{"x":-0.4,"y":240.71,"z":-438.23}]},{"lat":-20.35,"lon":-90,"b":[{"x":1.67,"y":176.73,"z":-467.67},{"x":3.37,"y":174.23,"z":-468.6},{"x":1.69,"y":171.28,"z":-469.69},{"x":-1.69,"y":171.28,"z":-469.69},{"x":-3.37,"y":174.23,"z":-468.6},{"x":-1.67,"y":176.73,"z":-467.67}]},{"lat":-18.55,"lon":-90,"b":[{"x":2.04,"y":162.61,"z":-472.75},{"x":4.1,"y":159.48,"z":-473.81},{"x":2.06,"y":155.83,"z":-475.03},{"x":-2.06,"y":155.83,"z":-475.03},{"x":-4.1,"y":159.48,"z":-473.81},{"x":-2.04,"y":162.61,"z":-472.75}]},{"lat":-16.71,"lon":-90,"b":[{"x":2.06,"y":147.42,"z":-477.7},{"x":4.14,"y":144.16,"z":-478.69},{"x":2.08,"y":140.42,"z":-479.81},{"x":-2.08,"y":140.42,"z":-479.81},{"x":-4.14,"y":144.16,"z":-478.69},{"x":-2.06,"y":147.42,"z":-477.7}]},{"lat":-14.84,"lon":-90,"b":[{"x":2.08,"y":131.77,"z":-482.25},{"x":4.18,"y":128.39,"z":-483.15},{"x":2.1,"y":124.57,"z":-484.16},{"x":-2.1,"y":124.57,"z":-484.16},{"x":-4.18,"y":128.39,"z":-483.15},{"x":-2.08,"y":131.77,"z":-482.25}]},{"lat":-12.93,"lon":-90,"b":[{"x":0.42,"y":112.63,"z":-487.13},{"x":0.84,"y":111.93,"z":-487.29},{"x":0.42,"y":111.16,"z":-487.47},{"x":-0.42,"y":111.16,"z":-487.47},{"x":-0.84,"y":111.93,"z":-487.29},{"x":-0.42,"y":112.63,"z":-487.13}]},{"lat":-29.73,"lon":-91.65,"b":[{"x":14.27,"y":250.63,"z":-432.36},{"x":10.75,"y":250.09,"z":-432.78},{"x":9.01,"y":247.37,"z":-434.37},{"x":10.8,"y":245.16,"z":-435.58},{"x":14.38,"y":245.69,"z":-435.19},{"x":16.12,"y":248.44,"z":-433.55}]},{"lat":-29.19,"lon":-93.34,"b":[{"x":25.85,"y":244.48,"z":-435.37},{"x":25.03,"y":244.37,"z":-435.48},{"x":24.63,"y":243.74,"z":-435.86},{"x":25.06,"y":243.21,"z":-436.13},{"x":25.9,"y":243.32,"z":-436.02},{"x":26.29,"y":243.96,"z":-435.64}]},{"lat":-28.61,"lon":-95.06,"b":[{"x":39.22,"y":240.22,"z":-436.74},{"x":38.2,"y":240.09,"z":-436.9},{"x":37.73,"y":239.32,"z":-437.36},{"x":38.27,"y":238.66,"z":-437.68},{"x":39.3,"y":238.78,"z":-437.52},{"x":39.77,"y":239.57,"z":-437.05}]},{"lat":-28,"lon":-96.81,"b":[{"x":53.17,"y":236.01,"z":-437.55},{"x":51.45,"y":235.82,"z":-437.85},{"x":50.66,"y":234.52,"z":-438.64},{"x":51.59,"y":233.39,"z":-439.14},{"x":53.34,"y":233.57,"z":-438.84},{"x":54.12,"y":234.89,"z":-438.03}]},{"lat":-27.34,"lon":-98.59,"b":[{"x":68.16,"y":232.69,"z":-437.21},{"x":64.11,"y":232.32,"z":-438.03},{"x":62.28,"y":229.24,"z":-439.9},{"x":64.53,"y":226.5,"z":-441},{"x":68.65,"y":226.86,"z":-440.19},{"x":70.46,"y":229.98,"z":-438.28}]},{"lat":-26.65,"lon":-100.39,"b":[{"x":82.42,"y":227.33,"z":-437.58},{"x":78.31,"y":227.01,"z":-438.5},{"x":76.5,"y":223.89,"z":-440.41},{"x":78.82,"y":221.04,"z":-441.44},{"x":82.99,"y":221.35,"z":-440.52},{"x":84.78,"y":224.52,"z":-438.57}]},{"lat":-25.65,"lon":-98.59,"b":[{"x":69.19,"y":219.58,"z":-443.78},{"x":65.07,"y":219.22,"z":-444.59},{"x":63.21,"y":216.02,"z":-446.41},{"x":65.47,"y":213.14,"z":-447.47},{"x":69.66,"y":213.49,"z":-446.67},{"x":71.51,"y":216.74,"z":-444.81}]},{"lat":-25.91,"lon":-102.22,"b":[{"x":96.94,"y":221.61,"z":-437.53},{"x":92.79,"y":221.35,"z":-438.57},{"x":90.99,"y":218.18,"z":-440.52},{"x":93.38,"y":215.24,"z":-441.47},{"x":97.6,"y":215.49,"z":-440.43},{"x":99.37,"y":218.7,"z":-438.44}]},{"lat":-24.92,"lon":-100.39,"b":[{"x":83.64,"y":213.89,"z":-444.07},{"x":79.47,"y":213.58,"z":-444.99},{"x":77.62,"y":210.33,"z":-446.85},{"x":79.96,"y":207.35,"z":-447.83},{"x":84.2,"y":207.65,"z":-446.92},{"x":86.03,"y":210.94,"z":-445.02}]},{"lat":-23.9,"lon":-98.59,"b":[{"x":70.18,"y":205.89,"z":-450.14},{"x":66,"y":205.54,"z":-450.94},{"x":64.1,"y":202.21,"z":-452.7},{"x":66.39,"y":199.19,"z":-453.71},{"x":70.63,"y":199.53,"z":-452.92},{"x":72.52,"y":202.9,"z":-451.12}]},{"lat":-25.14,"lon":-104.06,"b":[{"x":111.7,"y":215.55,"z":-437.04},{"x":107.5,"y":215.34,"z":-438.19},{"x":105.74,"y":212.13,"z":-440.18},{"x":108.19,"y":209.08,"z":-441.04},{"x":112.44,"y":209.28,"z":-439.89},{"x":114.19,"y":212.53,"z":-437.87}]},{"lat":-24.15,"lon":-102.22,"b":[{"x":98.36,"y":207.85,"z":-443.92},{"x":94.14,"y":207.59,"z":-444.96},{"x":92.3,"y":204.3,"z":-446.86},{"x":94.71,"y":201.21,"z":-447.75},{"x":99,"y":201.46,"z":-446.72},{"x":100.81,"y":204.8,"z":-444.78}]},{"lat":-23.14,"lon":-100.39,"b":[{"x":84.82,"y":199.86,"z":-450.33},{"x":80.58,"y":199.56,"z":-451.25},{"x":78.69,"y":196.19,"z":-453.05},{"x":81.06,"y":193.07,"z":-453.97},{"x":85.35,"y":193.35,"z":-453.06},{"x":87.23,"y":196.77,"z":-451.23}]},{"lat":-22.11,"lon":-98.59,"b":[{"x":71.1,"y":191.55,"z":-456.28},{"x":66.93,"y":191.22,"z":-457.05},{"x":65.03,"y":187.84,"z":-458.72},{"x":67.3,"y":184.74,"z":-459.65},{"x":71.52,"y":185.05,"z":-458.89},{"x":73.42,"y":188.49,"z":-457.19}]},{"lat":-17.81,"lon":-91.65,"b":[{"x":15.71,"y":156.38,"z":-474.59},{"x":11.75,"y":155.96,"z":-474.85},{"x":9.81,"y":152.48,"z":-476.02},{"x":11.8,"y":149.36,"z":-476.96},{"x":15.79,"y":149.75,"z":-476.73},{"x":17.75,"y":153.29,"z":-475.53}]},{"lat":-24.32,"lon":-105.92,"b":[{"x":126.65,"y":209.13,"z":-436.08},{"x":122.43,"y":208.98,"z":-437.36},{"x":120.68,"y":205.72,"z":-439.37},{"x":123.19,"y":202.57,"z":-440.14},{"x":127.47,"y":202.71,"z":-438.86},{"x":129.18,"y":206.01,"z":-436.81}]},{"lat":-23.35,"lon":-104.06,"b":[{"x":113.3,"y":201.45,"z":-443.3},{"x":109.04,"y":201.26,"z":-444.46},{"x":107.23,"y":197.91,"z":-446.39},{"x":109.7,"y":194.72,"z":-447.2},{"x":114.02,"y":194.91,"z":-446.03},{"x":115.81,"y":198.3,"z":-444.07}]},{"lat":-22.35,"lon":-102.22,"b":[{"x":99.72,"y":193.49,"z":-450.06},{"x":95.44,"y":193.24,"z":-451.1},{"x":93.56,"y":189.82,"z":-452.93},{"x":95.98,"y":186.6,"z":-453.77},{"x":100.33,"y":186.83,"z":-452.73},{"x":102.19,"y":190.3,"z":-450.86}]},{"lat":-21.32,"lon":-100.39,"b":[{"x":85.95,"y":185.25,"z":-456.32},{"x":81.65,"y":184.96,"z":-457.23},{"x":79.72,"y":181.47,"z":-458.96},{"x":82.1,"y":178.21,"z":-459.82},{"x":86.46,"y":178.48,"z":-458.92},{"x":88.38,"y":182.02,"z":-457.16}]},{"lat":-20.27,"lon":-98.59,"b":[{"x":72.04,"y":176.77,"z":-462.06},{"x":67.74,"y":176.44,"z":-462.84},{"x":65.76,"y":172.88,"z":-464.46},{"x":68.09,"y":169.6,"z":-465.33},{"x":72.45,"y":169.9,"z":-464.57},{"x":74.42,"y":173.51,"z":-462.92}]},{"lat":-19.21,"lon":-96.81,"b":[{"x":57.46,"y":167.04,"z":-467.7},{"x":54.4,"y":166.79,"z":-468.16},{"x":52.96,"y":164.21,"z":-469.24},{"x":54.58,"y":161.84,"z":-469.87},{"x":57.69,"y":162.07,"z":-469.42},{"x":59.12,"y":164.69,"z":-468.33}]},{"lat":-18.12,"lon":-95.06,"b":[{"x":42.89,"y":157.23,"z":-472.66},{"x":40.91,"y":157.06,"z":-472.89},{"x":39.97,"y":155.36,"z":-473.53},{"x":41,"y":153.81,"z":-473.95},{"x":43,"y":153.97,"z":-473.72},{"x":43.95,"y":155.69,"z":-473.07}]},{"lat":-17.03,"lon":-93.34,"b":[{"x":29.95,"y":150.15,"z":-475.91},{"x":25.72,"y":149.76,"z":-476.29},{"x":23.66,"y":146.05,"z":-477.54},{"x":25.82,"y":142.69,"z":-478.44},{"x":30.1,"y":143.05,"z":-478.09},{"x":32.16,"y":146.81,"z":-476.81}]},{"lat":-15.94,"lon":-91.65,"b":[{"x":15.96,"y":141,"z":-479.37},{"x":11.78,"y":140.6,"z":-479.62},{"x":9.72,"y":136.86,"z":-480.74},{"x":11.82,"y":133.48,"z":-481.64},{"x":16.04,"y":133.85,"z":-481.42},{"x":18.12,"y":137.64,"z":-480.28}]},{"lat":-23.47,"lon":-107.78,"b":[{"x":140.28,"y":199.51,"z":-436.47},{"x":139.75,"y":199.5,"z":-436.65},{"x":139.53,"y":199.09,"z":-436.9},{"x":139.85,"y":198.68,"z":-436.99},{"x":140.39,"y":198.69,"z":-436.81},{"x":140.6,"y":199.11,"z":-436.55}]},{"lat":-22.5,"lon":-105.92,"b":[{"x":128.08,"y":194.05,"z":-442.59},{"x":124.63,"y":193.94,"z":-443.62},{"x":123.2,"y":191.22,"z":-445.2},{"x":125.22,"y":188.57,"z":-445.76},{"x":128.71,"y":188.68,"z":-444.72},{"x":130.13,"y":191.44,"z":-443.13}]},{"lat":-21.51,"lon":-104.06,"b":[{"x":114.83,"y":186.76,"z":-449.3},{"x":110.51,"y":186.57,"z":-450.46},{"x":108.65,"y":183.11,"z":-452.33},{"x":111.13,"y":179.78,"z":-453.06},{"x":115.51,"y":179.96,"z":-451.89},{"x":117.35,"y":183.47,"z":-450}]},{"lat":-20.49,"lon":-102.22,"b":[{"x":101.02,"y":178.54,"z":-455.91},{"x":96.67,"y":178.31,"z":-456.94},{"x":94.75,"y":174.76,"z":-458.71},{"x":97.19,"y":171.4,"z":-459.46},{"x":101.59,"y":171.62,"z":-458.43},{"x":103.5,"y":175.21,"z":-456.64}]},{"lat":-19.45,"lon":-100.39,"b":[{"x":87.02,"y":170.06,"z":-462},{"x":82.66,"y":169.79,"z":-462.9},{"x":80.69,"y":166.18,"z":-464.55},{"x":83.08,"y":162.79,"z":-465.33},{"x":87.49,"y":163.04,"z":-464.43},{"x":89.46,"y":166.7,"z":-462.75}]},{"lat":-18.39,"lon":-98.59,"b":[{"x":72.89,"y":161.36,"z":-467.53},{"x":68.54,"y":161.06,"z":-468.29},{"x":66.52,"y":157.39,"z":-469.83},{"x":68.86,"y":153.98,"z":-470.62},{"x":73.27,"y":154.25,"z":-469.86},{"x":75.29,"y":157.97,"z":-468.3}]},{"lat":-17.31,"lon":-96.81,"b":[{"x":58.69,"y":152.47,"z":-472.48},{"x":54.35,"y":152.15,"z":-473.11},{"x":52.3,"y":148.43,"z":-474.52},{"x":54.59,"y":144.98,"z":-475.32},{"x":58.98,"y":145.28,"z":-474.71},{"x":61.03,"y":149.06,"z":-473.28}]},{"lat":-16.22,"lon":-95.06,"b":[{"x":44.32,"y":143.2,"z":-476.93},{"x":40.28,"y":142.87,"z":-477.4},{"x":38.33,"y":139.34,"z":-478.59},{"x":40.43,"y":136.09,"z":-479.35},{"x":44.52,"y":136.39,"z":-478.91},{"x":46.47,"y":139.96,"z":-477.69}]},{"lat":-15.13,"lon":-93.34,"b":[{"x":29.37,"y":132.67,"z":-481.14},{"x":26.88,"y":132.46,"z":-481.34},{"x":25.67,"y":130.26,"z":-482.01},{"x":26.94,"y":128.24,"z":-482.48},{"x":29.44,"y":128.43,"z":-482.28},{"x":30.66,"y":130.66,"z":-481.61}]},{"lat":-14.03,"lon":-91.65,"b":[{"x":15.66,"y":124.19,"z":-484.02},{"x":12.34,"y":123.9,"z":-484.2},{"x":10.7,"y":120.9,"z":-484.99},{"x":12.37,"y":118.14,"z":-485.63},{"x":15.72,"y":118.4,"z":-485.47},{"x":17.37,"y":121.45,"z":-484.66}]},{"lat":-22.58,"lon":-109.65,"b":[{"x":155.74,"y":192.86,"z":-434.2},{"x":154.57,"y":192.85,"z":-434.62},{"x":154.1,"y":191.93,"z":-435.19},{"x":154.82,"y":191,"z":-435.35},{"x":156.01,"y":191.01,"z":-434.92},{"x":156.47,"y":191.94,"z":-434.34}]},{"lat":-20.64,"lon":-105.92,"b":[{"x":128.83,"y":177.22,"z":-449.42},{"x":127.59,"y":177.18,"z":-449.79},{"x":127.06,"y":176.17,"z":-450.33},{"x":127.78,"y":175.2,"z":-450.5},{"x":129.04,"y":175.23,"z":-450.13},{"x":129.56,"y":176.25,"z":-449.59}]},{"lat":-19.63,"lon":-104.06,"b":[{"x":116.29,"y":171.49,"z":-454.97},{"x":111.91,"y":171.31,"z":-456.14},{"x":110,"y":167.72,"z":-457.93},{"x":112.49,"y":164.26,"z":-458.58},{"x":116.92,"y":164.43,"z":-457.41},{"x":118.81,"y":168.06,"z":-455.6}]},{"lat":-18.59,"lon":-102.22,"b":[{"x":102.24,"y":163.02,"z":-461.41},{"x":97.84,"y":162.8,"z":-462.45},{"x":95.87,"y":159.15,"z":-464.13},{"x":98.32,"y":155.66,"z":-464.8},{"x":102.77,"y":155.86,"z":-463.76},{"x":104.73,"y":159.56,"z":-462.06}]},{"lat":-17.53,"lon":-100.39,"b":[{"x":88.02,"y":154.33,"z":-467.3},{"x":83.61,"y":154.08,"z":-468.19},{"x":81.6,"y":150.36,"z":-469.75},{"x":84,"y":146.84,"z":-470.44},{"x":88.46,"y":147.07,"z":-469.55},{"x":90.47,"y":150.84,"z":-467.97}]},{"lat":-16.46,"lon":-98.59,"b":[{"x":73.25,"y":144.63,"z":-472.93},{"x":69.78,"y":144.41,"z":-473.52},{"x":68.17,"y":141.45,"z":-474.65},{"x":70.02,"y":138.66,"z":-475.2},{"x":73.52,"y":138.86,"z":-474.61},{"x":75.14,"y":141.87,"z":-473.47}]},{"lat":-15.38,"lon":-96.81,"b":[{"x":58.25,"y":134.48,"z":-478},{"x":56.05,"y":134.33,"z":-478.31},{"x":55.01,"y":132.42,"z":-478.96},{"x":56.16,"y":130.64,"z":-479.31},{"x":58.38,"y":130.77,"z":-479.01},{"x":59.43,"y":132.71,"z":-478.35}]},{"lat":51.51,"lon":-59.68,"b":[{"x":-157.68,"y":-391.38,"z":-268.23},{"x":-157.15,"y":-391.72,"z":-268.04},{"x":-156.58,"y":-391.69,"z":-268.42},{"x":-156.53,"y":-391.32,"z":-268.99},{"x":-157.05,"y":-390.96,"z":-269.2},{"x":-157.63,"y":-390.99,"z":-268.82}]},{"lat":47.95,"lon":-67.32,"b":[{"x":-132.77,"y":-371.68,"z":-306.85},{"x":-129.55,"y":-373.92,"z":-305.5},{"x":-125.94,"y":-373.47,"z":-307.57},{"x":-125.5,"y":-370.79,"z":-310.97},{"x":-128.68,"y":-368.53,"z":-312.34},{"x":-132.34,"y":-368.97,"z":-310.3}]},{"lat":45.97,"lon":-67.05,"b":[{"x":-136.86,"y":-359.61,"z":-319.24},{"x":-135.69,"y":-360.48,"z":-318.76},{"x":-134.35,"y":-360.33,"z":-319.51},{"x":-134.18,"y":-359.3,"z":-320.73},{"x":-135.34,"y":-358.43,"z":-321.22},{"x":-136.69,"y":-358.58,"z":-320.48}]},{"lat":46.69,"lon":-69.59,"b":[{"x":-123.43,"y":-364.28,"z":-319.37},{"x":-120.11,"y":-366.64,"z":-317.93},{"x":-116.34,"y":-366.09,"z":-319.97},{"x":-115.85,"y":-363.2,"z":-323.42},{"x":-119.12,"y":-360.82,"z":-324.88},{"x":-122.94,"y":-361.35,"z":-322.87}]},{"lat":43.14,"lon":-64.33,"b":[{"x":-159.12,"y":-341.94,"z":-328.23},{"x":-158.17,"y":-342.71,"z":-327.88},{"x":-157.09,"y":-342.62,"z":-328.5},{"x":-156.94,"y":-341.76,"z":-329.46},{"x":-157.87,"y":-340.99,"z":-329.81},{"x":-158.97,"y":-341.08,"z":-329.2}]},{"lat":43.96,"lon":-66.79,"b":[{"x":-145.73,"y":-347.43,"z":-328.61},{"x":-142.35,"y":-350.07,"z":-327.28},{"x":-138.48,"y":-349.64,"z":-329.4},{"x":-137.94,"y":-346.59,"z":-332.83},{"x":-141.27,"y":-343.94,"z":-334.18},{"x":-145.18,"y":-344.35,"z":-332.08}]},{"lat":44.71,"lon":-69.26,"b":[{"x":-129.68,"y":-352.22,"z":-330.24},{"x":-126.35,"y":-354.73,"z":-328.84},{"x":-122.54,"y":-354.2,"z":-330.85},{"x":-122.01,"y":-351.19,"z":-334.23},{"x":-125.29,"y":-348.67,"z":-335.65},{"x":-129.15,"y":-349.17,"z":-333.66}]},{"lat":45.39,"lon":-71.73,"b":[{"x":-113.88,"y":-356.51,"z":-331.46},{"x":-110.61,"y":-358.89,"z":-330},{"x":-106.86,"y":-358.27,"z":-331.9},{"x":-106.35,"y":-355.3,"z":-335.24},{"x":-109.57,"y":-352.91,"z":-336.72},{"x":-113.36,"y":-353.5,"z":-334.85}]},{"lat":38.13,"lon":-57.13,"b":[{"x":-214.93,"y":-308.68,"z":-329.38},{"x":-213.69,"y":-309.88,"z":-329.05},{"x":-212.23,"y":-309.89,"z":-329.99},{"x":-212,"y":-308.69,"z":-331.26},{"x":-213.22,"y":-307.48,"z":-331.6},{"x":-214.69,"y":-307.47,"z":-330.66}]},{"lat":39.17,"lon":-59.44,"b":[{"x":-198.88,"y":-315.84,"z":-332.64},{"x":-197.33,"y":-317.29,"z":-332.19},{"x":-195.51,"y":-317.24,"z":-333.31},{"x":-195.22,"y":-315.76,"z":-334.88},{"x":-196.76,"y":-314.32,"z":-335.34},{"x":-198.59,"y":-314.35,"z":-334.22}]},{"lat":40.16,"lon":-61.79,"b":[{"x":-181.24,"y":-322.46,"z":-336.39},{"x":-180.72,"y":-322.92,"z":-336.23},{"x":-180.12,"y":-322.89,"z":-336.58},{"x":-180.02,"y":-322.4,"z":-337.1},{"x":-180.53,"y":-321.94,"z":-337.27},{"x":-181.14,"y":-321.96,"z":-336.91}]},{"lat":41.08,"lon":-64.16,"b":[{"x":-167.64,"y":-328.72,"z":-337.31},{"x":-164.76,"y":-331.2,"z":-336.3},{"x":-161.4,"y":-330.94,"z":-338.18},{"x":-160.9,"y":-328.23,"z":-341.05},{"x":-163.74,"y":-325.75,"z":-342.07},{"x":-167.12,"y":-325.99,"z":-340.2}]},{"lat":41.93,"lon":-66.55,"b":[{"x":-151.96,"y":-334.43,"z":-339.11},{"x":-148.59,"y":-337.21,"z":-337.84},{"x":-144.68,"y":-336.81,"z":-339.94},{"x":-144.1,"y":-333.65,"z":-343.28},{"x":-147.42,"y":-330.86,"z":-344.56},{"x":-151.36,"y":-331.24,"z":-342.49}]},{"lat":42.71,"lon":-68.95,"b":[{"x":-135.84,"y":-339.59,"z":-340.82},{"x":-132.51,"y":-342.24,"z":-339.47},{"x":-128.66,"y":-341.74,"z":-341.46},{"x":-128.1,"y":-338.62,"z":-344.76},{"x":-131.37,"y":-335.97,"z":-346.12},{"x":-135.26,"y":-336.43,"z":-344.16}]},{"lat":43.43,"lon":-71.35,"b":[{"x":-119.95,"y":-344.25,"z":-342.1},{"x":-116.67,"y":-346.77,"z":-340.69},{"x":-112.89,"y":-346.18,"z":-342.56},{"x":-112.34,"y":-343.1,"z":-345.83},{"x":-115.56,"y":-340.58,"z":-347.25},{"x":-119.39,"y":-341.13,"z":-345.41}]},{"lat":44.08,"lon":-73.74,"b":[{"x":-101.72,"y":-348.01,"z":-344.26},{"x":-100.74,"y":-348.74,"z":-343.81},{"x":-99.61,"y":-348.53,"z":-344.35},{"x":-99.45,"y":-347.61,"z":-345.33},{"x":-100.41,"y":-346.88,"z":-345.79},{"x":-101.55,"y":-347.08,"z":-345.26}]},{"lat":33.72,"lon":-52.77,"b":[{"x":-252.9,"y":-277.45,"z":-330.2},{"x":-251.84,"y":-278.66,"z":-330},{"x":-250.53,"y":-278.73,"z":-330.92},{"x":-250.29,"y":-277.62,"z":-332.05},{"x":-251.34,"y":-276.42,"z":-332.25},{"x":-252.65,"y":-276.34,"z":-331.32}]},{"lat":34.88,"lon":-54.95,"b":[{"x":-238.45,"y":-285.79,"z":-333.77},{"x":-236.08,"y":-288.34,"z":-333.26},{"x":-233.2,"y":-288.44,"z":-335.2},{"x":-232.67,"y":-286,"z":-337.65},{"x":-235.02,"y":-283.46,"z":-338.16},{"x":-237.91,"y":-283.34,"z":-336.23}]},{"lat":35.99,"lon":-57.16,"b":[{"x":-220.77,"y":-293.82,"z":-338.97},{"x":-219.61,"y":-295.01,"z":-338.69},{"x":-218.21,"y":-295.02,"z":-339.58},{"x":-217.97,"y":-293.85,"z":-340.75},{"x":-219.11,"y":-292.66,"z":-341.04},{"x":-220.51,"y":-292.64,"z":-340.15}]},{"lat":37.06,"lon":-59.41,"b":[{"x":-207.06,"y":-301.29,"z":-340.99},{"x":-203.71,"y":-304.58,"z":-340.08},{"x":-199.69,"y":-304.51,"z":-342.52},{"x":-199,"y":-301.17,"z":-345.85},{"x":-202.32,"y":-297.89,"z":-346.77},{"x":-206.35,"y":-297.93,"z":-344.35}]},{"lat":38.06,"lon":-61.7,"b":[{"x":-190.69,"y":-308.33,"z":-344.23},{"x":-187.32,"y":-311.5,"z":-343.22},{"x":-183.31,"y":-311.33,"z":-345.54},{"x":-182.65,"y":-308.01,"z":-348.85},{"x":-185.97,"y":-304.85,"z":-349.87},{"x":-190,"y":-304.99,"z":-347.57}]},{"lat":39,"lon":-64,"b":[{"x":-174.32,"y":-314.87,"z":-346.98},{"x":-170.96,"y":-317.91,"z":-345.87},{"x":-166.98,"y":-317.64,"z":-348.07},{"x":-166.33,"y":-314.35,"z":-351.35},{"x":-169.65,"y":-311.31,"z":-352.47},{"x":-173.66,"y":-311.55,"z":-350.29}]},{"lat":39.88,"lon":-66.33,"b":[{"x":-158.04,"y":-320.9,"z":-349.25},{"x":-154.69,"y":-323.81,"z":-348.06},{"x":-150.75,"y":-323.44,"z":-350.13},{"x":-150.12,"y":-320.18,"z":-353.38},{"x":-153.42,"y":-317.27,"z":-354.58},{"x":-157.39,"y":-317.61,"z":-352.53}]},{"lat":40.7,"lon":-68.66,"b":[{"x":-141.89,"y":-326.42,"z":-351.06},{"x":-138.57,"y":-329.21,"z":-349.78},{"x":-134.68,"y":-328.74,"z":-351.74},{"x":-134.07,"y":-325.52,"z":-354.96},{"x":-137.34,"y":-322.73,"z":-356.24},{"x":-141.26,"y":-323.17,"z":-354.31}]},{"lat":41.45,"lon":-70.99,"b":[{"x":-125.94,"y":-331.46,"z":-352.43},{"x":-122.66,"y":-334.11,"z":-351.07},{"x":-118.83,"y":-333.55,"z":-352.92},{"x":-118.25,"y":-330.37,"z":-356.1},{"x":-121.47,"y":-327.71,"z":-357.46},{"x":-125.33,"y":-328.24,"z":-355.64}]},{"lat":42.13,"lon":-73.32,"b":[{"x":-108.81,"y":-335.79,"z":-354.06},{"x":-106.79,"y":-337.38,"z":-353.16},{"x":-104.45,"y":-336.97,"z":-354.25},{"x":-104.09,"y":-335.01,"z":-356.22},{"x":-106.07,"y":-333.42,"z":-357.12},{"x":-108.45,"y":-333.8,"z":-356.05}]},{"lat":29.13,"lon":-48.82,"b":[{"x":-288.83,"y":-243.25,"z":-327.68},{"x":-287.86,"y":-244.54,"z":-327.58},{"x":-286.59,"y":-244.68,"z":-328.58},{"x":-286.31,"y":-243.54,"z":-329.67},{"x":-287.28,"y":-242.27,"z":-329.77},{"x":-288.54,"y":-242.12,"z":-328.77}]},{"lat":30.37,"lon":-50.84,"b":[{"x":-275.18,"y":-252.51,"z":-332.34},{"x":-272.99,"y":-255.26,"z":-332.05},{"x":-270.17,"y":-255.51,"z":-334.16},{"x":-269.56,"y":-253.01,"z":-336.54},{"x":-271.75,"y":-250.28,"z":-336.82},{"x":-274.56,"y":-250.02,"z":-334.73}]},{"lat":31.58,"lon":-52.91,"b":[{"x":-260.77,"y":-261.5,"z":-336.95},{"x":-257.65,"y":-265.21,"z":-336.45},{"x":-253.7,"y":-265.46,"z":-339.24},{"x":-252.88,"y":-262.02,"z":-342.52},{"x":-255.98,"y":-258.32,"z":-343.02},{"x":-259.93,"y":-258.05,"z":-340.24}]},{"lat":32.74,"lon":-55.03,"b":[{"x":-244.99,"y":-270.2,"z":-341.89},{"x":-241.8,"y":-273.82,"z":-341.29},{"x":-237.8,"y":-273.97,"z":-343.96},{"x":-237,"y":-270.53,"z":-347.22},{"x":-240.17,"y":-266.93,"z":-347.83},{"x":-244.17,"y":-266.75,"z":-345.17}]},{"lat":33.86,"lon":-57.19,"b":[{"x":-228.97,"y":-278.47,"z":-346.33},{"x":-225.72,"y":-281.99,"z":-345.62},{"x":-221.7,"y":-282.05,"z":-348.17},{"x":-220.92,"y":-278.61,"z":-351.41},{"x":-224.14,"y":-275.12,"z":-352.13},{"x":-228.17,"y":-275.03,"z":-349.59}]},{"lat":34.93,"lon":-59.38,"b":[{"x":-212.79,"y":-286.29,"z":-350.26},{"x":-209.5,"y":-289.7,"z":-349.44},{"x":-205.46,"y":-289.65,"z":-351.86},{"x":-204.71,"y":-286.24,"z":-355.09},{"x":-207.97,"y":-282.85,"z":-355.91},{"x":-212.01,"y":-282.86,"z":-353.5}]},{"lat":35.95,"lon":-61.6,"b":[{"x":-196.51,"y":-293.64,"z":-353.67},{"x":-193.19,"y":-296.93,"z":-352.75},{"x":-189.16,"y":-296.78,"z":-355.05},{"x":-188.44,"y":-293.39,"z":-358.25},{"x":-191.71,"y":-290.11,"z":-359.17},{"x":-195.75,"y":-290.22,"z":-356.89}]},{"lat":36.92,"lon":-63.85,"b":[{"x":-180.2,"y":-300.5,"z":-356.58},{"x":-176.88,"y":-303.67,"z":-355.56},{"x":-172.87,"y":-303.43,"z":-357.73},{"x":-172.17,"y":-300.05,"z":-360.91},{"x":-175.45,"y":-296.9,"z":-361.93},{"x":-179.48,"y":-297.11,"z":-359.78}]},{"lat":37.82,"lon":-66.11,"b":[{"x":-163.94,"y":-306.88,"z":-358.99},{"x":-160.63,"y":-309.92,"z":-357.88},{"x":-156.65,"y":-309.58,"z":-359.93},{"x":-155.98,"y":-306.23,"z":-363.07},{"x":-159.25,"y":-303.2,"z":-364.19},{"x":-163.24,"y":-303.5,"z":-362.16}]},{"lat":38.67,"lon":-68.38,"b":[{"x":-147.79,"y":-312.76,"z":-360.93},{"x":-144.5,"y":-315.67,"z":-359.72},{"x":-140.57,"y":-315.24,"z":-361.66},{"x":-139.92,"y":-311.93,"z":-364.77},{"x":-143.17,"y":-309.02,"z":-365.98},{"x":-147.12,"y":-309.42,"z":-364.07}]},{"lat":39.45,"lon":-70.65,"b":[{"x":-131.81,"y":-318.15,"z":-362.4},{"x":-128.55,"y":-320.94,"z":-361.11},{"x":-124.68,"y":-320.42,"z":-362.93},{"x":-124.06,"y":-317.14,"z":-366.01},{"x":-127.27,"y":-314.36,"z":-367.3},{"x":-131.16,"y":-314.85,"z":-365.51}]},{"lat":40.17,"lon":-72.92,"b":[{"x":-115.3,"y":-322.97,"z":-363.79},{"x":-112.71,"y":-325.11,"z":-362.69},{"x":-109.66,"y":-324.62,"z":-364.06},{"x":-109.18,"y":-322.02,"z":-366.51},{"x":-111.72,"y":-319.88,"z":-367.61},{"x":-114.8,"y":-320.34,"z":-366.26}]},{"lat":20.63,"lon":-39.93,"b":[{"x":-359.41,"y":-176.05,"z":-299.69},{"x":-359.01,"y":-176.8,"z":-299.73},{"x":-358.41,"y":-176.94,"z":-300.37},{"x":-358.22,"y":-176.32,"z":-300.96},{"x":-358.62,"y":-175.56,"z":-300.91},{"x":-359.22,"y":-175.43,"z":-300.28}]},{"lat":21.92,"lon":-41.64,"b":[{"x":-349.64,"y":-186.02,"z":-305.09},{"x":-347.5,"y":-189.76,"z":-305.22},{"x":-344.4,"y":-190.4,"z":-308.32},{"x":-343.46,"y":-187.28,"z":-311.27},{"x":-345.61,"y":-183.55,"z":-311.11},{"x":-348.69,"y":-182.93,"z":-308.03}]},{"lat":23.21,"lon":-43.42,"b":[{"x":-335.85,"y":-196.66,"z":-313.81},{"x":-334.37,"y":-199.1,"z":-313.86},{"x":-332.26,"y":-199.49,"z":-315.84},{"x":-331.65,"y":-197.42,"z":-317.77},{"x":-333.14,"y":-194.99,"z":-317.71},{"x":-335.24,"y":-194.61,"z":-315.74}]},{"lat":24.49,"lon":-45.24,"b":[{"x":-321.01,"y":-207.18,"z":-322.51},{"x":-320.55,"y":-207.9,"z":-322.51},{"x":-319.9,"y":-208,"z":-323.08},{"x":-319.73,"y":-207.39,"z":-323.65},{"x":-320.19,"y":-206.67,"z":-323.65},{"x":-320.83,"y":-206.57,"z":-323.08}]},{"lat":27.02,"lon":-49.05,"b":[{"x":-294.81,"y":-226.75,"z":-334.07},{"x":-292.64,"y":-229.75,"z":-333.93},{"x":-289.73,"y":-230.09,"z":-336.23},{"x":-289,"y":-227.42,"z":-338.66},{"x":-291.17,"y":-224.44,"z":-338.8},{"x":-294.07,"y":-224.1,"z":-336.51}]},{"lat":28.24,"lon":-51.03,"b":[{"x":-280.86,"y":-236.21,"z":-339.47},{"x":-277.92,"y":-240.06,"z":-339.19},{"x":-274.05,"y":-240.42,"z":-342.08},{"x":-273.12,"y":-236.94,"z":-345.24},{"x":-276.04,"y":-233.11,"z":-345.52},{"x":-279.9,"y":-232.74,"z":-342.64}]},{"lat":29.44,"lon":-53.05,"b":[{"x":-265.63,"y":-245.46,"z":-345.12},{"x":-262.61,"y":-249.24,"z":-344.72},{"x":-258.66,"y":-249.51,"z":-347.5},{"x":-257.76,"y":-246.02,"z":-350.65},{"x":-260.77,"y":-242.27,"z":-351.04},{"x":-264.7,"y":-241.98,"z":-348.28}]},{"lat":30.61,"lon":-55.12,"b":[{"x":-250.07,"y":-254.35,"z":-350.27},{"x":-246.97,"y":-258.05,"z":-349.77},{"x":-242.97,"y":-258.23,"z":-352.42},{"x":-242.09,"y":-254.73,"z":-355.56},{"x":-245.18,"y":-251.06,"z":-356.05},{"x":-249.17,"y":-250.86,"z":-353.42}]},{"lat":31.74,"lon":-57.22,"b":[{"x":-234.24,"y":-262.85,"z":-354.91},{"x":-231.07,"y":-266.45,"z":-354.3},{"x":-227.04,"y":-266.54,"z":-356.83},{"x":-226.19,"y":-263.05,"z":-359.95},{"x":-229.34,"y":-259.47,"z":-360.56},{"x":-233.36,"y":-259.36,"z":-358.05}]},{"lat":32.82,"lon":-59.35,"b":[{"x":-218.21,"y":-270.92,"z":-359.03},{"x":-214.99,"y":-274.42,"z":-358.32},{"x":-210.95,"y":-274.41,"z":-360.72},{"x":-210.13,"y":-270.93,"z":-363.82},{"x":-213.32,"y":-267.45,"z":-364.54},{"x":-217.36,"y":-267.43,"z":-362.15}]},{"lat":33.85,"lon":-61.52,"b":[{"x":-202.06,"y":-278.55,"z":-362.63},{"x":-198.8,"y":-281.94,"z":-361.81},{"x":-194.76,"y":-281.83,"z":-364.09},{"x":-193.97,"y":-278.37,"z":-367.17},{"x":-197.19,"y":-275,"z":-367.99},{"x":-201.24,"y":-275.07,"z":-365.73}]},{"lat":34.83,"lon":-63.7,"b":[{"x":-185.85,"y":-285.72,"z":-365.72},{"x":-182.57,"y":-288.99,"z":-364.79},{"x":-178.55,"y":-288.79,"z":-366.94},{"x":-177.79,"y":-285.34,"z":-370},{"x":-181.02,"y":-282.09,"z":-370.92},{"x":-185.06,"y":-282.26,"z":-368.79}]},{"lat":35.76,"lon":-65.91,"b":[{"x":-169.65,"y":-292.42,"z":-368.29},{"x":-166.37,"y":-295.57,"z":-367.27},{"x":-162.38,"y":-295.27,"z":-369.29},{"x":-161.65,"y":-291.85,"z":-372.32},{"x":-164.88,"y":-288.71,"z":-373.35},{"x":-168.89,"y":-288.97,"z":-371.34}]},{"lat":36.63,"lon":-68.12,"b":[{"x":-153.53,"y":-298.64,"z":-370.37},{"x":-150.26,"y":-301.67,"z":-369.25},{"x":-146.31,"y":-301.27,"z":-371.15},{"x":-145.61,"y":-297.89,"z":-374.15},{"x":-148.83,"y":-294.87,"z":-375.27},{"x":-152.8,"y":-295.22,"z":-373.39}]},{"lat":37.44,"lon":-70.33,"b":[{"x":-137.55,"y":-304.39,"z":-371.97},{"x":-134.3,"y":-307.29,"z":-370.76},{"x":-130.41,"y":-306.81,"z":-372.55},{"x":-129.74,"y":-303.46,"z":-375.52},{"x":-132.94,"y":-300.56,"z":-376.73},{"x":-136.85,"y":-301,"z":-374.97}]},{"lat":38.19,"lon":-72.54,"b":[{"x":-121.76,"y":-309.66,"z":-373.12},{"x":-118.55,"y":-312.45,"z":-371.82},{"x":-114.73,"y":-311.88,"z":-373.5},{"x":-114.09,"y":-308.57,"z":-376.44},{"x":-117.25,"y":-305.79,"z":-377.73},{"x":-121.1,"y":-306.31,"z":-376.09}]},{"lat":17.4,"lon":-38.7,"b":[{"x":-372.77,"y":-149.46,"z":-297.82},{"x":-372.5,"y":-150.03,"z":-297.87},{"x":-372.06,"y":-150.13,"z":-298.36},{"x":-371.9,"y":-149.66,"z":-298.79},{"x":-372.17,"y":-149.09,"z":-298.74},{"x":-372.6,"y":-148.99,"z":-298.25}]},{"lat":18.66,"lon":-40.33,"b":[{"x":-364.19,"y":-159.25,"z":-303.2},{"x":-362.16,"y":-163.24,"z":-303.5},{"x":-358.99,"y":-163.94,"z":-306.88},{"x":-357.88,"y":-160.63,"z":-309.92},{"x":-359.93,"y":-156.65,"z":-309.58},{"x":-363.07,"y":-155.98,"z":-306.23}]},{"lat":19.92,"lon":-42.02,"b":[{"x":-352.47,"y":-169.65,"z":-311.31},{"x":-350.29,"y":-173.66,"z":-311.55},{"x":-346.98,"y":-174.32,"z":-314.87},{"x":-345.87,"y":-170.96,"z":-317.91},{"x":-348.07,"y":-166.98,"z":-317.64},{"x":-351.35,"y":-166.33,"z":-314.35}]},{"lat":21.18,"lon":-43.76,"b":[{"x":-340.11,"y":-179.99,"z":-319.14},{"x":-337.79,"y":-184,"z":-319.32},{"x":-334.35,"y":-184.62,"z":-322.56},{"x":-333.26,"y":-181.22,"z":-325.61},{"x":-335.59,"y":-177.24,"z":-325.41},{"x":-339,"y":-176.63,"z":-322.19}]},{"lat":22.44,"lon":-45.54,"b":[{"x":-327.15,"y":-190.23,"z":-326.66},{"x":-324.7,"y":-194.23,"z":-326.75},{"x":-321.13,"y":-194.8,"z":-329.92},{"x":-320.05,"y":-191.36,"z":-332.97},{"x":-322.52,"y":-187.39,"z":-332.85},{"x":-326.06,"y":-186.83,"z":-329.7}]},{"lat":23.69,"lon":-47.38,"b":[{"x":-313.63,"y":-200.32,"z":-333.81},{"x":-311.04,"y":-204.3,"z":-333.83},{"x":-307.36,"y":-204.81,"z":-336.9},{"x":-306.3,"y":-201.34,"z":-339.95},{"x":-308.9,"y":-197.39,"z":-339.91},{"x":-312.55,"y":-196.88,"z":-336.86}]},{"lat":24.92,"lon":-49.27,"b":[{"x":-299.58,"y":-210.21,"z":-340.57},{"x":-296.86,"y":-214.15,"z":-340.49},{"x":-293.09,"y":-214.59,"z":-343.47},{"x":-292.05,"y":-211.1,"z":-346.5},{"x":-294.76,"y":-207.19,"z":-346.57},{"x":-298.51,"y":-206.75,"z":-343.61}]},{"lat":26.14,"lon":-51.2,"b":[{"x":-285.04,"y":-219.86,"z":-346.89},{"x":-282.22,"y":-223.75,"z":-346.71},{"x":-278.36,"y":-224.12,"z":-349.58},{"x":-277.34,"y":-220.61,"z":-352.61},{"x":-280.17,"y":-216.75,"z":-352.77},{"x":-284.01,"y":-216.37,"z":-349.92}]},{"lat":27.33,"lon":-53.18,"b":[{"x":-270.09,"y":-229.23,"z":-352.74},{"x":-267.16,"y":-233.06,"z":-352.46},{"x":-263.23,"y":-233.34,"z":-355.22},{"x":-262.25,"y":-229.82,"z":-358.23},{"x":-265.16,"y":-226.02,"z":-358.5},{"x":-269.08,"y":-225.72,"z":-355.77}]},{"lat":28.49,"lon":-55.19,"b":[{"x":-254.77,"y":-238.27,"z":-358.1},{"x":-251.76,"y":-242.03,"z":-357.72},{"x":-247.78,"y":-242.23,"z":-360.35},{"x":-246.82,"y":-238.69,"z":-363.36},{"x":-249.82,"y":-234.97,"z":-363.73},{"x":-253.79,"y":-234.75,"z":-361.12}]},{"lat":29.62,"lon":-57.24,"b":[{"x":-239.16,"y":-246.96,"z":-362.95},{"x":-236.07,"y":-250.63,"z":-362.46},{"x":-232.05,"y":-250.74,"z":-364.97},{"x":-231.13,"y":-247.2,"z":-367.96},{"x":-234.19,"y":-243.56,"z":-368.45},{"x":-238.21,"y":-243.42,"z":-365.96}]},{"lat":30.71,"lon":-59.33,"b":[{"x":-223.32,"y":-255.25,"z":-367.28},{"x":-220.18,"y":-258.83,"z":-366.68},{"x":-216.13,"y":-258.85,"z":-369.06},{"x":-215.24,"y":-255.32,"z":-372.03},{"x":-218.36,"y":-251.77,"z":-372.63},{"x":-222.4,"y":-251.72,"z":-370.27}]},{"lat":31.75,"lon":-61.44,"b":[{"x":-207.33,"y":-263.13,"z":-371.08},{"x":-204.13,"y":-266.61,"z":-370.37},{"x":-200.09,"y":-266.53,"z":-372.63},{"x":-199.23,"y":-263.01,"z":-375.57},{"x":-202.39,"y":-259.56,"z":-376.29},{"x":-206.44,"y":-259.6,"z":-374.05}]},{"lat":32.75,"lon":-63.57,"b":[{"x":-191.24,"y":-270.58,"z":-374.35},{"x":-188.02,"y":-273.95,"z":-373.53},{"x":-183.98,"y":-273.78,"z":-375.66},{"x":-183.17,"y":-270.28,"z":-378.59},{"x":-186.35,"y":-266.93,"z":-379.41},{"x":-190.39,"y":-267.06,"z":-377.3}]},{"lat":33.69,"lon":-65.71,"b":[{"x":-175.14,"y":-277.57,"z":-377.1},{"x":-171.9,"y":-280.83,"z":-376.18},{"x":-167.89,"y":-280.57,"z":-378.18},{"x":-167.11,"y":-277.09,"z":-381.08},{"x":-170.3,"y":-273.85,"z":-382.01},{"x":-174.32,"y":-274.07,"z":-380.03}]},{"lat":34.59,"lon":-67.87,"b":[{"x":-159.08,"y":-284.12,"z":-379.34},{"x":-155.85,"y":-287.26,"z":-378.32},{"x":-151.88,"y":-286.9,"z":-380.2},{"x":-151.13,"y":-283.45,"z":-383.08},{"x":-154.31,"y":-280.33,"z":-384.1},{"x":-158.3,"y":-280.64,"z":-382.25}]},{"lat":35.43,"lon":-70.02,"b":[{"x":-143.13,"y":-290.2,"z":-381.09},{"x":-139.91,"y":-293.22,"z":-379.97},{"x":-136,"y":-292.78,"z":-381.73},{"x":-135.28,"y":-289.36,"z":-384.58},{"x":-138.45,"y":-286.35,"z":-385.7},{"x":-142.38,"y":-286.75,"z":-383.97}]},{"lat":36.21,"lon":-72.18,"b":[{"x":-126.55,"y":-295.73,"z":-382.72},{"x":-124.01,"y":-298.04,"z":-381.76},{"x":-120.95,"y":-297.62,"z":-383.07},{"x":-120.41,"y":-294.93,"z":-385.31},{"x":-122.91,"y":-292.63,"z":-386.27},{"x":-125.98,"y":-293.01,"z":-384.99}]},{"lat":15.5,"lon":-39.12,"b":[{"x":-375.41,"y":-133.25,"z":-302.11},{"x":-374.45,"y":-135.38,"z":-302.35},{"x":-372.81,"y":-135.76,"z":-304.2},{"x":-372.16,"y":-134,"z":-305.78},{"x":-373.13,"y":-131.88,"z":-305.52},{"x":-374.75,"y":-131.51,"z":-303.69}]},{"lat":16.72,"lon":-40.72,"b":[{"x":-365.98,"y":-143.17,"z":-309.02},{"x":-364.07,"y":-147.12,"z":-309.42},{"x":-360.93,"y":-147.79,"z":-312.76},{"x":-359.72,"y":-144.5,"z":-315.67},{"x":-361.66,"y":-140.57,"z":-315.24},{"x":-364.77,"y":-139.92,"z":-311.93}]},{"lat":17.95,"lon":-42.38,"b":[{"x":-354.58,"y":-153.42,"z":-317.27},{"x":-352.53,"y":-157.39,"z":-317.61},{"x":-349.25,"y":-158.04,"z":-320.9},{"x":-348.06,"y":-154.69,"z":-323.81},{"x":-350.13,"y":-150.75,"z":-323.44},{"x":-353.38,"y":-150.12,"z":-320.18}]},{"lat":19.18,"lon":-44.08,"b":[{"x":-342.57,"y":-163.64,"z":-325.26},{"x":-340.37,"y":-167.63,"z":-325.53},{"x":-336.96,"y":-168.24,"z":-328.76},{"x":-335.78,"y":-164.85,"z":-331.67},{"x":-337.99,"y":-160.89,"z":-331.36},{"x":-341.37,"y":-160.3,"z":-328.17}]},{"lat":20.41,"lon":-45.83,"b":[{"x":-329.95,"y":-173.8,"z":-332.94},{"x":-327.61,"y":-177.79,"z":-333.15},{"x":-324.08,"y":-178.35,"z":-336.29},{"x":-322.91,"y":-174.92,"z":-339.2},{"x":-325.26,"y":-170.96,"z":-338.97},{"x":-328.76,"y":-170.41,"z":-335.86}]},{"lat":21.64,"lon":-47.63,"b":[{"x":-316.75,"y":-183.85,"z":-340.28},{"x":-314.28,"y":-187.82,"z":-340.4},{"x":-310.63,"y":-188.33,"z":-343.46},{"x":-309.49,"y":-184.86,"z":-346.36},{"x":-311.97,"y":-180.92,"z":-346.22},{"x":-315.59,"y":-180.42,"z":-343.19}]},{"lat":22.86,"lon":-49.48,"b":[{"x":-303.02,"y":-193.74,"z":-347.23},{"x":-300.43,"y":-197.68,"z":-347.26},{"x":-296.67,"y":-198.13,"z":-350.22},{"x":-295.55,"y":-194.63,"z":-353.12},{"x":-298.15,"y":-190.72,"z":-353.06},{"x":-301.88,"y":-190.27,"z":-350.13}]},{"lat":24.06,"lon":-51.37,"b":[{"x":-288.8,"y":-203.42,"z":-353.75},{"x":-286.08,"y":-207.33,"z":-353.68},{"x":-282.25,"y":-207.71,"z":-356.53},{"x":-281.15,"y":-204.19,"z":-359.42},{"x":-283.86,"y":-200.31,"z":-359.47},{"x":-287.68,"y":-199.93,"z":-356.64}]},{"lat":25.24,"lon":-53.3,"b":[{"x":-274.14,"y":-212.86,"z":-359.81},{"x":-271.31,"y":-216.72,"z":-359.64},{"x":-267.4,"y":-217.03,"z":-362.38},{"x":-266.34,"y":-213.49,"z":-365.26},{"x":-269.15,"y":-209.66,"z":-365.41},{"x":-273.04,"y":-209.34,"z":-362.7}]},{"lat":26.4,"lon":-55.27,"b":[{"x":-259.09,"y":-222.02,"z":-365.38},{"x":-256.17,"y":-225.82,"z":-365.11},{"x":-252.2,"y":-226.04,"z":-367.73},{"x":-251.17,"y":-222.49,"z":-370.59},{"x":-254.07,"y":-218.73,"z":-370.85},{"x":-258.02,"y":-218.48,"z":-368.26}]},{"lat":27.52,"lon":-57.27,"b":[{"x":-243.72,"y":-230.86,"z":-370.44},{"x":-240.72,"y":-234.58,"z":-370.06},{"x":-236.71,"y":-234.72,"z":-372.56},{"x":-235.71,"y":-231.16,"z":-375.4},{"x":-238.69,"y":-227.47,"z":-375.78},{"x":-242.69,"y":-227.3,"z":-373.31}]},{"lat":28.61,"lon":-59.3,"b":[{"x":-228.1,"y":-239.34,"z":-374.98},{"x":-225.03,"y":-242.98,"z":-374.49},{"x":-220.99,"y":-243.03,"z":-376.86},{"x":-220.03,"y":-239.47,"z":-379.69},{"x":-223.08,"y":-235.86,"z":-380.17},{"x":-227.1,"y":-235.78,"z":-377.83}]},{"lat":29.66,"lon":-61.36,"b":[{"x":-212.29,"y":-247.44,"z":-378.99},{"x":-209.17,"y":-250.99,"z":-378.39},{"x":-205.12,"y":-250.95,"z":-380.62},{"x":-204.2,"y":-247.4,"z":-383.44},{"x":-207.29,"y":-243.88,"z":-384.03},{"x":-211.33,"y":-243.88,"z":-381.82}]},{"lat":30.67,"lon":-63.43,"b":[{"x":-196.36,"y":-255.13,"z":-382.46},{"x":-193.2,"y":-258.59,"z":-381.75},{"x":-189.16,"y":-258.46,"z":-383.86},{"x":-188.28,"y":-254.91,"z":-386.65},{"x":-191.4,"y":-251.49,"z":-387.36},{"x":-195.44,"y":-251.58,"z":-385.27}]},{"lat":31.63,"lon":-65.53,"b":[{"x":-180.38,"y":-262.41,"z":-385.4},{"x":-177.2,"y":-265.75,"z":-384.58},{"x":-173.18,"y":-265.53,"z":-386.56},{"x":-172.34,"y":-262.01,"z":-389.33},{"x":-175.48,"y":-258.69,"z":-390.15},{"x":-179.5,"y":-258.86,"z":-388.2}]},{"lat":32.55,"lon":-67.63,"b":[{"x":-164.41,"y":-269.25,"z":-387.82},{"x":-161.23,"y":-272.48,"z":-386.9},{"x":-157.24,"y":-272.17,"z":-388.75},{"x":-156.44,"y":-268.67,"z":-391.5},{"x":-159.59,"y":-265.46,"z":-392.42},{"x":-163.58,"y":-265.72,"z":-390.59}]},{"lat":33.41,"lon":-69.73,"b":[{"x":-148.53,"y":-275.64,"z":-389.73},{"x":-145.34,"y":-278.77,"z":-388.71},{"x":-141.41,"y":-278.37,"z":-390.44},{"x":-140.65,"y":-274.9,"z":-393.17},{"x":-143.79,"y":-271.8,"z":-394.19},{"x":-147.73,"y":-272.14,"z":-392.48}]},{"lat":34.22,"lon":-71.84,"b":[{"x":-131.18,"y":-281.43,"z":-391.85},{"x":-129.31,"y":-283.2,"z":-391.19},{"x":-127.03,"y":-282.92,"z":-392.14},{"x":-126.61,"y":-280.89,"z":-393.74},{"x":-128.44,"y":-279.13,"z":-394.39},{"x":-130.73,"y":-279.38,"z":-393.46}]},{"lat":11.32,"lon":-36.5,"b":[{"x":-394.43,"y":-98.06,"z":-291.2},{"x":-394.26,"y":-98.53,"z":-291.28},{"x":-393.92,"y":-98.61,"z":-291.7},{"x":-393.76,"y":-98.22,"z":-292.05},{"x":-393.94,"y":-97.76,"z":-291.97},{"x":-394.27,"y":-97.68,"z":-291.55}]},{"lat":12.47,"lon":-37.98,"b":[{"x":-386.46,"y":-107.57,"z":-298.39},{"x":-385.54,"y":-109.87,"z":-298.73},{"x":-383.82,"y":-110.29,"z":-300.79},{"x":-383.04,"y":-108.37,"z":-302.48},{"x":-383.97,"y":-106.07,"z":-302.11},{"x":-385.67,"y":-105.68,"z":-300.08}]},{"lat":13.64,"lon":-39.51,"b":[{"x":-377.24,"y":-117.36,"z":-306.36},{"x":-375.88,"y":-120.56,"z":-306.8},{"x":-373.41,"y":-121.11,"z":-309.58},{"x":-372.34,"y":-118.44,"z":-311.89},{"x":-373.73,"y":-115.27,"z":-311.42},{"x":-376.17,"y":-114.74,"z":-308.67}]},{"lat":14.82,"lon":-41.09,"b":[{"x":-367.3,"y":-127.27,"z":-314.36},{"x":-365.51,"y":-131.16,"z":-314.85},{"x":-362.4,"y":-131.81,"z":-318.15},{"x":-361.11,"y":-128.55,"z":-320.94},{"x":-362.93,"y":-124.68,"z":-320.42},{"x":-366.01,"y":-124.06,"z":-317.14}]},{"lat":16.02,"lon":-42.72,"b":[{"x":-356.24,"y":-137.34,"z":-322.73},{"x":-354.31,"y":-141.26,"z":-323.17},{"x":-351.06,"y":-141.89,"z":-326.42},{"x":-349.78,"y":-138.57,"z":-329.21},{"x":-351.74,"y":-134.68,"z":-328.74},{"x":-354.96,"y":-134.07,"z":-325.52}]},{"lat":17.22,"lon":-44.39,"b":[{"x":-344.56,"y":-147.42,"z":-330.86},{"x":-342.49,"y":-151.36,"z":-331.24},{"x":-339.11,"y":-151.96,"z":-334.43},{"x":-337.84,"y":-148.59,"z":-337.21},{"x":-339.94,"y":-144.68,"z":-336.81},{"x":-343.28,"y":-144.1,"z":-333.65}]},{"lat":18.42,"lon":-46.11,"b":[{"x":-332.28,"y":-157.46,"z":-338.7},{"x":-330.07,"y":-161.42,"z":-339.01},{"x":-326.56,"y":-161.97,"z":-342.12},{"x":-325.31,"y":-158.56,"z":-344.9},{"x":-327.55,"y":-154.64,"z":-344.57},{"x":-331.02,"y":-154.1,"z":-341.48}]},{"lat":19.63,"lon":-47.87,"b":[{"x":-319.43,"y":-167.43,"z":-346.21},{"x":-317.07,"y":-171.38,"z":-346.44},{"x":-313.46,"y":-171.89,"z":-349.46},{"x":-312.23,"y":-168.44,"z":-352.23},{"x":-314.59,"y":-164.52,"z":-351.98},{"x":-318.18,"y":-164.02,"z":-348.98}]},{"lat":20.82,"lon":-49.68,"b":[{"x":-306.03,"y":-177.28,"z":-353.33},{"x":-303.55,"y":-181.22,"z":-353.48},{"x":-299.82,"y":-181.67,"z":-356.41},{"x":-298.62,"y":-178.18,"z":-359.17},{"x":-301.11,"y":-174.28,"z":-359.01},{"x":-304.8,"y":-173.83,"z":-356.1}]},{"lat":22.01,"lon":-51.53,"b":[{"x":-292.12,"y":-186.96,"z":-360.04},{"x":-289.52,"y":-190.87,"z":-360.09},{"x":-285.71,"y":-191.26,"z":-362.92},{"x":-284.54,"y":-187.75,"z":-365.67},{"x":-287.14,"y":-183.87,"z":-365.6},{"x":-290.92,"y":-183.48,"z":-362.8}]},{"lat":23.18,"lon":-53.42,"b":[{"x":-277.77,"y":-196.44,"z":-366.3},{"x":-275.05,"y":-200.32,"z":-366.26},{"x":-271.16,"y":-200.64,"z":-368.97},{"x":-270.02,"y":-197.1,"z":-371.71},{"x":-272.73,"y":-193.26,"z":-371.74},{"x":-276.59,"y":-192.93,"z":-369.05}]},{"lat":24.33,"lon":-55.34,"b":[{"x":-263.01,"y":-205.68,"z":-372.09},{"x":-260.19,"y":-209.5,"z":-371.93},{"x":-256.24,"y":-209.74,"z":-374.53},{"x":-255.14,"y":-206.19,"z":-377.25},{"x":-257.94,"y":-202.4,"z":-377.39},{"x":-261.87,"y":-202.14,"z":-374.82}]},{"lat":25.45,"lon":-57.29,"b":[{"x":-247.91,"y":-214.63,"z":-377.36},{"x":-245,"y":-218.39,"z":-377.1},{"x":-241.01,"y":-218.56,"z":-379.57},{"x":-239.94,"y":-214.99,"z":-382.28},{"x":-242.83,"y":-211.26,"z":-382.53},{"x":-246.8,"y":-211.07,"z":-380.08}]},{"lat":26.54,"lon":-59.28,"b":[{"x":-232.52,"y":-223.26,"z":-382.11},{"x":-229.54,"y":-226.95,"z":-381.74},{"x":-225.52,"y":-227.03,"z":-384.08},{"x":-224.49,"y":-223.46,"z":-386.78},{"x":-227.45,"y":-219.81,"z":-387.14},{"x":-231.46,"y":-219.69,"z":-384.82}]},{"lat":27.59,"lon":-61.28,"b":[{"x":-216.93,"y":-231.55,"z":-386.33},{"x":-213.89,"y":-235.16,"z":-385.85},{"x":-209.85,"y":-235.15,"z":-388.06},{"x":-208.86,"y":-231.58,"z":-390.74},{"x":-211.88,"y":-228,"z":-391.22},{"x":-215.9,"y":-227.97,"z":-389.03}]},{"lat":28.61,"lon":-63.31,"b":[{"x":-201.18,"y":-239.46,"z":-390.01},{"x":-198.1,"y":-242.98,"z":-389.42},{"x":-194.06,"y":-242.89,"z":-391.5},{"x":-193.12,"y":-239.32,"z":-394.16},{"x":-196.17,"y":-235.84,"z":-394.75},{"x":-200.2,"y":-235.88,"z":-392.69}]},{"lat":29.59,"lon":-65.35,"b":[{"x":-185.36,"y":-246.98,"z":-393.16},{"x":-182.24,"y":-250.4,"z":-392.45},{"x":-178.22,"y":-250.22,"z":-394.4},{"x":-177.32,"y":-246.67,"z":-397.04},{"x":-180.4,"y":-243.28,"z":-397.74},{"x":-184.42,"y":-243.41,"z":-395.81}]},{"lat":30.52,"lon":-67.4,"b":[{"x":-169.52,"y":-254.09,"z":-395.77},{"x":-166.38,"y":-257.41,"z":-394.95},{"x":-162.39,"y":-257.15,"z":-396.78},{"x":-161.54,"y":-253.61,"z":-399.4},{"x":-164.63,"y":-250.32,"z":-400.21},{"x":-168.62,"y":-250.53,"z":-398.41}]},{"lat":31.4,"lon":-69.46,"b":[{"x":-153.73,"y":-260.78,"z":-397.86},{"x":-150.58,"y":-263.99,"z":-396.94},{"x":-146.64,"y":-263.65,"z":-398.65},{"x":-145.83,"y":-260.13,"z":-401.24},{"x":-148.93,"y":-256.95,"z":-402.16},{"x":-152.88,"y":-257.24,"z":-400.48}]},{"lat":32.23,"lon":-71.51,"b":[{"x":-136.4,"y":-266.89,"z":-400.15},{"x":-134.58,"y":-268.7,"z":-399.56},{"x":-132.32,"y":-268.45,"z":-400.48},{"x":-131.88,"y":-266.42,"z":-401.98},{"x":-133.67,"y":-264.63,"z":-402.56},{"x":-135.93,"y":-264.85,"z":-401.66}]},{"lat":8.49,"lon":-35.51,"b":[{"x":-404.79,"y":-73.22,"z":-284.13},{"x":-403.73,"y":-76.55,"z":-284.75},{"x":-401.4,"y":-77.14,"z":-287.88},{"x":-400.14,"y":-74.37,"z":-290.35},{"x":-401.23,"y":-71.06,"z":-289.68},{"x":-403.54,"y":-70.5,"z":-286.59}]},{"lat":9.58,"lon":-36.93,"b":[{"x":-396.68,"y":-82.57,"z":-292.86},{"x":-395.42,"y":-86.22,"z":-293.51},{"x":-392.77,"y":-86.86,"z":-296.87},{"x":-391.4,"y":-83.82,"z":-299.53},{"x":-392.7,"y":-80.19,"z":-298.82},{"x":-395.33,"y":-79.58,"z":-295.51}]},{"lat":10.69,"lon":-38.39,"b":[{"x":-387.8,"y":-92.12,"z":-301.76},{"x":-386.41,"y":-95.84,"z":-302.39},{"x":-383.61,"y":-96.48,"z":-305.74},{"x":-382.24,"y":-93.38,"z":-308.4},{"x":-383.68,"y":-89.69,"z":-307.71},{"x":-386.44,"y":-89.07,"z":-304.42}]},{"lat":11.82,"lon":-39.9,"b":[{"x":-378.31,"y":-101.81,"z":-310.57},{"x":-376.77,"y":-105.58,"z":-311.17},{"x":-373.84,"y":-106.22,"z":-314.48},{"x":-372.47,"y":-103.06,"z":-317.15},{"x":-374.04,"y":-99.31,"z":-316.5},{"x":-376.94,"y":-98.7,"z":-313.23}]},{"lat":12.97,"lon":-41.45,"b":[{"x":-368.2,"y":-111.6,"z":-319.23},{"x":-366.52,"y":-115.43,"z":-319.8},{"x":-363.44,"y":-116.05,"z":-323.07},{"x":-362.08,"y":-112.83,"z":-325.73},{"x":-363.79,"y":-109.04,"z":-325.12},{"x":-366.83,"y":-108.44,"z":-321.89}]},{"lat":14.13,"lon":-43.05,"b":[{"x":-357.46,"y":-121.47,"z":-327.71},{"x":-355.64,"y":-125.33,"z":-328.24},{"x":-352.43,"y":-125.94,"z":-331.46},{"x":-351.07,"y":-122.66,"z":-334.11},{"x":-352.92,"y":-118.83,"z":-333.55},{"x":-356.1,"y":-118.25,"z":-330.37}]},{"lat":15.3,"lon":-44.69,"b":[{"x":-346.12,"y":-131.37,"z":-335.97},{"x":-344.16,"y":-135.26,"z":-336.43},{"x":-340.82,"y":-135.84,"z":-339.59},{"x":-339.47,"y":-132.51,"z":-342.24},{"x":-341.46,"y":-128.66,"z":-341.74},{"x":-344.76,"y":-128.1,"z":-338.62}]},{"lat":16.48,"lon":-46.38,"b":[{"x":-334.18,"y":-141.27,"z":-343.94},{"x":-332.08,"y":-145.18,"z":-344.35},{"x":-328.61,"y":-145.73,"z":-347.43},{"x":-327.28,"y":-142.35,"z":-350.07},{"x":-329.4,"y":-138.48,"z":-349.64},{"x":-332.83,"y":-137.94,"z":-346.59}]},{"lat":17.66,"lon":-48.1,"b":[{"x":-321.66,"y":-151.13,"z":-351.6},{"x":-319.43,"y":-155.05,"z":-351.93},{"x":-315.84,"y":-155.55,"z":-354.93},{"x":-314.54,"y":-152.13,"z":-357.56},{"x":-316.79,"y":-148.25,"z":-357.2},{"x":-320.33,"y":-147.75,"z":-354.24}]},{"lat":18.83,"lon":-49.87,"b":[{"x":-308.6,"y":-160.9,"z":-358.89},{"x":-306.23,"y":-164.82,"z":-359.14},{"x":-302.55,"y":-165.27,"z":-362.05},{"x":-301.27,"y":-161.81,"z":-364.67},{"x":-303.64,"y":-157.94,"z":-364.4},{"x":-307.29,"y":-157.48,"z":-361.52}]},{"lat":20,"lon":-51.68,"b":[{"x":-295.03,"y":-170.55,"z":-365.78},{"x":-292.54,"y":-174.45,"z":-365.94},{"x":-288.76,"y":-174.85,"z":-368.74},{"x":-287.51,"y":-171.35,"z":-371.35},{"x":-290,"y":-167.5,"z":-371.17},{"x":-293.75,"y":-167.09,"z":-368.4}]},{"lat":21.15,"lon":-53.53,"b":[{"x":-280.99,"y":-180.03,"z":-372.23},{"x":-278.38,"y":-183.91,"z":-372.3},{"x":-274.52,"y":-184.24,"z":-374.99},{"x":-273.31,"y":-180.72,"z":-377.58},{"x":-275.92,"y":-176.89,"z":-377.51},{"x":-279.74,"y":-176.54,"z":-374.84}]},{"lat":22.29,"lon":-55.41,"b":[{"x":-266.53,"y":-189.31,"z":-378.22},{"x":-263.82,"y":-193.14,"z":-378.18},{"x":-259.9,"y":-193.41,"z":-380.75},{"x":-258.72,"y":-189.86,"z":-383.33},{"x":-261.43,"y":-186.07,"z":-383.36},{"x":-265.32,"y":-185.78,"z":-380.81}]},{"lat":23.4,"lon":-57.32,"b":[{"x":-251.72,"y":-198.34,"z":-383.7},{"x":-248.91,"y":-202.12,"z":-383.56},{"x":-244.94,"y":-202.31,"z":-386},{"x":-243.8,"y":-198.75,"z":-388.57},{"x":-246.59,"y":-195.01,"z":-388.7},{"x":-250.54,"y":-194.79,"z":-386.28}]},{"lat":24.49,"lon":-59.25,"b":[{"x":-236.6,"y":-207.09,"z":-388.67},{"x":-233.71,"y":-210.81,"z":-388.41},{"x":-229.7,"y":-210.92,"z":-390.73},{"x":-228.61,"y":-207.35,"z":-393.28},{"x":-231.48,"y":-203.67,"z":-393.53},{"x":-235.46,"y":-203.52,"z":-391.23}]},{"lat":25.54,"lon":-61.21,"b":[{"x":-221.24,"y":-215.52,"z":-393.1},{"x":-218.28,"y":-219.18,"z":-392.74},{"x":-214.26,"y":-219.21,"z":-394.93},{"x":-213.21,"y":-215.63,"z":-397.46},{"x":-216.14,"y":-212.02,"z":-397.82},{"x":-220.15,"y":-211.95,"z":-395.65}]},{"lat":26.57,"lon":-63.19,"b":[{"x":-205.71,"y":-223.62,"z":-397},{"x":-202.69,"y":-227.19,"z":-396.52},{"x":-198.67,"y":-227.14,"z":-398.58},{"x":-197.67,"y":-223.57,"z":-401.09},{"x":-200.65,"y":-220.03,"z":-401.57},{"x":-204.66,"y":-220.04,"z":-399.53}]},{"lat":27.55,"lon":-65.18,"b":[{"x":-190.06,"y":-231.35,"z":-400.35},{"x":-187.01,"y":-234.84,"z":-399.76},{"x":-183,"y":-234.71,"z":-401.69},{"x":-182.04,"y":-231.14,"z":-404.19},{"x":-185.06,"y":-227.69,"z":-404.77},{"x":-189.06,"y":-227.77,"z":-402.87}]},{"lat":28.5,"lon":-67.19,"b":[{"x":-174.38,"y":-238.71,"z":-403.17},{"x":-171.3,"y":-242.1,"z":-402.46},{"x":-167.31,"y":-241.88,"z":-404.26},{"x":-166.41,"y":-238.33,"z":-406.75},{"x":-169.44,"y":-234.97,"z":-407.44},{"x":-173.43,"y":-235.14,"z":-405.66}]},{"lat":29.4,"lon":-69.19,"b":[{"x":-158.71,"y":-245.67,"z":-405.45},{"x":-155.61,"y":-248.96,"z":-404.64},{"x":-151.67,"y":-248.66,"z":-406.32},{"x":-150.81,"y":-245.12,"z":-408.79},{"x":-153.86,"y":-241.86,"z":-409.59},{"x":-157.8,"y":-242.11,"z":-407.94}]},{"lat":30.25,"lon":-71.2,"b":[{"x":-142.17,"y":-252.14,"z":-407.62},{"x":-139.82,"y":-254.56,"z":-406.93},{"x":-136.87,"y":-254.28,"z":-408.11},{"x":-136.25,"y":-251.61,"z":-409.97},{"x":-138.56,"y":-249.21,"z":-410.66},{"x":-141.52,"y":-249.46,"z":-409.5}]},{"lat":6.83,"lon":-35.94,"b":[{"x":-404.33,"y":-58.88,"z":-288.09},{"x":-403.28,"y":-62.36,"z":-288.82},{"x":-400.79,"y":-62.96,"z":-292.14},{"x":-399.37,"y":-60.04,"z":-294.69},{"x":-400.45,"y":-56.58,"z":-293.91},{"x":-402.92,"y":-56.01,"z":-290.63}]},{"lat":7.88,"lon":-37.34,"b":[{"x":-396.3,"y":-67.97,"z":-297.09},{"x":-395.13,"y":-71.54,"z":-297.81},{"x":-392.51,"y":-72.14,"z":-301.13},{"x":-391.08,"y":-69.16,"z":-303.67},{"x":-392.29,"y":-65.62,"z":-302.9},{"x":-394.88,"y":-65.05,"z":-299.64}]},{"lat":8.96,"lon":-38.78,"b":[{"x":-387.7,"y":-77.25,"z":-306.04},{"x":-386.4,"y":-80.87,"z":-306.75},{"x":-383.63,"y":-81.49,"z":-310.05},{"x":-382.2,"y":-78.44,"z":-312.59},{"x":-383.53,"y":-74.84,"z":-311.84},{"x":-386.27,"y":-74.26,"z":-308.59}]},{"lat":10.05,"lon":-40.26,"b":[{"x":-378.49,"y":-86.67,"z":-314.91},{"x":-377.06,"y":-90.36,"z":-315.59},{"x":-374.16,"y":-90.97,"z":-318.86},{"x":-372.72,"y":-87.86,"z":-321.4},{"x":-374.19,"y":-84.2,"z":-320.68},{"x":-377.06,"y":-83.62,"z":-317.45}]},{"lat":11.16,"lon":-41.79,"b":[{"x":-368.68,"y":-96.22,"z":-323.65},{"x":-367.11,"y":-99.96,"z":-324.3},{"x":-364.07,"y":-100.56,"z":-327.53},{"x":-362.64,"y":-97.39,"z":-330.07},{"x":-364.24,"y":-93.68,"z":-329.38},{"x":-367.25,"y":-93.11,"z":-326.19}]},{"lat":12.29,"lon":-43.36,"b":[{"x":-358.27,"y":-105.86,"z":-332.22},{"x":-356.56,"y":-109.65,"z":-332.83},{"x":-353.39,"y":-110.23,"z":-336.01},{"x":-351.96,"y":-107.01,"z":-338.54},{"x":-353.7,"y":-103.26,"z":-337.89},{"x":-356.84,"y":-102.69,"z":-334.76}]},{"lat":13.43,"lon":-44.97,"b":[{"x":-347.25,"y":-115.56,"z":-340.58},{"x":-345.41,"y":-119.39,"z":-341.13},{"x":-342.1,"y":-119.95,"z":-344.25},{"x":-340.69,"y":-116.67,"z":-346.77},{"x":-342.56,"y":-112.89,"z":-346.18},{"x":-345.83,"y":-112.34,"z":-343.1}]},{"lat":14.58,"lon":-46.63,"b":[{"x":-335.65,"y":-125.29,"z":-348.67},{"x":-333.66,"y":-129.15,"z":-349.17},{"x":-330.24,"y":-129.68,"z":-352.22},{"x":-328.84,"y":-126.35,"z":-354.73},{"x":-330.85,"y":-122.54,"z":-354.2},{"x":-334.23,"y":-122.01,"z":-351.19}]},{"lat":15.73,"lon":-48.32,"b":[{"x":-323.47,"y":-135.01,"z":-356.46},{"x":-321.35,"y":-138.88,"z":-356.9},{"x":-317.81,"y":-139.38,"z":-359.86},{"x":-316.43,"y":-136,"z":-362.36},{"x":-318.57,"y":-132.17,"z":-361.9},{"x":-322.07,"y":-131.68,"z":-358.97}]},{"lat":16.88,"lon":-50.06,"b":[{"x":-310.75,"y":-144.68,"z":-363.91},{"x":-308.5,"y":-148.56,"z":-364.27},{"x":-304.85,"y":-149.01,"z":-367.14},{"x":-303.5,"y":-145.59,"z":-369.62},{"x":-305.77,"y":-141.76,"z":-369.25},{"x":-309.37,"y":-141.3,"z":-366.41}]},{"lat":18.02,"lon":-51.83,"b":[{"x":-297.52,"y":-154.26,"z":-370.97},{"x":-295.14,"y":-158.13,"z":-371.24},{"x":-291.39,"y":-158.54,"z":-374.01},{"x":-290.07,"y":-155.08,"z":-376.48},{"x":-292.46,"y":-151.25,"z":-376.19},{"x":-296.16,"y":-150.83,"z":-373.45}]},{"lat":19.16,"lon":-53.64,"b":[{"x":-283.81,"y":-163.7,"z":-377.6},{"x":-281.31,"y":-167.56,"z":-377.78},{"x":-277.49,"y":-167.91,"z":-380.44},{"x":-276.2,"y":-164.42,"z":-382.89},{"x":-278.7,"y":-160.61,"z":-382.7},{"x":-282.49,"y":-160.24,"z":-380.07}]},{"lat":20.28,"lon":-55.47,"b":[{"x":-269.67,"y":-172.98,"z":-383.77},{"x":-267.06,"y":-176.81,"z":-383.85},{"x":-263.17,"y":-177.1,"z":-386.4},{"x":-261.92,"y":-173.58,"z":-388.84},{"x":-264.53,"y":-169.8,"z":-388.75},{"x":-268.38,"y":-169.49,"z":-386.23}]},{"lat":21.38,"lon":-57.34,"b":[{"x":-255.15,"y":-182.06,"z":-389.46},{"x":-252.45,"y":-185.85,"z":-389.44},{"x":-248.5,"y":-186.06,"z":-391.86},{"x":-247.3,"y":-182.52,"z":-394.28},{"x":-250,"y":-178.78,"z":-394.3},{"x":-253.91,"y":-178.53,"z":-391.9}]},{"lat":22.47,"lon":-59.23,"b":[{"x":-240.32,"y":-190.88,"z":-394.64},{"x":-237.52,"y":-194.62,"z":-394.5},{"x":-233.54,"y":-194.77,"z":-396.8},{"x":-232.38,"y":-191.21,"z":-399.21},{"x":-235.16,"y":-187.52,"z":-399.33},{"x":-239.11,"y":-187.34,"z":-397.06}]},{"lat":23.52,"lon":-61.15,"b":[{"x":-225.22,"y":-199.44,"z":-399.29},{"x":-222.35,"y":-203.12,"z":-399.04},{"x":-218.34,"y":-203.19,"z":-401.21},{"x":-217.23,"y":-199.62,"z":-403.6},{"x":-220.08,"y":-195.98,"z":-403.84},{"x":-224.06,"y":-195.87,"z":-401.69}]},{"lat":24.55,"lon":-63.08,"b":[{"x":-209.92,"y":-207.68,"z":-403.4},{"x":-206.99,"y":-211.29,"z":-403.04},{"x":-202.97,"y":-211.29,"z":-405.08},{"x":-201.92,"y":-207.71,"z":-407.45},{"x":-204.82,"y":-204.15,"z":-407.81},{"x":-208.81,"y":-204.11,"z":-405.79}]},{"lat":25.54,"lon":-65.02,"b":[{"x":-194.48,"y":-215.6,"z":-406.97},{"x":-191.5,"y":-219.13,"z":-406.49},{"x":-187.5,"y":-219.05,"z":-408.4},{"x":-186.49,"y":-215.47,"z":-410.76},{"x":-189.44,"y":-211.98,"z":-411.23},{"x":-193.43,"y":-212.02,"z":-409.34}]},{"lat":26.49,"lon":-66.98,"b":[{"x":-178.98,"y":-223.16,"z":-410},{"x":-175.96,"y":-226.61,"z":-409.41},{"x":-171.98,"y":-226.45,"z":-411.19},{"x":-171.02,"y":-222.88,"z":-413.53},{"x":-174,"y":-219.48,"z":-414.11},{"x":-177.97,"y":-219.59,"z":-412.36}]},{"lat":27.41,"lon":-68.94,"b":[{"x":-163.46,"y":-230.36,"z":-412.49},{"x":-160.42,"y":-233.72,"z":-411.79},{"x":-156.47,"y":-233.47,"z":-413.45},{"x":-155.57,"y":-229.92,"z":-415.78},{"x":-158.56,"y":-226.6,"z":-416.47},{"x":-162.5,"y":-226.8,"z":-414.83}]},{"lat":28.28,"lon":-70.9,"b":[{"x":-147.01,"y":-237.11,"z":-414.87},{"x":-144.72,"y":-239.56,"z":-414.26},{"x":-141.8,"y":-239.31,"z":-415.41},{"x":-141.16,"y":-236.67,"z":-417.15},{"x":-143.4,"y":-234.25,"z":-417.75},{"x":-146.33,"y":-234.45,"z":-416.61}]},{"lat":5.22,"lon":-36.36,"b":[{"x":-401.56,"y":-45.34,"z":-294.42},{"x":-401.32,"y":-46.16,"z":-294.61},{"x":-400.73,"y":-46.29,"z":-295.39},{"x":-400.38,"y":-45.61,"z":-295.98},{"x":-400.62,"y":-44.8,"z":-295.78},{"x":-401.2,"y":-44.67,"z":-295}]},{"lat":6.23,"lon":-37.74,"b":[{"x":-395.59,"y":-53.74,"z":-300.95},{"x":-394.5,"y":-57.2,"z":-301.73},{"x":-391.9,"y":-57.77,"z":-304.99},{"x":-390.41,"y":-54.85,"z":-307.43},{"x":-391.54,"y":-51.42,"z":-306.6},{"x":-394.11,"y":-50.88,"z":-303.38}]},{"lat":7.27,"lon":-39.16,"b":[{"x":-387.24,"y":-62.72,"z":-309.93},{"x":-386.03,"y":-66.25,"z":-310.7},{"x":-383.3,"y":-66.83,"z":-313.95},{"x":-381.8,"y":-63.85,"z":-316.38},{"x":-383.05,"y":-60.34,"z":-315.56},{"x":-385.75,"y":-59.8,"z":-312.36}]},{"lat":8.33,"lon":-40.62,"b":[{"x":-378.31,"y":-71.86,"z":-318.83},{"x":-376.98,"y":-75.46,"z":-319.59},{"x":-374.1,"y":-76.04,"z":-322.81},{"x":-372.6,"y":-73,"z":-325.23},{"x":-373.98,"y":-69.43,"z":-324.44},{"x":-376.82,"y":-68.88,"z":-321.26}]},{"lat":9.41,"lon":-42.12,"b":[{"x":-368.8,"y":-81.15,"z":-327.63},{"x":-367.33,"y":-84.8,"z":-328.35},{"x":-364.32,"y":-85.38,"z":-331.54},{"x":-362.82,"y":-82.28,"z":-333.96},{"x":-364.33,"y":-78.66,"z":-333.19},{"x":-367.3,"y":-78.1,"z":-330.05}]},{"lat":10.5,"lon":-43.66,"b":[{"x":-358.69,"y":-90.55,"z":-336.27},{"x":-357.09,"y":-94.26,"z":-336.96},{"x":-353.95,"y":-94.82,"z":-340.1},{"x":-352.46,"y":-91.66,"z":-342.5},{"x":-354.1,"y":-87.99,"z":-341.78},{"x":-357.19,"y":-87.44,"z":-338.68}]},{"lat":11.6,"lon":-45.25,"b":[{"x":-348,"y":-100.03,"z":-344.71},{"x":-346.26,"y":-103.79,"z":-345.36},{"x":-342.99,"y":-104.33,"z":-348.43},{"x":-341.51,"y":-101.11,"z":-350.83},{"x":-343.28,"y":-97.4,"z":-350.15},{"x":-346.51,"y":-96.87,"z":-347.12}]},{"lat":12.72,"lon":-46.87,"b":[{"x":-336.72,"y":-109.57,"z":-352.91},{"x":-334.85,"y":-113.36,"z":-353.5},{"x":-331.46,"y":-113.88,"z":-356.51},{"x":-330,"y":-110.61,"z":-358.89},{"x":-331.9,"y":-106.86,"z":-358.27},{"x":-335.24,"y":-106.35,"z":-355.3}]},{"lat":13.84,"lon":-48.54,"b":[{"x":-324.88,"y":-119.12,"z":-360.82},{"x":-322.87,"y":-122.94,"z":-361.35},{"x":-319.37,"y":-123.43,"z":-364.28},{"x":-317.93,"y":-120.11,"z":-366.64},{"x":-319.97,"y":-116.34,"z":-366.09},{"x":-323.42,"y":-115.85,"z":-363.2}]},{"lat":14.97,"lon":-50.23,"b":[{"x":-312.5,"y":-128.66,"z":-368.4},{"x":-310.36,"y":-132.49,"z":-368.86},{"x":-306.76,"y":-132.94,"z":-371.7},{"x":-305.34,"y":-129.57,"z":-374.05},{"x":-307.5,"y":-125.79,"z":-373.57},{"x":-311.06,"y":-125.33,"z":-370.77}]},{"lat":16.09,"lon":-51.97,"b":[{"x":-299.61,"y":-138.14,"z":-375.61},{"x":-297.34,"y":-141.97,"z":-375.99},{"x":-293.64,"y":-142.38,"z":-378.73},{"x":-292.25,"y":-138.97,"z":-381.06},{"x":-294.54,"y":-135.18,"z":-380.67},{"x":-298.19,"y":-134.76,"z":-377.96}]},{"lat":17.21,"lon":-53.74,"b":[{"x":-286.23,"y":-147.52,"z":-382.41},{"x":-283.84,"y":-151.35,"z":-382.7},{"x":-280.06,"y":-151.71,"z":-385.33},{"x":-278.71,"y":-148.26,"z":-387.65},{"x":-281.11,"y":-144.48,"z":-387.35},{"x":-284.85,"y":-144.1,"z":-384.74}]},{"lat":18.31,"lon":-55.53,"b":[{"x":-272.42,"y":-156.77,"z":-388.77},{"x":-269.92,"y":-160.58,"z":-388.96},{"x":-266.06,"y":-160.88,"z":-391.48},{"x":-264.76,"y":-157.4,"z":-393.78},{"x":-267.26,"y":-153.64,"z":-393.57},{"x":-271.07,"y":-153.32,"z":-391.08}]},{"lat":19.41,"lon":-57.36,"b":[{"x":-258.22,"y":-165.85,"z":-394.65},{"x":-255.61,"y":-169.63,"z":-394.74},{"x":-251.7,"y":-169.87,"z":-397.14},{"x":-250.44,"y":-166.36,"z":-399.42},{"x":-253.04,"y":-162.63,"z":-399.32},{"x":-256.91,"y":-162.36,"z":-396.95}]},{"lat":20.48,"lon":-59.21,"b":[{"x":-243.68,"y":-174.72,"z":-400.03},{"x":-240.98,"y":-178.46,"z":-400.01},{"x":-237.03,"y":-178.64,"z":-402.28},{"x":-235.81,"y":-175.11,"z":-404.55},{"x":-238.5,"y":-171.42,"z":-404.56},{"x":-242.41,"y":-171.21,"z":-402.31}]},{"lat":21.53,"lon":-61.08,"b":[{"x":-228.86,"y":-183.35,"z":-404.89},{"x":-226.08,"y":-187.05,"z":-404.76},{"x":-222.1,"y":-187.15,"z":-406.91},{"x":-220.93,"y":-183.61,"z":-409.16},{"x":-223.69,"y":-179.96,"z":-409.28},{"x":-227.64,"y":-179.82,"z":-407.15}]},{"lat":22.56,"lon":-62.97,"b":[{"x":-213.81,"y":-191.72,"z":-409.22},{"x":-210.97,"y":-195.35,"z":-408.98},{"x":-206.98,"y":-195.38,"z":-410.99},{"x":-205.86,"y":-191.83,"z":-413.23},{"x":-208.68,"y":-188.24,"z":-413.46},{"x":-212.65,"y":-188.17,"z":-411.47}]},{"lat":23.55,"lon":-64.87,"b":[{"x":-198.61,"y":-199.78,"z":-413.01},{"x":-195.71,"y":-203.35,"z":-412.65},{"x":-191.72,"y":-203.31,"z":-414.54},{"x":-190.66,"y":-199.75,"z":-416.76},{"x":-193.53,"y":-196.23,"z":-417.1},{"x":-197.49,"y":-196.22,"z":-415.24}]},{"lat":24.51,"lon":-66.78,"b":[{"x":-183.3,"y":-207.53,"z":-416.25},{"x":-180.36,"y":-211.02,"z":-415.78},{"x":-176.39,"y":-210.9,"z":-417.54},{"x":-175.38,"y":-207.34,"z":-419.75},{"x":-178.29,"y":-203.9,"z":-420.21},{"x":-182.24,"y":-203.97,"z":-418.47}]},{"lat":25.44,"lon":-68.7,"b":[{"x":-167.96,"y":-214.93,"z":-418.96},{"x":-164.98,"y":-218.34,"z":-418.38},{"x":-161.04,"y":-218.14,"z":-420.01},{"x":-160.09,"y":-214.6,"z":-422.2},{"x":-163.03,"y":-211.23,"z":-422.78},{"x":-166.95,"y":-211.37,"z":-421.17}]},{"lat":26.33,"lon":-70.62,"b":[{"x":-151.21,"y":-221.9,"z":-421.72},{"x":-149.31,"y":-224.01,"z":-421.29},{"x":-146.83,"y":-223.84,"z":-422.24},{"x":-146.27,"y":-221.6,"z":-423.63},{"x":-148.13,"y":-219.52,"z":-424.06},{"x":-150.6,"y":-219.65,"z":-423.11}]},{"lat":4.63,"lon":-38.12,"b":[{"x":-393.58,"y":-40.07,"z":-305.7},{"x":-392.97,"y":-42.11,"z":-306.21},{"x":-391.41,"y":-42.44,"z":-308.16},{"x":-390.66,"y":-40.49,"z":-309.37},{"x":-391.49,"y":-38.23,"z":-308.61},{"x":-392.84,"y":-38.15,"z":-306.89}]},{"lat":5.63,"lon":-39.52,"b":[{"x":-386.46,"y":-48.56,"z":-313.43},{"x":-385.34,"y":-51.99,"z":-314.26},{"x":-382.63,"y":-52.54,"z":-317.46},{"x":-381.39,"y":-49.28,"z":-319.47},{"x":-382.86,"y":-45.51,"z":-318.26},{"x":-385.23,"y":-45.34,"z":-315.42}]},{"lat":6.66,"lon":-40.96,"b":[{"x":-377.8,"y":-57.42,"z":-322.36},{"x":-376.55,"y":-60.92,"z":-323.18},{"x":-373.71,"y":-61.47,"z":-326.35},{"x":-372.45,"y":-58.17,"z":-328.39},{"x":-374.04,"y":-54.36,"z":-327.23},{"x":-376.55,"y":-54.15,"z":-324.38}]},{"lat":7.7,"lon":-42.44,"b":[{"x":-368.56,"y":-66.43,"z":-331.19},{"x":-367.19,"y":-69.99,"z":-331.99},{"x":-364.22,"y":-70.55,"z":-335.12},{"x":-362.95,"y":-67.21,"z":-337.19},{"x":-364.65,"y":-63.36,"z":-336.09},{"x":-367.3,"y":-63.13,"z":-333.23}]},{"lat":8.76,"lon":-43.96,"b":[{"x":-358.76,"y":-75.58,"z":-339.88},{"x":-357.25,"y":-79.2,"z":-340.65},{"x":-354.15,"y":-79.74,"z":-343.74},{"x":-352.87,"y":-76.37,"z":-345.82},{"x":-354.69,"y":-72.49,"z":-344.79},{"x":-357.48,"y":-72.24,"z":-341.94}]},{"lat":9.83,"lon":-45.51,"b":[{"x":-348.37,"y":-84.82,"z":-348.39},{"x":-346.74,"y":-88.49,"z":-349.11},{"x":-343.51,"y":-89.03,"z":-352.15},{"x":-342.22,"y":-85.63,"z":-354.25},{"x":-344.15,"y":-81.73,"z":-353.3},{"x":-347.09,"y":-81.46,"z":-350.47}]},{"lat":10.91,"lon":-47.11,"b":[{"x":-337.42,"y":-94.15,"z":-356.67},{"x":-335.65,"y":-97.86,"z":-357.35},{"x":-332.31,"y":-98.37,"z":-360.32},{"x":-331,"y":-94.95,"z":-362.44},{"x":-333.04,"y":-91.03,"z":-361.57},{"x":-336.13,"y":-90.75,"z":-358.77}]},{"lat":12.01,"lon":-48.74,"b":[{"x":-325.92,"y":-103.52,"z":-364.69},{"x":-324.01,"y":-107.26,"z":-365.3},{"x":-320.56,"y":-107.75,"z":-368.2},{"x":-319.24,"y":-104.3,"z":-370.33},{"x":-321.39,"y":-100.38,"z":-369.55},{"x":-324.61,"y":-100.09,"z":-366.8}]},{"lat":13.1,"lon":-50.4,"b":[{"x":-313.87,"y":-112.89,"z":-372.39},{"x":-311.84,"y":-116.66,"z":-372.94},{"x":-308.28,"y":-117.12,"z":-375.74},{"x":-306.95,"y":-113.65,"z":-377.88},{"x":-309.2,"y":-109.74,"z":-377.21},{"x":-312.56,"y":-109.44,"z":-374.52}]},{"lat":14.2,"lon":-52.1,"b":[{"x":-301.32,"y":-122.24,"z":-379.73},{"x":-299.16,"y":-126.02,"z":-380.21},{"x":-295.5,"y":-126.44,"z":-382.91},{"x":-294.17,"y":-122.96,"z":-385.07},{"x":-296.5,"y":-119.07,"z":-384.5},{"x":-299.99,"y":-118.77,"z":-381.87}]},{"lat":15.3,"lon":-53.83,"b":[{"x":-288.28,"y":-131.53,"z":-386.68},{"x":-286,"y":-135.32,"z":-387.08},{"x":-282.26,"y":-135.69,"z":-389.68},{"x":-280.92,"y":-132.2,"z":-391.84},{"x":-283.33,"y":-128.34,"z":-391.39},{"x":-286.95,"y":-128.05,"z":-388.84}]},{"lat":16.39,"lon":-55.59,"b":[{"x":-274.8,"y":-140.72,"z":-393.21},{"x":-272.4,"y":-144.5,"z":-393.51},{"x":-268.59,"y":-144.82,"z":-396},{"x":-267.26,"y":-141.32,"z":-398.16},{"x":-269.73,"y":-137.5,"z":-397.83},{"x":-273.47,"y":-137.23,"z":-395.37}]},{"lat":17.47,"lon":-57.38,"b":[{"x":-260.92,"y":-149.77,"z":-399.27},{"x":-258.42,"y":-153.53,"z":-399.47},{"x":-254.55,"y":-153.8,"z":-401.85},{"x":-253.21,"y":-150.3,"z":-404.01},{"x":-255.74,"y":-146.53,"z":-403.8},{"x":-259.59,"y":-146.27,"z":-401.44}]},{"lat":18.53,"lon":-59.19,"b":[{"x":-246.69,"y":-158.66,"z":-404.85},{"x":-244.09,"y":-162.39,"z":-404.95},{"x":-240.18,"y":-162.6,"z":-407.2},{"x":-238.84,"y":-159.09,"z":-409.36},{"x":-241.42,"y":-155.38,"z":-409.28},{"x":-245.35,"y":-155.15,"z":-407.01}]},{"lat":19.57,"lon":-61.02,"b":[{"x":-232.16,"y":-167.34,"z":-409.91},{"x":-229.48,"y":-171.03,"z":-409.91},{"x":-225.53,"y":-171.17,"z":-412.03},{"x":-224.2,"y":-167.68,"z":-414.19},{"x":-226.8,"y":-164.03,"z":-414.23},{"x":-230.83,"y":-163.84,"z":-412.08}]},{"lat":20.6,"lon":-62.87,"b":[{"x":-217.39,"y":-175.78,"z":-414.46},{"x":-214.63,"y":-179.42,"z":-414.34},{"x":-210.67,"y":-179.5,"z":-416.33},{"x":-209.34,"y":-176.01,"z":-418.48},{"x":-211.97,"y":-172.44,"z":-418.65},{"x":-216.06,"y":-172.29,"z":-416.62}]},{"lat":21.59,"lon":-64.73,"b":[{"x":-202.44,"y":-183.96,"z":-418.46},{"x":-199.61,"y":-187.54,"z":-418.23},{"x":-195.65,"y":-187.55,"z":-420.09},{"x":-194.32,"y":-184.08,"z":-422.24},{"x":-196.96,"y":-180.59,"z":-422.53},{"x":-201.11,"y":-180.48,"z":-420.61}]},{"lat":22.56,"lon":-66.6,"b":[{"x":-187.36,"y":-191.85,"z":-421.93},{"x":-184.48,"y":-195.37,"z":-421.58},{"x":-180.53,"y":-195.3,"z":-423.32},{"x":-179.21,"y":-191.85,"z":-425.45},{"x":-181.84,"y":-188.45,"z":-425.86},{"x":-186.03,"y":-188.38,"z":-424.07}]},{"lat":23.5,"lon":-68.47,"b":[{"x":-172.21,"y":-199.43,"z":-424.86},{"x":-169.3,"y":-202.88,"z":-424.4},{"x":-165.37,"y":-202.74,"z":-426.01},{"x":-164.07,"y":-199.31,"z":-428.13},{"x":-166.67,"y":-196,"z":-428.65},{"x":-170.89,"y":-195.98,"z":-426.99}]},{"lat":24.4,"lon":-70.35,"b":[{"x":-155.84,"y":-206.64,"z":-427.75},{"x":-153.82,"y":-208.95,"z":-427.35},{"x":-151.15,"y":-208.8,"z":-428.38},{"x":-150.25,"y":-206.47,"z":-429.82},{"x":-152.03,"y":-204.26,"z":-430.26},{"x":-154.94,"y":-204.28,"z":-429.2}]},{"lat":3.76,"lon":-39.52,"b":[{"x":-385.63,"y":-30.61,"z":-316.72},{"x":-386.21,"y":-32.72,"z":-315.81},{"x":-385.41,"y":-34.92,"z":-316.55},{"x":-384.02,"y":-35.02,"z":-318.22},{"x":-383.42,"y":-32.89,"z":-319.17},{"x":-384.24,"y":-30.67,"z":-318.41}]},{"lat":2.86,"lon":-40.96,"b":[{"x":-377.26,"y":-24.57,"z":-327.21},{"x":-377.38,"y":-24.96,"z":-327.04},{"x":-377.23,"y":-25.36,"z":-327.18},{"x":-376.96,"y":-25.38,"z":-327.49},{"x":-376.84,"y":-24.98,"z":-327.66},{"x":-376.99,"y":-24.58,"z":-327.51}]},{"lat":4.76,"lon":-40.96,"b":[{"x":-377.7,"y":-37.74,"z":-325.37},{"x":-378.7,"y":-41.35,"z":-323.76},{"x":-377.23,"y":-45.12,"z":-324.97},{"x":-374.72,"y":-45.32,"z":-327.82},{"x":-373.69,"y":-41.69,"z":-329.48},{"x":-375.19,"y":-37.87,"z":-328.24}]},{"lat":3.87,"lon":-42.44,"b":[{"x":-369.6,"y":-29.88,"z":-335.32},{"x":-370.73,"y":-33.57,"z":-333.73},{"x":-369.23,"y":-37.39,"z":-334.98},{"x":-366.58,"y":-37.55,"z":-337.86},{"x":-365.43,"y":-33.84,"z":-339.5},{"x":-366.96,"y":-29.97,"z":-338.21}]},{"lat":5.79,"lon":-42.44,"b":[{"x":-368.66,"y":-46.58,"z":-334.46},{"x":-369.69,"y":-50.22,"z":-332.8},{"x":-368.1,"y":-54.03,"z":-333.96},{"x":-365.45,"y":-54.26,"z":-336.81},{"x":-364.39,"y":-50.61,"z":-338.53},{"x":-366.01,"y":-46.74,"z":-337.33}]},{"lat":2.94,"lon":-43.96,"b":[{"x":-360.01,"y":-24.18,"z":-346.09},{"x":-360.48,"y":-25.6,"z":-345.5},{"x":-359.91,"y":-27.04,"z":-345.99},{"x":-358.86,"y":-27.09,"z":-347.07},{"x":-358.39,"y":-25.67,"z":-347.67},{"x":-358.97,"y":-24.21,"z":-347.17}]},{"lat":4.89,"lon":-43.96,"b":[{"x":-360.19,"y":-38.74,"z":-344.53},{"x":-361.33,"y":-42.46,"z":-342.9},{"x":-359.72,"y":-46.32,"z":-344.09},{"x":-356.92,"y":-46.51,"z":-346.96},{"x":-355.75,"y":-42.78,"z":-348.65},{"x":-357.39,"y":-38.87,"z":-347.42}]},{"lat":6.83,"lon":-43.96,"b":[{"x":-359.03,"y":-55.58,"z":-343.43},{"x":-360.09,"y":-59.23,"z":-341.71},{"x":-358.38,"y":-63.09,"z":-342.81},{"x":-355.59,"y":-63.34,"z":-345.66},{"x":-354.5,"y":-59.68,"z":-347.43},{"x":-356.24,"y":-55.77,"z":-346.3}]},{"lat":1.98,"lon":-45.51,"b":[{"x":-351.37,"y":-14.17,"z":-355.37},{"x":-352.46,"y":-17.26,"z":-354.15},{"x":-351.21,"y":-20.39,"z":-355.22},{"x":-348.85,"y":-20.47,"z":-357.53},{"x":-347.73,"y":-17.36,"z":-358.78},{"x":-349,"y":-14.2,"z":-357.69}]},{"lat":3.96,"lon":-45.51,"b":[{"x":-351.12,"y":-30.64,"z":-354.55},{"x":-352.39,"y":-34.43,"z":-352.95},{"x":-350.75,"y":-38.34,"z":-354.18},{"x":-347.81,"y":-38.5,"z":-357.05},{"x":-346.51,"y":-34.68,"z":-358.7},{"x":-348.18,"y":-30.73,"z":-357.44}]},{"lat":5.93,"lon":-45.51,"b":[{"x":-350.18,"y":-47.76,"z":-353.6},{"x":-351.35,"y":-51.5,"z":-351.91},{"x":-349.62,"y":-55.4,"z":-353.04},{"x":-346.68,"y":-55.61,"z":-355.89},{"x":-345.47,"y":-51.87,"z":-357.63},{"x":-347.24,"y":-47.92,"z":-356.46}]},{"lat":7.89,"lon":-45.51,"b":[{"x":-348.83,"y":-64.72,"z":-352.23},{"x":-349.91,"y":-68.38,"z":-350.46},{"x":-348.09,"y":-72.27,"z":-351.5},{"x":-345.15,"y":-72.54,"z":-354.32},{"x":-344.04,"y":-68.87,"z":-356.14},{"x":-345.89,"y":-64.93,"z":-355.08}]},{"lat":1,"lon":-47.11,"b":[{"x":-340.63,"y":-7.81,"z":-365.91},{"x":-340.99,"y":-8.75,"z":-365.55},{"x":-340.61,"y":-9.7,"z":-365.88},{"x":-339.87,"y":-9.72,"z":-366.57},{"x":-339.5,"y":-8.77,"z":-366.94},{"x":-339.89,"y":-7.81,"z":-366.6}]},{"lat":3.01,"lon":-47.11,"b":[{"x":-341.46,"y":-22.29,"z":-364.47},{"x":-342.85,"y":-26.16,"z":-362.91},{"x":-341.18,"y":-30.11,"z":-364.18},{"x":-338.09,"y":-30.23,"z":-367.04},{"x":-336.67,"y":-26.34,"z":-368.64},{"x":-338.37,"y":-22.35,"z":-367.34}]},{"lat":5.01,"lon":-47.11,"b":[{"x":-340.72,"y":-39.68,"z":-363.68},{"x":-342.02,"y":-43.49,"z":-362.03},{"x":-340.26,"y":-47.44,"z":-363.19},{"x":-337.17,"y":-47.62,"z":-366.04},{"x":-335.84,"y":-43.79,"z":-367.73},{"x":-337.63,"y":-39.8,"z":-366.54}]},{"lat":6.99,"lon":-47.11,"b":[{"x":-339.58,"y":-56.92,"z":-362.46},{"x":-340.79,"y":-60.67,"z":-360.72},{"x":-338.93,"y":-64.6,"z":-361.78},{"x":-335.85,"y":-64.84,"z":-364.6},{"x":-334.61,"y":-61.08,"z":-366.39},{"x":-336.49,"y":-57.1,"z":-365.31}]},{"lat":8.96,"lon":-47.11,"b":[{"x":-338.04,"y":-73.97,"z":-360.82},{"x":-339.16,"y":-77.63,"z":-359},{"x":-337.22,"y":-81.54,"z":-359.96},{"x":-334.14,"y":-81.82,"z":-362.75},{"x":-332.99,"y":-78.15,"z":-364.62},{"x":-334.96,"y":-74.2,"z":-363.64}]},{"lat":0,"lon":-48.74,"b":[{"x":-329.92,"y":0.42,"z":-375.69},{"x":-330.09,"y":0,"z":-375.54},{"x":-329.92,"y":-0.42,"z":-375.69},{"x":-329.57,"y":-0.43,"z":-375.99},{"x":-329.4,"y":0,"z":-376.15},{"x":-329.57,"y":0.43,"z":-375.99}]},{"lat":2.03,"lon":-48.74,"b":[{"x":-330.74,"y":-14.82,"z":-374.62},{"x":-331.83,"y":-17.67,"z":-373.53},{"x":-330.6,"y":-20.55,"z":-374.47},{"x":-328.25,"y":-20.62,"z":-376.52},{"x":-327.14,"y":-17.75,"z":-377.64},{"x":-328.39,"y":-14.84,"z":-376.68}]},{"lat":4.05,"lon":-48.74,"b":[{"x":-330.66,"y":-31.34,"z":-373.65},{"x":-332.08,"y":-35.23,"z":-372.04},{"x":-330.29,"y":-39.23,"z":-373.23},{"x":-327.05,"y":-39.37,"z":-376.06},{"x":-325.6,"y":-35.46,"z":-377.7},{"x":-327.42,"y":-31.43,"z":-376.48}]},{"lat":6.07,"lon":-48.74,"b":[{"x":-329.73,"y":-48.86,"z":-372.59},{"x":-331.06,"y":-52.69,"z":-370.89},{"x":-329.18,"y":-56.67,"z":-371.97},{"x":-325.94,"y":-56.86,"z":-374.78},{"x":-324.58,"y":-53.02,"z":-376.52},{"x":-326.49,"y":-49,"z":-375.42}]},{"lat":8.07,"lon":-48.74,"b":[{"x":-328.4,"y":-66.19,"z":-371.09},{"x":-329.64,"y":-69.95,"z":-369.3},{"x":-327.67,"y":-73.9,"z":-370.28},{"x":-324.44,"y":-74.15,"z":-373.06},{"x":-323.17,"y":-70.39,"z":-374.89},{"x":-325.16,"y":-66.39,"z":-373.89}]},{"lat":10.05,"lon":-48.74,"b":[{"x":-326.69,"y":-83.29,"z":-369.15},{"x":-327.84,"y":-86.96,"z":-367.28},{"x":-325.79,"y":-90.87,"z":-368.15},{"x":-322.57,"y":-91.17,"z":-370.9},{"x":-321.38,"y":-87.5,"z":-372.81},{"x":-323.46,"y":-83.53,"z":-371.93}]},{"lat":-1.03,"lon":-50.4,"b":[{"x":-319.83,"y":11.99,"z":-384.06},{"x":-321.15,"y":8.93,"z":-383.05},{"x":-319.9,"y":5.89,"z":-384.15},{"x":-317.33,"y":5.89,"z":-386.28},{"x":-315.99,"y":8.97,"z":-387.31},{"x":-317.26,"y":12.03,"z":-386.19}]},{"lat":1.03,"lon":-50.4,"b":[{"x":-319.83,"y":-6.07,"z":-384.21},{"x":-321,"y":-8.93,"z":-383.18},{"x":-319.76,"y":-11.81,"z":-384.13},{"x":-317.34,"y":-11.84,"z":-386.14},{"x":-316.15,"y":-8.97,"z":-387.19},{"x":-317.4,"y":-6.07,"z":-386.22}]},{"lat":3.07,"lon":-50.4,"b":[{"x":-319.99,"y":-22.77,"z":-383.43},{"x":-321.53,"y":-26.73,"z":-381.88},{"x":-319.71,"y":-30.76,"z":-383.1},{"x":-316.32,"y":-30.87,"z":-385.9},{"x":-314.75,"y":-26.89,"z":-387.48},{"x":-316.59,"y":-22.83,"z":-386.23}]},{"lat":5.12,"lon":-50.4,"b":[{"x":-319.27,"y":-40.54,"z":-382.56},{"x":-320.72,"y":-44.44,"z":-380.92},{"x":-318.81,"y":-48.47,"z":-382.02},{"x":-315.42,"y":-48.62,"z":-384.8},{"x":-313.94,"y":-44.71,"z":-386.49},{"x":-315.88,"y":-40.64,"z":-385.36}]},{"lat":7.14,"lon":-50.4,"b":[{"x":-318.15,"y":-58.15,"z":-381.22},{"x":-319.51,"y":-61.99,"z":-379.48},{"x":-317.52,"y":-65.99,"z":-380.47},{"x":-314.14,"y":-66.19,"z":-383.23},{"x":-312.74,"y":-62.35,"z":-385.01},{"x":-314.76,"y":-58.3,"z":-384}]},{"lat":9.15,"lon":-50.4,"b":[{"x":-316.65,"y":-75.54,"z":-379.42},{"x":-317.92,"y":-79.3,"z":-377.59},{"x":-315.85,"y":-83.26,"z":-378.47},{"x":-312.48,"y":-83.52,"z":-381.2},{"x":-311.17,"y":-79.76,"z":-383.07},{"x":-313.27,"y":-75.75,"z":-382.18}]},{"lat":11.14,"lon":-50.4,"b":[{"x":-314.78,"y":-92.66,"z":-377.18},{"x":-315.96,"y":-96.32,"z":-375.27},{"x":-313.82,"y":-100.24,"z":-376.04},{"x":-310.46,"y":-100.54,"z":-378.73},{"x":-309.23,"y":-96.88,"z":-380.69},{"x":-311.4,"y":-92.91,"z":-379.9}]},{"lat":-4.14,"lon":-52.1,"b":[{"x":-307.1,"y":38.09,"z":-392.68},{"x":-308.09,"y":36.01,"z":-392.1},{"x":-307.28,"y":33.97,"z":-392.91},{"x":-305.47,"y":34.01,"z":-394.32},{"x":-304.46,"y":36.11,"z":-394.91},{"x":-305.29,"y":38.15,"z":-394.08}]},{"lat":-2.07,"lon":-52.1,"b":[{"x":-308.53,"y":22.08,"z":-392.75},{"x":-310.37,"y":18.01,"z":-391.5},{"x":-308.71,"y":13.99,"z":-392.98},{"x":-305.16,"y":14.01,"z":-395.73},{"x":-303.29,"y":18.11,"z":-397.01},{"x":-304.99,"y":22.15,"z":-395.5}]},{"lat":0,"lon":-52.1,"b":[{"x":-308.82,"y":4.05,"z":-393.12},{"x":-310.58,"y":0,"z":-391.76},{"x":-308.82,"y":-4.05,"z":-393.12},{"x":-305.27,"y":-4.08,"z":-395.87},{"x":-303.49,"y":0,"z":-397.27},{"x":-305.27,"y":4.08,"z":-395.87}]},{"lat":2.07,"lon":-52.1,"b":[{"x":-308.49,"y":-14.5,"z":-393.14},{"x":-309.94,"y":-18.02,"z":-391.85},{"x":-308.33,"y":-21.58,"z":-392.94},{"x":-305.23,"y":-21.64,"z":-395.35},{"x":-303.74,"y":-18.1,"z":-396.67},{"x":-305.38,"y":-14.52,"z":-395.55}]},{"lat":4.14,"lon":-52.1,"b":[{"x":-308.2,"y":-31.98,"z":-392.33},{"x":-309.77,"y":-35.95,"z":-390.74},{"x":-307.84,"y":-40.02,"z":-391.87},{"x":-304.3,"y":-40.14,"z":-394.61},{"x":-302.69,"y":-36.15,"z":-396.23},{"x":-304.66,"y":-32.05,"z":-395.08}]},{"lat":6.19,"lon":-52.1,"b":[{"x":-307.29,"y":-49.84,"z":-391.17},{"x":-308.78,"y":-53.76,"z":-389.48},{"x":-306.76,"y":-57.8,"z":-390.5},{"x":-303.23,"y":-57.97,"z":-393.22},{"x":-301.71,"y":-54.05,"z":-394.94},{"x":-303.76,"y":-49.96,"z":-393.91}]},{"lat":8.23,"lon":-52.1,"b":[{"x":-306,"y":-67.51,"z":-389.53},{"x":-307.4,"y":-71.35,"z":-387.75},{"x":-305.3,"y":-75.37,"z":-388.64},{"x":-301.78,"y":-75.58,"z":-391.34},{"x":-300.35,"y":-71.74,"z":-393.16},{"x":-302.47,"y":-67.68,"z":-392.25}]},{"lat":10.25,"lon":-52.1,"b":[{"x":-304.34,"y":-84.93,"z":-387.42},{"x":-305.65,"y":-88.69,"z":-385.54},{"x":-303.48,"y":-92.65,"z":-386.33},{"x":-299.97,"y":-92.91,"z":-388.99},{"x":-298.63,"y":-89.16,"z":-390.9},{"x":-300.82,"y":-85.14,"z":-390.11}]},{"lat":12.24,"lon":-52.1,"b":[{"x":-302.33,"y":-102.03,"z":-384.86},{"x":-303.56,"y":-105.7,"z":-382.9},{"x":-301.32,"y":-109.6,"z":-383.57},{"x":-297.82,"y":-109.9,"z":-386.2},{"x":-296.56,"y":-106.25,"z":-388.19},{"x":-298.83,"y":-102.29,"z":-387.52}]},{"lat":-5.21,"lon":-53.83,"b":[{"x":-294.9,"y":48.1,"z":-400.83},{"x":-296.29,"y":45.32,"z":-400.13},{"x":-295.2,"y":42.6,"z":-401.23},{"x":-292.69,"y":42.66,"z":-403.06},{"x":-291.28,"y":45.47,"z":-403.77},{"x":-292.4,"y":48.19,"z":-402.65}]},{"lat":-3.13,"lon":-53.83,"b":[{"x":-296.26,"y":31.34,"z":-401.47},{"x":-298.22,"y":27.24,"z":-400.31},{"x":-296.53,"y":23.2,"z":-401.82},{"x":-292.84,"y":23.24,"z":-404.51},{"x":-290.85,"y":27.37,"z":-405.69},{"x":-292.58,"y":31.43,"z":-404.15}]},{"lat":-1.04,"lon":-53.83,"b":[{"x":-296.74,"y":13.19,"z":-402.12},{"x":-298.62,"y":9.09,"z":-400.84},{"x":-296.83,"y":5.01,"z":-402.23},{"x":-293.14,"y":5.01,"z":-404.93},{"x":-291.24,"y":9.14,"z":-406.23},{"x":-293.05,"y":13.23,"z":-404.81}]},{"lat":1.04,"lon":-53.83,"b":[{"x":-296.83,"y":-5.01,"z":-402.23},{"x":-298.62,"y":-9.09,"z":-400.84},{"x":-296.74,"y":-13.19,"z":-402.12},{"x":-293.05,"y":-13.23,"z":-404.81},{"x":-291.24,"y":-9.14,"z":-406.23},{"x":-293.14,"y":-5.01,"z":-404.93}]},{"lat":3.13,"lon":-53.83,"b":[{"x":-296.53,"y":-23.2,"z":-401.82},{"x":-298.22,"y":-27.24,"z":-400.31},{"x":-296.26,"y":-31.34,"z":-401.47},{"x":-292.58,"y":-31.43,"z":-404.15},{"x":-290.85,"y":-27.37,"z":-405.69},{"x":-292.84,"y":-23.24,"z":-404.51}]},{"lat":5.21,"lon":-53.83,"b":[{"x":-295.83,"y":-41.29,"z":-400.88},{"x":-297.44,"y":-45.28,"z":-399.26},{"x":-295.39,"y":-49.37,"z":-400.29},{"x":-291.72,"y":-49.5,"z":-402.96},{"x":-290.08,"y":-45.5,"z":-404.61},{"x":-292.15,"y":-41.38,"z":-403.56}]},{"lat":7.27,"lon":-53.83,"b":[{"x":-294.76,"y":-59.22,"z":-399.42},{"x":-296.27,"y":-63.14,"z":-397.7},{"x":-294.15,"y":-67.2,"z":-398.61},{"x":-290.48,"y":-67.38,"z":-401.25},{"x":-288.93,"y":-63.45,"z":-403.01},{"x":-291.08,"y":-59.35,"z":-402.09}]},{"lat":9.32,"lon":-53.83,"b":[{"x":-293.31,"y":-76.92,"z":-397.46},{"x":-294.74,"y":-80.76,"z":-395.64},{"x":-292.55,"y":-84.78,"z":-396.43},{"x":-288.89,"y":-84.99,"z":-399.05},{"x":-287.43,"y":-81.15,"z":-400.91},{"x":-289.65,"y":-77.09,"z":-400.11}]},{"lat":11.34,"lon":-53.83,"b":[{"x":-291.52,"y":-94.33,"z":-395.03},{"x":-292.86,"y":-98.08,"z":-393.12},{"x":-290.6,"y":-102.04,"z":-393.79},{"x":-286.96,"y":-102.29,"z":-396.38},{"x":-285.57,"y":-98.55,"z":-398.33},{"x":-287.87,"y":-94.54,"z":-397.65}]},{"lat":13.34,"lon":-53.83,"b":[{"x":-289.39,"y":-111.39,"z":-392.14},{"x":-290.65,"y":-115.04,"z":-390.15},{"x":-288.32,"y":-118.92,"z":-390.72},{"x":-284.71,"y":-119.21,"z":-393.27},{"x":-283.4,"y":-115.58,"z":-395.29},{"x":-285.75,"y":-111.64,"z":-394.73}]},{"lat":-4.2,"lon":-55.59,"b":[{"x":-283.44,"y":40.69,"z":-409.8},{"x":-285.51,"y":36.57,"z":-408.75},{"x":-283.78,"y":32.51,"z":-410.29},{"x":-279.95,"y":32.58,"z":-412.9},{"x":-277.86,"y":36.73,"z":-413.97},{"x":-279.62,"y":40.8,"z":-412.4}]},{"lat":-2.11,"lon":-55.59,"b":[{"x":-284.09,"y":22.45,"z":-410.74},{"x":-286.08,"y":18.32,"z":-409.57},{"x":-284.27,"y":14.22,"z":-410.99},{"x":-280.44,"y":14.25,"z":-413.61},{"x":-278.42,"y":18.4,"z":-414.81},{"x":-280.27,"y":22.51,"z":-413.36}]},{"lat":0,"lon":-55.59,"b":[{"x":-284.37,"y":4.12,"z":-411.14},{"x":-286.27,"y":0,"z":-409.85},{"x":-284.37,"y":-4.12,"z":-411.14},{"x":-280.54,"y":-4.14,"z":-413.77},{"x":-278.61,"y":0,"z":-415.09},{"x":-280.54,"y":4.14,"z":-413.77}]},{"lat":2.11,"lon":-55.59,"b":[{"x":-284.27,"y":-14.22,"z":-410.99},{"x":-286.08,"y":-18.32,"z":-409.57},{"x":-284.09,"y":-22.45,"z":-410.74},{"x":-280.27,"y":-22.51,"z":-413.36},{"x":-278.42,"y":-18.4,"z":-414.81},{"x":-280.44,"y":-14.25,"z":-413.61}]},{"lat":4.2,"lon":-55.59,"b":[{"x":-283.78,"y":-32.51,"z":-410.29},{"x":-285.51,"y":-36.57,"z":-408.75},{"x":-283.44,"y":-40.69,"z":-409.8},{"x":-279.62,"y":-40.8,"z":-412.4},{"x":-277.86,"y":-36.73,"z":-413.97},{"x":-279.95,"y":-32.58,"z":-412.9}]},{"lat":6.29,"lon":-55.59,"b":[{"x":-282.92,"y":-50.67,"z":-409.04},{"x":-284.56,"y":-54.67,"z":-407.39},{"x":-282.41,"y":-58.77,"z":-408.31},{"x":-278.6,"y":-58.91,"z":-410.9},{"x":-276.93,"y":-54.91,"z":-412.58},{"x":-279.1,"y":-50.78,"z":-411.64}]},{"lat":8.36,"lon":-55.59,"b":[{"x":-281.69,"y":-68.63,"z":-407.26},{"x":-283.24,"y":-72.56,"z":-405.51},{"x":-281.02,"y":-76.62,"z":-406.31},{"x":-277.23,"y":-76.8,"z":-408.87},{"x":-275.64,"y":-72.88,"z":-410.66},{"x":-277.88,"y":-68.77,"z":-409.85}]},{"lat":10.41,"lon":-55.59,"b":[{"x":-280.11,"y":-86.33,"z":-404.98},{"x":-281.58,"y":-90.17,"z":-403.13},{"x":-279.29,"y":-94.18,"z":-403.8},{"x":-275.51,"y":-94.39,"z":-406.34},{"x":-274.01,"y":-90.56,"z":-408.22},{"x":-276.32,"y":-86.5,"z":-407.54}]},{"lat":12.44,"lon":-55.59,"b":[{"x":-278.2,"y":-103.69,"z":-402.22},{"x":-279.59,"y":-107.44,"z":-400.27},{"x":-277.23,"y":-111.38,"z":-400.83},{"x":-273.48,"y":-111.62,"z":-403.34},{"x":-272.05,"y":-107.89,"z":-405.31},{"x":-274.42,"y":-103.91,"z":-404.75}]},{"lat":14.43,"lon":-55.59,"b":[{"x":-275.98,"y":-120.68,"z":-399},{"x":-277.29,"y":-124.31,"z":-396.98},{"x":-274.88,"y":-128.17,"z":-397.43},{"x":-271.14,"y":-128.44,"z":-399.89},{"x":-269.79,"y":-124.83,"z":-401.94},{"x":-272.22,"y":-120.92,"z":-401.5}]},{"lat":-5.29,"lon":-57.38,"b":[{"x":-269.84,"y":49.53,"z":-417.93},{"x":-271.7,"y":45.99,"z":-417.13},{"x":-270.2,"y":42.5,"z":-418.47},{"x":-266.81,"y":42.57,"z":-420.63},{"x":-264.93,"y":46.14,"z":-421.44},{"x":-266.46,"y":49.62,"z":-420.08}]},{"lat":-3.18,"lon":-57.38,"b":[{"x":-270.9,"y":31.81,"z":-418.95},{"x":-273,"y":27.66,"z":-417.89},{"x":-271.15,"y":23.55,"z":-419.34},{"x":-267.19,"y":23.58,"z":-421.87},{"x":-265.08,"y":27.77,"z":-422.95},{"x":-266.95,"y":31.89,"z":-421.48}]},{"lat":-1.06,"lon":-57.38,"b":[{"x":-271.36,"y":13.39,"z":-419.65},{"x":-273.37,"y":9.23,"z":-418.46},{"x":-271.44,"y":5.09,"z":-419.78},{"x":-267.48,"y":5.09,"z":-422.32},{"x":-265.44,"y":9.27,"z":-423.53},{"x":-267.39,"y":13.43,"z":-422.19}]},{"lat":1.06,"lon":-57.38,"b":[{"x":-271.44,"y":-5.09,"z":-419.78},{"x":-273.37,"y":-9.23,"z":-418.46},{"x":-271.36,"y":-13.39,"z":-419.65},{"x":-267.39,"y":-13.43,"z":-422.19},{"x":-265.44,"y":-9.27,"z":-423.53},{"x":-267.48,"y":-5.09,"z":-422.32}]},{"lat":3.18,"lon":-57.38,"b":[{"x":-271.15,"y":-23.55,"z":-419.34},{"x":-273,"y":-27.66,"z":-417.89},{"x":-270.9,"y":-31.81,"z":-418.95},{"x":-266.95,"y":-31.89,"z":-421.48},{"x":-265.08,"y":-27.77,"z":-422.95},{"x":-267.19,"y":-23.58,"z":-421.87}]},{"lat":5.29,"lon":-57.38,"b":[{"x":-270.5,"y":-41.91,"z":-418.33},{"x":-272.26,"y":-45.97,"z":-416.76},{"x":-270.09,"y":-50.11,"z":-417.69},{"x":-266.14,"y":-50.22,"z":-420.2},{"x":-264.35,"y":-46.15,"z":-421.79},{"x":-266.54,"y":-41.98,"z":-420.85}]},{"lat":7.38,"lon":-57.38,"b":[{"x":-269.49,"y":-60.1,"z":-416.76},{"x":-271.16,"y":-64.1,"z":-415.08},{"x":-268.91,"y":-68.2,"z":-415.88},{"x":-264.98,"y":-68.34,"z":-418.37},{"x":-263.28,"y":-64.35,"z":-420.08},{"x":-265.54,"y":-60.21,"z":-419.27}]},{"lat":9.46,"lon":-57.38,"b":[{"x":-268.13,"y":-78.06,"z":-414.65},{"x":-269.72,"y":-81.98,"z":-412.87},{"x":-267.4,"y":-86.03,"z":-413.55},{"x":-263.49,"y":-86.2,"z":-416.01},{"x":-261.87,"y":-82.29,"z":-417.83},{"x":-264.2,"y":-78.2,"z":-417.15}]},{"lat":11.51,"lon":-57.38,"b":[{"x":-266.44,"y":-95.71,"z":-412.04},{"x":-267.94,"y":-99.54,"z":-410.15},{"x":-265.57,"y":-103.53,"z":-410.71},{"x":-261.68,"y":-103.73,"z":-413.15},{"x":-260.13,"y":-99.91,"z":-415.06},{"x":-262.52,"y":-95.88,"z":-414.51}]},{"lat":13.53,"lon":-57.38,"b":[{"x":-264.44,"y":-112.99,"z":-408.94},{"x":-265.86,"y":-116.72,"z":-406.97},{"x":-263.43,"y":-120.63,"z":-407.41},{"x":-259.56,"y":-120.86,"z":-409.81},{"x":-258.1,"y":-117.15,"z":-411.81},{"x":-260.54,"y":-113.2,"z":-411.38}]},{"lat":15.52,"lon":-57.38,"b":[{"x":-262.14,"y":-129.86,"z":-405.39},{"x":-263.49,"y":-133.48,"z":-403.34},{"x":-261.02,"y":-137.3,"z":-403.67},{"x":-257.18,"y":-137.55,"z":-406.04},{"x":-255.78,"y":-133.96,"z":-408.12},{"x":-258.27,"y":-130.09,"z":-407.8}]},{"lat":-6.37,"lon":-59.19,"b":[{"x":-256.22,"y":59.48,"z":-425.13},{"x":-258.44,"y":55.41,"z":-424.34},{"x":-256.69,"y":51.42,"z":-425.9},{"x":-252.68,"y":51.49,"z":-428.28},{"x":-250.44,"y":55.59,"z":-429.08},{"x":-252.22,"y":59.58,"z":-427.5}]},{"lat":-4.26,"lon":-59.19,"b":[{"x":-257.21,"y":41.24,"z":-426.69},{"x":-259.4,"y":37.07,"z":-425.75},{"x":-257.53,"y":32.95,"z":-427.22},{"x":-253.44,"y":32.99,"z":-429.65},{"x":-251.23,"y":37.19,"z":-430.6},{"x":-253.13,"y":41.31,"z":-429.12}]},{"lat":-2.13,"lon":-59.19,"b":[{"x":-257.82,"y":22.75,"z":-427.71},{"x":-259.93,"y":18.57,"z":-426.63},{"x":-257.98,"y":14.41,"z":-427.97},{"x":-253.89,"y":14.43,"z":-430.41},{"x":-251.75,"y":18.63,"z":-431.5},{"x":-253.73,"y":22.8,"z":-430.14}]},{"lat":0,"lon":-59.19,"b":[{"x":-258.08,"y":4.18,"z":-428.14},{"x":-260.11,"y":0,"z":-426.92},{"x":-258.08,"y":-4.18,"z":-428.14},{"x":-253.99,"y":-4.19,"z":-430.57},{"x":-251.93,"y":0,"z":-431.8},{"x":-253.99,"y":4.19,"z":-430.57}]},{"lat":2.13,"lon":-59.19,"b":[{"x":-257.98,"y":-14.41,"z":-427.97},{"x":-259.93,"y":-18.57,"z":-426.63},{"x":-257.82,"y":-22.75,"z":-427.71},{"x":-253.73,"y":-22.8,"z":-430.14},{"x":-251.75,"y":-18.63,"z":-431.5},{"x":-253.89,"y":-14.43,"z":-430.41}]},{"lat":4.26,"lon":-59.19,"b":[{"x":-257.53,"y":-32.95,"z":-427.22},{"x":-259.4,"y":-37.07,"z":-425.75},{"x":-257.21,"y":-41.24,"z":-426.69},{"x":-253.13,"y":-41.31,"z":-429.12},{"x":-251.23,"y":-37.19,"z":-430.6},{"x":-253.44,"y":-32.99,"z":-429.65}]},{"lat":6.37,"lon":-59.19,"b":[{"x":-256.72,"y":-51.34,"z":-425.89},{"x":-258.51,"y":-55.41,"z":-424.29},{"x":-256.25,"y":-59.55,"z":-425.11},{"x":-252.18,"y":-59.65,"z":-427.51},{"x":-250.37,"y":-55.59,"z":-429.12},{"x":-252.65,"y":-51.42,"z":-428.31}]},{"lat":8.47,"lon":-59.19,"b":[{"x":-255.58,"y":-69.53,"z":-423.99},{"x":-257.28,"y":-73.53,"z":-422.28},{"x":-254.96,"y":-77.62,"z":-422.96},{"x":-250.91,"y":-77.76,"z":-425.35},{"x":-249.17,"y":-73.77,"z":-427.08},{"x":-251.52,"y":-69.64,"z":-426.39}]},{"lat":10.55,"lon":-59.19,"b":[{"x":-254.11,"y":-87.45,"z":-421.55},{"x":-255.73,"y":-91.36,"z":-419.74},{"x":-253.34,"y":-95.39,"z":-420.29},{"x":-249.32,"y":-95.55,"z":-422.65},{"x":-247.66,"y":-91.65,"z":-424.48},{"x":-250.07,"y":-87.58,"z":-423.94}]},{"lat":12.6,"lon":-59.19,"b":[{"x":-252.33,"y":-105.02,"z":-418.6},{"x":-253.88,"y":-108.83,"z":-416.69},{"x":-251.43,"y":-112.79,"z":-417.12},{"x":-247.43,"y":-112.97,"z":-419.45},{"x":-245.85,"y":-109.18,"z":-421.38},{"x":-248.31,"y":-105.18,"z":-420.96}]},{"lat":14.61,"lon":-59.19,"b":[{"x":-250.27,"y":-122.19,"z":-415.17},{"x":-251.73,"y":-125.9,"z":-413.17},{"x":-249.24,"y":-129.77,"z":-413.49},{"x":-245.27,"y":-129.98,"z":-415.78},{"x":-243.76,"y":-126.29,"z":-417.8},{"x":-246.27,"y":-122.38,"z":-417.5}]},{"lat":16.59,"lon":-59.19,"b":[{"x":-247.93,"y":-138.92,"z":-411.29},{"x":-249.33,"y":-142.51,"z":-409.22},{"x":-246.79,"y":-146.28,"z":-409.42},{"x":-242.85,"y":-146.51,"z":-411.69},{"x":-241.42,"y":-142.94,"z":-413.78},{"x":-243.96,"y":-139.13,"z":-413.59}]},{"lat":-9.56,"lon":-61.02,"b":[{"x":-239.35,"y":84.14,"z":-430.82},{"x":-240.02,"y":83.01,"z":-430.67},{"x":-239.54,"y":81.91,"z":-431.14},{"x":-238.39,"y":81.94,"z":-431.78},{"x":-237.72,"y":83.07,"z":-431.93},{"x":-238.21,"y":84.17,"z":-431.45}]},{"lat":-7.46,"lon":-61.02,"b":[{"x":-241.86,"y":68.72,"z":-432.1},{"x":-244.05,"y":64.85,"z":-431.46},{"x":-242.35,"y":61.04,"z":-432.97},{"x":-238.43,"y":61.11,"z":-435.13},{"x":-236.22,"y":65.01,"z":-435.77},{"x":-237.95,"y":68.81,"z":-434.25}]},{"lat":-5.35,"lon":-61.02,"b":[{"x":-243.05,"y":50.68,"z":-433.91},{"x":-245.32,"y":46.51,"z":-433.1},{"x":-243.43,"y":42.38,"z":-434.59},{"x":-239.23,"y":42.43,"z":-436.91},{"x":-236.94,"y":46.63,"z":-437.73},{"x":-238.86,"y":50.75,"z":-436.22}]},{"lat":-3.21,"lon":-61.02,"b":[{"x":-243.8,"y":32.18,"z":-435.26},{"x":-246.01,"y":27.98,"z":-434.3},{"x":-244.03,"y":23.81,"z":-435.66},{"x":-239.82,"y":23.84,"z":-437.99},{"x":-237.6,"y":28.06,"z":-438.95},{"x":-239.6,"y":32.23,"z":-437.58}]},{"lat":-1.07,"lon":-61.02,"b":[{"x":-244.22,"y":13.54,"z":-436},{"x":-246.35,"y":9.34,"z":-434.91},{"x":-244.29,"y":5.15,"z":-436.14},{"x":-240.08,"y":5.15,"z":-438.47},{"x":-237.93,"y":9.37,"z":-439.57},{"x":-240.01,"y":13.57,"z":-438.33}]},{"lat":1.07,"lon":-61.02,"b":[{"x":-244.29,"y":-5.15,"z":-436.14},{"x":-246.35,"y":-9.34,"z":-434.91},{"x":-244.22,"y":-13.54,"z":-436},{"x":-240.01,"y":-13.57,"z":-438.33},{"x":-237.93,"y":-9.37,"z":-439.57},{"x":-240.08,"y":-5.15,"z":-438.47}]},{"lat":3.21,"lon":-61.02,"b":[{"x":-244.03,"y":-23.81,"z":-435.66},{"x":-246.01,"y":-27.98,"z":-434.3},{"x":-243.8,"y":-32.18,"z":-435.26},{"x":-239.6,"y":-32.23,"z":-437.58},{"x":-237.6,"y":-28.06,"z":-438.95},{"x":-239.82,"y":-23.84,"z":-437.99}]},{"lat":5.35,"lon":-61.02,"b":[{"x":-243.43,"y":-42.38,"z":-434.59},{"x":-245.32,"y":-46.51,"z":-433.1},{"x":-243.05,"y":-50.68,"z":-433.91},{"x":-238.86,"y":-50.75,"z":-436.22},{"x":-236.94,"y":-46.63,"z":-437.73},{"x":-239.23,"y":-42.43,"z":-436.91}]},{"lat":7.46,"lon":-61.02,"b":[{"x":-242.5,"y":-60.78,"z":-432.92},{"x":-244.31,"y":-64.84,"z":-431.31},{"x":-241.97,"y":-68.97,"z":-431.99},{"x":-237.8,"y":-69.07,"z":-434.28},{"x":-235.95,"y":-65.02,"z":-435.91},{"x":-238.31,"y":-60.85,"z":-435.23}]},{"lat":9.56,"lon":-61.02,"b":[{"x":-241.25,"y":-78.93,"z":-430.69},{"x":-242.98,"y":-82.91,"z":-428.96},{"x":-240.58,"y":-86.99,"z":-429.51},{"x":-236.43,"y":-87.11,"z":-431.78},{"x":-234.66,"y":-83.13,"z":-433.53},{"x":-237.08,"y":-79.02,"z":-432.98}]},{"lat":11.63,"lon":-61.02,"b":[{"x":-239.69,"y":-96.76,"z":-427.91},{"x":-241.35,"y":-100.66,"z":-426.08},{"x":-238.89,"y":-104.66,"z":-426.5},{"x":-234.77,"y":-104.8,"z":-428.75},{"x":-233.08,"y":-100.92,"z":-430.6},{"x":-235.54,"y":-96.88,"z":-430.18}]},{"lat":13.67,"lon":-61.02,"b":[{"x":-237.85,"y":-114.22,"z":-424.62},{"x":-239.43,"y":-118.01,"z":-422.7},{"x":-236.93,"y":-121.93,"z":-423},{"x":-232.83,"y":-122.09,"z":-425.22},{"x":-231.22,"y":-118.32,"z":-427.16},{"x":-233.73,"y":-114.36,"z":-426.87}]},{"lat":15.68,"lon":-61.02,"b":[{"x":-235.75,"y":-131.25,"z":-420.86},{"x":-237.25,"y":-134.93,"z":-418.85},{"x":-234.71,"y":-138.75,"z":-419.04},{"x":-230.65,"y":-138.93,"z":-421.22},{"x":-229.1,"y":-135.27,"z":-423.25},{"x":-231.65,"y":-131.41,"z":-423.08}]},{"lat":17.65,"lon":-61.02,"b":[{"x":-233.4,"y":-147.8,"z":-416.67},{"x":-234.83,"y":-151.36,"z":-414.58},{"x":-232.26,"y":-155.08,"z":-414.66},{"x":-228.23,"y":-155.27,"z":-416.81},{"x":-226.75,"y":-151.74,"z":-418.91},{"x":-229.34,"y":-147.98,"z":-418.85}]},{"lat":-10.64,"lon":-62.87,"b":[{"x":-224.31,"y":92.79,"z":-437.11},{"x":-224.6,"y":92.32,"z":-437.06},{"x":-224.39,"y":91.86,"z":-437.26},{"x":-223.9,"y":91.87,"z":-437.51},{"x":-223.61,"y":92.35,"z":-437.56},{"x":-223.82,"y":92.8,"z":-437.36}]},{"lat":-8.55,"lon":-62.87,"b":[{"x":-227.3,"y":78.34,"z":-438.32},{"x":-229.71,"y":74.23,"z":-437.77},{"x":-227.87,"y":70.17,"z":-439.4},{"x":-223.58,"y":70.24,"z":-441.58},{"x":-221.16,"y":74.38,"z":-442.12},{"x":-223.03,"y":78.42,"z":-440.48}]},{"lat":-6.43,"lon":-62.87,"b":[{"x":-228.47,"y":60.1,"z":-440.58},{"x":-230.83,"y":55.94,"z":-439.9},{"x":-228.91,"y":51.82,"z":-441.4},{"x":-224.61,"y":51.87,"z":-443.6},{"x":-222.24,"y":56.06,"z":-444.28},{"x":-224.19,"y":60.17,"z":-442.76}]},{"lat":-4.3,"lon":-62.87,"b":[{"x":-229.34,"y":41.62,"z":-442.26},{"x":-231.63,"y":37.43,"z":-441.44},{"x":-229.63,"y":33.25,"z":-442.81},{"x":-225.32,"y":33.28,"z":-445.02},{"x":-223.02,"y":37.5,"z":-445.84},{"x":-225.04,"y":41.67,"z":-444.45}]},{"lat":-2.15,"lon":-62.87,"b":[{"x":-229.9,"y":22.97,"z":-443.33},{"x":-232.12,"y":18.75,"z":-442.37},{"x":-230.05,"y":14.55,"z":-443.61},{"x":-225.73,"y":14.56,"z":-445.82},{"x":-223.49,"y":18.79,"z":-446.78},{"x":-225.59,"y":23,"z":-445.53}]},{"lat":0,"lon":-62.87,"b":[{"x":-230.13,"y":4.22,"z":-443.78},{"x":-232.29,"y":0,"z":-442.68},{"x":-230.13,"y":-4.22,"z":-443.78},{"x":-225.82,"y":-4.23,"z":-445.99},{"x":-223.65,"y":0,"z":-447.1},{"x":-225.82,"y":4.23,"z":-445.99}]},{"lat":2.15,"lon":-62.87,"b":[{"x":-230.05,"y":-14.55,"z":-443.61},{"x":-232.12,"y":-18.75,"z":-442.37},{"x":-229.9,"y":-22.97,"z":-443.33},{"x":-225.59,"y":-23,"z":-445.53},{"x":-223.49,"y":-18.79,"z":-446.78},{"x":-225.73,"y":-14.56,"z":-445.82}]},{"lat":4.3,"lon":-62.87,"b":[{"x":-229.63,"y":-33.25,"z":-442.81},{"x":-231.63,"y":-37.43,"z":-441.44},{"x":-229.34,"y":-41.62,"z":-442.26},{"x":-225.04,"y":-41.67,"z":-444.45},{"x":-223.02,"y":-37.5,"z":-445.84},{"x":-225.32,"y":-33.28,"z":-445.02}]},{"lat":6.43,"lon":-62.87,"b":[{"x":-228.91,"y":-51.82,"z":-441.4},{"x":-230.83,"y":-55.94,"z":-439.9},{"x":-228.47,"y":-60.1,"z":-440.58},{"x":-224.19,"y":-60.17,"z":-442.76},{"x":-222.24,"y":-56.06,"z":-444.28},{"x":-224.61,"y":-51.87,"z":-443.6}]},{"lat":8.55,"lon":-62.87,"b":[{"x":-227.87,"y":-70.17,"z":-439.4},{"x":-229.71,"y":-74.23,"z":-437.77},{"x":-227.3,"y":-78.34,"z":-438.32},{"x":-223.03,"y":-78.42,"z":-440.48},{"x":-221.16,"y":-74.38,"z":-442.12},{"x":-223.58,"y":-70.24,"z":-441.58}]},{"lat":10.64,"lon":-62.87,"b":[{"x":-226.53,"y":-88.24,"z":-436.83},{"x":-228.3,"y":-92.22,"z":-435.08},{"x":-225.84,"y":-96.26,"z":-435.5},{"x":-221.6,"y":-96.36,"z":-437.64},{"x":-219.8,"y":-92.41,"z":-439.4},{"x":-222.27,"y":-88.33,"z":-438.99}]},{"lat":12.71,"lon":-62.87,"b":[{"x":-224.92,"y":-105.96,"z":-433.71},{"x":-226.61,"y":-109.84,"z":-431.86},{"x":-224.1,"y":-113.8,"z":-432.15},{"x":-219.89,"y":-113.92,"z":-434.27},{"x":-218.17,"y":-110.06,"z":-436.13},{"x":-220.68,"y":-106.06,"z":-435.86}]},{"lat":14.74,"lon":-62.87,"b":[{"x":-223.04,"y":-123.27,"z":-430.09},{"x":-224.66,"y":-127.05,"z":-428.15},{"x":-222.11,"y":-130.91,"z":-428.32},{"x":-217.94,"y":-131.04,"z":-430.41},{"x":-216.28,"y":-127.3,"z":-432.37},{"x":-218.84,"y":-123.39,"z":-432.22}]},{"lat":16.73,"lon":-62.87,"b":[{"x":-220.93,"y":-140.12,"z":-426.01},{"x":-222.48,"y":-143.78,"z":-423.98},{"x":-219.89,"y":-147.54,"z":-424.04},{"x":-215.76,"y":-147.69,"z":-426.11},{"x":-214.17,"y":-144.06,"z":-428.14},{"x":-216.76,"y":-140.26,"z":-428.1}]},{"lat":18.69,"lon":-62.87,"b":[{"x":-218.59,"y":-156.47,"z":-421.5},{"x":-220.07,"y":-160.01,"z":-419.4},{"x":-217.46,"y":-163.65,"z":-419.36},{"x":-213.37,"y":-163.81,"z":-421.39},{"x":-211.85,"y":-160.31,"z":-423.5},{"x":-214.46,"y":-156.62,"z":-423.57}]},{"lat":-9.63,"lon":-64.73,"b":[{"x":-212,"y":86.97,"z":-444.32},{"x":-214.07,"y":83.55,"z":-443.98},{"x":-212.5,"y":80.16,"z":-445.36},{"x":-208.84,"y":80.2,"z":-447.08},{"x":-206.77,"y":83.65,"z":-447.42},{"x":-208.36,"y":87.02,"z":-446.03}]},{"lat":-7.52,"lon":-64.73,"b":[{"x":-213.54,"y":69.47,"z":-446.65},{"x":-215.96,"y":65.33,"z":-446.11},{"x":-214.01,"y":61.22,"z":-447.63},{"x":-209.63,"y":61.26,"z":-449.69},{"x":-207.21,"y":65.43,"z":-450.23},{"x":-209.17,"y":69.53,"z":-448.7}]},{"lat":-5.38,"lon":-64.73,"b":[{"x":-214.51,"y":51.05,"z":-448.67},{"x":-216.87,"y":46.86,"z":-447.99},{"x":-214.85,"y":42.69,"z":-449.37},{"x":-210.45,"y":42.72,"z":-451.45},{"x":-208.08,"y":46.93,"z":-452.13},{"x":-210.12,"y":51.09,"z":-450.73}]},{"lat":-3.24,"lon":-64.73,"b":[{"x":-215.18,"y":32.42,"z":-450.07},{"x":-217.48,"y":28.2,"z":-449.25},{"x":-215.39,"y":23.99,"z":-450.5},{"x":-210.98,"y":24,"z":-452.58},{"x":-208.67,"y":28.24,"z":-453.41},{"x":-210.78,"y":32.44,"z":-452.15}]},{"lat":-1.08,"lon":-64.73,"b":[{"x":-215.55,"y":13.65,"z":-450.85},{"x":-217.79,"y":9.41,"z":-449.89},{"x":-215.62,"y":5.18,"z":-451},{"x":-211.21,"y":5.18,"z":-453.08},{"x":-208.97,"y":9.43,"z":-454.05},{"x":-211.14,"y":13.66,"z":-452.93}]},{"lat":1.08,"lon":-64.73,"b":[{"x":-215.62,"y":-5.18,"z":-451},{"x":-217.79,"y":-9.41,"z":-449.89},{"x":-215.55,"y":-13.65,"z":-450.85},{"x":-211.14,"y":-13.66,"z":-452.93},{"x":-208.97,"y":-9.43,"z":-454.05},{"x":-211.21,"y":-5.18,"z":-453.08}]},{"lat":3.24,"lon":-64.73,"b":[{"x":-215.39,"y":-23.99,"z":-450.5},{"x":-217.48,"y":-28.2,"z":-449.25},{"x":-215.18,"y":-32.42,"z":-450.07},{"x":-210.78,"y":-32.44,"z":-452.15},{"x":-208.67,"y":-28.24,"z":-453.41},{"x":-210.98,"y":-24,"z":-452.58}]},{"lat":5.38,"lon":-64.73,"b":[{"x":-214.85,"y":-42.69,"z":-449.37},{"x":-216.87,"y":-46.86,"z":-447.99},{"x":-214.51,"y":-51.05,"z":-448.67},{"x":-210.12,"y":-51.09,"z":-450.73},{"x":-208.08,"y":-46.93,"z":-452.13},{"x":-210.45,"y":-42.72,"z":-451.45}]},{"lat":7.52,"lon":-64.73,"b":[{"x":-214.01,"y":-61.22,"z":-447.63},{"x":-215.96,"y":-65.33,"z":-446.11},{"x":-213.54,"y":-69.47,"z":-446.65},{"x":-209.17,"y":-69.53,"z":-448.7},{"x":-207.21,"y":-65.43,"z":-450.23},{"x":-209.63,"y":-61.26,"z":-449.69}]},{"lat":9.63,"lon":-64.73,"b":[{"x":-212.9,"y":-79.49,"z":-445.28},{"x":-214.77,"y":-83.53,"z":-443.64},{"x":-212.3,"y":-87.61,"z":-444.05},{"x":-207.95,"y":-87.68,"z":-446.08},{"x":-206.06,"y":-83.65,"z":-447.73},{"x":-208.53,"y":-79.55,"z":-447.34}]},{"lat":11.71,"lon":-64.73,"b":[{"x":-211.5,"y":-97.45,"z":-442.37},{"x":-213.3,"y":-101.4,"z":-440.62},{"x":-210.79,"y":-105.4,"z":-440.89},{"x":-206.47,"y":-105.48,"z":-442.91},{"x":-204.65,"y":-101.54,"z":-444.67},{"x":-207.16,"y":-97.51,"z":-444.41}]},{"lat":13.77,"lon":-64.73,"b":[{"x":-209.86,"y":-115.02,"z":-438.92},{"x":-211.58,"y":-118.87,"z":-437.07},{"x":-209.03,"y":-122.78,"z":-437.22},{"x":-204.75,"y":-122.87,"z":-439.21},{"x":-202.99,"y":-119.04,"z":-441.07},{"x":-205.55,"y":-115.09,"z":-440.94}]},{"lat":15.79,"lon":-64.73,"b":[{"x":-207.97,"y":-132.15,"z":-434.98},{"x":-209.63,"y":-135.89,"z":-433.03},{"x":-207.04,"y":-139.7,"z":-433.07},{"x":-202.81,"y":-139.79,"z":-435.03},{"x":-201.11,"y":-136.08,"z":-436.99},{"x":-203.7,"y":-132.24,"z":-436.98}]},{"lat":17.77,"lon":-64.73,"b":[{"x":-205.87,"y":-148.79,"z":-430.59},{"x":-207.46,"y":-152.42,"z":-428.55},{"x":-204.85,"y":-156.11,"z":-428.48},{"x":-200.66,"y":-156.22,"z":-430.42},{"x":-199.03,"y":-152.63,"z":-432.46},{"x":-201.64,"y":-148.89,"z":-432.55}]},{"lat":19.7,"lon":-64.73,"b":[{"x":-203.58,"y":-164.91,"z":-425.78},{"x":-205.1,"y":-168.41,"z":-423.68},{"x":-202.47,"y":-171.98,"z":-423.51},{"x":-198.33,"y":-172.1,"z":-425.42},{"x":-196.76,"y":-168.64,"z":-427.53},{"x":-199.38,"y":-165.02,"z":-427.72}]},{"lat":-8.59,"lon":-66.6,"b":[{"x":-198.31,"y":78.74,"z":-452.1},{"x":-200.78,"y":74.64,"z":-451.7},{"x":-198.82,"y":70.54,"z":-453.23},{"x":-194.36,"y":70.56,"z":-455.15},{"x":-191.89,"y":74.7,"z":-455.54},{"x":-193.88,"y":78.78,"z":-454.01}]},{"lat":-6.46,"lon":-66.6,"b":[{"x":-199.35,"y":60.42,"z":-454.46},{"x":-201.77,"y":56.25,"z":-453.92},{"x":-199.73,"y":52.09,"z":-455.32},{"x":-195.25,"y":52.11,"z":-457.25},{"x":-192.83,"y":56.3,"z":-457.78},{"x":-194.89,"y":60.45,"z":-456.38}]},{"lat":-4.32,"lon":-66.6,"b":[{"x":-200.12,"y":41.84,"z":-456.2},{"x":-202.48,"y":37.63,"z":-455.52},{"x":-200.37,"y":33.43,"z":-456.78},{"x":-195.88,"y":33.44,"z":-458.73},{"x":-193.52,"y":37.67,"z":-459.4},{"x":-195.64,"y":41.86,"z":-458.14}]},{"lat":-2.16,"lon":-66.6,"b":[{"x":-200.61,"y":23.09,"z":-457.32},{"x":-202.91,"y":18.86,"z":-456.5},{"x":-200.74,"y":14.62,"z":-457.61},{"x":-196.24,"y":14.63,"z":-459.56},{"x":-193.93,"y":18.87,"z":-460.38},{"x":-196.12,"y":23.1,"z":-459.26}]},{"lat":0,"lon":-66.6,"b":[{"x":-200.81,"y":4.24,"z":-457.79},{"x":-203.06,"y":0,"z":-456.82},{"x":-200.81,"y":-4.24,"z":-457.79},{"x":-196.32,"y":-4.25,"z":-459.74},{"x":-194.07,"y":0,"z":-460.71},{"x":-196.32,"y":4.25,"z":-459.74}]},{"lat":2.16,"lon":-66.6,"b":[{"x":-200.74,"y":-14.62,"z":-457.61},{"x":-202.91,"y":-18.86,"z":-456.5},{"x":-200.61,"y":-23.09,"z":-457.32},{"x":-196.12,"y":-23.1,"z":-459.26},{"x":-193.93,"y":-18.87,"z":-460.38},{"x":-196.24,"y":-14.63,"z":-459.56}]},{"lat":4.32,"lon":-66.6,"b":[{"x":-200.37,"y":-33.43,"z":-456.78},{"x":-202.48,"y":-37.63,"z":-455.52},{"x":-200.12,"y":-41.84,"z":-456.2},{"x":-195.64,"y":-41.86,"z":-458.14},{"x":-193.52,"y":-37.67,"z":-459.4},{"x":-195.88,"y":-33.44,"z":-458.73}]},{"lat":6.46,"lon":-66.6,"b":[{"x":-199.73,"y":-52.09,"z":-455.32},{"x":-201.77,"y":-56.25,"z":-453.92},{"x":-199.35,"y":-60.42,"z":-454.46},{"x":-194.89,"y":-60.45,"z":-456.38},{"x":-192.83,"y":-56.3,"z":-457.78},{"x":-195.25,"y":-52.11,"z":-457.25}]},{"lat":8.59,"lon":-66.6,"b":[{"x":-198.82,"y":-70.54,"z":-453.23},{"x":-200.78,"y":-74.64,"z":-451.7},{"x":-198.31,"y":-78.74,"z":-452.1},{"x":-193.88,"y":-78.78,"z":-454.01},{"x":-191.89,"y":-74.7,"z":-455.54},{"x":-194.36,"y":-70.56,"z":-455.15}]},{"lat":10.69,"lon":-66.6,"b":[{"x":-197.64,"y":-88.69,"z":-450.55},{"x":-199.54,"y":-92.72,"z":-448.9},{"x":-197.02,"y":-96.75,"z":-449.16},{"x":-192.62,"y":-96.79,"z":-451.06},{"x":-190.7,"y":-92.79,"z":-452.71},{"x":-193.21,"y":-88.73,"z":-452.46}]},{"lat":12.77,"lon":-66.6,"b":[{"x":-196.22,"y":-106.5,"z":-447.3},{"x":-198.04,"y":-110.43,"z":-445.54},{"x":-195.49,"y":-114.37,"z":-445.68},{"x":-191.12,"y":-114.42,"z":-447.55},{"x":-189.27,"y":-110.52,"z":-449.32},{"x":-191.81,"y":-106.54,"z":-449.2}]},{"lat":14.81,"lon":-66.6,"b":[{"x":-194.57,"y":-123.88,"z":-443.53},{"x":-196.32,"y":-127.71,"z":-441.67},{"x":-193.74,"y":-131.56,"z":-441.68},{"x":-189.41,"y":-131.61,"z":-443.54},{"x":-187.62,"y":-127.81,"z":-445.41},{"x":-190.19,"y":-123.93,"z":-445.41}]},{"lat":16.81,"lon":-66.6,"b":[{"x":-192.7,"y":-140.81,"z":-439.28},{"x":-194.39,"y":-144.52,"z":-437.32},{"x":-191.79,"y":-148.25,"z":-437.23},{"x":-187.5,"y":-148.31,"z":-439.06},{"x":-185.77,"y":-144.63,"z":-441.02},{"x":-188.37,"y":-140.86,"z":-441.14}]},{"lat":18.77,"lon":-66.6,"b":[{"x":-190.64,"y":-157.22,"z":-434.59},{"x":-192.27,"y":-160.81,"z":-432.55},{"x":-189.65,"y":-164.43,"z":-432.35},{"x":-185.41,"y":-164.49,"z":-434.16},{"x":-183.74,"y":-160.94,"z":-436.2},{"x":-186.35,"y":-157.28,"z":-436.42}]},{"lat":20.69,"lon":-66.6,"b":[{"x":-188.41,"y":-173.09,"z":-429.5},{"x":-189.98,"y":-176.55,"z":-427.4},{"x":-187.35,"y":-180.04,"z":-427.11},{"x":-183.16,"y":-180.11,"z":-428.89},{"x":-181.55,"y":-176.68,"z":-430.99},{"x":-184.17,"y":-173.15,"z":-431.31}]},{"lat":-17.81,"lon":-68.47,"b":[{"x":-174.94,"y":153.47,"z":-442.53},{"x":-175.32,"y":152.95,"z":-442.56},{"x":-175.07,"y":152.42,"z":-442.84},{"x":-174.45,"y":152.43,"z":-443.08},{"x":-174.07,"y":152.95,"z":-443.05},{"x":-174.33,"y":153.47,"z":-442.77}]},{"lat":-9.65,"lon":-68.47,"b":[{"x":-182.85,"y":87.88,"z":-456.91},{"x":-185.36,"y":83.82,"z":-456.66},{"x":-183.37,"y":79.74,"z":-458.19},{"x":-178.86,"y":79.74,"z":-459.97},{"x":-176.36,"y":83.83,"z":-460.21},{"x":-178.37,"y":87.89,"z":-458.67}]},{"lat":-7.54,"lon":-68.47,"b":[{"x":-183.93,"y":69.69,"z":-459.6},{"x":-186.4,"y":65.56,"z":-459.21},{"x":-184.34,"y":61.41,"z":-460.61},{"x":-179.81,"y":61.41,"z":-462.4},{"x":-177.35,"y":65.57,"z":-462.78},{"x":-179.42,"y":69.7,"z":-461.38}]},{"lat":-5.4,"lon":-68.47,"b":[{"x":-184.77,"y":51.21,"z":-461.69},{"x":-187.19,"y":47.02,"z":-461.16},{"x":-185.07,"y":42.83,"z":-462.42},{"x":-180.51,"y":42.83,"z":-464.22},{"x":-178.1,"y":47.03,"z":-464.74},{"x":-180.23,"y":51.22,"z":-463.48}]},{"lat":-3.25,"lon":-68.47,"b":[{"x":-185.35,"y":32.52,"z":-463.15},{"x":-187.72,"y":28.29,"z":-462.47},{"x":-185.53,"y":24.06,"z":-463.59},{"x":-180.97,"y":24.06,"z":-465.39},{"x":-178.61,"y":28.3,"z":-466.06},{"x":-180.8,"y":32.52,"z":-464.94}]},{"lat":-1.08,"lon":-68.47,"b":[{"x":-185.68,"y":13.69,"z":-463.95},{"x":-187.99,"y":9.44,"z":-463.13},{"x":-185.74,"y":5.2,"z":-464.1},{"x":-181.17,"y":5.2,"z":-465.9},{"x":-178.86,"y":9.45,"z":-466.73},{"x":-181.11,"y":13.69,"z":-465.75}]},{"lat":1.08,"lon":-68.47,"b":[{"x":-185.74,"y":-5.2,"z":-464.1},{"x":-187.99,"y":-9.44,"z":-463.13},{"x":-185.68,"y":-13.69,"z":-463.95},{"x":-181.11,"y":-13.69,"z":-465.75},{"x":-178.86,"y":-9.45,"z":-466.73},{"x":-181.17,"y":-5.2,"z":-465.9}]},{"lat":3.25,"lon":-68.47,"b":[{"x":-185.53,"y":-24.06,"z":-463.59},{"x":-187.72,"y":-28.29,"z":-462.47},{"x":-185.35,"y":-32.52,"z":-463.15},{"x":-180.8,"y":-32.52,"z":-464.94},{"x":-178.61,"y":-28.3,"z":-466.06},{"x":-180.97,"y":-24.06,"z":-465.39}]},{"lat":5.4,"lon":-68.47,"b":[{"x":-185.07,"y":-42.83,"z":-462.42},{"x":-187.19,"y":-47.02,"z":-461.16},{"x":-184.77,"y":-51.21,"z":-461.69},{"x":-180.23,"y":-51.22,"z":-463.48},{"x":-178.1,"y":-47.03,"z":-464.74},{"x":-180.51,"y":-42.83,"z":-464.22}]},{"lat":7.54,"lon":-68.47,"b":[{"x":-184.34,"y":-61.41,"z":-460.61},{"x":-186.4,"y":-65.56,"z":-459.21},{"x":-183.93,"y":-69.69,"z":-459.6},{"x":-179.42,"y":-69.7,"z":-461.38},{"x":-177.35,"y":-65.57,"z":-462.78},{"x":-179.81,"y":-61.41,"z":-462.4}]},{"lat":9.65,"lon":-68.47,"b":[{"x":-183.37,"y":-79.74,"z":-458.19},{"x":-185.36,"y":-83.82,"z":-456.66},{"x":-182.85,"y":-87.88,"z":-456.91},{"x":-178.37,"y":-87.89,"z":-458.67},{"x":-176.36,"y":-83.83,"z":-460.21},{"x":-178.86,"y":-79.74,"z":-459.97}]},{"lat":11.75,"lon":-68.47,"b":[{"x":-182.17,"y":-97.74,"z":-455.17},{"x":-184.09,"y":-101.74,"z":-453.52},{"x":-181.54,"y":-105.72,"z":-453.64},{"x":-177.09,"y":-105.73,"z":-455.39},{"x":-175.15,"y":-101.76,"z":-457.04},{"x":-177.68,"y":-97.75,"z":-456.94}]},{"lat":13.81,"lon":-68.47,"b":[{"x":-180.74,"y":-115.36,"z":-451.61},{"x":-182.6,"y":-119.26,"z":-449.84},{"x":-180.02,"y":-123.14,"z":-449.84},{"x":-175.61,"y":-123.16,"z":-451.58},{"x":-173.73,"y":-119.29,"z":-453.34},{"x":-176.29,"y":-115.37,"z":-453.36}]},{"lat":15.83,"lon":-68.47,"b":[{"x":-179.11,"y":-132.54,"z":-447.53},{"x":-180.9,"y":-136.33,"z":-445.66},{"x":-178.3,"y":-140.11,"z":-445.54},{"x":-173.93,"y":-140.12,"z":-447.26},{"x":-172.11,"y":-136.36,"z":-449.12},{"x":-174.69,"y":-132.55,"z":-449.26}]},{"lat":17.81,"lon":-68.47,"b":[{"x":-177.29,"y":-149.22,"z":-442.98},{"x":-179.02,"y":-152.9,"z":-441.02},{"x":-176.4,"y":-156.56,"z":-440.8},{"x":-172.08,"y":-156.57,"z":-442.5},{"x":-170.32,"y":-152.93,"z":-444.44},{"x":-172.92,"y":-149.24,"z":-444.7}]},{"lat":19.75,"lon":-68.47,"b":[{"x":-175.3,"y":-165.38,"z":-438.01},{"x":-176.97,"y":-168.93,"z":-435.97},{"x":-174.34,"y":-172.47,"z":-435.65},{"x":-170.07,"y":-172.48,"z":-437.33},{"x":-168.37,"y":-168.97,"z":-439.35},{"x":-170.98,"y":-165.39,"z":-439.71}]},{"lat":21.65,"lon":-68.47,"b":[{"x":-173.16,"y":-180.97,"z":-432.66},{"x":-174.77,"y":-184.4,"z":-430.56},{"x":-172.14,"y":-187.8,"z":-430.16},{"x":-167.92,"y":-187.82,"z":-431.81},{"x":-166.28,"y":-184.43,"z":-433.9},{"x":-168.89,"y":-180.99,"z":-434.34}]},{"lat":-18.79,"lon":-70.35,"b":[{"x":-160.61,"y":163.88,"z":-444.17},{"x":-162.71,"y":161.01,"z":-444.45},{"x":-161.3,"y":158.08,"z":-446.02},{"x":-157.76,"y":158.06,"z":-447.29},{"x":-155.68,"y":160.96,"z":-446.98},{"x":-157.12,"y":163.86,"z":-445.43}]},{"lat":-10.7,"lon":-70.35,"b":[{"x":-166.8,"y":95.99,"z":-461.41},{"x":-168.79,"y":92.84,"z":-461.33},{"x":-167.22,"y":89.65,"z":-462.53},{"x":-163.64,"y":89.64,"z":-463.81},{"x":-161.66,"y":92.81,"z":-463.88},{"x":-163.25,"y":95.97,"z":-462.68}]},{"lat":-8.6,"lon":-70.35,"b":[{"x":-168.32,"y":78.82,"z":-464.08},{"x":-170.82,"y":74.73,"z":-463.85},{"x":-168.75,"y":70.61,"z":-465.25},{"x":-164.17,"y":70.59,"z":-466.89},{"x":-161.69,"y":74.7,"z":-467.11},{"x":-163.77,"y":78.81,"z":-465.71}]},{"lat":-6.47,"lon":-70.35,"b":[{"x":-169.2,"y":60.48,"z":-466.51},{"x":-171.66,"y":56.33,"z":-466.13},{"x":-169.53,"y":52.14,"z":-467.4},{"x":-164.93,"y":52.13,"z":-469.04},{"x":-162.48,"y":56.3,"z":-469.41},{"x":-164.62,"y":60.47,"z":-468.15}]},{"lat":-4.32,"lon":-70.35,"b":[{"x":-169.86,"y":41.89,"z":-468.31},{"x":-172.27,"y":37.68,"z":-467.78},{"x":-170.08,"y":33.46,"z":-468.9},{"x":-165.46,"y":33.45,"z":-470.55},{"x":-163.06,"y":37.67,"z":-471.07},{"x":-165.26,"y":41.88,"z":-469.95}]},{"lat":-2.16,"lon":-70.35,"b":[{"x":-170.27,"y":23.12,"z":-469.46},{"x":-172.64,"y":18.88,"z":-468.78},{"x":-170.39,"y":14.64,"z":-469.76},{"x":-165.77,"y":14.63,"z":-471.41},{"x":-163.41,"y":18.87,"z":-472.08},{"x":-165.66,"y":23.11,"z":-471.1}]},{"lat":0,"lon":-70.35,"b":[{"x":-170.45,"y":4.25,"z":-469.94},{"x":-172.76,"y":0,"z":-469.12},{"x":-170.45,"y":-4.25,"z":-469.94},{"x":-165.83,"y":-4.25,"z":-471.59},{"x":-163.52,"y":0,"z":-472.42},{"x":-165.83,"y":4.25,"z":-471.59}]},{"lat":2.16,"lon":-70.35,"b":[{"x":-170.39,"y":-14.64,"z":-469.76},{"x":-172.64,"y":-18.88,"z":-468.78},{"x":-170.27,"y":-23.12,"z":-469.46},{"x":-165.66,"y":-23.11,"z":-471.1},{"x":-163.41,"y":-18.87,"z":-472.08},{"x":-165.77,"y":-14.63,"z":-471.41}]},{"lat":4.32,"lon":-70.35,"b":[{"x":-170.08,"y":-33.46,"z":-468.9},{"x":-172.27,"y":-37.68,"z":-467.78},{"x":-169.86,"y":-41.89,"z":-468.31},{"x":-165.26,"y":-41.88,"z":-469.95},{"x":-163.06,"y":-37.67,"z":-471.07},{"x":-165.46,"y":-33.45,"z":-470.55}]},{"lat":6.47,"lon":-70.35,"b":[{"x":-169.53,"y":-52.14,"z":-467.4},{"x":-171.66,"y":-56.33,"z":-466.13},{"x":-169.2,"y":-60.48,"z":-466.51},{"x":-164.62,"y":-60.47,"z":-468.15},{"x":-162.48,"y":-56.3,"z":-469.41},{"x":-164.93,"y":-52.13,"z":-469.04}]},{"lat":8.6,"lon":-70.35,"b":[{"x":-168.75,"y":-70.61,"z":-465.25},{"x":-170.82,"y":-74.73,"z":-463.85},{"x":-168.32,"y":-78.82,"z":-464.08},{"x":-163.77,"y":-78.81,"z":-465.71},{"x":-161.69,"y":-74.7,"z":-467.11},{"x":-164.17,"y":-70.59,"z":-466.89}]},{"lat":10.7,"lon":-70.35,"b":[{"x":-167.75,"y":-88.78,"z":-462.49},{"x":-169.76,"y":-92.84,"z":-460.96},{"x":-167.23,"y":-96.85,"z":-461.06},{"x":-162.7,"y":-96.83,"z":-462.68},{"x":-160.68,"y":-92.8,"z":-464.21},{"x":-163.2,"y":-88.76,"z":-464.12}]},{"lat":12.78,"lon":-70.35,"b":[{"x":-166.54,"y":-106.6,"z":-459.15},{"x":-168.49,"y":-110.57,"z":-457.5},{"x":-165.93,"y":-114.49,"z":-457.48},{"x":-161.44,"y":-114.46,"z":-459.09},{"x":-159.48,"y":-110.52,"z":-460.73},{"x":-162.02,"y":-106.58,"z":-460.77}]},{"lat":14.82,"lon":-70.35,"b":[{"x":-165.14,"y":-124,"z":-455.28},{"x":-167.02,"y":-127.87,"z":-453.52},{"x":-164.44,"y":-131.68,"z":-453.37},{"x":-159.99,"y":-131.66,"z":-454.97},{"x":-158.09,"y":-127.82,"z":-456.72},{"x":-160.65,"y":-123.98,"z":-456.88}]},{"lat":16.82,"lon":-70.35,"b":[{"x":-163.55,"y":-140.94,"z":-450.9},{"x":-165.37,"y":-144.7,"z":-449.04},{"x":-162.77,"y":-148.4,"z":-448.79},{"x":-158.38,"y":-148.37,"z":-450.37},{"x":-156.53,"y":-144.64,"z":-452.22},{"x":-159.11,"y":-140.91,"z":-452.5}]},{"lat":18.79,"lon":-70.35,"b":[{"x":-161.01,"y":-158.48,"z":-445.99},{"x":-162.23,"y":-161.01,"z":-444.64},{"x":-160.42,"y":-163.49,"z":-444.39},{"x":-157.41,"y":-163.47,"z":-445.48},{"x":-156.16,"y":-160.97,"z":-446.82},{"x":-157.96,"y":-158.46,"z":-447.09}]},{"lat":20.7,"lon":-70.35,"b":[{"x":-158.59,"y":-175.04,"z":-440.65},{"x":-159.42,"y":-176.77,"z":-439.66},{"x":-158.14,"y":-178.46,"z":-439.44},{"x":-156.03,"y":-178.44,"z":-440.2},{"x":-155.18,"y":-176.74,"z":-441.18},{"x":-156.45,"y":-175.02,"z":-441.42}]},{"lat":22.58,"lon":-70.35,"b":[{"x":-156.59,"y":-190.25,"z":-435.03},{"x":-157.41,"y":-191.94,"z":-433.98},{"x":-156.1,"y":-193.6,"z":-433.72},{"x":-153.99,"y":-193.58,"z":-434.49},{"x":-153.15,"y":-191.91,"z":-435.52},{"x":-154.44,"y":-190.23,"z":-435.8}]},{"lat":-19.73,"lon":-72.22,"b":[{"x":-144.29,"y":169.88,"z":-447.55},{"x":-145.09,"y":168.79,"z":-447.7},{"x":-144.53,"y":167.67,"z":-448.3},{"x":-143.16,"y":167.65,"z":-448.75},{"x":-142.36,"y":168.74,"z":-448.59},{"x":-142.93,"y":169.85,"z":-447.99}]},{"lat":-17.79,"lon":-72.22,"b":[{"x":-146.32,"y":154.62,"z":-452.37},{"x":-147.64,"y":152.78,"z":-452.57},{"x":-146.7,"y":150.88,"z":-453.51},{"x":-144.43,"y":150.85,"z":-454.25},{"x":-143.13,"y":152.7,"z":-454.04},{"x":-144.08,"y":154.58,"z":-453.11}]},{"lat":-11.73,"lon":-72.22,"b":[{"x":-150.4,"y":103.41,"z":-465.45},{"x":-151.53,"y":101.65,"z":-465.47},{"x":-150.63,"y":99.86,"z":-466.15},{"x":-148.59,"y":99.83,"z":-466.81},{"x":-147.47,"y":101.6,"z":-466.79},{"x":-148.37,"y":103.39,"z":-466.11}]},{"lat":-9.64,"lon":-72.22,"b":[{"x":-151.7,"y":86.02,"z":-468.55},{"x":-153.11,"y":83.75,"z":-468.5},{"x":-151.94,"y":81.43,"z":-469.29},{"x":-149.35,"y":81.41,"z":-470.12},{"x":-147.94,"y":83.7,"z":-470.17},{"x":-149.12,"y":85.99,"z":-469.38}]},{"lat":-7.53,"lon":-72.22,"b":[{"x":-153.49,"y":69.62,"z":-470.65},{"x":-155.98,"y":65.51,"z":-470.43},{"x":-153.84,"y":61.34,"z":-471.69},{"x":-149.21,"y":61.31,"z":-473.18},{"x":-146.74,"y":65.44,"z":-473.4},{"x":-148.88,"y":69.58,"z":-472.14}]},{"lat":-5.39,"lon":-72.22,"b":[{"x":-154.19,"y":51.16,"z":-472.79},{"x":-156.64,"y":46.99,"z":-472.41},{"x":-154.44,"y":42.78,"z":-473.54},{"x":-149.79,"y":42.76,"z":-475.03},{"x":-147.36,"y":46.94,"z":-475.4},{"x":-149.56,"y":51.13,"z":-474.28}]},{"lat":-3.24,"lon":-72.22,"b":[{"x":-154.67,"y":32.49,"z":-474.28},{"x":-157.08,"y":28.27,"z":-473.76},{"x":-154.83,"y":24.03,"z":-474.73},{"x":-150.17,"y":24.02,"z":-476.22},{"x":-147.78,"y":28.24,"z":-476.74},{"x":-150.03,"y":32.47,"z":-475.77}]},{"lat":-1.08,"lon":-72.22,"b":[{"x":-154.94,"y":13.68,"z":-475.1},{"x":-157.3,"y":9.44,"z":-474.43},{"x":-155,"y":5.19,"z":-475.25},{"x":-150.34,"y":5.19,"z":-476.75},{"x":-147.99,"y":9.43,"z":-477.42},{"x":-150.29,"y":13.67,"z":-476.6}]},{"lat":1.08,"lon":-72.22,"b":[{"x":-155,"y":-5.19,"z":-475.25},{"x":-157.3,"y":-9.44,"z":-474.43},{"x":-154.94,"y":-13.68,"z":-475.1},{"x":-150.29,"y":-13.67,"z":-476.6},{"x":-147.99,"y":-9.43,"z":-477.42},{"x":-150.34,"y":-5.19,"z":-476.75}]},{"lat":3.24,"lon":-72.22,"b":[{"x":-154.83,"y":-24.03,"z":-474.73},{"x":-157.08,"y":-28.27,"z":-473.76},{"x":-154.67,"y":-32.49,"z":-474.28},{"x":-150.03,"y":-32.47,"z":-475.77},{"x":-147.78,"y":-28.24,"z":-476.74},{"x":-150.17,"y":-24.02,"z":-476.22}]},{"lat":5.39,"lon":-72.22,"b":[{"x":-154.44,"y":-42.78,"z":-473.54},{"x":-156.64,"y":-46.99,"z":-472.41},{"x":-154.19,"y":-51.16,"z":-472.79},{"x":-149.56,"y":-51.13,"z":-474.28},{"x":-147.36,"y":-46.94,"z":-475.4},{"x":-149.79,"y":-42.76,"z":-475.03}]},{"lat":7.53,"lon":-72.22,"b":[{"x":-153.84,"y":-61.34,"z":-471.69},{"x":-155.98,"y":-65.51,"z":-470.43},{"x":-153.49,"y":-69.62,"z":-470.65},{"x":-148.88,"y":-69.58,"z":-472.14},{"x":-146.74,"y":-65.44,"z":-473.4},{"x":-149.21,"y":-61.31,"z":-473.18}]},{"lat":9.64,"lon":-72.22,"b":[{"x":-153.03,"y":-79.65,"z":-469.21},{"x":-155.11,"y":-83.75,"z":-467.81},{"x":-152.59,"y":-87.79,"z":-467.9},{"x":-148.02,"y":-87.74,"z":-469.38},{"x":-145.93,"y":-83.67,"z":-470.77},{"x":-148.42,"y":-79.61,"z":-470.69}]},{"lat":11.73,"lon":-72.22,"b":[{"x":-152.02,"y":-97.64,"z":-466.13},{"x":-154.05,"y":-101.66,"z":-464.6},{"x":-151.5,"y":-105.61,"z":-464.56},{"x":-146.96,"y":-105.55,"z":-466.03},{"x":-144.93,"y":-101.56,"z":-467.55},{"x":-147.45,"y":-97.59,"z":-467.61}]},{"lat":13.79,"lon":-72.22,"b":[{"x":-150.84,"y":-115.24,"z":-462.49},{"x":-152.8,"y":-119.17,"z":-460.84},{"x":-150.23,"y":-123.02,"z":-460.68},{"x":-145.73,"y":-122.95,"z":-462.14},{"x":-143.76,"y":-119.05,"z":-463.77},{"x":-146.3,"y":-115.18,"z":-463.96}]},{"lat":15.81,"lon":-72.22,"b":[{"x":-149.48,"y":-132.4,"z":-458.32},{"x":-151.38,"y":-136.23,"z":-456.56},{"x":-148.8,"y":-139.96,"z":-456.28},{"x":-144.35,"y":-139.89,"z":-457.74},{"x":-142.42,"y":-136.1,"z":-459.48},{"x":-144.98,"y":-132.33,"z":-459.78}]},{"lat":17.79,"lon":-72.22,"b":[{"x":-145.76,"y":-152.23,"z":-453.39},{"x":-146.03,"y":-152.77,"z":-453.13},{"x":-145.66,"y":-153.28,"z":-453.07},{"x":-145.03,"y":-153.27,"z":-453.28},{"x":-144.76,"y":-152.74,"z":-453.54},{"x":-145.12,"y":-152.22,"z":-453.6}]},{"lat":-18.72,"lon":-74.08,"b":[{"x":-130.13,"y":161.05,"z":-455.1},{"x":-130.52,"y":160.52,"z":-455.17},{"x":-130.24,"y":159.96,"z":-455.45},{"x":-129.56,"y":159.94,"z":-455.65},{"x":-129.18,"y":160.48,"z":-455.57},{"x":-129.47,"y":161.03,"z":-455.3}]},{"lat":-10.66,"lon":-74.08,"b":[{"x":-136.07,"y":95.11,"z":-471.58},{"x":-137.69,"y":92.56,"z":-471.61},{"x":-136.35,"y":89.94,"z":-472.51},{"x":-133.38,"y":89.9,"z":-473.36},{"x":-131.78,"y":92.46,"z":-473.32},{"x":-133.12,"y":95.06,"z":-472.43}]},{"lat":-8.57,"lon":-74.08,"b":[{"x":-137.7,"y":78.58,"z":-474.12},{"x":-140.19,"y":74.52,"z":-474.04},{"x":-138.05,"y":70.38,"z":-475.3},{"x":-133.41,"y":70.33,"z":-476.63},{"x":-130.94,"y":74.4,"z":-476.7},{"x":-133.08,"y":78.51,"z":-475.44}]},{"lat":-6.45,"lon":-74.08,"b":[{"x":-138.41,"y":60.29,"z":-476.58},{"x":-140.88,"y":56.16,"z":-476.36},{"x":-138.68,"y":51.97,"z":-477.48},{"x":-134.02,"y":51.94,"z":-478.81},{"x":-131.58,"y":56.07,"z":-479.02},{"x":-133.77,"y":60.24,"z":-477.91}]},{"lat":-4.31,"lon":-74.08,"b":[{"x":-138.95,"y":41.76,"z":-478.4},{"x":-141.38,"y":37.58,"z":-478.04},{"x":-139.13,"y":33.35,"z":-479.01},{"x":-134.45,"y":33.33,"z":-480.34},{"x":-132.04,"y":37.51,"z":-480.71},{"x":-134.28,"y":41.72,"z":-479.74}]},{"lat":-2.16,"lon":-74.08,"b":[{"x":-139.29,"y":23.05,"z":-479.57},{"x":-141.68,"y":18.83,"z":-479.05},{"x":-139.38,"y":14.59,"z":-479.87},{"x":-134.69,"y":14.58,"z":-481.21},{"x":-132.32,"y":18.8,"z":-481.72},{"x":-134.61,"y":23.02,"z":-480.9}]},{"lat":0,"lon":-74.08,"b":[{"x":-139.43,"y":4.24,"z":-480.06},{"x":-141.78,"y":0,"z":-479.39},{"x":-139.43,"y":-4.24,"z":-480.06},{"x":-134.75,"y":-4.23,"z":-481.4},{"x":-132.41,"y":0,"z":-482.06},{"x":-134.75,"y":4.23,"z":-481.4}]},{"lat":2.16,"lon":-74.08,"b":[{"x":-139.38,"y":-14.59,"z":-479.87},{"x":-141.68,"y":-18.83,"z":-479.05},{"x":-139.29,"y":-23.05,"z":-479.57},{"x":-134.61,"y":-23.02,"z":-480.9},{"x":-132.32,"y":-18.8,"z":-481.72},{"x":-134.69,"y":-14.58,"z":-481.21}]},{"lat":4.31,"lon":-74.08,"b":[{"x":-139.13,"y":-33.35,"z":-479.01},{"x":-141.38,"y":-37.58,"z":-478.04},{"x":-138.95,"y":-41.76,"z":-478.4},{"x":-134.28,"y":-41.72,"z":-479.74},{"x":-132.04,"y":-37.51,"z":-480.71},{"x":-134.45,"y":-33.33,"z":-480.34}]},{"lat":6.45,"lon":-74.08,"b":[{"x":-138.68,"y":-51.97,"z":-477.48},{"x":-140.88,"y":-56.16,"z":-476.36},{"x":-138.41,"y":-60.29,"z":-476.58},{"x":-133.77,"y":-60.24,"z":-477.91},{"x":-131.58,"y":-56.07,"z":-479.02},{"x":-134.02,"y":-51.94,"z":-478.81}]},{"lat":8.57,"lon":-74.08,"b":[{"x":-138.05,"y":-70.38,"z":-475.3},{"x":-140.19,"y":-74.52,"z":-474.04},{"x":-137.7,"y":-78.58,"z":-474.12},{"x":-133.08,"y":-78.51,"z":-475.44},{"x":-130.94,"y":-74.4,"z":-476.7},{"x":-133.41,"y":-70.33,"z":-476.63}]},{"lat":10.66,"lon":-74.08,"b":[{"x":-137.24,"y":-88.5,"z":-472.5},{"x":-139.33,"y":-92.58,"z":-471.1},{"x":-136.81,"y":-96.55,"z":-471.05},{"x":-132.22,"y":-96.46,"z":-472.37},{"x":-130.13,"y":-92.42,"z":-473.76},{"x":-132.62,"y":-88.43,"z":-473.83}]},{"lat":12.73,"lon":-74.08,"b":[{"x":-136.25,"y":-106.27,"z":-469.11},{"x":-138.29,"y":-110.26,"z":-467.59},{"x":-135.75,"y":-114.14,"z":-467.41},{"x":-131.2,"y":-114.04,"z":-468.73},{"x":-129.16,"y":-110.08,"z":-470.24},{"x":-131.67,"y":-106.19,"z":-470.44}]},{"lat":14.77,"lon":-74.08,"b":[{"x":-135.11,"y":-123.63,"z":-465.17},{"x":-137.09,"y":-127.53,"z":-463.54},{"x":-134.54,"y":-131.29,"z":-463.24},{"x":-130.04,"y":-131.18,"z":-464.55},{"x":-128.05,"y":-127.32,"z":-466.17},{"x":-130.57,"y":-123.53,"z":-466.49}]},{"lat":16.77,"lon":-74.08,"b":[{"x":-131.89,"y":-143.34,"z":-460.47},{"x":-132.36,"y":-144.26,"z":-460.05},{"x":-131.74,"y":-145.14,"z":-459.95},{"x":-130.67,"y":-145.11,"z":-460.27},{"x":-130.2,"y":-144.2,"z":-460.69},{"x":-130.81,"y":-143.32,"z":-460.79}]},{"lat":-19.63,"lon":-75.94,"b":[{"x":-115.57,"y":170.13,"z":-455.69},{"x":-117.13,"y":168.02,"z":-456.07},{"x":-115.96,"y":165.77,"z":-457.19},{"x":-113.22,"y":165.67,"z":-457.92},{"x":-111.69,"y":167.8,"z":-457.52},{"x":-112.86,"y":170.02,"z":-456.41}]},{"lat":-9.59,"lon":-75.94,"b":[{"x":-120.61,"y":84.87,"z":-477.72},{"x":-121.59,"y":83.3,"z":-477.75},{"x":-120.74,"y":81.69,"z":-478.24},{"x":-118.92,"y":81.65,"z":-478.7},{"x":-117.95,"y":83.23,"z":-478.67},{"x":-118.79,"y":84.83,"z":-478.18}]},{"lat":-7.48,"lon":-75.94,"b":[{"x":-122.61,"y":69.25,"z":-479.68},{"x":-125.08,"y":65.18,"z":-479.61},{"x":-122.88,"y":61.02,"z":-480.73},{"x":-118.22,"y":60.95,"z":-481.9},{"x":-115.77,"y":65.03,"z":-481.96},{"x":-117.97,"y":69.17,"z":-480.86}]},{"lat":-5.36,"lon":-75.94,"b":[{"x":-123.16,"y":50.89,"z":-481.83},{"x":-125.6,"y":46.75,"z":-481.62},{"x":-123.35,"y":42.55,"z":-482.59},{"x":-118.67,"y":42.51,"z":-483.77},{"x":-116.26,"y":46.65,"z":-483.97},{"x":-118.49,"y":50.83,"z":-483.01}]},{"lat":-3.22,"lon":-75.94,"b":[{"x":-123.54,"y":32.32,"z":-483.33},{"x":-125.95,"y":28.13,"z":-482.97},{"x":-123.66,"y":23.9,"z":-483.79},{"x":-118.97,"y":23.88,"z":-484.97},{"x":-116.58,"y":28.07,"z":-485.33},{"x":-118.86,"y":32.27,"z":-484.51}]},{"lat":-1.08,"lon":-75.94,"b":[{"x":-123.75,"y":13.61,"z":-484.17},{"x":-126.13,"y":9.39,"z":-483.65},{"x":-123.8,"y":5.16,"z":-484.32},{"x":-119.1,"y":5.16,"z":-485.5},{"x":-116.75,"y":9.37,"z":-486.01},{"x":-119.06,"y":13.58,"z":-485.34}]},{"lat":1.08,"lon":-75.94,"b":[{"x":-123.8,"y":-5.16,"z":-484.32},{"x":-126.13,"y":-9.39,"z":-483.65},{"x":-123.75,"y":-13.61,"z":-484.17},{"x":-119.06,"y":-13.58,"z":-485.34},{"x":-116.75,"y":-9.37,"z":-486.01},{"x":-119.1,"y":-5.16,"z":-485.5}]},{"lat":3.22,"lon":-75.94,"b":[{"x":-123.66,"y":-23.9,"z":-483.79},{"x":-125.95,"y":-28.13,"z":-482.97},{"x":-123.54,"y":-32.32,"z":-483.33},{"x":-118.86,"y":-32.27,"z":-484.51},{"x":-116.58,"y":-28.07,"z":-485.33},{"x":-118.97,"y":-23.88,"z":-484.97}]},{"lat":5.36,"lon":-75.94,"b":[{"x":-123.35,"y":-42.55,"z":-482.59},{"x":-125.6,"y":-46.75,"z":-481.62},{"x":-123.16,"y":-50.89,"z":-481.83},{"x":-118.49,"y":-50.83,"z":-483.01},{"x":-116.26,"y":-46.65,"z":-483.97},{"x":-118.67,"y":-42.51,"z":-483.77}]},{"lat":7.48,"lon":-75.94,"b":[{"x":-122.88,"y":-61.02,"z":-480.73},{"x":-125.08,"y":-65.18,"z":-479.61},{"x":-122.61,"y":-69.25,"z":-479.68},{"x":-117.97,"y":-69.17,"z":-480.86},{"x":-115.77,"y":-65.03,"z":-481.96},{"x":-118.22,"y":-60.95,"z":-481.9}]},{"lat":9.59,"lon":-75.94,"b":[{"x":-122.24,"y":-79.23,"z":-478.23},{"x":-124.39,"y":-83.34,"z":-476.97},{"x":-121.89,"y":-87.34,"z":-476.9},{"x":-117.29,"y":-87.23,"z":-478.08},{"x":-115.14,"y":-83.16,"z":-479.32},{"x":-117.6,"y":-79.15,"z":-479.4}]},{"lat":11.66,"lon":-75.94,"b":[{"x":-121.45,"y":-97.13,"z":-475.12},{"x":-123.54,"y":-101.17,"z":-473.73},{"x":-121.03,"y":-105.07,"z":-473.53},{"x":-116.46,"y":-104.95,"z":-474.71},{"x":-114.36,"y":-100.95,"z":-476.08},{"x":-116.84,"y":-97.03,"z":-476.29}]},{"lat":13.71,"lon":-75.94,"b":[{"x":-120.24,"y":-115.06,"z":-471.42},{"x":-122.07,"y":-118.6,"z":-470.07},{"x":-119.81,"y":-121.99,"z":-469.78},{"x":-115.77,"y":-121.86,"z":-470.83},{"x":-113.93,"y":-118.37,"z":-472.16},{"x":-116.16,"y":-114.96,"z":-472.46}]},{"lat":15.72,"lon":-75.94,"b":[{"x":-117.33,"y":-134.89,"z":-466.93},{"x":-117.65,"y":-135.51,"z":-466.67},{"x":-117.24,"y":-136.1,"z":-466.6},{"x":-116.52,"y":-136.08,"z":-466.79},{"x":-116.19,"y":-135.46,"z":-467.05},{"x":-116.6,"y":-134.86,"z":-467.12}]},{"lat":-25.91,"lon":-77.78,"b":[{"x":-95.37,"y":218.83,"z":-439.33},{"x":-95.63,"y":218.51,"z":-439.43},{"x":-95.44,"y":218.17,"z":-439.64},{"x":-94.99,"y":218.14,"z":-439.75},{"x":-94.73,"y":218.46,"z":-439.65},{"x":-94.92,"y":218.8,"z":-439.44}]},{"lat":-24.15,"lon":-77.78,"b":[{"x":-97.15,"y":205.67,"z":-445.24},{"x":-97.96,"y":204.66,"z":-445.52},{"x":-97.36,"y":203.56,"z":-446.16},{"x":-95.94,"y":203.48,"z":-446.51},{"x":-95.15,"y":204.5,"z":-446.21},{"x":-95.75,"y":205.59,"z":-445.58}]},{"lat":-20.49,"lon":-77.78,"b":[{"x":-100.31,"y":177.23,"z":-456.6},{"x":-101.86,"y":175.15,"z":-457.06},{"x":-100.67,"y":172.9,"z":-458.18},{"x":-97.91,"y":172.76,"z":-458.82},{"x":-96.39,"y":174.86,"z":-458.35},{"x":-97.59,"y":177.08,"z":-457.25}]},{"lat":-8.5,"lon":-77.78,"b":[{"x":-105.94,"y":76.34,"z":-482.59},{"x":-107.4,"y":73.97,"z":-482.64},{"x":-106.1,"y":71.52,"z":-483.3},{"x":-103.35,"y":71.47,"z":-483.9},{"x":-101.92,"y":73.85,"z":-483.85},{"x":-103.21,"y":76.27,"z":-483.2}]},{"lat":-6.4,"lon":-77.78,"b":[{"x":-106.27,"y":57.78,"z":-485.1},{"x":-107.48,"y":55.74,"z":-485.07},{"x":-106.37,"y":53.65,"z":-485.55},{"x":-104.04,"y":53.62,"z":-486.06},{"x":-102.84,"y":55.66,"z":-486.09},{"x":-103.95,"y":57.73,"z":-485.61}]},{"lat":-4.27,"lon":-77.78,"b":[{"x":-106.25,"y":38.61,"z":-487.02},{"x":-107.03,"y":37.28,"z":-486.95},{"x":-106.3,"y":35.93,"z":-487.22},{"x":-104.79,"y":35.91,"z":-487.54},{"x":-104.02,"y":37.25,"z":-487.61},{"x":-104.75,"y":38.59,"z":-487.35}]},{"lat":-2.14,"lon":-77.78,"b":[{"x":-107.67,"y":22.2,"z":-487.69},{"x":-109.68,"y":18.69,"z":-487.39},{"x":-107.73,"y":15.15,"z":-487.95},{"x":-103.8,"y":15.14,"z":-488.8},{"x":-101.82,"y":18.64,"z":-489.1},{"x":-103.74,"y":22.17,"z":-488.54}]},{"lat":0,"lon":-77.78,"b":[{"x":-108.15,"y":4.21,"z":-488.06},{"x":-110.51,"y":0,"z":-487.55},{"x":-108.15,"y":-4.21,"z":-488.06},{"x":-103.46,"y":-4.19,"z":-489.08},{"x":-101.13,"y":0,"z":-489.58},{"x":-103.46,"y":4.19,"z":-489.08}]},{"lat":2.14,"lon":-77.78,"b":[{"x":-108.11,"y":-14.48,"z":-487.87},{"x":-110.43,"y":-18.69,"z":-487.21},{"x":-108.04,"y":-22.88,"z":-487.57},{"x":-103.36,"y":-22.84,"z":-488.59},{"x":-101.06,"y":-18.64,"z":-489.24},{"x":-103.42,"y":-14.46,"z":-488.89}]},{"lat":4.27,"lon":-77.78,"b":[{"x":-107.92,"y":-33.1,"z":-487.01},{"x":-110.2,"y":-37.31,"z":-486.19},{"x":-107.78,"y":-41.45,"z":-486.4},{"x":-103.12,"y":-41.38,"z":-487.42},{"x":-100.85,"y":-37.2,"z":-488.23},{"x":-103.24,"y":-33.06,"z":-488.03}]},{"lat":6.4,"lon":-77.78,"b":[{"x":-107.58,"y":-51.59,"z":-485.47},{"x":-109.82,"y":-55.77,"z":-484.51},{"x":-107.38,"y":-59.85,"z":-484.57},{"x":-102.73,"y":-59.76,"z":-485.59},{"x":-100.51,"y":-55.61,"z":-486.55},{"x":-102.91,"y":-51.53,"z":-486.49}]},{"lat":8.5,"lon":-77.78,"b":[{"x":-107.1,"y":-69.87,"z":-483.29},{"x":-109.29,"y":-74.01,"z":-482.18},{"x":-106.83,"y":-78.01,"z":-482.1},{"x":-102.21,"y":-77.89,"z":-483.13},{"x":-100.02,"y":-73.79,"z":-484.22},{"x":-102.45,"y":-69.78,"z":-484.31}]},{"lat":10.58,"lon":-77.78,"b":[{"x":-105.95,"y":-88.72,"z":-480.46},{"x":-107.64,"y":-91.92,"z":-479.48},{"x":-105.69,"y":-95,"z":-479.31},{"x":-102.09,"y":-94.89,"z":-480.12},{"x":-100.4,"y":-91.72,"z":-481.09},{"x":-102.32,"y":-88.62,"z":-481.26}]},{"lat":12.64,"lon":-77.78,"b":[{"x":-103.52,"y":-108.98,"z":-476.86},{"x":-103.75,"y":-109.41,"z":-476.71},{"x":-103.48,"y":-109.82,"z":-476.68},{"x":-102.99,"y":-109.8,"z":-476.79},{"x":-102.76,"y":-109.38,"z":-476.93},{"x":-103.03,"y":-108.96,"z":-476.97}]},{"lat":-21.32,"lon":-79.61,"b":[{"x":-84.72,"y":183.03,"z":-457.49},{"x":-85.59,"y":181.87,"z":-457.79},{"x":-84.9,"y":180.61,"z":-458.42},{"x":-83.35,"y":180.51,"z":-458.74},{"x":-82.5,"y":181.68,"z":-458.43},{"x":-83.19,"y":182.92,"z":-457.81}]},{"lat":-1.06,"lon":-79.61,"b":[{"x":-90.86,"y":10.49,"z":-491.53},{"x":-91.54,"y":9.29,"z":-491.43},{"x":-90.87,"y":8.09,"z":-491.58},{"x":-89.53,"y":8.09,"z":-491.82},{"x":-88.86,"y":9.29,"z":-491.93},{"x":-89.52,"y":10.49,"z":-491.78}]},{"lat":1.06,"lon":-79.61,"b":[{"x":-92.54,"y":-5.11,"z":-491.25},{"x":-94.87,"y":-9.3,"z":-490.75},{"x":-92.51,"y":-13.48,"z":-491.1},{"x":-87.85,"y":-13.45,"z":-491.96},{"x":-85.54,"y":-9.27,"z":-492.46},{"x":-87.87,"y":-5.11,"z":-492.11}]},{"lat":3.19,"lon":-79.61,"b":[{"x":-91.96,"y":-24.53,"z":-490.79},{"x":-93.79,"y":-27.87,"z":-490.27},{"x":-91.89,"y":-31.16,"z":-490.43},{"x":-88.19,"y":-31.11,"z":-491.11},{"x":-86.38,"y":-27.79,"z":-491.63},{"x":-88.25,"y":-24.5,"z":-491.47}]},{"lat":5.31,"lon":-79.61,"b":[{"x":-92.22,"y":-42.15,"z":-489.53},{"x":-94.48,"y":-46.33,"z":-488.72},{"x":-92.07,"y":-50.42,"z":-488.78},{"x":-87.44,"y":-50.32,"z":-489.64},{"x":-85.19,"y":-46.17,"z":-490.44},{"x":-87.57,"y":-42.09,"z":-490.39}]},{"lat":7.41,"lon":-79.61,"b":[{"x":-91.27,"y":-61.46,"z":-487.68},{"x":-92.94,"y":-64.57,"z":-486.96},{"x":-91.12,"y":-67.59,"z":-486.89},{"x":-87.65,"y":-67.5,"z":-487.55},{"x":-86,"y":-64.41,"z":-488.26},{"x":-87.79,"y":-61.39,"z":-488.33}]},{"lat":-27.34,"lon":-81.41,"b":[{"x":-68.15,"y":232.66,"z":-437.23},{"x":-70.42,"y":229.98,"z":-438.28},{"x":-68.63,"y":226.89,"z":-440.18},{"x":-64.54,"y":226.53,"z":-440.98},{"x":-62.32,"y":229.25,"z":-439.89},{"x":-64.13,"y":232.29,"z":-438.04}]},{"lat":-25.65,"lon":-81.41,"b":[{"x":-68.73,"y":218.8,"z":-444.25},{"x":-70.47,"y":216.66,"z":-445.02},{"x":-69.08,"y":214.22,"z":-446.42},{"x":-65.94,"y":213.95,"z":-447.02},{"x":-64.23,"y":216.12,"z":-446.23},{"x":-65.63,"y":218.52,"z":-444.86}]},{"lat":-22.11,"lon":-81.41,"b":[{"x":-70.36,"y":190.24,"z":-456.96},{"x":-71.78,"y":188.38,"z":-457.52},{"x":-70.62,"y":186.28,"z":-458.55},{"x":-68.04,"y":186.09,"z":-459.02},{"x":-66.66,"y":187.98,"z":-458.45},{"x":-67.82,"y":190.04,"z":-457.43}]},{"lat":-8.4,"lon":-81.41,"b":[{"x":-75.31,"y":75.69,"z":-488.41},{"x":-76.85,"y":73.16,"z":-488.56},{"x":-75.43,"y":70.51,"z":-489.17},{"x":-72.48,"y":70.43,"z":-489.62},{"x":-70.97,"y":72.97,"z":-489.48},{"x":-72.38,"y":75.59,"z":-488.87}]},{"lat":2.12,"lon":-81.41,"b":[{"x":-74.92,"y":-17.97,"z":-494.02},{"x":-75.19,"y":-18.46,"z":-493.96},{"x":-74.92,"y":-18.94,"z":-493.98},{"x":-74.38,"y":-18.93,"z":-494.06},{"x":-74.11,"y":-18.45,"z":-494.12},{"x":-74.39,"y":-17.97,"z":-494.1}]},{"lat":4.22,"lon":-81.41,"b":[{"x":-75.14,"y":-35.73,"z":-493},{"x":-75.75,"y":-36.85,"z":-492.83},{"x":-75.11,"y":-37.95,"z":-492.84},{"x":-73.87,"y":-37.93,"z":-493.03},{"x":-73.26,"y":-36.81,"z":-493.21},{"x":-73.89,"y":-35.71,"z":-493.19}]},{"lat":6.32,"lon":-81.41,"b":[{"x":-74.67,"y":-54.34,"z":-491.38},{"x":-75.07,"y":-55.08,"z":-491.24},{"x":-74.65,"y":-55.8,"z":-491.22},{"x":-73.83,"y":-55.78,"z":-491.35},{"x":-73.43,"y":-55.04,"z":-491.49},{"x":-73.85,"y":-54.32,"z":-491.51}]},{"lat":-28,"lon":-83.19,"b":[{"x":-52.66,"y":235.18,"z":-438.07},{"x":-53,"y":234.78,"z":-438.24},{"x":-52.72,"y":234.32,"z":-438.53},{"x":-52.11,"y":234.25,"z":-438.64},{"x":-51.78,"y":234.65,"z":-438.46},{"x":-52.06,"y":235.11,"z":-438.18}]},{"lat":-22.86,"lon":-83.19,"b":[{"x":-55.29,"y":195.35,"z":-456.9},{"x":-56.03,"y":194.38,"z":-457.22},{"x":-55.4,"y":193.27,"z":-457.77},{"x":-54.04,"y":193.15,"z":-457.98},{"x":-53.32,"y":194.14,"z":-457.65},{"x":-53.95,"y":195.23,"z":-457.12}]},{"lat":-21.06,"lon":-83.19,"b":[{"x":-55.69,"y":180.21,"z":-463.05},{"x":-56.06,"y":179.7,"z":-463.2},{"x":-55.74,"y":179.13,"z":-463.46},{"x":-55.05,"y":179.07,"z":-463.56},{"x":-54.68,"y":179.58,"z":-463.41},{"x":-55,"y":180.15,"z":-463.15}]},{"lat":-13.41,"lon":-83.19,"b":[{"x":-58.15,"y":116.72,"z":-482.68},{"x":-58.63,"y":115.97,"z":-482.8},{"x":-58.2,"y":115.16,"z":-483.05},{"x":-57.28,"y":115.11,"z":-483.17},{"x":-56.8,"y":115.86,"z":-483.04},{"x":-57.24,"y":116.67,"z":-482.8}]},{"lat":-9.37,"lon":-83.19,"b":[{"x":-59.94,"y":83.99,"z":-489.18},{"x":-61.46,"y":81.5,"z":-489.42},{"x":-60.05,"y":78.89,"z":-490.02},{"x":-57.13,"y":78.78,"z":-490.38},{"x":-55.65,"y":81.27,"z":-490.15},{"x":-57.04,"y":83.86,"z":-489.55}]},{"lat":-14.28,"lon":-84.94,"b":[{"x":-44.88,"y":127.19,"z":-481.39},{"x":-47.18,"y":123.63,"z":-482.1},{"x":-45.06,"y":119.73,"z":-483.29},{"x":-40.67,"y":119.45,"z":-483.75},{"x":-38.42,"y":123.03,"z":-483.03},{"x":-40.52,"y":126.87,"z":-481.87}]},{"lat":-12.31,"lon":-84.94,"b":[{"x":-45.26,"y":110.51,"z":-485.46},{"x":-47.56,"y":106.83,"z":-486.06},{"x":-45.42,"y":102.86,"z":-487.12},{"x":-40.99,"y":102.62,"z":-487.56},{"x":-38.73,"y":106.31,"z":-486.96},{"x":-40.86,"y":110.23,"z":-485.91}]},{"lat":-10.31,"lon":-84.94,"b":[{"x":-45.55,"y":93.37,"z":-489.02},{"x":-47.82,"y":89.65,"z":-489.49},{"x":-45.69,"y":85.69,"z":-490.41},{"x":-41.3,"y":85.49,"z":-490.83},{"x":-39.08,"y":89.21,"z":-490.35},{"x":-41.19,"y":93.13,"z":-489.45}]},{"lat":-20.73,"lon":-86.66,"b":[{"x":-27.65,"y":177.63,"z":-466.55},{"x":-28.06,"y":177.05,"z":-466.75},{"x":-27.68,"y":176.38,"z":-467.02},{"x":-26.9,"y":176.3,"z":-467.1},{"x":-26.5,"y":176.89,"z":-466.9},{"x":-26.87,"y":177.54,"z":-466.63}]},{"lat":-15.13,"lon":-86.66,"b":[{"x":-29.81,"y":133.48,"z":-480.87},{"x":-31.58,"y":130.73,"z":-481.52},{"x":-29.92,"y":127.67,"z":-482.44},{"x":-26.49,"y":127.42,"z":-482.71},{"x":-24.77,"y":130.18,"z":-482.06},{"x":-26.42,"y":133.19,"z":-481.16}]},{"lat":-13.19,"lon":-86.66,"b":[{"x":-30.51,"y":117.91,"z":-484.87},{"x":-32.76,"y":114.33,"z":-485.58},{"x":-30.63,"y":110.41,"z":-486.63},{"x":-26.28,"y":110.12,"z":-486.94},{"x":-24.09,"y":113.72,"z":-486.23},{"x":-26.2,"y":117.59,"z":-485.2}]},{"lat":-11.21,"lon":-86.66,"b":[{"x":-29.37,"y":98.63,"z":-489.26},{"x":-30.18,"y":97.31,"z":-489.48},{"x":-29.41,"y":95.89,"z":-489.81},{"x":-27.84,"y":95.8,"z":-489.92},{"x":-27.05,"y":97.12,"z":-489.7},{"x":-27.81,"y":98.53,"z":-489.38}]},{"lat":-29.73,"lon":-88.35,"b":[{"x":-13.03,"y":248.71,"z":-433.54},{"x":-13.56,"y":248.09,"z":-433.88},{"x":-13.06,"y":247.3,"z":-434.35},{"x":-12.04,"y":247.15,"z":-434.46},{"x":-11.53,"y":247.78,"z":-434.11},{"x":-12.02,"y":248.56,"z":-433.66}]},{"lat":-21.44,"lon":-88.35,"b":[{"x":-13.85,"y":183.42,"z":-464.92},{"x":-14.28,"y":182.81,"z":-465.15},{"x":-13.87,"y":182.1,"z":-465.44},{"x":-13.03,"y":182,"z":-465.5},{"x":-12.61,"y":182.62,"z":-465.27},{"x":-13.02,"y":183.32,"z":-464.98}]},{"lat":-19.64,"lon":-88.35,"b":[{"x":-15.61,"y":171.57,"z":-469.32},{"x":-17.71,"y":168.49,"z":-470.36},{"x":-15.7,"y":164.91,"z":-471.7},{"x":-11.6,"y":164.48,"z":-471.97},{"x":-9.55,"y":167.59,"z":-470.92},{"x":-11.55,"y":171.11,"z":-469.61}]},{"lat":-17.81,"lon":-88.35,"b":[{"x":-15.09,"y":155.29,"z":-474.99},{"x":-16.49,"y":153.17,"z":-475.63},{"x":-15.15,"y":150.75,"z":-476.45},{"x":-12.41,"y":150.48,"z":-476.61},{"x":-11.05,"y":152.62,"z":-475.97},{"x":-12.38,"y":155,"z":-475.16}]},{"lat":-15.94,"lon":-88.35,"b":[{"x":-14.5,"y":138.37,"z":-480.23},{"x":-15.13,"y":137.38,"z":-480.49},{"x":-14.52,"y":136.27,"z":-480.83},{"x":-13.27,"y":136.16,"z":-480.9},{"x":-12.66,"y":137.16,"z":-480.63},{"x":-13.26,"y":138.26,"z":-480.3}]},{"lat":-14.03,"lon":-88.35,"b":[{"x":-16.11,"y":125,"z":-483.79},{"x":-18.29,"y":121.51,"z":-484.6},{"x":-16.18,"y":117.65,"z":-485.63},{"x":-11.92,"y":117.32,"z":-485.83},{"x":-9.8,"y":120.82,"z":-485.02},{"x":-11.89,"y":124.63,"z":-484.01}]},{"lat":-32.44,"lon":-92.76,"b":[{"x":17.67,"y":270.61,"z":-420.01},{"x":17.2,"y":267.42,"z":-422.07},{"x":19.81,"y":265,"z":-423.48},{"x":22.96,"y":265.77,"z":-422.84},{"x":23.47,"y":269.01,"z":-420.76},{"x":20.79,"y":271.44,"z":-419.33}]},{"lat":-33.67,"lon":-93.92,"b":[{"x":25.78,"y":279.56,"z":-413.68},{"x":25.29,"y":276.36,"z":-415.86},{"x":27.96,"y":273.93,"z":-417.29},{"x":31.19,"y":274.7,"z":-416.55},{"x":31.72,"y":277.96,"z":-414.35},{"x":28.99,"y":280.4,"z":-412.9}]},{"lat":-31.93,"lon":-94.5,"b":[{"x":30.64,"y":266.93,"z":-421.62},{"x":30.13,"y":263.69,"z":-423.69},{"x":32.81,"y":261.17,"z":-425.04},{"x":36.06,"y":261.89,"z":-424.34},{"x":36.61,"y":265.18,"z":-422.25},{"x":33.87,"y":267.7,"z":-420.88}]},{"lat":-34.91,"lon":-95.16,"b":[{"x":34.12,"y":288.56,"z":-406.84},{"x":33.61,"y":285.35,"z":-409.15},{"x":36.34,"y":282.91,"z":-410.59},{"x":39.65,"y":283.7,"z":-409.74},{"x":40.2,"y":286.97,"z":-407.41},{"x":37.4,"y":289.4,"z":-405.95}]},{"lat":-33.15,"lon":-95.73,"b":[{"x":39.07,"y":275.89,"z":-415.1},{"x":38.54,"y":272.63,"z":-417.3},{"x":41.28,"y":270.1,"z":-418.67},{"x":44.61,"y":270.83,"z":-417.86},{"x":45.18,"y":274.14,"z":-415.64},{"x":42.38,"y":276.67,"z":-414.25}]},{"lat":-31.38,"lon":-96.28,"b":[{"x":43.98,"y":262.92,"z":-422.95},{"x":43.43,"y":259.63,"z":-425.04},{"x":46.17,"y":257.03,"z":-426.33},{"x":49.52,"y":257.69,"z":-425.55},{"x":50.11,"y":261.03,"z":-423.44},{"x":47.31,"y":263.65,"z":-422.13}]},{"lat":-36.19,"lon":-96.47,"b":[{"x":42.67,"y":297.59,"z":-399.46},{"x":42.14,"y":294.37,"z":-401.9},{"x":44.94,"y":291.93,"z":-403.36},{"x":48.33,"y":292.72,"z":-402.4},{"x":48.89,"y":295.99,"z":-399.94},{"x":46.03,"y":298.42,"z":-398.46}]},{"lat":-34.39,"lon":-97.03,"b":[{"x":47.72,"y":284.89,"z":-408.05},{"x":47.17,"y":281.62,"z":-410.39},{"x":49.97,"y":279.09,"z":-411.78},{"x":53.38,"y":279.82,"z":-410.85},{"x":53.97,"y":283.14,"z":-408.5},{"x":51.11,"y":285.68,"z":-407.09}]},{"lat":-32.59,"lon":-97.57,"b":[{"x":52.73,"y":271.88,"z":-416.23},{"x":52.16,"y":268.57,"z":-418.45},{"x":54.96,"y":265.95,"z":-419.76},{"x":58.39,"y":266.62,"z":-418.87},{"x":59,"y":269.97,"z":-416.63},{"x":56.14,"y":272.61,"z":-415.31}]},{"lat":-30.79,"lon":-98.09,"b":[{"x":57.67,"y":258.59,"z":-423.97},{"x":57.08,"y":255.25,"z":-426.07},{"x":59.87,"y":252.55,"z":-427.3},{"x":63.32,"y":253.16,"z":-426.43},{"x":63.96,"y":256.54,"z":-424.32},{"x":61.11,"y":259.26,"z":-423.08}]},{"lat":-37.48,"lon":-97.86,"b":[{"x":51.42,"y":306.6,"z":-391.54},{"x":50.88,"y":303.38,"z":-394.11},{"x":53.74,"y":300.95,"z":-395.59},{"x":57.2,"y":301.73,"z":-394.5},{"x":57.77,"y":304.99,"z":-391.9},{"x":54.85,"y":307.43,"z":-390.41}]},{"lat":-35.65,"lon":-98.41,"b":[{"x":56.58,"y":293.91,"z":-400.45},{"x":56.01,"y":290.63,"z":-402.92},{"x":58.88,"y":288.09,"z":-404.33},{"x":62.36,"y":288.82,"z":-403.28},{"x":62.96,"y":292.14,"z":-400.79},{"x":60.04,"y":294.69,"z":-399.37}]},{"lat":-33.82,"lon":-98.94,"b":[{"x":61.69,"y":280.87,"z":-408.97},{"x":61.1,"y":277.55,"z":-411.32},{"x":63.96,"y":274.91,"z":-412.65},{"x":67.47,"y":275.58,"z":-411.63},{"x":68.1,"y":278.95,"z":-409.26},{"x":65.18,"y":281.6,"z":-407.92}]},{"lat":-31.98,"lon":-99.45,"b":[{"x":66.74,"y":267.52,"z":-417.04},{"x":66.12,"y":264.16,"z":-419.28},{"x":68.98,"y":261.44,"z":-420.52},{"x":72.5,"y":262.05,"z":-419.54},{"x":73.16,"y":265.45,"z":-417.29},{"x":70.25,"y":268.19,"z":-416.03}]},{"lat":-30.15,"lon":-99.93,"b":[{"x":71.7,"y":253.91,"z":-424.66},{"x":71.06,"y":250.53,"z":-426.77},{"x":73.91,"y":247.72,"z":-427.92},{"x":77.44,"y":248.28,"z":-426.97},{"x":78.13,"y":251.69,"z":-424.84},{"x":75.23,"y":254.52,"z":-423.68}]},{"lat":-38.78,"lon":-99.34,"b":[{"x":60.34,"y":315.56,"z":-383.05},{"x":59.8,"y":312.36,"z":-385.75},{"x":62.72,"y":309.93,"z":-387.24},{"x":66.25,"y":310.7,"z":-386.03},{"x":66.83,"y":313.95,"z":-383.3},{"x":63.85,"y":316.38,"z":-381.8}]},{"lat":-36.93,"lon":-99.88,"b":[{"x":65.62,"y":302.9,"z":-392.29},{"x":65.05,"y":299.64,"z":-394.88},{"x":67.97,"y":297.09,"z":-396.3},{"x":71.54,"y":297.81,"z":-395.13},{"x":72.14,"y":301.13,"z":-392.51},{"x":69.16,"y":303.67,"z":-391.08}]},{"lat":-35.07,"lon":-100.39,"b":[{"x":70.85,"y":289.86,"z":-401.13},{"x":70.25,"y":286.54,"z":-403.62},{"x":73.17,"y":283.89,"z":-404.96},{"x":76.76,"y":284.56,"z":-403.82},{"x":77.39,"y":287.93,"z":-401.31},{"x":74.41,"y":290.58,"z":-399.96}]},{"lat":-33.2,"lon":-100.87,"b":[{"x":76,"y":276.48,"z":-409.54},{"x":75.38,"y":273.11,"z":-411.92},{"x":78.29,"y":270.37,"z":-413.17},{"x":81.9,"y":270.98,"z":-412.07},{"x":82.56,"y":274.39,"z":-409.68},{"x":79.59,"y":277.15,"z":-408.41}]},{"lat":-31.33,"lon":-101.34,"b":[{"x":81.07,"y":262.8,"z":-417.5},{"x":80.42,"y":259.4,"z":-419.75},{"x":83.32,"y":256.58,"z":-420.92},{"x":86.93,"y":257.13,"z":-419.84},{"x":87.64,"y":260.56,"z":-417.58},{"x":84.68,"y":263.41,"z":-416.4}]},{"lat":-29.47,"lon":-101.79,"b":[{"x":86.04,"y":248.87,"z":-424.98},{"x":85.35,"y":245.45,"z":-427.1},{"x":88.23,"y":242.55,"z":-428.17},{"x":91.86,"y":243.04,"z":-427.12},{"x":92.59,"y":246.49,"z":-424.98},{"x":89.66,"y":249.42,"z":-423.9}]},{"lat":-40.1,"lon":-100.92,"b":[{"x":69.43,"y":324.44,"z":-373.98},{"x":68.88,"y":321.26,"z":-376.82},{"x":71.86,"y":318.83,"z":-378.31},{"x":75.46,"y":319.59,"z":-376.98},{"x":76.04,"y":322.81,"z":-374.1},{"x":73,"y":325.23,"z":-372.6}]},{"lat":-38.22,"lon":-101.43,"b":[{"x":74.84,"y":311.84,"z":-383.53},{"x":74.26,"y":308.59,"z":-386.27},{"x":77.25,"y":306.04,"z":-387.7},{"x":80.87,"y":306.75,"z":-386.4},{"x":81.49,"y":310.05,"z":-383.63},{"x":78.44,"y":312.59,"z":-382.2}]},{"lat":-36.33,"lon":-101.92,"b":[{"x":80.19,"y":298.82,"z":-392.7},{"x":79.58,"y":295.51,"z":-395.33},{"x":82.57,"y":292.86,"z":-396.68},{"x":86.22,"y":293.51,"z":-395.42},{"x":86.86,"y":296.87,"z":-392.77},{"x":83.82,"y":299.53,"z":-391.4}]},{"lat":-34.43,"lon":-102.39,"b":[{"x":85.46,"y":285.43,"z":-401.45},{"x":84.83,"y":282.06,"z":-403.97},{"x":87.8,"y":279.31,"z":-405.24},{"x":91.48,"y":279.91,"z":-404},{"x":92.15,"y":283.32,"z":-401.47},{"x":89.12,"y":286.09,"z":-400.19}]},{"lat":-32.53,"lon":-102.83,"b":[{"x":90.64,"y":271.71,"z":-409.75},{"x":89.97,"y":268.3,"z":-412.14},{"x":92.93,"y":265.46,"z":-413.32},{"x":96.62,"y":266,"z":-412.12},{"x":97.34,"y":269.45,"z":-409.71},{"x":94.32,"y":272.31,"z":-408.52}]},{"lat":-30.64,"lon":-103.26,"b":[{"x":95.71,"y":257.7,"z":-417.57},{"x":95.01,"y":254.27,"z":-419.84},{"x":97.95,"y":251.34,"z":-420.92},{"x":101.65,"y":251.83,"z":-419.75},{"x":102.4,"y":255.3,"z":-417.47},{"x":99.4,"y":258.25,"z":-416.37}]},{"lat":-28.75,"lon":-103.67,"b":[{"x":100.65,"y":243.47,"z":-424.89},{"x":99.91,"y":240.01,"z":-427.03},{"x":102.83,"y":237.01,"z":-428.01},{"x":106.53,"y":237.44,"z":-426.86},{"x":107.32,"y":240.92,"z":-424.71},{"x":104.35,"y":243.95,"z":-423.72}]},{"lat":-41.43,"lon":-102.59,"b":[{"x":78.66,"y":333.19,"z":-364.33},{"x":78.1,"y":330.05,"z":-367.3},{"x":81.15,"y":327.63,"z":-368.8},{"x":84.8,"y":328.35,"z":-367.33},{"x":85.38,"y":331.54,"z":-364.32},{"x":82.28,"y":333.96,"z":-362.82}]},{"lat":-39.52,"lon":-103.08,"b":[{"x":84.2,"y":320.68,"z":-374.19},{"x":83.62,"y":317.45,"z":-377.06},{"x":86.67,"y":314.91,"z":-378.49},{"x":90.36,"y":315.59,"z":-377.06},{"x":90.97,"y":318.86,"z":-374.16},{"x":87.86,"y":321.4,"z":-372.72}]},{"lat":-37.61,"lon":-103.54,"b":[{"x":89.69,"y":307.71,"z":-383.68},{"x":89.07,"y":304.42,"z":-386.44},{"x":92.12,"y":301.76,"z":-387.8},{"x":95.84,"y":302.39,"z":-386.41},{"x":96.48,"y":305.74,"z":-383.61},{"x":93.38,"y":308.4,"z":-382.24}]},{"lat":-35.68,"lon":-103.98,"b":[{"x":95.09,"y":294.34,"z":-392.76},{"x":94.44,"y":290.98,"z":-395.41},{"x":97.48,"y":288.22,"z":-396.69},{"x":101.22,"y":288.8,"z":-395.33},{"x":101.9,"y":292.2,"z":-392.65},{"x":98.81,"y":294.98,"z":-391.36}]},{"lat":-33.75,"lon":-104.41,"b":[{"x":100.39,"y":280.61,"z":-401.4},{"x":99.71,"y":277.2,"z":-403.93},{"x":102.73,"y":274.33,"z":-405.12},{"x":106.49,"y":274.87,"z":-403.79},{"x":107.21,"y":278.31,"z":-401.23},{"x":104.13,"y":281.19,"z":-400.03}]},{"lat":-31.82,"lon":-104.81,"b":[{"x":105.57,"y":266.55,"z":-409.56},{"x":104.86,"y":263.11,"z":-411.97},{"x":107.85,"y":260.15,"z":-413.07},{"x":111.62,"y":260.63,"z":-411.76},{"x":112.38,"y":264.11,"z":-409.34},{"x":109.33,"y":267.08,"z":-408.23}]},{"lat":-29.9,"lon":-105.19,"b":[{"x":110.61,"y":252.23,"z":-417.23},{"x":109.86,"y":248.76,"z":-419.51},{"x":112.83,"y":245.73,"z":-420.51},{"x":116.6,"y":246.15,"z":-419.23},{"x":117.4,"y":249.65,"z":-416.93},{"x":114.38,"y":252.7,"z":-415.93}]},{"lat":-27.99,"lon":-105.56,"b":[{"x":115.5,"y":237.69,"z":-424.38},{"x":114.71,"y":234.21,"z":-426.53},{"x":117.65,"y":231.12,"z":-427.42},{"x":121.42,"y":231.47,"z":-426.16},{"x":122.26,"y":234.98,"z":-424},{"x":119.28,"y":238.11,"z":-423.1}]},{"lat":-42.76,"lon":-104.37,"b":[{"x":87.99,"y":341.78,"z":-354.1},{"x":87.44,"y":338.68,"z":-357.19},{"x":90.55,"y":336.27,"z":-358.69},{"x":94.26,"y":336.96,"z":-357.09},{"x":94.82,"y":340.1,"z":-353.95},{"x":91.66,"y":342.5,"z":-352.46}]},{"lat":-40.83,"lon":-104.83,"b":[{"x":93.68,"y":329.38,"z":-364.24},{"x":93.11,"y":326.19,"z":-367.25},{"x":96.22,"y":323.65,"z":-368.68},{"x":99.96,"y":324.3,"z":-367.11},{"x":100.56,"y":327.53,"z":-364.07},{"x":97.39,"y":330.07,"z":-362.64}]},{"lat":-38.89,"lon":-105.26,"b":[{"x":99.31,"y":316.5,"z":-374.04},{"x":98.7,"y":313.23,"z":-376.94},{"x":101.81,"y":310.57,"z":-378.31},{"x":105.58,"y":311.17,"z":-376.77},{"x":106.22,"y":314.48,"z":-373.84},{"x":103.06,"y":317.15,"z":-372.47}]},{"lat":-36.94,"lon":-105.67,"b":[{"x":104.85,"y":303.17,"z":-383.44},{"x":104.21,"y":299.83,"z":-386.24},{"x":107.31,"y":297.06,"z":-387.53},{"x":111.1,"y":297.62,"z":-386.02},{"x":111.78,"y":301,"z":-383.2},{"x":108.63,"y":303.78,"z":-381.91}]},{"lat":-34.98,"lon":-106.07,"b":[{"x":110.29,"y":289.45,"z":-392.42},{"x":109.61,"y":286.05,"z":-395.1},{"x":112.68,"y":283.17,"z":-396.3},{"x":116.5,"y":283.68,"z":-394.83},{"x":117.22,"y":287.12,"z":-392.12},{"x":114.08,"y":290.01,"z":-390.91}]},{"lat":-33.02,"lon":-106.44,"b":[{"x":115.59,"y":275.37,"z":-400.93},{"x":114.87,"y":271.93,"z":-403.49},{"x":117.92,"y":268.95,"z":-404.59},{"x":121.76,"y":269.41,"z":-403.15},{"x":122.52,"y":272.89,"z":-400.57},{"x":119.41,"y":275.88,"z":-399.46}]},{"lat":-31.06,"lon":-106.8,"b":[{"x":120.74,"y":260.99,"z":-408.95},{"x":119.99,"y":257.51,"z":-411.38},{"x":123.01,"y":254.46,"z":-412.38},{"x":126.85,"y":254.86,"z":-410.96},{"x":127.66,"y":258.37,"z":-408.52},{"x":124.58,"y":261.45,"z":-407.5}]},{"lat":-29.11,"lon":-107.14,"b":[{"x":125.74,"y":246.37,"z":-416.45},{"x":124.94,"y":242.86,"z":-418.75},{"x":127.92,"y":239.74,"z":-419.64},{"x":131.76,"y":240.08,"z":-418.25},{"x":132.62,"y":243.61,"z":-415.94},{"x":129.58,"y":246.77,"z":-415.03}]},{"lat":-27.18,"lon":-107.47,"b":[{"x":130.55,"y":231.55,"z":-423.41},{"x":129.71,"y":228.04,"z":-425.58},{"x":132.65,"y":224.85,"z":-426.36},{"x":136.49,"y":225.14,"z":-424.99},{"x":137.38,"y":228.67,"z":-422.82},{"x":134.39,"y":231.89,"z":-422.02}]},{"lat":-44.08,"lon":-106.26,"b":[{"x":97.4,"y":350.15,"z":-343.28},{"x":96.87,"y":347.12,"z":-346.51},{"x":100.03,"y":344.71,"z":-348},{"x":103.79,"y":345.36,"z":-346.26},{"x":104.33,"y":348.43,"z":-342.99},{"x":101.11,"y":350.83,"z":-341.51}]},{"lat":-42.13,"lon":-106.68,"b":[{"x":103.26,"y":337.89,"z":-353.7},{"x":102.69,"y":334.76,"z":-356.84},{"x":105.86,"y":332.22,"z":-358.27},{"x":109.65,"y":332.83,"z":-356.56},{"x":110.23,"y":336.01,"z":-353.39},{"x":107.01,"y":338.54,"z":-351.96}]},{"lat":-40.17,"lon":-107.08,"b":[{"x":109.04,"y":325.12,"z":-363.79},{"x":108.44,"y":321.89,"z":-366.83},{"x":111.6,"y":319.23,"z":-368.2},{"x":115.43,"y":319.8,"z":-366.52},{"x":116.05,"y":323.07,"z":-363.44},{"x":112.83,"y":325.73,"z":-362.08}]},{"lat":-38.19,"lon":-107.46,"b":[{"x":114.73,"y":311.88,"z":-373.5},{"x":114.09,"y":308.57,"z":-376.44},{"x":117.25,"y":305.79,"z":-377.73},{"x":121.1,"y":306.31,"z":-376.09},{"x":121.76,"y":309.66,"z":-373.12},{"x":118.55,"y":312.45,"z":-371.82}]},{"lat":-36.21,"lon":-107.82,"b":[{"x":120.3,"y":298.2,"z":-382.8},{"x":119.63,"y":294.82,"z":-385.63},{"x":122.76,"y":291.93,"z":-386.84},{"x":126.63,"y":292.41,"z":-385.22},{"x":127.35,"y":295.82,"z":-382.37},{"x":124.15,"y":298.72,"z":-381.16}]},{"lat":-34.22,"lon":-108.16,"b":[{"x":125.74,"y":284.13,"z":-391.65},{"x":125.02,"y":280.69,"z":-394.36},{"x":128.13,"y":277.7,"z":-395.47},{"x":132.02,"y":278.13,"z":-393.89},{"x":132.78,"y":281.6,"z":-391.16},{"x":129.61,"y":284.61,"z":-390.04}]},{"lat":-32.23,"lon":-108.49,"b":[{"x":131.02,"y":269.72,"z":-400.02},{"x":130.26,"y":266.24,"z":-402.6},{"x":133.34,"y":263.16,"z":-403.61},{"x":137.24,"y":263.54,"z":-402.05},{"x":138.04,"y":267.05,"z":-399.45},{"x":134.91,"y":270.15,"z":-398.43}]},{"lat":-30.25,"lon":-108.8,"b":[{"x":136.13,"y":255.03,"z":-407.87},{"x":135.32,"y":251.52,"z":-410.32},{"x":138.36,"y":248.36,"z":-411.23},{"x":142.26,"y":248.68,"z":-409.7},{"x":143.11,"y":252.22,"z":-407.23},{"x":140.02,"y":255.41,"z":-406.32}]},{"lat":-28.28,"lon":-109.1,"b":[{"x":141.04,"y":240.11,"z":-415.19},{"x":140.19,"y":236.59,"z":-417.51},{"x":143.18,"y":233.36,"z":-418.3},{"x":147.08,"y":233.63,"z":-416.79},{"x":147.98,"y":237.18,"z":-414.47},{"x":144.94,"y":240.44,"z":-413.66}]},{"lat":-26.33,"lon":-109.38,"b":[{"x":146.6,"y":224.1,"z":-422.18},{"x":145.95,"y":221.58,"z":-423.74},{"x":148.06,"y":219.23,"z":-424.23},{"x":150.84,"y":219.38,"z":-423.16},{"x":151.52,"y":221.92,"z":-421.6},{"x":149.38,"y":224.29,"z":-421.1}]},{"lat":-45.39,"lon":-108.27,"b":[{"x":106.86,"y":358.27,"z":-331.9},{"x":106.35,"y":355.3,"z":-335.24},{"x":109.57,"y":352.91,"z":-336.72},{"x":113.36,"y":353.5,"z":-334.85},{"x":113.88,"y":356.51,"z":-331.46},{"x":110.61,"y":358.89,"z":-330}]},{"lat":-43.43,"lon":-108.65,"b":[{"x":112.89,"y":346.18,"z":-342.56},{"x":112.34,"y":343.1,"z":-345.83},{"x":115.56,"y":340.58,"z":-347.25},{"x":119.39,"y":341.13,"z":-345.41},{"x":119.95,"y":344.25,"z":-342.1},{"x":116.67,"y":346.77,"z":-340.69}]},{"lat":-41.45,"lon":-109.01,"b":[{"x":118.83,"y":333.55,"z":-352.92},{"x":118.25,"y":330.37,"z":-356.1},{"x":121.47,"y":327.71,"z":-357.46},{"x":125.33,"y":328.24,"z":-355.64},{"x":125.94,"y":331.46,"z":-352.43},{"x":122.66,"y":334.11,"z":-351.07}]},{"lat":-39.45,"lon":-109.35,"b":[{"x":124.68,"y":320.42,"z":-362.93},{"x":124.06,"y":317.14,"z":-366.01},{"x":127.27,"y":314.36,"z":-367.3},{"x":131.16,"y":314.85,"z":-365.51},{"x":131.81,"y":318.15,"z":-362.4},{"x":128.55,"y":320.94,"z":-361.11}]},{"lat":-37.44,"lon":-109.67,"b":[{"x":130.41,"y":306.81,"z":-372.55},{"x":129.74,"y":303.46,"z":-375.52},{"x":132.94,"y":300.56,"z":-376.73},{"x":136.85,"y":301,"z":-374.97},{"x":137.55,"y":304.39,"z":-371.97},{"x":134.3,"y":307.29,"z":-370.76}]},{"lat":-35.43,"lon":-109.98,"b":[{"x":136,"y":292.78,"z":-381.73},{"x":135.28,"y":289.36,"z":-384.58},{"x":138.45,"y":286.35,"z":-385.7},{"x":142.38,"y":286.75,"z":-383.97},{"x":143.13,"y":290.2,"z":-381.09},{"x":139.91,"y":293.22,"z":-379.97}]},{"lat":-33.41,"lon":-110.27,"b":[{"x":141.41,"y":278.37,"z":-390.44},{"x":140.65,"y":274.9,"z":-393.17},{"x":143.79,"y":271.8,"z":-394.19},{"x":147.73,"y":272.14,"z":-392.48},{"x":148.53,"y":275.64,"z":-389.73},{"x":145.34,"y":278.77,"z":-388.71}]},{"lat":-31.4,"lon":-110.54,"b":[{"x":146.64,"y":263.65,"z":-398.65},{"x":145.83,"y":260.13,"z":-401.24},{"x":148.93,"y":256.95,"z":-402.16},{"x":152.88,"y":257.24,"z":-400.48},{"x":153.73,"y":260.78,"z":-397.86},{"x":150.58,"y":263.99,"z":-396.94}]},{"lat":-29.4,"lon":-110.81,"b":[{"x":151.67,"y":248.66,"z":-406.32},{"x":150.81,"y":245.12,"z":-408.79},{"x":153.86,"y":241.86,"z":-409.59},{"x":157.8,"y":242.11,"z":-407.94},{"x":158.71,"y":245.67,"z":-405.45},{"x":155.61,"y":248.96,"z":-404.64}]},{"lat":-27.41,"lon":-111.06,"b":[{"x":158.04,"y":231.76,"z":-413.85},{"x":157.6,"y":230.05,"z":-414.97},{"x":159.05,"y":228.45,"z":-415.3},{"x":160.95,"y":228.55,"z":-414.52},{"x":161.41,"y":230.26,"z":-413.39},{"x":159.94,"y":231.88,"z":-413.05}]},{"lat":-25.44,"lon":-111.3,"b":[{"x":162.61,"y":216.38,"z":-420.36},{"x":162.16,"y":214.7,"z":-421.4},{"x":163.55,"y":213.11,"z":-421.67},{"x":165.41,"y":213.17,"z":-420.9},{"x":165.88,"y":214.86,"z":-419.86},{"x":164.47,"y":216.47,"z":-419.59}]},{"lat":-46.69,"lon":-110.41,"b":[{"x":116.34,"y":366.09,"z":-319.97},{"x":115.85,"y":363.2,"z":-323.42},{"x":119.12,"y":360.82,"z":-324.88},{"x":122.94,"y":361.35,"z":-322.87},{"x":123.43,"y":364.28,"z":-319.37},{"x":120.11,"y":366.64,"z":-317.93}]},{"lat":-44.71,"lon":-110.74,"b":[{"x":122.54,"y":354.2,"z":-330.85},{"x":122.01,"y":351.19,"z":-334.23},{"x":125.29,"y":348.67,"z":-335.65},{"x":129.15,"y":349.17,"z":-333.66},{"x":129.68,"y":352.22,"z":-330.24},{"x":126.35,"y":354.73,"z":-328.84}]},{"lat":-42.71,"lon":-111.05,"b":[{"x":128.66,"y":341.74,"z":-341.46},{"x":128.1,"y":338.62,"z":-344.76},{"x":131.37,"y":335.97,"z":-346.12},{"x":135.26,"y":336.43,"z":-344.16},{"x":135.84,"y":339.59,"z":-340.82},{"x":132.51,"y":342.24,"z":-339.47}]},{"lat":-40.7,"lon":-111.34,"b":[{"x":134.68,"y":328.74,"z":-351.74},{"x":134.07,"y":325.52,"z":-354.96},{"x":137.34,"y":322.73,"z":-356.24},{"x":141.26,"y":323.17,"z":-354.31},{"x":141.89,"y":326.42,"z":-351.06},{"x":138.57,"y":329.21,"z":-349.78}]},{"lat":-38.67,"lon":-111.62,"b":[{"x":140.57,"y":315.24,"z":-361.66},{"x":139.92,"y":311.93,"z":-364.77},{"x":143.17,"y":309.02,"z":-365.98},{"x":147.12,"y":309.42,"z":-364.07},{"x":147.79,"y":312.76,"z":-360.93},{"x":144.5,"y":315.67,"z":-359.72}]},{"lat":-36.63,"lon":-111.88,"b":[{"x":146.31,"y":301.27,"z":-371.15},{"x":145.61,"y":297.89,"z":-374.15},{"x":148.83,"y":294.87,"z":-375.27},{"x":152.8,"y":295.22,"z":-373.39},{"x":153.53,"y":298.64,"z":-370.37},{"x":150.26,"y":301.67,"z":-369.25}]},{"lat":-34.59,"lon":-112.13,"b":[{"x":151.88,"y":286.9,"z":-380.2},{"x":151.13,"y":283.45,"z":-383.08},{"x":154.31,"y":280.33,"z":-384.1},{"x":158.3,"y":280.64,"z":-382.25},{"x":159.08,"y":284.12,"z":-379.34},{"x":155.85,"y":287.26,"z":-378.32}]},{"lat":-32.55,"lon":-112.37,"b":[{"x":157.24,"y":272.17,"z":-388.75},{"x":156.44,"y":268.67,"z":-391.5},{"x":159.59,"y":265.46,"z":-392.42},{"x":163.58,"y":265.72,"z":-390.59},{"x":164.41,"y":269.25,"z":-387.82},{"x":161.23,"y":272.48,"z":-386.9}]},{"lat":-30.52,"lon":-112.6,"b":[{"x":162.53,"y":257,"z":-396.82},{"x":161.72,"y":253.62,"z":-399.32},{"x":164.67,"y":250.48,"z":-400.1},{"x":168.49,"y":250.68,"z":-398.37},{"x":169.34,"y":254.08,"z":-395.85},{"x":166.34,"y":257.25,"z":-395.07}]},{"lat":-28.5,"lon":-112.81,"b":[{"x":169.58,"y":239.42,"z":-404.84},{"x":169.35,"y":238.49,"z":-405.49},{"x":170.14,"y":237.62,"z":-405.67},{"x":171.17,"y":237.66,"z":-405.21},{"x":171.42,"y":238.59,"z":-404.56},{"x":170.62,"y":239.47,"z":-404.37}]},{"lat":-26.49,"lon":-113.02,"b":[{"x":172.7,"y":225.63,"z":-411.35},{"x":171.98,"y":222.92,"z":-413.13},{"x":174.24,"y":220.34,"z":-413.57},{"x":177.25,"y":220.42,"z":-412.24},{"x":178.02,"y":223.14,"z":-410.44},{"x":175.73,"y":225.76,"z":-410}]},{"lat":-47.95,"lon":-112.68,"b":[{"x":125.79,"y":373.57,"z":-307.5},{"x":125.33,"y":370.77,"z":-311.06},{"x":128.66,"y":368.4,"z":-312.5},{"x":132.49,"y":368.86,"z":-310.36},{"x":132.94,"y":371.7,"z":-306.76},{"x":129.57,"y":374.05,"z":-305.34}]},{"lat":-45.97,"lon":-112.95,"b":[{"x":132.17,"y":361.9,"z":-318.57},{"x":131.68,"y":358.97,"z":-322.07},{"x":135.01,"y":356.46,"z":-323.47},{"x":138.88,"y":356.9,"z":-321.35},{"x":139.38,"y":359.86,"z":-317.81},{"x":136,"y":362.36,"z":-316.43}]},{"lat":-43.96,"lon":-113.21,"b":[{"x":138.48,"y":349.64,"z":-329.4},{"x":137.94,"y":346.59,"z":-332.83},{"x":141.27,"y":343.94,"z":-334.18},{"x":145.18,"y":344.35,"z":-332.08},{"x":145.73,"y":347.43,"z":-328.61},{"x":142.35,"y":350.07,"z":-327.28}]},{"lat":-41.93,"lon":-113.45,"b":[{"x":144.68,"y":336.81,"z":-339.94},{"x":144.1,"y":333.65,"z":-343.28},{"x":147.42,"y":330.86,"z":-344.56},{"x":151.36,"y":331.24,"z":-342.49},{"x":151.96,"y":334.43,"z":-339.11},{"x":148.59,"y":337.21,"z":-337.84}]},{"lat":-39.88,"lon":-113.67,"b":[{"x":150.75,"y":323.44,"z":-350.13},{"x":150.12,"y":320.18,"z":-353.38},{"x":153.42,"y":317.27,"z":-354.58},{"x":157.39,"y":317.61,"z":-352.53},{"x":158.04,"y":320.9,"z":-349.25},{"x":154.69,"y":323.81,"z":-348.06}]},{"lat":-37.82,"lon":-113.89,"b":[{"x":156.65,"y":309.58,"z":-359.93},{"x":155.98,"y":306.23,"z":-363.07},{"x":159.25,"y":303.2,"z":-364.19},{"x":163.24,"y":303.5,"z":-362.16},{"x":163.94,"y":306.88,"z":-358.99},{"x":160.63,"y":309.92,"z":-357.88}]},{"lat":-35.76,"lon":-114.09,"b":[{"x":162.38,"y":295.27,"z":-369.29},{"x":161.65,"y":291.85,"z":-372.32},{"x":164.88,"y":288.71,"z":-373.35},{"x":168.89,"y":288.97,"z":-371.34},{"x":169.65,"y":292.42,"z":-368.29},{"x":166.37,"y":295.57,"z":-367.27}]},{"lat":-33.69,"lon":-114.29,"b":[{"x":167.89,"y":280.57,"z":-378.18},{"x":167.11,"y":277.09,"z":-381.08},{"x":170.3,"y":273.85,"z":-382.01},{"x":174.32,"y":274.07,"z":-380.03},{"x":175.14,"y":277.57,"z":-377.1},{"x":171.9,"y":280.83,"z":-376.18}]},{"lat":-31.63,"lon":-114.47,"b":[{"x":173.57,"y":265.12,"z":-386.67},{"x":172.84,"y":262.04,"z":-389.1},{"x":175.59,"y":259.13,"z":-389.81},{"x":179.11,"y":259.29,"z":-388.1},{"x":179.88,"y":262.39,"z":-385.66},{"x":177.09,"y":265.32,"z":-384.94}]},{"lat":-29.59,"lon":-114.65,"b":[{"x":179.27,"y":249.09,"z":-394.67},{"x":178.68,"y":246.74,"z":-396.41},{"x":180.72,"y":244.49,"z":-396.88},{"x":183.38,"y":244.58,"z":-395.6},{"x":184,"y":246.94,"z":-393.84},{"x":181.93,"y":249.2,"z":-393.38}]},{"lat":-27.55,"lon":-114.82,"b":[{"x":185.15,"y":232.29,"z":-402.16},{"x":184.87,"y":231.24,"z":-402.9},{"x":185.76,"y":230.22,"z":-403.07},{"x":186.94,"y":230.24,"z":-402.51},{"x":187.24,"y":231.3,"z":-401.77},{"x":186.34,"y":232.33,"z":-401.59}]},{"lat":-49.19,"lon":-115.09,"b":[{"x":135.18,"y":380.67,"z":-294.54},{"x":134.76,"y":377.96,"z":-298.19},{"x":138.14,"y":375.61,"z":-299.61},{"x":141.97,"y":375.99,"z":-297.34},{"x":142.38,"y":378.73,"z":-293.64},{"x":138.97,"y":381.06,"z":-292.25}]},{"lat":-47.2,"lon":-115.29,"b":[{"x":141.76,"y":369.25,"z":-305.77},{"x":141.3,"y":366.41,"z":-309.37},{"x":144.68,"y":363.91,"z":-310.75},{"x":148.56,"y":364.27,"z":-308.5},{"x":149.01,"y":367.14,"z":-304.85},{"x":145.59,"y":369.62,"z":-303.5}]},{"lat":-45.18,"lon":-115.48,"b":[{"x":148.25,"y":357.2,"z":-316.79},{"x":147.75,"y":354.24,"z":-320.33},{"x":151.13,"y":351.6,"z":-321.66},{"x":155.05,"y":351.93,"z":-319.43},{"x":155.55,"y":354.93,"z":-315.84},{"x":152.13,"y":357.56,"z":-314.54}]},{"lat":-43.14,"lon":-115.67,"b":[{"x":154.64,"y":344.57,"z":-327.55},{"x":154.1,"y":341.48,"z":-331.02},{"x":157.46,"y":338.7,"z":-332.28},{"x":161.42,"y":339.01,"z":-330.07},{"x":161.97,"y":342.12,"z":-326.56},{"x":158.56,"y":344.9,"z":-325.31}]},{"lat":-41.08,"lon":-115.84,"b":[{"x":160.89,"y":331.36,"z":-337.99},{"x":160.3,"y":328.17,"z":-341.37},{"x":163.64,"y":325.26,"z":-342.57},{"x":167.63,"y":325.53,"z":-340.37},{"x":168.24,"y":328.76,"z":-336.96},{"x":164.85,"y":331.67,"z":-335.78}]},{"lat":-39,"lon":-116,"b":[{"x":166.98,"y":317.64,"z":-348.07},{"x":166.33,"y":314.35,"z":-351.35},{"x":169.65,"y":311.31,"z":-352.47},{"x":173.66,"y":311.55,"z":-350.29},{"x":174.32,"y":314.87,"z":-346.98},{"x":170.96,"y":317.91,"z":-345.87}]},{"lat":-36.92,"lon":-116.15,"b":[{"x":172.87,"y":303.43,"z":-357.73},{"x":172.17,"y":300.05,"z":-360.91},{"x":175.45,"y":296.9,"z":-361.93},{"x":179.48,"y":297.11,"z":-359.78},{"x":180.2,"y":300.5,"z":-356.58},{"x":176.88,"y":303.67,"z":-355.56}]},{"lat":-34.83,"lon":-116.3,"b":[{"x":178.55,"y":288.79,"z":-366.94},{"x":177.79,"y":285.34,"z":-370},{"x":181.02,"y":282.09,"z":-370.92},{"x":185.06,"y":282.26,"z":-368.79},{"x":185.85,"y":285.72,"z":-365.72},{"x":182.57,"y":288.99,"z":-364.79}]},{"lat":-32.75,"lon":-116.43,"b":[{"x":183.98,"y":273.78,"z":-375.66},{"x":183.17,"y":270.28,"z":-378.59},{"x":186.35,"y":266.93,"z":-379.41},{"x":190.39,"y":267.06,"z":-377.3},{"x":191.24,"y":270.58,"z":-374.35},{"x":188.02,"y":273.95,"z":-373.53}]},{"lat":-30.67,"lon":-116.57,"b":[{"x":191.08,"y":256.4,"z":-384.34},{"x":190.73,"y":255.01,"z":-385.43},{"x":191.96,"y":253.66,"z":-385.71},{"x":193.55,"y":253.7,"z":-384.89},{"x":193.91,"y":255.09,"z":-383.79},{"x":192.67,"y":256.45,"z":-383.51}]},{"lat":-50.37,"lon":-117.63,"b":[{"x":144.48,"y":387.35,"z":-281.11},{"x":144.1,"y":384.74,"z":-284.85},{"x":147.52,"y":382.41,"z":-286.23},{"x":151.35,"y":382.7,"z":-283.84},{"x":151.71,"y":385.33,"z":-280.06},{"x":148.26,"y":387.65,"z":-278.71}]},{"lat":-48.38,"lon":-117.76,"b":[{"x":151.25,"y":376.19,"z":-292.46},{"x":150.83,"y":373.45,"z":-296.16},{"x":154.26,"y":370.97,"z":-297.52},{"x":158.13,"y":371.24,"z":-295.14},{"x":158.54,"y":374.01,"z":-291.39},{"x":155.08,"y":376.48,"z":-290.07}]},{"lat":-46.36,"lon":-117.88,"b":[{"x":157.94,"y":364.4,"z":-303.64},{"x":157.48,"y":361.52,"z":-307.29},{"x":160.9,"y":358.89,"z":-308.6},{"x":164.82,"y":359.14,"z":-306.23},{"x":165.27,"y":362.05,"z":-302.55},{"x":161.81,"y":364.67,"z":-301.27}]},{"lat":-44.31,"lon":-118,"b":[{"x":164.52,"y":351.98,"z":-314.59},{"x":164.02,"y":348.98,"z":-318.18},{"x":167.43,"y":346.21,"z":-319.43},{"x":171.38,"y":346.44,"z":-317.07},{"x":171.89,"y":349.46,"z":-313.46},{"x":168.44,"y":352.23,"z":-312.23}]},{"lat":-42.24,"lon":-118.11,"b":[{"x":170.96,"y":338.97,"z":-325.26},{"x":170.41,"y":335.86,"z":-328.76},{"x":173.8,"y":332.94,"z":-329.95},{"x":177.79,"y":333.15,"z":-327.61},{"x":178.35,"y":336.29,"z":-324.08},{"x":174.92,"y":339.2,"z":-322.91}]},{"lat":-40.16,"lon":-118.21,"b":[{"x":177.24,"y":325.41,"z":-335.59},{"x":176.63,"y":322.19,"z":-339},{"x":179.99,"y":319.14,"z":-340.11},{"x":184,"y":319.32,"z":-337.79},{"x":184.62,"y":322.56,"z":-334.35},{"x":181.22,"y":325.61,"z":-333.26}]},{"lat":-38.06,"lon":-118.3,"b":[{"x":183.31,"y":311.33,"z":-345.54},{"x":182.65,"y":308.01,"z":-348.85},{"x":185.97,"y":304.85,"z":-349.87},{"x":190,"y":304.99,"z":-347.57},{"x":190.69,"y":308.33,"z":-344.23},{"x":187.32,"y":311.5,"z":-343.22}]},{"lat":-35.95,"lon":-118.4,"b":[{"x":189.16,"y":296.78,"z":-355.05},{"x":188.44,"y":293.39,"z":-358.25},{"x":191.71,"y":290.11,"z":-359.17},{"x":195.75,"y":290.22,"z":-356.89},{"x":196.51,"y":293.64,"z":-353.67},{"x":193.19,"y":296.93,"z":-352.75}]},{"lat":-33.85,"lon":-118.48,"b":[{"x":195.52,"y":281.06,"z":-364.3},{"x":194.91,"y":278.4,"z":-366.66},{"x":197.38,"y":275.81,"z":-367.29},{"x":200.49,"y":275.87,"z":-365.56},{"x":201.12,"y":278.54,"z":-363.18},{"x":198.62,"y":281.15,"z":-362.55}]},{"lat":-51.51,"lon":-120.32,"b":[{"x":153.64,"y":393.57,"z":-267.26},{"x":153.32,"y":391.08,"z":-271.07},{"x":156.77,"y":388.77,"z":-272.42},{"x":160.58,"y":388.96,"z":-269.92},{"x":160.88,"y":391.48,"z":-266.06},{"x":157.4,"y":393.78,"z":-264.76}]},{"lat":-49.52,"lon":-120.37,"b":[{"x":160.61,"y":382.7,"z":-278.7},{"x":160.24,"y":380.07,"z":-282.49},{"x":163.7,"y":377.6,"z":-283.81},{"x":167.56,"y":377.78,"z":-281.31},{"x":167.91,"y":380.44,"z":-277.49},{"x":164.42,"y":382.89,"z":-276.2}]},{"lat":-47.5,"lon":-120.41,"b":[{"x":167.5,"y":371.17,"z":-290},{"x":167.09,"y":368.4,"z":-293.75},{"x":170.55,"y":365.78,"z":-295.03},{"x":174.45,"y":365.94,"z":-292.54},{"x":174.85,"y":368.74,"z":-288.76},{"x":171.35,"y":371.35,"z":-287.51}]},{"lat":-45.45,"lon":-120.45,"b":[{"x":174.28,"y":359.01,"z":-301.11},{"x":173.83,"y":356.1,"z":-304.8},{"x":177.28,"y":353.33,"z":-306.03},{"x":181.22,"y":353.48,"z":-303.55},{"x":181.67,"y":356.41,"z":-299.82},{"x":178.18,"y":359.17,"z":-298.62}]},{"lat":-43.38,"lon":-120.49,"b":[{"x":180.92,"y":346.22,"z":-311.97},{"x":180.42,"y":343.19,"z":-315.59},{"x":183.85,"y":340.28,"z":-316.75},{"x":187.82,"y":340.4,"z":-314.28},{"x":188.33,"y":343.46,"z":-310.63},{"x":184.86,"y":346.36,"z":-309.49}]},{"lat":-41.28,"lon":-120.52,"b":[{"x":187.39,"y":332.85,"z":-322.52},{"x":186.83,"y":329.7,"z":-326.06},{"x":190.23,"y":326.66,"z":-327.15},{"x":194.23,"y":326.75,"z":-324.7},{"x":194.8,"y":329.92,"z":-321.13},{"x":191.36,"y":332.97,"z":-320.05}]},{"lat":-39.17,"lon":-120.56,"b":[{"x":193.66,"y":318.93,"z":-332.72},{"x":193.04,"y":315.68,"z":-336.16},{"x":196.4,"y":312.51,"z":-337.18},{"x":200.42,"y":312.58,"z":-334.74},{"x":201.05,"y":315.85,"z":-331.27},{"x":197.66,"y":319.03,"z":-330.27}]},{"lat":-37.06,"lon":-120.59,"b":[{"x":199.69,"y":304.51,"z":-342.52},{"x":199,"y":301.17,"z":-345.85},{"x":202.32,"y":297.89,"z":-346.77},{"x":206.35,"y":297.93,"z":-344.35},{"x":207.06,"y":301.29,"z":-340.99},{"x":203.71,"y":304.58,"z":-340.08}]},{"lat":-34.93,"lon":-120.62,"b":[{"x":206.29,"y":288.82,"z":-352.09},{"x":205.72,"y":286.26,"z":-354.5},{"x":208.17,"y":283.72,"z":-355.12},{"x":211.2,"y":283.73,"z":-353.32},{"x":211.78,"y":286.3,"z":-350.88},{"x":209.31,"y":288.85,"z":-350.27}]},{"lat":-52.58,"lon":-123.15,"b":[{"x":162.63,"y":399.32,"z":-253.04},{"x":162.36,"y":396.95,"z":-256.91},{"x":165.85,"y":394.65,"z":-258.22},{"x":169.63,"y":394.74,"z":-255.61},{"x":169.87,"y":397.14,"z":-251.7},{"x":166.36,"y":399.42,"z":-250.44}]},{"lat":-50.6,"lon":-123.1,"b":[{"x":169.8,"y":388.75,"z":-264.53},{"x":169.49,"y":386.23,"z":-268.38},{"x":172.98,"y":383.77,"z":-269.67},{"x":176.81,"y":383.85,"z":-267.06},{"x":177.1,"y":386.4,"z":-263.17},{"x":173.58,"y":388.84,"z":-261.92}]},{"lat":-48.59,"lon":-123.06,"b":[{"x":178.52,"y":376.34,"z":-276.51},{"x":178.33,"y":374.91,"z":-278.56},{"x":180.2,"y":373.52,"z":-279.23},{"x":182.28,"y":373.55,"z":-277.83},{"x":182.46,"y":374.99,"z":-275.76},{"x":180.57,"y":376.38,"z":-275.11}]},{"lat":-46.54,"lon":-123.01,"b":[{"x":184.12,"y":365.41,"z":-287.23},{"x":183.75,"y":362.81,"z":-290.74},{"x":186.99,"y":360.25,"z":-291.86},{"x":190.63,"y":360.3,"z":-289.44},{"x":190.99,"y":362.92,"z":-285.9},{"x":187.72,"y":365.48,"z":-284.81}]},{"lat":-44.47,"lon":-122.98,"b":[{"x":190.72,"y":353.06,"z":-298.15},{"x":190.27,"y":350.13,"z":-301.88},{"x":193.74,"y":347.23,"z":-303.02},{"x":197.68,"y":347.26,"z":-300.43},{"x":198.13,"y":350.22,"z":-296.67},{"x":194.63,"y":353.12,"z":-295.55}]},{"lat":-42.37,"lon":-122.94,"b":[{"x":197.39,"y":339.91,"z":-308.9},{"x":196.88,"y":336.86,"z":-312.55},{"x":200.32,"y":333.81,"z":-313.63},{"x":204.3,"y":333.83,"z":-311.04},{"x":204.81,"y":336.9,"z":-307.36},{"x":201.34,"y":339.95,"z":-306.3}]},{"lat":-40.25,"lon":-122.9,"b":[{"x":203.86,"y":326.19,"z":-319.32},{"x":203.29,"y":323.02,"z":-322.89},{"x":206.68,"y":319.84,"z":-323.89},{"x":210.68,"y":319.83,"z":-321.31},{"x":211.26,"y":323.02,"z":-317.72},{"x":207.83,"y":326.2,"z":-316.73}]},{"lat":-38.13,"lon":-122.87,"b":[{"x":211.08,"y":310.98,"z":-329.66},{"x":210.63,"y":308.68,"z":-332.11},{"x":212.99,"y":306.35,"z":-332.75},{"x":215.83,"y":306.33,"z":-330.94},{"x":216.28,"y":308.65,"z":-328.48},{"x":213.9,"y":310.98,"z":-327.84}]},{"lat":-53.59,"lon":-126.11,"b":[{"x":171.42,"y":404.56,"z":-238.5},{"x":171.21,"y":402.31,"z":-242.41},{"x":174.72,"y":400.03,"z":-243.68},{"x":178.46,"y":400.01,"z":-240.98},{"x":178.64,"y":402.28,"z":-237.03},{"x":175.11,"y":404.55,"z":-235.81}]},{"lat":-51.62,"lon":-125.96,"b":[{"x":178.78,"y":394.3,"z":-250},{"x":178.53,"y":391.9,"z":-253.91},{"x":182.06,"y":389.46,"z":-255.15},{"x":185.85,"y":389.44,"z":-252.45},{"x":186.06,"y":391.86,"z":-248.5},{"x":182.52,"y":394.28,"z":-247.3}]},{"lat":-49.62,"lon":-125.82,"b":[{"x":186.8,"y":382.85,"z":-261.68},{"x":186.57,"y":380.82,"z":-264.77},{"x":189.37,"y":378.76,"z":-265.74},{"x":192.42,"y":378.73,"z":-263.58},{"x":192.63,"y":380.77,"z":-260.46},{"x":189.81,"y":382.83,"z":-259.53}]},{"lat":-54.51,"lon":-129.21,"b":[{"x":179.96,"y":409.28,"z":-223.69},{"x":179.82,"y":407.15,"z":-227.64},{"x":183.35,"y":404.89,"z":-228.86},{"x":187.05,"y":404.76,"z":-226.08},{"x":187.15,"y":406.91,"z":-222.1},{"x":183.61,"y":409.16,"z":-220.93}]},{"lat":-52.56,"lon":-128.95,"b":[{"x":189.26,"y":398.2,"z":-235.75},{"x":189.17,"y":397.04,"z":-237.77},{"x":190.98,"y":395.8,"z":-238.38},{"x":192.88,"y":395.73,"z":-236.96},{"x":192.96,"y":396.91,"z":-234.93},{"x":191.14,"y":398.13,"z":-234.34}]},{"lat":-50.57,"lon":-128.71,"b":[{"x":198.03,"y":386.6,"z":-247.61},{"x":198,"y":386.23,"z":-248.21},{"x":198.54,"y":385.84,"z":-248.39},{"x":199.11,"y":385.82,"z":-247.96},{"x":199.14,"y":386.19,"z":-247.35},{"x":198.6,"y":386.58,"z":-247.18}]},{"lat":-55.35,"lon":-132.43,"b":[{"x":189.38,"y":412.77,"z":-209.06},{"x":189.33,"y":411.42,"z":-211.75},{"x":191.74,"y":409.89,"z":-212.54},{"x":194.21,"y":409.72,"z":-210.61},{"x":194.24,"y":411.1,"z":-207.89},{"x":191.82,"y":412.61,"z":-207.14}]},{"lat":-53.42,"lon":-132.05,"b":[{"x":197.83,"y":402.65,"z":-220.68},{"x":197.78,"y":401.61,"z":-222.6},{"x":199.5,"y":400.45,"z":-223.16},{"x":201.27,"y":400.33,"z":-221.77},{"x":201.31,"y":401.38,"z":-219.84},{"x":199.58,"y":402.53,"z":-219.31}]},{"lat":-58.29,"lon":-153.21,"b":[{"x":233.9,"y":425.77,"z":-118.29},{"x":233.97,"y":425.51,"z":-119.07},{"x":234.7,"y":425.07,"z":-119.24},{"x":235.34,"y":424.89,"z":-118.63},{"x":235.25,"y":425.15,"z":-117.85},{"x":234.54,"y":425.59,"z":-117.69}]},{"lat":-58.42,"lon":-156.7,"b":[{"x":237.57,"y":427.68,"z":-102.95},{"x":237.93,"y":426.72,"z":-106.06},{"x":240.85,"y":424.91,"z":-106.72},{"x":243.4,"y":424.08,"z":-104.23},{"x":242.99,"y":425.06,"z":-101.12},{"x":240.09,"y":426.86,"z":-100.5}]},{"lat":-56.78,"lon":-155.5,"b":[{"x":248.73,"y":418.62,"z":-113.49},{"x":248.79,"y":418.44,"z":-114.03},{"x":249.29,"y":418.11,"z":-114.15},{"x":249.73,"y":417.96,"z":-113.72},{"x":249.66,"y":418.15,"z":-113.17},{"x":249.16,"y":418.48,"z":-113.07}]},{"lat":-58.46,"lon":-160.12,"b":[{"x":244.55,"y":426.98,"z":-88.64},{"x":244.75,"y":426.54,"z":-90.17},{"x":246.2,"y":425.64,"z":-90.47},{"x":247.43,"y":425.19,"z":-89.24},{"x":247.2,"y":425.64,"z":-87.72},{"x":245.77,"y":426.53,"z":-87.43}]},{"lat":-56.87,"lon":-158.83,"b":[{"x":253.45,"y":419.59,"z":-98.39},{"x":253.64,"y":419.13,"z":-99.84},{"x":255,"y":418.23,"z":-100.14},{"x":256.16,"y":417.8,"z":-98.96},{"x":255.95,"y":418.28,"z":-97.51},{"x":254.6,"y":419.17,"z":-97.23}]},{"lat":-55.29,"lon":-160.8,"b":[{"x":267.24,"y":412.12,"z":-93.29},{"x":267.5,"y":411.54,"z":-95.07},{"x":269.17,"y":410.38,"z":-95.42},{"x":270.55,"y":409.81,"z":-93.96},{"x":270.26,"y":410.4,"z":-92.18},{"x":268.61,"y":411.56,"z":-91.86}]},{"lat":-1.44,"lon":29.74,"b":[{"x":-432.25,"y":14.39,"z":250.8},{"x":-432.7,"y":10.63,"z":250.23},{"x":-434.4,"y":8.78,"z":247.34},{"x":-435.69,"y":10.69,"z":244.97},{"x":-435.26,"y":14.5,"z":245.54},{"x":-433.52,"y":16.35,"z":248.48}]},{"lat":-2.92,"lon":29.23,"b":[{"x":-433.95,"y":27.3,"z":246.76},{"x":-434.48,"y":23.46,"z":246.23},{"x":-436.23,"y":21.61,"z":243.29},{"x":-437.48,"y":23.6,"z":240.84},{"x":-436.97,"y":27.51,"z":241.36},{"x":-435.18,"y":29.35,"z":244.34}]},{"lat":-1.46,"lon":28.17,"b":[{"x":-438.9,"y":14.61,"z":238.96},{"x":-439.32,"y":10.79,"z":238.4},{"x":-440.98,"y":8.91,"z":235.39},{"x":-442.25,"y":10.85,"z":232.9},{"x":-441.85,"y":14.72,"z":233.46},{"x":-440.15,"y":16.6,"z":236.51}]},{"lat":-4.44,"lon":28.71,"b":[{"x":-435.37,"y":40.58,"z":242.4},{"x":-435.99,"y":36.66,"z":241.92},{"x":-437.77,"y":34.82,"z":238.93},{"x":-438.98,"y":36.9,"z":236.39},{"x":-438.38,"y":40.88,"z":236.86},{"x":-436.55,"y":42.72,"z":239.89}]},{"lat":-2.96,"lon":27.63,"b":[{"x":-440.61,"y":27.72,"z":234.61},{"x":-441.12,"y":23.82,"z":234.09},{"x":-442.82,"y":21.94,"z":231.04},{"x":-444.05,"y":23.96,"z":228.45},{"x":-443.56,"y":27.92,"z":228.96},{"x":-441.82,"y":29.8,"z":232.06}]},{"lat":-1.48,"lon":26.56,"b":[{"x":-445.41,"y":14.83,"z":226.58},{"x":-445.81,"y":10.95,"z":226.03},{"x":-447.42,"y":9.04,"z":222.9},{"x":-448.66,"y":11,"z":220.29},{"x":-448.29,"y":14.94,"z":220.82},{"x":-446.64,"y":16.85,"z":224}]},{"lat":-6.01,"lon":28.17,"b":[{"x":-436.46,"y":54.21,"z":237.71},{"x":-437.18,"y":50.22,"z":237.28},{"x":-439.01,"y":48.38,"z":234.26},{"x":-440.17,"y":50.54,"z":231.61},{"x":-439.47,"y":54.6,"z":232.03},{"x":-437.59,"y":56.42,"z":235.1}]},{"lat":-4.51,"lon":27.07,"b":[{"x":-442.02,"y":41.2,"z":229.93},{"x":-442.62,"y":37.22,"z":229.46},{"x":-444.36,"y":35.34,"z":226.36},{"x":-445.54,"y":37.45,"z":223.68},{"x":-444.96,"y":41.49,"z":224.14},{"x":-443.17,"y":43.36,"z":227.29}]},{"lat":-3.01,"lon":25.98,"b":[{"x":-447.12,"y":28.13,"z":221.91},{"x":-447.6,"y":24.17,"z":221.4},{"x":-449.25,"y":22.26,"z":218.23},{"x":-450.45,"y":24.31,"z":215.51},{"x":-449.99,"y":28.33,"z":216},{"x":-448.3,"y":30.24,"z":219.22}]},{"lat":-1.5,"lon":24.9,"b":[{"x":-451.75,"y":15.04,"z":213.65},{"x":-452.12,"y":11.1,"z":213.11},{"x":-453.67,"y":9.17,"z":209.88},{"x":-454.88,"y":11.16,"z":207.13},{"x":-454.54,"y":15.15,"z":207.65},{"x":-452.95,"y":17.09,"z":210.93}]},{"lat":-7.63,"lon":27.61,"b":[{"x":-437.21,"y":68.16,"z":232.69},{"x":-438.03,"y":64.11,"z":232.32},{"x":-439.9,"y":62.28,"z":229.24},{"x":-441,"y":64.53,"z":226.5},{"x":-440.19,"y":68.65,"z":226.86},{"x":-438.28,"y":70.46,"z":229.98}]},{"lat":-6.1,"lon":26.5,"b":[{"x":-443.08,"y":55.03,"z":224.93},{"x":-443.79,"y":50.98,"z":224.51},{"x":-445.57,"y":49.1,"z":221.36},{"x":-446.69,"y":51.29,"z":218.58},{"x":-446.01,"y":55.41,"z":218.98},{"x":-444.18,"y":57.27,"z":222.18}]},{"lat":-4.58,"lon":25.39,"b":[{"x":-448.5,"y":41.81,"z":216.9},{"x":-449.08,"y":37.76,"z":216.45},{"x":-450.77,"y":35.85,"z":213.22},{"x":-451.92,"y":37.99,"z":210.41},{"x":-451.35,"y":42.09,"z":210.85},{"x":-449.62,"y":44,"z":214.12}]},{"lat":-3.05,"lon":24.29,"b":[{"x":-453.43,"y":28.53,"z":208.64},{"x":-453.9,"y":24.51,"z":208.15},{"x":-455.48,"y":22.57,"z":204.86},{"x":-456.65,"y":24.64,"z":202.02},{"x":-456.2,"y":28.72,"z":202.49},{"x":-454.57,"y":30.66,"z":205.83}]},{"lat":-1.52,"lon":23.19,"b":[{"x":-457.87,"y":15.24,"z":200.17},{"x":-458.22,"y":11.25,"z":199.65},{"x":-459.7,"y":9.29,"z":196.31},{"x":-460.87,"y":11.31,"z":193.43},{"x":-460.55,"y":15.35,"z":193.92},{"x":-459.03,"y":17.32,"z":197.32}]},{"lat":-9.28,"lon":27.03,"b":[{"x":-437.58,"y":82.42,"z":227.33},{"x":-438.5,"y":78.31,"z":227.01},{"x":-440.41,"y":76.5,"z":223.89},{"x":-441.44,"y":78.82,"z":221.04},{"x":-440.52,"y":82.99,"z":221.35},{"x":-438.57,"y":84.78,"z":224.52}]},{"lat":-7.74,"lon":25.9,"b":[{"x":-443.78,"y":69.19,"z":219.58},{"x":-444.59,"y":65.07,"z":219.22},{"x":-446.41,"y":63.21,"z":216.02},{"x":-447.47,"y":65.47,"z":213.14},{"x":-446.67,"y":69.66,"z":213.49},{"x":-444.81,"y":71.51,"z":216.74}]},{"lat":-6.19,"lon":24.78,"b":[{"x":-449.52,"y":55.83,"z":211.57},{"x":-450.2,"y":51.71,"z":211.16},{"x":-451.93,"y":49.81,"z":207.89},{"x":-453.01,"y":52.02,"z":204.97},{"x":-452.34,"y":56.2,"z":205.36},{"x":-450.57,"y":58.1,"z":208.69}]},{"lat":-4.64,"lon":23.66,"b":[{"x":-454.77,"y":42.39,"z":203.31},{"x":-455.33,"y":38.29,"z":202.86},{"x":-456.96,"y":36.34,"z":199.52},{"x":-458.06,"y":38.5,"z":196.57},{"x":-457.51,"y":42.66,"z":197},{"x":-455.85,"y":44.61,"z":200.39}]},{"lat":-3.09,"lon":22.55,"b":[{"x":-459.51,"y":28.91,"z":194.82},{"x":-459.95,"y":24.83,"z":194.35},{"x":-461.47,"y":22.86,"z":190.95},{"x":-462.58,"y":24.96,"z":187.97},{"x":-462.16,"y":29.09,"z":188.42},{"x":-460.61,"y":31.07,"z":191.87}]},{"lat":-1.54,"lon":21.44,"b":[{"x":-463.74,"y":15.44,"z":186.15},{"x":-464.06,"y":11.4,"z":185.66},{"x":-465.46,"y":9.41,"z":182.2},{"x":-466.58,"y":11.45,"z":179.19},{"x":-466.29,"y":15.54,"z":179.66},{"x":-464.85,"y":17.54,"z":183.17}]},{"lat":-10.97,"lon":26.43,"b":[{"x":-437.53,"y":96.94,"z":221.61},{"x":-438.57,"y":92.79,"z":221.35},{"x":-440.52,"y":90.99,"z":218.18},{"x":-441.47,"y":93.38,"z":215.24},{"x":-440.43,"y":97.6,"z":215.49},{"x":-438.44,"y":99.37,"z":218.7}]},{"lat":-9.42,"lon":25.29,"b":[{"x":-444.07,"y":83.64,"z":213.89},{"x":-444.99,"y":79.47,"z":213.58},{"x":-446.85,"y":77.62,"z":210.33},{"x":-447.83,"y":79.96,"z":207.35},{"x":-446.92,"y":84.2,"z":207.65},{"x":-445.02,"y":86.03,"z":210.94}]},{"lat":-7.85,"lon":24.14,"b":[{"x":-450.14,"y":70.18,"z":205.89},{"x":-450.94,"y":66,"z":205.54},{"x":-452.7,"y":64.1,"z":202.21},{"x":-453.71,"y":66.39,"z":199.19},{"x":-452.92,"y":70.63,"z":199.53},{"x":-451.12,"y":72.52,"z":202.9}]},{"lat":-6.28,"lon":23.01,"b":[{"x":-455.72,"y":56.6,"z":197.63},{"x":-456.39,"y":52.42,"z":197.24},{"x":-458.06,"y":50.48,"z":193.85},{"x":-459.08,"y":52.72,"z":190.8},{"x":-458.42,"y":56.95,"z":191.17},{"x":-456.72,"y":58.89,"z":194.61}]},{"lat":-4.7,"lon":21.88,"b":[{"x":-460.78,"y":42.95,"z":189.14},{"x":-461.33,"y":38.79,"z":188.72},{"x":-462.88,"y":36.82,"z":185.27},{"x":-463.93,"y":39,"z":182.18},{"x":-463.4,"y":43.21,"z":182.59},{"x":-461.81,"y":45.19,"z":186.09}]},{"lat":-3.13,"lon":20.76,"b":[{"x":-465.31,"y":29.28,"z":180.46},{"x":-465.73,"y":25.15,"z":180.01},{"x":-467.18,"y":23.15,"z":176.5},{"x":-468.23,"y":25.27,"z":173.39},{"x":-467.83,"y":29.45,"z":173.81},{"x":-466.36,"y":31.46,"z":177.37}]},{"lat":-1.56,"lon":19.65,"b":[{"x":-469.31,"y":15.62,"z":171.6},{"x":-469.6,"y":11.53,"z":171.13},{"x":-470.92,"y":9.52,"z":167.58},{"x":-471.98,"y":11.58,"z":164.44},{"x":-471.71,"y":15.72,"z":164.88},{"x":-470.36,"y":17.75,"z":168.49}]},{"lat":-12.7,"lon":25.81,"b":[{"x":-437.04,"y":111.7,"z":215.55},{"x":-438.19,"y":107.5,"z":215.34},{"x":-440.18,"y":105.74,"z":212.13},{"x":-441.04,"y":108.19,"z":209.08},{"x":-439.89,"y":112.44,"z":209.28},{"x":-437.87,"y":114.19,"z":212.53}]},{"lat":-11.13,"lon":24.65,"b":[{"x":-443.92,"y":98.36,"z":207.85},{"x":-444.96,"y":94.14,"z":207.59},{"x":-446.86,"y":92.3,"z":204.3},{"x":-447.75,"y":94.71,"z":201.21},{"x":-446.72,"y":99,"z":201.46},{"x":-444.78,"y":100.81,"z":204.8}]},{"lat":-9.55,"lon":23.49,"b":[{"x":-450.33,"y":84.82,"z":199.86},{"x":-451.25,"y":80.58,"z":199.56},{"x":-453.05,"y":78.69,"z":196.19},{"x":-453.97,"y":81.06,"z":193.07},{"x":-453.06,"y":85.35,"z":193.35},{"x":-451.23,"y":87.23,"z":196.77}]},{"lat":-7.96,"lon":22.34,"b":[{"x":-456.25,"y":71.13,"z":191.61},{"x":-457.04,"y":66.89,"z":191.27},{"x":-458.74,"y":64.95,"z":187.83},{"x":-459.68,"y":67.26,"z":184.68},{"x":-458.9,"y":71.56,"z":185},{"x":-457.17,"y":73.5,"z":188.49}]},{"lat":-6.36,"lon":21.19,"b":[{"x":-461.64,"y":57.34,"z":183.13},{"x":-462.3,"y":53.1,"z":182.75},{"x":-463.89,"y":51.13,"z":179.25},{"x":-464.85,"y":53.38,"z":176.06},{"x":-464.21,"y":57.67,"z":176.41},{"x":-462.59,"y":59.65,"z":179.97}]},{"lat":-4.76,"lon":20.06,"b":[{"x":-466.5,"y":43.49,"z":174.43},{"x":-467.03,"y":39.27,"z":174.03},{"x":-468.5,"y":37.26,"z":170.47},{"x":-469.47,"y":39.46,"z":167.25},{"x":-468.96,"y":43.73,"z":167.63},{"x":-467.46,"y":45.74,"z":171.24}]},{"lat":-3.16,"lon":18.93,"b":[{"x":-470.8,"y":29.62,"z":165.56},{"x":-471.2,"y":25.44,"z":165.14},{"x":-472.55,"y":23.41,"z":161.53},{"x":-473.53,"y":25.55,"z":158.29},{"x":-473.15,"y":29.78,"z":158.68},{"x":-471.77,"y":31.82,"z":162.35}]},{"lat":-1.58,"lon":17.81,"b":[{"x":-474.53,"y":15.8,"z":156.55},{"x":-474.8,"y":11.66,"z":156.11},{"x":-476.03,"y":9.62,"z":152.46},{"x":-477.01,"y":11.7,"z":149.2},{"x":-476.77,"y":15.89,"z":149.6},{"x":-475.51,"y":17.94,"z":153.31}]},{"lat":-14.47,"lon":25.17,"b":[{"x":-436.08,"y":126.65,"z":209.13},{"x":-437.36,"y":122.43,"z":208.98},{"x":-439.37,"y":120.68,"z":205.72},{"x":-440.14,"y":123.19,"z":202.57},{"x":-438.86,"y":127.47,"z":202.71},{"x":-436.81,"y":129.18,"z":206.01}]},{"lat":-12.89,"lon":23.99,"b":[{"x":-443.3,"y":113.3,"z":201.45},{"x":-444.46,"y":109.04,"z":201.26},{"x":-446.39,"y":107.23,"z":197.91},{"x":-447.2,"y":109.7,"z":194.72},{"x":-446.03,"y":114.02,"z":194.91},{"x":-444.07,"y":115.81,"z":198.3}]},{"lat":-11.29,"lon":22.81,"b":[{"x":-450.06,"y":99.72,"z":193.49},{"x":-451.1,"y":95.44,"z":193.24},{"x":-452.93,"y":93.56,"z":189.82},{"x":-453.77,"y":95.98,"z":186.6},{"x":-452.73,"y":100.33,"z":186.83},{"x":-450.86,"y":102.19,"z":190.3}]},{"lat":-9.68,"lon":21.64,"b":[{"x":-456.32,"y":85.95,"z":185.25},{"x":-457.23,"y":81.65,"z":184.96},{"x":-458.96,"y":79.72,"z":181.47},{"x":-459.82,"y":82.1,"z":178.21},{"x":-458.92,"y":86.46,"z":178.48},{"x":-457.16,"y":88.38,"z":182.02}]},{"lat":-8.06,"lon":20.48,"b":[{"x":-462.06,"y":72.04,"z":176.77},{"x":-462.84,"y":67.74,"z":176.44},{"x":-464.46,"y":65.76,"z":172.88},{"x":-465.33,"y":68.09,"z":169.6},{"x":-464.57,"y":72.45,"z":169.9},{"x":-462.92,"y":74.42,"z":173.51}]},{"lat":-6.43,"lon":19.33,"b":[{"x":-467.25,"y":58.04,"z":168.07},{"x":-467.89,"y":53.75,"z":167.72},{"x":-469.39,"y":51.73,"z":164.1},{"x":-470.28,"y":54.01,"z":160.78},{"x":-469.65,"y":58.35,"z":161.11},{"x":-468.12,"y":60.36,"z":164.78}]},{"lat":-4.81,"lon":18.19,"b":[{"x":-471.87,"y":43.99,"z":159.18},{"x":-472.38,"y":39.72,"z":158.81},{"x":-473.76,"y":37.68,"z":155.14},{"x":-474.66,"y":39.9,"z":151.8},{"x":-474.17,"y":44.21,"z":152.15},{"x":-472.76,"y":46.26,"z":155.87}]},{"lat":-3.2,"lon":17.06,"b":[{"x":-475.91,"y":29.95,"z":150.15},{"x":-476.29,"y":25.72,"z":149.76},{"x":-477.54,"y":23.66,"z":146.05},{"x":-478.44,"y":25.82,"z":142.69},{"x":-478.09,"y":30.1,"z":143.05},{"x":-476.81,"y":32.16,"z":146.81}]},{"lat":-1.59,"lon":15.94,"b":[{"x":-479.37,"y":15.96,"z":141},{"x":-479.62,"y":11.78,"z":140.6},{"x":-480.74,"y":9.72,"z":136.86},{"x":-481.64,"y":11.82,"z":133.48},{"x":-481.42,"y":16.04,"z":133.85},{"x":-480.28,"y":18.12,"z":137.64}]},{"lat":-16.27,"lon":24.51,"b":[{"x":-434.63,"y":141.74,"z":202.36},{"x":-436.03,"y":137.5,"z":202.27},{"x":-438.07,"y":135.79,"z":198.96},{"x":-438.74,"y":138.34,"z":195.71},{"x":-437.33,"y":142.63,"z":195.8},{"x":-435.26,"y":144.31,"z":199.14}]},{"lat":-14.68,"lon":23.31,"b":[{"x":-442.19,"y":128.42,"z":194.71},{"x":-443.48,"y":124.14,"z":194.57},{"x":-445.44,"y":122.35,"z":191.18},{"x":-446.14,"y":124.87,"z":187.89},{"x":-444.84,"y":129.21,"z":188.03},{"x":-442.86,"y":130.97,"z":191.46}]},{"lat":-13.06,"lon":22.11,"b":[{"x":-449.3,"y":114.83,"z":186.76},{"x":-450.46,"y":110.51,"z":186.57},{"x":-452.33,"y":108.65,"z":183.11},{"x":-453.06,"y":111.13,"z":179.78},{"x":-451.89,"y":115.51,"z":179.96},{"x":-450,"y":117.35,"z":183.47}]},{"lat":-11.43,"lon":20.93,"b":[{"x":-455.91,"y":101.02,"z":178.54},{"x":-456.94,"y":96.67,"z":178.31},{"x":-458.71,"y":94.75,"z":174.76},{"x":-459.46,"y":97.19,"z":171.4},{"x":-458.43,"y":101.59,"z":171.62},{"x":-456.64,"y":103.5,"z":175.21}]},{"lat":-9.8,"lon":19.75,"b":[{"x":-462,"y":87.02,"z":170.06},{"x":-462.9,"y":82.66,"z":169.79},{"x":-464.55,"y":80.69,"z":166.18},{"x":-465.33,"y":83.08,"z":162.79},{"x":-464.43,"y":87.49,"z":163.04},{"x":-462.75,"y":89.46,"z":166.7}]},{"lat":-8.15,"lon":18.58,"b":[{"x":-467.53,"y":72.89,"z":161.36},{"x":-468.29,"y":68.54,"z":161.06},{"x":-469.83,"y":66.52,"z":157.39},{"x":-470.62,"y":68.86,"z":153.98},{"x":-469.86,"y":73.27,"z":154.25},{"x":-468.3,"y":75.29,"z":157.97}]},{"lat":-6.5,"lon":17.43,"b":[{"x":-472.48,"y":58.69,"z":152.47},{"x":-473.11,"y":54.35,"z":152.15},{"x":-474.52,"y":52.3,"z":148.43},{"x":-475.32,"y":54.59,"z":144.98},{"x":-474.71,"y":58.98,"z":145.28},{"x":-473.28,"y":61.03,"z":149.06}]},{"lat":-4.86,"lon":16.28,"b":[{"x":-476.85,"y":44.45,"z":143.43},{"x":-477.34,"y":40.14,"z":143.08},{"x":-478.62,"y":38.07,"z":139.32},{"x":-479.43,"y":40.3,"z":135.85},{"x":-478.95,"y":44.66,"z":136.17},{"x":-477.65,"y":46.74,"z":139.98}]},{"lat":-3.23,"lon":15.15,"b":[{"x":-480.62,"y":30.24,"z":134.26},{"x":-480.97,"y":25.97,"z":133.9},{"x":-482.12,"y":23.89,"z":130.1},{"x":-482.93,"y":26.06,"z":126.62},{"x":-482.59,"y":30.38,"z":126.95},{"x":-481.43,"y":32.48,"z":130.79}]},{"lat":-1.61,"lon":14.03,"b":[{"x":-483.79,"y":16.11,"z":125},{"x":-484.01,"y":11.89,"z":124.63},{"x":-485.02,"y":9.8,"z":120.82},{"x":-485.83,"y":11.92,"z":117.32},{"x":-485.63,"y":16.18,"z":117.65},{"x":-484.6,"y":18.29,"z":121.51}]},{"lat":-18.09,"lon":23.82,"b":[{"x":-432.66,"y":156.92,"z":195.24},{"x":-434.19,"y":152.69,"z":195.21},{"x":-436.25,"y":151.01,"z":191.87},{"x":-436.81,"y":153.59,"z":188.52},{"x":-435.27,"y":157.88,"z":188.55},{"x":-433.18,"y":159.53,"z":191.93}]},{"lat":-16.49,"lon":22.6,"b":[{"x":-440.56,"y":143.67,"z":187.62},{"x":-441.97,"y":139.38,"z":187.54},{"x":-443.96,"y":137.61,"z":184.1},{"x":-444.55,"y":140.17,"z":180.72},{"x":-443.12,"y":144.52,"z":180.8},{"x":-441.12,"y":146.26,"z":184.27}]},{"lat":-14.87,"lon":21.39,"b":[{"x":-448.01,"y":130.11,"z":179.7},{"x":-449.3,"y":125.77,"z":179.56},{"x":-451.2,"y":123.93,"z":176.05},{"x":-451.82,"y":126.46,"z":172.62},{"x":-450.52,"y":130.86,"z":172.75},{"x":-448.6,"y":132.67,"z":176.31}]},{"lat":-13.23,"lon":20.18,"b":[{"x":-454.97,"y":116.29,"z":171.49},{"x":-456.14,"y":111.91,"z":171.31},{"x":-457.93,"y":110,"z":167.72},{"x":-458.58,"y":112.49,"z":164.26},{"x":-457.41,"y":116.92,"z":164.43},{"x":-455.6,"y":118.81,"z":168.06}]},{"lat":-11.57,"lon":18.99,"b":[{"x":-461.41,"y":102.24,"z":163.02},{"x":-462.45,"y":97.84,"z":162.8},{"x":-464.13,"y":95.87,"z":159.15},{"x":-464.8,"y":98.32,"z":155.66},{"x":-463.76,"y":102.77,"z":155.86},{"x":-462.06,"y":104.73,"z":159.56}]},{"lat":-9.91,"lon":17.81,"b":[{"x":-467.3,"y":88.02,"z":154.33},{"x":-468.19,"y":83.61,"z":154.08},{"x":-469.75,"y":81.6,"z":150.36},{"x":-470.44,"y":84,"z":146.84},{"x":-469.55,"y":88.46,"z":147.07},{"x":-467.97,"y":90.47,"z":150.84}]},{"lat":-8.24,"lon":16.64,"b":[{"x":-472.6,"y":73.69,"z":145.43},{"x":-473.36,"y":69.28,"z":145.15},{"x":-474.79,"y":67.23,"z":141.38},{"x":-475.49,"y":69.58,"z":137.84},{"x":-474.74,"y":74.03,"z":138.09},{"x":-473.29,"y":76.09,"z":141.92}]},{"lat":-6.57,"lon":15.48,"b":[{"x":-477.3,"y":59.29,"z":136.38},{"x":-477.92,"y":54.9,"z":136.08},{"x":-479.22,"y":52.82,"z":132.26},{"x":-479.93,"y":55.12,"z":128.7},{"x":-479.33,"y":59.55,"z":128.97},{"x":-478,"y":61.64,"z":132.83}]},{"lat":-4.91,"lon":14.34,"b":[{"x":-481.39,"y":44.88,"z":127.19},{"x":-481.87,"y":40.52,"z":126.87},{"x":-483.03,"y":38.42,"z":123.03},{"x":-483.75,"y":40.67,"z":119.45},{"x":-483.29,"y":45.06,"z":119.73},{"x":-482.1,"y":47.18,"z":123.63}]},{"lat":-3.26,"lon":13.21,"b":[{"x":-484.87,"y":30.51,"z":117.91},{"x":-485.2,"y":26.2,"z":117.59},{"x":-486.23,"y":24.09,"z":113.72},{"x":-486.94,"y":26.28,"z":110.12},{"x":-486.63,"y":30.63,"z":110.41},{"x":-485.58,"y":32.76,"z":114.33}]},{"lat":-1.62,"lon":12.09,"b":[{"x":-487.73,"y":16.24,"z":108.58},{"x":-487.93,"y":11.98,"z":108.25},{"x":-488.82,"y":9.88,"z":104.37},{"x":-489.52,"y":12.01,"z":100.77},{"x":-489.34,"y":16.3,"z":101.05},{"x":-488.44,"y":18.43,"z":104.98}]},{"lat":-19.94,"lon":23.11,"b":[{"x":-430.16,"y":172.14,"z":187.8},{"x":-431.81,"y":167.92,"z":187.82},{"x":-433.9,"y":166.28,"z":184.43},{"x":-434.34,"y":168.89,"z":180.99},{"x":-432.66,"y":173.16,"z":180.97},{"x":-430.56,"y":174.77,"z":184.4}]},{"lat":-18.34,"lon":21.87,"b":[{"x":-438.38,"y":159,"z":180.2},{"x":-439.93,"y":154.71,"z":180.17},{"x":-441.94,"y":152.97,"z":176.69},{"x":-442.41,"y":155.56,"z":173.21},{"x":-440.85,"y":159.91,"z":173.24},{"x":-438.83,"y":161.61,"z":176.76}]},{"lat":-16.71,"lon":20.64,"b":[{"x":-446.18,"y":145.5,"z":172.3},{"x":-447.61,"y":141.15,"z":172.22},{"x":-449.52,"y":139.34,"z":168.66},{"x":-450.03,"y":141.9,"z":165.14},{"x":-448.59,"y":146.31,"z":165.21},{"x":-446.65,"y":148.09,"z":168.82}]},{"lat":-15.05,"lon":19.42,"b":[{"x":-453.49,"y":131.7,"z":164.11},{"x":-454.79,"y":127.31,"z":163.98},{"x":-456.61,"y":125.42,"z":160.34},{"x":-457.14,"y":127.95,"z":156.79},{"x":-455.83,"y":132.4,"z":156.91},{"x":-454,"y":134.27,"z":160.59}]},{"lat":-13.38,"lon":18.21,"b":[{"x":-460.29,"y":117.64,"z":155.65},{"x":-461.45,"y":113.21,"z":155.48},{"x":-463.16,"y":111.26,"z":151.78},{"x":-463.71,"y":113.75,"z":148.19},{"x":-462.54,"y":118.23,"z":148.34},{"x":-460.82,"y":120.17,"z":152.1}]},{"lat":-11.7,"lon":17.01,"b":[{"x":-466.53,"y":103.37,"z":146.96},{"x":-467.56,"y":98.92,"z":146.76},{"x":-469.14,"y":96.91,"z":142.99},{"x":-469.71,"y":99.36,"z":139.38},{"x":-468.68,"y":103.86,"z":139.56},{"x":-467.08,"y":105.87,"z":143.37}]},{"lat":-10.01,"lon":15.82,"b":[{"x":-472.18,"y":88.94,"z":138.07},{"x":-473.07,"y":84.48,"z":137.84},{"x":-474.53,"y":82.43,"z":134.02},{"x":-475.11,"y":84.83,"z":130.38},{"x":-474.23,"y":89.34,"z":130.58},{"x":-472.76,"y":91.39,"z":134.45}]},{"lat":-8.32,"lon":14.65,"b":[{"x":-477.23,"y":74.41,"z":129},{"x":-477.98,"y":69.95,"z":128.75},{"x":-479.3,"y":67.87,"z":124.89},{"x":-479.9,"y":70.22,"z":121.23},{"x":-479.16,"y":74.72,"z":121.45},{"x":-477.82,"y":76.82,"z":125.36}]},{"lat":-6.63,"lon":13.5,"b":[{"x":-481.66,"y":59.83,"z":119.81},{"x":-482.26,"y":55.4,"z":119.54},{"x":-483.45,"y":53.28,"z":115.64},{"x":-484.05,"y":55.59,"z":111.96},{"x":-483.46,"y":60.06,"z":112.2},{"x":-482.26,"y":62.19,"z":116.15}]},{"lat":-4.95,"lon":12.36,"b":[{"x":-485.46,"y":45.26,"z":110.51},{"x":-485.91,"y":40.86,"z":110.23},{"x":-486.96,"y":38.73,"z":106.31},{"x":-487.56,"y":40.99,"z":102.62},{"x":-487.12,"y":45.42,"z":102.86},{"x":-486.06,"y":47.56,"z":106.83}]},{"lat":-3.28,"lon":11.23,"b":[{"x":-488.62,"y":30.75,"z":101.16},{"x":-488.94,"y":26.4,"z":100.87},{"x":-489.84,"y":24.27,"z":96.94},{"x":-490.44,"y":26.47,"z":93.24},{"x":-490.14,"y":30.85,"z":93.48},{"x":-489.23,"y":33,"z":97.47}]},{"lat":-1.63,"lon":10.12,"b":[{"x":-491.4,"y":15.77,"z":90.7},{"x":-491.53,"y":12.65,"z":90.5},{"x":-492.08,"y":11.11,"z":87.64},{"x":-492.51,"y":12.67,"z":84.95},{"x":-492.39,"y":15.81,"z":85.12},{"x":-491.83,"y":17.37,"z":88.01}]},{"lat":-21.81,"lon":22.37,"b":[{"x":-427.11,"y":187.35,"z":180.04},{"x":-428.89,"y":183.16,"z":180.11},{"x":-430.99,"y":181.55,"z":176.68},{"x":-431.31,"y":184.17,"z":173.15},{"x":-429.5,"y":188.41,"z":173.09},{"x":-427.4,"y":189.98,"z":176.55}]},{"lat":-20.21,"lon":21.11,"b":[{"x":-435.65,"y":174.34,"z":172.47},{"x":-437.33,"y":170.07,"z":172.48},{"x":-439.35,"y":168.37,"z":168.97},{"x":-439.71,"y":170.98,"z":165.39},{"x":-438.01,"y":175.3,"z":165.38},{"x":-435.97,"y":176.97,"z":168.93}]},{"lat":-18.57,"lon":19.86,"b":[{"x":-443.78,"y":160.95,"z":164.58},{"x":-445.34,"y":156.61,"z":164.55},{"x":-447.28,"y":154.82,"z":160.95},{"x":-447.66,"y":157.41,"z":157.34},{"x":-446.08,"y":161.8,"z":157.36},{"x":-444.13,"y":163.56,"z":161.01}]},{"lat":-16.91,"lon":18.62,"b":[{"x":-451.44,"y":147.22,"z":156.4},{"x":-452.88,"y":142.81,"z":156.33},{"x":-454.71,"y":140.95,"z":152.64},{"x":-455.12,"y":143.51,"z":149},{"x":-453.67,"y":147.96,"z":149.07},{"x":-451.82,"y":149.81,"z":152.79}]},{"lat":-15.22,"lon":17.4,"b":[{"x":-458.58,"y":133.18,"z":147.96},{"x":-459.89,"y":128.73,"z":147.84},{"x":-461.62,"y":126.79,"z":144.09},{"x":-462.05,"y":129.32,"z":140.41},{"x":-460.73,"y":133.82,"z":140.52},{"x":-458.99,"y":135.74,"z":144.31}]},{"lat":-13.52,"lon":16.18,"b":[{"x":-465.18,"y":118.9,"z":139.28},{"x":-466.35,"y":114.41,"z":139.12},{"x":-467.96,"y":112.41,"z":135.31},{"x":-468.41,"y":114.9,"z":131.6},{"x":-467.23,"y":119.43,"z":131.74},{"x":-465.61,"y":121.42,"z":135.6}]},{"lat":-11.81,"lon":14.98,"b":[{"x":-471.2,"y":104.41,"z":130.39},{"x":-472.22,"y":99.9,"z":130.2},{"x":-473.7,"y":97.85,"z":126.33},{"x":-474.17,"y":100.3,"z":122.6},{"x":-473.14,"y":104.85,"z":122.77},{"x":-471.65,"y":106.9,"z":126.68}]},{"lat":-10.1,"lon":13.8,"b":[{"x":-476.6,"y":89.78,"z":121.32},{"x":-477.48,"y":85.27,"z":121.11},{"x":-478.83,"y":83.17,"z":117.2},{"x":-479.3,"y":85.58,"z":113.45},{"x":-478.43,"y":90.13,"z":113.63},{"x":-477.07,"y":92.23,"z":117.59}]},{"lat":-8.39,"lon":12.63,"b":[{"x":-481.38,"y":75.06,"z":112.11},{"x":-482.11,"y":70.56,"z":111.89},{"x":-483.32,"y":68.43,"z":107.94},{"x":-483.8,"y":70.8,"z":104.17},{"x":-483.07,"y":75.33,"z":104.37},{"x":-481.85,"y":77.47,"z":108.36}]},{"lat":-6.68,"lon":11.48,"b":[{"x":-485.51,"y":60.31,"z":102.81},{"x":-486.1,"y":55.84,"z":102.57},{"x":-487.16,"y":53.69,"z":98.6},{"x":-487.65,"y":56,"z":94.82},{"x":-487.07,"y":60.51,"z":95.02},{"x":-486,"y":62.67,"z":99.04}]},{"lat":-4.98,"lon":10.35,"b":[{"x":-489,"y":45.59,"z":93.44},{"x":-489.44,"y":41.15,"z":93.19},{"x":-490.36,"y":39,"z":89.21},{"x":-490.84,"y":41.26,"z":85.42},{"x":-490.41,"y":45.73,"z":85.63},{"x":-489.49,"y":47.9,"z":89.66}]},{"lat":-3.3,"lon":9.23,"b":[{"x":-492.42,"y":29.5,"z":81.37},{"x":-492.52,"y":28.05,"z":81.29},{"x":-492.78,"y":27.34,"z":79.97},{"x":-492.94,"y":28.07,"z":78.72},{"x":-492.84,"y":29.53,"z":78.78},{"x":-492.58,"y":30.25,"z":80.12}]},{"lat":-23.7,"lon":21.6,"b":[{"x":-423.51,"y":202.47,"z":171.98},{"x":-425.42,"y":198.33,"z":172.1},{"x":-427.53,"y":196.76,"z":168.64},{"x":-427.72,"y":199.38,"z":165.02},{"x":-425.78,"y":203.58,"z":164.91},{"x":-423.68,"y":205.1,"z":168.41}]},{"lat":-22.09,"lon":20.32,"b":[{"x":-432.35,"y":189.65,"z":164.43},{"x":-434.16,"y":185.41,"z":164.49},{"x":-436.2,"y":183.74,"z":160.94},{"x":-436.42,"y":186.35,"z":157.28},{"x":-434.59,"y":190.64,"z":157.22},{"x":-432.55,"y":192.27,"z":160.81}]},{"lat":-20.45,"lon":19.06,"b":[{"x":-440.8,"y":176.4,"z":156.56},{"x":-442.5,"y":172.08,"z":156.57},{"x":-444.44,"y":170.32,"z":152.93},{"x":-444.7,"y":172.92,"z":149.24},{"x":-442.98,"y":177.29,"z":149.22},{"x":-441.02,"y":179.02,"z":152.9}]},{"lat":-18.78,"lon":17.8,"b":[{"x":-448.79,"y":162.77,"z":148.4},{"x":-450.37,"y":158.38,"z":148.37},{"x":-452.22,"y":156.53,"z":144.64},{"x":-452.5,"y":159.11,"z":140.91},{"x":-450.9,"y":163.55,"z":140.94},{"x":-449.04,"y":165.37,"z":144.7}]},{"lat":-17.09,"lon":16.56,"b":[{"x":-456.28,"y":148.8,"z":139.96},{"x":-457.74,"y":144.35,"z":139.89},{"x":-459.48,"y":142.42,"z":136.1},{"x":-459.78,"y":144.98,"z":132.33},{"x":-458.32,"y":149.48,"z":132.4},{"x":-456.56,"y":151.38,"z":136.23}]},{"lat":-15.38,"lon":15.33,"b":[{"x":-463.24,"y":134.54,"z":131.29},{"x":-464.55,"y":130.04,"z":131.18},{"x":-466.17,"y":128.05,"z":127.32},{"x":-466.49,"y":130.57,"z":123.53},{"x":-465.17,"y":135.11,"z":123.63},{"x":-463.54,"y":137.09,"z":127.53}]},{"lat":-13.65,"lon":14.12,"b":[{"x":-469.61,"y":120.03,"z":122.4},{"x":-470.79,"y":115.5,"z":122.26},{"x":-472.28,"y":113.45,"z":118.35},{"x":-472.62,"y":115.94,"z":114.53},{"x":-471.44,"y":120.51,"z":114.65},{"x":-469.93,"y":122.55,"z":118.61}]},{"lat":-11.92,"lon":12.92,"b":[{"x":-475.38,"y":105.34,"z":113.34},{"x":-476.4,"y":100.79,"z":113.17},{"x":-477.76,"y":98.69,"z":109.21},{"x":-478.11,"y":101.14,"z":105.38},{"x":-477.09,"y":105.72,"z":105.52},{"x":-475.71,"y":107.82,"z":109.52}]},{"lat":-10.18,"lon":11.74,"b":[{"x":-480.51,"y":90.51,"z":104.13},{"x":-481.39,"y":85.96,"z":103.94},{"x":-482.61,"y":83.83,"z":99.95},{"x":-482.96,"y":86.24,"z":96.1},{"x":-482.09,"y":90.82,"z":96.25},{"x":-480.86,"y":92.96,"z":100.29}]},{"lat":-8.45,"lon":10.58,"b":[{"x":-484.99,"y":75.62,"z":94.81},{"x":-485.72,"y":71.09,"z":94.62},{"x":-486.79,"y":68.93,"z":90.6},{"x":-487.16,"y":71.29,"z":86.73},{"x":-486.44,"y":75.85,"z":86.9},{"x":-485.35,"y":78.03,"z":90.96}]},{"lat":-6.72,"lon":9.44,"b":[{"x":-488.82,"y":60.72,"z":85.43},{"x":-489.39,"y":56.21,"z":85.23},{"x":-490.32,"y":54.04,"z":81.2},{"x":-490.68,"y":56.35,"z":77.32},{"x":-490.12,"y":60.89,"z":77.49},{"x":-489.18,"y":63.08,"z":81.56}]},{"lat":-5.01,"lon":8.31,"b":[{"x":-492.04,"y":45.73,"z":75.76},{"x":-492.44,"y":41.55,"z":75.57},{"x":-493.17,"y":39.51,"z":71.79},{"x":-493.51,"y":41.63,"z":68.16},{"x":-493.12,"y":45.84,"z":68.31},{"x":-492.38,"y":47.9,"z":72.13}]},{"lat":-25.6,"lon":20.81,"b":[{"x":-419.36,"y":217.46,"z":163.65},{"x":-421.39,"y":213.37,"z":163.81},{"x":-423.5,"y":211.85,"z":160.31},{"x":-423.57,"y":214.46,"z":156.62},{"x":-421.5,"y":218.59,"z":156.47},{"x":-419.4,"y":220.07,"z":160.01}]},{"lat":-23.99,"lon":19.51,"b":[{"x":-428.48,"y":204.85,"z":156.11},{"x":-430.42,"y":200.66,"z":156.22},{"x":-432.46,"y":199.03,"z":152.63},{"x":-432.55,"y":201.64,"z":148.89},{"x":-430.59,"y":205.87,"z":148.79},{"x":-428.55,"y":207.46,"z":152.42}]},{"lat":-22.35,"lon":18.22,"b":[{"x":-437.23,"y":191.79,"z":148.25},{"x":-439.06,"y":187.5,"z":148.31},{"x":-441.02,"y":185.77,"z":144.63},{"x":-441.14,"y":188.37,"z":140.86},{"x":-439.28,"y":192.7,"z":140.81},{"x":-437.32,"y":194.39,"z":144.52}]},{"lat":-20.68,"lon":16.95,"b":[{"x":-445.54,"y":178.3,"z":140.11},{"x":-447.26,"y":173.93,"z":140.12},{"x":-449.12,"y":172.11,"z":136.36},{"x":-449.26,"y":174.69,"z":132.55},{"x":-447.53,"y":179.11,"z":132.54},{"x":-445.66,"y":180.9,"z":136.33}]},{"lat":-18.98,"lon":15.69,"b":[{"x":-453.37,"y":164.44,"z":131.68},{"x":-454.97,"y":159.99,"z":131.66},{"x":-456.72,"y":158.09,"z":127.82},{"x":-456.88,"y":160.65,"z":123.98},{"x":-455.28,"y":165.14,"z":124},{"x":-453.52,"y":167.02,"z":127.87}]},{"lat":-17.25,"lon":14.45,"b":[{"x":-460.68,"y":150.23,"z":123.02},{"x":-462.14,"y":145.73,"z":122.95},{"x":-463.77,"y":143.76,"z":119.05},{"x":-463.96,"y":146.3,"z":115.18},{"x":-462.49,"y":150.84,"z":115.24},{"x":-460.84,"y":152.8,"z":119.17}]},{"lat":-15.51,"lon":13.22,"b":[{"x":-467.41,"y":135.75,"z":114.14},{"x":-468.73,"y":131.2,"z":114.04},{"x":-470.24,"y":129.16,"z":110.08},{"x":-470.44,"y":131.67,"z":106.19},{"x":-469.11,"y":136.25,"z":106.27},{"x":-467.59,"y":138.29,"z":110.26}]},{"lat":-13.76,"lon":12.01,"b":[{"x":-473.53,"y":121.03,"z":105.07},{"x":-474.71,"y":116.46,"z":104.95},{"x":-476.08,"y":114.36,"z":100.95},{"x":-476.29,"y":116.84,"z":97.03},{"x":-475.12,"y":121.45,"z":97.13},{"x":-473.73,"y":123.54,"z":101.17}]},{"lat":-12.01,"lon":10.82,"b":[{"x":-479.03,"y":106.14,"z":95.86},{"x":-480.05,"y":101.56,"z":95.72},{"x":-481.28,"y":99.42,"z":91.68},{"x":-481.51,"y":101.86,"z":87.75},{"x":-480.48,"y":106.48,"z":87.87},{"x":-479.24,"y":108.62,"z":91.94}]},{"lat":-10.25,"lon":9.65,"b":[{"x":-483.87,"y":91.15,"z":86.54},{"x":-484.74,"y":86.56,"z":86.38},{"x":-485.83,"y":84.39,"z":82.32},{"x":-486.05,"y":86.79,"z":78.38},{"x":-485.19,"y":91.4,"z":78.51},{"x":-484.09,"y":93.59,"z":82.61}]},{"lat":-8.5,"lon":8.5,"b":[{"x":-488.04,"y":76.1,"z":77.15},{"x":-488.76,"y":71.53,"z":76.98},{"x":-489.7,"y":69.34,"z":72.91},{"x":-489.93,"y":71.69,"z":68.96},{"x":-489.22,"y":76.29,"z":69.09},{"x":-488.27,"y":78.5,"z":73.2}]},{"lat":-6.76,"lon":7.36,"b":[{"x":-491.54,"y":61.06,"z":67.72},{"x":-492.11,"y":56.52,"z":67.56},{"x":-492.9,"y":54.32,"z":63.48},{"x":-493.13,"y":56.64,"z":59.53},{"x":-492.57,"y":61.19,"z":59.66},{"x":-491.77,"y":63.41,"z":63.77}]},{"lat":-5.03,"lon":6.25,"b":[{"x":-494.37,"y":46.09,"z":58.31},{"x":-494.79,"y":41.6,"z":58.15},{"x":-495.43,"y":39.41,"z":54.08},{"x":-495.66,"y":41.67,"z":50.13},{"x":-495.25,"y":46.18,"z":50.25},{"x":-494.6,"y":48.4,"z":54.36}]},{"lat":-27.5,"lon":19.99,"b":[{"x":-414.66,"y":232.26,"z":155.08},{"x":-416.81,"y":228.23,"z":155.27},{"x":-418.91,"y":226.75,"z":151.74},{"x":-418.85,"y":229.34,"z":147.98},{"x":-416.67,"y":233.4,"z":147.8},{"x":-414.58,"y":234.83,"z":151.36}]},{"lat":-25.9,"lon":18.67,"b":[{"x":-424.04,"y":219.89,"z":147.54},{"x":-426.11,"y":215.76,"z":147.69},{"x":-428.14,"y":214.17,"z":144.06},{"x":-428.1,"y":216.76,"z":140.26},{"x":-426.01,"y":220.93,"z":140.12},{"x":-423.98,"y":222.48,"z":143.78}]},{"lat":-24.26,"lon":17.36,"b":[{"x":-433.07,"y":207.04,"z":139.7},{"x":-435.03,"y":202.81,"z":139.79},{"x":-436.99,"y":201.11,"z":136.08},{"x":-436.98,"y":203.7,"z":132.24},{"x":-434.98,"y":207.97,"z":132.15},{"x":-433.03,"y":209.63,"z":135.89}]},{"lat":-22.58,"lon":16.07,"b":[{"x":-441.68,"y":193.74,"z":131.56},{"x":-443.54,"y":189.41,"z":131.61},{"x":-445.41,"y":187.62,"z":127.81},{"x":-445.41,"y":190.19,"z":123.93},{"x":-443.53,"y":194.57,"z":123.88},{"x":-441.67,"y":196.32,"z":127.71}]},{"lat":-20.88,"lon":14.8,"b":[{"x":-449.84,"y":180.02,"z":123.14},{"x":-451.58,"y":175.61,"z":123.16},{"x":-453.34,"y":173.73,"z":119.29},{"x":-453.36,"y":176.29,"z":115.37},{"x":-451.61,"y":180.74,"z":115.36},{"x":-449.84,"y":182.6,"z":119.26}]},{"lat":-19.15,"lon":13.54,"b":[{"x":-457.48,"y":165.93,"z":114.49},{"x":-459.09,"y":161.44,"z":114.46},{"x":-460.73,"y":159.48,"z":110.52},{"x":-460.77,"y":162.02,"z":106.58},{"x":-459.15,"y":166.54,"z":106.6},{"x":-457.5,"y":168.49,"z":110.57}]},{"lat":-17.4,"lon":12.3,"b":[{"x":-464.56,"y":151.5,"z":105.61},{"x":-466.03,"y":146.96,"z":105.55},{"x":-467.55,"y":144.93,"z":101.56},{"x":-467.61,"y":147.45,"z":97.59},{"x":-466.13,"y":152.02,"z":97.64},{"x":-464.6,"y":154.05,"z":101.66}]},{"lat":-15.63,"lon":11.08,"b":[{"x":-471.05,"y":136.81,"z":96.55},{"x":-472.37,"y":132.22,"z":96.46},{"x":-473.76,"y":130.13,"z":92.42},{"x":-473.83,"y":132.62,"z":88.43},{"x":-472.5,"y":137.24,"z":88.5},{"x":-471.1,"y":139.33,"z":92.58}]},{"lat":-13.86,"lon":9.88,"b":[{"x":-476.9,"y":121.89,"z":87.34},{"x":-478.08,"y":117.29,"z":87.23},{"x":-479.32,"y":115.14,"z":83.16},{"x":-479.4,"y":117.6,"z":79.15},{"x":-478.23,"y":122.24,"z":79.23},{"x":-476.97,"y":124.39,"z":83.34}]},{"lat":-12.08,"lon":8.7,"b":[{"x":-482.1,"y":106.83,"z":78.01},{"x":-483.13,"y":102.21,"z":77.89},{"x":-484.22,"y":100.02,"z":73.79},{"x":-484.31,"y":102.45,"z":69.78},{"x":-483.29,"y":107.1,"z":69.87},{"x":-482.18,"y":109.29,"z":74.01}]},{"lat":-10.31,"lon":7.53,"b":[{"x":-486.63,"y":91.67,"z":68.61},{"x":-487.5,"y":87.05,"z":68.49},{"x":-488.45,"y":84.85,"z":64.37},{"x":-488.54,"y":87.23,"z":60.35},{"x":-487.68,"y":91.87,"z":60.45},{"x":-486.72,"y":94.09,"z":64.6}]},{"lat":-8.54,"lon":6.39,"b":[{"x":-490.48,"y":76.48,"z":59.18},{"x":-491.19,"y":71.89,"z":59.05},{"x":-491.99,"y":69.66,"z":54.94},{"x":-492.08,"y":72.01,"z":50.92},{"x":-491.38,"y":76.62,"z":51.01},{"x":-490.57,"y":78.87,"z":55.16}]},{"lat":-6.79,"lon":5.27,"b":[{"x":-493.65,"y":61.32,"z":49.76},{"x":-494.21,"y":56.77,"z":49.63},{"x":-494.85,"y":54.54,"z":45.53},{"x":-494.94,"y":56.85,"z":41.51},{"x":-494.39,"y":61.42,"z":41.59},{"x":-493.74,"y":63.67,"z":45.74}]},{"lat":-29.4,"lon":19.13,"b":[{"x":-409.46,"y":246.77,"z":146.22},{"x":-411.69,"y":242.9,"z":146.44},{"x":-413.74,"y":241.49,"z":142.94},{"x":-413.55,"y":243.99,"z":139.19},{"x":-411.3,"y":247.89,"z":138.99},{"x":-409.26,"y":249.26,"z":142.51}]},{"lat":-27.81,"lon":17.79,"b":[{"x":-419.04,"y":234.71,"z":138.75},{"x":-421.22,"y":230.65,"z":138.93},{"x":-423.25,"y":229.1,"z":135.27},{"x":-423.08,"y":231.65,"z":131.41},{"x":-420.86,"y":235.75,"z":131.25},{"x":-418.85,"y":237.25,"z":134.93}]},{"lat":-26.17,"lon":16.47,"b":[{"x":-428.32,"y":222.11,"z":130.91},{"x":-430.41,"y":217.94,"z":131.04},{"x":-432.37,"y":216.28,"z":127.3},{"x":-432.22,"y":218.84,"z":123.39},{"x":-430.09,"y":223.04,"z":123.27},{"x":-428.15,"y":224.66,"z":127.05}]},{"lat":-24.5,"lon":15.16,"b":[{"x":-437.22,"y":209.03,"z":122.78},{"x":-439.21,"y":204.75,"z":122.87},{"x":-441.07,"y":202.99,"z":119.04},{"x":-440.94,"y":205.55,"z":115.09},{"x":-438.92,"y":209.86,"z":115.02},{"x":-437.07,"y":211.58,"z":118.87}]},{"lat":-22.79,"lon":13.87,"b":[{"x":-445.68,"y":195.49,"z":114.37},{"x":-447.55,"y":191.12,"z":114.42},{"x":-449.32,"y":189.27,"z":110.52},{"x":-449.2,"y":191.81,"z":106.54},{"x":-447.3,"y":196.22,"z":106.5},{"x":-445.54,"y":198.04,"z":110.43}]},{"lat":-21.06,"lon":12.6,"b":[{"x":-453.64,"y":181.54,"z":105.72},{"x":-455.39,"y":177.09,"z":105.73},{"x":-457.04,"y":175.15,"z":101.76},{"x":-456.94,"y":177.68,"z":97.75},{"x":-455.17,"y":182.17,"z":97.74},{"x":-453.52,"y":184.09,"z":101.74}]},{"lat":-19.3,"lon":11.35,"b":[{"x":-461.06,"y":167.23,"z":96.85},{"x":-462.68,"y":162.7,"z":96.83},{"x":-464.21,"y":160.68,"z":92.8},{"x":-464.12,"y":163.2,"z":88.76},{"x":-462.49,"y":167.75,"z":88.78},{"x":-460.96,"y":169.76,"z":92.84}]},{"lat":-17.52,"lon":10.11,"b":[{"x":-467.9,"y":152.59,"z":87.79},{"x":-469.38,"y":148.02,"z":87.74},{"x":-470.77,"y":145.93,"z":83.67},{"x":-470.69,"y":148.42,"z":79.61},{"x":-469.21,"y":153.03,"z":79.65},{"x":-467.81,"y":155.11,"z":83.75}]},{"lat":-15.73,"lon":8.9,"b":[{"x":-474.12,"y":137.7,"z":78.58},{"x":-475.44,"y":133.08,"z":78.51},{"x":-476.7,"y":130.94,"z":74.4},{"x":-476.63,"y":133.41,"z":70.33},{"x":-475.3,"y":138.05,"z":70.38},{"x":-474.04,"y":140.19,"z":74.52}]},{"lat":-13.94,"lon":7.71,"b":[{"x":-479.68,"y":122.61,"z":69.25},{"x":-480.86,"y":117.97,"z":69.17},{"x":-481.96,"y":115.77,"z":65.03},{"x":-481.9,"y":118.22,"z":60.95},{"x":-480.73,"y":122.88,"z":61.02},{"x":-479.61,"y":125.08,"z":65.18}]},{"lat":-12.14,"lon":6.54,"b":[{"x":-484.57,"y":107.38,"z":59.85},{"x":-485.59,"y":102.73,"z":59.76},{"x":-486.55,"y":100.51,"z":55.61},{"x":-486.49,"y":102.91,"z":51.53},{"x":-485.47,"y":107.58,"z":51.59},{"x":-484.51,"y":109.82,"z":55.77}]},{"lat":-10.35,"lon":5.4,"b":[{"x":-488.78,"y":92.07,"z":50.42},{"x":-489.64,"y":87.44,"z":50.32},{"x":-490.44,"y":85.19,"z":46.17},{"x":-490.39,"y":87.57,"z":42.09},{"x":-489.53,"y":92.22,"z":42.15},{"x":-488.72,"y":94.48,"z":46.33}]},{"lat":-8.57,"lon":4.27,"b":[{"x":-492.29,"y":76.76,"z":40.98},{"x":-493,"y":72.15,"z":40.89},{"x":-493.65,"y":69.9,"z":36.75},{"x":-493.6,"y":72.23,"z":32.67},{"x":-492.89,"y":76.86,"z":32.73},{"x":-492.24,"y":79.14,"z":36.9}]},{"lat":-6.8,"lon":3.17,"b":[{"x":-495.12,"y":61.5,"z":31.59},{"x":-495.67,"y":56.93,"z":31.51},{"x":-496.17,"y":54.69,"z":27.39},{"x":-496.12,"y":56.98,"z":23.32},{"x":-495.57,"y":61.56,"z":23.36},{"x":-495.07,"y":63.84,"z":27.51}]},{"lat":-29.71,"lon":16.88,"b":[{"x":-413.49,"y":249.24,"z":129.77},{"x":-415.78,"y":245.27,"z":129.98},{"x":-417.8,"y":243.76,"z":126.29},{"x":-417.5,"y":246.27,"z":122.38},{"x":-415.17,"y":250.27,"z":122.19},{"x":-413.17,"y":251.73,"z":125.9}]},{"lat":-28.08,"lon":15.54,"b":[{"x":-423,"y":236.93,"z":121.93},{"x":-425.22,"y":232.83,"z":122.09},{"x":-427.16,"y":231.22,"z":118.32},{"x":-426.87,"y":233.73,"z":114.36},{"x":-424.62,"y":237.85,"z":114.22},{"x":-422.7,"y":239.43,"z":118.01}]},{"lat":-26.42,"lon":14.22,"b":[{"x":-432.15,"y":224.1,"z":113.8},{"x":-434.27,"y":219.89,"z":113.92},{"x":-436.13,"y":218.17,"z":110.06},{"x":-435.86,"y":220.68,"z":106.06},{"x":-433.71,"y":224.92,"z":105.96},{"x":-431.86,"y":226.61,"z":109.84}]},{"lat":-24.71,"lon":12.91,"b":[{"x":-440.89,"y":210.79,"z":105.4},{"x":-442.91,"y":206.47,"z":105.48},{"x":-444.67,"y":204.65,"z":101.54},{"x":-444.41,"y":207.16,"z":97.51},{"x":-442.37,"y":211.5,"z":97.45},{"x":-440.62,"y":213.3,"z":101.4}]},{"lat":-22.97,"lon":11.63,"b":[{"x":-449.16,"y":197.02,"z":96.75},{"x":-451.06,"y":192.62,"z":96.79},{"x":-452.71,"y":190.7,"z":92.79},{"x":-452.46,"y":193.21,"z":88.73},{"x":-450.55,"y":197.64,"z":88.69},{"x":-448.9,"y":199.54,"z":92.72}]},{"lat":-21.21,"lon":10.36,"b":[{"x":-456.91,"y":182.85,"z":87.88},{"x":-458.67,"y":178.37,"z":87.89},{"x":-460.21,"y":176.36,"z":83.83},{"x":-459.97,"y":178.86,"z":79.74},{"x":-458.19,"y":183.37,"z":79.74},{"x":-456.66,"y":185.36,"z":83.82}]},{"lat":-19.43,"lon":9.12,"b":[{"x":-464.08,"y":168.32,"z":78.82},{"x":-465.71,"y":163.77,"z":78.81},{"x":-467.11,"y":161.69,"z":74.7},{"x":-466.89,"y":164.17,"z":70.59},{"x":-465.25,"y":168.75,"z":70.61},{"x":-463.85,"y":170.82,"z":74.73}]},{"lat":-17.62,"lon":7.9,"b":[{"x":-470.65,"y":153.49,"z":69.62},{"x":-472.14,"y":148.88,"z":69.58},{"x":-473.4,"y":146.74,"z":65.44},{"x":-473.18,"y":149.21,"z":61.31},{"x":-471.69,"y":153.84,"z":61.34},{"x":-470.43,"y":155.98,"z":65.51}]},{"lat":-15.81,"lon":6.7,"b":[{"x":-476.58,"y":138.41,"z":60.29},{"x":-477.91,"y":133.77,"z":60.24},{"x":-479.02,"y":131.58,"z":56.07},{"x":-478.81,"y":134.02,"z":51.94},{"x":-477.48,"y":138.68,"z":51.97},{"x":-476.36,"y":140.88,"z":56.16}]},{"lat":-14,"lon":5.53,"b":[{"x":-481.83,"y":123.16,"z":50.89},{"x":-483.01,"y":118.49,"z":50.83},{"x":-483.97,"y":116.26,"z":46.65},{"x":-483.77,"y":118.67,"z":42.51},{"x":-482.59,"y":123.35,"z":42.55},{"x":-481.62,"y":125.6,"z":46.75}]},{"lat":-12.18,"lon":4.37,"b":[{"x":-486.4,"y":107.78,"z":41.45},{"x":-487.42,"y":103.12,"z":41.38},{"x":-488.23,"y":100.85,"z":37.2},{"x":-488.03,"y":103.24,"z":33.06},{"x":-487.01,"y":107.92,"z":33.1},{"x":-486.19,"y":110.2,"z":37.31}]},{"lat":-10.38,"lon":3.24,"b":[{"x":-490.27,"y":92.36,"z":32.01},{"x":-491.13,"y":87.7,"z":31.95},{"x":-491.79,"y":85.43,"z":27.78},{"x":-491.59,"y":87.78,"z":23.65},{"x":-490.73,"y":92.44,"z":23.68},{"x":-490.07,"y":94.74,"z":27.88}]},{"lat":-8.59,"lon":2.14,"b":[{"x":-493.45,"y":76.94,"z":22.62},{"x":-494.15,"y":72.32,"z":22.56},{"x":-494.65,"y":70.04,"z":18.41},{"x":-494.45,"y":72.36,"z":14.29},{"x":-493.75,"y":76.99,"z":14.31},{"x":-493.25,"y":79.3,"z":18.49}]},{"lat":-6.81,"lon":1.06,"b":[{"x":-495.93,"y":61.61,"z":13.3},{"x":-496.48,"y":57.03,"z":13.26},{"x":-496.83,"y":54.76,"z":9.14},{"x":-496.63,"y":57.04,"z":5.04},{"x":-496.08,"y":61.63,"z":5.04},{"x":-495.73,"y":63.93,"z":9.18}]},{"lat":-5.06,"lon":0,"b":[{"x":-497.95,"y":44.87,"z":1.32},{"x":-498.08,"y":43.41,"z":1.31},{"x":-498.15,"y":42.69,"z":0},{"x":-498.08,"y":43.41,"z":-1.31},{"x":-497.95,"y":44.87,"z":-1.32},{"x":-497.89,"y":45.6,"z":0}]},{"lat":-31.61,"lon":15.94,"b":[{"x":-409.12,"y":262.27,"z":117.56},{"x":-409.51,"y":261.65,"z":117.59},{"x":-409.83,"y":261.41,"z":117},{"x":-409.76,"y":261.81,"z":116.36},{"x":-409.37,"y":262.43,"z":116.33},{"x":-409.05,"y":262.66,"z":116.93}]},{"lat":-29.99,"lon":14.58,"b":[{"x":-417.12,"y":251.43,"z":112.79},{"x":-419.45,"y":247.43,"z":112.97},{"x":-421.38,"y":245.85,"z":109.18},{"x":-420.96,"y":248.31,"z":105.18},{"x":-418.6,"y":252.33,"z":105.02},{"x":-416.69,"y":253.88,"z":108.83}]},{"lat":-28.33,"lon":13.24,"b":[{"x":-426.5,"y":238.89,"z":104.66},{"x":-428.75,"y":234.77,"z":104.8},{"x":-430.6,"y":233.08,"z":100.92},{"x":-430.18,"y":235.54,"z":96.88},{"x":-427.91,"y":239.69,"z":96.76},{"x":-426.08,"y":241.35,"z":100.66}]},{"lat":-26.63,"lon":11.92,"b":[{"x":-435.5,"y":225.84,"z":96.26},{"x":-437.64,"y":221.6,"z":96.36},{"x":-439.4,"y":219.8,"z":92.41},{"x":-438.99,"y":222.27,"z":88.33},{"x":-436.83,"y":226.53,"z":88.24},{"x":-435.08,"y":228.3,"z":92.22}]},{"lat":-24.89,"lon":10.62,"b":[{"x":-444.05,"y":212.3,"z":87.61},{"x":-446.08,"y":207.95,"z":87.68},{"x":-447.73,"y":206.06,"z":83.65},{"x":-447.34,"y":208.53,"z":79.55},{"x":-445.28,"y":212.9,"z":79.49},{"x":-443.64,"y":214.77,"z":83.53}]},{"lat":-23.13,"lon":9.35,"b":[{"x":-452.1,"y":198.31,"z":78.74},{"x":-454.01,"y":193.88,"z":78.78},{"x":-455.54,"y":191.89,"z":74.7},{"x":-455.15,"y":194.36,"z":70.56},{"x":-453.23,"y":198.82,"z":70.54},{"x":-451.7,"y":200.78,"z":74.64}]},{"lat":-21.34,"lon":8.1,"b":[{"x":-459.6,"y":183.93,"z":69.69},{"x":-461.38,"y":179.42,"z":69.7},{"x":-462.78,"y":177.35,"z":65.57},{"x":-462.4,"y":179.81,"z":61.41},{"x":-460.61,"y":184.34,"z":61.41},{"x":-459.21,"y":186.4,"z":65.56}]},{"lat":-19.52,"lon":6.87,"b":[{"x":-466.51,"y":169.2,"z":60.48},{"x":-468.15,"y":164.62,"z":60.47},{"x":-469.41,"y":162.48,"z":56.3},{"x":-469.04,"y":164.93,"z":52.13},{"x":-467.4,"y":169.53,"z":52.14},{"x":-466.13,"y":171.66,"z":56.33}]},{"lat":-17.7,"lon":5.66,"b":[{"x":-472.79,"y":154.19,"z":51.16},{"x":-474.28,"y":149.56,"z":51.13},{"x":-475.4,"y":147.36,"z":46.94},{"x":-475.03,"y":149.79,"z":42.76},{"x":-473.54,"y":154.44,"z":42.78},{"x":-472.41,"y":156.64,"z":46.99}]},{"lat":-15.87,"lon":4.48,"b":[{"x":-478.4,"y":138.95,"z":41.76},{"x":-479.74,"y":134.28,"z":41.72},{"x":-480.71,"y":132.04,"z":37.51},{"x":-480.34,"y":134.45,"z":33.33},{"x":-479.01,"y":139.13,"z":33.35},{"x":-478.04,"y":141.38,"z":37.58}]},{"lat":-14.04,"lon":3.32,"b":[{"x":-483.33,"y":123.54,"z":32.32},{"x":-484.51,"y":118.86,"z":32.27},{"x":-485.33,"y":116.58,"z":28.07},{"x":-484.97,"y":118.97,"z":23.88},{"x":-483.79,"y":123.66,"z":23.9},{"x":-482.97,"y":125.95,"z":28.13}]},{"lat":-12.21,"lon":2.19,"b":[{"x":-487.57,"y":108.04,"z":22.88},{"x":-488.59,"y":103.36,"z":22.84},{"x":-489.24,"y":101.06,"z":18.64},{"x":-488.89,"y":103.42,"z":14.46},{"x":-487.87,"y":108.11,"z":14.48},{"x":-487.21,"y":110.43,"z":18.69}]},{"lat":-10.39,"lon":1.08,"b":[{"x":-491.1,"y":92.51,"z":13.48},{"x":-491.96,"y":87.85,"z":13.45},{"x":-492.46,"y":85.54,"z":9.27},{"x":-492.11,"y":87.87,"z":5.11},{"x":-491.25,"y":92.54,"z":5.11},{"x":-490.75,"y":94.87,"z":9.3}]},{"lat":-8.59,"lon":0,"b":[{"x":-493.94,"y":77.02,"z":4.16},{"x":-494.64,"y":72.39,"z":4.14},{"x":-494.99,"y":70.09,"z":0},{"x":-494.64,"y":72.39,"z":-4.14},{"x":-493.94,"y":77.02,"z":-4.16},{"x":-493.58,"y":79.35,"z":0}]},{"lat":-6.81,"lon":-1.06,"b":[{"x":-496.08,"y":61.63,"z":-5.04},{"x":-496.63,"y":57.04,"z":-5.04},{"x":-496.83,"y":54.76,"z":-9.14},{"x":-496.48,"y":57.03,"z":-13.26},{"x":-495.93,"y":61.61,"z":-13.3},{"x":-495.73,"y":63.93,"z":-9.18}]},{"lat":-5.06,"lon":-2.09,"b":[{"x":-497.58,"y":46.27,"z":-14.31},{"x":-497.96,"y":41.99,"z":-14.29},{"x":-498.01,"y":39.85,"z":-18.12},{"x":-497.68,"y":41.96,"z":-22},{"x":-497.3,"y":46.24,"z":-22.06},{"x":-497.25,"y":48.42,"z":-18.21}]},{"lat":-31.89,"lon":13.59,"b":[{"x":-410.83,"y":265.48,"z":103.29},{"x":-413.12,"y":261.83,"z":103.48},{"x":-414.91,"y":260.38,"z":99.9},{"x":-414.39,"y":262.62,"z":96.12},{"x":-412.08,"y":266.29,"z":95.96},{"x":-410.31,"y":267.7,"z":99.55}]},{"lat":-30.23,"lon":12.23,"b":[{"x":-420.29,"y":253.34,"z":95.39},{"x":-422.65,"y":249.32,"z":95.55},{"x":-424.48,"y":247.66,"z":91.65},{"x":-423.94,"y":250.07,"z":87.58},{"x":-421.55,"y":254.11,"z":87.45},{"x":-419.74,"y":255.73,"z":91.36}]},{"lat":-28.54,"lon":10.9,"b":[{"x":-429.51,"y":240.58,"z":86.99},{"x":-431.78,"y":236.43,"z":87.11},{"x":-433.53,"y":234.66,"z":83.13},{"x":-432.98,"y":237.08,"z":79.02},{"x":-430.69,"y":241.25,"z":78.93},{"x":-428.96,"y":242.98,"z":82.91}]},{"lat":-26.81,"lon":9.59,"b":[{"x":-438.32,"y":227.3,"z":78.34},{"x":-440.48,"y":223.03,"z":78.42},{"x":-442.12,"y":221.16,"z":74.38},{"x":-441.58,"y":223.58,"z":70.24},{"x":-439.4,"y":227.87,"z":70.17},{"x":-437.77,"y":229.71,"z":74.23}]},{"lat":-25.04,"lon":8.3,"b":[{"x":-446.65,"y":213.54,"z":69.47},{"x":-448.7,"y":209.17,"z":69.53},{"x":-450.23,"y":207.21,"z":65.43},{"x":-449.69,"y":209.63,"z":61.26},{"x":-447.63,"y":214.01,"z":61.22},{"x":-446.11,"y":215.96,"z":65.33}]},{"lat":-23.25,"lon":7.04,"b":[{"x":-454.46,"y":199.35,"z":60.42},{"x":-456.38,"y":194.89,"z":60.45},{"x":-457.78,"y":192.83,"z":56.3},{"x":-457.25,"y":195.25,"z":52.11},{"x":-455.32,"y":199.73,"z":52.09},{"x":-453.92,"y":201.77,"z":56.25}]},{"lat":-21.43,"lon":5.8,"b":[{"x":-461.69,"y":184.77,"z":51.21},{"x":-463.48,"y":180.23,"z":51.22},{"x":-464.74,"y":178.1,"z":47.03},{"x":-464.22,"y":180.51,"z":42.83},{"x":-462.42,"y":185.07,"z":42.83},{"x":-461.16,"y":187.19,"z":47.02}]},{"lat":-19.6,"lon":4.59,"b":[{"x":-468.31,"y":169.86,"z":41.89},{"x":-469.95,"y":165.26,"z":41.88},{"x":-471.07,"y":163.06,"z":37.67},{"x":-470.55,"y":165.46,"z":33.45},{"x":-468.9,"y":170.08,"z":33.46},{"x":-467.78,"y":172.27,"z":37.68}]},{"lat":-17.75,"lon":3.4,"b":[{"x":-474.28,"y":154.67,"z":32.49},{"x":-475.77,"y":150.03,"z":32.47},{"x":-476.74,"y":147.78,"z":28.24},{"x":-476.22,"y":150.17,"z":24.02},{"x":-474.73,"y":154.83,"z":24.03},{"x":-473.76,"y":157.08,"z":28.27}]},{"lat":-15.9,"lon":2.24,"b":[{"x":-479.57,"y":139.29,"z":23.05},{"x":-480.9,"y":134.61,"z":23.02},{"x":-481.72,"y":132.32,"z":18.8},{"x":-481.21,"y":134.69,"z":14.58},{"x":-479.87,"y":139.38,"z":14.59},{"x":-479.05,"y":141.68,"z":18.83}]},{"lat":-14.06,"lon":1.11,"b":[{"x":-484.17,"y":123.75,"z":13.61},{"x":-485.34,"y":119.06,"z":13.58},{"x":-486.01,"y":116.75,"z":9.37},{"x":-485.5,"y":119.1,"z":5.16},{"x":-484.32,"y":123.8,"z":5.16},{"x":-483.65,"y":126.13,"z":9.39}]},{"lat":-12.22,"lon":0,"b":[{"x":-488.06,"y":108.15,"z":4.21},{"x":-489.08,"y":103.46,"z":4.19},{"x":-489.58,"y":101.13,"z":0},{"x":-489.08,"y":103.46,"z":-4.19},{"x":-488.06,"y":108.15,"z":-4.21},{"x":-487.55,"y":110.51,"z":0}]},{"lat":-10.39,"lon":-1.08,"b":[{"x":-491.25,"y":92.54,"z":-5.11},{"x":-492.11,"y":87.87,"z":-5.11},{"x":-492.46,"y":85.54,"z":-9.27},{"x":-491.96,"y":87.85,"z":-13.45},{"x":-491.1,"y":92.51,"z":-13.48},{"x":-490.75,"y":94.87,"z":-9.3}]},{"lat":-8.59,"lon":-2.14,"b":[{"x":-493.75,"y":76.99,"z":-14.31},{"x":-494.45,"y":72.36,"z":-14.29},{"x":-494.65,"y":70.04,"z":-18.41},{"x":-494.15,"y":72.32,"z":-22.56},{"x":-493.45,"y":76.94,"z":-22.62},{"x":-493.25,"y":79.3,"z":-18.49}]},{"lat":-6.8,"lon":-3.17,"b":[{"x":-495.57,"y":61.56,"z":-23.36},{"x":-496.12,"y":56.98,"z":-23.32},{"x":-496.17,"y":54.69,"z":-27.39},{"x":-495.67,"y":56.93,"z":-31.51},{"x":-495.12,"y":61.5,"z":-31.59},{"x":-495.07,"y":63.84,"z":-27.51}]},{"lat":-5.05,"lon":-4.18,"b":[{"x":-496.73,"y":45.43,"z":-33.78},{"x":-496.98,"y":42.65,"z":-33.74},{"x":-496.93,"y":41.25,"z":-36.21},{"x":-496.62,"y":42.62,"z":-38.73},{"x":-496.37,"y":45.4,"z":-38.8},{"x":-496.43,"y":46.82,"z":-36.32}]},{"lat":-36.89,"lon":15.37,"b":[{"x":-384.76,"y":300.62,"z":107.48},{"x":-385.84,"y":299.19,"z":107.6},{"x":-386.66,"y":298.67,"z":106.1},{"x":-386.38,"y":299.6,"z":104.47},{"x":-385.29,"y":301.04,"z":104.37},{"x":-384.48,"y":301.55,"z":105.87}]},{"lat":-32.12,"lon":11.19,"b":[{"x":-413.55,"y":267.4,"z":86.03},{"x":-416.01,"y":263.49,"z":86.2},{"x":-417.83,"y":261.87,"z":82.29},{"x":-417.15,"y":264.2,"z":78.2},{"x":-414.65,"y":268.13,"z":78.06},{"x":-412.87,"y":269.72,"z":81.98}]},{"lat":-30.44,"lon":9.84,"b":[{"x":-422.96,"y":254.96,"z":77.62},{"x":-425.35,"y":250.91,"z":77.76},{"x":-427.08,"y":249.17,"z":73.77},{"x":-426.39,"y":251.52,"z":69.64},{"x":-423.99,"y":255.58,"z":69.53},{"x":-422.28,"y":257.28,"z":73.53}]},{"lat":-28.71,"lon":8.52,"b":[{"x":-431.99,"y":241.97,"z":68.97},{"x":-434.28,"y":237.8,"z":69.07},{"x":-435.91,"y":235.95,"z":65.02},{"x":-435.23,"y":238.31,"z":60.85},{"x":-432.92,"y":242.5,"z":60.78},{"x":-431.31,"y":244.31,"z":64.84}]},{"lat":-26.95,"lon":7.22,"b":[{"x":-440.58,"y":228.47,"z":60.1},{"x":-442.76,"y":224.19,"z":60.17},{"x":-444.28,"y":222.24,"z":56.06},{"x":-443.6,"y":224.61,"z":51.87},{"x":-441.4,"y":228.91,"z":51.82},{"x":-439.9,"y":230.83,"z":55.94}]},{"lat":-25.15,"lon":5.95,"b":[{"x":-448.67,"y":214.51,"z":51.05},{"x":-450.73,"y":210.12,"z":51.09},{"x":-452.13,"y":208.08,"z":46.93},{"x":-451.45,"y":210.45,"z":42.72},{"x":-449.37,"y":214.85,"z":42.69},{"x":-447.99,"y":216.87,"z":46.86}]},{"lat":-23.33,"lon":4.71,"b":[{"x":-456.2,"y":200.12,"z":41.84},{"x":-458.14,"y":195.64,"z":41.86},{"x":-459.4,"y":193.52,"z":37.67},{"x":-458.73,"y":195.88,"z":33.44},{"x":-456.78,"y":200.37,"z":33.43},{"x":-455.52,"y":202.48,"z":37.63}]},{"lat":-21.49,"lon":3.49,"b":[{"x":-463.15,"y":185.35,"z":32.52},{"x":-464.94,"y":180.8,"z":32.52},{"x":-466.06,"y":178.61,"z":28.3},{"x":-465.39,"y":180.97,"z":24.06},{"x":-463.59,"y":185.53,"z":24.06},{"x":-462.47,"y":187.72,"z":28.29}]},{"lat":-19.64,"lon":2.3,"b":[{"x":-469.46,"y":170.27,"z":23.12},{"x":-471.1,"y":165.66,"z":23.11},{"x":-472.08,"y":163.41,"z":18.87},{"x":-471.41,"y":165.77,"z":14.63},{"x":-469.76,"y":170.39,"z":14.64},{"x":-468.78,"y":172.64,"z":18.88}]},{"lat":-17.78,"lon":1.14,"b":[{"x":-475.1,"y":154.94,"z":13.68},{"x":-476.6,"y":150.29,"z":13.67},{"x":-477.42,"y":147.99,"z":9.43},{"x":-476.75,"y":150.34,"z":5.19},{"x":-475.25,"y":155,"z":5.19},{"x":-474.43,"y":157.3,"z":9.44}]},{"lat":-15.92,"lon":0,"b":[{"x":-480.06,"y":139.43,"z":4.24},{"x":-481.4,"y":134.75,"z":4.23},{"x":-482.06,"y":132.41,"z":0},{"x":-481.4,"y":134.75,"z":-4.23},{"x":-480.06,"y":139.43,"z":-4.24},{"x":-479.39,"y":141.78,"z":0}]},{"lat":-14.06,"lon":-1.11,"b":[{"x":-484.32,"y":123.8,"z":-5.16},{"x":-485.5,"y":119.1,"z":-5.16},{"x":-486.01,"y":116.75,"z":-9.37},{"x":-485.34,"y":119.06,"z":-13.58},{"x":-484.17,"y":123.75,"z":-13.61},{"x":-483.65,"y":126.13,"z":-9.39}]},{"lat":-12.21,"lon":-2.19,"b":[{"x":-487.87,"y":108.11,"z":-14.48},{"x":-488.89,"y":103.42,"z":-14.46},{"x":-489.24,"y":101.06,"z":-18.64},{"x":-488.59,"y":103.36,"z":-22.84},{"x":-487.57,"y":108.04,"z":-22.88},{"x":-487.21,"y":110.43,"z":-18.69}]},{"lat":-10.38,"lon":-3.24,"b":[{"x":-490.73,"y":92.44,"z":-23.68},{"x":-491.59,"y":87.78,"z":-23.65},{"x":-491.79,"y":85.43,"z":-27.78},{"x":-491.13,"y":87.7,"z":-31.95},{"x":-490.27,"y":92.36,"z":-32.01},{"x":-490.07,"y":94.74,"z":-27.88}]},{"lat":-8.57,"lon":-4.27,"b":[{"x":-492.89,"y":76.86,"z":-32.73},{"x":-493.6,"y":72.23,"z":-32.67},{"x":-493.65,"y":69.9,"z":-36.75},{"x":-493,"y":72.15,"z":-40.89},{"x":-492.29,"y":76.76,"z":-40.98},{"x":-492.24,"y":79.14,"z":-36.9}]},{"lat":-6.79,"lon":-5.27,"b":[{"x":-494.39,"y":61.42,"z":-41.59},{"x":-494.94,"y":56.85,"z":-41.51},{"x":-494.85,"y":54.54,"z":-45.53},{"x":-494.21,"y":56.77,"z":-49.63},{"x":-493.65,"y":61.32,"z":-49.76},{"x":-493.74,"y":63.67,"z":-45.74}]},{"lat":-5.03,"lon":-6.25,"b":[{"x":-495.24,"y":45.99,"z":-50.57},{"x":-495.61,"y":41.85,"z":-50.46},{"x":-495.41,"y":39.76,"z":-54.09},{"x":-494.82,"y":41.78,"z":-57.83},{"x":-494.43,"y":45.91,"z":-57.98},{"x":-494.64,"y":48.04,"z":-54.35}]},{"lat":-37.19,"lon":12.9,"b":[{"x":-387.57,"y":302.67,"z":90.27},{"x":-388.52,"y":301.42,"z":90.36},{"x":-389.21,"y":300.94,"z":89.02},{"x":-388.92,"y":301.72,"z":87.59},{"x":-387.96,"y":302.98,"z":87.51},{"x":-387.29,"y":303.45,"z":88.85}]},{"lat":-33.99,"lon":10.11,"b":[{"x":-406.73,"y":280.67,"z":75.72},{"x":-408.7,"y":277.76,"z":75.86},{"x":-410.07,"y":276.54,"z":72.84},{"x":-409.45,"y":278.26,"z":69.69},{"x":-407.47,"y":281.19,"z":69.58},{"x":-406.12,"y":282.38,"z":72.6}]},{"lat":-32.32,"lon":8.74,"b":[{"x":-415.88,"y":268.91,"z":68.2},{"x":-418.37,"y":264.98,"z":68.34},{"x":-420.08,"y":263.28,"z":64.35},{"x":-419.27,"y":265.54,"z":60.21},{"x":-416.76,"y":269.49,"z":60.1},{"x":-415.08,"y":271.16,"z":64.1}]},{"lat":-30.6,"lon":7.41,"b":[{"x":-425.11,"y":256.25,"z":59.55},{"x":-427.51,"y":252.18,"z":59.65},{"x":-429.12,"y":250.37,"z":55.59},{"x":-428.31,"y":252.65,"z":51.42},{"x":-425.89,"y":256.72,"z":51.34},{"x":-424.29,"y":258.51,"z":55.41}]},{"lat":-28.84,"lon":6.11,"b":[{"x":-433.91,"y":243.05,"z":50.68},{"x":-436.22,"y":238.86,"z":50.75},{"x":-437.73,"y":236.94,"z":46.63},{"x":-436.91,"y":239.23,"z":42.43},{"x":-434.59,"y":243.43,"z":42.38},{"x":-433.1,"y":245.32,"z":46.51}]},{"lat":-27.05,"lon":4.83,"b":[{"x":-442.26,"y":229.34,"z":41.62},{"x":-444.45,"y":225.04,"z":41.67},{"x":-445.84,"y":223.02,"z":37.5},{"x":-445.02,"y":225.32,"z":33.28},{"x":-442.81,"y":229.63,"z":33.25},{"x":-441.44,"y":231.63,"z":37.43}]},{"lat":-25.23,"lon":3.58,"b":[{"x":-450.07,"y":215.18,"z":32.42},{"x":-452.15,"y":210.78,"z":32.44},{"x":-453.41,"y":208.67,"z":28.24},{"x":-452.58,"y":210.98,"z":24},{"x":-450.5,"y":215.39,"z":23.99},{"x":-449.25,"y":217.48,"z":28.2}]},{"lat":-23.39,"lon":2.36,"b":[{"x":-457.32,"y":200.61,"z":23.09},{"x":-459.26,"y":196.12,"z":23.1},{"x":-460.38,"y":193.93,"z":18.87},{"x":-459.56,"y":196.24,"z":14.63},{"x":-457.61,"y":200.74,"z":14.62},{"x":-456.5,"y":202.91,"z":18.86}]},{"lat":-21.53,"lon":1.16,"b":[{"x":-463.95,"y":185.68,"z":13.69},{"x":-465.75,"y":181.11,"z":13.69},{"x":-466.73,"y":178.86,"z":9.45},{"x":-465.9,"y":181.17,"z":5.2},{"x":-464.1,"y":185.74,"z":5.2},{"x":-463.13,"y":187.99,"z":9.44}]},{"lat":-19.65,"lon":0,"b":[{"x":-469.94,"y":170.45,"z":4.25},{"x":-471.59,"y":165.83,"z":4.25},{"x":-472.42,"y":163.52,"z":0},{"x":-471.59,"y":165.83,"z":-4.25},{"x":-469.94,"y":170.45,"z":-4.25},{"x":-469.12,"y":172.76,"z":0}]},{"lat":-17.78,"lon":-1.14,"b":[{"x":-475.25,"y":155,"z":-5.19},{"x":-476.75,"y":150.34,"z":-5.19},{"x":-477.42,"y":147.99,"z":-9.43},{"x":-476.6,"y":150.29,"z":-13.67},{"x":-475.1,"y":154.94,"z":-13.68},{"x":-474.43,"y":157.3,"z":-9.44}]},{"lat":-15.9,"lon":-2.24,"b":[{"x":-479.87,"y":139.38,"z":-14.59},{"x":-481.21,"y":134.69,"z":-14.58},{"x":-481.72,"y":132.32,"z":-18.8},{"x":-480.9,"y":134.61,"z":-23.02},{"x":-479.57,"y":139.29,"z":-23.05},{"x":-479.05,"y":141.68,"z":-18.83}]},{"lat":-14.04,"lon":-3.32,"b":[{"x":-483.79,"y":123.66,"z":-23.9},{"x":-484.97,"y":118.97,"z":-23.88},{"x":-485.33,"y":116.58,"z":-28.07},{"x":-484.51,"y":118.86,"z":-32.27},{"x":-483.33,"y":123.54,"z":-32.32},{"x":-482.97,"y":125.95,"z":-28.13}]},{"lat":-12.18,"lon":-4.37,"b":[{"x":-487.01,"y":107.92,"z":-33.1},{"x":-488.03,"y":103.24,"z":-33.06},{"x":-488.23,"y":100.85,"z":-37.2},{"x":-487.42,"y":103.12,"z":-41.38},{"x":-486.4,"y":107.78,"z":-41.45},{"x":-486.19,"y":110.2,"z":-37.31}]},{"lat":-10.35,"lon":-5.4,"b":[{"x":-489.53,"y":92.22,"z":-42.15},{"x":-490.39,"y":87.57,"z":-42.09},{"x":-490.44,"y":85.19,"z":-46.17},{"x":-489.64,"y":87.44,"z":-50.32},{"x":-488.78,"y":92.07,"z":-50.42},{"x":-488.72,"y":94.48,"z":-46.33}]},{"lat":-8.54,"lon":-6.39,"b":[{"x":-491.38,"y":76.62,"z":-51.01},{"x":-492.08,"y":72.01,"z":-50.92},{"x":-491.99,"y":69.66,"z":-54.94},{"x":-491.19,"y":71.89,"z":-59.05},{"x":-490.48,"y":76.48,"z":-59.18},{"x":-490.57,"y":78.87,"z":-55.16}]},{"lat":-6.76,"lon":-7.36,"b":[{"x":-492.57,"y":61.19,"z":-59.66},{"x":-493.13,"y":56.64,"z":-59.53},{"x":-492.9,"y":54.32,"z":-63.48},{"x":-492.11,"y":56.52,"z":-67.56},{"x":-491.54,"y":61.06,"z":-67.72},{"x":-491.77,"y":63.41,"z":-63.77}]},{"lat":-5.01,"lon":-8.31,"b":[{"x":-493.11,"y":45.8,"z":-68.38},{"x":-493.5,"y":41.67,"z":-68.23},{"x":-493.17,"y":39.58,"z":-71.8},{"x":-492.45,"y":41.58,"z":-75.51},{"x":-492.05,"y":45.69,"z":-75.69},{"x":-492.38,"y":47.82,"z":-72.13}]},{"lat":-40.5,"lon":13.27,"b":[{"x":-369.87,"y":324.81,"z":87.64},{"x":-370.17,"y":324.47,"z":87.67},{"x":-370.37,"y":324.34,"z":87.28},{"x":-370.28,"y":324.56,"z":86.85},{"x":-369.98,"y":324.91,"z":86.82},{"x":-369.78,"y":325.03,"z":87.22}]},{"lat":-35.83,"lon":8.99,"b":[{"x":-398.61,"y":294.15,"z":67.2},{"x":-401.25,"y":290.48,"z":67.38},{"x":-403.01,"y":288.93,"z":63.45},{"x":-402.09,"y":291.08,"z":59.35},{"x":-399.42,"y":294.76,"z":59.22},{"x":-397.7,"y":296.27,"z":63.14}]},{"lat":-34.17,"lon":7.61,"b":[{"x":-408.31,"y":282.41,"z":58.77},{"x":-410.9,"y":278.6,"z":58.91},{"x":-412.58,"y":276.93,"z":54.91},{"x":-411.64,"y":279.1,"z":50.78},{"x":-409.04,"y":282.92,"z":50.67},{"x":-407.39,"y":284.56,"z":54.67}]},{"lat":-32.46,"lon":6.27,"b":[{"x":-417.69,"y":270.09,"z":50.11},{"x":-420.2,"y":266.14,"z":50.22},{"x":-421.79,"y":264.35,"z":46.15},{"x":-420.85,"y":266.54,"z":41.98},{"x":-418.33,"y":270.5,"z":41.91},{"x":-416.76,"y":272.26,"z":45.97}]},{"lat":-30.72,"lon":4.96,"b":[{"x":-426.69,"y":257.21,"z":41.24},{"x":-429.12,"y":253.13,"z":41.31},{"x":-430.6,"y":251.23,"z":37.19},{"x":-429.65,"y":253.44,"z":32.99},{"x":-427.22,"y":257.53,"z":32.95},{"x":-425.75,"y":259.4,"z":37.07}]},{"lat":-28.93,"lon":3.67,"b":[{"x":-435.26,"y":243.8,"z":32.18},{"x":-437.58,"y":239.6,"z":32.23},{"x":-438.95,"y":237.6,"z":28.06},{"x":-437.99,"y":239.82,"z":23.84},{"x":-435.66,"y":244.03,"z":23.81},{"x":-434.3,"y":246.01,"z":27.98}]},{"lat":-27.11,"lon":2.42,"b":[{"x":-443.33,"y":229.9,"z":22.97},{"x":-445.53,"y":225.59,"z":23},{"x":-446.78,"y":223.49,"z":18.79},{"x":-445.82,"y":225.73,"z":14.56},{"x":-443.61,"y":230.05,"z":14.55},{"x":-442.37,"y":232.12,"z":18.75}]},{"lat":-25.27,"lon":1.19,"b":[{"x":-450.85,"y":215.55,"z":13.65},{"x":-452.93,"y":211.14,"z":13.66},{"x":-454.05,"y":208.97,"z":9.43},{"x":-453.08,"y":211.21,"z":5.18},{"x":-451,"y":215.62,"z":5.18},{"x":-449.89,"y":217.79,"z":9.41}]},{"lat":-23.4,"lon":0,"b":[{"x":-457.79,"y":200.81,"z":4.24},{"x":-459.74,"y":196.32,"z":4.25},{"x":-460.71,"y":194.07,"z":0},{"x":-459.74,"y":196.32,"z":-4.25},{"x":-457.79,"y":200.81,"z":-4.24},{"x":-456.82,"y":203.06,"z":0}]},{"lat":-21.53,"lon":-1.16,"b":[{"x":-464.1,"y":185.74,"z":-5.2},{"x":-465.9,"y":181.17,"z":-5.2},{"x":-466.73,"y":178.86,"z":-9.45},{"x":-465.75,"y":181.11,"z":-13.69},{"x":-463.95,"y":185.68,"z":-13.69},{"x":-463.13,"y":187.99,"z":-9.44}]},{"lat":-19.64,"lon":-2.3,"b":[{"x":-469.76,"y":170.39,"z":-14.64},{"x":-471.41,"y":165.77,"z":-14.63},{"x":-472.08,"y":163.41,"z":-18.87},{"x":-471.1,"y":165.66,"z":-23.11},{"x":-469.46,"y":170.27,"z":-23.12},{"x":-468.78,"y":172.64,"z":-18.88}]},{"lat":-17.75,"lon":-3.4,"b":[{"x":-474.73,"y":154.83,"z":-24.03},{"x":-476.22,"y":150.17,"z":-24.02},{"x":-476.74,"y":147.78,"z":-28.24},{"x":-475.77,"y":150.03,"z":-32.47},{"x":-474.28,"y":154.67,"z":-32.49},{"x":-473.76,"y":157.08,"z":-28.27}]},{"lat":-15.87,"lon":-4.48,"b":[{"x":-479.01,"y":139.13,"z":-33.35},{"x":-480.34,"y":134.45,"z":-33.33},{"x":-480.71,"y":132.04,"z":-37.51},{"x":-479.74,"y":134.28,"z":-41.72},{"x":-478.4,"y":138.95,"z":-41.76},{"x":-478.04,"y":141.38,"z":-37.58}]},{"lat":-14,"lon":-5.53,"b":[{"x":-482.59,"y":123.35,"z":-42.55},{"x":-483.77,"y":118.67,"z":-42.51},{"x":-483.97,"y":116.26,"z":-46.65},{"x":-483.01,"y":118.49,"z":-50.83},{"x":-481.83,"y":123.16,"z":-50.89},{"x":-481.62,"y":125.6,"z":-46.75}]},{"lat":-12.14,"lon":-6.54,"b":[{"x":-485.47,"y":107.58,"z":-51.59},{"x":-486.49,"y":102.91,"z":-51.53},{"x":-486.55,"y":100.51,"z":-55.61},{"x":-485.59,"y":102.73,"z":-59.76},{"x":-484.57,"y":107.38,"z":-59.85},{"x":-484.51,"y":109.82,"z":-55.77}]},{"lat":-10.31,"lon":-7.53,"b":[{"x":-487.68,"y":91.87,"z":-60.45},{"x":-488.54,"y":87.23,"z":-60.35},{"x":-488.45,"y":84.85,"z":-64.37},{"x":-487.5,"y":87.05,"z":-68.49},{"x":-486.63,"y":91.67,"z":-68.61},{"x":-486.72,"y":94.09,"z":-64.6}]},{"lat":-8.5,"lon":-8.5,"b":[{"x":-489.22,"y":76.29,"z":-69.09},{"x":-489.93,"y":71.69,"z":-68.96},{"x":-489.7,"y":69.34,"z":-72.91},{"x":-488.76,"y":71.53,"z":-76.98},{"x":-488.04,"y":76.1,"z":-77.15},{"x":-488.27,"y":78.5,"z":-73.2}]},{"lat":-6.72,"lon":-9.44,"b":[{"x":-490.12,"y":60.89,"z":-77.49},{"x":-490.68,"y":56.35,"z":-77.32},{"x":-490.32,"y":54.04,"z":-81.2},{"x":-489.39,"y":56.21,"z":-85.23},{"x":-488.82,"y":60.72,"z":-85.43},{"x":-489.18,"y":63.08,"z":-81.56}]},{"lat":-42.25,"lon":12.15,"b":[{"x":-360.01,"y":337.2,"z":81.44},{"x":-362.73,"y":334.2,"z":81.72},{"x":-364.54,"y":333.08,"z":78.15},{"x":-363.59,"y":334.99,"z":74.3},{"x":-360.85,"y":337.99,"z":74.07},{"x":-359.08,"y":339.08,"z":77.64}]},{"lat":-39.23,"lon":9.24,"b":[{"x":-381.17,"y":317.02,"z":64.53},{"x":-382.87,"y":314.93,"z":64.66},{"x":-383.97,"y":314.08,"z":62.29},{"x":-383.34,"y":315.32,"z":59.79},{"x":-381.63,"y":317.41,"z":59.69},{"x":-380.56,"y":318.25,"z":62.06}]},{"lat":-35.99,"lon":6.44,"b":[{"x":-400.32,"y":295.37,"z":49.29},{"x":-402.94,"y":291.76,"z":49.43},{"x":-404.56,"y":290.15,"z":45.5},{"x":-403.53,"y":292.18,"z":41.45},{"x":-400.9,"y":295.8,"z":41.36},{"x":-399.31,"y":297.37,"z":45.28}]},{"lat":-34.3,"lon":5.09,"b":[{"x":-409.8,"y":283.44,"z":40.69},{"x":-412.4,"y":279.62,"z":40.8},{"x":-413.97,"y":277.86,"z":36.73},{"x":-412.9,"y":279.95,"z":32.58},{"x":-410.29,"y":283.78,"z":32.51},{"x":-408.75,"y":285.51,"z":36.57}]},{"lat":-32.56,"lon":3.77,"b":[{"x":-418.95,"y":270.9,"z":31.81},{"x":-421.48,"y":266.95,"z":31.89},{"x":-422.95,"y":265.08,"z":27.77},{"x":-421.87,"y":267.19,"z":23.58},{"x":-419.34,"y":271.15,"z":23.55},{"x":-417.89,"y":273,"z":27.66}]},{"lat":-30.79,"lon":2.48,"b":[{"x":-427.71,"y":257.82,"z":22.75},{"x":-430.14,"y":253.73,"z":22.8},{"x":-431.5,"y":251.75,"z":18.63},{"x":-430.41,"y":253.89,"z":14.43},{"x":-427.97,"y":257.98,"z":14.41},{"x":-426.63,"y":259.93,"z":18.57}]},{"lat":-28.97,"lon":1.23,"b":[{"x":-436,"y":244.22,"z":13.54},{"x":-438.33,"y":240.01,"z":13.57},{"x":-439.57,"y":237.93,"z":9.37},{"x":-438.47,"y":240.08,"z":5.15},{"x":-436.14,"y":244.29,"z":5.15},{"x":-434.91,"y":246.35,"z":9.34}]},{"lat":-27.13,"lon":0,"b":[{"x":-443.78,"y":230.13,"z":4.22},{"x":-445.99,"y":225.82,"z":4.23},{"x":-447.1,"y":223.65,"z":0},{"x":-445.99,"y":225.82,"z":-4.23},{"x":-443.78,"y":230.13,"z":-4.22},{"x":-442.68,"y":232.29,"z":0}]},{"lat":-25.27,"lon":-1.19,"b":[{"x":-451,"y":215.62,"z":-5.18},{"x":-453.08,"y":211.21,"z":-5.18},{"x":-454.05,"y":208.97,"z":-9.43},{"x":-452.93,"y":211.14,"z":-13.66},{"x":-450.85,"y":215.55,"z":-13.65},{"x":-449.89,"y":217.79,"z":-9.41}]},{"lat":-23.39,"lon":-2.36,"b":[{"x":-457.61,"y":200.74,"z":-14.62},{"x":-459.56,"y":196.24,"z":-14.63},{"x":-460.38,"y":193.93,"z":-18.87},{"x":-459.26,"y":196.12,"z":-23.1},{"x":-457.32,"y":200.61,"z":-23.09},{"x":-456.5,"y":202.91,"z":-18.86}]},{"lat":-21.49,"lon":-3.49,"b":[{"x":-463.59,"y":185.53,"z":-24.06},{"x":-465.39,"y":180.97,"z":-24.06},{"x":-466.06,"y":178.61,"z":-28.3},{"x":-464.94,"y":180.8,"z":-32.52},{"x":-463.15,"y":185.35,"z":-32.52},{"x":-462.47,"y":187.72,"z":-28.29}]},{"lat":-19.6,"lon":-4.59,"b":[{"x":-468.9,"y":170.08,"z":-33.46},{"x":-470.55,"y":165.46,"z":-33.45},{"x":-471.07,"y":163.06,"z":-37.67},{"x":-469.95,"y":165.26,"z":-41.88},{"x":-468.31,"y":169.86,"z":-41.89},{"x":-467.78,"y":172.27,"z":-37.68}]},{"lat":-17.7,"lon":-5.66,"b":[{"x":-473.54,"y":154.44,"z":-42.78},{"x":-475.03,"y":149.79,"z":-42.76},{"x":-475.4,"y":147.36,"z":-46.94},{"x":-474.28,"y":149.56,"z":-51.13},{"x":-472.79,"y":154.19,"z":-51.16},{"x":-472.41,"y":156.64,"z":-46.99}]},{"lat":-15.81,"lon":-6.7,"b":[{"x":-477.48,"y":138.68,"z":-51.97},{"x":-478.81,"y":134.02,"z":-51.94},{"x":-479.02,"y":131.58,"z":-56.07},{"x":-477.91,"y":133.77,"z":-60.24},{"x":-476.58,"y":138.41,"z":-60.29},{"x":-476.36,"y":140.88,"z":-56.16}]},{"lat":-13.94,"lon":-7.71,"b":[{"x":-480.73,"y":122.88,"z":-61.02},{"x":-481.9,"y":118.22,"z":-60.95},{"x":-481.96,"y":115.77,"z":-65.03},{"x":-480.86,"y":117.97,"z":-69.17},{"x":-479.68,"y":122.61,"z":-69.25},{"x":-479.61,"y":125.08,"z":-65.18}]},{"lat":-12.08,"lon":-8.7,"b":[{"x":-483.29,"y":107.1,"z":-69.87},{"x":-484.31,"y":102.45,"z":-69.78},{"x":-484.22,"y":100.02,"z":-73.79},{"x":-483.13,"y":102.21,"z":-77.89},{"x":-482.1,"y":106.83,"z":-78.01},{"x":-482.18,"y":109.29,"z":-74.01}]},{"lat":-10.25,"lon":-9.65,"b":[{"x":-485.19,"y":91.4,"z":-78.51},{"x":-486.05,"y":86.79,"z":-78.38},{"x":-485.83,"y":84.39,"z":-82.32},{"x":-484.74,"y":86.56,"z":-86.38},{"x":-483.87,"y":91.15,"z":-86.54},{"x":-484.09,"y":93.59,"z":-82.61}]},{"lat":-8.45,"lon":-10.58,"b":[{"x":-486.44,"y":75.85,"z":-86.9},{"x":-487.16,"y":71.29,"z":-86.73},{"x":-486.79,"y":68.93,"z":-90.6},{"x":-485.72,"y":71.09,"z":-94.62},{"x":-484.99,"y":75.62,"z":-94.81},{"x":-485.35,"y":78.03,"z":-90.96}]},{"lat":-6.68,"lon":-11.48,"b":[{"x":-486.95,"y":59.83,"z":-96.13},{"x":-487.36,"y":56.63,"z":-95.99},{"x":-487.02,"y":54.99,"z":-98.67},{"x":-486.26,"y":56.51,"z":-101.49},{"x":-485.85,"y":59.68,"z":-101.66},{"x":-486.19,"y":61.36,"z":-98.98}]},{"lat":-43.96,"lon":10.99,"b":[{"x":-351.53,"y":348.07,"z":72.2},{"x":-354.3,"y":345.19,"z":72.47},{"x":-356.09,"y":344.09,"z":68.86},{"x":-355.05,"y":345.91,"z":65},{"x":-352.25,"y":348.8,"z":64.79},{"x":-350.51,"y":349.86,"z":68.39}]},{"lat":-42.5,"lon":9.51,"b":[{"x":-363.23,"y":338.01,"z":61.62},{"x":-363.78,"y":337.41,"z":61.67},{"x":-364.13,"y":337.16,"z":60.93},{"x":-363.92,"y":337.53,"z":60.14},{"x":-363.36,"y":338.14,"z":60.11},{"x":-363.02,"y":338.38,"z":60.85}]},{"lat":-36.1,"lon":3.88,"b":[{"x":-401.58,"y":296.14,"z":31.05},{"x":-404.07,"y":292.72,"z":31.13},{"x":-405.5,"y":291.12,"z":27.37},{"x":-404.41,"y":292.97,"z":23.53},{"x":-401.91,"y":296.39,"z":23.49},{"x":-400.51,"y":297.96,"z":27.24}]},{"lat":-34.38,"lon":2.55,"b":[{"x":-410.74,"y":284.09,"z":22.45},{"x":-413.36,"y":280.27,"z":22.51},{"x":-414.81,"y":278.42,"z":18.4},{"x":-413.61,"y":280.44,"z":14.25},{"x":-410.99,"y":284.27,"z":14.22},{"x":-409.57,"y":286.08,"z":18.32}]},{"lat":-32.61,"lon":1.26,"b":[{"x":-419.65,"y":271.36,"z":13.39},{"x":-422.19,"y":267.39,"z":13.43},{"x":-423.53,"y":265.44,"z":9.27},{"x":-422.32,"y":267.48,"z":5.09},{"x":-419.78,"y":271.44,"z":5.09},{"x":-418.46,"y":273.37,"z":9.23}]},{"lat":-30.81,"lon":0,"b":[{"x":-428.14,"y":258.08,"z":4.18},{"x":-430.57,"y":253.99,"z":4.19},{"x":-431.8,"y":251.93,"z":0},{"x":-430.57,"y":253.99,"z":-4.19},{"x":-428.14,"y":258.08,"z":-4.18},{"x":-426.92,"y":260.11,"z":0}]},{"lat":-28.97,"lon":-1.23,"b":[{"x":-436.14,"y":244.29,"z":-5.15},{"x":-438.47,"y":240.08,"z":-5.15},{"x":-439.57,"y":237.93,"z":-9.37},{"x":-438.33,"y":240.01,"z":-13.57},{"x":-436,"y":244.22,"z":-13.54},{"x":-434.91,"y":246.35,"z":-9.34}]},{"lat":-27.11,"lon":-2.42,"b":[{"x":-443.61,"y":230.05,"z":-14.55},{"x":-445.82,"y":225.73,"z":-14.56},{"x":-446.78,"y":223.49,"z":-18.79},{"x":-445.53,"y":225.59,"z":-23},{"x":-443.33,"y":229.9,"z":-22.97},{"x":-442.37,"y":232.12,"z":-18.75}]},{"lat":-25.23,"lon":-3.58,"b":[{"x":-450.5,"y":215.39,"z":-23.99},{"x":-452.58,"y":210.98,"z":-24},{"x":-453.41,"y":208.67,"z":-28.24},{"x":-452.15,"y":210.78,"z":-32.44},{"x":-450.07,"y":215.18,"z":-32.42},{"x":-449.25,"y":217.48,"z":-28.2}]},{"lat":-23.33,"lon":-4.71,"b":[{"x":-456.78,"y":200.37,"z":-33.43},{"x":-458.73,"y":195.88,"z":-33.44},{"x":-459.4,"y":193.52,"z":-37.67},{"x":-458.14,"y":195.64,"z":-41.86},{"x":-456.2,"y":200.12,"z":-41.84},{"x":-455.52,"y":202.48,"z":-37.63}]},{"lat":-21.43,"lon":-5.8,"b":[{"x":-462.42,"y":185.07,"z":-42.83},{"x":-464.22,"y":180.51,"z":-42.83},{"x":-464.74,"y":178.1,"z":-47.03},{"x":-463.48,"y":180.23,"z":-51.22},{"x":-461.69,"y":184.77,"z":-51.21},{"x":-461.16,"y":187.19,"z":-47.02}]},{"lat":-19.52,"lon":-6.87,"b":[{"x":-467.4,"y":169.53,"z":-52.14},{"x":-469.04,"y":164.93,"z":-52.13},{"x":-469.41,"y":162.48,"z":-56.3},{"x":-468.15,"y":164.62,"z":-60.47},{"x":-466.51,"y":169.2,"z":-60.48},{"x":-466.13,"y":171.66,"z":-56.33}]},{"lat":-17.62,"lon":-7.9,"b":[{"x":-471.69,"y":153.84,"z":-61.34},{"x":-473.18,"y":149.21,"z":-61.31},{"x":-473.4,"y":146.74,"z":-65.44},{"x":-472.14,"y":148.88,"z":-69.58},{"x":-470.65,"y":153.49,"z":-69.62},{"x":-470.43,"y":155.98,"z":-65.51}]},{"lat":-15.73,"lon":-8.9,"b":[{"x":-475.3,"y":138.05,"z":-70.38},{"x":-476.63,"y":133.41,"z":-70.33},{"x":-476.7,"y":130.94,"z":-74.4},{"x":-475.44,"y":133.08,"z":-78.51},{"x":-474.12,"y":137.7,"z":-78.58},{"x":-474.04,"y":140.19,"z":-74.52}]},{"lat":-13.86,"lon":-9.88,"b":[{"x":-478.23,"y":122.24,"z":-79.23},{"x":-479.4,"y":117.6,"z":-79.15},{"x":-479.32,"y":115.14,"z":-83.16},{"x":-478.08,"y":117.29,"z":-87.23},{"x":-476.9,"y":121.89,"z":-87.34},{"x":-476.97,"y":124.39,"z":-83.34}]},{"lat":-12.01,"lon":-10.82,"b":[{"x":-480.48,"y":106.48,"z":-87.87},{"x":-481.51,"y":101.86,"z":-87.75},{"x":-481.28,"y":99.42,"z":-91.68},{"x":-480.05,"y":101.56,"z":-95.72},{"x":-479.03,"y":106.14,"z":-95.86},{"x":-479.24,"y":108.62,"z":-91.94}]},{"lat":-10.18,"lon":-11.74,"b":[{"x":-482.09,"y":90.82,"z":-96.25},{"x":-482.96,"y":86.24,"z":-96.1},{"x":-482.61,"y":83.83,"z":-99.95},{"x":-481.39,"y":85.96,"z":-103.94},{"x":-480.51,"y":90.51,"z":-104.13},{"x":-480.86,"y":92.96,"z":-100.29}]},{"lat":-8.39,"lon":-12.63,"b":[{"x":-483.06,"y":75.27,"z":-104.47},{"x":-483.77,"y":70.85,"z":-104.28},{"x":-483.3,"y":68.56,"z":-107.95},{"x":-482.13,"y":70.62,"z":-111.79},{"x":-481.41,"y":75,"z":-112.01},{"x":-481.88,"y":77.34,"z":-108.36}]},{"lat":-45.62,"lon":9.79,"b":[{"x":-342.81,"y":358.38,"z":63.09},{"x":-345.66,"y":355.59,"z":63.34},{"x":-347.43,"y":354.5,"z":59.68},{"x":-346.3,"y":356.24,"z":55.77},{"x":-343.43,"y":359.03,"z":55.58},{"x":-341.71,"y":360.09,"z":59.23}]},{"lat":-44.19,"lon":8.29,"b":[{"x":-353.44,"y":349.36,"z":54.54},{"x":-355.63,"y":347.1,"z":54.71},{"x":-356.97,"y":346.17,"z":51.83},{"x":-356.08,"y":347.53,"z":48.79},{"x":-353.87,"y":349.79,"z":48.67},{"x":-352.57,"y":350.69,"z":51.54}]},{"lat":-42.69,"lon":6.82,"b":[{"x":-364.48,"y":339.33,"z":44.6},{"x":-365.19,"y":338.56,"z":44.65},{"x":-365.62,"y":338.22,"z":43.69},{"x":-365.32,"y":338.67,"z":42.68},{"x":-364.6,"y":339.45,"z":42.65},{"x":-364.19,"y":339.77,"z":43.61}]},{"lat":-36.16,"lon":1.29,"b":[{"x":-402.88,"y":295.85,"z":11.08},{"x":-404.18,"y":294.07,"z":11.1},{"x":-404.86,"y":293.19,"z":9.13},{"x":-404.23,"y":294.11,"z":7.14},{"x":-402.94,"y":295.89,"z":7.14},{"x":-402.26,"y":296.75,"z":9.1}]},{"lat":-34.41,"lon":0,"b":[{"x":-411.14,"y":284.37,"z":4.12},{"x":-413.77,"y":280.54,"z":4.14},{"x":-415.09,"y":278.61,"z":0},{"x":-413.77,"y":280.54,"z":-4.14},{"x":-411.14,"y":284.37,"z":-4.12},{"x":-409.85,"y":286.27,"z":0}]},{"lat":-32.61,"lon":-1.26,"b":[{"x":-419.78,"y":271.44,"z":-5.09},{"x":-422.32,"y":267.48,"z":-5.09},{"x":-423.53,"y":265.44,"z":-9.27},{"x":-422.19,"y":267.39,"z":-13.43},{"x":-419.65,"y":271.36,"z":-13.39},{"x":-418.46,"y":273.37,"z":-9.23}]},{"lat":-30.79,"lon":-2.48,"b":[{"x":-427.97,"y":257.98,"z":-14.41},{"x":-430.41,"y":253.89,"z":-14.43},{"x":-431.5,"y":251.75,"z":-18.63},{"x":-430.14,"y":253.73,"z":-22.8},{"x":-427.71,"y":257.82,"z":-22.75},{"x":-426.63,"y":259.93,"z":-18.57}]},{"lat":-28.93,"lon":-3.67,"b":[{"x":-435.66,"y":244.03,"z":-23.81},{"x":-437.99,"y":239.82,"z":-23.84},{"x":-438.95,"y":237.6,"z":-28.06},{"x":-437.58,"y":239.6,"z":-32.23},{"x":-435.26,"y":243.8,"z":-32.18},{"x":-434.3,"y":246.01,"z":-27.98}]},{"lat":-27.05,"lon":-4.83,"b":[{"x":-442.81,"y":229.63,"z":-33.25},{"x":-445.02,"y":225.32,"z":-33.28},{"x":-445.84,"y":223.02,"z":-37.5},{"x":-444.45,"y":225.04,"z":-41.67},{"x":-442.26,"y":229.34,"z":-41.62},{"x":-441.44,"y":231.63,"z":-37.43}]},{"lat":-25.15,"lon":-5.95,"b":[{"x":-449.37,"y":214.85,"z":-42.69},{"x":-451.45,"y":210.45,"z":-42.72},{"x":-452.13,"y":208.08,"z":-46.93},{"x":-450.73,"y":210.12,"z":-51.09},{"x":-448.67,"y":214.51,"z":-51.05},{"x":-447.99,"y":216.87,"z":-46.86}]},{"lat":-23.25,"lon":-7.04,"b":[{"x":-455.32,"y":199.73,"z":-52.09},{"x":-457.25,"y":195.25,"z":-52.11},{"x":-457.78,"y":192.83,"z":-56.3},{"x":-456.38,"y":194.89,"z":-60.45},{"x":-454.46,"y":199.35,"z":-60.42},{"x":-453.92,"y":201.77,"z":-56.25}]},{"lat":-21.34,"lon":-8.1,"b":[{"x":-460.61,"y":184.34,"z":-61.41},{"x":-462.4,"y":179.81,"z":-61.41},{"x":-462.78,"y":177.35,"z":-65.57},{"x":-461.38,"y":179.42,"z":-69.7},{"x":-459.6,"y":183.93,"z":-69.69},{"x":-459.21,"y":186.4,"z":-65.56}]},{"lat":-19.43,"lon":-9.12,"b":[{"x":-465.25,"y":168.75,"z":-70.61},{"x":-466.89,"y":164.17,"z":-70.59},{"x":-467.11,"y":161.69,"z":-74.7},{"x":-465.71,"y":163.77,"z":-78.81},{"x":-464.08,"y":168.32,"z":-78.82},{"x":-463.85,"y":170.82,"z":-74.73}]},{"lat":-17.52,"lon":-10.11,"b":[{"x":-469.21,"y":153.03,"z":-79.65},{"x":-470.69,"y":148.42,"z":-79.61},{"x":-470.77,"y":145.93,"z":-83.67},{"x":-469.38,"y":148.02,"z":-87.74},{"x":-467.9,"y":152.59,"z":-87.79},{"x":-467.81,"y":155.11,"z":-83.75}]},{"lat":-15.63,"lon":-11.08,"b":[{"x":-472.5,"y":137.24,"z":-88.5},{"x":-473.83,"y":132.62,"z":-88.43},{"x":-473.76,"y":130.13,"z":-92.42},{"x":-472.37,"y":132.22,"z":-96.46},{"x":-471.05,"y":136.81,"z":-96.55},{"x":-471.1,"y":139.33,"z":-92.58}]},{"lat":-13.76,"lon":-12.01,"b":[{"x":-475.12,"y":121.45,"z":-97.13},{"x":-476.29,"y":116.84,"z":-97.03},{"x":-476.08,"y":114.36,"z":-100.95},{"x":-474.71,"y":116.46,"z":-104.95},{"x":-473.53,"y":121.03,"z":-105.07},{"x":-473.73,"y":123.54,"z":-101.17}]},{"lat":-11.92,"lon":-12.92,"b":[{"x":-477.09,"y":105.72,"z":-105.52},{"x":-478.11,"y":101.14,"z":-105.38},{"x":-477.76,"y":98.69,"z":-109.21},{"x":-476.4,"y":100.79,"z":-113.17},{"x":-475.38,"y":105.34,"z":-113.34},{"x":-475.71,"y":107.82,"z":-109.52}]},{"lat":-10.1,"lon":-13.8,"b":[{"x":-478.41,"y":90.04,"z":-113.76},{"x":-479.26,"y":85.66,"z":-113.59},{"x":-478.8,"y":83.33,"z":-117.21},{"x":-477.5,"y":85.35,"z":-120.98},{"x":-476.65,"y":89.7,"z":-121.18},{"x":-477.1,"y":92.07,"z":-117.58}]},{"lat":-47.24,"lon":8.54,"b":[{"x":-333.96,"y":368.1,"z":54.03},{"x":-336.81,"y":365.45,"z":54.26},{"x":-338.53,"y":364.39,"z":50.61},{"x":-337.33,"y":366.01,"z":46.74},{"x":-334.46,"y":368.66,"z":46.58},{"x":-332.8,"y":369.69,"z":50.22}]},{"lat":-45.83,"lon":7.03,"b":[{"x":-344.09,"y":359.72,"z":46.32},{"x":-346.96,"y":356.92,"z":46.51},{"x":-348.65,"y":355.75,"z":42.78},{"x":-347.42,"y":357.39,"z":38.87},{"x":-344.53,"y":360.19,"z":38.74},{"x":-342.9,"y":361.33,"z":42.46}]},{"lat":-44.35,"lon":5.55,"b":[{"x":-354.18,"y":350.75,"z":38.34},{"x":-357.05,"y":347.81,"z":38.5},{"x":-358.7,"y":346.51,"z":34.68},{"x":-357.44,"y":348.18,"z":30.73},{"x":-354.55,"y":351.12,"z":30.64},{"x":-352.95,"y":352.39,"z":34.43}]},{"lat":-42.82,"lon":4.11,"b":[{"x":-365.54,"y":340.06,"z":26.88},{"x":-366,"y":339.57,"z":26.9},{"x":-366.26,"y":339.34,"z":26.27},{"x":-366.05,"y":339.61,"z":25.62},{"x":-365.59,"y":340.11,"z":25.62},{"x":-365.34,"y":340.33,"z":26.24}]},{"lat":-41.23,"lon":2.7,"b":[{"x":-374.96,"y":330.15,"z":19.33},{"x":-376.13,"y":328.81,"z":19.36},{"x":-376.77,"y":328.18,"z":17.73},{"x":-376.22,"y":328.89,"z":16.08},{"x":-375.05,"y":330.22,"z":16.07},{"x":-374.43,"y":330.85,"z":17.69}]},{"lat":-37.9,"lon":0,"b":[{"x":-394.3,"y":307.43,"z":0.73},{"x":-394.79,"y":306.79,"z":0.73},{"x":-395.04,"y":306.47,"z":0},{"x":-394.79,"y":306.79,"z":-0.73},{"x":-394.3,"y":307.43,"z":-0.73},{"x":-394.06,"y":307.74,"z":0}]},{"lat":-34.38,"lon":-2.55,"b":[{"x":-411.2,"y":283.95,"z":-14.91},{"x":-413.39,"y":280.75,"z":-14.93},{"x":-414.38,"y":279.07,"z":-18.4},{"x":-413.18,"y":280.61,"z":-21.83},{"x":-410.99,"y":283.8,"z":-21.78},{"x":-410.01,"y":285.46,"z":-18.33}]},{"lat":-32.56,"lon":-3.77,"b":[{"x":-419.34,"y":271.15,"z":-23.55},{"x":-421.87,"y":267.19,"z":-23.58},{"x":-422.95,"y":265.08,"z":-27.77},{"x":-421.48,"y":266.95,"z":-31.89},{"x":-418.95,"y":270.9,"z":-31.81},{"x":-417.89,"y":273,"z":-27.66}]},{"lat":-30.72,"lon":-4.96,"b":[{"x":-427.22,"y":257.53,"z":-32.95},{"x":-429.65,"y":253.44,"z":-32.99},{"x":-430.6,"y":251.23,"z":-37.19},{"x":-429.12,"y":253.13,"z":-41.31},{"x":-426.69,"y":257.21,"z":-41.24},{"x":-425.75,"y":259.4,"z":-37.07}]},{"lat":-28.84,"lon":-6.11,"b":[{"x":-434.59,"y":243.43,"z":-42.38},{"x":-436.91,"y":239.23,"z":-42.43},{"x":-437.73,"y":236.94,"z":-46.63},{"x":-436.22,"y":238.86,"z":-50.75},{"x":-433.91,"y":243.05,"z":-50.68},{"x":-433.1,"y":245.32,"z":-46.51}]},{"lat":-26.95,"lon":-7.22,"b":[{"x":-441.4,"y":228.91,"z":-51.82},{"x":-443.6,"y":224.61,"z":-51.87},{"x":-444.28,"y":222.24,"z":-56.06},{"x":-442.76,"y":224.19,"z":-60.17},{"x":-440.58,"y":228.47,"z":-60.1},{"x":-439.9,"y":230.83,"z":-55.94}]},{"lat":-25.04,"lon":-8.3,"b":[{"x":-447.63,"y":214.01,"z":-61.22},{"x":-449.69,"y":209.63,"z":-61.26},{"x":-450.23,"y":207.21,"z":-65.43},{"x":-448.7,"y":209.17,"z":-69.53},{"x":-446.65,"y":213.54,"z":-69.47},{"x":-446.11,"y":215.96,"z":-65.33}]},{"lat":-23.13,"lon":-9.35,"b":[{"x":-453.23,"y":198.82,"z":-70.54},{"x":-455.15,"y":194.36,"z":-70.56},{"x":-455.54,"y":191.89,"z":-74.7},{"x":-454.01,"y":193.88,"z":-78.78},{"x":-452.1,"y":198.31,"z":-78.74},{"x":-451.7,"y":200.78,"z":-74.64}]},{"lat":-21.21,"lon":-10.36,"b":[{"x":-458.19,"y":183.37,"z":-79.74},{"x":-459.97,"y":178.86,"z":-79.74},{"x":-460.21,"y":176.36,"z":-83.83},{"x":-458.67,"y":178.37,"z":-87.89},{"x":-456.91,"y":182.85,"z":-87.88},{"x":-456.66,"y":185.36,"z":-83.82}]},{"lat":-19.3,"lon":-11.35,"b":[{"x":-462.49,"y":167.75,"z":-88.78},{"x":-464.12,"y":163.2,"z":-88.76},{"x":-464.21,"y":160.68,"z":-92.8},{"x":-462.68,"y":162.7,"z":-96.83},{"x":-461.06,"y":167.23,"z":-96.85},{"x":-460.96,"y":169.76,"z":-92.84}]},{"lat":-17.4,"lon":-12.3,"b":[{"x":-466.13,"y":152.02,"z":-97.64},{"x":-467.61,"y":147.45,"z":-97.59},{"x":-467.55,"y":144.93,"z":-101.56},{"x":-466.03,"y":146.96,"z":-105.55},{"x":-464.56,"y":151.5,"z":-105.61},{"x":-464.6,"y":154.05,"z":-101.66}]},{"lat":-15.51,"lon":-13.22,"b":[{"x":-469.11,"y":136.25,"z":-106.27},{"x":-470.44,"y":131.67,"z":-106.19},{"x":-470.24,"y":129.16,"z":-110.08},{"x":-468.73,"y":131.2,"z":-114.04},{"x":-467.41,"y":135.75,"z":-114.14},{"x":-467.59,"y":138.29,"z":-110.26}]},{"lat":-13.65,"lon":-14.12,"b":[{"x":-471.44,"y":120.51,"z":-114.65},{"x":-472.62,"y":115.94,"z":-114.53},{"x":-472.28,"y":113.45,"z":-118.35},{"x":-470.79,"y":115.5,"z":-122.26},{"x":-469.61,"y":120.03,"z":-122.4},{"x":-469.93,"y":122.55,"z":-118.61}]},{"lat":-11.81,"lon":-14.98,"b":[{"x":-473.11,"y":104.67,"z":-123.03},{"x":-474.07,"y":100.45,"z":-122.88},{"x":-473.63,"y":98.17,"z":-126.35},{"x":-472.26,"y":100.08,"z":-129.94},{"x":-471.31,"y":104.26,"z":-130.11},{"x":-471.73,"y":106.58,"z":-126.67}]},{"lat":-48.81,"lon":7.25,"b":[{"x":-324.97,"y":377.23,"z":45.12},{"x":-327.82,"y":374.72,"z":45.32},{"x":-329.48,"y":373.69,"z":41.69},{"x":-328.24,"y":375.19,"z":37.87},{"x":-325.37,"y":377.7,"z":37.74},{"x":-323.76,"y":378.7,"z":41.35}]},{"lat":-47.42,"lon":5.72,"b":[{"x":-334.98,"y":369.23,"z":37.39},{"x":-337.86,"y":366.58,"z":37.55},{"x":-339.5,"y":365.43,"z":33.84},{"x":-338.21,"y":366.96,"z":29.97},{"x":-335.32,"y":369.6,"z":29.88},{"x":-333.73,"y":370.73,"z":33.57}]},{"lat":-45.97,"lon":4.23,"b":[{"x":-344.98,"y":360.65,"z":29.39},{"x":-347.86,"y":357.85,"z":29.52},{"x":-349.46,"y":356.58,"z":25.73},{"x":-348.14,"y":358.14,"z":21.82},{"x":-345.25,"y":360.93,"z":21.76},{"x":-343.69,"y":362.17,"z":25.53}]},{"lat":-44.45,"lon":2.78,"b":[{"x":-354.91,"y":351.47,"z":21.15},{"x":-357.79,"y":348.53,"z":21.24},{"x":-359.35,"y":347.14,"z":17.37},{"x":-357.98,"y":348.72,"z":13.43},{"x":-355.09,"y":351.66,"z":13.4},{"x":-353.58,"y":353.02,"z":17.25}]},{"lat":-42.89,"lon":1.37,"b":[{"x":-364.72,"y":341.69,"z":12.67},{"x":-367.59,"y":338.6,"z":12.73},{"x":-369.1,"y":337.08,"z":8.79},{"x":-367.69,"y":338.69,"z":4.82},{"x":-364.82,"y":341.78,"z":4.82},{"x":-363.35,"y":343.27,"z":8.73}]},{"lat":-41.26,"lon":0,"b":[{"x":-374.37,"y":331.3,"z":3.97},{"x":-377.22,"y":328.06,"z":4},{"x":-378.66,"y":326.42,"z":0},{"x":-377.22,"y":328.06,"z":-4},{"x":-374.37,"y":331.3,"z":-3.97},{"x":-372.97,"y":332.91,"z":0}]},{"lat":-39.59,"lon":-1.33,"b":[{"x":-383.81,"y":320.31,"z":-4.92},{"x":-386.62,"y":316.91,"z":-4.92},{"x":-387.98,"y":315.15,"z":-8.98},{"x":-386.5,"y":316.82,"z":-13},{"x":-383.7,"y":320.21,"z":-12.95},{"x":-382.37,"y":321.94,"z":-8.92}]},{"lat":-37.87,"lon":-2.62,"b":[{"x":-392.98,"y":308.71,"z":-13.99},{"x":-395.73,"y":305.16,"z":-14.01},{"x":-397.01,"y":303.29,"z":-18.11},{"x":-395.5,"y":304.99,"z":-22.15},{"x":-392.75,"y":308.53,"z":-22.08},{"x":-391.5,"y":310.37,"z":-18.01}]},{"lat":-36.1,"lon":-3.88,"b":[{"x":-402.91,"y":294.84,"z":-26.83},{"x":-403.22,"y":294.41,"z":-26.84},{"x":-403.36,"y":294.18,"z":-27.32},{"x":-403.18,"y":294.38,"z":-27.79},{"x":-402.87,"y":294.81,"z":-27.78},{"x":-402.73,"y":295.04,"z":-27.3}]},{"lat":-34.3,"lon":-5.09,"b":[{"x":-410.29,"y":283.78,"z":-32.51},{"x":-412.9,"y":279.95,"z":-32.58},{"x":-413.97,"y":277.86,"z":-36.73},{"x":-412.4,"y":279.62,"z":-40.8},{"x":-409.8,"y":283.44,"z":-40.69},{"x":-408.75,"y":285.51,"z":-36.57}]},{"lat":-32.46,"lon":-6.27,"b":[{"x":-418.33,"y":270.5,"z":-41.91},{"x":-420.85,"y":266.54,"z":-41.98},{"x":-421.79,"y":264.35,"z":-46.15},{"x":-420.2,"y":266.14,"z":-50.22},{"x":-417.69,"y":270.09,"z":-50.11},{"x":-416.76,"y":272.26,"z":-45.97}]},{"lat":-30.6,"lon":-7.41,"b":[{"x":-425.89,"y":256.72,"z":-51.34},{"x":-428.31,"y":252.65,"z":-51.42},{"x":-429.12,"y":250.37,"z":-55.59},{"x":-427.51,"y":252.18,"z":-59.65},{"x":-425.11,"y":256.25,"z":-59.55},{"x":-424.29,"y":258.51,"z":-55.41}]},{"lat":-28.71,"lon":-8.52,"b":[{"x":-432.92,"y":242.5,"z":-60.78},{"x":-435.23,"y":238.31,"z":-60.85},{"x":-435.91,"y":235.95,"z":-65.02},{"x":-434.28,"y":237.8,"z":-69.07},{"x":-431.99,"y":241.97,"z":-68.97},{"x":-431.31,"y":244.31,"z":-64.84}]},{"lat":-26.81,"lon":-9.59,"b":[{"x":-439.4,"y":227.87,"z":-70.17},{"x":-441.58,"y":223.58,"z":-70.24},{"x":-442.12,"y":221.16,"z":-74.38},{"x":-440.48,"y":223.03,"z":-78.42},{"x":-438.32,"y":227.3,"z":-78.34},{"x":-437.77,"y":229.71,"z":-74.23}]},{"lat":-24.89,"lon":-10.62,"b":[{"x":-445.28,"y":212.9,"z":-79.49},{"x":-447.34,"y":208.53,"z":-79.55},{"x":-447.73,"y":206.06,"z":-83.65},{"x":-446.08,"y":207.95,"z":-87.68},{"x":-444.05,"y":212.3,"z":-87.61},{"x":-443.64,"y":214.77,"z":-83.53}]},{"lat":-22.97,"lon":-11.63,"b":[{"x":-450.55,"y":197.64,"z":-88.69},{"x":-452.46,"y":193.21,"z":-88.73},{"x":-452.71,"y":190.7,"z":-92.79},{"x":-451.06,"y":192.62,"z":-96.79},{"x":-449.16,"y":197.02,"z":-96.75},{"x":-448.9,"y":199.54,"z":-92.72}]},{"lat":-21.06,"lon":-12.6,"b":[{"x":-455.17,"y":182.17,"z":-97.74},{"x":-456.94,"y":177.68,"z":-97.75},{"x":-457.04,"y":175.15,"z":-101.76},{"x":-455.39,"y":177.09,"z":-105.73},{"x":-453.64,"y":181.54,"z":-105.72},{"x":-453.52,"y":184.09,"z":-101.74}]},{"lat":-19.15,"lon":-13.54,"b":[{"x":-459.15,"y":166.54,"z":-106.6},{"x":-460.77,"y":162.02,"z":-106.58},{"x":-460.73,"y":159.48,"z":-110.52},{"x":-459.09,"y":161.44,"z":-114.46},{"x":-457.48,"y":165.93,"z":-114.49},{"x":-457.5,"y":168.49,"z":-110.57}]},{"lat":-17.25,"lon":-14.45,"b":[{"x":-462.49,"y":150.84,"z":-115.24},{"x":-463.96,"y":146.3,"z":-115.18},{"x":-463.77,"y":143.76,"z":-119.05},{"x":-462.14,"y":145.73,"z":-122.95},{"x":-460.68,"y":150.23,"z":-123.02},{"x":-460.84,"y":152.8,"z":-119.17}]},{"lat":-15.38,"lon":-15.33,"b":[{"x":-465.17,"y":135.11,"z":-123.63},{"x":-466.49,"y":130.57,"z":-123.53},{"x":-466.17,"y":128.05,"z":-127.32},{"x":-464.55,"y":130.04,"z":-131.18},{"x":-463.24,"y":134.54,"z":-131.29},{"x":-463.54,"y":137.09,"z":-127.53}]},{"lat":-13.52,"lon":-16.18,"b":[{"x":-467.18,"y":119.07,"z":-132.29},{"x":-468.18,"y":115.2,"z":-132.17},{"x":-467.8,"y":113.07,"z":-135.33},{"x":-466.43,"y":114.78,"z":-138.59},{"x":-465.43,"y":118.61,"z":-138.73},{"x":-465.8,"y":120.77,"z":-135.58}]},{"lat":-50.33,"lon":5.9,"b":[{"x":-315.89,"y":385.79,"z":36.39},{"x":-318.73,"y":383.43,"z":36.56},{"x":-320.34,"y":382.42,"z":32.94},{"x":-319.05,"y":383.8,"z":29.18},{"x":-316.19,"y":386.17,"z":29.07},{"x":-314.64,"y":387.15,"z":32.67}]},{"lat":-48.96,"lon":4.36,"b":[{"x":-325.76,"y":378.16,"z":28.63},{"x":-328.63,"y":375.65,"z":28.77},{"x":-330.22,"y":374.53,"z":25.07},{"x":-328.88,"y":375.93,"z":21.26},{"x":-326,"y":378.44,"z":21.19},{"x":-324.47,"y":379.54,"z":24.87}]},{"lat":-47.53,"lon":2.87,"b":[{"x":-335.64,"y":369.95,"z":20.62},{"x":-338.52,"y":367.3,"z":20.72},{"x":-340.08,"y":366.06,"z":16.95},{"x":-338.7,"y":367.49,"z":13.1},{"x":-335.81,"y":370.14,"z":13.07},{"x":-334.3,"y":371.36,"z":16.81}]},{"lat":-46.04,"lon":1.41,"b":[{"x":-345.47,"y":361.16,"z":12.37},{"x":-348.36,"y":358.37,"z":12.43},{"x":-349.88,"y":357,"z":8.59},{"x":-348.45,"y":358.46,"z":4.71},{"x":-345.56,"y":361.25,"z":4.71},{"x":-344.09,"y":362.59,"z":8.52}]},{"lat":-44.49,"lon":0,"b":[{"x":-355.24,"y":351.75,"z":3.81},{"x":-358.07,"y":348.86,"z":3.84},{"x":-359.51,"y":347.4,"z":0},{"x":-358.07,"y":348.86,"z":-3.84},{"x":-355.24,"y":351.75,"z":-3.81},{"x":-353.84,"y":353.18,"z":0}]},{"lat":-42.89,"lon":-1.37,"b":[{"x":-364.88,"y":341.72,"z":-4.99},{"x":-367.63,"y":338.76,"z":-4.99},{"x":-368.97,"y":337.22,"z":-8.79},{"x":-367.53,"y":338.67,"z":-12.55},{"x":-364.79,"y":341.63,"z":-12.5},{"x":-363.48,"y":343.14,"z":-8.73}]},{"lat":-41.23,"lon":-2.7,"b":[{"x":-374.24,"y":331.19,"z":-13.71},{"x":-377.09,"y":327.94,"z":-13.74},{"x":-378.42,"y":326.21,"z":-17.76},{"x":-376.87,"y":327.76,"z":-21.72},{"x":-374.03,"y":331,"z":-21.64},{"x":-372.74,"y":332.7,"z":-17.65}]},{"lat":-39.53,"lon":-3.99,"b":[{"x":-383.43,"y":319.99,"z":-22.77},{"x":-386.23,"y":316.59,"z":-22.83},{"x":-387.48,"y":314.75,"z":-26.89},{"x":-385.9,"y":316.32,"z":-30.87},{"x":-383.1,"y":319.71,"z":-30.76},{"x":-381.88,"y":321.53,"z":-26.73}]},{"lat":-37.78,"lon":-5.24,"b":[{"x":-392.33,"y":308.2,"z":-31.98},{"x":-395.08,"y":304.66,"z":-32.05},{"x":-396.23,"y":302.69,"z":-36.15},{"x":-394.61,"y":304.3,"z":-40.14},{"x":-391.87,"y":307.84,"z":-40.02},{"x":-390.74,"y":309.77,"z":-35.95}]},{"lat":-35.99,"lon":-6.44,"b":[{"x":-401.69,"y":294.38,"z":-44.3},{"x":-402.41,"y":293.39,"z":-44.32},{"x":-402.69,"y":292.83,"z":-45.43},{"x":-402.25,"y":293.27,"z":-46.5},{"x":-401.53,"y":294.26,"z":-46.47},{"x":-401.26,"y":294.81,"z":-45.37}]},{"lat":-32.32,"lon":-8.74,"b":[{"x":-417,"y":268.88,"z":-61.25},{"x":-418.82,"y":266.03,"z":-61.32},{"x":-419.41,"y":264.39,"z":-64.32},{"x":-418.17,"y":265.62,"z":-67.21},{"x":-416.37,"y":268.47,"z":-67.11},{"x":-415.79,"y":270.09,"z":-64.14}]},{"lat":-30.44,"lon":-9.84,"b":[{"x":-424.48,"y":254.12,"z":-72.19},{"x":-425.34,"y":252.66,"z":-72.23},{"x":-425.58,"y":251.83,"z":-73.7},{"x":-424.96,"y":252.45,"z":-75.13},{"x":-424.11,"y":253.89,"z":-75.08},{"x":-423.87,"y":254.72,"z":-73.62}]},{"lat":-28.54,"lon":-10.9,"b":[{"x":-431.05,"y":239.9,"z":-81.28},{"x":-432.03,"y":238.11,"z":-81.32},{"x":-432.26,"y":237.08,"z":-83.08},{"x":-431.52,"y":237.83,"z":-84.79},{"x":-430.54,"y":239.61,"z":-84.74},{"x":-430.31,"y":240.64,"z":-82.99}]},{"lat":-26.63,"lon":-11.92,"b":[{"x":-436.83,"y":226.53,"z":-88.24},{"x":-438.99,"y":222.27,"z":-88.33},{"x":-439.4,"y":219.8,"z":-92.41},{"x":-437.64,"y":221.6,"z":-96.36},{"x":-435.5,"y":225.84,"z":-96.26},{"x":-435.08,"y":228.3,"z":-92.22}]},{"lat":-24.71,"lon":-12.91,"b":[{"x":-442.37,"y":211.5,"z":-97.45},{"x":-444.41,"y":207.16,"z":-97.51},{"x":-444.67,"y":204.65,"z":-101.54},{"x":-442.91,"y":206.47,"z":-105.48},{"x":-440.89,"y":210.79,"z":-105.4},{"x":-440.62,"y":213.3,"z":-101.4}]},{"lat":-22.79,"lon":-13.87,"b":[{"x":-447.3,"y":196.22,"z":-106.5},{"x":-449.2,"y":191.81,"z":-106.54},{"x":-449.32,"y":189.27,"z":-110.52},{"x":-447.55,"y":191.12,"z":-114.42},{"x":-445.68,"y":195.49,"z":-114.37},{"x":-445.54,"y":198.04,"z":-110.43}]},{"lat":-20.88,"lon":-14.8,"b":[{"x":-451.61,"y":180.74,"z":-115.36},{"x":-453.36,"y":176.29,"z":-115.37},{"x":-453.34,"y":173.73,"z":-119.29},{"x":-451.58,"y":175.61,"z":-123.16},{"x":-449.84,"y":180.02,"z":-123.14},{"x":-449.84,"y":182.6,"z":-119.26}]},{"lat":-18.98,"lon":-15.69,"b":[{"x":-455.27,"y":164.77,"z":-124.56},{"x":-456.65,"y":160.93,"z":-124.53},{"x":-456.5,"y":158.73,"z":-127.83},{"x":-455,"y":160.36,"z":-131.12},{"x":-453.63,"y":164.17,"z":-131.14},{"x":-453.76,"y":166.39,"z":-127.88}]},{"lat":-17.09,"lon":-16.56,"b":[{"x":-458.18,"y":147.77,"z":-134.95},{"x":-458.66,"y":146.28,"z":-134.92},{"x":-458.56,"y":145.44,"z":-136.17},{"x":-457.98,"y":146.07,"z":-137.42},{"x":-457.5,"y":147.54,"z":-137.45},{"x":-457.6,"y":148.4,"z":-136.21}]},{"lat":-51.79,"lon":4.5,"b":[{"x":-307.18,"y":393.54,"z":26.85},{"x":-309.23,"y":391.93,"z":26.96},{"x":-310.35,"y":391.21,"z":24.36},{"x":-309.39,"y":392.13,"z":21.67},{"x":-307.34,"y":393.74,"z":21.62},{"x":-306.25,"y":394.44,"z":24.2}]},{"lat":-50.44,"lon":2.96,"b":[{"x":-316.63,"y":386.4,"z":19.69},{"x":-319.19,"y":384.28,"z":19.78},{"x":-320.56,"y":383.3,"z":16.49},{"x":-319.33,"y":384.45,"z":13.13},{"x":-316.77,"y":386.57,"z":13.1},{"x":-315.44,"y":387.53,"z":16.37}]},{"lat":-49.03,"lon":1.46,"b":[{"x":-326.2,"y":378.67,"z":12.04},{"x":-329.08,"y":376.16,"z":12.11},{"x":-330.59,"y":374.95,"z":8.37},{"x":-329.17,"y":376.26,"z":4.58},{"x":-326.28,"y":378.76,"z":4.58},{"x":-324.83,"y":379.95,"z":8.3}]},{"lat":-47.56,"lon":0,"b":[{"x":-335.91,"y":370.25,"z":3.78},{"x":-338.81,"y":367.61,"z":3.82},{"x":-340.28,"y":366.27,"z":0},{"x":-338.81,"y":367.61,"z":-3.82},{"x":-335.91,"y":370.25,"z":-3.78},{"x":-334.49,"y":371.57,"z":0}]},{"lat":-46.04,"lon":-1.41,"b":[{"x":-346.28,"y":360.57,"z":-6.63},{"x":-347.73,"y":359.17,"z":-6.63},{"x":-348.44,"y":358.44,"z":-8.57},{"x":-347.68,"y":359.13,"z":-10.49},{"x":-346.23,"y":360.52,"z":-10.46},{"x":-345.54,"y":361.24,"z":-8.54}]},{"lat":-42.82,"lon":-4.11,"b":[{"x":-364.65,"y":341.25,"z":-22.82},{"x":-367.14,"y":338.57,"z":-22.87},{"x":-368.26,"y":337.09,"z":-26.33},{"x":-366.87,"y":338.32,"z":-29.7},{"x":-364.39,"y":341,"z":-29.59},{"x":-363.3,"y":342.45,"z":-26.17}]},{"lat":-41.14,"lon":-5.39,"b":[{"x":-373.65,"y":330.66,"z":-31.34},{"x":-376.48,"y":327.42,"z":-31.43},{"x":-377.7,"y":325.6,"z":-35.46},{"x":-376.06,"y":327.05,"z":-39.37},{"x":-373.23,"y":330.29,"z":-39.23},{"x":-372.04,"y":332.08,"z":-35.23}]},{"lat":-39.41,"lon":-6.63,"b":[{"x":-382.56,"y":319.27,"z":-40.54},{"x":-385.36,"y":315.88,"z":-40.64},{"x":-386.49,"y":313.94,"z":-44.71},{"x":-384.8,"y":315.42,"z":-48.62},{"x":-382.02,"y":318.81,"z":-48.47},{"x":-380.92,"y":320.72,"z":-44.44}]},{"lat":-37.64,"lon":-7.83,"b":[{"x":-391.18,"y":307.28,"z":-49.87},{"x":-393.9,"y":303.77,"z":-49.99},{"x":-394.92,"y":301.74,"z":-54.05},{"x":-393.21,"y":303.24,"z":-57.95},{"x":-390.51,"y":306.75,"z":-57.78},{"x":-389.5,"y":308.75,"z":-53.76}]},{"lat":-26.42,"lon":-14.22,"b":[{"x":-433.97,"y":223.15,"z":-108.83},{"x":-434.58,"y":221.94,"z":-108.86},{"x":-434.66,"y":221.22,"z":-110.01},{"x":-434.13,"y":221.72,"z":-111.11},{"x":-433.53,"y":222.92,"z":-111.07},{"x":-433.44,"y":223.64,"z":-109.94}]},{"lat":-24.5,"lon":-15.16,"b":[{"x":-439.07,"y":208.28,"z":-117.5},{"x":-439.82,"y":206.67,"z":-117.53},{"x":-439.87,"y":205.71,"z":-119.01},{"x":-439.17,"y":206.37,"z":-120.44},{"x":-438.42,"y":207.97,"z":-120.41},{"x":-438.37,"y":208.93,"z":-118.94}]},{"lat":-22.58,"lon":-16.07,"b":[{"x":-443.57,"y":193.47,"z":-125.56},{"x":-444.64,"y":190.97,"z":-125.59},{"x":-444.64,"y":189.5,"z":-127.81},{"x":-443.57,"y":190.53,"z":-129.98},{"x":-442.51,"y":193,"z":-129.95},{"x":-442.5,"y":194.48,"z":-127.75}]},{"lat":-20.68,"lon":-16.95,"b":[{"x":-447.5,"y":177.7,"z":-134.65},{"x":-448.28,"y":175.71,"z":-134.66},{"x":-448.22,"y":174.54,"z":-136.37},{"x":-447.38,"y":175.36,"z":-138.07},{"x":-446.6,"y":177.33,"z":-138.06},{"x":-446.66,"y":178.5,"z":-136.36}]},{"lat":-51.87,"lon":1.5,"b":[{"x":-307.98,"y":393.74,"z":9.68},{"x":-309.22,"y":392.76,"z":9.72},{"x":-309.87,"y":392.29,"z":8.12},{"x":-309.25,"y":392.8,"z":6.5},{"x":-308.01,"y":393.78,"z":6.5},{"x":-307.38,"y":394.24,"z":8.09}]},{"lat":-50.48,"lon":0,"b":[{"x":-317.34,"y":386.33,"z":2.1},{"x":-318.98,"y":384.98,"z":2.12},{"x":-319.81,"y":384.3,"z":0},{"x":-318.98,"y":384.98,"z":-2.12},{"x":-317.34,"y":386.33,"z":-2.1},{"x":-316.54,"y":387,"z":0}]},{"lat":-49.03,"lon":-1.46,"b":[{"x":-326.99,"y":378.16,"z":-6.42},{"x":-328.45,"y":376.88,"z":-6.42},{"x":-329.18,"y":376.22,"z":-8.35},{"x":-328.41,"y":376.84,"z":-10.26},{"x":-326.94,"y":378.11,"z":-10.22},{"x":-326.24,"y":378.77,"z":-8.32}]},{"lat":-47.53,"lon":-2.87,"b":[{"x":-336.14,"y":369.82,"z":-13.99},{"x":-338.34,"y":367.8,"z":-14.01},{"x":-339.39,"y":366.72,"z":-16.93},{"x":-338.21,"y":367.66,"z":-19.8},{"x":-336.01,"y":369.67,"z":-19.72},{"x":-335,"y":370.74,"z":-16.83}]},{"lat":-42.69,"lon":-6.82,"b":[{"x":-363.79,"y":340.57,"z":-40.03},{"x":-366.4,"y":337.76,"z":-40.14},{"x":-367.48,"y":336.13,"z":-43.78},{"x":-365.93,"y":337.33,"z":-47.26},{"x":-363.35,"y":340.15,"z":-47.1},{"x":-362.29,"y":341.75,"z":-43.51}]},{"lat":-40.98,"lon":-8.05,"b":[{"x":-372.83,"y":329.35,"z":-49.68},{"x":-375.07,"y":326.78,"z":-49.79},{"x":-375.95,"y":325.26,"z":-52.99},{"x":-374.57,"y":326.34,"z":-56.04},{"x":-372.34,"y":328.92,"z":-55.89},{"x":-371.48,"y":330.41,"z":-52.72}]},{"lat":-39.23,"lon":-9.24,"b":[{"x":-381.74,"y":317.2,"z":-60.13},{"x":-383.16,"y":315.48,"z":-60.21},{"x":-383.67,"y":314.45,"z":-62.27},{"x":-382.77,"y":315.16,"z":-64.22},{"x":-381.36,"y":316.88,"z":-64.12},{"x":-380.86,"y":317.89,"z":-62.08}]},{"lat":-28.08,"lon":-15.54,"b":[{"x":-424.95,"y":235.72,"z":-117.66},{"x":-425.25,"y":235.16,"z":-117.68},{"x":-425.29,"y":234.83,"z":-118.22},{"x":-425.03,"y":235.04,"z":-118.72},{"x":-424.73,"y":235.59,"z":-118.7},{"x":-424.69,"y":235.93,"z":-118.17}]},{"lat":-53.24,"lon":0,"b":[{"x":-298.61,"y":401,"z":1.6},{"x":-299.87,"y":400.06,"z":1.61},{"x":-300.5,"y":399.59,"z":0},{"x":-299.87,"y":400.06,"z":-1.61},{"x":-298.61,"y":401,"z":-1.6},{"x":-297.99,"y":401.47,"z":0}]},{"lat":-51.87,"lon":-1.5,"b":[{"x":-307.22,"y":394.39,"z":-4.46},{"x":-310.06,"y":392.16,"z":-4.46},{"x":-311.46,"y":390.99,"z":-8.14},{"x":-309.98,"y":392.07,"z":-11.78},{"x":-307.15,"y":394.3,"z":-11.71},{"x":-305.79,"y":395.45,"z":-8.07}]},{"lat":-50.44,"lon":-2.96,"b":[{"x":-317.26,"y":386.14,"z":-14.44},{"x":-318.8,"y":384.87,"z":-14.46},{"x":-319.54,"y":384.18,"z":-16.47},{"x":-318.71,"y":384.77,"z":-18.43},{"x":-317.18,"y":386.04,"z":-18.38},{"x":-316.47,"y":386.71,"z":-16.39}]},{"lat":-42.5,"lon":-9.51,"b":[{"x":-363.37,"y":338.12,"z":-60.15},{"x":-363.91,"y":337.54,"z":-60.18},{"x":-364.11,"y":337.19,"z":-60.93},{"x":-363.77,"y":337.42,"z":-61.63},{"x":-363.24,"y":338,"z":-61.59},{"x":-363.05,"y":338.35,"z":-60.85}]},{"lat":-14.68,"lon":-23.31,"b":[{"x":-444.29,"y":126.94,"z":-191.01},{"x":-444.43,"y":126.48,"z":-190.99},{"x":-444.35,"y":126.21,"z":-191.35},{"x":-444.14,"y":126.4,"z":-191.71},{"x":-444,"y":126.86,"z":-191.73},{"x":-444.08,"y":127.13,"z":-191.38}]},{"lat":-54.55,"lon":-1.55,"b":[{"x":-288.78,"y":408.09,"z":-4.96},{"x":-291.06,"y":406.47,"z":-4.96},{"x":-292.19,"y":405.61,"z":-7.89},{"x":-291,"y":406.39,"z":-10.8},{"x":-288.73,"y":408.02,"z":-10.74},{"x":-287.64,"y":408.86,"z":-7.84}]},{"lat":-53.2,"lon":-3.06,"b":[{"x":-298.35,"y":400.95,"z":-13.97},{"x":-299.9,"y":399.79,"z":-13.99},{"x":-300.65,"y":399.15,"z":-16},{"x":-299.82,"y":399.69,"z":-17.97},{"x":-298.27,"y":400.85,"z":-17.91},{"x":-297.55,"y":401.48,"z":-15.92}]},{"lat":-51.79,"lon":-4.5,"b":[{"x":-307.74,"y":393.39,"z":-22.74},{"x":-308.93,"y":392.45,"z":-22.77},{"x":-309.49,"y":391.92,"z":-24.32},{"x":-308.84,"y":392.33,"z":-25.83},{"x":-307.65,"y":393.27,"z":-25.78},{"x":-307.11,"y":393.79,"z":-24.24}]}]} ================================================ FILE: src/assets/themes/apollo-notype.json ================================================ { "colors": { "r": 235, "g": 235, "b": 235, "black": "#000000", "light_black": "#191919", "grey": "#262827" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#ebebeb", "background": "#191919", "cursor": "#ebebeb", "cursorAccent": "#ebebeb", "selection": "rgba(235,235,235,0.3)" }, "globe": { "base": "#000000", "marker": "#ebebeb", "pin": "#ebebeb", "satellite": "#ebebeb" }, "injectCSS": "section#filesystem{left:0;width:100vw}section#filesystem>h3.title,section#filesystem>div{width:100vw}section#keyboard{display:none;}" } ================================================ FILE: src/assets/themes/apollo.json ================================================ { "colors": { "r": 235, "g": 235, "b": 235, "black": "#000000", "light_black": "#191919", "grey": "#262827" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#ebebeb", "background": "#191919", "cursor": "#ebebeb", "cursorAccent": "#ebebeb", "selection": "rgba(235,235,235,0.3)" }, "globe": { "base": "#000000", "marker": "#ebebeb", "pin": "#ebebeb", "satellite": "#ebebeb" } } ================================================ FILE: src/assets/themes/blade.json ================================================ { "colors": { "r": 204, "g": 94, "b": 55, "black": "#000000", "light_black": "#090B0A", "grey": "#262827" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "underline", "foreground": "#cc5e37", "background": "#090B0A", "cursor": "#cc5e37", "cursorAccent": "#cc5e37", "selection": "rgba(204,94,55,0.3)" }, "globe": { "base": "#cc5e37", "marker": "#cc5e37", "pin": "#cc5e37", "satellite": "#cc5e37" } } ================================================ FILE: src/assets/themes/chalkboard-ligatures.json ================================================ { "colors": { "r": 239, "g": 240, "b": 235, "black": "#282a36", "light_black": "#222430", "grey": "#222430", "red": "#ff5c57", "green": "#5af78e", "yellow": "#f3f99d", "blue": "#57c7ff", "magenta": "#ff6ac1", "cyan": "#9aedfe", "white": "#f1f1f0", "brightBlack": "#686868", "brightRed": "#ff5c57", "brightGreen": "#5af78e", "brightYellow": "#f3f99d", "brightBlue": "#57c7ff", "brightMagenta": "#ff6ac1", "brightCyan": "#9aedfe", "brightWhite": "#eff0eb" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Code", "cursorStyle": "block", "foreground": "#eff0eb", "background": "#282a36", "cursor": "#97979b", "cursorAccent": "#282a36", "selection": "rgba(239,240,235,0.3)" }, "globe": { "base": "#000000", "marker": "#f3f99d", "pin": "#eff0eb", "satellite": "#ff5c57" } } ================================================ FILE: src/assets/themes/chalkboard-notype.json ================================================ { "colors": { "r": 239, "g": 240, "b": 235, "black": "#282a36", "light_black": "#222430", "grey": "#222430", "red": "#ff5c57", "green": "#5af78e", "yellow": "#f3f99d", "blue": "#57c7ff", "magenta": "#ff6ac1", "cyan": "#9aedfe", "white": "#f1f1f0", "brightBlack": "#686868", "brightRed": "#ff5c57", "brightGreen": "#5af78e", "brightYellow": "#f3f99d", "brightBlue": "#57c7ff", "brightMagenta": "#ff6ac1", "brightCyan": "#9aedfe", "brightWhite": "#eff0eb" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#eff0eb", "background": "#282a36", "cursor": "#97979b", "cursorAccent": "#282a36", "selection": "rgba(239,240,235,0.3)" }, "globe": { "base": "#000000", "marker": "#f3f99d", "pin": "#eff0eb", "satellite": "#ff5c57" }, "injectCSS": "section#filesystem{left:0;width:100vw}section#filesystem>h3.title,section#filesystem>div{width:100vw}section#keyboard{display:none;}" } ================================================ FILE: src/assets/themes/chalkboard.json ================================================ { "colors": { "r": 239, "g": 240, "b": 235, "black": "#282a36", "light_black": "#222430", "grey": "#222430", "red": "#ff5c57", "green": "#5af78e", "yellow": "#f3f99d", "blue": "#57c7ff", "magenta": "#ff6ac1", "cyan": "#9aedfe", "white": "#f1f1f0", "brightBlack": "#686868", "brightRed": "#ff5c57", "brightGreen": "#5af78e", "brightYellow": "#f3f99d", "brightBlue": "#57c7ff", "brightMagenta": "#ff6ac1", "brightCyan": "#9aedfe", "brightWhite": "#eff0eb" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#eff0eb", "background": "#282a36", "cursor": "#97979b", "cursorAccent": "#282a36", "selection": "rgba(239,240,235,0.3)" }, "globe": { "base": "#000000", "marker": "#f3f99d", "pin": "#eff0eb", "satellite": "#ff5c57" } } ================================================ FILE: src/assets/themes/cyborg-focus.json ================================================ { "colors": { "r": 95, "g": 215, "b": 215, "black": "#011f1f", "light_black": "#0a3333", "grey": "#034747", "red": "#ad3e5a", "green": "#3cd66f", "yellow": "#c5d63c", "blue": "#3c4dd6", "magenta": "#ad31ad", "cyan": "#31adad", "white": "#a3c2c2", "brightBlack": "#454585", "brightRed": "#eb0954", "brightGreen": "#85ff5c", "brightYellow": "#ffff5c", "brightBlue": "#5c5cff", "brightMagenta": "#ff47d6", "brightCyan": "#5cffff", "brightWhite": "#e6fafa" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Code", "cursorStyle": "block", "foreground": "#a3c2c2", "background": "#0a3333", "cursor": "#5cffff", "cursorAccent": "#85ff5c", "selection": "#ffff5c" }, "globe": { "base": "#5c5cff", "marker": "#eb0954", "pin": "#85ff5c", "satellite": "#ffff5c" }, "injectCSS": "section#keyboard{position:absolute;bottom:3%;right:0;width:17%}section#keyboard .keyboard_row{position:absolute;bottom:0;width:100%;text-align:center}section#keyboard .keyboard_key{position:absolute;bottom:0;display:none}section#keyboard .keyboard_key.active,section#keyboard .keyboard_key.blink{position:absolute;bottom:0;display:flex;color:#263a3a}section#keyboard div.keyboard_key#keyboard_spacebar{min-width:auto;width:80%;right:15%}section#keyboard div.keyboard_row#row_2 div.keyboard_key.keyboard_enter{display:none !important}section#keyboard div.keyboard_key[data-cmd^=\"ESCAPED\"]{left:0} section>h3.title:first-child{border-bottom:0}section>h3.title:first-child::before{border-left:0}section>h3.title:first-child::after{border-right:0} section#filesystem{position:absolute;top:auto;left:0;bottom:0;width:17%}section#filesystem>h3.title{width:17%}section#filesystem>h3.title:first-child>p{width:24%}section#filesystem>h3.title:first-child>p:last-child{position:static;right:auto;width:72%}section#filesystem div#fs_disp_container{width:100%}section#filesystem.list-view>div#fs_disp_container:not(.disks)>div>h4{font-size:0.8vh}section#filesystem.list-view>div#fs_disp_container:not(.disks)>div>h4:nth-of-type(1){display:none}section#filesystem.list-view>div#fs_disp_container:not(.disks)>div>h4:nth-of-type(2){width:25%}div#fs_space_bar{display:none} section#main_shell{height:94.5%;padding:0.37vh;position:absolute;top:2.5vh}ul#main_shell_tabs{margin-left:-0.37vh;margin-top:-0.35vh}ul#main_shell_tabs>li{padding-top:0.55vh;padding-bottom:0.2vh}.terminal .xterm-viewport{padding-bottom:0}.xterm{height:100%}.xterm .xterm-screen{top:0.8vh;left:0.4vh}" } ================================================ FILE: src/assets/themes/cyborg.json ================================================ { "colors": { "r": 95, "g": 215, "b": 215, "black": "#011f1f", "light_black": "#0a3333", "grey": "#034747", "red": "#ad3e5a", "green": "#3cd66f", "yellow": "#c5d63c", "blue": "#3c4dd6", "magenta": "#ad31ad", "cyan": "#31adad", "white": "#a3c2c2", "brightBlack": "#454585", "brightRed": "#eb0954", "brightGreen": "#85ff5c", "brightYellow": "#ffff5c", "brightBlue": "#5c5cff", "brightMagenta": "#ff47d6", "brightCyan": "#5cffff", "brightWhite": "#e6fafa" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Code", "cursorStyle": "block", "foreground": "#a3c2c2", "background": "#0a3333", "cursor": "#5cffff", "cursorAccent": "#85ff5c", "selection": "#ffff5c" }, "globe": { "base": "#5c5cff", "marker": "#eb0954", "pin": "#85ff5c", "satellite": "#ffff5c" }, "injectCSS": "" } ================================================ FILE: src/assets/themes/interstellar.json ================================================ { "colors": { "r": 3, "g": 169, "b": 244, "black": "#f3f3f3", "light_black": "#dedede", "grey": "#bfbfbf" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "bar", "foreground": "#03A9F4", "background": "#dedede", "cursor": "#03A9F4", "cursorAccent": "#03A9F4", "selection": "rgba(3,169,244,0.3)" }, "globe": { "base": "#03A9F4", "marker": "#03A9F4", "pin": "#03A9F4", "satellite": "#03A9F4" } } ================================================ FILE: src/assets/themes/matrix.json ================================================ { "colors": { "r": 0, "g": 143, "b": 17, "black": "#0D0208", "light_black": "#090B0A", "grey": "#262827" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "underline", "foreground": "#00ff41", "background": "#0D0208", "cursor": "#00ff41", "cursorAccent": "#00ff41", "selection": "#008f11" }, "globe": { "base": "#008f11", "marker": "#008f11", "pin": "#008f11", "satellite": "#008f11" } } ================================================ FILE: src/assets/themes/navy-disrupted.json ================================================ { "colors": { "r": 20, "g": 119, "b": 205, "black": "#282a36", "light_black": "#222430", "grey": "#222430", "red": "#ff5c57", "green": "#5af78e", "yellow": "#f3f99d", "blue": "#57c7ff", "magenta": "#ff6ac1", "cyan": "#9aedfe", "white": "#f1f1f0", "brightBlack": "#686868", "brightRed": "#ff5c57", "brightGreen": "#5af78e", "brightYellow": "#f3f99d", "brightBlue": "#57c7ff", "brightMagenta": "#ff6ac1", "brightCyan": "#9aedfe", "brightWhite": "#eff0eb" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#87b7cc", "background": "#222430", "cursor": "#87b7cc", "cursorAccent": "#16739c", "selection": "rgba(239,240,235,0.3)" }, "globe": { "base": "#16739c", "marker": "#ad0c0c", "pin": "#04b80a", "satellite": "#e3f213" }, "injectCSS": "section#main_shell{position:relative;left:29vh;}section#main_shell>h3.title{left:calc(29vh + 16.5vw)!important;}section#mod_column_right{left:28.5vh!important;}section#mod_column_right>h3.title{left:29.6vh!important;}div#mod_netstat_inner{height:6.85vh;padding-top:.5vh;}div#mod_globe_innercontainer{padding-bottom:.95vh;}div#mod_conninfo canvas{height:8vh!important;} @media (aspect-ratio:64/27) {section#mod_column_left > h3.title{left:1.6vh!important}section#mod_column_left{left:1vh !important}section#mod_column_right > h3.title{left:44vh!important}section#mod_column_right{left:43vh !important}section#main_shell > h3.title{left:37vw !important;width:60% !important}section#main_shell{left:41vh;width:60%}}" } ================================================ FILE: src/assets/themes/navy-notype.json ================================================ { "colors": { "r": 20, "g": 119, "b": 205, "black": "#282a36", "light_black": "#222430", "grey": "#222430", "red": "#ff5c57", "green": "#5af78e", "yellow": "#f3f99d", "blue": "#57c7ff", "magenta": "#ff6ac1", "cyan": "#9aedfe", "white": "#f1f1f0", "brightBlack": "#686868", "brightRed": "#ff5c57", "brightGreen": "#5af78e", "brightYellow": "#f3f99d", "brightBlue": "#57c7ff", "brightMagenta": "#ff6ac1", "brightCyan": "#9aedfe", "brightWhite": "#eff0eb" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#87b7cc", "background": "#222430", "cursor": "#87b7cc", "cursorAccent": "#16739c", "selection": "rgba(239,240,235,0.3)" }, "globe": { "base": "#16739c", "marker": "#ad0c0c", "pin": "#04b80a", "satellite": "#e3f213" }, "injectCSS": "section#filesystem{left:0;width:100vw}section#filesystem>h3.title,section#filesystem>div{width:100vw}section#keyboard{display:none;}" } ================================================ FILE: src/assets/themes/navy.json ================================================ { "colors": { "r": 20, "g": 119, "b": 205, "black": "#282a36", "light_black": "#222430", "grey": "#222430", "red": "#ff5c57", "green": "#5af78e", "yellow": "#f3f99d", "blue": "#57c7ff", "magenta": "#ff6ac1", "cyan": "#9aedfe", "white": "#f1f1f0", "brightBlack": "#686868", "brightRed": "#ff5c57", "brightGreen": "#5af78e", "brightYellow": "#f3f99d", "brightBlue": "#57c7ff", "brightMagenta": "#ff6ac1", "brightCyan": "#9aedfe", "brightWhite": "#eff0eb" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#87b7cc", "background": "#222430", "cursor": "#87b7cc", "cursorAccent": "#16739c", "selection": "rgba(239,240,235,0.3)" }, "globe": { "base": "#16739c", "marker": "#ad0c0c", "pin": "#04b80a", "satellite": "#e3f213" } } ================================================ FILE: src/assets/themes/nord.json ================================================ { "colors": { "r": 216, "g": 222, "b": 233, "black": "#3B4252", "red": "#BF616A", "green": "#A3BE8C", "yellow": "#EBCB8B", "blue": "#81A1C1", "magenta": "#B48EAD", "cyan": "#88C0D0", "white": "#E5E9F0", "lightBlack": "#4C566A", "lightRed": "#BF616A", "lightGreen": "#A3BE8C", "lightYellow": "#EBCB8B", "lightBlue": "#81A1C1", "lightMagenta": "#B48EAD", "lightCyan": "#8FBCBB", "lightWhite": "#ECEFF4", "light_black": "#2E3440", "grey": "#4c566a" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#D8DEE9", "background": "#2E3440", "cursor": "#D8DEE9", "selection": "rgba(67, 76, 94, 0.8)" }, "globe": { "base": "#000000", "marker": "#EBCB8B", "pin": "#81A1C1", "satellite": "#BF616A" } } ================================================ FILE: src/assets/themes/red.json ================================================ { "colors": { "r": 204, "g": 0, "b": 34, "black": "#000000", "light_black": "#090B0A", "grey": "#0f2e3d" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "underline", "foreground": "#cc0022", "background": "#090B0A", "cursor": "#cc0022", "cursorAccent": "#cc0022", "selection": "rgba(204,0,34,0.3)" }, "globe": { "base": "#cc0022", "marker": "#cc0022", "pin": "#cc0022", "satellite": "#cc0022" } } ================================================ FILE: src/assets/themes/tron-colorfilter.json ================================================ { "colors": { "r": 170, "g": 207, "b": 209, "black": "#000000", "light_black": "#05080d", "grey": "#262828" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#aacfd1", "background": "#05080d", "cursor": "#aacfd1", "cursorAccent": "#aacfd1", "selection": "rgba(170,207,209,0.3)", "colorFilter": [ "rotate(180)", "saturate(0.5)", "mix(0.7)" ] }, "globe": { "base": "#000000", "marker": "#aacfd1", "pin": "#aacfd1", "satellite": "#aacfd1" } } ================================================ FILE: src/assets/themes/tron-disrupted.json ================================================ { "colors": { "r": 170, "g": 207, "b": 209, "black": "#000000", "light_black": "#05080d", "grey": "#262828" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#aacfd1", "background": "#05080d", "cursor": "#aacfd1", "cursorAccent": "#aacfd1", "selection": "rgba(170,207,209,0.3)" }, "globe": { "base": "#000000", "marker": "#aacfd1", "pin": "#aacfd1", "satellite": "#aacfd1" }, "injectCSS": "section#main_shell{position:relative;left:29vh;}section#main_shell>h3.title{left:calc(29vh + 16.5vw)!important;}section#mod_column_right{left:28.5vh!important;}section#mod_column_right>h3.title{left:29.6vh!important;}div#mod_netstat_inner{height:6.85vh;padding-top:.5vh;}div#mod_globe_innercontainer{padding-bottom:.95vh;}div#mod_conninfo canvas{height:8vh!important;} @media (aspect-ratio:64/27) {section#mod_column_left > h3.title{left:1.6vh!important}section#mod_column_left{left:1vh !important}section#mod_column_right > h3.title{left:44vh!important}section#mod_column_right{left:43vh !important}section#main_shell > h3.title{left:37vw !important;width:60% !important}section#main_shell{left:41vh;width:60%}}" } ================================================ FILE: src/assets/themes/tron-fulltype.json ================================================ { "colors": { "r": 170, "g": 207, "b": 209, "black": "#000000", "light_black": "#05080d", "grey": "#262828" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#aacfd1", "background": "#05080d", "cursor": "#aacfd1", "cursorAccent": "#aacfd1", "selection": "rgba(170,207,209,0.3)" }, "globe": { "base": "#000000", "marker": "#aacfd1", "pin": "#aacfd1", "satellite": "#aacfd1" }, "injectCSS": "section#keyboard{width: 100vw;} div.keyboard_key{margin: 0vh 0.8vh;} div.keyboard_key#keyboard_spacebar{width: 53.5vh;min-width: 53.5vh;} section#filesystem{display:none;}" } ================================================ FILE: src/assets/themes/tron-notype.json ================================================ { "colors": { "r": 170, "g": 207, "b": 209, "black": "#000000", "light_black": "#05080d", "grey": "#262828" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#aacfd1", "background": "#05080d", "cursor": "#aacfd1", "cursorAccent": "#aacfd1", "selection": "rgba(170,207,209,0.3)" }, "globe": { "base": "#000000", "marker": "#aacfd1", "pin": "#aacfd1", "satellite": "#aacfd1" }, "injectCSS": "section#filesystem{left: 0;width:100vw} section#filesystem>h3.title, section#filesystem>div{width:100vw} section#keyboard{display:none;}" } ================================================ FILE: src/assets/themes/tron-typeleft.json ================================================ { "colors": { "r": 170, "g": 207, "b": 209, "black": "#000000", "light_black": "#05080d", "grey": "#262828" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#aacfd1", "background": "#05080d", "cursor": "#aacfd1", "cursorAccent": "#aacfd1", "selection": "rgba(170,207,209,0.3)" }, "globe": { "base": "#000000", "marker": "#aacfd1", "pin": "#aacfd1", "satellite": "#aacfd1" }, "injectCSS": "section#filesystem{left: 55vw;} section#keyboard{right: 44vw;}" } ================================================ FILE: src/assets/themes/tron.json ================================================ { "colors": { "r": 170, "g": 207, "b": 209, "black": "#000000", "light_black": "#05080d", "grey": "#262828" }, "cssvars": { "font_main": "United Sans Medium", "font_main_light": "United Sans Light" }, "terminal": { "fontFamily": "Fira Mono", "cursorStyle": "block", "foreground": "#aacfd1", "background": "#05080d", "cursor": "#aacfd1", "cursorAccent": "#aacfd1", "selection": "rgba(170,207,209,0.3)" }, "globe": { "base": "#000000", "marker": "#aacfd1", "pin": "#aacfd1", "satellite": "#aacfd1" } } ================================================ FILE: src/assets/vendor/encom-globe.js ================================================ /** * This is a fork of the Encom Globe by Rob "arscan" Scanlon (https://robscanlon.com) * Original Source: https://github.com/arscan/encom-globe **/ (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o 0){ nf = new Face(prev[j-1], prev[j], bottom[j]); newFaces.push(nf); } } } } faces = newFaces; var newPoints = {}; for(var p in points){ var np = points[p].project(radius); newPoints[np] = np; } points = newPoints; this.tiles = []; for(var p in points){ this.tiles.push(new Tile(points[p], hexSize)); } }; module.exports = Hexasphere; },{"./face":2,"./point":4,"./tile":5}],4:[function(require,module,exports){ var Point = function(x,y,z){ if(x !== undefined && y !== undefined && z !== undefined){ this.x = x; this.y = y; this.z = z; } this.faces = []; } Point.prototype.subdivide = function(point, count, checkPoint){ var segments = []; segments.push(this); for(var i = 1; i< count; i++){ var np = new Point(this.x * (1-(i/count)) + point.x * (i/count), this.y * (1-(i/count)) + point.y * (i/count), this.z * (1-(i/count)) + point.z * (i/count)); np = checkPoint(np); segments.push(np); } segments.push(point); return segments; } Point.prototype.segment = function(point, percent){ var newPoint = new Point(); percent = Math.max(0.01, Math.min(1, percent)); newPoint.x = point.x * (1-percent) + this.x * percent; newPoint.y = point.y * (1-percent) + this.y * percent; newPoint.z = point.z * (1-percent) + this.z * percent; return newPoint; }; Point.prototype.midpoint = function(point, location){ return this.segment(point, .5); } Point.prototype.project = function(radius, percent){ if(percent == undefined){ percent = 1.0; } percent = Math.max(0, Math.min(1, percent)); var yx = this.y / this.x; var zx = this.z / this.x; var yz = this.z / this.y; var mag = Math.sqrt(Math.pow(this.x, 2) + Math.pow(this.y, 2) + Math.pow(this.z, 2)); var ratio = radius/ mag; this.x = this.x * ratio * percent; this.y = this.y * ratio * percent; this.z = this.z * ratio * percent; return this; }; Point.prototype.registerFace = function(face){ this.faces.push(face); } Point.prototype.getOrderedFaces = function(){ var workingArray = this.faces.slice(); var ret = []; var i = 0; while(i < this.faces.length){ if(i == 0){ ret.push(workingArray[i]); workingArray.splice(i,1); } else { var hit = false; var j = 0; while(j < workingArray.length && !hit){ if(workingArray[j].isAdjacentTo(ret[i-1])){ hit = true; ret.push(workingArray[j]); workingArray.splice(j, 1); } j++; } } i++; } return ret; } Point.prototype.findCommonFace = function(other, notThisFace){ for(var i = 0; i< this.faces.length; i++){ for(var j = 0; j< other.faces.length; j++){ if(this.faces[i].id === other.faces[j].id && this.faces[i].id !== notThisFace.id){ return this.faces[i]; } } } return null; } Point.prototype.toString = function(){ return "" + Math.round(this.x*100)/100 + "," + Math.round(this.y*100)/100 + "," + Math.round(this.z*100)/100; } module.exports = Point; },{}],5:[function(require,module,exports){ var Point = require('./point'); var Tile = function(centerPoint, hexSize){ if(hexSize == undefined){ hexSize = 1; } hexSize = Math.max(.01, Math.min(1.0, hexSize)); this.centerPoint = centerPoint; this.faces = centerPoint.getOrderedFaces(); this.boundary = []; this.triangles = []; for(var f=0; f< this.faces.length; f++){ this.boundary.push(this.faces[f].getCentroid().segment(this.centerPoint, hexSize)); } }; Tile.prototype.getLatLon = function(radius, boundaryNum){ var point = this.centerPoint; if(typeof boundaryNum == "number" && boundaryNum < this.boundary.length){ point = this.boundary[boundaryNum]; } var phi = Math.acos(point.y / radius); //lat var theta = (Math.atan2(point.x, point.z) + Math.PI + Math.PI / 2) % (Math.PI * 2) - Math.PI; // lon // theta is a hack, since I want to rotate by Math.PI/2 to start. sorryyyyyyyyyyy return { lat: 180 * phi / Math.PI - 90, lon: 180 * theta / Math.PI }; }; Tile.prototype.scaledBoundary = function(scale){ scale = Math.max(0, Math.min(1, scale)); var ret = []; for(var i = 0; i < this.boundary.length; i++){ ret.push(this.centerPoint.segment(this.boundary[i], 1 - scale)); } return ret; }; Tile.prototype.toString = function(){ return this.centerPoint.toString(); }; module.exports = Tile; },{"./point":4}],6:[function(require,module,exports){ /* ---------------------------------------------------------------------------- pusher.color.js A color parsing and manipulation library ---------------------------------------------------------------------------- The MIT License (MIT). Copyright (c) 2013, Pusher Inc. */ /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ---------------------------------------------------------------------------- */ (function() { //-----------------------------------------------------------------------// // Local Misc. Utility Functions //-----------------------------------------------------------------------// function normalize360(v) { v = v % 360; return (v < 0) ? 360 + v : v; } function unsigned(i) { // the >>> operator will force unsigned return i >>> 0; } function trimLc(s) { return s.replace(/^\s+/,'').replace(/\s+$/,'').toLowerCase(); } function slice(obj, index) { return Array.prototype.slice.call(obj, index); } function append(arr, value) { arr.push(value); return arr; } function clamp(x,a,b) { return !(x > a) ? a : !(x < b) ? b : x; } function mix(x,y,a) { return (1 - a) * x + a * y; } // Float to byte function f2b(f) { f = Math.round(255 * f); if (!(f > 0)) return 0; else if (!(f < 255)) return 255; else return f & 0xFF; }; // Byte to float function b2f(b) { return b / 255.0; }; //-----------------------------------------------------------------------// // Color conversion functions //-----------------------------------------------------------------------// /** * Converts an RGB color value to HSL. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSL_color_space. * * @param Number r The red color value * @param Number g The green color value * @param Number b The blue color value * @return Array The HSL representation * * @credit http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript */ function rgbToHsl(r, g, b) { var max = Math.max(r, g, b), min = Math.min(r, g, b); var h, s, l = (max + min) / 2; if(max == min) { h = s = 0; // achromatic } else { var d = max - min; s = l > 0.5 ? d / (2 - max - min) : d / (max + min); switch (max) { case r: h = (g - b) / d + (g < b ? 6 : 0); break; case g: h = (b - r) / d + 2; break; case b: h = (r - g) / d + 4; break; } h /= 6; } return [h, s, l]; } /** * Converts an HSL color value to RGB. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSL_color_space. * * @param Number h The hue * @param Number s The saturation * @param Number l The lightness * @return Array The RGB representation * @credit http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript */ function hslToRgb(h, s, l) { var r, g, b; if (s == 0) { r = g = b = l; // achromatic } else { function hue2rgb(p, q, t){ if(t < 0) t += 1; if(t > 1) t -= 1; if(t < 1/6) return p + (q - p) * 6 * t; if(t < 1/2) return q; if(t < 2/3) return p + (q - p) * (2/3 - t) * 6; return p; } var q = l < 0.5 ? l * (1 + s) : l + s - l * s; var p = 2 * l - q; r = hue2rgb(p, q, h + 1/3); g = hue2rgb(p, q, h); b = hue2rgb(p, q, h - 1/3); } return [r, g, b]; } function hex4ToRgba(color) { var rgba = [ parseInt(color.substr(1,1), 16), parseInt(color.substr(2,1), 16), parseInt(color.substr(3,1), 16), 1.0 ]; for (var i = 0; i < 3; ++i) rgba[i] = (rgba[i] * 16 + rgba[i]) / 255.0; return rgba; }; function hex7ToRgba(color) { return [ parseInt(color.substr(1,2), 16) / 255, parseInt(color.substr(3,2), 16) / 255, parseInt(color.substr(5,2), 16) / 255, 1.0 ]; }; var namedColors = { "aliceblue": [240, 248, 255 ], "antiquewhite": [250, 235, 215 ], "aqua": [0, 255, 255 ], "aquamarine": [127, 255, 212 ], "azure": [240, 255, 255 ], "beige": [245, 245, 220 ], "bisque": [255, 228, 196], "black": [0, 0, 0], "blanchedalmond": [255, 235, 205], "blue": [0, 0, 255], "blueviolet": [138, 43, 226], "brown": [165, 42, 42], "burlywood": [222, 184, 135], "cadetblue": [95, 158, 160], "chartreuse": [127, 255, 0], "chocolate": [210, 105, 30], "coral": [255, 127, 80], "cornflowerblue": [100, 149, 237], "cornsilk": [255, 248, 220], "crimson": [220, 20, 60], "cyan": [0, 255, 255], "darkblue": [0, 0, 139], "darkcyan": [0, 139, 139], "darkgoldenrod": [184, 134, 11], "darkgray": [169, 169, 169], "darkgreen": [0, 100, 0], "darkgrey": [169, 169, 169], "darkkhaki": [189, 183, 107], "darkmagenta": [139, 0, 139], "darkolivegreen": [85, 107, 47], "darkorange": [255, 140, 0], "darkorchid": [153, 50, 204], "darkred": [139, 0, 0], "darksalmon": [233, 150, 122], "darkseagreen": [143, 188, 143], "darkslateblue": [72, 61, 139], "darkslategray": [47, 79, 79], "darkslategrey": [47, 79, 79], "darkturquoise": [0, 206, 209], "darkviolet": [148, 0, 211], "deeppink": [255, 20, 147], "deepskyblue": [0, 191, 255], "dimgray": [105, 105, 105], "dimgrey": [105, 105, 105], "dodgerblue": [30, 144, 255], "firebrick": [178, 34, 34], "floralwhite": [255, 250, 240], "forestgreen": [34, 139, 34], "fuchsia": [255, 0, 255], "gainsboro": [220, 220, 220], "ghostwhite": [248, 248, 255], "gold": [255, 215, 0], "goldenrod": [218, 165, 32], "gray": [128, 128, 128], "green": [0, 128, 0], "greenyellow": [173, 255, 47], "grey": [128, 128, 128], "honeydew": [240, 255, 240], "hotpink": [255, 105, 180], "indianred": [205, 92, 92], "indigo": [75, 0, 130], "ivory": [255, 255, 240], "khaki": [240, 230, 140], "lavender": [230, 230, 250], "lavenderblush": [255, 240, 245], "lawngreen": [124, 252, 0], "lemonchiffon": [255, 250, 205], "lightblue": [173, 216, 230], "lightcoral": [240, 128, 128], "lightcyan": [224, 255, 255], "lightgoldenrodyellow": [250, 250, 210], "lightgray": [211, 211, 211], "lightgreen": [144, 238, 144], "lightgrey": [211, 211, 211], "lightpink": [255, 182, 193], "lightsalmon": [255, 160, 122], "lightseagreen": [32, 178, 170], "lightskyblue": [135, 206, 250], "lightslategray": [119, 136, 153], "lightslategrey": [119, 136, 153], "lightsteelblue": [176, 196, 222], "lightyellow": [255, 255, 224], "lime": [0, 255, 0], "limegreen": [50, 205, 50], "linen": [250, 240, 230], "magenta": [255, 0, 255], "maroon": [128, 0, 0], "mediumaquamarine": [102, 205, 170], "mediumblue": [0, 0, 205], "mediumorchid": [186, 85, 211], "mediumpurple": [147, 112, 216], "mediumseagreen": [60, 179, 113], "mediumslateblue": [123, 104, 238], "mediumspringgreen": [0, 250, 154], "mediumturquoise": [72, 209, 204], "mediumvioletred": [199, 21, 133], "midnightblue": [25, 25, 112], "mintcream": [245, 255, 250], "mistyrose": [255, 228, 225], "moccasin": [255, 228, 181], "navajowhite": [255, 222, 173], "navy": [0, 0, 128], "oldlace": [253, 245, 230], "olive": [128, 128, 0], "olivedrab": [107, 142, 35], "orange": [255, 165, 0], "orangered": [255, 69, 0], "orchid": [218, 112, 214], "palegoldenrod": [238, 232, 170], "palegreen": [152, 251, 152], "paleturquoise": [175, 238, 238], "palevioletred": [216, 112, 147], "papayawhip": [255, 239, 213], "peachpuff": [255, 218, 185], "peru": [205, 133, 63], "pink": [255, 192, 203], "plum": [221, 160, 221], "powderblue": [176, 224, 230], "purple": [128, 0, 128], "red": [255, 0, 0], "rosybrown": [188, 143, 143], "royalblue": [65, 105, 225], "saddlebrown": [139, 69, 19], "salmon": [250, 128, 114], "sandybrown": [244, 164, 96], "seagreen": [46, 139, 87], "seashell": [255, 245, 238], "sienna": [160, 82, 45], "silver": [192, 192, 192], "skyblue": [135, 206, 235], "slateblue": [106, 90, 205], "slategray": [112, 128, 144], "slategrey": [112, 128, 144], "snow": [255, 250, 250], "springgreen": [0, 255, 127], "steelblue": [70, 130, 180], "tan": [210, 180, 140], "teal": [0, 128, 128], "thistle": [216, 191, 216], "tomato": [255, 99, 71], "turquoise": [64, 224, 208], "violet": [238, 130, 238], "wheat": [245, 222, 179], "white": [255, 255, 255], "whitesmoke": [245, 245, 245], "yellow": [255, 255, 0], "yellowgreen": [154, 205, 50] }; /* Credit: http://matthaynes.net/blog/2008/08/07/javascript-colour-functions/ */ function rgbaToHsva(rgba) { var r = rgba[0]; var g = rgba[1]; var b = rgba[2]; var min = Math.min(Math.min(r, g), b), max = Math.max(Math.max(r, g), b), delta = max - min; var value = max; var saturation, hue; // Hue if (max == min) { hue = 0; } else if (max == r) { hue = (60 * ((g - b) / (max - min))) % 360; } else if (max == g) { hue = 60 * ((b - r) / (max - min)) + 120; } else if (max == b) { hue = 60 * ((r - g) / (max - min)) + 240; } if (hue < 0) { hue += 360; } // Saturation if (max == 0) { saturation = 0; } else { saturation = 1 - (min / max); } return [ Math.round(hue), Math.round(saturation * 100), Math.round(value * 100), rgba[3] ]; }; /* Credit: http://matthaynes.net/blog/2008/08/07/javascript-colour-functions/ */ function hsvaToRgba (hsva) { var h = normalize360(hsva[0]); var s = hsva[1]; var v = hsva[2]; var s = s / 100; var v = v / 100; var hi = Math.floor((h / 60) % 6); var f = (h / 60) - hi; var p = v * (1 - s); var q = v * (1 - f * s); var t = v * (1 - (1 - f) * s); var rgb = []; switch (hi) { case 0: rgb = [v, t, p]; break; case 1: rgb = [q, v, p]; break; case 2: rgb = [p, v, t]; break; case 3: rgb = [p, q, v]; break; case 4: rgb = [t, p, v]; break; case 5: rgb = [v, p, q]; break; } return [ rgb[0], rgb[1], rgb[2], hsva[3] ]; }; function rgbaToHsl(c) { var hsl = rgbToHsl(c[0], c[1], c[2]); hsl[0] = normalize360( Math.floor(hsl[0] * 360) ); hsl[1] = Math.floor(hsl[1] * 100); hsl[2] = Math.floor(hsl[2] * 100); return hsl; } function rgbaToHsla(c) { var hsl = rgbaToHsl(c); hsl.push(c[3]); return hsl; } function hslToRgba(c) { var h = parseFloat(c[0]) / 360; var s = parseFloat(c[1]) / 100; var l = parseFloat(c[2]) / 100; var rgb = hslToRgb(h, s, l); return [ rgb[0], rgb[1], rgb[2], 1 ]; } function hslaToRgba(c) { var h = parseFloat(c[0]) / 360; var s = parseFloat(c[1]) / 100; var l = parseFloat(c[2]) / 100; var rgb = hslToRgb(h, s, l); return [ rgb[0], rgb[1], rgb[2], parseFloat(c[3]) ]; } //-----------------------------------------------------------------------// // String parsers //-----------------------------------------------------------------------// var parse = { byteOrPercent : function (s) { var m; if (typeof s == 'string' && (m = s.match(/^([0-9]+)%$/))) return Math.floor( parseFloat(m[1]) * 255 / 100 ); else return parseFloat(s); }, floatOrPercent : function (s) { var m; if (typeof s == 'string' && (m = s.match(/^([0-9]+)%$/))) return parseFloat(m[1]) / 100; else return parseFloat(s); }, numberOrPercent : function (s, scale) { var m; if (typeof s == 'string' && (m = s.match(/^([0-9]+)%$/))) return (parseFloat(m[1]) / 100) * scale; else return parseFloat(s); }, rgba : function(v) { for (var i = 0; i < 3; ++i) v[i] = b2f( parse.byteOrPercent(v[i]) ); v[3] = parse.floatOrPercent(v[i]); return new Color(v); }, rgba8 : function(v) { return new Color([ b2f( parse.byteOrPercent(v[0]) ), b2f( parse.byteOrPercent(v[1]) ), b2f( parse.byteOrPercent(v[2]) ), b2f( parse.byteOrPercent(v[3]) ) ]); }, float3 : function (v) { for (var i = 0; i < 3; ++i) v[i] = parse.floatOrPercent(v[i]); v[3] = 1.0; return new Color(v); }, float4 : function (v) { for (var i = 0; i < 3; ++i) v[i] = parse.floatOrPercent(v[i]); v[3] = parse.floatOrPercent(v[i]); return new Color(v); }, hsla : function(v) { v[0] = parse.numberOrPercent(v[0], 360); v[1] = parse.numberOrPercent(v[1], 100); v[2] = parse.numberOrPercent(v[2], 100); v[3] = parse.numberOrPercent(v[3], 1); return new Color( hslaToRgba(v) ); }, hsva : function(v) { // 0-360, 0-100, 0-100, 0-1 v[0] = normalize360( parseFloat(v[0]) ); v[1] = Math.max( 0, Math.min( 100, parseFloat(v[1]) )); v[2] = Math.max( 0, Math.min( 100, parseFloat(v[2]) )); v[3] = parse.floatOrPercent(v[3]); return new Color( hsvaToRgba(v) ); } } //-----------------------------------------------------------------------// // Format helpers //-----------------------------------------------------------------------// var supportedFormats = { 'keyword' : {}, 'hex3' : {}, 'hex7' : {}, 'rgb' : { parse : function(v) { v = v.slice(0); v.push(1); return parse.rgba(v); } }, 'rgba' : { parse : parse.rgba }, 'hsl' : { parse : function(v) { v = v.slice(0); v.push(1); return parse.hsla(v); } }, 'hsla' : { parse : parse.hsla }, 'hsv' : { parse : function(v) { v = v.slice(0); v.push(1); return parse.hsva(v); } }, 'hsva' : { parse : parse.hsva }, 'rgb8' : { parse : function(v) { v = v.slice(0); v.push(1); return parse.rgba(v); } }, 'rgba8' : { parse : function(v) { return parse.rgba8(v); } }, 'packed_rgba' : { parse : function (v) { v = [ (v >> 24) & 255, (v >> 16) & 255, (v >> 8) & 255, (v & 255) / 255]; return parse.rgba(v); }, output : function(v) { return unsigned((f2b(v[0]) << 24) | (f2b(v[1]) << 16) | (f2b(v[2]) << 8) | f2b(v[3])); } }, 'packed_argb' : { parse : function (v) { v = [ (v >> 16) & 255, (v >> 8) & 255, (v >> 0) & 255, ((v >> 24) & 255) / 255]; return parse.rgba(v); }, output : function(v) { return unsigned((f2b(v[3]) << 24) | (f2b(v[0]) << 16) | (f2b(v[1]) << 8) | f2b(v[2])); } }, 'float3' : { parse : parse.float3 }, 'float4' : { parse : parse.float4 } }; //-----------------------------------------------------------------------// // Color object //-----------------------------------------------------------------------// function Color(value) { this._value = value; } //-----------------------------------------------------------------------// // color function //-----------------------------------------------------------------------// var color = function() { var match = null; if (arguments[0] instanceof Color) { return new Color( arguments[0]._value ); } else if (typeof arguments[0] == 'string') { var first = arguments[0][0]; // Hex3 E.g. #08C if (first == '#') { if (match = arguments[0].match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/i)) { return new Color( hex4ToRgba(match[0]) ); } // Hex6 e.g. #0088CC else if (match = arguments[0].match(/^#([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])([0-9A-Fa-f])$/i)) { return new Color( hex7ToRgba(match[0]) ); } } // Format string with additional args, e.g. 'rgb' else if (match = supportedFormats[arguments[0].toLowerCase()]) { if (arguments.length == 2) return match.parse(arguments[1]); else return match.parse(slice(arguments, 1)); } // Format + 1 param string, e.g. "packed_rgba(0x00FF00FF)" else if (match = arguments[0].match(/^\s*([A-Z][A-Z0-9_]+)\s*\(\s*([\-0-9A-FX]+)\s*\)\s*$/i)) { var format = supportedFormats[match[1].toLowerCase()]; return format.parse(match[2]); } // Format + 3/4 params string, e.g. "rgba(255, 255, 0, .4)" else if (match = arguments[0].match(/^\s*([A-Z][A-Z0-9]+)\s*\(\s*([0-9\.]+%?)\s*,\s*([0-9\.]+%?)\s*,\s*([0-9\.]+%?)\s*(,\s*([0-9\.]+%?)\s*)?\)\s*$/i)) { var format = supportedFormats[match[1].toLowerCase()]; if (match[5] === undefined) { var v = [ match[2], match[3], match[4] ]; return format.parse(v); } else { var v = [ match[2], match[3], match[4], match[6] ]; return format.parse(v); } } // Named color, e.g. "goldenrod" else if (arguments.length == 1 && (match = namedColors[trimLc(arguments[0])])) { var v = match; return new Color([ b2f(v[0]), b2f(v[1]), b2f(v[2]), 1 ]); } } throw "Could not parse color '" + arguments[0] + "'"; }; // // Method helpers // var fixed = { white : color('white'), black : color('black'), gray : color('gray') } function modifyComponent(index, arg) { if (arg == undefined) return f2b(this._value[index]); // First clone the internal data var v = slice(this._value, 0); if (typeof arg == 'string') { var m; if (m = arg.match(/^([+\-\\*]=?)([0-9.]+)/)) { var op = m[1]; var offset = parseFloat(m[2]); switch (op[0]) { case '+': v[index] += offset / 255; break; case '-': v[index] -= offset / 255; break; case '*': v[index] *= offset; break; } if (op[1] == '=') { this._value = v; return this; } else return new Color(v); } } else { var clone = this.clone(); clone._value[index] = arg; return clone; } } function modifyHsva(i) { return function () { function change(obj, op, value) { value = parseFloat(value); var hsva = rgbaToHsva(obj._value); var c = 0; switch (op) { case '=' : hsva[i] = value; c = 1; break; case '+' : hsva[i] += value; c = 1; break; case '+=' : hsva[i] += value; break; case '-' : hsva[i] -= value; c = 1; break; case '-=' : hsva[i] -= value; break; case '*' : hsva[i] *= value; c = 1; break; case '*=' : hsva[i] *= value; break; default: throw "Bad op " + op; } if (i == 0) hsva[i] = normalize360(hsva[i]); else if (i == 1 || i == 2) { if (hsva[i] < 0) hsva[i] = 0; else if (hsva[i] > 99) hsva[i] = 99; } if (c) obj = obj.clone(); obj._value = hsvaToRgba(hsva); return obj; } if (arguments.length == 0) return rgbaToHsva(this._value)[i]; else if (arguments.length == 1) { var m; if (typeof arguments[0] == 'string' && (m = arguments[0].match(/^([\+\-\*]=?)([0-9.]+)/))) return change(this, m[1], m[2]); else return change(this, '=', arguments[0]); } else if (arguments.length == 2) return change(this, arguments[0], arguments[1]); }; } // // Object methods // var methods = { 'clone' : function() { return new Color( this._value.slice(0) ); }, /* By design, the 'html' method returns only valid CSS3 type (e.g. 'hsv' is not a valid format for this method. */ 'html' : function() { var self = this; var v = this._value; var _fmt = { 'hex3' : function() { return self.hex3(); }, 'hex6' : function() { return self.hex6(); }, 'rgb' : function() { return "rgb(" + self.rgb().join(',') + ")"; }, 'rgba' : function() { return "rgba(" + self.rgba().join(',') + ")"; }, 'hsl' : function() { return 'hsl(' + rgbaToHsl(v).join(',') + ')'; }, 'hsla' : function() { return 'hsla(' + rgbaToHsla(v).join(',') + ')'; }, 'keyword' : function() { // Do a linear search by closest in RGB space. Not very efficient. var dist = 3 * (255 * 255) + 1; var keyword; for (name in namedColors) { var c = namedColors[name]; var d = 0; for (var i = 0; i < 3; ++i) { var t = v[i] - b2f(c[i]); d += t * t; } if (d < dist) { keyword = name; dist = d; } } return keyword; } }; var type = arguments[0] || 'rgba'; return _fmt[type](); }, 'red' : function() { return modifyComponent.call(this, 0, arguments[0]); }, 'green' : function() { return modifyComponent.call(this, 1, arguments[0]); }, 'blue' : function() { return modifyComponent.call(this, 2, arguments[0]); }, 'alpha' : function() { if (arguments.length == 1) { c = this.clone(); c._value[3] = parse.floatOrPercent(arguments[0]); return c; } else return this._value[3]; }, 'alpha8' : function() { if (arguments.length == 1) { c = this.clone(); c._value[3] = parse.byteOrPercent(arguments[0]) / 255.0; return c; } else return Math.floor(this._value[3] * 255); }, 'grayvalue' : function() { var c = this._value; return (c[0] + c[1] + c[2]) / 3; }, 'grayvalue8' : function() { return f2b( this.grayvalue() ); }, 'luminance' : function() { var c = this._value; return c[0] * 0.2126 + c[1] * 0.7152 + c[2] * 0.0722; }, 'luminance8' : function() { return f2b( this.luminance() ); }, 'hsv' : function() { return rgbaToHsva(this._value).slice(0,3); }, 'hsva' : function() { return rgbaToHsva(this._value); }, 'packed_rgba' : function() { return supportedFormats.packed_rgba.output(this._value); }, 'packed_argb' : function() { return supportedFormats.packed_argb.output(this._value); }, 'hue' : modifyHsva(0), 'saturation' : modifyHsva(1), 'value' : modifyHsva(2), 'clamp' : function() { var v = this._value; return new Color([ clamp(v[0], 0, 1), clamp(v[1], 0, 1), clamp(v[2], 0, 1), clamp(v[3], 0, 1) ]); }, 'blend' : function(colorToBlend, amount) { if (typeof amount !== 'number') amount = parse.floatOrPercent(amount); var c = this; var c2 = color(colorToBlend); return new Color([ mix(c._value[0], c2._value[0], amount), mix(c._value[1], c2._value[1], amount), mix(c._value[2], c2._value[2], amount), mix(c._value[3], c2._value[3], amount) ]); }, 'add' : function (d) { var u = this._value; var v = color(d)._value; return new Color([ u[0] + v[0] * v[3], u[1] + v[1] * v[3], u[2] + v[2] * v[3], u[3] ]); }, 'inc' : function (d) { var u = this._value; var v = color(d)._value; u[0] += v[0] * v[3]; u[1] += v[1] * v[3]; u[2] += v[2] * v[3]; return this; }, 'dec' : function (d) { var u = this._value; var v = color(d)._value; u[0] -= v[0] * v[3]; u[1] -= v[1] * v[3]; u[2] -= v[2] * v[3]; return this; }, 'subtract' : function (d) { var u = this._value; var v = color(d)._value; return new Color([ u[0] - v[0] * v[3], u[1] - v[1] * v[3], u[2] - v[2] * v[3], u[3] ]); }, 'multiply' : function (d) { var u = this._value; var v = color(d)._value; return new Color([ u[0] * v[0], u[1] * v[1], u[2] * v[2], u[3] * v[3] ]); }, 'scale' : function (d) { var u = this._value; return new Color([ u[0] * d, u[1] * d, u[2] * d, u[3] ]); }, 'xor' : function (d) { var u = this.rgba8(); var v = color(d).rgba8(); return color('rgba8', u[0] ^ v[0], u[1] ^ v[1], u[2] ^ v[2], u[3]); }, 'tint' : function(amount) { return this.blend( fixed.white, amount ); }, 'shade' : function(amount) { return this.blend( fixed.black, amount ); }, 'tone' : function(amount) { return this.blend( fixed.gray, amount ); }, 'complement' : function() { var hsva = this.hsva(); hsva[0] = normalize360(hsva[0] + 180); return new Color( hsvaToRgba(hsva) ); }, 'triad' : function() { return [ new Color(this._value), this.hue('+120'), this.hue('+240') ]; }, 'hueSet' : function() { var h = 0; var set = []; for (var s = 100; s >= 30; s -= 35) for (var v = 100; v >= 30; v -= 35) set.push( this.hue('+', h).saturation(s).value(v) ); return set; }, 'hueRange' : function(range, count) { var base = this.hue(); var set = []; for (var i = 0; i < count; ++i) { var h = base + (2 * (i/(count-1) - .5) * range); set.push( this.hue('=', h) ); } return set; }, 'contrastWhiteBlack' : function() { return (this.value() < 50) ? color('white') : color('black'); }, 'contrastGray' : function() { var hsva = this.hsva(); var value = (hsva[2] < 30) ? (hsva[2] + 20) : (hsva[2] - 20); return new Color( hsvaToRgba([ hsva[0], 0, value, hsva[3] ]) ); }, 'hex3' : function() { function hex(d, max) { return Math.min(Math.round(f2b(d) / 16), 15).toString(16); } return "#" + hex(this._value[0]) + hex(this._value[1]) + hex(this._value[2]); }, 'hex6' : function() { function hex(d, max) { var h = f2b(d).toString(16); return (h.length < 2) ? "0" + h : h; } return "#" + hex(this._value[0]) + hex(this._value[1]) + hex(this._value[2]); }, 'rgb' : function() { var v = this._value; return [ f2b(v[0]), f2b(v[1]), f2b(v[2]) ]; }, 'rgba' : function() { var v = this._value; return [ f2b(v[0]), f2b(v[1]), f2b(v[2]), v[3] ]; }, 'rgb8' : function() { var v = this._value; return [ f2b(v[0]), f2b(v[1]), f2b(v[2]) ]; }, 'rgba8' : function() { var v = this._value; return [ f2b(v[0]), f2b(v[1]), f2b(v[2]), this.alpha8() ]; }, 'float3' : function() { return [ this._value[0], this._value[1], this._value[2] ]; }, 'float4' : function() { return [ this._value[0], this._value[1], this._value[2], this._value[3] ]; } }; // Aliases methods['sub'] = methods['subtract']; methods['mul'] = methods['multiply']; for (var name in methods) Color.prototype[name] = methods[name]; /* Lower-level, less flexible, but faster routines */ color.float3 = function(r,g,b) { return new Color([ r, g, b, 1.0 ]); }; color.float4 = function(r,g,b,a) { return new Color([ r, g, b, a ]); }; // // Export // color.version = "0.2.4"; color.Color = Color; // Determine if this is the node.js or the browser if (typeof module !== "undefined" && module.exports ) { module.exports = color; } else if (typeof window !== "undefined") { window.pusher = window.pusher || {}; window.pusher.color = color; } })(); },{}],7:[function(require,module,exports){ ;(function inject(clean, precision, undef) { var isArray = function (a) { return Object.prototype.toString.call(a) === "[object Array]"; }; function Vec2(x, y) { if (!(this instanceof Vec2)) { return new Vec2(x, y); } if (isArray(x)) { y = x[1]; x = x[0]; } else if('object' === typeof x && x) { y = x.y; x = x.x; } this.x = Vec2.clean(x || 0); this.y = Vec2.clean(y || 0); } Vec2.prototype = { change : function(fn) { if (fn) { if (this.observers) { this.observers.push(fn); } else { this.observers = [fn]; } } else if (this.observers) { for (var i=this.observers.length-1; i>=0; i--) { this.observers[i](this); } } return this; }, ignore : function(fn) { if (this.observers) { var o = this.observers, l = o.length; while(l--) { o[l] === fn && o.splice(l, 1); } } return this; }, // set x and y set: function(x, y, silent) { if('number' != typeof x) { silent = y; y = x.y; x = x.x; } if(this.x === x && this.y === y) { return this; } this.x = Vec2.clean(x); this.y = Vec2.clean(y); if(silent !== false) { return this.change(); } }, // reset x and y to zero zero : function() { return this.set(0, 0); }, // return a new vector with the same component values // as this one clone : function() { return new (this.constructor)(this.x, this.y); }, // negate the values of this vector negate : function(returnNew) { if (returnNew) { return new (this.constructor)(-this.x, -this.y); } else { return this.set(-this.x, -this.y); } }, // Add the incoming `vec2` vector to this vector add : function(vec2, returnNew) { if (!returnNew) { this.x += vec2.x; this.y += vec2.y; return this.change(); } else { // Return a new vector if `returnNew` is truthy return new (this.constructor)( this.x + vec2.x, this.y + vec2.y ); } }, // Subtract the incoming `vec2` from this vector subtract : function(vec2, returnNew) { if (!returnNew) { this.x -= vec2.x; this.y -= vec2.y; return this.change(); } else { // Return a new vector if `returnNew` is truthy return new (this.constructor)( this.x - vec2.x, this.y - vec2.y ); } }, // Multiply this vector by the incoming `vec2` multiply : function(vec2, returnNew) { var x,y; if ('number' !== typeof vec2) { //.x !== undef) { x = vec2.x; y = vec2.y; // Handle incoming scalars } else { x = y = vec2; } if (!returnNew) { return this.set(this.x * x, this.y * y); } else { return new (this.constructor)( this.x * x, this.y * y ); } }, // Rotate this vector. Accepts a `Rotation` or angle in radians. // // Passing a truthy `inverse` will cause the rotation to // be reversed. // // If `returnNew` is truthy, a new // `Vec2` will be created with the values resulting from // the rotation. Otherwise the rotation will be applied // to this vector directly, and this vector will be returned. rotate : function(r, inverse, returnNew) { var x = this.x, y = this.y, cos = Math.cos(r), sin = Math.sin(r), rx, ry; inverse = (inverse) ? -1 : 1; rx = cos * x - (inverse * sin) * y; ry = (inverse * sin) * x + cos * y; if (returnNew) { return new (this.constructor)(rx, ry); } else { return this.set(rx, ry); } }, // Calculate the length of this vector length : function() { var x = this.x, y = this.y; return Math.sqrt(x * x + y * y); }, // Get the length squared. For performance, use this instead of `Vec2#length` (if possible). lengthSquared : function() { var x = this.x, y = this.y; return x*x+y*y; }, // Return the distance betwen this `Vec2` and the incoming vec2 vector // and return a scalar distance : function(vec2) { var x = this.x - vec2.x; var y = this.y - vec2.y; return Math.sqrt(x*x + y*y); }, // Convert this vector into a unit vector. // Returns the length. normalize : function(returnNew) { var length = this.length(); // Collect a ratio to shrink the x and y coords var invertedLength = (length < Number.MIN_VALUE) ? 0 : 1/length; if (!returnNew) { // Convert the coords to be greater than zero // but smaller than or equal to 1.0 return this.set(this.x * invertedLength, this.y * invertedLength); } else { return new (this.constructor)(this.x * invertedLength, this.y * invertedLength); } }, // Determine if another `Vec2`'s components match this one's // also accepts 2 scalars equal : function(v, w) { if (w === undef) { w = v.y; v = v.x; } return (Vec2.clean(v) === this.x && Vec2.clean(w) === this.y); }, // Return a new `Vec2` that contains the absolute value of // each of this vector's parts abs : function(returnNew) { var x = Math.abs(this.x), y = Math.abs(this.y); if (returnNew) { return new (this.constructor)(x, y); } else { return this.set(x, y); } }, // Return a new `Vec2` consisting of the smallest values // from this vector and the incoming // // When returnNew is truthy, a new `Vec2` will be returned // otherwise the minimum values in either this or `v` will // be applied to this vector. min : function(v, returnNew) { var tx = this.x, ty = this.y, vx = v.x, vy = v.y, x = tx < vx ? tx : vx, y = ty < vy ? ty : vy; if (returnNew) { return new (this.constructor)(x, y); } else { return this.set(x, y); } }, // Return a new `Vec2` consisting of the largest values // from this vector and the incoming // // When returnNew is truthy, a new `Vec2` will be returned // otherwise the minimum values in either this or `v` will // be applied to this vector. max : function(v, returnNew) { var tx = this.x, ty = this.y, vx = v.x, vy = v.y, x = tx > vx ? tx : vx, y = ty > vy ? ty : vy; if (returnNew) { return new (this.constructor)(x, y); } else { return this.set(x, y); } }, // Clamp values into a range. // If this vector's values are lower than the `low`'s // values, then raise them. If they are higher than // `high`'s then lower them. // // Passing returnNew as true will cause a new Vec2 to be // returned. Otherwise, this vector's values will be clamped clamp : function(low, high, returnNew) { var ret = this.min(high, true).max(low); if (returnNew) { return ret; } else { return this.set(ret.x, ret.y); } }, // Perform linear interpolation between two vectors // amount is a decimal between 0 and 1 lerp : function(vec, amount) { return this.add(vec.subtract(this, true).multiply(amount), true); }, // Get the skew vector such that dot(skew_vec, other) == cross(vec, other) skew : function() { // Returns a new vector. return new (this.constructor)(-this.y, this.x); }, // calculate the dot product between // this vector and the incoming dot : function(b) { return Vec2.clean(this.x * b.x + b.y * this.y); }, // calculate the perpendicular dot product between // this vector and the incoming perpDot : function(b) { return Vec2.clean(this.x * b.y - this.y * b.x); }, // Determine the angle between two vec2s angleTo : function(vec) { return Math.atan2(this.perpDot(vec), this.dot(vec)); }, // Divide this vector's components by a scalar divide : function(vec2, returnNew) { var x,y; if ('number' !== typeof vec2) { x = vec2.x; y = vec2.y; // Handle incoming scalars } else { x = y = vec2; } if (x === 0 || y === 0) { throw new Error('division by zero') } if (isNaN(x) || isNaN(y)) { throw new Error('NaN detected'); } if (returnNew) { return new (this.constructor)(this.x / x, this.y / y); } return this.set(this.x / x, this.y / y); }, isPointOnLine : function(start, end) { return (start.y - this.y) * (start.x - end.x) === (start.y - end.y) * (start.x - this.x); }, toArray: function() { return [this.x, this.y]; }, fromArray: function(array) { return this.set(array[0], array[1]); }, toJSON: function () { return {x: this.x, y: this.y}; }, toString: function() { return '(' + this.x + ', ' + this.y + ')'; }, constructor : Vec2 }; Vec2.fromArray = function(array, ctor) { return new (ctor || Vec2)(array[0], array[1]); }; // Floating point stability Vec2.precision = precision || 8; var p = Math.pow(10, Vec2.precision); Vec2.clean = clean || function(val) { if (isNaN(val)) { throw new Error('NaN detected'); } if (!isFinite(val)) { throw new Error('Infinity detected'); } if(Math.round(val) === val) { return val; } return Math.round(val * p)/p; }; Vec2.inject = inject; if(!clean) { Vec2.fast = inject(function (k) { return k; }); // Expose, but also allow creating a fresh Vec2 subclass. if (typeof module !== 'undefined' && typeof module.exports == 'object') { module.exports = Vec2; } else { window.Vec2 = window.Vec2 || Vec2; } } return Vec2; })(); },{}],8:[function(require,module,exports){ var Vec2 = require('vec2'), Quadtree2Helper = require('./quadtree2helper'), Quadtree2Validator = require('./quadtree2validator'), Quadtree2Quadrant = require('./quadtree2quadrant'), Quadtree2; Quadtree2 = function Quadtree2(size, quadrantObjectsLimit, quadrantLevelLimit) { var id, // Container for private data. data = { objects_ : {}, quadrants_ : {}, ids_ : 1, quadrantIds_ : 1, autoId_ : true, inited_ : false, debug_ : false, size_ : undefined, root_ : undefined, quadrantObjectsLimit_ : undefined, quadrantLevelLimit_ : undefined, quadrantSizeLimit_ : undefined }, validator = new Quadtree2Validator(), // Inserted object keys. k = { p : 'pos_', r : 'rad_', id : 'id_' }, // Property definitions. constraints = { data : { necessary : { size_ : validator.isVec2, quadrantObjectsLimit_ : validator.isNumber, quadrantLevelLimit_ : validator.isNumber } }, k : { necessary : { p : validator.isVec2 }, c : { necessary : { r : validator.isNumber }, } } }, // Private function definitions. fns = { nextId : function nextId() { return data.ids_++; }, nextQuadrantId : function nextQuadrantId(sum) { var id = data.quadrantIds_; data.quadrantIds_ += sum || 4; return id; }, hasCollision : function hasCollision(objA, objB) { return objA[k.r] + objB[k.r] > objA[k.p].distance(objB[k.p]); }, removeQuadrantParentQuadrants : function removeQuadrantParentQuadrants(quadrant, quadrants) { if (!quadrant.parent_) { return; } if (quadrants[quadrant.parent_.id_]) { delete quadrants[quadrant.parent_.id_]; fns.removeQuadrantParentQuadrants(quadrant.parent_, quadrants); } }, getSubtreeTopQuadrant : function getSubtreeTopQuadrant(quadrant, quadrants) { if (!quadrant.parent_ || !quadrants[quadrant.parent_.id_]) { return quadrant; } return getSubtreeTopQuadrant(quadrant.parent_, quadrants); }, removeQuadrantChildtree : function removeQuadrantChildtree(quadrant, quadrants) { var i, children = quadrant.getChildren(); for (i = 0; i < children.length; i++) { if (!quadrants[children[i].id_]) { return; } delete quadrants[children[i].id_]; fns.removeQuadrantChildtree(children[i], quadrants); } }, getIntersectingQuadrants: function getIntersectingQuadrants(obj, quadrant, result) { var i, children; if (!quadrant.intersects(obj[k.p], obj[k.r])) { fns.removeQuadrantParentQuadrants(quadrant, result.biggest); return; } result.biggest[quadrant.id_] = quadrant; children = quadrant.getChildren(); if (children.length) { for (i = 0; i < children.length; i++) { getIntersectingQuadrants(obj, children[i], result); } } else { result.leaves[quadrant.id_] = quadrant; } }, getSmallestIntersectingQuadrants : function getSmallestIntersectingQuadrants(obj, quadrant, result) { var id, top; if (!quadrant) { quadrant = data.root_; } if (!result) { result = { leaves : {}, biggest : {} }; } fns.getIntersectingQuadrants(obj, quadrant, result); for (id in result.leaves) { if (!result.biggest[id]) { continue; } top = fns.getSubtreeTopQuadrant(result.leaves[id], result.biggest); fns.removeQuadrantChildtree(top, result.biggest); } return result.biggest; }, removeQuadrantObjects : function removeQuadrantObjects(quadrant) { var i, removed = quadrant.removeObjects([], 1); for (i = 0; i < removed.length; i++) { delete data.quadrants_[removed[i].obj[k.id]][removed[i].quadrant.id_]; } return removed; }, removeObjectFromQuadrants : function removeObjectFromQuadrants(obj, quadrants) { var id; if (quadrants === undefined) { quadrants = data.quadrants_[obj[k.id]]; } for (id in quadrants) { fns.removeObjectFromQuadrant(obj, quadrants[id]); } }, removeObjectFromQuadrant : function removeObjectFromQuadrant(obj, quadrant) { quadrant.removeObject(obj[k.id]); delete data.quadrants_[obj[k.id]][quadrant.id_]; if (quadrant.hasChildren() || !quadrant.parent_) { return; } fns.refactorSubtree(quadrant.parent_); }, refactorSubtree : function refactorSubtree(quadrant) { var i, id, count, child, obj; if (quadrant.refactoring_) { return; } // Lets check for grandchildren. for (i = 0; i < quadrant.children_.length; i++) { child = quadrant.children_[i]; if (child.hasChildren()) { return; } } count = quadrant.getObjectCountForLimit(); if (count > data.quadrantObjectsLimit_) { return; } quadrant.refactoring_ = true; for (i = 0; i < quadrant.children_.length; i++) { child = quadrant.children_[i]; for (id in child.objects_) { obj = child.objects_[id]; fns.removeObjectFromQuadrant(obj, child); fns.addObjectToQuadrant(obj, quadrant); } } quadrant.looseChildren(); quadrant.refactoring_ = false; if (!quadrant.parent_) { return; } fns.refactorSubtree(quadrant.parent_); }, updateObjectQuadrants : function updateObjectQuadrants(obj) { var oldQuadrants = data.quadrants_[obj[k.id]], newQuadrants = fns.getSmallestIntersectingQuadrants(obj), oldIds = Quadtree2Helper.getIdsOfObjects(oldQuadrants), newIds = Quadtree2Helper.getIdsOfObjects(newQuadrants), diffIds = Quadtree2Helper.arrayDiffs(oldIds, newIds), removeIds = diffIds[0], addIds = diffIds[1], i; for (i = 0; i < addIds.length; i++) { fns.populateSubtree(obj, newQuadrants[addIds[i]]); } for (i = 0; i < removeIds.length; i++) { if (!oldQuadrants[removeIds[i]]) { continue; } fns.removeObjectFromQuadrant(obj, oldQuadrants[removeIds[i]]); } }, addObjectToQuadrant : function addObjectToQuadrant(obj, quadrant) { var id = obj[k.id]; if (data.quadrants_[id] === undefined) data.quadrants_[id] = {}; data.quadrants_[id][quadrant.id_] = quadrant; quadrant.addObject(id, obj); }, populateSubtree : function populateSubtree(obj, quadrant) { var i, id, addBySubtree, smallestQs, intersectingChildren, removed; if (!quadrant) { quadrant = data.root_; } if (quadrant.hasChildren()) { // Get smallest quadrants which intersect. smallestQs = fns.getSmallestIntersectingQuadrants(obj, quadrant); for (id in smallestQs) { if (smallestQs[id] === quadrant) { // If its myself because all my children would intersect with // it, then no point storing the obj in children => addObject. fns.addObjectToQuadrant(obj, quadrant); return; } // Propagate further to children fns.populateSubtree(obj, smallestQs[id]); } } else if (quadrant.getObjectCount() < data.quadrantObjectsLimit_ || quadrant.size_.x < data.quadrantSizeLimit_.x ) { // Has no children but still got place, so store it. fns.addObjectToQuadrant(obj, quadrant); } else { // Got no place so lets make children. quadrant.makeChildren(fns.nextQuadrantId()); // Remove all the stored objects until the parent. removed = fns.removeQuadrantObjects(quadrant); removed.push({ obj : obj, quadrant : quadrant }); // Recalculate all objects which were stored before. for (i = 0; i < removed.length; i++) { fns.populateSubtree(removed[i].obj, removed[i].quadrant); } } }, init : function init() { var divider; if (!data.quadrantLevelLimit_) data.quadrantLevelLimit_ = 6; validator.byCallbackObject(data, constraints.data.necessary); data.root_ = new Quadtree2Quadrant(new Vec2(0,0), data.size_.clone(), fns.nextQuadrantId(1)); divider = Math.pow(2, data.quadrantLevelLimit_); data.quadrantSizeLimit_ = data.size_.clone().divide(divider); data.inited_ = true; }, checkInit : function checkInit(init) { if (init && !data.inited_) { fns.init(); } return data.inited_; }, checkObjectKeys : function checkObjectKeys(obj) { validator.isNumber(obj[k.id], k.id); validator.isNumber(obj[k.r], k.r); validator.hasNoKey(data.objects_, obj[k.id], k.id); validator.byCallbackObject(obj, constraints.k.necessary, k); }, setObjId : function setObjId(obj) { if (data.autoId_ && !obj[k.id]) { obj[k.id] = fns.nextId(); } }, removeObjectById : function removeObjectById(id) { validator.hasKey(data.objects_, id, k.id); fns.removeObjectFromQuadrants(data.objects_[id]); delete data.objects_[id]; }, updateObjectById : function updateObjectById(id) { validator.hasKey(data.objects_, id, k.id); fns.updateObjectQuadrants(data.objects_[id]); }, getObjectsByObject : function getObjectsByObject(obj) { var i, id, quadrants = data.quadrants_[obj[k.id]], result = { objects : {}, quadrants : {} }; for (id in quadrants) { quadrants[id].getObjectsUp(result); for (i = 0; i < quadrants[id].children_.length; i++) { quadrants[id].children_[i].getObjectsDown(result); } } delete result.objects[obj[k.id]]; return result.objects; } }, // Debug functions debugFns = { getQuadrants: function getQuadrants() { return data.root_.getChildren(true, [data.root_]); }, getLeafQuadrants : function getLeafQuadrants() { return debugFns.getQuadrants().filter(function(q){ return !q.hasChildren(); }); } }, // Public function definitions publicFns = { getQuadrantObjectsLimit: function getQuadrantObjectsLimit() { return data.quadrantObjectsLimit_; }, setQuadrantObjectsLimit : function getQuadrantObjectsLimit(quadrantObjectsLimit) { if (quadrantObjectsLimit === undefined) { return; } validator.isNumber(quadrantObjectsLimit, 'quadrantObjectsLimit_'); data.quadrantObjectsLimit_ = quadrantObjectsLimit; }, getQuadrantLevelLimit : function getQuadrantLevelLimit() { return data.quadrantLevelLimit_; }, setQuadrantLevelLimit: function setQuadrantLevelLimit(quadrantLevelLimit) { if (quadrantLevelLimit === undefined) { return; } validator.isNumber(quadrantLevelLimit, 'quadrantLevelLimit_'); data.quadrantLevelLimit_ = quadrantLevelLimit; }, setObjectKey : function setObjectKey(key, val) { validator.fnFalse(fns.checkInit); if (val === undefined) { return; } validator.hasKey(k, key, key); validator.isString(val, key); if (key === 'id') { data.autoId_ = false; } k[key] = val; }, getSize : function getSize() { return data.size_.clone(); }, setSize : function setSize(size) { if (size === undefined) { return; } validator.isVec2(size, 'size_'); data.size_ = size.clone(); }, addObjects : function addObject(objs) { objs.forEach(function(obj) { publicFns.addObject(obj); }); }, addObject : function addObject(obj) { validator.isDefined(obj, 'obj'); validator.isObject(obj, 'obj'); fns.checkInit(true); fns.setObjId(obj); fns.checkObjectKeys(obj); fns.populateSubtree(obj); data.objects_[obj[k.id]] = obj; }, removeObjects : function removeObjects(objs) { var i; for (i = 0; i < objs.length; i++) { publicFns.removeObject(objs[i]); } }, removeObject : function removeObject(obj) { fns.checkInit(true); validator.hasKey(obj, k.id, k.id); fns.removeObjectById(obj[k.id]); }, updateObjects : function updateObjects(objs) { var i; for(i = 0; i < objs.length; i++) { publicFns.updateObject(objs[i]); } }, updateObject : function updateObject(obj) { fns.checkInit(true); validator.hasKey(obj, k.id, k.id); fns.updateObjectById(obj[k.id]); }, getPossibleCollisionsForObject : function getPossibleCollisionsForObject(obj) { fns.checkInit(true); validator.hasKey(obj, k.id, k.id); return fns.getObjectsByObject(obj); }, getCollisionsForObject : function getCollisionsForObject(obj) { var id, objects; fns.checkInit(true); validator.hasKey(obj, k.id, k.id); objects = fns.getObjectsByObject(obj); for (id in objects) { if (!fns.hasCollision(obj, objects[id])) { delete objects[id]; } } return objects; }, getCount : function getCount() { return Object.keys(data.objects_).length; }, // Copies and returns data.objects_; getObjects : function getObjects() { var id, result = {}; for (id in data.objects_) { result[id] = data.objects_[id]; } return result; }, getQuadrantCount : function getQuadrantCount(obj) { if (obj) { return Object.keys(data.quadrants_[obj[k.id]]).length; } return 1 + data.root_.getChildCount(true); }, getQuadrantObjectCount : function getQuadrantObjectCount() { return data.root_.getObjectCount(true); }, debug : function debug(val) { var id; if(val !== undefined){ data.debug_ = val; // For testing purpose allow exposing private functions. fns.checkInit(true); for (id in debugFns) { this[id] = debugFns[id]; } for (id in fns) { this[id] = fns[id]; } this.data_ = data; } return data.debug_; } }; // Generate public functions. for (id in publicFns) { this[id] = publicFns[id]; } this.setSize(size); this.setQuadrantObjectsLimit(quadrantObjectsLimit); this.setQuadrantLevelLimit(quadrantLevelLimit); }; module.exports = Quadtree2; },{"./quadtree2helper":9,"./quadtree2quadrant":10,"./quadtree2validator":11,"vec2":7}],9:[function(require,module,exports){ var Quadtree2Helper = { fnName : function fnName(fn) { var ret = fn.toString(); ret = ret.substr('function '.length); ret = ret.substr(0, ret.indexOf('(')); return ret; }, // A verbose exception generator helper. thrower : function thrower(code, message, key) { var error = code; if(key) { error += '_' + key; } if(message) { error += ' - '; } if(message && key) { error += key + ': '; } if(message) { error += message; } throw new Error(error); }, getIdsOfObjects : function getIdsOfObjects(hash) { var result = []; for (var id in hash) { result.push(hash[id].id_); } return result; }, compare : function compare(a,b) { return a - b; }, arrayDiffs : function arrayDiffs(arrA, arrB) { var i = 0, j = 0, retA = [], retB = []; arrA.sort(this.compare); arrB.sort(this.compare); while (i < arrA.length && j < arrB.length) { if (arrA[i] === arrB[j]) { i++; j++; continue; } if (arrA[i] < arrB[j]) { retA.push(arrA[i]); i++; continue; } else { retB.push(arrB[j]); j++; } } if(i < arrA.length) { retA.push.apply(retA, arrA.slice(i, arrA.length)); } else { retB.push.apply(retB, arrB.slice(j, arrB.length)); } return [retA, retB]; } }; module.exports = Quadtree2Helper; },{}],10:[function(require,module,exports){ var Quadtree2Quadrant = function Quadtree2Quadrant(leftTop, size, id, parent) { this.leftTop_ = leftTop.clone(); this.children_ = []; this.objects_ = {}; this.objectCount_ = 0; this.id_ = id || 0; this.parent_ = parent; this.refactoring_ = false; this.setSize(size); }; Quadtree2Quadrant.prototype = { setSize : function setSize(size) { if(!size) { return; } this.size_ = size; this.rad_ = size.multiply(0.5, true); this.center_ = this.leftTop_.add(this.rad_, true); this.leftBot_ = this.leftTop_.clone(); this.leftBot_.y += size.y; this.rightTop_ = this.leftTop_.clone(); this.rightTop_.x += size.x; this.rightBot_ = this.leftTop_.add(size, true); this.leftMid_ = this.center_.clone(); this.leftMid_.x = this.leftTop_.x; this.topMid_ = this.center_.clone(); this.topMid_.y = this.leftTop_.y; }, makeChildren : function makeChildren(id) { if (this.children_.length > 0) { return false; } this.children_.push( new Quadtree2Quadrant(this.leftTop_, this.rad_, id++, this), new Quadtree2Quadrant(this.topMid_, this.rad_, id++, this), new Quadtree2Quadrant(this.leftMid_, this.rad_, id++, this), new Quadtree2Quadrant(this.center_, this.rad_, id++, this) ); return id; }, looseChildren : function looseChildren() { this.children_ = []; }, addObjects : function addObjects(objs) { var id; for (id in objs) { this.addObject(id, objs[id]); } }, addObject : function addObject(id, obj) { this.objectCount_++; this.objects_[id] = obj; }, removeObjects : function removeObjects(removed, dir) { var id; if (!removed) { removed = []; } for (id in this.objects_) { removed.push({ obj : this.objects_[id], quadrant : this }); delete this.objects_[id]; } this.objectCount_ = 0; if (!dir || dir === 1) { if (this.parent_) { this.parent_.removeObjects(removed, 1); } } if (!dir || dir === -1) { this.children_.forEach(function(child) { child.removeObjects(removed, -1); }); } return removed; }, removeObject : function removeObject(id) { var result = this.objects_[id]; this.objectCount_--; delete(this.objects_[id]); return result; }, getObjectCountForLimit : function getObjectCountForLimit() { var i, id, objects = {}; for (id in this.objects_) { objects[id] = true; } for (i = 0; i < this.children_.length; i++) { for (id in this.children_[i].objects_) { objects[id] = true; } } return Object.keys(objects).length; }, getObjectCount : function getObjectCount(recursive, onelevel) { var result = this.objectCount_; if (recursive) { this.children_.forEach(function(child) { result += child.getObjectCount(!onelevel && recursive); }); } return result; }, intersectingChildren : function intersectingChildren(pos, rad) { return this.children_.filter(function(child) { return child.intersects(pos, rad); }); }, intersects : function intersects(pos, rad) { var dist = pos.subtract(this.center_, true).abs(), cornerDist; if (dist.x > this.rad_.x + rad) { return false; } if (dist.y > this.rad_.y + rad) { return false; } if (dist.x <= this.rad_.x) { return true; } if (dist.y <= this.rad_.y) { return true; } cornerDistSq = Math.pow(dist.x - this.rad_.x, 2) + Math.pow(dist.y - this.rad_.y, 2); return cornerDistSq <= Math.pow(rad, 2); }, hasChildren : function hasChildren() { return this.getChildCount() !== 0; }, getChildCount : function getChildCount(recursive) { var count = this.children_.length; if (recursive) { this.children_.forEach(function(child) { count += child.getChildCount(recursive); }); } return count; }, getChildren : function getChildren(recursive, result) { if (!result) result = []; result.push.apply(result, this.children_); if (recursive) { this.children_.forEach(function(child) { child.getChildren(recursive, result); }); } return result; }, getObjectsUp : function getObjectsUp(result) { var id; if (result.quadrants[this.id_]) { return; } result.quadrants[this.id_] = true; for (id in this.objects_) { result.objects[id] = this.objects_[id]; } if (this.parent_) { this.parent_.getObjectsUp(result); } }, getObjectsDown : function getObjectsDown(result) { var id; if (result.quadrants[this.id_]) { return; } result.quadrants[this.id_] = true; for (id in this.objects_) { result.objects[id] = this.objects_[id]; } for (id = 0; id < this.children_.length; id++) { this.children_[id].getObjectsDown(result); } } }; module.exports = Quadtree2Quadrant; },{}],11:[function(require,module,exports){ var Vec2 = require('vec2'), Quadtree2Helper = require('./quadtree2helper'), Quadtree2Validator = function Quadtree2Validator() {}; Quadtree2Validator.prototype = { isNumber : function isNumber(param, key) { if ('number' !== typeof param) { Quadtree2Helper.thrower('NaN', 'Not a Number', key); } }, isString : function isString(param, key) { if (!(typeof param === 'string' || param instanceof String)) { Quadtree2Helper.thrower('NaS', 'Not a String', key); } }, isVec2 : function isVec2(param, key) { var throwIt = false; throwIt = 'object' !== typeof param || param.x === undefined || param.y === undefined; if(throwIt) { Quadtree2Helper.thrower('NaV', 'Not a Vec2', key); } }, isDefined : function isDefined(param, key) { if (param === undefined) { Quadtree2Helper.thrower('ND', 'Not defined', key); } }, isObject : function isObject(param, key) { if ('object' !== typeof param) { Quadtree2Helper.thrower('NaO', 'Not an Object', key); } }, hasKey : function hasKey(obj, k, key) { this.isDefined(obj, 'obj'); if ( Object.keys(obj).indexOf(k.toString()) === -1 ) { Quadtree2Helper.thrower('OhnK', 'Object has no key', key + k); } }, hasNoKey : function hasNoKey(obj, k, key) { this.isDefined(obj, 'obj'); if ( Object.keys(obj).indexOf(k.toString()) !== -1 ) { Quadtree2Helper.thrower('OhK', 'Object has key', key + k); } }, fnFalse : function fn(cb) { if(cb()) { Quadtree2Helper.thrower('FarT', 'function already returns true', Quadtree2Helper.fnName(cb)); } }, byCallbackObject : function byCallbackObject(obj, cbObj, keyTable) { var key; for (key in cbObj) { if (keyTable !== undefined) { cbObj[key](obj[keyTable[key]], keyTable[key]); } else { cbObj[key](obj[key], key); } } } }; module.exports = Quadtree2Validator; },{"./quadtree2helper":9,"vec2":7}],12:[function(require,module,exports){ var self = self || {};/** * @author mrdoob / http://mrdoob.com/ * @author Larry Battle / http://bateru.com/news * @author bhouston / http://exocortex.com */ var THREE = { REVISION: '66' }; self.console = self.console || { info: function () {}, log: function () {}, debug: function () {}, warn: function () {}, error: function () {} }; // http://paulirish.com/2011/requestanimationframe-for-smart-animating/ // http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating // requestAnimationFrame polyfill by Erik Möller // fixes from Paul Irish and Tino Zijdel // using 'self' instead of 'window' for compatibility with both NodeJS and IE10. ( function () { var lastTime = 0; var vendors = [ 'ms', 'moz', 'webkit', 'o' ]; for ( var x = 0; x < vendors.length && !self.requestAnimationFrame; ++ x ) { self.requestAnimationFrame = self[ vendors[ x ] + 'RequestAnimationFrame' ]; self.cancelAnimationFrame = self[ vendors[ x ] + 'CancelAnimationFrame' ] || self[ vendors[ x ] + 'CancelRequestAnimationFrame' ]; } if ( self.requestAnimationFrame === undefined && self['setTimeout'] !== undefined ) { self.requestAnimationFrame = function ( callback ) { var currTime = Date.now(), timeToCall = Math.max( 0, 16 - ( currTime - lastTime ) ); var id = self.setTimeout( function() { callback( currTime + timeToCall ); }, timeToCall ); lastTime = currTime + timeToCall; return id; }; } if( self.cancelAnimationFrame === undefined && self['clearTimeout'] !== undefined ) { self.cancelAnimationFrame = function ( id ) { self.clearTimeout( id ) }; } }() ); // GL STATE CONSTANTS THREE.CullFaceNone = 0; THREE.CullFaceBack = 1; THREE.CullFaceFront = 2; THREE.CullFaceFrontBack = 3; THREE.FrontFaceDirectionCW = 0; THREE.FrontFaceDirectionCCW = 1; // SHADOWING TYPES THREE.BasicShadowMap = 0; THREE.PCFShadowMap = 1; THREE.PCFSoftShadowMap = 2; // MATERIAL CONSTANTS // side THREE.FrontSide = 0; THREE.BackSide = 1; THREE.DoubleSide = 2; // shading THREE.NoShading = 0; THREE.FlatShading = 1; THREE.SmoothShading = 2; // colors THREE.NoColors = 0; THREE.FaceColors = 1; THREE.VertexColors = 2; // blending modes THREE.NoBlending = 0; THREE.NormalBlending = 1; THREE.AdditiveBlending = 2; THREE.SubtractiveBlending = 3; THREE.MultiplyBlending = 4; THREE.CustomBlending = 5; // custom blending equations // (numbers start from 100 not to clash with other // mappings to OpenGL constants defined in Texture.js) THREE.AddEquation = 100; THREE.SubtractEquation = 101; THREE.ReverseSubtractEquation = 102; // custom blending destination factors THREE.ZeroFactor = 200; THREE.OneFactor = 201; THREE.SrcColorFactor = 202; THREE.OneMinusSrcColorFactor = 203; THREE.SrcAlphaFactor = 204; THREE.OneMinusSrcAlphaFactor = 205; THREE.DstAlphaFactor = 206; THREE.OneMinusDstAlphaFactor = 207; // custom blending source factors //THREE.ZeroFactor = 200; //THREE.OneFactor = 201; //THREE.SrcAlphaFactor = 204; //THREE.OneMinusSrcAlphaFactor = 205; //THREE.DstAlphaFactor = 206; //THREE.OneMinusDstAlphaFactor = 207; THREE.DstColorFactor = 208; THREE.OneMinusDstColorFactor = 209; THREE.SrcAlphaSaturateFactor = 210; // TEXTURE CONSTANTS THREE.MultiplyOperation = 0; THREE.MixOperation = 1; THREE.AddOperation = 2; // Mapping modes THREE.UVMapping = function () {}; THREE.CubeReflectionMapping = function () {}; THREE.CubeRefractionMapping = function () {}; THREE.SphericalReflectionMapping = function () {}; THREE.SphericalRefractionMapping = function () {}; // Wrapping modes THREE.RepeatWrapping = 1000; THREE.ClampToEdgeWrapping = 1001; THREE.MirroredRepeatWrapping = 1002; // Filters THREE.NearestFilter = 1003; THREE.NearestMipMapNearestFilter = 1004; THREE.NearestMipMapLinearFilter = 1005; THREE.LinearFilter = 1006; THREE.LinearMipMapNearestFilter = 1007; THREE.LinearMipMapLinearFilter = 1008; // Data types THREE.UnsignedByteType = 1009; THREE.ByteType = 1010; THREE.ShortType = 1011; THREE.UnsignedShortType = 1012; THREE.IntType = 1013; THREE.UnsignedIntType = 1014; THREE.FloatType = 1015; // Pixel types //THREE.UnsignedByteType = 1009; THREE.UnsignedShort4444Type = 1016; THREE.UnsignedShort5551Type = 1017; THREE.UnsignedShort565Type = 1018; // Pixel formats THREE.AlphaFormat = 1019; THREE.RGBFormat = 1020; THREE.RGBAFormat = 1021; THREE.LuminanceFormat = 1022; THREE.LuminanceAlphaFormat = 1023; // Compressed texture formats THREE.RGB_S3TC_DXT1_Format = 2001; THREE.RGBA_S3TC_DXT1_Format = 2002; THREE.RGBA_S3TC_DXT3_Format = 2003; THREE.RGBA_S3TC_DXT5_Format = 2004; /* // Potential future PVRTC compressed texture formats THREE.RGB_PVRTC_4BPPV1_Format = 2100; THREE.RGB_PVRTC_2BPPV1_Format = 2101; THREE.RGBA_PVRTC_4BPPV1_Format = 2102; THREE.RGBA_PVRTC_2BPPV1_Format = 2103; */ /** * @author mrdoob / http://mrdoob.com/ */ THREE.Color = function ( color ) { if ( arguments.length === 3 ) { return this.setRGB( arguments[ 0 ], arguments[ 1 ], arguments[ 2 ] ); } return this.set( color ) }; THREE.Color.prototype = { constructor: THREE.Color, r: 1, g: 1, b: 1, set: function ( value ) { if ( value instanceof THREE.Color ) { this.copy( value ); } else if ( typeof value === 'number' ) { this.setHex( value ); } else if ( typeof value === 'string' ) { this.setStyle( value ); } return this; }, setHex: function ( hex ) { hex = Math.floor( hex ); this.r = ( hex >> 16 & 255 ) / 255; this.g = ( hex >> 8 & 255 ) / 255; this.b = ( hex & 255 ) / 255; return this; }, setRGB: function ( r, g, b ) { this.r = r; this.g = g; this.b = b; return this; }, setHSL: function ( h, s, l ) { // h,s,l ranges are in 0.0 - 1.0 if ( s === 0 ) { this.r = this.g = this.b = l; } else { var hue2rgb = function ( p, q, t ) { if ( t < 0 ) t += 1; if ( t > 1 ) t -= 1; if ( t < 1 / 6 ) return p + ( q - p ) * 6 * t; if ( t < 1 / 2 ) return q; if ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t ); return p; }; var p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s ); var q = ( 2 * l ) - p; this.r = hue2rgb( q, p, h + 1 / 3 ); this.g = hue2rgb( q, p, h ); this.b = hue2rgb( q, p, h - 1 / 3 ); } return this; }, setStyle: function ( style ) { // rgb(255,0,0) if ( /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.test( style ) ) { var color = /^rgb\((\d+), ?(\d+), ?(\d+)\)$/i.exec( style ); this.r = Math.min( 255, parseInt( color[ 1 ], 10 ) ) / 255; this.g = Math.min( 255, parseInt( color[ 2 ], 10 ) ) / 255; this.b = Math.min( 255, parseInt( color[ 3 ], 10 ) ) / 255; return this; } // rgb(100%,0%,0%) if ( /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.test( style ) ) { var color = /^rgb\((\d+)\%, ?(\d+)\%, ?(\d+)\%\)$/i.exec( style ); this.r = Math.min( 100, parseInt( color[ 1 ], 10 ) ) / 100; this.g = Math.min( 100, parseInt( color[ 2 ], 10 ) ) / 100; this.b = Math.min( 100, parseInt( color[ 3 ], 10 ) ) / 100; return this; } // #ff0000 if ( /^\#([0-9a-f]{6})$/i.test( style ) ) { var color = /^\#([0-9a-f]{6})$/i.exec( style ); this.setHex( parseInt( color[ 1 ], 16 ) ); return this; } // #f00 if ( /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test( style ) ) { var color = /^\#([0-9a-f])([0-9a-f])([0-9a-f])$/i.exec( style ); this.setHex( parseInt( color[ 1 ] + color[ 1 ] + color[ 2 ] + color[ 2 ] + color[ 3 ] + color[ 3 ], 16 ) ); return this; } // red if ( /^(\w+)$/i.test( style ) ) { this.setHex( THREE.ColorKeywords[ style ] ); return this; } }, copy: function ( color ) { this.r = color.r; this.g = color.g; this.b = color.b; return this; }, copyGammaToLinear: function ( color ) { this.r = color.r * color.r; this.g = color.g * color.g; this.b = color.b * color.b; return this; }, copyLinearToGamma: function ( color ) { this.r = Math.sqrt( color.r ); this.g = Math.sqrt( color.g ); this.b = Math.sqrt( color.b ); return this; }, convertGammaToLinear: function () { var r = this.r, g = this.g, b = this.b; this.r = r * r; this.g = g * g; this.b = b * b; return this; }, convertLinearToGamma: function () { this.r = Math.sqrt( this.r ); this.g = Math.sqrt( this.g ); this.b = Math.sqrt( this.b ); return this; }, getHex: function () { return ( this.r * 255 ) << 16 ^ ( this.g * 255 ) << 8 ^ ( this.b * 255 ) << 0; }, getHexString: function () { return ( '000000' + this.getHex().toString( 16 ) ).slice( - 6 ); }, getHSL: function ( optionalTarget ) { // h,s,l ranges are in 0.0 - 1.0 var hsl = optionalTarget || { h: 0, s: 0, l: 0 }; var r = this.r, g = this.g, b = this.b; var max = Math.max( r, g, b ); var min = Math.min( r, g, b ); var hue, saturation; var lightness = ( min + max ) / 2.0; if ( min === max ) { hue = 0; saturation = 0; } else { var delta = max - min; saturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min ); switch ( max ) { case r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break; case g: hue = ( b - r ) / delta + 2; break; case b: hue = ( r - g ) / delta + 4; break; } hue /= 6; } hsl.h = hue; hsl.s = saturation; hsl.l = lightness; return hsl; }, getStyle: function () { return 'rgb(' + ( ( this.r * 255 ) | 0 ) + ',' + ( ( this.g * 255 ) | 0 ) + ',' + ( ( this.b * 255 ) | 0 ) + ')'; }, offsetHSL: function ( h, s, l ) { var hsl = this.getHSL(); hsl.h += h; hsl.s += s; hsl.l += l; this.setHSL( hsl.h, hsl.s, hsl.l ); return this; }, add: function ( color ) { this.r += color.r; this.g += color.g; this.b += color.b; return this; }, addColors: function ( color1, color2 ) { this.r = color1.r + color2.r; this.g = color1.g + color2.g; this.b = color1.b + color2.b; return this; }, addScalar: function ( s ) { this.r += s; this.g += s; this.b += s; return this; }, multiply: function ( color ) { this.r *= color.r; this.g *= color.g; this.b *= color.b; return this; }, multiplyScalar: function ( s ) { this.r *= s; this.g *= s; this.b *= s; return this; }, lerp: function ( color, alpha ) { this.r += ( color.r - this.r ) * alpha; this.g += ( color.g - this.g ) * alpha; this.b += ( color.b - this.b ) * alpha; return this; }, equals: function ( c ) { return ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b ); }, fromArray: function ( array ) { this.r = array[ 0 ]; this.g = array[ 1 ]; this.b = array[ 2 ]; return this; }, toArray: function () { return [ this.r, this.g, this.b ]; }, clone: function () { return new THREE.Color().setRGB( this.r, this.g, this.b ); } }; THREE.ColorKeywords = { "aliceblue": 0xF0F8FF, "antiquewhite": 0xFAEBD7, "aqua": 0x00FFFF, "aquamarine": 0x7FFFD4, "azure": 0xF0FFFF, "beige": 0xF5F5DC, "bisque": 0xFFE4C4, "black": 0x000000, "blanchedalmond": 0xFFEBCD, "blue": 0x0000FF, "blueviolet": 0x8A2BE2, "brown": 0xA52A2A, "burlywood": 0xDEB887, "cadetblue": 0x5F9EA0, "chartreuse": 0x7FFF00, "chocolate": 0xD2691E, "coral": 0xFF7F50, "cornflowerblue": 0x6495ED, "cornsilk": 0xFFF8DC, "crimson": 0xDC143C, "cyan": 0x00FFFF, "darkblue": 0x00008B, "darkcyan": 0x008B8B, "darkgoldenrod": 0xB8860B, "darkgray": 0xA9A9A9, "darkgreen": 0x006400, "darkgrey": 0xA9A9A9, "darkkhaki": 0xBDB76B, "darkmagenta": 0x8B008B, "darkolivegreen": 0x556B2F, "darkorange": 0xFF8C00, "darkorchid": 0x9932CC, "darkred": 0x8B0000, "darksalmon": 0xE9967A, "darkseagreen": 0x8FBC8F, "darkslateblue": 0x483D8B, "darkslategray": 0x2F4F4F, "darkslategrey": 0x2F4F4F, "darkturquoise": 0x00CED1, "darkviolet": 0x9400D3, "deeppink": 0xFF1493, "deepskyblue": 0x00BFFF, "dimgray": 0x696969, "dimgrey": 0x696969, "dodgerblue": 0x1E90FF, "firebrick": 0xB22222, "floralwhite": 0xFFFAF0, "forestgreen": 0x228B22, "fuchsia": 0xFF00FF, "gainsboro": 0xDCDCDC, "ghostwhite": 0xF8F8FF, "gold": 0xFFD700, "goldenrod": 0xDAA520, "gray": 0x808080, "green": 0x008000, "greenyellow": 0xADFF2F, "grey": 0x808080, "honeydew": 0xF0FFF0, "hotpink": 0xFF69B4, "indianred": 0xCD5C5C, "indigo": 0x4B0082, "ivory": 0xFFFFF0, "khaki": 0xF0E68C, "lavender": 0xE6E6FA, "lavenderblush": 0xFFF0F5, "lawngreen": 0x7CFC00, "lemonchiffon": 0xFFFACD, "lightblue": 0xADD8E6, "lightcoral": 0xF08080, "lightcyan": 0xE0FFFF, "lightgoldenrodyellow": 0xFAFAD2, "lightgray": 0xD3D3D3, "lightgreen": 0x90EE90, "lightgrey": 0xD3D3D3, "lightpink": 0xFFB6C1, "lightsalmon": 0xFFA07A, "lightseagreen": 0x20B2AA, "lightskyblue": 0x87CEFA, "lightslategray": 0x778899, "lightslategrey": 0x778899, "lightsteelblue": 0xB0C4DE, "lightyellow": 0xFFFFE0, "lime": 0x00FF00, "limegreen": 0x32CD32, "linen": 0xFAF0E6, "magenta": 0xFF00FF, "maroon": 0x800000, "mediumaquamarine": 0x66CDAA, "mediumblue": 0x0000CD, "mediumorchid": 0xBA55D3, "mediumpurple": 0x9370DB, "mediumseagreen": 0x3CB371, "mediumslateblue": 0x7B68EE, "mediumspringgreen": 0x00FA9A, "mediumturquoise": 0x48D1CC, "mediumvioletred": 0xC71585, "midnightblue": 0x191970, "mintcream": 0xF5FFFA, "mistyrose": 0xFFE4E1, "moccasin": 0xFFE4B5, "navajowhite": 0xFFDEAD, "navy": 0x000080, "oldlace": 0xFDF5E6, "olive": 0x808000, "olivedrab": 0x6B8E23, "orange": 0xFFA500, "orangered": 0xFF4500, "orchid": 0xDA70D6, "palegoldenrod": 0xEEE8AA, "palegreen": 0x98FB98, "paleturquoise": 0xAFEEEE, "palevioletred": 0xDB7093, "papayawhip": 0xFFEFD5, "peachpuff": 0xFFDAB9, "peru": 0xCD853F, "pink": 0xFFC0CB, "plum": 0xDDA0DD, "powderblue": 0xB0E0E6, "purple": 0x800080, "red": 0xFF0000, "rosybrown": 0xBC8F8F, "royalblue": 0x4169E1, "saddlebrown": 0x8B4513, "salmon": 0xFA8072, "sandybrown": 0xF4A460, "seagreen": 0x2E8B57, "seashell": 0xFFF5EE, "sienna": 0xA0522D, "silver": 0xC0C0C0, "skyblue": 0x87CEEB, "slateblue": 0x6A5ACD, "slategray": 0x708090, "slategrey": 0x708090, "snow": 0xFFFAFA, "springgreen": 0x00FF7F, "steelblue": 0x4682B4, "tan": 0xD2B48C, "teal": 0x008080, "thistle": 0xD8BFD8, "tomato": 0xFF6347, "turquoise": 0x40E0D0, "violet": 0xEE82EE, "wheat": 0xF5DEB3, "white": 0xFFFFFF, "whitesmoke": 0xF5F5F5, "yellow": 0xFFFF00, "yellowgreen": 0x9ACD32 }; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley * @author bhouston / http://exocortex.com */ THREE.Quaternion = function ( x, y, z, w ) { this._x = x || 0; this._y = y || 0; this._z = z || 0; this._w = ( w !== undefined ) ? w : 1; }; THREE.Quaternion.prototype = { constructor: THREE.Quaternion, _x: 0,_y: 0, _z: 0, _w: 0, _euler: undefined, _updateEuler: function ( callback ) { if ( this._euler !== undefined ) { this._euler.setFromQuaternion( this, undefined, false ); } }, get x () { return this._x; }, set x ( value ) { this._x = value; this._updateEuler(); }, get y () { return this._y; }, set y ( value ) { this._y = value; this._updateEuler(); }, get z () { return this._z; }, set z ( value ) { this._z = value; this._updateEuler(); }, get w () { return this._w; }, set w ( value ) { this._w = value; this._updateEuler(); }, set: function ( x, y, z, w ) { this._x = x; this._y = y; this._z = z; this._w = w; this._updateEuler(); return this; }, copy: function ( quaternion ) { this._x = quaternion._x; this._y = quaternion._y; this._z = quaternion._z; this._w = quaternion._w; this._updateEuler(); return this; }, setFromEuler: function ( euler, update ) { if ( euler instanceof THREE.Euler === false ) { throw new Error( 'ERROR: Quaternion\'s .setFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); } // http://www.mathworks.com/matlabcentral/fileexchange/ // 20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/ // content/SpinCalc.m var c1 = Math.cos( euler._x / 2 ); var c2 = Math.cos( euler._y / 2 ); var c3 = Math.cos( euler._z / 2 ); var s1 = Math.sin( euler._x / 2 ); var s2 = Math.sin( euler._y / 2 ); var s3 = Math.sin( euler._z / 2 ); if ( euler.order === 'XYZ' ) { this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; } else if ( euler.order === 'YXZ' ) { this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; } else if ( euler.order === 'ZXY' ) { this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; } else if ( euler.order === 'ZYX' ) { this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; } else if ( euler.order === 'YZX' ) { this._x = s1 * c2 * c3 + c1 * s2 * s3; this._y = c1 * s2 * c3 + s1 * c2 * s3; this._z = c1 * c2 * s3 - s1 * s2 * c3; this._w = c1 * c2 * c3 - s1 * s2 * s3; } else if ( euler.order === 'XZY' ) { this._x = s1 * c2 * c3 - c1 * s2 * s3; this._y = c1 * s2 * c3 - s1 * c2 * s3; this._z = c1 * c2 * s3 + s1 * s2 * c3; this._w = c1 * c2 * c3 + s1 * s2 * s3; } if ( update !== false ) this._updateEuler(); return this; }, setFromAxisAngle: function ( axis, angle ) { // from http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm // axis have to be normalized var halfAngle = angle / 2, s = Math.sin( halfAngle ); this._x = axis.x * s; this._y = axis.y * s; this._z = axis.z * s; this._w = Math.cos( halfAngle ); this._updateEuler(); return this; }, setFromRotationMatrix: function ( m ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var te = m.elements, m11 = te[0], m12 = te[4], m13 = te[8], m21 = te[1], m22 = te[5], m23 = te[9], m31 = te[2], m32 = te[6], m33 = te[10], trace = m11 + m22 + m33, s; if ( trace > 0 ) { s = 0.5 / Math.sqrt( trace + 1.0 ); this._w = 0.25 / s; this._x = ( m32 - m23 ) * s; this._y = ( m13 - m31 ) * s; this._z = ( m21 - m12 ) * s; } else if ( m11 > m22 && m11 > m33 ) { s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 ); this._w = (m32 - m23 ) / s; this._x = 0.25 * s; this._y = (m12 + m21 ) / s; this._z = (m13 + m31 ) / s; } else if ( m22 > m33 ) { s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 ); this._w = (m13 - m31 ) / s; this._x = (m12 + m21 ) / s; this._y = 0.25 * s; this._z = (m23 + m32 ) / s; } else { s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 ); this._w = ( m21 - m12 ) / s; this._x = ( m13 + m31 ) / s; this._y = ( m23 + m32 ) / s; this._z = 0.25 * s; } this._updateEuler(); return this; }, inverse: function () { this.conjugate().normalize(); return this; }, conjugate: function () { this._x *= -1; this._y *= -1; this._z *= -1; this._updateEuler(); return this; }, lengthSq: function () { return this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w; }, length: function () { return Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w ); }, normalize: function () { var l = this.length(); if ( l === 0 ) { this._x = 0; this._y = 0; this._z = 0; this._w = 1; } else { l = 1 / l; this._x = this._x * l; this._y = this._y * l; this._z = this._z * l; this._w = this._w * l; } return this; }, multiply: function ( q, p ) { if ( p !== undefined ) { console.warn( 'DEPRECATED: Quaternion\'s .multiply() now only accepts one argument. Use .multiplyQuaternions( a, b ) instead.' ); return this.multiplyQuaternions( q, p ); } return this.multiplyQuaternions( this, q ); }, multiplyQuaternions: function ( a, b ) { // from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm var qax = a._x, qay = a._y, qaz = a._z, qaw = a._w; var qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w; this._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby; this._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz; this._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx; this._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz; this._updateEuler(); return this; }, multiplyVector3: function ( vector ) { console.warn( 'DEPRECATED: Quaternion\'s .multiplyVector3() has been removed. Use is now vector.applyQuaternion( quaternion ) instead.' ); return vector.applyQuaternion( this ); }, slerp: function ( qb, t ) { var x = this._x, y = this._y, z = this._z, w = this._w; // http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/ var cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z; if ( cosHalfTheta < 0 ) { this._w = -qb._w; this._x = -qb._x; this._y = -qb._y; this._z = -qb._z; cosHalfTheta = -cosHalfTheta; } else { this.copy( qb ); } if ( cosHalfTheta >= 1.0 ) { this._w = w; this._x = x; this._y = y; this._z = z; return this; } var halfTheta = Math.acos( cosHalfTheta ); var sinHalfTheta = Math.sqrt( 1.0 - cosHalfTheta * cosHalfTheta ); if ( Math.abs( sinHalfTheta ) < 0.001 ) { this._w = 0.5 * ( w + this._w ); this._x = 0.5 * ( x + this._x ); this._y = 0.5 * ( y + this._y ); this._z = 0.5 * ( z + this._z ); return this; } var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta, ratioB = Math.sin( t * halfTheta ) / sinHalfTheta; this._w = ( w * ratioA + this._w * ratioB ); this._x = ( x * ratioA + this._x * ratioB ); this._y = ( y * ratioA + this._y * ratioB ); this._z = ( z * ratioA + this._z * ratioB ); this._updateEuler(); return this; }, equals: function ( quaternion ) { return ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w ); }, fromArray: function ( array ) { this._x = array[ 0 ]; this._y = array[ 1 ]; this._z = array[ 2 ]; this._w = array[ 3 ]; this._updateEuler(); return this; }, toArray: function () { return [ this._x, this._y, this._z, this._w ]; }, clone: function () { return new THREE.Quaternion( this._x, this._y, this._z, this._w ); } }; THREE.Quaternion.slerp = function ( qa, qb, qm, t ) { return qm.copy( qa ).slerp( qb, t ); } /** * @author mrdoob / http://mrdoob.com/ * @author philogb / http://blog.thejit.org/ * @author egraether / http://egraether.com/ * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.Vector2 = function ( x, y ) { this.x = x || 0; this.y = y || 0; }; THREE.Vector2.prototype = { constructor: THREE.Vector2, set: function ( x, y ) { this.x = x; this.y = y; return this; }, setX: function ( x ) { this.x = x; return this; }, setY: function ( y ) { this.y = y; return this; }, setComponent: function ( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; default: throw new Error( "index is out of range: " + index ); } }, getComponent: function ( index ) { switch ( index ) { case 0: return this.x; case 1: return this.y; default: throw new Error( "index is out of range: " + index ); } }, copy: function ( v ) { this.x = v.x; this.y = v.y; return this; }, add: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector2\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } this.x += v.x; this.y += v.y; return this; }, addVectors: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; return this; }, addScalar: function ( s ) { this.x += s; this.y += s; return this; }, sub: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector2\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } this.x -= v.x; this.y -= v.y; return this; }, subVectors: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; return this; }, multiplyScalar: function ( s ) { this.x *= s; this.y *= s; return this; }, divideScalar: function ( scalar ) { if ( scalar !== 0 ) { var invScalar = 1 / scalar; this.x *= invScalar; this.y *= invScalar; } else { this.x = 0; this.y = 0; } return this; }, min: function ( v ) { if ( this.x > v.x ) { this.x = v.x; } if ( this.y > v.y ) { this.y = v.y; } return this; }, max: function ( v ) { if ( this.x < v.x ) { this.x = v.x; } if ( this.y < v.y ) { this.y = v.y; } return this; }, clamp: function ( min, max ) { // This function assumes min < max, if this assumption isn't true it will not operate correctly if ( this.x < min.x ) { this.x = min.x; } else if ( this.x > max.x ) { this.x = max.x; } if ( this.y < min.y ) { this.y = min.y; } else if ( this.y > max.y ) { this.y = max.y; } return this; }, clampScalar: ( function () { var min, max; return function ( minVal, maxVal ) { if ( min === undefined ) { min = new THREE.Vector2(); max = new THREE.Vector2(); } min.set( minVal, minVal ); max.set( maxVal, maxVal ); return this.clamp( min, max ); }; } )(), floor: function () { this.x = Math.floor( this.x ); this.y = Math.floor( this.y ); return this; }, ceil: function () { this.x = Math.ceil( this.x ); this.y = Math.ceil( this.y ); return this; }, round: function () { this.x = Math.round( this.x ); this.y = Math.round( this.y ); return this; }, roundToZero: function () { this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); return this; }, negate: function () { return this.multiplyScalar( - 1 ); }, dot: function ( v ) { return this.x * v.x + this.y * v.y; }, lengthSq: function () { return this.x * this.x + this.y * this.y; }, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y ); }, normalize: function () { return this.divideScalar( this.length() ); }, distanceTo: function ( v ) { return Math.sqrt( this.distanceToSquared( v ) ); }, distanceToSquared: function ( v ) { var dx = this.x - v.x, dy = this.y - v.y; return dx * dx + dy * dy; }, setLength: function ( l ) { var oldLength = this.length(); if ( oldLength !== 0 && l !== oldLength ) { this.multiplyScalar( l / oldLength ); } return this; }, lerp: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; return this; }, equals: function( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) ); }, fromArray: function ( array ) { this.x = array[ 0 ]; this.y = array[ 1 ]; return this; }, toArray: function () { return [ this.x, this.y ]; }, clone: function () { return new THREE.Vector2( this.x, this.y ); } }; /** * @author mrdoob / http://mrdoob.com/ * @author *kile / http://kile.stravaganza.org/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ * @author egraether / http://egraether.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.Vector3 = function ( x, y, z ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; }; THREE.Vector3.prototype = { constructor: THREE.Vector3, set: function ( x, y, z ) { this.x = x; this.y = y; this.z = z; return this; }, setX: function ( x ) { this.x = x; return this; }, setY: function ( y ) { this.y = y; return this; }, setZ: function ( z ) { this.z = z; return this; }, setComponent: function ( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; case 2: this.z = value; break; default: throw new Error( "index is out of range: " + index ); } }, getComponent: function ( index ) { switch ( index ) { case 0: return this.x; case 1: return this.y; case 2: return this.z; default: throw new Error( "index is out of range: " + index ); } }, copy: function ( v ) { this.x = v.x; this.y = v.y; this.z = v.z; return this; }, add: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector3\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } this.x += v.x; this.y += v.y; this.z += v.z; return this; }, addScalar: function ( s ) { this.x += s; this.y += s; this.z += s; return this; }, addVectors: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; this.z = a.z + b.z; return this; }, sub: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector3\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } this.x -= v.x; this.y -= v.y; this.z -= v.z; return this; }, subVectors: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; this.z = a.z - b.z; return this; }, multiply: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector3\'s .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' ); return this.multiplyVectors( v, w ); } this.x *= v.x; this.y *= v.y; this.z *= v.z; return this; }, multiplyScalar: function ( scalar ) { this.x *= scalar; this.y *= scalar; this.z *= scalar; return this; }, multiplyVectors: function ( a, b ) { this.x = a.x * b.x; this.y = a.y * b.y; this.z = a.z * b.z; return this; }, applyEuler: function () { var quaternion; return function ( euler ) { if ( euler instanceof THREE.Euler === false ) { console.error( 'ERROR: Vector3\'s .applyEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); } if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); this.applyQuaternion( quaternion.setFromEuler( euler ) ); return this; }; }(), applyAxisAngle: function () { var quaternion; return function ( axis, angle ) { if ( quaternion === undefined ) quaternion = new THREE.Quaternion(); this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) ); return this; }; }(), applyMatrix3: function ( m ) { var x = this.x; var y = this.y; var z = this.z; var e = m.elements; this.x = e[0] * x + e[3] * y + e[6] * z; this.y = e[1] * x + e[4] * y + e[7] * z; this.z = e[2] * x + e[5] * y + e[8] * z; return this; }, applyMatrix4: function ( m ) { // input: THREE.Matrix4 affine matrix var x = this.x, y = this.y, z = this.z; var e = m.elements; this.x = e[0] * x + e[4] * y + e[8] * z + e[12]; this.y = e[1] * x + e[5] * y + e[9] * z + e[13]; this.z = e[2] * x + e[6] * y + e[10] * z + e[14]; return this; }, applyProjection: function ( m ) { // input: THREE.Matrix4 projection matrix var x = this.x, y = this.y, z = this.z; var e = m.elements; var d = 1 / ( e[3] * x + e[7] * y + e[11] * z + e[15] ); // perspective divide this.x = ( e[0] * x + e[4] * y + e[8] * z + e[12] ) * d; this.y = ( e[1] * x + e[5] * y + e[9] * z + e[13] ) * d; this.z = ( e[2] * x + e[6] * y + e[10] * z + e[14] ) * d; return this; }, applyQuaternion: function ( q ) { var x = this.x; var y = this.y; var z = this.z; var qx = q.x; var qy = q.y; var qz = q.z; var qw = q.w; // calculate quat * vector var ix = qw * x + qy * z - qz * y; var iy = qw * y + qz * x - qx * z; var iz = qw * z + qx * y - qy * x; var iw = -qx * x - qy * y - qz * z; // calculate result * inverse quat this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy; this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz; this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx; return this; }, transformDirection: function ( m ) { // input: THREE.Matrix4 affine matrix // vector interpreted as a direction var x = this.x, y = this.y, z = this.z; var e = m.elements; this.x = e[0] * x + e[4] * y + e[8] * z; this.y = e[1] * x + e[5] * y + e[9] * z; this.z = e[2] * x + e[6] * y + e[10] * z; this.normalize(); return this; }, divide: function ( v ) { this.x /= v.x; this.y /= v.y; this.z /= v.z; return this; }, divideScalar: function ( scalar ) { if ( scalar !== 0 ) { var invScalar = 1 / scalar; this.x *= invScalar; this.y *= invScalar; this.z *= invScalar; } else { this.x = 0; this.y = 0; this.z = 0; } return this; }, min: function ( v ) { if ( this.x > v.x ) { this.x = v.x; } if ( this.y > v.y ) { this.y = v.y; } if ( this.z > v.z ) { this.z = v.z; } return this; }, max: function ( v ) { if ( this.x < v.x ) { this.x = v.x; } if ( this.y < v.y ) { this.y = v.y; } if ( this.z < v.z ) { this.z = v.z; } return this; }, clamp: function ( min, max ) { // This function assumes min < max, if this assumption isn't true it will not operate correctly if ( this.x < min.x ) { this.x = min.x; } else if ( this.x > max.x ) { this.x = max.x; } if ( this.y < min.y ) { this.y = min.y; } else if ( this.y > max.y ) { this.y = max.y; } if ( this.z < min.z ) { this.z = min.z; } else if ( this.z > max.z ) { this.z = max.z; } return this; }, clampScalar: ( function () { var min, max; return function ( minVal, maxVal ) { if ( min === undefined ) { min = new THREE.Vector3(); max = new THREE.Vector3(); } min.set( minVal, minVal, minVal ); max.set( maxVal, maxVal, maxVal ); return this.clamp( min, max ); }; } )(), floor: function () { this.x = Math.floor( this.x ); this.y = Math.floor( this.y ); this.z = Math.floor( this.z ); return this; }, ceil: function () { this.x = Math.ceil( this.x ); this.y = Math.ceil( this.y ); this.z = Math.ceil( this.z ); return this; }, round: function () { this.x = Math.round( this.x ); this.y = Math.round( this.y ); this.z = Math.round( this.z ); return this; }, roundToZero: function () { this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); return this; }, negate: function () { return this.multiplyScalar( - 1 ); }, dot: function ( v ) { return this.x * v.x + this.y * v.y + this.z * v.z; }, lengthSq: function () { return this.x * this.x + this.y * this.y + this.z * this.z; }, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); }, lengthManhattan: function () { return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ); }, normalize: function () { return this.divideScalar( this.length() ); }, setLength: function ( l ) { var oldLength = this.length(); if ( oldLength !== 0 && l !== oldLength ) { this.multiplyScalar( l / oldLength ); } return this; }, lerp: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; this.z += ( v.z - this.z ) * alpha; return this; }, cross: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector3\'s .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' ); return this.crossVectors( v, w ); } var x = this.x, y = this.y, z = this.z; this.x = y * v.z - z * v.y; this.y = z * v.x - x * v.z; this.z = x * v.y - y * v.x; return this; }, crossVectors: function ( a, b ) { var ax = a.x, ay = a.y, az = a.z; var bx = b.x, by = b.y, bz = b.z; this.x = ay * bz - az * by; this.y = az * bx - ax * bz; this.z = ax * by - ay * bx; return this; }, projectOnVector: function () { var v1, dot; return function ( vector ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); v1.copy( vector ).normalize(); dot = this.dot( v1 ); return this.copy( v1 ).multiplyScalar( dot ); }; }(), projectOnPlane: function () { var v1; return function ( planeNormal ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); v1.copy( this ).projectOnVector( planeNormal ); return this.sub( v1 ); } }(), reflect: function () { // reflect incident vector off plane orthogonal to normal // normal is assumed to have unit length var v1; return function ( normal ) { if ( v1 === undefined ) v1 = new THREE.Vector3(); return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) ); } }(), angleTo: function ( v ) { var theta = this.dot( v ) / ( this.length() * v.length() ); // clamp, to handle numerical problems return Math.acos( THREE.Math.clamp( theta, -1, 1 ) ); }, distanceTo: function ( v ) { return Math.sqrt( this.distanceToSquared( v ) ); }, distanceToSquared: function ( v ) { var dx = this.x - v.x; var dy = this.y - v.y; var dz = this.z - v.z; return dx * dx + dy * dy + dz * dz; }, setEulerFromRotationMatrix: function ( m, order ) { console.error( "REMOVED: Vector3\'s setEulerFromRotationMatrix has been removed in favor of Euler.setFromRotationMatrix(), please update your code."); }, setEulerFromQuaternion: function ( q, order ) { console.error( "REMOVED: Vector3\'s setEulerFromQuaternion: has been removed in favor of Euler.setFromQuaternion(), please update your code."); }, getPositionFromMatrix: function ( m ) { console.warn( "DEPRECATED: Vector3\'s .getPositionFromMatrix() has been renamed to .setFromMatrixPosition(). Please update your code." ); return this.setFromMatrixPosition( m ); }, getScaleFromMatrix: function ( m ) { console.warn( "DEPRECATED: Vector3\'s .getScaleFromMatrix() has been renamed to .setFromMatrixScale(). Please update your code." ); return this.setFromMatrixScale( m ); }, getColumnFromMatrix: function ( index, matrix ) { console.warn( "DEPRECATED: Vector3\'s .getColumnFromMatrix() has been renamed to .setFromMatrixColumn(). Please update your code." ); return this.setFromMatrixColumn( index, matrix ); }, setFromMatrixPosition: function ( m ) { this.x = m.elements[ 12 ]; this.y = m.elements[ 13 ]; this.z = m.elements[ 14 ]; return this; }, setFromMatrixScale: function ( m ) { var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length(); var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length(); var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length(); this.x = sx; this.y = sy; this.z = sz; return this; }, setFromMatrixColumn: function ( index, matrix ) { var offset = index * 4; var me = matrix.elements; this.x = me[ offset ]; this.y = me[ offset + 1 ]; this.z = me[ offset + 2 ]; return this; }, equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) ); }, fromArray: function ( array ) { this.x = array[ 0 ]; this.y = array[ 1 ]; this.z = array[ 2 ]; return this; }, toArray: function () { return [ this.x, this.y, this.z ]; }, clone: function () { return new THREE.Vector3( this.x, this.y, this.z ); } };/** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author philogb / http://blog.thejit.org/ * @author mikael emtinger / http://gomo.se/ * @author egraether / http://egraether.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.Vector4 = function ( x, y, z, w ) { this.x = x || 0; this.y = y || 0; this.z = z || 0; this.w = ( w !== undefined ) ? w : 1; }; THREE.Vector4.prototype = { constructor: THREE.Vector4, set: function ( x, y, z, w ) { this.x = x; this.y = y; this.z = z; this.w = w; return this; }, setX: function ( x ) { this.x = x; return this; }, setY: function ( y ) { this.y = y; return this; }, setZ: function ( z ) { this.z = z; return this; }, setW: function ( w ) { this.w = w; return this; }, setComponent: function ( index, value ) { switch ( index ) { case 0: this.x = value; break; case 1: this.y = value; break; case 2: this.z = value; break; case 3: this.w = value; break; default: throw new Error( "index is out of range: " + index ); } }, getComponent: function ( index ) { switch ( index ) { case 0: return this.x; case 1: return this.y; case 2: return this.z; case 3: return this.w; default: throw new Error( "index is out of range: " + index ); } }, copy: function ( v ) { this.x = v.x; this.y = v.y; this.z = v.z; this.w = ( v.w !== undefined ) ? v.w : 1; return this; }, add: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector4\'s .add() now only accepts one argument. Use .addVectors( a, b ) instead.' ); return this.addVectors( v, w ); } this.x += v.x; this.y += v.y; this.z += v.z; this.w += v.w; return this; }, addScalar: function ( s ) { this.x += s; this.y += s; this.z += s; this.w += s; return this; }, addVectors: function ( a, b ) { this.x = a.x + b.x; this.y = a.y + b.y; this.z = a.z + b.z; this.w = a.w + b.w; return this; }, sub: function ( v, w ) { if ( w !== undefined ) { console.warn( 'DEPRECATED: Vector4\'s .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' ); return this.subVectors( v, w ); } this.x -= v.x; this.y -= v.y; this.z -= v.z; this.w -= v.w; return this; }, subVectors: function ( a, b ) { this.x = a.x - b.x; this.y = a.y - b.y; this.z = a.z - b.z; this.w = a.w - b.w; return this; }, multiplyScalar: function ( scalar ) { this.x *= scalar; this.y *= scalar; this.z *= scalar; this.w *= scalar; return this; }, applyMatrix4: function ( m ) { var x = this.x; var y = this.y; var z = this.z; var w = this.w; var e = m.elements; this.x = e[0] * x + e[4] * y + e[8] * z + e[12] * w; this.y = e[1] * x + e[5] * y + e[9] * z + e[13] * w; this.z = e[2] * x + e[6] * y + e[10] * z + e[14] * w; this.w = e[3] * x + e[7] * y + e[11] * z + e[15] * w; return this; }, divideScalar: function ( scalar ) { if ( scalar !== 0 ) { var invScalar = 1 / scalar; this.x *= invScalar; this.y *= invScalar; this.z *= invScalar; this.w *= invScalar; } else { this.x = 0; this.y = 0; this.z = 0; this.w = 1; } return this; }, setAxisAngleFromQuaternion: function ( q ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm // q is assumed to be normalized this.w = 2 * Math.acos( q.w ); var s = Math.sqrt( 1 - q.w * q.w ); if ( s < 0.0001 ) { this.x = 1; this.y = 0; this.z = 0; } else { this.x = q.x / s; this.y = q.y / s; this.z = q.z / s; } return this; }, setAxisAngleFromRotationMatrix: function ( m ) { // http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) var angle, x, y, z, // variables for result epsilon = 0.01, // margin to allow for rounding errors epsilon2 = 0.1, // margin to distinguish between 0 and 180 degrees te = m.elements, m11 = te[0], m12 = te[4], m13 = te[8], m21 = te[1], m22 = te[5], m23 = te[9], m31 = te[2], m32 = te[6], m33 = te[10]; if ( ( Math.abs( m12 - m21 ) < epsilon ) && ( Math.abs( m13 - m31 ) < epsilon ) && ( Math.abs( m23 - m32 ) < epsilon ) ) { // singularity found // first check for identity matrix which must have +1 for all terms // in leading diagonal and zero in other terms if ( ( Math.abs( m12 + m21 ) < epsilon2 ) && ( Math.abs( m13 + m31 ) < epsilon2 ) && ( Math.abs( m23 + m32 ) < epsilon2 ) && ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) { // this singularity is identity matrix so angle = 0 this.set( 1, 0, 0, 0 ); return this; // zero angle, arbitrary axis } // otherwise this singularity is angle = 180 angle = Math.PI; var xx = ( m11 + 1 ) / 2; var yy = ( m22 + 1 ) / 2; var zz = ( m33 + 1 ) / 2; var xy = ( m12 + m21 ) / 4; var xz = ( m13 + m31 ) / 4; var yz = ( m23 + m32 ) / 4; if ( ( xx > yy ) && ( xx > zz ) ) { // m11 is the largest diagonal term if ( xx < epsilon ) { x = 0; y = 0.707106781; z = 0.707106781; } else { x = Math.sqrt( xx ); y = xy / x; z = xz / x; } } else if ( yy > zz ) { // m22 is the largest diagonal term if ( yy < epsilon ) { x = 0.707106781; y = 0; z = 0.707106781; } else { y = Math.sqrt( yy ); x = xy / y; z = yz / y; } } else { // m33 is the largest diagonal term so base result on this if ( zz < epsilon ) { x = 0.707106781; y = 0.707106781; z = 0; } else { z = Math.sqrt( zz ); x = xz / z; y = yz / z; } } this.set( x, y, z, angle ); return this; // return 180 deg rotation } // as we have reached here there are no singularities so we can handle normally var s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) + ( m13 - m31 ) * ( m13 - m31 ) + ( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize if ( Math.abs( s ) < 0.001 ) s = 1; // prevent divide by zero, should not happen if matrix is orthogonal and should be // caught by singularity test above, but I've left it in just in case this.x = ( m32 - m23 ) / s; this.y = ( m13 - m31 ) / s; this.z = ( m21 - m12 ) / s; this.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 ); return this; }, min: function ( v ) { if ( this.x > v.x ) { this.x = v.x; } if ( this.y > v.y ) { this.y = v.y; } if ( this.z > v.z ) { this.z = v.z; } if ( this.w > v.w ) { this.w = v.w; } return this; }, max: function ( v ) { if ( this.x < v.x ) { this.x = v.x; } if ( this.y < v.y ) { this.y = v.y; } if ( this.z < v.z ) { this.z = v.z; } if ( this.w < v.w ) { this.w = v.w; } return this; }, clamp: function ( min, max ) { // This function assumes min < max, if this assumption isn't true it will not operate correctly if ( this.x < min.x ) { this.x = min.x; } else if ( this.x > max.x ) { this.x = max.x; } if ( this.y < min.y ) { this.y = min.y; } else if ( this.y > max.y ) { this.y = max.y; } if ( this.z < min.z ) { this.z = min.z; } else if ( this.z > max.z ) { this.z = max.z; } if ( this.w < min.w ) { this.w = min.w; } else if ( this.w > max.w ) { this.w = max.w; } return this; }, clampScalar: ( function () { var min, max; return function ( minVal, maxVal ) { if ( min === undefined ) { min = new THREE.Vector4(); max = new THREE.Vector4(); } min.set( minVal, minVal, minVal, minVal ); max.set( maxVal, maxVal, maxVal, maxVal ); return this.clamp( min, max ); }; } )(), floor: function () { this.x = Math.floor( this.x ); this.y = Math.floor( this.y ); this.z = Math.floor( this.z ); this.w = Math.floor( this.w ); return this; }, ceil: function () { this.x = Math.ceil( this.x ); this.y = Math.ceil( this.y ); this.z = Math.ceil( this.z ); this.w = Math.ceil( this.w ); return this; }, round: function () { this.x = Math.round( this.x ); this.y = Math.round( this.y ); this.z = Math.round( this.z ); this.w = Math.round( this.w ); return this; }, roundToZero: function () { this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x ); this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y ); this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z ); this.w = ( this.w < 0 ) ? Math.ceil( this.w ) : Math.floor( this.w ); return this; }, negate: function () { return this.multiplyScalar( -1 ); }, dot: function ( v ) { return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w; }, lengthSq: function () { return this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w; }, length: function () { return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w ); }, lengthManhattan: function () { return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w ); }, normalize: function () { return this.divideScalar( this.length() ); }, setLength: function ( l ) { var oldLength = this.length(); if ( oldLength !== 0 && l !== oldLength ) { this.multiplyScalar( l / oldLength ); } return this; }, lerp: function ( v, alpha ) { this.x += ( v.x - this.x ) * alpha; this.y += ( v.y - this.y ) * alpha; this.z += ( v.z - this.z ) * alpha; this.w += ( v.w - this.w ) * alpha; return this; }, equals: function ( v ) { return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) ); }, fromArray: function ( array ) { this.x = array[ 0 ]; this.y = array[ 1 ]; this.z = array[ 2 ]; this.w = array[ 3 ]; return this; }, toArray: function () { return [ this.x, this.y, this.z, this.w ]; }, clone: function () { return new THREE.Vector4( this.x, this.y, this.z, this.w ); } }; /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley * @author bhouston / http://exocortex.com */ THREE.Euler = function ( x, y, z, order ) { this._x = x || 0; this._y = y || 0; this._z = z || 0; this._order = order || THREE.Euler.DefaultOrder; }; THREE.Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ]; THREE.Euler.DefaultOrder = 'XYZ'; THREE.Euler.prototype = { constructor: THREE.Euler, _x: 0, _y: 0, _z: 0, _order: THREE.Euler.DefaultOrder, _quaternion: undefined, _updateQuaternion: function () { if ( this._quaternion !== undefined ) { this._quaternion.setFromEuler( this, false ); } }, get x () { return this._x; }, set x ( value ) { this._x = value; this._updateQuaternion(); }, get y () { return this._y; }, set y ( value ) { this._y = value; this._updateQuaternion(); }, get z () { return this._z; }, set z ( value ) { this._z = value; this._updateQuaternion(); }, get order () { return this._order; }, set order ( value ) { this._order = value; this._updateQuaternion(); }, set: function ( x, y, z, order ) { this._x = x; this._y = y; this._z = z; this._order = order || this._order; this._updateQuaternion(); return this; }, copy: function ( euler ) { this._x = euler._x; this._y = euler._y; this._z = euler._z; this._order = euler._order; this._updateQuaternion(); return this; }, setFromVector: function( v, order ) { this._x = v.x; this._y = v.y; this._z = v.z; this._order = order || this._order; this._updateQuaternion(); return this; }, setFromRotationMatrix: function ( m, order ) { // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) // clamp, to handle numerical problems function clamp( x ) { return Math.min( Math.max( x, -1 ), 1 ); } var te = m.elements; var m11 = te[0], m12 = te[4], m13 = te[8]; var m21 = te[1], m22 = te[5], m23 = te[9]; var m31 = te[2], m32 = te[6], m33 = te[10]; order = order || this._order; if ( order === 'XYZ' ) { this._y = Math.asin( clamp( m13 ) ); if ( Math.abs( m13 ) < 0.99999 ) { this._x = Math.atan2( - m23, m33 ); this._z = Math.atan2( - m12, m11 ); } else { this._x = Math.atan2( m32, m22 ); this._z = 0; } } else if ( order === 'YXZ' ) { this._x = Math.asin( - clamp( m23 ) ); if ( Math.abs( m23 ) < 0.99999 ) { this._y = Math.atan2( m13, m33 ); this._z = Math.atan2( m21, m22 ); } else { this._y = Math.atan2( - m31, m11 ); this._z = 0; } } else if ( order === 'ZXY' ) { this._x = Math.asin( clamp( m32 ) ); if ( Math.abs( m32 ) < 0.99999 ) { this._y = Math.atan2( - m31, m33 ); this._z = Math.atan2( - m12, m22 ); } else { this._y = 0; this._z = Math.atan2( m21, m11 ); } } else if ( order === 'ZYX' ) { this._y = Math.asin( - clamp( m31 ) ); if ( Math.abs( m31 ) < 0.99999 ) { this._x = Math.atan2( m32, m33 ); this._z = Math.atan2( m21, m11 ); } else { this._x = 0; this._z = Math.atan2( - m12, m22 ); } } else if ( order === 'YZX' ) { this._z = Math.asin( clamp( m21 ) ); if ( Math.abs( m21 ) < 0.99999 ) { this._x = Math.atan2( - m23, m22 ); this._y = Math.atan2( - m31, m11 ); } else { this._x = 0; this._y = Math.atan2( m13, m33 ); } } else if ( order === 'XZY' ) { this._z = Math.asin( - clamp( m12 ) ); if ( Math.abs( m12 ) < 0.99999 ) { this._x = Math.atan2( m32, m22 ); this._y = Math.atan2( m13, m11 ); } else { this._x = Math.atan2( - m23, m33 ); this._y = 0; } } else { console.warn( 'WARNING: Euler.setFromRotationMatrix() given unsupported order: ' + order ) } this._order = order; this._updateQuaternion(); return this; }, setFromQuaternion: function ( q, order, update ) { // q is assumed to be normalized // clamp, to handle numerical problems function clamp( x ) { return Math.min( Math.max( x, -1 ), 1 ); } // http://www.mathworks.com/matlabcentral/fileexchange/20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/content/SpinCalc.m var sqx = q.x * q.x; var sqy = q.y * q.y; var sqz = q.z * q.z; var sqw = q.w * q.w; order = order || this._order; if ( order === 'XYZ' ) { this._x = Math.atan2( 2 * ( q.x * q.w - q.y * q.z ), ( sqw - sqx - sqy + sqz ) ); this._y = Math.asin( clamp( 2 * ( q.x * q.z + q.y * q.w ) ) ); this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw + sqx - sqy - sqz ) ); } else if ( order === 'YXZ' ) { this._x = Math.asin( clamp( 2 * ( q.x * q.w - q.y * q.z ) ) ); this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw - sqx - sqy + sqz ) ); this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw - sqx + sqy - sqz ) ); } else if ( order === 'ZXY' ) { this._x = Math.asin( clamp( 2 * ( q.x * q.w + q.y * q.z ) ) ); this._y = Math.atan2( 2 * ( q.y * q.w - q.z * q.x ), ( sqw - sqx - sqy + sqz ) ); this._z = Math.atan2( 2 * ( q.z * q.w - q.x * q.y ), ( sqw - sqx + sqy - sqz ) ); } else if ( order === 'ZYX' ) { this._x = Math.atan2( 2 * ( q.x * q.w + q.z * q.y ), ( sqw - sqx - sqy + sqz ) ); this._y = Math.asin( clamp( 2 * ( q.y * q.w - q.x * q.z ) ) ); this._z = Math.atan2( 2 * ( q.x * q.y + q.z * q.w ), ( sqw + sqx - sqy - sqz ) ); } else if ( order === 'YZX' ) { this._x = Math.atan2( 2 * ( q.x * q.w - q.z * q.y ), ( sqw - sqx + sqy - sqz ) ); this._y = Math.atan2( 2 * ( q.y * q.w - q.x * q.z ), ( sqw + sqx - sqy - sqz ) ); this._z = Math.asin( clamp( 2 * ( q.x * q.y + q.z * q.w ) ) ); } else if ( order === 'XZY' ) { this._x = Math.atan2( 2 * ( q.x * q.w + q.y * q.z ), ( sqw - sqx + sqy - sqz ) ); this._y = Math.atan2( 2 * ( q.x * q.z + q.y * q.w ), ( sqw + sqx - sqy - sqz ) ); this._z = Math.asin( clamp( 2 * ( q.z * q.w - q.x * q.y ) ) ); } else { console.warn( 'WARNING: Euler.setFromQuaternion() given unsupported order: ' + order ) } this._order = order; if ( update !== false ) this._updateQuaternion(); return this; }, reorder: function () { // WARNING: this discards revolution information -bhouston var q = new THREE.Quaternion(); return function ( newOrder ) { q.setFromEuler( this ); this.setFromQuaternion( q, newOrder ); }; }(), fromArray: function ( array ) { this._x = array[ 0 ]; this._y = array[ 1 ]; this._z = array[ 2 ]; if ( array[ 3 ] !== undefined ) this._order = array[ 3 ]; this._updateQuaternion(); return this; }, toArray: function () { return [ this._x, this._y, this._z, this._order ]; }, equals: function ( euler ) { return ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order ); }, clone: function () { return new THREE.Euler( this._x, this._y, this._z, this._order ); } }; /** * @author bhouston / http://exocortex.com */ THREE.Line3 = function ( start, end ) { this.start = ( start !== undefined ) ? start : new THREE.Vector3(); this.end = ( end !== undefined ) ? end : new THREE.Vector3(); }; THREE.Line3.prototype = { constructor: THREE.Line3, set: function ( start, end ) { this.start.copy( start ); this.end.copy( end ); return this; }, copy: function ( line ) { this.start.copy( line.start ); this.end.copy( line.end ); return this; }, center: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.addVectors( this.start, this.end ).multiplyScalar( 0.5 ); }, delta: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.subVectors( this.end, this.start ); }, distanceSq: function () { return this.start.distanceToSquared( this.end ); }, distance: function () { return this.start.distanceTo( this.end ); }, at: function ( t, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return this.delta( result ).multiplyScalar( t ).add( this.start ); }, closestPointToPointParameter: function() { var startP = new THREE.Vector3(); var startEnd = new THREE.Vector3(); return function ( point, clampToLine ) { startP.subVectors( point, this.start ); startEnd.subVectors( this.end, this.start ); var startEnd2 = startEnd.dot( startEnd ); var startEnd_startP = startEnd.dot( startP ); var t = startEnd_startP / startEnd2; if ( clampToLine ) { t = THREE.Math.clamp( t, 0, 1 ); } return t; }; }(), closestPointToPoint: function ( point, clampToLine, optionalTarget ) { var t = this.closestPointToPointParameter( point, clampToLine ); var result = optionalTarget || new THREE.Vector3(); return this.delta( result ).multiplyScalar( t ).add( this.start ); }, applyMatrix4: function ( matrix ) { this.start.applyMatrix4( matrix ); this.end.applyMatrix4( matrix ); return this; }, equals: function ( line ) { return line.start.equals( this.start ) && line.end.equals( this.end ); }, clone: function () { return new THREE.Line3().copy( this ); } }; /** * @author bhouston / http://exocortex.com */ THREE.Box2 = function ( min, max ) { this.min = ( min !== undefined ) ? min : new THREE.Vector2( Infinity, Infinity ); this.max = ( max !== undefined ) ? max : new THREE.Vector2( -Infinity, -Infinity ); }; THREE.Box2.prototype = { constructor: THREE.Box2, set: function ( min, max ) { this.min.copy( min ); this.max.copy( max ); return this; }, setFromPoints: function ( points ) { if ( points.length > 0 ) { var point = points[ 0 ]; this.min.copy( point ); this.max.copy( point ); for ( var i = 1, il = points.length; i < il; i ++ ) { point = points[ i ]; if ( point.x < this.min.x ) { this.min.x = point.x; } else if ( point.x > this.max.x ) { this.max.x = point.x; } if ( point.y < this.min.y ) { this.min.y = point.y; } else if ( point.y > this.max.y ) { this.max.y = point.y; } } } else { this.makeEmpty(); } return this; }, setFromCenterAndSize: function () { var v1 = new THREE.Vector2(); return function ( center, size ) { var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); this.min.copy( center ).sub( halfSize ); this.max.copy( center ).add( halfSize ); return this; }; }(), copy: function ( box ) { this.min.copy( box.min ); this.max.copy( box.max ); return this; }, makeEmpty: function () { this.min.x = this.min.y = Infinity; this.max.x = this.max.y = -Infinity; return this; }, empty: function () { // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ); }, center: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector2(); return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); }, size: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector2(); return result.subVectors( this.max, this.min ); }, expandByPoint: function ( point ) { this.min.min( point ); this.max.max( point ); return this; }, expandByVector: function ( vector ) { this.min.sub( vector ); this.max.add( vector ); return this; }, expandByScalar: function ( scalar ) { this.min.addScalar( -scalar ); this.max.addScalar( scalar ); return this; }, containsPoint: function ( point ) { if ( point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y ) { return false; } return true; }, containsBox: function ( box ) { if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) ) { return true; } return false; }, getParameter: function ( point, optionalTarget ) { // This can potentially have a divide by zero if the box // has a size dimension of 0. var result = optionalTarget || new THREE.Vector2(); return result.set( ( point.x - this.min.x ) / ( this.max.x - this.min.x ), ( point.y - this.min.y ) / ( this.max.y - this.min.y ) ); }, isIntersectionBox: function ( box ) { // using 6 splitting planes to rule out intersections. if ( box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y ) { return false; } return true; }, clampPoint: function ( point, optionalTarget ) { var result = optionalTarget || new THREE.Vector2(); return result.copy( point ).clamp( this.min, this.max ); }, distanceToPoint: function () { var v1 = new THREE.Vector2(); return function ( point ) { var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); return clampedPoint.sub( point ).length(); }; }(), intersect: function ( box ) { this.min.max( box.min ); this.max.min( box.max ); return this; }, union: function ( box ) { this.min.min( box.min ); this.max.max( box.max ); return this; }, translate: function ( offset ) { this.min.add( offset ); this.max.add( offset ); return this; }, equals: function ( box ) { return box.min.equals( this.min ) && box.max.equals( this.max ); }, clone: function () { return new THREE.Box2().copy( this ); } }; /** * @author bhouston / http://exocortex.com * @author WestLangley / http://github.com/WestLangley */ THREE.Box3 = function ( min, max ) { this.min = ( min !== undefined ) ? min : new THREE.Vector3( Infinity, Infinity, Infinity ); this.max = ( max !== undefined ) ? max : new THREE.Vector3( -Infinity, -Infinity, -Infinity ); }; THREE.Box3.prototype = { constructor: THREE.Box3, set: function ( min, max ) { this.min.copy( min ); this.max.copy( max ); return this; }, addPoint: function ( point ) { if ( point.x < this.min.x ) { this.min.x = point.x; } else if ( point.x > this.max.x ) { this.max.x = point.x; } if ( point.y < this.min.y ) { this.min.y = point.y; } else if ( point.y > this.max.y ) { this.max.y = point.y; } if ( point.z < this.min.z ) { this.min.z = point.z; } else if ( point.z > this.max.z ) { this.max.z = point.z; } }, setFromPoints: function ( points ) { if ( points.length > 0 ) { var point = points[ 0 ]; this.min.copy( point ); this.max.copy( point ); for ( var i = 1, il = points.length; i < il; i ++ ) { this.addPoint( points[ i ] ) } } else { this.makeEmpty(); } return this; }, setFromCenterAndSize: function() { var v1 = new THREE.Vector3(); return function ( center, size ) { var halfSize = v1.copy( size ).multiplyScalar( 0.5 ); this.min.copy( center ).sub( halfSize ); this.max.copy( center ).add( halfSize ); return this; }; }(), setFromObject: function() { // Computes the world-axis-aligned bounding box of an object (including its children), // accounting for both the object's, and childrens', world transforms var v1 = new THREE.Vector3(); return function( object ) { var scope = this; object.updateMatrixWorld( true ); this.makeEmpty(); object.traverse( function ( node ) { if ( node.geometry !== undefined && node.geometry.vertices !== undefined ) { var vertices = node.geometry.vertices; for ( var i = 0, il = vertices.length; i < il; i++ ) { v1.copy( vertices[ i ] ); v1.applyMatrix4( node.matrixWorld ); scope.expandByPoint( v1 ); } } } ); return this; }; }(), copy: function ( box ) { this.min.copy( box.min ); this.max.copy( box.max ); return this; }, makeEmpty: function () { this.min.x = this.min.y = this.min.z = Infinity; this.max.x = this.max.y = this.max.z = -Infinity; return this; }, empty: function () { // this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes return ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z ); }, center: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.addVectors( this.min, this.max ).multiplyScalar( 0.5 ); }, size: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.subVectors( this.max, this.min ); }, expandByPoint: function ( point ) { this.min.min( point ); this.max.max( point ); return this; }, expandByVector: function ( vector ) { this.min.sub( vector ); this.max.add( vector ); return this; }, expandByScalar: function ( scalar ) { this.min.addScalar( -scalar ); this.max.addScalar( scalar ); return this; }, containsPoint: function ( point ) { if ( point.x < this.min.x || point.x > this.max.x || point.y < this.min.y || point.y > this.max.y || point.z < this.min.z || point.z > this.max.z ) { return false; } return true; }, containsBox: function ( box ) { if ( ( this.min.x <= box.min.x ) && ( box.max.x <= this.max.x ) && ( this.min.y <= box.min.y ) && ( box.max.y <= this.max.y ) && ( this.min.z <= box.min.z ) && ( box.max.z <= this.max.z ) ) { return true; } return false; }, getParameter: function ( point, optionalTarget ) { // This can potentially have a divide by zero if the box // has a size dimension of 0. var result = optionalTarget || new THREE.Vector3(); return result.set( ( point.x - this.min.x ) / ( this.max.x - this.min.x ), ( point.y - this.min.y ) / ( this.max.y - this.min.y ), ( point.z - this.min.z ) / ( this.max.z - this.min.z ) ); }, isIntersectionBox: function ( box ) { // using 6 splitting planes to rule out intersections. if ( box.max.x < this.min.x || box.min.x > this.max.x || box.max.y < this.min.y || box.min.y > this.max.y || box.max.z < this.min.z || box.min.z > this.max.z ) { return false; } return true; }, clampPoint: function ( point, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.copy( point ).clamp( this.min, this.max ); }, distanceToPoint: function() { var v1 = new THREE.Vector3(); return function ( point ) { var clampedPoint = v1.copy( point ).clamp( this.min, this.max ); return clampedPoint.sub( point ).length(); }; }(), getBoundingSphere: function() { var v1 = new THREE.Vector3(); return function ( optionalTarget ) { var result = optionalTarget || new THREE.Sphere(); result.center = this.center(); result.radius = this.size( v1 ).length() * 0.5; return result; }; }(), intersect: function ( box ) { this.min.max( box.min ); this.max.min( box.max ); return this; }, union: function ( box ) { this.min.min( box.min ); this.max.max( box.max ); return this; }, applyMatrix4: function() { var points = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; return function ( matrix ) { // NOTE: I am using a binary pattern to specify all 2^3 combinations below points[0].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000 points[1].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001 points[2].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010 points[3].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011 points[4].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100 points[5].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101 points[6].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110 points[7].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111 this.makeEmpty(); this.setFromPoints( points ); return this; }; }(), translate: function ( offset ) { this.min.add( offset ); this.max.add( offset ); return this; }, equals: function ( box ) { return box.min.equals( this.min ) && box.max.equals( this.max ); }, clone: function () { return new THREE.Box3().copy( this ); } }; /** * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley * @author bhouston / http://exocortex.com */ THREE.Matrix3 = function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { this.elements = new Float32Array(9); this.set( ( n11 !== undefined ) ? n11 : 1, n12 || 0, n13 || 0, n21 || 0, ( n22 !== undefined ) ? n22 : 1, n23 || 0, n31 || 0, n32 || 0, ( n33 !== undefined ) ? n33 : 1 ); }; THREE.Matrix3.prototype = { constructor: THREE.Matrix3, set: function ( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) { var te = this.elements; te[0] = n11; te[3] = n12; te[6] = n13; te[1] = n21; te[4] = n22; te[7] = n23; te[2] = n31; te[5] = n32; te[8] = n33; return this; }, identity: function () { this.set( 1, 0, 0, 0, 1, 0, 0, 0, 1 ); return this; }, copy: function ( m ) { var me = m.elements; this.set( me[0], me[3], me[6], me[1], me[4], me[7], me[2], me[5], me[8] ); return this; }, multiplyVector3: function ( vector ) { console.warn( 'DEPRECATED: Matrix3\'s .multiplyVector3() has been removed. Use vector.applyMatrix3( matrix ) instead.' ); return vector.applyMatrix3( this ); }, multiplyVector3Array: function() { var v1 = new THREE.Vector3(); return function ( a ) { for ( var i = 0, il = a.length; i < il; i += 3 ) { v1.x = a[ i ]; v1.y = a[ i + 1 ]; v1.z = a[ i + 2 ]; v1.applyMatrix3(this); a[ i ] = v1.x; a[ i + 1 ] = v1.y; a[ i + 2 ] = v1.z; } return a; }; }(), multiplyScalar: function ( s ) { var te = this.elements; te[0] *= s; te[3] *= s; te[6] *= s; te[1] *= s; te[4] *= s; te[7] *= s; te[2] *= s; te[5] *= s; te[8] *= s; return this; }, determinant: function () { var te = this.elements; var a = te[0], b = te[1], c = te[2], d = te[3], e = te[4], f = te[5], g = te[6], h = te[7], i = te[8]; return a*e*i - a*f*h - b*d*i + b*f*g + c*d*h - c*e*g; }, getInverse: function ( matrix, throwOnInvertible ) { // input: THREE.Matrix4 // ( based on http://code.google.com/p/webgl-mjs/ ) var me = matrix.elements; var te = this.elements; te[ 0 ] = me[10] * me[5] - me[6] * me[9]; te[ 1 ] = - me[10] * me[1] + me[2] * me[9]; te[ 2 ] = me[6] * me[1] - me[2] * me[5]; te[ 3 ] = - me[10] * me[4] + me[6] * me[8]; te[ 4 ] = me[10] * me[0] - me[2] * me[8]; te[ 5 ] = - me[6] * me[0] + me[2] * me[4]; te[ 6 ] = me[9] * me[4] - me[5] * me[8]; te[ 7 ] = - me[9] * me[0] + me[1] * me[8]; te[ 8 ] = me[5] * me[0] - me[1] * me[4]; var det = me[ 0 ] * te[ 0 ] + me[ 1 ] * te[ 3 ] + me[ 2 ] * te[ 6 ]; // no inverse if ( det === 0 ) { var msg = "Matrix3.getInverse(): can't invert matrix, determinant is 0"; if ( throwOnInvertible || false ) { throw new Error( msg ); } else { console.warn( msg ); } this.identity(); return this; } this.multiplyScalar( 1.0 / det ); return this; }, transpose: function () { var tmp, m = this.elements; tmp = m[1]; m[1] = m[3]; m[3] = tmp; tmp = m[2]; m[2] = m[6]; m[6] = tmp; tmp = m[5]; m[5] = m[7]; m[7] = tmp; return this; }, getNormalMatrix: function ( m ) { // input: THREE.Matrix4 this.getInverse( m ).transpose(); return this; }, transposeIntoArray: function ( r ) { var m = this.elements; r[ 0 ] = m[ 0 ]; r[ 1 ] = m[ 3 ]; r[ 2 ] = m[ 6 ]; r[ 3 ] = m[ 1 ]; r[ 4 ] = m[ 4 ]; r[ 5 ] = m[ 7 ]; r[ 6 ] = m[ 2 ]; r[ 7 ] = m[ 5 ]; r[ 8 ] = m[ 8 ]; return this; }, fromArray: function ( array ) { this.elements.set( array ); return this; }, toArray: function () { var te = this.elements; return [ te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], te[ 8 ] ]; }, clone: function () { var te = this.elements; return new THREE.Matrix3( te[0], te[3], te[6], te[1], te[4], te[7], te[2], te[5], te[8] ); } }; /** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ * @author philogb / http://blog.thejit.org/ * @author jordi_ros / http://plattsoft.com * @author D1plo1d / http://github.com/D1plo1d * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author timknip / http://www.floorplanner.com/ * @author bhouston / http://exocortex.com * @author WestLangley / http://github.com/WestLangley */ THREE.Matrix4 = function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { this.elements = new Float32Array( 16 ); // TODO: if n11 is undefined, then just set to identity, otherwise copy all other values into matrix // we should not support semi specification of Matrix4, it is just weird. var te = this.elements; te[0] = ( n11 !== undefined ) ? n11 : 1; te[4] = n12 || 0; te[8] = n13 || 0; te[12] = n14 || 0; te[1] = n21 || 0; te[5] = ( n22 !== undefined ) ? n22 : 1; te[9] = n23 || 0; te[13] = n24 || 0; te[2] = n31 || 0; te[6] = n32 || 0; te[10] = ( n33 !== undefined ) ? n33 : 1; te[14] = n34 || 0; te[3] = n41 || 0; te[7] = n42 || 0; te[11] = n43 || 0; te[15] = ( n44 !== undefined ) ? n44 : 1; }; THREE.Matrix4.prototype = { constructor: THREE.Matrix4, set: function ( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) { var te = this.elements; te[0] = n11; te[4] = n12; te[8] = n13; te[12] = n14; te[1] = n21; te[5] = n22; te[9] = n23; te[13] = n24; te[2] = n31; te[6] = n32; te[10] = n33; te[14] = n34; te[3] = n41; te[7] = n42; te[11] = n43; te[15] = n44; return this; }, identity: function () { this.set( 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); return this; }, copy: function ( m ) { this.elements.set( m.elements ); return this; }, extractPosition: function ( m ) { console.warn( 'DEPRECATED: Matrix4\'s .extractPosition() has been renamed to .copyPosition().' ); return this.copyPosition( m ); }, copyPosition: function ( m ) { var te = this.elements; var me = m.elements; te[12] = me[12]; te[13] = me[13]; te[14] = me[14]; return this; }, extractRotation: function () { var v1 = new THREE.Vector3(); return function ( m ) { var te = this.elements; var me = m.elements; var scaleX = 1 / v1.set( me[0], me[1], me[2] ).length(); var scaleY = 1 / v1.set( me[4], me[5], me[6] ).length(); var scaleZ = 1 / v1.set( me[8], me[9], me[10] ).length(); te[0] = me[0] * scaleX; te[1] = me[1] * scaleX; te[2] = me[2] * scaleX; te[4] = me[4] * scaleY; te[5] = me[5] * scaleY; te[6] = me[6] * scaleY; te[8] = me[8] * scaleZ; te[9] = me[9] * scaleZ; te[10] = me[10] * scaleZ; return this; }; }(), makeRotationFromEuler: function ( euler ) { if ( euler instanceof THREE.Euler === false ) { console.error( 'ERROR: Matrix\'s .makeRotationFromEuler() now expects a Euler rotation rather than a Vector3 and order. Please update your code.' ); } var te = this.elements; var x = euler.x, y = euler.y, z = euler.z; var a = Math.cos( x ), b = Math.sin( x ); var c = Math.cos( y ), d = Math.sin( y ); var e = Math.cos( z ), f = Math.sin( z ); if ( euler.order === 'XYZ' ) { var ae = a * e, af = a * f, be = b * e, bf = b * f; te[0] = c * e; te[4] = - c * f; te[8] = d; te[1] = af + be * d; te[5] = ae - bf * d; te[9] = - b * c; te[2] = bf - ae * d; te[6] = be + af * d; te[10] = a * c; } else if ( euler.order === 'YXZ' ) { var ce = c * e, cf = c * f, de = d * e, df = d * f; te[0] = ce + df * b; te[4] = de * b - cf; te[8] = a * d; te[1] = a * f; te[5] = a * e; te[9] = - b; te[2] = cf * b - de; te[6] = df + ce * b; te[10] = a * c; } else if ( euler.order === 'ZXY' ) { var ce = c * e, cf = c * f, de = d * e, df = d * f; te[0] = ce - df * b; te[4] = - a * f; te[8] = de + cf * b; te[1] = cf + de * b; te[5] = a * e; te[9] = df - ce * b; te[2] = - a * d; te[6] = b; te[10] = a * c; } else if ( euler.order === 'ZYX' ) { var ae = a * e, af = a * f, be = b * e, bf = b * f; te[0] = c * e; te[4] = be * d - af; te[8] = ae * d + bf; te[1] = c * f; te[5] = bf * d + ae; te[9] = af * d - be; te[2] = - d; te[6] = b * c; te[10] = a * c; } else if ( euler.order === 'YZX' ) { var ac = a * c, ad = a * d, bc = b * c, bd = b * d; te[0] = c * e; te[4] = bd - ac * f; te[8] = bc * f + ad; te[1] = f; te[5] = a * e; te[9] = - b * e; te[2] = - d * e; te[6] = ad * f + bc; te[10] = ac - bd * f; } else if ( euler.order === 'XZY' ) { var ac = a * c, ad = a * d, bc = b * c, bd = b * d; te[0] = c * e; te[4] = - f; te[8] = d * e; te[1] = ac * f + bd; te[5] = a * e; te[9] = ad * f - bc; te[2] = bc * f - ad; te[6] = b * e; te[10] = bd * f + ac; } // last column te[3] = 0; te[7] = 0; te[11] = 0; // bottom row te[12] = 0; te[13] = 0; te[14] = 0; te[15] = 1; return this; }, setRotationFromQuaternion: function ( q ) { console.warn( 'DEPRECATED: Matrix4\'s .setRotationFromQuaternion() has been deprecated in favor of makeRotationFromQuaternion. Please update your code.' ); return this.makeRotationFromQuaternion( q ); }, makeRotationFromQuaternion: function ( q ) { var te = this.elements; var x = q.x, y = q.y, z = q.z, w = q.w; var x2 = x + x, y2 = y + y, z2 = z + z; var xx = x * x2, xy = x * y2, xz = x * z2; var yy = y * y2, yz = y * z2, zz = z * z2; var wx = w * x2, wy = w * y2, wz = w * z2; te[0] = 1 - ( yy + zz ); te[4] = xy - wz; te[8] = xz + wy; te[1] = xy + wz; te[5] = 1 - ( xx + zz ); te[9] = yz - wx; te[2] = xz - wy; te[6] = yz + wx; te[10] = 1 - ( xx + yy ); // last column te[3] = 0; te[7] = 0; te[11] = 0; // bottom row te[12] = 0; te[13] = 0; te[14] = 0; te[15] = 1; return this; }, lookAt: function() { var x = new THREE.Vector3(); var y = new THREE.Vector3(); var z = new THREE.Vector3(); return function ( eye, target, up ) { var te = this.elements; z.subVectors( eye, target ).normalize(); if ( z.length() === 0 ) { z.z = 1; } x.crossVectors( up, z ).normalize(); if ( x.length() === 0 ) { z.x += 0.0001; x.crossVectors( up, z ).normalize(); } y.crossVectors( z, x ); te[0] = x.x; te[4] = y.x; te[8] = z.x; te[1] = x.y; te[5] = y.y; te[9] = z.y; te[2] = x.z; te[6] = y.z; te[10] = z.z; return this; }; }(), multiply: function ( m, n ) { if ( n !== undefined ) { console.warn( 'DEPRECATED: Matrix4\'s .multiply() now only accepts one argument. Use .multiplyMatrices( a, b ) instead.' ); return this.multiplyMatrices( m, n ); } return this.multiplyMatrices( this, m ); }, multiplyMatrices: function ( a, b ) { var ae = a.elements; var be = b.elements; var te = this.elements; var a11 = ae[0], a12 = ae[4], a13 = ae[8], a14 = ae[12]; var a21 = ae[1], a22 = ae[5], a23 = ae[9], a24 = ae[13]; var a31 = ae[2], a32 = ae[6], a33 = ae[10], a34 = ae[14]; var a41 = ae[3], a42 = ae[7], a43 = ae[11], a44 = ae[15]; var b11 = be[0], b12 = be[4], b13 = be[8], b14 = be[12]; var b21 = be[1], b22 = be[5], b23 = be[9], b24 = be[13]; var b31 = be[2], b32 = be[6], b33 = be[10], b34 = be[14]; var b41 = be[3], b42 = be[7], b43 = be[11], b44 = be[15]; te[0] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41; te[4] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42; te[8] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43; te[12] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44; te[1] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41; te[5] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42; te[9] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43; te[13] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44; te[2] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41; te[6] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42; te[10] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43; te[14] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44; te[3] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41; te[7] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42; te[11] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43; te[15] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44; return this; }, multiplyToArray: function ( a, b, r ) { var te = this.elements; this.multiplyMatrices( a, b ); r[ 0 ] = te[0]; r[ 1 ] = te[1]; r[ 2 ] = te[2]; r[ 3 ] = te[3]; r[ 4 ] = te[4]; r[ 5 ] = te[5]; r[ 6 ] = te[6]; r[ 7 ] = te[7]; r[ 8 ] = te[8]; r[ 9 ] = te[9]; r[ 10 ] = te[10]; r[ 11 ] = te[11]; r[ 12 ] = te[12]; r[ 13 ] = te[13]; r[ 14 ] = te[14]; r[ 15 ] = te[15]; return this; }, multiplyScalar: function ( s ) { var te = this.elements; te[0] *= s; te[4] *= s; te[8] *= s; te[12] *= s; te[1] *= s; te[5] *= s; te[9] *= s; te[13] *= s; te[2] *= s; te[6] *= s; te[10] *= s; te[14] *= s; te[3] *= s; te[7] *= s; te[11] *= s; te[15] *= s; return this; }, multiplyVector3: function ( vector ) { console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector3() has been removed. Use vector.applyMatrix4( matrix ) or vector.applyProjection( matrix ) instead.' ); return vector.applyProjection( this ); }, multiplyVector4: function ( vector ) { console.warn( 'DEPRECATED: Matrix4\'s .multiplyVector4() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, multiplyVector3Array: function() { var v1 = new THREE.Vector3(); return function ( a ) { for ( var i = 0, il = a.length; i < il; i += 3 ) { v1.x = a[ i ]; v1.y = a[ i + 1 ]; v1.z = a[ i + 2 ]; v1.applyProjection( this ); a[ i ] = v1.x; a[ i + 1 ] = v1.y; a[ i + 2 ] = v1.z; } return a; }; }(), rotateAxis: function ( v ) { console.warn( 'DEPRECATED: Matrix4\'s .rotateAxis() has been removed. Use Vector3.transformDirection( matrix ) instead.' ); v.transformDirection( this ); }, crossVector: function ( vector ) { console.warn( 'DEPRECATED: Matrix4\'s .crossVector() has been removed. Use vector.applyMatrix4( matrix ) instead.' ); return vector.applyMatrix4( this ); }, determinant: function () { var te = this.elements; var n11 = te[0], n12 = te[4], n13 = te[8], n14 = te[12]; var n21 = te[1], n22 = te[5], n23 = te[9], n24 = te[13]; var n31 = te[2], n32 = te[6], n33 = te[10], n34 = te[14]; var n41 = te[3], n42 = te[7], n43 = te[11], n44 = te[15]; //TODO: make this more efficient //( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm ) return ( n41 * ( +n14 * n23 * n32 -n13 * n24 * n32 -n14 * n22 * n33 +n12 * n24 * n33 +n13 * n22 * n34 -n12 * n23 * n34 ) + n42 * ( +n11 * n23 * n34 -n11 * n24 * n33 +n14 * n21 * n33 -n13 * n21 * n34 +n13 * n24 * n31 -n14 * n23 * n31 ) + n43 * ( +n11 * n24 * n32 -n11 * n22 * n34 -n14 * n21 * n32 +n12 * n21 * n34 +n14 * n22 * n31 -n12 * n24 * n31 ) + n44 * ( -n13 * n22 * n31 -n11 * n23 * n32 +n11 * n22 * n33 +n13 * n21 * n32 -n12 * n21 * n33 +n12 * n23 * n31 ) ); }, transpose: function () { var te = this.elements; var tmp; tmp = te[1]; te[1] = te[4]; te[4] = tmp; tmp = te[2]; te[2] = te[8]; te[8] = tmp; tmp = te[6]; te[6] = te[9]; te[9] = tmp; tmp = te[3]; te[3] = te[12]; te[12] = tmp; tmp = te[7]; te[7] = te[13]; te[13] = tmp; tmp = te[11]; te[11] = te[14]; te[14] = tmp; return this; }, flattenToArray: function ( flat ) { var te = this.elements; flat[ 0 ] = te[0]; flat[ 1 ] = te[1]; flat[ 2 ] = te[2]; flat[ 3 ] = te[3]; flat[ 4 ] = te[4]; flat[ 5 ] = te[5]; flat[ 6 ] = te[6]; flat[ 7 ] = te[7]; flat[ 8 ] = te[8]; flat[ 9 ] = te[9]; flat[ 10 ] = te[10]; flat[ 11 ] = te[11]; flat[ 12 ] = te[12]; flat[ 13 ] = te[13]; flat[ 14 ] = te[14]; flat[ 15 ] = te[15]; return flat; }, flattenToArrayOffset: function( flat, offset ) { var te = this.elements; flat[ offset ] = te[0]; flat[ offset + 1 ] = te[1]; flat[ offset + 2 ] = te[2]; flat[ offset + 3 ] = te[3]; flat[ offset + 4 ] = te[4]; flat[ offset + 5 ] = te[5]; flat[ offset + 6 ] = te[6]; flat[ offset + 7 ] = te[7]; flat[ offset + 8 ] = te[8]; flat[ offset + 9 ] = te[9]; flat[ offset + 10 ] = te[10]; flat[ offset + 11 ] = te[11]; flat[ offset + 12 ] = te[12]; flat[ offset + 13 ] = te[13]; flat[ offset + 14 ] = te[14]; flat[ offset + 15 ] = te[15]; return flat; }, getPosition: function() { var v1 = new THREE.Vector3(); return function () { console.warn( 'DEPRECATED: Matrix4\'s .getPosition() has been removed. Use Vector3.setFromMatrixPosition( matrix ) instead.' ); var te = this.elements; return v1.set( te[12], te[13], te[14] ); }; }(), setPosition: function ( v ) { var te = this.elements; te[12] = v.x; te[13] = v.y; te[14] = v.z; return this; }, getInverse: function ( m, throwOnInvertible ) { // based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm var te = this.elements; var me = m.elements; var n11 = me[0], n12 = me[4], n13 = me[8], n14 = me[12]; var n21 = me[1], n22 = me[5], n23 = me[9], n24 = me[13]; var n31 = me[2], n32 = me[6], n33 = me[10], n34 = me[14]; var n41 = me[3], n42 = me[7], n43 = me[11], n44 = me[15]; te[0] = n23*n34*n42 - n24*n33*n42 + n24*n32*n43 - n22*n34*n43 - n23*n32*n44 + n22*n33*n44; te[4] = n14*n33*n42 - n13*n34*n42 - n14*n32*n43 + n12*n34*n43 + n13*n32*n44 - n12*n33*n44; te[8] = n13*n24*n42 - n14*n23*n42 + n14*n22*n43 - n12*n24*n43 - n13*n22*n44 + n12*n23*n44; te[12] = n14*n23*n32 - n13*n24*n32 - n14*n22*n33 + n12*n24*n33 + n13*n22*n34 - n12*n23*n34; te[1] = n24*n33*n41 - n23*n34*n41 - n24*n31*n43 + n21*n34*n43 + n23*n31*n44 - n21*n33*n44; te[5] = n13*n34*n41 - n14*n33*n41 + n14*n31*n43 - n11*n34*n43 - n13*n31*n44 + n11*n33*n44; te[9] = n14*n23*n41 - n13*n24*n41 - n14*n21*n43 + n11*n24*n43 + n13*n21*n44 - n11*n23*n44; te[13] = n13*n24*n31 - n14*n23*n31 + n14*n21*n33 - n11*n24*n33 - n13*n21*n34 + n11*n23*n34; te[2] = n22*n34*n41 - n24*n32*n41 + n24*n31*n42 - n21*n34*n42 - n22*n31*n44 + n21*n32*n44; te[6] = n14*n32*n41 - n12*n34*n41 - n14*n31*n42 + n11*n34*n42 + n12*n31*n44 - n11*n32*n44; te[10] = n12*n24*n41 - n14*n22*n41 + n14*n21*n42 - n11*n24*n42 - n12*n21*n44 + n11*n22*n44; te[14] = n14*n22*n31 - n12*n24*n31 - n14*n21*n32 + n11*n24*n32 + n12*n21*n34 - n11*n22*n34; te[3] = n23*n32*n41 - n22*n33*n41 - n23*n31*n42 + n21*n33*n42 + n22*n31*n43 - n21*n32*n43; te[7] = n12*n33*n41 - n13*n32*n41 + n13*n31*n42 - n11*n33*n42 - n12*n31*n43 + n11*n32*n43; te[11] = n13*n22*n41 - n12*n23*n41 - n13*n21*n42 + n11*n23*n42 + n12*n21*n43 - n11*n22*n43; te[15] = n12*n23*n31 - n13*n22*n31 + n13*n21*n32 - n11*n23*n32 - n12*n21*n33 + n11*n22*n33; var det = n11 * te[ 0 ] + n21 * te[ 4 ] + n31 * te[ 8 ] + n41 * te[ 12 ]; if ( det == 0 ) { var msg = "Matrix4.getInverse(): can't invert matrix, determinant is 0"; if ( throwOnInvertible || false ) { throw new Error( msg ); } else { console.warn( msg ); } this.identity(); return this; } this.multiplyScalar( 1 / det ); return this; }, translate: function ( v ) { console.warn( 'DEPRECATED: Matrix4\'s .translate() has been removed.'); }, rotateX: function ( angle ) { console.warn( 'DEPRECATED: Matrix4\'s .rotateX() has been removed.'); }, rotateY: function ( angle ) { console.warn( 'DEPRECATED: Matrix4\'s .rotateY() has been removed.'); }, rotateZ: function ( angle ) { console.warn( 'DEPRECATED: Matrix4\'s .rotateZ() has been removed.'); }, rotateByAxis: function ( axis, angle ) { console.warn( 'DEPRECATED: Matrix4\'s .rotateByAxis() has been removed.'); }, scale: function ( v ) { var te = this.elements; var x = v.x, y = v.y, z = v.z; te[0] *= x; te[4] *= y; te[8] *= z; te[1] *= x; te[5] *= y; te[9] *= z; te[2] *= x; te[6] *= y; te[10] *= z; te[3] *= x; te[7] *= y; te[11] *= z; return this; }, getMaxScaleOnAxis: function () { var te = this.elements; var scaleXSq = te[0] * te[0] + te[1] * te[1] + te[2] * te[2]; var scaleYSq = te[4] * te[4] + te[5] * te[5] + te[6] * te[6]; var scaleZSq = te[8] * te[8] + te[9] * te[9] + te[10] * te[10]; return Math.sqrt( Math.max( scaleXSq, Math.max( scaleYSq, scaleZSq ) ) ); }, makeTranslation: function ( x, y, z ) { this.set( 1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, z, 0, 0, 0, 1 ); return this; }, makeRotationX: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( 1, 0, 0, 0, 0, c, -s, 0, 0, s, c, 0, 0, 0, 0, 1 ); return this; }, makeRotationY: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( c, 0, s, 0, 0, 1, 0, 0, -s, 0, c, 0, 0, 0, 0, 1 ); return this; }, makeRotationZ: function ( theta ) { var c = Math.cos( theta ), s = Math.sin( theta ); this.set( c, -s, 0, 0, s, c, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1 ); return this; }, makeRotationAxis: function ( axis, angle ) { // Based on http://www.gamedev.net/reference/articles/article1199.asp var c = Math.cos( angle ); var s = Math.sin( angle ); var t = 1 - c; var x = axis.x, y = axis.y, z = axis.z; var tx = t * x, ty = t * y; this.set( tx * x + c, tx * y - s * z, tx * z + s * y, 0, tx * y + s * z, ty * y + c, ty * z - s * x, 0, tx * z - s * y, ty * z + s * x, t * z * z + c, 0, 0, 0, 0, 1 ); return this; }, makeScale: function ( x, y, z ) { this.set( x, 0, 0, 0, 0, y, 0, 0, 0, 0, z, 0, 0, 0, 0, 1 ); return this; }, compose: function ( position, quaternion, scale ) { this.makeRotationFromQuaternion( quaternion ); this.scale( scale ); this.setPosition( position ); return this; }, decompose: function () { var vector = new THREE.Vector3(); var matrix = new THREE.Matrix4(); return function ( position, quaternion, scale ) { var te = this.elements; var sx = vector.set( te[0], te[1], te[2] ).length(); var sy = vector.set( te[4], te[5], te[6] ).length(); var sz = vector.set( te[8], te[9], te[10] ).length(); // if determine is negative, we need to invert one scale var det = this.determinant(); if( det < 0 ) { sx = -sx; } position.x = te[12]; position.y = te[13]; position.z = te[14]; // scale the rotation part matrix.elements.set( this.elements ); // at this point matrix is incomplete so we can't use .copy() var invSX = 1 / sx; var invSY = 1 / sy; var invSZ = 1 / sz; matrix.elements[0] *= invSX; matrix.elements[1] *= invSX; matrix.elements[2] *= invSX; matrix.elements[4] *= invSY; matrix.elements[5] *= invSY; matrix.elements[6] *= invSY; matrix.elements[8] *= invSZ; matrix.elements[9] *= invSZ; matrix.elements[10] *= invSZ; quaternion.setFromRotationMatrix( matrix ); scale.x = sx; scale.y = sy; scale.z = sz; return this; }; }(), makeFrustum: function ( left, right, bottom, top, near, far ) { var te = this.elements; var x = 2 * near / ( right - left ); var y = 2 * near / ( top - bottom ); var a = ( right + left ) / ( right - left ); var b = ( top + bottom ) / ( top - bottom ); var c = - ( far + near ) / ( far - near ); var d = - 2 * far * near / ( far - near ); te[0] = x; te[4] = 0; te[8] = a; te[12] = 0; te[1] = 0; te[5] = y; te[9] = b; te[13] = 0; te[2] = 0; te[6] = 0; te[10] = c; te[14] = d; te[3] = 0; te[7] = 0; te[11] = - 1; te[15] = 0; return this; }, makePerspective: function ( fov, aspect, near, far ) { var ymax = near * Math.tan( THREE.Math.degToRad( fov * 0.5 ) ); var ymin = - ymax; var xmin = ymin * aspect; var xmax = ymax * aspect; return this.makeFrustum( xmin, xmax, ymin, ymax, near, far ); }, makeOrthographic: function ( left, right, top, bottom, near, far ) { var te = this.elements; var w = right - left; var h = top - bottom; var p = far - near; var x = ( right + left ) / w; var y = ( top + bottom ) / h; var z = ( far + near ) / p; te[0] = 2 / w; te[4] = 0; te[8] = 0; te[12] = -x; te[1] = 0; te[5] = 2 / h; te[9] = 0; te[13] = -y; te[2] = 0; te[6] = 0; te[10] = -2/p; te[14] = -z; te[3] = 0; te[7] = 0; te[11] = 0; te[15] = 1; return this; }, fromArray: function ( array ) { this.elements.set( array ); return this; }, toArray: function () { var te = this.elements; return [ te[ 0 ], te[ 1 ], te[ 2 ], te[ 3 ], te[ 4 ], te[ 5 ], te[ 6 ], te[ 7 ], te[ 8 ], te[ 9 ], te[ 10 ], te[ 11 ], te[ 12 ], te[ 13 ], te[ 14 ], te[ 15 ] ]; }, clone: function () { var te = this.elements; return new THREE.Matrix4( te[0], te[4], te[8], te[12], te[1], te[5], te[9], te[13], te[2], te[6], te[10], te[14], te[3], te[7], te[11], te[15] ); } }; /** * @author bhouston / http://exocortex.com */ THREE.Ray = function ( origin, direction ) { this.origin = ( origin !== undefined ) ? origin : new THREE.Vector3(); this.direction = ( direction !== undefined ) ? direction : new THREE.Vector3(); }; THREE.Ray.prototype = { constructor: THREE.Ray, set: function ( origin, direction ) { this.origin.copy( origin ); this.direction.copy( direction ); return this; }, copy: function ( ray ) { this.origin.copy( ray.origin ); this.direction.copy( ray.direction ); return this; }, at: function ( t, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.copy( this.direction ).multiplyScalar( t ).add( this.origin ); }, recast: function () { var v1 = new THREE.Vector3(); return function ( t ) { this.origin.copy( this.at( t, v1 ) ); return this; }; }(), closestPointToPoint: function ( point, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); result.subVectors( point, this.origin ); var directionDistance = result.dot( this.direction ); if ( directionDistance < 0 ) { return result.copy( this.origin ); } return result.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); }, distanceToPoint: function () { var v1 = new THREE.Vector3(); return function ( point ) { var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction ); // point behind the ray if ( directionDistance < 0 ) { return this.origin.distanceTo( point ); } v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin ); return v1.distanceTo( point ); }; }(), distanceSqToSegment: function( v0, v1, optionalPointOnRay, optionalPointOnSegment ) { // from http://www.geometrictools.com/LibMathematics/Distance/Wm5DistRay3Segment3.cpp // It returns the min distance between the ray and the segment // defined by v0 and v1 // It can also set two optional targets : // - The closest point on the ray // - The closest point on the segment var segCenter = v0.clone().add( v1 ).multiplyScalar( 0.5 ); var segDir = v1.clone().sub( v0 ).normalize(); var segExtent = v0.distanceTo( v1 ) * 0.5; var diff = this.origin.clone().sub( segCenter ); var a01 = - this.direction.dot( segDir ); var b0 = diff.dot( this.direction ); var b1 = - diff.dot( segDir ); var c = diff.lengthSq(); var det = Math.abs( 1 - a01 * a01 ); var s0, s1, sqrDist, extDet; if ( det >= 0 ) { // The ray and segment are not parallel. s0 = a01 * b1 - b0; s1 = a01 * b0 - b1; extDet = segExtent * det; if ( s0 >= 0 ) { if ( s1 >= - extDet ) { if ( s1 <= extDet ) { // region 0 // Minimum at interior points of ray and segment. var invDet = 1 / det; s0 *= invDet; s1 *= invDet; sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c; } else { // region 1 s1 = segExtent; s0 = Math.max( 0, - ( a01 * s1 + b0) ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } } else { // region 5 s1 = - segExtent; s0 = Math.max( 0, - ( a01 * s1 + b0) ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } } else { if ( s1 <= - extDet) { // region 4 s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) ); s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } else if ( s1 <= extDet ) { // region 3 s0 = 0; s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent ); sqrDist = s1 * ( s1 + 2 * b1 ) + c; } else { // region 2 s0 = Math.max( 0, - ( a01 * segExtent + b0 ) ); s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } } } else { // Ray and segment are parallel. s1 = ( a01 > 0 ) ? - segExtent : segExtent; s0 = Math.max( 0, - ( a01 * s1 + b0 ) ); sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c; } if ( optionalPointOnRay ) { optionalPointOnRay.copy( this.direction.clone().multiplyScalar( s0 ).add( this.origin ) ); } if ( optionalPointOnSegment ) { optionalPointOnSegment.copy( segDir.clone().multiplyScalar( s1 ).add( segCenter ) ); } return sqrDist; }, isIntersectionSphere: function ( sphere ) { return this.distanceToPoint( sphere.center ) <= sphere.radius; }, isIntersectionPlane: function ( plane ) { // check if the ray lies on the plane first var distToPoint = plane.distanceToPoint( this.origin ); if ( distToPoint === 0 ) { return true; } var denominator = plane.normal.dot( this.direction ); if ( denominator * distToPoint < 0 ) { return true } // ray origin is behind the plane (and is pointing behind it) return false; }, distanceToPlane: function ( plane ) { var denominator = plane.normal.dot( this.direction ); if ( denominator == 0 ) { // line is coplanar, return origin if( plane.distanceToPoint( this.origin ) == 0 ) { return 0; } // Null is preferable to undefined since undefined means.... it is undefined return null; } var t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator; // Return if the ray never intersects the plane return t >= 0 ? t : null; }, intersectPlane: function ( plane, optionalTarget ) { var t = this.distanceToPlane( plane ); if ( t === null ) { return null; } return this.at( t, optionalTarget ); }, isIntersectionBox: function () { var v = new THREE.Vector3(); return function ( box ) { return this.intersectBox( box, v ) !== null; } }(), intersectBox: function ( box , optionalTarget ) { // http://www.scratchapixel.com/lessons/3d-basic-lessons/lesson-7-intersecting-simple-shapes/ray-box-intersection/ var tmin,tmax,tymin,tymax,tzmin,tzmax; var invdirx = 1/this.direction.x, invdiry = 1/this.direction.y, invdirz = 1/this.direction.z; var origin = this.origin; if (invdirx >= 0) { tmin = (box.min.x - origin.x) * invdirx; tmax = (box.max.x - origin.x) * invdirx; } else { tmin = (box.max.x - origin.x) * invdirx; tmax = (box.min.x - origin.x) * invdirx; } if (invdiry >= 0) { tymin = (box.min.y - origin.y) * invdiry; tymax = (box.max.y - origin.y) * invdiry; } else { tymin = (box.max.y - origin.y) * invdiry; tymax = (box.min.y - origin.y) * invdiry; } if ((tmin > tymax) || (tymin > tmax)) return null; // These lines also handle the case where tmin or tmax is NaN // (result of 0 * Infinity). x !== x returns true if x is NaN if (tymin > tmin || tmin !== tmin ) tmin = tymin; if (tymax < tmax || tmax !== tmax ) tmax = tymax; if (invdirz >= 0) { tzmin = (box.min.z - origin.z) * invdirz; tzmax = (box.max.z - origin.z) * invdirz; } else { tzmin = (box.max.z - origin.z) * invdirz; tzmax = (box.min.z - origin.z) * invdirz; } if ((tmin > tzmax) || (tzmin > tmax)) return null; if (tzmin > tmin || tmin !== tmin ) tmin = tzmin; if (tzmax < tmax || tmax !== tmax ) tmax = tzmax; //return point closest to the ray (positive side) if ( tmax < 0 ) return null; return this.at( tmin >= 0 ? tmin : tmax, optionalTarget ); }, intersectTriangle: function() { // Compute the offset origin, edges, and normal. var diff = new THREE.Vector3(); var edge1 = new THREE.Vector3(); var edge2 = new THREE.Vector3(); var normal = new THREE.Vector3(); return function ( a, b, c, backfaceCulling, optionalTarget ) { // from http://www.geometrictools.com/LibMathematics/Intersection/Wm5IntrRay3Triangle3.cpp edge1.subVectors( b, a ); edge2.subVectors( c, a ); normal.crossVectors( edge1, edge2 ); // Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction, // E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by // |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2)) // |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q)) // |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N) var DdN = this.direction.dot( normal ); var sign; if ( DdN > 0 ) { if ( backfaceCulling ) return null; sign = 1; } else if ( DdN < 0 ) { sign = - 1; DdN = - DdN; } else { return null; } diff.subVectors( this.origin, a ); var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) ); // b1 < 0, no intersection if ( DdQxE2 < 0 ) { return null; } var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) ); // b2 < 0, no intersection if ( DdE1xQ < 0 ) { return null; } // b1+b2 > 1, no intersection if ( DdQxE2 + DdE1xQ > DdN ) { return null; } // Line intersects triangle, check if ray does. var QdN = - sign * diff.dot( normal ); // t < 0, no intersection if ( QdN < 0 ) { return null; } // Ray intersects triangle. return this.at( QdN / DdN, optionalTarget ); } }(), applyMatrix4: function ( matrix4 ) { this.direction.add( this.origin ).applyMatrix4( matrix4 ); this.origin.applyMatrix4( matrix4 ); this.direction.sub( this.origin ); this.direction.normalize(); return this; }, equals: function ( ray ) { return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction ); }, clone: function () { return new THREE.Ray().copy( this ); } }; /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ */ THREE.Sphere = function ( center, radius ) { this.center = ( center !== undefined ) ? center : new THREE.Vector3(); this.radius = ( radius !== undefined ) ? radius : 0; }; THREE.Sphere.prototype = { constructor: THREE.Sphere, set: function ( center, radius ) { this.center.copy( center ); this.radius = radius; return this; }, setFromPoints: function () { var box = new THREE.Box3(); return function ( points, optionalCenter ) { var center = this.center; if ( optionalCenter !== undefined ) { center.copy( optionalCenter ); } else { box.setFromPoints( points ).center( center ); } var maxRadiusSq = 0; for ( var i = 0, il = points.length; i < il; i ++ ) { maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) ); } this.radius = Math.sqrt( maxRadiusSq ); return this; }; }(), copy: function ( sphere ) { this.center.copy( sphere.center ); this.radius = sphere.radius; return this; }, empty: function () { return ( this.radius <= 0 ); }, containsPoint: function ( point ) { return ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) ); }, distanceToPoint: function ( point ) { return ( point.distanceTo( this.center ) - this.radius ); }, intersectsSphere: function ( sphere ) { var radiusSum = this.radius + sphere.radius; return sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum ); }, clampPoint: function ( point, optionalTarget ) { var deltaLengthSq = this.center.distanceToSquared( point ); var result = optionalTarget || new THREE.Vector3(); result.copy( point ); if ( deltaLengthSq > ( this.radius * this.radius ) ) { result.sub( this.center ).normalize(); result.multiplyScalar( this.radius ).add( this.center ); } return result; }, getBoundingBox: function ( optionalTarget ) { var box = optionalTarget || new THREE.Box3(); box.set( this.center, this.center ); box.expandByScalar( this.radius ); return box; }, applyMatrix4: function ( matrix ) { this.center.applyMatrix4( matrix ); this.radius = this.radius * matrix.getMaxScaleOnAxis(); return this; }, translate: function ( offset ) { this.center.add( offset ); return this; }, equals: function ( sphere ) { return sphere.center.equals( this.center ) && ( sphere.radius === this.radius ); }, clone: function () { return new THREE.Sphere().copy( this ); } }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author bhouston / http://exocortex.com */ THREE.Frustum = function ( p0, p1, p2, p3, p4, p5 ) { this.planes = [ ( p0 !== undefined ) ? p0 : new THREE.Plane(), ( p1 !== undefined ) ? p1 : new THREE.Plane(), ( p2 !== undefined ) ? p2 : new THREE.Plane(), ( p3 !== undefined ) ? p3 : new THREE.Plane(), ( p4 !== undefined ) ? p4 : new THREE.Plane(), ( p5 !== undefined ) ? p5 : new THREE.Plane() ]; }; THREE.Frustum.prototype = { constructor: THREE.Frustum, set: function ( p0, p1, p2, p3, p4, p5 ) { var planes = this.planes; planes[0].copy( p0 ); planes[1].copy( p1 ); planes[2].copy( p2 ); planes[3].copy( p3 ); planes[4].copy( p4 ); planes[5].copy( p5 ); return this; }, copy: function ( frustum ) { var planes = this.planes; for( var i = 0; i < 6; i ++ ) { planes[i].copy( frustum.planes[i] ); } return this; }, setFromMatrix: function ( m ) { var planes = this.planes; var me = m.elements; var me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3]; var me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7]; var me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11]; var me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15]; planes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize(); planes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize(); planes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize(); planes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize(); planes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize(); planes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize(); return this; }, intersectsObject: function () { var sphere = new THREE.Sphere(); return function ( object ) { var geometry = object.geometry; if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( object.matrixWorld ); return this.intersectsSphere( sphere ); }; }(), intersectsSphere: function ( sphere ) { var planes = this.planes; var center = sphere.center; var negRadius = -sphere.radius; for ( var i = 0; i < 6; i ++ ) { var distance = planes[ i ].distanceToPoint( center ); if ( distance < negRadius ) { return false; } } return true; }, intersectsBox : function() { var p1 = new THREE.Vector3(), p2 = new THREE.Vector3(); return function( box ) { var planes = this.planes; for ( var i = 0; i < 6 ; i ++ ) { var plane = planes[i]; p1.x = plane.normal.x > 0 ? box.min.x : box.max.x; p2.x = plane.normal.x > 0 ? box.max.x : box.min.x; p1.y = plane.normal.y > 0 ? box.min.y : box.max.y; p2.y = plane.normal.y > 0 ? box.max.y : box.min.y; p1.z = plane.normal.z > 0 ? box.min.z : box.max.z; p2.z = plane.normal.z > 0 ? box.max.z : box.min.z; var d1 = plane.distanceToPoint( p1 ); var d2 = plane.distanceToPoint( p2 ); // if both outside plane, no intersection if ( d1 < 0 && d2 < 0 ) { return false; } } return true; }; }(), containsPoint: function ( point ) { var planes = this.planes; for ( var i = 0; i < 6; i ++ ) { if ( planes[ i ].distanceToPoint( point ) < 0 ) { return false; } } return true; }, clone: function () { return new THREE.Frustum().copy( this ); } }; /** * @author bhouston / http://exocortex.com */ THREE.Plane = function ( normal, constant ) { this.normal = ( normal !== undefined ) ? normal : new THREE.Vector3( 1, 0, 0 ); this.constant = ( constant !== undefined ) ? constant : 0; }; THREE.Plane.prototype = { constructor: THREE.Plane, set: function ( normal, constant ) { this.normal.copy( normal ); this.constant = constant; return this; }, setComponents: function ( x, y, z, w ) { this.normal.set( x, y, z ); this.constant = w; return this; }, setFromNormalAndCoplanarPoint: function ( normal, point ) { this.normal.copy( normal ); this.constant = - point.dot( this.normal ); // must be this.normal, not normal, as this.normal is normalized return this; }, setFromCoplanarPoints: function() { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); return function ( a, b, c ) { var normal = v1.subVectors( c, b ).cross( v2.subVectors( a, b ) ).normalize(); // Q: should an error be thrown if normal is zero (e.g. degenerate plane)? this.setFromNormalAndCoplanarPoint( normal, a ); return this; }; }(), copy: function ( plane ) { this.normal.copy( plane.normal ); this.constant = plane.constant; return this; }, normalize: function () { // Note: will lead to a divide by zero if the plane is invalid. var inverseNormalLength = 1.0 / this.normal.length(); this.normal.multiplyScalar( inverseNormalLength ); this.constant *= inverseNormalLength; return this; }, negate: function () { this.constant *= -1; this.normal.negate(); return this; }, distanceToPoint: function ( point ) { return this.normal.dot( point ) + this.constant; }, distanceToSphere: function ( sphere ) { return this.distanceToPoint( sphere.center ) - sphere.radius; }, projectPoint: function ( point, optionalTarget ) { return this.orthoPoint( point, optionalTarget ).sub( point ).negate(); }, orthoPoint: function ( point, optionalTarget ) { var perpendicularMagnitude = this.distanceToPoint( point ); var result = optionalTarget || new THREE.Vector3(); return result.copy( this.normal ).multiplyScalar( perpendicularMagnitude ); }, isIntersectionLine: function ( line ) { // Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it. var startSign = this.distanceToPoint( line.start ); var endSign = this.distanceToPoint( line.end ); return ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 ); }, intersectLine: function() { var v1 = new THREE.Vector3(); return function ( line, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); var direction = line.delta( v1 ); var denominator = this.normal.dot( direction ); if ( denominator == 0 ) { // line is coplanar, return origin if( this.distanceToPoint( line.start ) == 0 ) { return result.copy( line.start ); } // Unsure if this is the correct method to handle this case. return undefined; } var t = - ( line.start.dot( this.normal ) + this.constant ) / denominator; if( t < 0 || t > 1 ) { return undefined; } return result.copy( direction ).multiplyScalar( t ).add( line.start ); }; }(), coplanarPoint: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.copy( this.normal ).multiplyScalar( - this.constant ); }, applyMatrix4: function() { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); var m1 = new THREE.Matrix3(); return function ( matrix, optionalNormalMatrix ) { // compute new normal based on theory here: // http://www.songho.ca/opengl/gl_normaltransform.html var normalMatrix = optionalNormalMatrix || m1.getNormalMatrix( matrix ); var newNormal = v1.copy( this.normal ).applyMatrix3( normalMatrix ); var newCoplanarPoint = this.coplanarPoint( v2 ); newCoplanarPoint.applyMatrix4( matrix ); this.setFromNormalAndCoplanarPoint( newNormal, newCoplanarPoint ); return this; }; }(), translate: function ( offset ) { this.constant = this.constant - offset.dot( this.normal ); return this; }, equals: function ( plane ) { return plane.normal.equals( this.normal ) && ( plane.constant == this.constant ); }, clone: function () { return new THREE.Plane().copy( this ); } }; /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.Math = { PI2: Math.PI * 2, generateUUID: function () { // http://www.broofa.com/Tools/Math.uuid.htm var chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); var uuid = new Array(36); var rnd = 0, r; return function () { for ( var i = 0; i < 36; i ++ ) { if ( i == 8 || i == 13 || i == 18 || i == 23 ) { uuid[ i ] = '-'; } else if ( i == 14 ) { uuid[ i ] = '4'; } else { if (rnd <= 0x02) rnd = 0x2000000 + (Math.random()*0x1000000)|0; r = rnd & 0xf; rnd = rnd >> 4; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } return uuid.join(''); }; }(), // Clamp value to range clamp: function ( x, a, b ) { return ( x < a ) ? a : ( ( x > b ) ? b : x ); }, // Clamp value to range to range mapLinear: function ( x, a1, a2, b1, b2 ) { return b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 ); }, // http://en.wikipedia.org/wiki/Smoothstep smoothstep: function ( x, min, max ) { if ( x <= min ) return 0; if ( x >= max ) return 1; x = ( x - min )/( max - min ); return x*x*(3 - 2*x); }, smootherstep: function ( x, min, max ) { if ( x <= min ) return 0; if ( x >= max ) return 1; x = ( x - min )/( max - min ); return x*x*x*(x*(x*6 - 15) + 10); }, // Random float from <0, 1> with 16 bits of randomness // (standard Math.random() creates repetitive patterns when applied over larger space) random16: function () { return ( 65280 * Math.random() + 255 * Math.random() ) / 65535; }, // Random integer from interval randInt: function ( low, high ) { return low + Math.floor( Math.random() * ( high - low + 1 ) ); }, // Random float from interval randFloat: function ( low, high ) { return low + Math.random() * ( high - low ); }, // Random float from <-range/2, range/2> interval randFloatSpread: function ( range ) { return range * ( 0.5 - Math.random() ); }, sign: function ( x ) { return ( x < 0 ) ? - 1 : ( x > 0 ) ? 1 : 0; }, degToRad: function() { var degreeToRadiansFactor = Math.PI / 180; return function ( degrees ) { return degrees * degreeToRadiansFactor; }; }(), radToDeg: function() { var radianToDegreesFactor = 180 / Math.PI; return function ( radians ) { return radians * radianToDegreesFactor; }; }(), isPowerOfTwo: function ( value ) { return ( value & ( value - 1 ) ) === 0 && value !== 0; } }; /** * Spline from Tween.js, slightly optimized (and trashed) * http://sole.github.com/tween.js/examples/05_spline.html * * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Spline = function ( points ) { this.points = points; var c = [], v3 = { x: 0, y: 0, z: 0 }, point, intPoint, weight, w2, w3, pa, pb, pc, pd; this.initFromArray = function( a ) { this.points = []; for ( var i = 0; i < a.length; i++ ) { this.points[ i ] = { x: a[ i ][ 0 ], y: a[ i ][ 1 ], z: a[ i ][ 2 ] }; } }; this.getPoint = function ( k ) { point = ( this.points.length - 1 ) * k; intPoint = Math.floor( point ); weight = point - intPoint; c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; c[ 1 ] = intPoint; c[ 2 ] = intPoint > this.points.length - 2 ? this.points.length - 1 : intPoint + 1; c[ 3 ] = intPoint > this.points.length - 3 ? this.points.length - 1 : intPoint + 2; pa = this.points[ c[ 0 ] ]; pb = this.points[ c[ 1 ] ]; pc = this.points[ c[ 2 ] ]; pd = this.points[ c[ 3 ] ]; w2 = weight * weight; w3 = weight * w2; v3.x = interpolate( pa.x, pb.x, pc.x, pd.x, weight, w2, w3 ); v3.y = interpolate( pa.y, pb.y, pc.y, pd.y, weight, w2, w3 ); v3.z = interpolate( pa.z, pb.z, pc.z, pd.z, weight, w2, w3 ); return v3; }; this.getControlPointsArray = function () { var i, p, l = this.points.length, coords = []; for ( i = 0; i < l; i ++ ) { p = this.points[ i ]; coords[ i ] = [ p.x, p.y, p.z ]; } return coords; }; // approximate length by summing linear segments this.getLength = function ( nSubDivisions ) { var i, index, nSamples, position, point = 0, intPoint = 0, oldIntPoint = 0, oldPosition = new THREE.Vector3(), tmpVec = new THREE.Vector3(), chunkLengths = [], totalLength = 0; // first point has 0 length chunkLengths[ 0 ] = 0; if ( !nSubDivisions ) nSubDivisions = 100; nSamples = this.points.length * nSubDivisions; oldPosition.copy( this.points[ 0 ] ); for ( i = 1; i < nSamples; i ++ ) { index = i / nSamples; position = this.getPoint( index ); tmpVec.copy( position ); totalLength += tmpVec.distanceTo( oldPosition ); oldPosition.copy( position ); point = ( this.points.length - 1 ) * index; intPoint = Math.floor( point ); if ( intPoint != oldIntPoint ) { chunkLengths[ intPoint ] = totalLength; oldIntPoint = intPoint; } } // last point ends with total length chunkLengths[ chunkLengths.length ] = totalLength; return { chunks: chunkLengths, total: totalLength }; }; this.reparametrizeByArcLength = function ( samplingCoef ) { var i, j, index, indexCurrent, indexNext, linearDistance, realDistance, sampling, position, newpoints = [], tmpVec = new THREE.Vector3(), sl = this.getLength(); newpoints.push( tmpVec.copy( this.points[ 0 ] ).clone() ); for ( i = 1; i < this.points.length; i++ ) { //tmpVec.copy( this.points[ i - 1 ] ); //linearDistance = tmpVec.distanceTo( this.points[ i ] ); realDistance = sl.chunks[ i ] - sl.chunks[ i - 1 ]; sampling = Math.ceil( samplingCoef * realDistance / sl.total ); indexCurrent = ( i - 1 ) / ( this.points.length - 1 ); indexNext = i / ( this.points.length - 1 ); for ( j = 1; j < sampling - 1; j++ ) { index = indexCurrent + j * ( 1 / sampling ) * ( indexNext - indexCurrent ); position = this.getPoint( index ); newpoints.push( tmpVec.copy( position ).clone() ); } newpoints.push( tmpVec.copy( this.points[ i ] ).clone() ); } this.points = newpoints; }; // Catmull-Rom function interpolate( p0, p1, p2, p3, t, t2, t3 ) { var v0 = ( p2 - p0 ) * 0.5, v1 = ( p3 - p1 ) * 0.5; return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; }; }; /** * @author bhouston / http://exocortex.com * @author mrdoob / http://mrdoob.com/ */ THREE.Triangle = function ( a, b, c ) { this.a = ( a !== undefined ) ? a : new THREE.Vector3(); this.b = ( b !== undefined ) ? b : new THREE.Vector3(); this.c = ( c !== undefined ) ? c : new THREE.Vector3(); }; THREE.Triangle.normal = function() { var v0 = new THREE.Vector3(); return function ( a, b, c, optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); result.subVectors( c, b ); v0.subVectors( a, b ); result.cross( v0 ); var resultLengthSq = result.lengthSq(); if( resultLengthSq > 0 ) { return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) ); } return result.set( 0, 0, 0 ); }; }(); // static/instance method to calculate barycoordinates // based on: http://www.blackpawn.com/texts/pointinpoly/default.html THREE.Triangle.barycoordFromPoint = function() { var v0 = new THREE.Vector3(); var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); return function ( point, a, b, c, optionalTarget ) { v0.subVectors( c, a ); v1.subVectors( b, a ); v2.subVectors( point, a ); var dot00 = v0.dot( v0 ); var dot01 = v0.dot( v1 ); var dot02 = v0.dot( v2 ); var dot11 = v1.dot( v1 ); var dot12 = v1.dot( v2 ); var denom = ( dot00 * dot11 - dot01 * dot01 ); var result = optionalTarget || new THREE.Vector3(); // colinear or singular triangle if( denom == 0 ) { // arbitrary location outside of triangle? // not sure if this is the best idea, maybe should be returning undefined return result.set( -2, -1, -1 ); } var invDenom = 1 / denom; var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom; var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom; // barycoordinates must always sum to 1 return result.set( 1 - u - v, v, u ); }; }(); THREE.Triangle.containsPoint = function() { var v1 = new THREE.Vector3(); return function ( point, a, b, c ) { var result = THREE.Triangle.barycoordFromPoint( point, a, b, c, v1 ); return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 ); }; }(); THREE.Triangle.prototype = { constructor: THREE.Triangle, set: function ( a, b, c ) { this.a.copy( a ); this.b.copy( b ); this.c.copy( c ); return this; }, setFromPointsAndIndices: function ( points, i0, i1, i2 ) { this.a.copy( points[i0] ); this.b.copy( points[i1] ); this.c.copy( points[i2] ); return this; }, copy: function ( triangle ) { this.a.copy( triangle.a ); this.b.copy( triangle.b ); this.c.copy( triangle.c ); return this; }, area: function() { var v0 = new THREE.Vector3(); var v1 = new THREE.Vector3(); return function () { v0.subVectors( this.c, this.b ); v1.subVectors( this.a, this.b ); return v0.cross( v1 ).length() * 0.5; }; }(), midpoint: function ( optionalTarget ) { var result = optionalTarget || new THREE.Vector3(); return result.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 ); }, normal: function ( optionalTarget ) { return THREE.Triangle.normal( this.a, this.b, this.c, optionalTarget ); }, plane: function ( optionalTarget ) { var result = optionalTarget || new THREE.Plane(); return result.setFromCoplanarPoints( this.a, this.b, this.c ); }, barycoordFromPoint: function ( point, optionalTarget ) { return THREE.Triangle.barycoordFromPoint( point, this.a, this.b, this.c, optionalTarget ); }, containsPoint: function ( point ) { return THREE.Triangle.containsPoint( point, this.a, this.b, this.c ); }, equals: function ( triangle ) { return triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c ); }, clone: function () { return new THREE.Triangle().copy( this ); } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.Vertex = function ( v ) { console.warn( 'THREE.Vertex has been DEPRECATED. Use THREE.Vector3 instead.') return v; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.UV = function ( u, v ) { console.warn( 'THREE.UV has been DEPRECATED. Use THREE.Vector2 instead.') return new THREE.Vector2( u, v ); }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.Clock = function ( autoStart ) { this.autoStart = ( autoStart !== undefined ) ? autoStart : true; this.startTime = 0; this.oldTime = 0; this.elapsedTime = 0; this.running = false; }; THREE.Clock.prototype = { constructor: THREE.Clock, start: function () { this.startTime = self.performance !== undefined && self.performance.now !== undefined ? self.performance.now() : Date.now(); this.oldTime = this.startTime; this.running = true; }, stop: function () { this.getElapsedTime(); this.running = false; }, getElapsedTime: function () { this.getDelta(); return this.elapsedTime; }, getDelta: function () { var diff = 0; if ( this.autoStart && ! this.running ) { this.start(); } if ( this.running ) { var newTime = self.performance !== undefined && self.performance.now !== undefined ? self.performance.now() : Date.now(); diff = 0.001 * ( newTime - this.oldTime ); this.oldTime = newTime; this.elapsedTime += diff; } return diff; } }; /** * https://github.com/mrdoob/eventdispatcher.js/ */ THREE.EventDispatcher = function () {} THREE.EventDispatcher.prototype = { constructor: THREE.EventDispatcher, apply: function ( object ) { object.addEventListener = THREE.EventDispatcher.prototype.addEventListener; object.hasEventListener = THREE.EventDispatcher.prototype.hasEventListener; object.removeEventListener = THREE.EventDispatcher.prototype.removeEventListener; object.dispatchEvent = THREE.EventDispatcher.prototype.dispatchEvent; }, addEventListener: function ( type, listener ) { if ( this._listeners === undefined ) this._listeners = {}; var listeners = this._listeners; if ( listeners[ type ] === undefined ) { listeners[ type ] = []; } if ( listeners[ type ].indexOf( listener ) === - 1 ) { listeners[ type ].push( listener ); } }, hasEventListener: function ( type, listener ) { if ( this._listeners === undefined ) return false; var listeners = this._listeners; if ( listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1 ) { return true; } return false; }, removeEventListener: function ( type, listener ) { if ( this._listeners === undefined ) return; var listeners = this._listeners; var listenerArray = listeners[ type ]; if ( listenerArray !== undefined ) { var index = listenerArray.indexOf( listener ); if ( index !== - 1 ) { listenerArray.splice( index, 1 ); } } }, dispatchEvent: function () { var array = []; return function ( event ) { if ( this._listeners === undefined ) return; var listeners = this._listeners; var listenerArray = listeners[ event.type ]; if ( listenerArray !== undefined ) { event.target = this; var length = listenerArray.length; for ( var i = 0; i < length; i ++ ) { array[ i ] = listenerArray[ i ]; } for ( var i = 0; i < length; i ++ ) { array[ i ].call( this, event ); } } }; }() }; /** * @author mrdoob / http://mrdoob.com/ * @author bhouston / http://exocortex.com/ * @author stephomi / http://stephaneginier.com/ */ ( function ( THREE ) { THREE.Raycaster = function ( origin, direction, near, far ) { this.ray = new THREE.Ray( origin, direction ); // direction is assumed to be normalized (for accurate distance calculations) this.near = near || 0; this.far = far || Infinity; }; var sphere = new THREE.Sphere(); var localRay = new THREE.Ray(); var facePlane = new THREE.Plane(); var intersectPoint = new THREE.Vector3(); var matrixPosition = new THREE.Vector3(); var inverseMatrix = new THREE.Matrix4(); var descSort = function ( a, b ) { return a.distance - b.distance; }; var vA = new THREE.Vector3(); var vB = new THREE.Vector3(); var vC = new THREE.Vector3(); var intersectObject = function ( object, raycaster, intersects ) { if ( object instanceof THREE.Sprite ) { matrixPosition.setFromMatrixPosition( object.matrixWorld ); var distance = raycaster.ray.distanceToPoint( matrixPosition ); if ( distance > object.scale.x ) { return intersects; } intersects.push( { distance: distance, point: object.position, face: null, object: object } ); } else if ( object instanceof THREE.LOD ) { matrixPosition.setFromMatrixPosition( object.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( matrixPosition ); intersectObject( object.getObjectForDistance( distance ), raycaster, intersects ); } else if ( object instanceof THREE.Mesh ) { var geometry = object.geometry; // Checking boundingSphere distance to ray if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( object.matrixWorld ); if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { return intersects; } // Check boundingBox before continuing inverseMatrix.getInverse( object.matrixWorld ); localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); if ( geometry.boundingBox !== null ) { if ( localRay.isIntersectionBox( geometry.boundingBox ) === false ) { return intersects; } } if ( geometry instanceof THREE.BufferGeometry ) { var material = object.material; if ( material === undefined ) return intersects; var attributes = geometry.attributes; var a, b, c; var precision = raycaster.precision; if ( attributes.index !== undefined ) { var offsets = geometry.offsets; var indices = attributes.index.array; var positions = attributes.position.array; for ( var oi = 0, ol = offsets.length; oi < ol; ++oi ) { var start = offsets[ oi ].start; var count = offsets[ oi ].count; var index = offsets[ oi ].index; for ( var i = start, il = start + count; i < il; i += 3 ) { a = index + indices[ i ]; b = index + indices[ i + 1 ]; c = index + indices[ i + 2 ]; vA.set( positions[ a * 3 ], positions[ a * 3 + 1 ], positions[ a * 3 + 2 ] ); vB.set( positions[ b * 3 ], positions[ b * 3 + 1 ], positions[ b * 3 + 2 ] ); vC.set( positions[ c * 3 ], positions[ c * 3 + 1 ], positions[ c * 3 + 2 ] ); if ( material.side === THREE.BackSide ) { var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); } else { var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); } if ( intersectionPoint === null ) continue; intersectionPoint.applyMatrix4( object.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; intersects.push( { distance: distance, point: intersectionPoint, indices: [a, b, c], face: null, faceIndex: null, object: object } ); } } } else { var offsets = geometry.offsets; var positions = attributes.position.array; for ( var i = 0, il = attributes.position.array.length; i < il; i += 3 ) { a = i; b = i + 1; c = i + 2; vA.set( positions[ a * 3 ], positions[ a * 3 + 1 ], positions[ a * 3 + 2 ] ); vB.set( positions[ b * 3 ], positions[ b * 3 + 1 ], positions[ b * 3 + 2 ] ); vC.set( positions[ c * 3 ], positions[ c * 3 + 1 ], positions[ c * 3 + 2 ] ); if ( material.side === THREE.BackSide ) { var intersectionPoint = localRay.intersectTriangle( vC, vB, vA, true ); } else { var intersectionPoint = localRay.intersectTriangle( vA, vB, vC, material.side !== THREE.DoubleSide ); } if ( intersectionPoint === null ) continue; intersectionPoint.applyMatrix4( object.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; intersects.push( { distance: distance, point: intersectionPoint, indices: [a, b, c], face: null, faceIndex: null, object: object } ); } } } else if ( geometry instanceof THREE.Geometry ) { var isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; var objectMaterials = isFaceMaterial === true ? object.material.materials : null; var a, b, c, d; var precision = raycaster.precision; var vertices = geometry.vertices; for ( var f = 0, fl = geometry.faces.length; f < fl; f ++ ) { var face = geometry.faces[ f ]; var material = isFaceMaterial === true ? objectMaterials[ face.materialIndex ] : object.material; if ( material === undefined ) continue; a = vertices[ face.a ]; b = vertices[ face.b ]; c = vertices[ face.c ]; if ( material.morphTargets === true ) { var morphTargets = geometry.morphTargets; var morphInfluences = object.morphTargetInfluences; vA.set( 0, 0, 0 ); vB.set( 0, 0, 0 ); vC.set( 0, 0, 0 ); for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { var influence = morphInfluences[ t ]; if ( influence === 0 ) continue; var targets = morphTargets[ t ].vertices; vA.x += ( targets[ face.a ].x - a.x ) * influence; vA.y += ( targets[ face.a ].y - a.y ) * influence; vA.z += ( targets[ face.a ].z - a.z ) * influence; vB.x += ( targets[ face.b ].x - b.x ) * influence; vB.y += ( targets[ face.b ].y - b.y ) * influence; vB.z += ( targets[ face.b ].z - b.z ) * influence; vC.x += ( targets[ face.c ].x - c.x ) * influence; vC.y += ( targets[ face.c ].y - c.y ) * influence; vC.z += ( targets[ face.c ].z - c.z ) * influence; } vA.add( a ); vB.add( b ); vC.add( c ); a = vA; b = vB; c = vC; } if ( material.side === THREE.BackSide ) { var intersectionPoint = localRay.intersectTriangle( c, b, a, true ); } else { var intersectionPoint = localRay.intersectTriangle( a, b, c, material.side !== THREE.DoubleSide ); } if ( intersectionPoint === null ) continue; intersectionPoint.applyMatrix4( object.matrixWorld ); var distance = raycaster.ray.origin.distanceTo( intersectionPoint ); if ( distance < precision || distance < raycaster.near || distance > raycaster.far ) continue; intersects.push( { distance: distance, point: intersectionPoint, face: face, faceIndex: f, object: object } ); } } } else if ( object instanceof THREE.Line ) { var precision = raycaster.linePrecision; var precisionSq = precision * precision; var geometry = object.geometry; if ( geometry.boundingSphere === null ) geometry.computeBoundingSphere(); // Checking boundingSphere distance to ray sphere.copy( geometry.boundingSphere ); sphere.applyMatrix4( object.matrixWorld ); if ( raycaster.ray.isIntersectionSphere( sphere ) === false ) { return intersects; } inverseMatrix.getInverse( object.matrixWorld ); localRay.copy( raycaster.ray ).applyMatrix4( inverseMatrix ); /* if ( geometry instanceof THREE.BufferGeometry ) { } else */ if ( geometry instanceof THREE.Geometry ) { var vertices = geometry.vertices; var nbVertices = vertices.length; var interSegment = new THREE.Vector3(); var interRay = new THREE.Vector3(); var step = object.type === THREE.LineStrip ? 1 : 2; for ( var i = 0; i < nbVertices - 1; i = i + step ) { var distSq = localRay.distanceSqToSegment( vertices[ i ], vertices[ i + 1 ], interRay, interSegment ); if ( distSq > precisionSq ) continue; var distance = localRay.origin.distanceTo( interRay ); if ( distance < raycaster.near || distance > raycaster.far ) continue; intersects.push( { distance: distance, // What do we want? intersection point on the ray or on the segment?? // point: raycaster.ray.at( distance ), point: interSegment.clone().applyMatrix4( object.matrixWorld ), face: null, faceIndex: null, object: object } ); } } } }; var intersectDescendants = function ( object, raycaster, intersects ) { var descendants = object.getDescendants(); for ( var i = 0, l = descendants.length; i < l; i ++ ) { intersectObject( descendants[ i ], raycaster, intersects ); } }; // THREE.Raycaster.prototype.precision = 0.0001; THREE.Raycaster.prototype.linePrecision = 1; THREE.Raycaster.prototype.set = function ( origin, direction ) { this.ray.set( origin, direction ); // direction is assumed to be normalized (for accurate distance calculations) }; THREE.Raycaster.prototype.intersectObject = function ( object, recursive ) { var intersects = []; if ( recursive === true ) { intersectDescendants( object, this, intersects ); } intersectObject( object, this, intersects ); intersects.sort( descSort ); return intersects; }; THREE.Raycaster.prototype.intersectObjects = function ( objects, recursive ) { var intersects = []; for ( var i = 0, l = objects.length; i < l; i ++ ) { intersectObject( objects[ i ], this, intersects ); if ( recursive === true ) { intersectDescendants( objects[ i ], this, intersects ); } } intersects.sort( descSort ); return intersects; }; }( THREE ) ); /** * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.Object3D = function () { this.id = THREE.Object3DIdCount ++; this.uuid = THREE.Math.generateUUID(); this.name = ''; this.parent = undefined; this.children = []; this.up = new THREE.Vector3( 0, 1, 0 ); this.position = new THREE.Vector3(); this._rotation = new THREE.Euler(); this._quaternion = new THREE.Quaternion(); this.scale = new THREE.Vector3( 1, 1, 1 ); // keep rotation and quaternion in sync this._rotation._quaternion = this.quaternion; this._quaternion._euler = this.rotation; this.renderDepth = null; this.rotationAutoUpdate = true; this.matrix = new THREE.Matrix4(); this.matrixWorld = new THREE.Matrix4(); this.matrixAutoUpdate = true; this.matrixWorldNeedsUpdate = true; this.visible = true; this.castShadow = false; this.receiveShadow = false; this.frustumCulled = true; this.userData = {}; }; THREE.Object3D.prototype = { constructor: THREE.Object3D, get rotation () { return this._rotation; }, set rotation ( value ) { this._rotation = value; this._rotation._quaternion = this._quaternion; this._quaternion._euler = this._rotation; this._rotation._updateQuaternion(); }, get quaternion () { return this._quaternion; }, set quaternion ( value ) { this._quaternion = value; this._quaternion._euler = this._rotation; this._rotation._quaternion = this._quaternion; this._quaternion._updateEuler(); }, get eulerOrder () { console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); return this.rotation.order; }, set eulerOrder ( value ) { console.warn( 'DEPRECATED: Object3D\'s .eulerOrder has been moved to Object3D\'s .rotation.order.' ); this.rotation.order = value; }, get useQuaternion () { console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); }, set useQuaternion ( value ) { console.warn( 'DEPRECATED: Object3D\'s .useQuaternion has been removed. The library now uses quaternions by default.' ); }, applyMatrix: function ( matrix ) { this.matrix.multiplyMatrices( matrix, this.matrix ); this.matrix.decompose( this.position, this.quaternion, this.scale ); }, setRotationFromAxisAngle: function ( axis, angle ) { // assumes axis is normalized this.quaternion.setFromAxisAngle( axis, angle ); }, setRotationFromEuler: function ( euler ) { this.quaternion.setFromEuler( euler, true ); }, setRotationFromMatrix: function ( m ) { // assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled) this.quaternion.setFromRotationMatrix( m ); }, setRotationFromQuaternion: function ( q ) { // assumes q is normalized this.quaternion.copy( q ); }, rotateOnAxis: function() { // rotate object on axis in object space // axis is assumed to be normalized var q1 = new THREE.Quaternion(); return function ( axis, angle ) { q1.setFromAxisAngle( axis, angle ); this.quaternion.multiply( q1 ); return this; } }(), rotateX: function () { var v1 = new THREE.Vector3( 1, 0, 0 ); return function ( angle ) { return this.rotateOnAxis( v1, angle ); }; }(), rotateY: function () { var v1 = new THREE.Vector3( 0, 1, 0 ); return function ( angle ) { return this.rotateOnAxis( v1, angle ); }; }(), rotateZ: function () { var v1 = new THREE.Vector3( 0, 0, 1 ); return function ( angle ) { return this.rotateOnAxis( v1, angle ); }; }(), translateOnAxis: function () { // translate object by distance along axis in object space // axis is assumed to be normalized var v1 = new THREE.Vector3(); return function ( axis, distance ) { v1.copy( axis ); v1.applyQuaternion( this.quaternion ); this.position.add( v1.multiplyScalar( distance ) ); return this; } }(), translate: function ( distance, axis ) { console.warn( 'DEPRECATED: Object3D\'s .translate() has been removed. Use .translateOnAxis( axis, distance ) instead. Note args have been changed.' ); return this.translateOnAxis( axis, distance ); }, translateX: function () { var v1 = new THREE.Vector3( 1, 0, 0 ); return function ( distance ) { return this.translateOnAxis( v1, distance ); }; }(), translateY: function () { var v1 = new THREE.Vector3( 0, 1, 0 ); return function ( distance ) { return this.translateOnAxis( v1, distance ); }; }(), translateZ: function () { var v1 = new THREE.Vector3( 0, 0, 1 ); return function ( distance ) { return this.translateOnAxis( v1, distance ); }; }(), localToWorld: function ( vector ) { return vector.applyMatrix4( this.matrixWorld ); }, worldToLocal: function () { var m1 = new THREE.Matrix4(); return function ( vector ) { return vector.applyMatrix4( m1.getInverse( this.matrixWorld ) ); }; }(), lookAt: function () { // This routine does not support objects with rotated and/or translated parent(s) var m1 = new THREE.Matrix4(); return function ( vector ) { m1.lookAt( vector, this.position, this.up ); this.quaternion.setFromRotationMatrix( m1 ); }; }(), add: function ( object ) { if ( object === this ) { console.warn( 'THREE.Object3D.add: An object can\'t be added as a child of itself.' ); return; } if ( object instanceof THREE.Object3D ) { if ( object.parent !== undefined ) { object.parent.remove( object ); } object.parent = this; object.dispatchEvent( { type: 'added' } ); this.children.push( object ); // add to scene var scene = this; while ( scene.parent !== undefined ) { scene = scene.parent; } if ( scene !== undefined && scene instanceof THREE.Scene ) { scene.__addObject( object ); } } }, remove: function ( object ) { var index = this.children.indexOf( object ); if ( index !== - 1 ) { object.parent = undefined; object.dispatchEvent( { type: 'removed' } ); this.children.splice( index, 1 ); // remove from scene var scene = this; while ( scene.parent !== undefined ) { scene = scene.parent; } if ( scene !== undefined && scene instanceof THREE.Scene ) { scene.__removeObject( object ); } } }, traverse: function ( callback ) { callback( this ); for ( var i = 0, l = this.children.length; i < l; i ++ ) { this.children[ i ].traverse( callback ); } }, getObjectById: function ( id, recursive ) { for ( var i = 0, l = this.children.length; i < l; i ++ ) { var child = this.children[ i ]; if ( child.id === id ) { return child; } if ( recursive === true ) { child = child.getObjectById( id, recursive ); if ( child !== undefined ) { return child; } } } return undefined; }, getObjectByName: function ( name, recursive ) { for ( var i = 0, l = this.children.length; i < l; i ++ ) { var child = this.children[ i ]; if ( child.name === name ) { return child; } if ( recursive === true ) { child = child.getObjectByName( name, recursive ); if ( child !== undefined ) { return child; } } } return undefined; }, getChildByName: function ( name, recursive ) { console.warn( 'DEPRECATED: Object3D\'s .getChildByName() has been renamed to .getObjectByName().' ); return this.getObjectByName( name, recursive ); }, getDescendants: function ( array ) { if ( array === undefined ) array = []; Array.prototype.push.apply( array, this.children ); for ( var i = 0, l = this.children.length; i < l; i ++ ) { this.children[ i ].getDescendants( array ); } return array; }, updateMatrix: function () { this.matrix.compose( this.position, this.quaternion, this.scale ); this.matrixWorldNeedsUpdate = true; }, updateMatrixWorld: function ( force ) { if ( this.matrixAutoUpdate === true ) this.updateMatrix(); if ( this.matrixWorldNeedsUpdate === true || force === true ) { if ( this.parent === undefined ) { this.matrixWorld.copy( this.matrix ); } else { this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); } this.matrixWorldNeedsUpdate = false; force = true; } // update children for ( var i = 0, l = this.children.length; i < l; i ++ ) { this.children[ i ].updateMatrixWorld( force ); } }, clone: function ( object, recursive ) { if ( object === undefined ) object = new THREE.Object3D(); if ( recursive === undefined ) recursive = true; object.name = this.name; object.up.copy( this.up ); object.position.copy( this.position ); object.quaternion.copy( this.quaternion ); object.scale.copy( this.scale ); object.renderDepth = this.renderDepth; object.rotationAutoUpdate = this.rotationAutoUpdate; object.matrix.copy( this.matrix ); object.matrixWorld.copy( this.matrixWorld ); object.matrixAutoUpdate = this.matrixAutoUpdate; object.matrixWorldNeedsUpdate = this.matrixWorldNeedsUpdate; object.visible = this.visible; object.castShadow = this.castShadow; object.receiveShadow = this.receiveShadow; object.frustumCulled = this.frustumCulled; object.userData = JSON.parse( JSON.stringify( this.userData ) ); if ( recursive === true ) { for ( var i = 0; i < this.children.length; i ++ ) { var child = this.children[ i ]; object.add( child.clone() ); } } return object; } }; THREE.EventDispatcher.prototype.apply( THREE.Object3D.prototype ); THREE.Object3DIdCount = 0; /** * @author mrdoob / http://mrdoob.com/ * @author supereggbert / http://www.paulbrunt.co.uk/ * @author julianwa / https://github.com/julianwa */ THREE.Projector = function () { var _object, _objectCount, _objectPool = [], _objectPoolLength = 0, _vertex, _vertexCount, _vertexPool = [], _vertexPoolLength = 0, _face, _faceCount, _facePool = [], _facePoolLength = 0, _line, _lineCount, _linePool = [], _linePoolLength = 0, _sprite, _spriteCount, _spritePool = [], _spritePoolLength = 0, _renderData = { objects: [], lights: [], elements: [] }, _vA = new THREE.Vector3(), _vB = new THREE.Vector3(), _vC = new THREE.Vector3(), _vector3 = new THREE.Vector3(), _vector4 = new THREE.Vector4(), _clipBox = new THREE.Box3( new THREE.Vector3( -1, -1, -1 ), new THREE.Vector3( 1, 1, 1 ) ), _boundingBox = new THREE.Box3(), _points3 = new Array( 3 ), _points4 = new Array( 4 ), _viewMatrix = new THREE.Matrix4(), _viewProjectionMatrix = new THREE.Matrix4(), _modelMatrix, _modelViewProjectionMatrix = new THREE.Matrix4(), _normalMatrix = new THREE.Matrix3(), _frustum = new THREE.Frustum(), _clippedVertex1PositionScreen = new THREE.Vector4(), _clippedVertex2PositionScreen = new THREE.Vector4(); this.projectVector = function ( vector, camera ) { camera.matrixWorldInverse.getInverse( camera.matrixWorld ); _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); return vector.applyProjection( _viewProjectionMatrix ); }; this.unprojectVector = function () { var projectionMatrixInverse = new THREE.Matrix4(); return function ( vector, camera ) { projectionMatrixInverse.getInverse( camera.projectionMatrix ); _viewProjectionMatrix.multiplyMatrices( camera.matrixWorld, projectionMatrixInverse ); return vector.applyProjection( _viewProjectionMatrix ); }; }(); this.pickingRay = function ( vector, camera ) { // set two vectors with opposing z values vector.z = -1.0; var end = new THREE.Vector3( vector.x, vector.y, 1.0 ); this.unprojectVector( vector, camera ); this.unprojectVector( end, camera ); // find direction from vector to end end.sub( vector ).normalize(); return new THREE.Raycaster( vector, end ); }; var projectObject = function ( object ) { if ( object.visible === false ) return; if ( object instanceof THREE.Light ) { _renderData.lights.push( object ); } else if ( object instanceof THREE.Mesh || object instanceof THREE.Line || object instanceof THREE.Sprite ) { if ( object.frustumCulled === false || _frustum.intersectsObject( object ) === true ) { _object = getNextObjectInPool(); _object.id = object.id; _object.object = object; if ( object.renderDepth !== null ) { _object.z = object.renderDepth; } else { _vector3.setFromMatrixPosition( object.matrixWorld ); _vector3.applyProjection( _viewProjectionMatrix ); _object.z = _vector3.z; } _renderData.objects.push( _object ); } } for ( var i = 0, l = object.children.length; i < l; i ++ ) { projectObject( object.children[ i ] ); } }; var projectGraph = function ( root, sortObjects ) { _objectCount = 0; _renderData.objects.length = 0; _renderData.lights.length = 0; projectObject( root ); if ( sortObjects === true ) { _renderData.objects.sort( painterSort ); } }; var RenderList = function () { var normals = []; var object = null; var normalMatrix = new THREE.Matrix3(); var setObject = function ( value ) { object = value; normalMatrix.getNormalMatrix( object.matrixWorld ); normals.length = 0; }; var projectVertex = function ( vertex ) { var position = vertex.position; var positionWorld = vertex.positionWorld; var positionScreen = vertex.positionScreen; positionWorld.copy( position ).applyMatrix4( _modelMatrix ); positionScreen.copy( positionWorld ).applyMatrix4( _viewProjectionMatrix ); var invW = 1 / positionScreen.w; positionScreen.x *= invW; positionScreen.y *= invW; positionScreen.z *= invW; vertex.visible = positionScreen.x >= -1 && positionScreen.x <= 1 && positionScreen.y >= -1 && positionScreen.y <= 1 && positionScreen.z >= -1 && positionScreen.z <= 1; }; var pushVertex = function ( x, y, z ) { _vertex = getNextVertexInPool(); _vertex.position.set( x, y, z ); projectVertex( _vertex ); }; var pushNormal = function ( x, y, z ) { normals.push( x, y, z ); }; var checkTriangleVisibility = function ( v1, v2, v3 ) { _points3[ 0 ] = v1.positionScreen; _points3[ 1 ] = v2.positionScreen; _points3[ 2 ] = v3.positionScreen; if ( v1.visible === true || v2.visible === true || v3.visible === true || _clipBox.isIntersectionBox( _boundingBox.setFromPoints( _points3 ) ) ) { return ( ( v3.positionScreen.x - v1.positionScreen.x ) * ( v2.positionScreen.y - v1.positionScreen.y ) - ( v3.positionScreen.y - v1.positionScreen.y ) * ( v2.positionScreen.x - v1.positionScreen.x ) ) < 0; } return false; }; var pushLine = function ( a, b ) { var v1 = _vertexPool[ a ]; var v2 = _vertexPool[ b ]; _line = getNextLineInPool(); _line.id = object.id; _line.v1.copy( v1 ); _line.v2.copy( v2 ); _line.z = ( v1.positionScreen.z + v2.positionScreen.z ) / 2; _line.material = object.material; _renderData.elements.push( _line ); }; var pushTriangle = function ( a, b, c ) { var v1 = _vertexPool[ a ]; var v2 = _vertexPool[ b ]; var v3 = _vertexPool[ c ]; if ( checkTriangleVisibility( v1, v2, v3 ) === true ) { _face = getNextFaceInPool(); _face.id = object.id; _face.v1.copy( v1 ); _face.v2.copy( v2 ); _face.v3.copy( v3 ); _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; for ( var i = 0; i < 3; i ++ ) { var offset = arguments[ i ] * 3; var normal = _face.vertexNormalsModel[ i ]; normal.set( normals[ offset + 0 ], normals[ offset + 1 ], normals[ offset + 2 ] ); normal.applyMatrix3( normalMatrix ).normalize(); } _face.vertexNormalsLength = 3; _face.material = object.material; _renderData.elements.push( _face ); } }; return { setObject: setObject, projectVertex: projectVertex, checkTriangleVisibility: checkTriangleVisibility, pushVertex: pushVertex, pushNormal: pushNormal, pushLine: pushLine, pushTriangle: pushTriangle } }; var renderList = new RenderList(); this.projectScene = function ( scene, camera, sortObjects, sortElements ) { var object, geometry, vertices, faces, face, faceVertexNormals, faceVertexUvs, uvs, isFaceMaterial, objectMaterials; _faceCount = 0; _lineCount = 0; _spriteCount = 0; _renderData.elements.length = 0; if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); if ( camera.parent === undefined ) camera.updateMatrixWorld(); _viewMatrix.copy( camera.matrixWorldInverse.getInverse( camera.matrixWorld ) ); _viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, _viewMatrix ); _frustum.setFromMatrix( _viewProjectionMatrix ); projectGraph( scene, sortObjects ); for ( var o = 0, ol = _renderData.objects.length; o < ol; o ++ ) { object = _renderData.objects[ o ].object; geometry = object.geometry; renderList.setObject( object ); _modelMatrix = object.matrixWorld; _vertexCount = 0; if ( object instanceof THREE.Mesh ) { if ( geometry instanceof THREE.BufferGeometry ) { var attributes = geometry.attributes; var offsets = geometry.offsets; if ( attributes.position === undefined ) continue; var positions = attributes.position.array; for ( var i = 0, l = positions.length; i < l; i += 3 ) { renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); } var normals = attributes.normal.array; for ( var i = 0, l = normals.length; i < l; i += 3 ) { renderList.pushNormal( normals[ i ], normals[ i + 1 ], normals[ i + 2 ] ); } if ( attributes.index !== undefined ) { var indices = attributes.index.array; if ( offsets.length > 0 ) { for ( var o = 0; o < offsets.length; o ++ ) { var offset = offsets[ o ]; var index = offset.index; for ( var i = offset.start, l = offset.start + offset.count; i < l; i += 3 ) { renderList.pushTriangle( indices[ i ] + index, indices[ i + 1 ] + index, indices[ i + 2 ] + index ); } } } else { for ( var i = 0, l = indices.length; i < l; i += 3 ) { renderList.pushTriangle( indices[ i ], indices[ i + 1 ], indices[ i + 2 ] ); } } } else { for ( var i = 0, l = positions.length / 3; i < l; i += 3 ) { renderList.pushTriangle( i, i + 1, i + 2 ); } } } else if ( geometry instanceof THREE.Geometry ) { vertices = geometry.vertices; faces = geometry.faces; faceVertexUvs = geometry.faceVertexUvs; _normalMatrix.getNormalMatrix( _modelMatrix ); isFaceMaterial = object.material instanceof THREE.MeshFaceMaterial; objectMaterials = isFaceMaterial === true ? object.material : null; for ( var v = 0, vl = vertices.length; v < vl; v ++ ) { var vertex = vertices[ v ]; renderList.pushVertex( vertex.x, vertex.y, vertex.z ); } for ( var f = 0, fl = faces.length; f < fl; f ++ ) { face = faces[ f ]; var material = isFaceMaterial === true ? objectMaterials.materials[ face.materialIndex ] : object.material; if ( material === undefined ) continue; var side = material.side; var v1 = _vertexPool[ face.a ]; var v2 = _vertexPool[ face.b ]; var v3 = _vertexPool[ face.c ]; if ( material.morphTargets === true ) { var morphTargets = geometry.morphTargets; var morphInfluences = object.morphTargetInfluences; var v1p = v1.position; var v2p = v2.position; var v3p = v3.position; _vA.set( 0, 0, 0 ); _vB.set( 0, 0, 0 ); _vC.set( 0, 0, 0 ); for ( var t = 0, tl = morphTargets.length; t < tl; t ++ ) { var influence = morphInfluences[ t ]; if ( influence === 0 ) continue; var targets = morphTargets[ t ].vertices; _vA.x += ( targets[ face.a ].x - v1p.x ) * influence; _vA.y += ( targets[ face.a ].y - v1p.y ) * influence; _vA.z += ( targets[ face.a ].z - v1p.z ) * influence; _vB.x += ( targets[ face.b ].x - v2p.x ) * influence; _vB.y += ( targets[ face.b ].y - v2p.y ) * influence; _vB.z += ( targets[ face.b ].z - v2p.z ) * influence; _vC.x += ( targets[ face.c ].x - v3p.x ) * influence; _vC.y += ( targets[ face.c ].y - v3p.y ) * influence; _vC.z += ( targets[ face.c ].z - v3p.z ) * influence; } v1.position.add( _vA ); v2.position.add( _vB ); v3.position.add( _vC ); renderList.projectVertex( v1 ); renderList.projectVertex( v2 ); renderList.projectVertex( v3 ); } var visible = renderList.checkTriangleVisibility( v1, v2, v3 ); if ( ( visible === false && side === THREE.FrontSide ) || ( visible === true && side === THREE.BackSide ) ) continue; _face = getNextFaceInPool(); _face.id = object.id; _face.v1.copy( v1 ); _face.v2.copy( v2 ); _face.v3.copy( v3 ); _face.normalModel.copy( face.normal ); if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { _face.normalModel.negate(); } _face.normalModel.applyMatrix3( _normalMatrix ).normalize(); _face.centroidModel.copy( face.centroid ).applyMatrix4( _modelMatrix ); faceVertexNormals = face.vertexNormals; for ( var n = 0, nl = Math.min( faceVertexNormals.length, 3 ); n < nl; n ++ ) { var normalModel = _face.vertexNormalsModel[ n ]; normalModel.copy( faceVertexNormals[ n ] ); if ( visible === false && ( side === THREE.BackSide || side === THREE.DoubleSide ) ) { normalModel.negate(); } normalModel.applyMatrix3( _normalMatrix ).normalize(); } _face.vertexNormalsLength = faceVertexNormals.length; for ( var c = 0, cl = Math.min( faceVertexUvs.length, 3 ); c < cl; c ++ ) { uvs = faceVertexUvs[ c ][ f ]; if ( uvs === undefined ) continue; for ( var u = 0, ul = uvs.length; u < ul; u ++ ) { _face.uvs[ c ][ u ] = uvs[ u ]; } } _face.color = face.color; _face.material = material; _face.z = ( v1.positionScreen.z + v2.positionScreen.z + v3.positionScreen.z ) / 3; _renderData.elements.push( _face ); } } } else if ( object instanceof THREE.Line ) { if ( geometry instanceof THREE.BufferGeometry ) { var attributes = geometry.attributes; if ( attributes.position !== undefined ) { var positions = attributes.position.array; for ( var i = 0, l = positions.length; i < l; i += 3 ) { renderList.pushVertex( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); } if ( attributes.index !== undefined ) { var indices = attributes.index.array; for ( var i = 0, l = indices.length; i < l; i += 2 ) { renderList.pushLine( indices[ i ], indices[ i + 1 ] ); } } else { for ( var i = 0, l = ( positions.length / 3 ) - 1; i < l; i ++ ) { renderList.pushLine( i, i + 1 ); } } } } else if ( geometry instanceof THREE.Geometry ) { _modelViewProjectionMatrix.multiplyMatrices( _viewProjectionMatrix, _modelMatrix ); vertices = object.geometry.vertices; if ( vertices.length === 0 ) continue; v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ 0 ] ).applyMatrix4( _modelViewProjectionMatrix ); // Handle LineStrip and LinePieces var step = object.type === THREE.LinePieces ? 2 : 1; for ( var v = 1, vl = vertices.length; v < vl; v ++ ) { v1 = getNextVertexInPool(); v1.positionScreen.copy( vertices[ v ] ).applyMatrix4( _modelViewProjectionMatrix ); if ( ( v + 1 ) % step > 0 ) continue; v2 = _vertexPool[ _vertexCount - 2 ]; _clippedVertex1PositionScreen.copy( v1.positionScreen ); _clippedVertex2PositionScreen.copy( v2.positionScreen ); if ( clipLine( _clippedVertex1PositionScreen, _clippedVertex2PositionScreen ) === true ) { // Perform the perspective divide _clippedVertex1PositionScreen.multiplyScalar( 1 / _clippedVertex1PositionScreen.w ); _clippedVertex2PositionScreen.multiplyScalar( 1 / _clippedVertex2PositionScreen.w ); _line = getNextLineInPool(); _line.id = object.id; _line.v1.positionScreen.copy( _clippedVertex1PositionScreen ); _line.v2.positionScreen.copy( _clippedVertex2PositionScreen ); _line.z = Math.max( _clippedVertex1PositionScreen.z, _clippedVertex2PositionScreen.z ); _line.material = object.material; if ( object.material.vertexColors === THREE.VertexColors ) { _line.vertexColors[ 0 ].copy( object.geometry.colors[ v ] ); _line.vertexColors[ 1 ].copy( object.geometry.colors[ v - 1 ] ); } _renderData.elements.push( _line ); } } } } else if ( object instanceof THREE.Sprite ) { _vector4.set( _modelMatrix.elements[12], _modelMatrix.elements[13], _modelMatrix.elements[14], 1 ); _vector4.applyMatrix4( _viewProjectionMatrix ); var invW = 1 / _vector4.w; _vector4.z *= invW; if ( _vector4.z >= -1 && _vector4.z <= 1 ) { _sprite = getNextSpriteInPool(); _sprite.id = object.id; _sprite.x = _vector4.x * invW; _sprite.y = _vector4.y * invW; _sprite.z = _vector4.z; _sprite.object = object; _sprite.rotation = object.rotation; _sprite.scale.x = object.scale.x * Math.abs( _sprite.x - ( _vector4.x + camera.projectionMatrix.elements[0] ) / ( _vector4.w + camera.projectionMatrix.elements[12] ) ); _sprite.scale.y = object.scale.y * Math.abs( _sprite.y - ( _vector4.y + camera.projectionMatrix.elements[5] ) / ( _vector4.w + camera.projectionMatrix.elements[13] ) ); _sprite.material = object.material; _renderData.elements.push( _sprite ); } } } if ( sortElements === true ) _renderData.elements.sort( painterSort ); return _renderData; }; // Pools function getNextObjectInPool() { if ( _objectCount === _objectPoolLength ) { var object = new THREE.RenderableObject(); _objectPool.push( object ); _objectPoolLength ++; _objectCount ++; return object; } return _objectPool[ _objectCount ++ ]; } function getNextVertexInPool() { if ( _vertexCount === _vertexPoolLength ) { var vertex = new THREE.RenderableVertex(); _vertexPool.push( vertex ); _vertexPoolLength ++; _vertexCount ++; return vertex; } return _vertexPool[ _vertexCount ++ ]; } function getNextFaceInPool() { if ( _faceCount === _facePoolLength ) { var face = new THREE.RenderableFace(); _facePool.push( face ); _facePoolLength ++; _faceCount ++; return face; } return _facePool[ _faceCount ++ ]; } function getNextLineInPool() { if ( _lineCount === _linePoolLength ) { var line = new THREE.RenderableLine(); _linePool.push( line ); _linePoolLength ++; _lineCount ++ return line; } return _linePool[ _lineCount ++ ]; } function getNextSpriteInPool() { if ( _spriteCount === _spritePoolLength ) { var sprite = new THREE.RenderableSprite(); _spritePool.push( sprite ); _spritePoolLength ++; _spriteCount ++ return sprite; } return _spritePool[ _spriteCount ++ ]; } // function painterSort( a, b ) { if ( a.z !== b.z ) { return b.z - a.z; } else if ( a.id !== b.id ) { return a.id - b.id; } else { return 0; } } function clipLine( s1, s2 ) { var alpha1 = 0, alpha2 = 1, // Calculate the boundary coordinate of each vertex for the near and far clip planes, // Z = -1 and Z = +1, respectively. bc1near = s1.z + s1.w, bc2near = s2.z + s2.w, bc1far = - s1.z + s1.w, bc2far = - s2.z + s2.w; if ( bc1near >= 0 && bc2near >= 0 && bc1far >= 0 && bc2far >= 0 ) { // Both vertices lie entirely within all clip planes. return true; } else if ( ( bc1near < 0 && bc2near < 0) || (bc1far < 0 && bc2far < 0 ) ) { // Both vertices lie entirely outside one of the clip planes. return false; } else { // The line segment spans at least one clip plane. if ( bc1near < 0 ) { // v1 lies outside the near plane, v2 inside alpha1 = Math.max( alpha1, bc1near / ( bc1near - bc2near ) ); } else if ( bc2near < 0 ) { // v2 lies outside the near plane, v1 inside alpha2 = Math.min( alpha2, bc1near / ( bc1near - bc2near ) ); } if ( bc1far < 0 ) { // v1 lies outside the far plane, v2 inside alpha1 = Math.max( alpha1, bc1far / ( bc1far - bc2far ) ); } else if ( bc2far < 0 ) { // v2 lies outside the far plane, v2 inside alpha2 = Math.min( alpha2, bc1far / ( bc1far - bc2far ) ); } if ( alpha2 < alpha1 ) { // The line segment spans two boundaries, but is outside both of them. // (This can't happen when we're only clipping against just near/far but good // to leave the check here for future usage if other clip planes are added.) return false; } else { // Update the s1 and s2 vertices to match the clipped line segment. s1.lerp( s2, alpha1 ); s2.lerp( s1, 1 - alpha2 ); return true; } } } }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Face3 = function ( a, b, c, normal, color, materialIndex ) { this.a = a; this.b = b; this.c = c; this.normal = normal instanceof THREE.Vector3 ? normal : new THREE.Vector3(); this.vertexNormals = normal instanceof Array ? normal : [ ]; this.color = color instanceof THREE.Color ? color : new THREE.Color(); this.vertexColors = color instanceof Array ? color : []; this.vertexTangents = []; this.materialIndex = materialIndex !== undefined ? materialIndex : 0; this.centroid = new THREE.Vector3(); }; THREE.Face3.prototype = { constructor: THREE.Face3, clone: function () { var face = new THREE.Face3( this.a, this.b, this.c ); face.normal.copy( this.normal ); face.color.copy( this.color ); face.centroid.copy( this.centroid ); face.materialIndex = this.materialIndex; var i, il; for ( i = 0, il = this.vertexNormals.length; i < il; i ++ ) face.vertexNormals[ i ] = this.vertexNormals[ i ].clone(); for ( i = 0, il = this.vertexColors.length; i < il; i ++ ) face.vertexColors[ i ] = this.vertexColors[ i ].clone(); for ( i = 0, il = this.vertexTangents.length; i < il; i ++ ) face.vertexTangents[ i ] = this.vertexTangents[ i ].clone(); return face; } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.Face4 = function ( a, b, c, d, normal, color, materialIndex ) { console.warn( 'THREE.Face4 has been removed. A THREE.Face3 will be created instead.') return new THREE.Face3( a, b, c, normal, color, materialIndex ); }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.BufferGeometry = function () { this.id = THREE.GeometryIdCount ++; this.uuid = THREE.Math.generateUUID(); this.name = ''; // attributes this.attributes = {}; // offsets for chunks when using indexed elements this.offsets = []; // boundings this.boundingBox = null; this.boundingSphere = null; }; THREE.BufferGeometry.prototype = { constructor: THREE.BufferGeometry, addAttribute: function ( name, type, numItems, itemSize ) { this.attributes[ name ] = { array: new type( numItems * itemSize ), itemSize: itemSize }; return this.attributes[ name ]; }, applyMatrix: function ( matrix ) { var position = this.attributes.position; if ( position !== undefined ) { matrix.multiplyVector3Array( position.array ); position.needsUpdate = true; } var normal = this.attributes.normal; if ( normal !== undefined ) { var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); normalMatrix.multiplyVector3Array( normal.array ); normal.needsUpdate = true; } }, computeBoundingBox: function () { if ( this.boundingBox === null ) { this.boundingBox = new THREE.Box3(); } var positions = this.attributes[ "position" ].array; if ( positions ) { var bb = this.boundingBox; if( positions.length >= 3 ) { bb.min.x = bb.max.x = positions[ 0 ]; bb.min.y = bb.max.y = positions[ 1 ]; bb.min.z = bb.max.z = positions[ 2 ]; } for ( var i = 3, il = positions.length; i < il; i += 3 ) { var x = positions[ i ]; var y = positions[ i + 1 ]; var z = positions[ i + 2 ]; // bounding box if ( x < bb.min.x ) { bb.min.x = x; } else if ( x > bb.max.x ) { bb.max.x = x; } if ( y < bb.min.y ) { bb.min.y = y; } else if ( y > bb.max.y ) { bb.max.y = y; } if ( z < bb.min.z ) { bb.min.z = z; } else if ( z > bb.max.z ) { bb.max.z = z; } } } if ( positions === undefined || positions.length === 0 ) { this.boundingBox.min.set( 0, 0, 0 ); this.boundingBox.max.set( 0, 0, 0 ); } }, computeBoundingSphere: function () { var box = new THREE.Box3(); var vector = new THREE.Vector3(); return function () { if ( this.boundingSphere === null ) { this.boundingSphere = new THREE.Sphere(); } var positions = this.attributes[ "position" ].array; if ( positions ) { box.makeEmpty(); var center = this.boundingSphere.center; for ( var i = 0, il = positions.length; i < il; i += 3 ) { vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); box.addPoint( vector ); } box.center( center ); var maxRadiusSq = 0; for ( var i = 0, il = positions.length; i < il; i += 3 ) { vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] ); maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); } this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); } } }(), computeVertexNormals: function () { if ( this.attributes[ "position" ] ) { var i, il; var j, jl; var nVertexElements = this.attributes[ "position" ].array.length; if ( this.attributes[ "normal" ] === undefined ) { this.attributes[ "normal" ] = { itemSize: 3, array: new Float32Array( nVertexElements ) }; } else { // reset existing normals to zero for ( i = 0, il = this.attributes[ "normal" ].array.length; i < il; i ++ ) { this.attributes[ "normal" ].array[ i ] = 0; } } var positions = this.attributes[ "position" ].array; var normals = this.attributes[ "normal" ].array; var vA, vB, vC, x, y, z, pA = new THREE.Vector3(), pB = new THREE.Vector3(), pC = new THREE.Vector3(), cb = new THREE.Vector3(), ab = new THREE.Vector3(); // indexed elements if ( this.attributes[ "index" ] ) { var indices = this.attributes[ "index" ].array; var offsets = this.offsets; for ( j = 0, jl = offsets.length; j < jl; ++ j ) { var start = offsets[ j ].start; var count = offsets[ j ].count; var index = offsets[ j ].index; for ( i = start, il = start + count; i < il; i += 3 ) { vA = index + indices[ i ]; vB = index + indices[ i + 1 ]; vC = index + indices[ i + 2 ]; x = positions[ vA * 3 ]; y = positions[ vA * 3 + 1 ]; z = positions[ vA * 3 + 2 ]; pA.set( x, y, z ); x = positions[ vB * 3 ]; y = positions[ vB * 3 + 1 ]; z = positions[ vB * 3 + 2 ]; pB.set( x, y, z ); x = positions[ vC * 3 ]; y = positions[ vC * 3 + 1 ]; z = positions[ vC * 3 + 2 ]; pC.set( x, y, z ); cb.subVectors( pC, pB ); ab.subVectors( pA, pB ); cb.cross( ab ); normals[ vA * 3 ] += cb.x; normals[ vA * 3 + 1 ] += cb.y; normals[ vA * 3 + 2 ] += cb.z; normals[ vB * 3 ] += cb.x; normals[ vB * 3 + 1 ] += cb.y; normals[ vB * 3 + 2 ] += cb.z; normals[ vC * 3 ] += cb.x; normals[ vC * 3 + 1 ] += cb.y; normals[ vC * 3 + 2 ] += cb.z; } } // non-indexed elements (unconnected triangle soup) } else { for ( i = 0, il = positions.length; i < il; i += 9 ) { x = positions[ i ]; y = positions[ i + 1 ]; z = positions[ i + 2 ]; pA.set( x, y, z ); x = positions[ i + 3 ]; y = positions[ i + 4 ]; z = positions[ i + 5 ]; pB.set( x, y, z ); x = positions[ i + 6 ]; y = positions[ i + 7 ]; z = positions[ i + 8 ]; pC.set( x, y, z ); cb.subVectors( pC, pB ); ab.subVectors( pA, pB ); cb.cross( ab ); normals[ i ] = cb.x; normals[ i + 1 ] = cb.y; normals[ i + 2 ] = cb.z; normals[ i + 3 ] = cb.x; normals[ i + 4 ] = cb.y; normals[ i + 5 ] = cb.z; normals[ i + 6 ] = cb.x; normals[ i + 7 ] = cb.y; normals[ i + 8 ] = cb.z; } } this.normalizeNormals(); this.normalsNeedUpdate = true; } }, normalizeNormals: function () { var normals = this.attributes[ "normal" ].array; var x, y, z, n; for ( var i = 0, il = normals.length; i < il; i += 3 ) { x = normals[ i ]; y = normals[ i + 1 ]; z = normals[ i + 2 ]; n = 1.0 / Math.sqrt( x * x + y * y + z * z ); normals[ i ] *= n; normals[ i + 1 ] *= n; normals[ i + 2 ] *= n; } }, computeTangents: function () { // based on http://www.terathon.com/code/tangent.html // (per vertex tangents) if ( this.attributes[ "index" ] === undefined || this.attributes[ "position" ] === undefined || this.attributes[ "normal" ] === undefined || this.attributes[ "uv" ] === undefined ) { console.warn( "Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()" ); return; } var indices = this.attributes[ "index" ].array; var positions = this.attributes[ "position" ].array; var normals = this.attributes[ "normal" ].array; var uvs = this.attributes[ "uv" ].array; var nVertices = positions.length / 3; if ( this.attributes[ "tangent" ] === undefined ) { var nTangentElements = 4 * nVertices; this.attributes[ "tangent" ] = { itemSize: 4, array: new Float32Array( nTangentElements ) }; } var tangents = this.attributes[ "tangent" ].array; var tan1 = [], tan2 = []; for ( var k = 0; k < nVertices; k ++ ) { tan1[ k ] = new THREE.Vector3(); tan2[ k ] = new THREE.Vector3(); } var xA, yA, zA, xB, yB, zB, xC, yC, zC, uA, vA, uB, vB, uC, vC, x1, x2, y1, y2, z1, z2, s1, s2, t1, t2, r; var sdir = new THREE.Vector3(), tdir = new THREE.Vector3(); function handleTriangle( a, b, c ) { xA = positions[ a * 3 ]; yA = positions[ a * 3 + 1 ]; zA = positions[ a * 3 + 2 ]; xB = positions[ b * 3 ]; yB = positions[ b * 3 + 1 ]; zB = positions[ b * 3 + 2 ]; xC = positions[ c * 3 ]; yC = positions[ c * 3 + 1 ]; zC = positions[ c * 3 + 2 ]; uA = uvs[ a * 2 ]; vA = uvs[ a * 2 + 1 ]; uB = uvs[ b * 2 ]; vB = uvs[ b * 2 + 1 ]; uC = uvs[ c * 2 ]; vC = uvs[ c * 2 + 1 ]; x1 = xB - xA; x2 = xC - xA; y1 = yB - yA; y2 = yC - yA; z1 = zB - zA; z2 = zC - zA; s1 = uB - uA; s2 = uC - uA; t1 = vB - vA; t2 = vC - vA; r = 1.0 / ( s1 * t2 - s2 * t1 ); sdir.set( ( t2 * x1 - t1 * x2 ) * r, ( t2 * y1 - t1 * y2 ) * r, ( t2 * z1 - t1 * z2 ) * r ); tdir.set( ( s1 * x2 - s2 * x1 ) * r, ( s1 * y2 - s2 * y1 ) * r, ( s1 * z2 - s2 * z1 ) * r ); tan1[ a ].add( sdir ); tan1[ b ].add( sdir ); tan1[ c ].add( sdir ); tan2[ a ].add( tdir ); tan2[ b ].add( tdir ); tan2[ c ].add( tdir ); } var i, il; var j, jl; var iA, iB, iC; var offsets = this.offsets; for ( j = 0, jl = offsets.length; j < jl; ++ j ) { var start = offsets[ j ].start; var count = offsets[ j ].count; var index = offsets[ j ].index; for ( i = start, il = start + count; i < il; i += 3 ) { iA = index + indices[ i ]; iB = index + indices[ i + 1 ]; iC = index + indices[ i + 2 ]; handleTriangle( iA, iB, iC ); } } var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(); var n = new THREE.Vector3(), n2 = new THREE.Vector3(); var w, t, test; function handleVertex( v ) { n.x = normals[ v * 3 ]; n.y = normals[ v * 3 + 1 ]; n.z = normals[ v * 3 + 2 ]; n2.copy( n ); t = tan1[ v ]; // Gram-Schmidt orthogonalize tmp.copy( t ); tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); // Calculate handedness tmp2.crossVectors( n2, t ); test = tmp2.dot( tan2[ v ] ); w = ( test < 0.0 ) ? -1.0 : 1.0; tangents[ v * 4 ] = tmp.x; tangents[ v * 4 + 1 ] = tmp.y; tangents[ v * 4 + 2 ] = tmp.z; tangents[ v * 4 + 3 ] = w; } for ( j = 0, jl = offsets.length; j < jl; ++ j ) { var start = offsets[ j ].start; var count = offsets[ j ].count; var index = offsets[ j ].index; for ( i = start, il = start + count; i < il; i += 3 ) { iA = index + indices[ i ]; iB = index + indices[ i + 1 ]; iC = index + indices[ i + 2 ]; handleVertex( iA ); handleVertex( iB ); handleVertex( iC ); } } }, /* computeOffsets Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices. This method will effectively rewrite the index buffer and remap all attributes to match the new indices. WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets. indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks. */ computeOffsets: function(indexBufferSize) { var size = indexBufferSize; if(indexBufferSize === undefined) size = 65535; //WebGL limits type of index buffer values to 16-bit. var s = Date.now(); var indices = this.attributes['index'].array; var vertices = this.attributes['position'].array; var verticesCount = (vertices.length/3); var facesCount = (indices.length/3); /* console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length); console.log("Faces to process: "+(indices.length/3)); console.log("Reordering "+verticesCount+" vertices."); */ var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers var indexPtr = 0; var vertexPtr = 0; var offsets = [ { start:0, count:0, index:0 } ]; var offset = offsets[0]; var duplicatedVertices = 0; var newVerticeMaps = 0; var faceVertices = new Int32Array(6); var vertexMap = new Int32Array( vertices.length ); var revVertexMap = new Int32Array( vertices.length ); for(var j = 0; j < vertices.length; j++) { vertexMap[j] = -1; revVertexMap[j] = -1; } /* Traverse every face and reorder vertices in the proper offsets of 65k. We can have more than 65k entries in the index buffer per offset, but only reference 65k values. */ for(var findex = 0; findex < facesCount; findex++) { newVerticeMaps = 0; for(var vo = 0; vo < 3; vo++) { var vid = indices[ findex*3 + vo ]; if(vertexMap[vid] == -1) { //Unmapped vertice faceVertices[vo*2] = vid; faceVertices[vo*2+1] = -1; newVerticeMaps++; } else if(vertexMap[vid] < offset.index) { //Reused vertices from previous block (duplicate) faceVertices[vo*2] = vid; faceVertices[vo*2+1] = -1; duplicatedVertices++; } else { //Reused vertice in the current block faceVertices[vo*2] = vid; faceVertices[vo*2+1] = vertexMap[vid]; } } var faceMax = vertexPtr + newVerticeMaps; if(faceMax > (offset.index + size)) { var new_offset = { start:indexPtr, count:0, index:vertexPtr }; offsets.push(new_offset); offset = new_offset; //Re-evaluate reused vertices in light of new offset. for(var v = 0; v < 6; v+=2) { var new_vid = faceVertices[v+1]; if(new_vid > -1 && new_vid < offset.index) faceVertices[v+1] = -1; } } //Reindex the face. for(var v = 0; v < 6; v+=2) { var vid = faceVertices[v]; var new_vid = faceVertices[v+1]; if(new_vid === -1) new_vid = vertexPtr++; vertexMap[vid] = new_vid; revVertexMap[new_vid] = vid; sortedIndices[indexPtr++] = new_vid - offset.index; //XXX overflows at 16bit offset.count++; } } /* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */ this.reorderBuffers(sortedIndices, revVertexMap, vertexPtr); this.offsets = offsets; /* var orderTime = Date.now(); console.log("Reorder time: "+(orderTime-s)+"ms"); console.log("Duplicated "+duplicatedVertices+" vertices."); console.log("Compute Buffers time: "+(Date.now()-s)+"ms"); console.log("Draw offsets: "+offsets.length); */ return offsets; }, /* reoderBuffers: Reorder attributes based on a new indexBuffer and indexMap. indexBuffer - Uint16Array of the new ordered indices. indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex. vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack). */ reorderBuffers: function(indexBuffer, indexMap, vertexCount) { /* Create a copy of all attributes for reordering. */ var sortedAttributes = {}; var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; for( var attr in this.attributes ) { if(attr == 'index') continue; var sourceArray = this.attributes[attr].array; for ( var i = 0, il = types.length; i < il; i++ ) { var type = types[i]; if (sourceArray instanceof type) { sortedAttributes[attr] = new type( this.attributes[attr].itemSize * vertexCount ); break; } } } /* Move attribute positions based on the new index map */ for(var new_vid = 0; new_vid < vertexCount; new_vid++) { var vid = indexMap[new_vid]; for ( var attr in this.attributes ) { if(attr == 'index') continue; var attrArray = this.attributes[attr].array; var attrSize = this.attributes[attr].itemSize; var sortedAttr = sortedAttributes[attr]; for(var k = 0; k < attrSize; k++) sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ]; } } /* Carry the new sorted buffers locally */ this.attributes['index'].array = indexBuffer; for ( var attr in this.attributes ) { if(attr == 'index') continue; this.attributes[attr].array = sortedAttributes[attr]; this.attributes[attr].numItems = this.attributes[attr].itemSize * vertexCount; } }, clone: function () { var geometry = new THREE.BufferGeometry(); var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ]; for ( var attr in this.attributes ) { var sourceAttr = this.attributes[ attr ]; var sourceArray = sourceAttr.array; var attribute = { itemSize: sourceAttr.itemSize, array: null }; for ( var i = 0, il = types.length; i < il; i ++ ) { var type = types[ i ]; if ( sourceArray instanceof type ) { attribute.array = new type( sourceArray ); break; } } geometry.attributes[ attr ] = attribute; } for ( var i = 0, il = this.offsets.length; i < il; i ++ ) { var offset = this.offsets[ i ]; geometry.offsets.push( { start: offset.start, index: offset.index, count: offset.count } ); } return geometry; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype ); /** * @author mrdoob / http://mrdoob.com/ * @author kile / http://kile.stravaganza.org/ * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author zz85 / http://www.lab4games.net/zz85/blog * @author bhouston / http://exocortex.com */ THREE.Geometry = function () { this.id = THREE.GeometryIdCount ++; this.uuid = THREE.Math.generateUUID(); this.name = ''; this.vertices = []; this.colors = []; // one-to-one vertex colors, used in ParticleSystem and Line this.faces = []; this.faceVertexUvs = [[]]; this.morphTargets = []; this.morphColors = []; this.morphNormals = []; this.skinWeights = []; this.skinIndices = []; this.lineDistances = []; this.boundingBox = null; this.boundingSphere = null; this.hasTangents = false; this.dynamic = true; // the intermediate typed arrays will be deleted when set to false // update flags this.verticesNeedUpdate = false; this.elementsNeedUpdate = false; this.uvsNeedUpdate = false; this.normalsNeedUpdate = false; this.tangentsNeedUpdate = false; this.colorsNeedUpdate = false; this.lineDistancesNeedUpdate = false; this.buffersNeedUpdate = false; }; THREE.Geometry.prototype = { constructor: THREE.Geometry, applyMatrix: function ( matrix ) { var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); for ( var i = 0, il = this.vertices.length; i < il; i ++ ) { var vertex = this.vertices[ i ]; vertex.applyMatrix4( matrix ); } for ( var i = 0, il = this.faces.length; i < il; i ++ ) { var face = this.faces[ i ]; face.normal.applyMatrix3( normalMatrix ).normalize(); for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { face.vertexNormals[ j ].applyMatrix3( normalMatrix ).normalize(); } face.centroid.applyMatrix4( matrix ); } if ( this.boundingBox instanceof THREE.Box3 ) { this.computeBoundingBox(); } if ( this.boundingSphere instanceof THREE.Sphere ) { this.computeBoundingSphere(); } }, computeCentroids: function () { var f, fl, face; for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; face.centroid.set( 0, 0, 0 ); face.centroid.add( this.vertices[ face.a ] ); face.centroid.add( this.vertices[ face.b ] ); face.centroid.add( this.vertices[ face.c ] ); face.centroid.divideScalar( 3 ); } }, computeFaceNormals: function () { var cb = new THREE.Vector3(), ab = new THREE.Vector3(); for ( var f = 0, fl = this.faces.length; f < fl; f ++ ) { var face = this.faces[ f ]; var vA = this.vertices[ face.a ]; var vB = this.vertices[ face.b ]; var vC = this.vertices[ face.c ]; cb.subVectors( vC, vB ); ab.subVectors( vA, vB ); cb.cross( ab ); cb.normalize(); face.normal.copy( cb ); } }, computeVertexNormals: function ( areaWeighted ) { var v, vl, f, fl, face, vertices; vertices = new Array( this.vertices.length ); for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { vertices[ v ] = new THREE.Vector3(); } if ( areaWeighted ) { // vertex normals weighted by triangle areas // http://www.iquilezles.org/www/articles/normals/normals.htm var vA, vB, vC, vD; var cb = new THREE.Vector3(), ab = new THREE.Vector3(), db = new THREE.Vector3(), dc = new THREE.Vector3(), bc = new THREE.Vector3(); for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; vA = this.vertices[ face.a ]; vB = this.vertices[ face.b ]; vC = this.vertices[ face.c ]; cb.subVectors( vC, vB ); ab.subVectors( vA, vB ); cb.cross( ab ); vertices[ face.a ].add( cb ); vertices[ face.b ].add( cb ); vertices[ face.c ].add( cb ); } } else { for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; vertices[ face.a ].add( face.normal ); vertices[ face.b ].add( face.normal ); vertices[ face.c ].add( face.normal ); } } for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { vertices[ v ].normalize(); } for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; face.vertexNormals[ 0 ] = vertices[ face.a ].clone(); face.vertexNormals[ 1 ] = vertices[ face.b ].clone(); face.vertexNormals[ 2 ] = vertices[ face.c ].clone(); } }, computeMorphNormals: function () { var i, il, f, fl, face; // save original normals // - create temp variables on first access // otherwise just copy (for faster repeated calls) for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; if ( ! face.__originalFaceNormal ) { face.__originalFaceNormal = face.normal.clone(); } else { face.__originalFaceNormal.copy( face.normal ); } if ( ! face.__originalVertexNormals ) face.__originalVertexNormals = []; for ( i = 0, il = face.vertexNormals.length; i < il; i ++ ) { if ( ! face.__originalVertexNormals[ i ] ) { face.__originalVertexNormals[ i ] = face.vertexNormals[ i ].clone(); } else { face.__originalVertexNormals[ i ].copy( face.vertexNormals[ i ] ); } } } // use temp geometry to compute face and vertex normals for each morph var tmpGeo = new THREE.Geometry(); tmpGeo.faces = this.faces; for ( i = 0, il = this.morphTargets.length; i < il; i ++ ) { // create on first access if ( ! this.morphNormals[ i ] ) { this.morphNormals[ i ] = {}; this.morphNormals[ i ].faceNormals = []; this.morphNormals[ i ].vertexNormals = []; var dstNormalsFace = this.morphNormals[ i ].faceNormals; var dstNormalsVertex = this.morphNormals[ i ].vertexNormals; var faceNormal, vertexNormals; for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; faceNormal = new THREE.Vector3(); vertexNormals = { a: new THREE.Vector3(), b: new THREE.Vector3(), c: new THREE.Vector3() }; dstNormalsFace.push( faceNormal ); dstNormalsVertex.push( vertexNormals ); } } var morphNormals = this.morphNormals[ i ]; // set vertices to morph target tmpGeo.vertices = this.morphTargets[ i ].vertices; // compute morph normals tmpGeo.computeFaceNormals(); tmpGeo.computeVertexNormals(); // store morph normals var faceNormal, vertexNormals; for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; faceNormal = morphNormals.faceNormals[ f ]; vertexNormals = morphNormals.vertexNormals[ f ]; faceNormal.copy( face.normal ); vertexNormals.a.copy( face.vertexNormals[ 0 ] ); vertexNormals.b.copy( face.vertexNormals[ 1 ] ); vertexNormals.c.copy( face.vertexNormals[ 2 ] ); } } // restore original normals for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; face.normal = face.__originalFaceNormal; face.vertexNormals = face.__originalVertexNormals; } }, computeTangents: function () { // based on http://www.terathon.com/code/tangent.html // tangents go to vertices var f, fl, v, vl, i, il, vertexIndex, face, uv, vA, vB, vC, uvA, uvB, uvC, x1, x2, y1, y2, z1, z2, s1, s2, t1, t2, r, t, test, tan1 = [], tan2 = [], sdir = new THREE.Vector3(), tdir = new THREE.Vector3(), tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3(), n = new THREE.Vector3(), w; for ( v = 0, vl = this.vertices.length; v < vl; v ++ ) { tan1[ v ] = new THREE.Vector3(); tan2[ v ] = new THREE.Vector3(); } function handleTriangle( context, a, b, c, ua, ub, uc ) { vA = context.vertices[ a ]; vB = context.vertices[ b ]; vC = context.vertices[ c ]; uvA = uv[ ua ]; uvB = uv[ ub ]; uvC = uv[ uc ]; x1 = vB.x - vA.x; x2 = vC.x - vA.x; y1 = vB.y - vA.y; y2 = vC.y - vA.y; z1 = vB.z - vA.z; z2 = vC.z - vA.z; s1 = uvB.x - uvA.x; s2 = uvC.x - uvA.x; t1 = uvB.y - uvA.y; t2 = uvC.y - uvA.y; r = 1.0 / ( s1 * t2 - s2 * t1 ); sdir.set( ( t2 * x1 - t1 * x2 ) * r, ( t2 * y1 - t1 * y2 ) * r, ( t2 * z1 - t1 * z2 ) * r ); tdir.set( ( s1 * x2 - s2 * x1 ) * r, ( s1 * y2 - s2 * y1 ) * r, ( s1 * z2 - s2 * z1 ) * r ); tan1[ a ].add( sdir ); tan1[ b ].add( sdir ); tan1[ c ].add( sdir ); tan2[ a ].add( tdir ); tan2[ b ].add( tdir ); tan2[ c ].add( tdir ); } for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; uv = this.faceVertexUvs[ 0 ][ f ]; // use UV layer 0 for tangents handleTriangle( this, face.a, face.b, face.c, 0, 1, 2 ); } var faceIndex = [ 'a', 'b', 'c', 'd' ]; for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; for ( i = 0; i < Math.min( face.vertexNormals.length, 3 ); i++ ) { n.copy( face.vertexNormals[ i ] ); vertexIndex = face[ faceIndex[ i ] ]; t = tan1[ vertexIndex ]; // Gram-Schmidt orthogonalize tmp.copy( t ); tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize(); // Calculate handedness tmp2.crossVectors( face.vertexNormals[ i ], t ); test = tmp2.dot( tan2[ vertexIndex ] ); w = (test < 0.0) ? -1.0 : 1.0; face.vertexTangents[ i ] = new THREE.Vector4( tmp.x, tmp.y, tmp.z, w ); } } this.hasTangents = true; }, computeLineDistances: function ( ) { var d = 0; var vertices = this.vertices; for ( var i = 0, il = vertices.length; i < il; i ++ ) { if ( i > 0 ) { d += vertices[ i ].distanceTo( vertices[ i - 1 ] ); } this.lineDistances[ i ] = d; } }, computeBoundingBox: function () { if ( this.boundingBox === null ) { this.boundingBox = new THREE.Box3(); } this.boundingBox.setFromPoints( this.vertices ); }, computeBoundingSphere: function () { if ( this.boundingSphere === null ) { this.boundingSphere = new THREE.Sphere(); } this.boundingSphere.setFromPoints( this.vertices ); }, /* * Checks for duplicate vertices with hashmap. * Duplicated vertices are removed * and faces' vertices are updated. */ mergeVertices: function () { var verticesMap = {}; // Hashmap for looking up vertice by position coordinates (and making sure they are unique) var unique = [], changes = []; var v, key; var precisionPoints = 4; // number of decimal points, eg. 4 for epsilon of 0.0001 var precision = Math.pow( 10, precisionPoints ); var i,il, face; var indices, k, j, jl, u; for ( i = 0, il = this.vertices.length; i < il; i ++ ) { v = this.vertices[ i ]; key = Math.round( v.x * precision ) + '_' + Math.round( v.y * precision ) + '_' + Math.round( v.z * precision ); if ( verticesMap[ key ] === undefined ) { verticesMap[ key ] = i; unique.push( this.vertices[ i ] ); changes[ i ] = unique.length - 1; } else { //console.log('Duplicate vertex found. ', i, ' could be using ', verticesMap[key]); changes[ i ] = changes[ verticesMap[ key ] ]; } }; // if faces are completely degenerate after merging vertices, we // have to remove them from the geometry. var faceIndicesToRemove = []; for( i = 0, il = this.faces.length; i < il; i ++ ) { face = this.faces[ i ]; face.a = changes[ face.a ]; face.b = changes[ face.b ]; face.c = changes[ face.c ]; indices = [ face.a, face.b, face.c ]; var dupIndex = -1; // if any duplicate vertices are found in a Face3 // we have to remove the face as nothing can be saved for ( var n = 0; n < 3; n ++ ) { if ( indices[ n ] == indices[ ( n + 1 ) % 3 ] ) { dupIndex = n; faceIndicesToRemove.push( i ); break; } } } for ( i = faceIndicesToRemove.length - 1; i >= 0; i -- ) { var idx = faceIndicesToRemove[ i ]; this.faces.splice( idx, 1 ); for ( j = 0, jl = this.faceVertexUvs.length; j < jl; j ++ ) { this.faceVertexUvs[ j ].splice( idx, 1 ); } } // Use unique set of vertices var diff = this.vertices.length - unique.length; this.vertices = unique; return diff; }, // Geometry splitting makeGroups: ( function () { var geometryGroupCounter = 0; return function ( usesFaceMaterial ) { var f, fl, face, materialIndex, groupHash, hash_map = {}; var numMorphTargets = this.morphTargets.length; var numMorphNormals = this.morphNormals.length; this.geometryGroups = {}; for ( f = 0, fl = this.faces.length; f < fl; f ++ ) { face = this.faces[ f ]; materialIndex = usesFaceMaterial ? face.materialIndex : 0; if ( ! ( materialIndex in hash_map ) ) { hash_map[ materialIndex ] = { 'hash': materialIndex, 'counter': 0 }; } groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; if ( ! ( groupHash in this.geometryGroups ) ) { this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; } if ( this.geometryGroups[ groupHash ].vertices + 3 > 65535 ) { hash_map[ materialIndex ].counter += 1; groupHash = hash_map[ materialIndex ].hash + '_' + hash_map[ materialIndex ].counter; if ( ! ( groupHash in this.geometryGroups ) ) { this.geometryGroups[ groupHash ] = { 'faces3': [], 'materialIndex': materialIndex, 'vertices': 0, 'numMorphTargets': numMorphTargets, 'numMorphNormals': numMorphNormals }; } } this.geometryGroups[ groupHash ].faces3.push( f ); this.geometryGroups[ groupHash ].vertices += 3; } this.geometryGroupsList = []; for ( var g in this.geometryGroups ) { this.geometryGroups[ g ].id = geometryGroupCounter ++; this.geometryGroupsList.push( this.geometryGroups[ g ] ); } }; } )(), clone: function () { var geometry = new THREE.Geometry(); var vertices = this.vertices; for ( var i = 0, il = vertices.length; i < il; i ++ ) { geometry.vertices.push( vertices[ i ].clone() ); } var faces = this.faces; for ( var i = 0, il = faces.length; i < il; i ++ ) { geometry.faces.push( faces[ i ].clone() ); } var uvs = this.faceVertexUvs[ 0 ]; for ( var i = 0, il = uvs.length; i < il; i ++ ) { var uv = uvs[ i ], uvCopy = []; for ( var j = 0, jl = uv.length; j < jl; j ++ ) { uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); } geometry.faceVertexUvs[ 0 ].push( uvCopy ); } return geometry; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.Geometry.prototype ); THREE.GeometryIdCount = 0; /** * @author mrdoob / http://mrdoob.com/ */ THREE.Geometry2 = function ( size ) { THREE.BufferGeometry.call( this ); this.vertices = this.addAttribute( 'position', Float32Array, size, 3 ).array; this.normals = this.addAttribute( 'normal', Float32Array, size, 3 ).array; this.uvs = this.addAttribute( 'uv', Float32Array, size, 2 ).array; this.boundingBox = null; this.boundingSphere = null; }; THREE.Geometry2.prototype = Object.create( THREE.BufferGeometry.prototype );/** * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ * @author WestLangley / http://github.com/WestLangley */ THREE.Camera = function () { THREE.Object3D.call( this ); this.matrixWorldInverse = new THREE.Matrix4(); this.projectionMatrix = new THREE.Matrix4(); }; THREE.Camera.prototype = Object.create( THREE.Object3D.prototype ); THREE.Camera.prototype.lookAt = function () { // This routine does not support cameras with rotated and/or translated parent(s) var m1 = new THREE.Matrix4(); return function ( vector ) { m1.lookAt( this.position, vector, this.up ); this.quaternion.setFromRotationMatrix( m1 ); }; }(); THREE.Camera.prototype.clone = function (camera) { if ( camera === undefined ) camera = new THREE.Camera(); THREE.Object3D.prototype.clone.call( this, camera ); camera.matrixWorldInverse.copy( this.matrixWorldInverse ); camera.projectionMatrix.copy( this.projectionMatrix ); return camera; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.OrthographicCamera = function ( left, right, top, bottom, near, far ) { THREE.Camera.call( this ); this.left = left; this.right = right; this.top = top; this.bottom = bottom; this.near = ( near !== undefined ) ? near : 0.1; this.far = ( far !== undefined ) ? far : 2000; this.updateProjectionMatrix(); }; THREE.OrthographicCamera.prototype = Object.create( THREE.Camera.prototype ); THREE.OrthographicCamera.prototype.updateProjectionMatrix = function () { this.projectionMatrix.makeOrthographic( this.left, this.right, this.top, this.bottom, this.near, this.far ); }; THREE.OrthographicCamera.prototype.clone = function () { var camera = new THREE.OrthographicCamera(); THREE.Camera.prototype.clone.call( this, camera ); camera.left = this.left; camera.right = this.right; camera.top = this.top; camera.bottom = this.bottom; camera.near = this.near; camera.far = this.far; return camera; }; /** * @author mrdoob / http://mrdoob.com/ * @author greggman / http://games.greggman.com/ * @author zz85 / http://www.lab4games.net/zz85/blog */ THREE.PerspectiveCamera = function ( fov, aspect, near, far ) { THREE.Camera.call( this ); this.fov = fov !== undefined ? fov : 50; this.aspect = aspect !== undefined ? aspect : 1; this.near = near !== undefined ? near : 0.1; this.far = far !== undefined ? far : 2000; this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype = Object.create( THREE.Camera.prototype ); /** * Uses Focal Length (in mm) to estimate and set FOV * 35mm (fullframe) camera is used if frame size is not specified; * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html */ THREE.PerspectiveCamera.prototype.setLens = function ( focalLength, frameHeight ) { if ( frameHeight === undefined ) frameHeight = 24; this.fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); this.updateProjectionMatrix(); } /** * Sets an offset in a larger frustum. This is useful for multi-window or * multi-monitor/multi-machine setups. * * For example, if you have 3x2 monitors and each monitor is 1920x1080 and * the monitors are in grid like this * * +---+---+---+ * | A | B | C | * +---+---+---+ * | D | E | F | * +---+---+---+ * * then for each monitor you would call it like this * * var w = 1920; * var h = 1080; * var fullWidth = w * 3; * var fullHeight = h * 2; * * --A-- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 0, w, h ); * --B-- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 0, w, h ); * --C-- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 0, w, h ); * --D-- * camera.setOffset( fullWidth, fullHeight, w * 0, h * 1, w, h ); * --E-- * camera.setOffset( fullWidth, fullHeight, w * 1, h * 1, w, h ); * --F-- * camera.setOffset( fullWidth, fullHeight, w * 2, h * 1, w, h ); * * Note there is no reason monitors have to be the same size or in a grid. */ THREE.PerspectiveCamera.prototype.setViewOffset = function ( fullWidth, fullHeight, x, y, width, height ) { this.fullWidth = fullWidth; this.fullHeight = fullHeight; this.x = x; this.y = y; this.width = width; this.height = height; this.updateProjectionMatrix(); }; THREE.PerspectiveCamera.prototype.updateProjectionMatrix = function () { if ( this.fullWidth ) { var aspect = this.fullWidth / this.fullHeight; var top = Math.tan( THREE.Math.degToRad( this.fov * 0.5 ) ) * this.near; var bottom = -top; var left = aspect * bottom; var right = aspect * top; var width = Math.abs( right - left ); var height = Math.abs( top - bottom ); this.projectionMatrix.makeFrustum( left + this.x * width / this.fullWidth, left + ( this.x + this.width ) * width / this.fullWidth, top - ( this.y + this.height ) * height / this.fullHeight, top - this.y * height / this.fullHeight, this.near, this.far ); } else { this.projectionMatrix.makePerspective( this.fov, this.aspect, this.near, this.far ); } }; THREE.PerspectiveCamera.prototype.clone = function () { var camera = new THREE.PerspectiveCamera(); THREE.Camera.prototype.clone.call( this, camera ); camera.fov = this.fov; camera.aspect = this.aspect; camera.near = this.near; camera.far = this.far; return camera; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Light = function ( color ) { THREE.Object3D.call( this ); this.color = new THREE.Color( color ); }; THREE.Light.prototype = Object.create( THREE.Object3D.prototype ); THREE.Light.prototype.clone = function ( light ) { if ( light === undefined ) light = new THREE.Light(); THREE.Object3D.prototype.clone.call( this, light ); light.color.copy( this.color ); return light; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.AmbientLight = function ( color ) { THREE.Light.call( this, color ); }; THREE.AmbientLight.prototype = Object.create( THREE.Light.prototype ); THREE.AmbientLight.prototype.clone = function () { var light = new THREE.AmbientLight(); THREE.Light.prototype.clone.call( this, light ); return light; }; /** * @author MPanknin / http://www.redplant.de/ * @author alteredq / http://alteredqualia.com/ */ THREE.AreaLight = function ( color, intensity ) { THREE.Light.call( this, color ); this.normal = new THREE.Vector3( 0, -1, 0 ); this.right = new THREE.Vector3( 1, 0, 0 ); this.intensity = ( intensity !== undefined ) ? intensity : 1; this.width = 1.0; this.height = 1.0; this.constantAttenuation = 1.5; this.linearAttenuation = 0.5; this.quadraticAttenuation = 0.1; }; THREE.AreaLight.prototype = Object.create( THREE.Light.prototype ); /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.DirectionalLight = function ( color, intensity ) { THREE.Light.call( this, color ); this.position.set( 0, 1, 0 ); this.target = new THREE.Object3D(); this.intensity = ( intensity !== undefined ) ? intensity : 1; this.castShadow = false; this.onlyShadow = false; // this.shadowCameraNear = 50; this.shadowCameraFar = 5000; this.shadowCameraLeft = -500; this.shadowCameraRight = 500; this.shadowCameraTop = 500; this.shadowCameraBottom = -500; this.shadowCameraVisible = false; this.shadowBias = 0; this.shadowDarkness = 0.5; this.shadowMapWidth = 512; this.shadowMapHeight = 512; // this.shadowCascade = false; this.shadowCascadeOffset = new THREE.Vector3( 0, 0, -1000 ); this.shadowCascadeCount = 2; this.shadowCascadeBias = [ 0, 0, 0 ]; this.shadowCascadeWidth = [ 512, 512, 512 ]; this.shadowCascadeHeight = [ 512, 512, 512 ]; this.shadowCascadeNearZ = [ -1.000, 0.990, 0.998 ]; this.shadowCascadeFarZ = [ 0.990, 0.998, 1.000 ]; this.shadowCascadeArray = []; // this.shadowMap = null; this.shadowMapSize = null; this.shadowCamera = null; this.shadowMatrix = null; }; THREE.DirectionalLight.prototype = Object.create( THREE.Light.prototype ); THREE.DirectionalLight.prototype.clone = function () { var light = new THREE.DirectionalLight(); THREE.Light.prototype.clone.call( this, light ); light.target = this.target.clone(); light.intensity = this.intensity; light.castShadow = this.castShadow; light.onlyShadow = this.onlyShadow; return light; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.HemisphereLight = function ( skyColor, groundColor, intensity ) { THREE.Light.call( this, skyColor ); this.position.set( 0, 100, 0 ); this.groundColor = new THREE.Color( groundColor ); this.intensity = ( intensity !== undefined ) ? intensity : 1; }; THREE.HemisphereLight.prototype = Object.create( THREE.Light.prototype ); THREE.HemisphereLight.prototype.clone = function () { var light = new THREE.HemisphereLight(); THREE.Light.prototype.clone.call( this, light ); light.groundColor.copy( this.groundColor ); light.intensity = this.intensity; return light; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.PointLight = function ( color, intensity, distance ) { THREE.Light.call( this, color ); this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; }; THREE.PointLight.prototype = Object.create( THREE.Light.prototype ); THREE.PointLight.prototype.clone = function () { var light = new THREE.PointLight(); THREE.Light.prototype.clone.call( this, light ); light.intensity = this.intensity; light.distance = this.distance; return light; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.SpotLight = function ( color, intensity, distance, angle, exponent ) { THREE.Light.call( this, color ); this.position.set( 0, 1, 0 ); this.target = new THREE.Object3D(); this.intensity = ( intensity !== undefined ) ? intensity : 1; this.distance = ( distance !== undefined ) ? distance : 0; this.angle = ( angle !== undefined ) ? angle : Math.PI / 3; this.exponent = ( exponent !== undefined ) ? exponent : 10; this.castShadow = false; this.onlyShadow = false; // this.shadowCameraNear = 50; this.shadowCameraFar = 5000; this.shadowCameraFov = 50; this.shadowCameraVisible = false; this.shadowBias = 0; this.shadowDarkness = 0.5; this.shadowMapWidth = 512; this.shadowMapHeight = 512; // this.shadowMap = null; this.shadowMapSize = null; this.shadowCamera = null; this.shadowMatrix = null; }; THREE.SpotLight.prototype = Object.create( THREE.Light.prototype ); THREE.SpotLight.prototype.clone = function () { var light = new THREE.SpotLight(); THREE.Light.prototype.clone.call( this, light ); light.target = this.target.clone(); light.intensity = this.intensity; light.distance = this.distance; light.angle = this.angle; light.exponent = this.exponent; light.castShadow = this.castShadow; light.onlyShadow = this.onlyShadow; return light; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.Loader = function ( showStatus ) { this.showStatus = showStatus; this.statusDomElement = showStatus ? THREE.Loader.prototype.addStatusElement() : null; this.onLoadStart = function () {}; this.onLoadProgress = function () {}; this.onLoadComplete = function () {}; }; THREE.Loader.prototype = { constructor: THREE.Loader, crossOrigin: undefined, addStatusElement: function () { var e = document.createElement( "div" ); e.style.position = "absolute"; e.style.right = "0px"; e.style.top = "0px"; e.style.fontSize = "0.8em"; e.style.textAlign = "left"; e.style.background = "rgba(0,0,0,0.25)"; e.style.color = "#fff"; e.style.width = "120px"; e.style.padding = "0.5em 0.5em 0.5em 0.5em"; e.style.zIndex = 1000; e.innerHTML = "Loading ..."; return e; }, updateProgress: function ( progress ) { var message = "Loaded "; if ( progress.total ) { message += ( 100 * progress.loaded / progress.total ).toFixed(0) + "%"; } else { message += ( progress.loaded / 1000 ).toFixed(2) + " KB"; } this.statusDomElement.innerHTML = message; }, extractUrlBase: function ( url ) { var parts = url.split( '/' ); if ( parts.length === 1 ) return './'; parts.pop(); return parts.join( '/' ) + '/'; }, initMaterials: function ( materials, texturePath ) { var array = []; for ( var i = 0; i < materials.length; ++ i ) { array[ i ] = THREE.Loader.prototype.createMaterial( materials[ i ], texturePath ); } return array; }, needsTangents: function ( materials ) { for( var i = 0, il = materials.length; i < il; i ++ ) { var m = materials[ i ]; if ( m instanceof THREE.ShaderMaterial ) return true; } return false; }, createMaterial: function ( m, texturePath ) { var _this = this; function is_pow2( n ) { var l = Math.log( n ) / Math.LN2; return Math.floor( l ) == l; } function nearest_pow2( n ) { var l = Math.log( n ) / Math.LN2; return Math.pow( 2, Math.round( l ) ); } function load_image( where, url ) { var image = new Image(); image.onload = function () { if ( !is_pow2( this.width ) || !is_pow2( this.height ) ) { var width = nearest_pow2( this.width ); var height = nearest_pow2( this.height ); where.image.width = width; where.image.height = height; where.image.getContext( '2d' ).drawImage( this, 0, 0, width, height ); } else { where.image = this; } where.needsUpdate = true; }; if ( _this.crossOrigin !== undefined ) image.crossOrigin = _this.crossOrigin; image.src = url; } function create_texture( where, name, sourceFile, repeat, offset, wrap, anisotropy ) { var isCompressed = /\.dds$/i.test( sourceFile ); var fullPath = texturePath + sourceFile; if ( isCompressed ) { var texture = THREE.ImageUtils.loadCompressedTexture( fullPath ); where[ name ] = texture; } else { var texture = document.createElement( 'canvas' ); where[ name ] = new THREE.Texture( texture ); } where[ name ].sourceFile = sourceFile; if( repeat ) { where[ name ].repeat.set( repeat[ 0 ], repeat[ 1 ] ); if ( repeat[ 0 ] !== 1 ) where[ name ].wrapS = THREE.RepeatWrapping; if ( repeat[ 1 ] !== 1 ) where[ name ].wrapT = THREE.RepeatWrapping; } if ( offset ) { where[ name ].offset.set( offset[ 0 ], offset[ 1 ] ); } if ( wrap ) { var wrapMap = { "repeat": THREE.RepeatWrapping, "mirror": THREE.MirroredRepeatWrapping } if ( wrapMap[ wrap[ 0 ] ] !== undefined ) where[ name ].wrapS = wrapMap[ wrap[ 0 ] ]; if ( wrapMap[ wrap[ 1 ] ] !== undefined ) where[ name ].wrapT = wrapMap[ wrap[ 1 ] ]; } if ( anisotropy ) { where[ name ].anisotropy = anisotropy; } if ( ! isCompressed ) { load_image( where[ name ], fullPath ); } } function rgb2hex( rgb ) { return ( rgb[ 0 ] * 255 << 16 ) + ( rgb[ 1 ] * 255 << 8 ) + rgb[ 2 ] * 255; } // defaults var mtype = "MeshLambertMaterial"; var mpars = { color: 0xeeeeee, opacity: 1.0, map: null, lightMap: null, normalMap: null, bumpMap: null, wireframe: false }; // parameters from model file if ( m.shading ) { var shading = m.shading.toLowerCase(); if ( shading === "phong" ) mtype = "MeshPhongMaterial"; else if ( shading === "basic" ) mtype = "MeshBasicMaterial"; } if ( m.blending !== undefined && THREE[ m.blending ] !== undefined ) { mpars.blending = THREE[ m.blending ]; } if ( m.transparent !== undefined || m.opacity < 1.0 ) { mpars.transparent = m.transparent; } if ( m.depthTest !== undefined ) { mpars.depthTest = m.depthTest; } if ( m.depthWrite !== undefined ) { mpars.depthWrite = m.depthWrite; } if ( m.visible !== undefined ) { mpars.visible = m.visible; } if ( m.flipSided !== undefined ) { mpars.side = THREE.BackSide; } if ( m.doubleSided !== undefined ) { mpars.side = THREE.DoubleSide; } if ( m.wireframe !== undefined ) { mpars.wireframe = m.wireframe; } if ( m.vertexColors !== undefined ) { if ( m.vertexColors === "face" ) { mpars.vertexColors = THREE.FaceColors; } else if ( m.vertexColors ) { mpars.vertexColors = THREE.VertexColors; } } // colors if ( m.colorDiffuse ) { mpars.color = rgb2hex( m.colorDiffuse ); } else if ( m.DbgColor ) { mpars.color = m.DbgColor; } if ( m.colorSpecular ) { mpars.specular = rgb2hex( m.colorSpecular ); } if ( m.colorAmbient ) { mpars.ambient = rgb2hex( m.colorAmbient ); } // modifiers if ( m.transparency ) { mpars.opacity = m.transparency; } if ( m.specularCoef ) { mpars.shininess = m.specularCoef; } // textures if ( m.mapDiffuse && texturePath ) { create_texture( mpars, "map", m.mapDiffuse, m.mapDiffuseRepeat, m.mapDiffuseOffset, m.mapDiffuseWrap, m.mapDiffuseAnisotropy ); } if ( m.mapLight && texturePath ) { create_texture( mpars, "lightMap", m.mapLight, m.mapLightRepeat, m.mapLightOffset, m.mapLightWrap, m.mapLightAnisotropy ); } if ( m.mapBump && texturePath ) { create_texture( mpars, "bumpMap", m.mapBump, m.mapBumpRepeat, m.mapBumpOffset, m.mapBumpWrap, m.mapBumpAnisotropy ); } if ( m.mapNormal && texturePath ) { create_texture( mpars, "normalMap", m.mapNormal, m.mapNormalRepeat, m.mapNormalOffset, m.mapNormalWrap, m.mapNormalAnisotropy ); } if ( m.mapSpecular && texturePath ) { create_texture( mpars, "specularMap", m.mapSpecular, m.mapSpecularRepeat, m.mapSpecularOffset, m.mapSpecularWrap, m.mapSpecularAnisotropy ); } // if ( m.mapBumpScale ) { mpars.bumpScale = m.mapBumpScale; } // special case for normal mapped material if ( m.mapNormal ) { var shader = THREE.ShaderLib[ "normalmap" ]; var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); uniforms[ "tNormal" ].value = mpars.normalMap; if ( m.mapNormalFactor ) { uniforms[ "uNormalScale" ].value.set( m.mapNormalFactor, m.mapNormalFactor ); } if ( mpars.map ) { uniforms[ "tDiffuse" ].value = mpars.map; uniforms[ "enableDiffuse" ].value = true; } if ( mpars.specularMap ) { uniforms[ "tSpecular" ].value = mpars.specularMap; uniforms[ "enableSpecular" ].value = true; } if ( mpars.lightMap ) { uniforms[ "tAO" ].value = mpars.lightMap; uniforms[ "enableAO" ].value = true; } // for the moment don't handle displacement texture uniforms[ "diffuse" ].value.setHex( mpars.color ); uniforms[ "specular" ].value.setHex( mpars.specular ); uniforms[ "ambient" ].value.setHex( mpars.ambient ); uniforms[ "shininess" ].value = mpars.shininess; if ( mpars.opacity !== undefined ) { uniforms[ "opacity" ].value = mpars.opacity; } var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; var material = new THREE.ShaderMaterial( parameters ); if ( mpars.transparent ) { material.transparent = true; } } else { var material = new THREE[ mtype ]( mpars ); } if ( m.DbgName !== undefined ) material.name = m.DbgName; return material; } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.XHRLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.XHRLoader.prototype = { constructor: THREE.XHRLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var request = new XMLHttpRequest(); if ( onLoad !== undefined ) { request.addEventListener( 'load', function ( event ) { onLoad( event.target.responseText ); scope.manager.itemEnd( url ); }, false ); } if ( onProgress !== undefined ) { request.addEventListener( 'progress', function ( event ) { onProgress( event ); }, false ); } if ( onError !== undefined ) { request.addEventListener( 'error', function ( event ) { onError( event ); }, false ); } if ( this.crossOrigin !== undefined ) request.crossOrigin = this.crossOrigin; request.open( 'GET', url, true ); request.send( null ); scope.manager.itemStart( url ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.ImageLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.ImageLoader.prototype = { constructor: THREE.ImageLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var image = document.createElement( 'img' ); if ( onLoad !== undefined ) { image.addEventListener( 'load', function ( event ) { scope.manager.itemEnd( url ); onLoad( this ); }, false ); } if ( onProgress !== undefined ) { image.addEventListener( 'progress', function ( event ) { onProgress( event ); }, false ); } if ( onError !== undefined ) { image.addEventListener( 'error', function ( event ) { onError( event ); }, false ); } if ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin; image.src = url; scope.manager.itemStart( url ); return image; }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } } /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.JSONLoader = function ( showStatus ) { THREE.Loader.call( this, showStatus ); this.withCredentials = false; }; THREE.JSONLoader.prototype = Object.create( THREE.Loader.prototype ); THREE.JSONLoader.prototype.load = function ( url, callback, texturePath ) { var scope = this; // todo: unify load API to for easier SceneLoader use texturePath = texturePath && ( typeof texturePath === "string" ) ? texturePath : this.extractUrlBase( url ); this.onLoadStart(); this.loadAjaxJSON( this, url, callback, texturePath ); }; THREE.JSONLoader.prototype.loadAjaxJSON = function ( context, url, callback, texturePath, callbackProgress ) { var xhr = new XMLHttpRequest(); var length = 0; xhr.onreadystatechange = function () { if ( xhr.readyState === xhr.DONE ) { if ( xhr.status === 200 || xhr.status === 0 ) { if ( xhr.responseText ) { var json = JSON.parse( xhr.responseText ); if ( json.metadata.type === 'scene' ) { console.error( 'THREE.JSONLoader: "' + url + '" seems to be a Scene. Use THREE.SceneLoader instead.' ); return; } var result = context.parse( json, texturePath ); callback( result.geometry, result.materials ); } else { console.error( 'THREE.JSONLoader: "' + url + '" seems to be unreachable or the file is empty.' ); } // in context of more complex asset initialization // do not block on single failed file // maybe should go even one more level up context.onLoadComplete(); } else { console.error( 'THREE.JSONLoader: Couldn\'t load "' + url + '" (' + xhr.status + ')' ); } } else if ( xhr.readyState === xhr.LOADING ) { if ( callbackProgress ) { if ( length === 0 ) { length = xhr.getResponseHeader( 'Content-Length' ); } callbackProgress( { total: length, loaded: xhr.responseText.length } ); } } else if ( xhr.readyState === xhr.HEADERS_RECEIVED ) { if ( callbackProgress !== undefined ) { length = xhr.getResponseHeader( "Content-Length" ); } } }; xhr.open( "GET", url, true ); xhr.withCredentials = this.withCredentials; xhr.send( null ); }; THREE.JSONLoader.prototype.parse = function ( json, texturePath ) { var scope = this, geometry = new THREE.Geometry(), scale = ( json.scale !== undefined ) ? 1.0 / json.scale : 1.0; parseModel( scale ); parseSkin(); parseMorphing( scale ); geometry.computeCentroids(); geometry.computeFaceNormals(); geometry.computeBoundingSphere(); function parseModel( scale ) { function isBitSet( value, position ) { return value & ( 1 << position ); } var i, j, fi, offset, zLength, colorIndex, normalIndex, uvIndex, materialIndex, type, isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor, vertex, face, faceA, faceB, color, hex, normal, uvLayer, uv, u, v, faces = json.faces, vertices = json.vertices, normals = json.normals, colors = json.colors, nUvLayers = 0; if ( json.uvs !== undefined ) { // disregard empty arrays for ( i = 0; i < json.uvs.length; i++ ) { if ( json.uvs[ i ].length ) nUvLayers ++; } for ( i = 0; i < nUvLayers; i++ ) { geometry.faceVertexUvs[ i ] = []; } } offset = 0; zLength = vertices.length; while ( offset < zLength ) { vertex = new THREE.Vector3(); vertex.x = vertices[ offset ++ ] * scale; vertex.y = vertices[ offset ++ ] * scale; vertex.z = vertices[ offset ++ ] * scale; geometry.vertices.push( vertex ); } offset = 0; zLength = faces.length; while ( offset < zLength ) { type = faces[ offset ++ ]; isQuad = isBitSet( type, 0 ); hasMaterial = isBitSet( type, 1 ); hasFaceVertexUv = isBitSet( type, 3 ); hasFaceNormal = isBitSet( type, 4 ); hasFaceVertexNormal = isBitSet( type, 5 ); hasFaceColor = isBitSet( type, 6 ); hasFaceVertexColor = isBitSet( type, 7 ); // console.log("type", type, "bits", isQuad, hasMaterial, hasFaceVertexUv, hasFaceNormal, hasFaceVertexNormal, hasFaceColor, hasFaceVertexColor); if ( isQuad ) { faceA = new THREE.Face3(); faceA.a = faces[ offset ]; faceA.b = faces[ offset + 1 ]; faceA.c = faces[ offset + 3 ]; faceB = new THREE.Face3(); faceB.a = faces[ offset + 1 ]; faceB.b = faces[ offset + 2 ]; faceB.c = faces[ offset + 3 ]; offset += 4; if ( hasMaterial ) { materialIndex = faces[ offset ++ ]; faceA.materialIndex = materialIndex; faceB.materialIndex = materialIndex; } // to get face <=> uv index correspondence fi = geometry.faces.length; if ( hasFaceVertexUv ) { for ( i = 0; i < nUvLayers; i++ ) { uvLayer = json.uvs[ i ]; geometry.faceVertexUvs[ i ][ fi ] = []; geometry.faceVertexUvs[ i ][ fi + 1 ] = [] for ( j = 0; j < 4; j ++ ) { uvIndex = faces[ offset ++ ]; u = uvLayer[ uvIndex * 2 ]; v = uvLayer[ uvIndex * 2 + 1 ]; uv = new THREE.Vector2( u, v ); if ( j !== 2 ) geometry.faceVertexUvs[ i ][ fi ].push( uv ); if ( j !== 0 ) geometry.faceVertexUvs[ i ][ fi + 1 ].push( uv ); } } } if ( hasFaceNormal ) { normalIndex = faces[ offset ++ ] * 3; faceA.normal.set( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); faceB.normal.copy( faceA.normal ); } if ( hasFaceVertexNormal ) { for ( i = 0; i < 4; i++ ) { normalIndex = faces[ offset ++ ] * 3; normal = new THREE.Vector3( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); if ( i !== 2 ) faceA.vertexNormals.push( normal ); if ( i !== 0 ) faceB.vertexNormals.push( normal ); } } if ( hasFaceColor ) { colorIndex = faces[ offset ++ ]; hex = colors[ colorIndex ]; faceA.color.setHex( hex ); faceB.color.setHex( hex ); } if ( hasFaceVertexColor ) { for ( i = 0; i < 4; i++ ) { colorIndex = faces[ offset ++ ]; hex = colors[ colorIndex ]; if ( i !== 2 ) faceA.vertexColors.push( new THREE.Color( hex ) ); if ( i !== 0 ) faceB.vertexColors.push( new THREE.Color( hex ) ); } } geometry.faces.push( faceA ); geometry.faces.push( faceB ); } else { face = new THREE.Face3(); face.a = faces[ offset ++ ]; face.b = faces[ offset ++ ]; face.c = faces[ offset ++ ]; if ( hasMaterial ) { materialIndex = faces[ offset ++ ]; face.materialIndex = materialIndex; } // to get face <=> uv index correspondence fi = geometry.faces.length; if ( hasFaceVertexUv ) { for ( i = 0; i < nUvLayers; i++ ) { uvLayer = json.uvs[ i ]; geometry.faceVertexUvs[ i ][ fi ] = []; for ( j = 0; j < 3; j ++ ) { uvIndex = faces[ offset ++ ]; u = uvLayer[ uvIndex * 2 ]; v = uvLayer[ uvIndex * 2 + 1 ]; uv = new THREE.Vector2( u, v ); geometry.faceVertexUvs[ i ][ fi ].push( uv ); } } } if ( hasFaceNormal ) { normalIndex = faces[ offset ++ ] * 3; face.normal.set( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); } if ( hasFaceVertexNormal ) { for ( i = 0; i < 3; i++ ) { normalIndex = faces[ offset ++ ] * 3; normal = new THREE.Vector3( normals[ normalIndex ++ ], normals[ normalIndex ++ ], normals[ normalIndex ] ); face.vertexNormals.push( normal ); } } if ( hasFaceColor ) { colorIndex = faces[ offset ++ ]; face.color.setHex( colors[ colorIndex ] ); } if ( hasFaceVertexColor ) { for ( i = 0; i < 3; i++ ) { colorIndex = faces[ offset ++ ]; face.vertexColors.push( new THREE.Color( colors[ colorIndex ] ) ); } } geometry.faces.push( face ); } } }; function parseSkin() { if ( json.skinWeights ) { for ( var i = 0, l = json.skinWeights.length; i < l; i += 2 ) { var x = json.skinWeights[ i ]; var y = json.skinWeights[ i + 1 ]; var z = 0; var w = 0; geometry.skinWeights.push( new THREE.Vector4( x, y, z, w ) ); } } if ( json.skinIndices ) { for ( var i = 0, l = json.skinIndices.length; i < l; i += 2 ) { var a = json.skinIndices[ i ]; var b = json.skinIndices[ i + 1 ]; var c = 0; var d = 0; geometry.skinIndices.push( new THREE.Vector4( a, b, c, d ) ); } } geometry.bones = json.bones; if ( geometry.bones && geometry.bones.length > 0 && ( geometry.skinWeights.length !== geometry.skinIndices.length || geometry.skinIndices.length !== geometry.vertices.length ) ) { console.warn( 'When skinning, number of vertices (' + geometry.vertices.length + '), skinIndices (' + geometry.skinIndices.length + '), and skinWeights (' + geometry.skinWeights.length + ') should match.' ); } // could change this to json.animations[0] or remove completely geometry.animation = json.animation; geometry.animations = json.animations; }; function parseMorphing( scale ) { if ( json.morphTargets !== undefined ) { var i, l, v, vl, dstVertices, srcVertices; for ( i = 0, l = json.morphTargets.length; i < l; i ++ ) { geometry.morphTargets[ i ] = {}; geometry.morphTargets[ i ].name = json.morphTargets[ i ].name; geometry.morphTargets[ i ].vertices = []; dstVertices = geometry.morphTargets[ i ].vertices; srcVertices = json.morphTargets [ i ].vertices; for( v = 0, vl = srcVertices.length; v < vl; v += 3 ) { var vertex = new THREE.Vector3(); vertex.x = srcVertices[ v ] * scale; vertex.y = srcVertices[ v + 1 ] * scale; vertex.z = srcVertices[ v + 2 ] * scale; dstVertices.push( vertex ); } } } if ( json.morphColors !== undefined ) { var i, l, c, cl, dstColors, srcColors, color; for ( i = 0, l = json.morphColors.length; i < l; i++ ) { geometry.morphColors[ i ] = {}; geometry.morphColors[ i ].name = json.morphColors[ i ].name; geometry.morphColors[ i ].colors = []; dstColors = geometry.morphColors[ i ].colors; srcColors = json.morphColors [ i ].colors; for ( c = 0, cl = srcColors.length; c < cl; c += 3 ) { color = new THREE.Color( 0xffaa00 ); color.setRGB( srcColors[ c ], srcColors[ c + 1 ], srcColors[ c + 2 ] ); dstColors.push( color ); } } } }; if ( json.materials === undefined ) { return { geometry: geometry }; } else { var materials = this.initMaterials( json.materials, texturePath ); if ( this.needsTangents( materials ) ) { geometry.computeTangents(); } return { geometry: geometry, materials: materials }; } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.LoadingManager = function ( onLoad, onProgress, onError ) { var scope = this; var loaded = 0, total = 0; this.onLoad = onLoad; this.onProgress = onProgress; this.onError = onError; this.itemStart = function ( url ) { total ++; }; this.itemEnd = function ( url ) { loaded ++; if ( scope.onProgress !== undefined ) { scope.onProgress( url, loaded, total ); } if ( loaded === total && scope.onLoad !== undefined ) { scope.onLoad(); } }; }; THREE.DefaultLoadingManager = new THREE.LoadingManager(); /** * @author mrdoob / http://mrdoob.com/ */ THREE.BufferGeometryLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.BufferGeometryLoader.prototype = { constructor: THREE.BufferGeometryLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader(); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); } ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, parse: function ( json ) { var geometry = new THREE.BufferGeometry(); var attributes = json.attributes; var offsets = json.offsets; var boundingSphere = json.boundingSphere; for ( var key in attributes ) { var attribute = attributes[ key ]; geometry.attributes[ key ] = { itemSize: attribute.itemSize, array: new self[ attribute.type ]( attribute.array ) } } if ( offsets !== undefined ) { geometry.offsets = JSON.parse( JSON.stringify( offsets ) ); } if ( boundingSphere !== undefined ) { geometry.boundingSphere = new THREE.Sphere( new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), boundingSphere.radius ); } return geometry; } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.Geometry2Loader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.Geometry2Loader.prototype = { constructor: THREE.Geometry2Loader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader(); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); } ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, parse: function ( json ) { var geometry = new THREE.Geometry2( json.vertices.length / 3 ); var attributes = [ 'vertices', 'normals', 'uvs' ]; var boundingSphere = json.boundingSphere; for ( var key in attributes ) { var attribute = attributes[ key ]; geometry[ attribute ].set( json[ attribute ] ); } if ( boundingSphere !== undefined ) { geometry.boundingSphere = new THREE.Sphere( new THREE.Vector3().fromArray( boundingSphere.center !== undefined ? boundingSphere.center : [ 0, 0, 0 ] ), boundingSphere.radius ); } return geometry; } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.MaterialLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.MaterialLoader.prototype = { constructor: THREE.MaterialLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader(); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); } ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, parse: function ( json ) { var material = new THREE[ json.type ]; if ( json.color !== undefined ) material.color.setHex( json.color ); if ( json.ambient !== undefined ) material.ambient.setHex( json.ambient ); if ( json.emissive !== undefined ) material.emissive.setHex( json.emissive ); if ( json.specular !== undefined ) material.specular.setHex( json.specular ); if ( json.shininess !== undefined ) material.shininess = json.shininess; if ( json.vertexColors !== undefined ) material.vertexColors = json.vertexColors; if ( json.blending !== undefined ) material.blending = json.blending; if ( json.side !== undefined ) material.side = json.side; if ( json.opacity !== undefined ) material.opacity = json.opacity; if ( json.transparent !== undefined ) material.transparent = json.transparent; if ( json.wireframe !== undefined ) material.wireframe = json.wireframe; if ( json.materials !== undefined ) { for ( var i = 0, l = json.materials.length; i < l; i ++ ) { material.materials.push( this.parse( json.materials[ i ] ) ); } } return material; } }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.ObjectLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.ObjectLoader.prototype = { constructor: THREE.ObjectLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader( scope.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { onLoad( scope.parse( JSON.parse( text ) ) ); } ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, parse: function ( json ) { var geometries = this.parseGeometries( json.geometries ); var materials = this.parseMaterials( json.materials ); var object = this.parseObject( json.object, geometries, materials ); return object; }, parseGeometries: function ( json ) { var geometries = {}; if ( json !== undefined ) { var geometryLoader = new THREE.JSONLoader(); var geometry2Loader = new THREE.Geometry2Loader(); var bufferGeometryLoader = new THREE.BufferGeometryLoader(); for ( var i = 0, l = json.length; i < l; i ++ ) { var geometry; var data = json[ i ]; switch ( data.type ) { case 'PlaneGeometry': geometry = new THREE.PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments ); break; case 'BoxGeometry': case 'CubeGeometry': // DEPRECATED geometry = new THREE.BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments ); break; case 'CircleGeometry': geometry = new THREE.CircleGeometry( data.radius, data.segments ); break; case 'CylinderGeometry': geometry = new THREE.CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded ); break; case 'SphereGeometry': geometry = new THREE.SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength ); break; case 'IcosahedronGeometry': geometry = new THREE.IcosahedronGeometry( data.radius, data.detail ); break; case 'TorusGeometry': geometry = new THREE.TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc ); break; case 'TorusKnotGeometry': geometry = new THREE.TorusKnotGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.p, data.q, data.heightScale ); break; case 'BufferGeometry': geometry = bufferGeometryLoader.parse( data.data ); break; case 'Geometry2': geometry = geometry2Loader.parse( data.data ); break; case 'Geometry': geometry = geometryLoader.parse( data.data ).geometry; break; } geometry.uuid = data.uuid; if ( data.name !== undefined ) geometry.name = data.name; geometries[ data.uuid ] = geometry; } } return geometries; }, parseMaterials: function ( json ) { var materials = {}; if ( json !== undefined ) { var loader = new THREE.MaterialLoader(); for ( var i = 0, l = json.length; i < l; i ++ ) { var data = json[ i ]; var material = loader.parse( data ); material.uuid = data.uuid; if ( data.name !== undefined ) material.name = data.name; materials[ data.uuid ] = material; } } return materials; }, parseObject: function () { var matrix = new THREE.Matrix4(); return function ( data, geometries, materials ) { var object; switch ( data.type ) { case 'Scene': object = new THREE.Scene(); break; case 'PerspectiveCamera': object = new THREE.PerspectiveCamera( data.fov, data.aspect, data.near, data.far ); break; case 'OrthographicCamera': object = new THREE.OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far ); break; case 'AmbientLight': object = new THREE.AmbientLight( data.color ); break; case 'DirectionalLight': object = new THREE.DirectionalLight( data.color, data.intensity ); break; case 'PointLight': object = new THREE.PointLight( data.color, data.intensity, data.distance ); break; case 'SpotLight': object = new THREE.SpotLight( data.color, data.intensity, data.distance, data.angle, data.exponent ); break; case 'HemisphereLight': object = new THREE.HemisphereLight( data.color, data.groundColor, data.intensity ); break; case 'Mesh': var geometry = geometries[ data.geometry ]; var material = materials[ data.material ]; if ( geometry === undefined ) { console.error( 'THREE.ObjectLoader: Undefined geometry ' + data.geometry ); } if ( material === undefined ) { console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); } object = new THREE.Mesh( geometry, material ); break; case 'Sprite': var material = materials[ data.material ]; if ( material === undefined ) { console.error( 'THREE.ObjectLoader: Undefined material ' + data.material ); } object = new THREE.Sprite( material ); break; default: object = new THREE.Object3D(); } object.uuid = data.uuid; if ( data.name !== undefined ) object.name = data.name; if ( data.matrix !== undefined ) { matrix.fromArray( data.matrix ); matrix.decompose( object.position, object.quaternion, object.scale ); } else { if ( data.position !== undefined ) object.position.fromArray( data.position ); if ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation ); if ( data.scale !== undefined ) object.scale.fromArray( data.scale ); } if ( data.visible !== undefined ) object.visible = data.visible; if ( data.userData !== undefined ) object.userData = data.userData; if ( data.children !== undefined ) { for ( var child in data.children ) { object.add( this.parseObject( data.children[ child ], geometries, materials ) ); } } return object; } }() }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.SceneLoader = function () { this.onLoadStart = function () {}; this.onLoadProgress = function() {}; this.onLoadComplete = function () {}; this.callbackSync = function () {}; this.callbackProgress = function () {}; this.geometryHandlers = {}; this.hierarchyHandlers = {}; this.addGeometryHandler( "ascii", THREE.JSONLoader ); }; THREE.SceneLoader.prototype = { constructor: THREE.SceneLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.XHRLoader( scope.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( text ) { scope.parse( JSON.parse( text ), onLoad, url ); } ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; }, addGeometryHandler: function ( typeID, loaderClass ) { this.geometryHandlers[ typeID ] = { "loaderClass": loaderClass }; }, addHierarchyHandler: function ( typeID, loaderClass ) { this.hierarchyHandlers[ typeID ] = { "loaderClass": loaderClass }; }, parse: function ( json, callbackFinished, url ) { var scope = this; var urlBase = THREE.Loader.prototype.extractUrlBase( url ); var geometry, material, camera, fog, texture, images, color, light, hex, intensity, counter_models, counter_textures, total_models, total_textures, result; var target_array = []; var data = json; // async geometry loaders for ( var typeID in this.geometryHandlers ) { var loaderClass = this.geometryHandlers[ typeID ][ "loaderClass" ]; this.geometryHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); } // async hierachy loaders for ( var typeID in this.hierarchyHandlers ) { var loaderClass = this.hierarchyHandlers[ typeID ][ "loaderClass" ]; this.hierarchyHandlers[ typeID ][ "loaderObject" ] = new loaderClass(); } counter_models = 0; counter_textures = 0; result = { scene: new THREE.Scene(), geometries: {}, face_materials: {}, materials: {}, textures: {}, objects: {}, cameras: {}, lights: {}, fogs: {}, empties: {}, groups: {} }; if ( data.transform ) { var position = data.transform.position, rotation = data.transform.rotation, scale = data.transform.scale; if ( position ) { result.scene.position.fromArray( position ); } if ( rotation ) { result.scene.rotation.fromArray( rotation ); } if ( scale ) { result.scene.scale.fromArray( scale ); } if ( position || rotation || scale ) { result.scene.updateMatrix(); result.scene.updateMatrixWorld(); } } function get_url( source_url, url_type ) { if ( url_type == "relativeToHTML" ) { return source_url; } else { return urlBase + source_url; } }; // toplevel loader function, delegates to handle_children function handle_objects() { handle_children( result.scene, data.objects ); } // handle all the children from the loaded json and attach them to given parent function handle_children( parent, children ) { var mat, dst, pos, rot, scl, quat; for ( var objID in children ) { // check by id if child has already been handled, // if not, create new object var object = result.objects[ objID ]; var objJSON = children[ objID ]; if ( object === undefined ) { // meshes if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { if ( objJSON.loading === undefined ) { var reservedTypes = { "type": 1, "url": 1, "material": 1, "position": 1, "rotation": 1, "scale" : 1, "visible": 1, "children": 1, "userData": 1, "skin": 1, "morph": 1, "mirroredLoop": 1, "duration": 1 }; var loaderParameters = {}; for ( var parType in objJSON ) { if ( ! ( parType in reservedTypes ) ) { loaderParameters[ parType ] = objJSON[ parType ]; } } material = result.materials[ objJSON.material ]; objJSON.loading = true; var loader = scope.hierarchyHandlers[ objJSON.type ][ "loaderObject" ]; // ColladaLoader if ( loader.options ) { loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ) ); // UTF8Loader // OBJLoader } else { loader.load( get_url( objJSON.url, data.urlBaseType ), create_callback_hierachy( objID, parent, material, objJSON ), loaderParameters ); } } } else if ( objJSON.geometry !== undefined ) { geometry = result.geometries[ objJSON.geometry ]; // geometry already loaded if ( geometry ) { var needsTangents = false; material = result.materials[ objJSON.material ]; needsTangents = material instanceof THREE.ShaderMaterial; pos = objJSON.position; rot = objJSON.rotation; scl = objJSON.scale; mat = objJSON.matrix; quat = objJSON.quaternion; // use materials from the model file // if there is no material specified in the object if ( ! objJSON.material ) { material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); } // use materials from the model file // if there is just empty face material // (must create new material as each model has its own face material) if ( ( material instanceof THREE.MeshFaceMaterial ) && material.materials.length === 0 ) { material = new THREE.MeshFaceMaterial( result.face_materials[ objJSON.geometry ] ); } if ( material instanceof THREE.MeshFaceMaterial ) { for ( var i = 0; i < material.materials.length; i ++ ) { needsTangents = needsTangents || ( material.materials[ i ] instanceof THREE.ShaderMaterial ); } } if ( needsTangents ) { geometry.computeTangents(); } if ( objJSON.skin ) { object = new THREE.SkinnedMesh( geometry, material ); } else if ( objJSON.morph ) { object = new THREE.MorphAnimMesh( geometry, material ); if ( objJSON.duration !== undefined ) { object.duration = objJSON.duration; } if ( objJSON.time !== undefined ) { object.time = objJSON.time; } if ( objJSON.mirroredLoop !== undefined ) { object.mirroredLoop = objJSON.mirroredLoop; } if ( material.morphNormals ) { geometry.computeMorphNormals(); } } else { object = new THREE.Mesh( geometry, material ); } object.name = objID; if ( mat ) { object.matrixAutoUpdate = false; object.matrix.set( mat[0], mat[1], mat[2], mat[3], mat[4], mat[5], mat[6], mat[7], mat[8], mat[9], mat[10], mat[11], mat[12], mat[13], mat[14], mat[15] ); } else { object.position.fromArray( pos ); if ( quat ) { object.quaternion.fromArray( quat ); } else { object.rotation.fromArray( rot ); } object.scale.fromArray( scl ); } object.visible = objJSON.visible; object.castShadow = objJSON.castShadow; object.receiveShadow = objJSON.receiveShadow; parent.add( object ); result.objects[ objID ] = object; } // lights } else if ( objJSON.type === "AmbientLight" || objJSON.type === "PointLight" || objJSON.type === "DirectionalLight" || objJSON.type === "SpotLight" || objJSON.type === "HemisphereLight" || objJSON.type === "AreaLight" ) { var color = objJSON.color; var intensity = objJSON.intensity; var distance = objJSON.distance; var position = objJSON.position; var rotation = objJSON.rotation; switch ( objJSON.type ) { case 'AmbientLight': light = new THREE.AmbientLight( color ); break; case 'PointLight': light = new THREE.PointLight( color, intensity, distance ); light.position.fromArray( position ); break; case 'DirectionalLight': light = new THREE.DirectionalLight( color, intensity ); light.position.fromArray( objJSON.direction ); break; case 'SpotLight': light = new THREE.SpotLight( color, intensity, distance, 1 ); light.angle = objJSON.angle; light.position.fromArray( position ); light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); break; case 'HemisphereLight': light = new THREE.DirectionalLight( color, intensity, distance ); light.target.set( position[ 0 ], position[ 1 ] - distance, position[ 2 ] ); light.target.applyEuler( new THREE.Euler( rotation[ 0 ], rotation[ 1 ], rotation[ 2 ], 'XYZ' ) ); break; case 'AreaLight': light = new THREE.AreaLight(color, intensity); light.position.fromArray( position ); light.width = objJSON.size; light.height = objJSON.size_y; break; } parent.add( light ); light.name = objID; result.lights[ objID ] = light; result.objects[ objID ] = light; // cameras } else if ( objJSON.type === "PerspectiveCamera" || objJSON.type === "OrthographicCamera" ) { pos = objJSON.position; rot = objJSON.rotation; quat = objJSON.quaternion; if ( objJSON.type === "PerspectiveCamera" ) { camera = new THREE.PerspectiveCamera( objJSON.fov, objJSON.aspect, objJSON.near, objJSON.far ); } else if ( objJSON.type === "OrthographicCamera" ) { camera = new THREE.OrthographicCamera( objJSON.left, objJSON.right, objJSON.top, objJSON.bottom, objJSON.near, objJSON.far ); } camera.name = objID; camera.position.fromArray( pos ); if ( quat !== undefined ) { camera.quaternion.fromArray( quat ); } else if ( rot !== undefined ) { camera.rotation.fromArray( rot ); } parent.add( camera ); result.cameras[ objID ] = camera; result.objects[ objID ] = camera; // pure Object3D } else { pos = objJSON.position; rot = objJSON.rotation; scl = objJSON.scale; quat = objJSON.quaternion; object = new THREE.Object3D(); object.name = objID; object.position.fromArray( pos ); if ( quat ) { object.quaternion.fromArray( quat ); } else { object.rotation.fromArray( rot ); } object.scale.fromArray( scl ); object.visible = ( objJSON.visible !== undefined ) ? objJSON.visible : false; parent.add( object ); result.objects[ objID ] = object; result.empties[ objID ] = object; } if ( object ) { if ( objJSON.userData !== undefined ) { for ( var key in objJSON.userData ) { var value = objJSON.userData[ key ]; object.userData[ key ] = value; } } if ( objJSON.groups !== undefined ) { for ( var i = 0; i < objJSON.groups.length; i ++ ) { var groupID = objJSON.groups[ i ]; if ( result.groups[ groupID ] === undefined ) { result.groups[ groupID ] = []; } result.groups[ groupID ].push( objID ); } } } } if ( object !== undefined && objJSON.children !== undefined ) { handle_children( object, objJSON.children ); } } }; function handle_mesh( geo, mat, id ) { result.geometries[ id ] = geo; result.face_materials[ id ] = mat; handle_objects(); }; function handle_hierarchy( node, id, parent, material, obj ) { var p = obj.position; var r = obj.rotation; var q = obj.quaternion; var s = obj.scale; node.position.fromArray( p ); if ( q ) { node.quaternion.fromArray( q ); } else { node.rotation.fromArray( r ); } node.scale.fromArray( s ); // override children materials // if object material was specified in JSON explicitly if ( material ) { node.traverse( function ( child ) { child.material = material; } ); } // override children visibility // with root node visibility as specified in JSON var visible = ( obj.visible !== undefined ) ? obj.visible : true; node.traverse( function ( child ) { child.visible = visible; } ); parent.add( node ); node.name = id; result.objects[ id ] = node; handle_objects(); }; function create_callback_geometry( id ) { return function ( geo, mat ) { geo.name = id; handle_mesh( geo, mat, id ); counter_models -= 1; scope.onLoadComplete(); async_callback_gate(); } }; function create_callback_hierachy( id, parent, material, obj ) { return function ( event ) { var result; // loaders which use EventDispatcher if ( event.content ) { result = event.content; // ColladaLoader } else if ( event.dae ) { result = event.scene; // UTF8Loader } else { result = event; } handle_hierarchy( result, id, parent, material, obj ); counter_models -= 1; scope.onLoadComplete(); async_callback_gate(); } }; function create_callback_embed( id ) { return function ( geo, mat ) { geo.name = id; result.geometries[ id ] = geo; result.face_materials[ id ] = mat; } }; function async_callback_gate() { var progress = { totalModels : total_models, totalTextures : total_textures, loadedModels : total_models - counter_models, loadedTextures : total_textures - counter_textures }; scope.callbackProgress( progress, result ); scope.onLoadProgress(); if ( counter_models === 0 && counter_textures === 0 ) { finalize(); callbackFinished( result ); } }; function finalize() { // take care of targets which could be asynchronously loaded objects for ( var i = 0; i < target_array.length; i ++ ) { var ta = target_array[ i ]; var target = result.objects[ ta.targetName ]; if ( target ) { ta.object.target = target; } else { // if there was error and target of specified name doesn't exist in the scene file // create instead dummy target // (target must be added to scene explicitly as parent is already added) ta.object.target = new THREE.Object3D(); result.scene.add( ta.object.target ); } ta.object.target.userData.targetInverse = ta.object; } }; var callbackTexture = function ( count ) { counter_textures -= count; async_callback_gate(); scope.onLoadComplete(); }; // must use this instead of just directly calling callbackTexture // because of closure in the calling context loop var generateTextureCallback = function ( count ) { return function () { callbackTexture( count ); }; }; function traverse_json_hierarchy( objJSON, callback ) { callback( objJSON ); if ( objJSON.children !== undefined ) { for ( var objChildID in objJSON.children ) { traverse_json_hierarchy( objJSON.children[ objChildID ], callback ); } } }; // first go synchronous elements // fogs var fogID, fogJSON; for ( fogID in data.fogs ) { fogJSON = data.fogs[ fogID ]; if ( fogJSON.type === "linear" ) { fog = new THREE.Fog( 0x000000, fogJSON.near, fogJSON.far ); } else if ( fogJSON.type === "exp2" ) { fog = new THREE.FogExp2( 0x000000, fogJSON.density ); } color = fogJSON.color; fog.color.setRGB( color[0], color[1], color[2] ); result.fogs[ fogID ] = fog; } // now come potentially asynchronous elements // geometries // count how many geometries will be loaded asynchronously var geoID, geoJSON; for ( geoID in data.geometries ) { geoJSON = data.geometries[ geoID ]; if ( geoJSON.type in this.geometryHandlers ) { counter_models += 1; scope.onLoadStart(); } } // count how many hierarchies will be loaded asynchronously for ( var objID in data.objects ) { traverse_json_hierarchy( data.objects[ objID ], function ( objJSON ) { if ( objJSON.type && ( objJSON.type in scope.hierarchyHandlers ) ) { counter_models += 1; scope.onLoadStart(); } }); } total_models = counter_models; for ( geoID in data.geometries ) { geoJSON = data.geometries[ geoID ]; if ( geoJSON.type === "cube" ) { geometry = new THREE.BoxGeometry( geoJSON.width, geoJSON.height, geoJSON.depth, geoJSON.widthSegments, geoJSON.heightSegments, geoJSON.depthSegments ); geometry.name = geoID; result.geometries[ geoID ] = geometry; } else if ( geoJSON.type === "plane" ) { geometry = new THREE.PlaneGeometry( geoJSON.width, geoJSON.height, geoJSON.widthSegments, geoJSON.heightSegments ); geometry.name = geoID; result.geometries[ geoID ] = geometry; } else if ( geoJSON.type === "sphere" ) { geometry = new THREE.SphereGeometry( geoJSON.radius, geoJSON.widthSegments, geoJSON.heightSegments ); geometry.name = geoID; result.geometries[ geoID ] = geometry; } else if ( geoJSON.type === "cylinder" ) { geometry = new THREE.CylinderGeometry( geoJSON.topRad, geoJSON.botRad, geoJSON.height, geoJSON.radSegs, geoJSON.heightSegs ); geometry.name = geoID; result.geometries[ geoID ] = geometry; } else if ( geoJSON.type === "torus" ) { geometry = new THREE.TorusGeometry( geoJSON.radius, geoJSON.tube, geoJSON.segmentsR, geoJSON.segmentsT ); geometry.name = geoID; result.geometries[ geoID ] = geometry; } else if ( geoJSON.type === "icosahedron" ) { geometry = new THREE.IcosahedronGeometry( geoJSON.radius, geoJSON.subdivisions ); geometry.name = geoID; result.geometries[ geoID ] = geometry; } else if ( geoJSON.type in this.geometryHandlers ) { var loaderParameters = {}; for ( var parType in geoJSON ) { if ( parType !== "type" && parType !== "url" ) { loaderParameters[ parType ] = geoJSON[ parType ]; } } var loader = this.geometryHandlers[ geoJSON.type ][ "loaderObject" ]; loader.load( get_url( geoJSON.url, data.urlBaseType ), create_callback_geometry( geoID ), loaderParameters ); } else if ( geoJSON.type === "embedded" ) { var modelJson = data.embeds[ geoJSON.id ], texture_path = ""; // pass metadata along to jsonLoader so it knows the format version modelJson.metadata = data.metadata; if ( modelJson ) { var jsonLoader = this.geometryHandlers[ "ascii" ][ "loaderObject" ]; var model = jsonLoader.parse( modelJson, texture_path ); create_callback_embed( geoID )( model.geometry, model.materials ); } } } // textures // count how many textures will be loaded asynchronously var textureID, textureJSON; for ( textureID in data.textures ) { textureJSON = data.textures[ textureID ]; if ( textureJSON.url instanceof Array ) { counter_textures += textureJSON.url.length; for( var n = 0; n < textureJSON.url.length; n ++ ) { scope.onLoadStart(); } } else { counter_textures += 1; scope.onLoadStart(); } } total_textures = counter_textures; for ( textureID in data.textures ) { textureJSON = data.textures[ textureID ]; if ( textureJSON.mapping !== undefined && THREE[ textureJSON.mapping ] !== undefined ) { textureJSON.mapping = new THREE[ textureJSON.mapping ](); } if ( textureJSON.url instanceof Array ) { var count = textureJSON.url.length; var url_array = []; for( var i = 0; i < count; i ++ ) { url_array[ i ] = get_url( textureJSON.url[ i ], data.urlBaseType ); } var isCompressed = /\.dds$/i.test( url_array[ 0 ] ); if ( isCompressed ) { texture = THREE.ImageUtils.loadCompressedTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); } else { texture = THREE.ImageUtils.loadTextureCube( url_array, textureJSON.mapping, generateTextureCallback( count ) ); } } else { var isCompressed = /\.dds$/i.test( textureJSON.url ); var fullUrl = get_url( textureJSON.url, data.urlBaseType ); var textureCallback = generateTextureCallback( 1 ); if ( isCompressed ) { texture = THREE.ImageUtils.loadCompressedTexture( fullUrl, textureJSON.mapping, textureCallback ); } else { texture = THREE.ImageUtils.loadTexture( fullUrl, textureJSON.mapping, textureCallback ); } if ( THREE[ textureJSON.minFilter ] !== undefined ) texture.minFilter = THREE[ textureJSON.minFilter ]; if ( THREE[ textureJSON.magFilter ] !== undefined ) texture.magFilter = THREE[ textureJSON.magFilter ]; if ( textureJSON.anisotropy ) texture.anisotropy = textureJSON.anisotropy; if ( textureJSON.repeat ) { texture.repeat.set( textureJSON.repeat[ 0 ], textureJSON.repeat[ 1 ] ); if ( textureJSON.repeat[ 0 ] !== 1 ) texture.wrapS = THREE.RepeatWrapping; if ( textureJSON.repeat[ 1 ] !== 1 ) texture.wrapT = THREE.RepeatWrapping; } if ( textureJSON.offset ) { texture.offset.set( textureJSON.offset[ 0 ], textureJSON.offset[ 1 ] ); } // handle wrap after repeat so that default repeat can be overriden if ( textureJSON.wrap ) { var wrapMap = { "repeat": THREE.RepeatWrapping, "mirror": THREE.MirroredRepeatWrapping } if ( wrapMap[ textureJSON.wrap[ 0 ] ] !== undefined ) texture.wrapS = wrapMap[ textureJSON.wrap[ 0 ] ]; if ( wrapMap[ textureJSON.wrap[ 1 ] ] !== undefined ) texture.wrapT = wrapMap[ textureJSON.wrap[ 1 ] ]; } } result.textures[ textureID ] = texture; } // materials var matID, matJSON; var parID; for ( matID in data.materials ) { matJSON = data.materials[ matID ]; for ( parID in matJSON.parameters ) { if ( parID === "envMap" || parID === "map" || parID === "lightMap" || parID === "bumpMap" ) { matJSON.parameters[ parID ] = result.textures[ matJSON.parameters[ parID ] ]; } else if ( parID === "shading" ) { matJSON.parameters[ parID ] = ( matJSON.parameters[ parID ] === "flat" ) ? THREE.FlatShading : THREE.SmoothShading; } else if ( parID === "side" ) { if ( matJSON.parameters[ parID ] == "double" ) { matJSON.parameters[ parID ] = THREE.DoubleSide; } else if ( matJSON.parameters[ parID ] == "back" ) { matJSON.parameters[ parID ] = THREE.BackSide; } else { matJSON.parameters[ parID ] = THREE.FrontSide; } } else if ( parID === "blending" ) { matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.NormalBlending; } else if ( parID === "combine" ) { matJSON.parameters[ parID ] = matJSON.parameters[ parID ] in THREE ? THREE[ matJSON.parameters[ parID ] ] : THREE.MultiplyOperation; } else if ( parID === "vertexColors" ) { if ( matJSON.parameters[ parID ] == "face" ) { matJSON.parameters[ parID ] = THREE.FaceColors; // default to vertex colors if "vertexColors" is anything else face colors or 0 / null / false } else if ( matJSON.parameters[ parID ] ) { matJSON.parameters[ parID ] = THREE.VertexColors; } } else if ( parID === "wrapRGB" ) { var v3 = matJSON.parameters[ parID ]; matJSON.parameters[ parID ] = new THREE.Vector3( v3[ 0 ], v3[ 1 ], v3[ 2 ] ); } } if ( matJSON.parameters.opacity !== undefined && matJSON.parameters.opacity < 1.0 ) { matJSON.parameters.transparent = true; } if ( matJSON.parameters.normalMap ) { var shader = THREE.ShaderLib[ "normalmap" ]; var uniforms = THREE.UniformsUtils.clone( shader.uniforms ); var diffuse = matJSON.parameters.color; var specular = matJSON.parameters.specular; var ambient = matJSON.parameters.ambient; var shininess = matJSON.parameters.shininess; uniforms[ "tNormal" ].value = result.textures[ matJSON.parameters.normalMap ]; if ( matJSON.parameters.normalScale ) { uniforms[ "uNormalScale" ].value.set( matJSON.parameters.normalScale[ 0 ], matJSON.parameters.normalScale[ 1 ] ); } if ( matJSON.parameters.map ) { uniforms[ "tDiffuse" ].value = matJSON.parameters.map; uniforms[ "enableDiffuse" ].value = true; } if ( matJSON.parameters.envMap ) { uniforms[ "tCube" ].value = matJSON.parameters.envMap; uniforms[ "enableReflection" ].value = true; uniforms[ "reflectivity" ].value = matJSON.parameters.reflectivity; } if ( matJSON.parameters.lightMap ) { uniforms[ "tAO" ].value = matJSON.parameters.lightMap; uniforms[ "enableAO" ].value = true; } if ( matJSON.parameters.specularMap ) { uniforms[ "tSpecular" ].value = result.textures[ matJSON.parameters.specularMap ]; uniforms[ "enableSpecular" ].value = true; } if ( matJSON.parameters.displacementMap ) { uniforms[ "tDisplacement" ].value = result.textures[ matJSON.parameters.displacementMap ]; uniforms[ "enableDisplacement" ].value = true; uniforms[ "uDisplacementBias" ].value = matJSON.parameters.displacementBias; uniforms[ "uDisplacementScale" ].value = matJSON.parameters.displacementScale; } uniforms[ "diffuse" ].value.setHex( diffuse ); uniforms[ "specular" ].value.setHex( specular ); uniforms[ "ambient" ].value.setHex( ambient ); uniforms[ "shininess" ].value = shininess; if ( matJSON.parameters.opacity ) { uniforms[ "opacity" ].value = matJSON.parameters.opacity; } var parameters = { fragmentShader: shader.fragmentShader, vertexShader: shader.vertexShader, uniforms: uniforms, lights: true, fog: true }; material = new THREE.ShaderMaterial( parameters ); } else { material = new THREE[ matJSON.type ]( matJSON.parameters ); } material.name = matID; result.materials[ matID ] = material; } // second pass through all materials to initialize MeshFaceMaterials // that could be referring to other materials out of order for ( matID in data.materials ) { matJSON = data.materials[ matID ]; if ( matJSON.parameters.materials ) { var materialArray = []; for ( var i = 0; i < matJSON.parameters.materials.length; i ++ ) { var label = matJSON.parameters.materials[ i ]; materialArray.push( result.materials[ label ] ); } result.materials[ matID ].materials = materialArray; } } // objects ( synchronous init of procedural primitives ) handle_objects(); // defaults if ( result.cameras && data.defaults.camera ) { result.currentCamera = result.cameras[ data.defaults.camera ]; } if ( result.fogs && data.defaults.fog ) { result.scene.fog = result.fogs[ data.defaults.fog ]; } // synchronous callback scope.callbackSync( result ); // just in case there are no async elements async_callback_gate(); } } /** * @author mrdoob / http://mrdoob.com/ */ THREE.TextureLoader = function ( manager ) { this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager; }; THREE.TextureLoader.prototype = { constructor: THREE.TextureLoader, load: function ( url, onLoad, onProgress, onError ) { var scope = this; var loader = new THREE.ImageLoader( scope.manager ); loader.setCrossOrigin( this.crossOrigin ); loader.load( url, function ( image ) { var texture = new THREE.Texture( image ); texture.needsUpdate = true; if ( onLoad !== undefined ) { onLoad( texture ); } } ); }, setCrossOrigin: function ( value ) { this.crossOrigin = value; } }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Material = function () { this.id = THREE.MaterialIdCount ++; this.uuid = THREE.Math.generateUUID(); this.name = ''; this.side = THREE.FrontSide; this.opacity = 1; this.transparent = false; this.blending = THREE.NormalBlending; this.blendSrc = THREE.SrcAlphaFactor; this.blendDst = THREE.OneMinusSrcAlphaFactor; this.blendEquation = THREE.AddEquation; this.depthTest = true; this.depthWrite = true; this.polygonOffset = false; this.polygonOffsetFactor = 0; this.polygonOffsetUnits = 0; this.alphaTest = 0; this.overdraw = 0; // Overdrawn pixels (typically between 0 and 1) for fixing antialiasing gaps in CanvasRenderer this.visible = true; this.needsUpdate = true; }; THREE.Material.prototype = { constructor: THREE.Material, setValues: function ( values ) { if ( values === undefined ) return; for ( var key in values ) { var newValue = values[ key ]; if ( newValue === undefined ) { console.warn( 'THREE.Material: \'' + key + '\' parameter is undefined.' ); continue; } if ( key in this ) { var currentValue = this[ key ]; if ( currentValue instanceof THREE.Color ) { currentValue.set( newValue ); } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { currentValue.copy( newValue ); } else if ( key == 'overdraw') { // ensure overdraw is backwards-compatable with legacy boolean type this[ key ] = Number(newValue); } else { this[ key ] = newValue; } } } }, clone: function ( material ) { if ( material === undefined ) material = new THREE.Material(); material.name = this.name; material.side = this.side; material.opacity = this.opacity; material.transparent = this.transparent; material.blending = this.blending; material.blendSrc = this.blendSrc; material.blendDst = this.blendDst; material.blendEquation = this.blendEquation; material.depthTest = this.depthTest; material.depthWrite = this.depthWrite; material.polygonOffset = this.polygonOffset; material.polygonOffsetFactor = this.polygonOffsetFactor; material.polygonOffsetUnits = this.polygonOffsetUnits; material.alphaTest = this.alphaTest; material.overdraw = this.overdraw; material.visible = this.visible; return material; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.Material.prototype ); THREE.MaterialIdCount = 0; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * linewidth: , * linecap: "round", * linejoin: "round", * * vertexColors: * * fog: * } */ THREE.LineBasicMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); this.linewidth = 1; this.linecap = 'round'; this.linejoin = 'round'; this.vertexColors = false; this.fog = true; this.setValues( parameters ); }; THREE.LineBasicMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.LineBasicMaterial.prototype.clone = function () { var material = new THREE.LineBasicMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.linewidth = this.linewidth; material.linecap = this.linecap; material.linejoin = this.linejoin; material.vertexColors = this.vertexColors; material.fog = this.fog; return material; }; /** * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * linewidth: , * * scale: , * dashSize: , * gapSize: , * * vertexColors: * * fog: * } */ THREE.LineDashedMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); this.linewidth = 1; this.scale = 1; this.dashSize = 3; this.gapSize = 1; this.vertexColors = false; this.fog = true; this.setValues( parameters ); }; THREE.LineDashedMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.LineDashedMaterial.prototype.clone = function () { var material = new THREE.LineDashedMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.linewidth = this.linewidth; material.scale = this.scale; material.dashSize = this.dashSize; material.gapSize = this.gapSize; material.vertexColors = this.vertexColors; material.fog = this.fog; return material; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * lightMap: new THREE.Texture( ), * * specularMap: new THREE.Texture( ), * * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * * fog: * } */ THREE.MeshBasicMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); // emissive this.map = null; this.lightMap = null; this.specularMap = null; this.envMap = null; this.combine = THREE.MultiplyOperation; this.reflectivity = 1; this.refractionRatio = 0.98; this.fog = true; this.shading = THREE.SmoothShading; this.wireframe = false; this.wireframeLinewidth = 1; this.wireframeLinecap = 'round'; this.wireframeLinejoin = 'round'; this.vertexColors = THREE.NoColors; this.skinning = false; this.morphTargets = false; this.setValues( parameters ); }; THREE.MeshBasicMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshBasicMaterial.prototype.clone = function () { var material = new THREE.MeshBasicMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.map = this.map; material.lightMap = this.lightMap; material.specularMap = this.specularMap; material.envMap = this.envMap; material.combine = this.combine; material.reflectivity = this.reflectivity; material.refractionRatio = this.refractionRatio; material.fog = this.fog; material.shading = this.shading; material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; material.wireframeLinecap = this.wireframeLinecap; material.wireframeLinejoin = this.wireframeLinejoin; material.vertexColors = this.vertexColors; material.skinning = this.skinning; material.morphTargets = this.morphTargets; return material; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * ambient: , * emissive: , * opacity: , * * map: new THREE.Texture( ), * * lightMap: new THREE.Texture( ), * * specularMap: new THREE.Texture( ), * * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * morphNormals: , * * fog: * } */ THREE.MeshLambertMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); // diffuse this.ambient = new THREE.Color( 0xffffff ); this.emissive = new THREE.Color( 0x000000 ); this.wrapAround = false; this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); this.map = null; this.lightMap = null; this.specularMap = null; this.envMap = null; this.combine = THREE.MultiplyOperation; this.reflectivity = 1; this.refractionRatio = 0.98; this.fog = true; this.shading = THREE.SmoothShading; this.wireframe = false; this.wireframeLinewidth = 1; this.wireframeLinecap = 'round'; this.wireframeLinejoin = 'round'; this.vertexColors = THREE.NoColors; this.skinning = false; this.morphTargets = false; this.morphNormals = false; this.setValues( parameters ); }; THREE.MeshLambertMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshLambertMaterial.prototype.clone = function () { var material = new THREE.MeshLambertMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.ambient.copy( this.ambient ); material.emissive.copy( this.emissive ); material.wrapAround = this.wrapAround; material.wrapRGB.copy( this.wrapRGB ); material.map = this.map; material.lightMap = this.lightMap; material.specularMap = this.specularMap; material.envMap = this.envMap; material.combine = this.combine; material.reflectivity = this.reflectivity; material.refractionRatio = this.refractionRatio; material.fog = this.fog; material.shading = this.shading; material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; material.wireframeLinecap = this.wireframeLinecap; material.wireframeLinejoin = this.wireframeLinejoin; material.vertexColors = this.vertexColors; material.skinning = this.skinning; material.morphTargets = this.morphTargets; material.morphNormals = this.morphNormals; return material; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * ambient: , * emissive: , * specular: , * shininess: , * opacity: , * * map: new THREE.Texture( ), * * lightMap: new THREE.Texture( ), * * bumpMap: new THREE.Texture( ), * bumpScale: , * * normalMap: new THREE.Texture( ), * normalScale: , * * specularMap: new THREE.Texture( ), * * envMap: new THREE.TextureCube( [posx, negx, posy, negy, posz, negz] ), * combine: THREE.Multiply, * reflectivity: , * refractionRatio: , * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * morphNormals: , * * fog: * } */ THREE.MeshPhongMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); // diffuse this.ambient = new THREE.Color( 0xffffff ); this.emissive = new THREE.Color( 0x000000 ); this.specular = new THREE.Color( 0x111111 ); this.shininess = 30; this.metal = false; this.wrapAround = false; this.wrapRGB = new THREE.Vector3( 1, 1, 1 ); this.map = null; this.lightMap = null; this.bumpMap = null; this.bumpScale = 1; this.normalMap = null; this.normalScale = new THREE.Vector2( 1, 1 ); this.specularMap = null; this.envMap = null; this.combine = THREE.MultiplyOperation; this.reflectivity = 1; this.refractionRatio = 0.98; this.fog = true; this.shading = THREE.SmoothShading; this.wireframe = false; this.wireframeLinewidth = 1; this.wireframeLinecap = 'round'; this.wireframeLinejoin = 'round'; this.vertexColors = THREE.NoColors; this.skinning = false; this.morphTargets = false; this.morphNormals = false; this.setValues( parameters ); }; THREE.MeshPhongMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshPhongMaterial.prototype.clone = function () { var material = new THREE.MeshPhongMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.ambient.copy( this.ambient ); material.emissive.copy( this.emissive ); material.specular.copy( this.specular ); material.shininess = this.shininess; material.metal = this.metal; material.wrapAround = this.wrapAround; material.wrapRGB.copy( this.wrapRGB ); material.map = this.map; material.lightMap = this.lightMap; material.bumpMap = this.bumpMap; material.bumpScale = this.bumpScale; material.normalMap = this.normalMap; material.normalScale.copy( this.normalScale ); material.specularMap = this.specularMap; material.envMap = this.envMap; material.combine = this.combine; material.reflectivity = this.reflectivity; material.refractionRatio = this.refractionRatio; material.fog = this.fog; material.shading = this.shading; material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; material.wireframeLinecap = this.wireframeLinecap; material.wireframeLinejoin = this.wireframeLinejoin; material.vertexColors = this.vertexColors; material.skinning = this.skinning; material.morphTargets = this.morphTargets; material.morphNormals = this.morphNormals; return material; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * opacity: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: * } */ THREE.MeshDepthMaterial = function ( parameters ) { THREE.Material.call( this ); this.wireframe = false; this.wireframeLinewidth = 1; this.setValues( parameters ); }; THREE.MeshDepthMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshDepthMaterial.prototype.clone = function () { var material = new THREE.MeshDepthMaterial(); THREE.Material.prototype.clone.call( this, material ); material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; return material; }; /** * @author mrdoob / http://mrdoob.com/ * * parameters = { * opacity: , * * shading: THREE.FlatShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: * } */ THREE.MeshNormalMaterial = function ( parameters ) { THREE.Material.call( this, parameters ); this.shading = THREE.FlatShading; this.wireframe = false; this.wireframeLinewidth = 1; this.morphTargets = false; this.setValues( parameters ); }; THREE.MeshNormalMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.MeshNormalMaterial.prototype.clone = function () { var material = new THREE.MeshNormalMaterial(); THREE.Material.prototype.clone.call( this, material ); material.shading = this.shading; material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; return material; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.MeshFaceMaterial = function ( materials ) { this.materials = materials instanceof Array ? materials : []; }; THREE.MeshFaceMaterial.prototype.clone = function () { var material = new THREE.MeshFaceMaterial(); for ( var i = 0; i < this.materials.length; i ++ ) { material.materials.push( this.materials[ i ].clone() ); } return material; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * size: , * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * vertexColors: , * * fog: * } */ THREE.ParticleSystemMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); this.map = null; this.size = 1; this.sizeAttenuation = true; this.vertexColors = false; this.fog = true; this.setValues( parameters ); }; THREE.ParticleSystemMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.ParticleSystemMaterial.prototype.clone = function () { var material = new THREE.ParticleSystemMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.map = this.map; material.size = this.size; material.sizeAttenuation = this.sizeAttenuation; material.vertexColors = this.vertexColors; material.fog = this.fog; return material; }; // backwards compatibility THREE.ParticleBasicMaterial = THREE.ParticleSystemMaterial; /** * @author alteredq / http://alteredqualia.com/ * * parameters = { * fragmentShader: , * vertexShader: , * * uniforms: { "parameter1": { type: "f", value: 1.0 }, "parameter2": { type: "i" value2: 2 } }, * * defines: { "label" : "value" }, * * shading: THREE.SmoothShading, * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * wireframe: , * wireframeLinewidth: , * * lights: , * * vertexColors: THREE.NoColors / THREE.VertexColors / THREE.FaceColors, * * skinning: , * morphTargets: , * morphNormals: , * * fog: * } */ THREE.ShaderMaterial = function ( parameters ) { THREE.Material.call( this ); this.fragmentShader = "void main() {}"; this.vertexShader = "void main() {}"; this.uniforms = {}; this.defines = {}; this.attributes = null; this.shading = THREE.SmoothShading; this.linewidth = 1; this.wireframe = false; this.wireframeLinewidth = 1; this.fog = false; // set to use scene fog this.lights = false; // set to use scene lights this.vertexColors = THREE.NoColors; // set to use "color" attribute stream this.skinning = false; // set to use skinning attribute streams this.morphTargets = false; // set to use morph targets this.morphNormals = false; // set to use morph normals // When rendered geometry doesn't include these attributes but the material does, // use these default values in WebGL. This avoids errors when buffer data is missing. this.defaultAttributeValues = { "color" : [ 1, 1, 1], "uv" : [ 0, 0 ], "uv2" : [ 0, 0 ] }; // By default, bind position to attribute index 0. In WebGL, attribute 0 // should always be used to avoid potentially expensive emulation. this.index0AttributeName = "position"; this.setValues( parameters ); }; THREE.ShaderMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.ShaderMaterial.prototype.clone = function () { var material = new THREE.ShaderMaterial(); THREE.Material.prototype.clone.call( this, material ); material.fragmentShader = this.fragmentShader; material.vertexShader = this.vertexShader; material.uniforms = THREE.UniformsUtils.clone( this.uniforms ); material.attributes = this.attributes; material.defines = this.defines; material.shading = this.shading; material.wireframe = this.wireframe; material.wireframeLinewidth = this.wireframeLinewidth; material.fog = this.fog; material.lights = this.lights; material.vertexColors = this.vertexColors; material.skinning = this.skinning; material.morphTargets = this.morphTargets; material.morphNormals = this.morphNormals; return material; }; /** * @author alteredq / http://alteredqualia.com/ * * parameters = { * color: , * opacity: , * map: new THREE.Texture( ), * * blending: THREE.NormalBlending, * depthTest: , * depthWrite: , * * uvOffset: new THREE.Vector2(), * uvScale: new THREE.Vector2(), * * fog: * } */ THREE.SpriteMaterial = function ( parameters ) { THREE.Material.call( this ); // defaults this.color = new THREE.Color( 0xffffff ); this.map = null; this.rotation = 0; this.fog = false; // set parameters this.setValues( parameters ); }; THREE.SpriteMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.SpriteMaterial.prototype.clone = function () { var material = new THREE.SpriteMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.map = this.map; material.rotation = this.rotation; material.fog = this.fog; return material; }; /** * @author mrdoob / http://mrdoob.com/ * * parameters = { * color: , * program: , * opacity: , * blending: THREE.NormalBlending * } */ THREE.SpriteCanvasMaterial = function ( parameters ) { THREE.Material.call( this ); this.color = new THREE.Color( 0xffffff ); this.program = function ( context, color ) {}; this.setValues( parameters ); }; THREE.SpriteCanvasMaterial.prototype = Object.create( THREE.Material.prototype ); THREE.SpriteCanvasMaterial.prototype.clone = function () { var material = new THREE.SpriteCanvasMaterial(); THREE.Material.prototype.clone.call( this, material ); material.color.copy( this.color ); material.program = this.program; return material; }; // backwards compatibility THREE.ParticleCanvasMaterial = THREE.SpriteCanvasMaterial;/** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author szimek / https://github.com/szimek/ */ THREE.Texture = function ( image, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) { this.id = THREE.TextureIdCount ++; this.uuid = THREE.Math.generateUUID(); this.name = ''; this.image = image; this.mipmaps = []; this.mapping = mapping !== undefined ? mapping : new THREE.UVMapping(); this.wrapS = wrapS !== undefined ? wrapS : THREE.ClampToEdgeWrapping; this.wrapT = wrapT !== undefined ? wrapT : THREE.ClampToEdgeWrapping; this.magFilter = magFilter !== undefined ? magFilter : THREE.LinearFilter; this.minFilter = minFilter !== undefined ? minFilter : THREE.LinearMipMapLinearFilter; this.anisotropy = anisotropy !== undefined ? anisotropy : 1; this.format = format !== undefined ? format : THREE.RGBAFormat; this.type = type !== undefined ? type : THREE.UnsignedByteType; this.offset = new THREE.Vector2( 0, 0 ); this.repeat = new THREE.Vector2( 1, 1 ); this.generateMipmaps = true; this.premultiplyAlpha = false; this.flipY = true; this.unpackAlignment = 4; // valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml) this._needsUpdate = false; this.onUpdate = null; }; THREE.Texture.prototype = { constructor: THREE.Texture, get needsUpdate () { return this._needsUpdate; }, set needsUpdate ( value ) { if ( value === true ) this.update(); this._needsUpdate = value; }, clone: function ( texture ) { if ( texture === undefined ) texture = new THREE.Texture(); texture.image = this.image; texture.mipmaps = this.mipmaps.slice(0); texture.mapping = this.mapping; texture.wrapS = this.wrapS; texture.wrapT = this.wrapT; texture.magFilter = this.magFilter; texture.minFilter = this.minFilter; texture.anisotropy = this.anisotropy; texture.format = this.format; texture.type = this.type; texture.offset.copy( this.offset ); texture.repeat.copy( this.repeat ); texture.generateMipmaps = this.generateMipmaps; texture.premultiplyAlpha = this.premultiplyAlpha; texture.flipY = this.flipY; texture.unpackAlignment = this.unpackAlignment; return texture; }, update: function () { this.dispatchEvent( { type: 'update' } ); }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.Texture.prototype ); THREE.TextureIdCount = 0; /** * @author alteredq / http://alteredqualia.com/ */ THREE.CompressedTexture = function ( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); this.image = { width: width, height: height }; this.mipmaps = mipmaps; this.generateMipmaps = false; // WebGL currently can't generate mipmaps for compressed textures, they must be embedded in DDS file }; THREE.CompressedTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.CompressedTexture.prototype.clone = function () { var texture = new THREE.CompressedTexture(); THREE.Texture.prototype.clone.call( this, texture ); return texture; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.DataTexture = function ( data, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy ) { THREE.Texture.call( this, null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ); this.image = { data: data, width: width, height: height }; }; THREE.DataTexture.prototype = Object.create( THREE.Texture.prototype ); THREE.DataTexture.prototype.clone = function () { var texture = new THREE.DataTexture(); THREE.Texture.prototype.clone.call( this, texture ); return texture; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.ParticleSystem = function ( geometry, material ) { THREE.Object3D.call( this ); this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.ParticleSystemMaterial( { color: Math.random() * 0xffffff } ); this.sortParticles = false; this.frustumCulled = false; }; THREE.ParticleSystem.prototype = Object.create( THREE.Object3D.prototype ); THREE.ParticleSystem.prototype.clone = function ( object ) { if ( object === undefined ) object = new THREE.ParticleSystem( this.geometry, this.material ); object.sortParticles = this.sortParticles; THREE.Object3D.prototype.clone.call( this, object ); return object; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.Line = function ( geometry, material, type ) { THREE.Object3D.call( this ); this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.LineBasicMaterial( { color: Math.random() * 0xffffff } ); this.type = ( type !== undefined ) ? type : THREE.LineStrip; }; THREE.LineStrip = 0; THREE.LinePieces = 1; THREE.Line.prototype = Object.create( THREE.Object3D.prototype ); THREE.Line.prototype.clone = function ( object ) { if ( object === undefined ) object = new THREE.Line( this.geometry, this.material, this.type ); THREE.Object3D.prototype.clone.call( this, object ); return object; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author mikael emtinger / http://gomo.se/ * @author jonobr1 / http://jonobr1.com/ */ THREE.Mesh = function ( geometry, material ) { THREE.Object3D.call( this ); this.geometry = geometry !== undefined ? geometry : new THREE.Geometry(); this.material = material !== undefined ? material : new THREE.MeshBasicMaterial( { color: Math.random() * 0xffffff } ); this.updateMorphTargets(); }; THREE.Mesh.prototype = Object.create( THREE.Object3D.prototype ); THREE.Mesh.prototype.updateMorphTargets = function () { if ( this.geometry.morphTargets !== undefined && this.geometry.morphTargets.length > 0 ) { this.morphTargetBase = -1; this.morphTargetForcedOrder = []; this.morphTargetInfluences = []; this.morphTargetDictionary = {}; for ( var m = 0, ml = this.geometry.morphTargets.length; m < ml; m ++ ) { this.morphTargetInfluences.push( 0 ); this.morphTargetDictionary[ this.geometry.morphTargets[ m ].name ] = m; } } }; THREE.Mesh.prototype.getMorphTargetIndexByName = function ( name ) { if ( this.morphTargetDictionary[ name ] !== undefined ) { return this.morphTargetDictionary[ name ]; } console.log( "THREE.Mesh.getMorphTargetIndexByName: morph target " + name + " does not exist. Returning 0." ); return 0; }; THREE.Mesh.prototype.clone = function ( object ) { if ( object === undefined ) object = new THREE.Mesh( this.geometry, this.material ); THREE.Object3D.prototype.clone.call( this, object ); return object; }; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.Bone = function( belongsToSkin ) { THREE.Object3D.call( this ); this.skin = belongsToSkin; this.skinMatrix = new THREE.Matrix4(); }; THREE.Bone.prototype = Object.create( THREE.Object3D.prototype ); THREE.Bone.prototype.update = function ( parentSkinMatrix, forceUpdate ) { // update local if ( this.matrixAutoUpdate ) { forceUpdate |= this.updateMatrix(); } // update skin matrix if ( forceUpdate || this.matrixWorldNeedsUpdate ) { if( parentSkinMatrix ) { this.skinMatrix.multiplyMatrices( parentSkinMatrix, this.matrix ); } else { this.skinMatrix.copy( this.matrix ); } this.matrixWorldNeedsUpdate = false; forceUpdate = true; } // update children var child, i, l = this.children.length; for ( i = 0; i < l; i ++ ) { this.children[ i ].update( this.skinMatrix, forceUpdate ); } }; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.SkinnedMesh = function ( geometry, material, useVertexTexture ) { THREE.Mesh.call( this, geometry, material ); // this.useVertexTexture = useVertexTexture !== undefined ? useVertexTexture : true; // init bones this.identityMatrix = new THREE.Matrix4(); this.bones = []; this.boneMatrices = []; var b, bone, gbone, p, q, s; if ( this.geometry && this.geometry.bones !== undefined ) { for ( b = 0; b < this.geometry.bones.length; b ++ ) { gbone = this.geometry.bones[ b ]; p = gbone.pos; q = gbone.rotq; s = gbone.scl; bone = this.addBone(); bone.name = gbone.name; bone.position.set( p[0], p[1], p[2] ); bone.quaternion.set( q[0], q[1], q[2], q[3] ); if ( s !== undefined ) { bone.scale.set( s[0], s[1], s[2] ); } else { bone.scale.set( 1, 1, 1 ); } } for ( b = 0; b < this.bones.length; b ++ ) { gbone = this.geometry.bones[ b ]; bone = this.bones[ b ]; if ( gbone.parent === -1 ) { this.add( bone ); } else { this.bones[ gbone.parent ].add( bone ); } } // var nBones = this.bones.length; if ( this.useVertexTexture ) { // layout (1 matrix = 4 pixels) // RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4) // with 8x8 pixel texture max 16 bones (8 * 8 / 4) // 16x16 pixel texture max 64 bones (16 * 16 / 4) // 32x32 pixel texture max 256 bones (32 * 32 / 4) // 64x64 pixel texture max 1024 bones (64 * 64 / 4) var size; if ( nBones > 256 ) size = 64; else if ( nBones > 64 ) size = 32; else if ( nBones > 16 ) size = 16; else size = 8; this.boneTextureWidth = size; this.boneTextureHeight = size; this.boneMatrices = new Float32Array( this.boneTextureWidth * this.boneTextureHeight * 4 ); // 4 floats per RGBA pixel this.boneTexture = new THREE.DataTexture( this.boneMatrices, this.boneTextureWidth, this.boneTextureHeight, THREE.RGBAFormat, THREE.FloatType ); this.boneTexture.minFilter = THREE.NearestFilter; this.boneTexture.magFilter = THREE.NearestFilter; this.boneTexture.generateMipmaps = false; this.boneTexture.flipY = false; } else { this.boneMatrices = new Float32Array( 16 * nBones ); } this.pose(); } }; THREE.SkinnedMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.SkinnedMesh.prototype.addBone = function( bone ) { if ( bone === undefined ) { bone = new THREE.Bone( this ); } this.bones.push( bone ); return bone; }; THREE.SkinnedMesh.prototype.updateMatrixWorld = function () { var offsetMatrix = new THREE.Matrix4(); return function ( force ) { this.matrixAutoUpdate && this.updateMatrix(); // update matrixWorld if ( this.matrixWorldNeedsUpdate || force ) { if ( this.parent ) { this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); } else { this.matrixWorld.copy( this.matrix ); } this.matrixWorldNeedsUpdate = false; force = true; } // update children for ( var i = 0, l = this.children.length; i < l; i ++ ) { var child = this.children[ i ]; if ( child instanceof THREE.Bone ) { child.update( this.identityMatrix, false ); } else { child.updateMatrixWorld( true ); } } // make a snapshot of the bones' rest position if ( this.boneInverses == undefined ) { this.boneInverses = []; for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { var inverse = new THREE.Matrix4(); inverse.getInverse( this.bones[ b ].skinMatrix ); this.boneInverses.push( inverse ); } } // flatten bone matrices to array for ( var b = 0, bl = this.bones.length; b < bl; b ++ ) { // compute the offset between the current and the original transform; // TODO: we could get rid of this multiplication step if the skinMatrix // was already representing the offset; however, this requires some // major changes to the animation system offsetMatrix.multiplyMatrices( this.bones[ b ].skinMatrix, this.boneInverses[ b ] ); offsetMatrix.flattenToArrayOffset( this.boneMatrices, b * 16 ); } if ( this.useVertexTexture ) { this.boneTexture.needsUpdate = true; } }; }(); THREE.SkinnedMesh.prototype.pose = function () { this.updateMatrixWorld( true ); this.normalizeSkinWeights(); }; THREE.SkinnedMesh.prototype.normalizeSkinWeights = function () { if ( this.geometry instanceof THREE.Geometry ) { for ( var i = 0; i < this.geometry.skinIndices.length; i ++ ) { var sw = this.geometry.skinWeights[ i ]; var scale = 1.0 / sw.lengthManhattan(); if ( scale !== Infinity ) { sw.multiplyScalar( scale ); } else { sw.set( 1 ); // this will be normalized by the shader anyway } } } else { // skinning weights assumed to be normalized for THREE.BufferGeometry } }; THREE.SkinnedMesh.prototype.clone = function ( object ) { if ( object === undefined ) { object = new THREE.SkinnedMesh( this.geometry, this.material, this.useVertexTexture ); } THREE.Mesh.prototype.clone.call( this, object ); return object; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.MorphAnimMesh = function ( geometry, material ) { THREE.Mesh.call( this, geometry, material ); // API this.duration = 1000; // milliseconds this.mirroredLoop = false; this.time = 0; // internals this.lastKeyframe = 0; this.currentKeyframe = 0; this.direction = 1; this.directionBackwards = false; this.setFrameRange( 0, this.geometry.morphTargets.length - 1 ); }; THREE.MorphAnimMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.MorphAnimMesh.prototype.setFrameRange = function ( start, end ) { this.startKeyframe = start; this.endKeyframe = end; this.length = this.endKeyframe - this.startKeyframe + 1; }; THREE.MorphAnimMesh.prototype.setDirectionForward = function () { this.direction = 1; this.directionBackwards = false; }; THREE.MorphAnimMesh.prototype.setDirectionBackward = function () { this.direction = -1; this.directionBackwards = true; }; THREE.MorphAnimMesh.prototype.parseAnimations = function () { var geometry = this.geometry; if ( ! geometry.animations ) geometry.animations = {}; var firstAnimation, animations = geometry.animations; var pattern = /([a-z]+)(\d+)/; for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { var morph = geometry.morphTargets[ i ]; var parts = morph.name.match( pattern ); if ( parts && parts.length > 1 ) { var label = parts[ 1 ]; var num = parts[ 2 ]; if ( ! animations[ label ] ) animations[ label ] = { start: Infinity, end: -Infinity }; var animation = animations[ label ]; if ( i < animation.start ) animation.start = i; if ( i > animation.end ) animation.end = i; if ( ! firstAnimation ) firstAnimation = label; } } geometry.firstAnimation = firstAnimation; }; THREE.MorphAnimMesh.prototype.setAnimationLabel = function ( label, start, end ) { if ( ! this.geometry.animations ) this.geometry.animations = {}; this.geometry.animations[ label ] = { start: start, end: end }; }; THREE.MorphAnimMesh.prototype.playAnimation = function ( label, fps ) { var animation = this.geometry.animations[ label ]; if ( animation ) { this.setFrameRange( animation.start, animation.end ); this.duration = 1000 * ( ( animation.end - animation.start ) / fps ); this.time = 0; } else { console.warn( "animation[" + label + "] undefined" ); } }; THREE.MorphAnimMesh.prototype.updateAnimation = function ( delta ) { var frameTime = this.duration / this.length; this.time += this.direction * delta; if ( this.mirroredLoop ) { if ( this.time > this.duration || this.time < 0 ) { this.direction *= -1; if ( this.time > this.duration ) { this.time = this.duration; this.directionBackwards = true; } if ( this.time < 0 ) { this.time = 0; this.directionBackwards = false; } } } else { this.time = this.time % this.duration; if ( this.time < 0 ) this.time += this.duration; } var keyframe = this.startKeyframe + THREE.Math.clamp( Math.floor( this.time / frameTime ), 0, this.length - 1 ); if ( keyframe !== this.currentKeyframe ) { this.morphTargetInfluences[ this.lastKeyframe ] = 0; this.morphTargetInfluences[ this.currentKeyframe ] = 1; this.morphTargetInfluences[ keyframe ] = 0; this.lastKeyframe = this.currentKeyframe; this.currentKeyframe = keyframe; } var mix = ( this.time % frameTime ) / frameTime; if ( this.directionBackwards ) { mix = 1 - mix; } this.morphTargetInfluences[ this.currentKeyframe ] = mix; this.morphTargetInfluences[ this.lastKeyframe ] = 1 - mix; }; THREE.MorphAnimMesh.prototype.clone = function ( object ) { if ( object === undefined ) object = new THREE.MorphAnimMesh( this.geometry, this.material ); object.duration = this.duration; object.mirroredLoop = this.mirroredLoop; object.time = this.time; object.lastKeyframe = this.lastKeyframe; object.currentKeyframe = this.currentKeyframe; object.direction = this.direction; object.directionBackwards = this.directionBackwards; THREE.Mesh.prototype.clone.call( this, object ); return object; }; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.LOD = function () { THREE.Object3D.call( this ); this.objects = []; }; THREE.LOD.prototype = Object.create( THREE.Object3D.prototype ); THREE.LOD.prototype.addLevel = function ( object, distance ) { if ( distance === undefined ) distance = 0; distance = Math.abs( distance ); for ( var l = 0; l < this.objects.length; l ++ ) { if ( distance < this.objects[ l ].distance ) { break; } } this.objects.splice( l, 0, { distance: distance, object: object } ); this.add( object ); }; THREE.LOD.prototype.getObjectForDistance = function ( distance ) { for ( var i = 1, l = this.objects.length; i < l; i ++ ) { if ( distance < this.objects[ i ].distance ) { break; } } return this.objects[ i - 1 ].object; }; THREE.LOD.prototype.update = function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); return function ( camera ) { if ( this.objects.length > 1 ) { v1.setFromMatrixPosition( camera.matrixWorld ); v2.setFromMatrixPosition( this.matrixWorld ); var distance = v1.distanceTo( v2 ); this.objects[ 0 ].object.visible = true; for ( var i = 1, l = this.objects.length; i < l; i ++ ) { if ( distance >= this.objects[ i ].distance ) { this.objects[ i - 1 ].object.visible = false; this.objects[ i ].object.visible = true; } else { break; } } for( ; i < l; i ++ ) { this.objects[ i ].object.visible = false; } } }; }(); THREE.LOD.prototype.clone = function ( object ) { if ( object === undefined ) object = new THREE.LOD(); THREE.Object3D.prototype.clone.call( this, object ); for ( var i = 0, l = this.objects.length; i < l; i ++ ) { var x = this.objects[i].object.clone(); x.visible = i === 0; object.addLevel( x, this.objects[i].distance ); } return object; }; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.Sprite = ( function () { var geometry = new THREE.Geometry2( 3 ); geometry.vertices.set( [ - 0.5, - 0.5, 0, 0.5, - 0.5, 0, 0.5, 0.5, 0 ] ); return function ( material ) { THREE.Object3D.call( this ); this.geometry = geometry; this.material = ( material !== undefined ) ? material : new THREE.SpriteMaterial(); }; } )(); THREE.Sprite.prototype = Object.create( THREE.Object3D.prototype ); /* * Custom update matrix */ THREE.Sprite.prototype.updateMatrix = function () { this.matrix.compose( this.position, this.quaternion, this.scale ); this.matrixWorldNeedsUpdate = true; }; THREE.Sprite.prototype.clone = function ( object ) { if ( object === undefined ) object = new THREE.Sprite( this.material ); THREE.Object3D.prototype.clone.call( this, object ); return object; }; // Backwards compatibility THREE.Particle = THREE.Sprite;/** * @author mrdoob / http://mrdoob.com/ */ THREE.Scene = function () { THREE.Object3D.call( this ); this.fog = null; this.overrideMaterial = null; this.autoUpdate = true; // checked by the renderer this.matrixAutoUpdate = false; this.__lights = []; this.__objectsAdded = []; this.__objectsRemoved = []; }; THREE.Scene.prototype = Object.create( THREE.Object3D.prototype ); THREE.Scene.prototype.__addObject = function ( object ) { if ( object instanceof THREE.Light ) { if ( this.__lights.indexOf( object ) === - 1 ) { this.__lights.push( object ); } if ( object.target && object.target.parent === undefined ) { this.add( object.target ); } } else if ( !( object instanceof THREE.Camera || object instanceof THREE.Bone ) ) { this.__objectsAdded.push( object ); // check if previously removed var i = this.__objectsRemoved.indexOf( object ); if ( i !== -1 ) { this.__objectsRemoved.splice( i, 1 ); } } this.dispatchEvent( { type: 'objectAdded', object: object } ); object.dispatchEvent( { type: 'addedToScene', scene: this } ); for ( var c = 0; c < object.children.length; c ++ ) { this.__addObject( object.children[ c ] ); } }; THREE.Scene.prototype.__removeObject = function ( object ) { if ( object instanceof THREE.Light ) { var i = this.__lights.indexOf( object ); if ( i !== -1 ) { this.__lights.splice( i, 1 ); } if ( object.shadowCascadeArray ) { for ( var x = 0; x < object.shadowCascadeArray.length; x ++ ) { this.__removeObject( object.shadowCascadeArray[ x ] ); } } } else if ( !( object instanceof THREE.Camera ) ) { this.__objectsRemoved.push( object ); // check if previously added var i = this.__objectsAdded.indexOf( object ); if ( i !== -1 ) { this.__objectsAdded.splice( i, 1 ); } } this.dispatchEvent( { type: 'objectRemoved', object: object } ); object.dispatchEvent( { type: 'removedFromScene', scene: this } ); for ( var c = 0; c < object.children.length; c ++ ) { this.__removeObject( object.children[ c ] ); } }; THREE.Scene.prototype.clone = function ( object ) { if ( object === undefined ) object = new THREE.Scene(); THREE.Object3D.prototype.clone.call(this, object); if ( this.fog !== null ) object.fog = this.fog.clone(); if ( this.overrideMaterial !== null ) object.overrideMaterial = this.overrideMaterial.clone(); object.autoUpdate = this.autoUpdate; object.matrixAutoUpdate = this.matrixAutoUpdate; return object; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Fog = function ( color, near, far ) { this.name = ''; this.color = new THREE.Color( color ); this.near = ( near !== undefined ) ? near : 1; this.far = ( far !== undefined ) ? far : 1000; }; THREE.Fog.prototype.clone = function () { return new THREE.Fog( this.color.getHex(), this.near, this.far ); }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.FogExp2 = function ( color, density ) { this.name = ''; this.color = new THREE.Color( color ); this.density = ( density !== undefined ) ? density : 0.00025; }; THREE.FogExp2.prototype.clone = function () { return new THREE.FogExp2( this.color.getHex(), this.density ); }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.CanvasRenderer = function ( parameters ) { console.log( 'THREE.CanvasRenderer', THREE.REVISION ); var smoothstep = THREE.Math.smoothstep; parameters = parameters || {}; var _this = this, _renderData, _elements, _lights, _projector = new THREE.Projector(), _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), _canvasWidth = _canvas.width, _canvasHeight = _canvas.height, _canvasWidthHalf = Math.floor( _canvasWidth / 2 ), _canvasHeightHalf = Math.floor( _canvasHeight / 2 ), _context = _canvas.getContext( '2d', { alpha: parameters.alpha === true } ), _clearColor = new THREE.Color( 0x000000 ), _clearAlpha = 0, _contextGlobalAlpha = 1, _contextGlobalCompositeOperation = 0, _contextStrokeStyle = null, _contextFillStyle = null, _contextLineWidth = null, _contextLineCap = null, _contextLineJoin = null, _contextDashSize = null, _contextGapSize = 0, _camera, _v1, _v2, _v3, _v4, _v5 = new THREE.RenderableVertex(), _v6 = new THREE.RenderableVertex(), _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y, _v5x, _v5y, _v6x, _v6y, _color = new THREE.Color(), _color1 = new THREE.Color(), _color2 = new THREE.Color(), _color3 = new THREE.Color(), _color4 = new THREE.Color(), _diffuseColor = new THREE.Color(), _emissiveColor = new THREE.Color(), _lightColor = new THREE.Color(), _patterns = {}, _near, _far, _image, _uvs, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, _clipBox = new THREE.Box2(), _clearBox = new THREE.Box2(), _elemBox = new THREE.Box2(), _ambientLight = new THREE.Color(), _directionalLights = new THREE.Color(), _pointLights = new THREE.Color(), _vector3 = new THREE.Vector3(), // Needed for PointLight _normal = new THREE.Vector3(), _normalViewMatrix = new THREE.Matrix3(), _pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData, _gradientMap, _gradientMapContext, _gradientMapQuality = 16; _pixelMap = document.createElement( 'canvas' ); _pixelMap.width = _pixelMap.height = 2; _pixelMapContext = _pixelMap.getContext( '2d' ); _pixelMapContext.fillStyle = 'rgba(0,0,0,1)'; _pixelMapContext.fillRect( 0, 0, 2, 2 ); _pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 ); _pixelMapData = _pixelMapImage.data; _gradientMap = document.createElement( 'canvas' ); _gradientMap.width = _gradientMap.height = _gradientMapQuality; _gradientMapContext = _gradientMap.getContext( '2d' ); _gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 ); _gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality ); _gradientMapQuality --; // Fix UVs // dash+gap fallbacks for Firefox and everything else if ( _context.setLineDash === undefined ) { if ( _context.mozDash !== undefined ) { _context.setLineDash = function ( values ) { _context.mozDash = values[ 0 ] !== null ? values : null; } } else { _context.setLineDash = function () {} } } this.domElement = _canvas; this.devicePixelRatio = parameters.devicePixelRatio !== undefined ? parameters.devicePixelRatio : self.devicePixelRatio !== undefined ? self.devicePixelRatio : 1; this.autoClear = true; this.sortObjects = true; this.sortElements = true; this.info = { render: { vertices: 0, faces: 0 } } // WebGLRenderer compatibility this.supportsVertexTextures = function () {}; this.setFaceCulling = function () {}; this.setSize = function ( width, height, updateStyle ) { _canvasWidth = width * this.devicePixelRatio; _canvasHeight = height * this.devicePixelRatio; _canvasWidthHalf = Math.floor( _canvasWidth / 2 ); _canvasHeightHalf = Math.floor( _canvasHeight / 2 ); _canvas.width = _canvasWidth; _canvas.height = _canvasHeight; if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { _canvas.style.width = width + 'px'; _canvas.style.height = height + 'px'; } _clipBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ), _clipBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); _contextGlobalAlpha = 1; _contextGlobalCompositeOperation = 0; _contextStrokeStyle = null; _contextFillStyle = null; _contextLineWidth = null; _contextLineCap = null; _contextLineJoin = null; }; this.setClearColor = function ( color, alpha ) { _clearColor.set( color ); _clearAlpha = alpha !== undefined ? alpha : 1; _clearBox.min.set( - _canvasWidthHalf, - _canvasHeightHalf ); _clearBox.max.set( _canvasWidthHalf, _canvasHeightHalf ); }; this.setClearColorHex = function ( hex, alpha ) { console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); this.setClearColor( hex, alpha ); }; this.getMaxAnisotropy = function () { return 0; }; this.clear = function () { _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); if ( _clearBox.empty() === false ) { _clearBox.intersect( _clipBox ); _clearBox.expandByScalar( 2 ); if ( _clearAlpha < 1 ) { _context.clearRect( _clearBox.min.x | 0, _clearBox.min.y | 0, ( _clearBox.max.x - _clearBox.min.x ) | 0, ( _clearBox.max.y - _clearBox.min.y ) | 0 ); } if ( _clearAlpha > 0 ) { setBlending( THREE.NormalBlending ); setOpacity( 1 ); setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearAlpha + ')' ); _context.fillRect( _clearBox.min.x | 0, _clearBox.min.y | 0, ( _clearBox.max.x - _clearBox.min.x ) | 0, ( _clearBox.max.y - _clearBox.min.y ) | 0 ); } _clearBox.makeEmpty(); } }; // compatibility this.clearColor = function () {}; this.clearDepth = function () {}; this.clearStencil = function () {}; this.render = function ( scene, camera ) { if ( camera instanceof THREE.Camera === false ) { console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' ); return; } if ( this.autoClear === true ) this.clear(); _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf ); _this.info.render.vertices = 0; _this.info.render.faces = 0; _renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements ); _elements = _renderData.elements; _lights = _renderData.lights; _camera = camera; _normalViewMatrix.getNormalMatrix( camera.matrixWorldInverse ); /* DEBUG setFillStyle( 'rgba( 0, 255, 255, 0.5 )' ); _context.fillRect( _clipBox.min.x, _clipBox.min.y, _clipBox.max.x - _clipBox.min.x, _clipBox.max.y - _clipBox.min.y ); */ calculateLights(); for ( var e = 0, el = _elements.length; e < el; e ++ ) { var element = _elements[ e ]; var material = element.material; if ( material === undefined || material.visible === false ) continue; _elemBox.makeEmpty(); if ( element instanceof THREE.RenderableSprite ) { _v1 = element; _v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf; renderSprite( _v1, element, material ); } else if ( element instanceof THREE.RenderableLine ) { _v1 = element.v1; _v2 = element.v2; _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen ] ); if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { renderLine( _v1, _v2, element, material ); } } else if ( element instanceof THREE.RenderableFace ) { _v1 = element.v1; _v2 = element.v2; _v3 = element.v3; if ( _v1.positionScreen.z < -1 || _v1.positionScreen.z > 1 ) continue; if ( _v2.positionScreen.z < -1 || _v2.positionScreen.z > 1 ) continue; if ( _v3.positionScreen.z < -1 || _v3.positionScreen.z > 1 ) continue; _v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf; _v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf; _v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf; if ( material.overdraw > 0 ) { expand( _v1.positionScreen, _v2.positionScreen, material.overdraw ); expand( _v2.positionScreen, _v3.positionScreen, material.overdraw ); expand( _v3.positionScreen, _v1.positionScreen, material.overdraw ); } _elemBox.setFromPoints( [ _v1.positionScreen, _v2.positionScreen, _v3.positionScreen ] ); if ( _clipBox.isIntersectionBox( _elemBox ) === true ) { renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material ); } } /* DEBUG setLineWidth( 1 ); setStrokeStyle( 'rgba( 0, 255, 0, 0.5 )' ); _context.strokeRect( _elemBox.min.x, _elemBox.min.y, _elemBox.max.x - _elemBox.min.x, _elemBox.max.y - _elemBox.min.y ); */ _clearBox.union( _elemBox ); } /* DEBUG setLineWidth( 1 ); setStrokeStyle( 'rgba( 255, 0, 0, 0.5 )' ); _context.strokeRect( _clearBox.min.x, _clearBox.min.y, _clearBox.max.x - _clearBox.min.x, _clearBox.max.y - _clearBox.min.y ); */ _context.setTransform( 1, 0, 0, 1, 0, 0 ); }; // function calculateLights() { _ambientLight.setRGB( 0, 0, 0 ); _directionalLights.setRGB( 0, 0, 0 ); _pointLights.setRGB( 0, 0, 0 ); for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { var light = _lights[ l ]; var lightColor = light.color; if ( light instanceof THREE.AmbientLight ) { _ambientLight.add( lightColor ); } else if ( light instanceof THREE.DirectionalLight ) { // for sprites _directionalLights.add( lightColor ); } else if ( light instanceof THREE.PointLight ) { // for sprites _pointLights.add( lightColor ); } } } function calculateLight( position, normal, color ) { for ( var l = 0, ll = _lights.length; l < ll; l ++ ) { var light = _lights[ l ]; _lightColor.copy( light.color ); if ( light instanceof THREE.DirectionalLight ) { var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ).normalize(); var amount = normal.dot( lightPosition ); if ( amount <= 0 ) continue; amount *= light.intensity; color.add( _lightColor.multiplyScalar( amount ) ); } else if ( light instanceof THREE.PointLight ) { var lightPosition = _vector3.setFromMatrixPosition( light.matrixWorld ); var amount = normal.dot( _vector3.subVectors( lightPosition, position ).normalize() ); if ( amount <= 0 ) continue; amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 ); if ( amount == 0 ) continue; amount *= light.intensity; color.add( _lightColor.multiplyScalar( amount ) ); } } } function renderSprite( v1, element, material ) { setOpacity( material.opacity ); setBlending( material.blending ); var scaleX = element.scale.x * _canvasWidthHalf; var scaleY = element.scale.y * _canvasHeightHalf; var dist = 0.5 * Math.sqrt( scaleX * scaleX + scaleY * scaleY ); // allow for rotated sprite _elemBox.min.set( v1.x - dist, v1.y - dist ); _elemBox.max.set( v1.x + dist, v1.y + dist ); if ( material instanceof THREE.SpriteMaterial || material instanceof THREE.ParticleSystemMaterial ) { // Backwards compatibility var texture = material.map; if ( texture !== null ) { if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { if ( texture.image !== undefined && texture.image.width > 0 ) { textureToPattern( texture ); } texture.addEventListener( 'update', onTextureUpdate ); } var pattern = _patterns[ texture.id ]; if ( pattern !== undefined ) { setFillStyle( pattern ); } else { setFillStyle( 'rgba( 0, 0, 0, 1 )' ); } // var bitmap = texture.image; var ox = bitmap.width * texture.offset.x; var oy = bitmap.height * texture.offset.y; var sx = bitmap.width * texture.repeat.x; var sy = bitmap.height * texture.repeat.y; var cx = scaleX / sx; var cy = scaleY / sy; _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.translate( - scaleX / 2, - scaleY / 2 ); _context.scale( cx, cy ); _context.translate( - ox, - oy ); _context.fillRect( ox, oy, sx, sy ); _context.restore(); } else { // no texture setFillStyle( material.color.getStyle() ); _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.scale( scaleX, - scaleY ); _context.fillRect( - 0.5, - 0.5, 1, 1 ); _context.restore(); } } else if ( material instanceof THREE.SpriteCanvasMaterial ) { setStrokeStyle( material.color.getStyle() ); setFillStyle( material.color.getStyle() ); _context.save(); _context.translate( v1.x, v1.y ); if ( material.rotation !== 0 ) _context.rotate( material.rotation ); _context.scale( scaleX, scaleY ); material.program( _context ); _context.restore(); } /* DEBUG setStrokeStyle( 'rgb(255,255,0)' ); _context.beginPath(); _context.moveTo( v1.x - 10, v1.y ); _context.lineTo( v1.x + 10, v1.y ); _context.moveTo( v1.x, v1.y - 10 ); _context.lineTo( v1.x, v1.y + 10 ); _context.stroke(); */ } function renderLine( v1, v2, element, material ) { setOpacity( material.opacity ); setBlending( material.blending ); _context.beginPath(); _context.moveTo( v1.positionScreen.x, v1.positionScreen.y ); _context.lineTo( v2.positionScreen.x, v2.positionScreen.y ); if ( material instanceof THREE.LineBasicMaterial ) { setLineWidth( material.linewidth ); setLineCap( material.linecap ); setLineJoin( material.linejoin ); if ( material.vertexColors !== THREE.VertexColors ) { setStrokeStyle( material.color.getStyle() ); } else { var colorStyle1 = element.vertexColors[0].getStyle(); var colorStyle2 = element.vertexColors[1].getStyle(); if ( colorStyle1 === colorStyle2 ) { setStrokeStyle( colorStyle1 ); } else { try { var grad = _context.createLinearGradient( v1.positionScreen.x, v1.positionScreen.y, v2.positionScreen.x, v2.positionScreen.y ); grad.addColorStop( 0, colorStyle1 ); grad.addColorStop( 1, colorStyle2 ); } catch ( exception ) { grad = colorStyle1; } setStrokeStyle( grad ); } } _context.stroke(); _elemBox.expandByScalar( material.linewidth * 2 ); } else if ( material instanceof THREE.LineDashedMaterial ) { setLineWidth( material.linewidth ); setLineCap( material.linecap ); setLineJoin( material.linejoin ); setStrokeStyle( material.color.getStyle() ); setDashAndGap( material.dashSize, material.gapSize ); _context.stroke(); _elemBox.expandByScalar( material.linewidth * 2 ); setDashAndGap( null, null ); } } function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material ) { _this.info.render.vertices += 3; _this.info.render.faces ++; setOpacity( material.opacity ); setBlending( material.blending ); _v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y; _v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y; _v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y; drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y ); if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null ) { _diffuseColor.copy( material.color ); _emissiveColor.copy( material.emissive ); if ( material.vertexColors === THREE.FaceColors ) { _diffuseColor.multiply( element.color ); } if ( material.wireframe === false && material.shading === THREE.SmoothShading && element.vertexNormalsLength === 3 ) { _color1.copy( _ambientLight ); _color2.copy( _ambientLight ); _color3.copy( _ambientLight ); calculateLight( element.v1.positionWorld, element.vertexNormalsModel[ 0 ], _color1 ); calculateLight( element.v2.positionWorld, element.vertexNormalsModel[ 1 ], _color2 ); calculateLight( element.v3.positionWorld, element.vertexNormalsModel[ 2 ], _color3 ); _color1.multiply( _diffuseColor ).add( _emissiveColor ); _color2.multiply( _diffuseColor ).add( _emissiveColor ); _color3.multiply( _diffuseColor ).add( _emissiveColor ); _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); _image = getGradientTexture( _color1, _color2, _color3, _color4 ); clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); } else { _color.copy( _ambientLight ); calculateLight( element.centroidModel, element.normalModel, _color ); _color.multiply( _diffuseColor ).add( _emissiveColor ); material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } } else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { if ( material.map !== null ) { if ( material.map.mapping instanceof THREE.UVMapping ) { _uvs = element.uvs[ 0 ]; patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].x, _uvs[ uv1 ].y, _uvs[ uv2 ].x, _uvs[ uv2 ].y, _uvs[ uv3 ].x, _uvs[ uv3 ].y, material.map ); } } else if ( material.envMap !== null ) { if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) { _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); _uv1x = 0.5 * _normal.x + 0.5; _uv1y = 0.5 * _normal.y + 0.5; _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); _uv2x = 0.5 * _normal.x + 0.5; _uv2y = 0.5 * _normal.y + 0.5; _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); _uv3x = 0.5 * _normal.x + 0.5; _uv3y = 0.5 * _normal.y + 0.5; patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap ); }/* else if ( material.envMap.mapping === THREE.SphericalRefractionMapping ) { }*/ } else { _color.copy( material.color ); if ( material.vertexColors === THREE.FaceColors ) { _color.multiply( element.color ); } material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } } else if ( material instanceof THREE.MeshDepthMaterial ) { _near = _camera.near; _far = _camera.far; _color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z * v1.positionScreen.w, _near, _far ); _color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z * v2.positionScreen.w, _near, _far ); _color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z * v3.positionScreen.w, _near, _far ); _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); _image = getGradientTexture( _color1, _color2, _color3, _color4 ); clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); } else if ( material instanceof THREE.MeshNormalMaterial ) { if ( material.shading === THREE.FlatShading ) { _normal.copy( element.normalModel ).applyMatrix3( _normalViewMatrix ); _color.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); material.wireframe === true ? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin ) : fillPath( _color ); } else if ( material.shading === THREE.SmoothShading ) { _normal.copy( element.vertexNormalsModel[ uv1 ] ).applyMatrix3( _normalViewMatrix ); _color1.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); _normal.copy( element.vertexNormalsModel[ uv2 ] ).applyMatrix3( _normalViewMatrix ); _color2.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); _normal.copy( element.vertexNormalsModel[ uv3 ] ).applyMatrix3( _normalViewMatrix ); _color3.setRGB( _normal.x, _normal.y, _normal.z ).multiplyScalar( 0.5 ).addScalar( 0.5 ); _color4.addColors( _color2, _color3 ).multiplyScalar( 0.5 ); _image = getGradientTexture( _color1, _color2, _color3, _color4 ); clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image ); } } } // function drawTriangle( x0, y0, x1, y1, x2, y2 ) { _context.beginPath(); _context.moveTo( x0, y0 ); _context.lineTo( x1, y1 ); _context.lineTo( x2, y2 ); _context.closePath(); } function strokePath( color, linewidth, linecap, linejoin ) { setLineWidth( linewidth ); setLineCap( linecap ); setLineJoin( linejoin ); setStrokeStyle( color.getStyle() ); _context.stroke(); _elemBox.expandByScalar( linewidth * 2 ); } function fillPath( color ) { setFillStyle( color.getStyle() ); _context.fill(); } function onTextureUpdate ( event ) { textureToPattern( event.target ); } function textureToPattern( texture ) { var repeatX = texture.wrapS === THREE.RepeatWrapping; var repeatY = texture.wrapT === THREE.RepeatWrapping; var image = texture.image; var canvas = document.createElement( 'canvas' ); canvas.width = image.width; canvas.height = image.height; var context = canvas.getContext( '2d' ); context.setTransform( 1, 0, 0, - 1, 0, image.height ); context.drawImage( image, 0, 0 ); _patterns[ texture.id ] = _context.createPattern( canvas, repeatX === true && repeatY === true ? 'repeat' : repeatX === true && repeatY === false ? 'repeat-x' : repeatX === false && repeatY === true ? 'repeat-y' : 'no-repeat' ); } function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) { if ( texture instanceof THREE.DataTexture ) return; if ( texture.hasEventListener( 'update', onTextureUpdate ) === false ) { if ( texture.image !== undefined && texture.image.width > 0 ) { textureToPattern( texture ); } texture.addEventListener( 'update', onTextureUpdate ); } var pattern = _patterns[ texture.id ]; if ( pattern !== undefined ) { setFillStyle( pattern ); } else { setFillStyle( 'rgba(0,0,0,1)' ); _context.fill(); return; } // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 var a, b, c, d, e, f, det, idet, offsetX = texture.offset.x / texture.repeat.x, offsetY = texture.offset.y / texture.repeat.y, width = texture.image.width * texture.repeat.x, height = texture.image.height * texture.repeat.y; u0 = ( u0 + offsetX ) * width; v0 = ( v0 + offsetY ) * height; u1 = ( u1 + offsetX ) * width; v1 = ( v1 + offsetY ) * height; u2 = ( u2 + offsetX ) * width; v2 = ( v2 + offsetY ) * height; x1 -= x0; y1 -= y0; x2 -= x0; y2 -= y0; u1 -= u0; v1 -= v0; u2 -= u0; v2 -= v0; det = u1 * v2 - u2 * v1; if ( det === 0 ) return; idet = 1 / det; a = ( v2 * x1 - v1 * x2 ) * idet; b = ( v2 * y1 - v1 * y2 ) * idet; c = ( u1 * x2 - u2 * x1 ) * idet; d = ( u1 * y2 - u2 * y1 ) * idet; e = x0 - a * u0 - c * v0; f = y0 - b * u0 - d * v0; _context.save(); _context.transform( a, b, c, d, e, f ); _context.fill(); _context.restore(); } function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) { // http://extremelysatisfactorytotalitarianism.com/blog/?p=2120 var a, b, c, d, e, f, det, idet, width = image.width - 1, height = image.height - 1; u0 *= width; v0 *= height; u1 *= width; v1 *= height; u2 *= width; v2 *= height; x1 -= x0; y1 -= y0; x2 -= x0; y2 -= y0; u1 -= u0; v1 -= v0; u2 -= u0; v2 -= v0; det = u1 * v2 - u2 * v1; idet = 1 / det; a = ( v2 * x1 - v1 * x2 ) * idet; b = ( v2 * y1 - v1 * y2 ) * idet; c = ( u1 * x2 - u2 * x1 ) * idet; d = ( u1 * y2 - u2 * y1 ) * idet; e = x0 - a * u0 - c * v0; f = y0 - b * u0 - d * v0; _context.save(); _context.transform( a, b, c, d, e, f ); _context.clip(); _context.drawImage( image, 0, 0 ); _context.restore(); } function getGradientTexture( color1, color2, color3, color4 ) { // http://mrdoob.com/blog/post/710 _pixelMapData[ 0 ] = ( color1.r * 255 ) | 0; _pixelMapData[ 1 ] = ( color1.g * 255 ) | 0; _pixelMapData[ 2 ] = ( color1.b * 255 ) | 0; _pixelMapData[ 4 ] = ( color2.r * 255 ) | 0; _pixelMapData[ 5 ] = ( color2.g * 255 ) | 0; _pixelMapData[ 6 ] = ( color2.b * 255 ) | 0; _pixelMapData[ 8 ] = ( color3.r * 255 ) | 0; _pixelMapData[ 9 ] = ( color3.g * 255 ) | 0; _pixelMapData[ 10 ] = ( color3.b * 255 ) | 0; _pixelMapData[ 12 ] = ( color4.r * 255 ) | 0; _pixelMapData[ 13 ] = ( color4.g * 255 ) | 0; _pixelMapData[ 14 ] = ( color4.b * 255 ) | 0; _pixelMapContext.putImageData( _pixelMapImage, 0, 0 ); _gradientMapContext.drawImage( _pixelMap, 0, 0 ); return _gradientMap; } // Hide anti-alias gaps function expand( v1, v2, pixels ) { var x = v2.x - v1.x, y = v2.y - v1.y, det = x * x + y * y, idet; if ( det === 0 ) return; idet = pixels / Math.sqrt( det ); x *= idet; y *= idet; v2.x += x; v2.y += y; v1.x -= x; v1.y -= y; } // Context cached methods. function setOpacity( value ) { if ( _contextGlobalAlpha !== value ) { _context.globalAlpha = value; _contextGlobalAlpha = value; } } function setBlending( value ) { if ( _contextGlobalCompositeOperation !== value ) { if ( value === THREE.NormalBlending ) { _context.globalCompositeOperation = 'source-over'; } else if ( value === THREE.AdditiveBlending ) { _context.globalCompositeOperation = 'lighter'; } else if ( value === THREE.SubtractiveBlending ) { _context.globalCompositeOperation = 'darker'; } _contextGlobalCompositeOperation = value; } } function setLineWidth( value ) { if ( _contextLineWidth !== value ) { _context.lineWidth = value; _contextLineWidth = value; } } function setLineCap( value ) { // "butt", "round", "square" if ( _contextLineCap !== value ) { _context.lineCap = value; _contextLineCap = value; } } function setLineJoin( value ) { // "round", "bevel", "miter" if ( _contextLineJoin !== value ) { _context.lineJoin = value; _contextLineJoin = value; } } function setStrokeStyle( value ) { if ( _contextStrokeStyle !== value ) { _context.strokeStyle = value; _contextStrokeStyle = value; } } function setFillStyle( value ) { if ( _contextFillStyle !== value ) { _context.fillStyle = value; _contextFillStyle = value; } } function setDashAndGap( dashSizeValue, gapSizeValue ) { if ( _contextDashSize !== dashSizeValue || _contextGapSize !== gapSizeValue ) { _context.setLineDash( [ dashSizeValue, gapSizeValue ] ); _contextDashSize = dashSizeValue; _contextGapSize = gapSizeValue; } } }; /** * Shader chunks for WebLG Shader library * * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ */ THREE.ShaderChunk = { // FOG fog_pars_fragment: [ "#ifdef USE_FOG", "uniform vec3 fogColor;", "#ifdef FOG_EXP2", "uniform float fogDensity;", "#else", "uniform float fogNear;", "uniform float fogFar;", "#endif", "#endif" ].join("\n"), fog_fragment: [ "#ifdef USE_FOG", "float depth = gl_FragCoord.z / gl_FragCoord.w;", "#ifdef FOG_EXP2", "const float LOG2 = 1.442695;", "float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );", "fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );", "#else", "float fogFactor = smoothstep( fogNear, fogFar, depth );", "#endif", "gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", "#endif" ].join("\n"), // ENVIRONMENT MAP envmap_pars_fragment: [ "#ifdef USE_ENVMAP", "uniform float reflectivity;", "uniform samplerCube envMap;", "uniform float flipEnvMap;", "uniform int combine;", "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", "uniform bool useRefract;", "uniform float refractionRatio;", "#else", "varying vec3 vReflect;", "#endif", "#endif" ].join("\n"), envmap_fragment: [ "#ifdef USE_ENVMAP", "vec3 reflectVec;", "#if defined( USE_BUMPMAP ) || defined( USE_NORMALMAP )", "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", "if ( useRefract ) {", "reflectVec = refract( cameraToVertex, normal, refractionRatio );", "} else { ", "reflectVec = reflect( cameraToVertex, normal );", "}", "#else", "reflectVec = vReflect;", "#endif", "#ifdef DOUBLE_SIDED", "float flipNormal = ( -1.0 + 2.0 * float( gl_FrontFacing ) );", "vec4 cubeColor = textureCube( envMap, flipNormal * vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", "#else", "vec4 cubeColor = textureCube( envMap, vec3( flipEnvMap * reflectVec.x, reflectVec.yz ) );", "#endif", "#ifdef GAMMA_INPUT", "cubeColor.xyz *= cubeColor.xyz;", "#endif", "if ( combine == 1 ) {", "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularStrength * reflectivity );", "} else if ( combine == 2 ) {", "gl_FragColor.xyz += cubeColor.xyz * specularStrength * reflectivity;", "} else {", "gl_FragColor.xyz = mix( gl_FragColor.xyz, gl_FragColor.xyz * cubeColor.xyz, specularStrength * reflectivity );", "}", "#endif" ].join("\n"), envmap_pars_vertex: [ "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", "varying vec3 vReflect;", "uniform float refractionRatio;", "uniform bool useRefract;", "#endif" ].join("\n"), worldpos_vertex : [ "#if defined( USE_ENVMAP ) || defined( PHONG ) || defined( LAMBERT ) || defined ( USE_SHADOWMAP )", "#ifdef USE_SKINNING", "vec4 worldPosition = modelMatrix * skinned;", "#endif", "#if defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", "vec4 worldPosition = modelMatrix * vec4( morphed, 1.0 );", "#endif", "#if ! defined( USE_MORPHTARGETS ) && ! defined( USE_SKINNING )", "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", "#endif", "#endif" ].join("\n"), envmap_vertex : [ "#if defined( USE_ENVMAP ) && ! defined( USE_BUMPMAP ) && ! defined( USE_NORMALMAP )", "vec3 worldNormal = mat3( modelMatrix[ 0 ].xyz, modelMatrix[ 1 ].xyz, modelMatrix[ 2 ].xyz ) * objectNormal;", "worldNormal = normalize( worldNormal );", "vec3 cameraToVertex = normalize( worldPosition.xyz - cameraPosition );", "if ( useRefract ) {", "vReflect = refract( cameraToVertex, worldNormal, refractionRatio );", "} else {", "vReflect = reflect( cameraToVertex, worldNormal );", "}", "#endif" ].join("\n"), // COLOR MAP (particles) map_particle_pars_fragment: [ "#ifdef USE_MAP", "uniform sampler2D map;", "#endif" ].join("\n"), map_particle_fragment: [ "#ifdef USE_MAP", "gl_FragColor = gl_FragColor * texture2D( map, vec2( gl_PointCoord.x, 1.0 - gl_PointCoord.y ) );", "#endif" ].join("\n"), // COLOR MAP (triangles) map_pars_vertex: [ "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", "varying vec2 vUv;", "uniform vec4 offsetRepeat;", "#endif" ].join("\n"), map_pars_fragment: [ "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", "varying vec2 vUv;", "#endif", "#ifdef USE_MAP", "uniform sampler2D map;", "#endif" ].join("\n"), map_vertex: [ "#if defined( USE_MAP ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP ) || defined( USE_SPECULARMAP )", "vUv = uv * offsetRepeat.zw + offsetRepeat.xy;", "#endif" ].join("\n"), map_fragment: [ "#ifdef USE_MAP", "vec4 texelColor = texture2D( map, vUv );", "#ifdef GAMMA_INPUT", "texelColor.xyz *= texelColor.xyz;", "#endif", "gl_FragColor = gl_FragColor * texelColor;", "#endif" ].join("\n"), // LIGHT MAP lightmap_pars_fragment: [ "#ifdef USE_LIGHTMAP", "varying vec2 vUv2;", "uniform sampler2D lightMap;", "#endif" ].join("\n"), lightmap_pars_vertex: [ "#ifdef USE_LIGHTMAP", "varying vec2 vUv2;", "#endif" ].join("\n"), lightmap_fragment: [ "#ifdef USE_LIGHTMAP", "gl_FragColor = gl_FragColor * texture2D( lightMap, vUv2 );", "#endif" ].join("\n"), lightmap_vertex: [ "#ifdef USE_LIGHTMAP", "vUv2 = uv2;", "#endif" ].join("\n"), // BUMP MAP bumpmap_pars_fragment: [ "#ifdef USE_BUMPMAP", "uniform sampler2D bumpMap;", "uniform float bumpScale;", // Derivative maps - bump mapping unparametrized surfaces by Morten Mikkelsen // http://mmikkelsen3d.blogspot.sk/2011/07/derivative-maps.html // Evaluate the derivative of the height w.r.t. screen-space using forward differencing (listing 2) "vec2 dHdxy_fwd() {", "vec2 dSTdx = dFdx( vUv );", "vec2 dSTdy = dFdy( vUv );", "float Hll = bumpScale * texture2D( bumpMap, vUv ).x;", "float dBx = bumpScale * texture2D( bumpMap, vUv + dSTdx ).x - Hll;", "float dBy = bumpScale * texture2D( bumpMap, vUv + dSTdy ).x - Hll;", "return vec2( dBx, dBy );", "}", "vec3 perturbNormalArb( vec3 surf_pos, vec3 surf_norm, vec2 dHdxy ) {", "vec3 vSigmaX = dFdx( surf_pos );", "vec3 vSigmaY = dFdy( surf_pos );", "vec3 vN = surf_norm;", // normalized "vec3 R1 = cross( vSigmaY, vN );", "vec3 R2 = cross( vN, vSigmaX );", "float fDet = dot( vSigmaX, R1 );", "vec3 vGrad = sign( fDet ) * ( dHdxy.x * R1 + dHdxy.y * R2 );", "return normalize( abs( fDet ) * surf_norm - vGrad );", "}", "#endif" ].join("\n"), // NORMAL MAP normalmap_pars_fragment: [ "#ifdef USE_NORMALMAP", "uniform sampler2D normalMap;", "uniform vec2 normalScale;", // Per-Pixel Tangent Space Normal Mapping // http://hacksoflife.blogspot.ch/2009/11/per-pixel-tangent-space-normal-mapping.html "vec3 perturbNormal2Arb( vec3 eye_pos, vec3 surf_norm ) {", "vec3 q0 = dFdx( eye_pos.xyz );", "vec3 q1 = dFdy( eye_pos.xyz );", "vec2 st0 = dFdx( vUv.st );", "vec2 st1 = dFdy( vUv.st );", "vec3 S = normalize( q0 * st1.t - q1 * st0.t );", "vec3 T = normalize( -q0 * st1.s + q1 * st0.s );", "vec3 N = normalize( surf_norm );", "vec3 mapN = texture2D( normalMap, vUv ).xyz * 2.0 - 1.0;", "mapN.xy = normalScale * mapN.xy;", "mat3 tsn = mat3( S, T, N );", "return normalize( tsn * mapN );", "}", "#endif" ].join("\n"), // SPECULAR MAP specularmap_pars_fragment: [ "#ifdef USE_SPECULARMAP", "uniform sampler2D specularMap;", "#endif" ].join("\n"), specularmap_fragment: [ "float specularStrength;", "#ifdef USE_SPECULARMAP", "vec4 texelSpecular = texture2D( specularMap, vUv );", "specularStrength = texelSpecular.r;", "#else", "specularStrength = 1.0;", "#endif" ].join("\n"), // LIGHTS LAMBERT lights_lambert_pars_vertex: [ "uniform vec3 ambient;", "uniform vec3 diffuse;", "uniform vec3 emissive;", "uniform vec3 ambientLightColor;", "#if MAX_DIR_LIGHTS > 0", "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", "#endif", "#if MAX_HEMI_LIGHTS > 0", "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", "#endif", "#if MAX_POINT_LIGHTS > 0", "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", "#endif", "#if MAX_SPOT_LIGHTS > 0", "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", "#endif", "#ifdef WRAP_AROUND", "uniform vec3 wrapRGB;", "#endif" ].join("\n"), lights_lambert_vertex: [ "vLightFront = vec3( 0.0 );", "#ifdef DOUBLE_SIDED", "vLightBack = vec3( 0.0 );", "#endif", "transformedNormal = normalize( transformedNormal );", "#if MAX_DIR_LIGHTS > 0", "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", "vec3 dirVector = normalize( lDirection.xyz );", "float dotProduct = dot( transformedNormal, dirVector );", "vec3 directionalLightWeighting = vec3( max( dotProduct, 0.0 ) );", "#ifdef DOUBLE_SIDED", "vec3 directionalLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", "#ifdef WRAP_AROUND", "vec3 directionalLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", "#endif", "#endif", "#ifdef WRAP_AROUND", "vec3 directionalLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", "directionalLightWeighting = mix( directionalLightWeighting, directionalLightWeightingHalf, wrapRGB );", "#ifdef DOUBLE_SIDED", "directionalLightWeightingBack = mix( directionalLightWeightingBack, directionalLightWeightingHalfBack, wrapRGB );", "#endif", "#endif", "vLightFront += directionalLightColor[ i ] * directionalLightWeighting;", "#ifdef DOUBLE_SIDED", "vLightBack += directionalLightColor[ i ] * directionalLightWeightingBack;", "#endif", "}", "#endif", "#if MAX_POINT_LIGHTS > 0", "for( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz - mvPosition.xyz;", "float lDistance = 1.0;", "if ( pointLightDistance[ i ] > 0.0 )", "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", "lVector = normalize( lVector );", "float dotProduct = dot( transformedNormal, lVector );", "vec3 pointLightWeighting = vec3( max( dotProduct, 0.0 ) );", "#ifdef DOUBLE_SIDED", "vec3 pointLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", "#ifdef WRAP_AROUND", "vec3 pointLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", "#endif", "#endif", "#ifdef WRAP_AROUND", "vec3 pointLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", "pointLightWeighting = mix( pointLightWeighting, pointLightWeightingHalf, wrapRGB );", "#ifdef DOUBLE_SIDED", "pointLightWeightingBack = mix( pointLightWeightingBack, pointLightWeightingHalfBack, wrapRGB );", "#endif", "#endif", "vLightFront += pointLightColor[ i ] * pointLightWeighting * lDistance;", "#ifdef DOUBLE_SIDED", "vLightBack += pointLightColor[ i ] * pointLightWeightingBack * lDistance;", "#endif", "}", "#endif", "#if MAX_SPOT_LIGHTS > 0", "for( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz - mvPosition.xyz;", "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - worldPosition.xyz ) );", "if ( spotEffect > spotLightAngleCos[ i ] ) {", "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", "float lDistance = 1.0;", "if ( spotLightDistance[ i ] > 0.0 )", "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", "lVector = normalize( lVector );", "float dotProduct = dot( transformedNormal, lVector );", "vec3 spotLightWeighting = vec3( max( dotProduct, 0.0 ) );", "#ifdef DOUBLE_SIDED", "vec3 spotLightWeightingBack = vec3( max( -dotProduct, 0.0 ) );", "#ifdef WRAP_AROUND", "vec3 spotLightWeightingHalfBack = vec3( max( -0.5 * dotProduct + 0.5, 0.0 ) );", "#endif", "#endif", "#ifdef WRAP_AROUND", "vec3 spotLightWeightingHalf = vec3( max( 0.5 * dotProduct + 0.5, 0.0 ) );", "spotLightWeighting = mix( spotLightWeighting, spotLightWeightingHalf, wrapRGB );", "#ifdef DOUBLE_SIDED", "spotLightWeightingBack = mix( spotLightWeightingBack, spotLightWeightingHalfBack, wrapRGB );", "#endif", "#endif", "vLightFront += spotLightColor[ i ] * spotLightWeighting * lDistance * spotEffect;", "#ifdef DOUBLE_SIDED", "vLightBack += spotLightColor[ i ] * spotLightWeightingBack * lDistance * spotEffect;", "#endif", "}", "}", "#endif", "#if MAX_HEMI_LIGHTS > 0", "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", "vec3 lVector = normalize( lDirection.xyz );", "float dotProduct = dot( transformedNormal, lVector );", "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", "float hemiDiffuseWeightBack = -0.5 * dotProduct + 0.5;", "vLightFront += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", "#ifdef DOUBLE_SIDED", "vLightBack += mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeightBack );", "#endif", "}", "#endif", "vLightFront = vLightFront * diffuse + ambient * ambientLightColor + emissive;", "#ifdef DOUBLE_SIDED", "vLightBack = vLightBack * diffuse + ambient * ambientLightColor + emissive;", "#endif" ].join("\n"), // LIGHTS PHONG lights_phong_pars_vertex: [ "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", "varying vec3 vWorldPosition;", "#endif" ].join("\n"), lights_phong_vertex: [ "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", "vWorldPosition = worldPosition.xyz;", "#endif" ].join("\n"), lights_phong_pars_fragment: [ "uniform vec3 ambientLightColor;", "#if MAX_DIR_LIGHTS > 0", "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", "#endif", "#if MAX_HEMI_LIGHTS > 0", "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", "#endif", "#if MAX_POINT_LIGHTS > 0", "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", "#endif", "#if MAX_SPOT_LIGHTS > 0", "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", "#endif", "#if MAX_SPOT_LIGHTS > 0 || defined( USE_BUMPMAP )", "varying vec3 vWorldPosition;", "#endif", "#ifdef WRAP_AROUND", "uniform vec3 wrapRGB;", "#endif", "varying vec3 vViewPosition;", "varying vec3 vNormal;" ].join("\n"), lights_phong_fragment: [ "vec3 normal = normalize( vNormal );", "vec3 viewPosition = normalize( vViewPosition );", "#ifdef DOUBLE_SIDED", "normal = normal * ( -1.0 + 2.0 * float( gl_FrontFacing ) );", "#endif", "#ifdef USE_NORMALMAP", "normal = perturbNormal2Arb( -vViewPosition, normal );", "#elif defined( USE_BUMPMAP )", "normal = perturbNormalArb( -vViewPosition, normal, dHdxy_fwd() );", "#endif", "#if MAX_POINT_LIGHTS > 0", "vec3 pointDiffuse = vec3( 0.0 );", "vec3 pointSpecular = vec3( 0.0 );", "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", "float lDistance = 1.0;", "if ( pointLightDistance[ i ] > 0.0 )", "lDistance = 1.0 - min( ( length( lVector ) / pointLightDistance[ i ] ), 1.0 );", "lVector = normalize( lVector );", // diffuse "float dotProduct = dot( normal, lVector );", "#ifdef WRAP_AROUND", "float pointDiffuseWeightFull = max( dotProduct, 0.0 );", "float pointDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", "#else", "float pointDiffuseWeight = max( dotProduct, 0.0 );", "#endif", "pointDiffuse += diffuse * pointLightColor[ i ] * pointDiffuseWeight * lDistance;", // specular "vec3 pointHalfVector = normalize( lVector + viewPosition );", "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", "float pointSpecularWeight = specularStrength * max( pow( pointDotNormalHalf, shininess ), 0.0 );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, pointHalfVector ), 0.0 ), 5.0 );", "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * lDistance * specularNormalization;", "}", "#endif", "#if MAX_SPOT_LIGHTS > 0", "vec3 spotDiffuse = vec3( 0.0 );", "vec3 spotSpecular = vec3( 0.0 );", "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", "vec3 lVector = lPosition.xyz + vViewPosition.xyz;", "float lDistance = 1.0;", "if ( spotLightDistance[ i ] > 0.0 )", "lDistance = 1.0 - min( ( length( lVector ) / spotLightDistance[ i ] ), 1.0 );", "lVector = normalize( lVector );", "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", "if ( spotEffect > spotLightAngleCos[ i ] ) {", "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", // diffuse "float dotProduct = dot( normal, lVector );", "#ifdef WRAP_AROUND", "float spotDiffuseWeightFull = max( dotProduct, 0.0 );", "float spotDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", "#else", "float spotDiffuseWeight = max( dotProduct, 0.0 );", "#endif", "spotDiffuse += diffuse * spotLightColor[ i ] * spotDiffuseWeight * lDistance * spotEffect;", // specular "vec3 spotHalfVector = normalize( lVector + viewPosition );", "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", "float spotSpecularWeight = specularStrength * max( pow( spotDotNormalHalf, shininess ), 0.0 );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, spotHalfVector ), 0.0 ), 5.0 );", "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * lDistance * specularNormalization * spotEffect;", "}", "}", "#endif", "#if MAX_DIR_LIGHTS > 0", "vec3 dirDiffuse = vec3( 0.0 );", "vec3 dirSpecular = vec3( 0.0 );" , "for( int i = 0; i < MAX_DIR_LIGHTS; i ++ ) {", "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", "vec3 dirVector = normalize( lDirection.xyz );", // diffuse "float dotProduct = dot( normal, dirVector );", "#ifdef WRAP_AROUND", "float dirDiffuseWeightFull = max( dotProduct, 0.0 );", "float dirDiffuseWeightHalf = max( 0.5 * dotProduct + 0.5, 0.0 );", "vec3 dirDiffuseWeight = mix( vec3( dirDiffuseWeightFull ), vec3( dirDiffuseWeightHalf ), wrapRGB );", "#else", "float dirDiffuseWeight = max( dotProduct, 0.0 );", "#endif", "dirDiffuse += diffuse * directionalLightColor[ i ] * dirDiffuseWeight;", // specular "vec3 dirHalfVector = normalize( dirVector + viewPosition );", "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", "float dirSpecularWeight = specularStrength * max( pow( dirDotNormalHalf, shininess ), 0.0 );", /* // fresnel term from skin shader "const float F0 = 0.128;", "float base = 1.0 - dot( viewPosition, dirHalfVector );", "float exponential = pow( base, 5.0 );", "float fresnel = exponential + F0 * ( 1.0 - exponential );", */ /* // fresnel term from fresnel shader "const float mFresnelBias = 0.08;", "const float mFresnelScale = 0.3;", "const float mFresnelPower = 5.0;", "float fresnel = mFresnelBias + mFresnelScale * pow( 1.0 + dot( normalize( -viewPosition ), normal ), mFresnelPower );", */ // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", //"dirSpecular += specular * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization * fresnel;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( dirVector, dirHalfVector ), 0.0 ), 5.0 );", "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", "}", "#endif", "#if MAX_HEMI_LIGHTS > 0", "vec3 hemiDiffuse = vec3( 0.0 );", "vec3 hemiSpecular = vec3( 0.0 );" , "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", "vec3 lVector = normalize( lDirection.xyz );", // diffuse "float dotProduct = dot( normal, lVector );", "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", "hemiDiffuse += diffuse * hemiColor;", // specular (sky light) "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", "float hemiSpecularWeightSky = specularStrength * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", // specular (ground light) "vec3 lVectorGround = -lVector;", "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", "float hemiSpecularWeightGround = specularStrength * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", "float dotProductGround = dot( normal, lVectorGround );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVector, hemiHalfVectorSky ), 0.0 ), 5.0 );", "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( max( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 0.0 ), 5.0 );", "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", "}", "#endif", "vec3 totalDiffuse = vec3( 0.0 );", "vec3 totalSpecular = vec3( 0.0 );", "#if MAX_DIR_LIGHTS > 0", "totalDiffuse += dirDiffuse;", "totalSpecular += dirSpecular;", "#endif", "#if MAX_HEMI_LIGHTS > 0", "totalDiffuse += hemiDiffuse;", "totalSpecular += hemiSpecular;", "#endif", "#if MAX_POINT_LIGHTS > 0", "totalDiffuse += pointDiffuse;", "totalSpecular += pointSpecular;", "#endif", "#if MAX_SPOT_LIGHTS > 0", "totalDiffuse += spotDiffuse;", "totalSpecular += spotSpecular;", "#endif", "#ifdef METAL", "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient + totalSpecular );", "#else", "gl_FragColor.xyz = gl_FragColor.xyz * ( emissive + totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", "#endif" ].join("\n"), // VERTEX COLORS color_pars_fragment: [ "#ifdef USE_COLOR", "varying vec3 vColor;", "#endif" ].join("\n"), color_fragment: [ "#ifdef USE_COLOR", "gl_FragColor = gl_FragColor * vec4( vColor, 1.0 );", "#endif" ].join("\n"), color_pars_vertex: [ "#ifdef USE_COLOR", "varying vec3 vColor;", "#endif" ].join("\n"), color_vertex: [ "#ifdef USE_COLOR", "#ifdef GAMMA_INPUT", "vColor = color * color;", "#else", "vColor = color;", "#endif", "#endif" ].join("\n"), // SKINNING skinning_pars_vertex: [ "#ifdef USE_SKINNING", "#ifdef BONE_TEXTURE", "uniform sampler2D boneTexture;", "uniform int boneTextureWidth;", "uniform int boneTextureHeight;", "mat4 getBoneMatrix( const in float i ) {", "float j = i * 4.0;", "float x = mod( j, float( boneTextureWidth ) );", "float y = floor( j / float( boneTextureWidth ) );", "float dx = 1.0 / float( boneTextureWidth );", "float dy = 1.0 / float( boneTextureHeight );", "y = dy * ( y + 0.5 );", "vec4 v1 = texture2D( boneTexture, vec2( dx * ( x + 0.5 ), y ) );", "vec4 v2 = texture2D( boneTexture, vec2( dx * ( x + 1.5 ), y ) );", "vec4 v3 = texture2D( boneTexture, vec2( dx * ( x + 2.5 ), y ) );", "vec4 v4 = texture2D( boneTexture, vec2( dx * ( x + 3.5 ), y ) );", "mat4 bone = mat4( v1, v2, v3, v4 );", "return bone;", "}", "#else", "uniform mat4 boneGlobalMatrices[ MAX_BONES ];", "mat4 getBoneMatrix( const in float i ) {", "mat4 bone = boneGlobalMatrices[ int(i) ];", "return bone;", "}", "#endif", "#endif" ].join("\n"), skinbase_vertex: [ "#ifdef USE_SKINNING", "mat4 boneMatX = getBoneMatrix( skinIndex.x );", "mat4 boneMatY = getBoneMatrix( skinIndex.y );", "mat4 boneMatZ = getBoneMatrix( skinIndex.z );", "mat4 boneMatW = getBoneMatrix( skinIndex.w );", "#endif" ].join("\n"), skinning_vertex: [ "#ifdef USE_SKINNING", "#ifdef USE_MORPHTARGETS", "vec4 skinVertex = vec4( morphed, 1.0 );", "#else", "vec4 skinVertex = vec4( position, 1.0 );", "#endif", "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", "skinned += boneMatY * skinVertex * skinWeight.y;", "skinned += boneMatZ * skinVertex * skinWeight.z;", "skinned += boneMatW * skinVertex * skinWeight.w;", "#endif" ].join("\n"), // MORPHING morphtarget_pars_vertex: [ "#ifdef USE_MORPHTARGETS", "#ifndef USE_MORPHNORMALS", "uniform float morphTargetInfluences[ 8 ];", "#else", "uniform float morphTargetInfluences[ 4 ];", "#endif", "#endif" ].join("\n"), morphtarget_vertex: [ "#ifdef USE_MORPHTARGETS", "vec3 morphed = vec3( 0.0 );", "morphed += ( morphTarget0 - position ) * morphTargetInfluences[ 0 ];", "morphed += ( morphTarget1 - position ) * morphTargetInfluences[ 1 ];", "morphed += ( morphTarget2 - position ) * morphTargetInfluences[ 2 ];", "morphed += ( morphTarget3 - position ) * morphTargetInfluences[ 3 ];", "#ifndef USE_MORPHNORMALS", "morphed += ( morphTarget4 - position ) * morphTargetInfluences[ 4 ];", "morphed += ( morphTarget5 - position ) * morphTargetInfluences[ 5 ];", "morphed += ( morphTarget6 - position ) * morphTargetInfluences[ 6 ];", "morphed += ( morphTarget7 - position ) * morphTargetInfluences[ 7 ];", "#endif", "morphed += position;", "#endif" ].join("\n"), default_vertex : [ "vec4 mvPosition;", "#ifdef USE_SKINNING", "mvPosition = modelViewMatrix * skinned;", "#endif", "#if !defined( USE_SKINNING ) && defined( USE_MORPHTARGETS )", "mvPosition = modelViewMatrix * vec4( morphed, 1.0 );", "#endif", "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHTARGETS )", "mvPosition = modelViewMatrix * vec4( position, 1.0 );", "#endif", "gl_Position = projectionMatrix * mvPosition;" ].join("\n"), morphnormal_vertex: [ "#ifdef USE_MORPHNORMALS", "vec3 morphedNormal = vec3( 0.0 );", "morphedNormal += ( morphNormal0 - normal ) * morphTargetInfluences[ 0 ];", "morphedNormal += ( morphNormal1 - normal ) * morphTargetInfluences[ 1 ];", "morphedNormal += ( morphNormal2 - normal ) * morphTargetInfluences[ 2 ];", "morphedNormal += ( morphNormal3 - normal ) * morphTargetInfluences[ 3 ];", "morphedNormal += normal;", "#endif" ].join("\n"), skinnormal_vertex: [ "#ifdef USE_SKINNING", "mat4 skinMatrix = skinWeight.x * boneMatX;", "skinMatrix += skinWeight.y * boneMatY;", "#ifdef USE_MORPHNORMALS", "vec4 skinnedNormal = skinMatrix * vec4( morphedNormal, 0.0 );", "#else", "vec4 skinnedNormal = skinMatrix * vec4( normal, 0.0 );", "#endif", "#endif" ].join("\n"), defaultnormal_vertex: [ "vec3 objectNormal;", "#ifdef USE_SKINNING", "objectNormal = skinnedNormal.xyz;", "#endif", "#if !defined( USE_SKINNING ) && defined( USE_MORPHNORMALS )", "objectNormal = morphedNormal;", "#endif", "#if !defined( USE_SKINNING ) && ! defined( USE_MORPHNORMALS )", "objectNormal = normal;", "#endif", "#ifdef FLIP_SIDED", "objectNormal = -objectNormal;", "#endif", "vec3 transformedNormal = normalMatrix * objectNormal;" ].join("\n"), // SHADOW MAP // based on SpiderGL shadow map and Fabien Sanglard's GLSL shadow mapping examples // http://spidergl.org/example.php?id=6 // http://fabiensanglard.net/shadowmapping shadowmap_pars_fragment: [ "#ifdef USE_SHADOWMAP", "uniform sampler2D shadowMap[ MAX_SHADOWS ];", "uniform vec2 shadowMapSize[ MAX_SHADOWS ];", "uniform float shadowDarkness[ MAX_SHADOWS ];", "uniform float shadowBias[ MAX_SHADOWS ];", "varying vec4 vShadowCoord[ MAX_SHADOWS ];", "float unpackDepth( const in vec4 rgba_depth ) {", "const vec4 bit_shift = vec4( 1.0 / ( 256.0 * 256.0 * 256.0 ), 1.0 / ( 256.0 * 256.0 ), 1.0 / 256.0, 1.0 );", "float depth = dot( rgba_depth, bit_shift );", "return depth;", "}", "#endif" ].join("\n"), shadowmap_fragment: [ "#ifdef USE_SHADOWMAP", "#ifdef SHADOWMAP_DEBUG", "vec3 frustumColors[3];", "frustumColors[0] = vec3( 1.0, 0.5, 0.0 );", "frustumColors[1] = vec3( 0.0, 1.0, 0.8 );", "frustumColors[2] = vec3( 0.0, 0.5, 1.0 );", "#endif", "#ifdef SHADOWMAP_CASCADE", "int inFrustumCount = 0;", "#endif", "float fDepth;", "vec3 shadowColor = vec3( 1.0 );", "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", "vec3 shadowCoord = vShadowCoord[ i ].xyz / vShadowCoord[ i ].w;", // "if ( something && something )" breaks ATI OpenGL shader compiler // "if ( all( something, something ) )" using this instead "bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );", "bool inFrustum = all( inFrustumVec );", // don't shadow pixels outside of light frustum // use just first frustum (for cascades) // don't shadow pixels behind far plane of light frustum "#ifdef SHADOWMAP_CASCADE", "inFrustumCount += int( inFrustum );", "bvec3 frustumTestVec = bvec3( inFrustum, inFrustumCount == 1, shadowCoord.z <= 1.0 );", "#else", "bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );", "#endif", "bool frustumTest = all( frustumTestVec );", "if ( frustumTest ) {", "shadowCoord.z += shadowBias[ i ];", "#if defined( SHADOWMAP_TYPE_PCF )", // Percentage-close filtering // (9 pixel kernel) // http://fabiensanglard.net/shadowmappingPCF/ "float shadow = 0.0;", /* // nested loops breaks shader compiler / validator on some ATI cards when using OpenGL // must enroll loop manually "for ( float y = -1.25; y <= 1.25; y += 1.25 )", "for ( float x = -1.25; x <= 1.25; x += 1.25 ) {", "vec4 rgbaDepth = texture2D( shadowMap[ i ], vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy );", // doesn't seem to produce any noticeable visual difference compared to simple "texture2D" lookup //"vec4 rgbaDepth = texture2DProj( shadowMap[ i ], vec4( vShadowCoord[ i ].w * ( vec2( x * xPixelOffset, y * yPixelOffset ) + shadowCoord.xy ), 0.05, vShadowCoord[ i ].w ) );", "float fDepth = unpackDepth( rgbaDepth );", "if ( fDepth < shadowCoord.z )", "shadow += 1.0;", "}", "shadow /= 9.0;", */ "const float shadowDelta = 1.0 / 9.0;", "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", "float dx0 = -1.25 * xPixelOffset;", "float dy0 = -1.25 * yPixelOffset;", "float dx1 = 1.25 * xPixelOffset;", "float dy1 = 1.25 * yPixelOffset;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "fDepth = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", "if ( fDepth < shadowCoord.z ) shadow += shadowDelta;", "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", "#elif defined( SHADOWMAP_TYPE_PCF_SOFT )", // Percentage-close filtering // (9 pixel kernel) // http://fabiensanglard.net/shadowmappingPCF/ "float shadow = 0.0;", "float xPixelOffset = 1.0 / shadowMapSize[ i ].x;", "float yPixelOffset = 1.0 / shadowMapSize[ i ].y;", "float dx0 = -1.0 * xPixelOffset;", "float dy0 = -1.0 * yPixelOffset;", "float dx1 = 1.0 * xPixelOffset;", "float dy1 = 1.0 * yPixelOffset;", "mat3 shadowKernel;", "mat3 depthKernel;", "depthKernel[0][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy0 ) ) );", "depthKernel[0][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, 0.0 ) ) );", "depthKernel[0][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx0, dy1 ) ) );", "depthKernel[1][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy0 ) ) );", "depthKernel[1][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy ) );", "depthKernel[1][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( 0.0, dy1 ) ) );", "depthKernel[2][0] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy0 ) ) );", "depthKernel[2][1] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, 0.0 ) ) );", "depthKernel[2][2] = unpackDepth( texture2D( shadowMap[ i ], shadowCoord.xy + vec2( dx1, dy1 ) ) );", "vec3 shadowZ = vec3( shadowCoord.z );", "shadowKernel[0] = vec3(lessThan(depthKernel[0], shadowZ ));", "shadowKernel[0] *= vec3(0.25);", "shadowKernel[1] = vec3(lessThan(depthKernel[1], shadowZ ));", "shadowKernel[1] *= vec3(0.25);", "shadowKernel[2] = vec3(lessThan(depthKernel[2], shadowZ ));", "shadowKernel[2] *= vec3(0.25);", "vec2 fractionalCoord = 1.0 - fract( shadowCoord.xy * shadowMapSize[i].xy );", "shadowKernel[0] = mix( shadowKernel[1], shadowKernel[0], fractionalCoord.x );", "shadowKernel[1] = mix( shadowKernel[2], shadowKernel[1], fractionalCoord.x );", "vec4 shadowValues;", "shadowValues.x = mix( shadowKernel[0][1], shadowKernel[0][0], fractionalCoord.y );", "shadowValues.y = mix( shadowKernel[0][2], shadowKernel[0][1], fractionalCoord.y );", "shadowValues.z = mix( shadowKernel[1][1], shadowKernel[1][0], fractionalCoord.y );", "shadowValues.w = mix( shadowKernel[1][2], shadowKernel[1][1], fractionalCoord.y );", "shadow = dot( shadowValues, vec4( 1.0 ) );", "shadowColor = shadowColor * vec3( ( 1.0 - shadowDarkness[ i ] * shadow ) );", "#else", "vec4 rgbaDepth = texture2D( shadowMap[ i ], shadowCoord.xy );", "float fDepth = unpackDepth( rgbaDepth );", "if ( fDepth < shadowCoord.z )", // spot with multiple shadows is darker "shadowColor = shadowColor * vec3( 1.0 - shadowDarkness[ i ] );", // spot with multiple shadows has the same color as single shadow spot //"shadowColor = min( shadowColor, vec3( shadowDarkness[ i ] ) );", "#endif", "}", "#ifdef SHADOWMAP_DEBUG", "#ifdef SHADOWMAP_CASCADE", "if ( inFrustum && inFrustumCount == 1 ) gl_FragColor.xyz *= frustumColors[ i ];", "#else", "if ( inFrustum ) gl_FragColor.xyz *= frustumColors[ i ];", "#endif", "#endif", "}", "#ifdef GAMMA_OUTPUT", "shadowColor *= shadowColor;", "#endif", "gl_FragColor.xyz = gl_FragColor.xyz * shadowColor;", "#endif" ].join("\n"), shadowmap_pars_vertex: [ "#ifdef USE_SHADOWMAP", "varying vec4 vShadowCoord[ MAX_SHADOWS ];", "uniform mat4 shadowMatrix[ MAX_SHADOWS ];", "#endif" ].join("\n"), shadowmap_vertex: [ "#ifdef USE_SHADOWMAP", "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", "}", "#endif" ].join("\n"), // ALPHATEST alphatest_fragment: [ "#ifdef ALPHATEST", "if ( gl_FragColor.a < ALPHATEST ) discard;", "#endif" ].join("\n"), // LINEAR SPACE linear_to_gamma_fragment: [ "#ifdef GAMMA_OUTPUT", "gl_FragColor.xyz = sqrt( gl_FragColor.xyz );", "#endif" ].join("\n") };/** * Uniform Utilities */ THREE.UniformsUtils = { merge: function ( uniforms ) { var u, p, tmp, merged = {}; for ( u = 0; u < uniforms.length; u ++ ) { tmp = this.clone( uniforms[ u ] ); for ( p in tmp ) { merged[ p ] = tmp[ p ]; } } return merged; }, clone: function ( uniforms_src ) { var u, p, parameter, parameter_src, uniforms_dst = {}; for ( u in uniforms_src ) { uniforms_dst[ u ] = {}; for ( p in uniforms_src[ u ] ) { parameter_src = uniforms_src[ u ][ p ]; if ( parameter_src instanceof THREE.Color || parameter_src instanceof THREE.Vector2 || parameter_src instanceof THREE.Vector3 || parameter_src instanceof THREE.Vector4 || parameter_src instanceof THREE.Matrix4 || parameter_src instanceof THREE.Texture ) { uniforms_dst[ u ][ p ] = parameter_src.clone(); } else if ( parameter_src instanceof Array ) { uniforms_dst[ u ][ p ] = parameter_src.slice(); } else { uniforms_dst[ u ][ p ] = parameter_src; } } } return uniforms_dst; } };/** * Uniforms library for shared webgl shaders */ THREE.UniformsLib = { common: { "diffuse" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, "opacity" : { type: "f", value: 1.0 }, "map" : { type: "t", value: null }, "offsetRepeat" : { type: "v4", value: new THREE.Vector4( 0, 0, 1, 1 ) }, "lightMap" : { type: "t", value: null }, "specularMap" : { type: "t", value: null }, "envMap" : { type: "t", value: null }, "flipEnvMap" : { type: "f", value: -1 }, "useRefract" : { type: "i", value: 0 }, "reflectivity" : { type: "f", value: 1.0 }, "refractionRatio" : { type: "f", value: 0.98 }, "combine" : { type: "i", value: 0 }, "morphTargetInfluences" : { type: "f", value: 0 } }, bump: { "bumpMap" : { type: "t", value: null }, "bumpScale" : { type: "f", value: 1 } }, normalmap: { "normalMap" : { type: "t", value: null }, "normalScale" : { type: "v2", value: new THREE.Vector2( 1, 1 ) } }, fog : { "fogDensity" : { type: "f", value: 0.00025 }, "fogNear" : { type: "f", value: 1 }, "fogFar" : { type: "f", value: 2000 }, "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } }, lights: { "ambientLightColor" : { type: "fv", value: [] }, "directionalLightDirection" : { type: "fv", value: [] }, "directionalLightColor" : { type: "fv", value: [] }, "hemisphereLightDirection" : { type: "fv", value: [] }, "hemisphereLightSkyColor" : { type: "fv", value: [] }, "hemisphereLightGroundColor" : { type: "fv", value: [] }, "pointLightColor" : { type: "fv", value: [] }, "pointLightPosition" : { type: "fv", value: [] }, "pointLightDistance" : { type: "fv1", value: [] }, "spotLightColor" : { type: "fv", value: [] }, "spotLightPosition" : { type: "fv", value: [] }, "spotLightDirection" : { type: "fv", value: [] }, "spotLightDistance" : { type: "fv1", value: [] }, "spotLightAngleCos" : { type: "fv1", value: [] }, "spotLightExponent" : { type: "fv1", value: [] } }, particle: { "psColor" : { type: "c", value: new THREE.Color( 0xeeeeee ) }, "opacity" : { type: "f", value: 1.0 }, "size" : { type: "f", value: 1.0 }, "scale" : { type: "f", value: 1.0 }, "map" : { type: "t", value: null }, "fogDensity" : { type: "f", value: 0.00025 }, "fogNear" : { type: "f", value: 1 }, "fogFar" : { type: "f", value: 2000 }, "fogColor" : { type: "c", value: new THREE.Color( 0xffffff ) } }, shadowmap: { "shadowMap": { type: "tv", value: [] }, "shadowMapSize": { type: "v2v", value: [] }, "shadowBias" : { type: "fv1", value: [] }, "shadowDarkness": { type: "fv1", value: [] }, "shadowMatrix" : { type: "m4v", value: [] } } };/** * Webgl Shader Library for three.js * * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author mikael emtinger / http://gomo.se/ */ THREE.ShaderLib = { 'basic': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "shadowmap" ] ] ), vertexShader: [ THREE.ShaderChunk[ "map_pars_vertex" ], THREE.ShaderChunk[ "lightmap_pars_vertex" ], THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "map_vertex" ], THREE.ShaderChunk[ "lightmap_vertex" ], THREE.ShaderChunk[ "color_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ], "#ifdef USE_ENVMAP", THREE.ShaderChunk[ "morphnormal_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], "#endif", THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join("\n"), fragmentShader: [ "uniform vec3 diffuse;", "uniform float opacity;", THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "lightmap_pars_fragment" ], THREE.ShaderChunk[ "envmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "specularmap_pars_fragment" ], "void main() {", "gl_FragColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "map_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], THREE.ShaderChunk[ "lightmap_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], "}" ].join("\n") }, 'lambert': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "lights" ], THREE.UniformsLib[ "shadowmap" ], { "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } } ] ), vertexShader: [ "#define LAMBERT", "varying vec3 vLightFront;", "#ifdef DOUBLE_SIDED", "varying vec3 vLightBack;", "#endif", THREE.ShaderChunk[ "map_pars_vertex" ], THREE.ShaderChunk[ "lightmap_pars_vertex" ], THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "lights_lambert_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "map_vertex" ], THREE.ShaderChunk[ "lightmap_vertex" ], THREE.ShaderChunk[ "color_vertex" ], THREE.ShaderChunk[ "morphnormal_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "lights_lambert_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join("\n"), fragmentShader: [ "uniform float opacity;", "varying vec3 vLightFront;", "#ifdef DOUBLE_SIDED", "varying vec3 vLightBack;", "#endif", THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "lightmap_pars_fragment" ], THREE.ShaderChunk[ "envmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "specularmap_pars_fragment" ], "void main() {", "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", THREE.ShaderChunk[ "map_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], "#ifdef DOUBLE_SIDED", //"float isFront = float( gl_FrontFacing );", //"gl_FragColor.xyz *= isFront * vLightFront + ( 1.0 - isFront ) * vLightBack;", "if ( gl_FrontFacing )", "gl_FragColor.xyz *= vLightFront;", "else", "gl_FragColor.xyz *= vLightBack;", "#else", "gl_FragColor.xyz *= vLightFront;", "#endif", THREE.ShaderChunk[ "lightmap_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], "}" ].join("\n") }, 'phong': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "bump" ], THREE.UniformsLib[ "normalmap" ], THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "lights" ], THREE.UniformsLib[ "shadowmap" ], { "ambient" : { type: "c", value: new THREE.Color( 0xffffff ) }, "emissive" : { type: "c", value: new THREE.Color( 0x000000 ) }, "specular" : { type: "c", value: new THREE.Color( 0x111111 ) }, "shininess": { type: "f", value: 30 }, "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } } ] ), vertexShader: [ "#define PHONG", "varying vec3 vViewPosition;", "varying vec3 vNormal;", THREE.ShaderChunk[ "map_pars_vertex" ], THREE.ShaderChunk[ "lightmap_pars_vertex" ], THREE.ShaderChunk[ "envmap_pars_vertex" ], THREE.ShaderChunk[ "lights_phong_pars_vertex" ], THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "map_vertex" ], THREE.ShaderChunk[ "lightmap_vertex" ], THREE.ShaderChunk[ "color_vertex" ], THREE.ShaderChunk[ "morphnormal_vertex" ], THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], THREE.ShaderChunk[ "defaultnormal_vertex" ], "vNormal = normalize( transformedNormal );", THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], "vViewPosition = -mvPosition.xyz;", THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "envmap_vertex" ], THREE.ShaderChunk[ "lights_phong_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join("\n"), fragmentShader: [ "uniform vec3 diffuse;", "uniform float opacity;", "uniform vec3 ambient;", "uniform vec3 emissive;", "uniform vec3 specular;", "uniform float shininess;", THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_pars_fragment" ], THREE.ShaderChunk[ "lightmap_pars_fragment" ], THREE.ShaderChunk[ "envmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "lights_phong_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "bumpmap_pars_fragment" ], THREE.ShaderChunk[ "normalmap_pars_fragment" ], THREE.ShaderChunk[ "specularmap_pars_fragment" ], "void main() {", "gl_FragColor = vec4( vec3 ( 1.0 ), opacity );", THREE.ShaderChunk[ "map_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "specularmap_fragment" ], THREE.ShaderChunk[ "lights_phong_fragment" ], THREE.ShaderChunk[ "lightmap_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "envmap_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], "}" ].join("\n") }, 'particle_basic': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "particle" ], THREE.UniformsLib[ "shadowmap" ] ] ), vertexShader: [ "uniform float size;", "uniform float scale;", THREE.ShaderChunk[ "color_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "color_vertex" ], "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", "#ifdef USE_SIZEATTENUATION", "gl_PointSize = size * ( scale / length( mvPosition.xyz ) );", "#else", "gl_PointSize = size;", "#endif", "gl_Position = projectionMatrix * mvPosition;", THREE.ShaderChunk[ "worldpos_vertex" ], THREE.ShaderChunk[ "shadowmap_vertex" ], "}" ].join("\n"), fragmentShader: [ "uniform vec3 psColor;", "uniform float opacity;", THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "map_particle_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], THREE.ShaderChunk[ "shadowmap_pars_fragment" ], "void main() {", "gl_FragColor = vec4( psColor, opacity );", THREE.ShaderChunk[ "map_particle_fragment" ], THREE.ShaderChunk[ "alphatest_fragment" ], THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "shadowmap_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], "}" ].join("\n") }, 'dashed': { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "common" ], THREE.UniformsLib[ "fog" ], { "scale": { type: "f", value: 1 }, "dashSize": { type: "f", value: 1 }, "totalSize": { type: "f", value: 2 } } ] ), vertexShader: [ "uniform float scale;", "attribute float lineDistance;", "varying float vLineDistance;", THREE.ShaderChunk[ "color_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "color_vertex" ], "vLineDistance = scale * lineDistance;", "vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );", "gl_Position = projectionMatrix * mvPosition;", "}" ].join("\n"), fragmentShader: [ "uniform vec3 diffuse;", "uniform float opacity;", "uniform float dashSize;", "uniform float totalSize;", "varying float vLineDistance;", THREE.ShaderChunk[ "color_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], "void main() {", "if ( mod( vLineDistance, totalSize ) > dashSize ) {", "discard;", "}", "gl_FragColor = vec4( diffuse, opacity );", THREE.ShaderChunk[ "color_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], "}" ].join("\n") }, 'depth': { uniforms: { "mNear": { type: "f", value: 1.0 }, "mFar" : { type: "f", value: 2000.0 }, "opacity" : { type: "f", value: 1.0 } }, vertexShader: [ "void main() {", "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", "}" ].join("\n"), fragmentShader: [ "uniform float mNear;", "uniform float mFar;", "uniform float opacity;", "void main() {", "float depth = gl_FragCoord.z / gl_FragCoord.w;", "float color = 1.0 - smoothstep( mNear, mFar, depth );", "gl_FragColor = vec4( vec3( color ), opacity );", "}" ].join("\n") }, 'normal': { uniforms: { "opacity" : { type: "f", value: 1.0 } }, vertexShader: [ "varying vec3 vNormal;", THREE.ShaderChunk[ "morphtarget_pars_vertex" ], "void main() {", "vNormal = normalize( normalMatrix * normal );", THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "default_vertex" ], "}" ].join("\n"), fragmentShader: [ "uniform float opacity;", "varying vec3 vNormal;", "void main() {", "gl_FragColor = vec4( 0.5 * normalize( vNormal ) + 0.5, opacity );", "}" ].join("\n") }, /* ------------------------------------------------------------------------- // Normal map shader // - Blinn-Phong // - normal + diffuse + specular + AO + displacement + reflection + shadow maps // - point and directional lights (use with "lights: true" material option) ------------------------------------------------------------------------- */ 'normalmap' : { uniforms: THREE.UniformsUtils.merge( [ THREE.UniformsLib[ "fog" ], THREE.UniformsLib[ "lights" ], THREE.UniformsLib[ "shadowmap" ], { "enableAO" : { type: "i", value: 0 }, "enableDiffuse" : { type: "i", value: 0 }, "enableSpecular" : { type: "i", value: 0 }, "enableReflection": { type: "i", value: 0 }, "enableDisplacement": { type: "i", value: 0 }, "tDisplacement": { type: "t", value: null }, // must go first as this is vertex texture "tDiffuse" : { type: "t", value: null }, "tCube" : { type: "t", value: null }, "tNormal" : { type: "t", value: null }, "tSpecular" : { type: "t", value: null }, "tAO" : { type: "t", value: null }, "uNormalScale": { type: "v2", value: new THREE.Vector2( 1, 1 ) }, "uDisplacementBias": { type: "f", value: 0.0 }, "uDisplacementScale": { type: "f", value: 1.0 }, "diffuse": { type: "c", value: new THREE.Color( 0xffffff ) }, "specular": { type: "c", value: new THREE.Color( 0x111111 ) }, "ambient": { type: "c", value: new THREE.Color( 0xffffff ) }, "shininess": { type: "f", value: 30 }, "opacity": { type: "f", value: 1 }, "useRefract": { type: "i", value: 0 }, "refractionRatio": { type: "f", value: 0.98 }, "reflectivity": { type: "f", value: 0.5 }, "uOffset" : { type: "v2", value: new THREE.Vector2( 0, 0 ) }, "uRepeat" : { type: "v2", value: new THREE.Vector2( 1, 1 ) }, "wrapRGB" : { type: "v3", value: new THREE.Vector3( 1, 1, 1 ) } } ] ), fragmentShader: [ "uniform vec3 ambient;", "uniform vec3 diffuse;", "uniform vec3 specular;", "uniform float shininess;", "uniform float opacity;", "uniform bool enableDiffuse;", "uniform bool enableSpecular;", "uniform bool enableAO;", "uniform bool enableReflection;", "uniform sampler2D tDiffuse;", "uniform sampler2D tNormal;", "uniform sampler2D tSpecular;", "uniform sampler2D tAO;", "uniform samplerCube tCube;", "uniform vec2 uNormalScale;", "uniform bool useRefract;", "uniform float refractionRatio;", "uniform float reflectivity;", "varying vec3 vTangent;", "varying vec3 vBinormal;", "varying vec3 vNormal;", "varying vec2 vUv;", "uniform vec3 ambientLightColor;", "#if MAX_DIR_LIGHTS > 0", "uniform vec3 directionalLightColor[ MAX_DIR_LIGHTS ];", "uniform vec3 directionalLightDirection[ MAX_DIR_LIGHTS ];", "#endif", "#if MAX_HEMI_LIGHTS > 0", "uniform vec3 hemisphereLightSkyColor[ MAX_HEMI_LIGHTS ];", "uniform vec3 hemisphereLightGroundColor[ MAX_HEMI_LIGHTS ];", "uniform vec3 hemisphereLightDirection[ MAX_HEMI_LIGHTS ];", "#endif", "#if MAX_POINT_LIGHTS > 0", "uniform vec3 pointLightColor[ MAX_POINT_LIGHTS ];", "uniform vec3 pointLightPosition[ MAX_POINT_LIGHTS ];", "uniform float pointLightDistance[ MAX_POINT_LIGHTS ];", "#endif", "#if MAX_SPOT_LIGHTS > 0", "uniform vec3 spotLightColor[ MAX_SPOT_LIGHTS ];", "uniform vec3 spotLightPosition[ MAX_SPOT_LIGHTS ];", "uniform vec3 spotLightDirection[ MAX_SPOT_LIGHTS ];", "uniform float spotLightAngleCos[ MAX_SPOT_LIGHTS ];", "uniform float spotLightExponent[ MAX_SPOT_LIGHTS ];", "uniform float spotLightDistance[ MAX_SPOT_LIGHTS ];", "#endif", "#ifdef WRAP_AROUND", "uniform vec3 wrapRGB;", "#endif", "varying vec3 vWorldPosition;", "varying vec3 vViewPosition;", THREE.ShaderChunk[ "shadowmap_pars_fragment" ], THREE.ShaderChunk[ "fog_pars_fragment" ], "void main() {", "gl_FragColor = vec4( vec3( 1.0 ), opacity );", "vec3 specularTex = vec3( 1.0 );", "vec3 normalTex = texture2D( tNormal, vUv ).xyz * 2.0 - 1.0;", "normalTex.xy *= uNormalScale;", "normalTex = normalize( normalTex );", "if( enableDiffuse ) {", "#ifdef GAMMA_INPUT", "vec4 texelColor = texture2D( tDiffuse, vUv );", "texelColor.xyz *= texelColor.xyz;", "gl_FragColor = gl_FragColor * texelColor;", "#else", "gl_FragColor = gl_FragColor * texture2D( tDiffuse, vUv );", "#endif", "}", "if( enableAO ) {", "#ifdef GAMMA_INPUT", "vec4 aoColor = texture2D( tAO, vUv );", "aoColor.xyz *= aoColor.xyz;", "gl_FragColor.xyz = gl_FragColor.xyz * aoColor.xyz;", "#else", "gl_FragColor.xyz = gl_FragColor.xyz * texture2D( tAO, vUv ).xyz;", "#endif", "}", "if( enableSpecular )", "specularTex = texture2D( tSpecular, vUv ).xyz;", "mat3 tsb = mat3( normalize( vTangent ), normalize( vBinormal ), normalize( vNormal ) );", "vec3 finalNormal = tsb * normalTex;", "#ifdef FLIP_SIDED", "finalNormal = -finalNormal;", "#endif", "vec3 normal = normalize( finalNormal );", "vec3 viewPosition = normalize( vViewPosition );", // point lights "#if MAX_POINT_LIGHTS > 0", "vec3 pointDiffuse = vec3( 0.0 );", "vec3 pointSpecular = vec3( 0.0 );", "for ( int i = 0; i < MAX_POINT_LIGHTS; i ++ ) {", "vec4 lPosition = viewMatrix * vec4( pointLightPosition[ i ], 1.0 );", "vec3 pointVector = lPosition.xyz + vViewPosition.xyz;", "float pointDistance = 1.0;", "if ( pointLightDistance[ i ] > 0.0 )", "pointDistance = 1.0 - min( ( length( pointVector ) / pointLightDistance[ i ] ), 1.0 );", "pointVector = normalize( pointVector );", // diffuse "#ifdef WRAP_AROUND", "float pointDiffuseWeightFull = max( dot( normal, pointVector ), 0.0 );", "float pointDiffuseWeightHalf = max( 0.5 * dot( normal, pointVector ) + 0.5, 0.0 );", "vec3 pointDiffuseWeight = mix( vec3 ( pointDiffuseWeightFull ), vec3( pointDiffuseWeightHalf ), wrapRGB );", "#else", "float pointDiffuseWeight = max( dot( normal, pointVector ), 0.0 );", "#endif", "pointDiffuse += pointDistance * pointLightColor[ i ] * diffuse * pointDiffuseWeight;", // specular "vec3 pointHalfVector = normalize( pointVector + viewPosition );", "float pointDotNormalHalf = max( dot( normal, pointHalfVector ), 0.0 );", "float pointSpecularWeight = specularTex.r * max( pow( pointDotNormalHalf, shininess ), 0.0 );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( pointVector, pointHalfVector ), 5.0 );", "pointSpecular += schlick * pointLightColor[ i ] * pointSpecularWeight * pointDiffuseWeight * pointDistance * specularNormalization;", "}", "#endif", // spot lights "#if MAX_SPOT_LIGHTS > 0", "vec3 spotDiffuse = vec3( 0.0 );", "vec3 spotSpecular = vec3( 0.0 );", "for ( int i = 0; i < MAX_SPOT_LIGHTS; i ++ ) {", "vec4 lPosition = viewMatrix * vec4( spotLightPosition[ i ], 1.0 );", "vec3 spotVector = lPosition.xyz + vViewPosition.xyz;", "float spotDistance = 1.0;", "if ( spotLightDistance[ i ] > 0.0 )", "spotDistance = 1.0 - min( ( length( spotVector ) / spotLightDistance[ i ] ), 1.0 );", "spotVector = normalize( spotVector );", "float spotEffect = dot( spotLightDirection[ i ], normalize( spotLightPosition[ i ] - vWorldPosition ) );", "if ( spotEffect > spotLightAngleCos[ i ] ) {", "spotEffect = max( pow( spotEffect, spotLightExponent[ i ] ), 0.0 );", // diffuse "#ifdef WRAP_AROUND", "float spotDiffuseWeightFull = max( dot( normal, spotVector ), 0.0 );", "float spotDiffuseWeightHalf = max( 0.5 * dot( normal, spotVector ) + 0.5, 0.0 );", "vec3 spotDiffuseWeight = mix( vec3 ( spotDiffuseWeightFull ), vec3( spotDiffuseWeightHalf ), wrapRGB );", "#else", "float spotDiffuseWeight = max( dot( normal, spotVector ), 0.0 );", "#endif", "spotDiffuse += spotDistance * spotLightColor[ i ] * diffuse * spotDiffuseWeight * spotEffect;", // specular "vec3 spotHalfVector = normalize( spotVector + viewPosition );", "float spotDotNormalHalf = max( dot( normal, spotHalfVector ), 0.0 );", "float spotSpecularWeight = specularTex.r * max( pow( spotDotNormalHalf, shininess ), 0.0 );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( spotVector, spotHalfVector ), 5.0 );", "spotSpecular += schlick * spotLightColor[ i ] * spotSpecularWeight * spotDiffuseWeight * spotDistance * specularNormalization * spotEffect;", "}", "}", "#endif", // directional lights "#if MAX_DIR_LIGHTS > 0", "vec3 dirDiffuse = vec3( 0.0 );", "vec3 dirSpecular = vec3( 0.0 );", "for( int i = 0; i < MAX_DIR_LIGHTS; i++ ) {", "vec4 lDirection = viewMatrix * vec4( directionalLightDirection[ i ], 0.0 );", "vec3 dirVector = normalize( lDirection.xyz );", // diffuse "#ifdef WRAP_AROUND", "float directionalLightWeightingFull = max( dot( normal, dirVector ), 0.0 );", "float directionalLightWeightingHalf = max( 0.5 * dot( normal, dirVector ) + 0.5, 0.0 );", "vec3 dirDiffuseWeight = mix( vec3( directionalLightWeightingFull ), vec3( directionalLightWeightingHalf ), wrapRGB );", "#else", "float dirDiffuseWeight = max( dot( normal, dirVector ), 0.0 );", "#endif", "dirDiffuse += directionalLightColor[ i ] * diffuse * dirDiffuseWeight;", // specular "vec3 dirHalfVector = normalize( dirVector + viewPosition );", "float dirDotNormalHalf = max( dot( normal, dirHalfVector ), 0.0 );", "float dirSpecularWeight = specularTex.r * max( pow( dirDotNormalHalf, shininess ), 0.0 );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlick = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( dirVector, dirHalfVector ), 5.0 );", "dirSpecular += schlick * directionalLightColor[ i ] * dirSpecularWeight * dirDiffuseWeight * specularNormalization;", "}", "#endif", // hemisphere lights "#if MAX_HEMI_LIGHTS > 0", "vec3 hemiDiffuse = vec3( 0.0 );", "vec3 hemiSpecular = vec3( 0.0 );" , "for( int i = 0; i < MAX_HEMI_LIGHTS; i ++ ) {", "vec4 lDirection = viewMatrix * vec4( hemisphereLightDirection[ i ], 0.0 );", "vec3 lVector = normalize( lDirection.xyz );", // diffuse "float dotProduct = dot( normal, lVector );", "float hemiDiffuseWeight = 0.5 * dotProduct + 0.5;", "vec3 hemiColor = mix( hemisphereLightGroundColor[ i ], hemisphereLightSkyColor[ i ], hemiDiffuseWeight );", "hemiDiffuse += diffuse * hemiColor;", // specular (sky light) "vec3 hemiHalfVectorSky = normalize( lVector + viewPosition );", "float hemiDotNormalHalfSky = 0.5 * dot( normal, hemiHalfVectorSky ) + 0.5;", "float hemiSpecularWeightSky = specularTex.r * max( pow( hemiDotNormalHalfSky, shininess ), 0.0 );", // specular (ground light) "vec3 lVectorGround = -lVector;", "vec3 hemiHalfVectorGround = normalize( lVectorGround + viewPosition );", "float hemiDotNormalHalfGround = 0.5 * dot( normal, hemiHalfVectorGround ) + 0.5;", "float hemiSpecularWeightGround = specularTex.r * max( pow( hemiDotNormalHalfGround, shininess ), 0.0 );", "float dotProductGround = dot( normal, lVectorGround );", // 2.0 => 2.0001 is hack to work around ANGLE bug "float specularNormalization = ( shininess + 2.0001 ) / 8.0;", "vec3 schlickSky = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVector, hemiHalfVectorSky ), 5.0 );", "vec3 schlickGround = specular + vec3( 1.0 - specular ) * pow( 1.0 - dot( lVectorGround, hemiHalfVectorGround ), 5.0 );", "hemiSpecular += hemiColor * specularNormalization * ( schlickSky * hemiSpecularWeightSky * max( dotProduct, 0.0 ) + schlickGround * hemiSpecularWeightGround * max( dotProductGround, 0.0 ) );", "}", "#endif", // all lights contribution summation "vec3 totalDiffuse = vec3( 0.0 );", "vec3 totalSpecular = vec3( 0.0 );", "#if MAX_DIR_LIGHTS > 0", "totalDiffuse += dirDiffuse;", "totalSpecular += dirSpecular;", "#endif", "#if MAX_HEMI_LIGHTS > 0", "totalDiffuse += hemiDiffuse;", "totalSpecular += hemiSpecular;", "#endif", "#if MAX_POINT_LIGHTS > 0", "totalDiffuse += pointDiffuse;", "totalSpecular += pointSpecular;", "#endif", "#if MAX_SPOT_LIGHTS > 0", "totalDiffuse += spotDiffuse;", "totalSpecular += spotSpecular;", "#endif", "#ifdef METAL", "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient + totalSpecular );", "#else", "gl_FragColor.xyz = gl_FragColor.xyz * ( totalDiffuse + ambientLightColor * ambient ) + totalSpecular;", "#endif", "if ( enableReflection ) {", "vec3 vReflect;", "vec3 cameraToVertex = normalize( vWorldPosition - cameraPosition );", "if ( useRefract ) {", "vReflect = refract( cameraToVertex, normal, refractionRatio );", "} else {", "vReflect = reflect( cameraToVertex, normal );", "}", "vec4 cubeColor = textureCube( tCube, vec3( -vReflect.x, vReflect.yz ) );", "#ifdef GAMMA_INPUT", "cubeColor.xyz *= cubeColor.xyz;", "#endif", "gl_FragColor.xyz = mix( gl_FragColor.xyz, cubeColor.xyz, specularTex.r * reflectivity );", "}", THREE.ShaderChunk[ "shadowmap_fragment" ], THREE.ShaderChunk[ "linear_to_gamma_fragment" ], THREE.ShaderChunk[ "fog_fragment" ], "}" ].join("\n"), vertexShader: [ "attribute vec4 tangent;", "uniform vec2 uOffset;", "uniform vec2 uRepeat;", "uniform bool enableDisplacement;", "#ifdef VERTEX_TEXTURES", "uniform sampler2D tDisplacement;", "uniform float uDisplacementScale;", "uniform float uDisplacementBias;", "#endif", "varying vec3 vTangent;", "varying vec3 vBinormal;", "varying vec3 vNormal;", "varying vec2 vUv;", "varying vec3 vWorldPosition;", "varying vec3 vViewPosition;", THREE.ShaderChunk[ "skinning_pars_vertex" ], THREE.ShaderChunk[ "shadowmap_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "skinnormal_vertex" ], // normal, tangent and binormal vectors "#ifdef USE_SKINNING", "vNormal = normalize( normalMatrix * skinnedNormal.xyz );", "vec4 skinnedTangent = skinMatrix * vec4( tangent.xyz, 0.0 );", "vTangent = normalize( normalMatrix * skinnedTangent.xyz );", "#else", "vNormal = normalize( normalMatrix * normal );", "vTangent = normalize( normalMatrix * tangent.xyz );", "#endif", "vBinormal = normalize( cross( vNormal, vTangent ) * tangent.w );", "vUv = uv * uRepeat + uOffset;", // displacement mapping "vec3 displacedPosition;", "#ifdef VERTEX_TEXTURES", "if ( enableDisplacement ) {", "vec3 dv = texture2D( tDisplacement, uv ).xyz;", "float df = uDisplacementScale * dv.x + uDisplacementBias;", "displacedPosition = position + normalize( normal ) * df;", "} else {", "#ifdef USE_SKINNING", "vec4 skinVertex = vec4( position, 1.0 );", "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", "skinned += boneMatY * skinVertex * skinWeight.y;", "displacedPosition = skinned.xyz;", "#else", "displacedPosition = position;", "#endif", "}", "#else", "#ifdef USE_SKINNING", "vec4 skinVertex = vec4( position, 1.0 );", "vec4 skinned = boneMatX * skinVertex * skinWeight.x;", "skinned += boneMatY * skinVertex * skinWeight.y;", "displacedPosition = skinned.xyz;", "#else", "displacedPosition = position;", "#endif", "#endif", // "vec4 mvPosition = modelViewMatrix * vec4( displacedPosition, 1.0 );", "vec4 worldPosition = modelMatrix * vec4( displacedPosition, 1.0 );", "gl_Position = projectionMatrix * mvPosition;", // "vWorldPosition = worldPosition.xyz;", "vViewPosition = -mvPosition.xyz;", // shadows "#ifdef USE_SHADOWMAP", "for( int i = 0; i < MAX_SHADOWS; i ++ ) {", "vShadowCoord[ i ] = shadowMatrix[ i ] * worldPosition;", "}", "#endif", "}" ].join("\n") }, /* ------------------------------------------------------------------------- // Cube map shader ------------------------------------------------------------------------- */ 'cube': { uniforms: { "tCube": { type: "t", value: null }, "tFlip": { type: "f", value: -1 } }, vertexShader: [ "varying vec3 vWorldPosition;", "void main() {", "vec4 worldPosition = modelMatrix * vec4( position, 1.0 );", "vWorldPosition = worldPosition.xyz;", "gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );", "}" ].join("\n"), fragmentShader: [ "uniform samplerCube tCube;", "uniform float tFlip;", "varying vec3 vWorldPosition;", "void main() {", "gl_FragColor = textureCube( tCube, vec3( tFlip * vWorldPosition.x, vWorldPosition.yz ) );", "}" ].join("\n") }, // Depth encoding into RGBA texture // based on SpiderGL shadow map example // http://spidergl.org/example.php?id=6 // originally from // http://www.gamedev.net/topic/442138-packing-a-float-into-a-a8r8g8b8-texture-shader/page__whichpage__1%25EF%25BF%25BD // see also here: // http://aras-p.info/blog/2009/07/30/encoding-floats-to-rgba-the-final/ 'depthRGBA': { uniforms: {}, vertexShader: [ THREE.ShaderChunk[ "morphtarget_pars_vertex" ], THREE.ShaderChunk[ "skinning_pars_vertex" ], "void main() {", THREE.ShaderChunk[ "skinbase_vertex" ], THREE.ShaderChunk[ "morphtarget_vertex" ], THREE.ShaderChunk[ "skinning_vertex" ], THREE.ShaderChunk[ "default_vertex" ], "}" ].join("\n"), fragmentShader: [ "vec4 pack_depth( const in float depth ) {", "const vec4 bit_shift = vec4( 256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0 );", "const vec4 bit_mask = vec4( 0.0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0 );", "vec4 res = fract( depth * bit_shift );", "res -= res.xxyz * bit_mask;", "return res;", "}", "void main() {", "gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z );", //"gl_FragData[ 0 ] = pack_depth( gl_FragCoord.z / gl_FragCoord.w );", //"float z = ( ( gl_FragCoord.z / gl_FragCoord.w ) - 3.0 ) / ( 4000.0 - 3.0 );", //"gl_FragData[ 0 ] = pack_depth( z );", //"gl_FragData[ 0 ] = vec4( z, z, z, 1.0 );", "}" ].join("\n") } }; /** * @author supereggbert / http://www.paulbrunt.co.uk/ * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author szimek / https://github.com/szimek/ */ THREE.WebGLRenderer = function ( parameters ) { parameters = parameters || {}; var _canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ), _context = parameters.context !== undefined ? parameters.context : null, _precision = parameters.precision !== undefined ? parameters.precision : 'highp', _buffers = {}, _alpha = parameters.alpha !== undefined ? parameters.alpha : false, _premultipliedAlpha = parameters.premultipliedAlpha !== undefined ? parameters.premultipliedAlpha : true, _antialias = parameters.antialias !== undefined ? parameters.antialias : false, _stencil = parameters.stencil !== undefined ? parameters.stencil : true, _preserveDrawingBuffer = parameters.preserveDrawingBuffer !== undefined ? parameters.preserveDrawingBuffer : false, _clearColor = new THREE.Color( 0x000000 ), _clearAlpha = 0; // public properties this.domElement = _canvas; this.context = null; this.devicePixelRatio = parameters.devicePixelRatio !== undefined ? parameters.devicePixelRatio : self.devicePixelRatio !== undefined ? self.devicePixelRatio : 1; // clearing this.autoClear = true; this.autoClearColor = true; this.autoClearDepth = true; this.autoClearStencil = true; // scene graph this.sortObjects = true; this.autoUpdateObjects = true; // physically based shading this.gammaInput = false; this.gammaOutput = false; // shadow map this.shadowMapEnabled = false; this.shadowMapAutoUpdate = true; this.shadowMapType = THREE.PCFShadowMap; this.shadowMapCullFace = THREE.CullFaceFront; this.shadowMapDebug = false; this.shadowMapCascade = false; // morphs this.maxMorphTargets = 8; this.maxMorphNormals = 4; // flags this.autoScaleCubemaps = true; // custom render plugins this.renderPluginsPre = []; this.renderPluginsPost = []; // info this.info = { memory: { programs: 0, geometries: 0, textures: 0 }, render: { calls: 0, vertices: 0, faces: 0, points: 0 } }; // internal properties var _this = this, _programs = [], _programs_counter = 0, // internal state cache _currentProgram = null, _currentFramebuffer = null, _currentMaterialId = -1, _currentGeometryGroupHash = null, _currentCamera = null, _usedTextureUnits = 0, // GL state cache _oldDoubleSided = -1, _oldFlipSided = -1, _oldBlending = -1, _oldBlendEquation = -1, _oldBlendSrc = -1, _oldBlendDst = -1, _oldDepthTest = -1, _oldDepthWrite = -1, _oldPolygonOffset = null, _oldPolygonOffsetFactor = null, _oldPolygonOffsetUnits = null, _oldLineWidth = null, _viewportX = 0, _viewportY = 0, _viewportWidth = _canvas.width, _viewportHeight = _canvas.height, _currentWidth = 0, _currentHeight = 0, _enabledAttributes = new Uint8Array( 16 ), // frustum _frustum = new THREE.Frustum(), // camera matrices cache _projScreenMatrix = new THREE.Matrix4(), _projScreenMatrixPS = new THREE.Matrix4(), _vector3 = new THREE.Vector3(), // light arrays cache _direction = new THREE.Vector3(), _lightsNeedUpdate = true, _lights = { ambient: [ 0, 0, 0 ], directional: { length: 0, colors: new Array(), positions: new Array() }, point: { length: 0, colors: new Array(), positions: new Array(), distances: new Array() }, spot: { length: 0, colors: new Array(), positions: new Array(), distances: new Array(), directions: new Array(), anglesCos: new Array(), exponents: new Array() }, hemi: { length: 0, skyColors: new Array(), groundColors: new Array(), positions: new Array() } }; // initialize var _gl; var _glExtensionTextureFloat; var _glExtensionTextureFloatLinear; var _glExtensionStandardDerivatives; var _glExtensionTextureFilterAnisotropic; var _glExtensionCompressedTextureS3TC; initGL(); setDefaultGLState(); this.context = _gl; // GPU capabilities var _maxTextures = _gl.getParameter( _gl.MAX_TEXTURE_IMAGE_UNITS ); var _maxVertexTextures = _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ); var _maxTextureSize = _gl.getParameter( _gl.MAX_TEXTURE_SIZE ); var _maxCubemapSize = _gl.getParameter( _gl.MAX_CUBE_MAP_TEXTURE_SIZE ); var _maxAnisotropy = _glExtensionTextureFilterAnisotropic ? _gl.getParameter( _glExtensionTextureFilterAnisotropic.MAX_TEXTURE_MAX_ANISOTROPY_EXT ) : 0; var _supportsVertexTextures = ( _maxVertexTextures > 0 ); var _supportsBoneTextures = _supportsVertexTextures && _glExtensionTextureFloat; var _compressedTextureFormats = _glExtensionCompressedTextureS3TC ? _gl.getParameter( _gl.COMPRESSED_TEXTURE_FORMATS ) : []; // var _vertexShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_FLOAT ); var _vertexShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_FLOAT ); var _vertexShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_FLOAT ); var _fragmentShaderPrecisionHighpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_FLOAT ); var _fragmentShaderPrecisionMediumpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_FLOAT ); var _fragmentShaderPrecisionLowpFloat = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_FLOAT ); var _vertexShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.HIGH_INT ); var _vertexShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.MEDIUM_INT ); var _vertexShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.VERTEX_SHADER, _gl.LOW_INT ); var _fragmentShaderPrecisionHighpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.HIGH_INT ); var _fragmentShaderPrecisionMediumpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.MEDIUM_INT ); var _fragmentShaderPrecisionLowpInt = _gl.getShaderPrecisionFormat( _gl.FRAGMENT_SHADER, _gl.LOW_INT ); // clamp precision to maximum available var highpAvailable = _vertexShaderPrecisionHighpFloat.precision > 0 && _fragmentShaderPrecisionHighpFloat.precision > 0; var mediumpAvailable = _vertexShaderPrecisionMediumpFloat.precision > 0 && _fragmentShaderPrecisionMediumpFloat.precision > 0; if ( _precision === "highp" && ! highpAvailable ) { if ( mediumpAvailable ) { _precision = "mediump"; console.warn( "WebGLRenderer: highp not supported, using mediump" ); } else { _precision = "lowp"; console.warn( "WebGLRenderer: highp and mediump not supported, using lowp" ); } } if ( _precision === "mediump" && ! mediumpAvailable ) { _precision = "lowp"; console.warn( "WebGLRenderer: mediump not supported, using lowp" ); } // API this.getContext = function () { return _gl; }; this.supportsVertexTextures = function () { return _supportsVertexTextures; }; this.supportsFloatTextures = function () { return _glExtensionTextureFloat; }; this.supportsStandardDerivatives = function () { return _glExtensionStandardDerivatives; }; this.supportsCompressedTextureS3TC = function () { return _glExtensionCompressedTextureS3TC; }; this.getMaxAnisotropy = function () { return _maxAnisotropy; }; this.getPrecision = function () { return _precision; }; this.setSize = function ( width, height, updateStyle ) { _canvas.width = width * this.devicePixelRatio; _canvas.height = height * this.devicePixelRatio; if ( this.devicePixelRatio !== 1 && updateStyle !== false ) { _canvas.style.width = width + 'px'; _canvas.style.height = height + 'px'; } this.setViewport( 0, 0, width, height ); }; this.setViewport = function ( x, y, width, height ) { _viewportX = x * this.devicePixelRatio; _viewportY = y * this.devicePixelRatio; _viewportWidth = width * this.devicePixelRatio; _viewportHeight = height * this.devicePixelRatio; _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); }; this.setScissor = function ( x, y, width, height ) { _gl.scissor( x * this.devicePixelRatio, y * this.devicePixelRatio, width * this.devicePixelRatio, height * this.devicePixelRatio ); }; this.enableScissorTest = function ( enable ) { enable ? _gl.enable( _gl.SCISSOR_TEST ) : _gl.disable( _gl.SCISSOR_TEST ); }; // Clearing this.setClearColor = function ( color, alpha ) { _clearColor.set( color ); _clearAlpha = alpha !== undefined ? alpha : 1; _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; this.setClearColorHex = function ( hex, alpha ) { console.warn( 'DEPRECATED: .setClearColorHex() is being removed. Use .setClearColor() instead.' ); this.setClearColor( hex, alpha ); }; this.getClearColor = function () { return _clearColor; }; this.getClearAlpha = function () { return _clearAlpha; }; this.clear = function ( color, depth, stencil ) { var bits = 0; if ( color === undefined || color ) bits |= _gl.COLOR_BUFFER_BIT; if ( depth === undefined || depth ) bits |= _gl.DEPTH_BUFFER_BIT; if ( stencil === undefined || stencil ) bits |= _gl.STENCIL_BUFFER_BIT; _gl.clear( bits ); }; this.clearColor = function () { _gl.clear( _gl.COLOR_BUFFER_BIT ); }; this.clearDepth = function () { _gl.clear( _gl.DEPTH_BUFFER_BIT ); }; this.clearStencil = function () { _gl.clear( _gl.STENCIL_BUFFER_BIT ); }; this.clearTarget = function ( renderTarget, color, depth, stencil ) { this.setRenderTarget( renderTarget ); this.clear( color, depth, stencil ); }; // Plugins this.addPostPlugin = function ( plugin ) { plugin.init( this ); this.renderPluginsPost.push( plugin ); }; this.addPrePlugin = function ( plugin ) { plugin.init( this ); this.renderPluginsPre.push( plugin ); }; // Rendering this.updateShadowMap = function ( scene, camera ) { _currentProgram = null; _oldBlending = -1; _oldDepthTest = -1; _oldDepthWrite = -1; _currentGeometryGroupHash = -1; _currentMaterialId = -1; _lightsNeedUpdate = true; _oldDoubleSided = -1; _oldFlipSided = -1; this.shadowMapPlugin.update( scene, camera ); }; // Internal functions // Buffer allocation function createParticleBuffers ( geometry ) { geometry.__webglVertexBuffer = _gl.createBuffer(); geometry.__webglColorBuffer = _gl.createBuffer(); _this.info.memory.geometries ++; }; function createLineBuffers ( geometry ) { geometry.__webglVertexBuffer = _gl.createBuffer(); geometry.__webglColorBuffer = _gl.createBuffer(); geometry.__webglLineDistanceBuffer = _gl.createBuffer(); _this.info.memory.geometries ++; }; function createMeshBuffers ( geometryGroup ) { geometryGroup.__webglVertexBuffer = _gl.createBuffer(); geometryGroup.__webglNormalBuffer = _gl.createBuffer(); geometryGroup.__webglTangentBuffer = _gl.createBuffer(); geometryGroup.__webglColorBuffer = _gl.createBuffer(); geometryGroup.__webglUVBuffer = _gl.createBuffer(); geometryGroup.__webglUV2Buffer = _gl.createBuffer(); geometryGroup.__webglSkinIndicesBuffer = _gl.createBuffer(); geometryGroup.__webglSkinWeightsBuffer = _gl.createBuffer(); geometryGroup.__webglFaceBuffer = _gl.createBuffer(); geometryGroup.__webglLineBuffer = _gl.createBuffer(); var m, ml; if ( geometryGroup.numMorphTargets ) { geometryGroup.__webglMorphTargetsBuffers = []; for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { geometryGroup.__webglMorphTargetsBuffers.push( _gl.createBuffer() ); } } if ( geometryGroup.numMorphNormals ) { geometryGroup.__webglMorphNormalsBuffers = []; for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { geometryGroup.__webglMorphNormalsBuffers.push( _gl.createBuffer() ); } } _this.info.memory.geometries ++; }; // Events var onGeometryDispose = function ( event ) { var geometry = event.target; geometry.removeEventListener( 'dispose', onGeometryDispose ); deallocateGeometry( geometry ); }; var onTextureDispose = function ( event ) { var texture = event.target; texture.removeEventListener( 'dispose', onTextureDispose ); deallocateTexture( texture ); _this.info.memory.textures --; }; var onRenderTargetDispose = function ( event ) { var renderTarget = event.target; renderTarget.removeEventListener( 'dispose', onRenderTargetDispose ); deallocateRenderTarget( renderTarget ); _this.info.memory.textures --; }; var onMaterialDispose = function ( event ) { var material = event.target; material.removeEventListener( 'dispose', onMaterialDispose ); deallocateMaterial( material ); }; // Buffer deallocation var deleteBuffers = function ( geometry ) { if ( geometry.__webglVertexBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglVertexBuffer ); if ( geometry.__webglNormalBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglNormalBuffer ); if ( geometry.__webglTangentBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglTangentBuffer ); if ( geometry.__webglColorBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglColorBuffer ); if ( geometry.__webglUVBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglUVBuffer ); if ( geometry.__webglUV2Buffer !== undefined ) _gl.deleteBuffer( geometry.__webglUV2Buffer ); if ( geometry.__webglSkinIndicesBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinIndicesBuffer ); if ( geometry.__webglSkinWeightsBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglSkinWeightsBuffer ); if ( geometry.__webglFaceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglFaceBuffer ); if ( geometry.__webglLineBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineBuffer ); if ( geometry.__webglLineDistanceBuffer !== undefined ) _gl.deleteBuffer( geometry.__webglLineDistanceBuffer ); // custom attributes if ( geometry.__webglCustomAttributesList !== undefined ) { for ( var id in geometry.__webglCustomAttributesList ) { _gl.deleteBuffer( geometry.__webglCustomAttributesList[ id ].buffer ); } } _this.info.memory.geometries --; }; var deallocateGeometry = function ( geometry ) { geometry.__webglInit = undefined; if ( geometry instanceof THREE.BufferGeometry ) { var attributes = geometry.attributes; for ( var key in attributes ) { if ( attributes[ key ].buffer !== undefined ) { _gl.deleteBuffer( attributes[ key ].buffer ); } } _this.info.memory.geometries --; } else { if ( geometry.geometryGroups !== undefined ) { for ( var g in geometry.geometryGroups ) { var geometryGroup = geometry.geometryGroups[ g ]; if ( geometryGroup.numMorphTargets !== undefined ) { for ( var m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { _gl.deleteBuffer( geometryGroup.__webglMorphTargetsBuffers[ m ] ); } } if ( geometryGroup.numMorphNormals !== undefined ) { for ( var m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { _gl.deleteBuffer( geometryGroup.__webglMorphNormalsBuffers[ m ] ); } } deleteBuffers( geometryGroup ); } } else { deleteBuffers( geometry ); } } }; var deallocateTexture = function ( texture ) { if ( texture.image && texture.image.__webglTextureCube ) { // cube texture _gl.deleteTexture( texture.image.__webglTextureCube ); } else { // 2D texture if ( ! texture.__webglInit ) return; texture.__webglInit = false; _gl.deleteTexture( texture.__webglTexture ); } }; var deallocateRenderTarget = function ( renderTarget ) { if ( !renderTarget || ! renderTarget.__webglTexture ) return; _gl.deleteTexture( renderTarget.__webglTexture ); if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { for ( var i = 0; i < 6; i ++ ) { _gl.deleteFramebuffer( renderTarget.__webglFramebuffer[ i ] ); _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer[ i ] ); } } else { _gl.deleteFramebuffer( renderTarget.__webglFramebuffer ); _gl.deleteRenderbuffer( renderTarget.__webglRenderbuffer ); } }; var deallocateMaterial = function ( material ) { var program = material.program; if ( program === undefined ) return; material.program = undefined; // only deallocate GL program if this was the last use of shared program // assumed there is only single copy of any program in the _programs list // (that's how it's constructed) var i, il, programInfo; var deleteProgram = false; for ( i = 0, il = _programs.length; i < il; i ++ ) { programInfo = _programs[ i ]; if ( programInfo.program === program ) { programInfo.usedTimes --; if ( programInfo.usedTimes === 0 ) { deleteProgram = true; } break; } } if ( deleteProgram === true ) { // avoid using array.splice, this is costlier than creating new array from scratch var newPrograms = []; for ( i = 0, il = _programs.length; i < il; i ++ ) { programInfo = _programs[ i ]; if ( programInfo.program !== program ) { newPrograms.push( programInfo ); } } _programs = newPrograms; _gl.deleteProgram( program ); _this.info.memory.programs --; } }; // Buffer initialization function initCustomAttributes ( geometry, object ) { var nvertices = geometry.vertices.length; var material = object.material; if ( material.attributes ) { if ( geometry.__webglCustomAttributesList === undefined ) { geometry.__webglCustomAttributesList = []; } for ( var a in material.attributes ) { var attribute = material.attributes[ a ]; if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { attribute.__webglInitialized = true; var size = 1; // "f" and "i" if ( attribute.type === "v2" ) size = 2; else if ( attribute.type === "v3" ) size = 3; else if ( attribute.type === "v4" ) size = 4; else if ( attribute.type === "c" ) size = 3; attribute.size = size; attribute.array = new Float32Array( nvertices * size ); attribute.buffer = _gl.createBuffer(); attribute.buffer.belongsToAttribute = a; attribute.needsUpdate = true; } geometry.__webglCustomAttributesList.push( attribute ); } } }; function initParticleBuffers ( geometry, object ) { var nvertices = geometry.vertices.length; geometry.__vertexArray = new Float32Array( nvertices * 3 ); geometry.__colorArray = new Float32Array( nvertices * 3 ); geometry.__sortArray = []; geometry.__webglParticleCount = nvertices; initCustomAttributes ( geometry, object ); }; function initLineBuffers ( geometry, object ) { var nvertices = geometry.vertices.length; geometry.__vertexArray = new Float32Array( nvertices * 3 ); geometry.__colorArray = new Float32Array( nvertices * 3 ); geometry.__lineDistanceArray = new Float32Array( nvertices * 1 ); geometry.__webglLineCount = nvertices; initCustomAttributes ( geometry, object ); }; function initMeshBuffers ( geometryGroup, object ) { var geometry = object.geometry, faces3 = geometryGroup.faces3, nvertices = faces3.length * 3, ntris = faces3.length * 1, nlines = faces3.length * 3, material = getBufferMaterial( object, geometryGroup ), uvType = bufferGuessUVType( material ), normalType = bufferGuessNormalType( material ), vertexColorType = bufferGuessVertexColorType( material ); // console.log( "uvType", uvType, "normalType", normalType, "vertexColorType", vertexColorType, object, geometryGroup, material ); geometryGroup.__vertexArray = new Float32Array( nvertices * 3 ); if ( normalType ) { geometryGroup.__normalArray = new Float32Array( nvertices * 3 ); } if ( geometry.hasTangents ) { geometryGroup.__tangentArray = new Float32Array( nvertices * 4 ); } if ( vertexColorType ) { geometryGroup.__colorArray = new Float32Array( nvertices * 3 ); } if ( uvType ) { if ( geometry.faceVertexUvs.length > 0 ) { geometryGroup.__uvArray = new Float32Array( nvertices * 2 ); } if ( geometry.faceVertexUvs.length > 1 ) { geometryGroup.__uv2Array = new Float32Array( nvertices * 2 ); } } if ( object.geometry.skinWeights.length && object.geometry.skinIndices.length ) { geometryGroup.__skinIndexArray = new Float32Array( nvertices * 4 ); geometryGroup.__skinWeightArray = new Float32Array( nvertices * 4 ); } geometryGroup.__faceArray = new Uint16Array( ntris * 3 ); geometryGroup.__lineArray = new Uint16Array( nlines * 2 ); var m, ml; if ( geometryGroup.numMorphTargets ) { geometryGroup.__morphTargetsArrays = []; for ( m = 0, ml = geometryGroup.numMorphTargets; m < ml; m ++ ) { geometryGroup.__morphTargetsArrays.push( new Float32Array( nvertices * 3 ) ); } } if ( geometryGroup.numMorphNormals ) { geometryGroup.__morphNormalsArrays = []; for ( m = 0, ml = geometryGroup.numMorphNormals; m < ml; m ++ ) { geometryGroup.__morphNormalsArrays.push( new Float32Array( nvertices * 3 ) ); } } geometryGroup.__webglFaceCount = ntris * 3; geometryGroup.__webglLineCount = nlines * 2; // custom attributes if ( material.attributes ) { if ( geometryGroup.__webglCustomAttributesList === undefined ) { geometryGroup.__webglCustomAttributesList = []; } for ( var a in material.attributes ) { // Do a shallow copy of the attribute object so different geometryGroup chunks use different // attribute buffers which are correctly indexed in the setMeshBuffers function var originalAttribute = material.attributes[ a ]; var attribute = {}; for ( var property in originalAttribute ) { attribute[ property ] = originalAttribute[ property ]; } if ( !attribute.__webglInitialized || attribute.createUniqueBuffers ) { attribute.__webglInitialized = true; var size = 1; // "f" and "i" if( attribute.type === "v2" ) size = 2; else if( attribute.type === "v3" ) size = 3; else if( attribute.type === "v4" ) size = 4; else if( attribute.type === "c" ) size = 3; attribute.size = size; attribute.array = new Float32Array( nvertices * size ); attribute.buffer = _gl.createBuffer(); attribute.buffer.belongsToAttribute = a; originalAttribute.needsUpdate = true; attribute.__original = originalAttribute; } geometryGroup.__webglCustomAttributesList.push( attribute ); } } geometryGroup.__inittedArrays = true; }; function getBufferMaterial( object, geometryGroup ) { return object.material instanceof THREE.MeshFaceMaterial ? object.material.materials[ geometryGroup.materialIndex ] : object.material; }; function materialNeedsSmoothNormals ( material ) { return material && material.shading !== undefined && material.shading === THREE.SmoothShading; }; function bufferGuessNormalType ( material ) { // only MeshBasicMaterial and MeshDepthMaterial don't need normals if ( ( material instanceof THREE.MeshBasicMaterial && !material.envMap ) || material instanceof THREE.MeshDepthMaterial ) { return false; } if ( materialNeedsSmoothNormals( material ) ) { return THREE.SmoothShading; } else { return THREE.FlatShading; } }; function bufferGuessVertexColorType( material ) { if ( material.vertexColors ) { return material.vertexColors; } return false; }; function bufferGuessUVType( material ) { // material must use some texture to require uvs if ( material.map || material.lightMap || material.bumpMap || material.normalMap || material.specularMap || material instanceof THREE.ShaderMaterial ) { return true; } return false; }; // function initDirectBuffers( geometry ) { var a, attribute, type; for ( a in geometry.attributes ) { if ( a === "index" ) { type = _gl.ELEMENT_ARRAY_BUFFER; } else { type = _gl.ARRAY_BUFFER; } attribute = geometry.attributes[ a ]; attribute.buffer = _gl.createBuffer(); _gl.bindBuffer( type, attribute.buffer ); _gl.bufferData( type, attribute.array, _gl.STATIC_DRAW ); } }; // Buffer setting function setParticleBuffers ( geometry, hint, object ) { var v, c, vertex, offset, index, color, vertices = geometry.vertices, vl = vertices.length, colors = geometry.colors, cl = colors.length, vertexArray = geometry.__vertexArray, colorArray = geometry.__colorArray, sortArray = geometry.__sortArray, dirtyVertices = geometry.verticesNeedUpdate, dirtyElements = geometry.elementsNeedUpdate, dirtyColors = geometry.colorsNeedUpdate, customAttributes = geometry.__webglCustomAttributesList, i, il, a, ca, cal, value, customAttribute; if ( object.sortParticles ) { _projScreenMatrixPS.copy( _projScreenMatrix ); _projScreenMatrixPS.multiply( object.matrixWorld ); for ( v = 0; v < vl; v ++ ) { vertex = vertices[ v ]; _vector3.copy( vertex ); _vector3.applyProjection( _projScreenMatrixPS ); sortArray[ v ] = [ _vector3.z, v ]; } sortArray.sort( numericalSort ); for ( v = 0; v < vl; v ++ ) { vertex = vertices[ sortArray[v][1] ]; offset = v * 3; vertexArray[ offset ] = vertex.x; vertexArray[ offset + 1 ] = vertex.y; vertexArray[ offset + 2 ] = vertex.z; } for ( c = 0; c < cl; c ++ ) { offset = c * 3; color = colors[ sortArray[c][1] ]; colorArray[ offset ] = color.r; colorArray[ offset + 1 ] = color.g; colorArray[ offset + 2 ] = color.b; } if ( customAttributes ) { for ( i = 0, il = customAttributes.length; i < il; i ++ ) { customAttribute = customAttributes[ i ]; if ( ! ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) continue; offset = 0; cal = customAttribute.value.length; if ( customAttribute.size === 1 ) { for ( ca = 0; ca < cal; ca ++ ) { index = sortArray[ ca ][ 1 ]; customAttribute.array[ ca ] = customAttribute.value[ index ]; } } else if ( customAttribute.size === 2 ) { for ( ca = 0; ca < cal; ca ++ ) { index = sortArray[ ca ][ 1 ]; value = customAttribute.value[ index ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; offset += 2; } } else if ( customAttribute.size === 3 ) { if ( customAttribute.type === "c" ) { for ( ca = 0; ca < cal; ca ++ ) { index = sortArray[ ca ][ 1 ]; value = customAttribute.value[ index ]; customAttribute.array[ offset ] = value.r; customAttribute.array[ offset + 1 ] = value.g; customAttribute.array[ offset + 2 ] = value.b; offset += 3; } } else { for ( ca = 0; ca < cal; ca ++ ) { index = sortArray[ ca ][ 1 ]; value = customAttribute.value[ index ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; offset += 3; } } } else if ( customAttribute.size === 4 ) { for ( ca = 0; ca < cal; ca ++ ) { index = sortArray[ ca ][ 1 ]; value = customAttribute.value[ index ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; customAttribute.array[ offset + 3 ] = value.w; offset += 4; } } } } } else { if ( dirtyVertices ) { for ( v = 0; v < vl; v ++ ) { vertex = vertices[ v ]; offset = v * 3; vertexArray[ offset ] = vertex.x; vertexArray[ offset + 1 ] = vertex.y; vertexArray[ offset + 2 ] = vertex.z; } } if ( dirtyColors ) { for ( c = 0; c < cl; c ++ ) { color = colors[ c ]; offset = c * 3; colorArray[ offset ] = color.r; colorArray[ offset + 1 ] = color.g; colorArray[ offset + 2 ] = color.b; } } if ( customAttributes ) { for ( i = 0, il = customAttributes.length; i < il; i ++ ) { customAttribute = customAttributes[ i ]; if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices") ) { cal = customAttribute.value.length; offset = 0; if ( customAttribute.size === 1 ) { for ( ca = 0; ca < cal; ca ++ ) { customAttribute.array[ ca ] = customAttribute.value[ ca ]; } } else if ( customAttribute.size === 2 ) { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; offset += 2; } } else if ( customAttribute.size === 3 ) { if ( customAttribute.type === "c" ) { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.r; customAttribute.array[ offset + 1 ] = value.g; customAttribute.array[ offset + 2 ] = value.b; offset += 3; } } else { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; offset += 3; } } } else if ( customAttribute.size === 4 ) { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; customAttribute.array[ offset + 3 ] = value.w; offset += 4; } } } } } } if ( dirtyVertices || object.sortParticles ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); } if ( dirtyColors || object.sortParticles ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); } if ( customAttributes ) { for ( i = 0, il = customAttributes.length; i < il; i ++ ) { customAttribute = customAttributes[ i ]; if ( customAttribute.needsUpdate || object.sortParticles ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); } } } }; function setLineBuffers ( geometry, hint ) { var v, c, d, vertex, offset, color, vertices = geometry.vertices, colors = geometry.colors, lineDistances = geometry.lineDistances, vl = vertices.length, cl = colors.length, dl = lineDistances.length, vertexArray = geometry.__vertexArray, colorArray = geometry.__colorArray, lineDistanceArray = geometry.__lineDistanceArray, dirtyVertices = geometry.verticesNeedUpdate, dirtyColors = geometry.colorsNeedUpdate, dirtyLineDistances = geometry.lineDistancesNeedUpdate, customAttributes = geometry.__webglCustomAttributesList, i, il, a, ca, cal, value, customAttribute; if ( dirtyVertices ) { for ( v = 0; v < vl; v ++ ) { vertex = vertices[ v ]; offset = v * 3; vertexArray[ offset ] = vertex.x; vertexArray[ offset + 1 ] = vertex.y; vertexArray[ offset + 2 ] = vertex.z; } _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglVertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); } if ( dirtyColors ) { for ( c = 0; c < cl; c ++ ) { color = colors[ c ]; offset = c * 3; colorArray[ offset ] = color.r; colorArray[ offset + 1 ] = color.g; colorArray[ offset + 2 ] = color.b; } _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglColorBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); } if ( dirtyLineDistances ) { for ( d = 0; d < dl; d ++ ) { lineDistanceArray[ d ] = lineDistances[ d ]; } _gl.bindBuffer( _gl.ARRAY_BUFFER, geometry.__webglLineDistanceBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, lineDistanceArray, hint ); } if ( customAttributes ) { for ( i = 0, il = customAttributes.length; i < il; i ++ ) { customAttribute = customAttributes[ i ]; if ( customAttribute.needsUpdate && ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) ) { offset = 0; cal = customAttribute.value.length; if ( customAttribute.size === 1 ) { for ( ca = 0; ca < cal; ca ++ ) { customAttribute.array[ ca ] = customAttribute.value[ ca ]; } } else if ( customAttribute.size === 2 ) { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; offset += 2; } } else if ( customAttribute.size === 3 ) { if ( customAttribute.type === "c" ) { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.r; customAttribute.array[ offset + 1 ] = value.g; customAttribute.array[ offset + 2 ] = value.b; offset += 3; } } else { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; offset += 3; } } } else if ( customAttribute.size === 4 ) { for ( ca = 0; ca < cal; ca ++ ) { value = customAttribute.value[ ca ]; customAttribute.array[ offset ] = value.x; customAttribute.array[ offset + 1 ] = value.y; customAttribute.array[ offset + 2 ] = value.z; customAttribute.array[ offset + 3 ] = value.w; offset += 4; } } _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); } } } }; function setMeshBuffers( geometryGroup, object, hint, dispose, material ) { if ( ! geometryGroup.__inittedArrays ) { return; } var normalType = bufferGuessNormalType( material ), vertexColorType = bufferGuessVertexColorType( material ), uvType = bufferGuessUVType( material ), needsSmoothNormals = ( normalType === THREE.SmoothShading ); var f, fl, fi, face, vertexNormals, faceNormal, normal, vertexColors, faceColor, vertexTangents, uv, uv2, v1, v2, v3, v4, t1, t2, t3, t4, n1, n2, n3, n4, c1, c2, c3, c4, sw1, sw2, sw3, sw4, si1, si2, si3, si4, sa1, sa2, sa3, sa4, sb1, sb2, sb3, sb4, m, ml, i, il, vn, uvi, uv2i, vk, vkl, vka, nka, chf, faceVertexNormals, a, vertexIndex = 0, offset = 0, offset_uv = 0, offset_uv2 = 0, offset_face = 0, offset_normal = 0, offset_tangent = 0, offset_line = 0, offset_color = 0, offset_skin = 0, offset_morphTarget = 0, offset_custom = 0, offset_customSrc = 0, value, vertexArray = geometryGroup.__vertexArray, uvArray = geometryGroup.__uvArray, uv2Array = geometryGroup.__uv2Array, normalArray = geometryGroup.__normalArray, tangentArray = geometryGroup.__tangentArray, colorArray = geometryGroup.__colorArray, skinIndexArray = geometryGroup.__skinIndexArray, skinWeightArray = geometryGroup.__skinWeightArray, morphTargetsArrays = geometryGroup.__morphTargetsArrays, morphNormalsArrays = geometryGroup.__morphNormalsArrays, customAttributes = geometryGroup.__webglCustomAttributesList, customAttribute, faceArray = geometryGroup.__faceArray, lineArray = geometryGroup.__lineArray, geometry = object.geometry, // this is shared for all chunks dirtyVertices = geometry.verticesNeedUpdate, dirtyElements = geometry.elementsNeedUpdate, dirtyUvs = geometry.uvsNeedUpdate, dirtyNormals = geometry.normalsNeedUpdate, dirtyTangents = geometry.tangentsNeedUpdate, dirtyColors = geometry.colorsNeedUpdate, dirtyMorphTargets = geometry.morphTargetsNeedUpdate, vertices = geometry.vertices, chunk_faces3 = geometryGroup.faces3, obj_faces = geometry.faces, obj_uvs = geometry.faceVertexUvs[ 0 ], obj_uvs2 = geometry.faceVertexUvs[ 1 ], obj_colors = geometry.colors, obj_skinIndices = geometry.skinIndices, obj_skinWeights = geometry.skinWeights, morphTargets = geometry.morphTargets, morphNormals = geometry.morphNormals; if ( dirtyVertices ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; v1 = vertices[ face.a ]; v2 = vertices[ face.b ]; v3 = vertices[ face.c ]; vertexArray[ offset ] = v1.x; vertexArray[ offset + 1 ] = v1.y; vertexArray[ offset + 2 ] = v1.z; vertexArray[ offset + 3 ] = v2.x; vertexArray[ offset + 4 ] = v2.y; vertexArray[ offset + 5 ] = v2.z; vertexArray[ offset + 6 ] = v3.x; vertexArray[ offset + 7 ] = v3.y; vertexArray[ offset + 8 ] = v3.z; offset += 9; } _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, vertexArray, hint ); } if ( dirtyMorphTargets ) { for ( vk = 0, vkl = morphTargets.length; vk < vkl; vk ++ ) { offset_morphTarget = 0; for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { chf = chunk_faces3[ f ]; face = obj_faces[ chf ]; // morph positions v1 = morphTargets[ vk ].vertices[ face.a ]; v2 = morphTargets[ vk ].vertices[ face.b ]; v3 = morphTargets[ vk ].vertices[ face.c ]; vka = morphTargetsArrays[ vk ]; vka[ offset_morphTarget ] = v1.x; vka[ offset_morphTarget + 1 ] = v1.y; vka[ offset_morphTarget + 2 ] = v1.z; vka[ offset_morphTarget + 3 ] = v2.x; vka[ offset_morphTarget + 4 ] = v2.y; vka[ offset_morphTarget + 5 ] = v2.z; vka[ offset_morphTarget + 6 ] = v3.x; vka[ offset_morphTarget + 7 ] = v3.y; vka[ offset_morphTarget + 8 ] = v3.z; // morph normals if ( material.morphNormals ) { if ( needsSmoothNormals ) { faceVertexNormals = morphNormals[ vk ].vertexNormals[ chf ]; n1 = faceVertexNormals.a; n2 = faceVertexNormals.b; n3 = faceVertexNormals.c; } else { n1 = morphNormals[ vk ].faceNormals[ chf ]; n2 = n1; n3 = n1; } nka = morphNormalsArrays[ vk ]; nka[ offset_morphTarget ] = n1.x; nka[ offset_morphTarget + 1 ] = n1.y; nka[ offset_morphTarget + 2 ] = n1.z; nka[ offset_morphTarget + 3 ] = n2.x; nka[ offset_morphTarget + 4 ] = n2.y; nka[ offset_morphTarget + 5 ] = n2.z; nka[ offset_morphTarget + 6 ] = n3.x; nka[ offset_morphTarget + 7 ] = n3.y; nka[ offset_morphTarget + 8 ] = n3.z; } // offset_morphTarget += 9; } _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ vk ] ); _gl.bufferData( _gl.ARRAY_BUFFER, morphTargetsArrays[ vk ], hint ); if ( material.morphNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ vk ] ); _gl.bufferData( _gl.ARRAY_BUFFER, morphNormalsArrays[ vk ], hint ); } } } if ( obj_skinWeights.length ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; // weights sw1 = obj_skinWeights[ face.a ]; sw2 = obj_skinWeights[ face.b ]; sw3 = obj_skinWeights[ face.c ]; skinWeightArray[ offset_skin ] = sw1.x; skinWeightArray[ offset_skin + 1 ] = sw1.y; skinWeightArray[ offset_skin + 2 ] = sw1.z; skinWeightArray[ offset_skin + 3 ] = sw1.w; skinWeightArray[ offset_skin + 4 ] = sw2.x; skinWeightArray[ offset_skin + 5 ] = sw2.y; skinWeightArray[ offset_skin + 6 ] = sw2.z; skinWeightArray[ offset_skin + 7 ] = sw2.w; skinWeightArray[ offset_skin + 8 ] = sw3.x; skinWeightArray[ offset_skin + 9 ] = sw3.y; skinWeightArray[ offset_skin + 10 ] = sw3.z; skinWeightArray[ offset_skin + 11 ] = sw3.w; // indices si1 = obj_skinIndices[ face.a ]; si2 = obj_skinIndices[ face.b ]; si3 = obj_skinIndices[ face.c ]; skinIndexArray[ offset_skin ] = si1.x; skinIndexArray[ offset_skin + 1 ] = si1.y; skinIndexArray[ offset_skin + 2 ] = si1.z; skinIndexArray[ offset_skin + 3 ] = si1.w; skinIndexArray[ offset_skin + 4 ] = si2.x; skinIndexArray[ offset_skin + 5 ] = si2.y; skinIndexArray[ offset_skin + 6 ] = si2.z; skinIndexArray[ offset_skin + 7 ] = si2.w; skinIndexArray[ offset_skin + 8 ] = si3.x; skinIndexArray[ offset_skin + 9 ] = si3.y; skinIndexArray[ offset_skin + 10 ] = si3.z; skinIndexArray[ offset_skin + 11 ] = si3.w; offset_skin += 12; } if ( offset_skin > 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, skinIndexArray, hint ); _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, skinWeightArray, hint ); } } if ( dirtyColors && vertexColorType ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; vertexColors = face.vertexColors; faceColor = face.color; if ( vertexColors.length === 3 && vertexColorType === THREE.VertexColors ) { c1 = vertexColors[ 0 ]; c2 = vertexColors[ 1 ]; c3 = vertexColors[ 2 ]; } else { c1 = faceColor; c2 = faceColor; c3 = faceColor; } colorArray[ offset_color ] = c1.r; colorArray[ offset_color + 1 ] = c1.g; colorArray[ offset_color + 2 ] = c1.b; colorArray[ offset_color + 3 ] = c2.r; colorArray[ offset_color + 4 ] = c2.g; colorArray[ offset_color + 5 ] = c2.b; colorArray[ offset_color + 6 ] = c3.r; colorArray[ offset_color + 7 ] = c3.g; colorArray[ offset_color + 8 ] = c3.b; offset_color += 9; } if ( offset_color > 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, colorArray, hint ); } } if ( dirtyTangents && geometry.hasTangents ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; vertexTangents = face.vertexTangents; t1 = vertexTangents[ 0 ]; t2 = vertexTangents[ 1 ]; t3 = vertexTangents[ 2 ]; tangentArray[ offset_tangent ] = t1.x; tangentArray[ offset_tangent + 1 ] = t1.y; tangentArray[ offset_tangent + 2 ] = t1.z; tangentArray[ offset_tangent + 3 ] = t1.w; tangentArray[ offset_tangent + 4 ] = t2.x; tangentArray[ offset_tangent + 5 ] = t2.y; tangentArray[ offset_tangent + 6 ] = t2.z; tangentArray[ offset_tangent + 7 ] = t2.w; tangentArray[ offset_tangent + 8 ] = t3.x; tangentArray[ offset_tangent + 9 ] = t3.y; tangentArray[ offset_tangent + 10 ] = t3.z; tangentArray[ offset_tangent + 11 ] = t3.w; offset_tangent += 12; } _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, tangentArray, hint ); } if ( dirtyNormals && normalType ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; vertexNormals = face.vertexNormals; faceNormal = face.normal; if ( vertexNormals.length === 3 && needsSmoothNormals ) { for ( i = 0; i < 3; i ++ ) { vn = vertexNormals[ i ]; normalArray[ offset_normal ] = vn.x; normalArray[ offset_normal + 1 ] = vn.y; normalArray[ offset_normal + 2 ] = vn.z; offset_normal += 3; } } else { for ( i = 0; i < 3; i ++ ) { normalArray[ offset_normal ] = faceNormal.x; normalArray[ offset_normal + 1 ] = faceNormal.y; normalArray[ offset_normal + 2 ] = faceNormal.z; offset_normal += 3; } } } _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, normalArray, hint ); } if ( dirtyUvs && obj_uvs && uvType ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { fi = chunk_faces3[ f ]; uv = obj_uvs[ fi ]; if ( uv === undefined ) continue; for ( i = 0; i < 3; i ++ ) { uvi = uv[ i ]; uvArray[ offset_uv ] = uvi.x; uvArray[ offset_uv + 1 ] = uvi.y; offset_uv += 2; } } if ( offset_uv > 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, uvArray, hint ); } } if ( dirtyUvs && obj_uvs2 && uvType ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { fi = chunk_faces3[ f ]; uv2 = obj_uvs2[ fi ]; if ( uv2 === undefined ) continue; for ( i = 0; i < 3; i ++ ) { uv2i = uv2[ i ]; uv2Array[ offset_uv2 ] = uv2i.x; uv2Array[ offset_uv2 + 1 ] = uv2i.y; offset_uv2 += 2; } } if ( offset_uv2 > 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); _gl.bufferData( _gl.ARRAY_BUFFER, uv2Array, hint ); } } if ( dirtyElements ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { faceArray[ offset_face ] = vertexIndex; faceArray[ offset_face + 1 ] = vertexIndex + 1; faceArray[ offset_face + 2 ] = vertexIndex + 2; offset_face += 3; lineArray[ offset_line ] = vertexIndex; lineArray[ offset_line + 1 ] = vertexIndex + 1; lineArray[ offset_line + 2 ] = vertexIndex; lineArray[ offset_line + 3 ] = vertexIndex + 2; lineArray[ offset_line + 4 ] = vertexIndex + 1; lineArray[ offset_line + 5 ] = vertexIndex + 2; offset_line += 6; vertexIndex += 3; } _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faceArray, hint ); _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, lineArray, hint ); } if ( customAttributes ) { for ( i = 0, il = customAttributes.length; i < il; i ++ ) { customAttribute = customAttributes[ i ]; if ( ! customAttribute.__original.needsUpdate ) continue; offset_custom = 0; offset_customSrc = 0; if ( customAttribute.size === 1 ) { if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; customAttribute.array[ offset_custom ] = customAttribute.value[ face.a ]; customAttribute.array[ offset_custom + 1 ] = customAttribute.value[ face.b ]; customAttribute.array[ offset_custom + 2 ] = customAttribute.value[ face.c ]; offset_custom += 3; } } else if ( customAttribute.boundTo === "faces" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { value = customAttribute.value[ chunk_faces3[ f ] ]; customAttribute.array[ offset_custom ] = value; customAttribute.array[ offset_custom + 1 ] = value; customAttribute.array[ offset_custom + 2 ] = value; offset_custom += 3; } } } else if ( customAttribute.size === 2 ) { if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; v1 = customAttribute.value[ face.a ]; v2 = customAttribute.value[ face.b ]; v3 = customAttribute.value[ face.c ]; customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v2.x; customAttribute.array[ offset_custom + 3 ] = v2.y; customAttribute.array[ offset_custom + 4 ] = v3.x; customAttribute.array[ offset_custom + 5 ] = v3.y; offset_custom += 6; } } else if ( customAttribute.boundTo === "faces" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { value = customAttribute.value[ chunk_faces3[ f ] ]; v1 = value; v2 = value; v3 = value; customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v2.x; customAttribute.array[ offset_custom + 3 ] = v2.y; customAttribute.array[ offset_custom + 4 ] = v3.x; customAttribute.array[ offset_custom + 5 ] = v3.y; offset_custom += 6; } } } else if ( customAttribute.size === 3 ) { var pp; if ( customAttribute.type === "c" ) { pp = [ "r", "g", "b" ]; } else { pp = [ "x", "y", "z" ]; } if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; v1 = customAttribute.value[ face.a ]; v2 = customAttribute.value[ face.b ]; v3 = customAttribute.value[ face.c ]; customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; offset_custom += 9; } } else if ( customAttribute.boundTo === "faces" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { value = customAttribute.value[ chunk_faces3[ f ] ]; v1 = value; v2 = value; v3 = value; customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; offset_custom += 9; } } else if ( customAttribute.boundTo === "faceVertices" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { value = customAttribute.value[ chunk_faces3[ f ] ]; v1 = value[ 0 ]; v2 = value[ 1 ]; v3 = value[ 2 ]; customAttribute.array[ offset_custom ] = v1[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 1 ] = v1[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 2 ] = v1[ pp[ 2 ] ]; customAttribute.array[ offset_custom + 3 ] = v2[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 4 ] = v2[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 5 ] = v2[ pp[ 2 ] ]; customAttribute.array[ offset_custom + 6 ] = v3[ pp[ 0 ] ]; customAttribute.array[ offset_custom + 7 ] = v3[ pp[ 1 ] ]; customAttribute.array[ offset_custom + 8 ] = v3[ pp[ 2 ] ]; offset_custom += 9; } } } else if ( customAttribute.size === 4 ) { if ( customAttribute.boundTo === undefined || customAttribute.boundTo === "vertices" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { face = obj_faces[ chunk_faces3[ f ] ]; v1 = customAttribute.value[ face.a ]; v2 = customAttribute.value[ face.b ]; v3 = customAttribute.value[ face.c ]; customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v1.z; customAttribute.array[ offset_custom + 3 ] = v1.w; customAttribute.array[ offset_custom + 4 ] = v2.x; customAttribute.array[ offset_custom + 5 ] = v2.y; customAttribute.array[ offset_custom + 6 ] = v2.z; customAttribute.array[ offset_custom + 7 ] = v2.w; customAttribute.array[ offset_custom + 8 ] = v3.x; customAttribute.array[ offset_custom + 9 ] = v3.y; customAttribute.array[ offset_custom + 10 ] = v3.z; customAttribute.array[ offset_custom + 11 ] = v3.w; offset_custom += 12; } } else if ( customAttribute.boundTo === "faces" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { value = customAttribute.value[ chunk_faces3[ f ] ]; v1 = value; v2 = value; v3 = value; customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v1.z; customAttribute.array[ offset_custom + 3 ] = v1.w; customAttribute.array[ offset_custom + 4 ] = v2.x; customAttribute.array[ offset_custom + 5 ] = v2.y; customAttribute.array[ offset_custom + 6 ] = v2.z; customAttribute.array[ offset_custom + 7 ] = v2.w; customAttribute.array[ offset_custom + 8 ] = v3.x; customAttribute.array[ offset_custom + 9 ] = v3.y; customAttribute.array[ offset_custom + 10 ] = v3.z; customAttribute.array[ offset_custom + 11 ] = v3.w; offset_custom += 12; } } else if ( customAttribute.boundTo === "faceVertices" ) { for ( f = 0, fl = chunk_faces3.length; f < fl; f ++ ) { value = customAttribute.value[ chunk_faces3[ f ] ]; v1 = value[ 0 ]; v2 = value[ 1 ]; v3 = value[ 2 ]; customAttribute.array[ offset_custom ] = v1.x; customAttribute.array[ offset_custom + 1 ] = v1.y; customAttribute.array[ offset_custom + 2 ] = v1.z; customAttribute.array[ offset_custom + 3 ] = v1.w; customAttribute.array[ offset_custom + 4 ] = v2.x; customAttribute.array[ offset_custom + 5 ] = v2.y; customAttribute.array[ offset_custom + 6 ] = v2.z; customAttribute.array[ offset_custom + 7 ] = v2.w; customAttribute.array[ offset_custom + 8 ] = v3.x; customAttribute.array[ offset_custom + 9 ] = v3.y; customAttribute.array[ offset_custom + 10 ] = v3.z; customAttribute.array[ offset_custom + 11 ] = v3.w; offset_custom += 12; } } } _gl.bindBuffer( _gl.ARRAY_BUFFER, customAttribute.buffer ); _gl.bufferData( _gl.ARRAY_BUFFER, customAttribute.array, hint ); } } if ( dispose ) { delete geometryGroup.__inittedArrays; delete geometryGroup.__colorArray; delete geometryGroup.__normalArray; delete geometryGroup.__tangentArray; delete geometryGroup.__uvArray; delete geometryGroup.__uv2Array; delete geometryGroup.__faceArray; delete geometryGroup.__vertexArray; delete geometryGroup.__lineArray; delete geometryGroup.__skinIndexArray; delete geometryGroup.__skinWeightArray; } }; // used by renderBufferDirect for THREE.Line function setupLinesVertexAttributes( material, programAttributes, geometryAttributes, startIndex ) { var attributeItem, attributeName, attributePointer, attributeSize; for ( attributeName in programAttributes ) { attributePointer = programAttributes[ attributeName ]; attributeItem = geometryAttributes[ attributeName ]; if ( attributePointer >= 0 ) { if ( attributeItem ) { attributeSize = attributeItem.itemSize; _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); enableAttribute( attributePointer ); _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 } else if ( material.defaultAttributeValues ) { if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } } } } } function setDirectBuffers( geometry, hint ) { var attributes = geometry.attributes; var attributeName, attributeItem; for ( attributeName in attributes ) { attributeItem = attributes[ attributeName ]; if ( attributeItem.needsUpdate ) { if ( attributeName === 'index' ) { _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.buffer ); _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, attributeItem.array, hint ); } else { _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); _gl.bufferData( _gl.ARRAY_BUFFER, attributeItem.array, hint ); } attributeItem.needsUpdate = false; } } } // Buffer rendering this.renderBufferImmediate = function ( object, program, material ) { if ( object.hasPositions && ! object.__webglVertexBuffer ) object.__webglVertexBuffer = _gl.createBuffer(); if ( object.hasNormals && ! object.__webglNormalBuffer ) object.__webglNormalBuffer = _gl.createBuffer(); if ( object.hasUvs && ! object.__webglUvBuffer ) object.__webglUvBuffer = _gl.createBuffer(); if ( object.hasColors && ! object.__webglColorBuffer ) object.__webglColorBuffer = _gl.createBuffer(); if ( object.hasPositions ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglVertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.positionArray, _gl.DYNAMIC_DRAW ); _gl.enableVertexAttribArray( program.attributes.position ); _gl.vertexAttribPointer( program.attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } if ( object.hasNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglNormalBuffer ); if ( material.shading === THREE.FlatShading ) { var nx, ny, nz, nax, nbx, ncx, nay, nby, ncy, naz, nbz, ncz, normalArray, i, il = object.count * 3; for( i = 0; i < il; i += 9 ) { normalArray = object.normalArray; nax = normalArray[ i ]; nay = normalArray[ i + 1 ]; naz = normalArray[ i + 2 ]; nbx = normalArray[ i + 3 ]; nby = normalArray[ i + 4 ]; nbz = normalArray[ i + 5 ]; ncx = normalArray[ i + 6 ]; ncy = normalArray[ i + 7 ]; ncz = normalArray[ i + 8 ]; nx = ( nax + nbx + ncx ) / 3; ny = ( nay + nby + ncy ) / 3; nz = ( naz + nbz + ncz ) / 3; normalArray[ i ] = nx; normalArray[ i + 1 ] = ny; normalArray[ i + 2 ] = nz; normalArray[ i + 3 ] = nx; normalArray[ i + 4 ] = ny; normalArray[ i + 5 ] = nz; normalArray[ i + 6 ] = nx; normalArray[ i + 7 ] = ny; normalArray[ i + 8 ] = nz; } } _gl.bufferData( _gl.ARRAY_BUFFER, object.normalArray, _gl.DYNAMIC_DRAW ); _gl.enableVertexAttribArray( program.attributes.normal ); _gl.vertexAttribPointer( program.attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } if ( object.hasUvs && material.map ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglUvBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.uvArray, _gl.DYNAMIC_DRAW ); _gl.enableVertexAttribArray( program.attributes.uv ); _gl.vertexAttribPointer( program.attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } if ( object.hasColors && material.vertexColors !== THREE.NoColors ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, object.__webglColorBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, object.colorArray, _gl.DYNAMIC_DRAW ); _gl.enableVertexAttribArray( program.attributes.color ); _gl.vertexAttribPointer( program.attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } _gl.drawArrays( _gl.TRIANGLES, 0, object.count ); object.count = 0; }; this.renderBufferDirect = function ( camera, lights, fog, material, geometry, object ) { if ( material.visible === false ) return; var linewidth, a, attribute; var attributeItem, attributeName, attributePointer, attributeSize; var program = setProgram( camera, lights, fog, material, object ); var programAttributes = program.attributes; var geometryAttributes = geometry.attributes; var updateBuffers = false, wireframeBit = material.wireframe ? 1 : 0, geometryHash = ( geometry.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; if ( geometryHash !== _currentGeometryGroupHash ) { _currentGeometryGroupHash = geometryHash; updateBuffers = true; } if ( updateBuffers ) { disableAttributes(); } // render mesh if ( object instanceof THREE.Mesh ) { var index = geometryAttributes[ "index" ]; // indexed triangles if ( index ) { var offsets = geometry.offsets; // if there is more than 1 chunk // must set attribute pointers to use new offsets for each chunk // even if geometry and materials didn't change if ( offsets.length > 1 ) updateBuffers = true; for ( var i = 0, il = offsets.length; i < il; i ++ ) { var startIndex = offsets[ i ].index; if ( updateBuffers ) { for ( attributeName in programAttributes ) { attributePointer = programAttributes[ attributeName ]; attributeItem = geometryAttributes[ attributeName ]; if ( attributePointer >= 0 ) { if ( attributeItem ) { attributeSize = attributeItem.itemSize; _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); enableAttribute( attributePointer ); _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, startIndex * attributeSize * 4 ); // 4 bytes per Float32 } else if ( material.defaultAttributeValues ) { if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } } } } // indices _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); } // render indexed triangles _gl.drawElements( _gl.TRIANGLES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16 _this.info.render.calls ++; _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared _this.info.render.faces += offsets[ i ].count / 3; } // non-indexed triangles } else { if ( updateBuffers ) { for ( attributeName in programAttributes ) { if ( attributeName === 'index') continue; attributePointer = programAttributes[ attributeName ]; attributeItem = geometryAttributes[ attributeName ]; if ( attributePointer >= 0 ) { if ( attributeItem ) { attributeSize = attributeItem.itemSize; _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); enableAttribute( attributePointer ); _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } } } } } var position = geometry.attributes[ "position" ]; // render non-indexed triangles _gl.drawArrays( _gl.TRIANGLES, 0, position.array.length / 3 ); _this.info.render.calls ++; _this.info.render.vertices += position.array.length / 3; _this.info.render.faces += position.array.length / 3 / 3; } // render particles } else if ( object instanceof THREE.ParticleSystem ) { if ( updateBuffers ) { for ( attributeName in programAttributes ) { attributePointer = programAttributes[ attributeName ]; attributeItem = geometryAttributes[ attributeName ]; if ( attributePointer >= 0 ) { if ( attributeItem ) { attributeSize = attributeItem.itemSize; _gl.bindBuffer( _gl.ARRAY_BUFFER, attributeItem.buffer ); enableAttribute( attributePointer ); _gl.vertexAttribPointer( attributePointer, attributeSize, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues && material.defaultAttributeValues[ attributeName ] ) { if ( material.defaultAttributeValues[ attributeName ].length === 2 ) { _gl.vertexAttrib2fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } else if ( material.defaultAttributeValues[ attributeName ].length === 3 ) { _gl.vertexAttrib3fv( attributePointer, material.defaultAttributeValues[ attributeName ] ); } } } } } var position = geometryAttributes[ "position" ]; // render particles _gl.drawArrays( _gl.POINTS, 0, position.array.length / 3 ); _this.info.render.calls ++; _this.info.render.points += position.array.length / 3; } else if ( object instanceof THREE.Line ) { var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; setLineWidth( material.linewidth ); var index = geometryAttributes[ "index" ]; // indexed lines if ( index ) { var offsets = geometry.offsets; // if there is more than 1 chunk // must set attribute pointers to use new offsets for each chunk // even if geometry and materials didn't change if ( offsets.length > 1 ) updateBuffers = true; for ( var i = 0, il = offsets.length; i < il; i ++ ) { var startIndex = offsets[ i ].index; if ( updateBuffers ) { setupLinesVertexAttributes(material, programAttributes, geometryAttributes, startIndex); // indices _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, index.buffer ); } // render indexed lines _gl.drawElements( _gl.LINES, offsets[ i ].count, _gl.UNSIGNED_SHORT, offsets[ i ].start * 2 ); // 2 bytes per Uint16Array _this.info.render.calls ++; _this.info.render.vertices += offsets[ i ].count; // not really true, here vertices can be shared } } // non-indexed lines else { if ( updateBuffers ) { setupLinesVertexAttributes(material, programAttributes, geometryAttributes, 0); } var position = geometryAttributes[ "position" ]; _gl.drawArrays( primitives, 0, position.array.length / 3 ); _this.info.render.calls ++; _this.info.render.points += position.array.length; } } }; this.renderBuffer = function ( camera, lights, fog, material, geometryGroup, object ) { if ( material.visible === false ) return; var linewidth, a, attribute, i, il; var program = setProgram( camera, lights, fog, material, object ); var attributes = program.attributes; var updateBuffers = false, wireframeBit = material.wireframe ? 1 : 0, geometryGroupHash = ( geometryGroup.id * 0xffffff ) + ( program.id * 2 ) + wireframeBit; if ( geometryGroupHash !== _currentGeometryGroupHash ) { _currentGeometryGroupHash = geometryGroupHash; updateBuffers = true; } if ( updateBuffers ) { disableAttributes(); } // vertices if ( !material.morphTargets && attributes.position >= 0 ) { if ( updateBuffers ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); enableAttribute( attributes.position ); _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } } else { if ( object.morphTargetBase ) { setupMorphTargets( material, geometryGroup, object ); } } if ( updateBuffers ) { // custom attributes // Use the per-geometryGroup custom attribute arrays which are setup in initMeshBuffers if ( geometryGroup.__webglCustomAttributesList ) { for ( i = 0, il = geometryGroup.__webglCustomAttributesList.length; i < il; i ++ ) { attribute = geometryGroup.__webglCustomAttributesList[ i ]; if ( attributes[ attribute.buffer.belongsToAttribute ] >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, attribute.buffer ); enableAttribute( attributes[ attribute.buffer.belongsToAttribute ] ); _gl.vertexAttribPointer( attributes[ attribute.buffer.belongsToAttribute ], attribute.size, _gl.FLOAT, false, 0, 0 ); } } } // colors if ( attributes.color >= 0 ) { if ( object.geometry.colors.length > 0 || object.geometry.faces.length > 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglColorBuffer ); enableAttribute( attributes.color ); _gl.vertexAttribPointer( attributes.color, 3, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues ) { _gl.vertexAttrib3fv( attributes.color, material.defaultAttributeValues.color ); } } // normals if ( attributes.normal >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglNormalBuffer ); enableAttribute( attributes.normal ); _gl.vertexAttribPointer( attributes.normal, 3, _gl.FLOAT, false, 0, 0 ); } // tangents if ( attributes.tangent >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglTangentBuffer ); enableAttribute( attributes.tangent ); _gl.vertexAttribPointer( attributes.tangent, 4, _gl.FLOAT, false, 0, 0 ); } // uvs if ( attributes.uv >= 0 ) { if ( object.geometry.faceVertexUvs[0] ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUVBuffer ); enableAttribute( attributes.uv ); _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues ) { _gl.vertexAttrib2fv( attributes.uv, material.defaultAttributeValues.uv ); } } if ( attributes.uv2 >= 0 ) { if ( object.geometry.faceVertexUvs[1] ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglUV2Buffer ); enableAttribute( attributes.uv2 ); _gl.vertexAttribPointer( attributes.uv2, 2, _gl.FLOAT, false, 0, 0 ); } else if ( material.defaultAttributeValues ) { _gl.vertexAttrib2fv( attributes.uv2, material.defaultAttributeValues.uv2 ); } } if ( material.skinning && attributes.skinIndex >= 0 && attributes.skinWeight >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinIndicesBuffer ); enableAttribute( attributes.skinIndex ); _gl.vertexAttribPointer( attributes.skinIndex, 4, _gl.FLOAT, false, 0, 0 ); _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglSkinWeightsBuffer ); enableAttribute( attributes.skinWeight ); _gl.vertexAttribPointer( attributes.skinWeight, 4, _gl.FLOAT, false, 0, 0 ); } // line distances if ( attributes.lineDistance >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglLineDistanceBuffer ); enableAttribute( attributes.lineDistance ); _gl.vertexAttribPointer( attributes.lineDistance, 1, _gl.FLOAT, false, 0, 0 ); } } // render mesh if ( object instanceof THREE.Mesh ) { // wireframe if ( material.wireframe ) { setLineWidth( material.wireframeLinewidth ); if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglLineBuffer ); _gl.drawElements( _gl.LINES, geometryGroup.__webglLineCount, _gl.UNSIGNED_SHORT, 0 ); // triangles } else { if ( updateBuffers ) _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, geometryGroup.__webglFaceBuffer ); _gl.drawElements( _gl.TRIANGLES, geometryGroup.__webglFaceCount, _gl.UNSIGNED_SHORT, 0 ); } _this.info.render.calls ++; _this.info.render.vertices += geometryGroup.__webglFaceCount; _this.info.render.faces += geometryGroup.__webglFaceCount / 3; // render lines } else if ( object instanceof THREE.Line ) { var primitives = ( object.type === THREE.LineStrip ) ? _gl.LINE_STRIP : _gl.LINES; setLineWidth( material.linewidth ); _gl.drawArrays( primitives, 0, geometryGroup.__webglLineCount ); _this.info.render.calls ++; // render particles } else if ( object instanceof THREE.ParticleSystem ) { _gl.drawArrays( _gl.POINTS, 0, geometryGroup.__webglParticleCount ); _this.info.render.calls ++; _this.info.render.points += geometryGroup.__webglParticleCount; } }; function enableAttribute( attribute ) { if ( _enabledAttributes[ attribute ] === 0 ) { _gl.enableVertexAttribArray( attribute ); _enabledAttributes[ attribute ] = 1; } }; function disableAttributes() { for ( var attribute in _enabledAttributes ) { if ( _enabledAttributes[ attribute ] === 1 ) { _gl.disableVertexAttribArray( attribute ); _enabledAttributes[ attribute ] = 0; } } }; function setupMorphTargets ( material, geometryGroup, object ) { // set base var attributes = material.program.attributes; if ( object.morphTargetBase !== -1 && attributes.position >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ object.morphTargetBase ] ); enableAttribute( attributes.position ); _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } else if ( attributes.position >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglVertexBuffer ); enableAttribute( attributes.position ); _gl.vertexAttribPointer( attributes.position, 3, _gl.FLOAT, false, 0, 0 ); } if ( object.morphTargetForcedOrder.length ) { // set forced order var m = 0; var order = object.morphTargetForcedOrder; var influences = object.morphTargetInfluences; while ( m < material.numSupportedMorphTargets && m < order.length ) { if ( attributes[ "morphTarget" + m ] >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ order[ m ] ] ); enableAttribute( attributes[ "morphTarget" + m ] ); _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); } if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ order[ m ] ] ); enableAttribute( attributes[ "morphNormal" + m ] ); _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); } object.__webglMorphTargetInfluences[ m ] = influences[ order[ m ] ]; m ++; } } else { // find the most influencing var influence, activeInfluenceIndices = []; var influences = object.morphTargetInfluences; var i, il = influences.length; for ( i = 0; i < il; i ++ ) { influence = influences[ i ]; if ( influence > 0 ) { activeInfluenceIndices.push( [ influence, i ] ); } } if ( activeInfluenceIndices.length > material.numSupportedMorphTargets ) { activeInfluenceIndices.sort( numericalSort ); activeInfluenceIndices.length = material.numSupportedMorphTargets; } else if ( activeInfluenceIndices.length > material.numSupportedMorphNormals ) { activeInfluenceIndices.sort( numericalSort ); } else if ( activeInfluenceIndices.length === 0 ) { activeInfluenceIndices.push( [ 0, 0 ] ); }; var influenceIndex, m = 0; while ( m < material.numSupportedMorphTargets ) { if ( activeInfluenceIndices[ m ] ) { influenceIndex = activeInfluenceIndices[ m ][ 1 ]; if ( attributes[ "morphTarget" + m ] >= 0 ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphTargetsBuffers[ influenceIndex ] ); enableAttribute( attributes[ "morphTarget" + m ] ); _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); } if ( attributes[ "morphNormal" + m ] >= 0 && material.morphNormals ) { _gl.bindBuffer( _gl.ARRAY_BUFFER, geometryGroup.__webglMorphNormalsBuffers[ influenceIndex ] ); enableAttribute( attributes[ "morphNormal" + m ] ); _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); } object.__webglMorphTargetInfluences[ m ] = influences[ influenceIndex ]; } else { /* _gl.vertexAttribPointer( attributes[ "morphTarget" + m ], 3, _gl.FLOAT, false, 0, 0 ); if ( material.morphNormals ) { _gl.vertexAttribPointer( attributes[ "morphNormal" + m ], 3, _gl.FLOAT, false, 0, 0 ); } */ object.__webglMorphTargetInfluences[ m ] = 0; } m ++; } } // load updated influences uniform if ( material.program.uniforms.morphTargetInfluences !== null ) { _gl.uniform1fv( material.program.uniforms.morphTargetInfluences, object.__webglMorphTargetInfluences ); } }; // Sorting function painterSortStable ( a, b ) { if ( a.z !== b.z ) { return b.z - a.z; } else { return a.id - b.id; } }; function numericalSort ( a, b ) { return b[ 0 ] - a[ 0 ]; }; // Rendering this.render = function ( scene, camera, renderTarget, forceClear ) { if ( camera instanceof THREE.Camera === false ) { console.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' ); return; } var i, il, webglObject, object, renderList, lights = scene.__lights, fog = scene.fog; // reset caching for this frame _currentMaterialId = -1; _lightsNeedUpdate = true; // update scene graph if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); // update camera matrices and frustum if ( camera.parent === undefined ) camera.updateMatrixWorld(); camera.matrixWorldInverse.getInverse( camera.matrixWorld ); _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); _frustum.setFromMatrix( _projScreenMatrix ); // update WebGL objects if ( this.autoUpdateObjects ) this.initWebGLObjects( scene ); // custom render plugins (pre pass) renderPlugins( this.renderPluginsPre, scene, camera ); // _this.info.render.calls = 0; _this.info.render.vertices = 0; _this.info.render.faces = 0; _this.info.render.points = 0; this.setRenderTarget( renderTarget ); if ( this.autoClear || forceClear ) { this.clear( this.autoClearColor, this.autoClearDepth, this.autoClearStencil ); } // set matrices for regular objects (frustum culled) renderList = scene.__webglObjects; for ( i = 0, il = renderList.length; i < il; i ++ ) { webglObject = renderList[ i ]; object = webglObject.object; webglObject.id = i; webglObject.render = false; if ( object.visible ) { if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { setupMatrices( object, camera ); unrollBufferMaterial( webglObject ); webglObject.render = true; if ( this.sortObjects === true ) { if ( object.renderDepth !== null ) { webglObject.z = object.renderDepth; } else { _vector3.setFromMatrixPosition( object.matrixWorld ); _vector3.applyProjection( _projScreenMatrix ); webglObject.z = _vector3.z; } } } } } if ( this.sortObjects ) { renderList.sort( painterSortStable ); } // set matrices for immediate objects renderList = scene.__webglObjectsImmediate; for ( i = 0, il = renderList.length; i < il; i ++ ) { webglObject = renderList[ i ]; object = webglObject.object; if ( object.visible ) { setupMatrices( object, camera ); unrollImmediateBufferMaterial( webglObject ); } } if ( scene.overrideMaterial ) { var material = scene.overrideMaterial; this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); this.setDepthTest( material.depthTest ); this.setDepthWrite( material.depthWrite ); setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); renderObjects( scene.__webglObjects, false, "", camera, lights, fog, true, material ); renderObjectsImmediate( scene.__webglObjectsImmediate, "", camera, lights, fog, false, material ); } else { var material = null; // opaque pass (front-to-back order) this.setBlending( THREE.NoBlending ); renderObjects( scene.__webglObjects, true, "opaque", camera, lights, fog, false, material ); renderObjectsImmediate( scene.__webglObjectsImmediate, "opaque", camera, lights, fog, false, material ); // transparent pass (back-to-front order) renderObjects( scene.__webglObjects, false, "transparent", camera, lights, fog, true, material ); renderObjectsImmediate( scene.__webglObjectsImmediate, "transparent", camera, lights, fog, true, material ); } // custom render plugins (post pass) renderPlugins( this.renderPluginsPost, scene, camera ); // Generate mipmap if we're using any kind of mipmap filtering if ( renderTarget && renderTarget.generateMipmaps && renderTarget.minFilter !== THREE.NearestFilter && renderTarget.minFilter !== THREE.LinearFilter ) { updateRenderTargetMipmap( renderTarget ); } // Ensure depth buffer writing is enabled so it can be cleared on next render this.setDepthTest( true ); this.setDepthWrite( true ); // _gl.finish(); }; function renderPlugins( plugins, scene, camera ) { if ( ! plugins.length ) return; for ( var i = 0, il = plugins.length; i < il; i ++ ) { // reset state for plugin (to start from clean slate) _currentProgram = null; _currentCamera = null; _oldBlending = -1; _oldDepthTest = -1; _oldDepthWrite = -1; _oldDoubleSided = -1; _oldFlipSided = -1; _currentGeometryGroupHash = -1; _currentMaterialId = -1; _lightsNeedUpdate = true; plugins[ i ].render( scene, camera, _currentWidth, _currentHeight ); // reset state after plugin (anything could have changed) _currentProgram = null; _currentCamera = null; _oldBlending = -1; _oldDepthTest = -1; _oldDepthWrite = -1; _oldDoubleSided = -1; _oldFlipSided = -1; _currentGeometryGroupHash = -1; _currentMaterialId = -1; _lightsNeedUpdate = true; } }; function renderObjects( renderList, reverse, materialType, camera, lights, fog, useBlending, overrideMaterial ) { var webglObject, object, buffer, material, start, end, delta; if ( reverse ) { start = renderList.length - 1; end = -1; delta = -1; } else { start = 0; end = renderList.length; delta = 1; } for ( var i = start; i !== end; i += delta ) { webglObject = renderList[ i ]; if ( webglObject.render ) { object = webglObject.object; buffer = webglObject.buffer; if ( overrideMaterial ) { material = overrideMaterial; } else { material = webglObject[ materialType ]; if ( ! material ) continue; if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); _this.setDepthTest( material.depthTest ); _this.setDepthWrite( material.depthWrite ); setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); } _this.setMaterialFaces( material ); if ( buffer instanceof THREE.BufferGeometry ) { _this.renderBufferDirect( camera, lights, fog, material, buffer, object ); } else { _this.renderBuffer( camera, lights, fog, material, buffer, object ); } } } }; function renderObjectsImmediate ( renderList, materialType, camera, lights, fog, useBlending, overrideMaterial ) { var webglObject, object, material, program; for ( var i = 0, il = renderList.length; i < il; i ++ ) { webglObject = renderList[ i ]; object = webglObject.object; if ( object.visible ) { if ( overrideMaterial ) { material = overrideMaterial; } else { material = webglObject[ materialType ]; if ( ! material ) continue; if ( useBlending ) _this.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); _this.setDepthTest( material.depthTest ); _this.setDepthWrite( material.depthWrite ); setPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits ); } _this.renderImmediateObject( camera, lights, fog, material, object ); } } }; this.renderImmediateObject = function ( camera, lights, fog, material, object ) { var program = setProgram( camera, lights, fog, material, object ); _currentGeometryGroupHash = -1; _this.setMaterialFaces( material ); if ( object.immediateRenderCallback ) { object.immediateRenderCallback( program, _gl, _frustum ); } else { object.render( function( object ) { _this.renderBufferImmediate( object, program, material ); } ); } }; function unrollImmediateBufferMaterial ( globject ) { var object = globject.object, material = object.material; if ( material.transparent ) { globject.transparent = material; globject.opaque = null; } else { globject.opaque = material; globject.transparent = null; } }; function unrollBufferMaterial ( globject ) { var object = globject.object; var buffer = globject.buffer; var geometry = object.geometry; var material = object.material; if ( material instanceof THREE.MeshFaceMaterial ) { var materialIndex = geometry instanceof THREE.BufferGeometry ? 0 : buffer.materialIndex; material = material.materials[ materialIndex ]; if ( material.transparent ) { globject.transparent = material; globject.opaque = null; } else { globject.opaque = material; globject.transparent = null; } } else { if ( material ) { if ( material.transparent ) { globject.transparent = material; globject.opaque = null; } else { globject.opaque = material; globject.transparent = null; } } } }; // Objects refresh this.initWebGLObjects = function ( scene ) { if ( !scene.__webglObjects ) { scene.__webglObjects = []; scene.__webglObjectsImmediate = []; scene.__webglSprites = []; scene.__webglFlares = []; } while ( scene.__objectsAdded.length ) { addObject( scene.__objectsAdded[ 0 ], scene ); scene.__objectsAdded.splice( 0, 1 ); } while ( scene.__objectsRemoved.length ) { removeObject( scene.__objectsRemoved[ 0 ], scene ); scene.__objectsRemoved.splice( 0, 1 ); } // update must be called after objects adding / removal for ( var o = 0, ol = scene.__webglObjects.length; o < ol; o ++ ) { var object = scene.__webglObjects[ o ].object; // TODO: Remove this hack (WebGLRenderer refactoring) if ( object.__webglInit === undefined ) { if ( object.__webglActive !== undefined ) { removeObject( object, scene ); } addObject( object, scene ); } updateObject( object ); } }; // Objects adding function addObject( object, scene ) { var g, geometry, material, geometryGroup; if ( object.__webglInit === undefined ) { object.__webglInit = true; object._modelViewMatrix = new THREE.Matrix4(); object._normalMatrix = new THREE.Matrix3(); if ( object.geometry !== undefined && object.geometry.__webglInit === undefined ) { object.geometry.__webglInit = true; object.geometry.addEventListener( 'dispose', onGeometryDispose ); } geometry = object.geometry; if ( geometry === undefined ) { // fail silently for now } else if ( geometry instanceof THREE.BufferGeometry ) { initDirectBuffers( geometry ); } else if ( object instanceof THREE.Mesh ) { material = object.material; if ( geometry.geometryGroups === undefined ) { geometry.makeGroups( material instanceof THREE.MeshFaceMaterial ); } // create separate VBOs per geometry chunk for ( g in geometry.geometryGroups ) { geometryGroup = geometry.geometryGroups[ g ]; // initialise VBO on the first access if ( ! geometryGroup.__webglVertexBuffer ) { createMeshBuffers( geometryGroup ); initMeshBuffers( geometryGroup, object ); geometry.verticesNeedUpdate = true; geometry.morphTargetsNeedUpdate = true; geometry.elementsNeedUpdate = true; geometry.uvsNeedUpdate = true; geometry.normalsNeedUpdate = true; geometry.tangentsNeedUpdate = true; geometry.colorsNeedUpdate = true; } } } else if ( object instanceof THREE.Line ) { if ( ! geometry.__webglVertexBuffer ) { createLineBuffers( geometry ); initLineBuffers( geometry, object ); geometry.verticesNeedUpdate = true; geometry.colorsNeedUpdate = true; geometry.lineDistancesNeedUpdate = true; } } else if ( object instanceof THREE.ParticleSystem ) { if ( ! geometry.__webglVertexBuffer ) { createParticleBuffers( geometry ); initParticleBuffers( geometry, object ); geometry.verticesNeedUpdate = true; geometry.colorsNeedUpdate = true; } } } if ( object.__webglActive === undefined ) { if ( object instanceof THREE.Mesh ) { geometry = object.geometry; if ( geometry instanceof THREE.BufferGeometry ) { addBuffer( scene.__webglObjects, geometry, object ); } else if ( geometry instanceof THREE.Geometry ) { for ( g in geometry.geometryGroups ) { geometryGroup = geometry.geometryGroups[ g ]; addBuffer( scene.__webglObjects, geometryGroup, object ); } } } else if ( object instanceof THREE.Line || object instanceof THREE.ParticleSystem ) { geometry = object.geometry; addBuffer( scene.__webglObjects, geometry, object ); } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { addBufferImmediate( scene.__webglObjectsImmediate, object ); } else if ( object instanceof THREE.Sprite ) { scene.__webglSprites.push( object ); } else if ( object instanceof THREE.LensFlare ) { scene.__webglFlares.push( object ); } object.__webglActive = true; } }; function addBuffer( objlist, buffer, object ) { objlist.push( { id: null, buffer: buffer, object: object, opaque: null, transparent: null, z: 0 } ); }; function addBufferImmediate( objlist, object ) { objlist.push( { id: null, object: object, opaque: null, transparent: null, z: 0 } ); }; // Objects updates function updateObject( object ) { var geometry = object.geometry, geometryGroup, customAttributesDirty, material; if ( geometry instanceof THREE.BufferGeometry ) { setDirectBuffers( geometry, _gl.DYNAMIC_DRAW ); } else if ( object instanceof THREE.Mesh ) { // check all geometry groups for( var i = 0, il = geometry.geometryGroupsList.length; i < il; i ++ ) { geometryGroup = geometry.geometryGroupsList[ i ]; material = getBufferMaterial( object, geometryGroup ); if ( geometry.buffersNeedUpdate ) { initMeshBuffers( geometryGroup, object ); } customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); if ( geometry.verticesNeedUpdate || geometry.morphTargetsNeedUpdate || geometry.elementsNeedUpdate || geometry.uvsNeedUpdate || geometry.normalsNeedUpdate || geometry.colorsNeedUpdate || geometry.tangentsNeedUpdate || customAttributesDirty ) { setMeshBuffers( geometryGroup, object, _gl.DYNAMIC_DRAW, !geometry.dynamic, material ); } } geometry.verticesNeedUpdate = false; geometry.morphTargetsNeedUpdate = false; geometry.elementsNeedUpdate = false; geometry.uvsNeedUpdate = false; geometry.normalsNeedUpdate = false; geometry.colorsNeedUpdate = false; geometry.tangentsNeedUpdate = false; geometry.buffersNeedUpdate = false; material.attributes && clearCustomAttributes( material ); } else if ( object instanceof THREE.Line ) { material = getBufferMaterial( object, geometry ); customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || geometry.lineDistancesNeedUpdate || customAttributesDirty ) { setLineBuffers( geometry, _gl.DYNAMIC_DRAW ); } geometry.verticesNeedUpdate = false; geometry.colorsNeedUpdate = false; geometry.lineDistancesNeedUpdate = false; material.attributes && clearCustomAttributes( material ); } else if ( object instanceof THREE.ParticleSystem ) { material = getBufferMaterial( object, geometry ); customAttributesDirty = material.attributes && areCustomAttributesDirty( material ); if ( geometry.verticesNeedUpdate || geometry.colorsNeedUpdate || object.sortParticles || customAttributesDirty ) { setParticleBuffers( geometry, _gl.DYNAMIC_DRAW, object ); } geometry.verticesNeedUpdate = false; geometry.colorsNeedUpdate = false; material.attributes && clearCustomAttributes( material ); } }; // Objects updates - custom attributes check function areCustomAttributesDirty( material ) { for ( var a in material.attributes ) { if ( material.attributes[ a ].needsUpdate ) return true; } return false; }; function clearCustomAttributes( material ) { for ( var a in material.attributes ) { material.attributes[ a ].needsUpdate = false; } }; // Objects removal function removeObject( object, scene ) { if ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem || object instanceof THREE.Line ) { removeInstances( scene.__webglObjects, object ); } else if ( object instanceof THREE.Sprite ) { removeInstancesDirect( scene.__webglSprites, object ); } else if ( object instanceof THREE.LensFlare ) { removeInstancesDirect( scene.__webglFlares, object ); } else if ( object instanceof THREE.ImmediateRenderObject || object.immediateRenderCallback ) { removeInstances( scene.__webglObjectsImmediate, object ); } delete object.__webglActive; }; function removeInstances( objlist, object ) { for ( var o = objlist.length - 1; o >= 0; o -- ) { if ( objlist[ o ].object === object ) { objlist.splice( o, 1 ); } } }; function removeInstancesDirect( objlist, object ) { for ( var o = objlist.length - 1; o >= 0; o -- ) { if ( objlist[ o ] === object ) { objlist.splice( o, 1 ); } } }; // Materials this.initMaterial = function ( material, lights, fog, object ) { material.addEventListener( 'dispose', onMaterialDispose ); var u, a, identifiers, i, parameters, maxLightCount, maxBones, maxShadows, shaderID; if ( material instanceof THREE.MeshDepthMaterial ) { shaderID = 'depth'; } else if ( material instanceof THREE.MeshNormalMaterial ) { shaderID = 'normal'; } else if ( material instanceof THREE.MeshBasicMaterial ) { shaderID = 'basic'; } else if ( material instanceof THREE.MeshLambertMaterial ) { shaderID = 'lambert'; } else if ( material instanceof THREE.MeshPhongMaterial ) { shaderID = 'phong'; } else if ( material instanceof THREE.LineBasicMaterial ) { shaderID = 'basic'; } else if ( material instanceof THREE.LineDashedMaterial ) { shaderID = 'dashed'; } else if ( material instanceof THREE.ParticleSystemMaterial ) { shaderID = 'particle_basic'; } if ( shaderID ) { setMaterialShaders( material, THREE.ShaderLib[ shaderID ] ); } // heuristics to create shader parameters according to lights in the scene // (not to blow over maxLights budget) maxLightCount = allocateLights( lights ); maxShadows = allocateShadows( lights ); maxBones = allocateBones( object ); parameters = { map: !!material.map, envMap: !!material.envMap, lightMap: !!material.lightMap, bumpMap: !!material.bumpMap, normalMap: !!material.normalMap, specularMap: !!material.specularMap, vertexColors: material.vertexColors, fog: fog, useFog: material.fog, fogExp: fog instanceof THREE.FogExp2, sizeAttenuation: material.sizeAttenuation, skinning: material.skinning, maxBones: maxBones, useVertexTexture: _supportsBoneTextures && object && object.useVertexTexture, morphTargets: material.morphTargets, morphNormals: material.morphNormals, maxMorphTargets: this.maxMorphTargets, maxMorphNormals: this.maxMorphNormals, maxDirLights: maxLightCount.directional, maxPointLights: maxLightCount.point, maxSpotLights: maxLightCount.spot, maxHemiLights: maxLightCount.hemi, maxShadows: maxShadows, shadowMapEnabled: this.shadowMapEnabled && object.receiveShadow && maxShadows > 0, shadowMapType: this.shadowMapType, shadowMapDebug: this.shadowMapDebug, shadowMapCascade: this.shadowMapCascade, alphaTest: material.alphaTest, metal: material.metal, wrapAround: material.wrapAround, doubleSided: material.side === THREE.DoubleSide, flipSided: material.side === THREE.BackSide }; material.program = buildProgram( shaderID, material.fragmentShader, material.vertexShader, material.uniforms, material.attributes, material.defines, parameters, material.index0AttributeName ); var attributes = material.program.attributes; if ( material.morphTargets ) { material.numSupportedMorphTargets = 0; var id, base = "morphTarget"; for ( i = 0; i < this.maxMorphTargets; i ++ ) { id = base + i; if ( attributes[ id ] >= 0 ) { material.numSupportedMorphTargets ++; } } } if ( material.morphNormals ) { material.numSupportedMorphNormals = 0; var id, base = "morphNormal"; for ( i = 0; i < this.maxMorphNormals; i ++ ) { id = base + i; if ( attributes[ id ] >= 0 ) { material.numSupportedMorphNormals ++; } } } material.uniformsList = []; for ( u in material.uniforms ) { material.uniformsList.push( [ material.uniforms[ u ], u ] ); } }; function setMaterialShaders( material, shaders ) { material.uniforms = THREE.UniformsUtils.clone( shaders.uniforms ); material.vertexShader = shaders.vertexShader; material.fragmentShader = shaders.fragmentShader; }; function setProgram( camera, lights, fog, material, object ) { _usedTextureUnits = 0; if ( material.needsUpdate ) { if ( material.program ) deallocateMaterial( material ); _this.initMaterial( material, lights, fog, object ); material.needsUpdate = false; } if ( material.morphTargets ) { if ( ! object.__webglMorphTargetInfluences ) { object.__webglMorphTargetInfluences = new Float32Array( _this.maxMorphTargets ); } } var refreshMaterial = false; var program = material.program, p_uniforms = program.uniforms, m_uniforms = material.uniforms; if ( program !== _currentProgram ) { _gl.useProgram( program ); _currentProgram = program; refreshMaterial = true; } if ( material.id !== _currentMaterialId ) { _currentMaterialId = material.id; refreshMaterial = true; } if ( refreshMaterial || camera !== _currentCamera ) { _gl.uniformMatrix4fv( p_uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); if ( camera !== _currentCamera ) _currentCamera = camera; } // skinning uniforms must be set even if material didn't change // auto-setting of texture unit for bone texture must go before other textures // not sure why, but otherwise weird things happen if ( material.skinning ) { if ( _supportsBoneTextures && object.useVertexTexture ) { if ( p_uniforms.boneTexture !== null ) { var textureUnit = getTextureUnit(); _gl.uniform1i( p_uniforms.boneTexture, textureUnit ); _this.setTexture( object.boneTexture, textureUnit ); } if ( p_uniforms.boneTextureWidth !== null ) { _gl.uniform1i( p_uniforms.boneTextureWidth, object.boneTextureWidth ); } if ( p_uniforms.boneTextureHeight !== null ) { _gl.uniform1i( p_uniforms.boneTextureHeight, object.boneTextureHeight ); } } else { if ( p_uniforms.boneGlobalMatrices !== null ) { _gl.uniformMatrix4fv( p_uniforms.boneGlobalMatrices, false, object.boneMatrices ); } } } if ( refreshMaterial ) { // refresh uniforms common to several materials if ( fog && material.fog ) { refreshUniformsFog( m_uniforms, fog ); } if ( material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || material.lights ) { if ( _lightsNeedUpdate ) { setupLights( program, lights ); _lightsNeedUpdate = false; } refreshUniformsLights( m_uniforms, _lights ); } if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) { refreshUniformsCommon( m_uniforms, material ); } // refresh single material specific uniforms if ( material instanceof THREE.LineBasicMaterial ) { refreshUniformsLine( m_uniforms, material ); } else if ( material instanceof THREE.LineDashedMaterial ) { refreshUniformsLine( m_uniforms, material ); refreshUniformsDash( m_uniforms, material ); } else if ( material instanceof THREE.ParticleSystemMaterial ) { refreshUniformsParticle( m_uniforms, material ); } else if ( material instanceof THREE.MeshPhongMaterial ) { refreshUniformsPhong( m_uniforms, material ); } else if ( material instanceof THREE.MeshLambertMaterial ) { refreshUniformsLambert( m_uniforms, material ); } else if ( material instanceof THREE.MeshDepthMaterial ) { m_uniforms.mNear.value = camera.near; m_uniforms.mFar.value = camera.far; m_uniforms.opacity.value = material.opacity; } else if ( material instanceof THREE.MeshNormalMaterial ) { m_uniforms.opacity.value = material.opacity; } if ( object.receiveShadow && ! material._shadowPass ) { refreshUniformsShadow( m_uniforms, lights ); } // load common uniforms loadUniformsGeneric( program, material.uniformsList ); // load material specific uniforms // (shader material also gets them for the sake of genericity) if ( material instanceof THREE.ShaderMaterial || material instanceof THREE.MeshPhongMaterial || material.envMap ) { if ( p_uniforms.cameraPosition !== null ) { _vector3.setFromMatrixPosition( camera.matrixWorld ); _gl.uniform3f( p_uniforms.cameraPosition, _vector3.x, _vector3.y, _vector3.z ); } } if ( material instanceof THREE.MeshPhongMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.ShaderMaterial || material.skinning ) { if ( p_uniforms.viewMatrix !== null ) { _gl.uniformMatrix4fv( p_uniforms.viewMatrix, false, camera.matrixWorldInverse.elements ); } } } loadUniformsMatrices( p_uniforms, object ); if ( p_uniforms.modelMatrix !== null ) { _gl.uniformMatrix4fv( p_uniforms.modelMatrix, false, object.matrixWorld.elements ); } return program; }; // Uniforms (refresh uniforms objects) function refreshUniformsCommon ( uniforms, material ) { uniforms.opacity.value = material.opacity; if ( _this.gammaInput ) { uniforms.diffuse.value.copyGammaToLinear( material.color ); } else { uniforms.diffuse.value = material.color; } uniforms.map.value = material.map; uniforms.lightMap.value = material.lightMap; uniforms.specularMap.value = material.specularMap; if ( material.bumpMap ) { uniforms.bumpMap.value = material.bumpMap; uniforms.bumpScale.value = material.bumpScale; } if ( material.normalMap ) { uniforms.normalMap.value = material.normalMap; uniforms.normalScale.value.copy( material.normalScale ); } // uv repeat and offset setting priorities // 1. color map // 2. specular map // 3. normal map // 4. bump map var uvScaleMap; if ( material.map ) { uvScaleMap = material.map; } else if ( material.specularMap ) { uvScaleMap = material.specularMap; } else if ( material.normalMap ) { uvScaleMap = material.normalMap; } else if ( material.bumpMap ) { uvScaleMap = material.bumpMap; } if ( uvScaleMap !== undefined ) { var offset = uvScaleMap.offset; var repeat = uvScaleMap.repeat; uniforms.offsetRepeat.value.set( offset.x, offset.y, repeat.x, repeat.y ); } uniforms.envMap.value = material.envMap; uniforms.flipEnvMap.value = ( material.envMap instanceof THREE.WebGLRenderTargetCube ) ? 1 : -1; if ( _this.gammaInput ) { //uniforms.reflectivity.value = material.reflectivity * material.reflectivity; uniforms.reflectivity.value = material.reflectivity; } else { uniforms.reflectivity.value = material.reflectivity; } uniforms.refractionRatio.value = material.refractionRatio; uniforms.combine.value = material.combine; uniforms.useRefract.value = material.envMap && material.envMap.mapping instanceof THREE.CubeRefractionMapping; }; function refreshUniformsLine ( uniforms, material ) { uniforms.diffuse.value = material.color; uniforms.opacity.value = material.opacity; }; function refreshUniformsDash ( uniforms, material ) { uniforms.dashSize.value = material.dashSize; uniforms.totalSize.value = material.dashSize + material.gapSize; uniforms.scale.value = material.scale; }; function refreshUniformsParticle ( uniforms, material ) { uniforms.psColor.value = material.color; uniforms.opacity.value = material.opacity; uniforms.size.value = material.size; uniforms.scale.value = _canvas.height / 2.0; // TODO: Cache this. uniforms.map.value = material.map; }; function refreshUniformsFog ( uniforms, fog ) { uniforms.fogColor.value = fog.color; if ( fog instanceof THREE.Fog ) { uniforms.fogNear.value = fog.near; uniforms.fogFar.value = fog.far; } else if ( fog instanceof THREE.FogExp2 ) { uniforms.fogDensity.value = fog.density; } }; function refreshUniformsPhong ( uniforms, material ) { uniforms.shininess.value = material.shininess; if ( _this.gammaInput ) { uniforms.ambient.value.copyGammaToLinear( material.ambient ); uniforms.emissive.value.copyGammaToLinear( material.emissive ); uniforms.specular.value.copyGammaToLinear( material.specular ); } else { uniforms.ambient.value = material.ambient; uniforms.emissive.value = material.emissive; uniforms.specular.value = material.specular; } if ( material.wrapAround ) { uniforms.wrapRGB.value.copy( material.wrapRGB ); } }; function refreshUniformsLambert ( uniforms, material ) { if ( _this.gammaInput ) { uniforms.ambient.value.copyGammaToLinear( material.ambient ); uniforms.emissive.value.copyGammaToLinear( material.emissive ); } else { uniforms.ambient.value = material.ambient; uniforms.emissive.value = material.emissive; } if ( material.wrapAround ) { uniforms.wrapRGB.value.copy( material.wrapRGB ); } }; function refreshUniformsLights ( uniforms, lights ) { uniforms.ambientLightColor.value = lights.ambient; uniforms.directionalLightColor.value = lights.directional.colors; uniforms.directionalLightDirection.value = lights.directional.positions; uniforms.pointLightColor.value = lights.point.colors; uniforms.pointLightPosition.value = lights.point.positions; uniforms.pointLightDistance.value = lights.point.distances; uniforms.spotLightColor.value = lights.spot.colors; uniforms.spotLightPosition.value = lights.spot.positions; uniforms.spotLightDistance.value = lights.spot.distances; uniforms.spotLightDirection.value = lights.spot.directions; uniforms.spotLightAngleCos.value = lights.spot.anglesCos; uniforms.spotLightExponent.value = lights.spot.exponents; uniforms.hemisphereLightSkyColor.value = lights.hemi.skyColors; uniforms.hemisphereLightGroundColor.value = lights.hemi.groundColors; uniforms.hemisphereLightDirection.value = lights.hemi.positions; }; function refreshUniformsShadow ( uniforms, lights ) { if ( uniforms.shadowMatrix ) { var j = 0; for ( var i = 0, il = lights.length; i < il; i ++ ) { var light = lights[ i ]; if ( ! light.castShadow ) continue; if ( light instanceof THREE.SpotLight || ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) ) { uniforms.shadowMap.value[ j ] = light.shadowMap; uniforms.shadowMapSize.value[ j ] = light.shadowMapSize; uniforms.shadowMatrix.value[ j ] = light.shadowMatrix; uniforms.shadowDarkness.value[ j ] = light.shadowDarkness; uniforms.shadowBias.value[ j ] = light.shadowBias; j ++; } } } }; // Uniforms (load to GPU) function loadUniformsMatrices ( uniforms, object ) { _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, object._modelViewMatrix.elements ); if ( uniforms.normalMatrix ) { _gl.uniformMatrix3fv( uniforms.normalMatrix, false, object._normalMatrix.elements ); } }; function getTextureUnit() { var textureUnit = _usedTextureUnits; if ( textureUnit >= _maxTextures ) { console.warn( "WebGLRenderer: trying to use " + textureUnit + " texture units while this GPU supports only " + _maxTextures ); } _usedTextureUnits += 1; return textureUnit; }; function loadUniformsGeneric ( program, uniforms ) { var uniform, value, type, location, texture, textureUnit, i, il, j, jl, offset; for ( j = 0, jl = uniforms.length; j < jl; j ++ ) { location = program.uniforms[ uniforms[ j ][ 1 ] ]; if ( !location ) continue; uniform = uniforms[ j ][ 0 ]; type = uniform.type; value = uniform.value; if ( type === "i" ) { // single integer _gl.uniform1i( location, value ); } else if ( type === "f" ) { // single float _gl.uniform1f( location, value ); } else if ( type === "v2" ) { // single THREE.Vector2 _gl.uniform2f( location, value.x, value.y ); } else if ( type === "v3" ) { // single THREE.Vector3 _gl.uniform3f( location, value.x, value.y, value.z ); } else if ( type === "v4" ) { // single THREE.Vector4 _gl.uniform4f( location, value.x, value.y, value.z, value.w ); } else if ( type === "c" ) { // single THREE.Color _gl.uniform3f( location, value.r, value.g, value.b ); } else if ( type === "iv1" ) { // flat array of integers (JS or typed array) _gl.uniform1iv( location, value ); } else if ( type === "iv" ) { // flat array of integers with 3 x N size (JS or typed array) _gl.uniform3iv( location, value ); } else if ( type === "fv1" ) { // flat array of floats (JS or typed array) _gl.uniform1fv( location, value ); } else if ( type === "fv" ) { // flat array of floats with 3 x N size (JS or typed array) _gl.uniform3fv( location, value ); } else if ( type === "v2v" ) { // array of THREE.Vector2 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 2 * value.length ); } for ( i = 0, il = value.length; i < il; i ++ ) { offset = i * 2; uniform._array[ offset ] = value[ i ].x; uniform._array[ offset + 1 ] = value[ i ].y; } _gl.uniform2fv( location, uniform._array ); } else if ( type === "v3v" ) { // array of THREE.Vector3 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 3 * value.length ); } for ( i = 0, il = value.length; i < il; i ++ ) { offset = i * 3; uniform._array[ offset ] = value[ i ].x; uniform._array[ offset + 1 ] = value[ i ].y; uniform._array[ offset + 2 ] = value[ i ].z; } _gl.uniform3fv( location, uniform._array ); } else if ( type === "v4v" ) { // array of THREE.Vector4 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 4 * value.length ); } for ( i = 0, il = value.length; i < il; i ++ ) { offset = i * 4; uniform._array[ offset ] = value[ i ].x; uniform._array[ offset + 1 ] = value[ i ].y; uniform._array[ offset + 2 ] = value[ i ].z; uniform._array[ offset + 3 ] = value[ i ].w; } _gl.uniform4fv( location, uniform._array ); } else if ( type === "m4") { // single THREE.Matrix4 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 16 ); } value.flattenToArray( uniform._array ); _gl.uniformMatrix4fv( location, false, uniform._array ); } else if ( type === "m4v" ) { // array of THREE.Matrix4 if ( uniform._array === undefined ) { uniform._array = new Float32Array( 16 * value.length ); } for ( i = 0, il = value.length; i < il; i ++ ) { value[ i ].flattenToArrayOffset( uniform._array, i * 16 ); } _gl.uniformMatrix4fv( location, false, uniform._array ); } else if ( type === "t" ) { // single THREE.Texture (2d or cube) texture = value; textureUnit = getTextureUnit(); _gl.uniform1i( location, textureUnit ); if ( !texture ) continue; if ( texture.image instanceof Array && texture.image.length === 6 ) { setCubeTexture( texture, textureUnit ); } else if ( texture instanceof THREE.WebGLRenderTargetCube ) { setCubeTextureDynamic( texture, textureUnit ); } else { _this.setTexture( texture, textureUnit ); } } else if ( type === "tv" ) { // array of THREE.Texture (2d) if ( uniform._array === undefined ) { uniform._array = []; } for( i = 0, il = uniform.value.length; i < il; i ++ ) { uniform._array[ i ] = getTextureUnit(); } _gl.uniform1iv( location, uniform._array ); for( i = 0, il = uniform.value.length; i < il; i ++ ) { texture = uniform.value[ i ]; textureUnit = uniform._array[ i ]; if ( !texture ) continue; _this.setTexture( texture, textureUnit ); } } else { console.warn( 'THREE.WebGLRenderer: Unknown uniform type: ' + type ); } } }; function setupMatrices ( object, camera ) { object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); object._normalMatrix.getNormalMatrix( object._modelViewMatrix ); }; // function setColorGamma( array, offset, color, intensitySq ) { array[ offset ] = color.r * color.r * intensitySq; array[ offset + 1 ] = color.g * color.g * intensitySq; array[ offset + 2 ] = color.b * color.b * intensitySq; }; function setColorLinear( array, offset, color, intensity ) { array[ offset ] = color.r * intensity; array[ offset + 1 ] = color.g * intensity; array[ offset + 2 ] = color.b * intensity; }; function setupLights ( program, lights ) { var l, ll, light, n, r = 0, g = 0, b = 0, color, skyColor, groundColor, intensity, intensitySq, position, distance, zlights = _lights, dirColors = zlights.directional.colors, dirPositions = zlights.directional.positions, pointColors = zlights.point.colors, pointPositions = zlights.point.positions, pointDistances = zlights.point.distances, spotColors = zlights.spot.colors, spotPositions = zlights.spot.positions, spotDistances = zlights.spot.distances, spotDirections = zlights.spot.directions, spotAnglesCos = zlights.spot.anglesCos, spotExponents = zlights.spot.exponents, hemiSkyColors = zlights.hemi.skyColors, hemiGroundColors = zlights.hemi.groundColors, hemiPositions = zlights.hemi.positions, dirLength = 0, pointLength = 0, spotLength = 0, hemiLength = 0, dirCount = 0, pointCount = 0, spotCount = 0, hemiCount = 0, dirOffset = 0, pointOffset = 0, spotOffset = 0, hemiOffset = 0; for ( l = 0, ll = lights.length; l < ll; l ++ ) { light = lights[ l ]; if ( light.onlyShadow ) continue; color = light.color; intensity = light.intensity; distance = light.distance; if ( light instanceof THREE.AmbientLight ) { if ( ! light.visible ) continue; if ( _this.gammaInput ) { r += color.r * color.r; g += color.g * color.g; b += color.b * color.b; } else { r += color.r; g += color.g; b += color.b; } } else if ( light instanceof THREE.DirectionalLight ) { dirCount += 1; if ( ! light.visible ) continue; _direction.setFromMatrixPosition( light.matrixWorld ); _vector3.setFromMatrixPosition( light.target.matrixWorld ); _direction.sub( _vector3 ); _direction.normalize(); // skip lights with undefined direction // these create troubles in OpenGL (making pixel black) if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; dirOffset = dirLength * 3; dirPositions[ dirOffset ] = _direction.x; dirPositions[ dirOffset + 1 ] = _direction.y; dirPositions[ dirOffset + 2 ] = _direction.z; if ( _this.gammaInput ) { setColorGamma( dirColors, dirOffset, color, intensity * intensity ); } else { setColorLinear( dirColors, dirOffset, color, intensity ); } dirLength += 1; } else if ( light instanceof THREE.PointLight ) { pointCount += 1; if ( ! light.visible ) continue; pointOffset = pointLength * 3; if ( _this.gammaInput ) { setColorGamma( pointColors, pointOffset, color, intensity * intensity ); } else { setColorLinear( pointColors, pointOffset, color, intensity ); } _vector3.setFromMatrixPosition( light.matrixWorld ); pointPositions[ pointOffset ] = _vector3.x; pointPositions[ pointOffset + 1 ] = _vector3.y; pointPositions[ pointOffset + 2 ] = _vector3.z; pointDistances[ pointLength ] = distance; pointLength += 1; } else if ( light instanceof THREE.SpotLight ) { spotCount += 1; if ( ! light.visible ) continue; spotOffset = spotLength * 3; if ( _this.gammaInput ) { setColorGamma( spotColors, spotOffset, color, intensity * intensity ); } else { setColorLinear( spotColors, spotOffset, color, intensity ); } _vector3.setFromMatrixPosition( light.matrixWorld ); spotPositions[ spotOffset ] = _vector3.x; spotPositions[ spotOffset + 1 ] = _vector3.y; spotPositions[ spotOffset + 2 ] = _vector3.z; spotDistances[ spotLength ] = distance; _direction.copy( _vector3 ); _vector3.setFromMatrixPosition( light.target.matrixWorld ); _direction.sub( _vector3 ); _direction.normalize(); spotDirections[ spotOffset ] = _direction.x; spotDirections[ spotOffset + 1 ] = _direction.y; spotDirections[ spotOffset + 2 ] = _direction.z; spotAnglesCos[ spotLength ] = Math.cos( light.angle ); spotExponents[ spotLength ] = light.exponent; spotLength += 1; } else if ( light instanceof THREE.HemisphereLight ) { hemiCount += 1; if ( ! light.visible ) continue; _direction.setFromMatrixPosition( light.matrixWorld ); _direction.normalize(); // skip lights with undefined direction // these create troubles in OpenGL (making pixel black) if ( _direction.x === 0 && _direction.y === 0 && _direction.z === 0 ) continue; hemiOffset = hemiLength * 3; hemiPositions[ hemiOffset ] = _direction.x; hemiPositions[ hemiOffset + 1 ] = _direction.y; hemiPositions[ hemiOffset + 2 ] = _direction.z; skyColor = light.color; groundColor = light.groundColor; if ( _this.gammaInput ) { intensitySq = intensity * intensity; setColorGamma( hemiSkyColors, hemiOffset, skyColor, intensitySq ); setColorGamma( hemiGroundColors, hemiOffset, groundColor, intensitySq ); } else { setColorLinear( hemiSkyColors, hemiOffset, skyColor, intensity ); setColorLinear( hemiGroundColors, hemiOffset, groundColor, intensity ); } hemiLength += 1; } } // null eventual remains from removed lights // (this is to avoid if in shader) for ( l = dirLength * 3, ll = Math.max( dirColors.length, dirCount * 3 ); l < ll; l ++ ) dirColors[ l ] = 0.0; for ( l = pointLength * 3, ll = Math.max( pointColors.length, pointCount * 3 ); l < ll; l ++ ) pointColors[ l ] = 0.0; for ( l = spotLength * 3, ll = Math.max( spotColors.length, spotCount * 3 ); l < ll; l ++ ) spotColors[ l ] = 0.0; for ( l = hemiLength * 3, ll = Math.max( hemiSkyColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiSkyColors[ l ] = 0.0; for ( l = hemiLength * 3, ll = Math.max( hemiGroundColors.length, hemiCount * 3 ); l < ll; l ++ ) hemiGroundColors[ l ] = 0.0; zlights.directional.length = dirLength; zlights.point.length = pointLength; zlights.spot.length = spotLength; zlights.hemi.length = hemiLength; zlights.ambient[ 0 ] = r; zlights.ambient[ 1 ] = g; zlights.ambient[ 2 ] = b; }; // GL state setting this.setFaceCulling = function ( cullFace, frontFaceDirection ) { if ( cullFace === THREE.CullFaceNone ) { _gl.disable( _gl.CULL_FACE ); } else { if ( frontFaceDirection === THREE.FrontFaceDirectionCW ) { _gl.frontFace( _gl.CW ); } else { _gl.frontFace( _gl.CCW ); } if ( cullFace === THREE.CullFaceBack ) { _gl.cullFace( _gl.BACK ); } else if ( cullFace === THREE.CullFaceFront ) { _gl.cullFace( _gl.FRONT ); } else { _gl.cullFace( _gl.FRONT_AND_BACK ); } _gl.enable( _gl.CULL_FACE ); } }; this.setMaterialFaces = function ( material ) { var doubleSided = material.side === THREE.DoubleSide; var flipSided = material.side === THREE.BackSide; if ( _oldDoubleSided !== doubleSided ) { if ( doubleSided ) { _gl.disable( _gl.CULL_FACE ); } else { _gl.enable( _gl.CULL_FACE ); } _oldDoubleSided = doubleSided; } if ( _oldFlipSided !== flipSided ) { if ( flipSided ) { _gl.frontFace( _gl.CW ); } else { _gl.frontFace( _gl.CCW ); } _oldFlipSided = flipSided; } }; this.setDepthTest = function ( depthTest ) { if ( _oldDepthTest !== depthTest ) { if ( depthTest ) { _gl.enable( _gl.DEPTH_TEST ); } else { _gl.disable( _gl.DEPTH_TEST ); } _oldDepthTest = depthTest; } }; this.setDepthWrite = function ( depthWrite ) { if ( _oldDepthWrite !== depthWrite ) { _gl.depthMask( depthWrite ); _oldDepthWrite = depthWrite; } }; function setLineWidth ( width ) { if ( width !== _oldLineWidth ) { _gl.lineWidth( width ); _oldLineWidth = width; } }; function setPolygonOffset ( polygonoffset, factor, units ) { if ( _oldPolygonOffset !== polygonoffset ) { if ( polygonoffset ) { _gl.enable( _gl.POLYGON_OFFSET_FILL ); } else { _gl.disable( _gl.POLYGON_OFFSET_FILL ); } _oldPolygonOffset = polygonoffset; } if ( polygonoffset && ( _oldPolygonOffsetFactor !== factor || _oldPolygonOffsetUnits !== units ) ) { _gl.polygonOffset( factor, units ); _oldPolygonOffsetFactor = factor; _oldPolygonOffsetUnits = units; } }; this.setBlending = function ( blending, blendEquation, blendSrc, blendDst ) { if ( blending !== _oldBlending ) { if ( blending === THREE.NoBlending ) { _gl.disable( _gl.BLEND ); } else if ( blending === THREE.AdditiveBlending ) { _gl.enable( _gl.BLEND ); _gl.blendEquation( _gl.FUNC_ADD ); _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE ); } else if ( blending === THREE.SubtractiveBlending ) { // TODO: Find blendFuncSeparate() combination _gl.enable( _gl.BLEND ); _gl.blendEquation( _gl.FUNC_ADD ); _gl.blendFunc( _gl.ZERO, _gl.ONE_MINUS_SRC_COLOR ); } else if ( blending === THREE.MultiplyBlending ) { // TODO: Find blendFuncSeparate() combination _gl.enable( _gl.BLEND ); _gl.blendEquation( _gl.FUNC_ADD ); _gl.blendFunc( _gl.ZERO, _gl.SRC_COLOR ); } else if ( blending === THREE.CustomBlending ) { _gl.enable( _gl.BLEND ); } else { _gl.enable( _gl.BLEND ); _gl.blendEquationSeparate( _gl.FUNC_ADD, _gl.FUNC_ADD ); _gl.blendFuncSeparate( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA, _gl.ONE, _gl.ONE_MINUS_SRC_ALPHA ); } _oldBlending = blending; } if ( blending === THREE.CustomBlending ) { if ( blendEquation !== _oldBlendEquation ) { _gl.blendEquation( paramThreeToGL( blendEquation ) ); _oldBlendEquation = blendEquation; } if ( blendSrc !== _oldBlendSrc || blendDst !== _oldBlendDst ) { _gl.blendFunc( paramThreeToGL( blendSrc ), paramThreeToGL( blendDst ) ); _oldBlendSrc = blendSrc; _oldBlendDst = blendDst; } } else { _oldBlendEquation = null; _oldBlendSrc = null; _oldBlendDst = null; } }; // Defines function generateDefines ( defines ) { var value, chunk, chunks = []; for ( var d in defines ) { value = defines[ d ]; if ( value === false ) continue; chunk = "#define " + d + " " + value; chunks.push( chunk ); } return chunks.join( "\n" ); }; // Shaders function buildProgram( shaderID, fragmentShader, vertexShader, uniforms, attributes, defines, parameters, index0AttributeName ) { var p, pl, d, program, code; var chunks = []; // Generate code if ( shaderID ) { chunks.push( shaderID ); } else { chunks.push( fragmentShader ); chunks.push( vertexShader ); } for ( d in defines ) { chunks.push( d ); chunks.push( defines[ d ] ); } for ( p in parameters ) { chunks.push( p ); chunks.push( parameters[ p ] ); } code = chunks.join(); // Check if code has been already compiled for ( p = 0, pl = _programs.length; p < pl; p ++ ) { var programInfo = _programs[ p ]; if ( programInfo.code === code ) { // console.log( "Code already compiled." /*: \n\n" + code*/ ); programInfo.usedTimes ++; return programInfo.program; } } var shadowMapTypeDefine = "SHADOWMAP_TYPE_BASIC"; if ( parameters.shadowMapType === THREE.PCFShadowMap ) { shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF"; } else if ( parameters.shadowMapType === THREE.PCFSoftShadowMap ) { shadowMapTypeDefine = "SHADOWMAP_TYPE_PCF_SOFT"; } // console.log( "building new program " ); // var customDefines = generateDefines( defines ); // program = _gl.createProgram(); var prefix_vertex = [ "precision " + _precision + " float;", "precision " + _precision + " int;", customDefines, _supportsVertexTextures ? "#define VERTEX_TEXTURES" : "", _this.gammaInput ? "#define GAMMA_INPUT" : "", _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, "#define MAX_SHADOWS " + parameters.maxShadows, "#define MAX_BONES " + parameters.maxBones, parameters.map ? "#define USE_MAP" : "", parameters.envMap ? "#define USE_ENVMAP" : "", parameters.lightMap ? "#define USE_LIGHTMAP" : "", parameters.bumpMap ? "#define USE_BUMPMAP" : "", parameters.normalMap ? "#define USE_NORMALMAP" : "", parameters.specularMap ? "#define USE_SPECULARMAP" : "", parameters.vertexColors ? "#define USE_COLOR" : "", parameters.skinning ? "#define USE_SKINNING" : "", parameters.useVertexTexture ? "#define BONE_TEXTURE" : "", parameters.morphTargets ? "#define USE_MORPHTARGETS" : "", parameters.morphNormals ? "#define USE_MORPHNORMALS" : "", parameters.wrapAround ? "#define WRAP_AROUND" : "", parameters.doubleSided ? "#define DOUBLE_SIDED" : "", parameters.flipSided ? "#define FLIP_SIDED" : "", parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", parameters.sizeAttenuation ? "#define USE_SIZEATTENUATION" : "", "uniform mat4 modelMatrix;", "uniform mat4 modelViewMatrix;", "uniform mat4 projectionMatrix;", "uniform mat4 viewMatrix;", "uniform mat3 normalMatrix;", "uniform vec3 cameraPosition;", "attribute vec3 position;", "attribute vec3 normal;", "attribute vec2 uv;", "attribute vec2 uv2;", "#ifdef USE_COLOR", "attribute vec3 color;", "#endif", "#ifdef USE_MORPHTARGETS", "attribute vec3 morphTarget0;", "attribute vec3 morphTarget1;", "attribute vec3 morphTarget2;", "attribute vec3 morphTarget3;", "#ifdef USE_MORPHNORMALS", "attribute vec3 morphNormal0;", "attribute vec3 morphNormal1;", "attribute vec3 morphNormal2;", "attribute vec3 morphNormal3;", "#else", "attribute vec3 morphTarget4;", "attribute vec3 morphTarget5;", "attribute vec3 morphTarget6;", "attribute vec3 morphTarget7;", "#endif", "#endif", "#ifdef USE_SKINNING", "attribute vec4 skinIndex;", "attribute vec4 skinWeight;", "#endif", "" ].join("\n"); var prefix_fragment = [ "precision " + _precision + " float;", "precision " + _precision + " int;", ( parameters.bumpMap || parameters.normalMap ) ? "#extension GL_OES_standard_derivatives : enable" : "", customDefines, "#define MAX_DIR_LIGHTS " + parameters.maxDirLights, "#define MAX_POINT_LIGHTS " + parameters.maxPointLights, "#define MAX_SPOT_LIGHTS " + parameters.maxSpotLights, "#define MAX_HEMI_LIGHTS " + parameters.maxHemiLights, "#define MAX_SHADOWS " + parameters.maxShadows, parameters.alphaTest ? "#define ALPHATEST " + parameters.alphaTest: "", _this.gammaInput ? "#define GAMMA_INPUT" : "", _this.gammaOutput ? "#define GAMMA_OUTPUT" : "", ( parameters.useFog && parameters.fog ) ? "#define USE_FOG" : "", ( parameters.useFog && parameters.fogExp ) ? "#define FOG_EXP2" : "", parameters.map ? "#define USE_MAP" : "", parameters.envMap ? "#define USE_ENVMAP" : "", parameters.lightMap ? "#define USE_LIGHTMAP" : "", parameters.bumpMap ? "#define USE_BUMPMAP" : "", parameters.normalMap ? "#define USE_NORMALMAP" : "", parameters.specularMap ? "#define USE_SPECULARMAP" : "", parameters.vertexColors ? "#define USE_COLOR" : "", parameters.metal ? "#define METAL" : "", parameters.wrapAround ? "#define WRAP_AROUND" : "", parameters.doubleSided ? "#define DOUBLE_SIDED" : "", parameters.flipSided ? "#define FLIP_SIDED" : "", parameters.shadowMapEnabled ? "#define USE_SHADOWMAP" : "", parameters.shadowMapEnabled ? "#define " + shadowMapTypeDefine : "", parameters.shadowMapDebug ? "#define SHADOWMAP_DEBUG" : "", parameters.shadowMapCascade ? "#define SHADOWMAP_CASCADE" : "", "uniform mat4 viewMatrix;", "uniform vec3 cameraPosition;", "" ].join("\n"); var glVertexShader = getShader( "vertex", prefix_vertex + vertexShader ); var glFragmentShader = getShader( "fragment", prefix_fragment + fragmentShader ); _gl.attachShader( program, glVertexShader ); _gl.attachShader( program, glFragmentShader ); // Force a particular attribute to index 0. // because potentially expensive emulation is done by browser if attribute 0 is disabled. // And, color, for example is often automatically bound to index 0 so disabling it if ( index0AttributeName !== undefined ) { _gl.bindAttribLocation( program, 0, index0AttributeName ); } _gl.linkProgram( program ); if ( _gl.getProgramParameter( program, _gl.LINK_STATUS ) === false ) { console.error( 'Could not initialise shader' ); console.error( 'gl.VALIDATE_STATUS', _gl.getProgramParameter( program, _gl.VALIDATE_STATUS ) ); console.error( 'gl.getError()', _gl.getError() ); } if ( _gl.getProgramInfoLog( program ) !== '' ) { // console.error( 'gl.getProgramInfoLog()', _gl.getProgramInfoLog( program ) ); } // clean up _gl.deleteShader( glFragmentShader ); _gl.deleteShader( glVertexShader ); // console.log( prefix_fragment + fragmentShader ); // console.log( prefix_vertex + vertexShader ); program.uniforms = {}; program.attributes = {}; var identifiers, u, a, i; // cache uniform locations identifiers = [ 'viewMatrix', 'modelViewMatrix', 'projectionMatrix', 'normalMatrix', 'modelMatrix', 'cameraPosition', 'morphTargetInfluences' ]; if ( parameters.useVertexTexture ) { identifiers.push( 'boneTexture' ); identifiers.push( 'boneTextureWidth' ); identifiers.push( 'boneTextureHeight' ); } else { identifiers.push( 'boneGlobalMatrices' ); } for ( u in uniforms ) { identifiers.push( u ); } cacheUniformLocations( program, identifiers ); // cache attributes locations identifiers = [ "position", "normal", "uv", "uv2", "tangent", "color", "skinIndex", "skinWeight", "lineDistance" ]; for ( i = 0; i < parameters.maxMorphTargets; i ++ ) { identifiers.push( "morphTarget" + i ); } for ( i = 0; i < parameters.maxMorphNormals; i ++ ) { identifiers.push( "morphNormal" + i ); } for ( a in attributes ) { identifiers.push( a ); } cacheAttributeLocations( program, identifiers ); program.id = _programs_counter ++; _programs.push( { program: program, code: code, usedTimes: 1 } ); _this.info.memory.programs = _programs.length; return program; }; // Shader parameters cache function cacheUniformLocations ( program, identifiers ) { var i, l, id; for( i = 0, l = identifiers.length; i < l; i ++ ) { id = identifiers[ i ]; program.uniforms[ id ] = _gl.getUniformLocation( program, id ); } }; function cacheAttributeLocations ( program, identifiers ) { var i, l, id; for( i = 0, l = identifiers.length; i < l; i ++ ) { id = identifiers[ i ]; program.attributes[ id ] = _gl.getAttribLocation( program, id ); } }; function addLineNumbers ( string ) { var chunks = string.split( "\n" ); for ( var i = 0, il = chunks.length; i < il; i ++ ) { // Chrome reports shader errors on lines // starting counting from 1 chunks[ i ] = ( i + 1 ) + ": " + chunks[ i ]; } return chunks.join( "\n" ); }; function getShader ( type, string ) { var shader; if ( type === "fragment" ) { shader = _gl.createShader( _gl.FRAGMENT_SHADER ); } else if ( type === "vertex" ) { shader = _gl.createShader( _gl.VERTEX_SHADER ); } _gl.shaderSource( shader, string ); _gl.compileShader( shader ); if ( !_gl.getShaderParameter( shader, _gl.COMPILE_STATUS ) ) { console.error( _gl.getShaderInfoLog( shader ) ); console.error( addLineNumbers( string ) ); return null; } return shader; }; // Textures function setTextureParameters ( textureType, texture, isImagePowerOfTwo ) { if ( isImagePowerOfTwo ) { _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, paramThreeToGL( texture.wrapS ) ); _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, paramThreeToGL( texture.wrapT ) ); _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, paramThreeToGL( texture.magFilter ) ); _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, paramThreeToGL( texture.minFilter ) ); } else { _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterFallback( texture.magFilter ) ); _gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterFallback( texture.minFilter ) ); } if ( _glExtensionTextureFilterAnisotropic && texture.type !== THREE.FloatType ) { if ( texture.anisotropy > 1 || texture.__oldAnisotropy ) { _gl.texParameterf( textureType, _glExtensionTextureFilterAnisotropic.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, _maxAnisotropy ) ); texture.__oldAnisotropy = texture.anisotropy; } } }; this.setTexture = function ( texture, slot ) { if ( texture.needsUpdate ) { if ( ! texture.__webglInit ) { texture.__webglInit = true; texture.addEventListener( 'dispose', onTextureDispose ); texture.__webglTexture = _gl.createTexture(); _this.info.memory.textures ++; } _gl.activeTexture( _gl.TEXTURE0 + slot ); _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); _gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha ); _gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment ); var image = texture.image, isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), glFormat = paramThreeToGL( texture.format ), glType = paramThreeToGL( texture.type ); setTextureParameters( _gl.TEXTURE_2D, texture, isImagePowerOfTwo ); var mipmap, mipmaps = texture.mipmaps; if ( texture instanceof THREE.DataTexture ) { // use manually created mipmaps if available // if there are no manual mipmaps // set 0 level mipmap and then use GL to generate other mipmap levels if ( mipmaps.length > 0 && isImagePowerOfTwo ) { for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { mipmap = mipmaps[ i ]; _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } texture.generateMipmaps = false; } else { _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, image.width, image.height, 0, glFormat, glType, image.data ); } } else if ( texture instanceof THREE.CompressedTexture ) { for( var i = 0, il = mipmaps.length; i < il; i ++ ) { mipmap = mipmaps[ i ]; if ( texture.format!==THREE.RGBAFormat ) { _gl.compressedTexImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } else { _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } } } else { // regular Texture (image, video, canvas) // use manually created mipmaps if available // if there are no manual mipmaps // set 0 level mipmap and then use GL to generate other mipmap levels if ( mipmaps.length > 0 && isImagePowerOfTwo ) { for ( var i = 0, il = mipmaps.length; i < il; i ++ ) { mipmap = mipmaps[ i ]; _gl.texImage2D( _gl.TEXTURE_2D, i, glFormat, glFormat, glType, mipmap ); } texture.generateMipmaps = false; } else { _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, glFormat, glType, texture.image ); } } if ( texture.generateMipmaps && isImagePowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); texture.needsUpdate = false; if ( texture.onUpdate ) texture.onUpdate(); } else { _gl.activeTexture( _gl.TEXTURE0 + slot ); _gl.bindTexture( _gl.TEXTURE_2D, texture.__webglTexture ); } }; function clampToMaxSize ( image, maxSize ) { if ( image.width <= maxSize && image.height <= maxSize ) { return image; } // Warning: Scaling through the canvas will only work with images that use // premultiplied alpha. var maxDimension = Math.max( image.width, image.height ); var newWidth = Math.floor( image.width * maxSize / maxDimension ); var newHeight = Math.floor( image.height * maxSize / maxDimension ); var canvas = document.createElement( 'canvas' ); canvas.width = newWidth; canvas.height = newHeight; var ctx = canvas.getContext( "2d" ); ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, newWidth, newHeight ); return canvas; } function setCubeTexture ( texture, slot ) { if ( texture.image.length === 6 ) { if ( texture.needsUpdate ) { if ( ! texture.image.__webglTextureCube ) { texture.addEventListener( 'dispose', onTextureDispose ); texture.image.__webglTextureCube = _gl.createTexture(); _this.info.memory.textures ++; } _gl.activeTexture( _gl.TEXTURE0 + slot ); _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); _gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY ); var isCompressed = texture instanceof THREE.CompressedTexture; var cubeImage = []; for ( var i = 0; i < 6; i ++ ) { if ( _this.autoScaleCubemaps && ! isCompressed ) { cubeImage[ i ] = clampToMaxSize( texture.image[ i ], _maxCubemapSize ); } else { cubeImage[ i ] = texture.image[ i ]; } } var image = cubeImage[ 0 ], isImagePowerOfTwo = THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height ), glFormat = paramThreeToGL( texture.format ), glType = paramThreeToGL( texture.type ); setTextureParameters( _gl.TEXTURE_CUBE_MAP, texture, isImagePowerOfTwo ); for ( var i = 0; i < 6; i ++ ) { if( !isCompressed ) { _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, glFormat, glType, cubeImage[ i ] ); } else { var mipmap, mipmaps = cubeImage[ i ].mipmaps; for( var j = 0, jl = mipmaps.length; j < jl; j ++ ) { mipmap = mipmaps[ j ]; if ( texture.format!==THREE.RGBAFormat ) { _gl.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, mipmap.data ); } else { _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data ); } } } } if ( texture.generateMipmaps && isImagePowerOfTwo ) { _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); } texture.needsUpdate = false; if ( texture.onUpdate ) texture.onUpdate(); } else { _gl.activeTexture( _gl.TEXTURE0 + slot ); _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.image.__webglTextureCube ); } } }; function setCubeTextureDynamic ( texture, slot ) { _gl.activeTexture( _gl.TEXTURE0 + slot ); _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, texture.__webglTexture ); }; // Render targets function setupFrameBuffer ( framebuffer, renderTarget, textureTarget ) { _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); _gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureTarget, renderTarget.__webglTexture, 0 ); }; function setupRenderBuffer ( renderbuffer, renderTarget ) { _gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer ); if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_COMPONENT16, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); /* For some reason this is not working. Defaulting to RGBA4. } else if( ! renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.STENCIL_INDEX8, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); */ } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.DEPTH_STENCIL, renderTarget.width, renderTarget.height ); _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderbuffer ); } else { _gl.renderbufferStorage( _gl.RENDERBUFFER, _gl.RGBA4, renderTarget.width, renderTarget.height ); } }; this.setRenderTarget = function ( renderTarget ) { var isCube = ( renderTarget instanceof THREE.WebGLRenderTargetCube ); if ( renderTarget && ! renderTarget.__webglFramebuffer ) { if ( renderTarget.depthBuffer === undefined ) renderTarget.depthBuffer = true; if ( renderTarget.stencilBuffer === undefined ) renderTarget.stencilBuffer = true; renderTarget.addEventListener( 'dispose', onRenderTargetDispose ); renderTarget.__webglTexture = _gl.createTexture(); _this.info.memory.textures ++; // Setup texture, create render and frame buffers var isTargetPowerOfTwo = THREE.Math.isPowerOfTwo( renderTarget.width ) && THREE.Math.isPowerOfTwo( renderTarget.height ), glFormat = paramThreeToGL( renderTarget.format ), glType = paramThreeToGL( renderTarget.type ); if ( isCube ) { renderTarget.__webglFramebuffer = []; renderTarget.__webglRenderbuffer = []; _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); setTextureParameters( _gl.TEXTURE_CUBE_MAP, renderTarget, isTargetPowerOfTwo ); for ( var i = 0; i < 6; i ++ ) { renderTarget.__webglFramebuffer[ i ] = _gl.createFramebuffer(); renderTarget.__webglRenderbuffer[ i ] = _gl.createRenderbuffer(); _gl.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); setupFrameBuffer( renderTarget.__webglFramebuffer[ i ], renderTarget, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i ); setupRenderBuffer( renderTarget.__webglRenderbuffer[ i ], renderTarget ); } if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); } else { renderTarget.__webglFramebuffer = _gl.createFramebuffer(); if ( renderTarget.shareDepthFrom ) { renderTarget.__webglRenderbuffer = renderTarget.shareDepthFrom.__webglRenderbuffer; } else { renderTarget.__webglRenderbuffer = _gl.createRenderbuffer(); } _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); setTextureParameters( _gl.TEXTURE_2D, renderTarget, isTargetPowerOfTwo ); _gl.texImage2D( _gl.TEXTURE_2D, 0, glFormat, renderTarget.width, renderTarget.height, 0, glFormat, glType, null ); setupFrameBuffer( renderTarget.__webglFramebuffer, renderTarget, _gl.TEXTURE_2D ); if ( renderTarget.shareDepthFrom ) { if ( renderTarget.depthBuffer && ! renderTarget.stencilBuffer ) { _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); } else if ( renderTarget.depthBuffer && renderTarget.stencilBuffer ) { _gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.RENDERBUFFER, renderTarget.__webglRenderbuffer ); } } else { setupRenderBuffer( renderTarget.__webglRenderbuffer, renderTarget ); } if ( isTargetPowerOfTwo ) _gl.generateMipmap( _gl.TEXTURE_2D ); } // Release everything if ( isCube ) { _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); } else { _gl.bindTexture( _gl.TEXTURE_2D, null ); } _gl.bindRenderbuffer( _gl.RENDERBUFFER, null ); _gl.bindFramebuffer( _gl.FRAMEBUFFER, null ); } var framebuffer, width, height, vx, vy; if ( renderTarget ) { if ( isCube ) { framebuffer = renderTarget.__webglFramebuffer[ renderTarget.activeCubeFace ]; } else { framebuffer = renderTarget.__webglFramebuffer; } width = renderTarget.width; height = renderTarget.height; vx = 0; vy = 0; } else { framebuffer = null; width = _viewportWidth; height = _viewportHeight; vx = _viewportX; vy = _viewportY; } if ( framebuffer !== _currentFramebuffer ) { _gl.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer ); _gl.viewport( vx, vy, width, height ); _currentFramebuffer = framebuffer; } _currentWidth = width; _currentHeight = height; }; function updateRenderTargetMipmap ( renderTarget ) { if ( renderTarget instanceof THREE.WebGLRenderTargetCube ) { _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, renderTarget.__webglTexture ); _gl.generateMipmap( _gl.TEXTURE_CUBE_MAP ); _gl.bindTexture( _gl.TEXTURE_CUBE_MAP, null ); } else { _gl.bindTexture( _gl.TEXTURE_2D, renderTarget.__webglTexture ); _gl.generateMipmap( _gl.TEXTURE_2D ); _gl.bindTexture( _gl.TEXTURE_2D, null ); } }; // Fallback filters for non-power-of-2 textures function filterFallback ( f ) { if ( f === THREE.NearestFilter || f === THREE.NearestMipMapNearestFilter || f === THREE.NearestMipMapLinearFilter ) { return _gl.NEAREST; } return _gl.LINEAR; }; // Map three.js constants to WebGL constants function paramThreeToGL ( p ) { if ( p === THREE.RepeatWrapping ) return _gl.REPEAT; if ( p === THREE.ClampToEdgeWrapping ) return _gl.CLAMP_TO_EDGE; if ( p === THREE.MirroredRepeatWrapping ) return _gl.MIRRORED_REPEAT; if ( p === THREE.NearestFilter ) return _gl.NEAREST; if ( p === THREE.NearestMipMapNearestFilter ) return _gl.NEAREST_MIPMAP_NEAREST; if ( p === THREE.NearestMipMapLinearFilter ) return _gl.NEAREST_MIPMAP_LINEAR; if ( p === THREE.LinearFilter ) return _gl.LINEAR; if ( p === THREE.LinearMipMapNearestFilter ) return _gl.LINEAR_MIPMAP_NEAREST; if ( p === THREE.LinearMipMapLinearFilter ) return _gl.LINEAR_MIPMAP_LINEAR; if ( p === THREE.UnsignedByteType ) return _gl.UNSIGNED_BYTE; if ( p === THREE.UnsignedShort4444Type ) return _gl.UNSIGNED_SHORT_4_4_4_4; if ( p === THREE.UnsignedShort5551Type ) return _gl.UNSIGNED_SHORT_5_5_5_1; if ( p === THREE.UnsignedShort565Type ) return _gl.UNSIGNED_SHORT_5_6_5; if ( p === THREE.ByteType ) return _gl.BYTE; if ( p === THREE.ShortType ) return _gl.SHORT; if ( p === THREE.UnsignedShortType ) return _gl.UNSIGNED_SHORT; if ( p === THREE.IntType ) return _gl.INT; if ( p === THREE.UnsignedIntType ) return _gl.UNSIGNED_INT; if ( p === THREE.FloatType ) return _gl.FLOAT; if ( p === THREE.AlphaFormat ) return _gl.ALPHA; if ( p === THREE.RGBFormat ) return _gl.RGB; if ( p === THREE.RGBAFormat ) return _gl.RGBA; if ( p === THREE.LuminanceFormat ) return _gl.LUMINANCE; if ( p === THREE.LuminanceAlphaFormat ) return _gl.LUMINANCE_ALPHA; if ( p === THREE.AddEquation ) return _gl.FUNC_ADD; if ( p === THREE.SubtractEquation ) return _gl.FUNC_SUBTRACT; if ( p === THREE.ReverseSubtractEquation ) return _gl.FUNC_REVERSE_SUBTRACT; if ( p === THREE.ZeroFactor ) return _gl.ZERO; if ( p === THREE.OneFactor ) return _gl.ONE; if ( p === THREE.SrcColorFactor ) return _gl.SRC_COLOR; if ( p === THREE.OneMinusSrcColorFactor ) return _gl.ONE_MINUS_SRC_COLOR; if ( p === THREE.SrcAlphaFactor ) return _gl.SRC_ALPHA; if ( p === THREE.OneMinusSrcAlphaFactor ) return _gl.ONE_MINUS_SRC_ALPHA; if ( p === THREE.DstAlphaFactor ) return _gl.DST_ALPHA; if ( p === THREE.OneMinusDstAlphaFactor ) return _gl.ONE_MINUS_DST_ALPHA; if ( p === THREE.DstColorFactor ) return _gl.DST_COLOR; if ( p === THREE.OneMinusDstColorFactor ) return _gl.ONE_MINUS_DST_COLOR; if ( p === THREE.SrcAlphaSaturateFactor ) return _gl.SRC_ALPHA_SATURATE; if ( _glExtensionCompressedTextureS3TC !== undefined ) { if ( p === THREE.RGB_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGB_S3TC_DXT1_EXT; if ( p === THREE.RGBA_S3TC_DXT1_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT1_EXT; if ( p === THREE.RGBA_S3TC_DXT3_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT3_EXT; if ( p === THREE.RGBA_S3TC_DXT5_Format ) return _glExtensionCompressedTextureS3TC.COMPRESSED_RGBA_S3TC_DXT5_EXT; } return 0; }; // Allocations function allocateBones ( object ) { if ( _supportsBoneTextures && object && object.useVertexTexture ) { return 1024; } else { // default for when object is not specified // ( for example when prebuilding shader // to be used with multiple objects ) // // - leave some extra space for other uniforms // - limit here is ANGLE's 254 max uniform vectors // (up to 54 should be safe) var nVertexUniforms = _gl.getParameter( _gl.MAX_VERTEX_UNIFORM_VECTORS ); var nVertexMatrices = Math.floor( ( nVertexUniforms - 20 ) / 4 ); var maxBones = nVertexMatrices; if ( object !== undefined && object instanceof THREE.SkinnedMesh ) { maxBones = Math.min( object.bones.length, maxBones ); if ( maxBones < object.bones.length ) { console.warn( "WebGLRenderer: too many bones - " + object.bones.length + ", this GPU supports just " + maxBones + " (try OpenGL instead of ANGLE)" ); } } return maxBones; } }; function allocateLights( lights ) { var dirLights = 0; var pointLights = 0; var spotLights = 0; var hemiLights = 0; for ( var l = 0, ll = lights.length; l < ll; l ++ ) { var light = lights[ l ]; if ( light.onlyShadow || light.visible === false ) continue; if ( light instanceof THREE.DirectionalLight ) dirLights ++; if ( light instanceof THREE.PointLight ) pointLights ++; if ( light instanceof THREE.SpotLight ) spotLights ++; if ( light instanceof THREE.HemisphereLight ) hemiLights ++; } return { 'directional' : dirLights, 'point' : pointLights, 'spot': spotLights, 'hemi': hemiLights }; }; function allocateShadows( lights ) { var maxShadows = 0; for ( var l = 0, ll = lights.length; l < ll; l++ ) { var light = lights[ l ]; if ( ! light.castShadow ) continue; if ( light instanceof THREE.SpotLight ) maxShadows ++; if ( light instanceof THREE.DirectionalLight && ! light.shadowCascade ) maxShadows ++; } return maxShadows; }; // Initialization function initGL() { try { var attributes = { alpha: _alpha, premultipliedAlpha: _premultipliedAlpha, antialias: _antialias, stencil: _stencil, preserveDrawingBuffer: _preserveDrawingBuffer }; _gl = _context || _canvas.getContext( 'webgl', attributes ) || _canvas.getContext( 'experimental-webgl', attributes ); if ( _gl === null ) { throw 'Error creating WebGL context.'; } } catch ( error ) { console.error( error ); } _glExtensionTextureFloat = _gl.getExtension( 'OES_texture_float' ); _glExtensionTextureFloatLinear = _gl.getExtension( 'OES_texture_float_linear' ); _glExtensionStandardDerivatives = _gl.getExtension( 'OES_standard_derivatives' ); _glExtensionTextureFilterAnisotropic = _gl.getExtension( 'EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || _gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' ); _glExtensionCompressedTextureS3TC = _gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || _gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' ); if ( ! _glExtensionTextureFloat ) { console.log( 'THREE.WebGLRenderer: Float textures not supported.' ); } if ( ! _glExtensionStandardDerivatives ) { console.log( 'THREE.WebGLRenderer: Standard derivatives not supported.' ); } if ( ! _glExtensionTextureFilterAnisotropic ) { console.log( 'THREE.WebGLRenderer: Anisotropic texture filtering not supported.' ); } if ( ! _glExtensionCompressedTextureS3TC ) { console.log( 'THREE.WebGLRenderer: S3TC compressed textures not supported.' ); } if ( _gl.getShaderPrecisionFormat === undefined ) { _gl.getShaderPrecisionFormat = function() { return { "rangeMin" : 1, "rangeMax" : 1, "precision" : 1 }; } } }; function setDefaultGLState () { _gl.clearColor( 0, 0, 0, 1 ); _gl.clearDepth( 1 ); _gl.clearStencil( 0 ); _gl.enable( _gl.DEPTH_TEST ); _gl.depthFunc( _gl.LEQUAL ); _gl.frontFace( _gl.CCW ); _gl.cullFace( _gl.BACK ); _gl.enable( _gl.CULL_FACE ); _gl.enable( _gl.BLEND ); _gl.blendEquation( _gl.FUNC_ADD ); _gl.blendFunc( _gl.SRC_ALPHA, _gl.ONE_MINUS_SRC_ALPHA ); _gl.viewport( _viewportX, _viewportY, _viewportWidth, _viewportHeight ); _gl.clearColor( _clearColor.r, _clearColor.g, _clearColor.b, _clearAlpha ); }; // default plugins (order is important) this.shadowMapPlugin = new THREE.ShadowMapPlugin(); this.addPrePlugin( this.shadowMapPlugin ); this.addPostPlugin( new THREE.SpritePlugin() ); this.addPostPlugin( new THREE.LensFlarePlugin() ); }; /** * @author szimek / https://github.com/szimek/ * @author alteredq / http://alteredqualia.com/ */ THREE.WebGLRenderTarget = function ( width, height, options ) { this.width = width; this.height = height; options = options || {}; this.wrapS = options.wrapS !== undefined ? options.wrapS : THREE.ClampToEdgeWrapping; this.wrapT = options.wrapT !== undefined ? options.wrapT : THREE.ClampToEdgeWrapping; this.magFilter = options.magFilter !== undefined ? options.magFilter : THREE.LinearFilter; this.minFilter = options.minFilter !== undefined ? options.minFilter : THREE.LinearMipMapLinearFilter; this.anisotropy = options.anisotropy !== undefined ? options.anisotropy : 1; this.offset = new THREE.Vector2( 0, 0 ); this.repeat = new THREE.Vector2( 1, 1 ); this.format = options.format !== undefined ? options.format : THREE.RGBAFormat; this.type = options.type !== undefined ? options.type : THREE.UnsignedByteType; this.depthBuffer = options.depthBuffer !== undefined ? options.depthBuffer : true; this.stencilBuffer = options.stencilBuffer !== undefined ? options.stencilBuffer : true; this.generateMipmaps = true; this.shareDepthFrom = null; }; THREE.WebGLRenderTarget.prototype = { constructor: THREE.WebGLRenderTarget, clone: function () { var tmp = new THREE.WebGLRenderTarget( this.width, this.height ); tmp.wrapS = this.wrapS; tmp.wrapT = this.wrapT; tmp.magFilter = this.magFilter; tmp.minFilter = this.minFilter; tmp.anisotropy = this.anisotropy; tmp.offset.copy( this.offset ); tmp.repeat.copy( this.repeat ); tmp.format = this.format; tmp.type = this.type; tmp.depthBuffer = this.depthBuffer; tmp.stencilBuffer = this.stencilBuffer; tmp.generateMipmaps = this.generateMipmaps; tmp.shareDepthFrom = this.shareDepthFrom; return tmp; }, dispose: function () { this.dispatchEvent( { type: 'dispose' } ); } }; THREE.EventDispatcher.prototype.apply( THREE.WebGLRenderTarget.prototype ); /** * @author alteredq / http://alteredqualia.com */ THREE.WebGLRenderTargetCube = function ( width, height, options ) { THREE.WebGLRenderTarget.call( this, width, height, options ); this.activeCubeFace = 0; // PX 0, NX 1, PY 2, NY 3, PZ 4, NZ 5 }; THREE.WebGLRenderTargetCube.prototype = Object.create( THREE.WebGLRenderTarget.prototype ); /** * @author mrdoob / http://mrdoob.com/ */ THREE.RenderableVertex = function () { this.position = new THREE.Vector3(); this.positionWorld = new THREE.Vector3(); this.positionScreen = new THREE.Vector4(); this.visible = true; }; THREE.RenderableVertex.prototype.copy = function ( vertex ) { this.positionWorld.copy( vertex.positionWorld ); this.positionScreen.copy( vertex.positionScreen ); }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.RenderableFace = function () { this.id = 0; this.v1 = new THREE.RenderableVertex(); this.v2 = new THREE.RenderableVertex(); this.v3 = new THREE.RenderableVertex(); this.centroidModel = new THREE.Vector3(); this.normalModel = new THREE.Vector3(); this.vertexNormalsModel = [ new THREE.Vector3(), new THREE.Vector3(), new THREE.Vector3() ]; this.vertexNormalsLength = 0; this.color = null; this.material = null; this.uvs = [[]]; this.z = 0; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.RenderableObject = function () { this.id = 0; this.object = null; this.z = 0; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.RenderableSprite = function () { this.id = 0; this.object = null; this.x = 0; this.y = 0; this.z = 0; this.rotation = 0; this.scale = new THREE.Vector2(); this.material = null; }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.RenderableLine = function () { this.id = 0; this.v1 = new THREE.RenderableVertex(); this.v2 = new THREE.RenderableVertex(); this.vertexColors = [ new THREE.Color(), new THREE.Color() ]; this.material = null; this.z = 0; }; /** * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.GeometryUtils = { // Merge two geometries or geometry and geometry from object (using object's transform) merge: function ( geometry1, object2 /* mesh | geometry */, materialIndexOffset ) { var matrix, normalMatrix, vertexOffset = geometry1.vertices.length, uvPosition = geometry1.faceVertexUvs[ 0 ].length, geometry2 = object2 instanceof THREE.Mesh ? object2.geometry : object2, vertices1 = geometry1.vertices, vertices2 = geometry2.vertices, faces1 = geometry1.faces, faces2 = geometry2.faces, uvs1 = geometry1.faceVertexUvs[ 0 ], uvs2 = geometry2.faceVertexUvs[ 0 ]; if ( materialIndexOffset === undefined ) materialIndexOffset = 0; if ( object2 instanceof THREE.Mesh ) { object2.matrixAutoUpdate && object2.updateMatrix(); matrix = object2.matrix; normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix ); } // vertices for ( var i = 0, il = vertices2.length; i < il; i ++ ) { var vertex = vertices2[ i ]; var vertexCopy = vertex.clone(); if ( matrix ) vertexCopy.applyMatrix4( matrix ); vertices1.push( vertexCopy ); } // faces for ( i = 0, il = faces2.length; i < il; i ++ ) { var face = faces2[ i ], faceCopy, normal, color, faceVertexNormals = face.vertexNormals, faceVertexColors = face.vertexColors; faceCopy = new THREE.Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset ); faceCopy.normal.copy( face.normal ); if ( normalMatrix ) { faceCopy.normal.applyMatrix3( normalMatrix ).normalize(); } for ( var j = 0, jl = faceVertexNormals.length; j < jl; j ++ ) { normal = faceVertexNormals[ j ].clone(); if ( normalMatrix ) { normal.applyMatrix3( normalMatrix ).normalize(); } faceCopy.vertexNormals.push( normal ); } faceCopy.color.copy( face.color ); for ( var j = 0, jl = faceVertexColors.length; j < jl; j ++ ) { color = faceVertexColors[ j ]; faceCopy.vertexColors.push( color.clone() ); } faceCopy.materialIndex = face.materialIndex + materialIndexOffset; faceCopy.centroid.copy( face.centroid ); if ( matrix ) { faceCopy.centroid.applyMatrix4( matrix ); } faces1.push( faceCopy ); } // uvs for ( i = 0, il = uvs2.length; i < il; i ++ ) { var uv = uvs2[ i ], uvCopy = []; for ( var j = 0, jl = uv.length; j < jl; j ++ ) { uvCopy.push( new THREE.Vector2( uv[ j ].x, uv[ j ].y ) ); } uvs1.push( uvCopy ); } }, // Get random point in triangle (via barycentric coordinates) // (uniform distribution) // http://www.cgafaq.info/wiki/Random_Point_In_Triangle randomPointInTriangle: function () { var vector = new THREE.Vector3(); return function ( vectorA, vectorB, vectorC ) { var point = new THREE.Vector3(); var a = THREE.Math.random16(); var b = THREE.Math.random16(); if ( ( a + b ) > 1 ) { a = 1 - a; b = 1 - b; } var c = 1 - a - b; point.copy( vectorA ); point.multiplyScalar( a ); vector.copy( vectorB ); vector.multiplyScalar( b ); point.add( vector ); vector.copy( vectorC ); vector.multiplyScalar( c ); point.add( vector ); return point; }; }(), // Get random point in face (triangle / quad) // (uniform distribution) randomPointInFace: function ( face, geometry, useCachedAreas ) { var vA, vB, vC, vD; vA = geometry.vertices[ face.a ]; vB = geometry.vertices[ face.b ]; vC = geometry.vertices[ face.c ]; return THREE.GeometryUtils.randomPointInTriangle( vA, vB, vC ); }, // Get uniformly distributed random points in mesh // - create array with cumulative sums of face areas // - pick random number from 0 to total area // - find corresponding place in area array by binary search // - get random point in face randomPointsInGeometry: function ( geometry, n ) { var face, i, faces = geometry.faces, vertices = geometry.vertices, il = faces.length, totalArea = 0, cumulativeAreas = [], vA, vB, vC, vD; // precompute face areas for ( i = 0; i < il; i ++ ) { face = faces[ i ]; vA = vertices[ face.a ]; vB = vertices[ face.b ]; vC = vertices[ face.c ]; face._area = THREE.GeometryUtils.triangleArea( vA, vB, vC ); totalArea += face._area; cumulativeAreas[ i ] = totalArea; } // binary search cumulative areas array function binarySearchIndices( value ) { function binarySearch( start, end ) { // return closest larger index // if exact number is not found if ( end < start ) return start; var mid = start + Math.floor( ( end - start ) / 2 ); if ( cumulativeAreas[ mid ] > value ) { return binarySearch( start, mid - 1 ); } else if ( cumulativeAreas[ mid ] < value ) { return binarySearch( mid + 1, end ); } else { return mid; } } var result = binarySearch( 0, cumulativeAreas.length - 1 ) return result; } // pick random face weighted by face area var r, index, result = []; var stats = {}; for ( i = 0; i < n; i ++ ) { r = THREE.Math.random16() * totalArea; index = binarySearchIndices( r ); result[ i ] = THREE.GeometryUtils.randomPointInFace( faces[ index ], geometry, true ); if ( ! stats[ index ] ) { stats[ index ] = 1; } else { stats[ index ] += 1; } } return result; }, // Get triangle area (half of parallelogram) // http://mathworld.wolfram.com/TriangleArea.html triangleArea: function () { var vector1 = new THREE.Vector3(); var vector2 = new THREE.Vector3(); return function ( vectorA, vectorB, vectorC ) { vector1.subVectors( vectorB, vectorA ); vector2.subVectors( vectorC, vectorA ); vector1.cross( vector2 ); return 0.5 * vector1.length(); }; }(), // Center geometry so that 0,0,0 is in center of bounding box center: function ( geometry ) { geometry.computeBoundingBox(); var bb = geometry.boundingBox; var offset = new THREE.Vector3(); offset.addVectors( bb.min, bb.max ); offset.multiplyScalar( -0.5 ); geometry.applyMatrix( new THREE.Matrix4().makeTranslation( offset.x, offset.y, offset.z ) ); geometry.computeBoundingBox(); return offset; }, triangulateQuads: function ( geometry ) { var i, il, j, jl; var faces = []; var faceVertexUvs = []; for ( i = 0, il = geometry.faceVertexUvs.length; i < il; i ++ ) { faceVertexUvs[ i ] = []; } for ( i = 0, il = geometry.faces.length; i < il; i ++ ) { var face = geometry.faces[ i ]; faces.push( face ); for ( j = 0, jl = geometry.faceVertexUvs.length; j < jl; j ++ ) { faceVertexUvs[ j ].push( geometry.faceVertexUvs[ j ][ i ] ); } } geometry.faces = faces; geometry.faceVertexUvs = faceVertexUvs; geometry.computeCentroids(); geometry.computeFaceNormals(); geometry.computeVertexNormals(); if ( geometry.hasTangents ) geometry.computeTangents(); } }; /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.ImageUtils = { crossOrigin: undefined, loadTexture: function ( url, mapping, onLoad, onError ) { var loader = new THREE.ImageLoader(); loader.crossOrigin = this.crossOrigin; var texture = new THREE.Texture( undefined, mapping ); var image = loader.load( url, function () { texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } ); texture.image = image; texture.sourceFile = url; return texture; }, loadCompressedTexture: function ( url, mapping, onLoad, onError ) { var texture = new THREE.CompressedTexture(); texture.mapping = mapping; var request = new XMLHttpRequest(); request.onload = function () { var buffer = request.response; var dds = THREE.ImageUtils.parseDDS( buffer, true ); texture.format = dds.format; texture.mipmaps = dds.mipmaps; texture.image.width = dds.width; texture.image.height = dds.height; // gl.generateMipmap fails for compressed textures // mipmaps must be embedded in the DDS file // or texture filters must not use mipmapping texture.generateMipmaps = false; texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } request.onerror = onError; request.open( 'GET', url, true ); request.responseType = "arraybuffer"; request.send( null ); return texture; }, loadTextureCube: function ( array, mapping, onLoad, onError ) { var images = []; images.loadCount = 0; var texture = new THREE.Texture(); texture.image = images; if ( mapping !== undefined ) texture.mapping = mapping; // no flipping needed for cube textures texture.flipY = false; for ( var i = 0, il = array.length; i < il; ++ i ) { var cubeImage = new Image(); images[ i ] = cubeImage; cubeImage.onload = function () { images.loadCount += 1; if ( images.loadCount === 6 ) { texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } }; cubeImage.onerror = onError; cubeImage.crossOrigin = this.crossOrigin; cubeImage.src = array[ i ]; } return texture; }, loadCompressedTextureCube: function ( array, mapping, onLoad, onError ) { var images = []; images.loadCount = 0; var texture = new THREE.CompressedTexture(); texture.image = images; if ( mapping !== undefined ) texture.mapping = mapping; // no flipping for cube textures // (also flipping doesn't work for compressed textures ) texture.flipY = false; // can't generate mipmaps for compressed textures // mips must be embedded in DDS files texture.generateMipmaps = false; var generateCubeFaceCallback = function ( rq, img ) { return function () { var buffer = rq.response; var dds = THREE.ImageUtils.parseDDS( buffer, true ); img.format = dds.format; img.mipmaps = dds.mipmaps; img.width = dds.width; img.height = dds.height; images.loadCount += 1; if ( images.loadCount === 6 ) { texture.format = dds.format; texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } } } // compressed cubemap textures as 6 separate DDS files if ( array instanceof Array ) { for ( var i = 0, il = array.length; i < il; ++ i ) { var cubeImage = {}; images[ i ] = cubeImage; var request = new XMLHttpRequest(); request.onload = generateCubeFaceCallback( request, cubeImage ); request.onerror = onError; var url = array[ i ]; request.open( 'GET', url, true ); request.responseType = "arraybuffer"; request.send( null ); } // compressed cubemap texture stored in a single DDS file } else { var url = array; var request = new XMLHttpRequest(); request.onload = function( ) { var buffer = request.response; var dds = THREE.ImageUtils.parseDDS( buffer, true ); if ( dds.isCubemap ) { var faces = dds.mipmaps.length / dds.mipmapCount; for ( var f = 0; f < faces; f ++ ) { images[ f ] = { mipmaps : [] }; for ( var i = 0; i < dds.mipmapCount; i ++ ) { images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); images[ f ].format = dds.format; images[ f ].width = dds.width; images[ f ].height = dds.height; } } texture.format = dds.format; texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } } request.onerror = onError; request.open( 'GET', url, true ); request.responseType = "arraybuffer"; request.send( null ); } return texture; }, loadDDSTexture: function ( url, mapping, onLoad, onError ) { var images = []; images.loadCount = 0; var texture = new THREE.CompressedTexture(); texture.image = images; if ( mapping !== undefined ) texture.mapping = mapping; // no flipping for cube textures // (also flipping doesn't work for compressed textures ) texture.flipY = false; // can't generate mipmaps for compressed textures // mips must be embedded in DDS files texture.generateMipmaps = false; { var request = new XMLHttpRequest(); request.onload = function( ) { var buffer = request.response; var dds = THREE.ImageUtils.parseDDS( buffer, true ); if ( dds.isCubemap ) { var faces = dds.mipmaps.length / dds.mipmapCount; for ( var f = 0; f < faces; f ++ ) { images[ f ] = { mipmaps : [] }; for ( var i = 0; i < dds.mipmapCount; i ++ ) { images[ f ].mipmaps.push( dds.mipmaps[ f * dds.mipmapCount + i ] ); images[ f ].format = dds.format; images[ f ].width = dds.width; images[ f ].height = dds.height; } } } else { texture.image.width = dds.width; texture.image.height = dds.height; texture.mipmaps = dds.mipmaps; } texture.format = dds.format; texture.needsUpdate = true; if ( onLoad ) onLoad( texture ); } request.onerror = onError; request.open( 'GET', url, true ); request.responseType = "arraybuffer"; request.send( null ); } return texture; }, parseDDS: function ( buffer, loadMipmaps ) { var dds = { mipmaps: [], width: 0, height: 0, format: null, mipmapCount: 1 }; // Adapted from @toji's DDS utils // https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js // All values and structures referenced from: // http://msdn.microsoft.com/en-us/library/bb943991.aspx/ var DDS_MAGIC = 0x20534444; var DDSD_CAPS = 0x1, DDSD_HEIGHT = 0x2, DDSD_WIDTH = 0x4, DDSD_PITCH = 0x8, DDSD_PIXELFORMAT = 0x1000, DDSD_MIPMAPCOUNT = 0x20000, DDSD_LINEARSIZE = 0x80000, DDSD_DEPTH = 0x800000; var DDSCAPS_COMPLEX = 0x8, DDSCAPS_MIPMAP = 0x400000, DDSCAPS_TEXTURE = 0x1000; var DDSCAPS2_CUBEMAP = 0x200, DDSCAPS2_CUBEMAP_POSITIVEX = 0x400, DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800, DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000, DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000, DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000, DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000, DDSCAPS2_VOLUME = 0x200000; var DDPF_ALPHAPIXELS = 0x1, DDPF_ALPHA = 0x2, DDPF_FOURCC = 0x4, DDPF_RGB = 0x40, DDPF_YUV = 0x200, DDPF_LUMINANCE = 0x20000; function fourCCToInt32( value ) { return value.charCodeAt(0) + (value.charCodeAt(1) << 8) + (value.charCodeAt(2) << 16) + (value.charCodeAt(3) << 24); } function int32ToFourCC( value ) { return String.fromCharCode( value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, (value >> 24) & 0xff ); } function loadARGBMip( buffer, dataOffset, width, height ) { var dataLength = width*height*4; var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength ); var byteArray = new Uint8Array( dataLength ); var dst = 0; var src = 0; for ( var y = 0; y < height; y++ ) { for ( var x = 0; x < width; x++ ) { var b = srcBuffer[src]; src++; var g = srcBuffer[src]; src++; var r = srcBuffer[src]; src++; var a = srcBuffer[src]; src++; byteArray[dst] = r; dst++; //r byteArray[dst] = g; dst++; //g byteArray[dst] = b; dst++; //b byteArray[dst] = a; dst++; //a } } return byteArray; } var FOURCC_DXT1 = fourCCToInt32("DXT1"); var FOURCC_DXT3 = fourCCToInt32("DXT3"); var FOURCC_DXT5 = fourCCToInt32("DXT5"); var headerLengthInt = 31; // The header length in 32 bit ints // Offsets into the header array var off_magic = 0; var off_size = 1; var off_flags = 2; var off_height = 3; var off_width = 4; var off_mipmapCount = 7; var off_pfFlags = 20; var off_pfFourCC = 21; var off_RGBBitCount = 22; var off_RBitMask = 23; var off_GBitMask = 24; var off_BBitMask = 25; var off_ABitMask = 26; var off_caps = 27; var off_caps2 = 28; var off_caps3 = 29; var off_caps4 = 30; // Parse header var header = new Int32Array( buffer, 0, headerLengthInt ); if ( header[ off_magic ] !== DDS_MAGIC ) { console.error( "ImageUtils.parseDDS(): Invalid magic number in DDS header" ); return dds; } if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) { console.error( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" ); return dds; } var blockBytes; var fourCC = header[ off_pfFourCC ]; var isRGBAUncompressed = false; switch ( fourCC ) { case FOURCC_DXT1: blockBytes = 8; dds.format = THREE.RGB_S3TC_DXT1_Format; break; case FOURCC_DXT3: blockBytes = 16; dds.format = THREE.RGBA_S3TC_DXT3_Format; break; case FOURCC_DXT5: blockBytes = 16; dds.format = THREE.RGBA_S3TC_DXT5_Format; break; default: if( header[off_RGBBitCount] ==32 && header[off_RBitMask]&0xff0000 && header[off_GBitMask]&0xff00 && header[off_BBitMask]&0xff && header[off_ABitMask]&0xff000000 ) { isRGBAUncompressed = true; blockBytes = 64; dds.format = THREE.RGBAFormat; } else { console.error( "ImageUtils.parseDDS(): Unsupported FourCC code: ", int32ToFourCC( fourCC ) ); return dds; } } dds.mipmapCount = 1; if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) { dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] ); } //TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc. dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false; dds.width = header[ off_width ]; dds.height = header[ off_height ]; var dataOffset = header[ off_size ] + 4; // Extract mipmaps buffers var width = dds.width; var height = dds.height; var faces = dds.isCubemap ? 6 : 1; for ( var face = 0; face < faces; face ++ ) { for ( var i = 0; i < dds.mipmapCount; i ++ ) { if( isRGBAUncompressed ) { var byteArray = loadARGBMip( buffer, dataOffset, width, height ); var dataLength = byteArray.length; } else { var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes; var byteArray = new Uint8Array( buffer, dataOffset, dataLength ); } var mipmap = { "data": byteArray, "width": width, "height": height }; dds.mipmaps.push( mipmap ); dataOffset += dataLength; width = Math.max( width * 0.5, 1 ); height = Math.max( height * 0.5, 1 ); } width = dds.width; height = dds.height; } return dds; }, getNormalMap: function ( image, depth ) { // Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/ var cross = function ( a, b ) { return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ]; } var subtract = function ( a, b ) { return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ]; } var normalize = function ( a ) { var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] ); return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ]; } depth = depth | 1; var width = image.width; var height = image.height; var canvas = document.createElement( 'canvas' ); canvas.width = width; canvas.height = height; var context = canvas.getContext( '2d' ); context.drawImage( image, 0, 0 ); var data = context.getImageData( 0, 0, width, height ).data; var imageData = context.createImageData( width, height ); var output = imageData.data; for ( var x = 0; x < width; x ++ ) { for ( var y = 0; y < height; y ++ ) { var ly = y - 1 < 0 ? 0 : y - 1; var uy = y + 1 > height - 1 ? height - 1 : y + 1; var lx = x - 1 < 0 ? 0 : x - 1; var ux = x + 1 > width - 1 ? width - 1 : x + 1; var points = []; var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ]; points.push( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] ); points.push( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] ); points.push( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] ); points.push( [ 1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] ); points.push( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] ); points.push( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] ); points.push( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] ); points.push( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] ); var normals = []; var num_points = points.length; for ( var i = 0; i < num_points; i ++ ) { var v1 = points[ i ]; var v2 = points[ ( i + 1 ) % num_points ]; v1 = subtract( v1, origin ); v2 = subtract( v2, origin ); normals.push( normalize( cross( v1, v2 ) ) ); } var normal = [ 0, 0, 0 ]; for ( var i = 0; i < normals.length; i ++ ) { normal[ 0 ] += normals[ i ][ 0 ]; normal[ 1 ] += normals[ i ][ 1 ]; normal[ 2 ] += normals[ i ][ 2 ]; } normal[ 0 ] /= normals.length; normal[ 1 ] /= normals.length; normal[ 2 ] /= normals.length; var idx = ( y * width + x ) * 4; output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ) | 0; output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ) | 0; output[ idx + 2 ] = ( normal[ 2 ] * 255 ) | 0; output[ idx + 3 ] = 255; } } context.putImageData( imageData, 0, 0 ); return canvas; }, generateDataTexture: function ( width, height, color ) { var size = width * height; var data = new Uint8Array( 3 * size ); var r = Math.floor( color.r * 255 ); var g = Math.floor( color.g * 255 ); var b = Math.floor( color.b * 255 ); for ( var i = 0; i < size; i ++ ) { data[ i * 3 ] = r; data[ i * 3 + 1 ] = g; data[ i * 3 + 2 ] = b; } var texture = new THREE.DataTexture( data, width, height, THREE.RGBFormat ); texture.needsUpdate = true; return texture; } }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.SceneUtils = { createMultiMaterialObject: function ( geometry, materials ) { var group = new THREE.Object3D(); for ( var i = 0, l = materials.length; i < l; i ++ ) { group.add( new THREE.Mesh( geometry, materials[ i ] ) ); } return group; }, detach : function ( child, parent, scene ) { child.applyMatrix( parent.matrixWorld ); parent.remove( child ); scene.add( child ); }, attach: function ( child, scene, parent ) { var matrixWorldInverse = new THREE.Matrix4(); matrixWorldInverse.getInverse( parent.matrixWorld ); child.applyMatrix( matrixWorldInverse ); scene.remove( child ); parent.add( child ); } }; /** * @author zz85 / http://www.lab4games.net/zz85/blog * @author alteredq / http://alteredqualia.com/ * * For Text operations in three.js (See TextGeometry) * * It uses techniques used in: * * typeface.js and canvastext * For converting fonts and rendering with javascript * http://typeface.neocracy.org * * Triangulation ported from AS3 * Simple Polygon Triangulation * http://actionsnippet.com/?p=1462 * * A Method to triangulate shapes with holes * http://www.sakri.net/blog/2009/06/12/an-approach-to-triangulating-polygons-with-holes/ * */ THREE.FontUtils = { faces : {}, // Just for now. face[weight][style] face : "helvetiker", weight: "normal", style : "normal", size : 150, divisions : 10, getFace : function() { return this.faces[ this.face ][ this.weight ][ this.style ]; }, loadFace : function( data ) { var family = data.familyName.toLowerCase(); var ThreeFont = this; ThreeFont.faces[ family ] = ThreeFont.faces[ family ] || {}; ThreeFont.faces[ family ][ data.cssFontWeight ] = ThreeFont.faces[ family ][ data.cssFontWeight ] || {}; ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; var face = ThreeFont.faces[ family ][ data.cssFontWeight ][ data.cssFontStyle ] = data; return data; }, drawText : function( text ) { var characterPts = [], allPts = []; // RenderText var i, p, face = this.getFace(), scale = this.size / face.resolution, offset = 0, chars = String( text ).split( '' ), length = chars.length; var fontPaths = []; for ( i = 0; i < length; i ++ ) { var path = new THREE.Path(); var ret = this.extractGlyphPoints( chars[ i ], face, scale, offset, path ); offset += ret.offset; fontPaths.push( ret.path ); } // get the width var width = offset / 2; // // for ( p = 0; p < allPts.length; p++ ) { // // allPts[ p ].x -= width; // // } //var extract = this.extractPoints( allPts, characterPts ); //extract.contour = allPts; //extract.paths = fontPaths; //extract.offset = width; return { paths : fontPaths, offset : width }; }, extractGlyphPoints : function( c, face, scale, offset, path ) { var pts = []; var i, i2, divisions, outline, action, length, scaleX, scaleY, x, y, cpx, cpy, cpx0, cpy0, cpx1, cpy1, cpx2, cpy2, laste, glyph = face.glyphs[ c ] || face.glyphs[ '?' ]; if ( !glyph ) return; if ( glyph.o ) { outline = glyph._cachedOutline || ( glyph._cachedOutline = glyph.o.split( ' ' ) ); length = outline.length; scaleX = scale; scaleY = scale; for ( i = 0; i < length; ) { action = outline[ i ++ ]; //console.log( action ); switch( action ) { case 'm': // Move To x = outline[ i++ ] * scaleX + offset; y = outline[ i++ ] * scaleY; path.moveTo( x, y ); break; case 'l': // Line To x = outline[ i++ ] * scaleX + offset; y = outline[ i++ ] * scaleY; path.lineTo(x,y); break; case 'q': // QuadraticCurveTo cpx = outline[ i++ ] * scaleX + offset; cpy = outline[ i++ ] * scaleY; cpx1 = outline[ i++ ] * scaleX + offset; cpy1 = outline[ i++ ] * scaleY; path.quadraticCurveTo(cpx1, cpy1, cpx, cpy); laste = pts[ pts.length - 1 ]; if ( laste ) { cpx0 = laste.x; cpy0 = laste.y; for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { var t = i2 / divisions; var tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); var ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); } } break; case 'b': // Cubic Bezier Curve cpx = outline[ i++ ] * scaleX + offset; cpy = outline[ i++ ] * scaleY; cpx1 = outline[ i++ ] * scaleX + offset; cpy1 = outline[ i++ ] * -scaleY; cpx2 = outline[ i++ ] * scaleX + offset; cpy2 = outline[ i++ ] * -scaleY; path.bezierCurveTo( cpx, cpy, cpx1, cpy1, cpx2, cpy2 ); laste = pts[ pts.length - 1 ]; if ( laste ) { cpx0 = laste.x; cpy0 = laste.y; for ( i2 = 1, divisions = this.divisions; i2 <= divisions; i2 ++ ) { var t = i2 / divisions; var tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); var ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); } } break; } } } return { offset: glyph.ha*scale, path:path}; } }; THREE.FontUtils.generateShapes = function( text, parameters ) { // Parameters parameters = parameters || {}; var size = parameters.size !== undefined ? parameters.size : 100; var curveSegments = parameters.curveSegments !== undefined ? parameters.curveSegments: 4; var font = parameters.font !== undefined ? parameters.font : "helvetiker"; var weight = parameters.weight !== undefined ? parameters.weight : "normal"; var style = parameters.style !== undefined ? parameters.style : "normal"; THREE.FontUtils.size = size; THREE.FontUtils.divisions = curveSegments; THREE.FontUtils.face = font; THREE.FontUtils.weight = weight; THREE.FontUtils.style = style; // Get a Font data json object var data = THREE.FontUtils.drawText( text ); var paths = data.paths; var shapes = []; for ( var p = 0, pl = paths.length; p < pl; p ++ ) { Array.prototype.push.apply( shapes, paths[ p ].toShapes() ); } return shapes; }; /** * This code is a quick port of code written in C++ which was submitted to * flipcode.com by John W. Ratcliff // July 22, 2000 * See original code and more information here: * http://www.flipcode.com/archives/Efficient_Polygon_Triangulation.shtml * * ported to actionscript by Zevan Rosser * www.actionsnippet.com * * ported to javascript by Joshua Koo * http://www.lab4games.net/zz85/blog * */ ( function( namespace ) { var EPSILON = 0.0000000001; // takes in an contour array and returns var process = function( contour, indices ) { var n = contour.length; if ( n < 3 ) return null; var result = [], verts = [], vertIndices = []; /* we want a counter-clockwise polygon in verts */ var u, v, w; if ( area( contour ) > 0.0 ) { for ( v = 0; v < n; v++ ) verts[ v ] = v; } else { for ( v = 0; v < n; v++ ) verts[ v ] = ( n - 1 ) - v; } var nv = n; /* remove nv - 2 vertices, creating 1 triangle every time */ var count = 2 * nv; /* error detection */ for( v = nv - 1; nv > 2; ) { /* if we loop, it is probably a non-simple polygon */ if ( ( count-- ) <= 0 ) { //** Triangulate: ERROR - probable bad polygon! //throw ( "Warning, unable to triangulate polygon!" ); //return null; // Sometimes warning is fine, especially polygons are triangulated in reverse. console.log( "Warning, unable to triangulate polygon!" ); if ( indices ) return vertIndices; return result; } /* three consecutive vertices in current polygon, */ u = v; if ( nv <= u ) u = 0; /* previous */ v = u + 1; if ( nv <= v ) v = 0; /* new v */ w = v + 1; if ( nv <= w ) w = 0; /* next */ if ( snip( contour, u, v, w, nv, verts ) ) { var a, b, c, s, t; /* true names of the vertices */ a = verts[ u ]; b = verts[ v ]; c = verts[ w ]; /* output Triangle */ result.push( [ contour[ a ], contour[ b ], contour[ c ] ] ); vertIndices.push( [ verts[ u ], verts[ v ], verts[ w ] ] ); /* remove v from the remaining polygon */ for( s = v, t = v + 1; t < nv; s++, t++ ) { verts[ s ] = verts[ t ]; } nv--; /* reset error detection counter */ count = 2 * nv; } } if ( indices ) return vertIndices; return result; }; // calculate area of the contour polygon var area = function ( contour ) { var n = contour.length; var a = 0.0; for( var p = n - 1, q = 0; q < n; p = q++ ) { a += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y; } return a * 0.5; }; var snip = function ( contour, u, v, w, n, verts ) { var p; var ax, ay, bx, by; var cx, cy, px, py; ax = contour[ verts[ u ] ].x; ay = contour[ verts[ u ] ].y; bx = contour[ verts[ v ] ].x; by = contour[ verts[ v ] ].y; cx = contour[ verts[ w ] ].x; cy = contour[ verts[ w ] ].y; if ( EPSILON > (((bx-ax)*(cy-ay)) - ((by-ay)*(cx-ax))) ) return false; var aX, aY, bX, bY, cX, cY; var apx, apy, bpx, bpy, cpx, cpy; var cCROSSap, bCROSScp, aCROSSbp; aX = cx - bx; aY = cy - by; bX = ax - cx; bY = ay - cy; cX = bx - ax; cY = by - ay; for ( p = 0; p < n; p++ ) { px = contour[ verts[ p ] ].x py = contour[ verts[ p ] ].y if ( ( (px === ax) && (py === ay) ) || ( (px === bx) && (py === by) ) || ( (px === cx) && (py === cy) ) ) continue; apx = px - ax; apy = py - ay; bpx = px - bx; bpy = py - by; cpx = px - cx; cpy = py - cy; // see if p is inside triangle abc aCROSSbp = aX*bpy - aY*bpx; cCROSSap = cX*apy - cY*apx; bCROSScp = bX*cpy - bY*cpx; if ( (aCROSSbp >= -EPSILON) && (bCROSScp >= -EPSILON) && (cCROSSap >= -EPSILON) ) return false; } return true; }; namespace.Triangulate = process; namespace.Triangulate.area = area; return namespace; })(THREE.FontUtils); // To use the typeface.js face files, hook up the API self._typeface_js = { faces: THREE.FontUtils.faces, loadFace: THREE.FontUtils.loadFace }; THREE.typeface_js = self._typeface_js; /** * @author zz85 / http://www.lab4games.net/zz85/blog * Extensible curve object * * Some common of Curve methods * .getPoint(t), getTangent(t) * .getPointAt(u), getTagentAt(u) * .getPoints(), .getSpacedPoints() * .getLength() * .updateArcLengths() * * This following classes subclasses THREE.Curve: * * -- 2d classes -- * THREE.LineCurve * THREE.QuadraticBezierCurve * THREE.CubicBezierCurve * THREE.SplineCurve * THREE.ArcCurve * THREE.EllipseCurve * * -- 3d classes -- * THREE.LineCurve3 * THREE.QuadraticBezierCurve3 * THREE.CubicBezierCurve3 * THREE.SplineCurve3 * THREE.ClosedSplineCurve3 * * A series of curves can be represented as a THREE.CurvePath * **/ /************************************************************** * Abstract Curve base class **************************************************************/ THREE.Curve = function () { }; // Virtual base class method to overwrite and implement in subclasses // - t [0 .. 1] THREE.Curve.prototype.getPoint = function ( t ) { console.log( "Warning, getPoint() not implemented!" ); return null; }; // Get point at relative position in curve according to arc length // - u [0 .. 1] THREE.Curve.prototype.getPointAt = function ( u ) { var t = this.getUtoTmapping( u ); return this.getPoint( t ); }; // Get sequence of points using getPoint( t ) THREE.Curve.prototype.getPoints = function ( divisions ) { if ( !divisions ) divisions = 5; var d, pts = []; for ( d = 0; d <= divisions; d ++ ) { pts.push( this.getPoint( d / divisions ) ); } return pts; }; // Get sequence of points using getPointAt( u ) THREE.Curve.prototype.getSpacedPoints = function ( divisions ) { if ( !divisions ) divisions = 5; var d, pts = []; for ( d = 0; d <= divisions; d ++ ) { pts.push( this.getPointAt( d / divisions ) ); } return pts; }; // Get total curve arc length THREE.Curve.prototype.getLength = function () { var lengths = this.getLengths(); return lengths[ lengths.length - 1 ]; }; // Get list of cumulative segment lengths THREE.Curve.prototype.getLengths = function ( divisions ) { if ( !divisions ) divisions = (this.__arcLengthDivisions) ? (this.__arcLengthDivisions): 200; if ( this.cacheArcLengths && ( this.cacheArcLengths.length == divisions + 1 ) && !this.needsUpdate) { //console.log( "cached", this.cacheArcLengths ); return this.cacheArcLengths; } this.needsUpdate = false; var cache = []; var current, last = this.getPoint( 0 ); var p, sum = 0; cache.push( 0 ); for ( p = 1; p <= divisions; p ++ ) { current = this.getPoint ( p / divisions ); sum += current.distanceTo( last ); cache.push( sum ); last = current; } this.cacheArcLengths = cache; return cache; // { sums: cache, sum:sum }; Sum is in the last element. }; THREE.Curve.prototype.updateArcLengths = function() { this.needsUpdate = true; this.getLengths(); }; // Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equi distance THREE.Curve.prototype.getUtoTmapping = function ( u, distance ) { var arcLengths = this.getLengths(); var i = 0, il = arcLengths.length; var targetArcLength; // The targeted u distance value to get if ( distance ) { targetArcLength = distance; } else { targetArcLength = u * arcLengths[ il - 1 ]; } //var time = Date.now(); // binary search for the index with largest value smaller than target u distance var low = 0, high = il - 1, comparison; while ( low <= high ) { i = Math.floor( low + ( high - low ) / 2 ); // less likely to overflow, though probably not issue here, JS doesn't really have integers, all numbers are floats comparison = arcLengths[ i ] - targetArcLength; if ( comparison < 0 ) { low = i + 1; continue; } else if ( comparison > 0 ) { high = i - 1; continue; } else { high = i; break; // DONE } } i = high; //console.log('b' , i, low, high, Date.now()- time); if ( arcLengths[ i ] == targetArcLength ) { var t = i / ( il - 1 ); return t; } // we could get finer grain at lengths, or use simple interpolatation between two points var lengthBefore = arcLengths[ i ]; var lengthAfter = arcLengths[ i + 1 ]; var segmentLength = lengthAfter - lengthBefore; // determine where we are between the 'before' and 'after' points var segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength; // add that fractional amount to t var t = ( i + segmentFraction ) / ( il -1 ); return t; }; // Returns a unit vector tangent at t // In case any sub curve does not implement its tangent derivation, // 2 points a small delta apart will be used to find its gradient // which seems to give a reasonable approximation THREE.Curve.prototype.getTangent = function( t ) { var delta = 0.0001; var t1 = t - delta; var t2 = t + delta; // Capping in case of danger if ( t1 < 0 ) t1 = 0; if ( t2 > 1 ) t2 = 1; var pt1 = this.getPoint( t1 ); var pt2 = this.getPoint( t2 ); var vec = pt2.clone().sub(pt1); return vec.normalize(); }; THREE.Curve.prototype.getTangentAt = function ( u ) { var t = this.getUtoTmapping( u ); return this.getTangent( t ); }; /************************************************************** * Utils **************************************************************/ THREE.Curve.Utils = { tangentQuadraticBezier: function ( t, p0, p1, p2 ) { return 2 * ( 1 - t ) * ( p1 - p0 ) + 2 * t * ( p2 - p1 ); }, // Puay Bing, thanks for helping with this derivative! tangentCubicBezier: function (t, p0, p1, p2, p3 ) { return -3 * p0 * (1 - t) * (1 - t) + 3 * p1 * (1 - t) * (1-t) - 6 *t *p1 * (1-t) + 6 * t * p2 * (1-t) - 3 * t * t * p2 + 3 * t * t * p3; }, tangentSpline: function ( t, p0, p1, p2, p3 ) { // To check if my formulas are correct var h00 = 6 * t * t - 6 * t; // derived from 2t^3 − 3t^2 + 1 var h10 = 3 * t * t - 4 * t + 1; // t^3 − 2t^2 + t var h01 = -6 * t * t + 6 * t; // − 2t3 + 3t2 var h11 = 3 * t * t - 2 * t; // t3 − t2 return h00 + h10 + h01 + h11; }, // Catmull-Rom interpolate: function( p0, p1, p2, p3, t ) { var v0 = ( p2 - p0 ) * 0.5; var v1 = ( p3 - p1 ) * 0.5; var t2 = t * t; var t3 = t * t2; return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; } }; // TODO: Transformation for Curves? /************************************************************** * 3D Curves **************************************************************/ // A Factory method for creating new curve subclasses THREE.Curve.create = function ( constructor, getPointFunc ) { constructor.prototype = Object.create( THREE.Curve.prototype ); constructor.prototype.getPoint = getPointFunc; return constructor; }; /** * @author zz85 / http://www.lab4games.net/zz85/blog * **/ /************************************************************** * Curved Path - a curve path is simply a array of connected * curves, but retains the api of a curve **************************************************************/ THREE.CurvePath = function () { this.curves = []; this.bends = []; this.autoClose = false; // Automatically closes the path }; THREE.CurvePath.prototype = Object.create( THREE.Curve.prototype ); THREE.CurvePath.prototype.add = function ( curve ) { this.curves.push( curve ); }; THREE.CurvePath.prototype.checkConnection = function() { // TODO // If the ending of curve is not connected to the starting // or the next curve, then, this is not a real path }; THREE.CurvePath.prototype.closePath = function() { // TODO Test // and verify for vector3 (needs to implement equals) // Add a line curve if start and end of lines are not connected var startPoint = this.curves[0].getPoint(0); var endPoint = this.curves[this.curves.length-1].getPoint(1); if (!startPoint.equals(endPoint)) { this.curves.push( new THREE.LineCurve(endPoint, startPoint) ); } }; // To get accurate point with reference to // entire path distance at time t, // following has to be done: // 1. Length of each sub path have to be known // 2. Locate and identify type of curve // 3. Get t for the curve // 4. Return curve.getPointAt(t') THREE.CurvePath.prototype.getPoint = function( t ) { var d = t * this.getLength(); var curveLengths = this.getCurveLengths(); var i = 0, diff, curve; // To think about boundaries points. while ( i < curveLengths.length ) { if ( curveLengths[ i ] >= d ) { diff = curveLengths[ i ] - d; curve = this.curves[ i ]; var u = 1 - diff / curve.getLength(); return curve.getPointAt( u ); break; } i ++; } return null; // loop where sum != 0, sum > d , sum+1 maxX ) maxX = p.x; else if ( p.x < minX ) minX = p.x; if ( p.y > maxY ) maxY = p.y; else if ( p.y < minY ) minY = p.y; if ( v3 ) { if ( p.z > maxZ ) maxZ = p.z; else if ( p.z < minZ ) minZ = p.z; } sum.add( p ); } var ret = { minX: minX, minY: minY, maxX: maxX, maxY: maxY, centroid: sum.divideScalar( il ) }; if ( v3 ) { ret.maxZ = maxZ; ret.minZ = minZ; } return ret; }; /************************************************************** * Create Geometries Helpers **************************************************************/ /// Generate geometry from path points (for Line or ParticleSystem objects) THREE.CurvePath.prototype.createPointsGeometry = function( divisions ) { var pts = this.getPoints( divisions, true ); return this.createGeometry( pts ); }; // Generate geometry from equidistance sampling along the path THREE.CurvePath.prototype.createSpacedPointsGeometry = function( divisions ) { var pts = this.getSpacedPoints( divisions, true ); return this.createGeometry( pts ); }; THREE.CurvePath.prototype.createGeometry = function( points ) { var geometry = new THREE.Geometry(); for ( var i = 0; i < points.length; i ++ ) { geometry.vertices.push( new THREE.Vector3( points[ i ].x, points[ i ].y, points[ i ].z || 0) ); } return geometry; }; /************************************************************** * Bend / Wrap Helper Methods **************************************************************/ // Wrap path / Bend modifiers? THREE.CurvePath.prototype.addWrapPath = function ( bendpath ) { this.bends.push( bendpath ); }; THREE.CurvePath.prototype.getTransformedPoints = function( segments, bends ) { var oldPts = this.getPoints( segments ); // getPoints getSpacedPoints var i, il; if ( !bends ) { bends = this.bends; } for ( i = 0, il = bends.length; i < il; i ++ ) { oldPts = this.getWrapPoints( oldPts, bends[ i ] ); } return oldPts; }; THREE.CurvePath.prototype.getTransformedSpacedPoints = function( segments, bends ) { var oldPts = this.getSpacedPoints( segments ); var i, il; if ( !bends ) { bends = this.bends; } for ( i = 0, il = bends.length; i < il; i ++ ) { oldPts = this.getWrapPoints( oldPts, bends[ i ] ); } return oldPts; }; // This returns getPoints() bend/wrapped around the contour of a path. // Read http://www.planetclegg.com/projects/WarpingTextToSplines.html THREE.CurvePath.prototype.getWrapPoints = function ( oldPts, path ) { var bounds = this.getBoundingBox(); var i, il, p, oldX, oldY, xNorm; for ( i = 0, il = oldPts.length; i < il; i ++ ) { p = oldPts[ i ]; oldX = p.x; oldY = p.y; xNorm = oldX / bounds.maxX; // If using actual distance, for length > path, requires line extrusions //xNorm = path.getUtoTmapping(xNorm, oldX); // 3 styles. 1) wrap stretched. 2) wrap stretch by arc length 3) warp by actual distance xNorm = path.getUtoTmapping( xNorm, oldX ); // check for out of bounds? var pathPt = path.getPoint( xNorm ); var normal = path.getTangent( xNorm ); normal.set( -normal.y, normal.x ).multiplyScalar( oldY ); p.x = pathPt.x + normal.x; p.y = pathPt.y + normal.y; } return oldPts; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.Gyroscope = function () { THREE.Object3D.call( this ); }; THREE.Gyroscope.prototype = Object.create( THREE.Object3D.prototype ); THREE.Gyroscope.prototype.updateMatrixWorld = function ( force ) { this.matrixAutoUpdate && this.updateMatrix(); // update matrixWorld if ( this.matrixWorldNeedsUpdate || force ) { if ( this.parent ) { this.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix ); this.matrixWorld.decompose( this.translationWorld, this.quaternionWorld, this.scaleWorld ); this.matrix.decompose( this.translationObject, this.quaternionObject, this.scaleObject ); this.matrixWorld.compose( this.translationWorld, this.quaternionObject, this.scaleWorld ); } else { this.matrixWorld.copy( this.matrix ); } this.matrixWorldNeedsUpdate = false; force = true; } // update children for ( var i = 0, l = this.children.length; i < l; i ++ ) { this.children[ i ].updateMatrixWorld( force ); } }; THREE.Gyroscope.prototype.translationWorld = new THREE.Vector3(); THREE.Gyroscope.prototype.translationObject = new THREE.Vector3(); THREE.Gyroscope.prototype.quaternionWorld = new THREE.Quaternion(); THREE.Gyroscope.prototype.quaternionObject = new THREE.Quaternion(); THREE.Gyroscope.prototype.scaleWorld = new THREE.Vector3(); THREE.Gyroscope.prototype.scaleObject = new THREE.Vector3(); /** * @author zz85 / http://www.lab4games.net/zz85/blog * Creates free form 2d path using series of points, lines or curves. * **/ THREE.Path = function ( points ) { THREE.CurvePath.call(this); this.actions = []; if ( points ) { this.fromPoints( points ); } }; THREE.Path.prototype = Object.create( THREE.CurvePath.prototype ); THREE.PathActions = { MOVE_TO: 'moveTo', LINE_TO: 'lineTo', QUADRATIC_CURVE_TO: 'quadraticCurveTo', // Bezier quadratic curve BEZIER_CURVE_TO: 'bezierCurveTo', // Bezier cubic curve CSPLINE_THRU: 'splineThru', // Catmull-rom spline ARC: 'arc', // Circle ELLIPSE: 'ellipse' }; // TODO Clean up PATH API // Create path using straight lines to connect all points // - vectors: array of Vector2 THREE.Path.prototype.fromPoints = function ( vectors ) { this.moveTo( vectors[ 0 ].x, vectors[ 0 ].y ); for ( var v = 1, vlen = vectors.length; v < vlen; v ++ ) { this.lineTo( vectors[ v ].x, vectors[ v ].y ); }; }; // startPath() endPath()? THREE.Path.prototype.moveTo = function ( x, y ) { var args = Array.prototype.slice.call( arguments ); this.actions.push( { action: THREE.PathActions.MOVE_TO, args: args } ); }; THREE.Path.prototype.lineTo = function ( x, y ) { var args = Array.prototype.slice.call( arguments ); var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new THREE.LineCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( x, y ) ); this.curves.push( curve ); this.actions.push( { action: THREE.PathActions.LINE_TO, args: args } ); }; THREE.Path.prototype.quadraticCurveTo = function( aCPx, aCPy, aX, aY ) { var args = Array.prototype.slice.call( arguments ); var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new THREE.QuadraticBezierCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( aCPx, aCPy ), new THREE.Vector2( aX, aY ) ); this.curves.push( curve ); this.actions.push( { action: THREE.PathActions.QUADRATIC_CURVE_TO, args: args } ); }; THREE.Path.prototype.bezierCurveTo = function( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) { var args = Array.prototype.slice.call( arguments ); var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; var curve = new THREE.CubicBezierCurve( new THREE.Vector2( x0, y0 ), new THREE.Vector2( aCP1x, aCP1y ), new THREE.Vector2( aCP2x, aCP2y ), new THREE.Vector2( aX, aY ) ); this.curves.push( curve ); this.actions.push( { action: THREE.PathActions.BEZIER_CURVE_TO, args: args } ); }; THREE.Path.prototype.splineThru = function( pts /*Array of Vector*/ ) { var args = Array.prototype.slice.call( arguments ); var lastargs = this.actions[ this.actions.length - 1 ].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; //--- var npts = [ new THREE.Vector2( x0, y0 ) ]; Array.prototype.push.apply( npts, pts ); var curve = new THREE.SplineCurve( npts ); this.curves.push( curve ); this.actions.push( { action: THREE.PathActions.CSPLINE_THRU, args: args } ); }; // FUTURE: Change the API or follow canvas API? THREE.Path.prototype.arc = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { var lastargs = this.actions[ this.actions.length - 1].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; this.absarc(aX + x0, aY + y0, aRadius, aStartAngle, aEndAngle, aClockwise ); }; THREE.Path.prototype.absarc = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { this.absellipse(aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise); }; THREE.Path.prototype.ellipse = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { var lastargs = this.actions[ this.actions.length - 1].args; var x0 = lastargs[ lastargs.length - 2 ]; var y0 = lastargs[ lastargs.length - 1 ]; this.absellipse(aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ); }; THREE.Path.prototype.absellipse = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { var args = Array.prototype.slice.call( arguments ); var curve = new THREE.EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ); this.curves.push( curve ); var lastPoint = curve.getPoint(1); args.push(lastPoint.x); args.push(lastPoint.y); this.actions.push( { action: THREE.PathActions.ELLIPSE, args: args } ); }; THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) { if ( ! divisions ) divisions = 40; var points = []; for ( var i = 0; i < divisions; i ++ ) { points.push( this.getPoint( i / divisions ) ); //if( !this.getPoint( i / divisions ) ) throw "DIE"; } // if ( closedPath ) { // // points.push( points[ 0 ] ); // // } return points; }; /* Return an array of vectors based on contour of the path */ THREE.Path.prototype.getPoints = function( divisions, closedPath ) { if (this.useSpacedPoints) { console.log('tata'); return this.getSpacedPoints( divisions, closedPath ); } divisions = divisions || 12; var points = []; var i, il, item, action, args; var cpx, cpy, cpx2, cpy2, cpx1, cpy1, cpx0, cpy0, laste, j, t, tx, ty; for ( i = 0, il = this.actions.length; i < il; i ++ ) { item = this.actions[ i ]; action = item.action; args = item.args; switch( action ) { case THREE.PathActions.MOVE_TO: points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); break; case THREE.PathActions.LINE_TO: points.push( new THREE.Vector2( args[ 0 ], args[ 1 ] ) ); break; case THREE.PathActions.QUADRATIC_CURVE_TO: cpx = args[ 2 ]; cpy = args[ 3 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = this.actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( j = 1; j <= divisions; j ++ ) { t = j / divisions; tx = THREE.Shape.Utils.b2( t, cpx0, cpx1, cpx ); ty = THREE.Shape.Utils.b2( t, cpy0, cpy1, cpy ); points.push( new THREE.Vector2( tx, ty ) ); } break; case THREE.PathActions.BEZIER_CURVE_TO: cpx = args[ 4 ]; cpy = args[ 5 ]; cpx1 = args[ 0 ]; cpy1 = args[ 1 ]; cpx2 = args[ 2 ]; cpy2 = args[ 3 ]; if ( points.length > 0 ) { laste = points[ points.length - 1 ]; cpx0 = laste.x; cpy0 = laste.y; } else { laste = this.actions[ i - 1 ].args; cpx0 = laste[ laste.length - 2 ]; cpy0 = laste[ laste.length - 1 ]; } for ( j = 1; j <= divisions; j ++ ) { t = j / divisions; tx = THREE.Shape.Utils.b3( t, cpx0, cpx1, cpx2, cpx ); ty = THREE.Shape.Utils.b3( t, cpy0, cpy1, cpy2, cpy ); points.push( new THREE.Vector2( tx, ty ) ); } break; case THREE.PathActions.CSPLINE_THRU: laste = this.actions[ i - 1 ].args; var last = new THREE.Vector2( laste[ laste.length - 2 ], laste[ laste.length - 1 ] ); var spts = [ last ]; var n = divisions * args[ 0 ].length; spts = spts.concat( args[ 0 ] ); var spline = new THREE.SplineCurve( spts ); for ( j = 1; j <= n; j ++ ) { points.push( spline.getPointAt( j / n ) ) ; } break; case THREE.PathActions.ARC: var aX = args[ 0 ], aY = args[ 1 ], aRadius = args[ 2 ], aStartAngle = args[ 3 ], aEndAngle = args[ 4 ], aClockwise = !!args[ 5 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; for ( j = 1; j <= tdivisions; j ++ ) { t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + aRadius * Math.cos( angle ); ty = aY + aRadius * Math.sin( angle ); //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.push( new THREE.Vector2( tx, ty ) ); } //console.log(points); break; case THREE.PathActions.ELLIPSE: var aX = args[ 0 ], aY = args[ 1 ], xRadius = args[ 2 ], yRadius = args[ 3 ], aStartAngle = args[ 4 ], aEndAngle = args[ 5 ], aClockwise = !!args[ 6 ]; var deltaAngle = aEndAngle - aStartAngle; var angle; var tdivisions = divisions * 2; for ( j = 1; j <= tdivisions; j ++ ) { t = j / tdivisions; if ( ! aClockwise ) { t = 1 - t; } angle = aStartAngle + t * deltaAngle; tx = aX + xRadius * Math.cos( angle ); ty = aY + yRadius * Math.sin( angle ); //console.log('t', t, 'angle', angle, 'tx', tx, 'ty', ty); points.push( new THREE.Vector2( tx, ty ) ); } //console.log(points); break; } // end switch } // Normalize to remove the closing point by default. var lastPoint = points[ points.length - 1]; var EPSILON = 0.0000000001; if ( Math.abs(lastPoint.x - points[ 0 ].x) < EPSILON && Math.abs(lastPoint.y - points[ 0 ].y) < EPSILON) points.splice( points.length - 1, 1); if ( closedPath ) { points.push( points[ 0 ] ); } return points; }; // Breaks path into shapes THREE.Path.prototype.toShapes = function( isCCW ) { function isPointInsidePolygon( inPt, inPolygon ) { var EPSILON = 0.0000000001; var polyLen = inPolygon.length; // inPt on polygon contour => immediate success or // toggling of inside/outside at every single! intersection point of an edge // with the horizontal line through inPt, left of inPt // not counting lowerY endpoints of edges and whole edges on that line var inside = false; for( var p = polyLen - 1, q = 0; q < polyLen; p = q++ ) { var edgeLowPt = inPolygon[ p ]; var edgeHighPt = inPolygon[ q ]; var edgeDx = edgeHighPt.x - edgeLowPt.x; var edgeDy = edgeHighPt.y - edgeLowPt.y; if ( Math.abs(edgeDy) > EPSILON ) { // not parallel if ( edgeDy < 0 ) { edgeLowPt = inPolygon[ q ]; edgeDx = -edgeDx; edgeHighPt = inPolygon[ p ]; edgeDy = -edgeDy; } if ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) continue; if ( inPt.y == edgeLowPt.y ) { if ( inPt.x == edgeLowPt.x ) return true; // inPt is on contour ? // continue; // no intersection or edgeLowPt => doesn't count !!! } else { var perpEdge = edgeDy * (inPt.x - edgeLowPt.x) - edgeDx * (inPt.y - edgeLowPt.y); if ( perpEdge == 0 ) return true; // inPt is on contour ? if ( perpEdge < 0 ) continue; inside = !inside; // true intersection left of inPt } } else { // parallel or colinear if ( inPt.y != edgeLowPt.y ) continue; // parallel // egde lies on the same horizontal line as inPt if ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) || ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) ) return true; // inPt: Point on contour ! // continue; } } return inside; } var i, il, item, action, args; var subPaths = [], lastPath = new THREE.Path(); for ( i = 0, il = this.actions.length; i < il; i ++ ) { item = this.actions[ i ]; args = item.args; action = item.action; if ( action == THREE.PathActions.MOVE_TO ) { if ( lastPath.actions.length != 0 ) { subPaths.push( lastPath ); lastPath = new THREE.Path(); } } lastPath[ action ].apply( lastPath, args ); } if ( lastPath.actions.length != 0 ) { subPaths.push( lastPath ); } // console.log(subPaths); if ( subPaths.length == 0 ) return []; var solid, tmpPath, tmpShape, shapes = []; if ( subPaths.length == 1) { tmpPath = subPaths[0]; tmpShape = new THREE.Shape(); tmpShape.actions = tmpPath.actions; tmpShape.curves = tmpPath.curves; shapes.push( tmpShape ); return shapes; } var holesFirst = !THREE.Shape.Utils.isClockWise( subPaths[ 0 ].getPoints() ); holesFirst = isCCW ? !holesFirst : holesFirst; // console.log("Holes first", holesFirst); var betterShapeHoles = []; var newShapes = []; var newShapeHoles = []; var mainIdx = 0; var tmpPoints; newShapes[mainIdx] = undefined; newShapeHoles[mainIdx] = []; for ( i = 0, il = subPaths.length; i < il; i ++ ) { tmpPath = subPaths[ i ]; tmpPoints = tmpPath.getPoints(); solid = THREE.Shape.Utils.isClockWise( tmpPoints ); solid = isCCW ? !solid : solid; if ( solid ) { if ( (! holesFirst ) && ( newShapes[mainIdx] ) ) mainIdx++; newShapes[mainIdx] = { s: new THREE.Shape(), p: tmpPoints }; newShapes[mainIdx].s.actions = tmpPath.actions; newShapes[mainIdx].s.curves = tmpPath.curves; if ( holesFirst ) mainIdx++; newShapeHoles[mainIdx] = []; //console.log('cw', i); } else { newShapeHoles[mainIdx].push( { h: tmpPath, p: tmpPoints[0] } ); //console.log('ccw', i); } } if ( newShapes.length > 1 ) { var ambigious = false; var toChange = []; for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++ ) { betterShapeHoles[sIdx] = []; } for (var sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx++ ) { var sh = newShapes[sIdx]; var sho = newShapeHoles[sIdx]; for (var hIdx = 0; hIdx < sho.length; hIdx++ ) { var ho = sho[hIdx]; var hole_unassigned = true; for (var s2Idx = 0; s2Idx < newShapes.length; s2Idx++ ) { if ( isPointInsidePolygon( ho.p, newShapes[s2Idx].p ) ) { if ( sIdx != s2Idx ) toChange.push( { froms: sIdx, tos: s2Idx, hole: hIdx } ); if ( hole_unassigned ) { hole_unassigned = false; betterShapeHoles[s2Idx].push( ho ); } else { ambigious = true; } } } if ( hole_unassigned ) { betterShapeHoles[sIdx].push( ho ); } } } // console.log("ambigious: ", ambigious); if ( toChange.length > 0 ) { // console.log("to change: ", toChange); if (! ambigious) newShapeHoles = betterShapeHoles; } } var tmpHoles, j, jl; for ( i = 0, il = newShapes.length; i < il; i ++ ) { tmpShape = newShapes[i].s; shapes.push( tmpShape ); tmpHoles = newShapeHoles[i]; for ( j = 0, jl = tmpHoles.length; j < jl; j ++ ) { tmpShape.holes.push( tmpHoles[j].h ); } } //console.log("shape", shapes); return shapes; }; /** * @author zz85 / http://www.lab4games.net/zz85/blog * Defines a 2d shape plane using paths. **/ // STEP 1 Create a path. // STEP 2 Turn path into shape. // STEP 3 ExtrudeGeometry takes in Shape/Shapes // STEP 3a - Extract points from each shape, turn to vertices // STEP 3b - Triangulate each shape, add faces. THREE.Shape = function () { THREE.Path.apply( this, arguments ); this.holes = []; }; THREE.Shape.prototype = Object.create( THREE.Path.prototype ); // Convenience method to return ExtrudeGeometry THREE.Shape.prototype.extrude = function ( options ) { var extruded = new THREE.ExtrudeGeometry( this, options ); return extruded; }; // Convenience method to return ShapeGeometry THREE.Shape.prototype.makeGeometry = function ( options ) { var geometry = new THREE.ShapeGeometry( this, options ); return geometry; }; // Get points of holes THREE.Shape.prototype.getPointsHoles = function ( divisions ) { var i, il = this.holes.length, holesPts = []; for ( i = 0; i < il; i ++ ) { holesPts[ i ] = this.holes[ i ].getTransformedPoints( divisions, this.bends ); } return holesPts; }; // Get points of holes (spaced by regular distance) THREE.Shape.prototype.getSpacedPointsHoles = function ( divisions ) { var i, il = this.holes.length, holesPts = []; for ( i = 0; i < il; i ++ ) { holesPts[ i ] = this.holes[ i ].getTransformedSpacedPoints( divisions, this.bends ); } return holesPts; }; // Get points of shape and holes (keypoints based on segments parameter) THREE.Shape.prototype.extractAllPoints = function ( divisions ) { return { shape: this.getTransformedPoints( divisions ), holes: this.getPointsHoles( divisions ) }; }; THREE.Shape.prototype.extractPoints = function ( divisions ) { if (this.useSpacedPoints) { return this.extractAllSpacedPoints(divisions); } return this.extractAllPoints(divisions); }; // // THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) { // // return { // // shape: this.transform( bend, divisions ), // holes: this.getPointsHoles( divisions, bend ) // // }; // // }; // Get points of shape and holes (spaced by regular distance) THREE.Shape.prototype.extractAllSpacedPoints = function ( divisions ) { return { shape: this.getTransformedSpacedPoints( divisions ), holes: this.getSpacedPointsHoles( divisions ) }; }; /************************************************************** * Utils **************************************************************/ THREE.Shape.Utils = { triangulateShape: function ( contour, holes ) { function point_in_segment_2D_colin( inSegPt1, inSegPt2, inOtherPt ) { // inOtherPt needs to be colinear to the inSegment if ( inSegPt1.x != inSegPt2.x ) { if ( inSegPt1.x < inSegPt2.x ) { return ( ( inSegPt1.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt2.x ) ); } else { return ( ( inSegPt2.x <= inOtherPt.x ) && ( inOtherPt.x <= inSegPt1.x ) ); } } else { if ( inSegPt1.y < inSegPt2.y ) { return ( ( inSegPt1.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt2.y ) ); } else { return ( ( inSegPt2.y <= inOtherPt.y ) && ( inOtherPt.y <= inSegPt1.y ) ); } } } function intersect_segments_2D( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1, inSeg2Pt2, inExcludeAdjacentSegs ) { var EPSILON = 0.0000000001; var seg1dx = inSeg1Pt2.x - inSeg1Pt1.x, seg1dy = inSeg1Pt2.y - inSeg1Pt1.y; var seg2dx = inSeg2Pt2.x - inSeg2Pt1.x, seg2dy = inSeg2Pt2.y - inSeg2Pt1.y; var seg1seg2dx = inSeg1Pt1.x - inSeg2Pt1.x; var seg1seg2dy = inSeg1Pt1.y - inSeg2Pt1.y; var limit = seg1dy * seg2dx - seg1dx * seg2dy; var perpSeg1 = seg1dy * seg1seg2dx - seg1dx * seg1seg2dy; if ( Math.abs(limit) > EPSILON ) { // not parallel var perpSeg2; if ( limit > 0 ) { if ( ( perpSeg1 < 0 ) || ( perpSeg1 > limit ) ) return []; perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; if ( ( perpSeg2 < 0 ) || ( perpSeg2 > limit ) ) return []; } else { if ( ( perpSeg1 > 0 ) || ( perpSeg1 < limit ) ) return []; perpSeg2 = seg2dy * seg1seg2dx - seg2dx * seg1seg2dy; if ( ( perpSeg2 > 0 ) || ( perpSeg2 < limit ) ) return []; } // i.e. to reduce rounding errors // intersection at endpoint of segment#1? if ( perpSeg2 == 0 ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; return [ inSeg1Pt1 ]; } if ( perpSeg2 == limit ) { if ( ( inExcludeAdjacentSegs ) && ( ( perpSeg1 == 0 ) || ( perpSeg1 == limit ) ) ) return []; return [ inSeg1Pt2 ]; } // intersection at endpoint of segment#2? if ( perpSeg1 == 0 ) return [ inSeg2Pt1 ]; if ( perpSeg1 == limit ) return [ inSeg2Pt2 ]; // return real intersection point var factorSeg1 = perpSeg2 / limit; return [ { x: inSeg1Pt1.x + factorSeg1 * seg1dx, y: inSeg1Pt1.y + factorSeg1 * seg1dy } ]; } else { // parallel or colinear if ( ( perpSeg1 != 0 ) || ( seg2dy * seg1seg2dx != seg2dx * seg1seg2dy ) ) return []; // they are collinear or degenerate var seg1Pt = ( (seg1dx == 0) && (seg1dy == 0) ); // segment1 ist just a point? var seg2Pt = ( (seg2dx == 0) && (seg2dy == 0) ); // segment2 ist just a point? // both segments are points if ( seg1Pt && seg2Pt ) { if ( (inSeg1Pt1.x != inSeg2Pt1.x) || (inSeg1Pt1.y != inSeg2Pt1.y) ) return []; // they are distinct points return [ inSeg1Pt1 ]; // they are the same point } // segment#1 is a single point if ( seg1Pt ) { if (! point_in_segment_2D_colin( inSeg2Pt1, inSeg2Pt2, inSeg1Pt1 ) ) return []; // but not in segment#2 return [ inSeg1Pt1 ]; } // segment#2 is a single point if ( seg2Pt ) { if (! point_in_segment_2D_colin( inSeg1Pt1, inSeg1Pt2, inSeg2Pt1 ) ) return []; // but not in segment#1 return [ inSeg2Pt1 ]; } // they are collinear segments, which might overlap var seg1min, seg1max, seg1minVal, seg1maxVal; var seg2min, seg2max, seg2minVal, seg2maxVal; if (seg1dx != 0) { // the segments are NOT on a vertical line if ( inSeg1Pt1.x < inSeg1Pt2.x ) { seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.x; seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.x; } else { seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.x; seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.x; } if ( inSeg2Pt1.x < inSeg2Pt2.x ) { seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.x; seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.x; } else { seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.x; seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.x; } } else { // the segments are on a vertical line if ( inSeg1Pt1.y < inSeg1Pt2.y ) { seg1min = inSeg1Pt1; seg1minVal = inSeg1Pt1.y; seg1max = inSeg1Pt2; seg1maxVal = inSeg1Pt2.y; } else { seg1min = inSeg1Pt2; seg1minVal = inSeg1Pt2.y; seg1max = inSeg1Pt1; seg1maxVal = inSeg1Pt1.y; } if ( inSeg2Pt1.y < inSeg2Pt2.y ) { seg2min = inSeg2Pt1; seg2minVal = inSeg2Pt1.y; seg2max = inSeg2Pt2; seg2maxVal = inSeg2Pt2.y; } else { seg2min = inSeg2Pt2; seg2minVal = inSeg2Pt2.y; seg2max = inSeg2Pt1; seg2maxVal = inSeg2Pt1.y; } } if ( seg1minVal <= seg2minVal ) { if ( seg1maxVal < seg2minVal ) return []; if ( seg1maxVal == seg2minVal ) { if ( inExcludeAdjacentSegs ) return []; return [ seg2min ]; } if ( seg1maxVal <= seg2maxVal ) return [ seg2min, seg1max ]; return [ seg2min, seg2max ]; } else { if ( seg1minVal > seg2maxVal ) return []; if ( seg1minVal == seg2maxVal ) { if ( inExcludeAdjacentSegs ) return []; return [ seg1min ]; } if ( seg1maxVal <= seg2maxVal ) return [ seg1min, seg1max ]; return [ seg1min, seg2max ]; } } } function isPointInsideAngle( inVertex, inLegFromPt, inLegToPt, inOtherPt ) { // The order of legs is important var EPSILON = 0.0000000001; // translation of all points, so that Vertex is at (0,0) var legFromPtX = inLegFromPt.x - inVertex.x, legFromPtY = inLegFromPt.y - inVertex.y; var legToPtX = inLegToPt.x - inVertex.x, legToPtY = inLegToPt.y - inVertex.y; var otherPtX = inOtherPt.x - inVertex.x, otherPtY = inOtherPt.y - inVertex.y; // main angle >0: < 180 deg.; 0: 180 deg.; <0: > 180 deg. var from2toAngle = legFromPtX * legToPtY - legFromPtY * legToPtX; var from2otherAngle = legFromPtX * otherPtY - legFromPtY * otherPtX; if ( Math.abs(from2toAngle) > EPSILON ) { // angle != 180 deg. var other2toAngle = otherPtX * legToPtY - otherPtY * legToPtX; // console.log( "from2to: " + from2toAngle + ", from2other: " + from2otherAngle + ", other2to: " + other2toAngle ); if ( from2toAngle > 0 ) { // main angle < 180 deg. return ( ( from2otherAngle >= 0 ) && ( other2toAngle >= 0 ) ); } else { // main angle > 180 deg. return ( ( from2otherAngle >= 0 ) || ( other2toAngle >= 0 ) ); } } else { // angle == 180 deg. // console.log( "from2to: 180 deg., from2other: " + from2otherAngle ); return ( from2otherAngle > 0 ); } } function removeHoles( contour, holes ) { var shape = contour.concat(); // work on this shape var hole; function isCutLineInsideAngles( inShapeIdx, inHoleIdx ) { // Check if hole point lies within angle around shape point var lastShapeIdx = shape.length - 1; var prevShapeIdx = inShapeIdx - 1; if ( prevShapeIdx < 0 ) prevShapeIdx = lastShapeIdx; var nextShapeIdx = inShapeIdx + 1; if ( nextShapeIdx > lastShapeIdx ) nextShapeIdx = 0; var insideAngle = isPointInsideAngle( shape[inShapeIdx], shape[ prevShapeIdx ], shape[ nextShapeIdx ], hole[inHoleIdx] ); if (! insideAngle ) { // console.log( "Vertex (Shape): " + inShapeIdx + ", Point: " + hole[inHoleIdx].x + "/" + hole[inHoleIdx].y ); return false; } // Check if shape point lies within angle around hole point var lastHoleIdx = hole.length - 1; var prevHoleIdx = inHoleIdx - 1; if ( prevHoleIdx < 0 ) prevHoleIdx = lastHoleIdx; var nextHoleIdx = inHoleIdx + 1; if ( nextHoleIdx > lastHoleIdx ) nextHoleIdx = 0; insideAngle = isPointInsideAngle( hole[inHoleIdx], hole[ prevHoleIdx ], hole[ nextHoleIdx ], shape[inShapeIdx] ); if (! insideAngle ) { // console.log( "Vertex (Hole): " + inHoleIdx + ", Point: " + shape[inShapeIdx].x + "/" + shape[inShapeIdx].y ); return false; } return true; } function intersectsShapeEdge( inShapePt, inHolePt ) { // checks for intersections with shape edges var sIdx, nextIdx, intersection; for ( sIdx = 0; sIdx < shape.length; sIdx++ ) { nextIdx = sIdx+1; nextIdx %= shape.length; intersection = intersect_segments_2D( inShapePt, inHolePt, shape[sIdx], shape[nextIdx], true ); if ( intersection.length > 0 ) return true; } return false; } var indepHoles = []; function intersectsHoleEdge( inShapePt, inHolePt ) { // checks for intersections with hole edges var ihIdx, chkHole, hIdx, nextIdx, intersection; for ( ihIdx = 0; ihIdx < indepHoles.length; ihIdx++ ) { chkHole = holes[indepHoles[ihIdx]]; for ( hIdx = 0; hIdx < chkHole.length; hIdx++ ) { nextIdx = hIdx+1; nextIdx %= chkHole.length; intersection = intersect_segments_2D( inShapePt, inHolePt, chkHole[hIdx], chkHole[nextIdx], true ); if ( intersection.length > 0 ) return true; } } return false; } var holeIndex, shapeIndex, shapePt, holePt, holeIdx, cutKey, failedCuts = [], tmpShape1, tmpShape2, tmpHole1, tmpHole2; for ( var h = 0, hl = holes.length; h < hl; h ++ ) { indepHoles.push( h ); } var counter = indepHoles.length * 2; while ( indepHoles.length > 0 ) { counter --; if ( counter < 0 ) { console.log( "Infinite Loop! Holes left:" + indepHoles.length + ", Probably Hole outside Shape!" ); break; } // search for shape-vertex and hole-vertex, // which can be connected without intersections for ( shapeIndex = 0; shapeIndex < shape.length; shapeIndex++ ) { shapePt = shape[ shapeIndex ]; holeIndex = -1; // search for hole which can be reached without intersections for ( var h = 0; h < indepHoles.length; h ++ ) { holeIdx = indepHoles[h]; // prevent multiple checks cutKey = shapePt.x + ":" + shapePt.y + ":" + holeIdx; if ( failedCuts[cutKey] !== undefined ) continue; hole = holes[holeIdx]; for ( var h2 = 0; h2 < hole.length; h2 ++ ) { holePt = hole[ h2 ]; if (! isCutLineInsideAngles( shapeIndex, h2 ) ) continue; if ( intersectsShapeEdge( shapePt, holePt ) ) continue; if ( intersectsHoleEdge( shapePt, holePt ) ) continue; holeIndex = h2; indepHoles.splice(h,1); tmpShape1 = shape.slice( 0, shapeIndex+1 ); tmpShape2 = shape.slice( shapeIndex ); tmpHole1 = hole.slice( holeIndex ); tmpHole2 = hole.slice( 0, holeIndex+1 ); shape = tmpShape1.concat( tmpHole1 ).concat( tmpHole2 ).concat( tmpShape2 ); // Debug only, to show the selected cuts // glob_CutLines.push( [ shapePt, holePt ] ); break; } if ( holeIndex >= 0 ) break; // hole-vertex found failedCuts[cutKey] = true; // remember failure } if ( holeIndex >= 0 ) break; // hole-vertex found } } return shape; /* shape with no holes */ } var i, il, f, face, key, index, allPointsMap = {}; // To maintain reference to old shape, one must match coordinates, or offset the indices from original arrays. It's probably easier to do the first. var allpoints = contour.concat(); for ( var h = 0, hl = holes.length; h < hl; h ++ ) { Array.prototype.push.apply( allpoints, holes[h] ); } //console.log( "allpoints",allpoints, allpoints.length ); // prepare all points map for ( i = 0, il = allpoints.length; i < il; i ++ ) { key = allpoints[ i ].x + ":" + allpoints[ i ].y; if ( allPointsMap[ key ] !== undefined ) { console.log( "Duplicate point", key ); } allPointsMap[ key ] = i; } // remove holes by cutting paths to holes and adding them to the shape var shapeWithoutHoles = removeHoles( contour, holes ); var triangles = THREE.FontUtils.Triangulate( shapeWithoutHoles, false ); // True returns indices for points of spooled shape //console.log( "triangles",triangles, triangles.length ); // check all face vertices against all points map for ( i = 0, il = triangles.length; i < il; i ++ ) { face = triangles[ i ]; for ( f = 0; f < 3; f ++ ) { key = face[ f ].x + ":" + face[ f ].y; index = allPointsMap[ key ]; if ( index !== undefined ) { face[ f ] = index; } } } return triangles.concat(); }, isClockWise: function ( pts ) { return THREE.FontUtils.Triangulate.area( pts ) < 0; }, // Bezier Curves formulas obtained from // http://en.wikipedia.org/wiki/B%C3%A9zier_curve // Quad Bezier Functions b2p0: function ( t, p ) { var k = 1 - t; return k * k * p; }, b2p1: function ( t, p ) { return 2 * ( 1 - t ) * t * p; }, b2p2: function ( t, p ) { return t * t * p; }, b2: function ( t, p0, p1, p2 ) { return this.b2p0( t, p0 ) + this.b2p1( t, p1 ) + this.b2p2( t, p2 ); }, // Cubic Bezier Functions b3p0: function ( t, p ) { var k = 1 - t; return k * k * k * p; }, b3p1: function ( t, p ) { var k = 1 - t; return 3 * k * k * t * p; }, b3p2: function ( t, p ) { var k = 1 - t; return 3 * k * t * t * p; }, b3p3: function ( t, p ) { return t * t * t * p; }, b3: function ( t, p0, p1, p2, p3 ) { return this.b3p0( t, p0 ) + this.b3p1( t, p1 ) + this.b3p2( t, p2 ) + this.b3p3( t, p3 ); } }; /************************************************************** * Line **************************************************************/ THREE.LineCurve = function ( v1, v2 ) { this.v1 = v1; this.v2 = v2; }; THREE.LineCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.LineCurve.prototype.getPoint = function ( t ) { var point = this.v2.clone().sub(this.v1); point.multiplyScalar( t ).add( this.v1 ); return point; }; // Line curve is linear, so we can overwrite default getPointAt THREE.LineCurve.prototype.getPointAt = function ( u ) { return this.getPoint( u ); }; THREE.LineCurve.prototype.getTangent = function( t ) { var tangent = this.v2.clone().sub(this.v1); return tangent.normalize(); };/************************************************************** * Quadratic Bezier curve **************************************************************/ THREE.QuadraticBezierCurve = function ( v0, v1, v2 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; }; THREE.QuadraticBezierCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.QuadraticBezierCurve.prototype.getPoint = function ( t ) { var tx, ty; tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); return new THREE.Vector2( tx, ty ); }; THREE.QuadraticBezierCurve.prototype.getTangent = function( t ) { var tx, ty; tx = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.x, this.v1.x, this.v2.x ); ty = THREE.Curve.Utils.tangentQuadraticBezier( t, this.v0.y, this.v1.y, this.v2.y ); // returns unit vector var tangent = new THREE.Vector2( tx, ty ); tangent.normalize(); return tangent; };/************************************************************** * Cubic Bezier curve **************************************************************/ THREE.CubicBezierCurve = function ( v0, v1, v2, v3 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; this.v3 = v3; }; THREE.CubicBezierCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.CubicBezierCurve.prototype.getPoint = function ( t ) { var tx, ty; tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); return new THREE.Vector2( tx, ty ); }; THREE.CubicBezierCurve.prototype.getTangent = function( t ) { var tx, ty; tx = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); ty = THREE.Curve.Utils.tangentCubicBezier( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); var tangent = new THREE.Vector2( tx, ty ); tangent.normalize(); return tangent; };/************************************************************** * Spline curve **************************************************************/ THREE.SplineCurve = function ( points /* array of Vector2 */ ) { this.points = (points == undefined) ? [] : points; }; THREE.SplineCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.SplineCurve.prototype.getPoint = function ( t ) { var v = new THREE.Vector2(); var c = []; var points = this.points, point, intPoint, weight; point = ( points.length - 1 ) * t; intPoint = Math.floor( point ); weight = point - intPoint; c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; c[ 1 ] = intPoint; c[ 2 ] = intPoint > points.length - 2 ? points.length -1 : intPoint + 1; c[ 3 ] = intPoint > points.length - 3 ? points.length -1 : intPoint + 2; v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); return v; };/************************************************************** * Ellipse curve **************************************************************/ THREE.EllipseCurve = function ( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise ) { this.aX = aX; this.aY = aY; this.xRadius = xRadius; this.yRadius = yRadius; this.aStartAngle = aStartAngle; this.aEndAngle = aEndAngle; this.aClockwise = aClockwise; }; THREE.EllipseCurve.prototype = Object.create( THREE.Curve.prototype ); THREE.EllipseCurve.prototype.getPoint = function ( t ) { var angle; var deltaAngle = this.aEndAngle - this.aStartAngle; if ( deltaAngle < 0 ) deltaAngle += Math.PI * 2; if ( deltaAngle > Math.PI * 2 ) deltaAngle -= Math.PI * 2; if ( this.aClockwise === true ) { angle = this.aEndAngle + ( 1 - t ) * ( Math.PI * 2 - deltaAngle ); } else { angle = this.aStartAngle + t * deltaAngle; } var tx = this.aX + this.xRadius * Math.cos( angle ); var ty = this.aY + this.yRadius * Math.sin( angle ); return new THREE.Vector2( tx, ty ); }; /************************************************************** * Arc curve **************************************************************/ THREE.ArcCurve = function ( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) { THREE.EllipseCurve.call( this, aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise ); }; THREE.ArcCurve.prototype = Object.create( THREE.EllipseCurve.prototype );/************************************************************** * Line3D **************************************************************/ THREE.LineCurve3 = THREE.Curve.create( function ( v1, v2 ) { this.v1 = v1; this.v2 = v2; }, function ( t ) { var r = new THREE.Vector3(); r.subVectors( this.v2, this.v1 ); // diff r.multiplyScalar( t ); r.add( this.v1 ); return r; } ); /************************************************************** * Quadratic Bezier 3D curve **************************************************************/ THREE.QuadraticBezierCurve3 = THREE.Curve.create( function ( v0, v1, v2 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; }, function ( t ) { var tx, ty, tz; tx = THREE.Shape.Utils.b2( t, this.v0.x, this.v1.x, this.v2.x ); ty = THREE.Shape.Utils.b2( t, this.v0.y, this.v1.y, this.v2.y ); tz = THREE.Shape.Utils.b2( t, this.v0.z, this.v1.z, this.v2.z ); return new THREE.Vector3( tx, ty, tz ); } );/************************************************************** * Cubic Bezier 3D curve **************************************************************/ THREE.CubicBezierCurve3 = THREE.Curve.create( function ( v0, v1, v2, v3 ) { this.v0 = v0; this.v1 = v1; this.v2 = v2; this.v3 = v3; }, function ( t ) { var tx, ty, tz; tx = THREE.Shape.Utils.b3( t, this.v0.x, this.v1.x, this.v2.x, this.v3.x ); ty = THREE.Shape.Utils.b3( t, this.v0.y, this.v1.y, this.v2.y, this.v3.y ); tz = THREE.Shape.Utils.b3( t, this.v0.z, this.v1.z, this.v2.z, this.v3.z ); return new THREE.Vector3( tx, ty, tz ); } );/************************************************************** * Spline 3D curve **************************************************************/ THREE.SplineCurve3 = THREE.Curve.create( function ( points /* array of Vector3 */) { this.points = (points == undefined) ? [] : points; }, function ( t ) { var v = new THREE.Vector3(); var c = []; var points = this.points, point, intPoint, weight; point = ( points.length - 1 ) * t; intPoint = Math.floor( point ); weight = point - intPoint; c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; c[ 1 ] = intPoint; c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; var pt0 = points[ c[0] ], pt1 = points[ c[1] ], pt2 = points[ c[2] ], pt3 = points[ c[3] ]; v.x = THREE.Curve.Utils.interpolate(pt0.x, pt1.x, pt2.x, pt3.x, weight); v.y = THREE.Curve.Utils.interpolate(pt0.y, pt1.y, pt2.y, pt3.y, weight); v.z = THREE.Curve.Utils.interpolate(pt0.z, pt1.z, pt2.z, pt3.z, weight); return v; } ); /* THREE.SplineCurve3.prototype.getTangent = function(t) { var v = new THREE.Vector3(); var c = []; var points = this.points, point, intPoint, weight; point = ( points.length - 1 ) * t; intPoint = Math.floor( point ); weight = point - intPoint; c[ 0 ] = intPoint == 0 ? intPoint : intPoint - 1; c[ 1 ] = intPoint; c[ 2 ] = intPoint > points.length - 2 ? points.length - 1 : intPoint + 1; c[ 3 ] = intPoint > points.length - 3 ? points.length - 1 : intPoint + 2; var pt0 = points[ c[0] ], pt1 = points[ c[1] ], pt2 = points[ c[2] ], pt3 = points[ c[3] ]; // t = weight; v.x = THREE.Curve.Utils.tangentSpline( t, pt0.x, pt1.x, pt2.x, pt3.x ); v.y = THREE.Curve.Utils.tangentSpline( t, pt0.y, pt1.y, pt2.y, pt3.y ); v.z = THREE.Curve.Utils.tangentSpline( t, pt0.z, pt1.z, pt2.z, pt3.z ); return v; }*/ /************************************************************** * Closed Spline 3D curve **************************************************************/ THREE.ClosedSplineCurve3 = THREE.Curve.create( function ( points /* array of Vector3 */) { this.points = (points == undefined) ? [] : points; }, function ( t ) { var v = new THREE.Vector3(); var c = []; var points = this.points, point, intPoint, weight; point = ( points.length - 0 ) * t; // This needs to be from 0-length +1 intPoint = Math.floor( point ); weight = point - intPoint; intPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / points.length ) + 1 ) * points.length; c[ 0 ] = ( intPoint - 1 ) % points.length; c[ 1 ] = ( intPoint ) % points.length; c[ 2 ] = ( intPoint + 1 ) % points.length; c[ 3 ] = ( intPoint + 2 ) % points.length; v.x = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].x, points[ c[ 1 ] ].x, points[ c[ 2 ] ].x, points[ c[ 3 ] ].x, weight ); v.y = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].y, points[ c[ 1 ] ].y, points[ c[ 2 ] ].y, points[ c[ 3 ] ].y, weight ); v.z = THREE.Curve.Utils.interpolate( points[ c[ 0 ] ].z, points[ c[ 1 ] ].z, points[ c[ 2 ] ].z, points[ c[ 3 ] ].z, weight ); return v; } );/** * @author mikael emtinger / http://gomo.se/ */ THREE.AnimationHandler = (function() { var playing = []; var library = {}; var that = {}; //--- update --- that.update = function( deltaTimeMS ) { for( var i = 0; i < playing.length; i ++ ) playing[ i ].update( deltaTimeMS ); }; //--- add --- that.addToUpdate = function( animation ) { if ( playing.indexOf( animation ) === -1 ) playing.push( animation ); }; //--- remove --- that.removeFromUpdate = function( animation ) { var index = playing.indexOf( animation ); if( index !== -1 ) playing.splice( index, 1 ); }; //--- add --- that.add = function( data ) { if ( library[ data.name ] !== undefined ) console.log( "THREE.AnimationHandler.add: Warning! " + data.name + " already exists in library. Overwriting." ); library[ data.name ] = data; initData( data ); }; //--- get --- that.get = function( name ) { if ( typeof name === "string" ) { if ( library[ name ] ) { return library[ name ]; } else { console.log( "THREE.AnimationHandler.get: Couldn't find animation " + name ); return null; } } else { // todo: add simple tween library } }; //--- parse --- that.parse = function( root ) { // setup hierarchy var hierarchy = []; if ( root instanceof THREE.SkinnedMesh ) { for( var b = 0; b < root.bones.length; b++ ) { hierarchy.push( root.bones[ b ] ); } } else { parseRecurseHierarchy( root, hierarchy ); } return hierarchy; }; var parseRecurseHierarchy = function( root, hierarchy ) { hierarchy.push( root ); for( var c = 0; c < root.children.length; c++ ) parseRecurseHierarchy( root.children[ c ], hierarchy ); } //--- init data --- var initData = function( data ) { if( data.initialized === true ) return; // loop through all keys for( var h = 0; h < data.hierarchy.length; h ++ ) { for( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { // remove minus times if( data.hierarchy[ h ].keys[ k ].time < 0 ) data.hierarchy[ h ].keys[ k ].time = 0; // create quaternions if( data.hierarchy[ h ].keys[ k ].rot !== undefined && !( data.hierarchy[ h ].keys[ k ].rot instanceof THREE.Quaternion ) ) { var quat = data.hierarchy[ h ].keys[ k ].rot; data.hierarchy[ h ].keys[ k ].rot = new THREE.Quaternion( quat[0], quat[1], quat[2], quat[3] ); } } // prepare morph target keys if( data.hierarchy[ h ].keys.length && data.hierarchy[ h ].keys[ 0 ].morphTargets !== undefined ) { // get all used var usedMorphTargets = {}; for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { var morphTargetName = data.hierarchy[ h ].keys[ k ].morphTargets[ m ]; usedMorphTargets[ morphTargetName ] = -1; } } data.hierarchy[ h ].usedMorphTargets = usedMorphTargets; // set all used on all frames for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { var influences = {}; for ( var morphTargetName in usedMorphTargets ) { for ( var m = 0; m < data.hierarchy[ h ].keys[ k ].morphTargets.length; m ++ ) { if ( data.hierarchy[ h ].keys[ k ].morphTargets[ m ] === morphTargetName ) { influences[ morphTargetName ] = data.hierarchy[ h ].keys[ k ].morphTargetsInfluences[ m ]; break; } } if ( m === data.hierarchy[ h ].keys[ k ].morphTargets.length ) { influences[ morphTargetName ] = 0; } } data.hierarchy[ h ].keys[ k ].morphTargetsInfluences = influences; } } // remove all keys that are on the same time for ( var k = 1; k < data.hierarchy[ h ].keys.length; k ++ ) { if ( data.hierarchy[ h ].keys[ k ].time === data.hierarchy[ h ].keys[ k - 1 ].time ) { data.hierarchy[ h ].keys.splice( k, 1 ); k --; } } // set index for ( var k = 0; k < data.hierarchy[ h ].keys.length; k ++ ) { data.hierarchy[ h ].keys[ k ].index = k; } } // done data.initialized = true; }; // interpolation types that.LINEAR = 0; that.CATMULLROM = 1; that.CATMULLROM_FORWARD = 2; return that; }()); /** * @author mikael emtinger / http://gomo.se/ * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ */ THREE.Animation = function ( root, name ) { this.root = root; this.data = THREE.AnimationHandler.get( name ); this.hierarchy = THREE.AnimationHandler.parse( root ); this.currentTime = 0; this.timeScale = 1; this.isPlaying = false; this.isPaused = true; this.loop = true; this.interpolationType = THREE.AnimationHandler.LINEAR; }; THREE.Animation.prototype.play = function ( startTime ) { this.currentTime = startTime !== undefined ? startTime : 0; if ( this.isPlaying === false ) { this.isPlaying = true; this.reset(); this.update( 0 ); } this.isPaused = false; THREE.AnimationHandler.addToUpdate( this ); }; THREE.Animation.prototype.pause = function() { if ( this.isPaused === true ) { THREE.AnimationHandler.addToUpdate( this ); } else { THREE.AnimationHandler.removeFromUpdate( this ); } this.isPaused = !this.isPaused; }; THREE.Animation.prototype.stop = function() { this.isPlaying = false; this.isPaused = false; THREE.AnimationHandler.removeFromUpdate( this ); }; THREE.Animation.prototype.reset = function () { for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { var object = this.hierarchy[ h ]; object.matrixAutoUpdate = true; if ( object.animationCache === undefined ) { object.animationCache = {}; object.animationCache.prevKey = { pos: 0, rot: 0, scl: 0 }; object.animationCache.nextKey = { pos: 0, rot: 0, scl: 0 }; object.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; } var prevKey = object.animationCache.prevKey; var nextKey = object.animationCache.nextKey; prevKey.pos = this.data.hierarchy[ h ].keys[ 0 ]; prevKey.rot = this.data.hierarchy[ h ].keys[ 0 ]; prevKey.scl = this.data.hierarchy[ h ].keys[ 0 ]; nextKey.pos = this.getNextKeyWith( "pos", h, 1 ); nextKey.rot = this.getNextKeyWith( "rot", h, 1 ); nextKey.scl = this.getNextKeyWith( "scl", h, 1 ); } }; THREE.Animation.prototype.update = (function(){ var points = []; var target = new THREE.Vector3(); // Catmull-Rom spline var interpolateCatmullRom = function ( points, scale ) { var c = [], v3 = [], point, intPoint, weight, w2, w3, pa, pb, pc, pd; point = ( points.length - 1 ) * scale; intPoint = Math.floor( point ); weight = point - intPoint; c[ 0 ] = intPoint === 0 ? intPoint : intPoint - 1; c[ 1 ] = intPoint; c[ 2 ] = intPoint > points.length - 2 ? intPoint : intPoint + 1; c[ 3 ] = intPoint > points.length - 3 ? intPoint : intPoint + 2; pa = points[ c[ 0 ] ]; pb = points[ c[ 1 ] ]; pc = points[ c[ 2 ] ]; pd = points[ c[ 3 ] ]; w2 = weight * weight; w3 = weight * w2; v3[ 0 ] = interpolate( pa[ 0 ], pb[ 0 ], pc[ 0 ], pd[ 0 ], weight, w2, w3 ); v3[ 1 ] = interpolate( pa[ 1 ], pb[ 1 ], pc[ 1 ], pd[ 1 ], weight, w2, w3 ); v3[ 2 ] = interpolate( pa[ 2 ], pb[ 2 ], pc[ 2 ], pd[ 2 ], weight, w2, w3 ); return v3; }; var interpolate = function ( p0, p1, p2, p3, t, t2, t3 ) { var v0 = ( p2 - p0 ) * 0.5, v1 = ( p3 - p1 ) * 0.5; return ( 2 * ( p1 - p2 ) + v0 + v1 ) * t3 + ( - 3 * ( p1 - p2 ) - 2 * v0 - v1 ) * t2 + v0 * t + p1; }; return function ( delta ) { if ( this.isPlaying === false ) return; this.currentTime += delta * this.timeScale; // var vector; var types = [ "pos", "rot", "scl" ]; var duration = this.data.length; if ( this.loop === true && this.currentTime > duration ) { this.currentTime %= duration; this.reset(); } else if ( this.loop === false && this.currentTime > duration ) { this.stop(); return; } this.currentTime = Math.min( this.currentTime, duration ); for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { var object = this.hierarchy[ h ]; var animationCache = object.animationCache; // loop through pos/rot/scl for ( var t = 0; t < 3; t ++ ) { // get keys var type = types[ t ]; var prevKey = animationCache.prevKey[ type ]; var nextKey = animationCache.nextKey[ type ]; if ( nextKey.time <= this.currentTime ) { prevKey = this.data.hierarchy[ h ].keys[ 0 ]; nextKey = this.getNextKeyWith( type, h, 1 ); while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { prevKey = nextKey; nextKey = this.getNextKeyWith( type, h, nextKey.index + 1 ); } animationCache.prevKey[ type ] = prevKey; animationCache.nextKey[ type ] = nextKey; } object.matrixAutoUpdate = true; object.matrixWorldNeedsUpdate = true; var scale = ( this.currentTime - prevKey.time ) / ( nextKey.time - prevKey.time ); var prevXYZ = prevKey[ type ]; var nextXYZ = nextKey[ type ]; if ( scale < 0 ) scale = 0; if ( scale > 1 ) scale = 1; // interpolate if ( type === "pos" ) { vector = object.position; if ( this.interpolationType === THREE.AnimationHandler.LINEAR ) { vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; } else if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { points[ 0 ] = this.getPrevKeyWith( "pos", h, prevKey.index - 1 )[ "pos" ]; points[ 1 ] = prevXYZ; points[ 2 ] = nextXYZ; points[ 3 ] = this.getNextKeyWith( "pos", h, nextKey.index + 1 )[ "pos" ]; scale = scale * 0.33 + 0.33; var currentPoint = interpolateCatmullRom( points, scale ); vector.x = currentPoint[ 0 ]; vector.y = currentPoint[ 1 ]; vector.z = currentPoint[ 2 ]; if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { var forwardPoint = interpolateCatmullRom( points, scale * 1.01 ); target.set( forwardPoint[ 0 ], forwardPoint[ 1 ], forwardPoint[ 2 ] ); target.sub( vector ); target.y = 0; target.normalize(); var angle = Math.atan2( target.x, target.z ); object.rotation.set( 0, angle, 0 ); } } } else if ( type === "rot" ) { THREE.Quaternion.slerp( prevXYZ, nextXYZ, object.quaternion, scale ); } else if ( type === "scl" ) { vector = object.scale; vector.x = prevXYZ[ 0 ] + ( nextXYZ[ 0 ] - prevXYZ[ 0 ] ) * scale; vector.y = prevXYZ[ 1 ] + ( nextXYZ[ 1 ] - prevXYZ[ 1 ] ) * scale; vector.z = prevXYZ[ 2 ] + ( nextXYZ[ 2 ] - prevXYZ[ 2 ] ) * scale; } } } }; })(); // Get next key with THREE.Animation.prototype.getNextKeyWith = function ( type, h, key ) { var keys = this.data.hierarchy[ h ].keys; if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { key = key < keys.length - 1 ? key : keys.length - 1; } else { key = key % keys.length; } for ( ; key < keys.length; key++ ) { if ( keys[ key ][ type ] !== undefined ) { return keys[ key ]; } } return this.data.hierarchy[ h ].keys[ 0 ]; }; // Get previous key with THREE.Animation.prototype.getPrevKeyWith = function ( type, h, key ) { var keys = this.data.hierarchy[ h ].keys; if ( this.interpolationType === THREE.AnimationHandler.CATMULLROM || this.interpolationType === THREE.AnimationHandler.CATMULLROM_FORWARD ) { key = key > 0 ? key : 0; } else { key = key >= 0 ? key : key + keys.length; } for ( ; key >= 0; key -- ) { if ( keys[ key ][ type ] !== undefined ) { return keys[ key ]; } } return this.data.hierarchy[ h ].keys[ keys.length - 1 ]; }; /** * @author mikael emtinger / http://gomo.se/ * @author mrdoob / http://mrdoob.com/ * @author alteredq / http://alteredqualia.com/ * @author khang duong * @author erik kitson */ THREE.KeyFrameAnimation = function ( root, data ) { this.root = root; this.data = THREE.AnimationHandler.get( data ); this.hierarchy = THREE.AnimationHandler.parse( root ); this.currentTime = 0; this.timeScale = 0.001; this.isPlaying = false; this.isPaused = true; this.loop = true; // initialize to first keyframes for ( var h = 0, hl = this.hierarchy.length; h < hl; h ++ ) { var keys = this.data.hierarchy[h].keys, sids = this.data.hierarchy[h].sids, obj = this.hierarchy[h]; if ( keys.length && sids ) { for ( var s = 0; s < sids.length; s++ ) { var sid = sids[ s ], next = this.getNextKeyWith( sid, h, 0 ); if ( next ) { next.apply( sid ); } } obj.matrixAutoUpdate = false; this.data.hierarchy[h].node.updateMatrix(); obj.matrixWorldNeedsUpdate = true; } } }; // Play THREE.KeyFrameAnimation.prototype.play = function ( startTime ) { this.currentTime = startTime !== undefined ? startTime : 0; if ( this.isPlaying === false ) { this.isPlaying = true; // reset key cache var h, hl = this.hierarchy.length, object, node; for ( h = 0; h < hl; h++ ) { object = this.hierarchy[ h ]; node = this.data.hierarchy[ h ]; if ( node.animationCache === undefined ) { node.animationCache = {}; node.animationCache.prevKey = null; node.animationCache.nextKey = null; node.animationCache.originalMatrix = object instanceof THREE.Bone ? object.skinMatrix : object.matrix; } var keys = this.data.hierarchy[h].keys; if (keys.length) { node.animationCache.prevKey = keys[ 0 ]; node.animationCache.nextKey = keys[ 1 ]; this.startTime = Math.min( keys[0].time, this.startTime ); this.endTime = Math.max( keys[keys.length - 1].time, this.endTime ); } } this.update( 0 ); } this.isPaused = false; THREE.AnimationHandler.addToUpdate( this ); }; // Pause THREE.KeyFrameAnimation.prototype.pause = function() { if( this.isPaused ) { THREE.AnimationHandler.addToUpdate( this ); } else { THREE.AnimationHandler.removeFromUpdate( this ); } this.isPaused = !this.isPaused; }; // Stop THREE.KeyFrameAnimation.prototype.stop = function() { this.isPlaying = false; this.isPaused = false; THREE.AnimationHandler.removeFromUpdate( this ); // reset JIT matrix and remove cache for ( var h = 0; h < this.data.hierarchy.length; h++ ) { var obj = this.hierarchy[ h ]; var node = this.data.hierarchy[ h ]; if ( node.animationCache !== undefined ) { var original = node.animationCache.originalMatrix; if( obj instanceof THREE.Bone ) { original.copy( obj.skinMatrix ); obj.skinMatrix = original; } else { original.copy( obj.matrix ); obj.matrix = original; } delete node.animationCache; } } }; // Update THREE.KeyFrameAnimation.prototype.update = function ( delta ) { if ( this.isPlaying === false ) return; this.currentTime += delta * this.timeScale; // var duration = this.data.length; if ( this.loop === true && this.currentTime > duration ) { this.currentTime %= duration; } this.currentTime = Math.min( this.currentTime, duration ); for ( var h = 0, hl = this.hierarchy.length; h < hl; h++ ) { var object = this.hierarchy[ h ]; var node = this.data.hierarchy[ h ]; var keys = node.keys, animationCache = node.animationCache; if ( keys.length ) { var prevKey = animationCache.prevKey; var nextKey = animationCache.nextKey; if ( nextKey.time <= this.currentTime ) { while ( nextKey.time < this.currentTime && nextKey.index > prevKey.index ) { prevKey = nextKey; nextKey = keys[ prevKey.index + 1 ]; } animationCache.prevKey = prevKey; animationCache.nextKey = nextKey; } if ( nextKey.time >= this.currentTime ) { prevKey.interpolate( nextKey, this.currentTime ); } else { prevKey.interpolate( nextKey, nextKey.time ); } this.data.hierarchy[ h ].node.updateMatrix(); object.matrixWorldNeedsUpdate = true; } } }; // Get next key with THREE.KeyFrameAnimation.prototype.getNextKeyWith = function( sid, h, key ) { var keys = this.data.hierarchy[ h ].keys; key = key % keys.length; for ( ; key < keys.length; key++ ) { if ( keys[ key ].hasTarget( sid ) ) { return keys[ key ]; } } return keys[ 0 ]; }; // Get previous key with THREE.KeyFrameAnimation.prototype.getPrevKeyWith = function( sid, h, key ) { var keys = this.data.hierarchy[ h ].keys; key = key >= 0 ? key : key + keys.length; for ( ; key >= 0; key-- ) { if ( keys[ key ].hasTarget( sid ) ) { return keys[ key ]; } } return keys[ keys.length - 1 ]; }; /** * @author mrdoob / http://mrdoob.com */ THREE.MorphAnimation = function ( mesh ) { this.mesh = mesh; this.frames = mesh.morphTargetInfluences.length; this.currentTime = 0; this.duration = 1000; this.loop = true; this.isPlaying = false; }; THREE.MorphAnimation.prototype = { play: function () { this.isPlaying = true; }, pause: function () { this.isPlaying = false; }, update: ( function () { var lastFrame = 0; var currentFrame = 0; return function ( delta ) { if ( this.isPlaying === false ) return; this.currentTime += delta; if ( this.loop === true && this.currentTime > this.duration ) { this.currentTime %= this.duration; } this.currentTime = Math.min( this.currentTime, this.duration ); var interpolation = this.duration / this.frames; var frame = Math.floor( this.currentTime / interpolation ); if ( frame != currentFrame ) { this.mesh.morphTargetInfluences[ lastFrame ] = 0; this.mesh.morphTargetInfluences[ currentFrame ] = 1; this.mesh.morphTargetInfluences[ frame ] = 0; lastFrame = currentFrame; currentFrame = frame; } this.mesh.morphTargetInfluences[ frame ] = ( this.currentTime % interpolation ) / interpolation; this.mesh.morphTargetInfluences[ lastFrame ] = 1 - this.mesh.morphTargetInfluences[ frame ]; } } )() }; /** * Camera for rendering cube maps * - renders scene into axis-aligned cube * * @author alteredq / http://alteredqualia.com/ */ THREE.CubeCamera = function ( near, far, cubeResolution ) { THREE.Object3D.call( this ); var fov = 90, aspect = 1; var cameraPX = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraPX.up.set( 0, -1, 0 ); cameraPX.lookAt( new THREE.Vector3( 1, 0, 0 ) ); this.add( cameraPX ); var cameraNX = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraNX.up.set( 0, -1, 0 ); cameraNX.lookAt( new THREE.Vector3( -1, 0, 0 ) ); this.add( cameraNX ); var cameraPY = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraPY.up.set( 0, 0, 1 ); cameraPY.lookAt( new THREE.Vector3( 0, 1, 0 ) ); this.add( cameraPY ); var cameraNY = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraNY.up.set( 0, 0, -1 ); cameraNY.lookAt( new THREE.Vector3( 0, -1, 0 ) ); this.add( cameraNY ); var cameraPZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraPZ.up.set( 0, -1, 0 ); cameraPZ.lookAt( new THREE.Vector3( 0, 0, 1 ) ); this.add( cameraPZ ); var cameraNZ = new THREE.PerspectiveCamera( fov, aspect, near, far ); cameraNZ.up.set( 0, -1, 0 ); cameraNZ.lookAt( new THREE.Vector3( 0, 0, -1 ) ); this.add( cameraNZ ); this.renderTarget = new THREE.WebGLRenderTargetCube( cubeResolution, cubeResolution, { format: THREE.RGBFormat, magFilter: THREE.LinearFilter, minFilter: THREE.LinearFilter } ); this.updateCubeMap = function ( renderer, scene ) { var renderTarget = this.renderTarget; var generateMipmaps = renderTarget.generateMipmaps; renderTarget.generateMipmaps = false; renderTarget.activeCubeFace = 0; renderer.render( scene, cameraPX, renderTarget ); renderTarget.activeCubeFace = 1; renderer.render( scene, cameraNX, renderTarget ); renderTarget.activeCubeFace = 2; renderer.render( scene, cameraPY, renderTarget ); renderTarget.activeCubeFace = 3; renderer.render( scene, cameraNY, renderTarget ); renderTarget.activeCubeFace = 4; renderer.render( scene, cameraPZ, renderTarget ); renderTarget.generateMipmaps = generateMipmaps; renderTarget.activeCubeFace = 5; renderer.render( scene, cameraNZ, renderTarget ); }; }; THREE.CubeCamera.prototype = Object.create( THREE.Object3D.prototype ); /** * @author zz85 / http://twitter.com/blurspline / http://www.lab4games.net/zz85/blog * * A general perpose camera, for setting FOV, Lens Focal Length, * and switching between perspective and orthographic views easily. * Use this only if you do not wish to manage * both a Orthographic and Perspective Camera * */ THREE.CombinedCamera = function ( width, height, fov, near, far, orthoNear, orthoFar ) { THREE.Camera.call( this ); this.fov = fov; this.left = -width / 2; this.right = width / 2 this.top = height / 2; this.bottom = -height / 2; // We could also handle the projectionMatrix internally, but just wanted to test nested camera objects this.cameraO = new THREE.OrthographicCamera( width / - 2, width / 2, height / 2, height / - 2, orthoNear, orthoFar ); this.cameraP = new THREE.PerspectiveCamera( fov, width / height, near, far ); this.zoom = 1; this.toPerspective(); var aspect = width/height; }; THREE.CombinedCamera.prototype = Object.create( THREE.Camera.prototype ); THREE.CombinedCamera.prototype.toPerspective = function () { // Switches to the Perspective Camera this.near = this.cameraP.near; this.far = this.cameraP.far; this.cameraP.fov = this.fov / this.zoom ; this.cameraP.updateProjectionMatrix(); this.projectionMatrix = this.cameraP.projectionMatrix; this.inPerspectiveMode = true; this.inOrthographicMode = false; }; THREE.CombinedCamera.prototype.toOrthographic = function () { // Switches to the Orthographic camera estimating viewport from Perspective var fov = this.fov; var aspect = this.cameraP.aspect; var near = this.cameraP.near; var far = this.cameraP.far; // The size that we set is the mid plane of the viewing frustum var hyperfocus = ( near + far ) / 2; var halfHeight = Math.tan( fov / 2 ) * hyperfocus; var planeHeight = 2 * halfHeight; var planeWidth = planeHeight * aspect; var halfWidth = planeWidth / 2; halfHeight /= this.zoom; halfWidth /= this.zoom; this.cameraO.left = -halfWidth; this.cameraO.right = halfWidth; this.cameraO.top = halfHeight; this.cameraO.bottom = -halfHeight; // this.cameraO.left = -farHalfWidth; // this.cameraO.right = farHalfWidth; // this.cameraO.top = farHalfHeight; // this.cameraO.bottom = -farHalfHeight; // this.cameraO.left = this.left / this.zoom; // this.cameraO.right = this.right / this.zoom; // this.cameraO.top = this.top / this.zoom; // this.cameraO.bottom = this.bottom / this.zoom; this.cameraO.updateProjectionMatrix(); this.near = this.cameraO.near; this.far = this.cameraO.far; this.projectionMatrix = this.cameraO.projectionMatrix; this.inPerspectiveMode = false; this.inOrthographicMode = true; }; THREE.CombinedCamera.prototype.setSize = function( width, height ) { this.cameraP.aspect = width / height; this.left = -width / 2; this.right = width / 2 this.top = height / 2; this.bottom = -height / 2; }; THREE.CombinedCamera.prototype.setFov = function( fov ) { this.fov = fov; if ( this.inPerspectiveMode ) { this.toPerspective(); } else { this.toOrthographic(); } }; // For mantaining similar API with PerspectiveCamera THREE.CombinedCamera.prototype.updateProjectionMatrix = function() { if ( this.inPerspectiveMode ) { this.toPerspective(); } else { this.toPerspective(); this.toOrthographic(); } }; /* * Uses Focal Length (in mm) to estimate and set FOV * 35mm (fullframe) camera is used if frame size is not specified; * Formula based on http://www.bobatkins.com/photography/technical/field_of_view.html */ THREE.CombinedCamera.prototype.setLens = function ( focalLength, frameHeight ) { if ( frameHeight === undefined ) frameHeight = 24; var fov = 2 * THREE.Math.radToDeg( Math.atan( frameHeight / ( focalLength * 2 ) ) ); this.setFov( fov ); return fov; }; THREE.CombinedCamera.prototype.setZoom = function( zoom ) { this.zoom = zoom; if ( this.inPerspectiveMode ) { this.toPerspective(); } else { this.toOrthographic(); } }; THREE.CombinedCamera.prototype.toFrontView = function() { this.rotation.x = 0; this.rotation.y = 0; this.rotation.z = 0; // should we be modifing the matrix instead? this.rotationAutoUpdate = false; }; THREE.CombinedCamera.prototype.toBackView = function() { this.rotation.x = 0; this.rotation.y = Math.PI; this.rotation.z = 0; this.rotationAutoUpdate = false; }; THREE.CombinedCamera.prototype.toLeftView = function() { this.rotation.x = 0; this.rotation.y = - Math.PI / 2; this.rotation.z = 0; this.rotationAutoUpdate = false; }; THREE.CombinedCamera.prototype.toRightView = function() { this.rotation.x = 0; this.rotation.y = Math.PI / 2; this.rotation.z = 0; this.rotationAutoUpdate = false; }; THREE.CombinedCamera.prototype.toTopView = function() { this.rotation.x = - Math.PI / 2; this.rotation.y = 0; this.rotation.z = 0; this.rotationAutoUpdate = false; }; THREE.CombinedCamera.prototype.toBottomView = function() { this.rotation.x = Math.PI / 2; this.rotation.y = 0; this.rotation.z = 0; this.rotationAutoUpdate = false; }; /** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Cube.as */ THREE.BoxGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) { THREE.Geometry.call( this ); var scope = this; this.width = width; this.height = height; this.depth = depth; this.widthSegments = widthSegments || 1; this.heightSegments = heightSegments || 1; this.depthSegments = depthSegments || 1; var width_half = this.width / 2; var height_half = this.height / 2; var depth_half = this.depth / 2; buildPlane( 'z', 'y', - 1, - 1, this.depth, this.height, width_half, 0 ); // px buildPlane( 'z', 'y', 1, - 1, this.depth, this.height, - width_half, 1 ); // nx buildPlane( 'x', 'z', 1, 1, this.width, this.depth, height_half, 2 ); // py buildPlane( 'x', 'z', 1, - 1, this.width, this.depth, - height_half, 3 ); // ny buildPlane( 'x', 'y', 1, - 1, this.width, this.height, depth_half, 4 ); // pz buildPlane( 'x', 'y', - 1, - 1, this.width, this.height, - depth_half, 5 ); // nz function buildPlane( u, v, udir, vdir, width, height, depth, materialIndex ) { var w, ix, iy, gridX = scope.widthSegments, gridY = scope.heightSegments, width_half = width / 2, height_half = height / 2, offset = scope.vertices.length; if ( ( u === 'x' && v === 'y' ) || ( u === 'y' && v === 'x' ) ) { w = 'z'; } else if ( ( u === 'x' && v === 'z' ) || ( u === 'z' && v === 'x' ) ) { w = 'y'; gridY = scope.depthSegments; } else if ( ( u === 'z' && v === 'y' ) || ( u === 'y' && v === 'z' ) ) { w = 'x'; gridX = scope.depthSegments; } var gridX1 = gridX + 1, gridY1 = gridY + 1, segment_width = width / gridX, segment_height = height / gridY, normal = new THREE.Vector3(); normal[ w ] = depth > 0 ? 1 : - 1; for ( iy = 0; iy < gridY1; iy ++ ) { for ( ix = 0; ix < gridX1; ix ++ ) { var vector = new THREE.Vector3(); vector[ u ] = ( ix * segment_width - width_half ) * udir; vector[ v ] = ( iy * segment_height - height_half ) * vdir; vector[ w ] = depth; scope.vertices.push( vector ); } } for ( iy = 0; iy < gridY; iy++ ) { for ( ix = 0; ix < gridX; ix++ ) { var a = ix + gridX1 * iy; var b = ix + gridX1 * ( iy + 1 ); var c = ( ix + 1 ) + gridX1 * ( iy + 1 ); var d = ( ix + 1 ) + gridX1 * iy; var uva = new THREE.Vector2( ix / gridX, 1 - iy / gridY ); var uvb = new THREE.Vector2( ix / gridX, 1 - ( iy + 1 ) / gridY ); var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iy + 1 ) / gridY ); var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iy / gridY ); var face = new THREE.Face3( a + offset, b + offset, d + offset ); face.normal.copy( normal ); face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); face.materialIndex = materialIndex; scope.faces.push( face ); scope.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); face = new THREE.Face3( b + offset, c + offset, d + offset ); face.normal.copy( normal ); face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); face.materialIndex = materialIndex; scope.faces.push( face ); scope.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); } } } this.computeCentroids(); this.mergeVertices(); }; THREE.BoxGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author hughes */ THREE.CircleGeometry = function ( radius, segments, thetaStart, thetaLength ) { THREE.Geometry.call( this ); this.radius = radius = radius || 50; this.segments = segments = segments !== undefined ? Math.max( 3, segments ) : 8; this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; var i, uvs = [], center = new THREE.Vector3(), centerUV = new THREE.Vector2( 0.5, 0.5 ); this.vertices.push(center); uvs.push( centerUV ); for ( i = 0; i <= segments; i ++ ) { var vertex = new THREE.Vector3(); var segment = thetaStart + i / segments * thetaLength; vertex.x = radius * Math.cos( segment ); vertex.y = radius * Math.sin( segment ); this.vertices.push( vertex ); uvs.push( new THREE.Vector2( ( vertex.x / radius + 1 ) / 2, ( vertex.y / radius + 1 ) / 2 ) ); } var n = new THREE.Vector3( 0, 0, 1 ); for ( i = 1; i <= segments; i ++ ) { var v1 = i; var v2 = i + 1 ; var v3 = 0; this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uvs[ i ].clone(), uvs[ i + 1 ].clone(), centerUV.clone() ] ); } this.computeCentroids(); this.computeFaceNormals(); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); }; THREE.CircleGeometry.prototype = Object.create( THREE.Geometry.prototype ); // DEPRECATED THREE.CubeGeometry = THREE.BoxGeometry; /** * @author mrdoob / http://mrdoob.com/ */ THREE.CylinderGeometry = function ( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded ) { THREE.Geometry.call( this ); this.radiusTop = radiusTop = radiusTop !== undefined ? radiusTop : 20; this.radiusBottom = radiusBottom = radiusBottom !== undefined ? radiusBottom : 20; this.height = height = height !== undefined ? height : 100; this.radialSegments = radialSegments = radialSegments || 8; this.heightSegments = heightSegments = heightSegments || 1; this.openEnded = openEnded = openEnded !== undefined ? openEnded : false; var heightHalf = height / 2; var x, y, vertices = [], uvs = []; for ( y = 0; y <= heightSegments; y ++ ) { var verticesRow = []; var uvsRow = []; var v = y / heightSegments; var radius = v * ( radiusBottom - radiusTop ) + radiusTop; for ( x = 0; x <= radialSegments; x ++ ) { var u = x / radialSegments; var vertex = new THREE.Vector3(); vertex.x = radius * Math.sin( u * Math.PI * 2 ); vertex.y = - v * height + heightHalf; vertex.z = radius * Math.cos( u * Math.PI * 2 ); this.vertices.push( vertex ); verticesRow.push( this.vertices.length - 1 ); uvsRow.push( new THREE.Vector2( u, 1 - v ) ); } vertices.push( verticesRow ); uvs.push( uvsRow ); } var tanTheta = ( radiusBottom - radiusTop ) / height; var na, nb; for ( x = 0; x < radialSegments; x ++ ) { if ( radiusTop !== 0 ) { na = this.vertices[ vertices[ 0 ][ x ] ].clone(); nb = this.vertices[ vertices[ 0 ][ x + 1 ] ].clone(); } else { na = this.vertices[ vertices[ 1 ][ x ] ].clone(); nb = this.vertices[ vertices[ 1 ][ x + 1 ] ].clone(); } na.setY( Math.sqrt( na.x * na.x + na.z * na.z ) * tanTheta ).normalize(); nb.setY( Math.sqrt( nb.x * nb.x + nb.z * nb.z ) * tanTheta ).normalize(); for ( y = 0; y < heightSegments; y ++ ) { var v1 = vertices[ y ][ x ]; var v2 = vertices[ y + 1 ][ x ]; var v3 = vertices[ y + 1 ][ x + 1 ]; var v4 = vertices[ y ][ x + 1 ]; var n1 = na.clone(); var n2 = na.clone(); var n3 = nb.clone(); var n4 = nb.clone(); var uv1 = uvs[ y ][ x ].clone(); var uv2 = uvs[ y + 1 ][ x ].clone(); var uv3 = uvs[ y + 1 ][ x + 1 ].clone(); var uv4 = uvs[ y ][ x + 1 ].clone(); this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); } } // top cap if ( openEnded === false && radiusTop > 0 ) { this.vertices.push( new THREE.Vector3( 0, heightHalf, 0 ) ); for ( x = 0; x < radialSegments; x ++ ) { var v1 = vertices[ 0 ][ x ]; var v2 = vertices[ 0 ][ x + 1 ]; var v3 = this.vertices.length - 1; var n1 = new THREE.Vector3( 0, 1, 0 ); var n2 = new THREE.Vector3( 0, 1, 0 ); var n3 = new THREE.Vector3( 0, 1, 0 ); var uv1 = uvs[ 0 ][ x ].clone(); var uv2 = uvs[ 0 ][ x + 1 ].clone(); var uv3 = new THREE.Vector2( uv2.x, 0 ); this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); } } // bottom cap if ( openEnded === false && radiusBottom > 0 ) { this.vertices.push( new THREE.Vector3( 0, - heightHalf, 0 ) ); for ( x = 0; x < radialSegments; x ++ ) { var v1 = vertices[ y ][ x + 1 ]; var v2 = vertices[ y ][ x ]; var v3 = this.vertices.length - 1; var n1 = new THREE.Vector3( 0, - 1, 0 ); var n2 = new THREE.Vector3( 0, - 1, 0 ); var n3 = new THREE.Vector3( 0, - 1, 0 ); var uv1 = uvs[ y ][ x + 1 ].clone(); var uv2 = uvs[ y ][ x ].clone(); var uv3 = new THREE.Vector2( uv2.x, 1 ); this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); } } this.computeCentroids(); this.computeFaceNormals(); } THREE.CylinderGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author zz85 / http://www.lab4games.net/zz85/blog * * Creates extruded geometry from a path shape. * * parameters = { * * curveSegments: , // number of points on the curves * steps: , // number of points for z-side extrusions / used for subdividing segements of extrude spline too * amount: , // Depth to extrude the shape * * bevelEnabled: , // turn on bevel * bevelThickness: , // how deep into the original shape bevel goes * bevelSize: , // how far from shape outline is bevel * bevelSegments: , // number of bevel layers * * extrudePath: // 3d spline path to extrude shape along. (creates Frames if .frames aren't defined) * frames: // containing arrays of tangents, normals, binormals * * material: // material index for front and back faces * extrudeMaterial: // material index for extrusion and beveled faces * uvGenerator: // object that provides UV generator functions * * } **/ THREE.ExtrudeGeometry = function ( shapes, options ) { if ( typeof( shapes ) === "undefined" ) { shapes = []; return; } THREE.Geometry.call( this ); shapes = shapes instanceof Array ? shapes : [ shapes ]; this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); this.addShapeList( shapes, options ); this.computeCentroids(); this.computeFaceNormals(); // can't really use automatic vertex normals // as then front and back sides get smoothed too // should do separate smoothing just for sides //this.computeVertexNormals(); //console.log( "took", ( Date.now() - startTime ) ); }; THREE.ExtrudeGeometry.prototype = Object.create( THREE.Geometry.prototype ); THREE.ExtrudeGeometry.prototype.addShapeList = function ( shapes, options ) { var sl = shapes.length; for ( var s = 0; s < sl; s ++ ) { var shape = shapes[ s ]; this.addShape( shape, options ); } }; THREE.ExtrudeGeometry.prototype.addShape = function ( shape, options ) { var amount = options.amount !== undefined ? options.amount : 100; var bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 6; // 10 var bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 2; // 8 var bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3; var bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true; // false var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; var steps = options.steps !== undefined ? options.steps : 1; var extrudePath = options.extrudePath; var extrudePts, extrudeByPath = false; var material = options.material; var extrudeMaterial = options.extrudeMaterial; // Use default WorldUVGenerator if no UV generators are specified. var uvgen = options.UVGenerator !== undefined ? options.UVGenerator : THREE.ExtrudeGeometry.WorldUVGenerator; var shapebb = this.shapebb; //shapebb = shape.getBoundingBox(); var splineTube, binormal, normal, position2; if ( extrudePath ) { extrudePts = extrudePath.getSpacedPoints( steps ); extrudeByPath = true; bevelEnabled = false; // bevels not supported for path extrusion // SETUP TNB variables // Reuse TNB from TubeGeomtry for now. // TODO1 - have a .isClosed in spline? splineTube = options.frames !== undefined ? options.frames : new THREE.TubeGeometry.FrenetFrames(extrudePath, steps, false); // console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length); binormal = new THREE.Vector3(); normal = new THREE.Vector3(); position2 = new THREE.Vector3(); } // Safeguards if bevels are not enabled if ( ! bevelEnabled ) { bevelSegments = 0; bevelThickness = 0; bevelSize = 0; } // Variables initalization var ahole, h, hl; // looping of holes var scope = this; var bevelPoints = []; var shapesOffset = this.vertices.length; var shapePoints = shape.extractPoints( curveSegments ); var vertices = shapePoints.shape; var holes = shapePoints.holes; var reverse = !THREE.Shape.Utils.isClockWise( vertices ) ; if ( reverse ) { vertices = vertices.reverse(); // Maybe we should also check if holes are in the opposite direction, just to be safe ... for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; if ( THREE.Shape.Utils.isClockWise( ahole ) ) { holes[ h ] = ahole.reverse(); } } reverse = false; // If vertices are in order now, we shouldn't need to worry about them again (hopefully)! } var faces = THREE.Shape.Utils.triangulateShape ( vertices, holes ); /* Vertices */ var contour = vertices; // vertices has all points but contour has only points of circumference for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; vertices = vertices.concat( ahole ); } function scalePt2 ( pt, vec, size ) { if ( !vec ) console.log( "die" ); return vec.clone().multiplyScalar( size ).add( pt ); } var b, bs, t, z, vert, vlen = vertices.length, face, flen = faces.length, cont, clen = contour.length; // Find directions for point movement var RAD_TO_DEGREES = 180 / Math.PI; function getBevelVec( inPt, inPrev, inNext ) { var EPSILON = 0.0000000001; var sign = THREE.Math.sign; // computes for inPt the corresponding point inPt' on a new contour // shiftet by 1 unit (length of normalized vector) to the left // if we walk along contour clockwise, this new contour is outside the old one // // inPt' is the intersection of the two lines parallel to the two // adjacent edges of inPt at a distance of 1 unit on the left side. var v_trans_x, v_trans_y, shrink_by = 1; // resulting translation vector for inPt // good reading for geometry algorithms (here: line-line intersection) // http://geomalgorithms.com/a05-_intersect-1.html var v_prev_x = inPt.x - inPrev.x, v_prev_y = inPt.y - inPrev.y; var v_next_x = inNext.x - inPt.x, v_next_y = inNext.y - inPt.y; var v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y ); // check for colinear edges var colinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x ); if ( Math.abs( colinear0 ) > EPSILON ) { // not colinear // length of vectors for normalizing var v_prev_len = Math.sqrt( v_prev_lensq ); var v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y ); // shift adjacent points by unit vectors to the left var ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len ); var ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len ); var ptNextShift_x = ( inNext.x - v_next_y / v_next_len ); var ptNextShift_y = ( inNext.y + v_next_x / v_next_len ); // scaling factor for v_prev to intersection point var sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y - ( ptNextShift_y - ptPrevShift_y ) * v_next_x ) / ( v_prev_x * v_next_y - v_prev_y * v_next_x ); // vector from inPt to intersection point v_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x ); v_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y ); // Don't normalize!, otherwise sharp corners become ugly // but prevent crazy spikes var v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y ) if ( v_trans_lensq <= 2 ) { return new THREE.Vector2( v_trans_x, v_trans_y ); } else { shrink_by = Math.sqrt( v_trans_lensq / 2 ); } } else { // handle special case of colinear edges var direction_eq = false; // assumes: opposite if ( v_prev_x > EPSILON ) { if ( v_next_x > EPSILON ) { direction_eq = true; } } else { if ( v_prev_x < -EPSILON ) { if ( v_next_x < -EPSILON ) { direction_eq = true; } } else { if ( sign(v_prev_y) == sign(v_next_y) ) { direction_eq = true; } } } if ( direction_eq ) { // console.log("Warning: lines are a straight sequence"); v_trans_x = -v_prev_y; v_trans_y = v_prev_x; shrink_by = Math.sqrt( v_prev_lensq ); } else { // console.log("Warning: lines are a straight spike"); v_trans_x = v_prev_x; v_trans_y = v_prev_y; shrink_by = Math.sqrt( v_prev_lensq / 2 ); } } return new THREE.Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by ); } var contourMovements = []; for ( var i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { if ( j === il ) j = 0; if ( k === il ) k = 0; // (j)---(i)---(k) // console.log('i,j,k', i, j , k) var pt_i = contour[ i ]; var pt_j = contour[ j ]; var pt_k = contour[ k ]; contourMovements[ i ]= getBevelVec( contour[ i ], contour[ j ], contour[ k ] ); } var holesMovements = [], oneHoleMovements, verticesMovements = contourMovements.concat(); for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; oneHoleMovements = []; for ( i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) { if ( j === il ) j = 0; if ( k === il ) k = 0; // (j)---(i)---(k) oneHoleMovements[ i ]= getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] ); } holesMovements.push( oneHoleMovements ); verticesMovements = verticesMovements.concat( oneHoleMovements ); } // Loop bevelSegments, 1 for the front, 1 for the back for ( b = 0; b < bevelSegments; b ++ ) { //for ( b = bevelSegments; b > 0; b -- ) { t = b / bevelSegments; z = bevelThickness * ( 1 - t ); //z = bevelThickness * t; bs = bevelSize * ( Math.sin ( t * Math.PI/2 ) ) ; // curved //bs = bevelSize * t ; // linear // contract shape for ( i = 0, il = contour.length; i < il; i ++ ) { vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); //vert = scalePt( contour[ i ], contourCentroid, bs, false ); v( vert.x, vert.y, - z ); } // expand holes for ( h = 0, hl = holes.length; h < hl; h++ ) { ahole = holes[ h ]; oneHoleMovements = holesMovements[ h ]; for ( i = 0, il = ahole.length; i < il; i++ ) { vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); //vert = scalePt( ahole[ i ], holesCentroids[ h ], bs, true ); v( vert.x, vert.y, -z ); } } } bs = bevelSize; // Back facing vertices for ( i = 0; i < vlen; i ++ ) { vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; if ( !extrudeByPath ) { v( vert.x, vert.y, 0 ); } else { // v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x ); normal.copy( splineTube.normals[0] ).multiplyScalar(vert.x); binormal.copy( splineTube.binormals[0] ).multiplyScalar(vert.y); position2.copy( extrudePts[0] ).add(normal).add(binormal); v( position2.x, position2.y, position2.z ); } } // Add stepped vertices... // Including front facing vertices var s; for ( s = 1; s <= steps; s ++ ) { for ( i = 0; i < vlen; i ++ ) { vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ]; if ( !extrudeByPath ) { v( vert.x, vert.y, amount / steps * s ); } else { // v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x ); normal.copy( splineTube.normals[s] ).multiplyScalar( vert.x ); binormal.copy( splineTube.binormals[s] ).multiplyScalar( vert.y ); position2.copy( extrudePts[s] ).add( normal ).add( binormal ); v( position2.x, position2.y, position2.z ); } } } // Add bevel segments planes //for ( b = 1; b <= bevelSegments; b ++ ) { for ( b = bevelSegments - 1; b >= 0; b -- ) { t = b / bevelSegments; z = bevelThickness * ( 1 - t ); //bs = bevelSize * ( 1-Math.sin ( ( 1 - t ) * Math.PI/2 ) ); bs = bevelSize * Math.sin ( t * Math.PI/2 ) ; // contract shape for ( i = 0, il = contour.length; i < il; i ++ ) { vert = scalePt2( contour[ i ], contourMovements[ i ], bs ); v( vert.x, vert.y, amount + z ); } // expand holes for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; oneHoleMovements = holesMovements[ h ]; for ( i = 0, il = ahole.length; i < il; i ++ ) { vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs ); if ( !extrudeByPath ) { v( vert.x, vert.y, amount + z ); } else { v( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z ); } } } } /* Faces */ // Top and bottom faces buildLidFaces(); // Sides faces buildSideFaces(); ///// Internal functions function buildLidFaces() { if ( bevelEnabled ) { var layer = 0 ; // steps + 1 var offset = vlen * layer; // Bottom faces for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; f3( face[ 2 ]+ offset, face[ 1 ]+ offset, face[ 0 ] + offset, true ); } layer = steps + bevelSegments * 2; offset = vlen * layer; // Top faces for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; f3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset, false ); } } else { // Bottom faces for ( i = 0; i < flen; i++ ) { face = faces[ i ]; f3( face[ 2 ], face[ 1 ], face[ 0 ], true ); } // Top faces for ( i = 0; i < flen; i ++ ) { face = faces[ i ]; f3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps, false ); } } } // Create faces for the z-sides of the shape function buildSideFaces() { var layeroffset = 0; sidewalls( contour, layeroffset ); layeroffset += contour.length; for ( h = 0, hl = holes.length; h < hl; h ++ ) { ahole = holes[ h ]; sidewalls( ahole, layeroffset ); //, true layeroffset += ahole.length; } } function sidewalls( contour, layeroffset ) { var j, k; i = contour.length; while ( --i >= 0 ) { j = i; k = i - 1; if ( k < 0 ) k = contour.length - 1; //console.log('b', i,j, i-1, k,vertices.length); var s = 0, sl = steps + bevelSegments * 2; for ( s = 0; s < sl; s ++ ) { var slen1 = vlen * s; var slen2 = vlen * ( s + 1 ); var a = layeroffset + j + slen1, b = layeroffset + k + slen1, c = layeroffset + k + slen2, d = layeroffset + j + slen2; f4( a, b, c, d, contour, s, sl, j, k ); } } } function v( x, y, z ) { scope.vertices.push( new THREE.Vector3( x, y, z ) ); } function f3( a, b, c, isBottom ) { a += shapesOffset; b += shapesOffset; c += shapesOffset; // normal, color, material scope.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); var uvs = isBottom ? uvgen.generateBottomUV( scope, shape, options, a, b, c ) : uvgen.generateTopUV( scope, shape, options, a, b, c ); scope.faceVertexUvs[ 0 ].push( uvs ); } function f4( a, b, c, d, wallContour, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { a += shapesOffset; b += shapesOffset; c += shapesOffset; d += shapesOffset; scope.faces.push( new THREE.Face3( a, b, d, null, null, extrudeMaterial ) ); scope.faces.push( new THREE.Face3( b, c, d, null, null, extrudeMaterial ) ); var uvs = uvgen.generateSideWallUV( scope, shape, wallContour, options, a, b, c, d, stepIndex, stepsLength, contourIndex1, contourIndex2 ); scope.faceVertexUvs[ 0 ].push( [ uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] ] ); scope.faceVertexUvs[ 0 ].push( [ uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] ] ); } }; THREE.ExtrudeGeometry.WorldUVGenerator = { generateTopUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { var ax = geometry.vertices[ indexA ].x, ay = geometry.vertices[ indexA ].y, bx = geometry.vertices[ indexB ].x, by = geometry.vertices[ indexB ].y, cx = geometry.vertices[ indexC ].x, cy = geometry.vertices[ indexC ].y; return [ new THREE.Vector2( ax, ay ), new THREE.Vector2( bx, by ), new THREE.Vector2( cx, cy ) ]; }, generateBottomUV: function( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ) { return this.generateTopUV( geometry, extrudedShape, extrudeOptions, indexA, indexB, indexC ); }, generateSideWallUV: function( geometry, extrudedShape, wallContour, extrudeOptions, indexA, indexB, indexC, indexD, stepIndex, stepsLength, contourIndex1, contourIndex2 ) { var ax = geometry.vertices[ indexA ].x, ay = geometry.vertices[ indexA ].y, az = geometry.vertices[ indexA ].z, bx = geometry.vertices[ indexB ].x, by = geometry.vertices[ indexB ].y, bz = geometry.vertices[ indexB ].z, cx = geometry.vertices[ indexC ].x, cy = geometry.vertices[ indexC ].y, cz = geometry.vertices[ indexC ].z, dx = geometry.vertices[ indexD ].x, dy = geometry.vertices[ indexD ].y, dz = geometry.vertices[ indexD ].z; if ( Math.abs( ay - by ) < 0.01 ) { return [ new THREE.Vector2( ax, 1 - az ), new THREE.Vector2( bx, 1 - bz ), new THREE.Vector2( cx, 1 - cz ), new THREE.Vector2( dx, 1 - dz ) ]; } else { return [ new THREE.Vector2( ay, 1 - az ), new THREE.Vector2( by, 1 - bz ), new THREE.Vector2( cy, 1 - cz ), new THREE.Vector2( dy, 1 - dz ) ]; } } }; THREE.ExtrudeGeometry.__v1 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v2 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v3 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v4 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v5 = new THREE.Vector2(); THREE.ExtrudeGeometry.__v6 = new THREE.Vector2(); /** * @author jonobr1 / http://jonobr1.com * * Creates a one-sided polygonal geometry from a path shape. Similar to * ExtrudeGeometry. * * parameters = { * * curveSegments: , // number of points on the curves. NOT USED AT THE MOMENT. * * material: // material index for front and back faces * uvGenerator: // object that provides UV generator functions * * } **/ THREE.ShapeGeometry = function ( shapes, options ) { THREE.Geometry.call( this ); if ( shapes instanceof Array === false ) shapes = [ shapes ]; this.shapebb = shapes[ shapes.length - 1 ].getBoundingBox(); this.addShapeList( shapes, options ); this.computeCentroids(); this.computeFaceNormals(); }; THREE.ShapeGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * Add an array of shapes to THREE.ShapeGeometry. */ THREE.ShapeGeometry.prototype.addShapeList = function ( shapes, options ) { for ( var i = 0, l = shapes.length; i < l; i++ ) { this.addShape( shapes[ i ], options ); } return this; }; /** * Adds a shape to THREE.ShapeGeometry, based on THREE.ExtrudeGeometry. */ THREE.ShapeGeometry.prototype.addShape = function ( shape, options ) { if ( options === undefined ) options = {}; var curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12; var material = options.material; var uvgen = options.UVGenerator === undefined ? THREE.ExtrudeGeometry.WorldUVGenerator : options.UVGenerator; var shapebb = this.shapebb; // var i, l, hole, s; var shapesOffset = this.vertices.length; var shapePoints = shape.extractPoints( curveSegments ); var vertices = shapePoints.shape; var holes = shapePoints.holes; var reverse = !THREE.Shape.Utils.isClockWise( vertices ); if ( reverse ) { vertices = vertices.reverse(); // Maybe we should also check if holes are in the opposite direction, just to be safe... for ( i = 0, l = holes.length; i < l; i++ ) { hole = holes[ i ]; if ( THREE.Shape.Utils.isClockWise( hole ) ) { holes[ i ] = hole.reverse(); } } reverse = false; } var faces = THREE.Shape.Utils.triangulateShape( vertices, holes ); // Vertices var contour = vertices; for ( i = 0, l = holes.length; i < l; i++ ) { hole = holes[ i ]; vertices = vertices.concat( hole ); } // var vert, vlen = vertices.length; var face, flen = faces.length; var cont, clen = contour.length; for ( i = 0; i < vlen; i++ ) { vert = vertices[ i ]; this.vertices.push( new THREE.Vector3( vert.x, vert.y, 0 ) ); } for ( i = 0; i < flen; i++ ) { face = faces[ i ]; var a = face[ 0 ] + shapesOffset; var b = face[ 1 ] + shapesOffset; var c = face[ 2 ] + shapesOffset; this.faces.push( new THREE.Face3( a, b, c, null, null, material ) ); this.faceVertexUvs[ 0 ].push( uvgen.generateBottomUV( this, shape, options, a, b, c ) ); } }; /** * @author astrodud / http://astrodud.isgreat.org/ * @author zz85 / https://github.com/zz85 * @author bhouston / http://exocortex.com */ // points - to create a closed torus, one must use a set of points // like so: [ a, b, c, d, a ], see first is the same as last. // segments - the number of circumference segments to create // phiStart - the starting radian // phiLength - the radian (0 to 2*PI) range of the lathed section // 2*pi is a closed lathe, less than 2PI is a portion. THREE.LatheGeometry = function ( points, segments, phiStart, phiLength ) { THREE.Geometry.call( this ); segments = segments || 12; phiStart = phiStart || 0; phiLength = phiLength || 2 * Math.PI; var inversePointLength = 1.0 / ( points.length - 1 ); var inverseSegments = 1.0 / segments; for ( var i = 0, il = segments; i <= il; i ++ ) { var phi = phiStart + i * inverseSegments * phiLength; var c = Math.cos( phi ), s = Math.sin( phi ); for ( var j = 0, jl = points.length; j < jl; j ++ ) { var pt = points[ j ]; var vertex = new THREE.Vector3(); vertex.x = c * pt.x - s * pt.y; vertex.y = s * pt.x + c * pt.y; vertex.z = pt.z; this.vertices.push( vertex ); } } var np = points.length; for ( var i = 0, il = segments; i < il; i ++ ) { for ( var j = 0, jl = points.length - 1; j < jl; j ++ ) { var base = j + np * i; var a = base; var b = base + np; var c = base + 1 + np; var d = base + 1; var u0 = i * inverseSegments; var v0 = j * inversePointLength; var u1 = u0 + inverseSegments; var v1 = v0 + inversePointLength; this.faces.push( new THREE.Face3( a, b, d ) ); this.faceVertexUvs[ 0 ].push( [ new THREE.Vector2( u0, v0 ), new THREE.Vector2( u1, v0 ), new THREE.Vector2( u0, v1 ) ] ); this.faces.push( new THREE.Face3( b, c, d ) ); this.faceVertexUvs[ 0 ].push( [ new THREE.Vector2( u1, v0 ), new THREE.Vector2( u1, v1 ), new THREE.Vector2( u0, v1 ) ] ); } } this.mergeVertices(); this.computeCentroids(); this.computeFaceNormals(); this.computeVertexNormals(); }; THREE.LatheGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author mrdoob / http://mrdoob.com/ * based on http://papervision3d.googlecode.com/svn/trunk/as3/trunk/src/org/papervision3d/objects/primitives/Plane.as */ THREE.PlaneGeometry = function ( width, height, widthSegments, heightSegments ) { THREE.Geometry.call( this ); this.width = width; this.height = height; this.widthSegments = widthSegments || 1; this.heightSegments = heightSegments || 1; var ix, iz; var width_half = width / 2; var height_half = height / 2; var gridX = this.widthSegments; var gridZ = this.heightSegments; var gridX1 = gridX + 1; var gridZ1 = gridZ + 1; var segment_width = this.width / gridX; var segment_height = this.height / gridZ; var normal = new THREE.Vector3( 0, 0, 1 ); for ( iz = 0; iz < gridZ1; iz ++ ) { for ( ix = 0; ix < gridX1; ix ++ ) { var x = ix * segment_width - width_half; var y = iz * segment_height - height_half; this.vertices.push( new THREE.Vector3( x, - y, 0 ) ); } } for ( iz = 0; iz < gridZ; iz ++ ) { for ( ix = 0; ix < gridX; ix ++ ) { var a = ix + gridX1 * iz; var b = ix + gridX1 * ( iz + 1 ); var c = ( ix + 1 ) + gridX1 * ( iz + 1 ); var d = ( ix + 1 ) + gridX1 * iz; var uva = new THREE.Vector2( ix / gridX, 1 - iz / gridZ ); var uvb = new THREE.Vector2( ix / gridX, 1 - ( iz + 1 ) / gridZ ); var uvc = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - ( iz + 1 ) / gridZ ); var uvd = new THREE.Vector2( ( ix + 1 ) / gridX, 1 - iz / gridZ ); var face = new THREE.Face3( a, b, d ); face.normal.copy( normal ); face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); this.faces.push( face ); this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); face = new THREE.Face3( b, c, d ); face.normal.copy( normal ); face.vertexNormals.push( normal.clone(), normal.clone(), normal.clone() ); this.faces.push( face ); this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); } } this.computeCentroids(); }; THREE.PlaneGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author Kaleb Murphy */ THREE.RingGeometry = function ( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) { THREE.Geometry.call( this ); innerRadius = innerRadius || 0; outerRadius = outerRadius || 50; thetaStart = thetaStart !== undefined ? thetaStart : 0; thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2; thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8; phiSegments = phiSegments !== undefined ? Math.max( 3, phiSegments ) : 8; var i, o, uvs = [], radius = innerRadius, radiusStep = ( ( outerRadius - innerRadius ) / phiSegments ); for ( i = 0; i <= phiSegments; i ++ ) { // concentric circles inside ring for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle var vertex = new THREE.Vector3(); var segment = thetaStart + o / thetaSegments * thetaLength; vertex.x = radius * Math.cos( segment ); vertex.y = radius * Math.sin( segment ); this.vertices.push( vertex ); uvs.push( new THREE.Vector2( ( vertex.x / outerRadius + 1 ) / 2, ( vertex.y / outerRadius + 1 ) / 2 ) ); } radius += radiusStep; } var n = new THREE.Vector3( 0, 0, 1 ); for ( i = 0; i < phiSegments; i ++ ) { // concentric circles inside ring var thetaSegment = i * thetaSegments; for ( o = 0; o <= thetaSegments; o ++ ) { // number of segments per circle var segment = o + thetaSegment; var v1 = segment + i; var v2 = segment + thetaSegments + i; var v3 = segment + thetaSegments + 1 + i; this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); v1 = segment + i; v2 = segment + thetaSegments + 1 + i; v3 = segment + 1 + i; this.faces.push( new THREE.Face3( v1, v2, v3, [ n.clone(), n.clone(), n.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uvs[ v1 ].clone(), uvs[ v2 ].clone(), uvs[ v3 ].clone() ]); } } this.computeCentroids(); this.computeFaceNormals(); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); }; THREE.RingGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author mrdoob / http://mrdoob.com/ */ THREE.SphereGeometry = function ( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) { THREE.Geometry.call( this ); this.radius = radius = radius || 50; this.widthSegments = widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 ); this.heightSegments = heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 ); this.phiStart = phiStart = phiStart !== undefined ? phiStart : 0; this.phiLength = phiLength = phiLength !== undefined ? phiLength : Math.PI * 2; this.thetaStart = thetaStart = thetaStart !== undefined ? thetaStart : 0; this.thetaLength = thetaLength = thetaLength !== undefined ? thetaLength : Math.PI; var x, y, vertices = [], uvs = []; for ( y = 0; y <= heightSegments; y ++ ) { var verticesRow = []; var uvsRow = []; for ( x = 0; x <= widthSegments; x ++ ) { var u = x / widthSegments; var v = y / heightSegments; var vertex = new THREE.Vector3(); vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); vertex.y = radius * Math.cos( thetaStart + v * thetaLength ); vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength ); this.vertices.push( vertex ); verticesRow.push( this.vertices.length - 1 ); uvsRow.push( new THREE.Vector2( u, 1 - v ) ); } vertices.push( verticesRow ); uvs.push( uvsRow ); } for ( y = 0; y < this.heightSegments; y ++ ) { for ( x = 0; x < this.widthSegments; x ++ ) { var v1 = vertices[ y ][ x + 1 ]; var v2 = vertices[ y ][ x ]; var v3 = vertices[ y + 1 ][ x ]; var v4 = vertices[ y + 1 ][ x + 1 ]; var n1 = this.vertices[ v1 ].clone().normalize(); var n2 = this.vertices[ v2 ].clone().normalize(); var n3 = this.vertices[ v3 ].clone().normalize(); var n4 = this.vertices[ v4 ].clone().normalize(); var uv1 = uvs[ y ][ x + 1 ].clone(); var uv2 = uvs[ y ][ x ].clone(); var uv3 = uvs[ y + 1 ][ x ].clone(); var uv4 = uvs[ y + 1 ][ x + 1 ].clone(); if ( Math.abs( this.vertices[ v1 ].y ) === this.radius ) { uv1.x = ( uv1.x + uv2.x ) / 2; this.faces.push( new THREE.Face3( v1, v3, v4, [ n1, n3, n4 ] ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv3, uv4 ] ); } else if ( Math.abs( this.vertices[ v3 ].y ) === this.radius ) { uv3.x = ( uv3.x + uv4.x ) / 2; this.faces.push( new THREE.Face3( v1, v2, v3, [ n1, n2, n3 ] ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv3 ] ); } else { this.faces.push( new THREE.Face3( v1, v2, v4, [ n1, n2, n4 ] ) ); this.faceVertexUvs[ 0 ].push( [ uv1, uv2, uv4 ] ); this.faces.push( new THREE.Face3( v2, v3, v4, [ n2.clone(), n3, n4.clone() ] ) ); this.faceVertexUvs[ 0 ].push( [ uv2.clone(), uv3, uv4.clone() ] ); } } } this.computeCentroids(); this.computeFaceNormals(); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); }; THREE.SphereGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author zz85 / http://www.lab4games.net/zz85/blog * @author alteredq / http://alteredqualia.com/ * * For creating 3D text geometry in three.js * * Text = 3D Text * * parameters = { * size: , // size of the text * height: , // thickness to extrude text * curveSegments: , // number of points on the curves * * font: , // font name * weight: , // font weight (normal, bold) * style: , // font style (normal, italics) * * bevelEnabled: , // turn on bevel * bevelThickness: , // how deep into text bevel goes * bevelSize: , // how far from text outline is bevel * } * */ /* Usage Examples // TextGeometry wrapper var text3d = new TextGeometry( text, options ); // Complete manner var textShapes = THREE.FontUtils.generateShapes( text, options ); var text3d = new ExtrudeGeometry( textShapes, options ); */ THREE.TextGeometry = function ( text, parameters ) { parameters = parameters || {}; var textShapes = THREE.FontUtils.generateShapes( text, parameters ); // translate parameters to ExtrudeGeometry API parameters.amount = parameters.height !== undefined ? parameters.height : 50; // defaults if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10; if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8; if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false; THREE.ExtrudeGeometry.call( this, textShapes, parameters ); }; THREE.TextGeometry.prototype = Object.create( THREE.ExtrudeGeometry.prototype ); /** * @author oosmoxiecode * @author mrdoob / http://mrdoob.com/ * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3DLite/src/away3dlite/primitives/Torus.as?r=2888 */ THREE.TorusGeometry = function ( radius, tube, radialSegments, tubularSegments, arc ) { THREE.Geometry.call( this ); var scope = this; this.radius = radius || 100; this.tube = tube || 40; this.radialSegments = radialSegments || 8; this.tubularSegments = tubularSegments || 6; this.arc = arc || Math.PI * 2; var center = new THREE.Vector3(), uvs = [], normals = []; for ( var j = 0; j <= this.radialSegments; j ++ ) { for ( var i = 0; i <= this.tubularSegments; i ++ ) { var u = i / this.tubularSegments * this.arc; var v = j / this.radialSegments * Math.PI * 2; center.x = this.radius * Math.cos( u ); center.y = this.radius * Math.sin( u ); var vertex = new THREE.Vector3(); vertex.x = ( this.radius + this.tube * Math.cos( v ) ) * Math.cos( u ); vertex.y = ( this.radius + this.tube * Math.cos( v ) ) * Math.sin( u ); vertex.z = this.tube * Math.sin( v ); this.vertices.push( vertex ); uvs.push( new THREE.Vector2( i / this.tubularSegments, j / this.radialSegments ) ); normals.push( vertex.clone().sub( center ).normalize() ); } } for ( var j = 1; j <= this.radialSegments; j ++ ) { for ( var i = 1; i <= this.tubularSegments; i ++ ) { var a = ( this.tubularSegments + 1 ) * j + i - 1; var b = ( this.tubularSegments + 1 ) * ( j - 1 ) + i - 1; var c = ( this.tubularSegments + 1 ) * ( j - 1 ) + i; var d = ( this.tubularSegments + 1 ) * j + i; var face = new THREE.Face3( a, b, d, [ normals[ a ].clone(), normals[ b ].clone(), normals[ d ].clone() ] ); this.faces.push( face ); this.faceVertexUvs[ 0 ].push( [ uvs[ a ].clone(), uvs[ b ].clone(), uvs[ d ].clone() ] ); face = new THREE.Face3( b, c, d, [ normals[ b ].clone(), normals[ c ].clone(), normals[ d ].clone() ] ); this.faces.push( face ); this.faceVertexUvs[ 0 ].push( [ uvs[ b ].clone(), uvs[ c ].clone(), uvs[ d ].clone() ] ); } } this.computeCentroids(); this.computeFaceNormals(); }; THREE.TorusGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author oosmoxiecode * based on http://code.google.com/p/away3d/source/browse/trunk/fp10/Away3D/src/away3d/primitives/TorusKnot.as?spec=svn2473&r=2473 */ THREE.TorusKnotGeometry = function ( radius, tube, radialSegments, tubularSegments, p, q, heightScale ) { THREE.Geometry.call( this ); var scope = this; this.radius = radius || 100; this.tube = tube || 40; this.radialSegments = radialSegments || 64; this.tubularSegments = tubularSegments || 8; this.p = p || 2; this.q = q || 3; this.heightScale = heightScale || 1; this.grid = new Array( this.radialSegments ); var tang = new THREE.Vector3(); var n = new THREE.Vector3(); var bitan = new THREE.Vector3(); for ( var i = 0; i < this.radialSegments; ++ i ) { this.grid[ i ] = new Array( this.tubularSegments ); var u = i / this.radialSegments * 2 * this.p * Math.PI; var p1 = getPos( u, this.q, this.p, this.radius, this.heightScale ); var p2 = getPos( u + 0.01, this.q, this.p, this.radius, this.heightScale ); tang.subVectors( p2, p1 ); n.addVectors( p2, p1 ); bitan.crossVectors( tang, n ); n.crossVectors( bitan, tang ); bitan.normalize(); n.normalize(); for ( var j = 0; j < this.tubularSegments; ++ j ) { var v = j / this.tubularSegments * 2 * Math.PI; var cx = - this.tube * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. var cy = this.tube * Math.sin( v ); var pos = new THREE.Vector3(); pos.x = p1.x + cx * n.x + cy * bitan.x; pos.y = p1.y + cx * n.y + cy * bitan.y; pos.z = p1.z + cx * n.z + cy * bitan.z; this.grid[ i ][ j ] = scope.vertices.push( pos ) - 1; } } for ( var i = 0; i < this.radialSegments; ++ i ) { for ( var j = 0; j < this.tubularSegments; ++ j ) { var ip = ( i + 1 ) % this.radialSegments; var jp = ( j + 1 ) % this.tubularSegments; var a = this.grid[ i ][ j ]; var b = this.grid[ ip ][ j ]; var c = this.grid[ ip ][ jp ]; var d = this.grid[ i ][ jp ]; var uva = new THREE.Vector2( i / this.radialSegments, j / this.tubularSegments ); var uvb = new THREE.Vector2( ( i + 1 ) / this.radialSegments, j / this.tubularSegments ); var uvc = new THREE.Vector2( ( i + 1 ) / this.radialSegments, ( j + 1 ) / this.tubularSegments ); var uvd = new THREE.Vector2( i / this.radialSegments, ( j + 1 ) / this.tubularSegments ); this.faces.push( new THREE.Face3( a, b, d ) ); this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); this.faces.push( new THREE.Face3( b, c, d ) ); this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); } } this.computeCentroids(); this.computeFaceNormals(); this.computeVertexNormals(); function getPos( u, in_q, in_p, radius, heightScale ) { var cu = Math.cos( u ); var su = Math.sin( u ); var quOverP = in_q / in_p * u; var cs = Math.cos( quOverP ); var tx = radius * ( 2 + cs ) * 0.5 * cu; var ty = radius * ( 2 + cs ) * su * 0.5; var tz = heightScale * radius * Math.sin( quOverP ) * 0.5; return new THREE.Vector3( tx, ty, tz ); } }; THREE.TorusKnotGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author WestLangley / https://github.com/WestLangley * @author zz85 / https://github.com/zz85 * @author miningold / https://github.com/miningold * * Modified from the TorusKnotGeometry by @oosmoxiecode * * Creates a tube which extrudes along a 3d spline * * Uses parallel transport frames as described in * http://www.cs.indiana.edu/pub/techreports/TR425.pdf */ THREE.TubeGeometry = function( path, segments, radius, radialSegments, closed ) { THREE.Geometry.call( this ); this.path = path; this.segments = segments || 64; this.radius = radius || 1; this.radialSegments = radialSegments || 8; this.closed = closed || false; this.grid = []; var scope = this, tangent, normal, binormal, numpoints = this.segments + 1, x, y, z, tx, ty, tz, u, v, cx, cy, pos, pos2 = new THREE.Vector3(), i, j, ip, jp, a, b, c, d, uva, uvb, uvc, uvd; var frames = new THREE.TubeGeometry.FrenetFrames( this.path, this.segments, this.closed ), tangents = frames.tangents, normals = frames.normals, binormals = frames.binormals; // proxy internals this.tangents = tangents; this.normals = normals; this.binormals = binormals; function vert( x, y, z ) { return scope.vertices.push( new THREE.Vector3( x, y, z ) ) - 1; } // consruct the grid for ( i = 0; i < numpoints; i++ ) { this.grid[ i ] = []; u = i / ( numpoints - 1 ); pos = path.getPointAt( u ); tangent = tangents[ i ]; normal = normals[ i ]; binormal = binormals[ i ]; for ( j = 0; j < this.radialSegments; j++ ) { v = j / this.radialSegments * 2 * Math.PI; cx = -this.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside. cy = this.radius * Math.sin( v ); pos2.copy( pos ); pos2.x += cx * normal.x + cy * binormal.x; pos2.y += cx * normal.y + cy * binormal.y; pos2.z += cx * normal.z + cy * binormal.z; this.grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z ); } } // construct the mesh for ( i = 0; i < this.segments; i++ ) { for ( j = 0; j < this.radialSegments; j++ ) { ip = ( this.closed ) ? (i + 1) % this.segments : i + 1; jp = (j + 1) % this.radialSegments; a = this.grid[ i ][ j ]; // *** NOT NECESSARILY PLANAR ! *** b = this.grid[ ip ][ j ]; c = this.grid[ ip ][ jp ]; d = this.grid[ i ][ jp ]; uva = new THREE.Vector2( i / this.segments, j / this.radialSegments ); uvb = new THREE.Vector2( ( i + 1 ) / this.segments, j / this.radialSegments ); uvc = new THREE.Vector2( ( i + 1 ) / this.segments, ( j + 1 ) / this.radialSegments ); uvd = new THREE.Vector2( i / this.segments, ( j + 1 ) / this.radialSegments ); this.faces.push( new THREE.Face3( a, b, d ) ); this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] ); this.faces.push( new THREE.Face3( b, c, d ) ); this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] ); } } this.computeCentroids(); this.computeFaceNormals(); this.computeVertexNormals(); }; THREE.TubeGeometry.prototype = Object.create( THREE.Geometry.prototype ); // For computing of Frenet frames, exposing the tangents, normals and binormals the spline THREE.TubeGeometry.FrenetFrames = function(path, segments, closed) { var tangent = new THREE.Vector3(), normal = new THREE.Vector3(), binormal = new THREE.Vector3(), tangents = [], normals = [], binormals = [], vec = new THREE.Vector3(), mat = new THREE.Matrix4(), numpoints = segments + 1, theta, epsilon = 0.0001, smallest, tx, ty, tz, i, u, v; // expose internals this.tangents = tangents; this.normals = normals; this.binormals = binormals; // compute the tangent vectors for each segment on the path for ( i = 0; i < numpoints; i++ ) { u = i / ( numpoints - 1 ); tangents[ i ] = path.getTangentAt( u ); tangents[ i ].normalize(); } initialNormal3(); function initialNormal1(lastBinormal) { // fixed start binormal. Has dangers of 0 vectors normals[ 0 ] = new THREE.Vector3(); binormals[ 0 ] = new THREE.Vector3(); if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 ); normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize(); binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); } function initialNormal2() { // This uses the Frenet-Serret formula for deriving binormal var t2 = path.getTangentAt( epsilon ); normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize(); binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] ); normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize(); } function initialNormal3() { // select an initial normal vector perpenicular to the first tangent vector, // and in the direction of the smallest tangent xyz component normals[ 0 ] = new THREE.Vector3(); binormals[ 0 ] = new THREE.Vector3(); smallest = Number.MAX_VALUE; tx = Math.abs( tangents[ 0 ].x ); ty = Math.abs( tangents[ 0 ].y ); tz = Math.abs( tangents[ 0 ].z ); if ( tx <= smallest ) { smallest = tx; normal.set( 1, 0, 0 ); } if ( ty <= smallest ) { smallest = ty; normal.set( 0, 1, 0 ); } if ( tz <= smallest ) { normal.set( 0, 0, 1 ); } vec.crossVectors( tangents[ 0 ], normal ).normalize(); normals[ 0 ].crossVectors( tangents[ 0 ], vec ); binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ); } // compute the slowly-varying normal and binormal vectors for each segment on the path for ( i = 1; i < numpoints; i++ ) { normals[ i ] = normals[ i-1 ].clone(); binormals[ i ] = binormals[ i-1 ].clone(); vec.crossVectors( tangents[ i-1 ], tangents[ i ] ); if ( vec.length() > epsilon ) { vec.normalize(); theta = Math.acos( THREE.Math.clamp( tangents[ i-1 ].dot( tangents[ i ] ), -1, 1 ) ); // clamp for floating pt errors normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) ); } binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); } // if the curve is closed, postprocess the vectors so the first and last normal vectors are the same if ( closed ) { theta = Math.acos( THREE.Math.clamp( normals[ 0 ].dot( normals[ numpoints-1 ] ), -1, 1 ) ); theta /= ( numpoints - 1 ); if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints-1 ] ) ) > 0 ) { theta = -theta; } for ( i = 1; i < numpoints; i++ ) { // twist a little... normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) ); binormals[ i ].crossVectors( tangents[ i ], normals[ i ] ); } } }; /** * @author clockworkgeek / https://github.com/clockworkgeek * @author timothypratley / https://github.com/timothypratley * @author WestLangley / http://github.com/WestLangley */ THREE.PolyhedronGeometry = function ( vertices, faces, radius, detail ) { THREE.Geometry.call( this ); radius = radius || 1; detail = detail || 0; var that = this; for ( var i = 0, l = vertices.length; i < l; i ++ ) { prepare( new THREE.Vector3( vertices[ i ][ 0 ], vertices[ i ][ 1 ], vertices[ i ][ 2 ] ) ); } var midpoints = [], p = this.vertices; var f = []; for ( var i = 0, l = faces.length; i < l; i ++ ) { var v1 = p[ faces[ i ][ 0 ] ]; var v2 = p[ faces[ i ][ 1 ] ]; var v3 = p[ faces[ i ][ 2 ] ]; f[ i ] = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); } for ( var i = 0, l = f.length; i < l; i ++ ) { subdivide(f[ i ], detail); } // Handle case when face straddles the seam for ( var i = 0, l = this.faceVertexUvs[ 0 ].length; i < l; i ++ ) { var uvs = this.faceVertexUvs[ 0 ][ i ]; var x0 = uvs[ 0 ].x; var x1 = uvs[ 1 ].x; var x2 = uvs[ 2 ].x; var max = Math.max( x0, Math.max( x1, x2 ) ); var min = Math.min( x0, Math.min( x1, x2 ) ); if ( max > 0.9 && min < 0.1 ) { // 0.9 is somewhat arbitrary if ( x0 < 0.2 ) uvs[ 0 ].x += 1; if ( x1 < 0.2 ) uvs[ 1 ].x += 1; if ( x2 < 0.2 ) uvs[ 2 ].x += 1; } } // Apply radius for ( var i = 0, l = this.vertices.length; i < l; i ++ ) { this.vertices[ i ].multiplyScalar( radius ); } // Merge vertices this.mergeVertices(); this.computeCentroids(); this.computeFaceNormals(); this.boundingSphere = new THREE.Sphere( new THREE.Vector3(), radius ); // Project vector onto sphere's surface function prepare( vector ) { var vertex = vector.normalize().clone(); vertex.index = that.vertices.push( vertex ) - 1; // Texture coords are equivalent to map coords, calculate angle and convert to fraction of a circle. var u = azimuth( vector ) / 2 / Math.PI + 0.5; var v = inclination( vector ) / Math.PI + 0.5; vertex.uv = new THREE.Vector2( u, 1 - v ); return vertex; } // Approximate a curved face with recursively sub-divided triangles. function make( v1, v2, v3 ) { var face = new THREE.Face3( v1.index, v2.index, v3.index, [ v1.clone(), v2.clone(), v3.clone() ] ); face.centroid.add( v1 ).add( v2 ).add( v3 ).divideScalar( 3 ); that.faces.push( face ); var azi = azimuth( face.centroid ); that.faceVertexUvs[ 0 ].push( [ correctUV( v1.uv, v1, azi ), correctUV( v2.uv, v2, azi ), correctUV( v3.uv, v3, azi ) ] ); } // Analytically subdivide a face to the required detail level. function subdivide(face, detail ) { var cols = Math.pow(2, detail); var cells = Math.pow(4, detail); var a = prepare( that.vertices[ face.a ] ); var b = prepare( that.vertices[ face.b ] ); var c = prepare( that.vertices[ face.c ] ); var v = []; // Construct all of the vertices for this subdivision. for ( var i = 0 ; i <= cols; i ++ ) { v[ i ] = []; var aj = prepare( a.clone().lerp( c, i / cols ) ); var bj = prepare( b.clone().lerp( c, i / cols ) ); var rows = cols - i; for ( var j = 0; j <= rows; j ++) { if ( j == 0 && i == cols ) { v[ i ][ j ] = aj; } else { v[ i ][ j ] = prepare( aj.clone().lerp( bj, j / rows ) ); } } } // Construct all of the faces. for ( var i = 0; i < cols ; i ++ ) { for ( var j = 0; j < 2 * (cols - i) - 1; j ++ ) { var k = Math.floor( j / 2 ); if ( j % 2 == 0 ) { make( v[ i ][ k + 1], v[ i + 1 ][ k ], v[ i ][ k ] ); } else { make( v[ i ][ k + 1 ], v[ i + 1][ k + 1], v[ i + 1 ][ k ] ); } } } } // Angle around the Y axis, counter-clockwise when looking from above. function azimuth( vector ) { return Math.atan2( vector.z, -vector.x ); } // Angle above the XZ plane. function inclination( vector ) { return Math.atan2( -vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) ); } // Texture fixing helper. Spheres have some odd behaviours. function correctUV( uv, vector, azimuth ) { if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) uv = new THREE.Vector2( uv.x - 1, uv.y ); if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) uv = new THREE.Vector2( azimuth / 2 / Math.PI + 0.5, uv.y ); return uv.clone(); } }; THREE.PolyhedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author timothypratley / https://github.com/timothypratley */ THREE.IcosahedronGeometry = function ( radius, detail ) { this.radius = radius; this.detail = detail; var t = ( 1 + Math.sqrt( 5 ) ) / 2; var vertices = [ [ -1, t, 0 ], [ 1, t, 0 ], [ -1, -t, 0 ], [ 1, -t, 0 ], [ 0, -1, t ], [ 0, 1, t ], [ 0, -1, -t ], [ 0, 1, -t ], [ t, 0, -1 ], [ t, 0, 1 ], [ -t, 0, -1 ], [ -t, 0, 1 ] ]; var faces = [ [ 0, 11, 5 ], [ 0, 5, 1 ], [ 0, 1, 7 ], [ 0, 7, 10 ], [ 0, 10, 11 ], [ 1, 5, 9 ], [ 5, 11, 4 ], [ 11, 10, 2 ], [ 10, 7, 6 ], [ 7, 1, 8 ], [ 3, 9, 4 ], [ 3, 4, 2 ], [ 3, 2, 6 ], [ 3, 6, 8 ], [ 3, 8, 9 ], [ 4, 9, 5 ], [ 2, 4, 11 ], [ 6, 2, 10 ], [ 8, 6, 7 ], [ 9, 8, 1 ] ]; THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); }; THREE.IcosahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author timothypratley / https://github.com/timothypratley */ THREE.OctahedronGeometry = function ( radius, detail ) { var vertices = [ [ 1, 0, 0 ], [ -1, 0, 0 ], [ 0, 1, 0 ], [ 0, -1, 0 ], [ 0, 0, 1 ], [ 0, 0, -1 ] ]; var faces = [ [ 0, 2, 4 ], [ 0, 4, 3 ], [ 0, 3, 5 ], [ 0, 5, 2 ], [ 1, 2, 5 ], [ 1, 5, 3 ], [ 1, 3, 4 ], [ 1, 4, 2 ] ]; THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); }; THREE.OctahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author timothypratley / https://github.com/timothypratley */ THREE.TetrahedronGeometry = function ( radius, detail ) { var vertices = [ [ 1, 1, 1 ], [ -1, -1, 1 ], [ -1, 1, -1 ], [ 1, -1, -1 ] ]; var faces = [ [ 2, 1, 0 ], [ 0, 3, 2 ], [ 1, 3, 0 ], [ 2, 3, 1 ] ]; THREE.PolyhedronGeometry.call( this, vertices, faces, radius, detail ); }; THREE.TetrahedronGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author zz85 / https://github.com/zz85 * Parametric Surfaces Geometry * based on the brilliant article by @prideout http://prideout.net/blog/?p=44 * * new THREE.ParametricGeometry( parametricFunction, uSegments, ySegements ); * */ THREE.ParametricGeometry = function ( func, slices, stacks ) { THREE.Geometry.call( this ); var verts = this.vertices; var faces = this.faces; var uvs = this.faceVertexUvs[ 0 ]; var i, il, j, p; var u, v; var stackCount = stacks + 1; var sliceCount = slices + 1; for ( i = 0; i <= stacks; i ++ ) { v = i / stacks; for ( j = 0; j <= slices; j ++ ) { u = j / slices; p = func( u, v ); verts.push( p ); } } var a, b, c, d; var uva, uvb, uvc, uvd; for ( i = 0; i < stacks; i ++ ) { for ( j = 0; j < slices; j ++ ) { a = i * sliceCount + j; b = i * sliceCount + j + 1; c = (i + 1) * sliceCount + j + 1; d = (i + 1) * sliceCount + j; uva = new THREE.Vector2( j / slices, i / stacks ); uvb = new THREE.Vector2( ( j + 1 ) / slices, i / stacks ); uvc = new THREE.Vector2( ( j + 1 ) / slices, ( i + 1 ) / stacks ); uvd = new THREE.Vector2( j / slices, ( i + 1 ) / stacks ); faces.push( new THREE.Face3( a, b, d ) ); uvs.push( [ uva, uvb, uvd ] ); faces.push( new THREE.Face3( b, c, d ) ); uvs.push( [ uvb.clone(), uvc, uvd.clone() ] ); } } // console.log(this); // magic bullet // var diff = this.mergeVertices(); // console.log('removed ', diff, ' vertices by merging'); this.computeCentroids(); this.computeFaceNormals(); this.computeVertexNormals(); }; THREE.ParametricGeometry.prototype = Object.create( THREE.Geometry.prototype ); /** * @author sroucheray / http://sroucheray.org/ * @author mrdoob / http://mrdoob.com/ */ THREE.AxisHelper = function ( size ) { size = size || 1; var geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3(), new THREE.Vector3( size, 0, 0 ), new THREE.Vector3(), new THREE.Vector3( 0, size, 0 ), new THREE.Vector3(), new THREE.Vector3( 0, 0, size ) ); geometry.colors.push( new THREE.Color( 0xff0000 ), new THREE.Color( 0xffaa00 ), new THREE.Color( 0x00ff00 ), new THREE.Color( 0xaaff00 ), new THREE.Color( 0x0000ff ), new THREE.Color( 0x00aaff ) ); var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); THREE.Line.call( this, geometry, material, THREE.LinePieces ); }; THREE.AxisHelper.prototype = Object.create( THREE.Line.prototype ); /** * @author WestLangley / http://github.com/WestLangley * @author zz85 / http://github.com/zz85 * @author bhouston / http://exocortex.com * * Creates an arrow for visualizing directions * * Parameters: * dir - Vector3 * origin - Vector3 * length - Number * hex - color in hex value * headLength - Number * headWidth - Number */ THREE.ArrowHelper = function ( dir, origin, length, hex, headLength, headWidth ) { // dir is assumed to be normalized THREE.Object3D.call( this ); if ( hex === undefined ) hex = 0xffff00; if ( length === undefined ) length = 1; if ( headLength === undefined ) headLength = 0.2 * length; if ( headWidth === undefined ) headWidth = 0.2 * headLength; this.position = origin; var lineGeometry = new THREE.Geometry(); lineGeometry.vertices.push( new THREE.Vector3( 0, 0, 0 ) ); lineGeometry.vertices.push( new THREE.Vector3( 0, 1, 0 ) ); this.line = new THREE.Line( lineGeometry, new THREE.LineBasicMaterial( { color: hex } ) ); this.line.matrixAutoUpdate = false; this.add( this.line ); var coneGeometry = new THREE.CylinderGeometry( 0, 0.5, 1, 5, 1 ); coneGeometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, - 0.5, 0 ) ); this.cone = new THREE.Mesh( coneGeometry, new THREE.MeshBasicMaterial( { color: hex } ) ); this.cone.matrixAutoUpdate = false; this.add( this.cone ); this.setDirection( dir ); this.setLength( length, headLength, headWidth ); }; THREE.ArrowHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.ArrowHelper.prototype.setDirection = function () { var axis = new THREE.Vector3(); var radians; return function ( dir ) { // dir is assumed to be normalized if ( dir.y > 0.99999 ) { this.quaternion.set( 0, 0, 0, 1 ); } else if ( dir.y < - 0.99999 ) { this.quaternion.set( 1, 0, 0, 0 ); } else { axis.set( dir.z, 0, - dir.x ).normalize(); radians = Math.acos( dir.y ); this.quaternion.setFromAxisAngle( axis, radians ); } }; }(); THREE.ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) { if ( headLength === undefined ) headLength = 0.2 * length; if ( headWidth === undefined ) headWidth = 0.2 * headLength; this.line.scale.set( 1, length, 1 ); this.line.updateMatrix(); this.cone.scale.set( headWidth, headLength, headWidth ); this.cone.position.y = length; this.cone.updateMatrix(); }; THREE.ArrowHelper.prototype.setColor = function ( hex ) { this.line.material.color.setHex( hex ); this.cone.material.color.setHex( hex ); }; /** * @author mrdoob / http://mrdoob.com/ */ THREE.BoxHelper = function ( object ) { // 5____4 // 1/___0/| // | 6__|_7 // 2/___3/ var vertices = [ new THREE.Vector3( 1, 1, 1 ), new THREE.Vector3( - 1, 1, 1 ), new THREE.Vector3( - 1, - 1, 1 ), new THREE.Vector3( 1, - 1, 1 ), new THREE.Vector3( 1, 1, - 1 ), new THREE.Vector3( - 1, 1, - 1 ), new THREE.Vector3( - 1, - 1, - 1 ), new THREE.Vector3( 1, - 1, - 1 ) ]; this.vertices = vertices; // TODO: Wouldn't be nice if Line had .segments? var geometry = new THREE.Geometry(); geometry.vertices.push( vertices[ 0 ], vertices[ 1 ], vertices[ 1 ], vertices[ 2 ], vertices[ 2 ], vertices[ 3 ], vertices[ 3 ], vertices[ 0 ], vertices[ 4 ], vertices[ 5 ], vertices[ 5 ], vertices[ 6 ], vertices[ 6 ], vertices[ 7 ], vertices[ 7 ], vertices[ 4 ], vertices[ 0 ], vertices[ 4 ], vertices[ 1 ], vertices[ 5 ], vertices[ 2 ], vertices[ 6 ], vertices[ 3 ], vertices[ 7 ] ); THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: 0xffff00 } ), THREE.LinePieces ); if ( object !== undefined ) { this.update( object ); } }; THREE.BoxHelper.prototype = Object.create( THREE.Line.prototype ); THREE.BoxHelper.prototype.update = function ( object ) { var geometry = object.geometry; if ( geometry.boundingBox === null ) { geometry.computeBoundingBox(); } var min = geometry.boundingBox.min; var max = geometry.boundingBox.max; var vertices = this.vertices; vertices[ 0 ].set( max.x, max.y, max.z ); vertices[ 1 ].set( min.x, max.y, max.z ); vertices[ 2 ].set( min.x, min.y, max.z ); vertices[ 3 ].set( max.x, min.y, max.z ); vertices[ 4 ].set( max.x, max.y, min.z ); vertices[ 5 ].set( min.x, max.y, min.z ); vertices[ 6 ].set( min.x, min.y, min.z ); vertices[ 7 ].set( max.x, min.y, min.z ); this.geometry.computeBoundingSphere(); this.geometry.verticesNeedUpdate = true; this.matrixAutoUpdate = false; this.matrixWorld = object.matrixWorld; }; /** * @author WestLangley / http://github.com/WestLangley */ // a helper to show the world-axis-aligned bounding box for an object THREE.BoundingBoxHelper = function ( object, hex ) { var color = ( hex !== undefined ) ? hex : 0x888888; this.object = object; this.box = new THREE.Box3(); THREE.Mesh.call( this, new THREE.BoxGeometry( 1, 1, 1 ), new THREE.MeshBasicMaterial( { color: color, wireframe: true } ) ); }; THREE.BoundingBoxHelper.prototype = Object.create( THREE.Mesh.prototype ); THREE.BoundingBoxHelper.prototype.update = function () { this.box.setFromObject( this.object ); this.box.size( this.scale ); this.box.center( this.position ); }; /** * @author alteredq / http://alteredqualia.com/ * * - shows frustum, line of sight and up of the camera * - suitable for fast updates * - based on frustum visualization in lightgl.js shadowmap example * http://evanw.github.com/lightgl.js/tests/shadowmap.html */ THREE.CameraHelper = function ( camera ) { var geometry = new THREE.Geometry(); var material = new THREE.LineBasicMaterial( { color: 0xffffff, vertexColors: THREE.FaceColors } ); var pointMap = {}; // colors var hexFrustum = 0xffaa00; var hexCone = 0xff0000; var hexUp = 0x00aaff; var hexTarget = 0xffffff; var hexCross = 0x333333; // near addLine( "n1", "n2", hexFrustum ); addLine( "n2", "n4", hexFrustum ); addLine( "n4", "n3", hexFrustum ); addLine( "n3", "n1", hexFrustum ); // far addLine( "f1", "f2", hexFrustum ); addLine( "f2", "f4", hexFrustum ); addLine( "f4", "f3", hexFrustum ); addLine( "f3", "f1", hexFrustum ); // sides addLine( "n1", "f1", hexFrustum ); addLine( "n2", "f2", hexFrustum ); addLine( "n3", "f3", hexFrustum ); addLine( "n4", "f4", hexFrustum ); // cone addLine( "p", "n1", hexCone ); addLine( "p", "n2", hexCone ); addLine( "p", "n3", hexCone ); addLine( "p", "n4", hexCone ); // up addLine( "u1", "u2", hexUp ); addLine( "u2", "u3", hexUp ); addLine( "u3", "u1", hexUp ); // target addLine( "c", "t", hexTarget ); addLine( "p", "c", hexCross ); // cross addLine( "cn1", "cn2", hexCross ); addLine( "cn3", "cn4", hexCross ); addLine( "cf1", "cf2", hexCross ); addLine( "cf3", "cf4", hexCross ); function addLine( a, b, hex ) { addPoint( a, hex ); addPoint( b, hex ); } function addPoint( id, hex ) { geometry.vertices.push( new THREE.Vector3() ); geometry.colors.push( new THREE.Color( hex ) ); if ( pointMap[ id ] === undefined ) { pointMap[ id ] = []; } pointMap[ id ].push( geometry.vertices.length - 1 ); } THREE.Line.call( this, geometry, material, THREE.LinePieces ); this.camera = camera; this.matrixWorld = camera.matrixWorld; this.matrixAutoUpdate = false; this.pointMap = pointMap; this.update(); }; THREE.CameraHelper.prototype = Object.create( THREE.Line.prototype ); THREE.CameraHelper.prototype.update = function () { var vector = new THREE.Vector3(); var camera = new THREE.Camera(); var projector = new THREE.Projector(); return function () { var scope = this; var w = 1, h = 1; // we need just camera projection matrix // world matrix must be identity camera.projectionMatrix.copy( this.camera.projectionMatrix ); // center / target setPoint( "c", 0, 0, -1 ); setPoint( "t", 0, 0, 1 ); // near setPoint( "n1", -w, -h, -1 ); setPoint( "n2", w, -h, -1 ); setPoint( "n3", -w, h, -1 ); setPoint( "n4", w, h, -1 ); // far setPoint( "f1", -w, -h, 1 ); setPoint( "f2", w, -h, 1 ); setPoint( "f3", -w, h, 1 ); setPoint( "f4", w, h, 1 ); // up setPoint( "u1", w * 0.7, h * 1.1, -1 ); setPoint( "u2", -w * 0.7, h * 1.1, -1 ); setPoint( "u3", 0, h * 2, -1 ); // cross setPoint( "cf1", -w, 0, 1 ); setPoint( "cf2", w, 0, 1 ); setPoint( "cf3", 0, -h, 1 ); setPoint( "cf4", 0, h, 1 ); setPoint( "cn1", -w, 0, -1 ); setPoint( "cn2", w, 0, -1 ); setPoint( "cn3", 0, -h, -1 ); setPoint( "cn4", 0, h, -1 ); function setPoint( point, x, y, z ) { vector.set( x, y, z ); projector.unprojectVector( vector, camera ); var points = scope.pointMap[ point ]; if ( points !== undefined ) { for ( var i = 0, il = points.length; i < il; i ++ ) { scope.geometry.vertices[ points[ i ] ].copy( vector ); } } } this.geometry.verticesNeedUpdate = true; }; }(); /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.DirectionalLightHelper = function ( light, size ) { THREE.Object3D.call( this ); this.light = light; this.light.updateMatrixWorld(); this.matrixWorld = light.matrixWorld; this.matrixAutoUpdate = false; size = size || 1; var geometry = new THREE.PlaneGeometry( size, size ); var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); this.lightPlane = new THREE.Mesh( geometry, material ); this.add( this.lightPlane ); geometry = new THREE.Geometry(); geometry.vertices.push( new THREE.Vector3() ); geometry.vertices.push( new THREE.Vector3() ); material = new THREE.LineBasicMaterial( { fog: false } ); material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); this.targetLine = new THREE.Line( geometry, material ); this.add( this.targetLine ); this.update(); }; THREE.DirectionalLightHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.DirectionalLightHelper.prototype.dispose = function () { this.lightPlane.geometry.dispose(); this.lightPlane.material.dispose(); this.targetLine.geometry.dispose(); this.targetLine.material.dispose(); }; THREE.DirectionalLightHelper.prototype.update = function () { var v1 = new THREE.Vector3(); var v2 = new THREE.Vector3(); var v3 = new THREE.Vector3(); return function () { v1.setFromMatrixPosition( this.light.matrixWorld ); v2.setFromMatrixPosition( this.light.target.matrixWorld ); v3.subVectors( v2, v1 ); this.lightPlane.lookAt( v3 ); this.lightPlane.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); this.targetLine.geometry.vertices[ 1 ].copy( v3 ); this.targetLine.geometry.verticesNeedUpdate = true; this.targetLine.material.color.copy( this.lightPlane.material.color ); } }(); /** * @author WestLangley / http://github.com/WestLangley */ THREE.EdgesHelper = function ( object, hex ) { var color = ( hex !== undefined ) ? hex : 0xffffff; var edge = [ 0, 0 ], hash = {}; var sortFunction = function ( a, b ) { return a - b }; var keys = [ 'a', 'b', 'c' ]; var geometry = new THREE.BufferGeometry(); var geometry2 = object.geometry.clone(); geometry2.mergeVertices(); geometry2.computeFaceNormals(); var vertices = geometry2.vertices; var faces = geometry2.faces; var numEdges = 0; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0; j < 3; j ++ ) { edge[ 0 ] = face[ keys[ j ] ]; edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; edge.sort( sortFunction ); var key = edge.toString(); if ( hash[ key ] === undefined ) { hash[ key ] = { vert1: edge[ 0 ], vert2: edge[ 1 ], face1: i, face2: undefined }; numEdges ++; } else { hash[ key ].face2 = i; } } } geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); var coords = geometry.attributes.position.array; var index = 0; for ( var key in hash ) { var h = hash[ key ]; if ( h.face2 === undefined || faces[ h.face1 ].normal.dot( faces[ h.face2 ].normal ) < 0.9999 ) { // hardwired const OK var vertex = vertices[ h.vert1 ]; coords[ index ++ ] = vertex.x; coords[ index ++ ] = vertex.y; coords[ index ++ ] = vertex.z; vertex = vertices[ h.vert2 ]; coords[ index ++ ] = vertex.x; coords[ index ++ ] = vertex.y; coords[ index ++ ] = vertex.z; } } THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); this.matrixAutoUpdate = false; this.matrixWorld = object.matrixWorld; }; THREE.EdgesHelper.prototype = Object.create( THREE.Line.prototype ); /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.FaceNormalsHelper = function ( object, size, hex, linewidth ) { this.object = object; this.size = ( size !== undefined ) ? size : 1; var color = ( hex !== undefined ) ? hex : 0xffff00; var width = ( linewidth !== undefined ) ? linewidth : 1; var geometry = new THREE.Geometry(); var faces = this.object.geometry.faces; for ( var i = 0, l = faces.length; i < l; i ++ ) { geometry.vertices.push( new THREE.Vector3() ); geometry.vertices.push( new THREE.Vector3() ); } THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); this.matrixAutoUpdate = false; this.normalMatrix = new THREE.Matrix3(); this.update(); }; THREE.FaceNormalsHelper.prototype = Object.create( THREE.Line.prototype ); THREE.FaceNormalsHelper.prototype.update = ( function ( object ) { var v1 = new THREE.Vector3(); return function ( object ) { this.object.updateMatrixWorld( true ); this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); var vertices = this.geometry.vertices; var faces = this.object.geometry.faces; var worldMatrix = this.object.matrixWorld; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; v1.copy( face.normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); var idx = 2 * i; vertices[ idx ].copy( face.centroid ).applyMatrix4( worldMatrix ); vertices[ idx + 1 ].addVectors( vertices[ idx ], v1 ); } this.geometry.verticesNeedUpdate = true; return this; } }()); /** * @author mrdoob / http://mrdoob.com/ */ THREE.GridHelper = function ( size, step ) { var geometry = new THREE.Geometry(); var material = new THREE.LineBasicMaterial( { vertexColors: THREE.VertexColors } ); this.color1 = new THREE.Color( 0x444444 ); this.color2 = new THREE.Color( 0x888888 ); for ( var i = - size; i <= size; i += step ) { geometry.vertices.push( new THREE.Vector3( - size, 0, i ), new THREE.Vector3( size, 0, i ), new THREE.Vector3( i, 0, - size ), new THREE.Vector3( i, 0, size ) ); var color = i === 0 ? this.color1 : this.color2; geometry.colors.push( color, color, color, color ); } THREE.Line.call( this, geometry, material, THREE.LinePieces ); }; THREE.GridHelper.prototype = Object.create( THREE.Line.prototype ); THREE.GridHelper.prototype.setColors = function( colorCenterLine, colorGrid ) { this.color1.set( colorCenterLine ); this.color2.set( colorGrid ); this.geometry.colorsNeedUpdate = true; } /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.HemisphereLightHelper = function ( light, sphereSize, arrowLength, domeSize ) { THREE.Object3D.call( this ); this.light = light; this.light.updateMatrixWorld(); this.matrixWorld = light.matrixWorld; this.matrixAutoUpdate = false; this.colors = [ new THREE.Color(), new THREE.Color() ]; var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); for ( var i = 0, il = 8; i < il; i ++ ) { geometry.faces[ i ].color = this.colors[ i < 4 ? 0 : 1 ]; } var material = new THREE.MeshBasicMaterial( { vertexColors: THREE.FaceColors, wireframe: true } ); this.lightSphere = new THREE.Mesh( geometry, material ); this.add( this.lightSphere ); this.update(); }; THREE.HemisphereLightHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.HemisphereLightHelper.prototype.dispose = function () { this.lightSphere.geometry.dispose(); this.lightSphere.material.dispose(); }; THREE.HemisphereLightHelper.prototype.update = function () { var vector = new THREE.Vector3(); return function () { this.colors[ 0 ].copy( this.light.color ).multiplyScalar( this.light.intensity ); this.colors[ 1 ].copy( this.light.groundColor ).multiplyScalar( this.light.intensity ); this.lightSphere.lookAt( vector.setFromMatrixPosition( this.light.matrixWorld ).negate() ); this.lightSphere.geometry.colorsNeedUpdate = true; } }(); /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ */ THREE.PointLightHelper = function ( light, sphereSize ) { this.light = light; this.light.updateMatrixWorld(); var geometry = new THREE.SphereGeometry( sphereSize, 4, 2 ); var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); THREE.Mesh.call( this, geometry, material ); this.matrixWorld = this.light.matrixWorld; this.matrixAutoUpdate = false; /* var distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 ); var distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } ); this.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial ); this.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial ); var d = light.distance; if ( d === 0.0 ) { this.lightDistance.visible = false; } else { this.lightDistance.scale.set( d, d, d ); } this.add( this.lightDistance ); */ }; THREE.PointLightHelper.prototype = Object.create( THREE.Mesh.prototype ); THREE.PointLightHelper.prototype.dispose = function () { this.geometry.dispose(); this.material.dispose(); }; THREE.PointLightHelper.prototype.update = function () { this.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); /* var d = this.light.distance; if ( d === 0.0 ) { this.lightDistance.visible = false; } else { this.lightDistance.visible = true; this.lightDistance.scale.set( d, d, d ); } */ }; /** * @author alteredq / http://alteredqualia.com/ * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.SpotLightHelper = function ( light ) { THREE.Object3D.call( this ); this.light = light; this.light.updateMatrixWorld(); this.matrixWorld = light.matrixWorld; this.matrixAutoUpdate = false; var geometry = new THREE.CylinderGeometry( 0, 1, 1, 8, 1, true ); geometry.applyMatrix( new THREE.Matrix4().makeTranslation( 0, -0.5, 0 ) ); geometry.applyMatrix( new THREE.Matrix4().makeRotationX( - Math.PI / 2 ) ); var material = new THREE.MeshBasicMaterial( { wireframe: true, fog: false } ); this.cone = new THREE.Mesh( geometry, material ); this.add( this.cone ); this.update(); }; THREE.SpotLightHelper.prototype = Object.create( THREE.Object3D.prototype ); THREE.SpotLightHelper.prototype.dispose = function () { this.cone.geometry.dispose(); this.cone.material.dispose(); }; THREE.SpotLightHelper.prototype.update = function () { var vector = new THREE.Vector3(); var vector2 = new THREE.Vector3(); return function () { var coneLength = this.light.distance ? this.light.distance : 10000; var coneWidth = coneLength * Math.tan( this.light.angle ); this.cone.scale.set( coneWidth, coneWidth, coneLength ); vector.setFromMatrixPosition( this.light.matrixWorld ); vector2.setFromMatrixPosition( this.light.target.matrixWorld ); this.cone.lookAt( vector2.sub( vector ) ); this.cone.material.color.copy( this.light.color ).multiplyScalar( this.light.intensity ); }; }(); /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.VertexNormalsHelper = function ( object, size, hex, linewidth ) { this.object = object; this.size = ( size !== undefined ) ? size : 1; var color = ( hex !== undefined ) ? hex : 0xff0000; var width = ( linewidth !== undefined ) ? linewidth : 1; var geometry = new THREE.Geometry(); var vertices = object.geometry.vertices; var faces = object.geometry.faces; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { geometry.vertices.push( new THREE.Vector3() ); geometry.vertices.push( new THREE.Vector3() ); } } THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); this.matrixAutoUpdate = false; this.normalMatrix = new THREE.Matrix3(); this.update(); }; THREE.VertexNormalsHelper.prototype = Object.create( THREE.Line.prototype ); THREE.VertexNormalsHelper.prototype.update = ( function ( object ) { var v1 = new THREE.Vector3(); return function( object ) { var keys = [ 'a', 'b', 'c', 'd' ]; this.object.updateMatrixWorld( true ); this.normalMatrix.getNormalMatrix( this.object.matrixWorld ); var vertices = this.geometry.vertices; var verts = this.object.geometry.vertices; var faces = this.object.geometry.faces; var worldMatrix = this.object.matrixWorld; var idx = 0; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0, jl = face.vertexNormals.length; j < jl; j ++ ) { var vertexId = face[ keys[ j ] ]; var vertex = verts[ vertexId ]; var normal = face.vertexNormals[ j ]; vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); v1.copy( normal ).applyMatrix3( this.normalMatrix ).normalize().multiplyScalar( this.size ); v1.add( vertices[ idx ] ); idx = idx + 1; vertices[ idx ].copy( v1 ); idx = idx + 1; } } this.geometry.verticesNeedUpdate = true; return this; } }()); /** * @author mrdoob / http://mrdoob.com/ * @author WestLangley / http://github.com/WestLangley */ THREE.VertexTangentsHelper = function ( object, size, hex, linewidth ) { this.object = object; this.size = ( size !== undefined ) ? size : 1; var color = ( hex !== undefined ) ? hex : 0x0000ff; var width = ( linewidth !== undefined ) ? linewidth : 1; var geometry = new THREE.Geometry(); var vertices = object.geometry.vertices; var faces = object.geometry.faces; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { geometry.vertices.push( new THREE.Vector3() ); geometry.vertices.push( new THREE.Vector3() ); } } THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color, linewidth: width } ), THREE.LinePieces ); this.matrixAutoUpdate = false; this.update(); }; THREE.VertexTangentsHelper.prototype = Object.create( THREE.Line.prototype ); THREE.VertexTangentsHelper.prototype.update = ( function ( object ) { var v1 = new THREE.Vector3(); return function( object ) { var keys = [ 'a', 'b', 'c', 'd' ]; this.object.updateMatrixWorld( true ); var vertices = this.geometry.vertices; var verts = this.object.geometry.vertices; var faces = this.object.geometry.faces; var worldMatrix = this.object.matrixWorld; var idx = 0; for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0, jl = face.vertexTangents.length; j < jl; j ++ ) { var vertexId = face[ keys[ j ] ]; var vertex = verts[ vertexId ]; var tangent = face.vertexTangents[ j ]; vertices[ idx ].copy( vertex ).applyMatrix4( worldMatrix ); v1.copy( tangent ).transformDirection( worldMatrix ).multiplyScalar( this.size ); v1.add( vertices[ idx ] ); idx = idx + 1; vertices[ idx ].copy( v1 ); idx = idx + 1; } } this.geometry.verticesNeedUpdate = true; return this; } }()); /** * @author mrdoob / http://mrdoob.com/ */ THREE.WireframeHelper = function ( object, hex ) { var color = ( hex !== undefined ) ? hex : 0xffffff; var edge = [ 0, 0 ], hash = {}; var sortFunction = function ( a, b ) { return a - b }; var keys = [ 'a', 'b', 'c' ]; var geometry = new THREE.BufferGeometry(); if ( object.geometry instanceof THREE.Geometry ) { var vertices = object.geometry.vertices; var faces = object.geometry.faces; var numEdges = 0; // allocate maximal size var edges = new Uint32Array( 6 * faces.length ); for ( var i = 0, l = faces.length; i < l; i ++ ) { var face = faces[ i ]; for ( var j = 0; j < 3; j ++ ) { edge[ 0 ] = face[ keys[ j ] ]; edge[ 1 ] = face[ keys[ ( j + 1 ) % 3 ] ]; edge.sort( sortFunction ); var key = edge.toString(); if ( hash[ key ] === undefined ) { edges[ 2 * numEdges ] = edge[ 0 ]; edges[ 2 * numEdges + 1 ] = edge[ 1 ]; hash[ key ] = true; numEdges ++; } } } geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); var coords = geometry.attributes.position.array; for ( var i = 0, l = numEdges; i < l; i ++ ) { for ( var j = 0; j < 2; j ++ ) { var vertex = vertices[ edges [ 2 * i + j] ]; var index = 6 * i + 3 * j; coords[ index + 0 ] = vertex.x; coords[ index + 1 ] = vertex.y; coords[ index + 2 ] = vertex.z; } } } else if ( object.geometry instanceof THREE.BufferGeometry && object.geometry.attributes.index !== undefined ) { // indexed BufferGeometry var vertices = object.geometry.attributes.position.array; var indices = object.geometry.attributes.index.array; var offsets = object.geometry.offsets; var numEdges = 0; // allocate maximal size var edges = new Uint32Array( 2 * indices.length ); for ( var o = 0, ol = offsets.length; o < ol; ++ o ) { var start = offsets[ o ].start; var count = offsets[ o ].count; var index = offsets[ o ].index; for ( var i = start, il = start + count; i < il; i += 3 ) { for ( var j = 0; j < 3; j ++ ) { edge[ 0 ] = index + indices[ i + j ]; edge[ 1 ] = index + indices[ i + ( j + 1 ) % 3 ]; edge.sort( sortFunction ); var key = edge.toString(); if ( hash[ key ] === undefined ) { edges[ 2 * numEdges ] = edge[ 0 ]; edges[ 2 * numEdges + 1 ] = edge[ 1 ]; hash[ key ] = true; numEdges ++; } } } } geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); var coords = geometry.attributes.position.array; for ( var i = 0, l = numEdges; i < l; i ++ ) { for ( var j = 0; j < 2; j ++ ) { var index = 6 * i + 3 * j; var index2 = 3 * edges[ 2 * i + j]; coords[ index + 0 ] = vertices[ index2 ]; coords[ index + 1 ] = vertices[ index2 + 1 ]; coords[ index + 2 ] = vertices[ index2 + 2 ]; } } } else if ( object.geometry instanceof THREE.BufferGeometry ) { // non-indexed BufferGeometry var vertices = object.geometry.attributes.position.array; var numEdges = vertices.length / 3; var numTris = numEdges / 3; geometry.addAttribute( 'position', Float32Array, 2 * numEdges, 3 ); var coords = geometry.attributes.position.array; for ( var i = 0, l = numTris; i < l; i ++ ) { for ( var j = 0; j < 3; j ++ ) { var index = 18 * i + 6 * j; var index1 = 9 * i + 3 * j; coords[ index + 0 ] = vertices[ index1 ]; coords[ index + 1 ] = vertices[ index1 + 1 ]; coords[ index + 2 ] = vertices[ index1 + 2 ]; var index2 = 9 * i + 3 * ( ( j + 1 ) % 3 ); coords[ index + 3 ] = vertices[ index2 ]; coords[ index + 4 ] = vertices[ index2 + 1 ]; coords[ index + 5 ] = vertices[ index2 + 2 ]; } } } THREE.Line.call( this, geometry, new THREE.LineBasicMaterial( { color: color } ), THREE.LinePieces ); this.matrixAutoUpdate = false; this.matrixWorld = object.matrixWorld; }; THREE.WireframeHelper.prototype = Object.create( THREE.Line.prototype ); /** * @author alteredq / http://alteredqualia.com/ */ THREE.ImmediateRenderObject = function () { THREE.Object3D.call( this ); this.render = function ( renderCallback ) { }; }; THREE.ImmediateRenderObject.prototype = Object.create( THREE.Object3D.prototype ); /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.LensFlare = function ( texture, size, distance, blending, color ) { THREE.Object3D.call( this ); this.lensFlares = []; this.positionScreen = new THREE.Vector3(); this.customUpdateCallback = undefined; if( texture !== undefined ) { this.add( texture, size, distance, blending, color ); } }; THREE.LensFlare.prototype = Object.create( THREE.Object3D.prototype ); /* * Add: adds another flare */ THREE.LensFlare.prototype.add = function ( texture, size, distance, blending, color, opacity ) { if( size === undefined ) size = -1; if( distance === undefined ) distance = 0; if( opacity === undefined ) opacity = 1; if( color === undefined ) color = new THREE.Color( 0xffffff ); if( blending === undefined ) blending = THREE.NormalBlending; distance = Math.min( distance, Math.max( 0, distance ) ); this.lensFlares.push( { texture: texture, // THREE.Texture size: size, // size in pixels (-1 = use texture.width) distance: distance, // distance (0-1) from light source (0=at light source) x: 0, y: 0, z: 0, // screen position (-1 => 1) z = 0 is ontop z = 1 is back scale: 1, // scale rotation: 1, // rotation opacity: opacity, // opacity color: color, // color blending: blending } ); // blending }; /* * Update lens flares update positions on all flares based on the screen position * Set myLensFlare.customUpdateCallback to alter the flares in your project specific way. */ THREE.LensFlare.prototype.updateLensFlares = function () { var f, fl = this.lensFlares.length; var flare; var vecX = -this.positionScreen.x * 2; var vecY = -this.positionScreen.y * 2; for( f = 0; f < fl; f ++ ) { flare = this.lensFlares[ f ]; flare.x = this.positionScreen.x + vecX * flare.distance; flare.y = this.positionScreen.y + vecY * flare.distance; flare.wantedRotation = flare.x * Math.PI * 0.25; flare.rotation += ( flare.wantedRotation - flare.rotation ) * 0.25; } }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.MorphBlendMesh = function( geometry, material ) { THREE.Mesh.call( this, geometry, material ); this.animationsMap = {}; this.animationsList = []; // prepare default animation // (all frames played together in 1 second) var numFrames = this.geometry.morphTargets.length; var name = "__default"; var startFrame = 0; var endFrame = numFrames - 1; var fps = numFrames / 1; this.createAnimation( name, startFrame, endFrame, fps ); this.setAnimationWeight( name, 1 ); }; THREE.MorphBlendMesh.prototype = Object.create( THREE.Mesh.prototype ); THREE.MorphBlendMesh.prototype.createAnimation = function ( name, start, end, fps ) { var animation = { startFrame: start, endFrame: end, length: end - start + 1, fps: fps, duration: ( end - start ) / fps, lastFrame: 0, currentFrame: 0, active: false, time: 0, direction: 1, weight: 1, directionBackwards: false, mirroredLoop: false }; this.animationsMap[ name ] = animation; this.animationsList.push( animation ); }; THREE.MorphBlendMesh.prototype.autoCreateAnimations = function ( fps ) { var pattern = /([a-z]+)(\d+)/; var firstAnimation, frameRanges = {}; var geometry = this.geometry; for ( var i = 0, il = geometry.morphTargets.length; i < il; i ++ ) { var morph = geometry.morphTargets[ i ]; var chunks = morph.name.match( pattern ); if ( chunks && chunks.length > 1 ) { var name = chunks[ 1 ]; var num = chunks[ 2 ]; if ( ! frameRanges[ name ] ) frameRanges[ name ] = { start: Infinity, end: -Infinity }; var range = frameRanges[ name ]; if ( i < range.start ) range.start = i; if ( i > range.end ) range.end = i; if ( ! firstAnimation ) firstAnimation = name; } } for ( var name in frameRanges ) { var range = frameRanges[ name ]; this.createAnimation( name, range.start, range.end, fps ); } this.firstAnimation = firstAnimation; }; THREE.MorphBlendMesh.prototype.setAnimationDirectionForward = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.direction = 1; animation.directionBackwards = false; } }; THREE.MorphBlendMesh.prototype.setAnimationDirectionBackward = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.direction = -1; animation.directionBackwards = true; } }; THREE.MorphBlendMesh.prototype.setAnimationFPS = function ( name, fps ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.fps = fps; animation.duration = ( animation.end - animation.start ) / animation.fps; } }; THREE.MorphBlendMesh.prototype.setAnimationDuration = function ( name, duration ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.duration = duration; animation.fps = ( animation.end - animation.start ) / animation.duration; } }; THREE.MorphBlendMesh.prototype.setAnimationWeight = function ( name, weight ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.weight = weight; } }; THREE.MorphBlendMesh.prototype.setAnimationTime = function ( name, time ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.time = time; } }; THREE.MorphBlendMesh.prototype.getAnimationTime = function ( name ) { var time = 0; var animation = this.animationsMap[ name ]; if ( animation ) { time = animation.time; } return time; }; THREE.MorphBlendMesh.prototype.getAnimationDuration = function ( name ) { var duration = -1; var animation = this.animationsMap[ name ]; if ( animation ) { duration = animation.duration; } return duration; }; THREE.MorphBlendMesh.prototype.playAnimation = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.time = 0; animation.active = true; } else { console.warn( "animation[" + name + "] undefined" ); } }; THREE.MorphBlendMesh.prototype.stopAnimation = function ( name ) { var animation = this.animationsMap[ name ]; if ( animation ) { animation.active = false; } }; THREE.MorphBlendMesh.prototype.update = function ( delta ) { for ( var i = 0, il = this.animationsList.length; i < il; i ++ ) { var animation = this.animationsList[ i ]; if ( ! animation.active ) continue; var frameTime = animation.duration / animation.length; animation.time += animation.direction * delta; if ( animation.mirroredLoop ) { if ( animation.time > animation.duration || animation.time < 0 ) { animation.direction *= -1; if ( animation.time > animation.duration ) { animation.time = animation.duration; animation.directionBackwards = true; } if ( animation.time < 0 ) { animation.time = 0; animation.directionBackwards = false; } } } else { animation.time = animation.time % animation.duration; if ( animation.time < 0 ) animation.time += animation.duration; } var keyframe = animation.startFrame + THREE.Math.clamp( Math.floor( animation.time / frameTime ), 0, animation.length - 1 ); var weight = animation.weight; if ( keyframe !== animation.currentFrame ) { this.morphTargetInfluences[ animation.lastFrame ] = 0; this.morphTargetInfluences[ animation.currentFrame ] = 1 * weight; this.morphTargetInfluences[ keyframe ] = 0; animation.lastFrame = animation.currentFrame; animation.currentFrame = keyframe; } var mix = ( animation.time % frameTime ) / frameTime; if ( animation.directionBackwards ) mix = 1 - mix; this.morphTargetInfluences[ animation.currentFrame ] = mix * weight; this.morphTargetInfluences[ animation.lastFrame ] = ( 1 - mix ) * weight; } }; /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.LensFlarePlugin = function () { var _gl, _renderer, _precision, _lensFlare = {}; this.init = function ( renderer ) { _gl = renderer.context; _renderer = renderer; _precision = renderer.getPrecision(); _lensFlare.vertices = new Float32Array( 8 + 8 ); _lensFlare.faces = new Uint16Array( 6 ); var i = 0; _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = -1; // vertex _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 0; // uv... etc. _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = -1; _lensFlare.vertices[ i++ ] = 1; _lensFlare.vertices[ i++ ] = 0; _lensFlare.vertices[ i++ ] = 1; i = 0; _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 1; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 0; _lensFlare.faces[ i++ ] = 2; _lensFlare.faces[ i++ ] = 3; // buffers _lensFlare.vertexBuffer = _gl.createBuffer(); _lensFlare.elementBuffer = _gl.createBuffer(); _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, _lensFlare.vertices, _gl.STATIC_DRAW ); _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.faces, _gl.STATIC_DRAW ); // textures _lensFlare.tempTexture = _gl.createTexture(); _lensFlare.occlusionTexture = _gl.createTexture(); _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, 16, 16, 0, _gl.RGB, _gl.UNSIGNED_BYTE, null ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); _gl.texImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, 16, 16, 0, _gl.RGBA, _gl.UNSIGNED_BYTE, null ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_S, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_WRAP_T, _gl.CLAMP_TO_EDGE ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MAG_FILTER, _gl.NEAREST ); _gl.texParameteri( _gl.TEXTURE_2D, _gl.TEXTURE_MIN_FILTER, _gl.NEAREST ); if ( _gl.getParameter( _gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS ) <= 0 ) { _lensFlare.hasVertexTexture = false; _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlare" ], _precision ); } else { _lensFlare.hasVertexTexture = true; _lensFlare.program = createProgram( THREE.ShaderFlares[ "lensFlareVertexTexture" ], _precision ); } _lensFlare.attributes = {}; _lensFlare.uniforms = {}; _lensFlare.attributes.vertex = _gl.getAttribLocation ( _lensFlare.program, "position" ); _lensFlare.attributes.uv = _gl.getAttribLocation ( _lensFlare.program, "uv" ); _lensFlare.uniforms.renderType = _gl.getUniformLocation( _lensFlare.program, "renderType" ); _lensFlare.uniforms.map = _gl.getUniformLocation( _lensFlare.program, "map" ); _lensFlare.uniforms.occlusionMap = _gl.getUniformLocation( _lensFlare.program, "occlusionMap" ); _lensFlare.uniforms.opacity = _gl.getUniformLocation( _lensFlare.program, "opacity" ); _lensFlare.uniforms.color = _gl.getUniformLocation( _lensFlare.program, "color" ); _lensFlare.uniforms.scale = _gl.getUniformLocation( _lensFlare.program, "scale" ); _lensFlare.uniforms.rotation = _gl.getUniformLocation( _lensFlare.program, "rotation" ); _lensFlare.uniforms.screenPosition = _gl.getUniformLocation( _lensFlare.program, "screenPosition" ); }; /* * Render lens flares * Method: renders 16x16 0xff00ff-colored points scattered over the light source area, * reads these back and calculates occlusion. * Then _lensFlare.update_lensFlares() is called to re-position and * update transparency of flares. Then they are rendered. * */ this.render = function ( scene, camera, viewportWidth, viewportHeight ) { var flares = scene.__webglFlares, nFlares = flares.length; if ( ! nFlares ) return; var tempPosition = new THREE.Vector3(); var invAspect = viewportHeight / viewportWidth, halfViewportWidth = viewportWidth * 0.5, halfViewportHeight = viewportHeight * 0.5; var size = 16 / viewportHeight, scale = new THREE.Vector2( size * invAspect, size ); var screenPosition = new THREE.Vector3( 1, 1, 0 ), screenPositionPixels = new THREE.Vector2( 1, 1 ); var uniforms = _lensFlare.uniforms, attributes = _lensFlare.attributes; // set _lensFlare program and reset blending _gl.useProgram( _lensFlare.program ); _gl.enableVertexAttribArray( _lensFlare.attributes.vertex ); _gl.enableVertexAttribArray( _lensFlare.attributes.uv ); // loop through all lens flares to update their occlusion and positions // setup gl and common used attribs/unforms _gl.uniform1i( uniforms.occlusionMap, 0 ); _gl.uniform1i( uniforms.map, 1 ); _gl.bindBuffer( _gl.ARRAY_BUFFER, _lensFlare.vertexBuffer ); _gl.vertexAttribPointer( attributes.vertex, 2, _gl.FLOAT, false, 2 * 8, 0 ); _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, _lensFlare.elementBuffer ); _gl.disable( _gl.CULL_FACE ); _gl.depthMask( false ); var i, j, jl, flare, sprite; for ( i = 0; i < nFlares; i ++ ) { size = 16 / viewportHeight; scale.set( size * invAspect, size ); // calc object screen position flare = flares[ i ]; tempPosition.set( flare.matrixWorld.elements[12], flare.matrixWorld.elements[13], flare.matrixWorld.elements[14] ); tempPosition.applyMatrix4( camera.matrixWorldInverse ); tempPosition.applyProjection( camera.projectionMatrix ); // setup arrays for gl programs screenPosition.copy( tempPosition ) screenPositionPixels.x = screenPosition.x * halfViewportWidth + halfViewportWidth; screenPositionPixels.y = screenPosition.y * halfViewportHeight + halfViewportHeight; // screen cull if ( _lensFlare.hasVertexTexture || ( screenPositionPixels.x > 0 && screenPositionPixels.x < viewportWidth && screenPositionPixels.y > 0 && screenPositionPixels.y < viewportHeight ) ) { // save current RGB to temp texture _gl.activeTexture( _gl.TEXTURE1 ); _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGB, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); // render pink quad _gl.uniform1i( uniforms.renderType, 0 ); _gl.uniform2f( uniforms.scale, scale.x, scale.y ); _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); _gl.disable( _gl.BLEND ); _gl.enable( _gl.DEPTH_TEST ); _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); // copy result to occlusionMap _gl.activeTexture( _gl.TEXTURE0 ); _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.occlusionTexture ); _gl.copyTexImage2D( _gl.TEXTURE_2D, 0, _gl.RGBA, screenPositionPixels.x - 8, screenPositionPixels.y - 8, 16, 16, 0 ); // restore graphics _gl.uniform1i( uniforms.renderType, 1 ); _gl.disable( _gl.DEPTH_TEST ); _gl.activeTexture( _gl.TEXTURE1 ); _gl.bindTexture( _gl.TEXTURE_2D, _lensFlare.tempTexture ); _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); // update object positions flare.positionScreen.copy( screenPosition ) if ( flare.customUpdateCallback ) { flare.customUpdateCallback( flare ); } else { flare.updateLensFlares(); } // render flares _gl.uniform1i( uniforms.renderType, 2 ); _gl.enable( _gl.BLEND ); for ( j = 0, jl = flare.lensFlares.length; j < jl; j ++ ) { sprite = flare.lensFlares[ j ]; if ( sprite.opacity > 0.001 && sprite.scale > 0.001 ) { screenPosition.x = sprite.x; screenPosition.y = sprite.y; screenPosition.z = sprite.z; size = sprite.size * sprite.scale / viewportHeight; scale.x = size * invAspect; scale.y = size; _gl.uniform3f( uniforms.screenPosition, screenPosition.x, screenPosition.y, screenPosition.z ); _gl.uniform2f( uniforms.scale, scale.x, scale.y ); _gl.uniform1f( uniforms.rotation, sprite.rotation ); _gl.uniform1f( uniforms.opacity, sprite.opacity ); _gl.uniform3f( uniforms.color, sprite.color.r, sprite.color.g, sprite.color.b ); _renderer.setBlending( sprite.blending, sprite.blendEquation, sprite.blendSrc, sprite.blendDst ); _renderer.setTexture( sprite.texture, 1 ); _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); } } } } // restore gl _gl.enable( _gl.CULL_FACE ); _gl.enable( _gl.DEPTH_TEST ); _gl.depthMask( true ); }; function createProgram ( shader, precision ) { var program = _gl.createProgram(); var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); var prefix = "precision " + precision + " float;\n"; _gl.shaderSource( fragmentShader, prefix + shader.fragmentShader ); _gl.shaderSource( vertexShader, prefix + shader.vertexShader ); _gl.compileShader( fragmentShader ); _gl.compileShader( vertexShader ); _gl.attachShader( program, fragmentShader ); _gl.attachShader( program, vertexShader ); _gl.linkProgram( program ); return program; }; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.ShadowMapPlugin = function () { var _gl, _renderer, _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, _frustum = new THREE.Frustum(), _projScreenMatrix = new THREE.Matrix4(), _min = new THREE.Vector3(), _max = new THREE.Vector3(), _matrixPosition = new THREE.Vector3(); this.init = function ( renderer ) { _gl = renderer.context; _renderer = renderer; var depthShader = THREE.ShaderLib[ "depthRGBA" ]; var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); _depthMaterial._shadowPass = true; _depthMaterialMorph._shadowPass = true; _depthMaterialSkin._shadowPass = true; _depthMaterialMorphSkin._shadowPass = true; }; this.render = function ( scene, camera ) { if ( ! ( _renderer.shadowMapEnabled && _renderer.shadowMapAutoUpdate ) ) return; this.update( scene, camera ); }; this.update = function ( scene, camera ) { var i, il, j, jl, n, shadowMap, shadowMatrix, shadowCamera, program, buffer, material, webglObject, object, light, renderList, lights = [], k = 0, fog = null; // set GL state for depth map _gl.clearColor( 1, 1, 1, 1 ); _gl.disable( _gl.BLEND ); _gl.enable( _gl.CULL_FACE ); _gl.frontFace( _gl.CCW ); if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { _gl.cullFace( _gl.FRONT ); } else { _gl.cullFace( _gl.BACK ); } _renderer.setDepthTest( true ); // preprocess lights // - skip lights that are not casting shadows // - create virtual lights for cascaded shadow maps for ( i = 0, il = scene.__lights.length; i < il; i ++ ) { light = scene.__lights[ i ]; if ( ! light.castShadow ) continue; if ( ( light instanceof THREE.DirectionalLight ) && light.shadowCascade ) { for ( n = 0; n < light.shadowCascadeCount; n ++ ) { var virtualLight; if ( ! light.shadowCascadeArray[ n ] ) { virtualLight = createVirtualLight( light, n ); virtualLight.originalCamera = camera; var gyro = new THREE.Gyroscope(); gyro.position = light.shadowCascadeOffset; gyro.add( virtualLight ); gyro.add( virtualLight.target ); camera.add( gyro ); light.shadowCascadeArray[ n ] = virtualLight; console.log( "Created virtualLight", virtualLight ); } else { virtualLight = light.shadowCascadeArray[ n ]; } updateVirtualLight( light, n ); lights[ k ] = virtualLight; k ++; } } else { lights[ k ] = light; k ++; } } // render depth map for ( i = 0, il = lights.length; i < il; i ++ ) { light = lights[ i ]; if ( ! light.shadowMap ) { var shadowFilter = THREE.LinearFilter; if ( _renderer.shadowMapType === THREE.PCFSoftShadowMap ) { shadowFilter = THREE.NearestFilter; } var pars = { minFilter: shadowFilter, magFilter: shadowFilter, format: THREE.RGBAFormat }; light.shadowMap = new THREE.WebGLRenderTarget( light.shadowMapWidth, light.shadowMapHeight, pars ); light.shadowMapSize = new THREE.Vector2( light.shadowMapWidth, light.shadowMapHeight ); light.shadowMatrix = new THREE.Matrix4(); } if ( ! light.shadowCamera ) { if ( light instanceof THREE.SpotLight ) { light.shadowCamera = new THREE.PerspectiveCamera( light.shadowCameraFov, light.shadowMapWidth / light.shadowMapHeight, light.shadowCameraNear, light.shadowCameraFar ); } else if ( light instanceof THREE.DirectionalLight ) { light.shadowCamera = new THREE.OrthographicCamera( light.shadowCameraLeft, light.shadowCameraRight, light.shadowCameraTop, light.shadowCameraBottom, light.shadowCameraNear, light.shadowCameraFar ); } else { console.error( "Unsupported light type for shadow" ); continue; } scene.add( light.shadowCamera ); if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); } if ( light.shadowCameraVisible && ! light.cameraHelper ) { light.cameraHelper = new THREE.CameraHelper( light.shadowCamera ); light.shadowCamera.add( light.cameraHelper ); } if ( light.isVirtual && virtualLight.originalCamera == camera ) { updateShadowCamera( camera, light ); } shadowMap = light.shadowMap; shadowMatrix = light.shadowMatrix; shadowCamera = light.shadowCamera; shadowCamera.position.setFromMatrixPosition( light.matrixWorld ); _matrixPosition.setFromMatrixPosition( light.target.matrixWorld ); shadowCamera.lookAt( _matrixPosition ); shadowCamera.updateMatrixWorld(); shadowCamera.matrixWorldInverse.getInverse( shadowCamera.matrixWorld ); if ( light.cameraHelper ) light.cameraHelper.visible = light.shadowCameraVisible; if ( light.shadowCameraVisible ) light.cameraHelper.update(); // compute shadow matrix shadowMatrix.set( 0.5, 0.0, 0.0, 0.5, 0.0, 0.5, 0.0, 0.5, 0.0, 0.0, 0.5, 0.5, 0.0, 0.0, 0.0, 1.0 ); shadowMatrix.multiply( shadowCamera.projectionMatrix ); shadowMatrix.multiply( shadowCamera.matrixWorldInverse ); // update camera matrices and frustum _projScreenMatrix.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse ); _frustum.setFromMatrix( _projScreenMatrix ); // render shadow map _renderer.setRenderTarget( shadowMap ); _renderer.clear(); // set object matrices & frustum culling renderList = scene.__webglObjects; for ( j = 0, jl = renderList.length; j < jl; j ++ ) { webglObject = renderList[ j ]; object = webglObject.object; webglObject.render = false; if ( object.visible && object.castShadow ) { if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); webglObject.render = true; } } } // render regular objects var objectMaterial, useMorphing, useSkinning; for ( j = 0, jl = renderList.length; j < jl; j ++ ) { webglObject = renderList[ j ]; if ( webglObject.render ) { object = webglObject.object; buffer = webglObject.buffer; // culling is overriden globally for all objects // while rendering depth map // need to deal with MeshFaceMaterial somehow // in that case just use the first of material.materials for now // (proper solution would require to break objects by materials // similarly to regular rendering and then set corresponding // depth materials per each chunk instead of just once per object) objectMaterial = getObjectMaterial( object ); useMorphing = object.geometry.morphTargets !== undefined && object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; if ( object.customDepthMaterial ) { material = object.customDepthMaterial; } else if ( useSkinning ) { material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; } else if ( useMorphing ) { material = _depthMaterialMorph; } else { material = _depthMaterial; } if ( buffer instanceof THREE.BufferGeometry ) { _renderer.renderBufferDirect( shadowCamera, scene.__lights, fog, material, buffer, object ); } else { _renderer.renderBuffer( shadowCamera, scene.__lights, fog, material, buffer, object ); } } } // set matrices and render immediate objects renderList = scene.__webglObjectsImmediate; for ( j = 0, jl = renderList.length; j < jl; j ++ ) { webglObject = renderList[ j ]; object = webglObject.object; if ( object.visible && object.castShadow ) { object._modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld ); _renderer.renderImmediateObject( shadowCamera, scene.__lights, fog, _depthMaterial, object ); } } } // restore GL state var clearColor = _renderer.getClearColor(), clearAlpha = _renderer.getClearAlpha(); _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); _gl.enable( _gl.BLEND ); if ( _renderer.shadowMapCullFace === THREE.CullFaceFront ) { _gl.cullFace( _gl.BACK ); } }; function createVirtualLight( light, cascade ) { var virtualLight = new THREE.DirectionalLight(); virtualLight.isVirtual = true; virtualLight.onlyShadow = true; virtualLight.castShadow = true; virtualLight.shadowCameraNear = light.shadowCameraNear; virtualLight.shadowCameraFar = light.shadowCameraFar; virtualLight.shadowCameraLeft = light.shadowCameraLeft; virtualLight.shadowCameraRight = light.shadowCameraRight; virtualLight.shadowCameraBottom = light.shadowCameraBottom; virtualLight.shadowCameraTop = light.shadowCameraTop; virtualLight.shadowCameraVisible = light.shadowCameraVisible; virtualLight.shadowDarkness = light.shadowDarkness; virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; virtualLight.shadowMapWidth = light.shadowCascadeWidth[ cascade ]; virtualLight.shadowMapHeight = light.shadowCascadeHeight[ cascade ]; virtualLight.pointsWorld = []; virtualLight.pointsFrustum = []; var pointsWorld = virtualLight.pointsWorld, pointsFrustum = virtualLight.pointsFrustum; for ( var i = 0; i < 8; i ++ ) { pointsWorld[ i ] = new THREE.Vector3(); pointsFrustum[ i ] = new THREE.Vector3(); } var nearZ = light.shadowCascadeNearZ[ cascade ]; var farZ = light.shadowCascadeFarZ[ cascade ]; pointsFrustum[ 0 ].set( -1, -1, nearZ ); pointsFrustum[ 1 ].set( 1, -1, nearZ ); pointsFrustum[ 2 ].set( -1, 1, nearZ ); pointsFrustum[ 3 ].set( 1, 1, nearZ ); pointsFrustum[ 4 ].set( -1, -1, farZ ); pointsFrustum[ 5 ].set( 1, -1, farZ ); pointsFrustum[ 6 ].set( -1, 1, farZ ); pointsFrustum[ 7 ].set( 1, 1, farZ ); return virtualLight; } // Synchronize virtual light with the original light function updateVirtualLight( light, cascade ) { var virtualLight = light.shadowCascadeArray[ cascade ]; virtualLight.position.copy( light.position ); virtualLight.target.position.copy( light.target.position ); virtualLight.lookAt( virtualLight.target ); virtualLight.shadowCameraVisible = light.shadowCameraVisible; virtualLight.shadowDarkness = light.shadowDarkness; virtualLight.shadowBias = light.shadowCascadeBias[ cascade ]; var nearZ = light.shadowCascadeNearZ[ cascade ]; var farZ = light.shadowCascadeFarZ[ cascade ]; var pointsFrustum = virtualLight.pointsFrustum; pointsFrustum[ 0 ].z = nearZ; pointsFrustum[ 1 ].z = nearZ; pointsFrustum[ 2 ].z = nearZ; pointsFrustum[ 3 ].z = nearZ; pointsFrustum[ 4 ].z = farZ; pointsFrustum[ 5 ].z = farZ; pointsFrustum[ 6 ].z = farZ; pointsFrustum[ 7 ].z = farZ; } // Fit shadow camera's ortho frustum to camera frustum function updateShadowCamera( camera, light ) { var shadowCamera = light.shadowCamera, pointsFrustum = light.pointsFrustum, pointsWorld = light.pointsWorld; _min.set( Infinity, Infinity, Infinity ); _max.set( -Infinity, -Infinity, -Infinity ); for ( var i = 0; i < 8; i ++ ) { var p = pointsWorld[ i ]; p.copy( pointsFrustum[ i ] ); THREE.ShadowMapPlugin.__projector.unprojectVector( p, camera ); p.applyMatrix4( shadowCamera.matrixWorldInverse ); if ( p.x < _min.x ) _min.x = p.x; if ( p.x > _max.x ) _max.x = p.x; if ( p.y < _min.y ) _min.y = p.y; if ( p.y > _max.y ) _max.y = p.y; if ( p.z < _min.z ) _min.z = p.z; if ( p.z > _max.z ) _max.z = p.z; } shadowCamera.left = _min.x; shadowCamera.right = _max.x; shadowCamera.top = _max.y; shadowCamera.bottom = _min.y; // can't really fit near/far //shadowCamera.near = _min.z; //shadowCamera.far = _max.z; shadowCamera.updateProjectionMatrix(); } // For the moment just ignore objects that have multiple materials with different animation methods // Only the first material will be taken into account for deciding which depth material to use for shadow maps function getObjectMaterial( object ) { return object.material instanceof THREE.MeshFaceMaterial ? object.material.materials[ 0 ] : object.material; }; }; THREE.ShadowMapPlugin.__projector = new THREE.Projector(); /** * @author mikael emtinger / http://gomo.se/ * @author alteredq / http://alteredqualia.com/ */ THREE.SpritePlugin = function () { var _gl, _renderer, _texture; var vertices, faces, vertexBuffer, elementBuffer; var program, attributes, uniforms; this.init = function ( renderer ) { _gl = renderer.context; _renderer = renderer; vertices = new Float32Array( [ - 0.5, - 0.5, 0, 0, 0.5, - 0.5, 1, 0, 0.5, 0.5, 1, 1, - 0.5, 0.5, 0, 1 ] ); faces = new Uint16Array( [ 0, 1, 2, 0, 2, 3 ] ); vertexBuffer = _gl.createBuffer(); elementBuffer = _gl.createBuffer(); _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer ); _gl.bufferData( _gl.ARRAY_BUFFER, vertices, _gl.STATIC_DRAW ); _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); _gl.bufferData( _gl.ELEMENT_ARRAY_BUFFER, faces, _gl.STATIC_DRAW ); program = createProgram(); attributes = { position: _gl.getAttribLocation ( program, 'position' ), uv: _gl.getAttribLocation ( program, 'uv' ) }; uniforms = { uvOffset: _gl.getUniformLocation( program, 'uvOffset' ), uvScale: _gl.getUniformLocation( program, 'uvScale' ), rotation: _gl.getUniformLocation( program, 'rotation' ), scale: _gl.getUniformLocation( program, 'scale' ), color: _gl.getUniformLocation( program, 'color' ), map: _gl.getUniformLocation( program, 'map' ), opacity: _gl.getUniformLocation( program, 'opacity' ), modelViewMatrix: _gl.getUniformLocation( program, 'modelViewMatrix' ), projectionMatrix: _gl.getUniformLocation( program, 'projectionMatrix' ), fogType: _gl.getUniformLocation( program, 'fogType' ), fogDensity: _gl.getUniformLocation( program, 'fogDensity' ), fogNear: _gl.getUniformLocation( program, 'fogNear' ), fogFar: _gl.getUniformLocation( program, 'fogFar' ), fogColor: _gl.getUniformLocation( program, 'fogColor' ), alphaTest: _gl.getUniformLocation( program, 'alphaTest' ) }; var canvas = document.createElement( 'canvas' ); canvas.width = 8; canvas.height = 8; var context = canvas.getContext( '2d' ); context.fillStyle = '#ffffff'; context.fillRect( 0, 0, canvas.width, canvas.height ); _texture = new THREE.Texture( canvas ); _texture.needsUpdate = true; }; this.render = function ( scene, camera, viewportWidth, viewportHeight ) { var sprites = scene.__webglSprites, nSprites = sprites.length; if ( ! nSprites ) return; // setup gl _gl.useProgram( program ); _gl.enableVertexAttribArray( attributes.position ); _gl.enableVertexAttribArray( attributes.uv ); _gl.disable( _gl.CULL_FACE ); _gl.enable( _gl.BLEND ); _gl.bindBuffer( _gl.ARRAY_BUFFER, vertexBuffer ); _gl.vertexAttribPointer( attributes.position, 2, _gl.FLOAT, false, 2 * 8, 0 ); _gl.vertexAttribPointer( attributes.uv, 2, _gl.FLOAT, false, 2 * 8, 8 ); _gl.bindBuffer( _gl.ELEMENT_ARRAY_BUFFER, elementBuffer ); _gl.uniformMatrix4fv( uniforms.projectionMatrix, false, camera.projectionMatrix.elements ); _gl.activeTexture( _gl.TEXTURE0 ); _gl.uniform1i( uniforms.map, 0 ); var oldFogType = 0; var sceneFogType = 0; var fog = scene.fog; if ( fog ) { _gl.uniform3f( uniforms.fogColor, fog.color.r, fog.color.g, fog.color.b ); if ( fog instanceof THREE.Fog ) { _gl.uniform1f( uniforms.fogNear, fog.near ); _gl.uniform1f( uniforms.fogFar, fog.far ); _gl.uniform1i( uniforms.fogType, 1 ); oldFogType = 1; sceneFogType = 1; } else if ( fog instanceof THREE.FogExp2 ) { _gl.uniform1f( uniforms.fogDensity, fog.density ); _gl.uniform1i( uniforms.fogType, 2 ); oldFogType = 2; sceneFogType = 2; } } else { _gl.uniform1i( uniforms.fogType, 0 ); oldFogType = 0; sceneFogType = 0; } // update positions and sort var i, sprite, material, fogType, scale = []; for( i = 0; i < nSprites; i ++ ) { sprite = sprites[ i ]; material = sprite.material; if ( sprite.visible === false ) continue; sprite._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, sprite.matrixWorld ); sprite.z = - sprite._modelViewMatrix.elements[ 14 ]; } sprites.sort( painterSortStable ); // render all sprites for( i = 0; i < nSprites; i ++ ) { sprite = sprites[ i ]; if ( sprite.visible === false ) continue; material = sprite.material; _gl.uniform1f( uniforms.alphaTest, material.alphaTest ); _gl.uniformMatrix4fv( uniforms.modelViewMatrix, false, sprite._modelViewMatrix.elements ); scale[ 0 ] = sprite.scale.x; scale[ 1 ] = sprite.scale.y; if ( scene.fog && material.fog ) { fogType = sceneFogType; } else { fogType = 0; } if ( oldFogType !== fogType ) { _gl.uniform1i( uniforms.fogType, fogType ); oldFogType = fogType; } if ( material.map !== null ) { _gl.uniform2f( uniforms.uvOffset, material.map.offset.x, material.map.offset.y ); _gl.uniform2f( uniforms.uvScale, material.map.repeat.x, material.map.repeat.y ); } else { _gl.uniform2f( uniforms.uvOffset, 0, 0 ); _gl.uniform2f( uniforms.uvScale, 1, 1 ); } _gl.uniform1f( uniforms.opacity, material.opacity ); _gl.uniform3f( uniforms.color, material.color.r, material.color.g, material.color.b ); _gl.uniform1f( uniforms.rotation, material.rotation ); _gl.uniform2fv( uniforms.scale, scale ); _renderer.setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst ); _renderer.setDepthTest( material.depthTest ); _renderer.setDepthWrite( material.depthWrite ); if ( material.map && material.map.image && material.map.image.width ) { _renderer.setTexture( material.map, 0 ); } else { _renderer.setTexture( _texture, 0 ); } _gl.drawElements( _gl.TRIANGLES, 6, _gl.UNSIGNED_SHORT, 0 ); } // restore gl _gl.enable( _gl.CULL_FACE ); }; function createProgram () { var program = _gl.createProgram(); var vertexShader = _gl.createShader( _gl.VERTEX_SHADER ); var fragmentShader = _gl.createShader( _gl.FRAGMENT_SHADER ); _gl.shaderSource( vertexShader, [ 'precision ' + _renderer.getPrecision() + ' float;', 'uniform mat4 modelViewMatrix;', 'uniform mat4 projectionMatrix;', 'uniform float rotation;', 'uniform vec2 scale;', 'uniform vec2 uvOffset;', 'uniform vec2 uvScale;', 'attribute vec2 position;', 'attribute vec2 uv;', 'varying vec2 vUV;', 'void main() {', 'vUV = uvOffset + uv * uvScale;', 'vec2 alignedPosition = position * scale;', 'vec2 rotatedPosition;', 'rotatedPosition.x = cos( rotation ) * alignedPosition.x - sin( rotation ) * alignedPosition.y;', 'rotatedPosition.y = sin( rotation ) * alignedPosition.x + cos( rotation ) * alignedPosition.y;', 'vec4 finalPosition;', 'finalPosition = modelViewMatrix * vec4( 0.0, 0.0, 0.0, 1.0 );', 'finalPosition.xy += rotatedPosition;', 'finalPosition = projectionMatrix * finalPosition;', 'gl_Position = finalPosition;', '}' ].join( '\n' ) ); _gl.shaderSource( fragmentShader, [ 'precision ' + _renderer.getPrecision() + ' float;', 'uniform vec3 color;', 'uniform sampler2D map;', 'uniform float opacity;', 'uniform int fogType;', 'uniform vec3 fogColor;', 'uniform float fogDensity;', 'uniform float fogNear;', 'uniform float fogFar;', 'uniform float alphaTest;', 'varying vec2 vUV;', 'void main() {', 'vec4 texture = texture2D( map, vUV );', 'if ( texture.a < alphaTest ) discard;', 'gl_FragColor = vec4( color * texture.xyz, texture.a * opacity );', 'if ( fogType > 0 ) {', 'float depth = gl_FragCoord.z / gl_FragCoord.w;', 'float fogFactor = 0.0;', 'if ( fogType == 1 ) {', 'fogFactor = smoothstep( fogNear, fogFar, depth );', '} else {', 'const float LOG2 = 1.442695;', 'float fogFactor = exp2( - fogDensity * fogDensity * depth * depth * LOG2 );', 'fogFactor = 1.0 - clamp( fogFactor, 0.0, 1.0 );', '}', 'gl_FragColor = mix( gl_FragColor, vec4( fogColor, gl_FragColor.w ), fogFactor );', '}', '}' ].join( '\n' ) ); _gl.compileShader( vertexShader ); _gl.compileShader( fragmentShader ); _gl.attachShader( program, vertexShader ); _gl.attachShader( program, fragmentShader ); _gl.linkProgram( program ); return program; }; function painterSortStable ( a, b ) { if ( a.z !== b.z ) { return b.z - a.z; } else { return b.id - a.id; } }; }; /** * @author alteredq / http://alteredqualia.com/ */ THREE.DepthPassPlugin = function () { this.enabled = false; this.renderTarget = null; var _gl, _renderer, _depthMaterial, _depthMaterialMorph, _depthMaterialSkin, _depthMaterialMorphSkin, _frustum = new THREE.Frustum(), _projScreenMatrix = new THREE.Matrix4(); this.init = function ( renderer ) { _gl = renderer.context; _renderer = renderer; var depthShader = THREE.ShaderLib[ "depthRGBA" ]; var depthUniforms = THREE.UniformsUtils.clone( depthShader.uniforms ); _depthMaterial = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms } ); _depthMaterialMorph = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true } ); _depthMaterialSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, skinning: true } ); _depthMaterialMorphSkin = new THREE.ShaderMaterial( { fragmentShader: depthShader.fragmentShader, vertexShader: depthShader.vertexShader, uniforms: depthUniforms, morphTargets: true, skinning: true } ); _depthMaterial._shadowPass = true; _depthMaterialMorph._shadowPass = true; _depthMaterialSkin._shadowPass = true; _depthMaterialMorphSkin._shadowPass = true; }; this.render = function ( scene, camera ) { if ( ! this.enabled ) return; this.update( scene, camera ); }; this.update = function ( scene, camera ) { var i, il, j, jl, n, program, buffer, material, webglObject, object, light, renderList, fog = null; // set GL state for depth map _gl.clearColor( 1, 1, 1, 1 ); _gl.disable( _gl.BLEND ); _renderer.setDepthTest( true ); // update scene if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); // update camera matrices and frustum camera.matrixWorldInverse.getInverse( camera.matrixWorld ); _projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse ); _frustum.setFromMatrix( _projScreenMatrix ); // render depth map _renderer.setRenderTarget( this.renderTarget ); _renderer.clear(); // set object matrices & frustum culling renderList = scene.__webglObjects; for ( j = 0, jl = renderList.length; j < jl; j ++ ) { webglObject = renderList[ j ]; object = webglObject.object; webglObject.render = false; if ( object.visible ) { if ( ! ( object instanceof THREE.Mesh || object instanceof THREE.ParticleSystem ) || ! ( object.frustumCulled ) || _frustum.intersectsObject( object ) ) { object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); webglObject.render = true; } } } // render regular objects var objectMaterial, useMorphing, useSkinning; for ( j = 0, jl = renderList.length; j < jl; j ++ ) { webglObject = renderList[ j ]; if ( webglObject.render ) { object = webglObject.object; buffer = webglObject.buffer; // todo: create proper depth material for particles if ( object instanceof THREE.ParticleSystem && !object.customDepthMaterial ) continue; objectMaterial = getObjectMaterial( object ); if ( objectMaterial ) _renderer.setMaterialFaces( object.material ); useMorphing = object.geometry.morphTargets.length > 0 && objectMaterial.morphTargets; useSkinning = object instanceof THREE.SkinnedMesh && objectMaterial.skinning; if ( object.customDepthMaterial ) { material = object.customDepthMaterial; } else if ( useSkinning ) { material = useMorphing ? _depthMaterialMorphSkin : _depthMaterialSkin; } else if ( useMorphing ) { material = _depthMaterialMorph; } else { material = _depthMaterial; } if ( buffer instanceof THREE.BufferGeometry ) { _renderer.renderBufferDirect( camera, scene.__lights, fog, material, buffer, object ); } else { _renderer.renderBuffer( camera, scene.__lights, fog, material, buffer, object ); } } } // set matrices and render immediate objects renderList = scene.__webglObjectsImmediate; for ( j = 0, jl = renderList.length; j < jl; j ++ ) { webglObject = renderList[ j ]; object = webglObject.object; if ( object.visible ) { object._modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld ); _renderer.renderImmediateObject( camera, scene.__lights, fog, _depthMaterial, object ); } } // restore GL state var clearColor = _renderer.getClearColor(), clearAlpha = _renderer.getClearAlpha(); _gl.clearColor( clearColor.r, clearColor.g, clearColor.b, clearAlpha ); _gl.enable( _gl.BLEND ); }; // For the moment just ignore objects that have multiple materials with different animation methods // Only the first material will be taken into account for deciding which depth material to use function getObjectMaterial( object ) { return object.material instanceof THREE.MeshFaceMaterial ? object.material.materials[ 0 ] : object.material; }; }; /** * @author mikael emtinger / http://gomo.se/ */ THREE.ShaderFlares = { 'lensFlareVertexTexture': { vertexShader: [ "uniform lowp int renderType;", "uniform vec3 screenPosition;", "uniform vec2 scale;", "uniform float rotation;", "uniform sampler2D occlusionMap;", "attribute vec2 position;", "attribute vec2 uv;", "varying vec2 vUV;", "varying float vVisibility;", "void main() {", "vUV = uv;", "vec2 pos = position;", "if( renderType == 2 ) {", "vec4 visibility = texture2D( occlusionMap, vec2( 0.1, 0.1 ) );", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.1 ) );", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.1 ) );", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) );", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.9 ) );", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) );", "visibility += texture2D( occlusionMap, vec2( 0.1, 0.9 ) );", "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) );", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.5 ) );", "vVisibility = visibility.r / 9.0;", "vVisibility *= 1.0 - visibility.g / 9.0;", "vVisibility *= visibility.b / 9.0;", "vVisibility *= 1.0 - visibility.a / 9.0;", "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", "}", "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", "}" ].join( "\n" ), fragmentShader: [ "uniform lowp int renderType;", "uniform sampler2D map;", "uniform float opacity;", "uniform vec3 color;", "varying vec2 vUV;", "varying float vVisibility;", "void main() {", // pink square "if( renderType == 0 ) {", "gl_FragColor = vec4( 1.0, 0.0, 1.0, 0.0 );", // restore "} else if( renderType == 1 ) {", "gl_FragColor = texture2D( map, vUV );", // flare "} else {", "vec4 texture = texture2D( map, vUV );", "texture.a *= opacity * vVisibility;", "gl_FragColor = texture;", "gl_FragColor.rgb *= color;", "}", "}" ].join( "\n" ) }, 'lensFlare': { vertexShader: [ "uniform lowp int renderType;", "uniform vec3 screenPosition;", "uniform vec2 scale;", "uniform float rotation;", "attribute vec2 position;", "attribute vec2 uv;", "varying vec2 vUV;", "void main() {", "vUV = uv;", "vec2 pos = position;", "if( renderType == 2 ) {", "pos.x = cos( rotation ) * position.x - sin( rotation ) * position.y;", "pos.y = sin( rotation ) * position.x + cos( rotation ) * position.y;", "}", "gl_Position = vec4( ( pos * scale + screenPosition.xy ).xy, screenPosition.z, 1.0 );", "}" ].join( "\n" ), fragmentShader: [ "precision mediump float;", "uniform lowp int renderType;", "uniform sampler2D map;", "uniform sampler2D occlusionMap;", "uniform float opacity;", "uniform vec3 color;", "varying vec2 vUV;", "void main() {", // pink square "if( renderType == 0 ) {", "gl_FragColor = vec4( texture2D( map, vUV ).rgb, 0.0 );", // restore "} else if( renderType == 1 ) {", "gl_FragColor = texture2D( map, vUV );", // flare "} else {", "float visibility = texture2D( occlusionMap, vec2( 0.5, 0.1 ) ).a;", "visibility += texture2D( occlusionMap, vec2( 0.9, 0.5 ) ).a;", "visibility += texture2D( occlusionMap, vec2( 0.5, 0.9 ) ).a;", "visibility += texture2D( occlusionMap, vec2( 0.1, 0.5 ) ).a;", "visibility = ( 1.0 - visibility / 4.0 );", "vec4 texture = texture2D( map, vUV );", "texture.a *= opacity * visibility;", "gl_FragColor = texture;", "gl_FragColor.rgb *= color;", "}", "}" ].join( "\n" ) } }; // Export the THREE object for **Node.js**, with // backwards-compatibility for the old `require()` API. If we're in // the browser, add `_` as a global object via a string identifier, // for Closure Compiler "advanced" mode. if (typeof exports !== 'undefined') { if (typeof module !== 'undefined' && module.exports) { exports = module.exports = THREE; } exports.THREE = THREE; } else { this['THREE'] = THREE; } },{}],13:[function(require,module,exports){ // tween.js - http://github.com/sole/tween.js /** * @author sole / http://soledadpenades.com * @author mrdoob / http://mrdoob.com * @author Robert Eisele / http://www.xarg.org * @author Philippe / http://philippe.elsass.me * @author Robert Penner / http://www.robertpenner.com/easing_terms_of_use.html * @author Paul Lewis / http://www.aerotwist.com/ * @author lechecacharro * @author Josh Faul / http://jocafa.com/ * @author egraether / http://egraether.com/ * @author endel / http://endel.me * @author Ben Delarre / http://delarre.net */ // Date.now shim for (ahem) Internet Explo(d|r)er if ( Date.now === undefined ) { Date.now = function () { return new Date().valueOf(); }; } var TWEEN = TWEEN || ( function () { var _tweens = []; return { REVISION: '13', getAll: function () { return _tweens; }, removeAll: function () { _tweens = []; }, add: function ( tween ) { _tweens.push( tween ); }, remove: function ( tween ) { var i = _tweens.indexOf( tween ); if ( i !== -1 ) { _tweens.splice( i, 1 ); } }, update: function ( time ) { if ( _tweens.length === 0 ) return false; var i = 0; time = time !== undefined ? time : ( typeof window !== 'undefined' && window.performance !== undefined && window.performance.now !== undefined ? window.performance.now() : Date.now() ); while ( i < _tweens.length ) { if ( _tweens[ i ].update( time ) ) { i++; } else { _tweens.splice( i, 1 ); } } return true; } }; } )(); TWEEN.Tween = function ( object ) { var _object = object; var _valuesStart = {}; var _valuesEnd = {}; var _valuesStartRepeat = {}; var _duration = 1000; var _repeat = 0; var _yoyo = false; var _isPlaying = false; var _reversed = false; var _delayTime = 0; var _startTime = null; var _easingFunction = TWEEN.Easing.Linear.None; var _interpolationFunction = TWEEN.Interpolation.Linear; var _chainedTweens = []; var _onStartCallback = null; var _onStartCallbackFired = false; var _onUpdateCallback = null; var _onCompleteCallback = null; var _onStopCallback = null; // Set all starting values present on the target object for ( var field in object ) { _valuesStart[ field ] = parseFloat(object[field], 10); } this.to = function ( properties, duration ) { if ( duration !== undefined ) { _duration = duration; } _valuesEnd = properties; return this; }; this.start = function ( time ) { TWEEN.add( this ); _isPlaying = true; _onStartCallbackFired = false; _startTime = time !== undefined ? time : ( typeof window !== 'undefined' && window.performance !== undefined && window.performance.now !== undefined ? window.performance.now() : Date.now() ); _startTime += _delayTime; for ( var property in _valuesEnd ) { // check if an Array was provided as property value if ( _valuesEnd[ property ] instanceof Array ) { if ( _valuesEnd[ property ].length === 0 ) { continue; } // create a local copy of the Array with the start value at the front _valuesEnd[ property ] = [ _object[ property ] ].concat( _valuesEnd[ property ] ); } _valuesStart[ property ] = _object[ property ]; if( ( _valuesStart[ property ] instanceof Array ) === false ) { _valuesStart[ property ] *= 1.0; // Ensures we're using numbers, not strings } _valuesStartRepeat[ property ] = _valuesStart[ property ] || 0; } return this; }; this.stop = function () { if ( !_isPlaying ) { return this; } TWEEN.remove( this ); _isPlaying = false; if ( _onStopCallback !== null ) { _onStopCallback.call( _object ); } this.stopChainedTweens(); return this; }; this.stopChainedTweens = function () { for ( var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++ ) { _chainedTweens[ i ].stop(); } }; this.delay = function ( amount ) { _delayTime = amount; return this; }; this.repeat = function ( times ) { _repeat = times; return this; }; this.yoyo = function( yoyo ) { _yoyo = yoyo; return this; }; this.easing = function ( easing ) { _easingFunction = easing; return this; }; this.interpolation = function ( interpolation ) { _interpolationFunction = interpolation; return this; }; this.chain = function () { _chainedTweens = arguments; return this; }; this.onStart = function ( callback ) { _onStartCallback = callback; return this; }; this.onUpdate = function ( callback ) { _onUpdateCallback = callback; return this; }; this.onComplete = function ( callback ) { _onCompleteCallback = callback; return this; }; this.onStop = function ( callback ) { _onStopCallback = callback; return this; }; this.update = function ( time ) { var property; if ( time < _startTime ) { return true; } if ( _onStartCallbackFired === false ) { if ( _onStartCallback !== null ) { _onStartCallback.call( _object ); } _onStartCallbackFired = true; } var elapsed = ( time - _startTime ) / _duration; elapsed = elapsed > 1 ? 1 : elapsed; var value = _easingFunction( elapsed ); for ( property in _valuesEnd ) { var start = _valuesStart[ property ] || 0; var end = _valuesEnd[ property ]; if ( end instanceof Array ) { _object[ property ] = _interpolationFunction( end, value ); } else { // Parses relative end values with start as base (e.g.: +10, -3) if ( typeof(end) === "string" ) { end = start + parseFloat(end, 10); } // protect against non numeric properties. if ( typeof(end) === "number" ) { _object[ property ] = start + ( end - start ) * value; } } } if ( _onUpdateCallback !== null ) { _onUpdateCallback.call( _object, value ); } if ( elapsed == 1 ) { if ( _repeat > 0 ) { if( isFinite( _repeat ) ) { _repeat--; } // reassign starting values, restart by making startTime = now for( property in _valuesStartRepeat ) { if ( typeof( _valuesEnd[ property ] ) === "string" ) { _valuesStartRepeat[ property ] = _valuesStartRepeat[ property ] + parseFloat(_valuesEnd[ property ], 10); } if (_yoyo) { var tmp = _valuesStartRepeat[ property ]; _valuesStartRepeat[ property ] = _valuesEnd[ property ]; _valuesEnd[ property ] = tmp; } _valuesStart[ property ] = _valuesStartRepeat[ property ]; } if (_yoyo) { _reversed = !_reversed; } _startTime = time + _delayTime; return true; } else { if ( _onCompleteCallback !== null ) { _onCompleteCallback.call( _object ); } for ( var i = 0, numChainedTweens = _chainedTweens.length; i < numChainedTweens; i++ ) { _chainedTweens[ i ].start( time ); } return false; } } return true; }; }; TWEEN.Easing = { Linear: { None: function ( k ) { return k; } }, Quadratic: { In: function ( k ) { return k * k; }, Out: function ( k ) { return k * ( 2 - k ); }, InOut: function ( k ) { if ( ( k *= 2 ) < 1 ) return 0.5 * k * k; return - 0.5 * ( --k * ( k - 2 ) - 1 ); } }, Cubic: { In: function ( k ) { return k * k * k; }, Out: function ( k ) { return --k * k * k + 1; }, InOut: function ( k ) { if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k; return 0.5 * ( ( k -= 2 ) * k * k + 2 ); } }, Quartic: { In: function ( k ) { return k * k * k * k; }, Out: function ( k ) { return 1 - ( --k * k * k * k ); }, InOut: function ( k ) { if ( ( k *= 2 ) < 1) return 0.5 * k * k * k * k; return - 0.5 * ( ( k -= 2 ) * k * k * k - 2 ); } }, Quintic: { In: function ( k ) { return k * k * k * k * k; }, Out: function ( k ) { return --k * k * k * k * k + 1; }, InOut: function ( k ) { if ( ( k *= 2 ) < 1 ) return 0.5 * k * k * k * k * k; return 0.5 * ( ( k -= 2 ) * k * k * k * k + 2 ); } }, Sinusoidal: { In: function ( k ) { return 1 - Math.cos( k * Math.PI / 2 ); }, Out: function ( k ) { return Math.sin( k * Math.PI / 2 ); }, InOut: function ( k ) { return 0.5 * ( 1 - Math.cos( Math.PI * k ) ); } }, Exponential: { In: function ( k ) { return k === 0 ? 0 : Math.pow( 1024, k - 1 ); }, Out: function ( k ) { return k === 1 ? 1 : 1 - Math.pow( 2, - 10 * k ); }, InOut: function ( k ) { if ( k === 0 ) return 0; if ( k === 1 ) return 1; if ( ( k *= 2 ) < 1 ) return 0.5 * Math.pow( 1024, k - 1 ); return 0.5 * ( - Math.pow( 2, - 10 * ( k - 1 ) ) + 2 ); } }, Circular: { In: function ( k ) { return 1 - Math.sqrt( 1 - k * k ); }, Out: function ( k ) { return Math.sqrt( 1 - ( --k * k ) ); }, InOut: function ( k ) { if ( ( k *= 2 ) < 1) return - 0.5 * ( Math.sqrt( 1 - k * k) - 1); return 0.5 * ( Math.sqrt( 1 - ( k -= 2) * k) + 1); } }, Elastic: { In: function ( k ) { var s, a = 0.1, p = 0.4; if ( k === 0 ) return 0; if ( k === 1 ) return 1; if ( !a || a < 1 ) { a = 1; s = p / 4; } else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI ); return - ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) ); }, Out: function ( k ) { var s, a = 0.1, p = 0.4; if ( k === 0 ) return 0; if ( k === 1 ) return 1; if ( !a || a < 1 ) { a = 1; s = p / 4; } else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI ); return ( a * Math.pow( 2, - 10 * k) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) + 1 ); }, InOut: function ( k ) { var s, a = 0.1, p = 0.4; if ( k === 0 ) return 0; if ( k === 1 ) return 1; if ( !a || a < 1 ) { a = 1; s = p / 4; } else s = p * Math.asin( 1 / a ) / ( 2 * Math.PI ); if ( ( k *= 2 ) < 1 ) return - 0.5 * ( a * Math.pow( 2, 10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) ); return a * Math.pow( 2, -10 * ( k -= 1 ) ) * Math.sin( ( k - s ) * ( 2 * Math.PI ) / p ) * 0.5 + 1; } }, Back: { In: function ( k ) { var s = 1.70158; return k * k * ( ( s + 1 ) * k - s ); }, Out: function ( k ) { var s = 1.70158; return --k * k * ( ( s + 1 ) * k + s ) + 1; }, InOut: function ( k ) { var s = 1.70158 * 1.525; if ( ( k *= 2 ) < 1 ) return 0.5 * ( k * k * ( ( s + 1 ) * k - s ) ); return 0.5 * ( ( k -= 2 ) * k * ( ( s + 1 ) * k + s ) + 2 ); } }, Bounce: { In: function ( k ) { return 1 - TWEEN.Easing.Bounce.Out( 1 - k ); }, Out: function ( k ) { if ( k < ( 1 / 2.75 ) ) { return 7.5625 * k * k; } else if ( k < ( 2 / 2.75 ) ) { return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75; } else if ( k < ( 2.5 / 2.75 ) ) { return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375; } else { return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375; } }, InOut: function ( k ) { if ( k < 0.5 ) return TWEEN.Easing.Bounce.In( k * 2 ) * 0.5; return TWEEN.Easing.Bounce.Out( k * 2 - 1 ) * 0.5 + 0.5; } } }; TWEEN.Interpolation = { Linear: function ( v, k ) { var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = TWEEN.Interpolation.Utils.Linear; if ( k < 0 ) return fn( v[ 0 ], v[ 1 ], f ); if ( k > 1 ) return fn( v[ m ], v[ m - 1 ], m - f ); return fn( v[ i ], v[ i + 1 > m ? m : i + 1 ], f - i ); }, Bezier: function ( v, k ) { var b = 0, n = v.length - 1, pw = Math.pow, bn = TWEEN.Interpolation.Utils.Bernstein, i; for ( i = 0; i <= n; i++ ) { b += pw( 1 - k, n - i ) * pw( k, i ) * v[ i ] * bn( n, i ); } return b; }, CatmullRom: function ( v, k ) { var m = v.length - 1, f = m * k, i = Math.floor( f ), fn = TWEEN.Interpolation.Utils.CatmullRom; if ( v[ 0 ] === v[ m ] ) { if ( k < 0 ) i = Math.floor( f = m * ( 1 + k ) ); return fn( v[ ( i - 1 + m ) % m ], v[ i ], v[ ( i + 1 ) % m ], v[ ( i + 2 ) % m ], f - i ); } else { if ( k < 0 ) return v[ 0 ] - ( fn( v[ 0 ], v[ 0 ], v[ 1 ], v[ 1 ], -f ) - v[ 0 ] ); if ( k > 1 ) return v[ m ] - ( fn( v[ m ], v[ m ], v[ m - 1 ], v[ m - 1 ], f - m ) - v[ m ] ); return fn( v[ i ? i - 1 : 0 ], v[ i ], v[ m < i + 1 ? m : i + 1 ], v[ m < i + 2 ? m : i + 2 ], f - i ); } }, Utils: { Linear: function ( p0, p1, t ) { return ( p1 - p0 ) * t + p0; }, Bernstein: function ( n , i ) { var fc = TWEEN.Interpolation.Utils.Factorial; return fc( n ) / fc( i ) / fc( n - i ); }, Factorial: ( function () { var a = [ 1 ]; return function ( n ) { var s = 1, i; if ( a[ n ] ) return a[ n ]; for ( i = n; i > 1; i-- ) s *= i; return a[ n ] = s; }; } )(), CatmullRom: function ( p0, p1, p2, p3, t ) { var v0 = ( p2 - p0 ) * 0.5, v1 = ( p3 - p1 ) * 0.5, t2 = t * t, t3 = t * t2; return ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1; } } }; module.exports=TWEEN; },{}],14:[function(require,module,exports){ ;(function inject(clean, precision, undef) { var isArray = function (a) { return Object.prototype.toString.call(a) === "[object Array]"; }; var defined = function(a) { return a !== undef; }; function Vec2(x, y) { if (!(this instanceof Vec2)) { return new Vec2(x, y); } if (isArray(x)) { y = x[1]; x = x[0]; } else if('object' === typeof x && x) { y = x.y; x = x.x; } this.x = Vec2.clean(x || 0); this.y = Vec2.clean(y || 0); } Vec2.prototype = { change : function(fn) { if (typeof fn === 'function') { if (this.observers) { this.observers.push(fn); } else { this.observers = [fn]; } } else if (this.observers && this.observers.length) { for (var i=this.observers.length-1; i>=0; i--) { this.observers[i](this, fn); } } return this; }, ignore : function(fn) { if (this.observers) { if (!fn) { this.observers = []; } else { var o = this.observers, l = o.length; while(l--) { o[l] === fn && o.splice(l, 1); } } } return this; }, // set x and y set: function(x, y, notify) { if('number' != typeof x) { notify = y; y = x.y; x = x.x; } if(this.x === x && this.y === y) { return this; } var orig = null; if (notify !== false && this.observers && this.observers.length) { orig = this.clone(); } this.x = Vec2.clean(x); this.y = Vec2.clean(y); if(notify !== false) { return this.change(orig); } }, // reset x and y to zero zero : function() { return this.set(0, 0); }, // return a new vector with the same component values // as this one clone : function() { return new (this.constructor)(this.x, this.y); }, // negate the values of this vector negate : function(returnNew) { if (returnNew) { return new (this.constructor)(-this.x, -this.y); } else { return this.set(-this.x, -this.y); } }, // Add the incoming `vec2` vector to this vector add : function(x, y, returnNew) { if (typeof x != 'number') { returnNew = y; if (isArray(x)) { y = x[1]; x = x[0]; } else { y = x.y; x = x.x; } } x += this.x; y += this.y; if (!returnNew) { return this.set(x, y); } else { // Return a new vector if `returnNew` is truthy return new (this.constructor)(x, y); } }, // Subtract the incoming `vec2` from this vector subtract : function(x, y, returnNew) { if (typeof x != 'number') { returnNew = y; if (isArray(x)) { y = x[1]; x = x[0]; } else { y = x.y; x = x.x; } } x = this.x - x; y = this.y - y; if (!returnNew) { return this.set(x, y); } else { // Return a new vector if `returnNew` is truthy return new (this.constructor)(x, y); } }, // Multiply this vector by the incoming `vec2` multiply : function(x, y, returnNew) { if (typeof x != 'number') { returnNew = y; if (isArray(x)) { y = x[1]; x = x[0]; } else { y = x.y; x = x.x; } } else if (typeof y != 'number') { returnNew = y; y = x; } x *= this.x; y *= this.y; if (!returnNew) { return this.set(x, y); } else { return new (this.constructor)(x, y); } }, // Rotate this vector. Accepts a `Rotation` or angle in radians. // // Passing a truthy `inverse` will cause the rotation to // be reversed. // // If `returnNew` is truthy, a new // `Vec2` will be created with the values resulting from // the rotation. Otherwise the rotation will be applied // to this vector directly, and this vector will be returned. rotate : function(r, inverse, returnNew) { var x = this.x, y = this.y, cos = Math.cos(r), sin = Math.sin(r), rx, ry; inverse = (inverse) ? -1 : 1; rx = cos * x - (inverse * sin) * y; ry = (inverse * sin) * x + cos * y; if (returnNew) { return new (this.constructor)(rx, ry); } else { return this.set(rx, ry); } }, // Calculate the length of this vector length : function() { var x = this.x, y = this.y; return Math.sqrt(x * x + y * y); }, // Get the length squared. For performance, use this instead of `Vec2#length` (if possible). lengthSquared : function() { var x = this.x, y = this.y; return x*x+y*y; }, // Return the distance betwen this `Vec2` and the incoming vec2 vector // and return a scalar distance : function(vec2) { var x = this.x - vec2.x; var y = this.y - vec2.y; return Math.sqrt(x*x + y*y); }, // Convert this vector into a unit vector. // Returns the length. normalize : function(returnNew) { var length = this.length(); // Collect a ratio to shrink the x and y coords var invertedLength = (length < Number.MIN_VALUE) ? 0 : 1/length; if (!returnNew) { // Convert the coords to be greater than zero // but smaller than or equal to 1.0 return this.set(this.x * invertedLength, this.y * invertedLength); } else { return new (this.constructor)(this.x * invertedLength, this.y * invertedLength); } }, // Determine if another `Vec2`'s components match this one's // also accepts 2 scalars equal : function(v, w) { if (typeof v != 'number') { if (isArray(v)) { w = v[1]; v = v[0]; } else { w = v.y; v = v.x; } } return (Vec2.clean(v) === this.x && Vec2.clean(w) === this.y); }, // Return a new `Vec2` that contains the absolute value of // each of this vector's parts abs : function(returnNew) { var x = Math.abs(this.x), y = Math.abs(this.y); if (returnNew) { return new (this.constructor)(x, y); } else { return this.set(x, y); } }, // Return a new `Vec2` consisting of the smallest values // from this vector and the incoming // // When returnNew is truthy, a new `Vec2` will be returned // otherwise the minimum values in either this or `v` will // be applied to this vector. min : function(v, returnNew) { var tx = this.x, ty = this.y, vx = v.x, vy = v.y, x = tx < vx ? tx : vx, y = ty < vy ? ty : vy; if (returnNew) { return new (this.constructor)(x, y); } else { return this.set(x, y); } }, // Return a new `Vec2` consisting of the largest values // from this vector and the incoming // // When returnNew is truthy, a new `Vec2` will be returned // otherwise the minimum values in either this or `v` will // be applied to this vector. max : function(v, returnNew) { var tx = this.x, ty = this.y, vx = v.x, vy = v.y, x = tx > vx ? tx : vx, y = ty > vy ? ty : vy; if (returnNew) { return new (this.constructor)(x, y); } else { return this.set(x, y); } }, // Clamp values into a range. // If this vector's values are lower than the `low`'s // values, then raise them. If they are higher than // `high`'s then lower them. // // Passing returnNew as true will cause a new Vec2 to be // returned. Otherwise, this vector's values will be clamped clamp : function(low, high, returnNew) { var ret = this.min(high, true).max(low); if (returnNew) { return ret; } else { return this.set(ret.x, ret.y); } }, // Perform linear interpolation between two vectors // amount is a decimal between 0 and 1 lerp : function(vec, amount, returnNew) { return this.add(vec.subtract(this, true).multiply(amount), returnNew); }, // Get the skew vector such that dot(skew_vec, other) == cross(vec, other) skew : function(returnNew) { if (!returnNew) { return this.set(-this.y, this.x) } else { return new (this.constructor)(-this.y, this.x); } }, // calculate the dot product between // this vector and the incoming dot : function(b) { return Vec2.clean(this.x * b.x + b.y * this.y); }, // calculate the perpendicular dot product between // this vector and the incoming perpDot : function(b) { return Vec2.clean(this.x * b.y - this.y * b.x); }, // Determine the angle between two vec2s angleTo : function(vec) { return Math.atan2(this.perpDot(vec), this.dot(vec)); }, // Divide this vector's components by a scalar divide : function(x, y, returnNew) { if (typeof x != 'number') { returnNew = y; if (isArray(x)) { y = x[1]; x = x[0]; } else { y = x.y; x = x.x; } } else if (typeof y != 'number') { returnNew = y; y = x; } if (x === 0 || y === 0) { throw new Error('division by zero') } if (isNaN(x) || isNaN(y)) { throw new Error('NaN detected'); } if (returnNew) { return new (this.constructor)(this.x / x, this.y / y); } return this.set(this.x / x, this.y / y); }, isPointOnLine : function(start, end) { return (start.y - this.y) * (start.x - end.x) === (start.y - end.y) * (start.x - this.x); }, toArray: function() { return [this.x, this.y]; }, fromArray: function(array) { return this.set(array[0], array[1]); }, toJSON: function () { return {x: this.x, y: this.y}; }, toString: function() { return '(' + this.x + ', ' + this.y + ')'; }, constructor : Vec2 }; Vec2.fromArray = function(array, ctor) { return new (ctor || Vec2)(array[0], array[1]); }; // Floating point stability Vec2.precision = precision || 8; var p = Math.pow(10, Vec2.precision); Vec2.clean = clean || function(val) { if (isNaN(val)) { throw new Error('NaN detected'); } if (!isFinite(val)) { throw new Error('Infinity detected'); } if(Math.round(val) === val) { return val; } return Math.round(val * p)/p; }; Vec2.inject = inject; if(!clean) { Vec2.fast = inject(function (k) { return k; }); // Expose, but also allow creating a fresh Vec2 subclass. if (typeof module !== 'undefined' && typeof module.exports == 'object') { module.exports = Vec2; } else { window.Vec2 = window.Vec2 || Vec2; } } return Vec2; })(); },{}],15:[function(require,module,exports){ var TWEEN = require('tween.js'), THREE = require('three'), Hexasphere = require('hexasphere.js'), Quadtree2 = require('quadtree2'), Vec2 = require('vec2'), Pin = require('./Pin'), Marker = require('./Marker'), Satellite = require('./Satellite'), SmokeProvider = require('./SmokeProvider'), pusherColor = require('pusher.color'), utils = require('./utils'); var latLonToXYZ = function(width, height, lat,lon){ var x = Math.floor(width/2.0 + (width/360.0)*lon); var y = Math.floor((height/2.0 + (height/180.0)*lat)); return {x: x, y:y}; }; var latLon2d = function(lat,lon){ var rad = 2 + (Math.abs(lat)/90) * 15; return {x: lat+90, y:lon + 180, rad: rad}; }; var addInitialData = function(){ if(this.data.length == 0){ return; } while(this.data.length > 0 && this.firstRunTime + (next = this.data.pop()).when < Date.now()){ this.addPin(next.lat, next.lng, next.label); } if(this.firstRunTime + next.when >= Date.now()){ this.data.push(next); } }; var createParticles = function(){ if(this.hexGrid){ this.scene.remove(this.hexGrid); } var pointVertexShader = [ "#define PI 3.141592653589793238462643", "#define DISTANCE 500.0", "#define INTRODURATION " + (parseFloat(this.introLinesDuration) + .00001), "#define INTROALTITUDE " + (parseFloat(this.introLinesAltitude) + .00001), "attribute float lng;", "uniform float currentTime;", "varying vec4 vColor;", "", "void main()", "{", " vec3 newPos = position;", " float opacityVal = 0.0;", " float introStart = INTRODURATION * ((180.0 + lng)/360.0);", " if(currentTime > introStart){", " opacityVal = 1.0;", " }", " if(currentTime > introStart && currentTime < introStart + INTRODURATION / 8.0){", " newPos = position * INTROALTITUDE;", " opacityVal = .3;", " }", " if(currentTime > introStart + INTRODURATION / 8.0 && currentTime < introStart + INTRODURATION / 8.0 + 200.0){", " newPos = position * (1.0 + ((INTROALTITUDE-1.0) * (1.0-(currentTime - introStart-(INTRODURATION/8.0))/200.0)));", " }", " vColor = vec4( color, opacityVal );", // set color associated to vertex; use later in fragment shader. " gl_Position = projectionMatrix * modelViewMatrix * vec4(newPos, 1.0);", "}" ].join("\n"); var pointFragmentShader = [ "varying vec4 vColor;", "void main()", "{", " gl_FragColor = vColor;", " float depth = gl_FragCoord.z / gl_FragCoord.w;", " float fogFactor = smoothstep(" + parseInt(this.cameraDistance) +".0," + (parseInt(this.cameraDistance+300)) +".0, depth );", " vec3 fogColor = vec3(0.0);", " gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w ), fogFactor );", "}" ].join("\n"); var pointAttributes = { lng: {type: 'f', value: null} }; this.pointUniforms = { currentTime: { type: 'f', value: 0.0} } var pointMaterial = new THREE.ShaderMaterial( { uniforms: this.pointUniforms, attributes: pointAttributes, vertexShader: pointVertexShader, fragmentShader: pointFragmentShader, transparent: true, vertexColors: THREE.VertexColors, side: THREE.DoubleSide }); var triangles = this.tiles.length * 4; var geometry = new THREE.BufferGeometry(); geometry.addAttribute( 'index', Uint16Array, triangles * 3, 1 ); geometry.addAttribute( 'position', Float32Array, triangles * 3, 3 ); geometry.addAttribute( 'normal', Float32Array, triangles * 3, 3 ); geometry.addAttribute( 'color', Float32Array, triangles * 3, 3 ); geometry.addAttribute( 'lng', Float32Array, triangles * 3, 1 ); var lng_values = geometry.attributes.lng.array; var baseColorSet = pusherColor(this.baseColor).hueSet(); var myColors = []; for(var i = 0; i< baseColorSet.length; i++){ myColors.push(baseColorSet[i].shade(Math.random()/3.0)); } // break geometry into // chunks of 21,845 triangles (3 unique vertices per triangle) // for indices to fit into 16 bit integer number // floor(2^16 / 3) = 21845 var chunkSize = 21845; var indices = geometry.attributes.index.array; for ( var i = 0; i < indices.length; i ++ ) { indices[ i ] = i % ( 3 * chunkSize ); } var positions = geometry.attributes.position.array; var colors = geometry.attributes.color.array; var n = 800, n2 = n/2; // triangles spread in the cube var d = 12, d2 = d/2; // individual triangle size var addTriangle = function(k, ax, ay, az, bx, by, bz, cx, cy, cz, lat, lng, color){ var p = k * 3; var i = p * 3; var colorIndex = Math.floor(Math.random()*myColors.length); var colorRGB = myColors[colorIndex].rgb(); lng_values[p] = lng; lng_values[p+1] = lng; lng_values[p+2] = lng; positions[ i ] = ax; positions[ i + 1 ] = ay; positions[ i + 2 ] = az; positions[ i + 3 ] = bx; positions[ i + 4 ] = by; positions[ i + 5 ] = bz; positions[ i + 6 ] = cx; positions[ i + 7 ] = cy; positions[ i + 8 ] = cz; colors[ i ] = color.r; colors[ i + 1 ] = color.g; colors[ i + 2 ] = color.b; colors[ i + 3 ] = color.r; colors[ i + 4 ] = color.g; colors[ i + 5 ] = color.b; colors[ i + 6 ] = color.r; colors[ i + 7 ] = color.g; colors[ i + 8 ] = color.b; }; for(var i =0; i< this.tiles.length; i++){ var t = this.tiles[i]; var k = i * 4; var colorIndex = Math.floor(Math.random()*myColors.length); var colorRGB = myColors[colorIndex].rgb(); var color = new THREE.Color(); color.setRGB(colorRGB[0]/255.0, colorRGB[1]/255.0, colorRGB[2]/255.0); addTriangle(k, t.b[0].x, t.b[0].y, t.b[0].z, t.b[1].x, t.b[1].y, t.b[1].z, t.b[2].x, t.b[2].y, t.b[2].z, t.lat, t.lon, color); addTriangle(k+1, t.b[0].x, t.b[0].y, t.b[0].z, t.b[2].x, t.b[2].y, t.b[2].z, t.b[3].x, t.b[3].y, t.b[3].z, t.lat, t.lon, color); addTriangle(k+2, t.b[0].x, t.b[0].y, t.b[0].z, t.b[3].x, t.b[3].y, t.b[3].z, t.b[4].x, t.b[4].y, t.b[4].z, t.lat, t.lon, color); if(t.b.length > 5){ // for the occasional pentagon that i have to deal with addTriangle(k+3, t.b[0].x, t.b[0].y, t.b[0].z, t.b[5].x, t.b[5].y, t.b[5].z, t.b[4].x, t.b[4].y, t.b[4].z, t.lat, t.lon, color); } } geometry.offsets = []; var offsets = triangles / chunkSize; for ( var i = 0; i < offsets; i ++ ) { var offset = { start: i * chunkSize * 3, index: i * chunkSize * 3, count: Math.min( triangles - ( i * chunkSize ), chunkSize ) * 3 }; geometry.offsets.push( offset ); } geometry.computeBoundingSphere(); this.hexGrid = new THREE.Mesh( geometry, pointMaterial ); this.scene.add( this.hexGrid ); }; var createIntroLines = function(){ var sPoint; var introLinesMaterial = new THREE.LineBasicMaterial({ color: this.introLinesColor, transparent: true, linewidth: 2, opacity: .5 }); for(var i = 0; i 0){ _this.scene.remove(_this.scene.children[0]); } if(typeof callback == "function"){ callback(); } }, 1000); }; Globe.prototype.addPin = function(lat, lon, text, altitude){ lat = parseFloat(lat); lon = parseFloat(lon); var opts = { lineColor: this.pinColor, topColor: this.pinColor } var altitude = altitude || 1.2; // if(typeof text != "string" || text.length === 0){ // altitude -= .05 + Math.random() * .05; // } var pin = new Pin(lat, lon, text, altitude, this.scene, this.smokeProvider, opts); this.pins.push(pin); // lets add quadtree stuff var pos = latLon2d(lat, lon); pin.pos_ = new Vec2(parseInt(pos.x),parseInt(pos.y)); if(text.length > 0){ pin.rad_ = pos.rad; } else { pin.rad_ = 1; } this.quadtree.addObject(pin); if(text.length > 0){ var collisions = this.quadtree.getCollisionsForObject(pin); var collisionCount = 0; var tooYoungCount = 0; var hidePins = []; for(var i in collisions){ if(collisions[i].text.length > 0){ collisionCount++; if(collisions[i].age() > 5000){ hidePins.push(collisions[i]); } else { tooYoungCount++; } } } if(collisionCount > 0 && tooYoungCount == 0){ for(var i = 0; i< hidePins.length; i++){ hidePins[i].hideLabel(); hidePins[i].hideSmoke(); hidePins[i].hideTop(); hidePins[i].changeAltitude(Math.random() * .05 + 1.1); } } else if (collisionCount > 0){ pin.hideLabel(); pin.hideSmoke(); pin.hideTop(); pin.changeAltitude(Math.random() * .05 + 1.1); } } if(this.pins.length > this.maxPins){ var oldPin = this.pins.shift(); this.quadtree.removeObject(oldPin); oldPin.remove(); } return pin; } Globe.prototype.addMarker = function(lat, lon, text, connected, altitude, color){ var marker; var opts = { markerColor: color || this.markerColor, lineColor: this.markerColor }; var altitude = altitude || 1.2; if(typeof connected == "boolean" && connected){ marker = new Marker(lat, lon, text, altitude, this.markers[this.markers.length-1], this.scene, opts); } else if(typeof connected == "object"){ marker = new Marker(lat, lon, text, altitude, connected, this.scene, opts); } else { marker = new Marker(lat, lon, text, altitude, null, this.scene, opts); } this.markers.push(marker); if(this.markers.length > this.maxMarkers){ this.markers.shift().remove(); } return marker; } Globe.prototype.addSatellite = function(lat, lon, altitude, opts, texture, animator){ /* texture and animator are optimizations so we don't have to regenerate certain * redundant assets */ if(!opts){ opts = {}; } if(opts.coreColor == undefined){ opts.coreColor = this.satelliteColor; } var satellite = new Satellite(lat, lon, altitude, this.scene, opts, texture, animator); if(!this.satellites[satellite.toString()]){ this.satellites[satellite.toString()] = satellite; } satellite.onRemove(function(){ delete this.satellites[satellite.toString()]; }.bind(this)); return satellite; }; Globe.prototype.addConstellation = function(sats, opts){ /* TODO: make it so that when you remove the first in a constellation it removes all others */ var texture, animator, satellite, constellation = []; for(var i = 0; i< sats.length; i++){ if(i === 0){ satellite = this.addSatellite(sats[i].lat, sats[i].lon, sats[i].altitude, opts); } else { satellite = this.addSatellite(sats[i].lat, sats[i].lon, sats[i].altitude, opts, constellation[0].canvas, constellation[0].texture); } constellation.push(satellite); } return constellation; }; Globe.prototype.setMaxPins = function(_maxPins){ this.maxPins = _maxPins; while(this.pins.length > this.maxPins){ var oldPin = this.pins.shift(); this.quadtree.removeObject(oldPin); oldPin.remove(); } }; Globe.prototype.setMaxMarkers = function(_maxMarkers){ this.maxMarkers = _maxMarkers; while(this.markers.length > this.maxMarkers){ this.markers.shift().remove(); } }; Globe.prototype.setBaseColor = function(_color){ this.baseColor = _color; createParticles.call(this); }; Globe.prototype.setMarkerColor = function(_color){ this.markerColor = _color; this.scene._encom_markerTexture = null; }; Globe.prototype.setPinColor = function(_color){ this.pinColor = _color; }; Globe.prototype.setScale = function(_scale){ this.scale = _scale; this.cameraDistance = 1700/_scale; if(this.scene && this.scene.fog){ this.scene.fog.near = this.cameraDistance; this.scene.fog.far = this.cameraDistance + 300; createParticles.call(this); this.camera.far = this.cameraDistance + 300; this.camera.updateProjectionMatrix(); } }; Globe.prototype.tick = function(){ if(!this.camera){ return; } if(!this.firstRunTime){ this.firstRunTime = Date.now(); } addInitialData.call(this); TWEEN.update(); if(!this.lastRenderDate){ this.lastRenderDate = new Date(); } if(!this.firstRenderDate){ this.firstRenderDate = new Date(); } this.totalRunTime = new Date() - this.firstRenderDate; var renderTime = new Date() - this.lastRenderDate; this.lastRenderDate = new Date(); var rotateCameraBy = (2 * Math.PI)/(this.dayLength/renderTime); this.cameraAngle += rotateCameraBy; if(!this.active){ this.cameraDistance += (1000 * renderTime/1000); } this.camera.position.x = this.cameraDistance * Math.cos(this.cameraAngle) * Math.cos(this.viewAngle); this.camera.position.y = Math.sin(this.viewAngle) * this.cameraDistance; this.camera.position.z = this.cameraDistance * Math.sin(this.cameraAngle) * Math.cos(this.viewAngle); for(var i in this.satellites){ this.satellites[i].tick(this.camera.position, this.cameraAngle, renderTime); } for(var i = 0; i< this.satelliteMeshes.length; i++){ var mesh = this.satelliteMeshes[i]; mesh.lookAt(this.camera.position); mesh.rotateZ(mesh.tiltDirection * Math.PI/2); mesh.rotateZ(Math.sin(this.cameraAngle + (mesh.lon / 180) * Math.PI) * mesh.tiltMultiplier * mesh.tiltDirection * -1); } if(this.introLinesDuration > this.totalRunTime){ if(this.totalRunTime/this.introLinesDuration < .1){ this.introLines.children[0].material.opacity = (this.totalRunTime/this.introLinesDuration) * (1 / .1) - .2; }if(this.totalRunTime/this.introLinesDuration > .8){ this.introLines.children[0].material.opacity = Math.max(1-this.totalRunTime/this.introLinesDuration,0) * (1 / .2); } else { this.introLines.children[0].material.opacity = 1; } this.introLines.rotateY((2 * Math.PI)/(this.introLinesDuration/renderTime)); } else if(this.introLines){ this.scene.remove(this.introLines); delete[this.introLines]; } // do the shaders this.pointUniforms.currentTime.value = this.totalRunTime; this.smokeProvider.tick(this.totalRunTime); this.camera.lookAt( this.scene.position ); this.renderer.render( this.scene, this.camera ); // cleanup dead pins and markers while(this.pins.find(x => x.removed)) { this.pins.splice(this.pins.findIndex(x => x.removed), 1); } while(this.markers.find(x => x.removed)) { this.markers.splice(this.markers.findIndex(x => x.removed), 1); } } module.exports = Globe; },{"./Marker":16,"./Pin":17,"./Satellite":18,"./SmokeProvider":19,"./utils":21,"hexasphere.js":3,"pusher.color":6,"quadtree2":8,"three":12,"tween.js":13,"vec2":14}],16:[function(require,module,exports){ var THREE = require('three'), TWEEN = require('tween.js'), utils = require('./utils'); var createMarkerTexture = function(markerColor) { var markerWidth = 30, markerHeight = 30, canvas, texture; if (markerColor === "transparent") { markerWidth = 0; markerHeight = 0; } canvas = utils.renderToCanvas(markerWidth, markerHeight, function(ctx){ ctx.fillStyle=markerColor; ctx.strokeStyle=markerColor; ctx.lineWidth=3; ctx.beginPath(); ctx.arc(markerWidth/2, markerHeight/2, markerWidth/3, 0, 2* Math.PI); ctx.stroke(); ctx.beginPath(); ctx.arc(markerWidth/2, markerHeight/2, markerWidth/5, 0, 2* Math.PI); ctx.fill(); }); texture = new THREE.Texture(canvas); texture.needsUpdate = true; return texture; }; var Marker = function(lat, lon, text, altitude, previous, scene, _opts){ /* options that can be passed in */ var opts = { lineColor: "#FFCC00", lineWidth: 1, markerColor: "#FFCC00", labelColor: "#FFF", font: "Inconsolata", fontSize: 20, drawTime: 2000, lineSegments: 150 } var point, previousPoint, markerMaterial, labelCanvas, labelTexture, labelMaterial ; this.lat = parseFloat(lat); this.lon = parseFloat(lon); this.text = text; this.altitude = parseFloat(altitude); this.scene = scene; this.previous = previous; this.next = []; if(this.previous){ this.previous.next.push(this); } if(_opts){ for(var i in opts){ if(_opts[i] != undefined){ opts[i] = _opts[i]; } } } this.opts = opts; point = utils.mapPoint(lat, lon); if(previous){ previousPoint = utils.mapPoint(previous.lat, previous.lon); } if(!scene._encom_markerTexture){ scene._encom_markerTexture = createMarkerTexture(this.opts.markerColor); } markerMaterial = new THREE.SpriteMaterial({map: scene._encom_markerTexture, opacity: .7, depthTest: true, fog: true}); this.marker = new THREE.Sprite(markerMaterial); this.marker.scale.set(0, 0); this.marker.position.set(point.x * altitude, point.y * altitude, point.z * altitude); labelCanvas = utils.createLabel(text.toUpperCase(), this.opts.fontSize, this.opts.labelColor, this.opts.font, this.opts.markerColor); labelTexture = new THREE.Texture(labelCanvas); labelTexture.needsUpdate = true; labelMaterial = new THREE.SpriteMaterial({ map : labelTexture, useScreenCoordinates: false, opacity: 0, depthTest: true, fog: true }); this.labelSprite = new THREE.Sprite(labelMaterial); this.labelSprite.position = {x: point.x * altitude * 1.1, y: point.y*altitude*1.05 + (point.y < 0 ? -15 : 30), z: point.z * altitude * 1.1}; this.labelSprite.scale.set(labelCanvas.width, labelCanvas.height); new TWEEN.Tween( {opacity: 0}) .to( {opacity: 1}, 500 ) .onUpdate(function(){ labelMaterial.opacity = this.opacity }).start(); var _this = this; //arrghghh new TWEEN.Tween({x: 0, y: 0}) .to({x: 50, y: 50}, 2000) .easing( TWEEN.Easing.Elastic.Out ) .onUpdate(function(){ _this.marker.scale.set(this.x, this.y); }) .delay((this.previous ? _this.opts.drawTime : 0)) .start(); if(this.previous){ var materialSpline, materialSplineDotted, latdist, londist, startPoint, pointList = [], pointList2 = [], nextlat, nextlon, currentLat, currentLon, currentPoint, currentVert, update; _this.geometrySpline = new THREE.Geometry(); materialSpline = new THREE.LineBasicMaterial({ color: this.opts.lineColor, transparent: true, linewidth: 3, opacity: .5 }); _this.geometrySplineDotted = new THREE.Geometry(); materialSplineDotted = new THREE.LineBasicMaterial({ color: this.opts.lineColor, linewidth: 1, transparent: true, opacity: .5 }); latdist = (lat - previous.lat)/_this.opts.lineSegments; londist = (lon - previous.lon)/_this.opts.lineSegments; startPoint = utils.mapPoint(previous.lat,previous.lon); pointList = []; pointList2 = []; for(var j = 0; j< _this.opts.lineSegments + 1; j++){ // var nextlat = ((90 + lat1 + j*1)%180)-90; // var nextlon = ((180 + lng1 + j*1)%360)-180; var nextlat = (((90 + previous.lat + j*latdist)%180)-90) * (.5 + Math.cos(j*(5*Math.PI/2)/_this.opts.lineSegments)/2) + (j*lat/_this.opts.lineSegments/2); var nextlon = ((180 + previous.lon + j*londist)%360)-180; pointList.push({lat: nextlat, lon: nextlon, index: j}); if(j == 0 || j == _this.opts.lineSegments){ pointList2.push({lat: nextlat, lon: nextlon, index: j}); } else { pointList2.push({lat: nextlat+1, lon: nextlon, index: j}); } // var thisPoint = mapPoint(nextlat, nextlon); sPoint = new THREE.Vector3(startPoint.x*1.2, startPoint.y*1.2, startPoint.z*1.2); sPoint2 = new THREE.Vector3(startPoint.x*1.2, startPoint.y*1.2, startPoint.z*1.2); // sPoint = new THREE.Vector3(thisPoint.x*1.2, thisPoint.y*1.2, thisPoint.z*1.2); sPoint.globe_index = j; sPoint2.globe_index = j; _this.geometrySpline.vertices.push(sPoint); _this.geometrySplineDotted.vertices.push(sPoint2); } currentLat = previous.lat; currentLon = previous.lon; currentPoint; currentVert; update = function(){ var nextSpot = pointList.shift(); var nextSpot2 = pointList2.shift(); for(var x = 0; x< _this.geometrySpline.vertices.length; x++){ currentVert = _this.geometrySpline.vertices[x]; currentPoint = utils.mapPoint(nextSpot.lat, nextSpot.lon); currentVert2 = _this.geometrySplineDotted.vertices[x]; currentPoint2 = utils.mapPoint(nextSpot2.lat, nextSpot2.lon); if(x >= nextSpot.index){ currentVert.set(currentPoint.x*1.2, currentPoint.y*1.2, currentPoint.z*1.2); currentVert2.set(currentPoint2.x*1.19, currentPoint2.y*1.19, currentPoint2.z*1.19); } _this.geometrySpline.verticesNeedUpdate = true; _this.geometrySplineDotted.verticesNeedUpdate = true; } if(pointList.length > 0){ setTimeout(update,_this.opts.drawTime/_this.opts.lineSegments); } }; update(); this.scene.add(new THREE.Line(_this.geometrySpline, materialSpline)); this.scene.add(new THREE.Line(_this.geometrySplineDotted, materialSplineDotted, THREE.LinePieces)); } this.scene.add(this.marker); this.scene.add(this.labelSprite); }; Marker.prototype.remove = function(){ var x = 0; var _this = this; var update = function(ref){ for(var i = 0; i< x; i++){ ref.geometrySpline.vertices[i].set(ref.geometrySpline.vertices[i+1]); ref.geometrySplineDotted.vertices[i].set(ref.geometrySplineDotted.vertices[i+1]); ref.geometrySpline.verticesNeedUpdate = true; ref.geometrySplineDotted.verticesNeedUpdate = true; } x++; if(x < ref.geometrySpline.vertices.length){ setTimeout(function(){update(ref)}, _this.opts.drawTime/_this.opts.lineSegments) } else { _this.scene.remove(ref.geometrySpline); _this.scene.remove(ref.geometrySplineDotted); } } for(var j = 0; j< _this.next.length; j++){ (function(k){ update(_this.next[k]); })(j); } _this.scene.remove(_this.marker); _this.scene.remove(_this.labelSprite); _this.removed = true; }; module.exports = Marker; },{"./utils":21,"three":12,"tween.js":13}],17:[function(require,module,exports){ var THREE = require('three'), TWEEN = require('tween.js'), utils = require('./utils'); var createTopCanvas = function(color) { var markerWidth = 20, markerHeight = 20; return utils.renderToCanvas(markerWidth, markerHeight, function(ctx){ ctx.fillStyle=color; ctx.beginPath(); ctx.arc(markerWidth/2, markerHeight/2, markerWidth/4, 0, 2* Math.PI); ctx.fill(); }); }; var Pin = function(lat, lon, text, altitude, scene, smokeProvider, _opts){ /* options that can be passed in */ var opts = { lineColor: "#8FD8D8", lineWidth: 1, topColor: "#8FD8D8", smokeColor: "#FFF", labelColor: "#FFF", font: "Inconsolata", showLabel: (text.length > 0), showTop: (text.length > 0), showSmoke: (text.length > 0) } var lineMaterial, labelCanvas, labelTexture, labelMaterial, topTexture, topMaterial, point, line; this.lat = lat; this.lon = lon; this.text = text; this.altitude = altitude; this.scene = scene; this.smokeProvider = smokeProvider; this.dateCreated = Date.now(); if(_opts){ for(var i in opts){ if(_opts[i] != undefined){ opts[i] = _opts[i]; } } } this.opts = opts; this.topVisible = opts.showTop; this.smokeVisible = opts.showSmoke; this.labelVisible = opts.showLabel; /* the line */ this.lineGeometry = new THREE.Geometry(); lineMaterial = new THREE.LineBasicMaterial({ color: opts.lineColor, linewidth: opts.lineWidth }); point = utils.mapPoint(lat,lon); this.lineGeometry.vertices.push(new THREE.Vector3(point.x, point.y, point.z)); this.lineGeometry.vertices.push(new THREE.Vector3(point.x, point.y, point.z)); this.line = new THREE.Line(this.lineGeometry, lineMaterial); /* the label */ labelCanvas = utils.createLabel(text, 18, opts.labelColor, opts.font); labelTexture = new THREE.Texture(labelCanvas); labelTexture.needsUpdate = true; labelMaterial = new THREE.SpriteMaterial({ map : labelTexture, useScreenCoordinates: false, opacity:0, depthTest: true, fog: true }); this.labelSprite = new THREE.Sprite(labelMaterial); this.labelSprite.position = {x: point.x*altitude*1.1, y: point.y*altitude + (point.y < 0 ? -15 : 30), z: point.z*altitude*1.1}; this.labelSprite.scale.set(labelCanvas.width, labelCanvas.height); /* the top */ topTexture = new THREE.Texture(createTopCanvas(opts.topColor)); topTexture.needsUpdate = true; topMaterial = new THREE.SpriteMaterial({map: topTexture, depthTest: true, fog: true, opacity: 0}); this.topSprite = new THREE.Sprite(topMaterial); this.topSprite.scale.set(20, 20); this.topSprite.position.set(point.x * altitude, point.y * altitude, point.z * altitude); /* the smoke */ if(this.smokeVisible){ this.smokeId = smokeProvider.setFire(lat, lon, altitude); } var _this = this; //arghhh /* intro animations */ if(opts.showTop || opts.showLabel){ new TWEEN.Tween( {opacity: 0}) .to( {opacity: 1}, 500 ) .onUpdate(function(){ if(_this.topVisible){ topMaterial.opacity = this.opacity; } else { topMaterial.opacity = 0; } if(_this.labelVisible){ labelMaterial.opacity = this.opacity; } else { labelMaterial.opacity = 0; } }).delay(1000) .start(); } new TWEEN.Tween(point) .to( {x: point.x*altitude, y: point.y*altitude, z: point.z*altitude}, 1500 ) .easing( TWEEN.Easing.Elastic.Out ) .onUpdate(function(){ _this.lineGeometry.vertices[1].x = this.x; _this.lineGeometry.vertices[1].y = this.y; _this.lineGeometry.vertices[1].z = this.z; _this.lineGeometry.verticesNeedUpdate = true; }).start(); /* add to scene */ this.scene.add(this.labelSprite); this.scene.add(this.line); this.scene.add(this.topSprite); }; Pin.prototype.toString = function(){ return "" + this.lat + "_" + this.lon; } Pin.prototype.changeAltitude = function(altitude){ var point = utils.mapPoint(this.lat, this.lon); var _this = this; // arghhhh new TWEEN.Tween({altitude: this.altitude}) .to( {altitude: altitude}, 1500 ) .easing( TWEEN.Easing.Elastic.Out ) .onUpdate(function(){ if(_this.smokeVisible){ _this.smokeProvider.changeAltitude(this.altitude, _this.smokeId); } if(_this.topVisible){ _this.topSprite.position.set(point.x * this.altitude, point.y * this.altitude, point.z * this.altitude); } if(_this.labelVisible){ _this.labelSprite.position = {x: point.x*this.altitude*1.1, y: point.y*this.altitude + (point.y < 0 ? -15 : 30), z: point.z*this.altitude*1.1}; } _this.lineGeometry.vertices[1].x = point.x * this.altitude; _this.lineGeometry.vertices[1].y = point.y * this.altitude; _this.lineGeometry.vertices[1].z = point.z * this.altitude; _this.lineGeometry.verticesNeedUpdate = true; }) .onComplete(function(){ _this.altitude = altitude; }).start(); }; Pin.prototype.hideTop = function(){ if(this.topVisible){ this.topSprite.material.opacity = 0.0; this.topVisible = false; } }; Pin.prototype.showTop = function(){ if(!this.topVisible){ this.topSprite.material.opacity = 1.0; this.topVisible = true; } }; Pin.prototype.hideLabel = function(){ if(this.labelVisible){ this.labelSprite.material.opacity = 0.0; this.labelVisible = false; } }; Pin.prototype.showLabel = function(){ if(!this.labelVisible){ this.labelSprite.material.opacity = 1.0; this.labelVisible = true; } }; Pin.prototype.hideSmoke = function(){ if(this.smokeVisible){ this.smokeProvider.extinguish(this.smokeId); this.smokeVisible = false; } }; Pin.prototype.showSmoke = function(){ if(!this.smokeVisible){ this.smokeId = this.smokeProvider.setFire(this.lat, this.lon, this.altitude); this.smokeVisible = true; } }; Pin.prototype.age = function(){ return Date.now() - this.dateCreated; }; Pin.prototype.remove = function(){ this.scene.remove(this.labelSprite); this.scene.remove(this.line); this.scene.remove(this.topSprite); this.removed = true; if(this.smokeVisible){ this.smokeProvider.extinguish(this.smokeId); } }; module.exports = Pin; },{"./utils":21,"three":12,"tween.js":13}],18:[function(require,module,exports){ var TextureAnimator = require('./TextureAnimator'), THREE = require('three'), utils = require('./utils'); var createCanvas = function(numFrames, pixels, rows, waveStart, numWaves, waveColor, coreColor, shieldColor) { var cols = numFrames / rows; var waveInterval = Math.floor((numFrames-waveStart)/numWaves); var waveDist = pixels - 25; // width - center of satellite var distPerFrame = waveDist / (numFrames-waveStart) var offsetx = 0; var offsety = 0; var curRow = 0; var waveColorRGB = utils.hexToRgb(waveColor); return utils.renderToCanvas(numFrames * pixels / rows, pixels * rows, function(ctx){ for(var i = 0; i< numFrames; i++){ if(i - curRow * cols >= cols){ offsetx = 0; offsety += pixels; curRow++; } var centerx = offsetx + 25; var centery = offsety + Math.floor(pixels/2); /* circle around core */ // i have between 0 and wavestart to fade in // i have between wavestart and waveend - (time between waves*2) // to do a full spin close and then back open // i have between waveend-2*(timebetween waves)/2 and waveend to rotate Math.PI/4 degrees // this is probably the ugliest code in all of here -- basically I just messed arund with stuff until it looked ok ctx.lineWidth=2; ctx.strokeStyle=shieldColor; var buffer=Math.PI/16; var start = -Math.PI + Math.PI/4; var radius = 8; var repeatAt = Math.floor(numFrames-2*(numFrames-waveStart)/numWaves)+1; /* fade in and out */ if(i=numFrames){ ctx.arc(centerx, centery, radius,n* Math.PI/2 + start+buffer, n*Math.PI/2 + start+Math.PI/2-2*buffer); } else if(i > waveStart && i < swirlDone){ var totalTimeToComplete = swirlDone - waveStart; var distToGo = 3*Math.PI/2; var currentStep = (i-waveStart); var movementPerStep = distToGo / totalTimeToComplete; var startAngle = -Math.PI + Math.PI/4 + buffer + movementPerStep*currentStep; ctx.arc(centerx, centery, radius,Math.max(n*Math.PI/2 + start,startAngle), Math.max(n*Math.PI/2 + start + Math.PI/2 - 2*buffer, startAngle +Math.PI/2 - 2*buffer)); } else if(i >= swirlDone && i< repeatAt){ var totalTimeToComplete = repeatAt - swirlDone; var distToGo = n*2*Math.PI/4; var currentStep = (i-swirlDone); var movementPerStep = distToGo / totalTimeToComplete; var startAngle = Math.PI/2 + Math.PI/4 + buffer + movementPerStep*currentStep; ctx.arc(centerx, centery, radius,startAngle, startAngle + Math.PI/2 - 2*buffer); } else if(i >= repeatAt && i < (numFrames-repeatAt)/2 + repeatAt){ var totalTimeToComplete = (numFrames-repeatAt)/2; var distToGo = Math.PI/2; var currentStep = (i-repeatAt); var movementPerStep = distToGo / totalTimeToComplete; var startAngle = n*(Math.PI/2)+ Math.PI/4 + buffer + movementPerStep*currentStep; ctx.arc(centerx, centery, radius,startAngle, startAngle + Math.PI/2 - 2*buffer); } else{ ctx.arc(centerx, centery, radius,n* Math.PI/2 + start+buffer, n*Math.PI/2 + start+Math.PI/2-2*buffer); } ctx.stroke(); } // frame i'm on * distance per frame /* waves going out */ var frameOn; for(var wi = 0; wi 0 && frameOn * distPerFrame < pixels - 25){ ctx.strokeStyle="rgba(" + waveColorRGB.r + "," + waveColorRGB.g + "," + waveColorRGB.b + "," + (.9-frameOn*distPerFrame/(pixels-25)) + ")"; ctx.lineWidth=2; ctx.beginPath(); ctx.arc(centerx, centery, frameOn * distPerFrame, -Math.PI/12, Math.PI/12); ctx.stroke(); } } /* red circle in middle */ ctx.fillStyle="#000"; ctx.beginPath(); ctx.arc(centerx,centery,3,0,2*Math.PI); ctx.fill(); ctx.strokeStyle=coreColor; ctx.lineWidth=2; ctx.beginPath(); if(i 0 ? -1 : 1); this.mesh.lon = lon; this.mesh.position.set(point.x, point.y, point.z); this.mesh.rotation.z = -1*(lat/90)* Math.PI/2; this.mesh.rotation.y = (lon/180)* Math.PI scene.add(this.mesh); } Satellite.prototype.changeAltitude = function(_altitude){ var newPoint = utils.mapPoint(this.lat, this.lon); newPoint.x *= _altitude; newPoint.y *= _altitude; newPoint.z *= _altitude; this.altitude = _altitude; this.mesh.position.set(newPoint.x, newPoint.y, newPoint.z); }; Satellite.prototype.changeCanvas = function(numWaves, waveColor, coreColor, shieldColor){ /* private vars */ numFrames = 50; pixels = 100; rows = 10; waveStart = Math.floor(numFrames/8); if(!numWaves){ numWaves = this.opts.numWaves; } else { this.opts.numWaves = numWaves; } if(!waveColor){ waveColor = this.opts.waveColor; } else { this.opts.waveColor = waveColor; } if(!coreColor){ coreColor = this.opts.coreColor; } else { this.opts.coreColor = coreColor; } if(!shieldColor){ shieldColor = this.opts.shieldColor; } else { this.opts.shieldColor = shieldColor; } this.canvas = createCanvas(numFrames, pixels, rows, waveStart, numWaves, waveColor, coreColor, shieldColor); this.texture = new THREE.Texture(this.canvas) this.texture.needsUpdate = true; repeatAt = Math.floor(numFrames-2*(numFrames-waveStart)/numWaves)+1; this.animator = new TextureAnimator(this.texture,rows, numFrames/rows, numFrames, 80, repeatAt); this.material.map = this.texture; }; Satellite.prototype.tick = function(cameraPosition, cameraAngle, renderTime) { // underscore should be good enough this.mesh.lookAt(cameraPosition); this.mesh.rotateZ(this.mesh.tiltDirection * Math.PI/2); this.mesh.rotateZ(Math.sin(cameraAngle + (this.mesh.lon / 180) * Math.PI) * this.mesh.tiltMultiplier * this.mesh.tiltDirection * -1); if(this.animator){ this.animator.update(renderTime); } }; Satellite.prototype.remove = function() { this.scene.remove(this.mesh); for(var i = 0; i< this.onRemoveList.length; i++){ this.onRemoveList[i](); } }; Satellite.prototype.onRemove = function(fn){ this.onRemoveList.push(fn); } Satellite.prototype.toString = function(){ return "" + this.lat + '_' + this.lon + '_' + this.altitude; }; module.exports = Satellite; },{"./TextureAnimator":20,"./utils":21,"three":12}],19:[function(require,module,exports){ var THREE = require('three'), utils = require('./utils'); var vertexShader = [ "#define PI 3.141592653589793238462643", "#define DISTANCE 500.0", "attribute float myStartTime;", "attribute float myStartLat;", "attribute float myStartLon;", "attribute float altitude;", "attribute float active;", "uniform float currentTime;", "uniform vec3 color;", "varying vec4 vColor;", "", "vec3 getPos(float lat, float lon)", "{", " if (lon < -180.0){", " lon = lon + 360.0;", " }", " float phi = (90.0 - lat) * PI / 180.0;", " float theta = (180.0 - lon) * PI / 180.0;", " float x = DISTANCE * sin(phi) * cos(theta) * altitude;", " float y = DISTANCE * cos(phi) * altitude;", " float z = DISTANCE * sin(phi) * sin(theta) * altitude;", " return vec3(x, y, z);", "}", "", "void main()", "{", " float dt = currentTime - myStartTime;", " if (dt < 0.0){", " dt = 0.0;", " }", " if (dt > 0.0 && active > 0.0) {", " dt = mod(dt,1500.0);", " }", " float opacity = 1.0 - dt/ 1500.0;", " if (dt == 0.0 || active == 0.0){", " opacity = 0.0;", " }", " vec3 newPos = getPos(myStartLat, myStartLon - ( dt / 50.0));", " vColor = vec4( color, opacity );", // set color associated to vertex; use later in fragment shader. " vec4 mvPosition = modelViewMatrix * vec4( newPos, 1.0 );", " gl_PointSize = 2.5 - (dt / 1500.0);", " gl_Position = projectionMatrix * mvPosition;", "}" ].join("\n"); var fragmentShader = [ "varying vec4 vColor;", "void main()", "{", " gl_FragColor = vColor;", " float depth = gl_FragCoord.z / gl_FragCoord.w;", " float fogFactor = smoothstep(1500.0, 1800.0, depth );", " vec3 fogColor = vec3(0.0);", " gl_FragColor = mix( vColor, vec4( fogColor, gl_FragColor.w), fogFactor );", "}" ].join("\n"); var SmokeProvider = function(scene, _opts){ /* options that can be passed in */ var opts = { smokeCount: 5000, smokePerPin: 30, smokePerSecond: 20 } if(_opts){ for(var i in opts){ if(_opts[i] !== undefined){ opts[i] = _opts[i]; } } } this.opts = opts; this.geometry = new THREE.Geometry(); this.attributes = { myStartTime: {type: 'f', value: []}, myStartLat: {type: 'f', value: []}, myStartLon: {type: 'f', value: []}, altitude: {type: 'f', value: []}, active: {type: 'f', value: []} }; this.uniforms = { currentTime: { type: 'f', value: 0.0}, color: { type: 'c', value: new THREE.Color("#aaa")}, } var material = new THREE.ShaderMaterial( { uniforms: this.uniforms, attributes: this.attributes, vertexShader: vertexShader, fragmentShader: fragmentShader, transparent: true }); for(var i = 0; i< opts.smokeCount; i++){ var vertex = new THREE.Vector3(); vertex.set(0,0,0); this.geometry.vertices.push( vertex ); this.attributes.myStartTime.value[i] = 0.0; this.attributes.myStartLat.value[i] = 0.0; this.attributes.myStartLon.value[i] = 0.0; this.attributes.altitude.value[i] = 0.0; this.attributes.active.value[i] = 0.0; } this.attributes.myStartTime.needsUpdate = true; this.attributes.myStartLat.needsUpdate = true; this.attributes.myStartLon.needsUpdate = true; this.attributes.altitude.needsUpdate = true; this.attributes.active.needsUpdate = true; this.smokeIndex = 0; this.totalRunTime = 0; scene.add( new THREE.ParticleSystem( this.geometry, material)); }; SmokeProvider.prototype.setFire = function(lat, lon, altitude){ var point = utils.mapPoint(lat, lon); /* add the smoke */ var startSmokeIndex = this.smokeIndex; for(var i = 0; i< this.opts.smokePerPin; i++){ this.geometry.vertices[this.smokeIndex].set(point.x * altitude, point.y * altitude, point.z * altitude); this.geometry.verticesNeedUpdate = true; this.attributes.myStartTime.value[this.smokeIndex] = this.totalRunTime + (1000*i/this.opts.smokePerSecond + 1500); this.attributes.myStartLat.value[this.smokeIndex] = lat; this.attributes.myStartLon.value[this.smokeIndex] = lon; this.attributes.altitude.value[this.smokeIndex] = altitude; this.attributes.active.value[this.smokeIndex] = 1.0; this.attributes.myStartTime.needsUpdate = true; this.attributes.myStartLat.needsUpdate = true; this.attributes.myStartLon.needsUpdate = true; this.attributes.altitude.needsUpdate = true; this.attributes.active.needsUpdate = true; this.smokeIndex++; this.smokeIndex = this.smokeIndex % this.geometry.vertices.length; } return startSmokeIndex; }; SmokeProvider.prototype.extinguish = function(index){ for(var i = 0; i< this.opts.smokePerPin; i++){ this.attributes.active.value[(i + index) % this.opts.smokeCount] = 0.0; this.attributes.active.needsUpdate = true; } }; SmokeProvider.prototype.changeAltitude = function(altitude, index){ for(var i = 0; i< this.opts.smokePerPin; i++){ this.attributes.altitude.value[(i + index) % this.opts.smokeCount] = altitude; this.attributes.altitude.needsUpdate = true; } }; SmokeProvider.prototype.tick = function(totalRunTime){ this.totalRunTime = totalRunTime; this.uniforms.currentTime.value = this.totalRunTime; }; module.exports = SmokeProvider; },{"./utils":21,"three":12}],20:[function(require,module,exports){ var THREE = require('three'); // based on http://stemkoski.github.io/Three.js/Texture-Animation.html var TextureAnimator = function(texture, tilesVert, tilesHoriz, numTiles, tileDispDuration, repeatAtTile) { // note: texture passed by reference, will be updated by the update function. if(repeatAtTile == undefined){ this.repeatAtTile=-1; } this.shutDownFlag = (this.repeatAtTile < 0); this.done = false; this.tilesHorizontal = tilesHoriz; this.tilesVertical = tilesVert; // how many images does this spritesheet contain? // usually equals tilesHoriz * tilesVert, but not necessarily, // if there at blank tiles at the bottom of the spritesheet. this.numberOfTiles = numTiles; texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.repeat.set( 1 / this.tilesHorizontal, 1 / this.tilesVertical ); // how long should each image be displayed? this.tileDisplayDuration = tileDispDuration; // how long has the current image been displayed? this.currentDisplayTime = 0; // which image is currently being displayed? this.currentTile = 0; texture.offset.y = 1; this.update = function( milliSec ) { this.currentDisplayTime += milliSec; while (!this.done && this.currentDisplayTime > this.tileDisplayDuration) { if(this.shutDownFlag && this.currentTile >= numTiles){ this.done = true; this.shutDownCb(); } else { this.currentDisplayTime -= this.tileDisplayDuration; this.currentTile++; if (this.currentTile == numTiles && !this.shutDownFlag) this.currentTile = repeatAtTile; var currentColumn = this.currentTile % this.tilesHorizontal; texture.offset.x = currentColumn / this.tilesHorizontal; var currentRow = Math.floor( this.currentTile / this.tilesHorizontal ); texture.offset.y = 1-(currentRow / this.tilesVertical) - 1/this.tilesVertical; } } }; this.shutDown = function(cb){ _this.shutDownFlag = true; _this.shutDownCb = cb; } }; module.exports = TextureAnimator; },{"three":12}],21:[function(require,module,exports){ var utils = { renderToCanvas: function (width, height, renderFunction) { var buffer = document.createElement('canvas'); buffer.width = width; buffer.height = height; renderFunction(buffer.getContext('2d')); return buffer; }, mapPoint: function(lat, lng, scale) { if(!scale){ scale = 500; } var phi = (90 - lat) * Math.PI / 180; var theta = (180 - lng) * Math.PI / 180; var x = scale * Math.sin(phi) * Math.cos(theta); var y = scale * Math.cos(phi); var z = scale * Math.sin(phi) * Math.sin(theta); return {x: x, y: y, z:z}; }, /* from http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb */ hexToRgb: function(hex) { // Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF") var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i; hex = hex.replace(shorthandRegex, function(m, r, g, b) { return r + r + g + g + b + b; }); var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); return result ? { r: parseInt(result[1], 16), g: parseInt(result[2], 16), b: parseInt(result[3], 16) } : null; }, createLabel: function(text, size, color, font, underlineColor) { var canvas = document.createElement("canvas"); var context = canvas.getContext("2d"); context.font = size + "pt " + font; var textWidth = context.measureText(text).width; canvas.width = textWidth; canvas.height = size + 10; // better if canvases have even heights if(canvas.width % 2){ canvas.width++; } if(canvas.height % 2){ canvas.height++; } if(underlineColor){ canvas.height += 30; } context.font = size + "pt " + font; context.textAlign = "center"; context.textBaseline = "middle"; context.strokeStyle = 'black'; context.miterLimit = 2; context.lineJoin = 'circle'; context.lineWidth = 6; context.strokeText(text, canvas.width / 2, canvas.height / 2); context.lineWidth = 2; context.fillStyle = color; context.fillText(text, canvas.width / 2, canvas.height / 2); if(underlineColor){ context.strokeStyle=underlineColor; context.lineWidth=4; context.beginPath(); context.moveTo(0, canvas.height-10); context.lineTo(canvas.width-1, canvas.height-10); context.stroke(); } return canvas; }, }; module.exports = utils; },{}]},{},[1]); ================================================ FILE: src/classes/audiofx.class.js ================================================ class AudioManager { constructor() { const path = require("path"); const {Howl, Howler} = require("howler"); if (window.settings.audio === true) { if(window.settings.disableFeedbackAudio === false) { this.stdout = new Howl({ src: [path.join(__dirname, "assets", "audio", "stdout.wav")], volume: 0.4 }); this.stdin = new Howl({ src: [path.join(__dirname, "assets", "audio", "stdin.wav")], volume: 0.4 }); this.folder = new Howl({ src: [path.join(__dirname, "assets", "audio", "folder.wav")] }); this.granted = new Howl({ src: [path.join(__dirname, "assets", "audio", "granted.wav")] }); } this.keyboard = new Howl({ src: [path.join(__dirname, "assets", "audio", "keyboard.wav")] }); this.theme = new Howl({ src: [path.join(__dirname, "assets", "audio", "theme.wav")] }); this.expand = new Howl({ src: [path.join(__dirname, "assets", "audio", "expand.wav")] }); this.panels = new Howl({ src: [path.join(__dirname, "assets", "audio", "panels.wav")] }); this.scan = new Howl({ src: [path.join(__dirname, "assets", "audio", "scan.wav")] }); this.denied = new Howl({ src: [path.join(__dirname, "assets", "audio", "denied.wav")] }); this.info = new Howl({ src: [path.join(__dirname, "assets", "audio", "info.wav")] }); this.alarm = new Howl({ src: [path.join(__dirname, "assets", "audio", "alarm.wav")] }); this.error = new Howl({ src: [path.join(__dirname, "assets", "audio", "error.wav")] }); Howler.volume(window.settings.audioVolume); } else { Howler.volume(0.0); } // Return a proxy to avoid errors if sounds aren't loaded return new Proxy(this, { get: (target, sound) => { if (sound in target) { return target[sound]; } else { return { play: () => {return true;} } } } }); } } module.exports = { AudioManager }; ================================================ FILE: src/classes/clock.class.js ================================================ class Clock { constructor(parentId) { if (!parentId) throw "Missing parameters"; // Load settings this.twelveHours = (window.settings.clockHours === 12); // Create DOM this.parent = document.getElementById(parentId); this.parent.innerHTML += `

??:??:??

`; this.lastTime = new Date(); this.updateClock(); this.updater = setInterval(() => { this.updateClock(); }, 1000); } updateClock() { let time = new Date(); let array = [time.getHours(), time.getMinutes(), time.getSeconds()]; // 12-hour mode translation if (this.twelveHours) { this.ampm = (array[0] >= 12) ? "PM" : "AM"; if (array[0] > 12) array[0] = array[0] - 12; if (array[0] === 0) array[0] = 12; } array.forEach((e, i) => { if (e.toString().length !== 2) { array[i] = "0"+e; } }); let clockString = `${array[0]}:${array[1]}:${array[2]}`; array = clockString.match(/.{1}/g); clockString = ""; array.forEach(e => { if (e === ":") clockString += ""+e+""; else clockString += ""+e+""; }); if (this.twelveHours) clockString += `${this.ampm}`; document.getElementById("mod_clock_text").innerHTML = clockString; this.lastTime = time; } } module.exports = { Clock }; ================================================ FILE: src/classes/conninfo.class.js ================================================ class Conninfo { constructor(parentId) { if (!parentId) throw "Missing parameters"; // Create DOM this.parent = document.getElementById(parentId); this.parent.innerHTML += `

NETWORK TRAFFICUP / DOWN, MB/S

TOTAL0B OUT, 0B IN

OFFLINE

`; this.current = document.querySelector("#mod_conninfo_innercontainer > h1 > i"); this.total = document.querySelector("#mod_conninfo_innercontainer > h2 > i"); this._pb = require("pretty-bytes"); // Init Smoothie let TimeSeries = require("smoothie").TimeSeries; let SmoothieChart = require("smoothie").SmoothieChart; // Set chart options let chartOptions = [{ limitFPS: 40, responsive: true, millisPerPixel: 70, interpolation: 'linear', grid:{ millisPerLine: 5000, fillStyle:'transparent', strokeStyle:`rgba(${window.theme.r},${window.theme.g},${window.theme.b},0.4)`, verticalSections:3, borderVisible:false }, labels:{ fontSize: 10, fillStyle: `rgb(${window.theme.r},${window.theme.g},${window.theme.b})`, precision: 2 } }]; chartOptions.push(Object.assign({}, chartOptions[0])); // Deep copy object, see http://jsben.ch/bWfk9 chartOptions[0].minValue = 0; chartOptions[1].maxValue = 0; // Create chart this.series = [new TimeSeries(), new TimeSeries()]; this.charts = [new SmoothieChart(chartOptions[0]), new SmoothieChart(chartOptions[1])]; this.charts[0].addTimeSeries(this.series[0], {lineWidth:1.7,strokeStyle:`rgb(${window.theme.r},${window.theme.g},${window.theme.b})`}); this.charts[1].addTimeSeries(this.series[1], {lineWidth:1.7,strokeStyle:`rgb(${window.theme.r},${window.theme.g},${window.theme.b})`}); this.charts[0].streamTo(document.getElementById("mod_conninfo_canvas_top"), 1000); this.charts[1].streamTo(document.getElementById("mod_conninfo_canvas_bottom"), 1000); // Init updater this.updateInfo(); this.infoUpdater = setInterval(() => { this.updateInfo(); }, 1000); } updateInfo() { let time = new Date().getTime(); if (window.mods.netstat.offline || window.mods.netstat.iface === null) { this.series[0].append(time, 0); this.series[1].append(time, 0); document.querySelector("div#mod_conninfo").setAttribute("class", "offline"); return; } else { document.querySelector("div#mod_conninfo").setAttribute("class", ""); window.si.networkStats(window.mods.netstat.iface).then(data => { let max0 = this.series[0].maxValue; let max1 = -this.series[1].minValue; if (max0 > max1) { this.series[1].minValue = -max0; } else if (max1 > max0) { this.series[0].maxValue = max1; } this.series[0].append(time, data[0].tx_sec/125000); this.series[1].append(time, -data[0].rx_sec/125000); this.total.innerText = `${this._pb(data[0].tx_bytes)} OUT, ${this._pb(data[0].rx_bytes)} IN`.toUpperCase(); this.current.innerText = "UP " + parseFloat(data[0].tx_sec/125000).toFixed(2) + " DOWN " + parseFloat(data[0].rx_sec/125000).toFixed(2); }); } } } module.exports = { Conninfo }; ================================================ FILE: src/classes/cpuinfo.class.js ================================================ class Cpuinfo { constructor(parentId) { if (!parentId) throw "Missing parameters"; // Create initial DOM this.parent = document.getElementById(parentId); this.parent.innerHTML += `
`; this.container = document.getElementById("mod_cpuinfo"); // Init Smoothie let TimeSeries = require("smoothie").TimeSeries; let SmoothieChart = require("smoothie").SmoothieChart; this.series = []; this.charts = []; window.si.cpu().then(data => { let divide = Math.floor(data.cores/2); this.divide = divide; let cpuName = data.manufacturer+data.brand; cpuName = cpuName.substr(0, 30); cpuName.substr(0, Math.min(cpuName.length, cpuName.lastIndexOf(" "))); let innercontainer = document.createElement("div"); innercontainer.setAttribute("id", "mod_cpuinfo_innercontainer"); innercontainer.innerHTML = `

CPU USAGE${cpuName}

# 1 - ${divide}
Avg. --%

# ${divide+1} - ${data.cores}
Avg. --%

${(process.platform === "win32") ? "CORES" : "TEMP"}
${(process.platform === "win32") ? data.cores : "--°C"}

SPD
--GHz

MAX
--GHz

TASKS
---

`; this.container.append(innercontainer); for (var i = 0; i < 2; i++) { this.charts.push(new SmoothieChart({ limitFPS: 30, responsive: true, millisPerPixel: 50, grid:{ fillStyle:'transparent', strokeStyle:'transparent', verticalSections:0, borderVisible:false }, labels:{ disabled: true }, yRangeFunction: () => { return {min:0,max:100}; } })); } for (var i = 0; i < data.cores; i++) { // Create TimeSeries this.series.push(new TimeSeries()); let serie = this.series[i]; let options = { lineWidth: 1.7, strokeStyle: `rgb(${window.theme.r},${window.theme.g},${window.theme.b})` }; if (i < divide) { this.charts[0].addTimeSeries(serie, options); } else { this.charts[1].addTimeSeries(serie, options); } } for (var i = 0; i < 2; i++) { this.charts[i].streamTo(document.getElementById(`mod_cpuinfo_canvas_${i}`), 500); } // Init updater this.updatingCPUload = false; this.updateCPUload(); if (process.platform !== "win32") {this.updateCPUtemp();} this.updatingCPUspeed = false; this.updateCPUspeed(); this.updatingCPUtasks = false; this.updateCPUtasks(); this.loadUpdater = setInterval(() => { this.updateCPUload(); }, 500); if (process.platform !== "win32") { this.tempUpdater = setInterval(() => { this.updateCPUtemp(); }, 2000); } this.speedUpdater = setInterval(() => { this.updateCPUspeed(); }, 1000); this.tasksUpdater = setInterval(() => { this.updateCPUtasks(); }, 5000); }); } updateCPUload() { if (this.updatingCPUload) return; this.updatingCPUload = true; window.si.currentLoad().then(data => { let average = [[], []]; if (!data.cpus) return; // Prevent memleak in rare case where systeminformation takes extra time to retrieve CPU info (see github issue #216) data.cpus.forEach((e, i) => { this.series[i].append(new Date().getTime(), e.load); if (i < this.divide) { average[0].push(e.load); } else { average[1].push(e.load); } }); average.forEach((stats, i) => { average[i] = Math.round(stats.reduce((a, b) => a + b, 0)/stats.length); try { document.getElementById(`mod_cpuinfo_usagecounter${i}`).innerText = `Avg. ${average[i]}%`; } catch(e) { // Fail silently, DOM element is probably getting refreshed (new theme, etc) } }); this.updatingCPUload = false; }); } updateCPUtemp() { window.si.cpuTemperature().then(data => { try { document.getElementById("mod_cpuinfo_temp").innerText = `${data.max}°C`; } catch(e) { // See above notice } }); } updateCPUspeed() { if (this.updatingCPUspeed) return; this.updatingCPUspeed = true window.si.cpu().then(data => { try { document.getElementById("mod_cpuinfo_speed_min").innerText = `${data.speed}GHz`; document.getElementById("mod_cpuinfo_speed_max").innerText = `${data.speedMax}GHz`; } catch(e) { // See above notice } this.updatingCPUspeed = false; }); } updateCPUtasks() { if (this.updatingCPUtasks) return; this.updatingCPUtasks = true; window.si.processes().then(data => { try { document.getElementById("mod_cpuinfo_tasks").innerText = `${data.all}`; } catch(e) { // See above notice } this.updatingCPUtasks = false; }); } } module.exports = { Cpuinfo }; ================================================ FILE: src/classes/docReader.class.js ================================================ class DocReader { constructor(opts) { pdfjsLib.GlobalWorkerOptions.workerSrc = './node_modules/pdfjs-dist/build/pdf.worker.js'; const modalElementId = "modal_" + opts.modalId; const path = opts.path; const scale = 1; const canvas = document.getElementById(modalElementId).querySelector(".pdf_canvas"); const context = canvas.getContext('2d'); const loadingTask = pdfjsLib.getDocument(path); let pdfDoc = null, pageNum = 1, pageRendering = false, pageNumPending = null, zoom = 100 this.renderPage = (num) => { pageRendering = true; loadingTask.promise.then(function (pdf) { pdfDoc.getPage(num).then(function (page) { const viewport = page.getViewport({ scale: scale }); canvas.height = viewport.height; canvas.width = viewport.width; const renderContext = { canvasContext: context, viewport: viewport, }; const renderTask = page.render(renderContext); renderTask.promise.then(function () { pageRendering = false; if (pageNumPending !== null) { renderPage(pageNumPending); pageNumPending = null; } }); }); }); document.getElementById(modalElementId).querySelector(".page_num").textContent = num; } this.queueRenderPage = (num) => { if (pageRendering) { pageNumPending = num; } else { this.renderPage(num); } } this.onPrevPage = () => { if (pageNum <= 1) { return; } pageNum--; this.queueRenderPage(pageNum); } this.onNextPage = () => { if (pageNum >= pdfDoc.numPages) { return; } pageNum++; this.queueRenderPage(pageNum); } this.zoomIn = () => { if (zoom >= 200) { return; } zoom = zoom + 10; canvas.style.zoom = zoom + "%"; } this.zoomOut = () => { if (zoom <= 50) { return; } zoom = zoom - 10; canvas.style.zoom = zoom + "%"; } document.getElementById(modalElementId).querySelector(".previous_page").addEventListener('click', this.onPrevPage); document.getElementById(modalElementId).querySelector(".next_page").addEventListener('click', this.onNextPage); document.getElementById(modalElementId).querySelector(".zoom_in").addEventListener('click', this.zoomIn); document.getElementById(modalElementId).querySelector(".zoom_out").addEventListener('click', this.zoomOut); pdfjsLib.getDocument(path).promise.then((pdfDoc_) => { pdfDoc = pdfDoc_; document.getElementById(modalElementId).querySelector(".page_count").textContent = pdfDoc.numPages; this.renderPage(pageNum); }); } } module.exports = { DocReader }; ================================================ FILE: src/classes/filesystem.class.js ================================================ class FilesystemDisplay { constructor(opts) { if (!opts.parentId) throw "Missing options"; const fs = require("fs"); const path = require("path"); this.cwd = []; this.cwd_path = null; this.iconcolor = `rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b})`; this._formatBytes = (a,b) => {if(0==a)return"0 Bytes";var c=1024,d=b||2,e=["Bytes","KB","MB","GB","TB","PB","EB","ZB","YB"],f=Math.floor(Math.log(a)/Math.log(c));return parseFloat((a/Math.pow(c,f)).toFixed(d))+" "+e[f]}; this.fileIconsMatcher = require("./assets/misc/file-icons-match.js"); this.icons = require("./assets/icons/file-icons.json"); this.edexIcons = { theme: { width: 24, height: 24, svg: '' }, themesDir: { width: 24, height: 24, svg: `` }, kblayout: { width: 24, height: 24, svg: '' }, kblayoutsDir: { width: 24, height: 24, svg: `` }, settings: { width: 24, height: 24, svg: '' } }; const container = document.getElementById(opts.parentId); container.innerHTML = `

FILESYSTEM

EXIT DISPLAY

Calculating available space...

`; this.filesContainer = document.getElementById("fs_disp_container"); this.space_bar = { text: document.querySelector("#fs_space_bar > h3"), bar: document.querySelector("#fs_space_bar > progress") }; this.fsBlock = {}; this.dirpath = ""; this.failed = false; this._noTracking = false; this._runNextTick = false; this._reading = false; this._timer = setInterval(() => { if (this._runNextTick === true) { this._runNextTick = false; this.readFS(this.dirpath); } }, 1000); this._asyncFSwrapper = new Proxy(fs, { get: function(fs, prop) { if (prop in fs) { return function(...args) { return new Promise((resolve, reject) => { fs[prop](...args, (err, d) => { if (typeof err !== "undefined" && err !== null) reject(err); if (typeof d !== "undefined") resolve(d); if (typeof d === "undefined" && typeof err === "undefined") resolve(); }); }); } } }, set: function() { return false; } }); this.setFailedState = () => { this.failed = true; container.innerHTML = `

FILESYSTEM

EXECUTION FAILED

CANNOT ACCESS CURRENT WORKING DIRECTORY

`; }; this.followTab = () => { // Don't follow tabs when running in detached mode, see #432 if (this._noTracking) return false; let num = window.currentTerm; window.term[num].oncwdchange = cwd => { // See #501 if (this._noTracking) return false; if (cwd && cwd !== this.cwd_path && window.currentTerm === num) { this.cwd_path = cwd; if (this._fsWatcher) { this._fsWatcher.close(); } if (cwd.startsWith("FALLBACK |-- ")) { this.readFS(cwd.slice(13)); this._noTracking = true; } else { this.readFS(cwd); this.watchFS(cwd); } } }; }; this.followTab(); this.watchFS = dir => { if (this._fsWatcher) { this._fsWatcher.close(); } this._fsWatcher = fs.watch(dir, (eventType, filename) => { if (eventType != "change") { // #758 - Don't refresh file view if only file contents have changed. this._runNextTick = true; } }); }; this.toggleHidedotfiles = () => { if (window.settings.hideDotfiles) { container.classList.remove("hideDotfiles"); window.settings.hideDotfiles = false; } else { container.classList.add("hideDotfiles"); window.settings.hideDotfiles = true; } }; this.toggleListview = () => { if (window.settings.fsListView) { container.classList.remove("list-view"); window.settings.fsListView = false; } else { container.classList.add("list-view"); window.settings.fsListView = true; } }; this.readFS = async dir => { if (this.failed === true || this._reading) return false; this._reading = true; document.getElementById("fs_disp_title_dir").innerText = this.dirpath; this.filesContainer.setAttribute("class", ""); this.filesContainer.innerHTML = ""; if (this._noTracking) { document.querySelector("section#filesystem > h3.title > p:first-of-type").innerText = "FILESYSTEM - TRACKING FAILED, RUNNING DETACHED FROM TTY"; } if (process.platform === "win32" && dir.endsWith(":")) dir = dir+"\\"; let tcwd = dir; let content = await this._asyncFSwrapper.readdir(tcwd).catch(err => { console.warn(err); if (this._noTracking === true && this.dirpath) { // #262 this.setFailedState(); setTimeout(() => { this.readFS(this.dirpath); }, 1000); } else { this.setFailedState(); } }); this.reCalculateDiskUsage(tcwd); this.cwd = []; await new Promise((resolve, reject) => { if (content.length === 0) resolve(); content.forEach(async (file, i) => { let fstat = await this._asyncFSwrapper.lstat(path.join(tcwd, file)).catch(e => { if (!e.message.includes("EPERM") && !e.message.includes("EBUSY")) { reject(); } }); let e = { name: window._escapeHtml(file), path: path.resolve(tcwd, file), type: "other", category: "other", hidden: false }; if (typeof fstat !== "undefined") { e.lastAccessed = fstat.mtime.getTime(); if (fstat.isDirectory()) { e.category = "dir"; e.type = "dir"; } if (e.category === "dir" && tcwd === settingsDir && file === "themes") e.type="edex-themesDir"; if (e.category === "dir" && tcwd === settingsDir && file === "keyboards") e.type = "edex-kblayoutsDir"; if (fstat.isSymbolicLink()) { e.category = "symlink"; e.type = "symlink"; } if (fstat.isFile()) { e.category = "file"; e.type = "file"; e.size = fstat.size; } } else { e.type = "system"; e.hidden = true; } if (e.category === "file" && tcwd === themesDir && file.endsWith(".json")) e.type = "edex-theme"; if (e.category === "file" && tcwd === keyboardsDir && file.endsWith(".json")) e.type = "edex-kblayout"; if (e.category === "file" && tcwd === settingsDir && file === "settings.json") e.type = "edex-settings"; if (e.category === "file" && tcwd === settingsDir && file === "shortcuts.json") e.type = "edex-shortcuts"; if (file.startsWith(".")) e.hidden = true; this.cwd.push(e); if (i === content.length-1) resolve(); }); }).catch(() => { this.setFailedState() }); if (this.failed) return false; let ordering = { dir: 0, symlink: 1, file: 2, other: 3 }; this.cwd.sort((a, b) => { return (ordering[a.category] - ordering[b.category] || a.name.localeCompare(b.name)); }); this.cwd.splice(0, 0, { name: "Show disks", type: "showDisks" }); if (tcwd !== "/" && /^[A-Z]:\\$/i.test(tcwd) === false) { this.cwd.splice(1, 0, { name: "Go up", type: "up" }); } this.dirpath = tcwd; this.render(this.cwd); this._reading = false; }; this.readDevices = async () => { if (this.failed === true) return false; let blocks = await window.si.blockDevices(); let devices = []; blocks.forEach(block => { if (fs.existsSync(block.mount)) { let type = (block.type === "rom") ? "rom" : "disk"; if (block.removable && block.type !== "rom") { type = "usb"; } devices.push({ name: (block.label !== "") ? `${block.label} (${block.name})` : `${block.mount} (${block.name})`, type, path: block.mount }); } }); this.render(devices, true); }; this.render = async (originBlockList, isDiskView) => { // Work on a clone of the blocklist to avoid altering fsDisp.cwd let blockList = JSON.parse(JSON.stringify(originBlockList)); if (this.failed === true) return false; if (isDiskView) { document.getElementById("fs_disp_title_dir").innerText = "Showing available block devices"; this.filesContainer.setAttribute("class", "disks"); } else { document.getElementById("fs_disp_title_dir").innerText = this.dirpath; this.filesContainer.setAttribute("class", ""); } if (this._noTracking) { document.querySelector("section#filesystem > h3.title > p:first-of-type").innerText = "FILESYSTEM - TRACKING FAILED, RUNNING DETACHED FROM TTY"; } let filesDOM = ``; blockList.forEach((e, blockIndex) => { let hidden = e.hidden ? " hidden" : ""; let cmdPrefix = `if (window.keyboard.container.dataset.isCtrlOn == "true") { electron.shell.openPath(fsDisp.cwd[${blockIndex}].path); electronWin.minimize(); } else if (window.keyboard.container.dataset.isShiftOn == "true") { window.term[window.currentTerm].write("\\""+fsDisp.cwd[${blockIndex}].path+"\\""); } else { `.replace(/\n+ */g, ''); // Minify let cmdSuffix = `}`; let cmd; if (!this._noTracking) { if (e.type === "dir" || e.type.endsWith("Dir")) { cmd = `window.term[window.currentTerm].writelr("cd \\""+fsDisp.cwd[${blockIndex}].name+"\\"")`; } else if (e.type === "up") { cmd = `window.term[window.currentTerm].writelr("cd ..")`; } else if (e.type === "disk" || e.type === "rom" || e.type === "usb") { if (process.platform === "win32") { cmd = `window.term[window.currentTerm].writelr("${e.path.replace(/\\/g, '')}")`; } else { cmd = `window.term[window.currentTerm].writelr("cd \\"${e.path.replace(/\\/g, '')}\\"")`; } } else { cmd = `window.term[window.currentTerm].write("\\""+fsDisp.cwd[${blockIndex}].path+"\\"")`; } } else { if (e.type === "dir" || e.type.endsWith("Dir")) { cmd = `window.fsDisp.readFS(fsDisp.cwd[${blockIndex}].path)`; } else if (e.type === "up") { cmd = `window.fsDisp.readFS(path.resolve(window.fsDisp.dirpath, ".."))`; } else if (e.type === "disk" || e.type === "rom" || e.type === "usb") { cmd = `window.fsDisp.readFS("${e.path.replace(/\\/g, '')}")`; } else { cmd = `window.term[window.currentTerm].write("\\""+fsDisp.cwd[${blockIndex}].path+"\\"")`; } } if (e.type === "file") { cmd = `window.fsDisp.openFile(${blockIndex})`; } if (e.type === "system") { cmd = ""; } if (e.type === "showDisks") { cmd = `window.fsDisp.readDevices()`; cmdPrefix = ''; cmdSuffix = ''; } if (e.type === "up") { // cmd is OS-specific and defined above cmdPrefix = ''; cmdSuffix = ''; } if (e.type === "edex-theme") { cmd = `window.themeChanger("${e.name.slice(0, -5)}")`; } if (e.type === "edex-kblayout") { cmd = `window.remakeKeyboard("${e.name.slice(0, -5)}")`; } if (e.type === "edex-settings") { cmd = `window.openSettings()`; } if (e.type === "edex-shortcuts") { cmd = `window.openShortcutsHelp()`; } let icon = ""; let type = ""; switch(e.type) { case "showDisks": icon = this.icons.showDisks; type = "--"; e.category = "showDisks"; break; case "up": icon = this.icons.up; type = "--"; e.category = "up"; break; case "symlink": icon = this.icons.symlink; break; case "disk": icon = this.icons.disk; break; case "rom": icon = this.icons.rom; break; case "usb": icon = this.icons.usb; break; case "edex-theme": icon = this.edexIcons.theme; type = "eDEX-UI theme"; break; case "edex-kblayout": icon = this.edexIcons.kblayout; type = "eDEX-UI keyboard layout"; break; case "edex-settings": case "edex-shortcuts": icon = this.edexIcons.settings; type = "eDEX-UI config file"; break; case "system": icon = this.edexIcons.settings; break; case "edex-themesDir": icon = this.edexIcons.themesDir; type = "eDEX-UI themes folder"; break; case "edex-kblayoutsDir": icon = this.edexIcons.kblayoutsDir; type = "eDEX-UI keyboards folder"; break; default: let iconName = this.fileIconsMatcher(e.name); icon = this.icons[iconName]; if (typeof icon === "undefined") { if (e.type === "file") icon = this.icons.file; if (e.type === "dir") { icon = this.icons.dir; type = "folder"; } if (typeof icon === "undefined") icon = this.icons.other; } else if (e.category !== "dir") { type = iconName.replace("icon-", ""); } else { type = "special folder"; } break; } if (type === "") type = e.type; e.type = type; // Handle displayable media if (e.type === 'video' || e.type === 'audio' || e.type === 'image') { this.cwd[blockIndex].type = e.type; cmd = `window.fsDisp.openMedia(${blockIndex})`; } if (typeof e.size === "number") { e.size = this._formatBytes(e.size); } else { e.size = "--"; } if (typeof e.lastAccessed === "number") { e.lastAccessed = new Date(e.lastAccessed).toLocaleString(); } else { e.lastAccessed = "--"; } filesDOM += `
${icon.svg}

${e.name}

${type}

${e.size}

${e.lastAccessed}

`; }); this.filesContainer.innerHTML = filesDOM; if (this.filesContainer.getAttribute("class").endsWith("disks")) { document.getElementById("fs_space_bar").setAttribute("onclick", "window.fsDisp.render(window.fsDisp.cwd)"); } else { document.getElementById("fs_space_bar").setAttribute("onclick", ""); } // Render animation let id = 0; while (this.filesContainer.childNodes[id]) { let e = this.filesContainer.childNodes[id]; e.setAttribute("class", e.className.replace(" animationWait", "")); if (window.settings.hideDotfiles !== true || e.className.indexOf("hidden") === -1) { window.audioManager.folder.play(); await _delay(30); } id++; } }; this.reCalculateDiskUsage = async path => { this.fsBlock = null; this.space_bar.text.innerHTML = "Calculating available space..."; this.space_bar.bar.removeAttribute("value"); window.si.fsSize().catch(() => { this.space_bar.text.innerHTML = "Could not calculate mountpoint usage."; this.space_bar.bar.value = 100; }).then(d => { d.forEach(fsBlock => { if (path.startsWith(fsBlock.mount)) { this.fsBlock = fsBlock; } }); this.renderDiskUsage(this.fsBlock); }); }; this.renderDiskUsage = async fsBlock => { if (document.getElementById("fs_space_bar").getAttribute("onclick") !== "" || fsBlock === null) return; let splitter = (process.platform === "win32") ? "\\" : "/"; let displayMount = (fsBlock.mount.length < 18) ? fsBlock.mount : "..."+splitter+fsBlock.mount.split(splitter).pop(); // See #226 if (!isNaN(fsBlock.use)) { this.space_bar.text.innerHTML = `Mount ${displayMount} used ${Math.round(fsBlock.use)}%`; this.space_bar.bar.value = Math.round(fsBlock.use); } else if (!isNaN((fsBlock.size / fsBlock.used) * 100)) { let usage = Math.round((fsBlock.size / fsBlock.used) * 100); this.space_bar.text.innerHTML = `Mount ${displayMount} used ${usage}%`; this.space_bar.bar.value = usage; } else { this.space_bar.text.innerHTML = "Could not calculate mountpoint usage."; this.space_bar.bar.value = 100; } }; // Automatically start indexing supposed beginning CWD // See #365 // ...except if we're hot-reloading, in which case this can mess up the rendering // See #392 if (window.performance.navigation.type === 0) { this.readFS(window.term[window.currentTerm].cwd || window.settings.cwd); } this.openFile = (name, path, type) => { //Might add text formatting at some point, not now though - Surge let block; if (typeof name === "number") { block = this.cwd[name]; name = block.name; } let mime = require("mime-types"); block.path = block.path.replace(/\\/g, "/"); let filetype = mime.lookup(name.split(".")[name.split(".").length - 1]); switch (filetype) { case "application/pdf": let html = `
Page: /
`; const newModal = new Modal( { type: "custom", title: _escapeHtml(name), html: html } ); new DocReader( { modalId: newModal.id, path: block.path } ); break; default: if (mime.charset(filetype) === "UTF-8") { fs.readFile(block.path, 'utf-8', (err, data) => { if (err) { new Modal({ type: "info", title: "Failed to load file: " + block.path, html: err }); console.log(err); }; window.keyboard.detach(); new Modal( { type: "custom", title: _escapeHtml(name), html: `

`, buttons: [ {label:"Save to Disk",action:`window.writeFile('${block.path}')`} ] }, () => { window.keyboard.attach(); window.term[window.currentTerm].term.focus(); } ); }); break; } } }; this.openMedia = (name, path, type) => { let block, html; if (typeof name === "number") { block = this.cwd[name]; name = block.name; } block.path = block.path.replace(/\\/g, "/"); switch (type || block.type) { case "image": html = ``; break; case "audio": html = `
${this.icons["play"].svg}
00:00:00
${this.icons["volume"].svg}
`; break; case "video": html = `
${this.icons["play"].svg}
00:00:00
${this.icons["volume"].svg}
${this.icons["fullscreen"].svg}
`; break; default: throw new Error("fsDisp media displayer: unknown type " + (type || block.type)); } const newModal = new Modal({ type: "custom", title: _escapeHtml(name), html }); if (block.type === "audio" || block.type === "video") { new MediaPlayer({ modalId: newModal.id, path: block.path, type: block.type }); } }; } } module.exports = { FilesystemDisplay }; ================================================ FILE: src/classes/fuzzyFinder.class.js ================================================ class FuzzyFinder { constructor() { if (document.getElementById("fuzzyFinder") || document.getElementById("settingsEditor")) { return false; } window.keyboard.detach(); this.disp = new Modal({ type: "custom", title: "Fuzzy cwd file search", html: `
`, buttons: [ {label: "Select", action: "window.activeFuzzyFinder.submit()"} ] }, () => { delete window.activeFuzzyFinder; window.keyboard.attach(); window.term[window.currentTerm].term.focus(); }); this.input = document.getElementById("fuzzyFinder"); this.results = document.getElementById("fuzzyFinder-results"); this.input.addEventListener('input', e => { if ((e.inputType && e.inputType.startsWith("delete")) || (e.detail && e.detail.startsWith("delete"))) { this.input.value = ""; this.search(""); } else { this.search(this.input.value); } }); this.input.addEventListener('change', e => { if (e.detail === "enter") { this.submit(); } }); this.input.addEventListener('keydown', e => { let selectedEl,selected,next,nextEl; switch(e.key) { case 'Enter': this.submit(); e.preventDefault(); break; case 'ArrowDown': selectedEl = document.querySelector('li.fuzzyFinderMatchSelected'); selected = Number(selectedEl.id.substr(17)); next = (document.getElementById(`fuzzyFinderMatch-${selected+1}`)) ? selected+1 : 0; nextEl = document.getElementById(`fuzzyFinderMatch-${next}`); selectedEl.removeAttribute("class"); nextEl.setAttribute("class", "fuzzyFinderMatchSelected"); e.preventDefault(); break; case 'ArrowUp': selectedEl = document.querySelector('li.fuzzyFinderMatchSelected'); selected = Number(selectedEl.id.substr(17)); next = (document.getElementById(`fuzzyFinderMatch-${selected-1}`)) ? selected-1: 0; nextEl = document.getElementById(`fuzzyFinderMatch-${next}`); selectedEl.removeAttribute("class"); nextEl.setAttribute("class", "fuzzyFinderMatchSelected"); e.preventDefault(); break; default: // Do nothing, input event will be triggered } }); this.search(""); this.input.focus(); } search(text) { let files = window.fsDisp.cwd; let i = 0; let results = files.filter(file => { if (i >= 5 || file.type === "showDisks" || file.type === "up") { return false; } else if (file.name.toLowerCase().includes(text.toLowerCase())) { i++ return true; } }); results.sort((a, b) => { if (a.name.toLowerCase().startsWith(text.toLowerCase()) && !b.name.toLowerCase().startsWith(text.toLowerCase())) { return -1; } else if (!a.name.toLowerCase().startsWith(text.toLowerCase()) && b.name.toLowerCase().startsWith(text.toLowerCase())) { return 1; } else { return 0; } }); if (results.length === 0) { this.results.innerHTML = `
  • No results
  • `; } let html = ""; results.forEach((file, i) => { html += `
  • ${file.name}
  • `; }); if (results.length !== 5) { for (let i = results.length; i < 5; i++) { html += "
  • "; } } this.results.innerHTML = html; } submit() { let file = document.querySelector("li.fuzzyFinderMatchSelected").innerText; if (file === "No results" || file.length <= 0) { this.disp.close(); return; } let filePath = path.resolve(window.fsDisp.dirpath, file); window.term[window.currentTerm].write(`'${filePath}'`); this.disp.close(); } } module.exports = { FuzzyFinder }; ================================================ FILE: src/classes/hardwareInspector.class.js ================================================ class HardwareInspector { constructor(parentId) { if (!parentId) throw "Missing parameters"; // Create DOM this.parent = document.getElementById(parentId); this._element = document.createElement("div"); this._element.setAttribute("id", "mod_hardwareInspector"); this._element.innerHTML = `

    MANUFACTURER

    NONE

    MODEL

    NONE

    CHASSIS

    NONE

    `; this.parent.append(this._element); this.updateInfo(); this.infoUpdater = setInterval(() => { this.updateInfo(); }, 20000); } updateInfo() { window.si.system().then(d => { window.si.chassis().then(e => { document.getElementById("mod_hardwareInspector_manufacturer").innerText = this._trimDataString(d.manufacturer); document.getElementById("mod_hardwareInspector_model").innerText = this._trimDataString(d.model, d.manufacturer, e.type); document.getElementById("mod_hardwareInspector_chassis").innerText = e.type; }); }); } _trimDataString(str, ...filters) { return str.trim().split(" ").filter(word => { if (typeof filters !== "object") return true; return !filters.includes(word); }).slice(0, 2).join(" "); } } module.exports = { HardwareInspector }; ================================================ FILE: src/classes/keyboard.class.js ================================================ class Keyboard { constructor(opts) { if (!opts.layout || !opts.container) throw "Missing options"; const layout = JSON.parse(require("fs").readFileSync(opts.layout, {encoding: "utf-8"})); this.ctrlseq = ["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", ""]; this.container = document.getElementById(opts.container); this.linkedToTerm = true; this.detach = () => { this.linkedToTerm = false; }; this.attach = () => { this.linkedToTerm = true; }; // Set default keyboard properties this.container.dataset.isShiftOn = false; this.container.dataset.isCapsLckOn = false; this.container.dataset.isAltOn = false; this.container.dataset.isCtrlOn = false; this.container.dataset.isFnOn = false; this.container.dataset.passwordMode = false; // Build arrays for enabling keyboard shortcuts this._shortcuts = { CtrlAltShift: [], CtrlAlt: [], CtrlShift: [], AltShift: [], Ctrl: [], Alt: [], Shift: [] }; window.shortcuts.forEach(scut => { let cut = Object.assign({}, scut); let mods = cut.trigger.split("+"); cut.trigger = mods.pop(); let order = ["Ctrl", "Alt", "Shift"]; mods.sort((a, b) => { return order.indexOf(a) - order.indexOf(b); }); let cat = mods.join(""); if (cut.type === "app" && cut.action === "TAB_X" && cut.trigger === "X") { for (let i = 1; i <= 5; i++) { let ncut = Object.assign({}, cut); ncut.trigger = `${i}`; ncut.action = `TAB_${i}`; this._shortcuts[cat].push(ncut); } } else { this._shortcuts[cat].push(cut); } }); // Parse keymap and create DOM Object.keys(layout).forEach(row => { this.container.innerHTML += `
    `; layout[row].forEach(keyObj => { let key = document.createElement("div"); key.setAttribute("class", "keyboard_key"); if (keyObj.cmd === " ") { key.setAttribute("id", "keyboard_spacebar"); } else if (keyObj.cmd === "\r") { key.setAttribute("class", "keyboard_key keyboard_enter"); key.innerHTML = `

    ${keyObj.name}

    `; } else { key.innerHTML = `
    ${keyObj.altshift_name || ""}

    ${keyObj.fn_name || ""}

    ${keyObj.alt_name || ""}

    ${keyObj.shift_name || ""}

    ${keyObj.name || ""}

    `; } // Icon support, overrides previously defined innerHTML // Arrow and other icons let icon = null; if (keyObj.name.startsWith("ESCAPED|-- ICON: ")) { keyObj.name = keyObj.name.substr(17); switch(keyObj.name) { case "ARROW_UP": icon = ``; break; case "ARROW_LEFT": icon = ``; break; case "ARROW_DOWN": icon = ``; break; case "ARROW_RIGHT": icon = ``; break; default: icon = ``; } key.innerHTML = icon; } Object.keys(keyObj).forEach(property => { for (let i = 1; i < this.ctrlseq.length; i++) { keyObj[property] = keyObj[property].replace("~~~CTRLSEQ"+i+"~~~", this.ctrlseq[i]); } if (property.endsWith("cmd")) { key.dataset[property] = keyObj[property]; } }); document.getElementById(row).appendChild(key); }); }); this.container.childNodes.forEach(row => { row.childNodes.forEach(key => { let enterElements = document.querySelectorAll(".keyboard_enter"); if (key.attributes["class"].value.endsWith("keyboard_enter")) { // The enter key is divided in two dom elements, so we bind their animations here key.onmousedown = e => { this.pressKey(key); key.holdTimeout = setTimeout(() => { key.holdInterval = setInterval(() => { this.pressKey(key); }, 70); }, 400); enterElements.forEach(key => { key.setAttribute("class", "keyboard_key active keyboard_enter"); }); // Keep focus on the terminal if (window.keyboard.linkedToTerm) window.term[window.currentTerm].term.focus(); if (this.container.dataset.passwordMode == "false") window.audioManager.granted.play(); e.preventDefault(); }; key.onmouseup = () => { clearTimeout(key.holdTimeout); clearInterval(key.holdInterval); enterElements.forEach(key => { key.setAttribute("class", "keyboard_key blink keyboard_enter"); }); setTimeout(() => { enterElements.forEach(key => { key.setAttribute("class", "keyboard_key keyboard_enter"); }); }, 100); }; } else { key.onmousedown = e => { if (/^ESCAPED\|-- (CTRL|SHIFT|ALT){1}.*/.test(key.dataset.cmd)) { let cmd = key.dataset.cmd.substr(11); if (cmd.startsWith("CTRL")) { this.container.dataset.isCtrlOn = "true"; } if (cmd.startsWith("SHIFT")) { this.container.dataset.isShiftOn = "true"; } if (cmd.startsWith("ALT")) { this.container.dataset.isAltOn = "true"; } } else { key.holdTimeout = setTimeout(() => { key.holdInterval = setInterval(() => { this.pressKey(key); }, 70); }, 400); this.pressKey(key); } // Keep focus on the terminal if (window.keyboard.linkedToTerm) window.term[window.currentTerm].term.focus(); if(this.container.dataset.passwordMode == "false") window.audioManager.stdin.play(); e.preventDefault(); }; key.onmouseup = e => { if (/^ESCAPED\|-- (CTRL|SHIFT|ALT){1}.*/.test(key.dataset.cmd)) { let cmd = key.dataset.cmd.substr(11); if (cmd.startsWith("CTRL")) { this.container.dataset.isCtrlOn = "false"; } if (cmd.startsWith("SHIFT")) { this.container.dataset.isShiftOn = "false"; } if (cmd.startsWith("ALT")) { this.container.dataset.isAltOn = "false"; } } else { clearTimeout(key.holdTimeout); clearInterval(key.holdInterval); } key.setAttribute("class", "keyboard_key blink"); setTimeout(() => { key.setAttribute("class", "keyboard_key"); }, 100); }; } // See #229 key.onmouseleave = () => { clearTimeout(key.holdTimeout); clearInterval(key.holdInterval); }; }); }); // Tactile multi-touch support (#100) this.container.addEventListener("touchstart", e => { e.preventDefault(); for (let i = 0; i < e.changedTouches.length; i++) { let key = e.changedTouches[i].target.parentElement; if (key.tagName === 'svg') key = key.parentElement; if (key.getAttribute("class").startsWith("keyboard_key")) { key.setAttribute("class", key.getAttribute("class")+" active"); key.onmousedown({preventDefault: () => {return true}}); } else { key = e.changedTouches[i].target; if (key.getAttribute("class").startsWith("keyboard_key")) { key.setAttribute("class", key.getAttribute("class")+" active"); key.onmousedown({preventDefault: () => {return true}}); } } } }); let dropKeyTouchHandler = e => { e.preventDefault(); for (let i = 0; i < e.changedTouches.length; i++) { let key = e.changedTouches[i].target.parentElement; if (key.tagName === 'svg') key = key.parentElement; if (key.getAttribute("class").startsWith("keyboard_key")) { key.setAttribute("class", key.getAttribute("class").replace("active", "")); key.onmouseup({preventDefault: () => {return true}}); } else { key = e.changedTouches[i].target; if (key.getAttribute("class").startsWith("keyboard_key")) { key.setAttribute("class", key.getAttribute("class").replace("active", "")); key.onmouseup({preventDefault: () => {return true}}); } } } }; this.container.addEventListener("touchend", dropKeyTouchHandler); this.container.addEventListener("touchcancel", dropKeyTouchHandler); // Bind actual keyboard actions to on-screen animations (for use without a touchscreen) let findKey = e => { // Fix incorrect querySelector error let physkey; (e.key === "\"") ? physkey = `\\"` : physkey = e.key; // Find basic keys (typically letters, upper and lower-case) let key = document.querySelector('div.keyboard_key[data-cmd="'+physkey+'"]'); if (key === null) key = document.querySelector('div.keyboard_key[data-shift_cmd="'+physkey+'"]'); // Find special keys (shift, control, arrows, etc.) if (key === null && e.code === "ShiftLeft") key = document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- SHIFT: LEFT"]'); if (key === null && e.code === "ShiftRight") key = document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- SHIFT: RIGHT"]'); if (key === null && e.code === "ControlLeft") key = document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- CTRL: LEFT"]'); if (key === null && e.code === "ControlRight") key = document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- CTRL: RIGHT"]'); if (key === null && e.code === "AltLeft") key = document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- FN: ON"]'); if (key === null && e.code === "AltRight") key = document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- ALT: RIGHT"]'); if (key === null && e.code === "CapsLock") key = document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- CAPSLCK: ON"]'); if (key === null && e.code === "Escape") key = document.querySelector('div.keyboard_key[data-cmd=""]'); if (key === null && e.code === "Backspace") key = document.querySelector('div.keyboard_key[data-cmd=""]'); if (key === null && e.code === "ArrowUp") key = document.querySelector('div.keyboard_key[data-cmd="OA"]'); if (key === null && e.code === "ArrowLeft") key = document.querySelector('div.keyboard_key[data-cmd="OD"]'); if (key === null && e.code === "ArrowDown") key = document.querySelector('div.keyboard_key[data-cmd="OB"]'); if (key === null && e.code === "ArrowRight") key = document.querySelector('div.keyboard_key[data-cmd="OC"]'); if (key === null && e.code === "Enter") key = document.querySelectorAll('div.keyboard_key.keyboard_enter'); // Find "rare" keys (ctrl and alt symbols) if (key === null) key = document.querySelector('div.keyboard_key[data-ctrl_cmd="'+e.key+'"]'); if (key === null) key = document.querySelector('div.keyboard_key[data-alt_cmd="'+e.key+'"]'); return key; }; this.keydownHandler = e => { // See #330 if (e.getModifierState("AltGraph") && e.code === "AltRight") { document.querySelector('div.keyboard_key[data-cmd="ESCAPED|-- CTRL: LEFT"]').setAttribute("class", "keyboard_key"); } // See #440 if (e.code === "ControlLeft" || e.code === "ControlRight") this.container.dataset.isCtrlOn = true; if (e.code === "ShiftLeft" || e.code === "ShiftRight") this.container.dataset.isShiftOn = true; if (e.code === "AltLeft" || e.code === "AltRight") this.container.dataset.isAltOn = true; if (e.code === "CapsLock" && this.container.dataset.isCapsLckOn !== "true") this.container.dataset.isCapsLckOn = true; if (e.code === "CapsLock" && this.container.dataset.isCapsLckOn === "true") this.container.dataset.isCapsLckOn = false; let key = findKey(e); if (key === null) return; if (key.length) { key.forEach(enterElement => { enterElement.setAttribute("class", "keyboard_key active keyboard_enter"); }); } else { key.setAttribute("class", "keyboard_key active"); } // See #516 if (e.repeat === false || (e.repeat === true && !e.code.startsWith('Shift') && !e.code.startsWith('Alt') && !e.code.startsWith('Control') && !e.code.startsWith('Caps'))) { if(this.container.dataset.passwordMode == "false") window.audioManager.stdin.play(); } }; document.onkeydown = this.keydownHandler; document.onkeyup = e => { // See #330 if (e.key === "Control" && e.getModifierState("AltGraph")) return; // See #440 if (e.code === "ControlLeft" || e.code === "ControlRight") this.container.dataset.isCtrlOn = false; if (e.code === "ShiftLeft" || e.code === "ShiftRight") this.container.dataset.isShiftOn = false; if (e.code === "AltLeft" || e.code === "AltRight") this.container.dataset.isAltOn = false; let key = findKey(e); if (key === null) return; if (key.length) { key.forEach(enterElement => { enterElement.setAttribute("class", "keyboard_key blink keyboard_enter"); }); setTimeout(() => { key.forEach(enterElement => { enterElement.setAttribute("class", "keyboard_key keyboard_enter"); }); }, 100); } else { key.setAttribute("class", "keyboard_key blink"); setTimeout(() => { key.setAttribute("class", "keyboard_key"); }, 100); } if(this.container.dataset.passwordMode == "false" && e.key === "Enter") window.audioManager.granted.play(); }; window.addEventListener("blur", () => { document.querySelectorAll("div.keyboard_key.active").forEach(key => { key.setAttribute("class", key.getAttribute("class").replace("active", "")); key.onmouseup({preventDefault: () => {return true}}); }); }); } pressKey(key) { let cmd = key.dataset.cmd || ""; // Keyboard shortcuts let shortcutsCat = ""; if (this.container.dataset.isCtrlOn === "true") shortcutsCat += "Ctrl"; if (this.container.dataset.isAltOn === "true") shortcutsCat += "Alt"; if (this.container.dataset.isShiftOn === "true") shortcutsCat += "Shift"; let shortcutsTriggered = false; if (shortcutsCat.length > 1) { this._shortcuts[shortcutsCat].forEach(cut => { if (!cut.enabled) return; let trig = cut.trigger.toLowerCase() .replace("plus", "+") .replace("space", " ") .replace("tab", "\t") .replace(/backspace|delete/, "\b") .replace(/esc|escape/, this.ctrlseq[1]) .replace(/return|enter/, "\r"); if (cmd !== trig) return; if (cut.type === "app") { window.useAppShortcut(cut.action); shortcutsTriggered = true; } else if (cut.type === "shell") { let fn = (cut.linebreak) ? writelr : write; window.term[window.currentTerm][fn](cut.action); } else { console.warn(`${cut.trigger} has unknown type`); } }); } if (shortcutsTriggered) return; // Modifiers if (this.container.dataset.isShiftOn === "true" && key.dataset.shift_cmd || this.container.dataset.isCapsLckOn === "true" && key.dataset.shift_cmd) cmd = key.dataset.shift_cmd; if (this.container.dataset.isCapsLckOn === "true" && key.dataset.capslck_cmd) cmd = key.dataset.capslck_cmd; if (this.container.dataset.isCtrlOn === "true" && key.dataset.ctrl_cmd) cmd = key.dataset.ctrl_cmd; if (this.container.dataset.isAltOn === "true" && key.dataset.alt_cmd) cmd = key.dataset.alt_cmd; if (this.container.dataset.isAltOn === "true" && this.container.dataset.isShiftOn === "true" && key.dataset.altshift_cmd) cmd = key.dataset.altshift_cmd; if (this.container.dataset.isFnOn === "true" && key.dataset.fn_cmd) cmd = key.dataset.fn_cmd; if (this.container.dataset.isNextCircum === "true") { cmd = this.addCircum(cmd); this.container.dataset.isNextCircum = "false"; } if (this.container.dataset.isNextTrema === "true") { cmd = this.addTrema(cmd); this.container.dataset.isNextTrema = "false"; } if (this.container.dataset.isNextAcute === "true") { cmd = this.addAcute(cmd); this.container.dataset.isNextAcute = "false"; } if (this.container.dataset.isNextGrave === "true") { cmd = this.addGrave(cmd); this.container.dataset.isNextGrave = "false"; } if (this.container.dataset.isNextCaron === "true") { cmd = this.addCaron(cmd); this.container.dataset.isNextCaron = "false"; } if (this.container.dataset.isNextBar === "true") { cmd = this.addBar(cmd); this.container.dataset.isNextBar = "false"; } if (this.container.dataset.isNextBreve === "true") { cmd = this.addBreve(cmd); this.container.dataset.isNextBreve = "false"; } if (this.container.dataset.isNextTilde === "true") { cmd = this.addTilde(cmd); this.container.dataset.isNextTilde = "false"; } if (this.container.dataset.isNextMacron === "true") { cmd = this.addMacron(cmd); this.container.dataset.isNextMacron = "false"; } if (this.container.dataset.isNextCedilla === "true") { cmd = this.addCedilla(cmd); this.container.dataset.isNextCedilla = "true"; } if (this.container.dataset.isNextOverring === "true") { cmd = this.addOverring(cmd); this.container.dataset.isNextOverring = "false"; } if (this.container.dataset.isNextGreek === "true") { cmd = this.toGreek(cmd); this.container.dataset.isNextGreek = "false"; } if (this.container.dataset.isNextIotasub === "true") { cmd = this.addIotasub(cmd); this.container.dataset.isNextIotasub = "false"; } // Escaped commands if (cmd.startsWith("ESCAPED|-- ")) { cmd = cmd.substr(11); switch(cmd) { case "CAPSLCK: ON": this.container.dataset.isCapsLckOn = "true"; return true; case "CAPSLCK: OFF": this.container.dataset.isCapsLckOn = "false"; return true; case "FN: ON": this.container.dataset.isFnOn = "true"; return true; case "FN: OFF": this.container.dataset.isFnOn = "false"; return true; case "CIRCUM": this.container.dataset.isNextCircum = "true"; return true; case "TREMA": this.container.dataset.isNextTrema = "true"; return true; case "ACUTE": this.container.dataset.isNextAcute = "true"; return true; case "GRAVE": this.container.dataset.isNextGrave = "true"; return true; case "CARON": this.container.dataset.isNextCaron = "true"; return true; case "BAR": this.container.dataset.isNextBar = "true"; return true; case "BREVE": this.container.dataset.isNextBreve = "true"; return true; case "TILDE": this.container.dataset.isNextTilde = "true"; return true; case "MACRON": this.container.dataset.isNextMacron = "true"; return true; case "CEDILLA": this.container.dataset.isNextCedilla = "true"; return true; case "OVERRING": this.container.dataset.isNextOverring = "true"; return true; case "GREEK": this.container.dataset.isNextGreek = "true"; return true; case "IOTASUB": this.container.dataset.isNextIotasub = "true"; return true; } } if (cmd === "\n") { if (window.keyboard.linkedToTerm) { window.term[window.currentTerm].writelr(""); } else { document.activeElement.dispatchEvent(new CustomEvent("change", {detail: "enter" })); } return true; } if (window.keyboard.linkedToTerm) { window.term[window.currentTerm].write(cmd); } else { let isDelete = false; if (typeof document.activeElement.value !== "undefined") { switch(cmd) { case "": document.activeElement.value = document.activeElement.value.slice(0, -1); isDelete = true; break; case "OD": document.activeElement.selectionStart--; document.activeElement.selectionEnd = document.activeElement.selectionStart; break; case "OC": document.activeElement.selectionEnd++; document.activeElement.selectionStart = document.activeElement.selectionEnd; break; default: if (this.ctrlseq.indexOf(cmd.slice(0, 1)) !== -1) { // Prevent trying to write other control sequences } else { document.activeElement.value = document.activeElement.value+cmd; } } } // Emulate oninput events document.activeElement.dispatchEvent(new CustomEvent("input", {detail: ((isDelete)? "delete" : "insert") })); document.activeElement.focus(); } } togglePasswordMode() { let d = this.container.dataset.passwordMode; (d === "true") ? d = "false" : d = "true"; this.container.dataset.passwordMode = d; window.passwordMode = d; return d; } addCircum(char) { switch(char) { case "a": return "â"; case "A": return "Â"; case "z": return "ẑ"; case "Z": return "Ẑ"; case "e": return "ê"; case "E": return "Ê"; case "y": return "ŷ"; case "Y": return "Ŷ"; case "u": return "û"; case "U": return "Û"; case "i": return "î"; case "I": return "Î"; case "o": return "ô"; case "O": return "Ô"; case "s": return "ŝ"; case "S": return "Ŝ"; case "g": return "ĝ"; case "G": return "Ĝ"; case "h": return "ĥ"; case "H": return "Ĥ"; case "j": return "ĵ"; case "J": return "Ĵ"; case "w": return "ŵ"; case "W": return "Ŵ"; case "c": return "ĉ"; case "C": return "Ĉ"; // the circumflex can also be used for superscript numbers case "1": return "¹"; case "2": return "²"; case "3": return "³"; case "4": return "⁴"; case "5": return "⁵"; case "6": return "⁶"; case "7": return "⁷"; case "8": return "⁸"; case "9": return "⁹"; case "0": return "⁰"; default: return char; } } addTrema(char) { switch(char) { case "a": return "ä"; case "A": return "Ä"; case "e": return "ë"; case "E": return "Ë"; case "t": return "ẗ"; // My keyboard says no uppercase ẗ case "y": return "ÿ"; case "Y": return "Ÿ"; case "u": return "ü"; case "U": return "Ü"; case "i": return "ï"; case "I": return "Ï"; case "o": return "ö"; case "O": return "Ö"; case "h": return "ḧ"; case "H": return "Ḧ"; case "w": return "ẅ"; case "W": return "Ẅ"; case "x": return "ẍ"; case "X": return "Ẍ"; default: return char; } } addAcute(char) { switch(char) { case "a": return "á"; case "A": return "Á"; case "c": return "ć"; case "C": return "Ć"; case "e": return "é"; case "E": return "E"; case "g": return "ǵ"; case "G": return "Ǵ"; case "i": return "í"; case "I": return "Í"; case "j": return "ȷ́"; case "J": return "J́"; case "k": return "ḱ"; case "K": return "Ḱ"; case "l": return "ĺ"; case "L": return "Ĺ"; case "m": return "ḿ"; case "M": return "Ḿ"; case "n": return "ń"; case "N": return "Ń"; case "o": return "ó"; case "O": return "Ó"; case "p": return "ṕ"; case "P": return "Ṕ"; case "r": return "ŕ"; case "R": return "Ŕ"; case "s": return "ś"; case "S": return "Ś"; case "u": return "ú"; case "U": return "Ú"; case "v": return "v́"; case "V": return "V́"; case "w": return "ẃ"; case "W": return "Ẃ"; case "y": return "ý"; case "Y": return "Ý"; case "z": return "ź"; case "Z": return "Ź"; case "ê": return "ế"; case "Ê": return "Ế"; case "ç": return "ḉ"; case "Ç": return "Ḉ"; default: return char; } } addGrave(char) { switch (char) { case "a": return "à"; case "A": return "À"; case "e": return "è"; case "E": return "È"; case "i": return "ì"; case "I": return "Ì"; case "m": return "m̀"; case "M": return "M̀"; case "n": return "ǹ"; case "N": return "Ǹ"; case "o": return "ò"; case "O": return "Ò"; case "u": return "ù"; case "U": return "Ù"; case "v": return "v̀"; case "V": return "V̀"; case "w": return "ẁ"; case "W": return "Ẁ"; case "y": return "ỳ"; case "Y": return "Ỳ"; case "ê": return "ề"; case "Ê": return "Ề"; default: return char; } } addCaron(char) { switch (char) { case "a": return "ǎ"; case "A": return "Ǎ"; case "c": return "č"; case "C": return "Č"; case "d": return "ď"; case "D": return "Ď"; case "e": return "ě"; case "E": return "Ě"; case "g": return "ǧ"; case "G": return "Ǧ"; case "h": return "ȟ"; case "H": return "Ȟ"; case "i": return "ǐ"; case "I": return "Ǐ"; case "j": return "ǰ"; case "k": return "ǩ"; case "K": return "Ǩ"; case "l": return "ľ"; case "L": return "Ľ"; case "n": return "ň"; case "N": return "Ň"; case "o": return "ǒ"; case "O": return "Ǒ"; case "r": return "ř"; case "R": return "Ř"; case "s": return "š"; case "S": return "Š"; case "t": return "ť"; case "T": return "Ť"; case "u": return "ǔ"; case "U": return "Ǔ"; case "z": return "ž"; case "Z": return "Ž"; // caron can also be used for subscript numbers case "1": return "₁"; case "2": return "₂"; case "3": return "₃"; case "4": return "₄"; case "5": return "₅"; case "6": return "₆"; case "7": return "₇"; case "8": return "₈"; case "9": return "₉"; case "0": return "₀"; default: return char; } } addBar(char) { switch (char) { case "a": return "ⱥ"; case "A": return "Ⱥ"; case "b": return "ƀ"; case "B": return "Ƀ"; case "c": return "ȼ"; case "C": return "Ȼ"; case "d": return "đ"; case "D": return "Đ"; case "e": return "ɇ"; case "E": return "Ɇ"; case "g": return "ǥ"; case "G": return "Ǥ"; case "h": return "ħ"; case "H": return "Ħ"; case "i": return "ɨ"; case "I": return "Ɨ"; case "j": return "ɉ"; case "J": return "Ɉ"; case "l": return "ł"; case "L": return "Ł"; case "o": return "ø"; case "O": return "Ø"; case "p": return "ᵽ"; case "P": return "Ᵽ"; case "r": return "ɍ"; case "R": return "Ɍ"; case "t": return "ŧ"; case "T": return "Ŧ"; case "u": return "ʉ"; case "U": return "Ʉ"; case "y": return "ɏ"; case "Y": return "Ɏ"; case "z": return "ƶ"; case "Z": return "Ƶ"; default: return char; } } addBreve(char) { switch (char) { case "a": return "ă"; case "A": return "Ă"; case "e": return "ĕ"; case "E": return "Ĕ"; case "g": return "ğ"; case "G": return "Ğ"; case "i": return "ĭ"; case "I": return "Ĭ"; case "o": return "ŏ"; case "O": return "Ŏ"; case "u": return "ŭ"; case "U": return "Ŭ"; case "à": return "ằ"; case "À": return "Ằ"; default: return char; } } addTilde(char) { switch (char) { case "a": return "ã"; case "A": return "Ã"; case "e": return "ẽ"; case "E": return "Ẽ"; case "i": return "ĩ"; case "I": return "Ĩ"; case "n": return "ñ"; case "N": return "Ñ"; case "o": return "õ"; case "O": return "Õ"; case "u": return "ũ"; case "U": return "Ũ"; case "v": return "ṽ"; case "V": return "Ṽ"; case "y": return "ỹ"; case "Y": return "Ỹ"; case "ê": return "ễ"; case "Ê": return "Ễ"; default: return char; } } addMacron(char) { switch (char) { case "a": return "ā"; case "A": return "Ā"; case "e": return "ē"; case "E": return "Ē"; case "g": return "ḡ"; case "G": return "Ḡ"; case "i": return "ī"; case "I": return "Ī"; case "o": return "ō"; case "O": return "Ō"; case "u": return "ū"; case "U": return "Ū"; case "y": return "ȳ"; case "Y": return "Ȳ"; case "é": return "ḗ"; case "É": return "Ḗ"; case "è": return "ḕ"; case "È": return "Ḕ"; default: return char; } } addCedilla(char) { switch (char) { case "c": return "ç"; case "C": return "Ç"; case "d": return "ḑ"; case "D": return "Ḑ"; case "e": return "ȩ"; case "E": return "Ȩ"; case "g": return "ģ"; case "G": return "Ģ"; case "h": return "ḩ"; case "H": return "Ḩ"; case "k": return "ķ"; case "K": return "Ķ"; case "l": return "ļ"; case "L": return "Ļ"; case "n": return "ņ"; case "N": return "Ņ"; case "r": return "ŗ"; case "R": return "Ŗ"; case "s": return "ş"; case "S": return "Ş"; case "t": return "ţ"; case "T": return "Ţ"; default: return char; } } addOverring(char) { switch (char) { case "a": return "å"; case "A": return "Å"; case "u": return "ů"; case "U": return "Ů"; case "w": return "ẘ"; // capital w with overring not supported on bépo layout apparently case "y": return "ẙ"; // same for capital y with overring default: return char; } } toGreek(char) { switch (char) { case "b": return "β"; case "p": return "π"; case "P": return "Π"; case "d": return "δ"; case "D": return "Δ"; case "l": return "λ"; case "L": return "Λ"; case "j": return "θ"; case "J": return "Θ"; case "z": return "ζ"; case "w": return "ω"; case "W": return "Ω"; case "A": return "α"; case "u": return "υ"; case "U": return "Υ"; case "i": return "ι"; case "e": return "ε"; case "t": return "τ"; case "s": return "σ"; case "S": return "Σ"; case "r": return "ρ"; case "R": return "Ρ"; case "n": return "ν"; case "m": return "μ"; case "y": return "ψ"; case "Y": return "Ψ"; case "x": return "ξ"; case "X": return "Ξ"; case "k": return "κ"; case "q": return "χ"; case "Q": return "Χ"; case "g": return "γ"; case "G": return "Γ"; case "h": return "η"; case "f": return "φ"; case "F": return "Φ"; default: return char; } } addIotasub(char) { switch (char) { case "o": return "ǫ"; case "O": return "Ǫ"; case "a": return "ą"; case "A": return "Ą"; case "u": return "ų"; case "U": return "Ų"; case "i": return "į"; case "I": return "Į"; case "e": return "ę"; case "E": return "Ę"; default: return char; } } } module.exports = { Keyboard }; ================================================ FILE: src/classes/locationGlobe.class.js ================================================ class LocationGlobe { constructor(parentId) { if (!parentId) throw "Missing parameters"; const path = require("path"); this._geodata = require(path.join(__dirname, "assets/misc/grid.json")); require(path.join(__dirname, "assets/vendor/encom-globe.js")); this.ENCOM = window.ENCOM; // Create DOM and include lib this.parent = document.getElementById(parentId); this.parent.innerHTML += `

    WORLD VIEWGLOBAL NETWORK MAP

    ENDPOINT LAT/LON0.0000, 0.0000

    OFFLINE

    `; this.lastgeo = {}; this.conns = []; setTimeout(() => { let container = document.getElementById("mod_globe_innercontainer"); let placeholder = document.getElementById("mod_globe_canvas_placeholder"); // Create Globe this.globe = new this.ENCOM.Globe(placeholder.offsetWidth, placeholder.offsetHeight, { font: window.theme.cssvars.font_main, data: [], tiles: this._geodata.tiles, baseColor: window.theme.globe.base || `rgb(${window.theme.r},${window.theme.g},${window.theme.b})`, markerColor: window.theme.globe.marker || `rgb(${window.theme.r},${window.theme.g},${window.theme.b})`, pinColor: window.theme.globe.pin || `rgb(${window.theme.r},${window.theme.g},${window.theme.b})`, satelliteColor: window.theme.globe.satellite || `rgb(${window.theme.r},${window.theme.g},${window.theme.b})`, scale: 1.1, viewAngle: 0.630, dayLength: 1000 * 45, introLinesDuration: 2000, introLinesColor: window.theme.globe.marker || `rgb(${window.theme.r},${window.theme.g},${window.theme.b})`, maxPins: 300, maxMarkers: 100 }); // Place Globe placeholder.remove(); container.append(this.globe.domElement); // Init animations this._animate = () => { if (window.mods.globe.globe) { window.mods.globe.globe.tick(); } if (window.mods.globe._animate) { setTimeout(() => { try { requestAnimationFrame(window.mods.globe._animate); } catch(e) { // We probably got caught in a theme change. Print it out but everything should keep running fine. console.warn(e); } }, 1000 / 30); } }; this.globe.init(window.theme.colors.light_black, () => { this._animate(); window.audioManager.scan.play(); }); // resize handler this.resizeHandler = () => { let canvas = document.querySelector("div#mod_globe canvas"); window.mods.globe.globe.camera.aspect = canvas.offsetWidth / canvas.offsetHeight; window.mods.globe.globe.camera.updateProjectionMatrix(); window.mods.globe.globe.renderer.setSize(canvas.offsetWidth, canvas.offsetHeight); }; window.addEventListener("resize", this.resizeHandler); // Connections this.conns = []; this.addConn = ip => { let data = null; try { data = window.mods.netstat.geoLookup.get(ip); } catch { // do nothing } let geo = (data !== null ? data.location : {}); if (geo.latitude && geo.longitude) { const lat = Number(geo.latitude); const lon = Number(geo.longitude); window.mods.globe.conns.push({ ip, pin: window.mods.globe.globe.addPin(lat, lon, "", 1.2), }); } }; this.removeConn = ip => { let index = this.conns.findIndex(x => x.ip === ip); this.conns[index].pin.remove(); this.conns.splice(index, 1); }; // Add random satellites let constellation = []; for(var i = 0; i< 2; i++){ for(var j = 0; j< 3; j++){ constellation.push({ lat: 50 * i - 30 + 15 * Math.random(), lon: 120 * j - 120 + 30 * i, altitude: Math.random() * (1.7 - 1.3) + 1.3 }); } } this.globe.addConstellation(constellation); }, 2000); // Init updaters when intro animation is done setTimeout(() => { this.updateLoc(); this.locUpdater = setInterval(() => { this.updateLoc(); }, 1000); this.updateConns(); this.connsUpdater = setInterval(() => { this.updateConns(); }, 3000); }, 4000); } addRandomConnectedMarkers() { const randomLat = this.getRandomInRange(40, 90, 3); const randomLong = this.getRandomInRange(-180, 0, 3); this.globe.addMarker(randomLat, randomLong, ''); this.globe.addMarker(randomLat - 20, randomLong + 150, '', true); } addTemporaryConnectedMarker(ip) { let data = window.mods.netstat.geoLookup.get(ip); let geo = (data !== null ? data.location : {}); if (geo.latitude && geo.longitude) { const lat = Number(geo.latitude); const lon = Number(geo.longitude); window.mods.globe.conns.push({ ip, pin: window.mods.globe.globe.addPin(lat, lon, "", 1.2) }); let mark = window.mods.globe.globe.addMarker(lat, lon, '', true); setTimeout(() => { mark.remove(); }, 3000); } } removeMarkers() { this.globe.markers.forEach(marker => { marker.remove(); }); this.globe.markers = []; } removePins() { this.globe.pins.forEach(pin => { pin.remove(); }); this.globe.pins = []; } getRandomInRange(from, to, fixed) { return (Math.random() * (to - from) + from).toFixed(fixed) * 1; } updateLoc() { if (window.mods.netstat.offline) { document.querySelector("div#mod_globe").setAttribute("class", "offline"); document.querySelector("i.mod_globe_headerInfo").innerText = "(OFFLINE)"; this.removePins(); this.removeMarkers(); this.conns = []; this.lastgeo = { latitude: 0, longitude: 0 }; } else { this.updateConOnlineConnection().then(() => { document.querySelector("div#mod_globe").setAttribute("class", ""); }).catch(() => { document.querySelector("i.mod_globe_headerInfo").innerText = "UNKNOWN"; }) } } async updateConOnlineConnection() { let newgeo = window.mods.netstat.ipinfo.geo; newgeo.latitude = Math.round(newgeo.latitude*10000)/10000; newgeo.longitude = Math.round(newgeo.longitude*10000)/10000; if (newgeo.latitude !== this.lastgeo.latitude || newgeo.longitude !== this.lastgeo.longitude) { document.querySelector("i.mod_globe_headerInfo").innerText = `${newgeo.latitude}, ${newgeo.longitude}`; this.removePins(); this.removeMarkers(); //this.addRandomConnectedPoints(); this.conns = []; this._locPin = this.globe.addPin(newgeo.latitude, newgeo.longitude, "", 1.2); this._locMarker = this.globe.addMarker(newgeo.latitude, newgeo.longitude, "", false, 1.2); } this.lastgeo = newgeo; document.querySelector("div#mod_globe").setAttribute("class", ""); } updateConns() { if (!window.mods.globe.globe || window.mods.netstat.offline) return false; window.si.networkConnections().then(conns => { let newconns = []; conns.forEach(conn => { let ip = conn.peeraddress; let state = conn.state; if (state === "ESTABLISHED" && ip !== "0.0.0.0" && ip !== "127.0.0.1" && ip !== "::") { newconns.push(ip); } }); this.conns.forEach(conn => { if (newconns.indexOf(conn.ip) !== -1) { newconns.splice(newconns.indexOf(conn.ip), 1); } else { this.removeConn(conn.ip); } }); newconns.forEach(ip => { this.addConn(ip); }); }); } } module.exports = { LocationGlobe }; ================================================ FILE: src/classes/mediaPlayer.class.js ================================================ class MediaPlayer { constructor(opts) { const modalElementId = "modal_" + opts.modalId; const type = opts.type; const icons = require("./assets/icons/file-icons.json"); const iconcolor = `rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b})`; const mediaContainer = document.getElementById(modalElementId).querySelector(".media_container"); const media = document.getElementById(modalElementId).querySelector(type); const mediaControls = document.getElementById(modalElementId).querySelector(".media_controls"); const playpause = document.getElementById(modalElementId).querySelector(".playpause"); const volumeIcon = document.getElementById(modalElementId).querySelector(".volume_icon"); const volume = document.getElementById(modalElementId).querySelector(".volume"); const volumeBar = document.getElementById(modalElementId).querySelector(".volume_bar"); const progress = document.getElementById(modalElementId).querySelector(".progress"); const progressBar = document.getElementById(modalElementId).querySelector(".progress_bar"); const fullscreen = document.getElementById(modalElementId).querySelector(".fs"); const mediaTime = document.getElementById(modalElementId).querySelector(".media_time"); let volumeDrag = false; let fullscreenVisible = true; let fullscreenTimeout; media.controls = false; mediaControls.setAttribute("data-state", "visible"); this.changeButtonState = (type) => { if (media.paused || media.ended) { playpause.setAttribute("data-state", "play"); playpause.innerHTML = ` ${icons["play"].svg} `; } else { playpause.setAttribute("data-state", "pause"); playpause.innerHTML = ` ${icons["pause"].svg} `; } }; this.setFullscreenData = (state) => { if (fullscreen === null) { return; } mediaContainer.setAttribute("data-fullscreen", !!state); fullscreen.setAttribute("data-state", !!state ? "cancel-fullscreen" : "go-fullscreen"); const buttonIcon = !!state ? "fullscreen-exit" : "fullscreen"; fullscreen.innerHTML = ` ${icons[buttonIcon].svg} `; }; this.handleFullscreen = () => { if (document.fullscreenElement) { document.exitFullscreen(); this.setFullscreenData(false); mediaContainer.removeEventListener('mousemove', this.handleFullscreenControls); fullscreenVisible = true; clearTimeout(fullscreenTimeout); this.fullscreenVisible(); } else { mediaContainer.requestFullscreen(); this.setFullscreenData(true); fullscreenVisible = false; this.fullscreenHidden(); mediaContainer.addEventListener('mousemove', this.handleFullscreenControls); } }; this.handleFullscreenControls = () => { if (!fullscreenVisible) { fullscreenVisible = true this.fullscreenVisible(); clearTimeout(fullscreenTimeout); fullscreenTimeout = setTimeout(() => { fullscreenVisible = false; this.fullscreenHidden(); }, 2000); } }; this.fullscreenHidden = () => { mediaContainer.style.cursor = "none"; mediaControls.classList.add("fullscreen_hidden"); }; this.fullscreenVisible = () => { mediaContainer.style.cursor = "default"; mediaControls.classList.remove("fullscreen_hidden"); }; this.mediaTimeToHMS = (time) => { let seconds = parseInt(time) const hours = parseInt(seconds / 3600); seconds = seconds % 3600; const minutes = parseInt(seconds / 60); seconds = seconds % 60; return (hours < 10 ? "0" : "") + hours + ":" + (minutes < 10 ? "0" : "") + minutes + ":" + (seconds < 10 ? "0" : "") + seconds; }; this.updateVolume = (x) => { let vol = (x - (volumeBar.offsetLeft + volumeBar.offsetParent.offsetLeft)) / volumeBar.clientWidth; if (vol > 1) { vol = 1; } if (vol < 0) { vol = 0; } volumeBar.style.clip = "rect(0px, " + ((vol * 100) / 20) + "vw,2vh,0px)"; media.volume = vol; this.updateVolumeIcon(vol); }; this.updateVolumeIcon = (vol) => { let icon = (vol > 0) ? "volume" : "mute"; volumeIcon.innerHTML = ` ${icons[icon].svg} `; }; media.addEventListener("loadedmetadata", () => { mediaTime.textContent = "00:00:00"; }); media.addEventListener("play", () => { this.changeButtonState("playpause") }, false); media.addEventListener("pause", () => { this.changeButtonState("playpause") }, false); media.addEventListener("timeupdate", () => { progressBar.style.width = Math.floor((media.currentTime / media.duration) * 100) + "%"; mediaTime.textContent = this.mediaTimeToHMS(media.currentTime); }); volume.addEventListener("mousedown", (e) => { volumeDrag = true; media.muted = false; this.updateVolume(e.pageX); }); volumeIcon.addEventListener("click", () => { media.muted = !media.muted; if (media.muted) { let icon = "mute"; volumeIcon.innerHTML = ` ${icons[icon].svg} `; } else { this.updateVolumeIcon(media.volume); } }); progress.addEventListener("click", function(e) { const pos = (e.pageX - (this.offsetLeft + this.offsetParent.offsetLeft)) / this.offsetWidth; media.currentTime = pos * media.duration; }); playpause.addEventListener("click", () => { (media.paused || media.ended) ? media.play(): media.pause(); }); if (fullscreen) fullscreen.addEventListener("click", () => { this.handleFullscreen() }); document.addEventListener("fullscreenchange", () => { this.setFullscreenData(!!(document.fullscreenElement)); }); document.addEventListener("mouseup", (e) => { if (volumeDrag) { volumeDrag = false; this.updateVolume(e.pageX); } }); document.addEventListener("mousemove", (e) => { if (volumeDrag) { this.updateVolume(e.pageX); } }); } } module.exports = { MediaPlayer }; ================================================ FILE: src/classes/modal.class.js ================================================ window.modals = {}; class Modal { constructor(options, onclose) { if (!options || !options.type) throw "Missing parameters"; this.type = options.type; this.id = require("nanoid").nanoid(); while (typeof window.modals[this.id] !== "undefined") { this.id = require("nanoid")(); } this.title = options.title || options.type || "Modal window"; this.message = options.message || "Lorem ipsum dolor sit amet."; this.onclose = onclose; this.classes = "modal_popup"; let buttons = []; let augs = []; let zindex = 0; // Reserve a slot in window.modals window.modals[this.id] = {}; switch(this.type) { case "error": this.classes += " error"; zindex = 1500; buttons.push({label:"PANIC", action:"window.modals['"+this.id+"'].close();"}, {label:"RELOAD", action:"window.location.reload(true);"}); augs.push("tr-clip", "bl-rect", "r-clip"); break; case "warning": this.classes += " warning"; zindex = 1000; buttons.push({label:"OK", action:"window.modals['"+this.id+"'].close();"}); augs.push("bl-clip", "tr-clip", "r-rect", "b-rect"); break; case "custom": this.classes += " info custom"; zindex = 500; buttons = options.buttons || []; buttons.push({label:"Close", action:"window.modals['"+this.id+"'].close();"}); augs.push("tr-clip", "bl-clip"); break; default: this.classes += " info"; zindex = 500; buttons.push({label:"OK", action:"window.modals['"+this.id+"'].close();"}); augs.push("tr-clip", "bl-clip"); break; } let DOMstring = ``; this.close = () => { let modalElement = document.getElementById("modal_"+this.id); modalElement.setAttribute("class", "modal_popup "+this.type+" blink"); window.audioManager.denied.play(); setTimeout(() => { modalElement.remove(); delete window.modals[this.id]; }, 100); if (typeof this.onclose === "function") { this.onclose(); } }; this.focus = () => { let modalElement = document.getElementById("modal_"+this.id); modalElement.setAttribute("class", this.classes+" focus"); Object.keys(window.modals).forEach(id => { if (id === this.id) return; window.modals[id].unfocus(); }); }; this.unfocus = () => { let modalElement = document.getElementById("modal_"+this.id); modalElement.setAttribute("class", this.classes); }; let tmp = document.createElement("div"); tmp.innerHTML = DOMstring; let element = tmp.firstChild; element.addEventListener("mousedown", () => { this.focus(); }); element.addEventListener("touchstart", () => { this.focus(); }); switch(this.type) { case "error": window.audioManager.error.play(); break; case "warning": window.audioManager.alarm.play(); break; default: window.audioManager.info.play(); break; } window.modals[this.id] = this; document.body.appendChild(element); this.focus(); // Allow dragging the modal around let draggedModal = document.getElementById(`modal_${this.id}`); let dragTarget = document.querySelector(`div#modal_${this.id} > h1:first-child`); draggedModal.zindex = draggedModal.getAttribute("style"); // Wait for correct rendering of medias and such before calculating rect size setTimeout(() => { let rect = draggedModal.getBoundingClientRect(); draggedModal.posX = rect.left; draggedModal.posY = rect.top; }, 500); // Mouse function modalMousedownHandler(e) { draggedModal.lastMouseX = e.clientX; draggedModal.lastMouseY = e.clientY; draggedModal.setAttribute("style", `${draggedModal.zindex}background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.5);left: ${draggedModal.posX}px;top: ${draggedModal.posY}px;`); window.addEventListener("mousemove", modalMousemoveHandler); window.addEventListener("mouseup", modalMouseupHandler); } function modalMousemoveHandler(e) { draggedModal.posX = draggedModal.posX + (e.clientX - draggedModal.lastMouseX); draggedModal.posY = draggedModal.posY + (e.clientY - draggedModal.lastMouseY); draggedModal.lastMouseX = e.clientX; draggedModal.lastMouseY = e.clientY; draggedModal.setAttribute("style", `${draggedModal.zindex}background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.5);left: ${draggedModal.posX}px;top: ${draggedModal.posY}px;`); } function modalMouseupHandler(e) { window.removeEventListener("mousemove", modalMousemoveHandler); draggedModal.setAttribute("style", `${draggedModal.zindex}left: ${draggedModal.posX}px;top: ${draggedModal.posY}px;`); window.removeEventListener("mouseup", modalMouseupHandler); } dragTarget.addEventListener("mousedown", modalMousedownHandler); // Touch function modalTouchstartHandler(e) { draggedModal.lastMouseX = e.changedTouches[0].clientX; draggedModal.lastMouseY = e.changedTouches[0].clientY; draggedModal.setAttribute("style", `${draggedModal.zindex}background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.5);left: ${draggedModal.posX}px;top: ${draggedModal.posY}px;`); window.addEventListener("touchmove", modalTouchmoveHandler); window.addEventListener("touchend", modalTouchendHandler); } function modalTouchmoveHandler(e) { draggedModal.posX = draggedModal.posX + (e.changedTouches[0].clientX - draggedModal.lastMouseX); draggedModal.posY = draggedModal.posY + (e.changedTouches[0].clientY - draggedModal.lastMouseY); draggedModal.lastMouseX = e.changedTouches[0].clientX; draggedModal.lastMouseY = e.changedTouches[0].clientY; draggedModal.setAttribute("style", `${draggedModal.zindex}background: rgba(var(--color_r), var(--color_g), var(--color_b), 0.5);left: ${draggedModal.posX}px;top: ${draggedModal.posY}px;`); } function modalTouchendHandler(e) { window.removeEventListener("touchmove", modalTouchmoveHandler); draggedModal.setAttribute("style", `${draggedModal.zindex}left: ${draggedModal.posX}px;top: ${draggedModal.posY}px;`); window.removeEventListener("touchend", modalTouchendHandler); } dragTarget.addEventListener("touchstart", modalTouchstartHandler); return this.id; } } module.exports = { Modal }; ================================================ FILE: src/classes/netstat.class.js ================================================ class Netstat { constructor(parentId) { if (!parentId) throw "Missing parameters"; // Create DOM this.parent = document.getElementById(parentId); this.parent.innerHTML += `

    NETWORK STATUS

    STATE

    UNKNOWN

    IPv4

    --.--.--.--

    PING

    --ms

    `; this.offline = false; this.lastconn = {finished: false}; // Prevent geoip lookup attempt until maxminddb is loaded this.iface = null; this.failedAttempts = {}; this.runsBeforeGeoIPUpdate = 0; this._httpsAgent = new require("https").Agent({ keepAlive: false, maxSockets: 10 }); // Init updaters this.updateInfo(); this.infoUpdater = setInterval(() => { this.updateInfo(); }, 2000); // Init GeoIP integrated backend this.geoLookup = { get: () => null }; let geolite2 = require("geolite2-redist"); let maxmind = require("maxmind"); geolite2.downloadDbs(require("path").join(require("@electron/remote").app.getPath("userData"), "geoIPcache")).then(() => { geolite2.open('GeoLite2-City', path => { return maxmind.open(path); }).catch(e => {throw e}).then(lookup => { this.geoLookup = lookup; this.lastconn.finished = true; }); }); } updateInfo() { window.si.networkInterfaces().then(async data => { let offline = false; let net = data[0]; let netID = 0; if (typeof window.settings.iface === "string") { while (net.iface !== window.settings.iface) { netID++; if (data[netID]) { net = data[netID]; } else { // No detected interface has the custom iface name, fallback to automatic detection on next loop window.settings.iface = false; return false; } } } else { // Find the first external, IPv4 connected networkInterface that has a MAC address set while (net.operstate !== "up" || net.internal === true || net.ip4 === "" || net.mac === "") { netID++; if (data[netID]) { net = data[netID]; } else { // No external connection! this.iface = null; document.getElementById("mod_netstat_iname").innerText = "Interface: (offline)"; this.offline = true; document.querySelector("#mod_netstat_innercontainer > div:first-child > h2").innerHTML = "OFFLINE"; document.querySelector("#mod_netstat_innercontainer > div:nth-child(2) > h2").innerHTML = "--.--.--.--"; document.querySelector("#mod_netstat_innercontainer > div:nth-child(3) > h2").innerHTML = "--ms"; break; } } } if (net.ip4 !== this.internalIPv4) this.runsBeforeGeoIPUpdate = 0; this.iface = net.iface; this.internalIPv4 = net.ip4; document.getElementById("mod_netstat_iname").innerText = "Interface: "+net.iface; if (net.ip4 === "127.0.0.1") { offline = true; } else { if (this.runsBeforeGeoIPUpdate === 0 && this.lastconn.finished) { this.lastconn = require("https").get({host: "myexternalip.com", port: 443, path: "/json", localAddress: net.ip4, agent: this._httpsAgent}, res => { let rawData = ""; res.on("data", chunk => { rawData += chunk; }); res.on("end", () => { try { let data = JSON.parse(rawData); this.ipinfo = { ip: data.ip, geo: this.geoLookup.get(data.ip).location }; let ip = this.ipinfo.ip; document.querySelector("#mod_netstat_innercontainer > div:nth-child(2) > h2").innerHTML = window._escapeHtml(ip); this.runsBeforeGeoIPUpdate = 10; } catch(e) { this.failedAttempts[e] = (this.failedAttempts[e] || 0) + 1; if (this.failedAttempts[e] > 2) return false; console.warn(e); console.info(rawData.toString()); let electron = require("electron"); electron.ipcRenderer.send("log", "note", "NetStat: Error parsing data from myexternalip.com"); electron.ipcRenderer.send("log", "debug", `Error: ${e}`); } }); }).on("error", e => { // Drop it }); } else if (this.runsBeforeGeoIPUpdate !== 0) { this.runsBeforeGeoIPUpdate = this.runsBeforeGeoIPUpdate - 1; } let p = await this.ping(window.settings.pingAddr || "1.1.1.1", 80, net.ip4).catch(() => { offline = true }); this.offline = offline; if (offline) { document.querySelector("#mod_netstat_innercontainer > div:first-child > h2").innerHTML = "OFFLINE"; document.querySelector("#mod_netstat_innercontainer > div:nth-child(2) > h2").innerHTML = "--.--.--.--"; document.querySelector("#mod_netstat_innercontainer > div:nth-child(3) > h2").innerHTML = "--ms"; } else { document.querySelector("#mod_netstat_innercontainer > div:first-child > h2").innerHTML = "ONLINE"; document.querySelector("#mod_netstat_innercontainer > div:nth-child(3) > h2").innerHTML = Math.round(p)+"ms"; } } }); } ping(target, port, local) { return new Promise((resolve, reject) => { let s = new require("net").Socket(); let start = process.hrtime(); s.connect({ port, host: target, localAddress: local, family: 4 }, () => { let time_arr = process.hrtime(start); let time = (time_arr[0] * 1e9 + time_arr[1]) / 1e6; resolve(time); s.destroy(); }); s.on('error', e => { s.destroy(); reject(e); }); s.setTimeout(1900, function() { s.destroy(); reject(new Error("Socket timeout")); }); }); } } module.exports = { Netstat }; ================================================ FILE: src/classes/ramwatcher.class.js ================================================ class RAMwatcher { constructor(parentId) { if (!parentId) throw "Missing parameters"; // Create DOM this.parent = document.getElementById(parentId); let modExtContainer = document.createElement("div"); let ramwatcherDOM = `

    MEMORY

    `; for (var i = 0; i < 440; i++) { ramwatcherDOM += `
    `; } ramwatcherDOM += `

    SWAP

    0.0 GiB

    `; modExtContainer.innerHTML = ramwatcherDOM; modExtContainer.setAttribute("id", "mod_ramwatcher"); this.parent.append(modExtContainer); this.points = Array.from(document.querySelectorAll("div.mod_ramwatcher_point")); this.shuffleArray(this.points); // Init updaters this.currentlyUpdating = false; this.updateInfo(); this.infoUpdater = setInterval(() => { this.updateInfo(); }, 1500); } updateInfo() { if (this.currentlyUpdating) return; this.currentlyUpdating = true; window.si.mem().then(data => { if (data.free+data.used !== data.total) throw("RAM Watcher Error: Bad memory values"); // Convert the data for the 440-points grid let active = Math.round((440*data.active)/data.total); let available = Math.round((440*(data.available-data.free))/data.total); // Update grid this.points.slice(0, active).forEach(domPoint => { if (domPoint.attributes.class.value !== "mod_ramwatcher_point active") { domPoint.setAttribute("class", "mod_ramwatcher_point active"); } }); this.points.slice(active, active+available).forEach(domPoint => { if (domPoint.attributes.class.value !== "mod_ramwatcher_point available") { domPoint.setAttribute("class", "mod_ramwatcher_point available"); } }); this.points.slice(active+available, this.points.length).forEach(domPoint => { if (domPoint.attributes.class.value !== "mod_ramwatcher_point free") { domPoint.setAttribute("class", "mod_ramwatcher_point free"); } }); // Update info text let totalGiB = Math.round((data.total/1073742000)*10)/10; // 1073742000 bytes = 1 Gibibyte (GiB), the *10 is to round to .1 decimal let usedGiB = Math.round((data.active/1073742000)*10)/10; document.getElementById("mod_ramwatcher_info").innerText = `USING ${usedGiB} OUT OF ${totalGiB} GiB`; // Update swap indicator let usedSwap = Math.round((100*data.swapused)/data.swaptotal); document.getElementById("mod_ramwatcher_swapbar").value = usedSwap || 0; let usedSwapGiB = Math.round((data.swapused/1073742000)*10)/10; document.getElementById("mod_ramwatcher_swaptext").innerText = `${usedSwapGiB} GiB`; this.currentlyUpdating = false; }); } shuffleArray(array) { for (let i = array.length - 1; i > 0; i--) { let j = Math.floor(Math.random() * (i + 1)); [array[i], array[j]] = [array[j], array[i]]; } } } module.exports = { RAMwatcher }; ================================================ FILE: src/classes/sysinfo.class.js ================================================ class Sysinfo { constructor(parentId) { if (!parentId) throw "Missing parameters"; // See #255 let os; switch (require("os").platform()) { case "darwin": os = "macOS"; break; case "win32": os = "win"; break; default: os = require("os").platform(); } // Create DOM this.parent = document.getElementById(parentId); this.parent.innerHTML += `

    1970

    JAN 1

    UPTIME

    0:0:0

    TYPE

    ${os}

    POWER

    00%

    `; this.updateDate(); this.updateUptime(); this.uptimeUpdater = setInterval(() => { this.updateUptime(); }, 60000); this.updateBattery(); this.batteryUpdater = setInterval(() => { this.updateBattery(); }, 3000); } updateDate() { let time = new Date(); document.querySelector("#mod_sysinfo > div:first-child > h1").innerHTML = time.getFullYear(); let month = time.getMonth(); switch(month) { case 0: month = "JAN"; break; case 1: month = "FEB"; break; case 2: month = "MAR"; break; case 3: month = "APR"; break; case 4: month = "MAY"; break; case 5: month = "JUN"; break; case 6: month = "JUL"; break; case 7: month = "AUG"; break; case 8: month = "SEP"; break; case 9: month = "OCT"; break; case 10: month = "NOV"; break; case 11: month = "DEC"; break; } document.querySelector("#mod_sysinfo > div:first-child > h2").innerHTML = month+" "+time.getDate(); let timeToNewDay = ((23 - time.getHours()) * 3600000) + ((59 - time.getMinutes()) * 60000); setTimeout(() => { this.updateDate(); }, timeToNewDay); } updateUptime() { let uptime = { raw: Math.floor(require("os").uptime()), days: 0, hours: 0, minutes: 0 }; uptime.days = Math.floor(uptime.raw/86400); uptime.raw -= uptime.days*86400; uptime.hours = Math.floor(uptime.raw/3600); uptime.raw -= uptime.hours*3600; uptime.minutes = Math.floor(uptime.raw/60); if (uptime.hours.toString().length !== 2) uptime.hours = "0"+uptime.hours; if (uptime.minutes.toString().length !== 2) uptime.minutes = "0"+uptime.minutes; document.querySelector("#mod_sysinfo > div:nth-child(2) > h2").innerHTML = uptime.days + 'd' + uptime.hours + ':' + uptime.minutes; } updateBattery() { window.si.battery().then(bat => { let indicator = document.querySelector("#mod_sysinfo > div:last-child > h2"); if (bat.hasBattery) { if (bat.isCharging) { indicator.innerHTML = "CHARGE"; } else if (bat.acConnected) { indicator.innerHTML = "WIRED"; } else { indicator.innerHTML = bat.percent+"%"; } } else { indicator.innerHTML = "ON"; } }); } } module.exports = { Sysinfo }; ================================================ FILE: src/classes/terminal.class.js ================================================ class Terminal { constructor(opts) { if (opts.role === "client") { if (!opts.parentId) throw "Missing options"; this.xTerm = require("xterm").Terminal; const {AttachAddon} = require("xterm-addon-attach"); const {FitAddon} = require("xterm-addon-fit"); const {LigaturesAddon} = require("xterm-addon-ligatures"); const {WebglAddon} = require("xterm-addon-webgl"); this.Ipc = require("electron").ipcRenderer; this.port = opts.port || 3000; this.cwd = ""; this.oncwdchange = () => {}; this._sendSizeToServer = () => { let cols = this.term.cols.toString(); let rows = this.term.rows.toString(); while (cols.length < 3) { cols = "0"+cols; } while (rows.length < 3) { rows = "0"+rows; } this.Ipc.send("terminal_channel-"+this.port, "Resize", cols, rows); }; // Support for custom color filters on the terminal - see #483 let doCustomFilter = (window.isTermFilterValidated) ? true : false; // Parse & validate color filter if (window.isTermFilterValidated !== true && typeof window.theme.terminal.colorFilter === "object" && window.theme.terminal.colorFilter.length > 0) { doCustomFilter = window.theme.terminal.colorFilter.every((step, i, a) => { let func = step.slice(0, step.indexOf("(")); switch(func) { case "negate": case "grayscale": a[i] = { func, arg: [] }; return true; case "lighten": case "darken": case "saturate": case "desaturate": case "whiten": case "blacken": case "fade": case "opaquer": case "rotate": case "mix": break; default: return false; } let arg = step.slice(step.indexOf("(")+1, step.indexOf(")")); if (typeof Number(arg) === "number") { a[i] = { func, arg: [Number(arg)] }; window.isTermFilterValidated = true; return true; } return false; }); } let color = require("color"); let colorify; if (doCustomFilter) { colorify = (base, target) => { let newColor = color(base); target = color(target); for (let i = 0; i < window.theme.terminal.colorFilter.length; i++) { if (window.theme.terminal.colorFilter[i].func === "mix") { newColor = newColor[window.theme.terminal.colorFilter[i].func](target, ...window.theme.terminal.colorFilter[i].arg); } else { newColor = newColor[window.theme.terminal.colorFilter[i].func](...window.theme.terminal.colorFilter[i].arg); } } return newColor.hex(); }; } else { colorify = (base, target) => { return color(base).grayscale().mix(color(target), 0.3).hex(); }; } let themeColor = `rgb(${window.theme.r}, ${window.theme.g}, ${window.theme.b})`; this.term = new this.xTerm({ cols: 80, rows: 24, cursorBlink: window.theme.terminal.cursorBlink || true, cursorStyle: window.theme.terminal.cursorStyle || "block", allowTransparency: window.theme.terminal.allowTransparency || false, fontFamily: window.theme.terminal.fontFamily || "Fira Mono", fontSize: window.theme.terminal.fontSize || window.settings.termFontSize || 15, fontWeight: window.theme.terminal.fontWeight || "normal", fontWeightBold: window.theme.terminal.fontWeightBold || "bold", letterSpacing: window.theme.terminal.letterSpacing || 0, lineHeight: window.theme.terminal.lineHeight || 1, scrollback: 1500, bellStyle: "none", theme: { foreground: window.theme.terminal.foreground, background: window.theme.terminal.background, cursor: window.theme.terminal.cursor, cursorAccent: window.theme.terminal.cursorAccent, selection: window.theme.terminal.selection, black: window.theme.colors.black || colorify("#2e3436", themeColor), red: window.theme.colors.red || colorify("#cc0000", themeColor), green: window.theme.colors.green || colorify("#4e9a06", themeColor), yellow: window.theme.colors.yellow || colorify("#c4a000", themeColor), blue: window.theme.colors.blue || colorify("#3465a4", themeColor), magenta: window.theme.colors.magenta || colorify("#75507b", themeColor), cyan: window.theme.colors.cyan || colorify("#06989a", themeColor), white: window.theme.colors.white || colorify("#d3d7cf", themeColor), brightBlack: window.theme.colors.brightBlack || colorify("#555753", themeColor), brightRed: window.theme.colors.brightRed || colorify("#ef2929", themeColor), brightGreen: window.theme.colors.brightGreen || colorify("#8ae234", themeColor), brightYellow: window.theme.colors.brightYellow || colorify("#fce94f", themeColor), brightBlue: window.theme.colors.brightBlue || colorify("#729fcf", themeColor), brightMagenta: window.theme.colors.brightMagenta || colorify("#ad7fa8", themeColor), brightCyan: window.theme.colors.brightCyan || colorify("#34e2e2", themeColor), brightWhite: window.theme.colors.brightWhite || colorify("#eeeeec", themeColor) } }); let fitAddon = new FitAddon(); this.term.loadAddon(fitAddon); this.term.open(document.getElementById(opts.parentId)); this.term.loadAddon(new WebglAddon()); let ligaturesAddon = new LigaturesAddon(); this.term.loadAddon(ligaturesAddon); this.term.attachCustomKeyEventHandler(e => { window.keyboard.keydownHandler(e); return true; }); // Prevent soft-keyboard on touch devices #733 document.querySelectorAll('.xterm-helper-textarea').forEach(textarea => textarea.setAttribute('readonly', 'readonly')) this.term.focus(); this.Ipc.send("terminal_channel-"+this.port, "Renderer startup"); this.Ipc.on("terminal_channel-"+this.port, (e, ...args) => { switch(args[0]) { case "New cwd": this.cwd = args[1]; this.oncwdchange(this.cwd); break; case "Fallback cwd": this.cwd = "FALLBACK |-- "+args[1]; this.oncwdchange(this.cwd); break; case "New process": if (this.onprocesschange) { this.onprocesschange(args[1]); } break; default: return; } }); this.resendCWD = () => { this.oncwdchange(this.cwd || null); }; let sockHost = opts.host || "127.0.0.1"; let sockPort = this.port; this.socket = new WebSocket("ws://"+sockHost+":"+sockPort); this.socket.onopen = () => { let attachAddon = new AttachAddon(this.socket); this.term.loadAddon(attachAddon); this.fit(); }; this.socket.onerror = e => {throw JSON.stringify(e)}; this.socket.onclose = e => { if (this.onclose) { this.onclose(e); } }; this.lastSoundFX = Date.now(); this.socket.addEventListener("message", e => { let d = Date.now(); if (d - this.lastSoundFX > 30) { if(window.passwordMode == "false") window.audioManager.stdout.play(); this.lastSoundFX = d; } if (d - this.lastRefit > 10000) { this.fit(); } // See #397 if (!window.settings.experimentalGlobeFeatures) return; let ips = e.data.match(/((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)/g); if (ips !== null && ips.length >= 1) { ips = ips.filter((val, index, self) => { return self.indexOf(val) === index; }); ips.forEach(ip => { window.mods.globe.addTemporaryConnectedMarker(ip); }); } }); let parent = document.getElementById(opts.parentId); parent.addEventListener("wheel", e => { this.term.scrollLines(Math.round(e.deltaY/10)); }); this._lastTouchY = null; parent.addEventListener("touchstart", e => { this._lastTouchY = e.targetTouches[0].screenY; }); parent.addEventListener("touchmove", e => { if (this._lastTouchY) { let y = e.changedTouches[0].screenY; let deltaY = y - this._lastTouchY; this._lastTouchY = y; this.term.scrollLines(-Math.round(deltaY/10)); } }); parent.addEventListener("touchend", e => { this._lastTouch = null; }); parent.addEventListener("touchcancel", e => { this._lastTouch = null; }); document.querySelector(".xterm-helper-textarea").addEventListener("keydown", e => { if (e.key === "F11" && window.settings.allowWindowed) { e.preventDefault(); window.toggleFullScreen(); } }); this.fit = () => { this.lastRefit = Date.now(); let {cols, rows} = fitAddon.proposeDimensions(); // Apply custom fixes based on screen ratio, see #302 let w = screen.width; let h = screen.height; let x = 1; let y = 0; function gcd(a, b) { return (b == 0) ? a : gcd(b, a%b); } let d = gcd(w, h); if (d === 100) { y = 1; x = 3;} // if (d === 120) y = 1; if (d === 256) x = 2; if (window.settings.termFontSize < 15) y = y - 1; cols = cols+x; rows = rows+y; if (this.term.cols !== cols || this.term.rows !== rows) { this.resize(cols, rows); } }; this.resize = (cols, rows) => { this.term.resize(cols, rows); this._sendSizeToServer(); }; this.write = cmd => { this.socket.send(cmd); }; this.writelr = cmd => { this.socket.send(cmd+"\r"); }; this.clipboard = { copy: () => { if (!this.term.hasSelection()) return false; document.execCommand("copy"); this.term.clearSelection(); this.clipboard.didCopy = true; }, paste: () => { this.write(remote.clipboard.readText()); this.clipboard.didCopy = false; }, didCopy: false }; } else if (opts.role === "server") { this.Pty = require("node-pty"); this.Websocket = require("ws").Server; this.Ipc = require("electron").ipcMain; this.renderer = null; this.port = opts.port || 3000; this._closed = false; this.onclosed = () => {}; this.onopened = () => {}; this.onresize = () => {}; this.ondisconnected = () => {}; this._disableCWDtracking = false; this._getTtyCWD = tty => { return new Promise((resolve, reject) => { let pid = tty._pid; switch(require("os").type()) { case "Linux": require("fs").readlink(`/proc/${pid}/cwd`, (e, cwd) => { if (e !== null) { reject(e); } else { resolve(cwd); } }); break; case "Darwin": require("child_process").exec(`lsof -a -d cwd -p ${pid} | tail -1 | awk '{ for (i=9; i<=NF; i++) printf "%s ", $i }'`, (e, cwd) => { if (e !== null) { reject(e); } else { resolve(cwd.trim()); } }); break; default: reject("Unsupported OS"); } }); }; this._getTtyProcess = tty => { return new Promise((resolve, reject) => { let pid = tty._pid; switch(require("os").type()) { case "Linux": case "Darwin": require("child_process").exec(`ps -o comm --no-headers --sort=+pid -g ${pid} | tail -1`, (e, proc) => { if (e !== null) { reject(e); } else { resolve(proc.trim()); } }); break; default: reject("Unsupported OS"); } }); }; this._nextTickUpdateTtyCWD = false; this._nextTickUpdateProcess = false; this._tick = setInterval(() => { if (this._nextTickUpdateTtyCWD && this._disableCWDtracking === false) { this._nextTickUpdateTtyCWD = false; this._getTtyCWD(this.tty).then(cwd => { if (this.tty._cwd === cwd) return; this.tty._cwd = cwd; if (this.renderer) { this.renderer.send("terminal_channel-"+this.port, "New cwd", cwd); } }).catch(e => { if (!this._closed) { console.log("Error while tracking TTY working directory: ", e); this._disableCWDtracking = true; try { this.renderer.send("terminal_channel-"+this.port, "Fallback cwd", opts.cwd || process.env.PWD); } catch(e) { // renderer closed } } }); } if (this.renderer && this._nextTickUpdateProcess) { this._nextTickUpdateProcess = false; this._getTtyProcess(this.tty).then(process => { if (this.tty._process === process) return; this.tty._process = process; if (this.renderer) { this.renderer.send("terminal_channel-"+this.port, "New process", process); } }).catch(e => { if (!this._closed) { console.log("Error while retrieving TTY subprocess: ", e); try { this.renderer.send("terminal_channel-"+this.port, "New process", ""); } catch(e) { // renderer closed } } }); } }, 1000); this.tty = this.Pty.spawn(opts.shell || "bash", (opts.params.length > 0 ? opts.params : (process.platform === "win32" ? [] : ["--login"])), { name: opts.env.TERM || "xterm-256color", cols: 80, rows: 24, cwd: opts.cwd || process.env.PWD, env: opts.env || process.env }); this.tty.onExit((code, signal) => { this._closed = true; this.onclosed(code, signal); }); this.wss = new this.Websocket({ port: this.port, clientTracking: true, verifyClient: info => { if (this.wss.clients.length >= 1) { return false; } else { return true; } } }); this.Ipc.on("terminal_channel-"+this.port, (e, ...args) => { switch(args[0]) { case "Renderer startup": this.renderer = e.sender; if (!this._disableCWDtracking && this.tty._cwd) { this.renderer.send("terminal_channel-"+this.port, "New cwd", this.tty._cwd); } if (this._disableCWDtracking) { this.renderer.send("terminal_channel-"+this.port, "Fallback cwd", opts.cwd || process.env.PWD); } break; case "Resize": let cols = args[1]; let rows = args[2]; try { this.tty.resize(Number(cols), Number(rows)); } catch (error) { //Keep going, it'll work anyways. } this.onresized(cols, rows); break; default: return; } }); this.wss.on("connection", ws => { this.onopened(this.tty._pid); ws.on("close", (code, reason) => { this.ondisconnected(code, reason); }); ws.on("message", msg => { this.tty.write(msg); }); this.tty.onData(data => { this._nextTickUpdateTtyCWD = true; this._nextTickUpdateProcess = true; try { ws.send(data); } catch (e) { // Websocket closed } }); }); this.close = () => { this.tty.kill(); this._closed = true; }; } else { throw "Unknown purpose"; } } } module.exports = { Terminal }; ================================================ FILE: src/classes/toplist.class.js ================================================ class Toplist { constructor(parentId) { if (!parentId) throw "Missing parameters"; // Create DOM this.parent = document.getElementById(parentId); this._element = document.createElement("div"); this._element.setAttribute("id", "mod_toplist"); this._element.innerHTML = `

    TOP PROCESSESPID | NAME | CPU | MEM


    `; this._element.onclick = this.processList; this.parent.append(this._element); this.currentlyUpdating = false; this.updateList(); this.listUpdater = setInterval(() => { this.updateList(); }, 2000); } updateList() { if (this.currentlyUpdating) return; this.currentlyUpdating = true; window.si.processes().then(data => { if (window.settings.excludeThreadsFromToplist === true) { data.list = data.list.sort((a, b) => { return (a.pid-b.pid); }).filter((e, index, a) => { let i = a.findIndex(x => x.name === e.name); if (i !== -1 && i !== index) { a[i].cpu = a[i].cpu+e.cpu; a[i].mem = a[i].mem+e.mem; return false; } return true; }); } let list = data.list.sort((a, b) => { return ((b.cpu-a.cpu)*100 + b.mem-a.mem); }).splice(0, 5); document.querySelectorAll("#mod_toplist_table > tr").forEach(el => { el.remove(); }); list.forEach(proc => { let el = document.createElement("tr"); el.innerHTML = `${proc.pid} ${proc.name} ${Math.round(proc.cpu*10)/10}% ${Math.round(proc.mem*10)/10}%`; document.getElementById("mod_toplist_table").append(el); }); this.currentlyUpdating = false; }); } processList(){ let sortKey; let ascending = false; let removed = false; let currentlyUpdating = false; function setSortKey(fieldName){ if (sortKey === fieldName){ if (ascending){ sortKey = undefined; ascending = false; } else{ ascending = true; } } else { sortKey = fieldName; ascending = false; } } function formatRuntime(ms){ const msInDay = 24 * 60 * 60 * 1000; let days = Math.floor(ms / msInDay); let remainingMS = ms % msInDay; const msInHour = 60 * 60 * 1000; let hours = Math.floor(remainingMS / msInHour); remainingMS = ms % msInHour; let msInMin = 60 * 1000; let minutes = Math.floor(remainingMS / msInMin); remainingMS = ms % msInMin; let seconds = Math.floor(remainingMS / 1000); return `${days < 10 ? "0" : ""}${days}:${hours < 10 ? "0" : ""}${hours}:${minutes < 10 ? "0" : ""}${minutes}:${seconds < 10 ? "0" : ""}${seconds}`; } function updateProcessList() { if (currentlyUpdating) return; currentlyUpdating = true; window.si.processes().then(data => { if (window.settings.excludeThreadsFromToplist === true) { data.list = data.list.sort((a, b) => { return (a.pid - b.pid); }).filter((e, index, a) => { let i = a.findIndex(x => x.name === e.name); if (i !== -1 && i !== index) { a[i].cpu = a[i].cpu + e.cpu; a[i].mem = a[i].mem + e.mem; return false; } return true; }); } data.list.forEach(proc => { proc.runtime = new Date(Date.now() - Date.parse(proc.started)); }); currentlyUpdating = false; let list = data.list.sort((a, b) => { switch (sortKey) { case "PID": if (ascending) return a.pid - b.pid; else return b.pid - a.pid; case "Name": if (ascending) { if (a.name > b.name) return -1; if (a.name < b.name) return 1; return 0; } else { if (a.name < b.name) return -1; if (a.name > b.name) return 1; return 0; } case "User": if (ascending) { if (a.user > b.user) return -1; if (a.user < b.user) return 1; return 0; } else { if (a.user < b.user) return -1; if (a.user > b.user) return 1; return 0; } case "CPU": if (ascending) return a.cpu - b.cpu; else return b.cpu - a.cpu; case "Memory": if (ascending) return a.mem - b.mem; else return b.mem - a.mem; case "State": if (a.state < b.state) return -1; if (a.state > b.state) return 1; return 0; case "Started": if (ascending) return Date.parse(a.started) - Date.parse(b.started); else return Date.parse(b.started) - Date.parse(a.started); case "Runtime": if (ascending) return a.runtime - b.runtime; else return b.runtime - a.runtime; default: // default to the same sorting as the toplist return ((b.cpu - a.cpu) * 100 + b.mem - a.mem); } }); if (removed) clearInterval(updateInterval); else { document.querySelectorAll("#processList > tr").forEach(el => { el.remove(); }); list.forEach(proc => { let el = document.createElement("tr"); el.innerHTML = `${proc.pid} ${proc.name} ${proc.user} ${Math.round(proc.cpu * 10) / 10}% ${Math.round(proc.mem * 10) / 10}% ${proc.state} ${proc.started} ${formatRuntime(proc.runtime)}`; document.getElementById("processList").append(el); }); } }); } window.keyboard.detach(); new Modal( { type: "custom", title: "Active Processes", html: `
    PID Name User CPU Memory State Started Runtime
    `, }, () => { removed = true; //clearInterval(updateInterval); } ); let headers = document.getElementsByClassName("header"); for (let header of headers){ let title = header.textContent; header.addEventListener("click", () => { for (let header of headers) { header.textContent = header.textContent.replace('\u25B2', "").replace('\u25BC', ""); } setSortKey(title); if (sortKey){ header.textContent = `${title}${ascending ? '\u25B2' : '\u25BC'}`; } }); } updateProcessList(); window.keyboard.attach(); window.term[window.currentTerm].term.focus(); var updateInterval = setInterval(updateProcessList, 1000); } } module.exports = { Toplist }; ================================================ FILE: src/classes/updateChecker.class.js ================================================ class UpdateChecker { constructor() { let https = require("https"); let electron = require("electron"); let remote = require("@electron/remote"); let current = remote.app.getVersion(); this._failed = false; this._willfail = false; this._fail = e => { this._failed = true; electron.ipcRenderer.send("log", "note", "UpdateChecker: Could not fetch latest release from GitHub's API."); electron.ipcRenderer.send("log", "debug", `Error: ${e}`); }; https.get({ protocol: "https:", host: "api.github.com", path: "/repos/GitSquared/edex-ui/releases/latest", headers: { "User-Agent": "eDEX-UI UpdateChecker" } }, res => { switch(res.statusCode) { case 200: break; case 404: this._fail("Got 404 (Not Found) response from server"); break; default: this._willfail = true; } let rawData = ""; res.on('data', chunk => { rawData += chunk; }); res.on('end', () => { let d = rawData; if (this._failed === true) { // Do nothing, it already failed } else if (this._willfail) { this._fail(d.toString()); } else { try { let release = JSON.parse(d.toString()); if (release.tag_name.slice(1) === current) { electron.ipcRenderer.send("log", "info", "UpdateChecker: Running latest version."); } else if (Number(release.tag_name.slice(1).replace(/\./g, "")) < Number(current.replace("-pre", "").replace(/\./g, ""))) { electron.ipcRenderer.send("log", "info", "UpdateChecker: Running an unreleased, development version."); } else { new Modal({ type: "info", title: "New version available", message: `eDEX-UI ${release.tag_name} is now available.
    Head over to github.com to download the latest version.` }); electron.ipcRenderer.send("log", "info", `UpdateChecker: New version ${release.tag_name} available.`); } } catch(e) { this._fail(e); } } }); }).on('error', e => { this._fail(e); }); } } module.exports = { UpdateChecker }; ================================================ FILE: src/package.json ================================================ { "name": "edex-ui", "productName": "eDEX-UI", "version": "2.2.8", "description": "eDEX-UI sci-fi interface", "keywords": [ "desktop", "sci-fi", "gui", "portable", "tty", "terminal" ], "main": "_boot.js", "repository": { "type": "git", "url": "git+https://github.com/GitSquared/edex-ui.git" }, "author": "Gabriel 'Squared' SAILLARD (https://gaby.dev)", "license": "GPL-3.0", "bugs": { "url": "https://github.com/GitSquared/edex-ui/issues" }, "homepage": "https://github.com/GitSquared/edex-ui#readme", "dependencies": { "@electron/remote": "^1.2.2", "augmented-ui": "^1.1.2", "color": "3.2.1", "geolite2-redist": "^2.0.4", "howler": "2.2.3", "maxmind": "4.3.2", "mime-types": "^2.1.33", "nanoid": "3.1.30", "node-pty": "0.10.1", "pdfjs-dist": "2.11.338", "pretty-bytes": "5.6.0", "shell-env": "3.0.1", "signale": "1.4.0", "smoothie": "1.35.0", "systeminformation": "5.9.7", "tail": "2.2.4", "username": "5.1.0", "which": "2.0.2", "ws": "7.5.5", "xterm": "4.14.1", "xterm-addon-attach": "0.6.0", "xterm-addon-fit": "0.5.0", "xterm-addon-ligatures": "0.5.1", "xterm-addon-webgl": "^0.11.2" }, "optionalDependencies": { "osx-temperature-sensor": "1.0.7" } } ================================================ FILE: src/ui.html ================================================ eDEX-UI