diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb b/BlueMapCommon/BlueMapVue/BlueMapWeb deleted file mode 160000 index b5cd8989..00000000 --- a/BlueMapCommon/BlueMapVue/BlueMapWeb +++ /dev/null @@ -1 +0,0 @@ -Subproject commit b5cd8989340198464e10af891afa8e4a13565dc5 diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/.github/workflows/nodejs.yml b/BlueMapCommon/BlueMapVue/BlueMapWeb/.github/workflows/nodejs.yml new file mode 100644 index 00000000..7f40e456 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/.github/workflows/nodejs.yml @@ -0,0 +1,25 @@ +name: Node.js CI + +on: [push, pull_request] + +jobs: + build: + + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [14.x] + + steps: + - uses: actions/checkout@v2 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v1 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run build + - uses: actions/upload-artifact@v2 + with: + name: artifacts + path: build/* \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/.gitignore b/BlueMapCommon/BlueMapVue/BlueMapWeb/.gitignore new file mode 100644 index 00000000..c0dd3adc --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/.gitignore @@ -0,0 +1,9 @@ +.classpath +.project +.idea + +build +doc +node_modules + +public/js \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/.npmignore b/BlueMapCommon/BlueMapVue/BlueMapWeb/.npmignore new file mode 100644 index 00000000..c712d3c8 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/.npmignore @@ -0,0 +1,13 @@ +.classpath +.project +.idea + +build +doc +node_modules + +public/js + +###### Below is additionally to .gitignore +.github +public diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/LICENSE b/BlueMapCommon/BlueMapVue/BlueMapWeb/LICENSE new file mode 100644 index 00000000..0a812477 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) Blue +Copyright (c) contributors + +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. \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/package-lock.json b/BlueMapCommon/BlueMapVue/BlueMapWeb/package-lock.json new file mode 100644 index 00000000..662f618b --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/package-lock.json @@ -0,0 +1,5777 @@ +{ + "name": "bluemap", + "version": "1.1.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "bluemap", + "version": "1.1.0", + "license": "MIT", + "dependencies": { + "hammerjs": "~2.0.8", + "three": "~0.123.0" + }, + "devDependencies": { + "@babel/core": "~7.11.6", + "@babel/plugin-proposal-class-properties": "~7.10.4", + "@babel/polyfill": "~7.11.5", + "@babel/preset-env": "~7.11.5", + "@rollup/plugin-babel": "~5.2.1", + "@types/babel__core": "~7.1.9", + "concurrently": "~5.3.0", + "copyfiles": "~2.3.0", + "http-server": "~0.12.3", + "rollup": "~2.28.2", + "rollup-plugin-terser": "~7.0.2" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.10.4" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz", + "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "semver": "^5.5.0" + } + }, + "node_modules/@babel/core": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz", + "integrity": "sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.6", + "@babel/helper-module-transforms": "^7.11.0", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.11.5", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.11.5", + "@babel/types": "^7.11.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz", + "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "dependencies": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", + "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.10.4", + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", + "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.10.5", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", + "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", + "regexpu-core": "^4.7.0" + } + }, + "node_modules/@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-explode-assignable-expression": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz", + "integrity": "sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", + "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "node_modules/@babel/helper-regex": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "dev": true, + "dependencies": { + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz", + "integrity": "sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "dependencies": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", + "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.11.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", + "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", + "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-proposal-async-generator-functions": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", + "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "node_modules/@babel/plugin-proposal-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", + "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-proposal-dynamic-import": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", + "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "node_modules/@babel/plugin-proposal-export-namespace-from": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", + "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "node_modules/@babel/plugin-proposal-json-strings": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", + "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "node_modules/@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz", + "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", + "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "node_modules/@babel/plugin-proposal-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", + "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "node_modules/@babel/plugin-proposal-object-rest-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", + "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.4" + } + }, + "node_modules/@babel/plugin-proposal-optional-catch-binding": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", + "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "node_modules/@babel/plugin-proposal-optional-chaining": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz", + "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "node_modules/@babel/plugin-proposal-private-methods": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", + "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-proposal-unicode-property-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", + "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", + "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", + "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", + "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", + "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", + "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz", + "integrity": "sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", + "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", + "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", + "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", + "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", + "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", + "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", + "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", + "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", + "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", + "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", + "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", + "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", + "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", + "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", + "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", + "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", + "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", + "dev": true, + "dependencies": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", + "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", + "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", + "dev": true, + "dependencies": { + "regenerator-transform": "^0.14.2" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", + "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", + "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", + "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", + "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", + "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", + "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", + "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", + "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "node_modules/@babel/polyfill": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.11.5.tgz", + "integrity": "sha512-FunXnE0Sgpd61pKSj2OSOs1D44rKTD3pGOfGilZ6LGrrIH0QEtJlTjqOqdF8Bs98JmjfGhni2BBkTfv9KcKJ9g==", + "dev": true, + "dependencies": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz", + "integrity": "sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.11.0", + "@babel/helper-compilation-targets": "^7.10.4", + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-proposal-async-generator-functions": "^7.10.4", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-dynamic-import": "^7.10.4", + "@babel/plugin-proposal-export-namespace-from": "^7.10.4", + "@babel/plugin-proposal-json-strings": "^7.10.4", + "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", + "@babel/plugin-proposal-numeric-separator": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.11.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", + "@babel/plugin-proposal-optional-chaining": "^7.11.0", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.10.4", + "@babel/plugin-transform-arrow-functions": "^7.10.4", + "@babel/plugin-transform-async-to-generator": "^7.10.4", + "@babel/plugin-transform-block-scoped-functions": "^7.10.4", + "@babel/plugin-transform-block-scoping": "^7.10.4", + "@babel/plugin-transform-classes": "^7.10.4", + "@babel/plugin-transform-computed-properties": "^7.10.4", + "@babel/plugin-transform-destructuring": "^7.10.4", + "@babel/plugin-transform-dotall-regex": "^7.10.4", + "@babel/plugin-transform-duplicate-keys": "^7.10.4", + "@babel/plugin-transform-exponentiation-operator": "^7.10.4", + "@babel/plugin-transform-for-of": "^7.10.4", + "@babel/plugin-transform-function-name": "^7.10.4", + "@babel/plugin-transform-literals": "^7.10.4", + "@babel/plugin-transform-member-expression-literals": "^7.10.4", + "@babel/plugin-transform-modules-amd": "^7.10.4", + "@babel/plugin-transform-modules-commonjs": "^7.10.4", + "@babel/plugin-transform-modules-systemjs": "^7.10.4", + "@babel/plugin-transform-modules-umd": "^7.10.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", + "@babel/plugin-transform-new-target": "^7.10.4", + "@babel/plugin-transform-object-super": "^7.10.4", + "@babel/plugin-transform-parameters": "^7.10.4", + "@babel/plugin-transform-property-literals": "^7.10.4", + "@babel/plugin-transform-regenerator": "^7.10.4", + "@babel/plugin-transform-reserved-words": "^7.10.4", + "@babel/plugin-transform-shorthand-properties": "^7.10.4", + "@babel/plugin-transform-spread": "^7.11.0", + "@babel/plugin-transform-sticky-regex": "^7.10.4", + "@babel/plugin-transform-template-literals": "^7.10.4", + "@babel/plugin-transform-typeof-symbol": "^7.10.4", + "@babel/plugin-transform-unicode-escapes": "^7.10.4", + "@babel/plugin-transform-unicode-regex": "^7.10.4", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.11.5", + "browserslist": "^4.12.0", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "node_modules/@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "node_modules/@babel/traverse": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz", + "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.5", + "@babel/types": "^7.11.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "node_modules/@babel/types": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", + "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "node_modules/@rollup/plugin-babel": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz", + "integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "dependencies": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", + "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz", + "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "node_modules/@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "node_modules/@types/node": { + "version": "14.11.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz", + "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==", + "dev": true + }, + "node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "node_modules/basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "node_modules/concurrently": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-5.3.0.tgz", + "integrity": "sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ==", + "dev": true, + "dependencies": { + "chalk": "^2.4.2", + "date-fns": "^2.0.1", + "lodash": "^4.17.15", + "read-pkg": "^4.0.1", + "rxjs": "^6.5.2", + "spawn-command": "^0.0.2-1", + "supports-color": "^6.1.0", + "tree-kill": "^1.2.2", + "yargs": "^13.3.0" + }, + "bin": { + "concurrently": "bin/concurrently.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/concurrently/node_modules/supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.1" + } + }, + "node_modules/copyfiles": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.3.0.tgz", + "integrity": "sha512-73v7KFuDFJ/ofkQjZBMjMBFWGgkS76DzXvBMUh7djsMOE5EELWtAO/hRB6Wr5Vj5Zg+YozvoHemv0vnXpqxmOQ==", + "dev": true, + "dependencies": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "yargs": "^15.3.1" + }, + "bin": { + "copyfiles": "copyfiles", + "copyup": "copyfiles" + } + }, + "node_modules/copyfiles/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "dependencies": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/copyfiles/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/copyfiles/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/copyfiles/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/copyfiles/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/copyfiles/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/copyfiles/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "dev": true + }, + "node_modules/core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "dependencies": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + } + }, + "node_modules/core-js-compat/node_modules/semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "node_modules/corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/date-fns": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", + "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==", + "dev": true, + "engines": { + "node": ">=0.11" + } + }, + "node_modules/debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "dependencies": { + "object-keys": "^1.0.12" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, + "dependencies": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + }, + "bin": { + "ecstatic": "lib/ecstatic.js" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.4.141", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.141.tgz", + "integrity": "sha512-mfBcbqc0qc6RlxrsIgLG2wCqkiPAjEezHxGTu7p3dHHFOurH4EjS9rFZndX5axC8264rI1Pcbw8uQP39oZckeA==", + "dev": true + }, + "node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/hammerjs": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-server": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", + "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "dev": true, + "dependencies": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.18.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0" + }, + "bin": { + "hs": "bin/http-server", + "http-server": "bin/http-server" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "node_modules/is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "node_modules/jest-worker": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz", + "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "dependencies": { + "leven": "^3.1.0" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "node_modules/noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true, + "bin": { + "opener": "bin/opener-bin.js" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "dependencies": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "engines": { + "node": ">= 0.12.0" + } + }, + "node_modules/portfinder/node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "dev": true, + "dependencies": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/regenerate": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "dependencies": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "node_modules/regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "node_modules/resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "dependencies": { + "path-parse": "^1.0.6" + } + }, + "node_modules/rollup": { + "version": "2.28.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.28.2.tgz", + "integrity": "sha512-8txbsFBFLmm9Xdt4ByTOGa9Muonmc8MfNjnGAR8U8scJlF1ZW7AgNZa7aqBXaKtlvnYP/ab++fQIq9dB9NWUbg==", + "dev": true, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=10.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.1.2" + } + }, + "node_modules/rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + } + }, + "node_modules/rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trimend/node_modules/es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, + "node_modules/string.prototype.trimstart/node_modules/es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "dependencies": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/terser": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.2.tgz", + "integrity": "sha512-H67sydwBz5jCUA32ZRL319ULu+Su1cAoZnnc+lXnenGRYWyLE3Scgkt8mNoAsMx0h5kdo758zdoS0LG9rYZXDQ==", + "dev": true, + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/terser/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/three": { + "version": "0.123.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.123.0.tgz", + "integrity": "sha512-KNnx/IbilvoHRkxOtL0ouozoDoElyuvAXhFB21RK7F5IPWSmqyFelICK6x3hJerLNSlAdHxR0hkuvMMhH9pqXg==" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "dependencies": { + "qs": "^6.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.10.4.tgz", + "integrity": "sha512-vG6SvB6oYEhvgisZNFRmRCUkLz11c7rp+tbNTynGqc6mS1d5ATd/sGyV6W0KZZnXRKMTzZDRgQT3Ou9jhpAfUg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/compat-data": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.11.0.tgz", + "integrity": "sha512-TPSvJfv73ng0pfnEOh17bYMPQbI95+nGWc71Ss4vZdRBHTDqmM9Z8ZV4rYz8Ks7sfzc95n30k6ODIq5UGnXcYQ==", + "dev": true, + "requires": { + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "semver": "^5.5.0" + } + }, + "@babel/core": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.11.6.tgz", + "integrity": "sha512-Wpcv03AGnmkgm6uS6k8iwhIwTrcP0m17TL1n1sy7qD0qelDu4XNeW0dN0mHfa+Gei211yDaLoEe/VlbXQzM4Bg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.6", + "@babel/helper-module-transforms": "^7.11.0", + "@babel/helpers": "^7.10.4", + "@babel/parser": "^7.11.5", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.11.5", + "@babel/types": "^7.11.5", + "convert-source-map": "^1.7.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.1", + "json5": "^2.1.2", + "lodash": "^4.17.19", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + } + }, + "@babel/generator": { + "version": "7.11.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.11.6.tgz", + "integrity": "sha512-DWtQ1PV3r+cLbySoHrwn9RWEgKMBLLma4OBQloPRyDYvc5msJM9kvTLo1YnlJd1P/ZuKbdli3ijr5q3FvAF3uA==", + "dev": true, + "requires": { + "@babel/types": "^7.11.5", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.10.4.tgz", + "integrity": "sha512-XQlqKQP4vXFB7BN8fEEerrmYvHp3fK/rBkRFz9jaJbzK0B1DSfej9Kc7ZzE8Z/OnId1jpJdNAZ3BFQjWG68rcA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.10.4.tgz", + "integrity": "sha512-L0zGlFrGWZK4PbT8AszSfLTM5sDU1+Az/En9VrdT8/LmEiJt4zXt+Jve9DCAnQcbqDhCI+29y/L93mrDzddCcg==", + "dev": true, + "requires": { + "@babel/helper-explode-assignable-expression": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.10.4.tgz", + "integrity": "sha512-a3rYhlsGV0UHNDvrtOXBg8/OpfV0OKTkxKPzIplS1zpx7CygDcWWxckxZeDd3gzPzC4kUT0A4nVFDK0wGMh4MQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.10.4", + "browserslist": "^4.12.0", + "invariant": "^2.2.4", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.10.5.tgz", + "integrity": "sha512-0nkdeijB7VlZoLT3r/mY3bUkw3T8WG/hNw+FATs/6+pG2039IJWjTYL0VTISqsNHMUTEnwbVnc89WIJX9Qed0A==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-member-expression-to-functions": "^7.10.5", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4" + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.10.4.tgz", + "integrity": "sha512-2/hu58IEPKeoLF45DBwx3XFqsbCXmkdAay4spVr2x0jYgRxrSNp+ePwvSsy9g6YSaNDcKIQVPXk1Ov8S2edk2g==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-regex": "^7.10.4", + "regexpu-core": "^4.7.0" + } + }, + "@babel/helper-define-map": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-define-map/-/helper-define-map-7.10.5.tgz", + "integrity": "sha512-fMw4kgFB720aQFXSVaXr79pjjcW5puTCM16+rECJ/plGS+zByelE8l9nCpV1GibxTnFVmUuYG9U8wYfQHdzOEQ==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/types": "^7.10.5", + "lodash": "^4.17.19" + } + }, + "@babel/helper-explode-assignable-expression": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.11.4.tgz", + "integrity": "sha512-ux9hm3zR4WV1Y3xXxXkdG/0gxF9nvI0YVmKVhvK9AfMoaQkemL3sJpXw+Xbz65azo8qJiEz2XVDUpK3KYhH3ZQ==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.4.tgz", + "integrity": "sha512-YdaSyz1n8gY44EmN7x44zBn9zQ1Ry2Y+3GTA+3vH6Mizke1Vw0aWDM66FOYEPw8//qKkmqOckrGgTYa+6sceqQ==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.4.tgz", + "integrity": "sha512-EkN3YDB+SRDgiIUnNgcmiD361ti+AVbL3f3Henf6dqqUyr5dMsorno0lJWJuLhDhkI5sYEpgj6y9kB8AOU1I2A==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.10.4.tgz", + "integrity": "sha512-wljroF5PgCk2juF69kanHVs6vrLwIPNp6DLD+Lrl3hoQ3PpPPikaDRNFA+0t81NOoMt2DL6WW/mdU8k4k6ZzuA==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.11.0.tgz", + "integrity": "sha512-JbFlKHFntRV5qKw3YC0CvQnDZ4XMwgzzBbld7Ly4Mj4cbFy3KywcR8NtNctRToMWJOVvLINJv525Gd6wwVEx/Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz", + "integrity": "sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-module-transforms": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.11.0.tgz", + "integrity": "sha512-02EVu8COMuTRO1TAzdMtpBPbe6aQ1w/8fePD2YgQmxZU4gpNWaL9gK3Jp7dxlkUlUCJOTaSeA+Hrm1BRQwqIhg==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/template": "^7.10.4", + "@babel/types": "^7.11.0", + "lodash": "^4.17.19" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.4.tgz", + "integrity": "sha512-n3UGKY4VXwXThEiKrgRAoVPBMqeoPgHVqiHZOanAJCG9nQUL2pLRQirUzl0ioKclHGpGqRgIOkgcIJaIWLpygg==", + "dev": true, + "requires": { + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz", + "integrity": "sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg==", + "dev": true + }, + "@babel/helper-regex": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/helper-regex/-/helper-regex-7.10.5.tgz", + "integrity": "sha512-68kdUAzDrljqBrio7DYAEgCoJHxppJOERHOgOrDN7WjOzP0ZQ1LsSDRXcemzVZaLvjaJsJEESb6qt+znNuENDg==", + "dev": true, + "requires": { + "lodash": "^4.17.19" + } + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.11.4", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.11.4.tgz", + "integrity": "sha512-tR5vJ/vBa9wFy3m5LLv2faapJLnDFxNWff2SAYkSE4rLUdbp7CdObYFgI7wK4T/Mj4UzpjPwzR8Pzmr5m7MHGA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-wrap-function": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-replace-supers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.4.tgz", + "integrity": "sha512-sPxZfFXocEymYTdVK1UNmFPBN+Hv5mJkLPsYWwGBxZAxaWfFu+xqp7b6qWD0yjNuNL2VKc6L5M18tOXUP7NU0A==", + "dev": true, + "requires": { + "@babel/helper-member-expression-to-functions": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-simple-access": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.4.tgz", + "integrity": "sha512-0fMy72ej/VEvF8ULmX6yb5MtHG4uH4Dbd6I/aHDb/JVg0bbivwt9Wg+h3uMvX+QSFtwr5MeItvazbrc4jtRAXw==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.11.0.tgz", + "integrity": "sha512-0XIdiQln4Elglgjbwo9wuJpL/K7AGCY26kmEt0+pRP0TAj4jjyNq1MjoRvikrTVqKcx4Gysxt4cXvVFXP/JO2Q==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.11.0.tgz", + "integrity": "sha512-74Vejvp6mHkGE+m+k5vHY93FX2cAtrw1zXrZXRlG4l410Nm9PxfEiVTn1PjDPV5SnmieiueY4AFg2xqhNFuuZg==", + "dev": true, + "requires": { + "@babel/types": "^7.11.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz", + "integrity": "sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw==", + "dev": true + }, + "@babel/helper-wrap-function": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz", + "integrity": "sha512-6py45WvEF0MhiLrdxtRjKjufwLL1/ob2qDJgg5JgNdojBAZSAKnAjkyOCNug6n+OBl4VW76XjvgSFTdaMcW0Ug==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/helpers": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.4.tgz", + "integrity": "sha512-L2gX/XeUONeEbI78dXSrJzGdz4GQ+ZTA/aazfUsFaWjSe95kiCuOZ5HsXvkiw3iwF+mFHSRUfJU8t6YavocdXA==", + "dev": true, + "requires": { + "@babel/template": "^7.10.4", + "@babel/traverse": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/highlight": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", + "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.11.5.tgz", + "integrity": "sha512-X9rD8qqm695vgmeaQ4fvz/o3+Wk4ZzQvSHkDBgpYKxpD4qTAUm88ZKtHkVqIOsYFFbIQ6wQYhC6q7pjqVK0E0Q==", + "dev": true + }, + "@babel/plugin-proposal-async-generator-functions": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.10.5.tgz", + "integrity": "sha512-cNMCVezQbrRGvXJwm9fu/1sJj9bHdGAgKodZdLqOQIpfoH3raqmRPBM17+lh7CzhiKRRBrGtZL9WcjxSoGYUSg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0" + } + }, + "@babel/plugin-proposal-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.10.4.tgz", + "integrity": "sha512-vhwkEROxzcHGNu2mzUC0OFFNXdZ4M23ib8aRRcJSsW8BZK9pQMD7QB7csl97NBbgGZO7ZyHUyKDnxzOaP4IrCg==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-dynamic-import": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.10.4.tgz", + "integrity": "sha512-up6oID1LeidOOASNXgv/CFbgBqTuKJ0cJjz6An5tWD+NVBNlp3VNSBxv2ZdU7SYl3NxJC7agAQDApZusV6uFwQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0" + } + }, + "@babel/plugin-proposal-export-namespace-from": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.10.4.tgz", + "integrity": "sha512-aNdf0LY6/3WXkhh0Fdb6Zk9j1NMD8ovj3F6r0+3j837Pn1S1PdNtcwJ5EG9WkVPNHPxyJDaxMaAOVq4eki0qbg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-proposal-json-strings": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.10.4.tgz", + "integrity": "sha512-fCL7QF0Jo83uy1K0P2YXrfX11tj3lkpN7l4dMv9Y9VkowkhkQDwFHFd8IiwyK5MZjE8UpbgokkgtcReH88Abaw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.0" + } + }, + "@babel/plugin-proposal-logical-assignment-operators": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.11.0.tgz", + "integrity": "sha512-/f8p4z+Auz0Uaf+i8Ekf1iM7wUNLcViFUGiPxKeXvxTSl63B875YPiVdUDdem7hREcI0E0kSpEhS8tF5RphK7Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-proposal-nullish-coalescing-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.10.4.tgz", + "integrity": "sha512-wq5n1M3ZUlHl9sqT2ok1T2/MTt6AXE0e1Lz4WzWBr95LsAZ5qDXe4KnFuauYyEyLiohvXFMdbsOTMyLZs91Zlw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0" + } + }, + "@babel/plugin-proposal-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.10.4.tgz", + "integrity": "sha512-73/G7QoRoeNkLZFxsoCCvlg4ezE4eM+57PnOqgaPOozd5myfj7p0muD1mRVJvbUWbOzD+q3No2bWbaKy+DJ8DA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-proposal-object-rest-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.11.0.tgz", + "integrity": "sha512-wzch41N4yztwoRw0ak+37wxwJM2oiIiy6huGCoqkvSTA9acYWcPfn9Y4aJqmFFJ70KTJUu29f3DQ43uJ9HXzEA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-transform-parameters": "^7.10.4" + } + }, + "@babel/plugin-proposal-optional-catch-binding": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.10.4.tgz", + "integrity": "sha512-LflT6nPh+GK2MnFiKDyLiqSqVHkQnVf7hdoAvyTnnKj9xB3docGRsdPuxp6qqqW19ifK3xgc9U5/FwrSaCNX5g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0" + } + }, + "@babel/plugin-proposal-optional-chaining": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.11.0.tgz", + "integrity": "sha512-v9fZIu3Y8562RRwhm1BbMRxtqZNFmFA2EG+pT2diuU8PT3H6T/KXoZ54KgYisfOFZHV6PfvAiBIZ9Rcz+/JCxA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0" + } + }, + "@babel/plugin-proposal-private-methods": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.10.4.tgz", + "integrity": "sha512-wh5GJleuI8k3emgTg5KkJK6kHNsGEr0uBTDBuQUBJwckk9xs1ez79ioheEVVxMLyPscB0LfkbVHslQqIzWV6Bw==", + "dev": true, + "requires": { + "@babel/helper-create-class-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-proposal-unicode-property-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.10.4.tgz", + "integrity": "sha512-H+3fOgPnEXFL9zGYtKQe4IDOPKYlZdF1kqFDQRRb8PK4B8af1vAGK04tF5iQAAsui+mHNBQSAtd2/ndEDe9wuA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.4.tgz", + "integrity": "sha512-GCSBF7iUle6rNugfURwNmCGG3Z/2+opxAMLs1nND4bhEG5PuxTIggDBoeYYSujAlLtsupzOHYJQgPS3pivwXIA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.10.4.tgz", + "integrity": "sha512-ni1brg4lXEmWyafKr0ccFWkJG0CeMt4WV1oyeBW6EFObF4oOHclbkj5cARxAPQyAQ2UTuplJyK4nfkXIMMFvsQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.10.4.tgz", + "integrity": "sha512-9J/oD1jV0ZCBcgnoFWFq1vJd4msoKb/TCpGNFyyLt0zABdcvgK3aYikZ8HjzB14c26bc7E3Q1yugpwGy2aTPNA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.10.4.tgz", + "integrity": "sha512-F6nREOan7J5UXTLsDsZG3DXmZSVofr2tGNwfdrVwkDWHfQckbQXnXSPfD7iO+c/2HGqycwyLST3DnZ16n+cBJQ==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-remap-async-to-generator": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.10.4.tgz", + "integrity": "sha512-WzXDarQXYYfjaV1szJvN3AD7rZgZzC1JtjJZ8dMHUyiK8mxPRahynp14zzNjU3VkPqPsO38CzxiWO1c9ARZ8JA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.11.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.11.1.tgz", + "integrity": "sha512-00dYeDE0EVEHuuM+26+0w/SCL0BH2Qy7LwHuI4Hi4MH5gkC8/AqMN5uWFJIsoXZrAphiMm1iXzBw6L2T+eA0ew==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.10.4.tgz", + "integrity": "sha512-2oZ9qLjt161dn1ZE0Ms66xBncQH4In8Sqw1YWgBUZuGVJJS5c0OFZXL6dP2MRHrkU/eKhWg8CzFJhRQl50rQxA==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-define-map": "^7.10.4", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-optimise-call-expression": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.10.4", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.10.4.tgz", + "integrity": "sha512-JFwVDXcP/hM/TbyzGq3l/XWGut7p46Z3QvqFMXTfk6/09m7xZHJUN9xHfsv7vqqD4YnfI5ueYdSJtXqqBLyjBw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.10.4.tgz", + "integrity": "sha512-+WmfvyfsyF603iPa6825mq6Qrb7uLjTOsa3XOFzlYcYDHSS4QmpOWOL0NNBY5qMbvrcf3tq0Cw+v4lxswOBpgA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.10.4.tgz", + "integrity": "sha512-ZEAVvUTCMlMFAbASYSVQoxIbHm2OkG2MseW6bV2JjIygOjdVv8tuxrCTzj1+Rynh7ODb8GivUy7dzEXzEhuPaA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.10.4.tgz", + "integrity": "sha512-GL0/fJnmgMclHiBTTWXNlYjYsA7rDrtsazHG6mglaGSTh0KsrW04qml+Bbz9FL0LcJIRwBWL5ZqlNHKTkU3xAA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.10.4.tgz", + "integrity": "sha512-S5HgLVgkBcRdyQAHbKj+7KyuWx8C6t5oETmUuwz1pt3WTWJhsUV0WIIXuVvfXMxl/QQyHKlSCNNtaIamG8fysw==", + "dev": true, + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.10.4.tgz", + "integrity": "sha512-ItdQfAzu9AlEqmusA/65TqJ79eRcgGmpPPFvBnGILXZH975G0LNjP1yjHvGgfuCxqrPPueXOPe+FsvxmxKiHHQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.10.4.tgz", + "integrity": "sha512-OcDCq2y5+E0dVD5MagT5X+yTRbcvFjDI2ZVAottGH6tzqjx/LKpgkUepu3hp/u4tZBzxxpNGwLsAvGBvQ2mJzg==", + "dev": true, + "requires": { + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.10.4.tgz", + "integrity": "sha512-Xd/dFSTEVuUWnyZiMu76/InZxLTYilOSr1UlHV+p115Z/Le2Fi1KXkJUYz0b42DfndostYlPub3m8ZTQlMaiqQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.10.4.tgz", + "integrity": "sha512-0bFOvPyAoTBhtcJLr9VcwZqKmSjFml1iVxvPL0ReomGU53CX53HsM4h2SzckNdkQcHox1bpAqzxBI1Y09LlBSw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.10.5.tgz", + "integrity": "sha512-elm5uruNio7CTLFItVC/rIzKLfQ17+fX7EVz5W0TMgIHFo1zY0Ozzx+lgwhL4plzl8OzVn6Qasx5DeEFyoNiRw==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.10.4.tgz", + "integrity": "sha512-Xj7Uq5o80HDLlW64rVfDBhao6OX89HKUmb+9vWYaLXBZOma4gA6tw4Ni1O5qVDoZWUV0fxMYA0aYzOawz0l+1w==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-simple-access": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.10.5.tgz", + "integrity": "sha512-f4RLO/OL14/FP1AEbcsWMzpbUz6tssRaeQg11RH1BP/XnPpRoVwgeYViMFacnkaw4k4wjRSjn3ip1Uw9TaXuMw==", + "dev": true, + "requires": { + "@babel/helper-hoist-variables": "^7.10.4", + "@babel/helper-module-transforms": "^7.10.5", + "@babel/helper-plugin-utils": "^7.10.4", + "babel-plugin-dynamic-import-node": "^2.3.3" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.10.4.tgz", + "integrity": "sha512-mohW5q3uAEt8T45YT7Qc5ws6mWgJAaL/8BfWD9Dodo1A3RKWli8wTS+WiQ/knF+tXlPirW/1/MqzzGfCExKECA==", + "dev": true, + "requires": { + "@babel/helper-module-transforms": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.10.4.tgz", + "integrity": "sha512-V6LuOnD31kTkxQPhKiVYzYC/Jgdq53irJC/xBSmqcNcqFGV+PER4l6rU5SH2Vl7bH9mLDHcc0+l9HUOe4RNGKA==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.10.4.tgz", + "integrity": "sha512-YXwWUDAH/J6dlfwqlWsztI2Puz1NtUAubXhOPLQ5gjR/qmQ5U96DY4FQO8At33JN4XPBhrjB8I4eMmLROjjLjw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.10.4.tgz", + "integrity": "sha512-5iTw0JkdRdJvr7sY0vHqTpnruUpTea32JHmq/atIWqsnNussbRzjEDyWep8UNztt1B5IusBYg8Irb0bLbiEBCQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-replace-supers": "^7.10.4" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.10.5.tgz", + "integrity": "sha512-xPHwUj5RdFV8l1wuYiu5S9fqWGM2DrYc24TMvUiRrPVm+SM3XeqU9BcokQX/kEUe+p2RBwy+yoiR1w/Blq6ubw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.10.4.tgz", + "integrity": "sha512-ofsAcKiUxQ8TY4sScgsGeR2vJIsfrzqvFb9GvJ5UdXDzl+MyYCaBj/FGzXuv7qE0aJcjWMILny1epqelnFlz8g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.10.4.tgz", + "integrity": "sha512-3thAHwtor39A7C04XucbMg17RcZ3Qppfxr22wYzZNcVIkPHfpM9J0SO8zuCV6SZa265kxBJSrfKTvDCYqBFXGw==", + "dev": true, + "requires": { + "regenerator-transform": "^0.14.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.10.4.tgz", + "integrity": "sha512-hGsw1O6Rew1fkFbDImZIEqA8GoidwTAilwCyWqLBM9f+e/u/sQMQu7uX6dyokfOayRuuVfKOW4O7HvaBWM+JlQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.10.4.tgz", + "integrity": "sha512-AC2K/t7o07KeTIxMoHneyX90v3zkm5cjHJEokrPEAGEy3UCp8sLKfnfOIGdZ194fyN4wfX/zZUWT9trJZ0qc+Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.11.0.tgz", + "integrity": "sha512-UwQYGOqIdQJe4aWNyS7noqAnN2VbaczPLiEtln+zPowRNlD+79w3oi2TWfYe0eZgd+gjZCbsydN7lzWysDt+gw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-skip-transparent-expression-wrappers": "^7.11.0" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.10.4.tgz", + "integrity": "sha512-Ddy3QZfIbEV0VYcVtFDCjeE4xwVTJWTmUtorAJkn6u/92Z/nWJNV+mILyqHKrUxXYKA2EoCilgoPePymKL4DvQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/helper-regex": "^7.10.4" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.10.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.10.5.tgz", + "integrity": "sha512-V/lnPGIb+KT12OQikDvgSuesRX14ck5FfJXt6+tXhdkJ+Vsd0lDCVtF6jcB4rNClYFzaB2jusZ+lNISDk2mMMw==", + "dev": true, + "requires": { + "@babel/helper-annotate-as-pure": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.10.4.tgz", + "integrity": "sha512-QqNgYwuuW0y0H+kUE/GWSR45t/ccRhe14Fs/4ZRouNNQsyd4o3PG4OtHiIrepbM2WKUBDAXKCAK/Lk4VhzTaGA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.10.4.tgz", + "integrity": "sha512-y5XJ9waMti2J+e7ij20e+aH+fho7Wb7W8rNuu72aKRwCHFqQdhkdU2lo3uZ9tQuboEJcUFayXdARhcxLQ3+6Fg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.10.4.tgz", + "integrity": "sha512-wNfsc4s8N2qnIwpO/WP2ZiSyjfpTamT2C9V9FDH/Ljub9zw6P3SjkXcFmc0RQUt96k2fmIvtla2MMjgTwIAC+A==", + "dev": true, + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/polyfill": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.11.5.tgz", + "integrity": "sha512-FunXnE0Sgpd61pKSj2OSOs1D44rKTD3pGOfGilZ6LGrrIH0QEtJlTjqOqdF8Bs98JmjfGhni2BBkTfv9KcKJ9g==", + "dev": true, + "requires": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/preset-env": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.11.5.tgz", + "integrity": "sha512-kXqmW1jVcnB2cdueV+fyBM8estd5mlNfaQi6lwLgRwCby4edpavgbFhiBNjmWA3JpB/yZGSISa7Srf+TwxDQoA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.11.0", + "@babel/helper-compilation-targets": "^7.10.4", + "@babel/helper-module-imports": "^7.10.4", + "@babel/helper-plugin-utils": "^7.10.4", + "@babel/plugin-proposal-async-generator-functions": "^7.10.4", + "@babel/plugin-proposal-class-properties": "^7.10.4", + "@babel/plugin-proposal-dynamic-import": "^7.10.4", + "@babel/plugin-proposal-export-namespace-from": "^7.10.4", + "@babel/plugin-proposal-json-strings": "^7.10.4", + "@babel/plugin-proposal-logical-assignment-operators": "^7.11.0", + "@babel/plugin-proposal-nullish-coalescing-operator": "^7.10.4", + "@babel/plugin-proposal-numeric-separator": "^7.10.4", + "@babel/plugin-proposal-object-rest-spread": "^7.11.0", + "@babel/plugin-proposal-optional-catch-binding": "^7.10.4", + "@babel/plugin-proposal-optional-chaining": "^7.11.0", + "@babel/plugin-proposal-private-methods": "^7.10.4", + "@babel/plugin-proposal-unicode-property-regex": "^7.10.4", + "@babel/plugin-syntax-async-generators": "^7.8.0", + "@babel/plugin-syntax-class-properties": "^7.10.4", + "@babel/plugin-syntax-dynamic-import": "^7.8.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.0", + "@babel/plugin-syntax-optional-chaining": "^7.8.0", + "@babel/plugin-syntax-top-level-await": "^7.10.4", + "@babel/plugin-transform-arrow-functions": "^7.10.4", + "@babel/plugin-transform-async-to-generator": "^7.10.4", + "@babel/plugin-transform-block-scoped-functions": "^7.10.4", + "@babel/plugin-transform-block-scoping": "^7.10.4", + "@babel/plugin-transform-classes": "^7.10.4", + "@babel/plugin-transform-computed-properties": "^7.10.4", + "@babel/plugin-transform-destructuring": "^7.10.4", + "@babel/plugin-transform-dotall-regex": "^7.10.4", + "@babel/plugin-transform-duplicate-keys": "^7.10.4", + "@babel/plugin-transform-exponentiation-operator": "^7.10.4", + "@babel/plugin-transform-for-of": "^7.10.4", + "@babel/plugin-transform-function-name": "^7.10.4", + "@babel/plugin-transform-literals": "^7.10.4", + "@babel/plugin-transform-member-expression-literals": "^7.10.4", + "@babel/plugin-transform-modules-amd": "^7.10.4", + "@babel/plugin-transform-modules-commonjs": "^7.10.4", + "@babel/plugin-transform-modules-systemjs": "^7.10.4", + "@babel/plugin-transform-modules-umd": "^7.10.4", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.10.4", + "@babel/plugin-transform-new-target": "^7.10.4", + "@babel/plugin-transform-object-super": "^7.10.4", + "@babel/plugin-transform-parameters": "^7.10.4", + "@babel/plugin-transform-property-literals": "^7.10.4", + "@babel/plugin-transform-regenerator": "^7.10.4", + "@babel/plugin-transform-reserved-words": "^7.10.4", + "@babel/plugin-transform-shorthand-properties": "^7.10.4", + "@babel/plugin-transform-spread": "^7.11.0", + "@babel/plugin-transform-sticky-regex": "^7.10.4", + "@babel/plugin-transform-template-literals": "^7.10.4", + "@babel/plugin-transform-typeof-symbol": "^7.10.4", + "@babel/plugin-transform-unicode-escapes": "^7.10.4", + "@babel/plugin-transform-unicode-regex": "^7.10.4", + "@babel/preset-modules": "^0.1.3", + "@babel/types": "^7.11.5", + "browserslist": "^4.12.0", + "core-js-compat": "^3.6.2", + "invariant": "^2.2.2", + "levenary": "^1.1.1", + "semver": "^5.5.0" + } + }, + "@babel/preset-modules": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.4.tgz", + "integrity": "sha512-J36NhwnfdzpmH41M1DrnkkgAqhZaqr/NBdPfQ677mLzlaXo+oDiv1deyCDtgAhz8p328otdob0Du7+xgHGZbKg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", + "@babel/plugin-transform-dotall-regex": "^7.4.4", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/runtime": { + "version": "7.11.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.11.2.tgz", + "integrity": "sha512-TeWkU52so0mPtDcaCTxNBI/IHiz0pZgr8VEFqXFtZWpYD08ZB6FaSwVAS8MKRQAP3bYKiVjwysOJgMFY28o6Tw==", + "dev": true, + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/template": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.10.4.tgz", + "integrity": "sha512-ZCjD27cGJFUB6nmCB1Enki3r+L5kJveX9pq1SvAUKoICy6CZ9yD8xO086YXdYhvNjBdnekm4ZnaP5yC8Cs/1tA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/parser": "^7.10.4", + "@babel/types": "^7.10.4" + } + }, + "@babel/traverse": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.11.5.tgz", + "integrity": "sha512-EjiPXt+r7LiCZXEfRpSJd+jUMnBd4/9OUv7Nx3+0u9+eimMwJmG0Q98lw4/289JCoxSE8OolDMNZaaF/JZ69WQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "@babel/generator": "^7.11.5", + "@babel/helper-function-name": "^7.10.4", + "@babel/helper-split-export-declaration": "^7.11.0", + "@babel/parser": "^7.11.5", + "@babel/types": "^7.11.5", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.19" + } + }, + "@babel/types": { + "version": "7.11.5", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.11.5.tgz", + "integrity": "sha512-bvM7Qz6eKnJVFIn+1LPtjlBFPVN5jNDc1XmN15vWe7Q3DPBufWWsLiIvUu7xW87uTG6QoggpIDnUgLQvPheU+Q==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.10.4", + "lodash": "^4.17.19", + "to-fast-properties": "^2.0.0" + } + }, + "@rollup/plugin-babel": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.2.1.tgz", + "integrity": "sha512-Jd7oqFR2dzZJ3NWANDyBjwTtX/lYbZpVcmkHrfQcpvawHs9E4c0nYk5U2mfZ6I/DZcIvy506KZJi54XK/jxH7A==", + "dev": true, + "requires": { + "@babel/helper-module-imports": "^7.10.4", + "@rollup/pluginutils": "^3.1.0" + } + }, + "@rollup/pluginutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz", + "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==", + "dev": true, + "requires": { + "@types/estree": "0.0.39", + "estree-walker": "^1.0.1", + "picomatch": "^2.2.2" + } + }, + "@types/babel__core": { + "version": "7.1.12", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.12.tgz", + "integrity": "sha512-wMTHiiTiBAAPebqaPiPDLFA4LYPKr6Ph0Xq/6rq1Ur3v66HXyG+clfR9CNETkD7MQS8ZHvpQOtA53DLws5WAEQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.2.tgz", + "integrity": "sha512-MdSJnBjl+bdwkLskZ3NGFp9YcXGx5ggLpQQPqtgakVhsWK0hTtNYhjpZLlWQTviGTvF8at+Bvli3jV7faPdgeQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.0.tgz", + "integrity": "sha512-NTPErx4/FiPCGScH7foPyr+/1Dkzkni+rHiYHHoTjvwou7AQzJkNeD60A9CXRy+ZEN2B1bggmkTMCDb+Mv5k+A==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.11.0.tgz", + "integrity": "sha512-kSjgDMZONiIfSH1Nxcr5JIRMwUetDki63FSQfpTCz8ogF3Ulqm8+mr5f78dUYs6vMiB6gBusQqfQmBvHZj/lwg==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/color-name": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz", + "integrity": "sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ==", + "dev": true + }, + "@types/estree": { + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz", + "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==", + "dev": true + }, + "@types/node": { + "version": "14.11.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.2.tgz", + "integrity": "sha512-jiE3QIxJ8JLNcb1Ps6rDbysDhN4xa8DJJvuC9prr6w+1tIh+QAbYyNF3tyiZNLDBIuBCf4KEcV2UvQm/V60xfA==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + }, + "babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "requires": { + "object.assign": "^4.1.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "basic-auth": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz", + "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "browserslist": { + "version": "4.20.3", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", + "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001332", + "electron-to-chromium": "^1.4.118", + "escalade": "^3.1.1", + "node-releases": "^2.0.3", + "picocolors": "^1.0.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001344", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001344.tgz", + "integrity": "sha512-0ZFjnlCaXNOAYcV7i+TtdKBp0L/3XEU2MF/x6Du1lrh+SRX4IfzIVL4HNJg5pB2PmFb8rszIGyOvsZnqqRoc2g==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concurrently": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-5.3.0.tgz", + "integrity": "sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "date-fns": "^2.0.1", + "lodash": "^4.17.15", + "read-pkg": "^4.0.1", + "rxjs": "^6.5.2", + "spawn-command": "^0.0.2-1", + "supports-color": "^6.1.0", + "tree-kill": "^1.2.2", + "yargs": "^13.3.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "convert-source-map": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", + "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copyfiles": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.3.0.tgz", + "integrity": "sha512-73v7KFuDFJ/ofkQjZBMjMBFWGgkS76DzXvBMUh7djsMOE5EELWtAO/hRB6Wr5Vj5Zg+YozvoHemv0vnXpqxmOQ==", + "dev": true, + "requires": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "yargs": "^15.3.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz", + "integrity": "sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA==", + "dev": true, + "requires": { + "@types/color-name": "^1.1.1", + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "string-width": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", + "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "strip-ansi": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dev": true, + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } + }, + "core-js": { + "version": "2.6.11", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.11.tgz", + "integrity": "sha512-5wjnpaT/3dV+XB4borEsnAYQchn00XSgTAWKDkEqv+K8KevjbzmofK6hfJ9TZIlpj2N0xQpazy7PiRQiWHqzWg==", + "dev": true + }, + "core-js-compat": { + "version": "3.6.5", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.6.5.tgz", + "integrity": "sha512-7ItTKOhOZbznhXAQ2g/slGg1PJV5zDO/WdkTwi7UEOJmkvsE32PWvx6mKtDjiMpjnR2CNf6BAD6sSxIlv7ptng==", + "dev": true, + "requires": { + "browserslist": "^4.8.5", + "semver": "7.0.0" + }, + "dependencies": { + "semver": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", + "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", + "dev": true + } + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "corser": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/corser/-/corser-2.0.1.tgz", + "integrity": "sha1-jtolLsqrWEDc2XXOuQ2TcMgZ/4c=", + "dev": true + }, + "date-fns": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.16.1.tgz", + "integrity": "sha512-sAJVKx/FqrLYHAQeN7VpJrPhagZc9R4ImZIWYRFZaaohR3KzmuK88touwsSwSVT8Qcbd4zoDsnGfX4GFB4imyQ==", + "dev": true + }, + "debug": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.2.0.tgz", + "integrity": "sha512-IX2ncY78vDTjZMFUdmsvIRFY2Cf4FnD0wRs+nQwJU8Lu99/tPFdb0VybiiMTPe3I6rQmwsqQqRBvxU+bZ/I8sg==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "ecstatic": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/ecstatic/-/ecstatic-3.3.2.tgz", + "integrity": "sha512-fLf9l1hnwrHI2xn9mEDT7KIi22UDqA2jaCwyCbSUJh9a1V+LEUSL/JO/6TIz/QyuBURWUHrFL5Kg2TtO1bkkog==", + "dev": true, + "requires": { + "he": "^1.1.1", + "mime": "^1.6.0", + "minimist": "^1.1.0", + "url-join": "^2.0.5" + } + }, + "electron-to-chromium": { + "version": "1.4.141", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.141.tgz", + "integrity": "sha512-mfBcbqc0qc6RlxrsIgLG2wCqkiPAjEezHxGTu7p3dHHFOurH4EjS9rFZndX5axC8264rI1Pcbw8uQP39oZckeA==", + "dev": true + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.0-next.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0-next.0.tgz", + "integrity": "sha512-elZXTZXKn51hUBdJjSZGYRujuzilgXo8vSPQzjGYXLvSlGiCo8VO8ZGV3kjo9a0WNJJ57hENagwbtlRuHuzkcQ==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-negative-zero": "^2.0.0", + "is-regex": "^1.1.1", + "object-inspect": "^1.8.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "estree-walker": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz", + "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", + "dev": true + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "follow-redirects": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.1.tgz", + "integrity": "sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.1.3.tgz", + "integrity": "sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gensync": { + "version": "1.0.0-beta.1", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz", + "integrity": "sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "hammerjs": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/hammerjs/-/hammerjs-2.0.8.tgz", + "integrity": "sha1-BO93hiz/K7edMPdpIJWTAiK/YPE=" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", + "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", + "dev": true + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dev": true, + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-server": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/http-server/-/http-server-0.12.3.tgz", + "integrity": "sha512-be0dKG6pni92bRjq0kvExtj/NrrAd28/8fCXkaI/4piTwQMSDSLMhWyW0NI1V+DBI3aa1HMlQu46/HjVLfmugA==", + "dev": true, + "requires": { + "basic-auth": "^1.0.3", + "colors": "^1.4.0", + "corser": "^2.0.1", + "ecstatic": "^3.3.2", + "http-proxy": "^1.18.0", + "minimist": "^1.2.5", + "opener": "^1.5.1", + "portfinder": "^1.0.25", + "secure-compare": "3.0.1", + "union": "~0.5.0" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-callable": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.2.tgz", + "integrity": "sha512-dnMqspv5nU3LoewK2N/y7KLtxtakvTuaCsU9FU50/QDmdbHNy/4/JuRtMHqRU22o3q+W89YQndQEeCVwK+3qrA==", + "dev": true + }, + "is-date-object": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-negative-zero": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.0.tgz", + "integrity": "sha1-lVOxIbD6wohp2p7UWeIMdUN4hGE=", + "dev": true + }, + "is-regex": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.1.tgz", + "integrity": "sha512-1+QkEcxiLlB7VEyFtyBg94e08OAsvq7FUBgApTq/w2ymCLyKJgDPsybBENVtA7XCQEgEXxKPonG+mvYRxh/LIg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.1" + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "dev": true + }, + "jest-worker": { + "version": "26.3.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.3.0.tgz", + "integrity": "sha512-Vmpn2F6IASefL+DVBhPzI2J9/GJUsqzomdeN+P+dK8/jKxbh8R3BtFnx3FIta7wYlPU62cpJMJQo4kuOowcMnw==", + "dev": true, + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^7.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json5": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", + "integrity": "sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levenary": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/levenary/-/levenary-1.1.1.tgz", + "integrity": "sha512-mkAdOIt79FD6irqjYSs4rdbnlT5vRonMEvBVPVb3XmevfS8kgRXwfes0dhPdEtzTWD/1eNE/Bm/G1iRt6DcnQQ==", + "dev": true, + "requires": { + "leven": "^3.1.0" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node-releases": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.5.tgz", + "integrity": "sha512-U9h1NLROZTq9uE1SNffn6WuPDg8icmi3ns4rEl/oTfIle4iLjTliCzgTsbaIFMq/Xn078/lfY/BL0GWZ+psK4Q==", + "dev": true + }, + "noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "object-inspect": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz", + "integrity": "sha512-jLdtEOB112fORuypAyl/50VRVIBIdVQOSUUGQHzJ4xBSbit81zRarz7GThkEFZy1RceYrWYcPcBFPQwHyAc1gA==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.1.tgz", + "integrity": "sha512-VT/cxmx5yaoHSOTSyrCygIDFco+RsibY2NM0a4RdEeY/4KgqezwFtK1yr3U67xYhqJSlASm2pKhLVzPj2lr4bA==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.0", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "opener": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz", + "integrity": "sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==", + "dev": true + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.2.2.tgz", + "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==", + "dev": true + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "dev": true, + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "qs": { + "version": "6.9.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.4.tgz", + "integrity": "sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "read-pkg": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-4.0.1.tgz", + "integrity": "sha1-ljYlN48+HE1IyFhytabsfV0JMjc=", + "dev": true, + "requires": { + "normalize-package-data": "^2.3.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0" + } + }, + "readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "regenerate": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.1.tgz", + "integrity": "sha512-j2+C8+NtXQgEKWk49MMP5P/u2GhnahTtVkRIHr5R5lVRlbKvmQ+oS+A5aLKWp2ma5VkT8sh6v+v4hbH0YHR66A==", + "dev": true + }, + "regenerate-unicode-properties": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-8.2.0.tgz", + "integrity": "sha512-F9DjY1vKLo/tPePDycuH3dn9H1OTPIkVD9Kz4LODu+F2C75mgjAJ7x/gwy6ZcSNRAAkhNlJSOHRe8k3p+K9WhA==", + "dev": true, + "requires": { + "regenerate": "^1.4.0" + } + }, + "regenerator-runtime": { + "version": "0.13.7", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", + "dev": true + }, + "regenerator-transform": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz", + "integrity": "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw==", + "dev": true, + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regexpu-core": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.7.1.tgz", + "integrity": "sha512-ywH2VUraA44DZQuRKzARmw6S66mr48pQVva4LBeRhcOltJ6hExvWly5ZjFLYo67xbIxb6W1q4bAGtgfEl20zfQ==", + "dev": true, + "requires": { + "regenerate": "^1.4.0", + "regenerate-unicode-properties": "^8.2.0", + "regjsgen": "^0.5.1", + "regjsparser": "^0.6.4", + "unicode-match-property-ecmascript": "^1.0.4", + "unicode-match-property-value-ecmascript": "^1.2.0" + } + }, + "regjsgen": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz", + "integrity": "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==", + "dev": true + }, + "regjsparser": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.6.4.tgz", + "integrity": "sha512-64O87/dPDgfk8/RQqC4gkZoGyyWFIEUTTh80CU6CWuK5vkCGyekIx+oKcEIYtP/RAxSQltCZHCNu/mdd7fqlJw==", + "dev": true, + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", + "dev": true + } + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz", + "integrity": "sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "rollup": { + "version": "2.28.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.28.2.tgz", + "integrity": "sha512-8txbsFBFLmm9Xdt4ByTOGa9Muonmc8MfNjnGAR8U8scJlF1ZW7AgNZa7aqBXaKtlvnYP/ab++fQIq9dB9NWUbg==", + "dev": true, + "requires": { + "fsevents": "~2.1.2" + } + }, + "rollup-plugin-terser": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz", + "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.10.4", + "jest-worker": "^26.2.1", + "serialize-javascript": "^4.0.0", + "terser": "^5.0.0" + } + }, + "rxjs": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", + "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "secure-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/secure-compare/-/secure-compare-3.0.1.tgz", + "integrity": "sha1-8aAymzCLIh+uN7mXTz1XjQypmeM=", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "serialize-javascript": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz", + "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-support": { + "version": "0.5.19", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz", + "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "spawn-command": { + "version": "0.0.2-1", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz", + "integrity": "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.6.tgz", + "integrity": "sha512-+orQK83kyMva3WyPf59k1+Y525csj5JejicWut55zeTWANuN17qSiSLUXWtzHeNWORSvT7GLDJ/E/XiIWoXBTw==", + "dev": true + }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", + "dev": true + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz", + "integrity": "sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "string.prototype.trimstart": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz", + "integrity": "sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + }, + "dependencies": { + "es-abstract": { + "version": "1.17.6", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.6.tgz", + "integrity": "sha512-Fr89bON3WFyUi5EvAeI48QTWX0AyekGgLA8H+c+7fbfCkJwRWRMLd8CQedNEyJuoYYhmtEqY92pgte1FAhBlhw==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1", + "is-callable": "^1.2.0", + "is-regex": "^1.1.0", + "object-inspect": "^1.7.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.0", + "string.prototype.trimend": "^1.0.1", + "string.prototype.trimstart": "^1.0.1" + } + } + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "terser": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.3.2.tgz", + "integrity": "sha512-H67sydwBz5jCUA32ZRL319ULu+Su1cAoZnnc+lXnenGRYWyLE3Scgkt8mNoAsMx0h5kdo758zdoS0LG9rYZXDQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "three": { + "version": "0.123.0", + "resolved": "https://registry.npmjs.org/three/-/three-0.123.0.tgz", + "integrity": "sha512-KNnx/IbilvoHRkxOtL0ouozoDoElyuvAXhFB21RK7F5IPWSmqyFelICK6x3hJerLNSlAdHxR0hkuvMMhH9pqXg==" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + } + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true + }, + "tslib": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.13.0.tgz", + "integrity": "sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==", + "dev": true + }, + "unicode-canonical-property-names-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", + "integrity": "sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==", + "dev": true + }, + "unicode-match-property-ecmascript": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz", + "integrity": "sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==", + "dev": true, + "requires": { + "unicode-canonical-property-names-ecmascript": "^1.0.4", + "unicode-property-aliases-ecmascript": "^1.0.4" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.2.0.tgz", + "integrity": "sha512-wjuQHGQVofmSJv1uVISKLE5zO2rNGzM/KCYZch/QQvez7C1hUhBIuZ701fYXExuufJFMPhv2SyL8CyoIfMLbIQ==", + "dev": true + }, + "unicode-property-aliases-ecmascript": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.1.0.tgz", + "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", + "dev": true + }, + "union": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/union/-/union-0.5.0.tgz", + "integrity": "sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==", + "dev": true, + "requires": { + "qs": "^6.4.0" + } + }, + "url-join": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-2.0.5.tgz", + "integrity": "sha1-WvIvGMBSoACkjXuCxenC4v7tpyg=", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true + }, + "y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + } + } +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/package.json b/BlueMapCommon/BlueMapVue/BlueMapWeb/package.json new file mode 100644 index 00000000..7b7c6450 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/package.json @@ -0,0 +1,43 @@ +{ + "name": "bluemap", + "version": "1.1.0", + "description": "A library to load and display Minecraft maps generated by BlueMap.", + "repository": { + "type": "git", + "url": "https://github.com/BlueMap-Minecraft/BlueMapWeb.git" + }, + "keywords": [ + "minecraft", + "minecraft-mod", + "minecraft-plugin", + "threejs", + "webgl", + "bluemap" + ], + "author": "Lukas Rieger (https://bluecolored.de/)", + "license": "MIT", + "bugs": { + "url": "https://github.com/BlueMap-Minecraft/BlueMap/issues" + }, + "homepage": "https://bluecolo.red/bluemap", + "dependencies": { + "hammerjs": "~2.0.8", + "three": "~0.123.0" + }, + "devDependencies": { + "@babel/core": "~7.11.6", + "@babel/plugin-proposal-class-properties": "~7.10.4", + "@babel/polyfill": "~7.11.5", + "@babel/preset-env": "~7.11.5", + "@rollup/plugin-babel": "~5.2.1", + "@types/babel__core": "~7.1.9", + "concurrently": "~5.3.0", + "copyfiles": "~2.3.0", + "http-server": "~0.12.3", + "rollup": "~2.28.2", + "rollup-plugin-terser": "~7.0.2" + }, + "scripts": { + "build": "rollup -c" + } +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/rollup-test.config.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/rollup-test.config.js new file mode 100644 index 00000000..6d8ca3a6 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/rollup-test.config.js @@ -0,0 +1,44 @@ +import babel from "@rollup/plugin-babel"; +import { terser } from "rollup-plugin-terser"; + +const babelrc = { + babelHelpers: 'bundled', + presets: [ + ['@babel/preset-env', { + targets: "> 0.25%, not dead", + bugfixes: true, + loose: true + }] + ], + plugins: [ + ['@babel/plugin-proposal-class-properties', { + loose: true + }] + ] +}; + +export default [ + { + input: 'src/BlueMap.js', + external: [ 'three', 'hammerjs' ], + plugins: [ + babel( { + compact: false, + babelrc: false, + ...babelrc + } ) + ], + output: [ + { + format: 'umd', + name: 'BlueMap', + file: 'build/bluemap.js', + indent: '\t', + globals: { + three: 'THREE', + hammerjs: 'Hammer', + } + } + ], + } +]; \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/rollup.config.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/rollup.config.js new file mode 100644 index 00000000..7babb5fc --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/rollup.config.js @@ -0,0 +1,77 @@ +import babel from "@rollup/plugin-babel"; +import { terser } from "rollup-plugin-terser"; + +const babelrc = { + babelHelpers: 'bundled', + presets: [ + ['@babel/preset-env', { + targets: "> 0.25%, not dead", + bugfixes: true, + loose: true + }] + ], + plugins: [ + ['@babel/plugin-proposal-class-properties', { + loose: true + }] + ] +}; + +export default [ + { + input: 'src/BlueMap.js', + external: [ 'three', 'hammerjs' ], + plugins: [ + babel( { + compact: false, + babelrc: false, + ...babelrc + } ) + ], + output: [ + { + format: 'umd', + name: 'BlueMap', + file: 'build/bluemap.js', + indent: '\t', + globals: { + three: 'THREE', + hammerjs: 'Hammer', + } + } + ], + }, + { + input: 'src/BlueMap.js', + external: [ 'three', 'hammerjs' ], + plugins: [ + babel( { + babelrc: false, + ...babelrc + } ), + terser(), + ], + output: [ + { + format: 'umd', + name: 'BlueMap', + file: 'build/bluemap.min.js', + globals: { + three: 'THREE', + hammerjs: 'Hammer', + } + } + ] + }, + { + input: 'src/BlueMap.js', + external: [ 'three', 'hammerjs' ], + plugins: [], + output: [ + { + format: 'esm', + file: 'build/bluemap.module.js' + } + ] + } +]; \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/BlueMap.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/BlueMap.js new file mode 100644 index 00000000..dbfb1d64 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/BlueMap.js @@ -0,0 +1,67 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Object3D} from "three"; + +export * from "./MapViewer"; + +export * from "./map/Map"; +export * from "./map/Tile"; +export * from "./map/TileLoader"; +export * from "./map/TileManager"; +export * from "./map/TileMap"; + +export * from "./markers/ExtrudeMarker"; +export * from "./markers/HtmlMarker"; +export * from "./markers/LineMarker"; +export * from "./markers/Marker"; +export * from "./markers/MarkerManager"; +export * from "./markers/MarkerSet"; +export * from "./markers/PlayerMarkerSet"; +export * from "./markers/ObjectMarker"; +export * from "./markers/PlayerMarker"; +export * from "./markers/PoiMarker"; +export * from "./markers/ShapeMarker"; + +export * from "./controls/map/MapControls"; +export * from "./controls/freeflight/FreeFlightControls"; + +export * from "./util/CombinedCamera"; +export * from "./util/Utils"; + +/** + * @param event {object} + * @return {boolean} - whether the event has been consumed (true) or not (false) + */ +Object3D.prototype.onClick = function(event) { + + if (this.parent){ + if (!Array.isArray(event.eventStack)) event.eventStack = []; + event.eventStack.push(this); + + return this.parent.onClick(event);asd + } + + return false; +}; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/MapViewer.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/MapViewer.js new file mode 100644 index 00000000..ba6150df --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/MapViewer.js @@ -0,0 +1,492 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Color, PerspectiveCamera, Raycaster, Scene, Vector2, Vector3, WebGLRenderer} from "three"; +import {Map} from "./map/Map"; +import {SkyboxScene} from "./skybox/SkyboxScene"; +import {ControlsManager} from "./controls/ControlsManager"; +import Stats from "./util/Stats"; +import {alert, dispatchEvent, elementOffset, generateCacheHash, htmlToElement, softClamp} from "./util/Utils"; +import {TileManager} from "./map/TileManager"; +import {HIRES_VERTEX_SHADER} from "./map/hires/HiresVertexShader"; +import {HIRES_FRAGMENT_SHADER} from "./map/hires/HiresFragmentShader"; +import {LOWRES_VERTEX_SHADER} from "./map/lowres/LowresVertexShader"; +import {LOWRES_FRAGMENT_SHADER} from "./map/lowres/LowresFragmentShader"; +import {CombinedCamera} from "./util/CombinedCamera"; +import {CSS2DRenderer} from "./util/CSS2DRenderer"; +import {MarkerSet} from "./markers/MarkerSet"; + +export class MapViewer { + + /** + * @param element {Element} + * @param events {EventTarget} + */ + constructor(element, events = element) { + Object.defineProperty( this, 'isMapViewer', { value: true } ); + + this.rootElement = element; + this.events = events; + + this.data = { + map: null, + camera: null, + controlsManager: null, + uniforms: { + sunlightStrength: { value: 1 }, + ambientLight: { value: 0 }, + skyColor: { value: new Color(0.5, 0.5, 1) }, + hiresTileMap: { + value: { + map: null, + size: TileManager.tileMapSize, + scale: new Vector2(1, 1), + translate: new Vector2(), + pos: new Vector2(), + } + } + }, + superSampling: 1, + loadedCenter: new Vector2(0, 0), + loadedHiresViewDistance: 200, + loadedLowresViewDistance: 2000, + } + + this.tileCacheHash = generateCacheHash(); + + this.stats = new Stats(); + this.stats.hide(); + + // renderer + this.renderer = new WebGLRenderer({ + antialias: true, + sortObjects: true, + preserveDrawingBuffer: true, + logarithmicDepthBuffer: true, + }); + this.renderer.autoClear = false; + this.renderer.uniforms = this.data.uniforms; + + // CSS2D renderer + this.css2dRenderer = new CSS2DRenderer(this.events); + + this.skyboxScene = new SkyboxScene(this.data.uniforms); + + this.camera = new CombinedCamera(75, 1, 0.1, 10000, 0); + this.skyboxCamera = new PerspectiveCamera(75, 1, 0.1, 10000); + this.skyboxCamera.updateProjectionMatrix(); + + this.controlsManager = new ControlsManager(this, this.camera); + + this.raycaster = new Raycaster(); + this.raycaster.layers.enableAll(); + this.raycaster.params.Line2 = {threshold: 20} + + /** @type {Map} */ + this.map = null; + + this.markers = new MarkerSet("bm-root"); + + this.lastFrame = 0; + + // initialize + this.initializeRootElement(); + + // handle window resizes + window.addEventListener("resize", this.handleContainerResize); + + // start render-loop + requestAnimationFrame(this.renderLoop); + } + + /** + * Initializes the root-element + */ + initializeRootElement() { + this.rootElement.innerHTML = ""; + + let outerDiv = htmlToElement(`
`); + this.rootElement.appendChild(outerDiv); + + // 3d-canvas + outerDiv.appendChild(this.renderer.domElement); + + // html-markers + this.css2dRenderer.domElement.style.position = 'absolute'; + this.css2dRenderer.domElement.style.top = '0'; + this.css2dRenderer.domElement.style.left = '0'; + this.css2dRenderer.domElement.style.pointerEvents = 'none'; + outerDiv.appendChild(this.css2dRenderer.domElement); + + // performance monitor + outerDiv.appendChild(this.stats.dom); + + this.handleContainerResize(); + } + + /** + * Updates the render-resolution and aspect ratio based on the size of the root-element + */ + handleContainerResize = () => { + this.renderer.setSize(this.rootElement.clientWidth, this.rootElement.clientHeight); + this.renderer.setPixelRatio(window.devicePixelRatio * this.superSampling); + + this.css2dRenderer.setSize(this.rootElement.clientWidth, this.rootElement.clientHeight); + + this.camera.aspect = this.rootElement.clientWidth / this.rootElement.clientHeight; + this.camera.updateProjectionMatrix(); + }; + + /** + * Triggers an interaction on the screen (map), e.g. a mouse-click. + * + * This will first attempt to invoke the onClick() method on the Object3D (e.g. Markers) that has been clicked. + * And if none of those consumed the event, it will fire a bluemapMapInteraction event. + * + * @param screenPosition {Vector2} - Clicked position on the screen (usually event.x, event.y) + * @param data {object} - Custom event data that will be added to the interaction-event + */ + handleMapInteraction(screenPosition, data = {}) { + let rootOffset = elementOffset(this.rootElement); + let normalizedScreenPos = new Vector2( + ((screenPosition.x - rootOffset.top) / this.rootElement.clientWidth) * 2 - 1, + -((screenPosition.y - rootOffset.left) / this.rootElement.clientHeight) * 2 + 1 + ); + + if (this.map && this.map.isLoaded){ + this.raycaster.setFromCamera(normalizedScreenPos, this.camera); + + // check Object3D interactions + const intersectScenes = [this.map.hiresTileManager.scene, this.markers]; + for (let i = 0; i < this.map.lowresTileManager.length; i++) { + intersectScenes.push(this.map.lowresTileManager[i].scene); + } + + let intersects = this.raycaster.intersectObjects(intersectScenes, true); + let hit = null; + let lowresHits = []; + let hiresHit = null; + let covered = false; + + for (let i = 0; i < intersects.length; i++) { + if (intersects[i].object){ + let object = intersects[i].object; + + // check if deeply-visible + let parent = object; + let visible = parent.visible; + while (visible && parent.parent){ + parent = parent.parent; + visible = parent.visible; + } + + if (visible) { + if (!hit) hit = intersects[i]; + + // find root-scene + let parentRoot = object; + while(parentRoot.parent) parentRoot = parentRoot.parent; + + for (let l = 0; l < this.map.lowresTileManager.length; l++) { + if (parentRoot === this.map.lowresTileManager[l].sceneParent) { + if (!lowresHits[l]) lowresHits[l] = intersects[i]; + } + } + + if (parentRoot === this.map.hiresTileManager.sceneParent) { + if (!hiresHit) hiresHit = intersects[i]; + } + + if (!covered || (object.material && !object.material.depthTest)) { + if (object.onClick && object.onClick({ + data: data, + intersection: intersects[i] + })) return; + } + + if (parentRoot !== this.map.lowresTileManager[0].sceneParent) { + covered = true; + } + } + } + } + + // fire event + dispatchEvent(this.events, "bluemapMapInteraction", { + data: data, + hit: hit, + hiresHit: hiresHit, + lowresHits: lowresHits, + intersections: intersects, + ray: this.raycaster.ray + }); + } + } + + /** + * @private + * The render-loop to update and possibly render a new frame. + * @param now {number} the current time in milliseconds + */ + renderLoop = (now) => { + requestAnimationFrame(this.renderLoop); + + // calculate delta time + if (this.lastFrame <= 0) this.lastFrame = now; + let delta = now - this.lastFrame; + this.lastFrame = now; + + // update stats + this.stats.begin(); + + // update controls + if (this.map != null) { + this.controlsManager.update(delta, this.map); + } + + // render + this.render(delta); + + // update stats + this.stats.update(); + }; + + /** + * @private + * Renders a frame + * @param delta {number} + */ + render(delta) { + dispatchEvent(this.events, "bluemapRenderFrame", { + delta: delta, + }); + + // render + this.renderer.clear(); + + // prepare skybox camera + this.skyboxCamera.rotation.copy(this.camera.rotation); + + // render skybox + this.renderer.render(this.skyboxScene, this.skyboxCamera); + this.renderer.clearDepth(); + + if (this.map && this.map.isLoaded) { + + // shift whole scene including camera towards 0,0 to tackle shader-precision issues + const s = 10000; + const sX = Math.round(this.camera.position.x / s) * s; + const sZ = Math.round(this.camera.position.z / s) * s; + this.camera.position.x -= sX; + this.camera.position.z -= sZ; + + // update uniforms + this.data.uniforms.hiresTileMap.value.pos.copy(this.map.hiresTileManager.centerTile); + this.data.uniforms.hiresTileMap.value.translate.set( + this.map.data.hires.translate.x - sX, + this.map.data.hires.translate.z - sZ + ); + + // prepare camera for lowres + const cameraFar = this.camera.far; + if (this.controlsManager.distance < 1000) { + this.camera.far = 1000000; // disable far clipping for lowres + } + this.camera.updateProjectionMatrix(); + + // render lowres + const highestLod = this.map.lowresTileManager.length - 1; + for (let i = this.map.lowresTileManager.length - 1; i >= 0; i--) { + if (i === highestLod || this.controlsManager.distance < 1000 * Math.pow(this.map.data.lowres.lodFactor, i + 1)) { + let scenePos = this.map.lowresTileManager[i].scene.position; + scenePos.x = -sX; + scenePos.z = -sZ; + + if (i === 0) { + this.camera.far = cameraFar; // reset far clipping for the highest lowres lod to make depth-tests possible + this.camera.updateProjectionMatrix(); + } + + this.renderer.render(this.map.lowresTileManager[i].sceneParent, this.camera); + + if (i !== 0) this.renderer.clearDepth(); // clear depth-buffer for all lowres except the highest + } + } + + this.camera.far = cameraFar; // reset far clipping + + // render hires + if (this.controlsManager.distance < 1000) { + this.camera.updateProjectionMatrix(); + let scenePos = this.map.hiresTileManager.scene.position; + scenePos.x = -sX; + scenePos.z = -sZ; + this.renderer.render(this.map.hiresTileManager.sceneParent, this.camera); + } + + // shift back + this.camera.position.x += sX; + this.camera.position.z += sZ; + + } + + // render markers + this.renderer.render(this.markers, this.camera); + this.css2dRenderer.render(this.markers, this.camera); + } + + /** + * Changes / Sets the map that will be loaded and displayed + * @param map {Map} + * @returns Promise + */ + switchMap(map = null) { + if (this.map && this.map.isMap) this.map.unload(); + + this.map = map; + + if (this.map && this.map.isMap) { + return map.load(HIRES_VERTEX_SHADER, HIRES_FRAGMENT_SHADER, LOWRES_VERTEX_SHADER, LOWRES_FRAGMENT_SHADER, this.data.uniforms, this.tileCacheHash) + .then(() => { + for (let texture of this.map.loadedTextures){ + this.renderer.initTexture(texture); + } + + this.data.uniforms.skyColor.value = map.data.skyColor; + this.data.uniforms.ambientLight.value = map.data.ambientLight; + this.data.uniforms.hiresTileMap.value.map = map.hiresTileManager.tileMap.texture; + this.data.uniforms.hiresTileMap.value.scale.set(map.data.hires.tileSize.x, map.data.hires.tileSize.z); + this.data.uniforms.hiresTileMap.value.translate.set(map.data.hires.translate.x, map.data.hires.translate.z); + + setTimeout(this.updateLoadedMapArea); + + dispatchEvent(this.events, "bluemapMapChanged", { + map: map + }); + }) + .catch(error => { + alert(this.events, error, "error"); + }); + } else { + return Promise.resolve(); + } + } + + /** + * Loads the given area on the map (and unloads everything outside that area) + * @param centerX {number} + * @param centerZ {number} + * @param hiresViewDistance {number?} + * @param lowresViewDistance {number?} + */ + loadMapArea(centerX, centerZ, hiresViewDistance = -1, lowresViewDistance = -1) { + this.data.loadedCenter.set(centerX, centerZ); + if (hiresViewDistance >= 0) this.data.loadedHiresViewDistance = hiresViewDistance; + if (lowresViewDistance >= 0) this.data.loadedLowresViewDistance = lowresViewDistance; + + this.updateLoadedMapArea(); + } + + updateLoadedMapArea = () => { + if (!this.map) return; + if (this.controlsManager.distance < 1000) { + this.map.loadMapArea(this.data.loadedCenter.x, this.data.loadedCenter.y, this.data.loadedHiresViewDistance, this.data.loadedLowresViewDistance); + } else { + this.map.loadMapArea(this.data.loadedCenter.x, this.data.loadedCenter.y, 0, this.data.loadedLowresViewDistance); + } + } + + clearTileCache(newTileCacheHash) { + if (!newTileCacheHash) newTileCacheHash = generateCacheHash(); + + this.tileCacheHash = newTileCacheHash; + if (this.map) { + for (let i = 0; i < this.map.lowresTileManager.length; i++) { + this.map.lowresTileManager[i].tileLoader.tileCacheHash = this.tileCacheHash; + } + this.map.hiresTileManager.tileLoader.tileCacheHash = this.tileCacheHash; + } + } + + /** + * @returns {number} + */ + get superSampling() { + return this.data.superSampling; + } + + /** + * @param value {number} + */ + set superSampling(value) { + this.data.superSampling = value; + this.handleContainerResize(); + } + + /** + * @returns {CombinedCamera} + */ + get camera() { + return this._camera; + } + + /** + * @param value {CombinedCamera} + */ + set camera(value) { + this._camera = value; + this.data.camera = value.data; + } + + /** + * @returns {ControlsManager} + */ + get controlsManager() { + return this._controlsManager; + } + + /** + * @param value {ControlsManager} + */ + set controlsManager(value) { + this._controlsManager = value; + this.data.controlsManager = value.data; + } + + /** + * @returns {Map} + */ + get map() { + return this._map; + } + + /** + * @param value {Map} + */ + set map(value) { + this._map = value; + if (value) this.data.map = value.data; + } + +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/ControlsManager.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/ControlsManager.js new file mode 100644 index 00000000..138c250e --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/ControlsManager.js @@ -0,0 +1,333 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils, Vector3} from "three"; +import {dispatchEvent} from "../util/Utils"; +import {Map} from "../map/Map"; + +export class ControlsManager { + + /** + * @param mapViewer {MapViewer} + * @param camera {CombinedCamera} + */ + constructor(mapViewer, camera) { + Object.defineProperty( this, 'isControlsManager', { value: true } ); + + this.data = { + mapViewer: null, + camera: null, + controls: null, + position: new Vector3(0, 0, 0), + rotation: 0, + angle: 0, + tilt: 0, + }; + + this.mapViewer = mapViewer; + this.camera = camera; + + /** @type {Vector3} */ + this.lastPosition = this.position.clone(); + this.lastRotation = this.rotation; + this.lastAngle = this.angle; + this.lastDistance = this.distance; + this.lastOrtho = this.ortho; + this.lastTilt = this.tilt; + + this.lastMapUpdatePosition = this.position.clone(); + this.lastMapUpdateDistance = this.distance; + + this.averageDeltaTime = 16; + + this._controls = null; + + // start + this.distance = 300; + this.position.set(0, 0, 0); + this.rotation = 0; + this.angle = 0; + this.tilt = 0; + this.ortho = 0; + + this.updateCamera(); + } + + /** + * @param deltaTime {number} + * @param map {Map} + */ + update(deltaTime, map) { + if (deltaTime > 50) deltaTime = 50; // assume min 20 UPS + this.averageDeltaTime = this.averageDeltaTime * 0.9 + deltaTime * 0.1; // average delta-time to avoid choppy controls on lag-spikes + + if (this._controls) this._controls.update(this.averageDeltaTime, map); + + this.updateCamera(); + } + + updateCamera() { + let valueChanged = this.isValueChanged(); + + if (valueChanged) { + this.resetValueChanged(); + + // wrap rotation + while (this.rotation >= Math.PI) this.rotation -= Math.PI * 2; + while (this.rotation <= -Math.PI) this.rotation += Math.PI * 2; + + // prevent problems with the rotation when the angle is 0 (top-down) or distance is 0 (first-person) + let rotatableAngle = this.angle; + if (Math.abs(rotatableAngle) <= 0.0001) rotatableAngle = 0.0001; + else if (Math.abs(rotatableAngle) - Math.PI <= 0.0001) rotatableAngle = rotatableAngle - 0.0001; + let rotatableDistance = this.distance; + if (Math.abs(rotatableDistance) <= 0.0001) rotatableDistance = 0.0001; + + // fix distance for orthogonal-camera + if (this.ortho > 0) { + rotatableDistance = MathUtils.lerp(rotatableDistance, Math.max(rotatableDistance, 300), Math.pow(this.ortho, 8)); + } + + // calculate rotationVector + let rotationVector = new Vector3(Math.sin(this.rotation), 0, -Math.cos(this.rotation)); // 0 is towards north + let angleRotationAxis = new Vector3(0, 1, 0).cross(rotationVector); + rotationVector.applyAxisAngle(angleRotationAxis, (Math.PI / 2) - rotatableAngle); + rotationVector.multiplyScalar(rotatableDistance); + + // position camera + this.camera.rotation.set(0, 0, 0); + this.camera.position.copy(this.position).sub(rotationVector); + this.camera.lookAt(this.position); + this.camera.rotateZ(this.tilt + rotatableAngle < 0 ? Math.PI : 0); + + // optimize far/near planes + if (this.ortho <= 0) { + let near = MathUtils.clamp(rotatableDistance / 1000, 0.01, 1); + let far = MathUtils.clamp(rotatableDistance * 2, Math.max(near + 1, 2000), rotatableDistance + 5000); + if (far - near > 10000) near = far - 10000; + this.camera.near = near; + this.camera.far = far; + } else if (this.angle === 0) { + this.camera.near = 1; + this.camera.far = rotatableDistance + 300; + } else { + this.camera.near = 1; + this.camera.far = 100000; + } + + // event + dispatchEvent(this.mapViewer.events, "bluemapCameraMoved", { + controlsManager: this, + camera: this.camera + }); + } + + // if the position changed, update map to show new position + if (this.mapViewer.map) { + let triggerDistance = 1; + if (valueChanged) { + if (this.distance > 300) { + triggerDistance = this.mapViewer.data.loadedLowresViewDistance * 0.5; + } else { + triggerDistance = this.mapViewer.data.loadedHiresViewDistance * 0.5; + } + } + + if ( + Math.abs(this.lastMapUpdatePosition.x - this.position.x) >= triggerDistance || + Math.abs(this.lastMapUpdatePosition.z - this.position.z) >= triggerDistance || + (this.distance < 1000 && this.lastMapUpdateDistance > 1000) + ) { + this.lastMapUpdatePosition = this.position.clone(); + this.lastMapUpdateDistance = this.distance; + this.mapViewer.loadMapArea(this.position.x, this.position.z); + } + } + } + + /** + * Triggers an interaction on the screen (map), e.g. a mouse-click + * @param screenPosition {THREE.Vector2} - Clicked position on the screen (usually event.x, event.y) + * @param data {object} - Custom event data that will be added to the interaction-event + */ + handleMapInteraction(screenPosition, data = {}) { + this.mapViewer.handleMapInteraction(screenPosition, data); + } + + isValueChanged() { + return !( + this.data.position.equals(this.lastPosition) && + this.data.rotation === this.lastRotation && + this.data.angle === this.lastAngle && + this.distance === this.lastDistance && + this.ortho === this.lastOrtho && + this.data.tilt === this.lastTilt + ); + } + + resetValueChanged() { + this.lastPosition.copy(this.data.position); + this.lastRotation = this.data.rotation; + this.lastAngle = this.data.angle; + this.lastDistance = this.distance; + this.lastOrtho = this.ortho; + this.lastTilt = this.data.tilt; + } + + /** + * @returns {number} + */ + get ortho() { + return this.camera.ortho; + } + + /** + * @param ortho {number} + */ + set ortho(ortho) { + this.camera.ortho = ortho; + } + + get distance() { + return this.camera.distance; + } + + set distance(distance) { + this.camera.distance = distance; + } + + /** @typedef ControlsLike {{ + * start: function(controls: ControlsManager), + * stop: function(), + * update: function(deltaTime: number, map: Map) + * }} + + /** + * @param controls {ControlsLike} + */ + set controls(controls) { + if (this._controls && this._controls.stop) + this._controls.stop(); + + this._controls = controls; + if (controls) this.data.controls = controls.data || null + + if (this._controls && this._controls.start) + this._controls.start(this); + } + + /** + * @returns {ControlsLike} + */ + get controls() { + return this._controls; + } + + /** + * @returns {MapViewer} + */ + get mapViewer() { + return this._mapViewer; + } + + /** + * @param value {MapViewer} + */ + set mapViewer(value) { + this._mapViewer = value; + this.data.mapViewer = value.data; + } + + /** + * @returns {CombinedCamera} + */ + get camera() { + return this._camera; + } + + /** + * @param value {CombinedCamera} + */ + set camera(value) { + this._camera = value; + this.data.camera = value.data; + } + + /** + * @returns {Vector3} + */ + get position() { + return this.data.position; + } + + /** + * @param value {Vector3} + */ + set position(value) { + this.data.position = value; + } + + /** + * @returns {number} + */ + get rotation() { + return this.data.rotation; + } + + /** + * @param value {number} + */ + set rotation(value) { + this.data.rotation = value; + } + + /** + * @returns {number} + */ + get angle() { + return this.data.angle; + } + + /** + * @param value {number} + */ + set angle(value) { + this.data.angle = value; + } + + /** + * @returns {number} + */ + get tilt() { + return this.data.tilt; + } + + /** + * @param value {number} + */ + set tilt(value) { + this.data.tilt = value; + } +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/KeyCombination.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/KeyCombination.js new file mode 100644 index 00000000..239676f2 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/KeyCombination.js @@ -0,0 +1,78 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +export class KeyCombination { + + static CTRL = 0; + static SHIFT = 1; + static ALT = 2; + + /** + * @param code {string} + * @param modifiers {...number} + */ + constructor(code, ...modifiers) { + + this.code = code; + this.ctrl = modifiers.includes(KeyCombination.CTRL) || this.code === "CtrlLeft" || this.code === "CtrlRight"; + this.shift = modifiers.includes(KeyCombination.SHIFT) || this.code === "ShiftLeft" || this.code === "ShiftRight"; + this.alt = modifiers.includes(KeyCombination.ALT) || this.code === "AltLeft" || this.code === "AltRight"; + + } + + /** + * @param evt {KeyboardEvent} + * @returns {boolean} + */ + testDown(evt) { + return this.code === evt.code && + this.ctrl === evt.ctrlKey && + this.shift === evt.shiftKey && + this.alt === evt.altKey; + } + + /** + * @param evt {KeyboardEvent} + * @returns {boolean} + */ + testUp(evt) { + return this.code === evt.code; + } + + static oneDown(evt, ...combinations) { + for (let combination of combinations){ + if (combination.testDown(evt)) return true; + } + return false; + } + + static oneUp(evt, ...combinations) { + for (let combination of combinations){ + if (combination.testUp(evt)) return true; + } + return false; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/FreeFlightControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/FreeFlightControls.js new file mode 100644 index 00000000..3c3523e3 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/FreeFlightControls.js @@ -0,0 +1,147 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils, Vector2} from "three"; +import {Manager, Pan, DIRECTION_ALL} from "hammerjs"; +import {animate, EasingFunctions} from "../../util/Utils"; +import {KeyMoveControls} from "./keyboard/KeyMoveControls"; +import {MouseRotateControls} from "./mouse/MouseRotateControls"; +import {MouseAngleControls} from "./mouse/MouseAngleControls"; +import {KeyHeightControls} from "./keyboard/KeyHeightControls"; +import {TouchPanControls} from "./touch/TouchPanControls"; + +export class FreeFlightControls { + + /** + * @param target {Element} + */ + constructor(target) { + this.target = target; + this.manager = null; + + this.data = { + + }; + + this.hammer = new Manager(this.target); + this.initializeHammer(); + + this.keyMove = new KeyMoveControls(this.target, 0.5, 0.1); + this.keyHeight = new KeyHeightControls(this.target, 0.5, 0.2); + this.mouseRotate = new MouseRotateControls(this.target, 1.5, -2, -1.5, 0.5); + this.mouseAngle = new MouseAngleControls(this.target, 1.5, -2, -1.5, 0.5); + this.touchPan = new TouchPanControls(this.target, this.hammer, 5, 0.15); + + this.started = false; + + this.clickStart = new Vector2(); + this.moveSpeed = 0.5; + + this.animationTargetHeight = 0; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.keyMove.start(manager); + this.keyHeight.start(manager); + this.mouseRotate.start(manager); + this.mouseAngle.start(manager); + this.touchPan.start(manager); + + this.target.addEventListener("contextmenu", this.onContextMenu); + this.target.addEventListener("mousedown", this.onMouseDown); + this.target.addEventListener("mouseup", this.onMouseUp); + window.addEventListener("wheel", this.onWheel, {passive: true}); + } + + stop() { + this.keyMove.stop(); + this.keyHeight.stop(); + this.mouseRotate.stop(); + this.mouseAngle.stop(); + this.touchPan.stop(); + + this.target.removeEventListener("contextmenu", this.onContextMenu); + this.target.removeEventListener("mousedown", this.onMouseDown); + this.target.removeEventListener("mouseup", this.onMouseUp); + window.removeEventListener("wheel", this.onWheel); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + this.keyMove.update(delta, map); + this.keyHeight.update(delta, map); + this.mouseRotate.update(delta, map); + this.mouseAngle.update(delta, map); + this.touchPan.update(delta, map); + + this.manager.angle = MathUtils.clamp(this.manager.angle, 0, Math.PI); + this.manager.distance = 0; + this.manager.ortho = 0; + } + + initializeHammer() { + let touchMove = new Pan({ event: 'move', pointers: 1, direction: DIRECTION_ALL, threshold: 0 }); + this.hammer.add(touchMove); + } + + onContextMenu = evt => { + evt.preventDefault(); + } + + onMouseDown = evt => { + this.clickStart.set(evt.x, evt.y); + } + + onMouseUp = evt => { + if (Math.abs(this.clickStart.x - evt.x) > 5) return; + if (Math.abs(this.clickStart.y - evt.y) > 5) return; + + document.body.requestFullscreen() + .finally(() => { + this.target.requestPointerLock(); + }); + } + + onWheel = evt => { + let delta = evt.deltaY; + if (evt.deltaMode === WheelEvent.DOM_DELTA_PIXEL) delta *= 0.01; + if (evt.deltaMode === WheelEvent.DOM_DELTA_LINE) delta *= 0.33; + + this.moveSpeed *= Math.pow(1.5, -delta * 0.25); + this.moveSpeed = MathUtils.clamp(this.moveSpeed, 0.05, 5); + + this.keyMove.speed = this.moveSpeed; + this.keyHeight.speed = this.moveSpeed; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/keyboard/KeyHeightControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/keyboard/KeyHeightControls.js new file mode 100644 index 00000000..7b4ea6c3 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/keyboard/KeyHeightControls.js @@ -0,0 +1,123 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; +import {KeyCombination} from "../../KeyCombination"; + +export class KeyHeightControls { + + static KEYS = { + UP: [ + new KeyCombination("Space"), + new KeyCombination("PageUp") + ], + DOWN: [ + new KeyCombination("ShiftLeft"), + new KeyCombination("ShiftRight"), + new KeyCombination("PageDown") + ], + } + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.deltaY = 0; + + this.up = false; + this.down = false; + + this.speed = speed; + this.stiffness = stiffness; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + window.addEventListener("keydown", this.onKeyDown); + window.addEventListener("keyup", this.onKeyUp); + } + + stop() { + window.removeEventListener("keydown", this.onKeyDown); + window.removeEventListener("keyup", this.onKeyUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.up) this.deltaY += 1; + if (this.down) this.deltaY -= 1; + + if (this.deltaY === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.position.y += this.deltaY * smoothing * this.speed * delta * 0.06; + + this.deltaY *= 1 - smoothing; + if (Math.abs(this.deltaY) < 0.0001) { + this.deltaY = 0; + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyDown = evt => { + if (KeyCombination.oneUp(evt, ...KeyHeightControls.KEYS.UP)){ + this.up = true; + evt.preventDefault(); + } + else if (KeyCombination.oneUp(evt, ...KeyHeightControls.KEYS.DOWN)){ + this.down = true; + evt.preventDefault(); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyUp = evt => { + if (KeyCombination.oneUp(evt, ...KeyHeightControls.KEYS.UP)){ + this.up = false; + } + if (KeyCombination.oneUp(evt, ...KeyHeightControls.KEYS.DOWN)){ + this.down = false; + } + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/keyboard/KeyMoveControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/keyboard/KeyMoveControls.js new file mode 100644 index 00000000..81509d9b --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/keyboard/KeyMoveControls.js @@ -0,0 +1,155 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils, Vector2} from "three"; +import {VEC2_ZERO} from "../../../util/Utils"; +import {KeyCombination} from "../../KeyCombination"; + +export class KeyMoveControls { + + static KEYS = { + LEFT: [ + new KeyCombination("ArrowLeft"), + new KeyCombination("KeyA") + ], + UP: [ + new KeyCombination("ArrowUp"), + new KeyCombination("KeyW") + ], + RIGHT: [ + new KeyCombination("ArrowRight"), + new KeyCombination("KeyD") + ], + DOWN: [ + new KeyCombination("ArrowDown"), + new KeyCombination("KeyS") + ], + } + + static temp_v2 = new Vector2(); + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.deltaPosition = new Vector2(); + + this.up = false; + this.down = false; + this.left = false; + this.right = false; + + this.speed = speed; + this.stiffness = stiffness; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + window.addEventListener("keydown", this.onKeyDown); + window.addEventListener("keyup", this.onKeyUp); + } + + stop() { + window.removeEventListener("keydown", this.onKeyDown); + window.removeEventListener("keyup", this.onKeyUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.up) this.deltaPosition.y -= 1; + if (this.down) this.deltaPosition.y += 1; + if (this.left) this.deltaPosition.x -= 1; + if (this.right) this.deltaPosition.x += 1; + + if (this.deltaPosition.x === 0 && this.deltaPosition.y === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + let rotatedDelta = KeyMoveControls.temp_v2.copy(this.deltaPosition); + rotatedDelta.rotateAround(VEC2_ZERO, this.manager.rotation); + + this.manager.position.x += rotatedDelta.x * smoothing * this.speed * delta * 0.06; + this.manager.position.z += rotatedDelta.y * smoothing * this.speed * delta * 0.06; + + this.deltaPosition.multiplyScalar(1 - smoothing); + if (this.deltaPosition.lengthSq() < 0.0001) { + this.deltaPosition.set(0, 0); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyDown = evt => { + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.UP)){ + this.up = true; + evt.preventDefault(); + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.DOWN)){ + this.down = true; + evt.preventDefault(); + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.LEFT)){ + this.left = true; + evt.preventDefault(); + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.RIGHT)){ + this.right = true; + evt.preventDefault(); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyUp = evt => { + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.UP)){ + this.up = false; + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.DOWN)){ + this.down = false; + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.LEFT)){ + this.left = false; + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.RIGHT)){ + this.right = false; + } + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/mouse/MouseAngleControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/mouse/MouseAngleControls.js new file mode 100644 index 00000000..082d9ff8 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/mouse/MouseAngleControls.js @@ -0,0 +1,139 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; + +export class MouseAngleControls { + + /** + * @param target {EventTarget} + * @param speedLeft {number} + * @param speedRight {number} + * @param speedCapture {number} + * @param stiffness {number} + */ + constructor(target, speedLeft, speedRight, speedCapture, stiffness) { + this.target = target; + this.manager = null; + + this.moving = false; + this.lastY = 0; + this.deltaAngle = 0; + + this.speedLeft = speedLeft; + this.speedRight = speedRight; + this.speedCapture = speedCapture; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplier = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.target.addEventListener("mousedown", this.onMouseDown); + window.addEventListener("mousemove", this.onMouseMove); + window.addEventListener("mouseup", this.onMouseUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.target.removeEventListener("mousedown", this.onMouseDown); + window.removeEventListener("mousemove", this.onMouseMove); + window.removeEventListener("mouseup", this.onMouseUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaAngle === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.angle += this.deltaAngle * smoothing; + + this.deltaAngle *= 1 - smoothing; + if (Math.abs(this.deltaAngle) < 0.0001) { + this.deltaAngle = 0; + } + } + + reset() { + this.deltaAngle = 0; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseDown = evt => { + this.moving = true; + this.deltaAngle = 0; + this.lastY = evt.y; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseMove = evt => { + if (document.pointerLockElement) { + this.deltaAngle += evt.movementY * this.speedCapture * this.pixelToSpeedMultiplier; + } + + else if(this.moving){ + if (evt.buttons === 1) { + this.deltaAngle += (evt.y - this.lastY) * this.speedLeft * this.pixelToSpeedMultiplier; + } else { + this.deltaAngle += (evt.y - this.lastY) * this.speedRight * this.pixelToSpeedMultiplier; + } + } + + this.lastY = evt.y; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseUp = evt => { + this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplier = 1 / this.target.clientHeight; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/mouse/MouseRotateControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/mouse/MouseRotateControls.js new file mode 100644 index 00000000..94d04e9e --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/mouse/MouseRotateControls.js @@ -0,0 +1,139 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; + +export class MouseRotateControls { + + /** + * @param target {Element} + * @param speedLeft {number} + * @param speedRight {number} + * @param speedCapture {number} + * @param stiffness {number} + */ + constructor(target, speedLeft, speedRight, speedCapture, stiffness) { + this.target = target; + this.manager = null; + + this.moving = false; + this.lastX = 0; + this.deltaRotation = 0; + + this.speedLeft = speedLeft; + this.speedRight = speedRight; + this.speedCapture = speedCapture; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplier = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.target.addEventListener("mousedown", this.onMouseDown); + window.addEventListener("mousemove", this.onMouseMove); + window.addEventListener("mouseup", this.onMouseUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.target.removeEventListener("mousedown", this.onMouseDown); + window.removeEventListener("mousemove", this.onMouseMove); + window.removeEventListener("mouseup", this.onMouseUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaRotation === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.rotation += this.deltaRotation * smoothing; + + this.deltaRotation *= 1 - smoothing; + if (Math.abs(this.deltaRotation) < 0.0001) { + this.deltaRotation = 0; + } + } + + reset() { + this.deltaRotation = 0; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseDown = evt => { + this.moving = true; + this.deltaRotation = 0; + this.lastX = evt.x; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseMove = evt => { + if (document.pointerLockElement) { + this.deltaRotation -= evt.movementX * this.speedCapture * this.pixelToSpeedMultiplier; + } + + else if(this.moving){ + if (evt.buttons === 1) { + this.deltaRotation -= (evt.x - this.lastX) * this.speedLeft * this.pixelToSpeedMultiplier; + } else { + this.deltaRotation -= (evt.x - this.lastX) * this.speedRight * this.pixelToSpeedMultiplier; + } + } + + this.lastX = evt.x; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseUp = evt => { + this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplier = (1 / this.target.clientWidth) * (this.target.clientWidth / this.target.clientHeight); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/touch/TouchPanControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/touch/TouchPanControls.js new file mode 100644 index 00000000..7c9b5f92 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/freeflight/touch/TouchPanControls.js @@ -0,0 +1,144 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils, Vector2} from "three"; + +export class TouchPanControls { + + static tempVec2_1 = new Vector2(); + + /** + * @param target {Element} + * @param hammer {Manager} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, hammer, speed, stiffness) { + this.target = target; + this.hammer = hammer; + this.manager = null; + + this.moving = false; + this.lastPosition = new Vector2(); + this.deltaPosition = new Vector2(); + + this.speed = speed; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplierX = 0; + this.pixelToSpeedMultiplierY = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.hammer.on("movestart", this.onTouchDown); + this.hammer.on("movemove", this.onTouchMove); + this.hammer.on("moveend", this.onTouchUp); + this.hammer.on("movecancel", this.onTouchUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.hammer.off("movestart", this.onTouchDown); + this.hammer.off("movemove", this.onTouchMove); + this.hammer.off("moveend", this.onTouchUp); + this.hammer.off("movecancel", this.onTouchUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaPosition.x === 0 && this.deltaPosition.y === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.rotation += this.deltaPosition.x * this.speed * this.pixelToSpeedMultiplierX * this.stiffness; + this.manager.angle -= this.deltaPosition.y * this.speed * this.pixelToSpeedMultiplierY * this.stiffness; + + this.deltaPosition.multiplyScalar(1 - smoothing); + if (this.deltaPosition.lengthSq() < 0.0001) { + this.deltaPosition.set(0, 0); + } + } + + reset() { + this.deltaPosition.set(0, 0); + } + + /** + * @private + * @param evt {object} + */ + onTouchDown = evt => { + if (evt.pointerType === "mouse") return; + + this.moving = true; + this.deltaPosition.set(0, 0); + this.lastPosition.set(evt.center.x, evt.center.y); + } + + /** + * @private + * @param evt {object} + */ + onTouchMove = evt => { + if (evt.pointerType === "mouse") return; + + let position = TouchPanControls.tempVec2_1.set(evt.center.x, evt.center.y); + + if(this.moving){ + this.deltaPosition.sub(position).add(this.lastPosition); + } + + this.lastPosition.copy(position); + } + + /** + * @private + * @param evt {object} + */ + onTouchUp = evt => { + if (evt.pointerType === "mouse") return; + + this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplierX = (1 / this.target.clientWidth) * (this.target.clientWidth / this.target.clientHeight); + this.pixelToSpeedMultiplierY = 1 / this.target.clientHeight; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/MapControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/MapControls.js new file mode 100644 index 00000000..3911d82f --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/MapControls.js @@ -0,0 +1,272 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MouseMoveControls} from "./mouse/MouseMoveControls"; +import {MouseZoomControls} from "./mouse/MouseZoomControls"; +import {MouseRotateControls} from "./mouse/MouseRotateControls"; +import {MouseAngleControls} from "./mouse/MouseAngleControls"; +import {MathUtils, Vector2, Vector3} from "three"; +import {Manager, Pan, Pinch, Rotate, Tap, DIRECTION_ALL, DIRECTION_VERTICAL} from "hammerjs"; +import {softClamp} from "../../util/Utils"; +import {MapHeightControls} from "./MapHeightControls"; +import {KeyMoveControls} from "./keyboard/KeyMoveControls"; +import {KeyAngleControls} from "./keyboard/KeyAngleControls"; +import {KeyRotateControls} from "./keyboard/KeyRotateControls"; +import {KeyZoomControls} from "./keyboard/KeyZoomControls"; +import {TouchMoveControls} from "./touch/TouchMoveControls"; +import {TouchRotateControls} from "./touch/TouchRotateControls"; +import {TouchAngleControls} from "./touch/TouchAngleControls"; +import {TouchZoomControls} from "./touch/TouchZoomControls"; +import {PlayerMarker} from "../../markers/PlayerMarker"; + +const HALF_PI = Math.PI * 0.5; + +export class MapControls { + + static _beforeMoveTemp = new Vector3(); + + /** + * @param rootElement {Element} + */ + constructor(rootElement) { + this.rootElement = rootElement; + + this.data = { + followingPlayer: null + }; + + /** @type {ControlsManager} */ + this.manager = null; + + this.hammer = new Manager(this.rootElement); + this.initializeHammer(); + + //controls + this.mouseMove = new MouseMoveControls(this.rootElement, 1.5,0.3); + this.mouseRotate = new MouseRotateControls(this.rootElement, 6, 0.3); + this.mouseAngle = new MouseAngleControls(this.rootElement, 3, 0.3); + this.mouseZoom = new MouseZoomControls(this.rootElement, 1, 0.2); + + this.keyMove = new KeyMoveControls(this.rootElement, 0.025, 0.2); + this.keyRotate = new KeyRotateControls(this.rootElement, 0.06, 0.15); + this.keyAngle = new KeyAngleControls(this.rootElement, 0.04, 0.15); + this.keyZoom = new KeyZoomControls(this.rootElement, 0.2, 0.15); + + this.touchMove = new TouchMoveControls(this.rootElement, this.hammer, 1.5,0.3); + this.touchRotate = new TouchRotateControls(this.hammer, 0.0174533, 0.3); + this.touchAngle = new TouchAngleControls(this.rootElement, this.hammer, 3, 0.3); + this.touchZoom = new TouchZoomControls(this.hammer); + + this.mapHeight = new MapHeightControls(0.2, 0.1); + + this.lastTap = -1; + this.lastTapCenter = null; + + this.minDistance = 5; + this.maxDistance = 100000; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.rootElement.addEventListener("contextmenu", this.onContextMenu); + this.hammer.on("tap", this.onTap); + + this.mouseMove.start(manager); + this.mouseRotate.start(manager); + this.mouseAngle.start(manager); + this.mouseZoom.start(manager); + + this.keyMove.start(manager); + this.keyRotate.start(manager); + this.keyAngle.start(manager); + this.keyZoom.start(manager); + + this.touchMove.start(manager); + this.touchRotate.start(manager); + this.touchAngle.start(manager); + this.touchZoom.start(manager); + + this.mapHeight.start(manager); + } + + stop() { + this.stopFollowingPlayerMarker(); + + this.rootElement.removeEventListener("contextmenu", this.onContextMenu); + this.hammer.off("tap", this.onTap); + + this.mouseMove.stop(); + this.mouseRotate.stop(); + this.mouseAngle.stop(); + this.mouseZoom.stop(); + + this.keyMove.stop(); + this.keyRotate.stop(); + this.keyAngle.stop(); + this.keyZoom.stop(); + + this.touchMove.stop(); + this.touchRotate.stop(); + this.touchAngle.stop(); + this.touchZoom.stop(); + + this.mapHeight.stop(); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + this.manager.position.y = 0; // reset target y position + + // move + MapControls._beforeMoveTemp.copy(this.manager.position); + this.mouseMove.update(delta, map); + this.keyMove.update(delta, map); + this.touchMove.update(delta, map); + + // if moved, stop following the marker and give back control + if (this.data.followingPlayer && !MapControls._beforeMoveTemp.equals(this.manager.position)) { + this.stopFollowingPlayerMarker(); + } + + // follow player marker + if (this.data.followingPlayer) { + this.manager.position.copy(this.data.followingPlayer.position); + } + + // zoom + this.mouseZoom.update(delta, map); + this.keyZoom.update(delta, map); + this.touchZoom.update(delta, map); + + this.manager.distance = softClamp(this.manager.distance, this.minDistance, this.maxDistance, 0.8); + + // max angle for current distance + let maxAngleForZoom = this.getMaxPerspectiveAngleForDistance(this.manager.distance); + + // rotation + this.mouseRotate.update(delta, map); + this.keyRotate.update(delta, map); + this.touchRotate.update(delta, map); + + const rotating = this.mouseRotate.moving || this.touchRotate.moving || + this.keyRotate.left || this.keyRotate.right + + // snap rotation to north on orthographic view + if (this.manager.ortho !== 0 && Math.abs(this.manager.rotation) < (rotating ? 0.05 : 0.3)) { + this.manager.rotation = softClamp(this.manager.rotation, 0, 0, 0.1); + } + + // tilt + if (this.manager.ortho === 0) { + this.mouseAngle.update(delta, map); + this.keyAngle.update(delta, map); + this.touchAngle.update(delta, map); + this.manager.angle = softClamp(this.manager.angle, 0, maxAngleForZoom, 0.8); + } + + // target height + if (this.manager.ortho === 0 || this.manager.angle === 0) { + this.mapHeight.maxAngle = maxAngleForZoom; + this.mapHeight.update(delta, map); + } + } + + reset() { + this.mouseMove.reset(); + this.mouseRotate.reset(); + this.mouseAngle.reset(); + this.mouseZoom.reset(); + + this.touchMove.reset(); + this.touchRotate.reset(); + this.touchAngle.reset(); + this.touchZoom.reset(); + } + + getMaxPerspectiveAngleForDistance(distance) { + return MathUtils.clamp((1 - Math.pow(Math.max(distance - 5, 0.001) / 500, 0.5)) * HALF_PI,0, HALF_PI) + } + + initializeHammer() { + let touchTap = new Tap({ event: 'tap', pointers: 1, taps: 1, threshold: 5 }); + let touchMove = new Pan({ event: 'move', pointers: 1, direction: DIRECTION_ALL, threshold: 0 }); + let touchTilt = new Pan({ event: 'tilt', pointers: 2, direction: DIRECTION_VERTICAL, threshold: 0 }); + let touchRotate = new Rotate({ event: 'rotate', pointers: 2, threshold: 0 }); + let touchZoom = new Pinch({ event: 'zoom', pointers: 2, threshold: 0 }); + + touchMove.recognizeWith(touchRotate); + touchMove.recognizeWith(touchTilt); + touchMove.recognizeWith(touchZoom); + touchTilt.recognizeWith(touchRotate); + touchTilt.recognizeWith(touchZoom); + touchRotate.recognizeWith(touchZoom); + + this.hammer.add(touchTap); + this.hammer.add(touchTilt); + this.hammer.add(touchMove); + this.hammer.add(touchRotate); + this.hammer.add(touchZoom); + } + + /** + * @param marker {object} + */ + followPlayerMarker(marker) { + if (marker.isPlayerMarker) marker = marker.data; + this.data.followingPlayer = marker; + } + + stopFollowingPlayerMarker() { + this.data.followingPlayer = null; + } + + onContextMenu = evt => { + evt.preventDefault(); + } + + onTap = evt => { + let doubleTap = false; + let center = new Vector2(evt.center.x, evt.center.y); + + let now = Date.now(); + if (this.lastTap > 0 && this.lastTapCenter && now - this.lastTap < 500 && this.lastTapCenter.distanceTo(center) < 5){ + doubleTap = true; + this.lastTap = -1; + } else { + this.lastTap = now; + this.lastTapCenter = center; + } + + this.manager.handleMapInteraction(new Vector2(evt.center.x, evt.center.y), {doubleTap: doubleTap}); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/MapHeightControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/MapHeightControls.js new file mode 100644 index 00000000..9a36a37b --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/MapHeightControls.js @@ -0,0 +1,103 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils, Vector2} from "three"; + +export class MapHeightControls { + + /** + * @param cameraHeightStiffness {number} + * @param targetHeightStiffness {number} + */ + constructor(cameraHeightStiffness, targetHeightStiffness) { + this.manager = null; + + this.cameraHeightStiffness = cameraHeightStiffness; + this.targetHeightStiffness = targetHeightStiffness; + this.maxAngle = Math.PI / 2; + + this.targetHeight = 0; + this.cameraHeight = 0; + + this.minCameraHeight = 0; + this.distanceTagretHeight = 0; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + } + + stop() {} + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + + // adjust target height + this.updateHeights(delta, map); + this.manager.position.y = Math.max(this.manager.position.y, this.getSuggestedHeight()); + } + + updateHeights(delta, map) { + //target height + let targetSmoothing = this.targetHeightStiffness / (16.666 / delta); + targetSmoothing = MathUtils.clamp(targetSmoothing, 0, 1); + + let targetTerrainHeight = map.terrainHeightAt(this.manager.position.x, this.manager.position.z) + 3 || 0; + + let targetDelta = targetTerrainHeight - this.targetHeight; + this.targetHeight += targetDelta * targetSmoothing; + if (Math.abs(targetDelta) < 0.001) this.targetHeight = targetTerrainHeight; + + // camera height + this.minCameraHeight = 0; + if (this.maxAngle >= 0.1) { + let cameraSmoothing = this.cameraHeightStiffness / (16.666 / delta); + cameraSmoothing = MathUtils.clamp(cameraSmoothing, 0, 1); + + let cameraTerrainHeight = map.terrainHeightAt(this.manager.camera.position.x, this.manager.camera.position.z) || 0; + + let cameraDelta = cameraTerrainHeight - this.cameraHeight; + this.cameraHeight += cameraDelta * cameraSmoothing; + if (Math.abs(cameraDelta) < 0.001) this.cameraHeight = cameraTerrainHeight; + + let maxAngleHeight = Math.cos(this.maxAngle) * this.manager.distance; + this.minCameraHeight = this.cameraHeight - maxAngleHeight + 1; + } + + // adjust targetHeight by distance + this.distanceTagretHeight = Math.max(MathUtils.lerp(this.targetHeight, 0, this.manager.distance / 500), 0); + } + + getSuggestedHeight() { + return Math.max(this.distanceTagretHeight, this.minCameraHeight); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyAngleControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyAngleControls.js new file mode 100644 index 00000000..2e2e063f --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyAngleControls.js @@ -0,0 +1,124 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; +import {KeyCombination} from "../../KeyCombination"; + +export class KeyAngleControls { + + static KEYS = { + UP: [ + new KeyCombination("ArrowUp", KeyCombination.ALT), + new KeyCombination("KeyW", KeyCombination.ALT), + new KeyCombination("PageUp") + ], + DOWN: [ + new KeyCombination("ArrowDown", KeyCombination.ALT), + new KeyCombination("KeyS", KeyCombination.ALT), + new KeyCombination("PageDown") + ], + } + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.deltaAngle = 0; + + this.up = false; + this.down = false; + + this.speed = speed; + this.stiffness = stiffness; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + window.addEventListener("keydown", this.onKeyDown); + window.addEventListener("keyup", this.onKeyUp); + } + + stop() { + window.removeEventListener("keydown", this.onKeyDown); + window.removeEventListener("keyup", this.onKeyUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.up) this.deltaAngle -= 1; + if (this.down) this.deltaAngle += 1; + + if (this.deltaAngle === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.angle += this.deltaAngle * smoothing * this.speed * delta * 0.06; + + this.deltaAngle *= 1 - smoothing; + if (Math.abs(this.deltaAngle) < 0.0001) { + this.deltaAngle = 0; + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyDown = evt => { + if (KeyCombination.oneDown(evt, ...KeyAngleControls.KEYS.UP)){ + this.up = true; + evt.preventDefault(); + } + if (KeyCombination.oneDown(evt, ...KeyAngleControls.KEYS.DOWN)){ + this.down = true; + evt.preventDefault(); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyUp = evt => { + if (KeyCombination.oneUp(evt, ...KeyAngleControls.KEYS.UP)){ + this.up = false; + } + if (KeyCombination.oneUp(evt, ...KeyAngleControls.KEYS.DOWN)){ + this.down = false; + } + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyMoveControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyMoveControls.js new file mode 100644 index 00000000..30aaf4a6 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyMoveControls.js @@ -0,0 +1,155 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils, Vector2} from "three"; +import {VEC2_ZERO} from "../../../util/Utils"; +import {KeyCombination} from "../../KeyCombination"; + +export class KeyMoveControls { + + static KEYS = { + LEFT: [ + new KeyCombination("ArrowLeft"), + new KeyCombination("KeyA") + ], + UP: [ + new KeyCombination("ArrowUp"), + new KeyCombination("KeyW") + ], + RIGHT: [ + new KeyCombination("ArrowRight"), + new KeyCombination("KeyD") + ], + DOWN: [ + new KeyCombination("ArrowDown"), + new KeyCombination("KeyS") + ], + } + + static temp_v2 = new Vector2(); + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.deltaPosition = new Vector2(); + + this.up = false; + this.down = false; + this.left = false; + this.right = false; + + this.speed = speed; + this.stiffness = stiffness; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + window.addEventListener("keydown", this.onKeyDown); + window.addEventListener("keyup", this.onKeyUp); + } + + stop() { + window.removeEventListener("keydown", this.onKeyDown); + window.removeEventListener("keyup", this.onKeyUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.up) this.deltaPosition.y -= 1; + if (this.down) this.deltaPosition.y += 1; + if (this.left) this.deltaPosition.x -= 1; + if (this.right) this.deltaPosition.x += 1; + + if (this.deltaPosition.x === 0 && this.deltaPosition.y === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + let rotatedDelta = KeyMoveControls.temp_v2.copy(this.deltaPosition); + rotatedDelta.rotateAround(VEC2_ZERO, this.manager.rotation); + + this.manager.position.x += rotatedDelta.x * smoothing * this.manager.distance * this.speed * delta * 0.06; + this.manager.position.z += rotatedDelta.y * smoothing * this.manager.distance * this.speed * delta * 0.06; + + this.deltaPosition.multiplyScalar(1 - smoothing); + if (this.deltaPosition.lengthSq() < 0.0001) { + this.deltaPosition.set(0, 0); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyDown = evt => { + if (KeyCombination.oneDown(evt, ...KeyMoveControls.KEYS.UP)){ + this.up = true; + evt.preventDefault(); + } + if (KeyCombination.oneDown(evt, ...KeyMoveControls.KEYS.DOWN)){ + this.down = true; + evt.preventDefault(); + } + if (KeyCombination.oneDown(evt, ...KeyMoveControls.KEYS.LEFT)){ + this.left = true; + evt.preventDefault(); + } + if (KeyCombination.oneDown(evt, ...KeyMoveControls.KEYS.RIGHT)){ + this.right = true; + evt.preventDefault(); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyUp = evt => { + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.UP)){ + this.up = false; + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.DOWN)){ + this.down = false; + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.LEFT)){ + this.left = false; + } + if (KeyCombination.oneUp(evt, ...KeyMoveControls.KEYS.RIGHT)){ + this.right = false; + } + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyRotateControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyRotateControls.js new file mode 100644 index 00000000..6ed2c4e7 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyRotateControls.js @@ -0,0 +1,124 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; +import {KeyCombination} from "../../KeyCombination"; + +export class KeyRotateControls { + + static KEYS = { + LEFT: [ + new KeyCombination("ArrowLeft", KeyCombination.ALT), + new KeyCombination("KeyA", KeyCombination.ALT), + new KeyCombination("Delete"), + ], + RIGHT: [ + new KeyCombination("ArrowRight", KeyCombination.ALT), + new KeyCombination("KeyD", KeyCombination.ALT), + new KeyCombination("End"), + ], + } + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.deltaRotation = 0; + + this.left = false; + this.right = false; + + this.speed = speed; + this.stiffness = stiffness; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + window.addEventListener("keydown", this.onKeyDown); + window.addEventListener("keyup", this.onKeyUp); + } + + stop() { + window.removeEventListener("keydown", this.onKeyDown); + window.removeEventListener("keyup", this.onKeyUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.left) this.deltaRotation += 1; + if (this.right) this.deltaRotation -= 1; + + if (this.deltaRotation === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.rotation += this.deltaRotation * smoothing * this.speed * delta * 0.06; + + this.deltaRotation *= 1 - smoothing; + if (Math.abs(this.deltaRotation) < 0.0001) { + this.deltaRotation = 0; + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyDown = evt => { + if (KeyCombination.oneDown(evt, ...KeyRotateControls.KEYS.LEFT)){ + this.left = true; + evt.preventDefault(); + } + if (KeyCombination.oneDown(evt, ...KeyRotateControls.KEYS.RIGHT)){ + this.right = true; + evt.preventDefault(); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyUp = evt => { + if (KeyCombination.oneUp(evt, ...KeyRotateControls.KEYS.LEFT)){ + this.left = false; + } + if (KeyCombination.oneUp(evt, ...KeyRotateControls.KEYS.RIGHT)){ + this.right = false; + } + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyZoomControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyZoomControls.js new file mode 100644 index 00000000..0c884dfd --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/keyboard/KeyZoomControls.js @@ -0,0 +1,122 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; +import {KeyCombination} from "../../KeyCombination"; + +export class KeyZoomControls { + + static KEYS = { + IN: [ + new KeyCombination("NumpadAdd"), + new KeyCombination("Insert"), + ], + OUT: [ + new KeyCombination("NumpadSubtract"), + new KeyCombination("Home"), + ], + } + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.deltaZoom = 0; + + this.in = false; + this.out = false; + + this.speed = speed; + this.stiffness = stiffness; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + window.addEventListener("keydown", this.onKeyDown); + window.addEventListener("keyup", this.onKeyUp); + } + + stop() { + window.removeEventListener("keydown", this.onKeyDown); + window.removeEventListener("keyup", this.onKeyUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.in) this.deltaZoom -= 1; + if (this.out) this.deltaZoom += 1; + + if (this.deltaZoom === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.distance *= Math.pow(1.5, this.deltaZoom * smoothing * this.speed * delta * 0.06); + + this.deltaZoom *= 1 - smoothing; + if (Math.abs(this.deltaZoom) < 0.0001) { + this.deltaZoom = 0; + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyDown = evt => { + if (KeyCombination.oneDown(evt, ...KeyZoomControls.KEYS.IN)){ + this.in = true; + evt.preventDefault(); + } + if (KeyCombination.oneDown(evt, ...KeyZoomControls.KEYS.OUT)){ + this.out = true; + evt.preventDefault(); + } + } + + /** + * @param evt {KeyboardEvent} + */ + onKeyUp = evt => { + if (KeyCombination.oneUp(evt, ...KeyZoomControls.KEYS.IN)){ + this.in = false; + } + if (KeyCombination.oneUp(evt, ...KeyZoomControls.KEYS.OUT)){ + this.out = false; + } + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseAngleControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseAngleControls.js new file mode 100644 index 00000000..467ed3ea --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseAngleControls.js @@ -0,0 +1,130 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; + +export class MouseAngleControls { + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.moving = false; + this.lastY = 0; + this.deltaAngle = 0; + + this.speed = speed; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplierY = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.target.addEventListener("mousedown", this.onMouseDown); + window.addEventListener("mousemove", this.onMouseMove); + window.addEventListener("mouseup", this.onMouseUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.target.removeEventListener("mousedown", this.onMouseDown); + window.removeEventListener("mousemove", this.onMouseMove); + window.removeEventListener("mouseup", this.onMouseUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaAngle === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.angle += this.deltaAngle * smoothing * this.speed * this.pixelToSpeedMultiplierY; + + this.deltaAngle *= 1 - smoothing; + if (Math.abs(this.deltaAngle) < 0.0001) { + this.deltaAngle = 0; + } + } + + reset() { + this.deltaAngle = 0; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseDown = evt => { + if ((evt.buttons !== undefined ? evt.buttons === 2 : evt.button === 2) || + ((evt.altKey || evt.ctrlKey) && (evt.buttons !== undefined ? evt.buttons === 1 : evt.button === 0))) { + this.moving = true; + this.deltaAngle = 0; + this.lastY = evt.y; + } + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseMove = evt => { + if(this.moving){ + this.deltaAngle -= evt.y - this.lastY; + } + + this.lastY = evt.y; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseUp = evt => { + this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplierY = 1 / this.target.clientHeight; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseMoveControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseMoveControls.js new file mode 100644 index 00000000..25b02ae0 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseMoveControls.js @@ -0,0 +1,140 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils, Vector2} from "three"; +import {VEC2_ZERO} from "../../../util/Utils"; + +export class MouseMoveControls { + + static tempVec2_1 = new Vector2(); + + /** + * @param target {Element} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.moving = false; + this.lastPosition = new Vector2(); + this.deltaPosition = new Vector2(); + + this.speed = speed; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplierX = 0; + this.pixelToSpeedMultiplierY = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.target.addEventListener("mousedown", this.onMouseDown); + window.addEventListener("mousemove", this.onMouseMove); + window.addEventListener("mouseup", this.onMouseUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.target.removeEventListener("mousedown", this.onMouseDown); + window.removeEventListener("mousemove", this.onMouseMove); + window.removeEventListener("mouseup", this.onMouseUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaPosition.x === 0 && this.deltaPosition.y === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + let directionDelta = MouseMoveControls.tempVec2_1.copy(this.deltaPosition); + directionDelta.rotateAround(VEC2_ZERO, this.manager.rotation); + + this.manager.position.x += directionDelta.x * smoothing * this.manager.distance * this.speed * this.pixelToSpeedMultiplierX; + this.manager.position.z += directionDelta.y * smoothing * this.manager.distance * this.speed * this.pixelToSpeedMultiplierY; + + this.deltaPosition.multiplyScalar(1 - smoothing); + if (this.deltaPosition.lengthSq() < 0.0001) { + this.deltaPosition.set(0, 0); + } + } + + reset() { + this.deltaPosition.set(0, 0); + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseDown = evt => { + if ((evt.buttons !== undefined ? evt.buttons === 1 : evt.button === 0) && !evt.altKey) { + this.moving = true; + this.deltaPosition.set(0, 0); + this.lastPosition.set(evt.x, evt.y); + } + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseMove = evt => { + let position = MouseMoveControls.tempVec2_1.set(evt.x, evt.y); + + if(this.moving){ + this.deltaPosition.sub(position).add(this.lastPosition); + } + + this.lastPosition.copy(position); + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseUp = evt => { + if (evt.button === 0) this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplierX = (1 / this.target.clientWidth) * (this.target.clientWidth / this.target.clientHeight); + this.pixelToSpeedMultiplierY = 1 / this.target.clientHeight; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseRotateControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseRotateControls.js new file mode 100644 index 00000000..b6e17d80 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseRotateControls.js @@ -0,0 +1,130 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; + +export class MouseRotateControls { + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.moving = false; + this.lastX = 0; + this.deltaRotation = 0; + + this.speed = speed; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplierX = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.target.addEventListener("mousedown", this.onMouseDown); + window.addEventListener("mousemove", this.onMouseMove); + window.addEventListener("mouseup", this.onMouseUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.target.removeEventListener("mousedown", this.onMouseDown); + window.removeEventListener("mousemove", this.onMouseMove); + window.removeEventListener("mouseup", this.onMouseUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaRotation === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.rotation += this.deltaRotation * smoothing * this.speed * this.pixelToSpeedMultiplierX; + + this.deltaRotation *= 1 - smoothing; + if (Math.abs(this.deltaRotation) < 0.0001) { + this.deltaRotation = 0; + } + } + + reset() { + this.deltaRotation = 0; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseDown = evt => { + if ((evt.buttons !== undefined ? evt.buttons === 2 : evt.button === 2) || + ((evt.altKey || evt.ctrlKey) && (evt.buttons !== undefined ? evt.buttons === 1 : evt.button === 0))) { + this.moving = true; + this.deltaRotation = 0; + this.lastX = evt.x; + } + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseMove = evt => { + if(this.moving){ + this.deltaRotation += evt.x - this.lastX; + } + + this.lastX = evt.x; + } + + /** + * @private + * @param evt {MouseEvent} + */ + onMouseUp = evt => { + this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplierX = (1 / this.target.clientWidth); //* (this.target.clientWidth / this.target.clientHeight); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseZoomControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseZoomControls.js new file mode 100644 index 00000000..c4c7d22e --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/mouse/MouseZoomControls.js @@ -0,0 +1,92 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; + +export class MouseZoomControls { + + /** + * @param target {EventTarget} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, speed, stiffness) { + this.target = target; + this.manager = null; + + this.stiffness = stiffness; + this.speed = speed; + + this.deltaZoom = 0; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.target.addEventListener("wheel", this.onMouseWheel, {passive: true}); + } + + stop() { + this.target.removeEventListener("wheel", this.onMouseWheel); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaZoom === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.distance *= Math.pow(1.5, this.deltaZoom * smoothing * this.speed); + + this.deltaZoom *= 1 - smoothing; + if (Math.abs(this.deltaZoom) < 0.0001) { + this.deltaZoom = 0; + } + } + + reset() { + this.deltaZoom = 0; + } + + /** + * @private + * @param evt {WheelEvent} + */ + onMouseWheel = evt => { + let delta = evt.deltaY; + if (evt.deltaMode === WheelEvent.DOM_DELTA_PIXEL) delta *= 0.01; + if (evt.deltaMode === WheelEvent.DOM_DELTA_LINE) delta *= 0.33; + + this.deltaZoom += delta; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchAngleControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchAngleControls.js new file mode 100644 index 00000000..8d376069 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchAngleControls.js @@ -0,0 +1,131 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; + +export class TouchAngleControls { + + /** + * @param target {Element} + * @param hammer {Manager} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, hammer, speed, stiffness) { + this.target = target; + this.hammer = hammer; + this.manager = null; + + this.moving = false; + this.lastY = 0; + this.deltaAngle = 0; + + this.speed = speed; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplierY = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.hammer.on("tiltstart", this.onTouchDown); + this.hammer.on("tiltmove", this.onTouchMove); + this.hammer.on("tiltend", this.onTouchUp); + this.hammer.on("tiltcancel", this.onTouchUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.hammer.off("tiltstart", this.onTouchDown); + this.hammer.off("tiltmove", this.onTouchMove); + this.hammer.off("tiltend", this.onTouchUp); + this.hammer.off("tiltcancel", this.onTouchUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaAngle === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.angle += this.deltaAngle * smoothing * this.speed * this.pixelToSpeedMultiplierY; + + this.deltaAngle *= 1 - smoothing; + if (Math.abs(this.deltaAngle) < 0.0001) { + this.deltaAngle = 0; + } + } + + reset() { + this.deltaAngle = 0; + } + + /** + * @private + * @param evt {object} + */ + onTouchDown = evt => { + this.moving = true; + this.deltaAngle = 0; + this.lastY = evt.center.y; + } + + /** + * @private + * @param evt {object} + */ + onTouchMove = evt => { + if(this.moving){ + this.deltaAngle -= evt.center.y - this.lastY; + } + + this.lastY = evt.center.y; + } + + /** + * @private + * @param evt {object} + */ + onTouchUp = evt => { + this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplierY = 1 / this.target.clientHeight; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchMoveControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchMoveControls.js new file mode 100644 index 00000000..336e7d18 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchMoveControls.js @@ -0,0 +1,148 @@ +import {MathUtils, Vector2} from "three"; +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {VEC2_ZERO} from "../../../util/Utils"; + +export class TouchMoveControls { + + static tempVec2_1 = new Vector2(); + + /** + * @param target {Element} + * @param hammer {Manager} + * @param speed {number} + * @param stiffness {number} + */ + constructor(target, hammer, speed, stiffness) { + this.target = target; + this.hammer = hammer; + this.manager = null; + + this.moving = false; + this.lastPosition = new Vector2(); + this.deltaPosition = new Vector2(); + + this.speed = speed; + this.stiffness = stiffness; + + this.pixelToSpeedMultiplierX = 0; + this.pixelToSpeedMultiplierY = 0; + this.updatePixelToSpeedMultiplier(); + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.hammer.on("movestart", this.onTouchDown); + this.hammer.on("movemove", this.onTouchMove); + this.hammer.on("moveend", this.onTouchUp); + this.hammer.on("movecancel", this.onTouchUp); + + window.addEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + stop() { + this.hammer.off("movestart", this.onTouchDown); + this.hammer.off("movemove", this.onTouchMove); + this.hammer.off("moveend", this.onTouchUp); + this.hammer.off("movecancel", this.onTouchUp); + + window.removeEventListener("resize", this.updatePixelToSpeedMultiplier); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaPosition.x === 0 && this.deltaPosition.y === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + let directionDelta = TouchMoveControls.tempVec2_1.copy(this.deltaPosition); + directionDelta.rotateAround(VEC2_ZERO, this.manager.rotation); + + this.manager.position.x += directionDelta.x * smoothing * this.manager.distance * this.speed * this.pixelToSpeedMultiplierX; + this.manager.position.z += directionDelta.y * smoothing * this.manager.distance * this.speed * this.pixelToSpeedMultiplierY; + + this.deltaPosition.multiplyScalar(1 - smoothing); + if (this.deltaPosition.lengthSq() < 0.0001) { + this.deltaPosition.set(0, 0); + } + } + + reset() { + this.deltaPosition.set(0, 0); + } + + /** + * @private + * @param evt {object} + */ + onTouchDown = evt => { + if (evt.pointerType === "mouse") return; + + this.moving = true; + this.deltaPosition.set(0, 0); + this.lastPosition.set(evt.center.x, evt.center.y); + } + + /** + * @private + * @param evt {object} + */ + onTouchMove = evt => { + if (evt.pointerType === "mouse") return; + + let position = TouchMoveControls.tempVec2_1.set(evt.center.x, evt.center.y); + + if(this.moving){ + this.deltaPosition.sub(position).add(this.lastPosition); + } + + this.lastPosition.copy(position); + } + + /** + * @private + * @param evt {object} + */ + onTouchUp = evt => { + if (evt.pointerType === "mouse") return; + + this.moving = false; + } + + updatePixelToSpeedMultiplier = () => { + this.pixelToSpeedMultiplierX = (1 / this.target.clientWidth) * (this.target.clientWidth / this.target.clientHeight); + this.pixelToSpeedMultiplierY = 1 / this.target.clientHeight; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchRotateControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchRotateControls.js new file mode 100644 index 00000000..5177d7a1 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchRotateControls.js @@ -0,0 +1,122 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MathUtils} from "three"; + +export class TouchRotateControls { + + /** + * @param hammer {Manager} + * @param speed {number} + * @param stiffness {number} + */ + constructor(hammer, speed, stiffness) { + this.hammer = hammer; + this.manager = null; + + this.moving = false; + this.lastRotation = 0; + this.deltaRotation = 0; + + this.speed = speed; + this.stiffness = stiffness; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.hammer.on("rotatestart", this.onTouchDown); + this.hammer.on("rotatemove", this.onTouchMove); + this.hammer.on("rotateend", this.onTouchUp); + this.hammer.on("rotatecancel", this.onTouchUp); + } + + stop() { + this.hammer.off("rotatestart", this.onTouchDown); + this.hammer.off("rotatemove", this.onTouchMove); + this.hammer.off("rotateend", this.onTouchUp); + this.hammer.off("rotatecancel", this.onTouchUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaRotation === 0) return; + + let smoothing = this.stiffness / (16.666 / delta); + smoothing = MathUtils.clamp(smoothing, 0, 1); + + this.manager.rotation += this.deltaRotation * smoothing * this.speed; + + this.deltaRotation *= 1 - smoothing; + if (Math.abs(this.deltaRotation) < 0.0001) { + this.deltaRotation = 0; + } + } + + reset() { + this.deltaRotation = 0; + } + + /** + * @private + * @param evt {object} + */ + onTouchDown = evt => { + this.moving = true; + this.deltaRotation = 0; + this.lastRotation = evt.rotation; + } + + /** + * @private + * @param evt {object} + */ + onTouchMove = evt => { + if(this.moving){ + let delta = evt.rotation - this.lastRotation; + if (delta > 180) delta -= 360; + if (delta < -180) delta += 360; + + this.deltaRotation -= delta; + } + + this.lastRotation = evt.rotation; + } + + /** + * @private + * @param evt {object} + */ + onTouchUp = evt => { + this.moving = false; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchZoomControls.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchZoomControls.js new file mode 100644 index 00000000..e959637d --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/controls/map/touch/TouchZoomControls.js @@ -0,0 +1,103 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +export class TouchZoomControls { + + /** + * @param hammer {Manager} + */ + constructor(hammer) { + this.hammer = hammer; + this.manager = null; + + this.moving = false; + this.deltaZoom = 1; + this.lastZoom = 1; + } + + /** + * @param manager {ControlsManager} + */ + start(manager) { + this.manager = manager; + + this.hammer.on("zoomstart", this.onTouchDown); + this.hammer.on("zoommove", this.onTouchMove); + this.hammer.on("zoomend", this.onTouchUp); + this.hammer.on("zoomcancel", this.onTouchUp); + } + + stop() { + this.hammer.off("zoomstart", this.onTouchDown); + this.hammer.off("zoommove", this.onTouchMove); + this.hammer.off("zoomend", this.onTouchUp); + this.hammer.off("zoomcancel", this.onTouchUp); + } + + /** + * @param delta {number} + * @param map {Map} + */ + update(delta, map) { + if (this.deltaZoom === 1) return; + + this.manager.distance /= this.deltaZoom; + this.deltaZoom = 1; + } + + reset() { + this.deltaZoom = 1; + } + + /** + * @private + * @param evt {object} + */ + onTouchDown = evt => { + this.moving = true; + this.lastZoom = 1; + } + + /** + * @private + * @param evt {object} + */ + onTouchMove = evt => { + if(this.moving){ + this.deltaZoom *= evt.scale / this.lastZoom; + } + + this.lastZoom = evt.scale; + } + + /** + * @private + * @param evt {object} + */ + onTouchUp = evt => { + this.moving = false; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/LowresTileLoader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/LowresTileLoader.js new file mode 100644 index 00000000..15017a33 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/LowresTileLoader.js @@ -0,0 +1,138 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {pathFromCoords} from "../util/Utils"; +import { + TextureLoader, + Mesh, + PlaneBufferGeometry, + VertexColors, + FrontSide, + ShaderMaterial, + NearestFilter, + ClampToEdgeWrapping, + NearestMipMapLinearFilter, + Vector2 +} from "three"; + +export class LowresTileLoader { + + constructor(tilePath, tileSettings, lod, vertexShader, fragmentShader, uniforms, loadBlocker = () => Promise.resolve(), tileCacheHash = 0) { + Object.defineProperty( this, 'isLowresTileLoader', { value: true } ); + + this.tilePath = tilePath; + this.tileSettings = tileSettings; + this.lod = lod; + this.loadBlocker = loadBlocker; + this.tileCacheHash = tileCacheHash; + + this.vertexShader = vertexShader; + this.fragmentShader = fragmentShader; + this.uniforms = uniforms; + + this.textureLoader = new TextureLoader(); + this.geometry = new PlaneBufferGeometry( + tileSettings.tileSize.x + 1, tileSettings.tileSize.z + 1, + Math.ceil(100 / (lod * 2)), Math.ceil(100 / (lod * 2)) + ); + this.geometry.deleteAttribute('normal'); + this.geometry.deleteAttribute('uv'); + this.geometry.rotateX(-Math.PI / 2); + this.geometry.translate(tileSettings.tileSize.x / 2 + 1, 0, tileSettings.tileSize.x / 2 + 1); + } + + load = (tileX, tileZ, cancelCheck = () => false) => { + let tileUrl = this.tilePath + this.lod + "/" + pathFromCoords(tileX, tileZ) + '.png'; + + //await this.loadBlocker(); + return new Promise((resolve, reject) => { + this.textureLoader.load(tileUrl + '?' + this.tileCacheHash, + async texture => { + texture.anisotropy = 1; + texture.generateMipmaps = false; + texture.magFilter = NearestFilter; + texture.minFilter = texture.generateMipmaps ? NearestMipMapLinearFilter : NearestFilter; + texture.wrapS = ClampToEdgeWrapping; + texture.wrapT = ClampToEdgeWrapping; + texture.flipY = false; + texture.flatShading = true; + + await this.loadBlocker(); + if (cancelCheck()){ + texture.dispose(); + reject({status: "cancelled"}); + return; + } + + const scale = Math.pow(this.tileSettings.lodFactor, this.lod - 1); + + let material = new ShaderMaterial({ + uniforms: { + ...this.uniforms, + tileSize: { + value: new Vector2(this.tileSettings.tileSize.x, this.tileSettings.tileSize.z) + }, + textureSize: { + value: new Vector2(texture.image.width, texture.image.height) + }, + textureImage: { + type: 't', + value: texture + }, + lod: { + value: this.lod + }, + lodScale: { + value: scale + } + }, + vertexShader: this.vertexShader, + fragmentShader: this.fragmentShader, + transparent: false, + depthWrite: true, + depthTest: true, + vertexColors: VertexColors, + side: FrontSide, + wireframe: false, + }); + + let object = new Mesh(this.geometry, material); + + object.position.set(tileX * this.tileSettings.tileSize.x * scale, 0, tileZ * this.tileSettings.tileSize.z * scale); + object.scale.set(scale, 1, scale); + + object.userData.tileUrl = tileUrl; + object.userData.tileType = "lowres"; + + object.updateMatrixWorld(true); + + resolve(object); + }, + undefined, + reject + ); + }); + } + +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/Map.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/Map.js new file mode 100644 index 00000000..d3b890b9 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/Map.js @@ -0,0 +1,434 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { + ClampToEdgeWrapping, + Color, + FileLoader, + FrontSide, + NearestFilter, + NearestMipMapLinearFilter, + Raycaster, + Scene, + ShaderMaterial, + Texture, + Vector3, + VertexColors +} from "three"; +import {alert, dispatchEvent, generateCacheHash, getPixel, hashTile, stringToImage, vecArrToObj} from "../util/Utils"; +import {TileManager} from "./TileManager"; +import {TileLoader} from "./TileLoader"; +import {LowresTileLoader} from "./LowresTileLoader"; + +export class Map { + + /** + * @param id {string} + * @param dataUrl {string} + * @param loadBlocker {function: Promise} + * @param events {EventTarget} + */ + constructor(id, dataUrl, loadBlocker, events = null) { + Object.defineProperty( this, 'isMap', { value: true } ); + + this.loadBlocker = loadBlocker; + this.events = events; + + this.data = { + id: id, + sorting: 0, + dataUrl: dataUrl, + settingsUrl: dataUrl + "settings.json", + texturesUrl: dataUrl + "textures.json", + name: id, + startPos: {x: 0, z: 0}, + skyColor: new Color(), + ambientLight: 0, + hires: { + tileSize: {x: 32, z: 32}, + scale: {x: 1, z: 1}, + translate: {x: 2, z: 2} + }, + lowres: { + tileSize: {x: 32, z: 32}, + lodFactor: 5, + lodCount: 3 + } + }; + + this.raycaster = new Raycaster(); + + /** @type {ShaderMaterial[]} */ + this.hiresMaterial = null; + /** @type {ShaderMaterial} */ + this.lowresMaterial = null; + /** @type {Texture[]} */ + this.loadedTextures = []; + + /** @type {TileManager} */ + this.hiresTileManager = null; + /** @type {TileManager[]} */ + this.lowresTileManager = null; + } + + /** + * Loads textures and materials for this map so it is ready to load map-tiles + * @param hiresVertexShader {string} + * @param hiresFragmentShader {string} + * @param lowresVertexShader {string} + * @param lowresFragmentShader {string} + * @param uniforms {object} + * @param tileCacheHash {number} + * @returns {Promise} + */ + load(hiresVertexShader, hiresFragmentShader, lowresVertexShader, lowresFragmentShader, uniforms, tileCacheHash = 0) { + this.unload() + + let settingsPromise = this.loadSettings(); + let textureFilePromise = this.loadTexturesFile(); + + this.lowresMaterial = this.createLowresMaterial(lowresVertexShader, lowresFragmentShader, uniforms); + + return Promise.all([settingsPromise, textureFilePromise]) + .then(values => { + let textures = values[1]; + if (textures === null) throw new Error("Failed to parse textures.json!"); + + this.hiresMaterial = this.createHiresMaterial(hiresVertexShader, hiresFragmentShader, uniforms, textures); + + this.hiresTileManager = new TileManager(new TileLoader(`${this.data.dataUrl}tiles/0/`, this.hiresMaterial, this.data.hires, this.loadBlocker, tileCacheHash), this.onTileLoad("hires"), this.onTileUnload("hires"), this.events); + this.hiresTileManager.scene.autoUpdate = false; + + this.lowresTileManager = []; + for (let i = 0; i < this.data.lowres.lodCount; i++) { + this.lowresTileManager[i] = new TileManager(new LowresTileLoader(`${this.data.dataUrl}tiles/`, this.data.lowres, i + 1, lowresVertexShader, lowresFragmentShader, uniforms, async () => {}, tileCacheHash), this.onTileLoad("lowres"), this.onTileUnload("lowres"), this.events); + this.lowresTileManager[i].scene.autoUpdate = false; + } + + alert(this.events, `Map '${this.data.id}' is loaded.`, "fine"); + }); + } + + /** + * Loads the settings of this map + * @returns {Promise} + */ + loadSettings() { + return this.loadSettingsFile() + .then(worldSettings => { + this.data.name = worldSettings.name ? worldSettings.name : this.data.name; + + this.data.sorting = worldSettings.sorting ? worldSettings.sorting : this.data.sorting; + + this.data.startPos = {...this.data.startPos, ...vecArrToObj(worldSettings.startPos, true)}; + + if (worldSettings.skyColor && worldSettings.skyColor.length >= 3) { + this.data.skyColor.setRGB( + worldSettings.skyColor[0], + worldSettings.skyColor[1], + worldSettings.skyColor[2] + ); + } + + this.data.ambientLight = worldSettings.ambientLight ? worldSettings.ambientLight : this.data.ambientLight; + + if (worldSettings.hires === undefined) worldSettings.hires = {}; + if (worldSettings.lowres === undefined) worldSettings.lowres = {}; + + this.data.hires = { + tileSize: {...this.data.hires.tileSize, ...vecArrToObj(worldSettings.hires.tileSize, true)}, + scale: {...this.data.hires.scale, ...vecArrToObj(worldSettings.hires.scale, true)}, + translate: {...this.data.hires.translate, ...vecArrToObj(worldSettings.hires.translate, true)} + }; + this.data.lowres = { + tileSize: {...this.data.lowres.tileSize, ...vecArrToObj(worldSettings.lowres.tileSize, true)}, + lodFactor: worldSettings.lowres.lodFactor !== undefined ? worldSettings.lowres.lodFactor : this.data.lowres.lodFactor, + lodCount: worldSettings.lowres.lodCount !== undefined ? worldSettings.lowres.lodCount : this.data.lowres.lodCount + }; + + alert(this.events, `Settings for map '${this.data.id}' loaded.`, "fine"); + }); + } + + onTileLoad = layer => tile => { + dispatchEvent(this.events, "bluemapMapTileLoaded", { + tile: tile, + layer: layer + }); + } + + onTileUnload = layer => tile => { + dispatchEvent(this.events, "bluemapMapTileUnloaded", { + tile: tile, + layer: layer + }); + } + + /** + * @param x {number} + * @param z {number} + * @param hiresViewDistance {number} + * @param lowresViewDistance {number} + */ + loadMapArea(x, z, hiresViewDistance, lowresViewDistance) { + if (!this.isLoaded) return; + + for (let i = this.lowresTileManager.length - 1; i >= 0; i--) { + const lod = i + 1; + const scale = Math.pow(this.data.lowres.lodFactor, lod - 1); + const lowresX = Math.floor(x / (this.data.lowres.tileSize.x * scale)); + const lowresZ = Math.floor(z / (this.data.lowres.tileSize.z * scale)); + const lowresViewX = Math.floor(lowresViewDistance / this.data.lowres.tileSize.x); + const lowresViewZ = Math.floor(lowresViewDistance / this.data.lowres.tileSize.z); + this.lowresTileManager[i].loadAroundTile(lowresX, lowresZ, lowresViewX, lowresViewZ); + } + + const hiresX = Math.floor((x - this.data.hires.translate.x) / this.data.hires.tileSize.x); + const hiresZ = Math.floor((z - this.data.hires.translate.z) / this.data.hires.tileSize.z); + const hiresViewX = Math.floor(hiresViewDistance / this.data.hires.tileSize.x); + const hiresViewZ = Math.floor(hiresViewDistance / this.data.hires.tileSize.z); + this.hiresTileManager.loadAroundTile(hiresX, hiresZ, hiresViewX, hiresViewZ); + } + + /** + * Loads the settings.json file for this map + * @returns {Promise} + */ + loadSettingsFile() { + return new Promise((resolve, reject) => { + alert(this.events, `Loading settings for map '${this.data.id}'...`, "fine"); + + let loader = new FileLoader(); + loader.setResponseType("json"); + loader.load(this.data.settingsUrl + "?" + generateCacheHash(), + resolve, + () => {}, + () => reject(`Failed to load the settings.json for map: ${this.data.id}`) + ) + }); + } + + /** + * Loads the textures.json file for this map + * @returns {Promise} + */ + loadTexturesFile() { + return new Promise((resolve, reject) => { + alert(this.events, `Loading textures for map '${this.data.id}'...`, "fine"); + + let loader = new FileLoader(); + loader.setResponseType("json"); + loader.load(this.data.texturesUrl + "?" + generateCacheHash(), + resolve, + () => {}, + () => reject(`Failed to load the textures.json for map: ${this.data.id}`) + ) + }); + } + + /** + * Creates a hires Material with the given textures + * @param vertexShader {string} + * @param fragmentShader {string} + * @param uniforms {object} + * @param textures {{ + * resourcePath: string, + * color: number[], + * halfTransparent: boolean, + * texture: string + * }[]} the textures-data + * @returns {ShaderMaterial[]} the hires Material (array because its a multi-material) + */ + createHiresMaterial(vertexShader, fragmentShader, uniforms, textures) { + let materials = []; + if (!Array.isArray(textures)) throw new Error("Invalid texture.json: 'textures' is not an array!") + for (let i = 0; i < textures.length; i++) { + let textureSettings = textures[i]; + + let color = textureSettings.color; + if (!Array.isArray(color) || color.length < 4){ + color = [0, 0, 0, 0]; + } + + let opaque = color[3] === 1; + let transparent = !!textureSettings.halfTransparent; + + let texture = new Texture(); + texture.image = stringToImage(textureSettings.texture); + + texture.anisotropy = 1; + texture.generateMipmaps = opaque || transparent; + texture.magFilter = NearestFilter; + texture.minFilter = texture.generateMipmaps ? NearestMipMapLinearFilter : NearestFilter; + texture.wrapS = ClampToEdgeWrapping; + texture.wrapT = ClampToEdgeWrapping; + texture.flipY = false; + texture.flatShading = true; + texture.image.addEventListener("load", () => texture.needsUpdate = true); + + this.loadedTextures.push(texture); + + let material = new ShaderMaterial({ + uniforms: { + ...uniforms, + textureImage: { + type: 't', + value: texture + }, + transparent: { value: transparent } + }, + vertexShader: vertexShader, + fragmentShader: fragmentShader, + transparent: transparent, + depthWrite: true, + depthTest: true, + vertexColors: VertexColors, + side: FrontSide, + wireframe: false, + }); + + material.needsUpdate = true; + materials[i] = material; + } + + return materials; + } + + /** + * Creates a lowres Material + * @param vertexShader {string} + * @param fragmentShader {string} + * @param uniforms {object} + * @returns {ShaderMaterial} the hires Material + */ + createLowresMaterial(vertexShader, fragmentShader, uniforms) { + return new ShaderMaterial({ + uniforms: uniforms, + vertexShader: vertexShader, + fragmentShader: fragmentShader, + transparent: false, + depthWrite: true, + depthTest: true, + vertexColors: VertexColors, + side: FrontSide, + wireframe: false + }); + } + + unload() { + if (this.hiresTileManager) this.hiresTileManager.unload(); + this.hiresTileManager = null; + + if (this.lowresTileManager) { + for (let i = 0; i < this.lowresTileManager.length; i++) { + this.lowresTileManager[i].unload(); + } + this.lowresTileManager = null; + } + + if (this.hiresMaterial) this.hiresMaterial.forEach(material => material.dispose()); + this.hiresMaterial = null; + + if (this.lowresMaterial) this.lowresMaterial.dispose(); + this.lowresMaterial = null; + + this.loadedTextures.forEach(texture => texture.dispose()); + this.loadedTextures = []; + } + + /** + * Ray-traces and returns the terrain-height at a specific location, returns false if there is no map-tile loaded at that location + * @param x {number} + * @param z {number} + * @returns {boolean|number} + */ + terrainHeightAt(x, z) { + if (!this.isLoaded) return false; + + this.raycaster.set( + new Vector3(x, 300, z), // ray-start + new Vector3(0, -1, 0) // ray-direction + ); + this.raycaster.near = 1; + this.raycaster.far = 300; + this.raycaster.layers.enableAll(); + + let hiresTileHash = hashTile(Math.floor((x - this.data.hires.translate.x) / this.data.hires.tileSize.x), Math.floor((z - this.data.hires.translate.z) / this.data.hires.tileSize.z)); + let tile = this.hiresTileManager.tiles.get(hiresTileHash); + + if (tile?.model) { + try { + let intersects = this.raycaster.intersectObjects([tile.model]); + if (intersects.length > 0) { + return intersects[0].point.y; + } + } catch (ignore) { + //empty + } + } + + for (let i = 0; i < this.lowresTileManager.length; i++) { + const lod = i + 1; + const scale = Math.pow(this.data.lowres.lodFactor, lod - 1); + const scaledTileSize = { + x: this.data.lowres.tileSize.x * scale, + z: this.data.lowres.tileSize.z * scale + } + const tileX = Math.floor(x / scaledTileSize.x); + const tileZ = Math.floor(z / scaledTileSize.z); + let lowresTileHash = hashTile(tileX, tileZ); + tile = this.lowresTileManager[i].tiles.get(lowresTileHash); + + if (!tile || !tile.model) continue; + + const texture = tile.model.material.uniforms?.textureImage?.value?.image; + if (texture == null) continue; + + const color = getPixel(texture, x - tileX * scaledTileSize.x, z - tileZ * scaledTileSize.z + this.data.lowres.tileSize.z + 1); + + let heightUnsigned = color[1] * 256.0 + color[2]; + if (heightUnsigned >= 32768.0) { + return -(65535.0 - heightUnsigned); + } else { + return heightUnsigned; + } + + + } + + return false; + } + + dispose() { + this.unload(); + } + + /** + * @returns {boolean} + */ + get isLoaded() { + return !!(this.hiresMaterial && this.lowresMaterial); + } + +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/Tile.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/Tile.js new file mode 100644 index 00000000..a7714314 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/Tile.js @@ -0,0 +1,103 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +export class Tile { + + /** + * @param x {number} + * @param z {number} + * @param onLoad {function(Tile)} + * @param onUnload {function(Tile)} + */ + constructor(x, z, onLoad, onUnload) { + Object.defineProperty( this, 'isTile', { value: true } ); + + /** @type {THREE.Mesh} */ + this.model = null; + + this.onLoad = onLoad; + this.onUnload = onUnload; + + this.x = x; + this.z = z; + + this.unloaded = true; + this.loading = false; + } + + /** + * @param tileLoader {TileLoader} + * @returns {Promise} + */ + load(tileLoader) { + if (this.loading) return Promise.reject("tile is already loading!"); + this.loading = true; + + this.unload(); + + this.unloaded = false; + return tileLoader.load(this.x, this.z, () => this.unloaded) + .then(model => { + if (this.unloaded){ + Tile.disposeModel(model); + return; + } + + this.model = model; + this.onLoad(this); + }) + .finally(() => { + this.loading = false; + }); + } + + unload() { + this.unloaded = true; + if (this.model) { + this.onUnload(this); + + Tile.disposeModel(this.model); + + this.model = null; + } + } + + static disposeModel(model) { + if (model.userData?.tileType === "hires") { + model.geometry.dispose(); + } + + else if (model.userData?.tileType === "lowres") { + model.material.uniforms.textureImage.value.dispose(); + model.material.dispose(); + } + } + + /** + * @returns {boolean} + */ + get loaded() { + return !!this.model; + } +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileLoader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileLoader.js new file mode 100644 index 00000000..8d2b756e --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileLoader.js @@ -0,0 +1,100 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {pathFromCoords} from "../util/Utils"; +import {BufferGeometryLoader, FileLoader, Mesh} from "three"; + +export class TileLoader { + + /** + * @param tilePath {string} + * @param material {THREE.Material | THREE.Material[]} + * @param tileSettings {{ + * tileSize: {x: number, z: number}, + * scale: {x: number, z: number}, + * translate: {x: number, z: number} + * }} + * @param loadBlocker {function: Promise} + * @param tileCacheHash {number} + */ + constructor(tilePath, material, tileSettings, loadBlocker = () => Promise.resolve(), tileCacheHash = 0) { + Object.defineProperty( this, 'isTileLoader', { value: true } ); + + this.tilePath = tilePath; + this.material = material; + this.tileSettings = tileSettings; + + this.tileCacheHash = tileCacheHash; + + this.loadBlocker = loadBlocker; + + this.fileLoader = new FileLoader(); + this.fileLoader.setResponseType('json'); + + this.bufferGeometryLoader = new BufferGeometryLoader(); + } + + load = (tileX, tileZ, cancelCheck = () => false) => { + let tileUrl = this.tilePath + pathFromCoords(tileX, tileZ) + '.json'; + + //await this.loadBlocker(); + return new Promise((resolve, reject) => { + this.fileLoader.load(tileUrl + '?' + this.tileCacheHash, + async json => { + let geometryJson = json.tileGeometry || {}; + if (!geometryJson.type || geometryJson.type !== 'BufferGeometry'){ + reject({status: "empty"}); + return; + } + + await this.loadBlocker(); + if (cancelCheck()){ + reject({status: "cancelled"}); + return; + } + + let geometry = this.bufferGeometryLoader.parse(geometryJson); + + let object = new Mesh(geometry, this.material); + + let tileSize = this.tileSettings.tileSize; + let translate = this.tileSettings.translate; + let scale = this.tileSettings.scale; + object.position.set(tileX * tileSize.x + translate.x, 0, tileZ * tileSize.z + translate.z); + object.scale.set(scale.x, 1, scale.z); + + object.userData.tileUrl = tileUrl; + object.userData.tileType = "hires"; + + object.updateMatrixWorld(true); + + resolve(object); + }, + () => {}, + reject + ); + }); + } + +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileManager.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileManager.js new file mode 100644 index 00000000..a52c55e9 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileManager.js @@ -0,0 +1,221 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { Vector2, Scene, Group } from 'three'; +import { Tile } from './Tile.js'; +import {alert, hashTile} from '../util/Utils.js'; +import {TileMap} from "./TileMap"; + +export class TileManager { + + static tileMapSize = 100; + static tileMapHalfSize = TileManager.tileMapSize / 2; + + /** + * @param tileLoader {TileLoader | LowresTileLoader} + * @param onTileLoad {function(Tile)} + * @param onTileUnload {function(Tile)} + * @param events {EventTarget} + */ + constructor(tileLoader, onTileLoad = null, onTileUnload = null, events = null) { + Object.defineProperty( this, 'isTileManager', { value: true } ); + + this.sceneParent = new Scene(); + this.scene = new Group(); + this.sceneParent.add(this.scene); + + this.events = events; + this.tileLoader = tileLoader; + + this.onTileLoad = onTileLoad || function(){}; + this.onTileUnload = onTileUnload || function(){}; + + this.viewDistanceX = 1; + this.viewDistanceZ = 1; + this.centerTile = new Vector2(0, 0); + + this.currentlyLoading = 0; + this.loadTimeout = null; + + //map of loaded tiles + this.tiles = new Map(); + + // a canvas that keeps track of the loaded tiles, used for shaders + this.tileMap = new TileMap(TileManager.tileMapSize, TileManager.tileMapSize); + + this.unloaded = true; + } + + /** + * @param x {number} + * @param z {number} + * @param viewDistanceX {number} + * @param viewDistanceZ {number} + */ + loadAroundTile(x, z, viewDistanceX, viewDistanceZ) { + this.unloaded = false; + + let unloadTiles = false; + if (this.viewDistanceX > viewDistanceX || this.viewDistanceZ > viewDistanceZ) { + unloadTiles = true; + } + + this.viewDistanceX = viewDistanceX; + this.viewDistanceZ = viewDistanceZ; + + if (viewDistanceX <= 0 || viewDistanceZ <= 0) { + this.removeAllTiles(); + return; + } + + if (unloadTiles || this.centerTile.x !== x || this.centerTile.y !== z) { + this.centerTile.set(x, z); + this.removeFarTiles(); + + this.tileMap.setAll(TileMap.EMPTY); + this.tiles.forEach(tile => { + if (!tile.loading && !tile.unloaded) { + this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.LOADED); + } + }); + } + + this.loadCloseTiles(); + } + + unload() { + this.unloaded = true; + this.removeAllTiles(); + } + + removeFarTiles() { + this.tiles.forEach((tile, hash, map) => { + if ( + tile.x + this.viewDistanceX < this.centerTile.x || + tile.x - this.viewDistanceX > this.centerTile.x || + tile.z + this.viewDistanceZ < this.centerTile.y || + tile.z - this.viewDistanceZ > this.centerTile.y + ) { + tile.unload(); + map.delete(hash); + } + }); + } + + removeAllTiles() { + this.tileMap.setAll(TileMap.EMPTY); + + this.tiles.forEach(tile => { + tile.unload(); + }); + this.tiles.clear(); + } + + loadCloseTiles = () => { + if (this.unloaded) return; + if (!this.loadNextTile()) return; + + if (this.loadTimeout) clearTimeout(this.loadTimeout); + + if (this.currentlyLoading < 8) { + this.loadTimeout = setTimeout(this.loadCloseTiles, 0); + } else { + this.loadTimeout = setTimeout(this.loadCloseTiles, 1000); + } + } + + /** + * @returns {boolean} + */ + loadNextTile() { + if (this.unloaded) return false; + + let x = 0; + let z = 0; + let d = 1; + let m = 1; + + while (m < Math.max(this.viewDistanceX, this.viewDistanceZ) * 2 + 1) { + while (2 * x * d < m) { + if (this.tryLoadTile(this.centerTile.x + x, this.centerTile.y + z)) return true; + x = x + d; + } + while (2 * z * d < m) { + if (this.tryLoadTile(this.centerTile.x + x, this.centerTile.y + z)) return true; + z = z + d; + } + d = -1 * d; + m = m + 1; + } + + return false; + } + + /** + * @param x {number} + * @param z {number} + * @returns {boolean} + */ + tryLoadTile(x, z) { + if (this.unloaded) return false; + + if (Math.abs(x - this.centerTile.x) > this.viewDistanceX) return false; + if (Math.abs(z - this.centerTile.y) > this.viewDistanceZ) return false; + + let tileHash = hashTile(x, z); + + let tile = this.tiles.get(tileHash); + if (tile !== undefined) return false; + + this.currentlyLoading++; + + tile = new Tile(x, z, this.handleLoadedTile, this.handleUnloadedTile); + this.tiles.set(tileHash, tile); + tile.load(this.tileLoader) + .then(() => { + if (this.loadTimeout) clearTimeout(this.loadTimeout); + this.loadTimeout = setTimeout(this.loadCloseTiles, 0); + }) + .catch(error => {}) + .finally(() => { + this.currentlyLoading--; + }); + + return true; + } + + handleLoadedTile = tile => { + this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.LOADED); + + this.scene.add(tile.model); + this.onTileLoad(tile); + } + + handleUnloadedTile = tile => { + this.tileMap.setTile(tile.x - this.centerTile.x + TileManager.tileMapHalfSize, tile.z - this.centerTile.y + TileManager.tileMapHalfSize, TileMap.EMPTY); + + this.scene.remove(tile.model); + this.onTileUnload(tile); + } +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileMap.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileMap.js new file mode 100644 index 00000000..cc5e2fe0 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/TileMap.js @@ -0,0 +1,81 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {ClampToEdgeWrapping, LinearFilter, NearestFilter, Texture} from "three"; + +export class TileMap { + + static EMPTY = "#000"; + static LOADED = "#fff"; + + /** + * @param width {number} + * @param height {number} + */ + constructor(width, height) { + this.canvas = document.createElementNS('http://www.w3.org/1999/xhtml', 'canvas'); + this.canvas.width = width; + this.canvas.height = height; + + /** + * @type CanvasRenderingContext2D + */ + this.tileMapContext = this.canvas.getContext('2d', { + alpha: false, + willReadFrequently: true, + }); + + this.texture = new Texture(this.canvas); + this.texture.generateMipmaps = false; + this.texture.magFilter = LinearFilter; + this.texture.minFilter = LinearFilter; + this.texture.wrapS = ClampToEdgeWrapping; + this.texture.wrapT = ClampToEdgeWrapping; + this.texture.flipY = false; + this.texture.needsUpdate = true; + } + + /** + * @param state {string} + */ + setAll(state) { + this.tileMapContext.fillStyle = state; + this.tileMapContext.fillRect(0, 0, this.canvas.width, this.canvas.height); + + this.texture.needsUpdate = true; + } + + /** + * @param x {number} + * @param z {number} + * @param state {string} + */ + setTile(x, z, state) { + this.tileMapContext.fillStyle = state; + this.tileMapContext.fillRect(x, z, 1, 1); + + this.texture.needsUpdate = true; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/hires/HiresFragmentShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/hires/HiresFragmentShader.js new file mode 100644 index 00000000..27f1d95b --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/hires/HiresFragmentShader.js @@ -0,0 +1,66 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { ShaderChunk } from 'three'; + +export const HIRES_FRAGMENT_SHADER = ` +${ShaderChunk.logdepthbuf_pars_fragment} + +#ifndef texture + #define texture texture2D +#endif + +uniform sampler2D textureImage; +uniform float sunlightStrength; +uniform float ambientLight; + +varying vec3 vPosition; +//varying vec3 vWorldPosition; +varying vec3 vNormal; +varying vec2 vUv; +varying vec3 vColor; +varying float vAo; +varying float vSunlight; +varying float vBlocklight; +//varying float vDistance; + +void main() { + vec4 color = texture(textureImage, vUv); + if (color.a <= 0.01) discard; + + //apply vertex-color + color.rgb *= vColor.rgb; + + //apply ao + color.rgb *= vAo; + + //apply light + float light = mix(vBlocklight, max(vSunlight, vBlocklight), sunlightStrength); + color.rgb *= mix(ambientLight, 1.0, light / 15.0); + + gl_FragColor = color; + + ${ShaderChunk.logdepthbuf_fragment} +} +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/hires/HiresVertexShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/hires/HiresVertexShader.js new file mode 100644 index 00000000..d919f420 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/hires/HiresVertexShader.js @@ -0,0 +1,56 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { ShaderChunk } from 'three'; + +export const HIRES_VERTEX_SHADER = ` +#include +${ShaderChunk.logdepthbuf_pars_vertex} + +attribute float ao; +attribute float sunlight; +attribute float blocklight; + +varying vec3 vPosition; +varying vec3 vNormal; +varying vec2 vUv; +varying vec3 vColor; +varying float vAo; +varying float vSunlight; +varying float vBlocklight; + +void main() { + vPosition = position; + vNormal = normal; + vUv = uv; + vColor = color; + vAo = ao; + vSunlight = sunlight; + vBlocklight = blocklight; + + gl_Position = projectionMatrix * (viewMatrix * modelMatrix * vec4(position, 1)); + + ${ShaderChunk.logdepthbuf_vertex} +} +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/lowres/LowresFragmentShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/lowres/LowresFragmentShader.js new file mode 100644 index 00000000..fb30d56c --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/lowres/LowresFragmentShader.js @@ -0,0 +1,125 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { ShaderChunk } from 'three'; + +export const LOWRES_FRAGMENT_SHADER = ` +${ShaderChunk.logdepthbuf_pars_fragment} + +#define PI 3.1415926535897932 + +#ifndef texture + #define texture texture2D +#endif + +struct TileMap { + sampler2D map; + float size; + vec2 scale; + vec2 translate; + vec2 pos; +}; + +uniform float sunlightStrength; +uniform float ambientLight; +uniform TileMap hiresTileMap; +uniform sampler2D textureImage; +uniform vec2 tileSize; +uniform vec2 textureSize; +uniform float lod; +uniform float lodScale; + +varying vec3 vPosition; +varying vec3 vWorldPosition; +varying float vDistance; + +float metaToHeight(vec4 meta) { + float heightUnsigned = meta.g * 65280.0 + meta.b * 255.0; + if (heightUnsigned >= 32768.0) { + return -(65535.0 - heightUnsigned); + } else { + return heightUnsigned; + } +} + +float metaToLight(vec4 meta) { + return meta.r * 255.0; +} + +vec2 posToColorUV(vec2 pos) { + return vec2(pos.x / textureSize.x, min(pos.y, tileSize.y) / textureSize.y); +} + +vec2 posToMetaUV(vec2 pos) { + return vec2(pos.x / textureSize.x, pos.y / textureSize.y + 0.5); +} + + +void main() { + //discard if hires tile is loaded at that position + if (vDistance < 900.0 && texture(hiresTileMap.map, ((vWorldPosition.xz - hiresTileMap.translate) / hiresTileMap.scale - hiresTileMap.pos) / hiresTileMap.size + 0.5).r > 0.75) discard; + + vec4 color = texture(textureImage, posToColorUV(vPosition.xz)); + vec4 meta = texture(textureImage, posToMetaUV(vPosition.xz)); + + float height = metaToHeight(meta); + + float heightX = metaToHeight(texture(textureImage, posToMetaUV(vPosition.xz + vec2(1.0, 0.0)))); + float heightZ = metaToHeight(texture(textureImage, posToMetaUV(vPosition.xz + vec2(0.0, 1.0)))); + float heightDiff = ((height - heightX) + (height - heightZ)) / lodScale; + float shade = clamp(heightDiff * 0.06, -0.2, 0.04); + + float ao = 0.0; + float aoStrength = 0.0; + if(lod == 1.0) { + aoStrength = smoothstep(PI - 0.8, PI - 0.2, acos(-clamp(viewMatrix[1][2], 0.0, 1.0))); + aoStrength *= 1.0 - smoothstep(300.0, 500.0, vDistance); + + if (aoStrength > 0.0) { + const float r = 3.0; + const float step = 0.2; + const float o = step / r * 0.1; + for (float vx = -r; vx <= r; vx++) { + for (float vz = -r; vz <= r; vz++) { + heightDiff = height - metaToHeight(texture(textureImage, posToMetaUV(vPosition.xz + vec2(vx * step, vz * step)))); + if (heightDiff < 0.0) { + ao -= o; + } + } + } + } + } + + color.rgb += mix(shade, shade * 0.3 + ao, aoStrength); + + float blockLight = metaToLight(meta); + float light = mix(blockLight, 15.0, sunlightStrength); + color.rgb *= mix(ambientLight, 1.0, light / 15.0); + + gl_FragColor = color; + + ${ShaderChunk.logdepthbuf_fragment} +} + +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/lowres/LowresVertexShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/lowres/LowresVertexShader.js new file mode 100644 index 00000000..067a552d --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/map/lowres/LowresVertexShader.js @@ -0,0 +1,69 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { ShaderChunk } from 'three'; + +export const LOWRES_VERTEX_SHADER = ` +#include +${ShaderChunk.logdepthbuf_pars_vertex} + +uniform sampler2D textureImage; +uniform vec2 tileSize; +uniform vec2 textureSize; + +varying vec3 vPosition; +varying vec3 vWorldPosition; +varying float vDistance; + +float metaToHeight(vec4 meta) { + float heightUnsigned = meta.g * 65280.0 + meta.b * 255.0; + if (heightUnsigned >= 32768.0) { + return -(65535.0 - heightUnsigned); + } else { + return heightUnsigned; + } +} + +vec2 posToMetaUV(vec2 pos) { + return vec2(pos.x / textureSize.x, pos.y / textureSize.y + 0.5); +} + +void main() { + vPosition = position; + + vec4 meta = texture(textureImage, posToMetaUV(position.xz)); + vPosition.y = metaToHeight(meta) + 1.0 - position.x * 0.0001 - position.z * 0.0002; //including small offset-tilt to prevent z-fighting + + vec4 worldPos = modelMatrix * vec4(vPosition, 1); + vec4 viewPos = viewMatrix * worldPos; + + vWorldPosition = worldPos.xyz; + vDistance = -viewPos.z; + + gl_Position = projectionMatrix * viewPos; + + ${ShaderChunk.logdepthbuf_vertex} +} + +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ExtrudeMarker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ExtrudeMarker.js new file mode 100644 index 00000000..8231893b --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ExtrudeMarker.js @@ -0,0 +1,467 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Color, DoubleSide, ExtrudeBufferGeometry, Mesh, ShaderMaterial, Shape, Vector2} from "three"; +import {LineMaterial} from "../util/lines/LineMaterial"; +import {MARKER_FILL_VERTEX_SHADER} from "./MarkerFillVertexShader"; +import {MARKER_FILL_FRAGMENT_SHADER} from "./MarkerFillFragmentShader"; +import {Line2} from "../util/lines/Line2"; +import {deepEquals} from "../util/Utils"; +import {LineSegmentsGeometry} from "../util/lines/LineSegmentsGeometry"; +import {ObjectMarker} from "./ObjectMarker"; + +export class ExtrudeMarker extends ObjectMarker { + + /** + * @param markerId {string} + */ + constructor(markerId) { + super(markerId); + Object.defineProperty(this, 'isExtrudeMarker', {value: true}); + this.data.type = "extrude"; + + let zero = new Vector2(); + let shape = new Shape([zero, zero, zero]); + this.fill = new ExtrudeMarkerFill(shape); + this.border = new ExtrudeMarkerBorder(shape); + this.border.renderOrder = -1; // render border before fill + + this.add(this.border, this.fill); + + this._markerData = {}; + } + + /** + * @param minY {number} + * @param maxY {number} + */ + setShapeY(minY, maxY) { + let relativeY = maxY - this.position.y; + let height = maxY - minY; + this.fill.position.y = relativeY; + this.border.position.y = relativeY; + this.fill.scale.y = height; + this.border.scale.y = height; + } + + /** + * @param shape {Shape} + */ + setShape(shape) { + this.fill.updateGeometry(shape); + this.border.updateGeometry(shape); + } + + /** + * @typedef {{r: number, g: number, b: number, a: number}} ColorLike + */ + + /** + * @param markerData {{ + * position: {x: number, y: number, z: number}, + * label: string, + * detail: string, + * shape: {x: number, z: number}[], + * shapeMinY: number, + * shapeMaxY: number, + * link: string, + * newTab: boolean, + * depthTest: boolean, + * lineWidth: number, + * lineColor: ColorLike, + * fillColor: ColorLike, + * minDistance: number, + * maxDistance: number + * }} + */ + updateFromData(markerData) { + super.updateFromData(markerData); + + // update shape only if needed, based on last update-data + if ( + !this._markerData.shape || !deepEquals(markerData.shape, this._markerData.shape) || + !this._markerData.position || !deepEquals(markerData.position, this._markerData.position) + ){ + this.setShape(this.createShapeFromData(markerData.shape)); + } + + // update shapeY + this.setShapeY((markerData.shapeMinY || 0) - 0.01, (markerData.shapeMaxY || 0) + 0.01); // offset by 0.01 to avoid z-fighting + + // update depthTest + this.border.depthTest = !!markerData.depthTest; + this.fill.depthTest = !!markerData.depthTest; + + // update border-width + this.border.linewidth = markerData.lineWidth !== undefined ? markerData.lineWidth : 2; + + // update border-color + let bc = markerData.lineColor || {}; + this.border.color.setRGB((bc.r || 0) / 255, (bc.g || 0) / 255, (bc.b || 0) / 255); + this.border.opacity = bc.a || 0; + + // update fill-color + let fc = markerData.fillColor || {}; + this.fill.color.setRGB((fc.r || 0) / 255, (fc.g || 0) / 255, (fc.b || 0) / 255); + this.fill.opacity = fc.a || 0; + + // update min/max distances + let minDist = markerData.minDistance || 0; + let maxDist = markerData.maxDistance !== undefined ? markerData.maxDistance : Number.MAX_VALUE; + this.border.fadeDistanceMin = minDist; + this.border.fadeDistanceMax = maxDist; + this.fill.fadeDistanceMin = minDist; + this.fill.fadeDistanceMax = maxDist; + + // save used marker data for next update + this._markerData = markerData; + } + + dispose() { + super.dispose(); + + this.fill.dispose(); + this.border.dispose(); + } + + /** + * @private + * Creates a shape from a data object, usually parsed json from a markers.json + * @param shapeData {object} + * @returns {Shape} + */ + createShapeFromData(shapeData) { + /** @type {THREE.Vector2[]} **/ + let points = []; + + if (Array.isArray(shapeData)){ + shapeData.forEach(point => { + let x = (point.x || 0) - this.position.x + 0.01; // offset by 0.01 to avoid z-fighting + let z = (point.z || 0) - this.position.z + 0.01; + + points.push(new Vector2(x, z)); + }); + } + + return new Shape(points); + } + +} + +class ExtrudeMarkerFill extends Mesh { + + /** + * @param shape {Shape} + */ + constructor(shape) { + let geometry = ExtrudeMarkerFill.createGeometry(shape); + let material = new ShaderMaterial({ + vertexShader: MARKER_FILL_VERTEX_SHADER, + fragmentShader: MARKER_FILL_FRAGMENT_SHADER, + side: DoubleSide, + depthTest: true, + transparent: true, + uniforms: { + markerColor: { value: new Color() }, + markerOpacity: { value: 0 }, + fadeDistanceMin: { value: 0 }, + fadeDistanceMax: { value: Number.MAX_VALUE }, + } + }); + + super(geometry, material); + } + + /** + * @returns {Color} + */ + get color(){ + return this.material.uniforms.markerColor.value; + } + + /** + * @returns {number} + */ + get opacity() { + return this.material.uniforms.markerOpacity.value; + } + + /** + * @param opacity {number} + */ + set opacity(opacity) { + this.material.uniforms.markerOpacity.value = opacity; + this.visible = opacity > 0; + } + + /** + * @returns {boolean} + */ + get depthTest() { + return this.material.depthTest; + } + + /** + * @param test {boolean} + */ + set depthTest(test) { + this.material.depthTest = test; + } + + /** + * @returns {number} + */ + get fadeDistanceMin() { + return this.material.uniforms.fadeDistanceMin.value; + } + + /** + * @param min {number} + */ + set fadeDistanceMin(min) { + this.material.uniforms.fadeDistanceMin.value = min; + } + + /** + * @returns {number} + */ + get fadeDistanceMax() { + return this.material.uniforms.fadeDistanceMax.value; + } + + /** + * @param max {number} + */ + set fadeDistanceMax(max) { + this.material.uniforms.fadeDistanceMax.value = max; + } + + onClick(event) { + if (event.intersection) { + if (event.intersection.distance > this.fadeDistanceMax) return false; + if (event.intersection.distance < this.fadeDistanceMin) return false; + } + + return super.onClick(event); + } + + /** + * @param shape {Shape} + */ + updateGeometry(shape) { + this.geometry.dispose(); + this.geometry = ExtrudeMarkerFill.createGeometry(shape); + } + + dispose() { + this.geometry.dispose(); + this.material.dispose(); + } + + /** + * @param shape {Shape} + * @returns {ExtrudeBufferGeometry} + */ + static createGeometry(shape) { + let geometry = new ExtrudeBufferGeometry(shape, { + depth: 1, + steps: 5, + bevelEnabled: false + }); + geometry.rotateX(Math.PI / 2); //make y to z + + return geometry; + } + +} + +class ExtrudeMarkerBorder extends Line2 { + + /** + * @param shape {Shape} + */ + constructor(shape) { + let geometry = new LineSegmentsGeometry(); + geometry.setPositions(ExtrudeMarkerBorder.createLinePoints(shape)); + + let material = new LineMaterial({ + color: new Color(), + opacity: 0, + transparent: true, + linewidth: 1, + depthTest: true, + vertexColors: false, + dashed: false, + }); + material.uniforms.fadeDistanceMin = { value: 0 }; + material.uniforms.fadeDistanceMax = { value: Number.MAX_VALUE }; + + material.resolution.set(window.innerWidth, window.innerHeight); + + super(geometry, material); + + this.computeLineDistances(); + } + + /** + * @returns {Color} + */ + get color(){ + return this.material.color; + } + + /** + * @returns {number} + */ + get opacity() { + return this.material.opacity; + } + + /** + * @param opacity {number} + */ + set opacity(opacity) { + this.material.opacity = opacity; + this.visible = opacity > 0; + } + + /** + * @returns {number} + */ + get linewidth() { + return this.material.linewidth; + } + + /** + * @param width {number} + */ + set linewidth(width) { + this.material.linewidth = width; + } + + /** + * @returns {boolean} + */ + get depthTest() { + return this.material.depthTest; + } + + /** + * @param test {boolean} + */ + set depthTest(test) { + this.material.depthTest = test; + } + + /** + * @returns {number} + */ + get fadeDistanceMin() { + return this.material.uniforms.fadeDistanceMin.value; + } + + /** + * @param min {number} + */ + set fadeDistanceMin(min) { + this.material.uniforms.fadeDistanceMin.value = min; + } + + /** + * @returns {number} + */ + get fadeDistanceMax() { + return this.material.uniforms.fadeDistanceMax.value; + } + + /** + * @param max {number} + */ + set fadeDistanceMax(max) { + this.material.uniforms.fadeDistanceMax.value = max; + } + + onClick(event) { + if (event.intersection) { + if (event.intersection.distance > this.fadeDistanceMax) return false; + if (event.intersection.distance < this.fadeDistanceMin) return false; + } + + return super.onClick(event); + } + + /** + * @param shape {Shape} + */ + updateGeometry(shape) { + this.geometry = new LineSegmentsGeometry(); + this.geometry.setPositions(ExtrudeMarkerBorder.createLinePoints(shape)); + this.computeLineDistances(); + } + + /** + * @param renderer {THREE.WebGLRenderer} + */ + onBeforeRender(renderer) { + renderer.getSize(this.material.resolution); + } + + dispose() { + this.geometry.dispose(); + this.material.dispose(); + } + + /** + * @param shape {Shape} + * @returns {number[]} + */ + static createLinePoints(shape) { + let points3d = []; + let points = shape.getPoints(5); + points.push(points[0]); + + let prevPoint = null; + points.forEach(point => { + + // vertical line + points3d.push(point.x, 0, point.y); + points3d.push(point.x, -1, point.y); + + if (prevPoint) { + // line to previous point top + points3d.push(prevPoint.x, 0, prevPoint.y); + points3d.push(point.x, 0, point.y); + + // line to previous point bottom + points3d.push(prevPoint.x, -1, prevPoint.y); + points3d.push(point.x, -1, point.y); + } + + prevPoint = point; + }); + + return points3d; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/HtmlMarker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/HtmlMarker.js new file mode 100644 index 00000000..31f39397 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/HtmlMarker.js @@ -0,0 +1,143 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Marker} from "./Marker"; +import {CSS2DObject} from "../util/CSS2DRenderer"; +import {htmlToElement} from "../util/Utils"; + +export class HtmlMarker extends Marker { + + /** + * @param markerId {string} + */ + constructor(markerId) { + super(markerId); + Object.defineProperty(this, 'isHtmlMarker', {value: true}); + this.data.type = "html"; + + this.data.label = null; + + this.data.classes = []; + + this.elementObject = new CSS2DObject(htmlToElement(`
`)); + this.elementObject.onBeforeRender = (renderer, scene, camera) => this.onBeforeRender(renderer, scene, camera); + + this.fadeDistanceMin = 0; + this.fadeDistanceMax = Number.MAX_VALUE; + + this.addEventListener( 'removed', () => { + if (this.element?.parentNode) this.element.parentNode.removeChild(this.element); + }); + + this.add(this.elementObject); + } + + onBeforeRender(renderer, scene, camera) { + if (this.fadeDistanceMax === Number.MAX_VALUE && this.fadeDistanceMin <= 0){ + this.element.parentNode.style.opacity = undefined; + } else { + this.element.parentNode.style.opacity = Marker.calculateDistanceOpacity(this.position, camera, this.fadeDistanceMin, this.fadeDistanceMax).toString(); + } + } + + /** + * @returns {string} + */ + get html() { + return this.element.innerHTML; + } + + /** + * @param html {string} + */ + set html(html) { + this.element.innerHTML = html; + } + + /** + * @returns {THREE.Vector2} + */ + get anchor() { + return this.elementObject.anchor; + } + + /** + * @returns {Element} + */ + get element() { + return this.elementObject.element.getElementsByTagName("div")[0]; + } + + /** + * @param markerData {{ + * position: {x: number, y: number, z: number}, + * label: string, + * anchor: {x: number, y: number}, + * html: string, + * classes: string[], + * minDistance: number, + * maxDistance: number + * }} + */ + updateFromData(markerData) { + + // update position + let pos = markerData.position || {}; + this.position.setX(pos.x || 0); + this.position.setY(pos.y || 0); + this.position.setZ(pos.z || 0); + + // update label + this.data.label = markerData.label || null; + + // update anchor + let anch = markerData.anchor || {}; + this.anchor.setX(anch.x || 0); + this.anchor.setY(anch.y || 0); + + // update html + if (this.element.innerHTML !== markerData.html){ + this.element.innerHTML = markerData.html; + } + + // update style-classes + if (this.data.classes !== markerData.classes) { + this.data.classes = markerData.classes; + this.element.classList.value = `bm-marker-${this.data.type}`; + this.element.classList.add(...markerData.classes); + } + + // update min/max distances + this.fadeDistanceMin = markerData.minDistance || 0; + this.fadeDistanceMax = markerData.maxDistance !== undefined ? markerData.maxDistance : Number.MAX_VALUE; + + } + + dispose() { + super.dispose(); + + if (this.element.parentNode) this.element.parentNode.removeChild(this.element); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/LineMarker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/LineMarker.js new file mode 100644 index 00000000..2328ab18 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/LineMarker.js @@ -0,0 +1,296 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Color} from "three"; +import {LineMaterial} from "../util/lines/LineMaterial"; +import {LineGeometry} from "../util/lines/LineGeometry"; +import {Line2} from "../util/lines/Line2"; +import {deepEquals} from "../util/Utils"; +import {ObjectMarker} from "./ObjectMarker"; + +export class LineMarker extends ObjectMarker { + + /** + * @param markerId {string} + */ + constructor(markerId) { + super(markerId); + Object.defineProperty(this, 'isLineMarker', {value: true}); + this.data.type = "line"; + + this.line = new LineMarkerLine([0, 0, 0]); + + this.add(this.line); + + this._markerData = {}; + } + + /** + * @param line {number[] | THREE.Vector3[] | THREE.Curve} + */ + setLine(line) { + /** @type {number[]} */ + let points; + + if (line.type === 'Curve' || line.type === 'CurvePath') { + line = line.getPoints(5); + } + + if (Array.isArray(line)) { + if (line.length === 0){ + points = []; + } else if (line[0].isVector3) { + points = []; + line.forEach(point => { + points.push(point.x, point.y, point.z); + }); + } else { + points = line; + } + } else { + throw new Error("Invalid argument type!"); + } + + this.line.updateGeometry(points); + } + + /** + * @typedef {{r: number, g: number, b: number, a: number}} ColorLike + */ + + /** + * @param markerData {{ + * position: {x: number, y: number, z: number}, + * label: string, + * detail: string, + * line: {x: number, y: number, z: number}[], + * link: string, + * newTab: boolean, + * depthTest: boolean, + * lineWidth: number, + * lineColor: ColorLike, + * minDistance: number, + * maxDistance: number + * }} + */ + updateFromData(markerData) { + super.updateFromData(markerData); + + // update shape only if needed, based on last update-data + if ( + !this._markerData.line || !deepEquals(markerData.line, this._markerData.line) || + !this._markerData.position || !deepEquals(markerData.position, this._markerData.position) + ){ + this.setLine(this.createPointsFromData(markerData.line)); + } + + // update depthTest + this.line.depthTest = !!markerData.depthTest; + + // update border-width + this.line.linewidth = markerData.lineWidth !== undefined ? markerData.lineWidth : 2; + + // update line-color + let lc = markerData.lineColor || {}; + this.line.color.setRGB((lc.r || 0) / 255, (lc.g || 0) / 255, (lc.b || 0) / 255); + this.line.opacity = lc.a || 0; + + // update min/max distances + let minDist = markerData.minDistance || 0; + let maxDist = markerData.maxDistance !== undefined ? markerData.maxDistance : Number.MAX_VALUE; + this.line.fadeDistanceMin = minDist; + this.line.fadeDistanceMax = maxDist; + + // save used marker data for next update + this._markerData = markerData; + } + + dispose() { + super.dispose(); + + this.line.dispose(); + } + + /** + * @private + * Creates a shape from a data object, usually parsed json from a markers.json + * @param shapeData {object} + * @returns {number[]} + */ + createPointsFromData(shapeData) { + /** @type {number[]} **/ + let points = []; + + if (Array.isArray(shapeData)){ + shapeData.forEach(point => { + let x = (point.x || 0) - this.position.x; + let y = (point.y || 0) - this.position.y; + let z = (point.z || 0) - this.position.z; + + points.push(x, y, z); + }); + } + + return points; + } + +} + +class LineMarkerLine extends Line2 { + + /** + * @param points {number[]} + */ + constructor(points) { + let geometry = new LineGeometry(); + geometry.setPositions(points); + + let material = new LineMaterial({ + color: new Color(), + opacity: 0, + transparent: true, + linewidth: 1, + depthTest: true, + vertexColors: false, + dashed: false, + }); + material.uniforms.fadeDistanceMin = { value: 0 }; + material.uniforms.fadeDistanceMax = { value: Number.MAX_VALUE }; + + material.resolution.set(window.innerWidth, window.innerHeight); + + super(geometry, material); + + this.computeLineDistances(); + } + + /** + * @returns {Color} + */ + get color(){ + return this.material.color; + } + + /** + * @returns {number} + */ + get opacity() { + return this.material.opacity; + } + + /** + * @param opacity {number} + */ + set opacity(opacity) { + this.material.opacity = opacity; + this.visible = opacity > 0; + } + + /** + * @returns {number} + */ + get linewidth() { + return this.material.linewidth; + } + + /** + * @param width {number} + */ + set linewidth(width) { + this.material.linewidth = width; + } + + /** + * @returns {boolean} + */ + get depthTest() { + return this.material.depthTest; + } + + /** + * @param test {boolean} + */ + set depthTest(test) { + this.material.depthTest = test; + } + + /** + * @returns {number} + */ + get fadeDistanceMin() { + return this.material.uniforms.fadeDistanceMin.value; + } + + /** + * @param min {number} + */ + set fadeDistanceMin(min) { + this.material.uniforms.fadeDistanceMin.value = min; + } + + /** + * @returns {number} + */ + get fadeDistanceMax() { + return this.material.uniforms.fadeDistanceMax.value; + } + + /** + * @param max {number} + */ + set fadeDistanceMax(max) { + this.material.uniforms.fadeDistanceMax.value = max; + } + + onClick(event) { + if (event.intersection) { + if (event.intersection.distance > this.fadeDistanceMax) return false; + if (event.intersection.distance < this.fadeDistanceMin) return false; + } + + return super.onClick(event); + } + + /** + * @param points {number[]} + */ + updateGeometry(points) { + this.geometry = new LineGeometry(); + this.geometry.setPositions(points); + this.computeLineDistances(); + } + + /** + * @param renderer {THREE.WebGLRenderer} + */ + onBeforeRender(renderer) { + renderer.getSize(this.material.resolution); + } + + dispose() { + this.geometry.dispose(); + this.material.dispose(); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/Marker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/Marker.js new file mode 100644 index 00000000..f1ad5157 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/Marker.js @@ -0,0 +1,95 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {MathUtils, Object3D, Vector3} from "three"; + +export class Marker extends Object3D { + + /** + * @param markerId {string} + */ + constructor(markerId) { + super(); + Object.defineProperty(this, 'isMarker', {value: true}); + + this.data = { + id: markerId, + type: "marker", + position: this.position, + visible: this.visible + }; + + // redirect parent properties + Object.defineProperty(this, "position", { + get() { return this.data.position }, + set(value) { this.data.position = value } + }); + Object.defineProperty(this, "visible", { + get() { return this.data.visible }, + set(value) { this.data.visible = value } + }); + } + + dispose() {} + + /** + * Updates this marker from the provided data object, usually parsed form json from a markers.json + * @param markerData {object} + */ + updateFromData(markerData) {} + + // -- helper methods -- + + static _posRelativeToCamera = new Vector3(); + static _cameraDirection = new Vector3(); + + /** + * @param position {Vector3} + * @param camera {THREE.Camera} + * @param fadeDistanceMax {number} + * @param fadeDistanceMin {number} + * @returns {number} - opacity between 0 and 1 + */ + static calculateDistanceOpacity(position, camera, fadeDistanceMin, fadeDistanceMax) { + let distance = Marker.calculateDistanceToCameraPlane(position, camera); + let minDelta = (distance - fadeDistanceMin) / fadeDistanceMin; + let maxDelta = (distance - fadeDistanceMax) / (fadeDistanceMax * 0.5); + return Math.min( + MathUtils.clamp(minDelta, 0, 1), + 1 - MathUtils.clamp(maxDelta + 1, 0, 1) + ); + } + + /** + * @param position {Vector3} + * @param camera {THREE.Camera} + * @returns {number} + */ + static calculateDistanceToCameraPlane (position, camera) { + Marker._posRelativeToCamera.subVectors(position, camera.position); + camera.getWorldDirection(Marker._cameraDirection); + return Marker._posRelativeToCamera.dot(Marker._cameraDirection); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerFillFragmentShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerFillFragmentShader.js new file mode 100644 index 00000000..847bf8ca --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerFillFragmentShader.js @@ -0,0 +1,68 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { ShaderChunk } from 'three'; + +export const MARKER_FILL_FRAGMENT_SHADER = ` +${ShaderChunk.logdepthbuf_pars_fragment} + +#define FLT_MAX 3.402823466e+38 + +varying vec3 vPosition; +//varying vec3 vWorldPosition; +//varying vec3 vNormal; +//varying vec2 vUv; +//varying vec3 vColor; +varying float vDistance; + +uniform vec3 markerColor; +uniform float markerOpacity; + +uniform float fadeDistanceMax; +uniform float fadeDistanceMin; + +void main() { + vec4 color = vec4(markerColor, markerOpacity); + + // distance fading + float fdMax = FLT_MAX; + if ( fadeDistanceMax > 0.0 ) fdMax = fadeDistanceMax; + + float minDelta = (vDistance - fadeDistanceMin) / fadeDistanceMin; + float maxDelta = (vDistance - fadeDistanceMax) / (fadeDistanceMax * 0.5); + float distanceOpacity = min( + clamp(minDelta, 0.0, 1.0), + 1.0 - clamp(maxDelta + 1.0, 0.0, 1.0) + ); + + color.a *= distanceOpacity; + + // apply vertex-color + //color.rgb *= vColor.rgb; + + gl_FragColor = color; + + ${ShaderChunk.logdepthbuf_fragment} +} +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerFillVertexShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerFillVertexShader.js new file mode 100644 index 00000000..76f3211a --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerFillVertexShader.js @@ -0,0 +1,53 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { ShaderChunk } from 'three'; + +export const MARKER_FILL_VERTEX_SHADER = ` +#include +${ShaderChunk.logdepthbuf_pars_vertex} + +varying vec3 vPosition; +//varying vec3 vWorldPosition; +//varying vec3 vNormal; +//varying vec2 vUv; +//varying vec3 vColor; +varying float vDistance; + +void main() { + vec4 worldPos = modelMatrix * vec4(position, 1); + vec4 viewPos = viewMatrix * worldPos; + + vPosition = position; + //vWorldPosition = worldPos.xyz; + //vNormal = normal; + //vUv = uv; + //vColor = vec3(1.0); + vDistance = -viewPos.z; + + gl_Position = projectionMatrix * viewPos; + + ${ShaderChunk.logdepthbuf_vertex} +} +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerManager.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerManager.js new file mode 100644 index 00000000..cbdd4ba5 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerManager.js @@ -0,0 +1,131 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {FileLoader} from "three"; +import {MarkerSet} from "./MarkerSet"; +import {alert, generateCacheHash} from "../util/Utils"; + +/** + * A manager for loading and updating markers from a file + */ +export class MarkerManager { + + /** + * @constructor + * @param root {MarkerSet} - The scene to which all markers will be added + * @param fileUrl {string} - The marker file from which this manager updates its markers + * @param events {EventTarget} + */ + constructor(root, fileUrl, events = null) { + Object.defineProperty(this, 'isMarkerManager', {value: true}); + + this.root = root; + this.fileUrl = fileUrl; + this.events = events; + this.disposed = false; + + /** @type {NodeJS.Timeout} */ + this._updateInterval = null; + } + + /** + * Sets the automatic-update frequency, setting this to 0 or negative disables automatic updates (default). + * This is better than using setInterval() on update() because this will wait for the update to finish before requesting the next update. + * @param ms - interval in milliseconds + */ + setAutoUpdateInterval(ms) { + if (this._updateInterval) clearTimeout(this._updateInterval); + if (ms > 0) { + let autoUpdate = () => { + if (this.disposed) return; + this.update() + .then(success => { + if (success) { + this._updateInterval = setTimeout(autoUpdate, ms); + } else { + this._updateInterval = setTimeout(autoUpdate, Math.max(ms, 1000 * 15)); + } + }) + .catch(e => { + alert(this.events, e, "warning"); + this._updateInterval = setTimeout(autoUpdate, Math.max(ms, 1000 * 15)); + }); + }; + + this._updateInterval = setTimeout(autoUpdate, ms); + } + } + + /** + * Loads the marker-file and updates all managed markers. + * @returns {Promise} - A promise completing when the markers finished updating + */ + update() { + return this.loadMarkerFile() + .then(markerFileData => this.updateFromData(markerFileData)); + } + + /** + * @protected + * @param markerData + */ + updateFromData(markerData) {} + + /** + * Stops automatic-updates and disposes all markersets and markers managed by this manager + */ + dispose() { + this.disposed = true; + this.setAutoUpdateInterval(0); + this.clear(); + } + + /** + * Removes all markers managed by this marker-manager + */ + clear() { + this.root.clear(); + } + + /** + * @private + * Loads the marker file + * @returns {Promise} - A promise completing with the parsed json object from the loaded file + */ + loadMarkerFile() { + return new Promise((resolve, reject) => { + let loader = new FileLoader(); + loader.setResponseType("json"); + loader.load(this.fileUrl + "?" + generateCacheHash(), + markerFileData => { + if (!markerFileData) reject(`Failed to parse '${this.fileUrl}'!`); + else resolve(markerFileData); + }, + () => {}, + () => reject(`Failed to load '${this.fileUrl}'!`) + ) + }); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerSet.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerSet.js new file mode 100644 index 00000000..6543bfa9 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/MarkerSet.js @@ -0,0 +1,215 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Scene} from "three"; +import {alert} from "../util/Utils"; +import {ShapeMarker} from "./ShapeMarker"; +import {ExtrudeMarker} from "./ExtrudeMarker"; +import {LineMarker} from "./LineMarker"; +import {HtmlMarker} from "./HtmlMarker"; +import {PoiMarker} from "./PoiMarker"; + +export class MarkerSet extends Scene { + + /** + * @param id {string} + */ + constructor(id) { + super(); + Object.defineProperty(this, 'isMarkerSet', {value: true}); + + /** @type {Map} */ + this.markerSets = new Map(); + /** @type {Map} */ + this.markers = new Map(); + + this.data = { + id: id, + label: id, + toggleable: true, + defaultHide: false, + markerSets: [], + markers: [], + visible: this.visible, + }; + + Object.defineProperty(this, "visible", { + get() { return this.data.visible }, + set(value) { this.data.visible = value } + }); + } + + updateFromData(data) { + // update set info + this.data.label = data.label || this.data.id; + this.data.toggleable = !!data.toggleable; + this.data.defaultHide = !!data.defaultHidden; + + // update markerSets + this.updateMarkerSetsFromData(data.markerSets); + + // update markers + this.updateMarkersFromData(data.markers); + } + + updateMarkerSetsFromData(data = {}, ignore = []) { + let updatedMarkerSets = new Set(ignore); + + // add & update MarkerSets + Object.keys(data).forEach(markerSetId => { + if (updatedMarkerSets.has(markerSetId)) return; + updatedMarkerSets.add(markerSetId); + + let markerSetData = data[markerSetId]; + try { + this.updateMarkerSetFromData(markerSetId, markerSetData); + } catch (err) { + alert(this.events, err, "fine"); + } + }); + + // remove not updated MarkerSets + this.markerSets.forEach((markerSet, setId) => { + if (!updatedMarkerSets.has(setId)) { + this.remove(markerSet); + } + }); + } + + updateMarkerSetFromData(markerSetId, data) { + let markerSet = this.markerSets.get(markerSetId); + + // create new if not existent + if (!markerSet) { + markerSet = new MarkerSet(markerSetId); + this.add(markerSet); + + if (data.defaultHidden) { + markerSet.visible = false; + } + } + + // update + markerSet.updateFromData(data); + } + + updateMarkersFromData(data = {}, ignore = []) { + let updatedMarkers = new Set(ignore); + + Object.keys(data).forEach(markerId => { + if (updatedMarkers.has(markerId)) return; + + let markerData = data[markerId]; + try { + this.updateMarkerFromData(markerId, markerData); + updatedMarkers.add(markerId); + } catch (err) { + alert(this.events, err, "fine"); + console.debug(err); + } + }); + + // remove not updated Markers + this.markers.forEach((marker, markerId) => { + if (!updatedMarkers.has(markerId)) { + this.remove(marker); + } + }); + } + + updateMarkerFromData(markerId, data) { + if (!data.type) throw new Error("marker-data has no type!"); + let marker = this.markers.get(markerId); + + // create new if not existent of wrong type + if (!marker || marker.data.type !== data.type) { + if (marker) this.remove(marker); + + switch (data.type) { + case "shape" : marker = new ShapeMarker(markerId); break; + case "extrude" : marker = new ExtrudeMarker(markerId); break; + case "line" : marker = new LineMarker(markerId); break; + case "html" : marker = new HtmlMarker(markerId); break; + case "poi" : marker = new PoiMarker(markerId); break; + default : throw new Error(`Unknown marker-type: '${data.type}'`); + } + + this.add(marker); + } + + // update marker + marker.updateFromData(data); + } + + /** + * Removes all markers and marker-sets + */ + clear() { + [...this.data.markerSets].forEach(markerSet => this.remove(markerSet)); + [...this.data.markers].forEach(marker => this.remove(marker)); + } + + add(...object) { + if (object.length === 1) { //super.add() will re-invoke this method for each array-entry if it's more than one + let o = object[0]; + if (o.isMarkerSet && !this.markerSets.has(o.data.id)) { + this.markerSets.set(o.data.id, o); + this.data.markerSets.push(o.data); + } + if (o.isMarker && !this.markers.has(o.data.id)) { + this.markers.set(o.data.id, o); + this.data.markers.push(o.data); + } + } + + return super.add(...object); + } + + remove(...object) { + if (object.length === 1) { //super.remove() will re-invoke this method for each array-entry if it's more than one + let o = object[0]; + if (o.isMarkerSet) { + let i = this.data.markerSets.indexOf(o.data); + if (i > -1) this.data.markerSets.splice(i, 1); + this.markerSets.delete(o.data.id); + o.dispose(); + } + if (o.isMarker) { + let i = this.data.markers.indexOf(o.data); + if (i > -1) this.data.markers.splice(i, 1); + this.markers.delete(o.data.id); + o.dispose(); + } + } + + return super.remove(...object); + } + + dispose() { + this.children.forEach(child => { + if (child.dispose) child.dispose(); + }); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/NormalMarkerManager.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/NormalMarkerManager.js new file mode 100644 index 00000000..d35721ac --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/NormalMarkerManager.js @@ -0,0 +1,51 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { MarkerManager } from "./MarkerManager"; +import { PLAYER_MARKER_SET_ID } from "./PlayerMarkerManager"; + +export class NormalMarkerManager extends MarkerManager { + + /** + * @constructor + * @param root {MarkerSet} - The scene to which all markers will be added + * @param fileUrl {string} - The marker file from which this manager updates its markers + * @param events {EventTarget} + */ + constructor(root, fileUrl, events = null) { + super(root, fileUrl, events); + } + + /** + * @protected + * @override + * @param markerData + * @returns {boolean} + */ + updateFromData(markerData) { + this.root.updateMarkerSetsFromData(markerData, [PLAYER_MARKER_SET_ID, "bm-popup-set"]); + return true; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ObjectMarker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ObjectMarker.js new file mode 100644 index 00000000..4bf73b27 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ObjectMarker.js @@ -0,0 +1,156 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Marker} from "./Marker"; +import {CSS2DObject} from "../util/CSS2DRenderer"; +import {animate, htmlToElement} from "../util/Utils"; +import {Vector3} from "three"; + +export class ObjectMarker extends Marker { + + /** + * @param markerId {string} + */ + constructor(markerId) { + super(markerId); + Object.defineProperty(this, 'isObjectMarker', {value: true}); + this.data.type = "object"; + + this.data.label = null; + this.data.detail = null; + this.data.link = null; + this.data.newTab = true; + + this.lastClick = -1; + } + + onClick(event) { + let pos = new Vector3(); + if (event.intersection) { + pos.copy(event.intersection.pointOnLine || event.intersection.point); + pos.sub(this.position); + } + + if (event.data.doubleTap) return false; + + if (this.data.detail || this.data.label) { + let popup = new LabelPopup(this.data.detail || this.data.label); + popup.position.copy(pos); + this.add(popup); + popup.open(); + } + + if (this.data.link){ + window.open(this.data.link, this.data.newTab ? '_blank' : '_self'); + } + + return true; + } + + /** + * @param markerData {{ + * position: {x: number, y: number, z: number}, + * label: string, + * detail: string, + * link: string, + * newTab: boolean + * }} + */ + updateFromData(markerData) { + + // update position + let pos = markerData.position || {}; + this.position.setX(pos.x || 0); + this.position.setY(pos.y || 0); + this.position.setZ(pos.z || 0); + + // update label + this.data.label = markerData.label || null; + + //update detail + this.data.detail = markerData.detail || null; + + // update link + this.data.link = markerData.link || null; + this.data.newTab = !!markerData.newTab; + } + +} + +export class LabelPopup extends CSS2DObject { + + /** + * @param label {string} + */ + constructor(label) { + super(htmlToElement(`
${label}
`)); + } + + /** + * @param autoClose {boolean} - whether this object should be automatically closed and removed again on any other interaction + */ + open(autoClose = true) { + let targetOpacity = this.element.style.opacity || 1; + + this.element.style.opacity = 0; + let inAnimation = animate(progress => { + this.element.style.opacity = (progress * targetOpacity).toString(); + }, 300); + + if (autoClose) { + let removeHandler = evt => { + if (evt.composedPath().includes(this.element)) return; + + inAnimation.cancel(); + this.close(); + + window.removeEventListener("mousedown", removeHandler); + window.removeEventListener("touchstart", removeHandler); + window.removeEventListener("keydown", removeHandler); + window.removeEventListener("mousewheel", removeHandler); + }; + + window.addEventListener("mousedown", removeHandler); + window.addEventListener("touchstart", removeHandler); + window.addEventListener("keydown", removeHandler); + window.addEventListener("mousewheel", removeHandler); + } + } + + /** + * @param remove {boolean} - whether this object should be removed from its parent when the close-animation finished + */ + close(remove = true) { + let startOpacity = parseFloat(this.element.style.opacity); + + animate(progress => { + this.element.style.opacity = (startOpacity - progress * startOpacity).toString(); + }, 300, completed => { + if (remove && completed && this.parent) { + this.parent.remove(this); + } + }); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarker.js new file mode 100644 index 00000000..5e29dfa8 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarker.js @@ -0,0 +1,151 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Marker} from "./Marker"; +import {CSS2DObject} from "../util/CSS2DRenderer"; +import {animate, EasingFunctions, htmlToElement} from "../util/Utils"; + +export class PlayerMarker extends Marker { + + /** + * @param markerId {string} + * @param playerUuid {string} + * @param playerHead {string} + */ + constructor(markerId, playerUuid, playerHead = "assets/steve.png") { + super(markerId); + Object.defineProperty(this, 'isPlayerMarker', {value: true}); + this.data.type = "player"; + + this.data.playerUuid = playerUuid; + this.data.name = playerUuid; + this.data.playerHead = playerHead; + + this.elementObject = new CSS2DObject(htmlToElement(` +
+ playerhead +
+
+ `)); + this.elementObject.onBeforeRender = (renderer, scene, camera) => this.onBeforeRender(renderer, scene, camera); + + this.playerHeadElement = this.element.getElementsByTagName("img")[0]; + this.playerNameElement = this.element.getElementsByTagName("div")[0]; + + this.addEventListener( 'removed', () => { + if (this.element.parentNode) this.element.parentNode.removeChild(this.element); + }); + + this.playerHeadElement.addEventListener('error', () => { + this.playerHeadElement.src = "assets/steve.png"; + }, {once: true}); + + this.add(this.elementObject); + } + + /** + * @returns {Element} + */ + get element() { + return this.elementObject.element.getElementsByTagName("div")[0]; + } + + onBeforeRender(renderer, scene, camera) { + let distance = Marker.calculateDistanceToCameraPlane(this.position, camera); + + let value = "near"; + if (distance > 1000) { + value = "med"; + } + if (distance > 5000) { + value = "far"; + } + + this.element.setAttribute("distance-data", value); + } + + /** + * @typedef PlayerLike {{ + * uuid: string, + * name: string, + * foreign: boolean, + * position: {x: number, y: number, z: number}, + * rotation: {yaw: number, pitch: number, roll: number} + * }} + */ + + /** + * @param markerData {PlayerLike} + */ + updateFromData(markerData) { + + // animate position update + let pos = markerData.position || {}; + if (!this.position.x && !this.position.y && !this.position.z) { + this.position.set( + pos.x || 0, + (pos.y || 0) + 1.8, + pos.z || 0 + ); + } else { + let startPos = { + x: this.position.x, + y: this.position.y, + z: this.position.z, + } + let deltaPos = { + x: (pos.x || 0) - startPos.x, + y: ((pos.y || 0) + 1.8) - startPos.y, + z: (pos.z || 0) - startPos.z, + } + if (deltaPos.x || deltaPos.y || deltaPos.z) { + animate(progress => { + let ease = EasingFunctions.easeInOutCubic(progress); + this.position.set( + startPos.x + deltaPos.x * ease || 0, + startPos.y + deltaPos.y * ease || 0, + startPos.z + deltaPos.z * ease || 0 + ); + }, 500); + } + } + + // update name + let name = markerData.name || this.data.playerUuid; + this.data.name = name; + if (this.playerNameElement.innerHTML !== name) + this.playerNameElement.innerHTML = name; + + // update world + this.data.foreign = markerData.foreign; + } + + dispose() { + super.dispose(); + + let element = this.elementObject.element; + if (element.parentNode) element.parentNode.removeChild(element); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarkerManager.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarkerManager.js new file mode 100644 index 00000000..b5bc5a39 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarkerManager.js @@ -0,0 +1,80 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import { PlayerMarkerSet } from "./PlayerMarkerSet"; +import { MarkerManager } from "./MarkerManager"; + +export const PLAYER_MARKER_SET_ID = "bm-players"; + +export class PlayerMarkerManager extends MarkerManager { + + /** + * @constructor + * @param root {MarkerSet} - The scene to which all markers will be added + * @param fileUrl {string} - The marker file from which this manager updates its markers + * @param playerheadsUrl {string} - The url from which playerhead images should be loaded + * @param events {EventTarget} + */ + constructor(root, fileUrl, playerheadsUrl, events = null) { + super(root, fileUrl, events); + + this.playerheadsUrl = playerheadsUrl; + } + + /** + * @protected + * @override + * @param markerFileData + * @returns {boolean} + */ + updateFromData(markerFileData) { + let playerMarkerSet = this.getPlayerMarkerSet(); + return playerMarkerSet.updateFromPlayerData(markerFileData); + } + + /** + * @private + * @returns {PlayerMarkerSet} + */ + getPlayerMarkerSet() { + /** @type {PlayerMarkerSet} */ + let playerMarkerSet = /** @type {PlayerMarkerSet} */ this.root.markerSets.get(PLAYER_MARKER_SET_ID); + + if (!playerMarkerSet) { + playerMarkerSet = new PlayerMarkerSet(PLAYER_MARKER_SET_ID, this.playerheadsUrl); + this.root.add(playerMarkerSet); + } + + return playerMarkerSet; + } + + /** + * @param playerUuid {string} + * @returns {PlayerMarker | undefined} + */ + getPlayerMarker(playerUuid) { + return this.getPlayerMarkerSet().getPlayerMarker(playerUuid) + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarkerSet.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarkerSet.js new file mode 100644 index 00000000..9008e933 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PlayerMarkerSet.js @@ -0,0 +1,102 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ + +import {MarkerSet} from "./MarkerSet"; +import {alert} from "../util/Utils"; +import {PlayerMarker} from "./PlayerMarker"; + +export class PlayerMarkerSet extends MarkerSet { + + constructor(id, playerheadsUrl) { + super(id); + this.data.label = "Player"; + this.data.toggleable = true; + this.data.defaultHide = false; + + this.data.playerheadsUrl = playerheadsUrl; + } + + updateFromPlayerData(data) { + if (!Array.isArray(data.players)) { + this.clear(); + return false; + } + + /** @type Set */ + let updatedPlayerMarkers = new Set(); + + // update + data.players.forEach(playerData => { + try { + let playerMarker = this.updatePlayerMarkerFromData(playerData); + updatedPlayerMarkers.add(playerMarker); + } catch (err) { + alert(this.events, err, "fine"); + } + }); + + // remove + this.markers.forEach(playerMarker => { + if (!updatedPlayerMarkers.has(playerMarker)) { + this.remove(playerMarker); + } + }); + + return true; + } + + updatePlayerMarkerFromData(markerData) { + let playerUuid = markerData.uuid; + if (!playerUuid) throw new Error("player-data has no uuid!"); + let markerId = this.getPlayerMarkerId(playerUuid); + + /** @type PlayerMarker */ + let marker = this.markers.get(markerId); + + // create new if not existent of wrong type + if (!marker || !marker.isPlayerMarker) { + if (marker) this.remove(marker); + marker = new PlayerMarker(markerId, playerUuid, `${this.data.playerheadsUrl}${playerUuid}.png`); + this.add(marker); + } + + // update + marker.updateFromData(markerData); + + // hide if from different world + marker.visible = !markerData.foreign; + + return marker; + } + + getPlayerMarker(playerUuid) { + return this.markers.get(this.getPlayerMarkerId(playerUuid)); + } + + getPlayerMarkerId(playerUuid) { + return "bm-player-" + playerUuid; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PoiMarker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PoiMarker.js new file mode 100644 index 00000000..40a84a70 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/PoiMarker.js @@ -0,0 +1,147 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {HtmlMarker} from "./HtmlMarker"; + +export class PoiMarker extends HtmlMarker { + + /** + * @param markerId {string} + */ + constructor(markerId) { + super(markerId); + Object.defineProperty(this, 'isPoiMarker', {value: true}); + this.data.type = "poi"; + + this.data.detail = null; + + this.html = `POI Icon (${this.data.id})
`; + + this.iconElement = this.element.getElementsByTagName("img").item(0); + this.labelElement = this.element.getElementsByTagName("div").item(0); + + this._lastIcon = null; + } + + onClick(event) { + if (event.data.doubleTap) return false; + + if (this.highlight || !this.data.label) return true; + this.highlight = true; + + let eventHandler = evt => { + if (evt.composedPath().includes(this.element)) return; + + this.highlight = false; + + window.removeEventListener("mousedown", eventHandler); + window.removeEventListener("touchstart", eventHandler); + window.removeEventListener("keydown", eventHandler); + window.removeEventListener("mousewheel", eventHandler); + }; + + setTimeout(function () { + window.addEventListener("mousedown", eventHandler); + window.addEventListener("touchstart", eventHandler); + window.addEventListener("keydown", eventHandler); + window.addEventListener("mousewheel", eventHandler); + }, 0); + + return true; + } + + set highlight(highlight) { + if (highlight) { + this.element.classList.add("bm-marker-highlight"); + } else { + this.element.classList.remove("bm-marker-highlight"); + } + } + + get highlight() { + return this.element.classList.contains("bm-marker-highlight"); + } + + /** + * @param markerData {{ + * position: {x: number, y: number, z: number}, + * anchor: {x: number, y: number}, + * iconAnchor: {x: number, y: number}, + * label: string, + * detail: string, + * icon: string, + * classes: string[], + * minDistance: number, + * maxDistance: number + * }} + */ + updateFromData(markerData) { + + // update position + let pos = markerData.position || {}; + this.position.setX(pos.x || 0); + this.position.setY(pos.y || 0); + this.position.setZ(pos.z || 0); + + // update anchor + let anch = markerData.anchor || markerData.iconAnchor || {}; //"iconAnchor" for backwards compatibility + this.iconElement.style.transform = `translate(${-anch.x}px, ${-anch.y}px)`; + //this.anchor.setX(anch.x || 0); + //this.anchor.setY(anch.y || 0); + + + // update label + if (this.data.label !== markerData.label){ + this.data.label = markerData.label || ""; + } + + // update detail + if (this.data.detail !== markerData.detail){ + this.data.detail = markerData.detail || this.data.label; + this.labelElement.innerHTML = this.data.detail || ""; + } + + // update icon + if (this._lastIcon !== markerData.icon){ + this.iconElement.src = markerData.icon || "assets/poi.svg"; + this._lastIcon = markerData.icon; + } + + // update style-classes + if (this.data.classes !== markerData.classes) { + this.data.classes = markerData.classes; + let highlight = this.element.classList.contains("bm-marker-highlight"); + + this.element.classList.value = `bm-marker-html`; + if (highlight) this.element.classList.add("bm-marker-highlight"); + this.element.classList.add(...markerData.classes); + } + + // update min/max distances + this.fadeDistanceMin = markerData.minDistance || 0; + this.fadeDistanceMax = markerData.maxDistance !== undefined ? markerData.maxDistance : Number.MAX_VALUE; + + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ShapeMarker.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ShapeMarker.js new file mode 100644 index 00000000..d8f69b16 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/markers/ShapeMarker.js @@ -0,0 +1,441 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {Color, DoubleSide, Mesh, ShaderMaterial, Shape, ShapeBufferGeometry, Vector2} from "three"; +import {LineMaterial} from "../util/lines/LineMaterial"; +import {MARKER_FILL_VERTEX_SHADER} from "./MarkerFillVertexShader"; +import {MARKER_FILL_FRAGMENT_SHADER} from "./MarkerFillFragmentShader"; +import {LineGeometry} from "../util/lines/LineGeometry"; +import {Line2} from "../util/lines/Line2"; +import {deepEquals} from "../util/Utils"; +import {ObjectMarker} from "./ObjectMarker"; + +export class ShapeMarker extends ObjectMarker { + + /** + * @param markerId {string} + */ + constructor(markerId) { + super(markerId); + Object.defineProperty(this, 'isShapeMarker', {value: true}); + this.data.type = "shape"; + + let zero = new Vector2(); + let shape = new Shape([zero, zero, zero]); + this.fill = new ShapeMarkerFill(shape); + this.border = new ShapeMarkerBorder(shape); + this.border.renderOrder = -1; // render border before fill + + this.add(this.border, this.fill); + + this._markerData = {}; + } + + /** + * @param y {number} + */ + setShapeY(y) { + let relativeY = y - this.position.y; + this.fill.position.y = relativeY; + this.border.position.y = relativeY; + } + + /** + * @param shape {Shape} + */ + setShape(shape) { + this.fill.updateGeometry(shape); + this.border.updateGeometry(shape); + } + + /** + * @typedef {{r: number, g: number, b: number, a: number}} ColorLike + */ + + /** + * @param markerData {{ + * position: {x: number, y: number, z: number}, + * label: string, + * detail: string, + * shape: {x: number, z: number}[], + * shapeY: number, + * height: number, + * link: string, + * newTab: boolean, + * depthTest: boolean, + * lineWidth: number, + * borderColor: ColorLike, + * lineColor: ColorLike, + * fillColor: ColorLike, + * minDistance: number, + * maxDistance: number + * }} + */ + updateFromData(markerData) { + super.updateFromData(markerData); + + // update shape only if needed, based on last update-data + if ( + !this._markerData.shape || !deepEquals(markerData.shape, this._markerData.shape) || + !this._markerData.position || !deepEquals(markerData.position, this._markerData.position) + ){ + this.setShape(this.createShapeFromData(markerData.shape)); + } + + // update shapeY + this.setShapeY((markerData.shapeY || markerData.height || 0) + 0.01); //"height" for backwards compatibility, adding 0.01 to avoid z-fighting + + // update depthTest + this.border.depthTest = !!markerData.depthTest; + this.fill.depthTest = !!markerData.depthTest; + + // update border-width + this.border.linewidth = markerData.lineWidth !== undefined ? markerData.lineWidth : 2; + + // update border-color + let bc = markerData.lineColor || markerData.borderColor || {}; //"borderColor" for backwards compatibility + this.border.color.setRGB((bc.r || 0) / 255, (bc.g || 0) / 255, (bc.b || 0) / 255); + this.border.opacity = bc.a || 0; + + // update fill-color + let fc = markerData.fillColor || {}; + this.fill.color.setRGB((fc.r || 0) / 255, (fc.g || 0) / 255, (fc.b || 0) / 255); + this.fill.opacity = fc.a || 0; + + // update min/max distances + let minDist = markerData.minDistance || 0; + let maxDist = markerData.maxDistance !== undefined ? markerData.maxDistance : Number.MAX_VALUE; + this.border.fadeDistanceMin = minDist; + this.border.fadeDistanceMax = maxDist; + this.fill.fadeDistanceMin = minDist; + this.fill.fadeDistanceMax = maxDist; + + // save used marker data for next update + this._markerData = markerData; + } + + dispose() { + super.dispose(); + + this.fill.dispose(); + this.border.dispose(); + } + + /** + * @private + * Creates a shape from a data object, usually parsed json from a markers.json + * @param shapeData {object} + * @returns {Shape} + */ + createShapeFromData(shapeData) { + /** @type {THREE.Vector2[]} **/ + let points = []; + + if (Array.isArray(shapeData)){ + shapeData.forEach(point => { + let x = (point.x || 0) - this.position.x; + let z = (point.z || 0) - this.position.z; + + points.push(new Vector2(x, z)); + }); + } + + return new Shape(points); + } + +} + +class ShapeMarkerFill extends Mesh { + + /** + * @param shape {Shape} + */ + constructor(shape) { + let geometry = ShapeMarkerFill.createGeometry(shape); + let material = new ShaderMaterial({ + vertexShader: MARKER_FILL_VERTEX_SHADER, + fragmentShader: MARKER_FILL_FRAGMENT_SHADER, + side: DoubleSide, + depthTest: true, + transparent: true, + uniforms: { + markerColor: { value: new Color() }, + markerOpacity: { value: 0 }, + fadeDistanceMin: { value: 0 }, + fadeDistanceMax: { value: Number.MAX_VALUE }, + } + }); + + super(geometry, material); + } + + /** + * @returns {Color} + */ + get color(){ + return this.material.uniforms.markerColor.value; + } + + /** + * @returns {number} + */ + get opacity() { + return this.material.uniforms.markerOpacity.value; + } + + /** + * @param opacity {number} + */ + set opacity(opacity) { + this.material.uniforms.markerOpacity.value = opacity; + this.visible = opacity > 0; + } + + /** + * @returns {boolean} + */ + get depthTest() { + return this.material.depthTest; + } + + /** + * @param test {boolean} + */ + set depthTest(test) { + this.material.depthTest = test; + } + + /** + * @returns {number} + */ + get fadeDistanceMin() { + return this.material.uniforms.fadeDistanceMin.value; + } + + /** + * @param min {number} + */ + set fadeDistanceMin(min) { + this.material.uniforms.fadeDistanceMin.value = min; + } + + /** + * @returns {number} + */ + get fadeDistanceMax() { + return this.material.uniforms.fadeDistanceMax.value; + } + + /** + * @param max {number} + */ + set fadeDistanceMax(max) { + this.material.uniforms.fadeDistanceMax.value = max; + } + + onClick(event) { + if (event.intersection) { + if (event.intersection.distance > this.fadeDistanceMax) return false; + if (event.intersection.distance < this.fadeDistanceMin) return false; + } + + return super.onClick(event); + } + + /** + * @param shape {Shape} + */ + updateGeometry(shape) { + this.geometry.dispose(); + this.geometry = ShapeMarkerFill.createGeometry(shape); + } + + dispose() { + this.geometry.dispose(); + this.material.dispose(); + } + + /** + * @param shape {Shape} + * @returns {ShapeBufferGeometry} + */ + static createGeometry(shape) { + let geometry = new ShapeBufferGeometry(shape, 5); + geometry.rotateX(Math.PI / 2); //make y to z + + return geometry; + } + +} + +class ShapeMarkerBorder extends Line2 { + + /** + * @param shape {Shape} + */ + constructor(shape) { + let geometry = new LineGeometry(); + geometry.setPositions(ShapeMarkerBorder.createLinePoints(shape)); + + let material = new LineMaterial({ + color: new Color(), + opacity: 0, + transparent: true, + linewidth: 1, + depthTest: true, + vertexColors: false, + dashed: false, + }); + material.uniforms.fadeDistanceMin = { value: 0 }; + material.uniforms.fadeDistanceMax = { value: Number.MAX_VALUE }; + + material.resolution.set(window.innerWidth, window.innerHeight); + + super(geometry, material); + + this.computeLineDistances(); + } + + /** + * @returns {Color} + */ + get color(){ + return this.material.color; + } + + /** + * @returns {number} + */ + get opacity() { + return this.material.opacity; + } + + /** + * @param opacity {number} + */ + set opacity(opacity) { + this.material.opacity = opacity; + this.visible = opacity > 0; + } + + /** + * @returns {number} + */ + get linewidth() { + return this.material.linewidth; + } + + /** + * @param width {number} + */ + set linewidth(width) { + this.material.linewidth = width; + } + + /** + * @returns {boolean} + */ + get depthTest() { + return this.material.depthTest; + } + + /** + * @param test {boolean} + */ + set depthTest(test) { + this.material.depthTest = test; + } + + /** + * @returns {number} + */ + get fadeDistanceMin() { + return this.material.uniforms.fadeDistanceMin.value; + } + + /** + * @param min {number} + */ + set fadeDistanceMin(min) { + this.material.uniforms.fadeDistanceMin.value = min; + } + + /** + * @returns {number} + */ + get fadeDistanceMax() { + return this.material.uniforms.fadeDistanceMax.value; + } + + /** + * @param max {number} + */ + set fadeDistanceMax(max) { + this.material.uniforms.fadeDistanceMax.value = max; + } + + onClick(event) { + if (event.intersection) { + if (event.intersection.distance > this.fadeDistanceMax) return false; + if (event.intersection.distance < this.fadeDistanceMin) return false; + } + + return super.onClick(event); + } + + /** + * @param shape {Shape} + */ + updateGeometry(shape) { + this.geometry = new LineGeometry(); + this.geometry.setPositions(ShapeMarkerBorder.createLinePoints(shape)); + this.computeLineDistances(); + } + + /** + * @param renderer {THREE.WebGLRenderer} + */ + onBeforeRender(renderer) { + renderer.getSize(this.material.resolution); + } + + dispose() { + this.geometry.dispose(); + this.material.dispose(); + } + + /** + * @param shape {Shape} + * @returns {number[]} + */ + static createLinePoints(shape) { + let points3d = []; + let points = shape.getPoints(5); + points.forEach(point => points3d.push(point.x, 0, point.y)); + points3d.push(points[0].x, 0, points[0].y); + + return points3d; + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyFragmentShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyFragmentShader.js new file mode 100644 index 00000000..67fe9e56 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyFragmentShader.js @@ -0,0 +1,42 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +export const SKY_FRAGMENT_SHADER = ` +uniform float sunlightStrength; +uniform float ambientLight; +uniform vec3 skyColor; + +varying vec3 vPosition; + +void main() { + float horizonWidth = 0.005; + float horizonHeight = 0.0; + + vec4 color = vec4(skyColor * max(sunlightStrength * sunlightStrength, ambientLight), 1.0); + float voidMultiplier = (clamp(vPosition.y - horizonHeight, -horizonWidth, horizonWidth) + horizonWidth) / (horizonWidth * 2.0); + color.rgb *= voidMultiplier; + + gl_FragColor = color; +} +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyVertexShader.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyVertexShader.js new file mode 100644 index 00000000..2c9cadb3 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyVertexShader.js @@ -0,0 +1,35 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +export const SKY_VERTEX_SHADER = ` +varying vec3 vPosition; +void main() { + vPosition = position; + + gl_Position = + projectionMatrix * + modelViewMatrix * + vec4(position, 1); +} +`; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyboxScene.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyboxScene.js new file mode 100644 index 00000000..d8f6236f --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/skybox/SkyboxScene.js @@ -0,0 +1,51 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {BackSide, Mesh, Scene, ShaderMaterial, SphereGeometry} from 'three'; + +import {SKY_FRAGMENT_SHADER} from './SkyFragmentShader'; +import {SKY_VERTEX_SHADER} from './SkyVertexShader'; + +export class SkyboxScene extends Scene { + + constructor(uniforms) { + super(); + + this.autoUpdate = false; + + Object.defineProperty(this, 'isSkyboxScene', {value: true}); + + let geometry = new SphereGeometry(1, 40, 5); + let material = new ShaderMaterial({ + uniforms: uniforms, + vertexShader: SKY_VERTEX_SHADER, + fragmentShader: SKY_FRAGMENT_SHADER, + side: BackSide + }); + let skybox = new Mesh(geometry, material); + + this.add(skybox); + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/CSS2DRenderer.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/CSS2DRenderer.js new file mode 100644 index 00000000..d2643362 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/CSS2DRenderer.js @@ -0,0 +1,233 @@ +/** + * @author mrdoob / http://mrdoob.com/ + * + * adapted for bluemap's purposes + */ + +import { + Matrix4, + Object3D, Vector2, + Vector3 +} from "three"; +import {dispatchEvent, htmlToElement} from "./Utils"; + +var CSS2DObject = function ( element ) { + + Object3D.call( this ); + + this.element = document.createElement("div"); + let parent = element.parentNode; + parent.replaceChild(this.element, element); + this.element.appendChild(element); + + this.element.style.position = 'absolute'; + + this.anchor = new Vector2(); + + this.events = null; + + this.addEventListener( 'removed', function () { + + this.traverse( function ( object ) { + + if ( object.element instanceof Element && object.element.parentNode !== null ) { + + object.element.parentNode.removeChild( object.element ); + + } + + } ); + + } ); + + let lastClick = -1; + let handleClick = event => { + let doubleTap = false; + + let now = Date.now(); + if (now - lastClick < 500){ + doubleTap = true; + } + + lastClick = now; + + let data = {doubleTap: doubleTap}; + + if (this.onClick( {event: event, data: data} )) { + event.preventDefault(); + event.stopPropagation(); + } else { + // fire event + dispatchEvent(this.events, "bluemapMapInteraction", { + data: data, + object: this, + }); + } + } + + this.element.addEventListener("click", handleClick); + this.element.addEventListener("touch", handleClick); + +}; + +CSS2DObject.prototype = Object.create( Object3D.prototype ); +CSS2DObject.prototype.constructor = CSS2DObject; + +// + +var CSS2DRenderer = function (events = null) { + + var _this = this; + + var _width, _height; + var _widthHalf, _heightHalf; + + var vector = new Vector3(); + var viewMatrix = new Matrix4(); + var viewProjectionMatrix = new Matrix4(); + + var cache = { + objects: new WeakMap() + }; + + var domElement = document.createElement( 'div' ); + domElement.style.overflow = 'hidden'; + + this.domElement = domElement; + + this.events = events; + + this.getSize = function () { + + return { + width: _width, + height: _height + }; + + }; + + this.setSize = function ( width, height ) { + + _width = width; + _height = height; + + _widthHalf = _width / 2; + _heightHalf = _height / 2; + + domElement.style.width = width + 'px'; + domElement.style.height = height + 'px'; + + }; + + var renderObject = function ( object, scene, camera, parentVisible ) { + + if ( object instanceof CSS2DObject ) { + + object.events = _this.events; + + object.onBeforeRender( _this, scene, camera ); + + vector.setFromMatrixPosition( object.matrixWorld ); + vector.applyMatrix4( viewProjectionMatrix ); + + var element = object.element; + var style = 'translate(' + ( vector.x * _widthHalf + _widthHalf - object.anchor.x) + 'px,' + ( - vector.y * _heightHalf + _heightHalf - object.anchor.y ) + 'px)'; + + element.style.WebkitTransform = style; + element.style.MozTransform = style; + element.style.oTransform = style; + element.style.transform = style; + + element.style.display = ( parentVisible && object.visible && vector.z >= - 1 && vector.z <= 1 && element.style.opacity !== "0" ) ? '' : 'none'; + + var objectData = { + distanceToCameraSquared: getDistanceToSquared( camera, object ) + }; + + cache.objects.set( object, objectData ); + + if ( element.parentNode !== domElement ) { + + domElement.appendChild( element ); + + } + + object.onAfterRender( _this, scene, camera ); + + } + + for ( var i = 0, l = object.children.length; i < l; i ++ ) { + + renderObject( object.children[ i ], scene, camera, parentVisible && object.visible ); + + } + + }; + + var getDistanceToSquared = function () { + + var a = new Vector3(); + var b = new Vector3(); + + return function ( object1, object2 ) { + + a.setFromMatrixPosition( object1.matrixWorld ); + b.setFromMatrixPosition( object2.matrixWorld ); + + return a.distanceToSquared( b ); + + }; + + }(); + + var filterAndFlatten = function ( scene ) { + + var result = []; + + scene.traverse( function ( object ) { + + if ( object instanceof CSS2DObject ) result.push( object ); + + } ); + + return result; + + }; + + var zOrder = function ( scene ) { + + var sorted = filterAndFlatten( scene ).sort( function ( a, b ) { + + var distanceA = cache.objects.get( a ).distanceToCameraSquared; + var distanceB = cache.objects.get( b ).distanceToCameraSquared; + + return distanceA - distanceB; + + } ); + + var zMax = sorted.length; + + for ( var i = 0, l = sorted.length; i < l; i ++ ) { + + sorted[ i ].element.style.zIndex = zMax - i; + + } + + }; + + this.render = function ( scene, camera ) { + + if ( scene.autoUpdate === true ) scene.updateMatrixWorld(); + if ( camera.parent === null ) camera.updateMatrixWorld(); + + viewMatrix.copy( camera.matrixWorldInverse ); + viewProjectionMatrix.multiplyMatrices( camera.projectionMatrix, viewMatrix ); + + renderObject( scene, scene, camera, true ); + zOrder( scene ); + + }; + +}; + +export { CSS2DObject, CSS2DRenderer }; \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/CombinedCamera.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/CombinedCamera.js new file mode 100644 index 00000000..54f08878 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/CombinedCamera.js @@ -0,0 +1,193 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {MathUtils, Matrix4, PerspectiveCamera} from "three"; + +export class CombinedCamera extends PerspectiveCamera { + + /** + * @param fov {number} + * @param aspect {number} + * @param near {number} + * @param far {number} + * @param ortho {number} + */ + constructor(fov, aspect, near, far, ortho) { + super(fov, aspect, near, far); + + this.needsUpdate = true; + + this.data = { + fov: this.fov, + aspect: this.aspect, + near: this.near, + far: this.far, + zoom: this.zoom, + ortho: ortho, + distance: 1, + }; + + // redirect parent properties + Object.defineProperty(this, "fov", { + get() { return this.data.fov }, + set(value) { if (value !== this.data.fov) { this.data.fov = value; this.needsUpdate = true }} + }); + Object.defineProperty(this, "aspect", { + get() { return this.data.aspect }, + set(value) { if (value !== this.data.aspect) { this.data.aspect = value; this.needsUpdate = true }} + }); + Object.defineProperty(this, "near", { + get() { return this.data.near }, + set(value) { if (value !== this.data.near) { this.data.near = value; this.needsUpdate = true }} + }); + Object.defineProperty(this, "far", { + get() { return this.data.far }, + set(value) { if (value !== this.data.far) { this.data.far = value; this.needsUpdate = true }} + }); + Object.defineProperty(this, "zoom", { + get() { return this.data.zoom }, + set(value) { if (value !== this.data.zoom) { this.data.zoom = value; this.needsUpdate = true }} + }); + + this.updateProjectionMatrix(); + } + + updateProjectionMatrix() { + if (!this.needsUpdate) return; + + if (!this.ortographicProjection) + this.ortographicProjection = new Matrix4(); + + if (!this.perspectiveProjection) + this.perspectiveProjection = new Matrix4(); + + if (!this.data) + this.data = {}; + + //copied from PerspectiveCamera + const near = this.near; + let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom; + let height = 2 * top; + let width = this.aspect * height; + let left = - 0.5 * width; + const view = this.view; + + if ( this.view !== null && this.view.enabled ) { + + const fullWidth = view.fullWidth, + fullHeight = view.fullHeight; + + left += view.offsetX * width / fullWidth; + top -= view.offsetY * height / fullHeight; + width *= view.width / fullWidth; + height *= view.height / fullHeight; + + } + + const skew = this.filmOffset; + if ( skew !== 0 ) left += near * skew / this.getFilmWidth(); + + // this part different to PerspectiveCamera + let normalizedOrtho = -Math.pow(this.ortho - 1, 6) + 1; + let orthoTop = Math.max(this.distance, 0.0001) * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom; + let orthoHeight = 2 * orthoTop; + let orthoWidth = this.aspect * orthoHeight; + let orthoLeft = - 0.5 * orthoWidth; + + this.perspectiveProjection.makePerspective( left, left + width, top, top - height, near, this.far ); + this.ortographicProjection.makeOrthographic( orthoLeft, orthoLeft + orthoWidth, orthoTop, orthoTop - orthoHeight, near, this.far ); + + for (let i = 0; i < 16; i++){ + this.projectionMatrix.elements[i] = (this.perspectiveProjection.elements[i] * (1 - normalizedOrtho)) + (this.ortographicProjection.elements[i] * normalizedOrtho); + } + // to here + + this.projectionMatrixInverse.copy( this.projectionMatrix ).invert(); + + this.needsUpdate = false; + } + + /** + * @returns {boolean} + */ + get isPerspectiveCamera() { + return this.ortho < 1; + } + + /** + * @returns {boolean} + */ + get isOrthographicCamera() { + return !this.isPerspectiveCamera; + } + + /** + * @returns {string} + */ + get type() { + return this.isPerspectiveCamera ? 'PerspectiveCamera' : 'OrthographicCamera'; + } + + /** + * @param type {string} + */ + set type(type) { + //ignore + } + + /** + * @returns {number} + */ + get ortho() { + return this.data.ortho; + } + + /** + * @param value {number} + */ + set ortho(value) { + if (value !== this.data.ortho){ + this.data.ortho = value; + this.needsUpdate = true; + } + } + + /** + * @returns {number} + */ + get distance() { + return this.data.distance; + } + + /** + * @param value {number} + */ + set distance(value) { + if (value !== this.data.distance) { + this.data.distance = value; + this.needsUpdate = true; + } + } + +} \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/Stats.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/Stats.js new file mode 100644 index 00000000..2d43227b --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/Stats.js @@ -0,0 +1,180 @@ +/** + * Taken from https://github.com/mrdoob/three.js/blob/master/examples/jsm/libs/stats.module.js + */ +let Stats = function () { + + let mode = 0; + + let container = document.createElement( 'div' ); + container.style.cssText = 'position:absolute;bottom:5px;right:5px;cursor:pointer;opacity:0.9;z-index:10000'; + container.addEventListener( 'click', function ( event ) { + + event.preventDefault(); + showPanel( ++ mode % container.children.length ); + + }, false ); + + // + + function addPanel( panel ) { + + container.appendChild( panel.dom ); + return panel; + + } + + function showPanel( id ) { + + for ( let i = 0; i < container.children.length; i ++ ) { + + container.children[ i ].style.display = i === id ? 'block' : 'none'; + + } + + mode = id; + + } + + function hide() { + showPanel(-1); + } + + // + + let beginTime = ( performance || Date ).now(), prevTime = beginTime, frames = 0; + let prevFrameTime = beginTime; + + let fpsPanel = addPanel( new Stats.Panel( 'FPS', '#0ff', '#002' ) ); + let msPanel = addPanel( new Stats.Panel( 'MS (render)', '#0f0', '#020' ) ); + let lastFrameMsPanel = addPanel( new Stats.Panel( 'MS (all)', '#f80', '#210' ) ); + + let memPanel = null; + if ( self.performance && self.performance.memory ) { + + memPanel = addPanel( new Stats.Panel( 'MB', '#f08', '#201' ) ); + + } + + showPanel( 0 ); + + return { + + REVISION: 16, + + dom: container, + + addPanel: addPanel, + showPanel: showPanel, + hide: hide, + + begin: function () { + + beginTime = ( performance || Date ).now(); + + }, + + end: function () { + + frames ++; + + let time = ( performance || Date ).now(); + + msPanel.update( time - beginTime, 200 ); + lastFrameMsPanel.update( time - prevFrameTime, 200 ) + + if ( time >= prevTime + 1000 ) { + + fpsPanel.update( ( frames * 1000 ) / ( time - prevTime ), 100 ); + + prevTime = time; + frames = 0; + + if ( memPanel ) { + + let memory = performance.memory; + memPanel.update( memory.usedJSHeapSize / 1048576, memory.jsHeapSizeLimit / 1048576 ); + + } + + } + + return time; + + }, + + update: function () { + + beginTime = this.end(); + prevFrameTime = beginTime; + + }, + + // Backwards Compatibility + + domElement: container, + setMode: showPanel + + }; + +}; + +Stats.Panel = function ( name, fg, bg ) { + + let min = Infinity, max = 0, round = Math.round; + let PR = round( window.devicePixelRatio || 1 ); + + let WIDTH = 160 * PR, HEIGHT = 96 * PR, + TEXT_X = 3 * PR, TEXT_Y = 3 * PR, + GRAPH_X = 3 * PR, GRAPH_Y = 15 * PR, + GRAPH_WIDTH = 154 * PR, GRAPH_HEIGHT = 77 * PR; + + let canvas = document.createElement( 'canvas' ); + canvas.width = WIDTH; + canvas.height = HEIGHT; + canvas.style.cssText = 'width:160px;height:96px'; + + let context = canvas.getContext( '2d' ); + context.font = 'bold ' + ( 9 * PR ) + 'px Helvetica,Arial,sans-serif'; + context.textBaseline = 'top'; + + context.fillStyle = bg; + context.fillRect( 0, 0, WIDTH, HEIGHT ); + + context.fillStyle = fg; + context.fillText( name, TEXT_X, TEXT_Y ); + context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT ); + + context.fillStyle = bg; + context.globalAlpha = 0.9; + context.fillRect( GRAPH_X, GRAPH_Y, GRAPH_WIDTH, GRAPH_HEIGHT ); + + return { + + dom: canvas, + + update: function ( value, maxValue ) { + + min = Math.min( min, value ); + max = Math.max( max, value ); + + context.fillStyle = bg; + context.globalAlpha = 1; + context.fillRect( 0, 0, WIDTH, GRAPH_Y ); + context.fillStyle = fg; + context.fillText( round( value ) + ' ' + name + ' (' + round( min ) + '-' + round( max ) + ')', TEXT_X, TEXT_Y ); + + context.drawImage( canvas, GRAPH_X + PR, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT, GRAPH_X, GRAPH_Y, GRAPH_WIDTH - PR, GRAPH_HEIGHT ); + + context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, GRAPH_HEIGHT ); + + context.fillStyle = bg; + context.globalAlpha = 0.9; + context.fillRect( GRAPH_X + GRAPH_WIDTH - PR, GRAPH_Y, PR, round( ( 1 - ( value / maxValue ) ) * GRAPH_HEIGHT ) ); + + } + + }; + +}; + +export default Stats; \ No newline at end of file diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/Utils.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/Utils.js new file mode 100644 index 00000000..cdb0497e --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/Utils.js @@ -0,0 +1,394 @@ +/* + * This file is part of BlueMap, licensed under the MIT License (MIT). + * + * Copyright (c) Blue (Lukas Rieger) + * Copyright (c) contributors + * + * 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. + */ +import {MathUtils, Vector2, Vector3} from "three"; + +export const VEC2_ZERO = new Vector2(0, 0); +export const VEC3_ZERO = new Vector3(0, 0, 0); +export const VEC3_X = new Vector3(1, 0, 0); +export const VEC3_Y = new Vector3(0, 1, 0); +export const VEC3_Z = new Vector3(0, 0, 1); + +/** + * Converts a url-encoded image string to an actual image-element + * @param string {string} + * @returns {HTMLElement} + */ +export const stringToImage = string => { + let image = document.createElementNS('http://www.w3.org/1999/xhtml', 'img'); + image.src = string; + return image; +}; + +/** + * Creates an optimized path from x,z coordinates used by bluemap to save tiles + * @param x {number} + * @param z {number} + * @returns {string} + */ +export const pathFromCoords = (x, z) => { + let path = 'x'; + path += splitNumberToPath(x); + + path += 'z'; + path += splitNumberToPath(z); + + path = path.substring(0, path.length - 1); + + return path; +}; + +/** + * Splits a number into an optimized folder-path used to save bluemap-tiles + * @param num {number} + * @returns {string} + */ +const splitNumberToPath = num => { + let path = ''; + + if (num < 0) { + num = -num; + path += '-'; + } + + let s = num.toString(); + + for (let i = 0; i < s.length; i++) { + path += s.charAt(i) + '/'; + } + + return path; +}; + +/** + * Hashes tile-coordinates to be saved in a map + * @param x {number} + * @param z {number} + * @returns {string} + */ +export const hashTile = (x, z) => `x${x}z${z}`; + +export const generateCacheHash = () => { + return Math.round(Math.random() * 1000000); +} + +/** + * Dispatches an event to the element of this map-viewer + * @param element {EventTarget} the element on that the event is dispatched + * @param event {string} + * @param detail {object} + * @returns {undefined|void|boolean} + */ +export const dispatchEvent = (element, event, detail = {}) => { + if (!element || !element.dispatchEvent) return; + + return element.dispatchEvent(new CustomEvent(event, { + detail: detail + })); +} + +/** + * Sends a "bluemapAlert" event with a message and a level. + * The level can be anything, but the app uses the levels + * - debug + * - fine + * - info + * - warning + * - error + * @param element {EventTarget} the element on that the event is dispatched + * @param message {object} + * @param level {string} + */ +export const alert = (element, message, level = "info") => { + + // alert event + let printToConsole = dispatchEvent(element, "bluemapAlert", { + message: message, + level: level + }); + + // log alert to console + if (printToConsole !== false) { + if (level === "info") { + console.log(`[BlueMap/${level}]`, message); + } else if (level === "warning") { + console.warn(`[BlueMap/${level}]`, message); + } else if (level === "error") { + console.error(`[BlueMap/${level}]`, message); + } else { + console.debug(`[BlueMap/${level}]`, message); + } + } +} + +/** + * Source: https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518 + * + * @param html {string} representing a single element + * @return {Element} + */ +export const htmlToElement = html => { + let template = document.createElement('template'); + template.innerHTML = html.trim(); + return template.content.firstChild; +} + +/** + * Source: https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518 + * + * @param html {string} representing any number of sibling elements + * @return {NodeList} + */ +export const htmlToElements = html => { + let template = document.createElement('template'); + template.innerHTML = html; + return template.content.childNodes; +} + +/** + * Schedules an animation + * @param durationMs {number} the duration of the animation in ms + * @param animationFrame {function(progress: number, deltaTime: number)} a function that is getting called each frame with the parameters (progress (0-1), deltaTime) + * @param postAnimation {function(finished: boolean)} a function that gets called once after the animation is finished or cancelled. The function accepts one bool-parameter whether the animation was finished (true) or canceled (false) + * @returns {{cancel: function()}} the animation object + */ +export const animate = function (animationFrame, durationMs = 1000, postAnimation = null) { + let animation = { + animationStart: -1, + lastFrame: -1, + cancelled: false, + + frame: function (time) { + if (this.cancelled) return; + + if (this.animationStart === -1) { + this.animationStart = time; + this.lastFrame = time; + } + + let progress = durationMs === 0 ? 1 : MathUtils.clamp((time - this.animationStart) / durationMs, 0, 1); + let deltaTime = time - this.lastFrame; + + animationFrame(progress, deltaTime); + + if (progress < 1) window.requestAnimationFrame(time => this.frame(time)); + else if (postAnimation) postAnimation(true); + + this.lastFrame = time; + }, + + cancel: function () { + this.cancelled = true; + if (postAnimation) postAnimation(false); + } + }; + + window.requestAnimationFrame(time => animation.frame(time)); + + return animation; +} + +/** + * Source: https://gist.github.com/gre/1650294 + * @type {{ + * easeOutCubic: (function(number): number), + * linear: (function(number): number), + * easeOutQuint: (function(number): number), + * easeInQuart: (function(number): number), + * easeInOutQuint: (function(number): number), + * easeInQuad: (function(number): number), + * easeOutQuart: (function(number): number), + * easeInCubic: (function(number): number), + * easeInQuint: (function(number): number), + * easeOutQuad: (function(number): number), + * easeInOutQuad: (function(number): number), + * easeInOutCubic: (function(number): number), + * easeInOutQuart: (function(number): number) + * }} + */ +export const EasingFunctions = { + // no easing, no acceleration + linear: t => t, + // accelerating from zero velocity + easeInQuad: t => t*t, + // decelerating to zero velocity + easeOutQuad: t => t*(2-t), + // acceleration until halfway, then deceleration + easeInOutQuad: t => t<.5 ? 2*t*t : -1+(4-2*t)*t, + // accelerating from zero velocity + easeInCubic: t => t*t*t, + // decelerating to zero velocity + easeOutCubic: t => (--t)*t*t+1, + // acceleration until halfway, then deceleration + easeInOutCubic: t => t<.5 ? 4*t*t*t : (t-1)*(2*t-2)*(2*t-2)+1, + // accelerating from zero velocity + easeInQuart: t => t*t*t*t, + // decelerating to zero velocity + easeOutQuart: t => 1-(--t)*t*t*t, + // acceleration until halfway, then deceleration + easeInOutQuart: t => t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t, + // accelerating from zero velocity + easeInQuint: t => t*t*t*t*t, + // decelerating to zero velocity + easeOutQuint: t => 1+(--t)*t*t*t*t, + // acceleration until halfway, then deceleration + easeInOutQuint: t => t<.5 ? 16*t*t*t*t*t : 1+16*(--t)*t*t*t*t +} + +/** + * Returns the offset position of an element + * + * Source: https://plainjs.com/javascript/styles/get-the-position-of-an-element-relative-to-the-document-24/ + * + * @param element {Element} + * @returns {{top: number, left: number}} + */ +export const elementOffset = element => { + let rect = element.getBoundingClientRect(), + scrollLeft = window.pageXOffset || document.documentElement.scrollLeft, + scrollTop = window.pageYOffset || document.documentElement.scrollTop; + return { top: rect.top + scrollTop, left: rect.left + scrollLeft } +} + +/** + * Very simple deep equals, should not be used for complex objects. Is designed for comparing parsed json-objects. + * @param object1 {object} + * @param object2 {object} + * @returns {boolean} + */ +export const deepEquals = (object1, object2) => { + if (Object.is(object1, object2)) return true; + + let type = typeof object1; + if (type !== typeof object2) return false; + + if (type === 'number' || type === 'boolean' || type === 'string') return false; + + if (Array.isArray(object1)){ + let len = object1.length; + if (len !== object2.length) return false; + for (let i = 0; i < len; i++) { + if (!deepEquals(object1[i], object2[i])) return false; + } + + return true; + } + + for (let property in object1) { + if (!object1.hasOwnProperty(property)) continue; + if (!deepEquals(object1[property], object2[property])) return false; + } + + return true; +} + +/** + * Adds one listener to multiple events + * @param target {EventTarget} + * @param types {string|string[]} + * @param listener {EventListenerOrEventListenerObject | null} + * @param options {boolean | AddEventListenerOptions?} + */ +export const addEventListeners = (target, types, listener, options) => { + if (!Array.isArray(types)){ + types = types.trim().split(" "); + } + + types.forEach(type => target.addEventListener(type, listener, options)); +} + +/** + * Removes one listener to multiple events + * @param target {EventTarget} + * @param types {string|string[]} + * @param listener {EventListenerOrEventListenerObject | null} + * @param options {boolean | EventListenerOptions?} + */ +export const removeEventListeners = (target, types, listener, options) => { + if (!Array.isArray(types)){ + types = types.trim().split(" "); + } + + types.forEach(type => target.removeEventListener(type, listener, options)); +} + +/** + * Softly clamps towards a minimum value + * @param value {number} + * @param min {number} + * @param stiffness {number} + * @returns {number} + */ +export const softMin = (value, min, stiffness) => { + if (value >= min) return value; + let delta = min - value; + if (delta < 0.0001) return min; + return value + delta * stiffness; +} + +/** + * Softly clamps towards a maximum value + * @param value {number} + * @param max {number} + * @param stiffness {number} + * @returns {number} + */ +export const softMax = (value, max, stiffness) => { + if (value <= max) return value; + let delta = value - max; + if (delta < 0.0001) return max; + return value - delta * stiffness; +} + +/** + * Softly clamps towards a minimum and maximum value + * @param value {number} + * @param min {number} + * @param max {number} + * @param stiffness {number} + * @returns {number} + */ +export const softClamp = (value, min, max, stiffness) => { + return softMax(softMin(value, min, stiffness), max, stiffness); +} + +export const vecArrToObj = (val, useZ = false) => { + if (val && val.length >= 2) { + if (useZ) return {x: val[0], z: val[1]}; + return {x: val[0], y: val[1]}; + } + return {}; +} + +const pixel = document.createElement('canvas'); +pixel.width = 1; +pixel.height = 1; +const pixelContext = pixel.getContext('2d', { + willReadFrequently: true +}); + +export const getPixel = (img, x, y) => { + pixelContext.drawImage(img, Math.floor(x), Math.floor(y), 1, 1, 0, 0, 1, 1); + return pixelContext.getImageData(0, 0, 1, 1).data; +} diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/Line2.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/Line2.js new file mode 100644 index 00000000..1078fac3 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/Line2.js @@ -0,0 +1,25 @@ + +import { LineSegments2 } from "./LineSegments2"; +import { LineGeometry } from "./LineGeometry"; +import { LineMaterial } from "./LineMaterial"; + +var Line2 = function ( geometry, material ) { + + if ( geometry === undefined ) geometry = new LineGeometry(); + if ( material === undefined ) material = new LineMaterial( { color: Math.random() * 0xffffff } ); + + LineSegments2.call( this, geometry, material ); + + this.type = 'Line2'; + +}; + +Line2.prototype = Object.assign( Object.create( LineSegments2.prototype ), { + + constructor: Line2, + + isLine2: true + +} ); + +export { Line2 }; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineGeometry.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineGeometry.js new file mode 100644 index 00000000..e10a3e72 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineGeometry.js @@ -0,0 +1,96 @@ + +import { LineSegmentsGeometry } from "./LineSegmentsGeometry"; + +var LineGeometry = function () { + + LineSegmentsGeometry.call( this ); + + this.type = 'LineGeometry'; + +}; + +LineGeometry.prototype = Object.assign( Object.create( LineSegmentsGeometry.prototype ), { + + constructor: LineGeometry, + + isLineGeometry: true, + + setPositions: function ( array ) { + + // converts [ x1, y1, z1, x2, y2, z2, ... ] to pairs format + + var length = array.length - 3; + var points = new Float32Array( 2 * length ); + + for ( var i = 0; i < length; i += 3 ) { + + points[ 2 * i ] = array[ i ]; + points[ 2 * i + 1 ] = array[ i + 1 ]; + points[ 2 * i + 2 ] = array[ i + 2 ]; + + points[ 2 * i + 3 ] = array[ i + 3 ]; + points[ 2 * i + 4 ] = array[ i + 4 ]; + points[ 2 * i + 5 ] = array[ i + 5 ]; + + } + + LineSegmentsGeometry.prototype.setPositions.call( this, points ); + + return this; + + }, + + setColors: function ( array ) { + + // converts [ r1, g1, b1, r2, g2, b2, ... ] to pairs format + + var length = array.length - 3; + var colors = new Float32Array( 2 * length ); + + for ( var i = 0; i < length; i += 3 ) { + + colors[ 2 * i ] = array[ i ]; + colors[ 2 * i + 1 ] = array[ i + 1 ]; + colors[ 2 * i + 2 ] = array[ i + 2 ]; + + colors[ 2 * i + 3 ] = array[ i + 3 ]; + colors[ 2 * i + 4 ] = array[ i + 4 ]; + colors[ 2 * i + 5 ] = array[ i + 5 ]; + + } + + LineSegmentsGeometry.prototype.setColors.call( this, colors ); + + return this; + + }, + + fromLine: function ( line ) { + + var geometry = line.geometry; + + if ( geometry.isGeometry ) { + + this.setPositions( geometry.vertices ); + + } else if ( geometry.isBufferGeometry ) { + + this.setPositions( geometry.attributes.position.array ); // assumes non-indexed + + } + + // set colors, maybe + + return this; + + }, + + copy: function ( /* source */ ) { + + return this; + + } + +} ); + +export { LineGeometry }; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineMaterial.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineMaterial.js new file mode 100644 index 00000000..185344ec --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineMaterial.js @@ -0,0 +1,424 @@ +import { + ShaderLib, + ShaderMaterial, + UniformsLib, + UniformsUtils, + Vector2 +} from "three"; +/** + * parameters = { + * color: , + * linewidth: , + * dashed: , + * dashScale: , + * dashSize: , + * gapSize: , + * resolution: , // to be set by renderer + * } + */ + +UniformsLib.line = { + + linewidth: { value: 1 }, + resolution: { value: new Vector2( 1, 1 ) }, + dashScale: { value: 1 }, + dashSize: { value: 1 }, + gapSize: { value: 1 }, + opacity: { value: 1 } + +}; + +ShaderLib[ 'line' ] = { + + uniforms: UniformsUtils.merge( [ + UniformsLib.common, + UniformsLib.fog, + UniformsLib.line + ] ), + + vertexShader: + ` + #include + #include + #include + #include + #include + + uniform float linewidth; + uniform vec2 resolution; + + attribute vec3 instanceStart; + attribute vec3 instanceEnd; + + attribute vec3 instanceColorStart; + attribute vec3 instanceColorEnd; + + varying vec2 vUv; + + varying float vDistance; + + #ifdef USE_DASH + + uniform float dashScale; + attribute float instanceDistanceStart; + attribute float instanceDistanceEnd; + varying float vLineDistance; + + #endif + + void trimSegment( const in vec4 start, inout vec4 end ) { + + // trim end segment so it terminates between the camera plane and the near plane + + // conservative estimate of the near plane + float a = projectionMatrix[ 2 ][ 2 ]; // 3nd entry in 3th column + float b = projectionMatrix[ 3 ][ 2 ]; // 3nd entry in 4th column + float nearEstimate = - 0.5 * b / a; + + float alpha = ( nearEstimate - start.z ) / ( end.z - start.z ); + + end.xyz = mix( start.xyz, end.xyz, alpha ); + + } + + void main() { + + #ifdef USE_COLOR + + vColor.xyz = ( position.y < 0.5 ) ? instanceColorStart : instanceColorEnd; + + #endif + + #ifdef USE_DASH + + vLineDistance = ( position.y < 0.5 ) ? dashScale * instanceDistanceStart : dashScale * instanceDistanceEnd; + + #endif + + float aspect = resolution.x / resolution.y; + + vUv = uv; + + // camera space + vec4 start = modelViewMatrix * vec4( instanceStart, 1.0 ); + vec4 end = modelViewMatrix * vec4( instanceEnd, 1.0 ); + + // special case for perspective projection, and segments that terminate either in, or behind, the camera plane + // clearly the gpu firmware has a way of addressing this issue when projecting into ndc space + // but we need to perform ndc-space calculations in the shader, so we must address this issue directly + // perhaps there is a more elegant solution -- WestLangley + + bool perspective = ( projectionMatrix[ 2 ][ 3 ] == - 1.0 ); // 4th entry in the 3rd column + + if ( perspective ) { + + if ( start.z < 0.0 && end.z >= 0.0 ) { + + trimSegment( start, end ); + + } else if ( end.z < 0.0 && start.z >= 0.0 ) { + + trimSegment( end, start ); + + } + + } + + // clip space + vec4 clipStart = projectionMatrix * start; + vec4 clipEnd = projectionMatrix * end; + + // ndc space + vec2 ndcStart = clipStart.xy / clipStart.w; + vec2 ndcEnd = clipEnd.xy / clipEnd.w; + + // direction + vec2 dir = ndcEnd - ndcStart; + + // account for clip-space aspect ratio + dir.x *= aspect; + dir = normalize( dir ); + + // perpendicular to dir + vec2 offset = vec2( dir.y, - dir.x ); + + // undo aspect ratio adjustment + dir.x /= aspect; + offset.x /= aspect; + + // sign flip + if ( position.x < 0.0 ) offset *= - 1.0; + + // endcaps + if ( position.y < 0.0 ) { + + offset += - dir; + + } else if ( position.y > 1.0 ) { + + offset += dir; + + } + + // adjust for linewidth + offset *= linewidth; + + // adjust for clip-space to screen-space conversion // maybe resolution should be based on viewport ... + offset /= resolution.y; + + // select end + vec4 clip = ( position.y < 0.5 ) ? clipStart : clipEnd; + + // back to clip space + offset *= clip.w; + + clip.xy += offset; + + gl_Position = clip; + + vec4 mvPosition = ( position.y < 0.5 ) ? start : end; // this is an approximation + + vDistance = -mvPosition.z; + + #include + #include + #include + + } + `, + + fragmentShader: + ` + #define FLT_MAX 3.402823466e+38 + + uniform vec3 diffuse; + uniform float opacity; + + uniform float fadeDistanceMax; + uniform float fadeDistanceMin; + + #ifdef USE_DASH + + uniform float dashSize; + uniform float gapSize; + + #endif + + varying float vLineDistance; + + #include + #include + #include + #include + #include + + varying vec2 vUv; + + varying float vDistance; + + void main() { + + #include + + #ifdef USE_DASH + + if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps + + if ( mod( vLineDistance, dashSize + gapSize ) > dashSize ) discard; // todo - FIX + + #endif + + if ( abs( vUv.y ) > 1.0 ) { + + float a = vUv.x; + float b = ( vUv.y > 0.0 ) ? vUv.y - 1.0 : vUv.y + 1.0; + float len2 = a * a + b * b; + + if ( len2 > 1.0 ) discard; + + } + + // distance fading + float fdMax = FLT_MAX; + if ( fadeDistanceMax > 0.0 ) fdMax = fadeDistanceMax; + + float minDelta = (vDistance - fadeDistanceMin) / fadeDistanceMin; + float maxDelta = (vDistance - fadeDistanceMax) / (fadeDistanceMax * 0.5); + float distanceOpacity = min( + clamp(minDelta, 0.0, 1.0), + 1.0 - clamp(maxDelta + 1.0, 0.0, 1.0) + ); + + vec4 diffuseColor = vec4( diffuse, opacity * distanceOpacity ); + + #include + #include + + gl_FragColor = vec4( diffuseColor.rgb, diffuseColor.a ); + + #include + #include + #include + #include + + } + ` +}; + +var LineMaterial = function ( parameters ) { + + ShaderMaterial.call( this, { + + type: 'LineMaterial', + + uniforms: UniformsUtils.clone( ShaderLib[ 'line' ].uniforms ), + + vertexShader: ShaderLib[ 'line' ].vertexShader, + fragmentShader: ShaderLib[ 'line' ].fragmentShader, + + clipping: true // required for clipping support + + } ); + + this.dashed = false; + + Object.defineProperties( this, { + + color: { + + enumerable: true, + + get: function () { + + return this.uniforms.diffuse.value; + + }, + + set: function ( value ) { + + this.uniforms.diffuse.value = value; + + } + + }, + + linewidth: { + + enumerable: true, + + get: function () { + + return this.uniforms.linewidth.value; + + }, + + set: function ( value ) { + + this.uniforms.linewidth.value = value; + + } + + }, + + dashScale: { + + enumerable: true, + + get: function () { + + return this.uniforms.dashScale.value; + + }, + + set: function ( value ) { + + this.uniforms.dashScale.value = value; + + } + + }, + + dashSize: { + + enumerable: true, + + get: function () { + + return this.uniforms.dashSize.value; + + }, + + set: function ( value ) { + + this.uniforms.dashSize.value = value; + + } + + }, + + gapSize: { + + enumerable: true, + + get: function () { + + return this.uniforms.gapSize.value; + + }, + + set: function ( value ) { + + this.uniforms.gapSize.value = value; + + } + + }, + + opacity: { + + enumerable: true, + + get: function () { + + return this.uniforms.opacity.value; + + }, + + set: function ( value ) { + + this.uniforms.opacity.value = value; + + } + + }, + + resolution: { + + enumerable: true, + + get: function () { + + return this.uniforms.resolution.value; + + }, + + set: function ( value ) { + + this.uniforms.resolution.value.copy( value ); + + } + + } + + } ); + + this.setValues( parameters ); + +}; + +LineMaterial.prototype = Object.create( ShaderMaterial.prototype ); +LineMaterial.prototype.constructor = LineMaterial; + +LineMaterial.prototype.isLineMaterial = true; + +export { LineMaterial }; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineSegments2.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineSegments2.js new file mode 100644 index 00000000..1e2202ae --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineSegments2.js @@ -0,0 +1,209 @@ +import { + InstancedInterleavedBuffer, + InterleavedBufferAttribute, + Line3, + MathUtils, + Matrix4, + Mesh, + Vector3, + Vector4 +} from "three"; +import { LineSegmentsGeometry } from "./LineSegmentsGeometry"; +import { LineMaterial } from "./LineMaterial"; + +var LineSegments2 = function ( geometry, material ) { + + if ( geometry === undefined ) geometry = new LineSegmentsGeometry(); + if ( material === undefined ) material = new LineMaterial( { color: Math.random() * 0xffffff } ); + + Mesh.call( this, geometry, material ); + + this.type = 'LineSegments2'; + +}; + +LineSegments2.prototype = Object.assign( Object.create( Mesh.prototype ), { + + constructor: LineSegments2, + + isLineSegments2: true, + + computeLineDistances: ( function () { // for backwards-compatability, but could be a method of LineSegmentsGeometry... + + var start = new Vector3(); + var end = new Vector3(); + + return function computeLineDistances() { + + var geometry = this.geometry; + + var instanceStart = geometry.attributes.instanceStart; + var instanceEnd = geometry.attributes.instanceEnd; + var lineDistances = new Float32Array( 2 * instanceStart.data.count ); + + for ( var i = 0, j = 0, l = instanceStart.data.count; i < l; i ++, j += 2 ) { + + start.fromBufferAttribute( instanceStart, i ); + end.fromBufferAttribute( instanceEnd, i ); + + lineDistances[ j ] = ( j === 0 ) ? 0 : lineDistances[ j - 1 ]; + lineDistances[ j + 1 ] = lineDistances[ j ] + start.distanceTo( end ); + + } + + var instanceDistanceBuffer = new InstancedInterleavedBuffer( lineDistances, 2, 1 ); // d0, d1 + + geometry.setAttribute( 'instanceDistanceStart', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 0 ) ); // d0 + geometry.setAttribute( 'instanceDistanceEnd', new InterleavedBufferAttribute( instanceDistanceBuffer, 1, 1 ) ); // d1 + + return this; + + }; + + }() ), + + raycast: ( function () { + + var start = new Vector4(); + var end = new Vector4(); + + var ssOrigin = new Vector4(); + var ssOrigin3 = new Vector3(); + var mvMatrix = new Matrix4(); + var line = new Line3(); + var closestPoint = new Vector3(); + + return function raycast( raycaster, intersects ) { + + if ( raycaster.camera === null ) { + + console.error( 'LineSegments2: "Raycaster.camera" needs to be set in order to raycast against LineSegments2.' ); + + } + + var threshold = ( raycaster.params.Line2 !== undefined ) ? raycaster.params.Line2.threshold || 0 : 0; + + var ray = raycaster.ray; + var camera = raycaster.camera; + var projectionMatrix = camera.projectionMatrix; + + var geometry = this.geometry; + var material = this.material; + var resolution = material.resolution; + var lineWidth = material.linewidth + threshold; + + var instanceStart = geometry.attributes.instanceStart; + var instanceEnd = geometry.attributes.instanceEnd; + + // pick a point 1 unit out along the ray to avoid the ray origin + // sitting at the camera origin which will cause "w" to be 0 when + // applying the projection matrix. + ray.at( 1, ssOrigin ); + + // ndc space [ - 1.0, 1.0 ] + ssOrigin.w = 1; + ssOrigin.applyMatrix4( camera.matrixWorldInverse ); + ssOrigin.applyMatrix4( projectionMatrix ); + ssOrigin.multiplyScalar( 1 / ssOrigin.w ); + + // screen space + ssOrigin.x *= resolution.x / 2; + ssOrigin.y *= resolution.y / 2; + ssOrigin.z = 0; + + ssOrigin3.copy( ssOrigin ); + + var matrixWorld = this.matrixWorld; + mvMatrix.multiplyMatrices( camera.matrixWorldInverse, matrixWorld ); + + for ( var i = 0, l = instanceStart.count; i < l; i ++ ) { + + start.fromBufferAttribute( instanceStart, i ); + end.fromBufferAttribute( instanceEnd, i ); + + start.w = 1; + end.w = 1; + + // camera space + start.applyMatrix4( mvMatrix ); + end.applyMatrix4( mvMatrix ); + + // clip space + start.applyMatrix4( projectionMatrix ); + end.applyMatrix4( projectionMatrix ); + + // ndc space [ - 1.0, 1.0 ] + start.multiplyScalar( 1 / start.w ); + end.multiplyScalar( 1 / end.w ); + + // skip the segment if it's outside the camera near and far planes + var isBehindCameraNear = start.z < - 1 && end.z < - 1; + var isPastCameraFar = start.z > 1 && end.z > 1; + if ( isBehindCameraNear || isPastCameraFar ) { + + continue; + + } + + // screen space + start.x *= resolution.x / 2; + start.y *= resolution.y / 2; + + end.x *= resolution.x / 2; + end.y *= resolution.y / 2; + + // create 2d segment + line.start.copy( start ); + line.start.z = 0; + + line.end.copy( end ); + line.end.z = 0; + + // get closest point on ray to segment + var param = line.closestPointToPointParameter( ssOrigin3, true ); + line.at( param, closestPoint ); + + // check if the intersection point is within clip space + var zPos = MathUtils.lerp( start.z, end.z, param ); + var isInClipSpace = zPos >= - 1 && zPos <= 1; + + var isInside = ssOrigin3.distanceTo( closestPoint ) < lineWidth * 0.5; + + if ( isInClipSpace && isInside ) { + + line.start.fromBufferAttribute( instanceStart, i ); + line.end.fromBufferAttribute( instanceEnd, i ); + + line.start.applyMatrix4( matrixWorld ); + line.end.applyMatrix4( matrixWorld ); + + var pointOnLine = new Vector3(); + var point = new Vector3(); + + ray.distanceSqToSegment( line.start, line.end, point, pointOnLine ); + + intersects.push( { + + point: point, + pointOnLine: pointOnLine, + distance: ray.origin.distanceTo( point ), + + object: this, + face: null, + faceIndex: i, + uv: null, + uv2: null, + + } ); + + } + + } + + }; + + }() ) + +} ); + +export { LineSegments2 }; diff --git a/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineSegmentsGeometry.js b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineSegmentsGeometry.js new file mode 100644 index 00000000..ef9548d2 --- /dev/null +++ b/BlueMapCommon/BlueMapVue/BlueMapWeb/src/util/lines/LineSegmentsGeometry.js @@ -0,0 +1,258 @@ +import { + Box3, + Float32BufferAttribute, + InstancedBufferGeometry, + InstancedInterleavedBuffer, + InterleavedBufferAttribute, + Sphere, + Vector3, + WireframeGeometry +} from "three"; + +var LineSegmentsGeometry = function () { + + InstancedBufferGeometry.call( this ); + + this.type = 'LineSegmentsGeometry'; + + var positions = [ - 1, 2, 0, 1, 2, 0, - 1, 1, 0, 1, 1, 0, - 1, 0, 0, 1, 0, 0, - 1, - 1, 0, 1, - 1, 0 ]; + var uvs = [ - 1, 2, 1, 2, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 2, 1, - 2 ]; + var index = [ 0, 2, 1, 2, 3, 1, 2, 4, 3, 4, 5, 3, 4, 6, 5, 6, 7, 5 ]; + + this.setIndex( index ); + this.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) ); + this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) ); + +}; + +LineSegmentsGeometry.prototype = Object.assign( Object.create( InstancedBufferGeometry.prototype ), { + + constructor: LineSegmentsGeometry, + + isLineSegmentsGeometry: true, + + applyMatrix4: function ( matrix ) { + + var start = this.attributes.instanceStart; + var end = this.attributes.instanceEnd; + + if ( start !== undefined ) { + + start.applyMatrix4( matrix ); + + end.applyMatrix4( matrix ); + + start.needsUpdate = true; + + } + + if ( this.boundingBox !== null ) { + + this.computeBoundingBox(); + + } + + if ( this.boundingSphere !== null ) { + + this.computeBoundingSphere(); + + } + + return this; + + }, + + setPositions: function ( array ) { + + var lineSegments; + + if ( array instanceof Float32Array ) { + + lineSegments = array; + + } else if ( Array.isArray( array ) ) { + + lineSegments = new Float32Array( array ); + + } + + var instanceBuffer = new InstancedInterleavedBuffer( lineSegments, 6, 1 ); // xyz, xyz + + this.setAttribute( 'instanceStart', new InterleavedBufferAttribute( instanceBuffer, 3, 0 ) ); // xyz + this.setAttribute( 'instanceEnd', new InterleavedBufferAttribute( instanceBuffer, 3, 3 ) ); // xyz + + // + + this.computeBoundingBox(); + this.computeBoundingSphere(); + + return this; + + }, + + setColors: function ( array ) { + + var colors; + + if ( array instanceof Float32Array ) { + + colors = array; + + } else if ( Array.isArray( array ) ) { + + colors = new Float32Array( array ); + + } + + var instanceColorBuffer = new InstancedInterleavedBuffer( colors, 6, 1 ); // rgb, rgb + + this.setAttribute( 'instanceColorStart', new InterleavedBufferAttribute( instanceColorBuffer, 3, 0 ) ); // rgb + this.setAttribute( 'instanceColorEnd', new InterleavedBufferAttribute( instanceColorBuffer, 3, 3 ) ); // rgb + + return this; + + }, + + fromWireframeGeometry: function ( geometry ) { + + this.setPositions( geometry.attributes.position.array ); + + return this; + + }, + + fromEdgesGeometry: function ( geometry ) { + + this.setPositions( geometry.attributes.position.array ); + + return this; + + }, + + fromMesh: function ( mesh ) { + + this.fromWireframeGeometry( new WireframeGeometry( mesh.geometry ) ); + + // set colors, maybe + + return this; + + }, + + fromLineSegments: function ( lineSegments ) { + + var geometry = lineSegments.geometry; + + if ( geometry.isGeometry ) { + + this.setPositions( geometry.vertices ); + + } else if ( geometry.isBufferGeometry ) { + + this.setPositions( geometry.attributes.position.array ); // assumes non-indexed + + } + + // set colors, maybe + + return this; + + }, + + computeBoundingBox: function () { + + var box = new Box3(); + + return function computeBoundingBox() { + + if ( this.boundingBox === null ) { + + this.boundingBox = new Box3(); + + } + + var start = this.attributes.instanceStart; + var end = this.attributes.instanceEnd; + + if ( start !== undefined && end !== undefined ) { + + this.boundingBox.setFromBufferAttribute( start ); + + box.setFromBufferAttribute( end ); + + this.boundingBox.union( box ); + + } + + }; + + }(), + + computeBoundingSphere: function () { + + var vector = new Vector3(); + + return function computeBoundingSphere() { + + if ( this.boundingSphere === null ) { + + this.boundingSphere = new Sphere(); + + } + + if ( this.boundingBox === null ) { + + this.computeBoundingBox(); + + } + + var start = this.attributes.instanceStart; + var end = this.attributes.instanceEnd; + + if ( start !== undefined && end !== undefined ) { + + var center = this.boundingSphere.center; + + this.boundingBox.getCenter( center ); + + var maxRadiusSq = 0; + + for ( var i = 0, il = start.count; i < il; i ++ ) { + + vector.fromBufferAttribute( start, i ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + + vector.fromBufferAttribute( end, i ); + maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) ); + + } + + this.boundingSphere.radius = Math.sqrt( maxRadiusSq ); + + if ( isNaN( this.boundingSphere.radius ) ) { + + console.error( 'THREE.LineSegmentsGeometry.computeBoundingSphere(): Computed radius is NaN. The instanced position data is likely to have NaN values.', this ); + + } + + } + + }; + + }(), + + toJSON: function () { + + }, + + applyMatrix: function ( matrix ) { + + console.warn( 'THREE.LineSegmentsGeometry: applyMatrix() has been renamed to applyMatrix4().' ); + + return this.applyMatrix4( matrix ); + + } + +} ); + +export { LineSegmentsGeometry };