diff --git a/.eslintrc.json b/.eslintrc.json index 23ba71190..5866aa92b 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -4,6 +4,7 @@ "sourceType": "module" }, "extends": ["eslint:recommended", "plugin:prettier/recommended"], + "plugins": ["eslint-plugin-local-rules"], "env": { "browser": true, "jest": false, @@ -14,6 +15,7 @@ "commonjs": true, "es2020": true }, + "ignorePatterns": ["*.d.ts"], "rules": { "prettier/prettier": ["error", { "endOfLine": "auto" }], "no-console": "off", @@ -42,14 +44,36 @@ "no-self-compare": 1, "no-throw-literal": 1, "no-unused-expressions": 1, - "no-useless-concat": 1, "no-void": 1, "no-sequences": 1, - "radix": 1 + "radix": 1, + "local-rules/wx-keys": 2 }, "globals": { "L": "readonly", "PLAYER": "readonly", "android": "readonly" - } + }, + "overrides": [ + { + "files": ["src/**/*.ts"], + "parser": "@typescript-eslint/parser", + "parserOptions": { + "project": "./tsconfig.json" + }, + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ], + "rules": { + "prettier/prettier": 0, + "lines-between-class-members": 0, + "@typescript-eslint/no-array-constructor": 1, + "@typescript-eslint/no-empty-function": 1, + "@typescript-eslint/no-inferrable-types": 1 + } + } + ] } diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml deleted file mode 100644 index f7f53b97c..000000000 --- a/.github/FUNDING.yml +++ /dev/null @@ -1 +0,0 @@ -custom: ['https://www.patreon.com/wasabee'] diff --git a/.github/workflows/dev.yaml b/.github/workflows/dev.yaml index 7a581c836..d4878e233 100644 --- a/.github/workflows/dev.yaml +++ b/.github/workflows/dev.yaml @@ -13,7 +13,7 @@ jobs: - name: Build πŸ”§ run: | npm install - npx gulp build-dev + npm run build-dev - name: Deploy πŸš€ uses: JamesIves/github-pages-deploy-action@4.1.1 diff --git a/.github/workflows/master.yaml b/.github/workflows/master.yaml index 6b943e9f0..50b2aeedb 100644 --- a/.github/workflows/master.yaml +++ b/.github/workflows/master.yaml @@ -15,7 +15,7 @@ jobs: - name: Build πŸ”§ run: | npm install - npx gulp build-prod + npm run build - name: Deploy πŸš€ if: ${{ github.ref_type == 'tag' }} diff --git a/.github/workflows/pr-build.yaml b/.github/workflows/pr-build.yaml new file mode 100644 index 000000000..a45f8040c --- /dev/null +++ b/.github/workflows/pr-build.yaml @@ -0,0 +1,23 @@ +name: Pull request build +on: + pull_request: + branches: [dev] + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout πŸ›ŽοΈ + uses: actions/checkout@v2.3.1 + + - name: Build + env: + PR_NUMBER: ${{ github.event.number }} + run: | + npm install + npm run build-pr + + - uses: actions/upload-artifact@v2 + with: + name: pr + path: releases/dev/wasabee.user.js diff --git a/.github/workflows/pr-comment.yaml b/.github/workflows/pr-comment.yaml new file mode 100644 index 000000000..5a1b8b60d --- /dev/null +++ b/.github/workflows/pr-comment.yaml @@ -0,0 +1,25 @@ +name: Pull request Comment +on: + workflow_run: + workflows: ["Pull request build"] + types: + - completed +jobs: + comment: + runs-on: ubuntu-latest + if: > + ${{ github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' }} + steps: + - uses: actions/download-artifact@v2 + with: + name: pr + + - name: Pull request artifacts + uses: gavv/pull-request-artifacts@v1.0.0 + with: + commit: ${{ github.event.pull_request.head.sha }} + repo-token: ${{ secrets.GITHUB_TOKEN }} + artifacts-branch: artifacts + artifacts: | + wasabee.user.js diff --git a/.github/workflows/testing.yml b/.github/workflows/testing.yml new file mode 100644 index 000000000..23f569e9f --- /dev/null +++ b/.github/workflows/testing.yml @@ -0,0 +1,23 @@ +name: Build and Deploy Testing +on: + push: + branches: + - testing +jobs: + build-and-deploy-testing: + runs-on: ubuntu-latest + steps: + - name: Checkout πŸ›ŽοΈ + uses: actions/checkout@v2.3.1 + + - name: Build πŸ”§ + run: | + npm install + npm run build-testing + + - name: Deploy πŸš€ + uses: JamesIves/github-pages-deploy-action@4.1.1 + with: + branch: dist # The branch the action should deploy to. + folder: releases # The folder the action should deploy. + clean: false # build is already clean (keep prod/dev) diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 4b2836e8b..000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "editor.formatOnSave": true, - "javascript.validate.enable": false -} diff --git a/README.md b/README.md index f09f4bd9e..d3965e852 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ ![GitHub issues](https://img.shields.io/github/issues/wasabee-project/Wasabee-IITC.svg) [![Build Status](https://travis-ci.org/wasabee-project/Wasabee-IITC.svg?branch=master)](https://travis-ci.org/wasabee-project/Wasabee-IITC) [![Releases](https://img.shields.io/github/v/release/wasabee-project/Wasabee-IITC)](https://github.com/wasabee-project/Wasabee-IITC/releases) +[![Crowdin](https://badges.crowdin.net/wasabee-iitc/localized.svg)](https://crowdin.com/project/wasabee-iitc) # Wasabee diff --git a/crowdin.yml b/crowdin.yml new file mode 100644 index 000000000..54c017dff --- /dev/null +++ b/crowdin.yml @@ -0,0 +1,5 @@ +files: + - source: /src/code/translations/English.json + translation: /src/code/translations/%language%.json + skip_untranslated_strings: true + update_option: "update_as_unapproved" diff --git a/eslint-local-rules.js b/eslint-local-rules.js new file mode 100644 index 000000000..daa69410d --- /dev/null +++ b/eslint-local-rules.js @@ -0,0 +1,45 @@ +"use strict"; + +const sourceLanguage = require("./src/code/translations/English.json"); + +module.exports = { + "wx-keys": { + meta: { + docs: { + description: "Check wX calls", + category: "Possible Errors", + recommended: false, + }, + schema: [], + }, + create: function (context) { + return { + CallExpression: function (node) { + const callee = node.callee; + if (callee.type !== "Identifier") return; + if (callee.name !== "wX") return; + const args = node.arguments; + if (args.length < 1 || args.length > 2) { + context.report({ + node: node, + message: "Invalid number of arguments for wX", + }); + } else { + if (args[0].type !== "Literal") return; + const key = args[0].value; + if (key in sourceLanguage) { + return; + } + context.report({ + node: node, + message: "Unknown wX key: {{ key }}", + data: { + key: args[0].raw + }, + }); + } + }, + }; + }, + }, +}; diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index b6c3bc8a9..000000000 --- a/gulpfile.js +++ /dev/null @@ -1,226 +0,0 @@ -// Requires -const fs = require("fs"); -const path = require("path"); -const gulp = require("gulp"); -const injectfile = require("gulp-inject-file"); // https://www.npmjs.com/package/gulp-inject-file -const rename = require("gulp-rename"); // https://www.npmjs.com/package/gulp-rename -const contents = require("gulp-inject-string"); // https://www.npmjs.com/package/gulp-inject-string -const cfg = require("./plugin.config.json"); -const trimlines = require("gulp-trimlines"); -const eslint = require("gulp-eslint"); -const del = require("del"); -const webpack = require("webpack"); -const PluginError = require("plugin-error"); -const prettier = require("gulp-prettier"); - -const ensureDirectoryExistence = (filePath) => { - const dirname = path.dirname(filePath); - if (fs.existsSync(dirname)) return; - - ensureDirectoryExistence(dirname); - fs.mkdirSync(dirname); -}; - -// Config -var status = { - headers: null, - mode: null, -}; - -// status related tasks -gulp.task("set-mode-dev", (cb) => { - status.mode = "dev"; - cb(); -}); - -gulp.task("set-mode-prod", (cb) => { - status.mode = "prod"; - cb(); -}); - -gulp.task("clear", (cb) => { - status.headers = null; - status.mode = null; - cb(); -}); - -// build tasks -gulp.task("buildheaders", (cb) => { - const content = fs.readFileSync(cfg.src.meta, "utf8"); - - let newContent = ""; - for (const l of content.split("\n")) { - let newline = l; - for (const k of Object.keys(cfg.headers.common)) { - if (l.indexOf(`@${k} `) == 3) { - const key = k.padEnd(13); - newline = `// @${key} ${cfg.headers.common[k]}`; - break; - } - } - for (const k of Object.keys(cfg.headers[status.mode])) { - if (l.indexOf(`@${k} `) == 3) { - const key = k.padEnd(13); - newline = `// @${key} ${cfg.headers[status.mode][k]}`; - break; - } - } - newContent += newline + "\n"; - } - - // XXX just append to the version rather than overwriting a fixed string now - const gbd = () => { - const d = new Date(); - let bd = d.getUTCFullYear(); - let t = ("0" + (d.getUTCMonth() + 1)).substr(-2); - bd += t; - t = ("0" + d.getUTCDate()).substr(-2); - bd += t; - t = ("0" + d.getUTCHours()).substr(-2); - bd += t; - t = ("0" + d.getUTCMinutes()).substr(-2); - bd += t; - t = ("0" + d.getUTCSeconds()).substr(-2); - bd += t; - return bd; - }; - newContent = newContent.replace("BUILDDATE", gbd()); - - status.headers = newContent; - - cb(); -}); - -gulp.task("webpack", (callback) => { - const webpackConfig = require("./webpack.config.js"); - if (status.mode === "prod") { - webpackConfig.mode = "production"; - webpackConfig.devtool = "nosources-source-map"; - } - if (status.mode === "dev") { - webpackConfig.mode = "development"; - webpackConfig.devtool = "eval-source-map"; - // webpackConfig.optimization.minimize = true; - } - webpack(webpackConfig, function (err, stats) { - if (err) { - throw new PluginError({ plugin: "webpack", message: err }); - } - - if (stats.hasErrors()) { - throw new PluginError({ - plugin: "webpack", - message: stats.toString({ - // output options - colors: true, - }), - }); - } - - console.log( - stats.toString({ - // output options - colors: true, - }) - ); - - callback(); - }); -}); - -gulp.task("buildplugin", (cb) => { - const destination = cfg.releaseFolder[status.mode]; - - gulp - .src(cfg.src.plugin) - // prepend headers - .pipe(contents.prepend(status.headers)) - // inject files - .pipe( - injectfile({ - pattern: "\\/\\*+\\s*inject:\\s*\\s*\\*+\\/", - }) - ) - // trim leading spaces - .pipe(trimlines({ leading: false })) - // rename and save - .pipe(rename(cfg.pluginName)) - .pipe(gulp.dest(destination)); - cb(); -}); - -gulp.task("buildmeta", (cb) => { - const p = path.join(cfg.releaseFolder[status.mode], cfg.metaName); - - ensureDirectoryExistence(p); - fs.writeFile(p, status.headers, (err) => { - cb(err); - }); -}); - -// ESLint -gulp.task("eslint", (cb) => { - gulp - .src([ - "**/*.js", - "!node_modules/**", - "!dist/**", - "!releases/**", - "!src/lib/**", - ]) - .pipe(eslint()) - .pipe(eslint.format()) - .pipe(eslint.failAfterError()); - cb(); -}); - -gulp.task("eslint-fix", () => { - return gulp - .src([ - "**/*.js", - "!node_modules/**", - "!dist/**", - "!releases/**", - "!src/lib/**", - ]) - .pipe(eslint({ fix: true })) - .pipe(eslint.format()) - .pipe(gulp.dest(".")) - .pipe(eslint.failAfterError()); -}); - -gulp.task("prettier", () => { - return gulp - .src([ - "**/*.js", - "!node_modules/**", - "!dist/**", - "!releases/**", - "!src/lib/**", - ]) - .pipe(prettier()) - .pipe(gulp.dest(".")); -}); - -gulp.task( - "build", - gulp.series(["buildheaders", "buildmeta", "webpack", "buildplugin"]) -); - -// eslint-fix already formats the file -gulp.task("format", gulp.series(["eslint-fix"])); -// gulp.task("format", gulp.series(["prettier"])); - -gulp.task( - "build-dev", - gulp.series(["set-mode-dev", "format", "build", "clear"]) -); - -gulp.task( - "build-prod", - gulp.series(["set-mode-prod", "format", "build", "clear"]) -); - -gulp.task("default", gulp.series(["build-dev"])); - -gulp.task("clean", () => del(["releases/*"])); diff --git a/package-lock.json b/package-lock.json index a0406b4fe..955f589ab 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,173 +1,136 @@ { "name": "wasabee-iitc", - "version": "0.18.0", + "version": "0.21.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "wasabee-iitc", - "version": "0.18.0", + "version": "0.21.1", "license": "ISC", "dependencies": { - "arc": "^0.1.1", - "color-string": "^1.5.5", - "geodesy": "^2.2.1", - "idb": "^6.0.0", - "sortablejs": "^1.12.0" + "@fortawesome/fontawesome-svg-core": "^6.1.0", + "@fortawesome/free-solid-svg-icons": "^6.1.0", + "arc": "^0.1.2", + "color-string": "^1.9.0", + "geodesy": "^2.3.0", + "idb": "^7.0.1", + "sortablejs": "^1.14.0" }, "devDependencies": { - "css-loader": "^5.2.4", + "@types/color-string": "^1.5.2", + "@types/jquery": "^3.5.14", + "@types/jqueryui": "^1.12.16", + "@types/leaflet": "^1.7.9", + "@types/spectrum": "^1.8.2", + "@typescript-eslint/eslint-plugin": "^5.15.0", + "@typescript-eslint/parser": "^5.15.0", + "css-loader": "^6.7.1", "del": "^6.0.0", - "eslint": "^7.26.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^3.4.0", - "fancy-log": "^1.3.3", - "gulp": "^4.0.2", - "gulp-eslint": "^6.0.0", - "gulp-inject-file": "^0.0.19", - "gulp-inject-string": "^1.1.1", - "gulp-prettier": "^3.0.0", - "gulp-rename": "^2.0.0", - "gulp-trimlines": "^1.0.1", - "html-loader": "^2.1.2", + "eslint": "^8.11.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-local-rules": "^1.1.0", + "eslint-plugin-prettier": "^4.0.0", + "eslint-webpack-plugin": "^3.1.1", + "fancy-log": "^2.0.0", + "html-loader": "^3.1.0", "lodash": "^4.17.21", - "plugin-error": "^1.0.1", - "prettier": "^2.3.0", - "pretty-quick": "^3.1.0", + "prettier": "^2.6.0", + "pretty-quick": "^3.1.3", "raw-loader": "^4.0.2", - "style-loader": "^2.0.0", - "to-string-loader": "^1.1.6", + "style-loader": "^3.3.1", + "through2": "^4.0.2", + "to-string-loader": "^1.2.0", + "ts-loader": "^9.2.8", + "tslib": "^2.3.1", + "typescript": "^4.6.2", "url-loader": "^4.1.1", - "webpack": "^5.37.0", - "webpack-cli": "^4.7.2" + "webpack": "^5.70.0", + "webpack-cli": "^4.9.2" } }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true - }, - "node_modules/@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/highlight/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==", + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, "engines": { - "node": ">=4" + "node": ">=10.0.0" } }, - "node_modules/@babel/highlight/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==", + "node_modules/@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=4" - } - }, - "node_modules/@babel/highlight/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/@babel/highlight/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/@babel/highlight/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": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@babel/highlight/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, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.0.tgz", + "integrity": "sha512-lFIJ5opxOKG9q88xOsuJJAdRZ+2WRldsZwUR/7MJoOMUMhF/LkHUjwWACIEPTa5Wo6uTDHvGRIX+XutdN7zYxA==", + "hasInstallScript": true, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/@babel/highlight/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, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.0.tgz", + "integrity": "sha512-racj+/EDnMZN0jcuHePOa+9kdHHOCpCAbBvVRnEi4G4DA5SWQiT/uXJ8WcfVEbLN51vPJjhukP4o+zH0cfYplg==", + "hasInstallScript": true, "dependencies": { - "has-flag": "^3.0.0" + "@fortawesome/fontawesome-common-types": "6.1.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", - "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==", - "dev": true, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.0.tgz", + "integrity": "sha512-OOr0jRHl5d41RzBS3sZh5Z3HmdPjMr43PxxKlYeLtQxFSixPf4sJFVM12/rTepB2m0rVShI0vtjHQmzOTlBaXg==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.1.0" + }, "engines": { - "node": ">=10.0.0" + "node": ">=6" } }, - "node_modules/@eslint/eslintrc": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", - "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "node_modules/@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, "dependencies": { - "ajv": "^6.12.4", + "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" + "minimatch": "^3.0.4" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -191,9 +154,9 @@ } }, "node_modules/@nodelib/fs.walk": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", - "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", @@ -203,10 +166,16 @@ "node": ">= 8" } }, + "node_modules/@types/color-string": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/color-string/-/color-string-1.5.2.tgz", + "integrity": "sha512-hAhTmfFYVdzgsKwpC9Flc6h9Do64PhKoNxy3YxE0ze+0LIh3a7TrDQAxiujmANQbDRDgGduEz+9sMS+Zd+J7hA==", + "dev": true + }, "node_modules/@types/eslint": { - "version": "7.2.13", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz", - "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==", + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", + "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", "dev": true, "dependencies": { "@types/estree": "*", @@ -214,9 +183,9 @@ } }, "node_modules/@types/eslint-scope": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", - "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "dev": true, "dependencies": { "@types/eslint": "*", @@ -224,179 +193,418 @@ } }, "node_modules/@types/estree": { - "version": "0.0.47", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz", - "integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==", + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "node_modules/@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", "dev": true }, + "node_modules/@types/jquery": { + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz", + "integrity": "sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg==", + "dev": true, + "dependencies": { + "@types/sizzle": "*" + } + }, + "node_modules/@types/jqueryui": { + "version": "1.12.16", + "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.16.tgz", + "integrity": "sha512-6huAQDpNlso9ayaUT9amBOA3kj02OCeUWs+UvDmbaJmwkHSg/HLsQOoap/D5uveN9ePwl72N45Bl+Frp5xyG1Q==", + "dev": true, + "dependencies": { + "@types/jquery": "*" + } + }, "node_modules/@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.10.tgz", + "integrity": "sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A==", "dev": true }, + "node_modules/@types/leaflet": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.9.tgz", + "integrity": "sha512-H8vPgD49HKzqM41ArHGZM70g/tfhp8W+JcPxfnF+5H/Xvp+xiP+KQOUNWU8U89fqS1Jj3cpRY/+nbnaHFzwnFA==", + "dev": true, + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", "dev": true }, "node_modules/@types/node": { - "version": "15.12.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.1.tgz", - "integrity": "sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw==", + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "dev": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "dev": true + }, + "node_modules/@types/spectrum": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@types/spectrum/-/spectrum-1.8.2.tgz", + "integrity": "sha512-PbEC/2Kipsd7Ch5IX4I2xCpp9nlQgBH+PzThWHV4knd7f0viLDY2w3hJ0QpF4/wwweUPPGoAZyb7W7HS4g+FMw==", + "dev": true, + "dependencies": { + "@types/jquery": "*", + "@types/tinycolor2": "*" + } + }, + "node_modules/@types/tinycolor2": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.3.tgz", + "integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==", "dev": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz", + "integrity": "sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.15.0", + "@typescript-eslint/type-utils": "5.15.0", + "@typescript-eslint/utils": "5.15.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.15.0.tgz", + "integrity": "sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.15.0", + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/typescript-estree": "5.15.0", + "debug": "^4.3.2" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz", + "integrity": "sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/visitor-keys": "5.15.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz", + "integrity": "sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "5.15.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.15.0.tgz", + "integrity": "sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz", + "integrity": "sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/visitor-keys": "5.15.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.15.0.tgz", + "integrity": "sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.15.0", + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/typescript-estree": "5.15.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz", + "integrity": "sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.15.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@webassemblyjs/ast": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", - "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0" + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" } }, "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", - "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", "dev": true }, "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", - "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", "dev": true }, "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", - "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", "dev": true }, "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", - "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", - "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", "dev": true }, "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", - "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" } }, "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", - "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, "dependencies": { "@xtuc/ieee754": "^1.2.0" } }, "node_modules/@webassemblyjs/leb128": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", - "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, "dependencies": { "@xtuc/long": "4.2.2" } }, "node_modules/@webassemblyjs/utf8": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", - "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", "dev": true }, "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", - "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/helper-wasm-section": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-opt": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "@webassemblyjs/wast-printer": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" } }, "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", - "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", - "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" } }, "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", - "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", - "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, "dependencies": { - "@webassemblyjs/ast": "1.11.0", + "@webassemblyjs/ast": "1.11.1", "@xtuc/long": "4.2.2" } }, "node_modules/@webpack-cli/configtest": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz", - "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "dev": true, "peerDependencies": { "webpack": "4.x.x || 5.x.x", @@ -404,9 +612,9 @@ } }, "node_modules/@webpack-cli/info": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz", - "integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "dev": true, "dependencies": { "envinfo": "^7.7.3" @@ -416,9 +624,9 @@ } }, "node_modules/@webpack-cli/serve": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.1.tgz", - "integrity": "sha512-4vSVUiOPJLmr45S8rMGy7WDvpWxfFxfP/Qx/cxZFCfvoypTYpPPL1X8VIZMe0WTA+Jr7blUxwUSEZNkjoMTgSw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "dev": true, "peerDependencies": { "webpack-cli": "4.x.x" @@ -442,9 +650,9 @@ "dev": true }, "node_modules/acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", "dev": true, "bin": { "acorn": "bin/acorn" @@ -453,10 +661,19 @@ "node": ">=0.4.0" } }, + "node_modules/acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", + "dev": true, + "peerDependencies": { + "acorn": "^8" + } + }, "node_modules/acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" @@ -500,2806 +717,2682 @@ "ajv": "^6.9.1" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "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": ">=6" + "node": ">=8" } }, - "node_modules/ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "dependencies": { - "type-fest": "^0.21.3" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-escapes/node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true, + "node_modules/arc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/arc/-/arc-0.1.2.tgz", + "integrity": "sha512-bGCkKR675zaomc6HP3dR6hc6HXXnpXrehMkayof2Ql5dZ3f2Bd8o+KfdAruSCcW471K7WFn2pDvSLG8Q0co0dw==", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.4.0" } }, - "node_modules/ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "dev": true, - "dependencies": { - "ansi-wrap": "0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, - "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", "dev": true, "engines": { "node": ">=8" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "dependencies": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true }, - "node_modules/anymatch/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/anymatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "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": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/anymatch/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "fill-range": "^7.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/anymatch/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/browserslist": { + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + } + ], "dependencies": { - "kind-of": "^6.0.0" + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/anymatch/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "bin": { + "browserslist": "cli.js" }, "engines": { - "node": ">=0.10.0" + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/anymatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/anymatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" } }, - "node_modules/anymatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/caniuse-lite": { + "version": "1.0.30001317", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz", + "integrity": "sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ==", "dev": true, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" } }, - "node_modules/anymatch/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/anymatch/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" } }, - "node_modules/append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "node_modules/clean-css": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", + "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", "dev": true, "dependencies": { - "buffer-equal": "^1.0.0" + "source-map": "~0.6.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.0" } }, - "node_modules/arc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/arc/-/arc-0.1.1.tgz", - "integrity": "sha512-gJsNNbnJW7UMU9ccjBaRh2evSyltbinzRGNPX9aiW28QxbGMtwMDC0YL6lkF73b+y+BUAOT/dUN2DMQDB1Is5w==", + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=6" } }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true, + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "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": { - "make-iterator": "^1.0.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", - "dev": true, + "node_modules/color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", "dependencies": { - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, - "node_modules/arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true, - "engines": { - "node": ">=0.10.0" + "bin": { + "color-support": "bin.js" } }, - "node_modules/array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "node_modules/colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true }, - "node_modules/array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 12" } }, - "node_modules/array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "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/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "dependencies": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-initial/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "node_modules/css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", "dev": true, "dependencies": { - "is-number": "^4.0.0" + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/array-last/node_modules/is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "dependencies": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" + "ms": "2.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "node_modules/del": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", "dev": true, + "dependencies": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, "engines": { - "node": ">=8" + "node": ">=6.0.0" } }, - "node_modules/assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, - "engines": { - "node": ">=0.10.0" + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "node_modules/electron-to-chromium": { + "version": "1.4.88", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.88.tgz", + "integrity": "sha512-oA7mzccefkvTNi9u7DXmT0LqvhnOiN2BhSrKerta7HeUC1cLoIwtbf2wL+Ah2ozh5KQd3/1njrGrwDBXx6d14Q==", + "dev": true + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true, "engines": { - "node": ">=8" + "node": ">= 4" } }, - "node_modules/async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" + "once": "^1.4.0" } }, - "node_modules/async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "node_modules/async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "node_modules/enhanced-resolve": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", + "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", "dev": true, "dependencies": { - "async-done": "^1.2.2" + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" } }, - "node_modules/atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "node_modules/envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", "dev": true, "bin": { - "atob": "bin/atob.js" + "envinfo": "dist/cli.js" }, "engines": { - "node": ">= 4.5.0" + "node": ">=4" } }, - "node_modules/bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "node_modules/es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", "dev": true, - "dependencies": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" - }, "engines": { - "node": ">= 0.10" + "node": ">=6" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true, - "dependencies": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/base/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/eslint": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", + "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", "dev": true, "dependencies": { - "is-descriptor": "^1.0.0" + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "bin": { + "eslint": "bin/eslint.js" }, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/base/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", "dev": true, - "dependencies": { - "kind-of": "^6.0.0" + "bin": { + "eslint-config-prettier": "bin/cli.js" }, - "engines": { - "node": ">=0.10.0" + "peerDependencies": { + "eslint": ">=7.0.0" } }, - "node_modules/base/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/eslint-plugin-local-rules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-local-rules/-/eslint-plugin-local-rules-1.1.0.tgz", + "integrity": "sha512-FdPyzxakUKgZkeNM3x/vvRcB6nCjTNbui5gWALhvcaH1R6aCiD37fWtdesagcyBpEe9S9XRHAJ8CJ4rUJ3K9tQ==", + "dev": true + }, + "node_modules/eslint-plugin-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", + "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "prettier-linter-helpers": "^1.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=7.28.0", + "prettier": ">=2.0.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } } }, - "node_modules/base/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0.0" } }, - "node_modules/base/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, + "dependencies": { + "eslint-visitor-keys": "^2.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=5" } }, - "node_modules/beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "node_modules/eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true, "engines": { - "node": "*" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "node_modules/eslint-webpack-plugin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", + "integrity": "sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg==", "dev": true, + "dependencies": { + "@types/eslint": "^7.28.2", + "jest-worker": "^27.3.1", + "micromatch": "^4.0.4", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0", + "webpack": "^5.0.0" } }, - "node_modules/bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", "dev": true, - "optional": true, "dependencies": { - "file-uri-to-path": "1.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "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==", + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "engines": { + "node": ">=4.0" } }, - "node_modules/braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "node_modules/espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "dependencies": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": ">=0.10.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", + "node_modules/esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "dependencies": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - }, - "bin": { - "browserslist": "cli.js" + "estraverse": "^5.1.0" }, "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "node": ">=0.10" } }, - "node_modules/buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { - "node": ">=0.4.0" + "node": ">=4.0" } }, - "node_modules/buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "node_modules/cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "dependencies": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" + "estraverse": "^5.2.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=4.0" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true, "engines": { - "node": ">=6" + "node": ">=4.0" } }, - "node_modules/camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, - "dependencies": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" + "engines": { + "node": ">=4.0" } }, - "node_modules/camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "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/caniuse-lite": { - "version": "1.0.30001235", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz", - "integrity": "sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A==", + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "engines": { + "node": ">=0.8.x" } }, - "node_modules/chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" }, "engines": { "node": ">=10" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "deprecated": "Chokidar 2 will break on node v14+. Upgrade to chokidar 3 with 15x less dependencies.", + "node_modules/fancy-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-2.0.0.tgz", + "integrity": "sha512-9CzxZbACXMUXW13tS0tI8XsGGmxWzO2DmYrGuBJOJ8k8q2K7hwfJA5qHjuPPe8wtsco33YR9wc+Rlr5wYFvhSA==", "dev": true, "dependencies": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" + "color-support": "^1.1.3" }, - "optionalDependencies": { - "fsevents": "^1.2.7" + "engines": { + "node": ">=10.13.0" } }, - "node_modules/chokidar/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" } }, - "node_modules/chokidar/node_modules/glob-parent/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "dependencies": { - "is-extglob": "^2.1.0" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 6" } }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "node_modules/fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, - "engines": { - "node": ">=6.0" + "dependencies": { + "reusify": "^1.0.4" } }, - "node_modules/class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "dependencies": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" + "flat-cache": "^3.0.4" }, "engines": { - "node": ">=0.10.0" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "dependencies": { - "source-map": "~0.6.0" + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 4.0" + "node": ">=8" } }, - "node_modules/clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "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": ">=6" + "node": ">=8" } }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "dependencies": { - "restore-cursor": "^3.1.0" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" }, "engines": { - "node": ">=8" + "node": "^10.12.0 || >=12.0.0" } }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, + "node_modules/flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", + "dev": 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/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/functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "node_modules/geodesy": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/geodesy/-/geodesy-2.3.0.tgz", + "integrity": "sha512-SZIJ8DfIzn5XD5IyNGRQBpTy0mQAn/M3uKgPBcVx4uVVpyIM7tNIJ3mL6dQn+31T/gI6TBdslqLmuQQybeZCqA==", "engines": { - "node": ">= 10" + "node": ">=8.0.0" } }, - "node_modules/cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - } - }, - "node_modules/cliui/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, + "pump": "^3.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "dependencies": { - "number-is-nan": "^1.0.0" + "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": ">=0.10.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/cliui/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "is-glob": "^4.0.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" } }, - "node_modules/cliui/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "dev": true + }, + "node_modules/globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "dependencies": { - "ansi-regex": "^2.0.0" + "type-fest": "^0.20.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, "engines": { - "node": ">=0.8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, "engines": { - "node": ">= 0.10" + "node": ">= 0.4.0" } }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "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/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/html-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-3.1.0.tgz", + "integrity": "sha512-ycMYFRiCF7YANcLDNP72kh3Po5pTcH+bROzdDwh00iVOAY/BwvpuZ1BKPziQ35Dk9D+UD84VGX1Lu/H4HpO4fw==", "dev": true, "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" + "html-minifier-terser": "^6.0.2", + "parse5": "^6.0.1" }, "engines": { - "node": ">=6" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/clone-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", "dev": true, "dependencies": { - "isobject": "^3.0.1" + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + }, + "bin": { + "html-minifier-terser": "cli.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/clone-deep/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8.12.0" } }, - "node_modules/clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "node_modules/cloneable-readable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "node_modules/idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, + "node_modules/ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">= 4" } }, - "node_modules/collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "dependencies": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "dependencies": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, "engines": { - "node": ">=7.0.0" + "node": ">=0.8.19" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" } }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, - "bin": { - "color-support": "bin.js" + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" } }, - "node_modules/colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", + "node_modules/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/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "node_modules/interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true, "engines": { - "node": ">= 6" + "node": ">= 0.10" } }, - "node_modules/component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "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/is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" }, - "node_modules/concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "node_modules/is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, - "engines": [ - "node >= 0.8" - ], "dependencies": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "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==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/copy-props": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", - "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, - "dependencies": { - "each-props": "^1.3.2", - "is-plain-object": "^5.0.0" + "engines": { + "node": ">=0.12.0" } }, - "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/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "node_modules/is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/css-loader": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.6.tgz", - "integrity": "sha512-0wyN5vXMQZu6BvjbrPdUJvkCzGEO24HC7IS7nW4llc6BBFC+zwR9CKtYGv63Puzsg10L/o12inMY5/2ByzfD6w==", + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", "dev": true, - "dependencies": { - "icss-utils": "^5.1.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^3.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.27.0 || ^5.0.0" - } - }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "bin": { - "cssesc": "bin/cssesc" - }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "dependencies": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "node_modules/dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true, + "isobject": "^3.0.1" + }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "dependencies": { - "ms": "2.1.2" - }, "engines": { - "node": ">=6.0" + "node": ">=8" }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "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/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, - "node_modules/decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", "dev": true, "engines": { - "node": ">=0.10" + "node": ">=0.10.0" } }, - "node_modules/deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "node_modules/default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "dependencies": { - "kind-of": "^5.0.2" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" } }, - "node_modules/default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">= 0.10" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "clone": "^1.0.2" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "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==", + "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/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "dependencies": { - "object-keys": "^1.0.12" + "minimist": "^1.2.5" + }, + "bin": { + "json5": "lib/cli.js" }, "engines": { - "node": ">= 0.4" + "node": ">=6" } }, - "node_modules/define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", "dev": true, - "dependencies": { - "is-descriptor": "^0.1.0" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "dependencies": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true, "engines": { - "node": ">= 0.9" + "node": ">= 0.8.0" } }, - "node_modules/detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "node_modules/loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=6.11.5" } }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "node_modules/loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", "dev": true, "dependencies": { - "path-type": "^4.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" }, "engines": { - "node": ">=8" + "node": ">=8.9.0" } }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "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": { - "esutils": "^2.0.2" + "p-locate": "^4.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=8" } }, - "node_modules/dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "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/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "dev": true, "dependencies": { - "no-case": "^3.0.4", "tslib": "^2.0.3" } }, - "node_modules/duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "node_modules/duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "dependencies": { - "readable-stream": "~1.1.9" + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" } }, - "node_modules/duplexer2/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "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/duplexer2/node_modules/readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "engines": { + "node": ">= 8" } }, - "node_modules/duplexer2/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/duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "dependencies": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" } }, - "node_modules/each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, - "dependencies": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" + "engines": { + "node": ">= 0.6" } }, - "node_modules/each-props/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "dependencies": { - "isobject": "^3.0.1" + "mime-db": "1.52.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/electron-to-chromium": { - "version": "1.3.749", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz", - "integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A==", - "dev": true - }, - "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/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true, "engines": { - "node": ">= 4" + "node": ">=6" } }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "once": "^1.4.0" + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" } }, - "node_modules/enhanced-resolve": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, "engines": { - "node": ">=10.13.0" + "node": ">=4" } }, - "node_modules/enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "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/multimatch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", "dev": true, "dependencies": { - "ansi-colors": "^4.1.1" + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" }, "engines": { - "node": ">=8.6" + "node": ">=8" } }, - "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true, "bin": { - "envinfo": "dist/cli.js" + "nanoid": "bin/nanoid.cjs" }, "engines": { - "node": ">=4" - } - }, - "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": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/error-ex/node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "node_modules/es-module-lexer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", - "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==", + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "node_modules/es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "node_modules/node-releases": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, - "dependencies": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "dependencies": { - "d": "^1.0.1", - "ext": "^1.1.2" + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" } }, - "node_modules/es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "dependencies": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" + "wrappy": "1" } }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, "engines": { "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz", - "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==", + "node_modules/optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", "dev": true, "dependencies": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" + "node": ">= 0.8.0" } }, - "node_modules/eslint-plugin-prettier": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", - "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", + "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": { - "prettier-linter-helpers": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": ">=6.0.0" - }, - "peerDependencies": { - "eslint": ">=5.0.0", - "prettier": ">=1.13.0" + "node": ">=6" }, - "peerDependenciesMeta": { - "eslint-config-prettier": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "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": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=8.0.0" + "node": ">=8" } }, - "node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "dependencies": { - "eslint-visitor-keys": "^1.1.0" + "aggregate-error": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/mysticatea" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "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": ">=4" + "node": ">=6" } }, - "node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "node_modules/param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, "dependencies": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" + "callsites": "^3.0.0" }, "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } + "node_modules/parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", + "dev": true }, - "node_modules/esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "node_modules/pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dev": true, "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "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": ">=4.0" + "node": ">=8" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "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, - "dependencies": { - "estraverse": "^5.2.0" - }, "engines": { - "node": ">=4.0" + "node": ">=0.10.0" } }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "engines": { - "node": ">=4.0" + "node": ">=8" } }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } + "node_modules/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/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/event-stream": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz", - "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", - "dev": true, - "dependencies": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } + "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/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, "engines": { - "node": ">=0.8.x" + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" + "find-up": "^4.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" + "node": ">=8" } }, - "node_modules/expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "node_modules/postcss": { + "version": "8.4.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", + "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + } + ], "dependencies": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" + "nanoid": "^3.3.1", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >=14" } }, - "node_modules/expand-brackets/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", "dev": true, - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/expand-brackets/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", "dev": true, "dependencies": { - "homedir-polyfill": "^1.0.1" + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", "dev": true, "dependencies": { - "type": "^2.0.0" + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/ext/node_modules/type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", - "dev": true - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "node_modules/extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, "dependencies": { - "is-extendable": "^0.1.0" + "icss-utils": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "node_modules/postcss-selector-parser": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { "node": ">=4" } }, - "node_modules/extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "dependencies": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/extglob/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "node_modules/prettier": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz", + "integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==", "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" + "bin": { + "prettier": "bin-prettier.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/extglob/node_modules/is-accessor-descriptor": { + "node_modules/prettier-linter-helpers": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "fast-diff": "^1.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/extglob/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/pretty-quick": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.3.tgz", + "integrity": "sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA==", "dev": true, "dependencies": { - "kind-of": "^6.0.0" + "chalk": "^3.0.0", + "execa": "^4.0.0", + "find-up": "^4.1.0", + "ignore": "^5.1.4", + "mri": "^1.1.5", + "multimatch": "^4.0.0" + }, + "bin": { + "pretty-quick": "bin/pretty-quick.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10.13" + }, + "peerDependencies": { + "prettier": ">=2.0.0" } }, - "node_modules/extglob/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/pretty-quick/node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", "dev": true, "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/extglob/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "dependencies": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true, - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", + "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": { - "reusify": "^1.0.4" + "safe-buffer": "^5.1.0" } }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "node_modules/raw-loader": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", + "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", "dev": true, "dependencies": { - "escape-string-regexp": "^1.0.5" + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" }, "engines": { - "node": ">=8" + "node": ">= 10.13.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/figures/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" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" } }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "dependencies": { - "flat-cache": "^3.0.4" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">= 6" } }, - "node_modules/file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "node_modules/fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "dependencies": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" + "resolve": "^1.9.0" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, - "node_modules/find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "dev": true - }, - "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==", + "node_modules/regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" } }, - "node_modules/findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "node_modules/relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, "engines": { "node": ">= 0.10" } }, - "node_modules/findup-sync/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "node_modules/resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/findup-sync/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "resolve-from": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/findup-sync/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/findup-sync/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/findup-sync/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, "engines": { + "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/findup-sync/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "dependencies": { - "is-plain-object": "^2.0.4" + "glob": "^7.1.3" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/findup-sync/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "queue-microtask": "^1.2.2" } }, - "node_modules/findup-sync/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] }, - "node_modules/findup-sync/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "node_modules/schema-utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "dev": true, + "node_modules/semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, "dependencies": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">= 0.10" + "node": ">=10" } }, - "node_modules/fined/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", "dev": true, "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "randombytes": "^2.1.0" } }, - "node_modules/first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "dependencies": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - }, "engines": { - "node": "^10.12.0 || >=12.0.0" + "node": ">=8" } }, - "node_modules/flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "node_modules/flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, + "node_modules/simple-swizzle": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "dependencies": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" + "is-arrayish": "^0.3.1" } }, - "node_modules/for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "node_modules/sortablejs": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz", + "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==" + }, + "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, - "dependencies": { - "for-in": "^1.0.1" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true, - "dependencies": { - "map-cache": "^0.2.2" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, - "node_modules/fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "dependencies": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "node_modules/fs-mkdirp-stream/node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" + "safe-buffer": "~5.2.0" } }, - "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": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "deprecated": "fsevents 1 will break on node v14+ and could be using insecure binaries. Upgrade to fsevents 2.", + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], "dependencies": { - "bindings": "^1.5.0", - "nan": "^2.12.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">= 4.0" + "node": ">=8" } }, - "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/functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "node_modules/gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", "dev": true, - "dependencies": { - "globule": "~0.1.0" - }, "engines": { - "node": ">= 0.8.0" + "node": ">=6" } }, - "node_modules/geodesy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/geodesy/-/geodesy-2.2.1.tgz", - "integrity": "sha512-jhUYGHFZz5hZ/f+lBZiwFNWRhOUV2iiVxyLOT8FixIUJHEDVMgcB1SWQs50P51uTVcVjsngjPAUUNWcWdWiPog==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, "engines": { - "node": ">=8.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "node_modules/style-loader": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" + "engines": { + "node": ">= 12.13.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" } }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "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": { - "pump": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=6" } }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "node_modules/terser": { + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", + "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", "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" + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" }, - "engines": { - "node": "*" + "bin": { + "terser": "bin/terser" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=10" } }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", "dev": true, "dependencies": { - "is-glob": "^4.0.1" + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" }, "engines": { - "node": ">= 6" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } } }, - "node_modules/glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "node_modules/terser/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/terser/node_modules/source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true, - "dependencies": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" - }, "engines": { - "node": ">= 0.10" + "node": ">= 8" } }, - "node_modules/glob-stream/node_modules/glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", "dev": true, "dependencies": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" + "readable-stream": "3" } }, - "node_modules/glob-stream/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "dependencies": { - "is-extglob": "^2.1.0" + "is-number": "^7.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8.0" } }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/glob-watcher": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", - "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", + "node_modules/to-string-loader": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.2.0.tgz", + "integrity": "sha512-KsWUL8FccgBW9FPFm4vYoQbOOcO5m6hKOGYoXjbseD9/4Ft+ravXN5jolQ9kTKYcK4zPt1j+khx97GPGnVoi6A==", "dev": true, "dependencies": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "normalize-path": "^3.0.0", - "object.defaults": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" + "loader-utils": "^1.0.0" } }, - "node_modules/glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", + "node_modules/to-string-loader/node_modules/json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", "dev": true, "dependencies": { - "find-index": "^0.1.1" + "minimist": "^1.2.0" }, - "engines": { - "node": ">= 0.10" + "bin": { + "json5": "lib/cli.js" } }, - "node_modules/global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "node_modules/to-string-loader/node_modules/loader-utils": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", + "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", "dev": true, "dependencies": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=4.0.0" } }, - "node_modules/global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "node_modules/ts-loader": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.8.tgz", + "integrity": "sha512-gxSak7IHUuRtwKf3FIPSW1VpZcqF9+MBrHOvBp9cjHh+525SjtCIJKVGjRKIAfxBwDGDGCFF00rTfzB1quxdSw==", "dev": true, "dependencies": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" }, "engines": { - "node": ">=0.10.0" + "node": ">=12.0.0" + }, + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" } }, - "node_modules/global-prefix/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "node_modules/tslib": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", "dev": true, "dependencies": { - "isexe": "^2.0.0" + "tslib": "^1.8.1" }, - "bin": { - "which": "bin/which" + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" } }, - "node_modules/globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", + "node_modules/tsutils/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, "dependencies": { - "type-fest": "^0.20.2" + "prelude-ls": "^1.2.1" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.8.0" } }, - "node_modules/globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", + "node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, "engines": { "node": ">=10" }, @@ -3307,13487 +3400,2547 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "node_modules/typescript": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", + "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, "engines": { - "node": ">= 4" + "node": ">=4.2.0" } }, - "node_modules/globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "dependencies": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" - }, - "engines": { - "node": ">= 0.8.0" + "punycode": "^2.1.0" } }, - "node_modules/globule/node_modules/glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "node_modules/url-loader": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", + "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", "dev": true, "dependencies": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" + "loader-utils": "^2.0.0", + "mime-types": "^2.1.27", + "schema-utils": "^3.0.0" }, "engines": { - "node": "*" - } - }, - "node_modules/globule/node_modules/graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", - "dev": true, - "engines": { - "node": ">=0.4.0" + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "file-loader": "*", + "webpack": "^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "file-loader": { + "optional": true + } } }, - "node_modules/globule/node_modules/inherits": { + "node_modules/util-deprecate": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", "dev": true }, - "node_modules/globule/node_modules/lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true, - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/globule/node_modules/lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "node_modules/globule/node_modules/minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "node_modules/watchpack": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "dev": true, "dependencies": { - "lru-cache": "2", - "sigmund": "~1.0.0" + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" }, "engines": { - "node": "*" + "node": ">=10.13.0" } }, - "node_modules/glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", - "dev": true, - "dependencies": { - "sparkles": "^1.0.0" + "node_modules/webpack": { + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.9.2", + "es-module-lexer": "^0.9.0", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.1.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } } }, - "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "node_modules/gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "node_modules/webpack-cli": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", + "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", "dev": true, "dependencies": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" + "@discoveryjs/json-ext": "^0.5.0", + "@webpack-cli/configtest": "^1.1.1", + "@webpack-cli/info": "^1.4.1", + "@webpack-cli/serve": "^1.6.1", + "colorette": "^2.0.14", + "commander": "^7.0.0", + "execa": "^5.0.0", + "fastest-levenshtein": "^1.0.12", + "import-local": "^3.0.2", + "interpret": "^2.2.0", + "rechoir": "^0.7.0", + "webpack-merge": "^5.7.3" }, "bin": { - "gulp": "bin/gulp.js" + "webpack-cli": "bin/cli.js" }, "engines": { - "node": ">= 0.10" + "node": ">=10.13.0" + }, + "peerDependencies": { + "webpack": "4.x.x || 5.x.x" + }, + "peerDependenciesMeta": { + "@webpack-cli/generators": { + "optional": true + }, + "@webpack-cli/migrate": { + "optional": true + }, + "webpack-bundle-analyzer": { + "optional": true + }, + "webpack-dev-server": { + "optional": true + } } }, - "node_modules/gulp-cli": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", - "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", + "node_modules/webpack-cli/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.4.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.2.0", - "yargs": "^7.1.0" - }, - "bin": { - "gulp": "bin/gulp.js" - }, "engines": { - "node": ">= 0.10" + "node": ">= 10" } }, - "node_modules/gulp-cli/node_modules/ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "node_modules/webpack-cli/node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", "dev": true, "dependencies": { - "ansi-wrap": "^0.1.0" + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, - "node_modules/gulp-eslint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", - "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", + "node_modules/webpack-cli/node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true, - "dependencies": { - "eslint": "^6.0.0", - "fancy-log": "^1.3.2", - "plugin-error": "^1.0.1" + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/gulp-eslint/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "node_modules/webpack-cli/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10.17.0" } }, - "node_modules/gulp-eslint/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==", + "node_modules/webpack-merge": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", + "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", "dev": true, "dependencies": { - "color-convert": "^1.9.0" + "clone-deep": "^4.0.1", + "wildcard": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=10.0.0" } }, - "node_modules/gulp-eslint/node_modules/astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", "dev": true, "engines": { - "node": ">=4" + "node": ">=10.13.0" } }, - "node_modules/gulp-eslint/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==", + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "isexe": "^2.0.0" }, - "engines": { - "node": ">=4" - } - }, - "node_modules/gulp-eslint/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" + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" } }, - "node_modules/gulp-eslint/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "node_modules/wildcard": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", + "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", "dev": true }, - "node_modules/gulp-eslint/node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "node_modules/word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, "engines": { - "node": ">=4.8" + "node": ">=0.10.0" } }, - "node_modules/gulp-eslint/node_modules/cross-spawn/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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true }, - "node_modules/gulp-eslint/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==", + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + }, + "dependencies": { + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", "dev": true }, - "node_modules/gulp-eslint/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=", + "@eslint/eslintrc": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.2.1.tgz", + "integrity": "sha512-bxvbYnBPN1Gibwyp6NrpnFzA3YtRL3BBAyEAFVIpNTm2Rn4Vy87GA5M4aSn3InRrlsbX5N0GW7XIx+U4SAEKdQ==", "dev": true, - "engines": { - "node": ">=0.8.0" + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.3.1", + "globals": "^13.9.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" } }, - "node_modules/gulp-eslint/node_modules/eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^8.10.0 || ^10.13.0 || >=11.10.1" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "@fortawesome/fontawesome-common-types": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.1.0.tgz", + "integrity": "sha512-lFIJ5opxOKG9q88xOsuJJAdRZ+2WRldsZwUR/7MJoOMUMhF/LkHUjwWACIEPTa5Wo6uTDHvGRIX+XutdN7zYxA==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.1.0.tgz", + "integrity": "sha512-racj+/EDnMZN0jcuHePOa+9kdHHOCpCAbBvVRnEi4G4DA5SWQiT/uXJ8WcfVEbLN51vPJjhukP4o+zH0cfYplg==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.1.0" } }, - "node_modules/gulp-eslint/node_modules/eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", + "@fortawesome/free-solid-svg-icons": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.1.0.tgz", + "integrity": "sha512-OOr0jRHl5d41RzBS3sZh5Z3HmdPjMr43PxxKlYeLtQxFSixPf4sJFVM12/rTepB2m0rVShI0vtjHQmzOTlBaXg==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.1.0" + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.5", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.5.tgz", + "integrity": "sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==", "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" } }, - "node_modules/gulp-eslint/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, - "engines": { - "node": ">=4" + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" } }, - "node_modules/gulp-eslint/node_modules/espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, - "dependencies": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6.0.0" + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" } }, - "node_modules/gulp-eslint/node_modules/file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", + "@types/color-string": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@types/color-string/-/color-string-1.5.2.tgz", + "integrity": "sha512-hAhTmfFYVdzgsKwpC9Flc6h9Do64PhKoNxy3YxE0ze+0LIh3a7TrDQAxiujmANQbDRDgGduEz+9sMS+Zd+J7hA==", + "dev": true + }, + "@types/eslint": { + "version": "7.29.0", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz", + "integrity": "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng==", "dev": true, - "dependencies": { - "flat-cache": "^2.0.1" - }, - "engines": { - "node": ">=4" + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" } }, - "node_modules/gulp-eslint/node_modules/flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", + "@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", "dev": true, - "dependencies": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - }, - "engines": { - "node": ">=4" + "requires": { + "@types/eslint": "*", + "@types/estree": "*" } }, - "node_modules/gulp-eslint/node_modules/flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", + "@types/estree": { + "version": "0.0.51", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", + "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", + "dev": true + }, + "@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==", "dev": true }, - "node_modules/gulp-eslint/node_modules/globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", + "@types/jquery": { + "version": "3.5.14", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.14.tgz", + "integrity": "sha512-X1gtMRMbziVQkErhTQmSe2jFwwENA/Zr+PprCkF63vFq+Yt5PZ4AlKqgmeNlwgn7dhsXEK888eIW2520EpC+xg==", "dev": true, - "dependencies": { - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "requires": { + "@types/sizzle": "*" } }, - "node_modules/gulp-eslint/node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "@types/jqueryui": { + "version": "1.12.16", + "resolved": "https://registry.npmjs.org/@types/jqueryui/-/jqueryui-1.12.16.tgz", + "integrity": "sha512-6huAQDpNlso9ayaUT9amBOA3kj02OCeUWs+UvDmbaJmwkHSg/HLsQOoap/D5uveN9ePwl72N45Bl+Frp5xyG1Q==", "dev": true, - "engines": { - "node": ">=4" + "requires": { + "@types/jquery": "*" } }, - "node_modules/gulp-eslint/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=", + "@types/json-schema": { + "version": "7.0.10", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.10.tgz", + "integrity": "sha512-BLO9bBq59vW3fxCpD4o0N4U+DXsvwvIcl+jofw0frQo/GrBFC+/jRZj1E7kgp6dvTyNmA4y6JCV5Id/r3mNP5A==", + "dev": true + }, + "@types/leaflet": { + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/@types/leaflet/-/leaflet-1.7.9.tgz", + "integrity": "sha512-H8vPgD49HKzqM41ArHGZM70g/tfhp8W+JcPxfnF+5H/Xvp+xiP+KQOUNWU8U89fqS1Jj3cpRY/+nbnaHFzwnFA==", "dev": true, - "engines": { - "node": ">=4" + "requires": { + "@types/geojson": "*" } }, - "node_modules/gulp-eslint/node_modules/levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/node": { + "version": "17.0.21", + "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz", + "integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==", + "dev": true + }, + "@types/sizzle": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.3.tgz", + "integrity": "sha512-JYM8x9EGF163bEyhdJBpR2QX1R5naCJHC8ucJylJ3w9/CVBaskdQ8WqBf8MmQrd1kRvp/a4TS8HJ+bxzR7ZJYQ==", + "dev": true + }, + "@types/spectrum": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/@types/spectrum/-/spectrum-1.8.2.tgz", + "integrity": "sha512-PbEC/2Kipsd7Ch5IX4I2xCpp9nlQgBH+PzThWHV4knd7f0viLDY2w3hJ0QpF4/wwweUPPGoAZyb7W7HS4g+FMw==", "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - }, - "engines": { - "node": ">= 0.8.0" + "requires": { + "@types/jquery": "*", + "@types/tinycolor2": "*" } }, - "node_modules/gulp-eslint/node_modules/optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", + "@types/tinycolor2": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.3.tgz", + "integrity": "sha512-Kf1w9NE5HEgGxCRyIcRXR/ZYtDv0V8FVPtYHwLxl0O+maGX0erE77pQlD0gpP+/KByMZ87mOA79SjifhSB3PjQ==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.15.0.tgz", + "integrity": "sha512-u6Db5JfF0Esn3tiAKELvoU5TpXVSkOpZ78cEGn/wXtT2RVqs2vkt4ge6N8cRCyw7YVKhmmLDbwI2pg92mlv7cA==", "dev": true, - "dependencies": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - }, - "engines": { - "node": ">= 0.8.0" + "requires": { + "@typescript-eslint/scope-manager": "5.15.0", + "@typescript-eslint/type-utils": "5.15.0", + "@typescript-eslint/utils": "5.15.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" } }, - "node_modules/gulp-eslint/node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "@typescript-eslint/parser": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.15.0.tgz", + "integrity": "sha512-NGAYP/+RDM2sVfmKiKOCgJYPstAO40vPAgACoWPO/+yoYKSgAXIFaBKsV8P0Cc7fwKgvj27SjRNX4L7f4/jCKQ==", "dev": true, - "engines": { - "node": ">=4" + "requires": { + "@typescript-eslint/scope-manager": "5.15.0", + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/typescript-estree": "5.15.0", + "debug": "^4.3.2" } }, - "node_modules/gulp-eslint/node_modules/prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "@typescript-eslint/scope-manager": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.15.0.tgz", + "integrity": "sha512-EFiZcSKrHh4kWk0pZaa+YNJosvKE50EnmN4IfgjkA3bTHElPtYcd2U37QQkNTqwMCS7LXeDeZzEqnsOH8chjSg==", "dev": true, - "engines": { - "node": ">= 0.8.0" + "requires": { + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/visitor-keys": "5.15.0" } }, - "node_modules/gulp-eslint/node_modules/regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", + "@typescript-eslint/type-utils": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.15.0.tgz", + "integrity": "sha512-KGeDoEQ7gHieLydujGEFLyLofipe9PIzfvA/41urz4hv+xVxPEbmMQonKSynZ0Ks2xDhJQ4VYjB3DnRiywvKDA==", "dev": true, - "engines": { - "node": ">=6.5.0" + "requires": { + "@typescript-eslint/utils": "5.15.0", + "debug": "^4.3.2", + "tsutils": "^3.21.0" } }, - "node_modules/gulp-eslint/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "@typescript-eslint/types": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.15.0.tgz", + "integrity": "sha512-yEiTN4MDy23vvsIksrShjNwQl2vl6kJeG9YkVJXjXZnkJElzVK8nfPsWKYxcsGWG8GhurYXP4/KGj3aZAxbeOA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.15.0.tgz", + "integrity": "sha512-Hb0e3dGc35b75xLzixM3cSbG1sSbrTBQDfIScqdyvrfJZVEi4XWAT+UL/HMxEdrJNB8Yk28SKxPLtAhfCbBInA==", "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "requires": { + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/visitor-keys": "5.15.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" } }, - "node_modules/gulp-eslint/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "@typescript-eslint/utils": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.15.0.tgz", + "integrity": "sha512-081rWu2IPKOgTOhHUk/QfxuFog8m4wxW43sXNOMSCdh578tGJ1PAaWPsj42LOa7pguh173tNlMigsbrHvh/mtA==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.15.0", + "@typescript-eslint/types": "5.15.0", + "@typescript-eslint/typescript-estree": "5.15.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" } }, - "node_modules/gulp-eslint/node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "@typescript-eslint/visitor-keys": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.15.0.tgz", + "integrity": "sha512-+vX5FKtgvyHbmIJdxMJ2jKm9z2BIlXJiuewI8dsDYMp5LzPUcuTT78Ya5iwvQg3VqSVdmxyM8Anj1Jeq7733ZQ==", "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "@typescript-eslint/types": "5.15.0", + "eslint-visitor-keys": "^3.0.0" } }, - "node_modules/gulp-eslint/node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "@webassemblyjs/ast": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", + "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", "dev": true, - "engines": { - "node": ">=0.10.0" + "requires": { + "@webassemblyjs/helper-numbers": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1" } }, - "node_modules/gulp-eslint/node_modules/slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", + "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", + "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", + "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", + "dev": true + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", + "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", "dev": true, - "dependencies": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - }, - "engines": { - "node": ">=6" + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@xtuc/long": "4.2.2" } }, - "node_modules/gulp-eslint/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==", + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", + "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", + "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, - "engines": { - "node": ">=6" + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1" } }, - "node_modules/gulp-eslint/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==", + "@webassemblyjs/ieee754": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", + "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, - "engines": { - "node": ">=6" + "requires": { + "@xtuc/ieee754": "^1.2.0" } }, - "node_modules/gulp-eslint/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==", + "@webassemblyjs/leb128": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", + "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" + "requires": { + "@xtuc/long": "4.2.2" } }, - "node_modules/gulp-eslint/node_modules/table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "dependencies": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - }, - "engines": { - "node": ">=6.0.0" - } + "@webassemblyjs/utf8": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", + "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", + "dev": true }, - "node_modules/gulp-eslint/node_modules/type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "@webassemblyjs/wasm-edit": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", + "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", "dev": true, - "dependencies": { - "prelude-ls": "~1.1.2" - }, - "engines": { - "node": ">= 0.8.0" + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/helper-wasm-section": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-opt": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "@webassemblyjs/wast-printer": "1.11.1" } }, - "node_modules/gulp-eslint/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "@webassemblyjs/wasm-gen": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", + "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", "dev": true, - "engines": { - "node": ">=8" + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, - "node_modules/gulp-eslint/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "@webassemblyjs/wasm-opt": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", + "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-buffer": "1.11.1", + "@webassemblyjs/wasm-gen": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1" } }, - "node_modules/gulp-inject-file": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/gulp-inject-file/-/gulp-inject-file-0.0.19.tgz", - "integrity": "sha512-z4DOiGHf0kpJHs3Ayh/WiCP+1LC3uQXlcqDXt+NCU/JCXQhySORCHicTuBYTZ9ZJCrcJ8DW3NlfNjxBMaR8W0w==", + "@webassemblyjs/wasm-parser": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", + "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", "dev": true, - "dependencies": { - "event-stream": "^3.3.4", - "gulp": "^3.9.1", - "gulp-util": "^3.0.8", - "lodash": "^2.4.2" + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/helper-api-error": "1.11.1", + "@webassemblyjs/helper-wasm-bytecode": "1.11.1", + "@webassemblyjs/ieee754": "1.11.1", + "@webassemblyjs/leb128": "1.11.1", + "@webassemblyjs/utf8": "1.11.1" } }, - "node_modules/gulp-inject-file/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "@webassemblyjs/wast-printer": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", + "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", "dev": true, - "engines": { - "node": ">=0.10.0" + "requires": { + "@webassemblyjs/ast": "1.11.1", + "@xtuc/long": "4.2.2" } }, - "node_modules/gulp-inject-file/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "@webpack-cli/configtest": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", + "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "requires": {} }, - "node_modules/gulp-inject-file/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "@webpack-cli/info": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", + "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "envinfo": "^7.7.3" } }, - "node_modules/gulp-inject-file/node_modules/clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", + "@webpack-cli/serve": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", + "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", "dev": true, - "engines": { - "node": "*" - } + "requires": {} }, - "node_modules/gulp-inject-file/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true }, - "node_modules/gulp-inject-file/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" - } + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true }, - "node_modules/gulp-inject-file/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true }, - "node_modules/gulp-inject-file/node_modules/findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "acorn-import-assertions": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", + "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } + "requires": {} }, - "node_modules/gulp-inject-file/node_modules/glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", "dev": true, - "dependencies": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": "*" - } + "requires": {} }, - "node_modules/gulp-inject-file/node_modules/glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", "dev": true, - "dependencies": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" - }, - "engines": { - "node": ">= 0.9" + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" } }, - "node_modules/gulp-inject-file/node_modules/glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, - "dependencies": { - "gaze": "^0.5.1" - }, - "engines": { - "node": ">= 0.9" + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "node_modules/gulp-inject-file/node_modules/graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", "dev": true, - "dependencies": { - "natives": "^1.1.3" - }, - "engines": { - "node": ">=0.4.0" - } + "requires": {} }, - "node_modules/gulp-inject-file/node_modules/gulp": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", - "dev": true, - "dependencies": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" - }, - "bin": { - "gulp": "bin/gulp.js" - }, - "engines": { - "node": ">= 0.9" - } + "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 }, - "node_modules/gulp-inject-file/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "color-convert": "^2.0.1" } }, - "node_modules/gulp-inject-file/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + "arc": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/arc/-/arc-0.1.2.tgz", + "integrity": "sha512-bGCkKR675zaomc6HP3dR6hc6HXXnpXrehMkayof2Ql5dZ3f2Bd8o+KfdAruSCcW471K7WFn2pDvSLG8Q0co0dw==" + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true }, - "node_modules/gulp-inject-file/node_modules/is-descriptor": { + "balanced-match": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "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, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/gulp-inject-file/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "fill-range": "^7.0.1" } }, - "node_modules/gulp-inject-file/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "browserslist": { + "version": "4.20.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.2.tgz", + "integrity": "sha512-CQOBCqp/9pDvDbx3xfMi+86pr4KXIf2FDkTTdeuYw8OxS9t898LA1Khq57gtufFILXpfgsSx5woNgsBgvGjpsA==", "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "caniuse-lite": "^1.0.30001317", + "electron-to-chromium": "^1.4.84", + "escalade": "^3.1.1", + "node-releases": "^2.0.2", + "picocolors": "^1.0.0" } }, - "node_modules/gulp-inject-file/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camel-case": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", + "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "requires": { + "pascal-case": "^3.1.2", + "tslib": "^2.0.3" } }, - "node_modules/gulp-inject-file/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "caniuse-lite": { + "version": "1.0.30001317", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001317.tgz", + "integrity": "sha512-xIZLh8gBm4dqNX0gkzrBeyI86J2eCjWzYAs40q88smG844YIrN4tVQl/RhquHvKEKImWWFIVh1Lxe5n1G/N+GQ==", "dev": true }, - "node_modules/gulp-inject-file/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-inject-file/node_modules/liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, - "dependencies": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">= 0.8" + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "node_modules/gulp-inject-file/node_modules/lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true, - "engines": [ - "node", - "rhino" - ] - }, - "node_modules/gulp-inject-file/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "dev": true }, - "node_modules/gulp-inject-file/node_modules/minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "clean-css": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-5.2.4.tgz", + "integrity": "sha512-nKseG8wCzEuji/4yrgM/5cthL9oTDc5UOQyFMvW/Q53oP6gLH690o1NbuTh6Y18nujr7BxlsFuS7gXLnLzKJGg==", "dev": true, - "dependencies": { - "brace-expansion": "^1.0.0" - }, - "engines": { - "node": "*" + "requires": { + "source-map": "~0.6.0" } }, - "node_modules/gulp-inject-file/node_modules/ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", "dev": true }, - "node_modules/gulp-inject-file/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=", + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" } }, - "node_modules/gulp-inject-file/node_modules/semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", + "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, - "bin": { - "semver": "bin/semver" + "requires": { + "color-name": "~1.1.4" } }, - "node_modules/gulp-inject-file/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 + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "node_modules/gulp-inject-file/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "color-string": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.0.tgz", + "integrity": "sha512-9Mrz2AQLefkH1UvASKj6v6hj/7eWgjnT/cVsR8CumieLoT+g900exWeNogqtweI8dxloXN9BDQTYro1oWu/5CQ==", + "requires": { + "color-name": "^1.0.0", + "simple-swizzle": "^0.2.2" } }, - "node_modules/gulp-inject-file/node_modules/strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "dependencies": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" - }, - "bin": { - "strip-bom": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true }, - "node_modules/gulp-inject-file/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } + "colorette": { + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", + "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", + "dev": true }, - "node_modules/gulp-inject-file/node_modules/through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "dependencies": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } + "commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true }, - "node_modules/gulp-inject-file/node_modules/unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", + "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/gulp-inject-file/node_modules/v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, - "dependencies": { - "user-home": "^1.1.1" - }, - "engines": { - "node": ">= 0.10.0" + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, - "node_modules/gulp-inject-file/node_modules/vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", + "css-loader": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.7.1.tgz", + "integrity": "sha512-yB5CNFa14MbPJcomwNh3wLThtkZgcNyI2bNMRt8iE5Z8Vwl7f8vQXFAzn2HDOJvtDq2NTZBUGMSUNNyrv3/+cw==", "dev": true, - "dependencies": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - }, - "engines": { - "node": ">= 0.9" + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.7", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.0", + "postcss-modules-scope": "^3.0.0", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.3.5" } }, - "node_modules/gulp-inject-file/node_modules/vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", - "dev": true, - "dependencies": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" - }, - "engines": { - "node": ">= 0.10" - } + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true }, - "node_modules/gulp-inject-string": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/gulp-inject-string/-/gulp-inject-string-1.1.2.tgz", - "integrity": "sha512-+jhEyG+cEqvMdJgxD+7WkO/hDXz7AQl5aP9Rp+f23QaUDi5xme2YNvUjxCTlEySUapn27Pskcq9o8MsBBdvt4g==", + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, - "dependencies": { - "event-stream": "3.3.4", - "plugin-error": "^1.0.1" + "requires": { + "ms": "2.1.2" } }, - "node_modules/gulp-inject-string/node_modules/event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, - "node_modules/gulp-inject-string/node_modules/map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "node_modules/gulp-inject-string/node_modules/split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "del": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", + "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" + "requires": { + "globby": "^11.0.1", + "graceful-fs": "^4.2.4", + "is-glob": "^4.0.1", + "is-path-cwd": "^2.2.0", + "is-path-inside": "^3.0.2", + "p-map": "^4.0.0", + "rimraf": "^3.0.2", + "slash": "^3.0.0" } }, - "node_modules/gulp-inject-string/node_modules/stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", "dev": true, - "dependencies": { - "duplexer": "~0.1.1" + "requires": { + "path-type": "^4.0.0" } }, - "node_modules/gulp-prettier": { + "doctrine": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-prettier/-/gulp-prettier-3.0.0.tgz", - "integrity": "sha512-vZFyC1F+7EjuI2WDUOcbPt9o3ZjdqjFMjr8a9Yk2K8EmNhP1w6X01QAkv5Ym3dsHCBsBA4AEFcYds2vOTSgx0A==", - "dev": true, - "dependencies": { - "plugin-error": "^1.0.1", - "prettier": "^2.0.0", - "through2": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/gulp-rename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", - "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", "dev": true, - "engines": { - "node": ">=4" + "requires": { + "esutils": "^2.0.2" } }, - "node_modules/gulp-trimlines": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gulp-trimlines/-/gulp-trimlines-1.0.1.tgz", - "integrity": "sha1-exeRa4UMoPBa9BkN0k6aweJunyY=", + "dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", "dev": true, - "dependencies": { - "through2": "^0.6.3" + "requires": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "node_modules/gulp-trimlines/node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "electron-to-chromium": { + "version": "1.4.88", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.88.tgz", + "integrity": "sha512-oA7mzccefkvTNi9u7DXmT0LqvhnOiN2BhSrKerta7HeUC1cLoIwtbf2wL+Ah2ozh5KQd3/1njrGrwDBXx6d14Q==", "dev": true }, - "node_modules/gulp-trimlines/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/gulp-trimlines/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=", + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", "dev": true }, - "node_modules/gulp-trimlines/node_modules/through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "dependencies": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "node_modules/gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5", + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", "dev": true, - "dependencies": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "engines": { - "node": ">=0.10" + "requires": { + "once": "^1.4.0" } }, - "node_modules/gulp-util/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "enhanced-resolve": { + "version": "5.9.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.2.tgz", + "integrity": "sha512-GIm3fQfwLJ8YZx2smuHpBKkXC1yOk+OBEmKckVyL0i/ea8mqDEykK3ld5dgH1QYPNyT/lIllxV2LULnxCHaHkA==", "dev": true, - "engines": { - "node": ">=0.10.0" + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" } }, - "node_modules/gulp-util/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } + "envinfo": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", + "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", + "dev": true }, - "node_modules/gulp-util/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + "es-module-lexer": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", + "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", + "dev": true }, - "node_modules/gulp-util/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" - } + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true }, - "node_modules/gulp-util/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/gulp-util/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/gulp-util/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/gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "dependencies": { - "glogg": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "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-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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/has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "dependencies": { - "sparkles": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "dependencies": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/has-values/node_modules/kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "dependencies": { - "parse-passwd": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/html-loader": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-2.1.2.tgz", - "integrity": "sha512-XB4O1+6mpLp4qy/3qg5+1QPZ/uXvWtO64hNAX87sKHwcHkp1LJGU7V3sJ9iVmRACElAZXQ4YOO/Lbkx5kYfl9A==", - "dev": true, - "dependencies": { - "html-minifier-terser": "^5.1.1", - "parse5": "^6.0.1" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - } - }, - "node_modules/html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", - "dev": true, - "dependencies": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", - "he": "^1.2.0", - "param-case": "^3.0.3", - "relateurl": "^0.2.7", - "terser": "^4.6.3" - }, - "bin": { - "html-minifier-terser": "cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/idb": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.2.tgz", - "integrity": "sha512-1DNDVu3yDhAZkFDlJf0t7r+GLZ248F5pTAtA7V0oVG3yjmV125qZOx3g0XpAEkGZVYQiFDAsSOnGet2bhugc3w==" - }, - "node_modules/ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "dependencies": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-accessor-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "dependencies": { - "binary-extensions": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "node_modules/is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-data-descriptor/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "dependencies": { - "is-unc-path": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "dev": true, - "dependencies": { - "unc-path-regex": "^0.1.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "node_modules/is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "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/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.2.tgz", - "integrity": "sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "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/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/just-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", - "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", - "dev": true - }, - "node_modules/kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", - "dev": true, - "dependencies": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.5" - }, - "engines": { - "node": ">= 0.6.3" - } - }, - "node_modules/lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "dependencies": { - "invert-kv": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", - "dev": true, - "dependencies": { - "flush-write-stream": "^1.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "dependencies": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/liftoff/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "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/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "node_modules/lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "node_modules/lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "node_modules/lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "node_modules/lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "node_modules/lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "node_modules/lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "node_modules/lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "node_modules/lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "node_modules/lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "node_modules/lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "node_modules/lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "dependencies": { - "lodash._root": "^3.0.0" - } - }, - "node_modules/lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "node_modules/lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "node_modules/lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "dependencies": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "node_modules/lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "dependencies": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "node_modules/lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "dependencies": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, - "node_modules/lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "node_modules/lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "dependencies": { - "tslib": "^2.0.3" - } - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/make-iterator/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, - "node_modules/map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "dependencies": { - "object-visit": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", - "dev": true, - "dependencies": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "engines": { - "node": ">= 0.10.0" - } - }, - "node_modules/matchdep/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "dependencies": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/matchdep/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/matchdep/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "dependencies": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/micromatch/node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "dev": true, - "dependencies": { - "fill-range": "^7.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/micromatch/node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/micromatch/node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.31", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "dev": true, - "dependencies": { - "mime-db": "1.48.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "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.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "node_modules/mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "dependencies": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/mixin-deep/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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/mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "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/multimatch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", - "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", - "dev": true, - "dependencies": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/multimatch/node_modules/array-differ": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "dependencies": { - "duplexer2": "0.0.2" - } - }, - "node_modules/mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", - "dev": true, - "optional": true - }, - "node_modules/nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", - "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/nanomatch/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "deprecated": "This module relies on Node.js's internals and will break at some point. Do not use it, and update to graceful-fs@4.x.", - "dev": true - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "dependencies": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node_modules/node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", - "dev": true - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/normalize-package-data/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/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", - "dev": true, - "dependencies": { - "once": "^1.3.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/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-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "dependencies": { - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", - "dev": true, - "dependencies": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", - "dev": true, - "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", - "dev": true, - "dependencies": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" - } - }, - "node_modules/orchestrator/node_modules/end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", - "dev": true, - "dependencies": { - "once": "~1.3.0" - } - }, - "node_modules/orchestrator/node_modules/once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.1" - } - }, - "node_modules/os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "dependencies": { - "lcid": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-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" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "dependencies": { - "aggregate-error": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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/param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", - "dev": true, - "dependencies": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", - "dev": true, - "dependencies": { - "error-ex": "^1.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", - "dev": true, - "dependencies": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "node_modules/pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", - "dev": true - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", - "dev": true, - "dependencies": { - "path-root-regex": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", - "dev": true, - "dependencies": { - "through": "~2.3" - } - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", - "dev": true, - "dependencies": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/plugin-error/node_modules/ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "dependencies": { - "ansi-wrap": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/plugin-error/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz", - "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==", - "dev": true, - "dependencies": { - "colorette": "^1.2.2", - "nanoid": "^3.1.23", - "source-map-js": "^0.6.2" - }, - "engines": { - "node": "^10 || ^12 || >=14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - } - }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, - "dependencies": { - "postcss-selector-parser": "^6.0.4" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "dependencies": { - "icss-utils": "^5.0.0" - }, - "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", - "dev": true, - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", - "dev": true, - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", - "dev": true, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/pretty-quick": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.0.tgz", - "integrity": "sha512-DtxIxksaUWCgPFN7E1ZZk4+Aav3CCuRdhrDSFZENb404sYMtuo9Zka823F+Mgeyt8Zt3bUiCjFzzWYE9LYqkmQ==", - "dev": true, - "dependencies": { - "chalk": "^3.0.0", - "execa": "^4.0.0", - "find-up": "^4.1.0", - "ignore": "^5.1.4", - "mri": "^1.1.5", - "multimatch": "^4.0.0" - }, - "bin": { - "pretty-quick": "bin/pretty-quick.js" - }, - "engines": { - "node": ">=10.13" - }, - "peerDependencies": { - "prettier": ">=2.0.0" - } - }, - "node_modules/pretty-quick/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-quick/node_modules/ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "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/progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", - "dev": true, - "dependencies": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" - } - }, - "node_modules/pumpify/node_modules/pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/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/raw-loader": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", - "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "node_modules/read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", - "dev": true, - "dependencies": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", - "dev": true, - "dependencies": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "dependencies": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "dependencies": { - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/readdirp/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/readdirp/node_modules/micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "dependencies": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", - "dev": true, - "dependencies": { - "resolve": "^1.1.6" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regex-not/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/remove-bom-stream": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", - "dev": true, - "dependencies": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/remove-bom-stream/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/remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "node_modules/repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "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-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", - "dev": true - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-cwd/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", - "dev": true, - "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", - "dev": true, - "dependencies": { - "value-or-function": "^3.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "deprecated": "https://github.com/lydell/resolve-url#deprecated", - "dev": true - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/rxjs/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "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/safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "dependencies": { - "ret": "~0.1.10" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/schema-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", - "dev": true, - "dependencies": { - "sver-compat": "^1.5.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "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/set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/set-value/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shallow-clone/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", - "dev": true - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/slice-ansi?sponsor=1" - } - }, - "node_modules/snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-node/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "dependencies": { - "kind-of": "^3.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - }, - "node_modules/snapdragon/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/sortablejs": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.13.0.tgz", - "integrity": "sha512-RBJirPY0spWCrU5yCmWM1eFs/XgX2J5c6b275/YyxFRgnzPhKl/TDeU2hNR8Dt7ITq66NRPM4UlOt+e5O4CFHg==" - }, - "node_modules/source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "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/source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", - "dev": true, - "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.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-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "node_modules/sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "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.9", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true - }, - "node_modules/split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", - "dev": true, - "dependencies": { - "through": "2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "dependencies": { - "extend-shallow": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/split-string/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stream-combiner": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", - "dev": true, - "dependencies": { - "duplexer": "~0.1.1", - "through": "~2.3.4" - } - }, - "node_modules/stream-consume": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", - "dev": true - }, - "node_modules/stream-exhaust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", - "dev": true - }, - "node_modules/stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", - "dev": true - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "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/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/strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", - "dev": true, - "dependencies": { - "is-utf8": "^0.2.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/style-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz", - "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" - } - }, - "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/sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", - "dev": true, - "dependencies": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "node_modules/table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "dependencies": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/table/node_modules/ajv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", - "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/table/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", - "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-webpack-plugin": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.3.tgz", - "integrity": "sha512-cxGbMqr6+A2hrIB5ehFIF+F/iST5ZOxvOmy9zih9ySbP1C2oEWQSOUS+2SNBTjzx5xLKO4xnod9eywdfq1Nb9A==", - "dev": true, - "dependencies": { - "jest-worker": "^27.0.2", - "p-limit": "^3.1.0", - "schema-utils": "^3.0.0", - "serialize-javascript": "^5.0.1", - "source-map": "^0.6.1", - "terser": "^5.7.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - } - }, - "node_modules/terser-webpack-plugin/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/terser-webpack-plugin/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/terser-webpack-plugin/node_modules/terser": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", - "integrity": "sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g==", - "dev": true, - "dependencies": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.19" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin/node_modules/terser/node_modules/source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/terser/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/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "node_modules/through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "dev": true, - "dependencies": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - } - }, - "node_modules/through2-filter/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/tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", - "dev": true, - "dependencies": { - "os-homedir": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", - "dev": true, - "dependencies": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "dependencies": { - "kind-of": "^3.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "dependencies": { - "is-buffer": "^1.1.5" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "dependencies": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-regex/node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/to-string-loader": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.1.6.tgz", - "integrity": "sha512-VNg62//PS1WfNwrK3n7t6wtK5Vdtx/qeYLLEioW46VMlYUwAYT6wnfB+OwS2FMTCalIHu0tk79D3RXX8ttmZTQ==", - "dev": true, - "dependencies": { - "loader-utils": "^1.0.0" - } - }, - "node_modules/to-string-loader/node_modules/json5": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", - "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/to-string-loader/node_modules/loader-utils": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.4.0.tgz", - "integrity": "sha512-qH0WSMBtn/oHuwjy/NucEgbx5dbxxnxup9s4PVXJUDHZBQY+s0NWA9rJf53RBnQZxfch7euUui7hpoAPvALZdA==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^1.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", - "dev": true, - "dependencies": { - "through2": "^2.0.3" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/to-through/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/tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", - "dev": true - }, - "node_modules/type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "node_modules/unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/undertaker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", - "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", - "dev": true, - "dependencies": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "fast-levenshtein": "^1.0.0", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/undertaker/node_modules/fast-levenshtein": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", - "dev": true - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "dev": true, - "dependencies": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" - } - }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "dependencies": { - "isarray": "1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", - "dev": true, - "engines": { - "node": ">=4", - "yarn": "*" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "deprecated": "Please see https://github.com/lydell/urix#deprecated", - "dev": true - }, - "node_modules/url-loader": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", - "integrity": "sha512-3BTV812+AVHHOJQO8O5MkWgZ5aosP7GnROJwvzLS9hWDj00lZ6Z0wNak423Lp9PBZN05N+Jk/N5Si8jRAlGyWA==", - "dev": true, - "dependencies": { - "loader-utils": "^2.0.0", - "mime-types": "^2.1.27", - "schema-utils": "^3.0.0" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "file-loader": "*", - "webpack": "^4.0.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "file-loader": { - "optional": true - } - } - }, - "node_modules/use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true, - "bin": { - "user-home": "cli.js" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "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/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "dependencies": { - "homedir-polyfill": "^1.0.1" - }, - "engines": { - "node": ">= 0.10" - } - }, - "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/value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz", - "integrity": "sha1-sEVbOPxeDPMNQyUTLkYZcMIJHN4=", - "dev": true, - "dependencies": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - }, - "engines": { - "node": ">= 0.9" - } - }, - "node_modules/vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", - "dev": true, - "dependencies": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-fs/node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/vinyl-fs/node_modules/clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "node_modules/vinyl-fs/node_modules/replace-ext": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", - "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-fs/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/vinyl-fs/node_modules/vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "dependencies": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", - "dev": true, - "dependencies": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-sourcemap/node_modules/clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/vinyl-sourcemap/node_modules/clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "node_modules/vinyl-sourcemap/node_modules/normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "dependencies": { - "remove-trailing-separator": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/vinyl-sourcemap/node_modules/replace-ext": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", - "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/vinyl-sourcemap/node_modules/vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "dependencies": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack": { - "version": "5.38.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.38.1.tgz", - "integrity": "sha512-OqRmYD1OJbHZph6RUMD93GcCZy4Z4wC0ele4FXyYF0J6AxO1vOSuIlU1hkS/lDlR9CDYBz64MZRmdbdnFFoT2g==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.47", - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/wasm-edit": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "acorn": "^8.2.1", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.0", - "es-module-lexer": "^0.4.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", - "json-parse-better-errors": "^1.0.2", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.1", - "watchpack": "^2.2.0", - "webpack-sources": "^2.3.0" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.2.tgz", - "integrity": "sha512-mEoLmnmOIZQNiRl0ebnjzQ74Hk0iKS5SiEEnpq3dRezoyR3yPaeQZCMCe+db4524pj1Pd5ghZXjT41KLzIhSLw==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.0.4", - "@webpack-cli/info": "^1.3.0", - "@webpack-cli/serve": "^1.5.1", - "colorette": "^1.2.1", - "commander": "^7.0.0", - "execa": "^5.0.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "@webpack-cli/migrate": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-cli/node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/webpack-cli/node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/webpack-cli/node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/webpack-cli/node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/webpack-cli/node_modules/rechoir": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", - "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", - "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz", - "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==", - "dev": true, - "dependencies": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/acorn": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz", - "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "node_modules/word-wrap": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", - "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1" - }, - "engines": { - "node": ">=4" - } - }, - "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": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yargs": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", - "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.1" - } - }, - "node_modules/yargs-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", - "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", - "dev": true, - "dependencies": { - "camelcase": "^3.0.0", - "object.assign": "^4.1.0" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.0.tgz", - "integrity": "sha512-V3ts7zMSu5lfiwWDVWzRDGIN+lnCEUdaXgtVHJgLb1rGaA6jMrtB9EmE7L18foXJIE8Un/A/h6NJfGQp/e1J4A==", - "dev": true - }, - "@babel/highlight": { - "version": "7.14.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.0.tgz", - "integrity": "sha512-YSCOwxvTYEIMSGaBQb5kDDsCopDdiUGsqpatp3fOlI4+2HQSkTmEVWnVuySdAC5EWCqSWWTv0ib63RjR7dTBdg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.14.0", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "dependencies": { - "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" - } - }, - "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" - } - }, - "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 - }, - "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 - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "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" - } - } - } - }, - "@discoveryjs/json-ext": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.3.tgz", - "integrity": "sha512-Fxt+AfXgjMoin2maPIYzFZnQjAXjAL0PHscM5pRTtatFqB+vZxAM9tLp2Optnuw3QOQC40jTNeGYFOMvyf7v9g==", - "dev": true - }, - "@eslint/eslintrc": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", - "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", - "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.1.1", - "espree": "^7.3.0", - "globals": "^13.9.0", - "ignore": "^4.0.6", - "import-fresh": "^3.2.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - } - }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.7.tgz", - "integrity": "sha512-BTIhocbPBSrRmHxOAJFtR18oLhxTtAFDAvL8hY1S3iU8k+E60W/YFs4jrixGzQjMpF4qPXxIQHcjVD9dz1C2QA==", - "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - } - }, - "@types/eslint": { - "version": "7.2.13", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-7.2.13.tgz", - "integrity": "sha512-LKmQCWAlnVHvvXq4oasNUMTJJb2GwSyTY8+1C7OH5ILR8mPLaljv1jxL1bXW3xB3jFbQxTKxJAvI8PyjB09aBg==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.0.tgz", - "integrity": "sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.48", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.48.tgz", - "integrity": "sha512-LfZwXoGUDo0C3me81HXgkBg5CTQYb6xzEl+fNmbO4JdRiSKQ8A0GD1OBBvKAIsbCUgoyAty7m99GqqMQe784ew==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", - "integrity": "sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==", - "dev": true - }, - "@types/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==", - "dev": true - }, - "@types/node": { - "version": "15.12.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-15.12.1.tgz", - "integrity": "sha512-zyxJM8I1c9q5sRMtVF+zdd13Jt6RU4r4qfhTd7lQubyThvLfx6yYekWSQjGCGV2Tkecgxnlpl/DNlb6Hg+dmEw==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.0.tgz", - "integrity": "sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz", - "integrity": "sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz", - "integrity": "sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz", - "integrity": "sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz", - "integrity": "sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz", - "integrity": "sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz", - "integrity": "sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz", - "integrity": "sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.0.tgz", - "integrity": "sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.0.tgz", - "integrity": "sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz", - "integrity": "sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/helper-wasm-section": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-opt": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "@webassemblyjs/wast-printer": "1.11.0" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz", - "integrity": "sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz", - "integrity": "sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-buffer": "1.11.0", - "@webassemblyjs/wasm-gen": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz", - "integrity": "sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/helper-api-error": "1.11.0", - "@webassemblyjs/helper-wasm-bytecode": "1.11.0", - "@webassemblyjs/ieee754": "1.11.0", - "@webassemblyjs/leb128": "1.11.0", - "@webassemblyjs/utf8": "1.11.0" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz", - "integrity": "sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.0", - "@xtuc/long": "4.2.2" - } - }, - "@webpack-cli/configtest": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.0.4.tgz", - "integrity": "sha512-cs3XLy+UcxiP6bj0A6u7MLLuwdXJ1c3Dtc0RkKg+wiI1g/Ti1om8+/2hc2A2B60NbBNAbMgyBMHvyymWm/j4wQ==", - "dev": true - }, - "@webpack-cli/info": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.3.0.tgz", - "integrity": "sha512-ASiVB3t9LOKHs5DyVUcxpraBXDOKubYu/ihHhU+t1UPpxsivg6Od2E2qU4gJCekfEddzRBzHhzA/Acyw/mlK/w==", - "dev": true, - "requires": { - "envinfo": "^7.7.3" - } - }, - "@webpack-cli/serve": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.0.tgz", - "integrity": "sha512-AxpcbdkUhl4248H33LDFgXpFpDE5/BU9rHi2Oj8J4z8JldoMXoSmCe1DXDKcw1ClK64g6fY1Hg+dW20vH81JvQ==", - "dev": true - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "acorn": { - "version": "7.4.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", - "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", - "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", - "dev": true, - "requires": {} - }, - "aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", - "dev": true, - "requires": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - } - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", - "dev": true - }, - "ansi-escapes": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", - "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", - "dev": true, - "requires": { - "type-fest": "^0.21.3" - }, - "dependencies": { - "type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "dev": true - } - } - }, - "ansi-gray": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", - "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", - "dev": true, - "requires": { - "ansi-wrap": "0.1.0" - } - }, - "ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "dev": true - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "ansi-wrap": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", - "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", - "dev": true - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "append-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", - "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", - "dev": true, - "requires": { - "buffer-equal": "^1.0.0" - } - }, - "arc": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/arc/-/arc-0.1.1.tgz", - "integrity": "sha512-gJsNNbnJW7UMU9ccjBaRh2evSyltbinzRGNPX9aiW28QxbGMtwMDC0YL6lkF73b+y+BUAOT/dUN2DMQDB1Is5w==" - }, - "archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", - "dev": true - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-filter": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", - "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", - "dev": true, - "requires": { - "make-iterator": "^1.0.0" - } - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", - "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", - "dev": true, - "requires": { - "make-iterator": "^1.0.0" - } - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=", - "dev": true - }, - "array-each": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", - "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", - "dev": true - }, - "array-initial": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", - "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", - "dev": true, - "requires": { - "array-slice": "^1.0.0", - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, - "array-last": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", - "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", - "dev": true, - "requires": { - "is-number": "^4.0.0" - }, - "dependencies": { - "is-number": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", - "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", - "dev": true - } - } - }, - "array-slice": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", - "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", - "dev": true - }, - "array-sort": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", - "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", - "dev": true, - "requires": { - "default-compare": "^1.0.0", - "get-value": "^2.0.6", - "kind-of": "^5.0.2" - } - }, - "array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "async-done": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.2.tgz", - "integrity": "sha512-uYkTP8dw2og1tu1nmza1n1CMW0qb8gWWlwqMmLb7MhBVs4BXrFziT6HXUd+/RlRA/i4H9AkofYloUbs1fwMqlw==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.2", - "process-nextick-args": "^2.0.0", - "stream-exhaust": "^1.0.1" - } - }, - "async-each": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", - "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", - "dev": true - }, - "async-settle": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", - "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", - "dev": true, - "requires": { - "async-done": "^1.2.2" - } - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "bach": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", - "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", - "dev": true, - "requires": { - "arr-filter": "^1.1.1", - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "array-each": "^1.0.0", - "array-initial": "^1.0.0", - "array-last": "^1.1.1", - "async-done": "^1.2.2", - "async-settle": "^1.0.0", - "now-and-later": "^2.0.0" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "beeper": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "binary-extensions": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", - "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", - "dev": true - }, - "bindings": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", - "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", - "dev": true, - "optional": true, - "requires": { - "file-uri-to-path": "1.0.0" - } - }, - "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" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "browserslist": { - "version": "4.16.6", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.6.tgz", - "integrity": "sha512-Wspk/PqO+4W9qp5iUTJsa1B/QrYn1keNCcEP5OvP7WBwT4KaDly0uONYmC6Xa3Z5IqnUgS0KcgLYu1l74x0ZXQ==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001219", - "colorette": "^1.2.2", - "electron-to-chromium": "^1.3.723", - "escalade": "^3.1.1", - "node-releases": "^1.1.71" - } - }, - "buffer-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", - "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", - "dev": true - }, - "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 - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camel-case": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz", - "integrity": "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==", - "dev": true, - "requires": { - "pascal-case": "^3.1.2", - "tslib": "^2.0.3" - } - }, - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - }, - "caniuse-lite": { - "version": "1.0.30001235", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001235.tgz", - "integrity": "sha512-zWEwIVqnzPkSAXOUlQnPW2oKoYb2aLQ4Q5ejdjBcnH63rfypaW34CxaeBn1VMya2XaEU3P/R2qHpWyj+l0BT1A==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "chokidar": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz", - "integrity": "sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - } - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - } - }, - "clean-css": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", - "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==", - "dev": true, - "requires": { - "source-map": "~0.6.0" - } - }, - "clean-stack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", - "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", - "dev": true - }, - "cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "requires": { - "restore-cursor": "^3.1.0" - } - }, - "cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true - }, - "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "clone": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", - "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", - "dev": true - }, - "clone-buffer": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", - "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", - "dev": true - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "clone-stats": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz", - "integrity": "sha1-uI+UqCzzi4eR1YBG6kAprYjKmdE=", - "dev": true - }, - "cloneable-readable": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz", - "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "process-nextick-args": "^2.0.0", - "readable-stream": "^2.3.5" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "collection-map": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", - "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", - "dev": true, - "requires": { - "arr-map": "^2.0.2", - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.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.3" - }, - "dependencies": { - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - } - } - }, - "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==" - }, - "color-string": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz", - "integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==", - "requires": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true - }, - "colorette": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true - }, - "commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "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 - }, - "concat-stream": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", - "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^2.2.2", - "typedarray": "^0.0.6" - } - }, - "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" - }, - "dependencies": { - "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 - } - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-props": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.5.tgz", - "integrity": "sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw==", - "dev": true, - "requires": { - "each-props": "^1.3.2", - "is-plain-object": "^5.0.0" - }, - "dependencies": { - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "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 - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "css-loader": { - "version": "5.2.6", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.6.tgz", - "integrity": "sha512-0wyN5vXMQZu6BvjbrPdUJvkCzGEO24HC7IS7nW4llc6BBFC+zwR9CKtYGv63Puzsg10L/o12inMY5/2ByzfD6w==", - "dev": true, - "requires": { - "icss-utils": "^5.1.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.15", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.1.0", - "schema-utils": "^3.0.0", - "semver": "^7.3.5" - } - }, - "cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true - }, - "d": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", - "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", - "dev": true, - "requires": { - "es5-ext": "^0.10.50", - "type": "^1.0.1" - } - }, - "dateformat": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz", - "integrity": "sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI=", - "dev": true - }, - "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "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 - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "default-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", - "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", - "dev": true, - "requires": { - "kind-of": "^5.0.2" - } - }, - "default-resolution": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", - "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", - "dev": true - }, - "defaults": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", - "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", - "dev": true, - "requires": { - "clone": "^1.0.2" - } - }, - "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" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "del": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/del/-/del-6.0.0.tgz", - "integrity": "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ==", - "dev": true, - "requires": { - "globby": "^11.0.1", - "graceful-fs": "^4.2.4", - "is-glob": "^4.0.1", - "is-path-cwd": "^2.2.0", - "is-path-inside": "^3.0.2", - "p-map": "^4.0.0", - "rimraf": "^3.0.2", - "slash": "^3.0.0" - } - }, - "deprecated": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz", - "integrity": "sha1-+cmvVGSvoeepcUWKi97yqpTVuxk=", - "dev": true - }, - "detect-file": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", - "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", - "dev": true - }, - "dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "requires": { - "path-type": "^4.0.0" - } - }, - "doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "requires": { - "esutils": "^2.0.2" - } - }, - "dot-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", - "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", - "dev": true, - "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" - } - }, - "duplexer": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true - }, - "duplexer2": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz", - "integrity": "sha1-xhTc9n4vsUmVqRcR5aYX6KYKMds=", - "dev": true, - "requires": { - "readable-stream": "~1.1.9" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "readable-stream": { - "version": "1.1.14", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "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 - } - } - }, - "duplexify": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", - "integrity": "sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==", - "dev": true, - "requires": { - "end-of-stream": "^1.0.0", - "inherits": "^2.0.1", - "readable-stream": "^2.0.0", - "stream-shift": "^1.0.0" - } - }, - "each-props": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", - "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.1", - "object.defaults": "^1.1.0" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "electron-to-chromium": { - "version": "1.3.749", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.749.tgz", - "integrity": "sha512-F+v2zxZgw/fMwPz/VUGIggG4ZndDsYy0vlpthi3tjmDZlcfbhN5mYW0evXUsBr2sUtuDANFtle410A9u/sd/4A==", - "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 - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "enhanced-resolve": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz", - "integrity": "sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "enquirer": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", - "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, - "requires": { - "ansi-colors": "^4.1.1" - } - }, - "envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "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" - }, - "dependencies": { - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - } - } - }, - "es-module-lexer": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.4.1.tgz", - "integrity": "sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==", - "dev": true - }, - "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", - "dev": true, - "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" - } - }, - "es6-iterator": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", - "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.35", - "es6-symbol": "^3.1.1" - } - }, - "es6-symbol": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", - "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", - "dev": true, - "requires": { - "d": "^1.0.1", - "ext": "^1.1.2" - } - }, - "es6-weak-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", - "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", - "dev": true, - "requires": { - "d": "1", - "es5-ext": "^0.10.46", - "es6-iterator": "^2.0.3", - "es6-symbol": "^3.1.1" - } - }, - "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": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.28.0.tgz", - "integrity": "sha512-UMfH0VSjP0G4p3EWirscJEQ/cHqnT/iuH6oNZOB94nBjWbMnhGEPxsZm1eyIW0C/9jLI0Fow4W5DXLjEI7mn1g==", - "dev": true, - "requires": { - "@babel/code-frame": "7.12.11", - "@eslint/eslintrc": "^0.4.2", - "ajv": "^6.10.0", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "enquirer": "^2.3.5", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^5.1.1", - "eslint-utils": "^2.1.0", - "eslint-visitor-keys": "^2.0.0", - "espree": "^7.3.1", - "esquery": "^1.4.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.1.2", - "globals": "^13.6.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.0.4", - "natural-compare": "^1.4.0", - "optionator": "^0.9.1", - "progress": "^2.0.0", - "regexpp": "^3.1.0", - "semver": "^7.2.1", - "strip-ansi": "^6.0.0", - "strip-json-comments": "^3.1.0", - "table": "^6.0.9", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - }, - "dependencies": { - "@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.10.4" - } - }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "astral-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", - "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", - "dev": true - }, - "chalk": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", - "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.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" - } - }, - "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 - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "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 - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" - } - }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - } - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", - "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - } - } - }, - "type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true - } - } - }, - "eslint-config-prettier": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", - "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", - "dev": true, - "requires": {} - }, - "eslint-plugin-prettier": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.0.tgz", - "integrity": "sha512-UDK6rJT6INSfcOo545jiaOwB701uAIt2/dR7WnFQoGCVl1/EMqdANBmwUaqqQ45aXprsTGzSa39LI1PyuRBxxw==", - "dev": true, - "requires": { - "prettier-linter-helpers": "^1.0.0" - } - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true - }, - "espree": { - "version": "7.3.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", - "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", - "dev": true, - "requires": { - "acorn": "^7.4.0", - "acorn-jsx": "^5.3.1", - "eslint-visitor-keys": "^1.3.0" - }, - "dependencies": { - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - } - } - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esquery": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", - "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", - "dev": true, - "requires": { - "estraverse": "^5.1.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", - "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "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 - }, - "event-stream": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.5.tgz", - "integrity": "sha512-vyibDcu5JL20Me1fP734QBH/kenBGLZap2n0+XXM7mvuUPzJ20Ydqj1aKcIeMdri1p+PU+4yAKugjN8KCVst+g==", - "dev": true, - "requires": { - "duplexer": "^0.1.1", - "from": "^0.1.7", - "map-stream": "0.0.7", - "pause-stream": "^0.0.11", - "split": "^1.0.1", - "stream-combiner": "^0.2.2", - "through": "^2.3.8" - } - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - } - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "dev": true - } - } - }, - "expand-tilde": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", - "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "ext": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", - "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", - "dev": true, - "requires": { - "type": "^2.0.0" - }, - "dependencies": { - "type": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/type/-/type-2.5.0.tgz", - "integrity": "sha512-180WMDQaIMm3+7hGXWf12GtdniDEy7nYcyFMKJn/eZz/6tSLXrUN9V0wKSbMjej0I1WHWbpREDEKHtqPQa9NNw==", - "dev": true - } - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "dev": true, - "requires": { - "is-extendable": "^0.1.0" - } - }, - "external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "requires": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "fancy-log": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", - "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", - "dev": true, - "requires": { - "ansi-gray": "^0.1.1", - "color-support": "^1.1.3", - "parse-node-version": "^1.0.0", - "time-stamp": "^1.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-diff": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", - "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", - "dev": true - }, - "fast-glob": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.5.tgz", - "integrity": "sha512-2DtFcgT68wiTTiwZ2hNdJfcHNke9XOfnwmBRWXhmeKM8rF0TGwmC/Qto3S7RoZKp5cilZbxzO5iTNTQsJ+EeDg==", - "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.0", - "merge2": "^1.3.0", - "micromatch": "^4.0.2", - "picomatch": "^2.2.1" - } - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "fastq": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", - "integrity": "sha512-7Eczs8gIPDrVzT+EksYBcupqMyxSHXXrHOLRRxU2/DicV8789MRBRR8+Hc2uWzUupOs4YS4JzBmBxjjCVBxD/g==", - "dev": true, - "requires": { - "reusify": "^1.0.4" - } - }, - "figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "requires": { - "escape-string-regexp": "^1.0.5" - }, - "dependencies": { - "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 - } - } - }, - "file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "requires": { - "flat-cache": "^3.0.4" - } - }, - "file-uri-to-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", - "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", - "dev": true, - "optional": true - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "find-index": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz", - "integrity": "sha1-Z101iyyjiS15Whq0cjL4tuLg3eQ=", - "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" - } - }, - "findup-sync": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", - "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "fined": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", - "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "is-plain-object": "^2.0.3", - "object.defaults": "^1.1.0", - "object.pick": "^1.2.0", - "parse-filepath": "^1.0.1" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "first-chunk-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz", - "integrity": "sha1-Wb+1DNkF9g18OUzT2ayqtOatk04=", - "dev": true - }, - "flagged-respawn": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", - "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", - "dev": true - }, - "flat-cache": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", - "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", - "dev": true, - "requires": { - "flatted": "^3.1.0", - "rimraf": "^3.0.2" - } - }, - "flatted": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.1.1.tgz", - "integrity": "sha512-zAoAQiudy+r5SvnSw3KJy5os/oRJYHzrzja/tBDqrZtNhUw8bt6y8OBzMWcjWr+8liV8Eb6yOhw8WZ7VFZ5ZzA==", - "dev": true - }, - "flush-write-stream": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz", - "integrity": "sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==", - "dev": true, - "requires": { - "inherits": "^2.0.3", - "readable-stream": "^2.3.6" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "for-own": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", - "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", - "dev": true, - "requires": { - "for-in": "^1.0.1" - } - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "from": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", - "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", - "dev": true - }, - "fs-mkdirp-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", - "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "through2": "^2.0.3" - }, - "dependencies": { - "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" - } - } - } - }, - "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": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "functional-red-black-tree": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", - "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", - "dev": true - }, - "gaze": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz", - "integrity": "sha1-QLcJU30k0dRXZ9takIaJ3+aaxE8=", - "dev": true, - "requires": { - "globule": "~0.1.0" - } - }, - "geodesy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/geodesy/-/geodesy-2.2.1.tgz", - "integrity": "sha512-jhUYGHFZz5hZ/f+lBZiwFNWRhOUV2iiVxyLOT8FixIUJHEDVMgcB1SWQs50P51uTVcVjsngjPAUUNWcWdWiPog==" - }, - "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "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" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "glob-stream": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", - "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", - "dev": true, - "requires": { - "extend": "^3.0.0", - "glob": "^7.1.1", - "glob-parent": "^3.1.0", - "is-negated-glob": "^1.0.0", - "ordered-read-streams": "^1.0.0", - "pumpify": "^1.3.5", - "readable-stream": "^2.1.5", - "remove-trailing-separator": "^1.0.1", - "to-absolute-glob": "^2.0.0", - "unique-stream": "^2.0.2" - }, - "dependencies": { - "glob-parent": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", - "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "glob-watcher": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.5.tgz", - "integrity": "sha512-zOZgGGEHPklZNjZQaZ9f41i7F2YwE+tS5ZHrDhbBCk3stwahn5vQxnFmBJZHoYdusR6R1bLSXeGUy/BhctwKzw==", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-done": "^1.2.0", - "chokidar": "^2.0.0", - "is-negated-glob": "^1.0.0", - "just-debounce": "^1.0.0", - "normalize-path": "^3.0.0", - "object.defaults": "^1.1.0" - } - }, - "glob2base": { - "version": "0.0.12", - "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz", - "integrity": "sha1-nUGbPijxLoOjYhZKJ3BVkiycDVY=", - "dev": true, - "requires": { - "find-index": "^0.1.1" - } - }, - "global-modules": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", - "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", - "dev": true, - "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" - } - }, - "global-prefix": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", - "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", - "dev": true, - "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" - }, - "dependencies": { - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "globals": { - "version": "13.9.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.9.0.tgz", - "integrity": "sha512-74/FduwI/JaIrr1H8e71UbDE+5x7pIPs1C2rrwC52SszOo043CsWOZEMW7o2Y58xwm9b+0RBKDxY5n2sUpEFxA==", - "dev": true, - "requires": { - "type-fest": "^0.20.2" - } - }, - "globby": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.0.3.tgz", - "integrity": "sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==", - "dev": true, - "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.1.1", - "ignore": "^5.1.4", - "merge2": "^1.3.0", - "slash": "^3.0.0" - }, - "dependencies": { - "ignore": { - "version": "5.1.8", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", - "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", - "dev": true - } - } - }, - "globule": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz", - "integrity": "sha1-2cjt3h2nnRJaFRt5UzuXhnY0auU=", - "dev": true, - "requires": { - "glob": "~3.1.21", - "lodash": "~1.0.1", - "minimatch": "~0.2.11" - }, - "dependencies": { - "glob": { - "version": "3.1.21", - "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", - "dev": true, - "requires": { - "graceful-fs": "~1.2.0", - "inherits": "1", - "minimatch": "~0.2.11" - } - }, - "graceful-fs": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", - "dev": true - }, - "inherits": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", - "dev": true - }, - "lodash": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz", - "integrity": "sha1-j1dWDIO1n8JwvT1WG2kAQ0MOJVE=", - "dev": true - }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", - "dev": true - }, - "minimatch": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", - "dev": true, - "requires": { - "lru-cache": "2", - "sigmund": "~1.0.0" - } - } - } - }, - "glogg": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", - "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", - "dev": true, - "requires": { - "sparkles": "^1.0.0" - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "gulp": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", - "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", - "dev": true, - "requires": { - "glob-watcher": "^5.0.3", - "gulp-cli": "^2.2.0", - "undertaker": "^1.2.1", - "vinyl-fs": "^3.0.0" - } - }, - "gulp-cli": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.3.0.tgz", - "integrity": "sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A==", - "dev": true, - "requires": { - "ansi-colors": "^1.0.1", - "archy": "^1.0.0", - "array-sort": "^1.0.0", - "color-support": "^1.1.3", - "concat-stream": "^1.6.0", - "copy-props": "^2.0.1", - "fancy-log": "^1.3.2", - "gulplog": "^1.0.0", - "interpret": "^1.4.0", - "isobject": "^3.0.1", - "liftoff": "^3.1.0", - "matchdep": "^2.0.0", - "mute-stdout": "^1.0.0", - "pretty-hrtime": "^1.0.0", - "replace-homedir": "^1.0.0", - "semver-greatest-satisfied-range": "^1.1.0", - "v8flags": "^3.2.0", - "yargs": "^7.1.0" - }, - "dependencies": { - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "requires": { - "ansi-wrap": "^0.1.0" - } - } - } - }, - "gulp-eslint": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/gulp-eslint/-/gulp-eslint-6.0.0.tgz", - "integrity": "sha512-dCVPSh1sA+UVhn7JSQt7KEb4An2sQNbOdB3PA8UCfxsoPlAKjJHxYHGXdXC7eb+V1FAnilSFFqslPrq037l1ig==", - "dev": true, - "requires": { - "eslint": "^6.0.0", - "fancy-log": "^1.3.2", - "plugin-error": "^1.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "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" - } - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "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" - } - }, - "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 - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - }, - "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "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 - }, - "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 - }, - "eslint": { - "version": "6.8.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-6.8.0.tgz", - "integrity": "sha512-K+Iayyo2LtyYhDSYwz5D5QdWw0hCacNzyq1Y821Xna2xSJj7cijoLLYmLxTQgcgZ9mC61nryMy9S7GRbYpI5Ig==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "ajv": "^6.10.0", - "chalk": "^2.1.0", - "cross-spawn": "^6.0.5", - "debug": "^4.0.1", - "doctrine": "^3.0.0", - "eslint-scope": "^5.0.0", - "eslint-utils": "^1.4.3", - "eslint-visitor-keys": "^1.1.0", - "espree": "^6.1.2", - "esquery": "^1.0.1", - "esutils": "^2.0.2", - "file-entry-cache": "^5.0.1", - "functional-red-black-tree": "^1.0.1", - "glob-parent": "^5.0.0", - "globals": "^12.1.0", - "ignore": "^4.0.6", - "import-fresh": "^3.0.0", - "imurmurhash": "^0.1.4", - "inquirer": "^7.0.0", - "is-glob": "^4.0.0", - "js-yaml": "^3.13.1", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.3.0", - "lodash": "^4.17.14", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "optionator": "^0.8.3", - "progress": "^2.0.0", - "regexpp": "^2.0.1", - "semver": "^6.1.2", - "strip-ansi": "^5.2.0", - "strip-json-comments": "^3.0.1", - "table": "^5.2.3", - "text-table": "^0.2.0", - "v8-compile-cache": "^2.0.3" - } - }, - "eslint-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-1.4.3.tgz", - "integrity": "sha512-fbBN5W2xdY45KulGXmLHZ3c3FHfVYmKg0IrAKGOkT/464PQsx2UeIzfz1RmEci+KLm1bBaAzZAh8+/E+XAeZ8Q==", - "dev": true, - "requires": { - "eslint-visitor-keys": "^1.1.0" - } - }, - "eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true - }, - "espree": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz", - "integrity": "sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==", - "dev": true, - "requires": { - "acorn": "^7.1.1", - "acorn-jsx": "^5.2.0", - "eslint-visitor-keys": "^1.1.0" - } - }, - "file-entry-cache": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-5.0.1.tgz", - "integrity": "sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==", - "dev": true, - "requires": { - "flat-cache": "^2.0.1" - } - }, - "flat-cache": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", - "integrity": "sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==", - "dev": true, - "requires": { - "flatted": "^2.0.0", - "rimraf": "2.6.3", - "write": "1.0.3" - } - }, - "flatted": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-2.0.2.tgz", - "integrity": "sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==", - "dev": true - }, - "globals": { - "version": "12.4.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-12.4.0.tgz", - "integrity": "sha512-BWICuzzDvDoH54NHKCseDanAhE3CeDorgDL5MT6LMXXj2WCnd9UC2szdk4AWLfjdgNBCXLUanXYcpBBKOSWGwg==", - "dev": true, - "requires": { - "type-fest": "^0.8.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 - }, - "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 - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "optionator": { - "version": "0.8.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz", - "integrity": "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.6", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "word-wrap": "~1.2.3" - } - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "regexpp": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-2.0.1.tgz", - "integrity": "sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==", - "dev": true - }, - "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "slice-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz", - "integrity": "sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "astral-regex": "^1.0.0", - "is-fullwidth-code-point": "^2.0.0" - } - }, - "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" - } - }, - "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" - } - }, - "table": { - "version": "5.4.6", - "resolved": "https://registry.npmjs.org/table/-/table-5.4.6.tgz", - "integrity": "sha512-wmEc8m4fjnob4gt5riFRtTu/6+4rSe12TpAELNSqHMfF3IqnA+CH37USM6/YR3qRZv7e56kAEAtd6nKZaxe0Ug==", - "dev": true, - "requires": { - "ajv": "^6.10.2", - "lodash": "^4.17.14", - "slice-ansi": "^2.1.0", - "string-width": "^3.0.0" - } - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - } - } - }, - "gulp-inject-file": { - "version": "0.0.19", - "resolved": "https://registry.npmjs.org/gulp-inject-file/-/gulp-inject-file-0.0.19.tgz", - "integrity": "sha512-z4DOiGHf0kpJHs3Ayh/WiCP+1LC3uQXlcqDXt+NCU/JCXQhySORCHicTuBYTZ9ZJCrcJ8DW3NlfNjxBMaR8W0w==", - "dev": true, - "requires": { - "event-stream": "^3.3.4", - "gulp": "^3.9.1", - "gulp-util": "^3.0.8", - "lodash": "^2.4.2" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "clone": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz", - "integrity": "sha1-xhJqkK1Pctv1rNskPMN3JP6T/B8=", - "dev": true - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "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 - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "glob": { - "version": "4.5.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", - "integrity": "sha1-xstz0yJsHv7wTePFbQEvAzd+4V8=", - "dev": true, - "requires": { - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^2.0.1", - "once": "^1.3.0" - } - }, - "glob-stream": { - "version": "3.1.18", - "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz", - "integrity": "sha1-kXCl8St5Awb9/lmPMT+PeVT9FDs=", - "dev": true, - "requires": { - "glob": "^4.3.1", - "glob2base": "^0.0.12", - "minimatch": "^2.0.1", - "ordered-read-streams": "^0.1.0", - "through2": "^0.6.1", - "unique-stream": "^1.0.0" - } - }, - "glob-watcher": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz", - "integrity": "sha1-uVtKjfdLOcgymLDAXJeLTZo7cQs=", - "dev": true, - "requires": { - "gaze": "^0.5.1" - } - }, - "graceful-fs": { - "version": "3.0.12", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.12.tgz", - "integrity": "sha512-J55gaCS4iTTJfTXIxSVw3EMQckcqkpdRv3IR7gu6sq0+tbC363Zx6KH/SEwXASK9JRbhyZmVjJEVJIOxYsB3Qg==", - "dev": true, - "requires": { - "natives": "^1.1.3" - } - }, - "gulp": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz", - "integrity": "sha1-VxzkWSjdQK9lFPxAEYZgFsE4RbQ=", - "dev": true, - "requires": { - "archy": "^1.0.0", - "chalk": "^1.0.0", - "deprecated": "^0.0.1", - "gulp-util": "^3.0.0", - "interpret": "^1.0.0", - "liftoff": "^2.1.0", - "minimist": "^1.1.0", - "orchestrator": "^0.3.0", - "pretty-hrtime": "^1.0.0", - "semver": "^4.1.0", - "tildify": "^1.0.0", - "v8flags": "^2.0.2", - "vinyl-fs": "^0.3.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.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 - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "liftoff": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.5.0.tgz", - "integrity": "sha1-IAkpG7Mc6oYbvxCnwVooyvdcMew=", - "dev": true, - "requires": { - "extend": "^3.0.0", - "findup-sync": "^2.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - } - }, - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - }, - "minimatch": { - "version": "2.0.10", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", - "integrity": "sha1-jQh8OcazjAAbl/ynzm0OHoCvusc=", - "dev": true, - "requires": { - "brace-expansion": "^1.0.0" - } - }, - "ordered-read-streams": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz", - "integrity": "sha1-/VZamvjrRHO6abbtijQ1LLVS8SY=", - "dev": true - }, - "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" - } - }, - "semver": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz", - "integrity": "sha1-MAvG4OhjdPe6YQaLWx7NV/xlMto=", - "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 - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz", - "integrity": "sha1-hbiGLzhEtabV7IRnqTWYFzo295Q=", - "dev": true, - "requires": { - "first-chunk-stream": "^1.0.0", - "is-utf8": "^0.2.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - }, - "unique-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz", - "integrity": "sha1-1ZpKdUJ0R9mqbJHnAmP40mpLEEs=", - "dev": true - }, - "v8flags": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.1.1.tgz", - "integrity": "sha1-qrGh+jDUX4jdMhFIh1rALAtV5bQ=", - "dev": true, - "requires": { - "user-home": "^1.1.1" - } - }, - "vinyl": { - "version": "0.4.6", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz", - "integrity": "sha1-LzVsh6VQolVGHza76ypbqL94SEc=", - "dev": true, - "requires": { - "clone": "^0.2.0", - "clone-stats": "^0.0.1" - } - }, - "vinyl-fs": { - "version": "0.3.14", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz", - "integrity": "sha1-mmhRzhysHBzqX+hsCTHWIMLPqeY=", - "dev": true, - "requires": { - "defaults": "^1.0.0", - "glob-stream": "^3.1.5", - "glob-watcher": "^0.0.6", - "graceful-fs": "^3.0.0", - "mkdirp": "^0.5.0", - "strip-bom": "^1.0.0", - "through2": "^0.6.1", - "vinyl": "^0.4.0" - } - } - } - }, - "gulp-inject-string": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/gulp-inject-string/-/gulp-inject-string-1.1.2.tgz", - "integrity": "sha512-+jhEyG+cEqvMdJgxD+7WkO/hDXz7AQl5aP9Rp+f23QaUDi5xme2YNvUjxCTlEySUapn27Pskcq9o8MsBBdvt4g==", - "dev": true, - "requires": { - "event-stream": "3.3.4", - "plugin-error": "^1.0.1" - }, - "dependencies": { - "event-stream": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", - "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", - "dev": true, - "requires": { - "duplexer": "~0.1.1", - "from": "~0", - "map-stream": "~0.1.0", - "pause-stream": "0.0.11", - "split": "0.3", - "stream-combiner": "~0.0.4", - "through": "~2.3.1" - } - }, - "map-stream": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", - "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", - "dev": true - }, - "split": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", - "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", - "dev": true, - "requires": { - "through": "2" - } - }, - "stream-combiner": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", - "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", - "dev": true, - "requires": { - "duplexer": "~0.1.1" - } - } - } - }, - "gulp-prettier": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gulp-prettier/-/gulp-prettier-3.0.0.tgz", - "integrity": "sha512-vZFyC1F+7EjuI2WDUOcbPt9o3ZjdqjFMjr8a9Yk2K8EmNhP1w6X01QAkv5Ym3dsHCBsBA4AEFcYds2vOTSgx0A==", - "dev": true, - "requires": { - "plugin-error": "^1.0.1", - "prettier": "^2.0.0", - "through2": "^3.0.0" - } - }, - "gulp-rename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz", - "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==", - "dev": true - }, - "gulp-trimlines": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gulp-trimlines/-/gulp-trimlines-1.0.1.tgz", - "integrity": "sha1-exeRa4UMoPBa9BkN0k6aweJunyY=", - "dev": true, - "requires": { - "through2": "^0.6.3" - }, - "dependencies": { - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "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" - } - }, - "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 - }, - "through2": { - "version": "0.6.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz", - "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=", - "dev": true, - "requires": { - "readable-stream": ">=1.0.33-1 <1.1.0-0", - "xtend": ">=4.0.0 <4.1.0-0" - } - } - } - }, - "gulp-util": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz", - "integrity": "sha1-AFTh50RQLifATBh8PsxQXdVLu08=", - "dev": true, - "requires": { - "array-differ": "^1.0.0", - "array-uniq": "^1.0.2", - "beeper": "^1.0.0", - "chalk": "^1.0.0", - "dateformat": "^2.0.0", - "fancy-log": "^1.1.0", - "gulplog": "^1.0.0", - "has-gulplog": "^0.1.0", - "lodash._reescape": "^3.0.0", - "lodash._reevaluate": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.template": "^3.0.0", - "minimist": "^1.1.0", - "multipipe": "^0.1.2", - "object-assign": "^3.0.0", - "replace-ext": "0.0.1", - "through2": "^2.0.0", - "vinyl": "^0.5.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "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 - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - }, - "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" - } - } - } - }, - "gulplog": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", - "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", - "dev": true, - "requires": { - "glogg": "^1.0.0" - } - }, - "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-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - } - } - }, - "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 - }, - "has-gulplog": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz", - "integrity": "sha1-ZBTIKRNpfaUVkDl9r7EvIpZ4Ec4=", - "dev": true, - "requires": { - "sparkles": "^1.0.0" - } - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "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 - }, - "homedir-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", - "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", - "dev": true, - "requires": { - "parse-passwd": "^1.0.0" - } - }, - "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 - }, - "html-loader": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-2.1.2.tgz", - "integrity": "sha512-XB4O1+6mpLp4qy/3qg5+1QPZ/uXvWtO64hNAX87sKHwcHkp1LJGU7V3sJ9iVmRACElAZXQ4YOO/Lbkx5kYfl9A==", - "dev": true, - "requires": { - "html-minifier-terser": "^5.1.1", - "parse5": "^6.0.1" - } - }, - "html-minifier-terser": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-5.1.1.tgz", - "integrity": "sha512-ZPr5MNObqnV/T9akshPKbVgyOqLmy+Bxo7juKCfTfnjNniTAMdy4hz21YQqoofMBJD2kdREaqPPdThoR78Tgxg==", - "dev": true, - "requires": { - "camel-case": "^4.1.1", - "clean-css": "^4.2.3", - "commander": "^4.1.1", - "he": "^1.2.0", - "param-case": "^3.0.3", - "relateurl": "^0.2.7", - "terser": "^4.6.3" - } - }, - "human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", - "dev": true, - "requires": {} - }, - "idb": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.2.tgz", - "integrity": "sha512-1DNDVu3yDhAZkFDlJf0t7r+GLZ248F5pTAtA7V0oVG3yjmV125qZOx3g0XpAEkGZVYQiFDAsSOnGet2bhugc3w==" - }, - "ignore": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", - "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - } - }, - "import-local": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", - "integrity": "sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", - "dev": true - }, - "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 - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true - }, - "inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "requires": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "dependencies": { - "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" - } - }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.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" - } - }, - "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 - }, - "has-flag": { - "version": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "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 - }, - "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" - } - } - } - }, - "interpret": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", - "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", - "dev": true - }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", - "dev": true - }, - "is-absolute": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", - "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", - "dev": true, - "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "is-binary-path": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", - "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", - "dev": true - }, - "is-core-module": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", - "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "dev": true - }, - "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 - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dev": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-negated-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", - "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", - "dev": true - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "is-path-cwd": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", - "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", - "dev": true - }, - "is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true - }, - "is-plain-object": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", - "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", - "dev": true - }, - "is-relative": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", - "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", - "dev": true, - "requires": { - "is-unc-path": "^1.0.0" - } - }, - "is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true - }, - "is-unc-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", - "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", - "dev": true, - "requires": { - "unc-path-regex": "^0.1.2" - } - }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", - "dev": true - }, - "is-valid-glob": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", - "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "jest-worker": { - "version": "27.0.2", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.0.2.tgz", - "integrity": "sha512-EoBdilOTTyOgmHXtw/cPc+ZrCA0KJMrkXzkrPGNwLmnvvlN1nj7MPrxpT7m+otSv2e1TLaVffzDnE/LB14zJMg==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.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": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "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 - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "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 - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", - "dev": true - }, - "json5": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", - "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "just-debounce": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.1.0.tgz", - "integrity": "sha512-qpcRocdkUmf+UTNBYx5w6dexX5J31AKK1OmPwH630a83DdVVUIngk55RSAiIGpQyoH0dlr872VHfPjnQnK1qDQ==", - "dev": true - }, - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - }, - "last-run": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", - "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", - "dev": true, - "requires": { - "default-resolution": "^2.0.0", - "es6-weak-map": "^2.0.1" - } - }, - "lazystream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", - "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", - "dev": true, - "requires": { - "readable-stream": "^2.0.5" - } - }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" - } - }, - "lead": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", - "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", - "dev": true, - "requires": { - "flush-write-stream": "^1.0.2" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "liftoff": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", - "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", - "dev": true, - "requires": { - "extend": "^3.0.0", - "findup-sync": "^3.0.0", - "fined": "^1.0.1", - "flagged-respawn": "^1.0.0", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.0", - "rechoir": "^0.6.2", - "resolve": "^1.1.7" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" - } - }, - "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true - }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "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" - } - }, - "lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true - }, - "lodash._basecopy": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", - "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", - "dev": true - }, - "lodash._basetostring": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz", - "integrity": "sha1-0YYdh3+CSlL2aYMtyvPuFVZqB9U=", - "dev": true - }, - "lodash._basevalues": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz", - "integrity": "sha1-W3dXYoAr3j0yl1A+JjAIIP32Ybc=", - "dev": true - }, - "lodash._getnative": { - "version": "3.9.1", - "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", - "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", - "dev": true - }, - "lodash._isiterateecall": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", - "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", - "dev": true - }, - "lodash._reescape": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz", - "integrity": "sha1-Kx1vXf4HyKNVdT5fJ/rH8c3hYWo=", - "dev": true - }, - "lodash._reevaluate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz", - "integrity": "sha1-WLx0xAZklTrgsSTYBpltrKQx4u0=", - "dev": true - }, - "lodash._reinterpolate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", - "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=", - "dev": true - }, - "lodash._root": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz", - "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=", - "dev": true - }, - "lodash.clonedeep": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", - "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", - "dev": true - }, - "lodash.escape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz", - "integrity": "sha1-mV7g3BjBtIzJLv+ucaEKq1tIdpg=", - "dev": true, - "requires": { - "lodash._root": "^3.0.0" - } - }, - "lodash.isarguments": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", - "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", - "dev": true - }, - "lodash.isarray": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", - "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", - "dev": true - }, - "lodash.keys": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", - "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", - "dev": true, - "requires": { - "lodash._getnative": "^3.0.0", - "lodash.isarguments": "^3.0.0", - "lodash.isarray": "^3.0.0" - } - }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "lodash.restparam": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz", - "integrity": "sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU=", - "dev": true - }, - "lodash.template": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz", - "integrity": "sha1-+M3sxhaaJVvpCYrosMU9N4kx0U8=", - "dev": true, - "requires": { - "lodash._basecopy": "^3.0.0", - "lodash._basetostring": "^3.0.0", - "lodash._basevalues": "^3.0.0", - "lodash._isiterateecall": "^3.0.0", - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0", - "lodash.keys": "^3.0.0", - "lodash.restparam": "^3.0.0", - "lodash.templatesettings": "^3.0.0" - } - }, - "lodash.templatesettings": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz", - "integrity": "sha1-+zB4RHU7Zrnxr6VOJix0UwfbqOU=", - "dev": true, - "requires": { - "lodash._reinterpolate": "^3.0.0", - "lodash.escape": "^3.0.0" - } - }, - "lodash.truncate": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", - "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", - "dev": true - }, - "lower-case": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", - "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", - "dev": true, - "requires": { - "tslib": "^2.0.3" - } - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "requires": { - "yallist": "^4.0.0" - } - }, - "make-iterator": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", - "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - }, - "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-stream": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz", - "integrity": "sha1-ih8HiW2CsQkmvTdEokIACfiJdKg=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "matchdep": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", - "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", - "dev": true, - "requires": { - "findup-sync": "^2.0.0", - "micromatch": "^3.0.4", - "resolve": "^1.4.0", - "stack-trace": "0.0.10" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "findup-sync": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", - "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", - "dev": true, - "requires": { - "detect-file": "^1.0.0", - "is-glob": "^3.1.0", - "micromatch": "^3.0.4", - "resolve-dir": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-glob": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", - "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } - } - }, - "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 - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", - "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", - "dev": true, - "requires": { - "braces": "^3.0.1", - "picomatch": "^2.2.3" - - } - }, - "mime-db": { - "version": "1.48.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.48.0.tgz", - "integrity": "sha512-FM3QwxV+TnZYQ2aRqhlKBMHxk10lTbMt3bBkMAp54ddrNeVSfcQYOOKuGuy3Ddrm38I04If834fOUSq1yzslJQ==", - "dev": true - }, - "mime-types": { - "version": "2.1.31", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.31.tgz", - "integrity": "sha512-XGZnNzm3QvgKxa8dpzyhFTHmpP3l5YNusmne07VUOXxou9CqUqYa/HBy124RqtVh/O2pECas/MOcsDgpilPOPg==", - "dev": true, - "requires": { - "mime-db": "1.48.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "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.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } - } - }, - "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" - } - }, - "mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", - "dev": true - }, - "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 - }, - "multimatch": { + "escape-string-regexp": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", - "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", - "dev": true, - "requires": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - }, - "dependencies": { - "array-differ": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", - "dev": true - } - } - }, - "multipipe": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz", - "integrity": "sha1-Ko8t33Du1WTf8tV/HhoTfZ8FB4s=", - "dev": true, - "requires": { - "duplexer2": "0.0.2" - } - }, - "mute-stdout": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", - "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", - "dev": true, - "optional": true - }, - "nanoid": { - "version": "3.1.23", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.23.tgz", - "integrity": "sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } - } - }, - "natives": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.6.tgz", - "integrity": "sha512-6+TDFewD4yxY14ptjKaS63GVdtKiES1pTPyxn9Jb0rBqPMZ7VcCiooEhPNsr+mqHtMGxa/5c/HhcC4uPEUw/nA==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "no-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", - "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", - "dev": true, - "requires": { - "lower-case": "^2.0.2", - "tslib": "^2.0.3" - } - }, - "node-releases": { - "version": "1.1.73", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.73.tgz", - "integrity": "sha512-uW7fodD6pyW2FZNZnp/Z3hvWKeEW1Y8R1+1CnErE8cXFXzl5blBOoVB41CvMer6P6Q0S5FXDwcHgFd1Wj0U9zg==", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, - "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==", + "eslint": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.11.0.tgz", + "integrity": "sha512-/KRpd9mIRg2raGxHRGwW9ZywYNAClZrHjdueHcrVDuO3a6bj83eoTirCCk0M0yPwOjWYKHwRVRid+xK4F/GHgA==", "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" + "@eslint/eslintrc": "^1.2.1", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.3.0", + "espree": "^9.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "regexpp": "^3.2.0", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" }, "dependencies": { - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "dev": true } } }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "eslint-config-prettier": { + "version": "8.5.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.5.0.tgz", + "integrity": "sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==", + "dev": true, + "requires": {} + }, + "eslint-plugin-local-rules": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-local-rules/-/eslint-plugin-local-rules-1.1.0.tgz", + "integrity": "sha512-FdPyzxakUKgZkeNM3x/vvRcB6nCjTNbui5gWALhvcaH1R6aCiD37fWtdesagcyBpEe9S9XRHAJ8CJ4rUJ3K9tQ==", "dev": true }, - "now-and-later": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", - "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "eslint-plugin-prettier": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-4.0.0.tgz", + "integrity": "sha512-98MqmCJ7vJodoQK359bqQWaxOE0CS8paAz/GgjaZLyex4TTk3g9HugoO89EqWCrFiOqn9EVvcoo7gZzONCWVwQ==", "dev": true, "requires": { - "once": "^1.3.2" + "prettier-linter-helpers": "^1.0.0" } }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "requires": { - "path-key": "^3.0.0" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true - }, - "object-assign": { + "eslint-utils": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz", - "integrity": "sha1-m+3VygiXlJvKR+f/QIBi1Un1h/I=", - "dev": true - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", "dev": true, "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "eslint-visitor-keys": "^2.0.0" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "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==", + "eslint-visitor-keys": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.3.0.tgz", + "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "eslint-webpack-plugin": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz", + "integrity": "sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg==", "dev": true, "requires": { - "isobject": "^3.0.0" + "@types/eslint": "^7.28.2", + "jest-worker": "^27.3.1", + "micromatch": "^4.0.4", + "normalize-path": "^3.0.0", + "schema-utils": "^3.1.1" } }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "espree": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.1.tgz", + "integrity": "sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==", "dev": true, "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.3.0" } }, - "object.defaults": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", - "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", "dev": true, "requires": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, - "object.map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", - "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "dev": true, "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } } }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true }, - "object.reduce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", - "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", - "dev": true, - "requires": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" - } + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", "dev": true, "requires": { - "mimic-fn": "^2.1.0" + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" } }, - "optionator": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", - "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "fancy-log": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-2.0.0.tgz", + "integrity": "sha512-9CzxZbACXMUXW13tS0tI8XsGGmxWzO2DmYrGuBJOJ8k8q2K7hwfJA5qHjuPPe8wtsco33YR9wc+Rlr5wYFvhSA==", "dev": true, "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.3" + "color-support": "^1.1.3" } }, - "orchestrator": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz", - "integrity": "sha1-FOfp4nZPcxX7rBhOUGx6pt+UrX4=", + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-diff": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz", + "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==", + "dev": true + }, + "fast-glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.11.tgz", + "integrity": "sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==", "dev": true, "requires": { - "end-of-stream": "~0.1.5", - "sequencify": "~0.0.7", - "stream-consume": "~0.1.0" + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" }, "dependencies": { - "end-of-stream": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz", - "integrity": "sha1-jhdyBsPICDfYVjLouTWd/osvbq8=", - "dev": true, - "requires": { - "once": "~1.3.0" - } - }, - "once": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz", - "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=", + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "requires": { - "wrappy": "1" + "is-glob": "^4.0.1" } } } }, - "ordered-read-streams": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", - "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", - "dev": true, - "requires": { - "readable-stream": "^2.0.1" - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "^1.0.0" - } - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "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": "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" - } - }, - "p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dev": true, - "requires": { - "aggregate-error": "^3.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==", + "fastest-levenshtein": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", + "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", "dev": true }, - "param-case": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", - "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", "dev": true, "requires": { - "dot-case": "^3.0.4", - "tslib": "^2.0.3" + "reusify": "^1.0.4" } }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", "dev": true, "requires": { - "callsites": "^3.0.0" + "flat-cache": "^3.0.4" } }, - "parse-filepath": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", - "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", "dev": true, "requires": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" + "to-regex-range": "^5.0.1" } }, - "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "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": { - "error-ex": "^1.2.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, - "parse-node-version": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", - "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", - "dev": true - }, - "parse-passwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", - "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", - "dev": true - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "pascal-case": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", - "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", "dev": true, "requires": { - "no-case": "^3.0.4", - "tslib": "^2.0.3" + "flatted": "^3.1.0", + "rimraf": "^3.0.2" } }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "flatted": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.5.tgz", + "integrity": "sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==", "dev": true }, - "path-dirname": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", - "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", "dev": true }, - "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==", + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", "dev": true }, - "path-is-absolute": { + "functional-red-black-tree": { "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-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", "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 + "geodesy": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/geodesy/-/geodesy-2.3.0.tgz", + "integrity": "sha512-SZIJ8DfIzn5XD5IyNGRQBpTy0mQAn/M3uKgPBcVx4uVVpyIM7tNIJ3mL6dQn+31T/gI6TBdslqLmuQQybeZCqA==" }, - "path-root": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", - "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", "dev": true, "requires": { - "path-root-regex": "^0.1.0" + "pump": "^3.0.0" } }, - "path-root-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", - "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", - "dev": true - }, - "path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true - }, - "pause-stream": { - "version": "0.0.11", - "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", - "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", "dev": true, "requires": { - "through": "~2.3" + "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" } }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "dev": true - }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", - "dev": true + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "globals": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.13.0.tgz", + "integrity": "sha512-EQ7Q18AJlPwp3vUDL4mKA0KXrXyNIQyWon6T6XQiBQF0XHvRsiCSrWmmeATpUzdJN2HhWZU6Pdl0a9zdep5p6A==", "dev": true, "requires": { - "pinkie": "^2.0.0" + "type-fest": "^0.20.2" } }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", "dev": true, "requires": { - "find-up": "^4.0.0" + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" } }, - "plugin-error": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", - "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", + "dev": true + }, + "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": { - "ansi-colors": "^1.0.1", - "arr-diff": "^4.0.0", - "arr-union": "^3.1.0", - "extend-shallow": "^3.0.2" - }, - "dependencies": { - "ansi-colors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", - "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", - "dev": true, - "requires": { - "ansi-wrap": "^0.1.0" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } + "function-bind": "^1.1.1" } }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "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 }, - "postcss": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.3.0.tgz", - "integrity": "sha512-+ogXpdAjWGa+fdYY5BQ96V/6tAo+TdSSIMP5huJBIygdWwKtVoB5JWZ7yUd4xZ8r+8Kvvx4nyg/PQ071H4UtcQ==", + "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 + }, + "html-loader": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/html-loader/-/html-loader-3.1.0.tgz", + "integrity": "sha512-ycMYFRiCF7YANcLDNP72kh3Po5pTcH+bROzdDwh00iVOAY/BwvpuZ1BKPziQ35Dk9D+UD84VGX1Lu/H4HpO4fw==", "dev": true, "requires": { - "colorette": "^1.2.2", - "nanoid": "^3.1.23", - "source-map-js": "^0.6.2" + "html-minifier-terser": "^6.0.2", + "parse5": "^6.0.1" } }, - "postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "html-minifier-terser": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", + "integrity": "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==", + "dev": true, + "requires": { + "camel-case": "^4.1.2", + "clean-css": "^5.2.2", + "commander": "^8.3.0", + "he": "^1.2.0", + "param-case": "^3.0.4", + "relateurl": "^0.2.7", + "terser": "^5.10.0" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "dev": true + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", "dev": true, "requires": {} }, - "postcss-modules-local-by-default": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", - "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", + "idb": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/idb/-/idb-7.0.1.tgz", + "integrity": "sha512-UUxlE7vGWK5RfB/fDwEGgRf84DY/ieqNha6msMV99UsEMQhJ1RwbCd8AYBj3QMgnE3VZnfQvm4oKVCJTYlqIgg==" + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", "dev": true, "requires": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" } }, - "postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", "dev": true, "requires": { - "postcss-selector-parser": "^6.0.4" + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" } }, - "postcss-modules-values": { + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "indent-string": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, - "requires": { - "icss-utils": "^5.0.0" - } + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true }, - "postcss-selector-parser": { - "version": "6.0.6", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz", - "integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==", + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, "requires": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "once": "^1.3.0", + "wrappy": "1" } }, - "postcss-value-parser": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz", - "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "prettier": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz", - "integrity": "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA==", + "interpret": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", + "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true }, - "prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "is-arrayish": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz", + "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" + }, + "is-core-module": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", + "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", "dev": true, "requires": { - "fast-diff": "^1.1.2" + "has": "^1.0.3" } }, - "pretty-hrtime": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", - "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", "dev": true }, - "pretty-quick": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.0.tgz", - "integrity": "sha512-DtxIxksaUWCgPFN7E1ZZk4+Aav3CCuRdhrDSFZENb404sYMtuo9Zka823F+Mgeyt8Zt3bUiCjFzzWYE9LYqkmQ==", + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, "requires": { - "chalk": "^3.0.0", - "execa": "^4.0.0", - "find-up": "^4.1.0", - "ignore": "^5.1.4", - "mri": "^1.1.5", - "multimatch": "^4.0.0" - }, - "dependencies": { - "chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.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" - } - }, - "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" - } - }, - "has-flag": { - "version": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" - }, - "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 - } + "is-extglob": "^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==", + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, - "progress": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", - "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "is-path-cwd": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz", + "integrity": "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==", "dev": true }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "isobject": "^3.0.1" } }, - "pumpify": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", - "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", "dev": true, "requires": { - "duplexify": "^3.6.0", - "inherits": "^2.0.3", - "pump": "^2.0.0" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "dependencies": { - "pump": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", - "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "dev": true, "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" + "has-flag": "^4.0.0" } } } }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "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 }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", "dev": true, "requires": { - "safe-buffer": "^5.1.0" + "minimist": "^1.2.5" } }, - "raw-loader": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", - "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, - "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "dev": true + }, + "loader-utils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", + "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" - }, - "dependencies": { - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - } + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" } }, - "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "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": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "dev": true, - "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" - } - }, - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } - } + "p-locate": "^4.1.0" } }, - "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==", + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", "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" - }, - "dependencies": { - "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 - } + "tslib": "^2.0.3" } }, - "readdirp": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", - "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - } - } + "yallist": "^4.0.0" } }, - "rechoir": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", - "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "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 + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", "dev": true, "requires": { - "resolve": "^1.1.6" + "braces": "^3.0.1", + "picomatch": "^2.2.3" } }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } + "mime-db": "1.52.0" } }, - "regexpp": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.1.0.tgz", - "integrity": "sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==", - "dev": true - }, - "relateurl": { - "version": "0.2.7", - "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", - "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, - "remove-bom-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", - "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { - "is-buffer": "^1.1.5", - "is-utf8": "^0.2.1" + "brace-expansion": "^1.1.7" } }, - "remove-bom-stream": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mri": { "version": "1.2.0", - "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", - "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true + }, + "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 + }, + "multimatch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", "dev": true, "requires": { - "remove-bom-buffer": "^3.0.0", - "safe-buffer": "^5.1.0", - "through2": "^2.0.3" - }, - "dependencies": { - "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" - } - } + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" } }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz", - "integrity": "sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ==", + "nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", "dev": true }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", "dev": true }, - "replace-ext": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz", - "integrity": "sha1-KbvZIHinOfC8zitO5B6DeVNSKSQ=", + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, - "replace-homedir": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", - "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", "dev": true, "requires": { - "homedir-polyfill": "^1.0.1", - "is-absolute": "^1.0.0", - "remove-trailing-separator": "^1.1.0" + "lower-case": "^2.0.2", + "tslib": "^2.0.3" } }, - "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-from-string": { + "node-releases": { "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.2.tgz", + "integrity": "sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==", "dev": true }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", "dev": true, "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" + "path-key": "^3.0.0" } }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", "dev": true, "requires": { - "resolve-from": "^5.0.0" - }, - "dependencies": { - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - } + "wrappy": "1" } }, - "resolve-dir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", - "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", "dev": true, "requires": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "mimic-fn": "^2.1.0" } }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } }, - "resolve-options": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", - "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "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": { - "value-or-function": "^3.0.0" + "p-try": "^2.0.0" } }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "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" + } }, - "restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dev": true, "requires": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "aggregate-error": "^3.0.0" } }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "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 }, - "reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "param-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz", + "integrity": "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==", + "dev": true, + "requires": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse5": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", + "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", "dev": true }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "pascal-case": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz", + "integrity": "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==", "dev": true, "requires": { - "glob": "^7.1.3" + "no-case": "^3.0.4", + "tslib": "^2.0.3" } }, - "run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", + "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 + }, + "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-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "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 + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "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.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", "dev": true, "requires": { - "queue-microtask": "^1.2.2" + "find-up": "^4.0.0" } }, - "rxjs": { - "version": "6.6.7", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", - "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "postcss": { + "version": "8.4.12", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.12.tgz", + "integrity": "sha512-lg6eITwYe9v6Hr5CncVbK70SoioNQIq81nsaG86ev5hAidQvmOeETBqs7jm43K2F5/Ley3ytDtriImV6TpNiSg==", "dev": true, "requires": { - "tslib": "^1.9.0" - }, - "dependencies": { - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - } + "nanoid": "^3.3.1", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" } }, - "safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "dev": true, + "requires": {} }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "postcss-modules-local-by-default": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz", + "integrity": "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==", "dev": true, "requires": { - "ret": "~0.1.10" + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" } }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "schema-utils": { + "postcss-modules-scope": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.0.0.tgz", - "integrity": "sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", "dev": true, "requires": { - "@types/json-schema": "^7.0.6", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "postcss-selector-parser": "^6.0.4" } }, - "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, "requires": { - "lru-cache": "^6.0.0" + "icss-utils": "^5.0.0" } }, - "semver-greatest-satisfied-range": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", - "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "postcss-selector-parser": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.9.tgz", + "integrity": "sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==", "dev": true, "requires": { - "sver-compat": "^1.5.0" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" } }, - "sequencify": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz", - "integrity": "sha1-kM/xnQLgcCf9dn9erT57ldHnOAw=", + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", "dev": true }, - "serialize-javascript": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-5.0.1.tgz", - "integrity": "sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "prettier": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.6.0.tgz", + "integrity": "sha512-m2FgJibYrBGGgQXNzfd0PuDGShJgRavjUoRCw1mZERIWVSXF0iLzLm+aOqTAbLnC3n6JzUhAA8uZnFVghHJ86A==", "dev": true }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", "dev": true, "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - }, - "dependencies": { - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } + "fast-diff": "^1.1.2" } }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "pretty-quick": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.3.tgz", + "integrity": "sha512-kOCi2FJabvuh1as9enxYmrnBC6tVMoVOenMaBqRfsvBHB0cbpYHjdQEpSglpASDFEXVwplpcGR4CLEaisYAFcA==", "dev": true, "requires": { - "kind-of": "^6.0.2" + "chalk": "^3.0.0", + "execa": "^4.0.0", + "find-up": "^4.1.0", + "ignore": "^5.1.4", + "mri": "^1.1.5", + "multimatch": "^4.0.0" }, "dependencies": { - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true + "chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } } } }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", "dev": true, "requires": { - "shebang-regex": "^3.0.0" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", "dev": true }, - "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, "requires": { - "is-arrayish": "^0.3.1" + "safe-buffer": "^5.1.0" } }, - "slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true + "raw-loader": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/raw-loader/-/raw-loader-4.0.2.tgz", + "integrity": "sha512-ZnScIV3ag9A4wPX/ZayxL/jZH+euYb6FcUinPcgiQW0+UBtEv0O6Q3lGd3cqJ+GHH+rksEv3Pj99oxJ3u3VIKA==", + "dev": true, + "requires": { + "loader-utils": "^2.0.0", + "schema-utils": "^3.0.0" + } }, - "slice-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", - "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "astral-regex": "^2.0.0", - "is-fullwidth-code-point": "^3.0.0" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", - "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 - } + "resolve": "^1.9.0" } }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "relateurl": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz", + "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=", + "dev": true + }, + "resolve": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", + "integrity": "sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==", "dev": true, "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - } + "is-core-module": "^2.8.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" } }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", "dev": true, "requires": { - "kind-of": "^3.2.0" + "resolve-from": "^5.0.0" }, "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true } } }, - "sortablejs": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.13.0.tgz", - "integrity": "sha512-RBJirPY0spWCrU5yCmWM1eFs/XgX2J5c6b275/YyxFRgnzPhKl/TDeU2hNR8Dt7ITq66NRPM4UlOt+e5O4CFHg==" - }, - "source-list-map": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", - "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true }, - "source-map-js": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz", - "integrity": "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug==", + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", "dev": true }, - "source-map-resolve": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", - "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "glob": "^7.1.3" } }, - "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==", + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" + "queue-microtask": "^1.2.2" } }, - "source-map-url": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz", - "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==", - "dev": true - }, - "sparkles": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", - "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, - "spdx-correct": { + "schema-utils": { "version": "3.1.1", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", - "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", + "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", "dev": true, "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" } }, - "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==", + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", "dev": true, "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "lru-cache": "^6.0.0" } }, - "spdx-license-ids": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", - "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", - "dev": true + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } }, - "split": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/split/-/split-1.0.1.tgz", - "integrity": "sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==", + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, "requires": { - "through": "2" + "kind-of": "^6.0.2" } }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "requires": { - "extend-shallow": "^3.0.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - } + "shebang-regex": "^3.0.0" } }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, - "stack-trace": { - "version": "0.0.10", - "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", - "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - } - }, - "stream-combiner": { + "simple-swizzle": { "version": "0.2.2", - "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", - "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", - "dev": true, + "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", + "integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=", "requires": { - "duplexer": "~0.1.1", - "through": "~2.3.4" + "is-arrayish": "^0.3.1" } }, - "stream-consume": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.1.tgz", - "integrity": "sha512-tNa3hzgkjEP7XbCkbRXe1jpg+ievoa0O4SCFlMOYEscGSS4JJsckGL8swUyAa/ApGU3Ae4t6Honor4HhL+tRyg==", + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, - "stream-exhaust": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", - "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "sortablejs": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/sortablejs/-/sortablejs-1.14.0.tgz", + "integrity": "sha512-pBXvQCs5/33fdN1/39pPL0NZF20LeRbLQ5jtnheIPN9JQAaufGjKdWduZn4U7wCtVuzKhmRkI0DFYHYRbB2H1w==" + }, + "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 }, - "stream-shift": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", - "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", "dev": true }, - "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==", + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" - }, - "dependencies": { - "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 - } + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" } }, - "string-width": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", - "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" + "safe-buffer": "~5.2.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" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "ansi-regex": "^5.0.1" } }, "strip-final-newline": { @@ -16803,14 +5956,11 @@ "dev": true }, "style-loader": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz", - "integrity": "sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz", + "integrity": "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==", "dev": true, - "requires": { - "loader-utils": "^2.0.0", - "schema-utils": "^3.0.0" - } + "requires": {} }, "supports-color": { "version": "7.2.0", @@ -16821,324 +5971,85 @@ "has-flag": "^4.0.0" } }, - "sver-compat": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", - "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", - "dev": true, - "requires": { - "es6-iterator": "^2.0.1", - "es6-symbol": "^3.1.1" - } - }, - "table": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", - "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", - "dev": true, - "requires": { - "ajv": "^8.0.1", - "lodash.clonedeep": "^4.5.0", - "lodash.truncate": "^4.4.2", - "slice-ansi": "^4.0.0", - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ajv": { - "version": "8.6.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.0.tgz", - "integrity": "sha512-cnUG4NSBiM4YFBxgZIj/In3/6KX+rQ2l2YPRVcvAMQGWEPKuXoPIhxzwqh31jA3IPbI4qEOp/5ILI4ynioXsGQ==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - } - }, - "json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - } - } + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true }, "tapable": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.0.tgz", - "integrity": "sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==", + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", "dev": true }, "terser": { - "version": "4.8.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz", - "integrity": "sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.6.1", - "source-map-support": "~0.5.12" - }, - "dependencies": { - "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 - } - } - }, - "terser-webpack-plugin": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.1.3.tgz", - "integrity": "sha512-cxGbMqr6+A2hrIB5ehFIF+F/iST5ZOxvOmy9zih9ySbP1C2oEWQSOUS+2SNBTjzx5xLKO4xnod9eywdfq1Nb9A==", - "dev": true, - "requires": { - "jest-worker": "^27.0.2", - "p-limit": "^3.1.0", - "schema-utils": "^3.0.0", - "serialize-javascript": "^5.0.1", - "source-map": "^0.6.1", - "terser": "^5.7.0" - }, - "dependencies": { - "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 - }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "requires": { - "yocto-queue": "^0.1.0" - } - }, - "terser": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.0.tgz", - "integrity": "sha512-HP5/9hp2UaZt5fYkuhNBR8YyRcT8juw8+uFbAme53iN9hblvKnLUTKkmwJG6ocWpIKf8UK4DoeWG4ty0J6S6/g==", - "dev": true, - "requires": { - "commander": "^2.20.0", - "source-map": "~0.7.2", - "source-map-support": "~0.5.19" - }, - "dependencies": { - "source-map": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", - "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", - "dev": true - } - } - } - } - }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", - "dev": true - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", - "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", - "dev": true, - "requires": { - "inherits": "^2.0.4", - "readable-stream": "2 || 3" - } - }, - "through2-filter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", - "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", - "dev": true, - "requires": { - "through2": "~2.0.0", - "xtend": "~4.0.0" - }, - "dependencies": { - "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" - } - } - } - }, - "tildify": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz", - "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=", - "dev": true, - "requires": { - "os-homedir": "^1.0.0" - } - }, - "time-stamp": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", - "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", - "dev": true - }, - "tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "requires": { - "os-tmpdir": "~1.0.2" - } - }, - "to-absolute-glob": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", - "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", - "dev": true, - "requires": { - "is-absolute": "^1.0.0", - "is-negated-glob": "^1.0.0" - } - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.12.1.tgz", + "integrity": "sha512-NXbs+7nisos5E+yXwAD+y7zrcTkMqb0dEJxIGtSKPdCBzopf7ni4odPul2aechpV7EXNvOudYOX2bb5tln1jbQ==", + "dev": true, + "requires": { + "acorn": "^8.5.0", + "commander": "^2.20.0", + "source-map": "~0.7.2", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "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 }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true } } }, + "terser-webpack-plugin": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", + "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", + "dev": true, + "requires": { + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.0", + "source-map": "^0.6.1", + "terser": "^5.7.2" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dev": true, + "requires": { + "readable-stream": "3" + } + }, "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "is-number": "^7.0.0" } }, "to-string-loader": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.1.6.tgz", - "integrity": "sha512-VNg62//PS1WfNwrK3n7t6wtK5Vdtx/qeYLLEioW46VMlYUwAYT6wnfB+OwS2FMTCalIHu0tk79D3RXX8ttmZTQ==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/to-string-loader/-/to-string-loader-1.2.0.tgz", + "integrity": "sha512-KsWUL8FccgBW9FPFm4vYoQbOOcO5m6hKOGYoXjbseD9/4Ft+ravXN5jolQ9kTKYcK4zPt1j+khx97GPGnVoi6A==", "dev": true, "requires": { "loader-utils": "^1.0.0" @@ -17166,38 +6077,40 @@ } } }, - "to-through": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", - "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "ts-loader": { + "version": "9.2.8", + "resolved": "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.8.tgz", + "integrity": "sha512-gxSak7IHUuRtwKf3FIPSW1VpZcqF9+MBrHOvBp9cjHh+525SjtCIJKVGjRKIAfxBwDGDGCFF00rTfzB1quxdSw==", "dev": true, "requires": { - "through2": "^2.0.3" - }, - "dependencies": { - "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" - } - } + "chalk": "^4.1.0", + "enhanced-resolve": "^5.0.0", + "micromatch": "^4.0.0", + "semver": "^7.3.4" } }, "tslib": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", - "integrity": "sha512-gS9GVHRU+RGn5KQM2rllAlR3dU6m7AcpJKdtH8gFvQiC4Otgk98XnmMU+nZenHt/+VhnBPWwgrJsyrdcw6i23w==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", + "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==", "dev": true }, - "type": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", - "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==", - "dev": true + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } }, "type-check": { "version": "0.4.0", @@ -17214,116 +6127,10 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true }, - "typedarray": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", - "dev": true - }, - "unc-path-regex": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", - "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", - "dev": true - }, - "undertaker": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.3.0.tgz", - "integrity": "sha512-/RXwi5m/Mu3H6IHQGww3GNt1PNXlbeCuclF2QYR14L/2CHPz3DFZkvB5hZ0N/QUkiXWCACML2jXViIQEQc2MLg==", - "dev": true, - "requires": { - "arr-flatten": "^1.0.1", - "arr-map": "^2.0.0", - "bach": "^1.0.0", - "collection-map": "^1.0.0", - "es6-weak-map": "^2.0.1", - "fast-levenshtein": "^1.0.0", - "last-run": "^1.1.0", - "object.defaults": "^1.0.0", - "object.reduce": "^1.0.0", - "undertaker-registry": "^1.0.0" - }, - "dependencies": { - "fast-levenshtein": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.1.4.tgz", - "integrity": "sha1-5qdUzI8V5YmHqpy9J69m/W9OWvk=", - "dev": true - } - } - }, - "undertaker-registry": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", - "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", - "dev": true - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unique-stream": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", - "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", - "dev": true, - "requires": { - "json-stable-stringify-without-jsonify": "^1.0.1", - "through2-filter": "^3.0.0" - } - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - } - } - }, - "upath": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz", - "integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==", + "typescript": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.2.tgz", + "integrity": "sha512-HM/hFigTBHZhLXshn9sN37H085+hQGeJHJ/X7LpBWLID/fbc2acUMfU+lGD98X81sKP+pFa9f0DZmCwB9GnbAg==", "dev": true }, "uri-js": { @@ -17335,12 +6142,6 @@ "punycode": "^2.1.0" } }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, "url-loader": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-4.1.1.tgz", @@ -17352,18 +6153,6 @@ "schema-utils": "^3.0.0" } }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "user-home": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz", - "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", - "dev": true - }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -17376,173 +6165,10 @@ "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", "dev": true }, - "v8flags": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", - "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", - "dev": true, - "requires": { - "homedir-polyfill": "^1.0.1" - } - }, - "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" - } - }, - "value-or-function": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", - "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", - "dev": true - }, - "vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "requires": { - "clone": "^1.0.0", - "clone-stats": "^0.0.1", - "replace-ext": "0.0.1" - } - }, - "vinyl-fs": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", - "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", - "dev": true, - "requires": { - "fs-mkdirp-stream": "^1.0.0", - "glob-stream": "^6.1.0", - "graceful-fs": "^4.0.0", - "is-valid-glob": "^1.0.0", - "lazystream": "^1.0.0", - "lead": "^1.0.0", - "object.assign": "^4.0.4", - "pumpify": "^1.3.5", - "readable-stream": "^2.3.3", - "remove-bom-buffer": "^3.0.0", - "remove-bom-stream": "^1.2.0", - "resolve-options": "^1.1.0", - "through2": "^2.0.0", - "to-through": "^2.0.0", - "value-or-function": "^3.0.0", - "vinyl": "^2.0.0", - "vinyl-sourcemap": "^1.1.0" - }, - "dependencies": { - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "replace-ext": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", - "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", - "dev": true - }, - "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" - } - }, - "vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } - } - }, - "vinyl-sourcemap": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", - "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", - "dev": true, - "requires": { - "append-buffer": "^1.0.2", - "convert-source-map": "^1.5.0", - "graceful-fs": "^4.1.6", - "normalize-path": "^2.1.1", - "now-and-later": "^2.0.0", - "remove-bom-buffer": "^3.0.0", - "vinyl": "^2.0.0" - }, - "dependencies": { - "clone": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", - "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", - "dev": true - }, - "clone-stats": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", - "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", - "dev": true - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "replace-ext": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz", - "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==", - "dev": true - }, - "vinyl": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz", - "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==", - "dev": true, - "requires": { - "clone": "^2.1.1", - "clone-buffer": "^1.0.0", - "clone-stats": "^1.0.0", - "cloneable-readable": "^1.0.0", - "remove-trailing-separator": "^1.0.1", - "replace-ext": "^1.0.0" - } - } - } - }, "watchpack": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.2.0.tgz", - "integrity": "sha512-up4YAn/XHgZHIxFBVCdlMiWDj6WaLKpwVeGQk2I5thdYxF/KmF0aaz6TfJZ/hfl1h/XlcDr7k1KH7ThDagpFaA==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", + "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", "dev": true, "requires": { "glob-to-regexp": "^0.4.1", @@ -17550,68 +6176,54 @@ } }, "webpack": { - "version": "5.38.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.38.1.tgz", - "integrity": "sha512-OqRmYD1OJbHZph6RUMD93GcCZy4Z4wC0ele4FXyYF0J6AxO1vOSuIlU1hkS/lDlR9CDYBz64MZRmdbdnFFoT2g==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.0", - "@types/estree": "^0.0.47", - "@webassemblyjs/ast": "1.11.0", - "@webassemblyjs/wasm-edit": "1.11.0", - "@webassemblyjs/wasm-parser": "1.11.0", - "acorn": "^8.2.1", + "version": "5.70.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.70.0.tgz", + "integrity": "sha512-ZMWWy8CeuTTjCxbeaQI21xSswseF2oNOwc70QSKNePvmxE7XW36i7vpBMYZFAUHPwQiEbNGCEYIOOlyRbdGmxw==", + "dev": true, + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^0.0.51", + "@webassemblyjs/ast": "1.11.1", + "@webassemblyjs/wasm-edit": "1.11.1", + "@webassemblyjs/wasm-parser": "1.11.1", + "acorn": "^8.4.1", + "acorn-import-assertions": "^1.7.6", "browserslist": "^4.14.5", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.8.0", - "es-module-lexer": "^0.4.0", + "enhanced-resolve": "^5.9.2", + "es-module-lexer": "^0.9.0", "eslint-scope": "5.1.1", "events": "^3.2.0", "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.4", + "graceful-fs": "^4.2.9", "json-parse-better-errors": "^1.0.2", "loader-runner": "^4.2.0", "mime-types": "^2.1.27", "neo-async": "^2.6.2", - "schema-utils": "^3.0.0", + "schema-utils": "^3.1.0", "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.1", - "watchpack": "^2.2.0", - "webpack-sources": "^2.3.0" - }, - "dependencies": { - "@types/estree": { - "version": "0.0.47", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.47.tgz", - "integrity": "sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==", - "dev": true - }, - "acorn": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.3.0.tgz", - "integrity": "sha512-tqPKHZ5CaBJw0Xmy0ZZvLs1qTV+BNFSyvn77ASXkpBNfIRk8ev26fKrD9iLGwGA9zedPao52GSHzq8lyZG0NUw==", - "dev": true - } + "terser-webpack-plugin": "^5.1.3", + "watchpack": "^2.3.1", + "webpack-sources": "^3.2.3" } }, "webpack-cli": { - "version": "4.7.1", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.1.tgz", - "integrity": "sha512-DJPd63AY53KXWOaD8cB8CaHR0epVP4O4GBIAk6wCPQHJugrAQ0B5kUkCg0c9vkIrD2kA6CXCmtWqKQsiVTo15A==", + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", + "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", "dev": true, "requires": { "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.0.4", - "@webpack-cli/info": "^1.3.0", - "@webpack-cli/serve": "^1.5.0", - "colorette": "^1.2.1", + "@webpack-cli/configtest": "^1.1.1", + "@webpack-cli/info": "^1.4.1", + "@webpack-cli/serve": "^1.6.1", + "colorette": "^2.0.14", "commander": "^7.0.0", "execa": "^5.0.0", "fastest-levenshtein": "^1.0.12", "import-local": "^3.0.2", "interpret": "^2.2.0", "rechoir": "^0.7.0", - "v8-compile-cache": "^2.2.0", "webpack-merge": "^5.7.3" }, "dependencies": { @@ -17649,21 +6261,6 @@ "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true - }, - "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true - }, - "rechoir": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.0.tgz", - "integrity": "sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==", - "dev": true, - "requires": { - "resolve": "^1.9.0" - } } } }, @@ -17678,14 +6275,10 @@ } }, "webpack-sources": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-2.3.0.tgz", - "integrity": "sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==", - "dev": true, - "requires": { - "source-list-map": "^2.0.1", - "source-map": "^0.6.1" - } + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "dev": true }, "which": { "version": "2.0.2", @@ -17696,12 +6289,6 @@ "isexe": "^2.0.0" } }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, "wildcard": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", @@ -17714,159 +6301,17 @@ "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", "dev": true }, - "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", - "dev": true, - "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", "dev": true }, - "write": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/write/-/write-1.0.3.tgz", - "integrity": "sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==", - "dev": true, - "requires": { - "mkdirp": "^0.5.1" - } - }, - "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": "3.2.2", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.2.tgz", - "integrity": "sha512-uGZHXkHnhF0XeeAPgnKfPv1bgKAYyVvmNL1xlKsPYZPaIHxGti2hHqvOCQv71XMsLxu1QjergkqogUnms5D3YQ==", - "dev": true - }, "yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true - }, - "yargs": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.2.tgz", - "integrity": "sha512-ZEjj/dQYQy0Zx0lgLMLR8QuaqTihnxirir7EwUHp1Axq4e3+k8jXU5K0VLbNvedv1f4EWtBonDIZm0NUr+jCcA==", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.1" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - } - } - }, - "yargs-parser": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.1.tgz", - "integrity": "sha512-wpav5XYiddjXxirPoCTUPbqM0PXvJ9hiBMvuJgInvo4/lAOTZzUprArw17q2O1P2+GHhbBr18/iQwjL5Z9BqfA==", - "dev": true, - "requires": { - "camelcase": "^3.0.0", - "object.assign": "^4.1.0" - } - }, - "yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true } } } diff --git a/package.json b/package.json index f303793c6..52928c7e5 100644 --- a/package.json +++ b/package.json @@ -1,37 +1,50 @@ { "name": "wasabee-iitc", - "version": "0.20.3", + "version": "0.21.1", "description": "IITC Plugin for Wasabee Project", "main": "gulpfile.js", "private": true, "devDependencies": { - "css-loader": "^5.2.6", + "@types/color-string": "^1.5.2", + "@types/jquery": "^3.5.14", + "@types/jqueryui": "^1.12.16", + "@types/leaflet": "^1.7.9", + "@types/spectrum": "^1.8.2", + "@typescript-eslint/eslint-plugin": "^5.15.0", + "@typescript-eslint/parser": "^5.15.0", + "css-loader": "^6.7.1", "del": "^6.0.0", - "eslint": "^7.28.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-prettier": "^3.4.0", - "fancy-log": "^1.3.3", - "gulp": "^4.0.2", - "gulp-eslint": "^6.0.0", - "gulp-inject-file": "^0.0.19", - "gulp-inject-string": "^1.1.1", - "gulp-prettier": "^3.0.0", - "gulp-rename": "^2.0.0", - "gulp-trimlines": "^1.0.1", - "html-loader": "^2.1.2", + "eslint": "^8.11.0", + "eslint-config-prettier": "^8.5.0", + "eslint-plugin-local-rules": "^1.1.0", + "eslint-plugin-prettier": "^4.0.0", + "eslint-webpack-plugin": "^3.1.1", + "fancy-log": "^2.0.0", + "html-loader": "^3.1.0", "lodash": "^4.17.21", - "plugin-error": "^1.0.1", - "prettier": "^2.3.1", - "pretty-quick": "^3.1.0", + "prettier": "^2.6.0", + "pretty-quick": "^3.1.3", "raw-loader": "^4.0.2", - "style-loader": "^2.0.0", - "to-string-loader": "^1.1.6", + "style-loader": "^3.3.1", + "through2": "^4.0.2", + "to-string-loader": "^1.2.0", + "ts-loader": "^9.2.8", + "tslib": "^2.3.1", + "typescript": "^4.6.2", "url-loader": "^4.1.1", - "webpack": "^5.38.1", - "webpack-cli": "^4.7.1" + "webpack": "^5.70.0", + "webpack-cli": "^4.9.2" }, "scripts": { - "test": "none" + "build": "webpack --progress --env build=prod", + "build-dev": "webpack --progress --env build=dev", + "build-scot": "webpack --progress --env build=scot", + "build-pr": "webpack --progress --env build=pr --env pr=${PR_NUMBER}", + "build-testing": "webpack --progress --env build=testing", + "format:check": "prettier --check src/code", + "format:run": "prettier --write src/code", + "lint:check": "eslint src", + "lint:fix": "eslint --fix src" }, "repository": { "type": "git", @@ -44,10 +57,13 @@ }, "homepage": "https://github.com/wasabee-project/Wasabee-IITC/blob/master/README.md", "dependencies": { - "arc": "^0.1.1", - "color-string": "^1.5.5", - "geodesy": "^2.2.1", - "idb": "^6.1.2", - "sortablejs": "^1.12.0" - } + "@fortawesome/fontawesome-svg-core": "^6.1.0", + "@fortawesome/free-solid-svg-icons": "^6.1.0", + "arc": "^0.1.2", + "color-string": "^1.9.0", + "geodesy": "^2.3.0", + "idb": "^7.0.1", + "sortablejs": "^1.14.0" + }, + "typings": "src/code/index.d.ts" } diff --git a/plugin.config.json b/plugin.config.json index 90a28d8ed..1ee9425e3 100644 --- a/plugin.config.json +++ b/plugin.config.json @@ -3,12 +3,25 @@ "prod": { "downloadURL": "https://cdn2.wasabee.rocks/iitcplugin/prod/wasabee.user.js", "updateURL": "https://cdn2.wasabee.rocks/iitcplugin/prod/wasabee.meta.js", - "version": "0.20.BUILDDATE" + "version": "0.21.BUILDDATE" }, "dev": { + "downloadURL": "https://cdn2.wasabee.rocks/iitcplugin/latest/dev/wasabee.user.js", + "updateURL": "https://cdn2.wasabee.rocks/iitcplugin/latest/dev/wasabee.meta.js", + "version": "0.21.BUILDDATE-dev" + }, + "testing": { + "downloadURL": "https://wasabee-project.github.io/Wasabee-IITC/testing/wasabee.user.js", + "updateURL": "https://wasabee-project.github.io/Wasabee-IITC/testing/wasabee.meta.js", + "version": "0.21.BUILDDATE-testing" + }, + "pr": { + "version": "0.21-pr" + }, + "scot": { "downloadURL": "https://am.wasabee.rocks/static/dev/wasabee.user.js", "updateURL": "https://am.wasabee.rocks/static/dev/wasabee.meta.js", - "version": "0.20.BUILDDATE-dev" + "version": "0.21.BUILDDATE-scot" }, "common": { "id": "Wasabee.user.js", @@ -16,10 +29,7 @@ "namespace": "https://wasabee.rocks/", "description": "Wasabee is not for dating.", "author": "Wasabee Project Team", - "category": "Draw", - "include": "https://intel.ingress.com/*", - "TESTinclude": "/https?:\\/\\/.*\\.ingress\\.com\\/?((intel|mission)?(\\/?(\\?|#).*)?)?/", - "grant": "none" + "category": "Draw" } }, "releaseFolder": { diff --git a/src/code/addButtons.js b/src/code/addButtons.ts similarity index 71% rename from src/code/addButtons.js rename to src/code/addButtons.ts index 4395a813d..16635974d 100644 --- a/src/code/addButtons.js +++ b/src/code/addButtons.ts @@ -1,4 +1,4 @@ -import { ButtonsControl } from "./leafletClasses"; +import { ButtonsControl, ButtonsControlOptions } from "./leafletClasses"; import QuickdrawButton from "./buttons/quickdrawButton"; import WasabeeButton from "./buttons/wasabeeButton"; import SyncButton from "./buttons/syncButton"; @@ -6,6 +6,7 @@ import OpButton from "./buttons/opButton"; import LinkButton from "./buttons/linkButton"; import MarkerButton from "./buttons/markerButton"; import UploadButton from "./buttons/uploadButton"; +import QuickDeleteButton from "./buttons/quickdelete"; /* This function adds the plugin buttons on the left side of the screen */ export function addButtons() { @@ -13,15 +14,17 @@ export function addButtons() { return; } - const options = {}; - // XXX next refactor pass, don't require a container to be passed in, get the formatting on ButtonsControl.onAdd() - options.container = L.DomUtil.create("ul", "leaflet-bar"); - options.position = "topleft"; - options.buttons = new Map(); + const options: ButtonsControlOptions = { + // XXX next refactor pass, don't require a container to be passed in, get the formatting on ButtonsControl.onAdd() + container: L.DomUtil.create("ul", "leaflet-bar"), + position: "topleft", + buttons: new Map(), + }; for (const Constructor of [ WasabeeButton, OpButton, QuickdrawButton, + QuickDeleteButton, LinkButton, MarkerButton, SyncButton, diff --git a/src/code/agent.js b/src/code/agent.js deleted file mode 100644 index cc70f3a8b..000000000 --- a/src/code/agent.js +++ /dev/null @@ -1,343 +0,0 @@ -import WasabeePortal from "./portal"; -import ConfirmDialog from "./dialogs/confirmDialog"; -import AgentDialog from "./dialogs/agentDialog"; -import { agentPromise, targetPromise, routePromise } from "./server"; -import { getSelectedOperation } from "./selectedOp"; -import wX from "./wX"; -import WasabeeMe from "./me"; -import WasabeeTeam from "./team"; - -export default class WasabeeAgent { - constructor(obj) { - if (typeof obj == "string") { - try { - obj = JSON.parse(obj); - } catch (e) { - console.error(e); - obj = {}; - } - } - // console.debug("passed to constructor", obj); - - // things which are stable across all teams - this.id = obj.id; - this.name = obj.name; - this.vname = obj.vname; - this.rocksname = obj.rocksname; - this.intelname = obj.intelname; - this.intelfaction = obj.intelfaction; - this.level = obj.level ? Number(obj.level) : 0; - this.enlid = obj.enlid ? obj.enlid : 0; - this.pic = obj.pic ? obj.pic : null; - this.Vverified = obj.Vverified ? obj.Vverified : false; - this.blacklisted = obj.blacklisted ? obj.blacklisted : false; - this.rocks = obj.rocks ? obj.rocks : false; - this.lat = obj.lat ? obj.lat : 0; - this.lng = obj.lng ? obj.lng : 0; - this.date = obj.date ? obj.date : null; // last location sub, not fetched - - /* what did we decide to do with these? - this.startlat = obj.startlat ? obj.startlat : 0; - this.startlng = obj.startlng ? obj.startlng : 0; - this.startradius = obj.startradius ? Number(obj.startradius) : 0; - this.sharestart = obj.sharestart ? obj.sharestart : false; */ - - // vary per-team, don't set on direct pulls - if (obj.ShareWD) this.ShareWD = obj.ShareWD; - if (obj.LoadWD) this.LoadWD = obj.LoadWD; - if (obj.squad) this.squad = obj.squad; - if (obj.state) this.state = obj.state; - // this.distance = obj.distance ? Number(obj.distance) : 0; // don't use this - - // not sent by server, but preserve if from cache - this.fetched = obj.fetched ? obj.fetched : Date.now(); - - // push the new data into the agent cache - // do not await this, let it happen in the background - this._updateCache(); - } - - async _getDisplayName(teamID = 0) { - if (teamID == 0) return this.name; - - const team = await WasabeeTeam.get(teamID); - if (team == null) return this.name; - // XXX is there a cute team.agents.filter() we can use here? - for (const a of team.agents) { - if (a.id == this.id) return a.name; - } - - return this.name; - } - - async _updateCache() { - // load anything currently cached - const cached = await window.plugin.wasabee.idb.get("agents", this.id); - - // nothing already in the cache, just dump this in and call it good - // will contain the extras, but that's fine for now - if (cached == null) { - // console.debug("not cached, adding"); - try { - await window.plugin.wasabee.idb.put("agents", this); - } catch (e) { - console.error(e); - } - return; - } - - // if the cached version is newer, do not update - if (cached.fetched >= this.fetched) { - // console.debug("incoming is older, not updating cache"); - return; - } - // note the new fetched time - cached.fetched = this.fetched; - // console.debug("updating cache"); - - // update location only if known - if (this.lat != 0 && this.lng != 0) { - cached.lat = this.lat; - cached.lng = this.lng; - cached.date = this.date; - } - - // these probably won't change, but just be sure - cached.name = this.name; - cached.level = this.level; - cached.enlid = this.enlid; - cached.pic = this.pic; - cached.Vverified = this.Vverified; - cached.blacklisted = this.blacklisted; - cached.rocks = this.rocks; - // cansendto is never true from a team pull, but might be true from a direct pull - - // remove things which make no sense in the global cache - delete cached.ShareWD; - delete cached.LoadWD; - delete cached.squad; - delete cached.state; - - try { - await window.plugin.wasabee.idb.put("agents", cached); - } catch (e) { - console.error(e); - } - } - - get latLng() { - if (this.lat && this.lng) return new L.LatLng(this.lat, this.lng); - return null; - } - - // hold agent data up to 24 hours by default -- don't bother the server if all we need to do is resolve GID -> name - static async get(gid, maxAgeSeconds = 86400) { - const cached = await window.plugin.wasabee.idb.get("agents", gid); - if (cached && cached.fetched > Date.now() - 1000 * maxAgeSeconds) { - const a = new WasabeeAgent(cached); - a.cached = true; - // console.debug("returning from cache", a); - return a; - } - - if (!WasabeeMe.isLoggedIn()) { - // console.debug("not logged in, giving up"); - return null; - } - - // console.debug("pulling server for new agent data (no team)"); - try { - const result = await agentPromise(gid); - return new WasabeeAgent(result); - } catch (e) { - console.error(e); - } - // console.debug("giving up"); - return null; - } - - async formatDisplay(teamID = 0) { - const display = L.DomUtil.create("a", "wasabee-agent-label"); - if (this.Vverified || this.rocks) { - L.DomUtil.addClass(display, "enl"); - } - if (this.blacklisted) { - L.DomUtil.addClass(display, "res"); - } - L.DomEvent.on(display, "click", (ev) => { - L.DomEvent.stop(ev); - const ad = new AgentDialog({ gid: this.id }); - ad.enable(); - }); - display.textContent = await this._getDisplayName(teamID); - return display; - } - - async getPopup() { - const content = L.DomUtil.create("div", "wasabee-agent-popup"); - const title = L.DomUtil.create("div", "desc", content); - title.id = this.id; - const fd = await this.formatDisplay(0); - title.innerHTML = fd.outerHTML + this.timeSinceformat(); - - const sendTarget = L.DomUtil.create("button", null, content); - sendTarget.textContent = wX("SEND TARGET"); - L.DomEvent.on(sendTarget, "click", (ev) => { - L.DomEvent.stop(ev); - const selectedPortal = WasabeePortal.getSelected(); - if (!selectedPortal) { - alert(wX("SELECT PORTAL")); - return; - } - - const d = new ConfirmDialog({ - title: wX("SEND TARGET"), - label: wX("SEND TARGET CONFIRM", { - portalName: selectedPortal.displayName, - agent: this.name, - }), - type: "agent", - callback: async () => { - try { - await targetPromise(this.id, selectedPortal); - alert(wX("TARGET SENT")); - } catch (e) { - console.error(e); - } - }, - }); - d.enable(); - }); - - // this needs wX - const requestRoute = L.DomUtil.create("button", null, content); - requestRoute.textContent = "Send Route to Target"; - requestRoute.style.display = "none"; // hide this until the server-side is ready - L.DomEvent.on(requestRoute, "click", (ev) => { - L.DomEvent.stop(ev); - const selectedPortal = WasabeePortal.getSelected(); - if (!selectedPortal) { - alert(wX("SELECT PORTAL")); - return; - } - - const d = new ConfirmDialog({ - title: "Send Route to Target", - label: "Do you really want to request the route to be sent?", - type: "agent", - callback: async () => { - try { - await routePromise(this.id, selectedPortal); - alert("Route Sent"); - } catch (e) { - console.error(e); - } - }, - }); - d.enable(); - }); - - const op = getSelectedOperation(); - const assignments = L.DomUtil.create("ul", "assignments", content); - for (const m of op.markers) { - if (m.assignedTo != this.id) continue; - const a = L.DomUtil.create("li", "assignment", assignments); - const portal = op.getPortal(m.portalId); - a.textContent = `${m.order}: ${wX(m.type)} `; - a.appendChild(portal.displayFormat()); - } - - return content; - } - - timeSinceformat() { - if (!this.date) return ""; - const date = Date.parse(this.date + " UTC"); - if (Number.isNaN(date)) return `(${this.date} UTC)`; // FireFox Date.parse no good - if (date == 0) return ""; - - const seconds = Math.floor((new Date() - date) / 1000); - if (seconds < 0) return ""; - let interval = Math.floor(seconds / 31536000 / 2592000 / 86400); - - if (interval > 1) return wX("AGES"); - interval = Math.floor(seconds / 3600); - if (interval > 1) return wX("HOURS", { hours: interval }); - interval = Math.floor(seconds / 60); - if (interval > 1) return wX("MINUTES", { minutes: interval }); - interval = Math.floor(seconds); - return wX("SECONDS", { seconds: interval }); - } - - // change this to return an L.Marker() to make the logic in mapDrawing simpler - icon(z = 7) { - if (z < 6) return this.globalIcon(); - if (z >= 6 && z < 9) return this.smallIcon(); - if (z >= 9 && z < 15) return this.mediumIcon(); - return this.bigIcon(); - } - - iconSize(z = 7) { - if (z < 6) return [30, 30]; - if (z >= 6 && z < 9) return [36, 47]; - if (z >= 9 && z < 15) return [40, 52]; - return [46, 60]; - } - - iconAnchor(z = 7) { - if (z < 6) return [15, 30]; - if (z >= 6 && z < 9) return [18, 47]; - if (z >= 9 && z < 15) return [20, 52]; - return [23, 60]; - } - - // XXX there has to be a way to apply the viewBox onto the paths, to get rid of that extra nonsense - globalIcon() { - const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); - icon.setAttribute("viewBox", "200 70 630 520"); - icon.setAttribute("height", "30"); - icon.setAttribute("width", "30"); - icon.setAttribute( - "style", - "fill-rule: evenodd; clip-rule: evenodd; stroke-miterlimit: 10;" - ); - icon.innerHTML = ``; - return icon; - } - - // XXX resize this properly - smallIcon() { - const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); - icon.setAttribute("viewBox", "0 0 52 68"); - icon.innerHTML = ` - - - `; - return icon; - } - - // XXX resize this properly - mediumIcon() { - const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); - icon.setAttribute("viewBox", "0 0 52 68"); - icon.innerHTML = ` - - - `; - return icon; - } - - bigIcon() { - const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); - icon.setAttribute("viewBox", "0 0 52 68"); - icon.innerHTML = ` - - - `; - return icon; - } -} diff --git a/src/code/anchor.js b/src/code/anchor.js deleted file mode 100644 index f20261b7b..000000000 --- a/src/code/anchor.js +++ /dev/null @@ -1,204 +0,0 @@ -import { swapPortal, deletePortal } from "./uiCommands"; -import { getSelectedOperation } from "./selectedOp"; -import AssignDialog from "./dialogs/assignDialog"; -import SendTargetDialog from "./dialogs/sendTargetDialog"; -import SetCommentDialog from "./dialogs/setCommentDialog"; -import LinkListDialog from "./dialogs/linkListDialog"; -import wX from "./wX"; - -// this class is for the popups, and for assign menu -export default class WasabeeAnchor { - constructor(portalId) { - const op = getSelectedOperation(); - this.ID = portalId; - this.portalId = portalId; - this.type = "anchor"; - this.comment = null; - this.state = null; - this.assignedTo = null; - this.order = 0; - - this._portal = op.getPortal(this.ID); - this.color = op.color; - this._opID = op.ID; - } - - // currently unused - toJSON() { - return { - ID: this.ID, - portalId: this.portalId, - type: this.type, - comment: this.coment, - state: this.state, - assignedTo: this.assignedTo, - order: this.order, - color: this.color, - }; - } - - // pointless, since these are never pushed to the server - set opOrder(o) { - this.order = Number.parseInt(o, 10); - } - - get opOrder() { - return this.order; - } - - get name() { - return this._portal.name; - } - - displayFormat(smallScreen = false) { - return this._portal.displayFormat(smallScreen); - } - - get latLng() { - return this._portal.latLng; - } - - popupContent(marker) { - // just log for now, if we see it, then we can figure out what is really going on - const operation = getSelectedOperation(); - const canWrite = operation.canWrite(); - if (operation == null) { - console.log("null op for anchor?"); - } - if (this._opID != operation.ID) { - console.log("anchor opID != selected opID"); - } - - marker.className = "wasabee-anchor-popup"; - const content = L.DomUtil.create("div", null); - const title = L.DomUtil.create("div", "desc", content); - title.appendChild(this._portal.displayFormat()); - const portalComment = L.DomUtil.create( - "div", - "wasabee-portal-comment", - content - ); - const pcLink = L.DomUtil.create("a", null, portalComment); - pcLink.textContent = this._portal.comment || wX("SET_PORTAL_COMMENT"); - if (canWrite) { - pcLink.href = "#"; - L.DomEvent.on(pcLink, "click", (ev) => { - L.DomEvent.stop(ev); - const scd = new SetCommentDialog({ - target: this._portal, - operation: operation, - }); - scd.enable(); - marker.closePopup(); - }); - } - if (this._portal.hardness) { - const portalHardness = L.DomUtil.create( - "div", - "wasabee-portal-hardness", - content - ); - const phLink = L.DomUtil.create("a", null, portalHardness); - phLink.textContent = this._portal.hardness; - if (canWrite) { - phLink.href = "#"; - L.DomEvent.on(phLink, "click", (ev) => { - L.DomEvent.stop(ev); - const scd = new SetCommentDialog({ - target: this._portal, - operation: operation, - }); - scd.enable(); - marker.closePopup(); - }); - } - } - - const requiredKeys = L.DomUtil.create("div", "desc", content); - const onHand = operation.KeysOnHandForPortal(this._portal.id); - const required = operation.KeysRequiredForPortal(this._portal.id); - requiredKeys.textContent = "Keys: " + onHand + " / " + required; - - const buttonSet = L.DomUtil.create( - "div", - "wasabee-marker-buttonset", - content - ); - const linksButton = L.DomUtil.create("button", null, buttonSet); - linksButton.textContent = wX("LINKS"); - L.DomEvent.on(linksButton, "click", (ev) => { - L.DomEvent.stop(ev); - const lld = new LinkListDialog({ portal: this._portal }); - lld.enable(); - marker.closePopup(); - }); - if (canWrite) { - const swapButton = L.DomUtil.create("button", null, buttonSet); - swapButton.textContent = wX("SWAP"); - L.DomEvent.on(swapButton, "click", (ev) => { - L.DomEvent.stop(ev); - swapPortal(operation, this._portal); - marker.closePopup(); - }); - const deleteButton = L.DomUtil.create("button", null, buttonSet); - deleteButton.textContent = wX("DELETE_ANCHOR"); - L.DomEvent.on(deleteButton, "click", (ev) => { - L.DomEvent.stop(ev); - deletePortal(operation, this._portal); - marker.closePopup(); - }); - } - - const gmapButton = L.DomUtil.create("button", null, buttonSet); - gmapButton.textContent = wX("ANCHOR_GMAP"); - L.DomEvent.on(gmapButton, "click", (ev) => { - L.DomEvent.stop(ev); - marker.closePopup(); - // use intent on android - if ( - typeof window.android !== "undefined" && - window.android && - window.android.intentPosLink - ) { - window.android.intentPosLink( - +this._portal.lat, - +this._portal.lng, - window.map.getZoom(), - this.name, - true - ); - } else { - window.open( - "https://www.google.com/maps/search/?api=1&query=" + - this._portal.lat + - "," + - this._portal.lng - ); - } - }); - - if (operation.canWriteServer()) { - const assignButton = L.DomUtil.create("button", null, buttonSet); - assignButton.textContent = wX("ASSIGN OUTBOUND"); - L.DomEvent.on(assignButton, "click", (ev) => { - L.DomEvent.stop(ev); - const ad = new AssignDialog({ target: this }); - ad.enable(); - marker.closePopup(); - }); - } - - if (operation.isOnCurrentServer()) { - const sendButton = L.DomUtil.create("button", null, buttonSet); - sendButton.textContent = wX("SEND TARGET"); - L.DomEvent.on(sendButton, "click", (ev) => { - L.DomEvent.stop(ev); - const std = new SendTargetDialog({ target: this }); - std.enable(); - marker.closePopup(); - }); - } - - return content; - } -} diff --git a/src/code/auth.ts b/src/code/auth.ts new file mode 100644 index 000000000..2802e2353 --- /dev/null +++ b/src/code/auth.ts @@ -0,0 +1,75 @@ +import { postToFirebase } from "./firebaseSupport"; +import WasabeeMe from "./model/me"; +import { oneTimeToken, SendAccessTokenAsync } from "./server"; + +const JWT_KEY = "wasabee-jwt"; + +function storeJWT(jwt) { + localStorage[JWT_KEY] = jwt; +} + +export function deleteJWT() { + localStorage.removeItem(JWT_KEY); +} + +export function getJWT() { + return localStorage.getItem(JWT_KEY); +} + +/** wrap send access token to get me */ +export async function sendAccessToken(token: string) { + const r = await SendAccessTokenAsync(token); + if (r && (r as any).jwt) { + storeJWT((r as any).jwt); + } + return r ? new WasabeeMe(r) : await WasabeeMe.waitGet(true); +} + +/** wrap ott to get me */ +export async function sendOneTimeToken(token: string) { + await oneTimeToken(token); + return await WasabeeMe.waitGet(true); +} + +/** GAPI */ + +/** */ +export function isAuthAvailable() { + return !!window.gapi.auth2.getAuthInstance(); +} + +/** Get access token from google */ +export function getAccessToken(selectAccount = false) { + return new Promise((resolve, reject) => { + const options = { + client_id: window.plugin.wasabee.static.constants.OAUTH_CLIENT_ID, + scope: "email profile openid", + response_type: "id_token permission", + prompt: selectAccount ? "select_account" : "none", + }; + + window.gapi.auth2.authorize(options, (response) => { + if (response.error) { + postToFirebase({ id: "exception", error: response.error }); + if (response.error === "idpiframe_initialization_failed") { + return reject("You need enable cookies or allow [*.]google.com"); + } + if (!selectAccount) { + if ( + response.error == "user_logged_out" || + response.error == "immediate_failed" + ) { + // retry with account selection + return resolve(getAccessToken(true)); + } + } + + const err = `error from gapiAuth: ${response.error}: ${response.error_subtype}`; + postToFirebase({ id: "exception", error: err }); + return reject(err); + } + + resolve(response.access_token); + }); + }); +} diff --git a/src/code/auxiliar.js b/src/code/auxiliar.js deleted file mode 100644 index c8a53fea2..000000000 --- a/src/code/auxiliar.js +++ /dev/null @@ -1,39 +0,0 @@ -import colorString from "color-string"; - -//** This function generates a unique ID for an object */ -export function generateId(len = 40) { - const arr = new Uint8Array(len / 2); - window.crypto.getRandomValues(arr); - return Array.from(arr, (dec) => { - return ("0" + dec.toString(16)).substr(-2); - }).join(""); -} - -export function newColors(incoming) { - switch (incoming) { - case "groupa": - return "orange"; - case "groupb": - return "yellow"; - case "groupc": - return "lime"; - case "groupd": - return "purple"; - case "groupe": - return "teal"; - case "groupf": - return "fuchsia"; - case "main": - return "red"; - default: - return incoming; - } -} - -export function convertColorToHex(color, on_error = "#000000") { - try { - return colorString.to.hex(colorString.get.rgb(newColors(color))); - } catch { - return on_error; - } -} diff --git a/src/code/auxiliar.ts b/src/code/auxiliar.ts new file mode 100644 index 000000000..4f38dd13f --- /dev/null +++ b/src/code/auxiliar.ts @@ -0,0 +1,74 @@ +import colorString from "color-string"; + +import { icon, IconLookup, IconName } from "@fortawesome/fontawesome-svg-core"; +// avoid import from "@fortawesome/free-solid-svg-icons" to reduce *dev* build size +import { faCheck } from "@fortawesome/free-solid-svg-icons/faCheck"; +import { faTrash } from "@fortawesome/free-solid-svg-icons/faTrash"; +import { faServer } from "@fortawesome/free-solid-svg-icons/faServer"; +import { faSync } from "@fortawesome/free-solid-svg-icons/faSync"; +import { faArrowsAltH } from "@fortawesome/free-solid-svg-icons/faArrowsAltH"; +import { faPen } from "@fortawesome/free-solid-svg-icons/faPen"; +import { faEraser } from "@fortawesome/free-solid-svg-icons/faEraser"; +import { faBan } from "@fortawesome/free-solid-svg-icons/faBan"; +import { faPalette } from "@fortawesome/free-solid-svg-icons/faPalette"; +import { faAsterisk } from "@fortawesome/free-solid-svg-icons/faAsterisk"; +import { faDesktop } from "@fortawesome/free-solid-svg-icons/faDesktop"; + +//** This function generates a unique ID for an object */ +export function generateId(len = 40) { + const arr = new Uint8Array(len / 2); + window.crypto.getRandomValues(arr); + return Array.from(arr, (dec) => { + return ("0" + dec.toString(16)).substr(-2); + }).join(""); +} + +export function newColors(incoming: string) { + switch (incoming) { + case "groupa": + return "orange"; + case "groupb": + return "yellow"; + case "groupc": + return "lime"; + case "groupd": + return "purple"; + case "groupe": + return "teal"; + case "groupf": + return "fuchsia"; + case "main": + return window.plugin.wasabee.skin.defaultOperationColor as string; + default: + return incoming; + } +} + +export function convertColorToHex(color: string, on_error = "#000000") { + try { + return colorString.to.hex(colorString.get.rgb(newColors(color))); + } catch { + return on_error; + } +} + +const icons = [ + faCheck, + faTrash, + faServer, + faSync, + faArrowsAltH, + faPen, + faEraser, + faBan, + faPalette, + faAsterisk, + faDesktop, +]; + +export function appendFAIcon(iconName: IconName, container: Element) { + const iconDef = icons.find((i) => i.iconName === iconName); + if (!iconDef) return; + const iconNode = icon(iconDef as IconLookup).node[0]; + container.appendChild(iconNode); +} \ No newline at end of file diff --git a/src/code/buttons/linkButton.d.ts b/src/code/buttons/linkButton.d.ts new file mode 100644 index 000000000..d351c36ae --- /dev/null +++ b/src/code/buttons/linkButton.d.ts @@ -0,0 +1,6 @@ +import { WButton } from "../leafletClasses"; + +declare class LinkButton extends WButton { + needWritePermission: true; +} +export default LinkButton; diff --git a/src/code/buttons/linkButton.js b/src/code/buttons/linkButton.js index ecf679232..7dec2550f 100644 --- a/src/code/buttons/linkButton.js +++ b/src/code/buttons/linkButton.js @@ -24,16 +24,11 @@ const LinkButton = WButton.extend({ title: this.title, }); - this.actionsContainer = this._createSubActions(this.getSubActions()); - - this._container.appendChild(this.actionsContainer); + this.setSubActions(this.getSubActions()); window.map.on("wasabee:ui:skin wasabee:ui:lang", () => { this.button.title = wX("LINKS BUTTON TITLE"); - const newSubActions = this._createSubActions(this.getSubActions()); - this._container.replaceChild(newSubActions, this.actionsContainer); - newSubActions.style.display = this.actionsContainer.style.display; - this.actionsContainer = newSubActions; + this.setSubActions(this.getSubActions()); }); }, diff --git a/src/code/buttons/markerButton.d.ts b/src/code/buttons/markerButton.d.ts new file mode 100644 index 000000000..f69f25a78 --- /dev/null +++ b/src/code/buttons/markerButton.d.ts @@ -0,0 +1,4 @@ +import { WButton } from "../leafletClasses"; + +declare class MarkerButton extends WButton {} +export default MarkerButton; diff --git a/src/code/buttons/markerButton.js b/src/code/buttons/markerButton.js index 5f37b9501..298701a53 100644 --- a/src/code/buttons/markerButton.js +++ b/src/code/buttons/markerButton.js @@ -23,19 +23,14 @@ const MarkerButton = WButton.extend({ title: this.title, }); - this.actionsContainer = this._createSubActions(this.getSubActions()); - - this._container.appendChild(this.actionsContainer); + this.setSubActions(this.getSubActions()); window.map.on("wasabee:ui:skin wasabee:ui:lang", this.update, this); }, update: function () { this.button.title = wX("MARKERS BUTTON TITLE"); - const newSubActions = this._createSubActions(this.getSubActions()); - this._container.replaceChild(newSubActions, this.actionsContainer); - newSubActions.style.display = this.actionsContainer.style.display; - this.actionsContainer = newSubActions; + this.setSubActions(this.getSubActions()); }, getSubActions: function () { diff --git a/src/code/buttons/opButton.d.ts b/src/code/buttons/opButton.d.ts new file mode 100644 index 000000000..8f8cc2859 --- /dev/null +++ b/src/code/buttons/opButton.d.ts @@ -0,0 +1,4 @@ +import { WButton } from "../leafletClasses"; + +declare class OpButton extends WButton {} +export default OpButton; diff --git a/src/code/buttons/opButton.js b/src/code/buttons/opButton.js index 2e25a2613..97fe1997f 100644 --- a/src/code/buttons/opButton.js +++ b/src/code/buttons/opButton.js @@ -25,16 +25,11 @@ const OpButton = WButton.extend({ title: this.title, }); - this.actionsContainer = this._createSubActions(this.getSubActions()); - - this._container.appendChild(this.actionsContainer); + this.setSubActions(this.getSubActions()); window.map.on("wasabee:ui:skin wasabee:ui:lang", () => { this.button.title = wX("OP_BUTTON"); - const newSubActions = this._createSubActions(this.getSubActions()); - this._container.replaceChild(newSubActions, this.actionsContainer); - newSubActions.style.display = this.actionsContainer.style.display; - this.actionsContainer = newSubActions; + this.setSubActions(this.getSubActions()); }); }, diff --git a/src/code/buttons/quickdelete.ts b/src/code/buttons/quickdelete.ts new file mode 100644 index 000000000..86f20b4d7 --- /dev/null +++ b/src/code/buttons/quickdelete.ts @@ -0,0 +1,283 @@ +import { WButton, WTooltip } from "../leafletClasses"; +import wX from "../wX"; + +import type { Wasabee } from "../init"; +import type { WLMarker } from "../ui/marker"; +import type { WLLink } from "../ui/link"; +import type { LeafletMouseEvent } from "leaflet"; +import { getSelectedOperation } from "../selectedOp"; +import type { WLAnchor } from "../ui/anchor"; +import { postToFirebase } from "../firebaseSupport"; + +const W: Wasabee = window.plugin.wasabee; + +class QuickDeleteButton extends WButton { + static TYPE = "QuickdeleteButton"; + + needWritePermission: true; + + handler: QuickDeleteHandler; + state: "off" | "on" | "instant"; + + constructor(container: HTMLElement) { + super(container); + + this.title = wX("toolbar.quick_delete.title"); + this.type = QuickDeleteButton.TYPE; + + this.handler = new QuickDeleteHandler(this); + + this.button = this._createButton({ + title: this.title, + container: container, + className: "wasabee-toolbar-quickdelete", + context: this, + callback: this.toggleActions, + }); + this.state = "off"; + + this.setSubActions(this.getSubActions()); + + this._container.appendChild(this.actionsContainer); + + window.map.on("wasabee:op:change", this.opChange, this); + + // update text + window.map.on("wasabee:ui:skin wasabee:ui:lang", () => { + this.button.title = wX("toolbar.quick_delete.title"); + this.setSubActions(this.getSubActions()); + }); + + this.update(); + } + + opChange() { + if (this.state == "on") this.disable(); + else if (this.state == "instant") { + this.handler.disable(); + this.handler.enable(); + } + } + + toggleActions() { + if (this.state == "off") { + this.state = "on"; + this.enable(); + this.setSubActions(this.getSubActions()); + postToFirebase({ id: "analytics", action: "quickdelete" }); + } else if (this.state == "on") { + this.disable(); + this.state = "instant"; + this.enable(); + this.setSubActions(this.getSubActions()); + postToFirebase({ id: "analytics", action: "quickdelete:instant" }); + this.button.classList.add("blink"); + } else { + this.disable(); + } + } + + actionApply() { + const operation = getSelectedOperation(); + operation.markers = operation.markers.filter( + (m) => !this.handler.deletedMarker.has(m.ID) + ); + operation.links = operation.links.filter( + (l) => !this.handler.deletedLink.has(l.ID) + ); + operation.cleanAnchorList(); + operation.cleanPortalList(); + operation.update(true); + operation.updateBlockers(); + this.disable(); + } + + actionCancel() { + this.disable(); + } + + getSubActions() { + if (this.state === "instant") + return [ + { + text: wX("toolbar.quick_delete.stop.text"), + title: wX("toolbar.quick_delete.stop.title"), + callback: this.disable, + context: this, + }, + ]; + + const applySubAction = { + text: wX("toolbar.quick_delete.apply.text"), + title: wX("toolbar.quick_delete.apply.title"), + callback: this.actionApply, + context: this, + }; + + const cancelSubAction = { + text: wX("toolbar.quick_delete.cancel.text"), + title: wX("toolbar.quick_delete.cancel.title"), + callback: this.actionCancel, + context: this, + }; + + return [applySubAction, cancelSubAction]; + } + + enable() { + super.enable(); + this.button.classList.add("active"); + this.handler.enable(); + return this; + } + + disable() { + super.disable(); + this.button.classList.remove("active"); + this.button.classList.remove("blink"); + this.handler.disable(); + this.state = "off"; + return this; + } +} + +class QuickDeleteHandler extends L.Handler { + deletedMarker: Set; + deletedLink: Set; + + control: QuickDeleteButton; + tooltip: WTooltip; + + constructor(control: QuickDeleteButton) { + super(window.map); + this.deletedMarker = new Set(); + this.deletedLink = new Set(); + this.control = control; + } + + clickMarker(event: LeafletMouseEvent) { + if (!this.enabled()) return; + const layer = event.target as WLMarker; + layer.closePopup(); + this.toggleMarker(layer); + } + + toggleMarker(layer: WLMarker) { + if (this.control.state == "instant") { + const operation = getSelectedOperation(); + return operation.removeMarkerByID(layer.options.id); + } + + if (this.deletedMarker.has(layer.options.id)) { + this.deletedMarker.delete(layer.options.id); + layer.setOpacity(1); + } else { + this.deletedMarker.add(layer.options.id); + layer.setOpacity(0.5); + } + } + + clickLink(event: LeafletMouseEvent) { + if (!this.enabled()) return; + const layer = event.target as WLLink; + layer.closePopup(); + this.toggleLink(layer); + } + + toggleLink(layer: WLLink) { + if (this.control.state == "instant") { + const operation = getSelectedOperation(); + return operation.removeLinkByID(layer.options.linkID); + } + + if (this.deletedLink.has(layer.options.linkID)) { + this.deletedLink.delete(layer.options.linkID); + layer.setStyle({ + opacity: window.plugin.wasabee.skin.linkStyle.opacity || 1, + }); + } else { + this.deletedLink.add(layer.options.linkID); + layer.setStyle({ + opacity: 0.5 * (window.plugin.wasabee.skin.linkStyle.opacity || 1), + }); + } + } + + clickAnchor(event: LeafletMouseEvent) { + if (!this.enabled()) return; + const layer = event.target as WLAnchor; + layer.closePopup(); + this.toggleAnchor(layer); + } + + toggleAnchor(layer: WLAnchor) { + const operation = getSelectedOperation(); + if (this.control.state == "instant") + return operation.removeAnchor(layer.options.portalId); + + const portal = operation.getPortal(layer.options.portalId); + const links = operation.getLinkListFromPortal(portal); + // toggle all links if all deleted + if (links.every((l) => this.deletedLink.has(l.ID))) { + W.linkLayerGroup.eachLayer((layer: WLLink) => { + if (links.find((l) => l.ID == layer.options.linkID)) + this.toggleLink(layer); + }); + } else { + // delete all links + W.linkLayerGroup.eachLayer((layer: WLLink) => { + if (!this.deletedLink.has(layer.options.linkID)) + if (links.find((l) => l.ID == layer.options.linkID)) + this.toggleLink(layer); + }); + } + } + + keyUpListener(e) { + if (!this.enabled()) return; + + // [esc] + if (e.originalEvent.keyCode === 27) { + this.control.disable(); + } + } + + addHooks() { + W.portalLayerGroup.eachLayer((layer: WLAnchor) => { + layer.on("spiderfiedclick", this.clickAnchor, this); + }); + W.markerLayerGroup.eachLayer((layer: WLMarker) => { + layer.on("spiderfiedclick", this.clickMarker, this); + }); + W.linkLayerGroup.eachLayer((layer: WLLink) => { + layer.on("click", this.clickLink, this); + }); + window.map.on("keyup", this.keyUpListener, this); + this.tooltip = new WTooltip(window.map); + this.tooltip.updateContent( + this.control.state === "instant" + ? wX("toolbar.quick_delete.tooltip.quick_mode") + : wX("toolbar.quick_delete.tooltip.toggle_mode") + ); + } + + removeHooks() { + W.portalLayerGroup.eachLayer((layer: WLAnchor) => { + layer.off("spiderfiedclick", this.clickAnchor, this); + }); + W.markerLayerGroup.eachLayer((layer: WLMarker) => { + layer.off("spiderfiedclick", this.clickMarker, this); + layer.setOpacity(1); + }); + W.linkLayerGroup.eachLayer((layer: WLLink) => { + layer.off("click", this.clickLink, this); + layer.setStyle({ + opacity: window.plugin.wasabee.skin.linkStyle.opacity || 1, + }); + }); + window.map.off("keyup", this.keyUpListener, this); + this.tooltip.dispose(); + } +} + +export default QuickDeleteButton; diff --git a/src/code/buttons/quickdrawButton.d.ts b/src/code/buttons/quickdrawButton.d.ts new file mode 100644 index 000000000..afbd5f109 --- /dev/null +++ b/src/code/buttons/quickdrawButton.d.ts @@ -0,0 +1,6 @@ +import { WButton } from "../leafletClasses"; + +declare class QuickdrawButton extends WButton { + needWritePermission: true; +} +export default QuickdrawButton; diff --git a/src/code/buttons/quickdrawButton.js b/src/code/buttons/quickdrawButton.js index e9b93187b..74f0199da 100644 --- a/src/code/buttons/quickdrawButton.js +++ b/src/code/buttons/quickdrawButton.js @@ -1,9 +1,10 @@ import { WTooltip, WButton } from "../leafletClasses"; import wX from "../wX"; -import WasabeePortal from "../portal"; import { getSelectedOperation } from "../selectedOp"; import { postToFirebase } from "../firebaseSupport"; +import PortalUI from "../ui/portal"; + const QuickdrawButton = WButton.extend({ statics: { TYPE: "QuickdrawButton", @@ -34,16 +35,11 @@ const QuickdrawButton = WButton.extend({ this.handler._nextDrawnLinksColor = ev.target.value; }); - this.actionsContainer = this._createSubActions(this.getSubActions()); - - this._container.appendChild(this.actionsContainer); + this.setSubActions(this.getSubActions()); window.map.on("wasabee:ui:skin wasabee:ui:lang", () => { this.button.title = wX("QD TITLE"); - const newSubActions = this._createSubActions(this.getSubActions()); - this._container.replaceChild(newSubActions, this.actionsContainer); - newSubActions.style.display = this.actionsContainer.style.display; - this.actionsContainer = newSubActions; + this.setSubActions(this.getSubActions()); if (this.handler._enabled) this.handler._tooltip.updateContent(this.handler._getTooltipText()); @@ -205,10 +201,8 @@ const QuickDrawControl = L.Handler.extend({ _onMouseMove: function (e) { if (e.latlng) { - this._tooltip.updatePosition(e.latlng); this._guideUpdate(e); } - L.DomEvent.preventDefault(e.originalEvent); }, _guideUpdate: function (e) { @@ -237,28 +231,28 @@ const QuickDrawControl = L.Handler.extend({ _getTooltipText: function () { if (this._drawMode === "quickdraw") { - if (!this._anchor1) return { text: wX("QDSTART") }; - if (!this._anchor2) return { text: wX("QDNEXT") }; - return { text: wX("QDCONT") }; + if (!this._anchor1) return wX("QDSTART"); + if (!this._anchor2) return wX("QDNEXT"); + return wX("QDCONT"); } if (this._drawMode === "star") { // XXX wX this - if (!this._anchor) return { text: "Select the star anchor" }; - return { text: "Select a portal" }; + if (!this._anchor) + return wX("toolbar.quick_draw.tooltip.star_mode.anchor"); + return wX("toolbar.quick_draw.tooltip.star_mode.portal"); } // must be in single-link mode // XXX wX this - if (!this._previous) return { text: "Click first portal" }; - return { text: "Click next portal" }; + if (!this._previous) + return wX("toolbar.quick_draw.tooltip.single_mode.first"); + return wX("toolbar.quick_draw.tooltip.single_mode.next"); }, _portalClicked: function (portal) { - const selectedPortal = WasabeePortal.fromIITC(portal); + const selectedPortal = PortalUI.fromIITC(portal); if (!selectedPortal) { // XXX wX this - this._tooltip.updateContent({ - text: "Portal data not loaded, please try again", - }); + this._tooltip.updateContent(wX("toolbar.quick_draw.tooltip.portal_fail")); return; } if (this._drawMode == "quickdraw") { diff --git a/src/code/buttons/syncButton.d.ts b/src/code/buttons/syncButton.d.ts new file mode 100644 index 000000000..c18959463 --- /dev/null +++ b/src/code/buttons/syncButton.d.ts @@ -0,0 +1,4 @@ +import { WButton } from "../leafletClasses"; + +declare class SyncButton extends WButton {} +export default SyncButton; diff --git a/src/code/buttons/syncButton.js b/src/code/buttons/syncButton.js index edd85f1da..ce173247c 100644 --- a/src/code/buttons/syncButton.js +++ b/src/code/buttons/syncButton.js @@ -1,5 +1,5 @@ import { WButton } from "../leafletClasses"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; import { fullSync } from "../uiCommands"; import wX from "../wX"; diff --git a/src/code/buttons/uploadButton.d.ts b/src/code/buttons/uploadButton.d.ts new file mode 100644 index 000000000..41205bbe2 --- /dev/null +++ b/src/code/buttons/uploadButton.d.ts @@ -0,0 +1,6 @@ +import { WButton } from "../leafletClasses"; + +declare class UploadButton extends WButton { + needWritePermission: true; +} +export default UploadButton; diff --git a/src/code/buttons/uploadButton.js b/src/code/buttons/uploadButton.js index de72c86a1..dbba1b477 100644 --- a/src/code/buttons/uploadButton.js +++ b/src/code/buttons/uploadButton.js @@ -5,11 +5,12 @@ import { GetWasabeeServer, opPromise, } from "../server"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; import { getSelectedOperation, makeSelectedOperation } from "../selectedOp"; import ConfirmDialog from "../dialogs/confirmDialog"; import MergeDialog from "../dialogs/mergeDialog"; import wX from "../wX"; +import { displayError, displayInfo } from "../error"; const UploadButton = WButton.extend({ statics: { @@ -22,7 +23,7 @@ const UploadButton = WButton.extend({ this.type = UploadButton.TYPE; // this.handler = null; const operation = getSelectedOperation(); - this.title = wX("UPLOAD BUTTON HOVER", operation.name); + this.title = wX("UPLOAD BUTTON HOVER", { opName: operation.name }); this._container = container; this.button = this._createButton({ @@ -38,10 +39,11 @@ const UploadButton = WButton.extend({ } try { + this.button.classList.add("loading"); const r = await uploadOpPromise(); // switch to the new version in local store -- uploadOpPromise stores it await makeSelectedOperation(r.ID); - alert(wX("UPLOADED")); + displayInfo(wX("UPLOADED")); this.update(); // this._invisible(); } catch (e) { @@ -49,12 +51,13 @@ const UploadButton = WButton.extend({ console.warn(e.toString() + ": trying as update"); try { await updateOpPromise(operation); - alert(wX("UPDATED")); + displayInfo(wX("UPDATED")); this.update(); } catch (e) { console.error(e); - alert(`Upload + Update Failed: ${e.toString()}`); + displayError(`Upload + Update Failed: ${e.toString()}`); } + this.button.classList.remove("loading"); } }, }); @@ -65,7 +68,7 @@ const UploadButton = WButton.extend({ update: function () { if (!WasabeeMe.isLoggedIn()) { this._invisible(); - this.title = wX("NOT LOGGED IN SHORT"); + this.title = ""; this.button.title = this.title; return; } @@ -80,21 +83,21 @@ const UploadButton = WButton.extend({ if (!operation.canWriteServer()) { this._invisible(); - this.title = wX("UPDATE PERM DENIED"); + this.title = ""; this.button.title = this.title; return; } if (!operation.localchanged) { this._invisible(); - this.title = wX("UPDATE HOVER NOT CHANGED", { opName: operation.name }); + this.title = ""; this.button.title = this.title; return; } if (operation.server && operation.server != GetWasabeeServer()) { this._invisible(); - this.title = wX("UPDATE HOVER WRONG SERVER", { opName: operation.name }); + this.title = ""; this.button.title = this.title; return; } @@ -110,6 +113,7 @@ const UploadButton = WButton.extend({ _invisible: function () { this.button.style.display = "none"; + this.button.classList.remove("loading"); }, // update operation that is either @@ -122,6 +126,7 @@ const UploadButton = WButton.extend({ if (operation.isServerOp()) { try { if (force) delete operation.lasteditid; + this.button.classList.add("loading"); const success = await updateOpPromise(operation); if (success) { operation.localchanged = false; @@ -131,7 +136,7 @@ const UploadButton = WButton.extend({ // reload if we use rebase if (operation != getSelectedOperation()) await makeSelectedOperation(operation.ID); - alert(wX("UPDATED")); + displayInfo(wX("UPDATED")); this.update(); } else { // need rebase or force @@ -150,14 +155,16 @@ const UploadButton = WButton.extend({ opOwn: getSelectedOperation(), opRemote: lastOp, updateCallback: (op) => this.doUpdate(op, true), + cancelText: wX("dialog.merge.cancel_upload"), }); md.enable(); } } } catch (e) { console.error(e); - alert(`Update Failed: ${e.toString()}`); + displayError(`Update Failed: ${e.toString()}`); } + this.button.classList.remove("loading"); return; } }, diff --git a/src/code/buttons/wasabeeButton.d.ts b/src/code/buttons/wasabeeButton.d.ts new file mode 100644 index 000000000..31db031db --- /dev/null +++ b/src/code/buttons/wasabeeButton.d.ts @@ -0,0 +1,4 @@ +import { WButton } from "../leafletClasses"; + +declare class WasabeeButton extends WButton {} +export default WasabeeButton; diff --git a/src/code/buttons/wasabeeButton.js b/src/code/buttons/wasabeeButton.js index 79f9855cd..1147ed4e7 100644 --- a/src/code/buttons/wasabeeButton.js +++ b/src/code/buttons/wasabeeButton.js @@ -1,17 +1,15 @@ import { WButton } from "../leafletClasses"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; import TeamListDialog from "../dialogs/teamListDialog"; import OpsDialog from "../dialogs/opsDialog"; import AuthDialog from "../dialogs/authDialog"; -import ConfirmDialog from "../dialogs/confirmDialog"; import NewopDialog from "../dialogs/newopDialog"; import SettingsDialog from "../dialogs/settingsDialog.js"; -import { resetOps, setupLocalStorage, removeNonOwnedOps } from "../selectedOp"; import DefensiveKeysDialog from "../dialogs/defensiveKeysDialog"; import { wX } from "../wX"; import { logoutPromise } from "../server"; import { postToFirebase } from "../firebaseSupport"; -import { resetCaches } from "../uiCommands"; +import { displayError } from "../error"; const WasabeeButton = WButton.extend({ statics: { @@ -37,23 +35,19 @@ const WasabeeButton = WButton.extend({ this._buildActions(); // build and display as if not logged in - this.actionsContainer = this._getActions(); - this._container.appendChild(this.actionsContainer); + this.setSubActions(this.getSubActions()); // check login state and update if necessary window.map.on("wasabee:ui:skin wasabee:ui:lang", () => { this.button.title = wX("WASABEE BUTTON TITLE"); this._buildActions(); - const newSubActions = this._getActions(); - this._container.replaceChild(newSubActions, this.actionsContainer); - newSubActions.style.display = this.actionsContainer.style.display; - this.actionsContainer = newSubActions; + this.setSubActions(this.getSubActions()); }); this.update(); }, - _getActions: function () { + getSubActions: function () { let tmp = []; if (!this._lastLoginState) { tmp = [this._loginAction]; @@ -72,7 +66,7 @@ const WasabeeButton = WButton.extend({ // settings always at the end tmp = tmp.concat(this._SettingsActions); - return this._createSubActions(tmp); + return tmp; }, _buildActions: function () { @@ -105,13 +99,10 @@ const WasabeeButton = WButton.extend({ text: wX("LOG_OUT"), callback: async () => { try { - // if not actually logged in, this removes ALL server ops - // but this button _should_ not be visible in that case - await removeNonOwnedOps(); await logoutPromise(); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } WasabeeMe.purge(); postToFirebase({ id: "wasabeeLogout" }); // trigger request firebase token on re-login @@ -151,25 +142,6 @@ const WasabeeButton = WButton.extend({ }, context: this, }, - { - title: wX("CLEAROPS BUTTON TITLE"), - text: wX("CLEAROPS BUTTON"), - callback: () => { - this.disable(); - const con = new ConfirmDialog({ - title: wX("CLEAROPS BUTTON TITLE"), - label: wX("CLEAROPS PROMPT"), - type: "operation", - callback: async () => { - await resetCaches(); - await resetOps(); - await setupLocalStorage(); - }, - }); - con.enable(); - }, - context: this, - }, ]; this._Dactions = [ @@ -187,7 +159,7 @@ const WasabeeButton = WButton.extend({ this._SettingsActions = [ { - title: "Settings", + title: wX("toolbar.wasabee.settings"), text: "βš™", callback: () => { this.disable(); @@ -209,9 +181,7 @@ const WasabeeButton = WButton.extend({ if (loggedIn) this.button.classList.add("wasabee-logged-in"); else this.button.classList.remove("wasabee-logged-in"); - const old = this.actionsContainer; - this.actionsContainer = this._getActions(); - old.parentNode.replaceChild(this.actionsContainer, old); + this.setSubActions(this.getSubActions()); this.disable(); } }, diff --git a/src/code/crosslinks.js b/src/code/crosslinks.ts similarity index 64% rename from src/code/crosslinks.js rename to src/code/crosslinks.ts index 3ae8b62ae..8d3d65846 100644 --- a/src/code/crosslinks.js +++ b/src/code/crosslinks.ts @@ -1,20 +1,39 @@ -import WasabeePortal from "./portal"; -import WasabeeLink from "./link"; +import WasabeePortal from "./model/portal"; +import WasabeeMarker from "./model/marker"; +import WasabeeBlocker from "./model/blocker"; import { getSelectedOperation } from "./selectedOp"; -const Wasabee = window.plugin.wasabee; +import PortalUI from "./ui/portal"; +import type WasabeeOp from "./model/operation"; +import type { IITC } from "../types/iitc"; +import type WasabeeLink from "./model/link"; // from iitc rework : https://github.com/IITC-CE/ingress-intel-total-conversion/pull/333 const d2r = Math.PI / 180; +const r2d = 180 / Math.PI; -function toCartesian(lat, lng) { +type Vec3 = [number, number, number]; +interface LLC extends L.LatLng { + _cartesian?: Vec3; +} + +function toCartesian(lat: number, lng: number): Vec3 { lat *= d2r; lng *= d2r; - var o = Math.cos(lat); + const o = Math.cos(lat); return [o * Math.cos(lng), o * Math.sin(lng), Math.sin(lat)]; } -function cross(t, n) { +export function toLatLng(xyz: Vec3): LLC { + const lat = Math.atan2(xyz[2], Math.sqrt(xyz[0] * xyz[0] + xyz[1] * xyz[1])); + const lng = Math.atan2(xyz[1], xyz[0]); + + const ll: LLC = L.latLng({ lat: lat * r2d, lng: lng * r2d }); + ll._cartesian = [...xyz]; + return ll; +} + +function cross(t: Vec3, n: Vec3): Vec3 { return [ t[1] * n[2] - t[2] * n[1], t[2] * n[0] - t[0] * n[2], @@ -22,17 +41,96 @@ function cross(t, n) { ]; } -function dot(t, n) { +function dot(t: Vec3, n: Vec3) { return t[0] * n[0] + t[1] * n[1] + t[2] * n[2]; } -function equals(a, b) { +function det(a: Vec3, b: Vec3, c: Vec3) { + return dot(cross(a, b), c); +} + +function norm2(a: Vec3) { + return a[0] * a[0] + a[1] * a[1] + a[2] * a[2]; +} + +function norm(a: Vec3) { + return Math.hypot(...a); +} + +// where is the fast inverse square root when we need it ? +export function normalize(a: Vec3): Vec3 { + const n = 1 / norm(a); + return [a[0] * n, a[1] * n, a[2] * n]; +} + +export function dist2(a: Vec3, b: Vec3) { + return norm2([a[0] - b[0], a[1] - b[1], a[2] - b[2]]); +} + +function equals(a: L.LatLng, b: L.LatLng) { return a.lat === b.lat && a.lng === b.lng; } // take L.LatLng // note: cache cos/sin calls in the object, in order to be efficient, try using same LatLng objects across calls, like using latLng from WasabeePortal attached to an op -export function greatCircleArcIntersectByLatLngs(a0, a1, b0, b1) { + +export function extendLatLngToLLC(ll: LLC) { + if (ll._cartesian) return ll; + ll._cartesian = toCartesian(ll.lat, ll.lng); + return ll; +} + +export function fieldSign( + a: WasabeePortal, + b: WasabeePortal, + c: WasabeePortal +) { + const ca = extendLatLngToLLC(a.latLng)._cartesian; + const cb = extendLatLngToLLC(b.latLng)._cartesian; + const cc = extendLatLngToLLC(c.latLng)._cartesian; + if (det(ca, cb, cc) > 0) return 1; + return -1; +} + +export function portalInField( + a: WasabeePortal, + b: WasabeePortal, + c: WasabeePortal, + portal: WasabeePortal +) { + const sign = fieldSign(a, b, c); + return ( + fieldSign(a, b, portal) * sign > 0 && + fieldSign(b, c, portal) * sign > 0 && + fieldSign(c, a, portal) * sign > 0 + ); +} + +export function fieldCenter( + a: WasabeePortal, + b: WasabeePortal, + c: WasabeePortal +) { + const ca = extendLatLngToLLC(a.latLng)._cartesian; + const cb = extendLatLngToLLC(b.latLng)._cartesian; + const cc = extendLatLngToLLC(c.latLng)._cartesian; + const ccenter: Vec3 = [ + ca[0] + cb[0] + cc[0], + ca[1] + cb[1] + cc[1], + ca[2] + cb[2] + cc[2], + ]; + return toLatLng(ccenter); +} + +export function greatCircleArcIntersectByLatLngs(a0: LLC[], a1: LLC[]): boolean; +export function greatCircleArcIntersectByLatLngs( + a0: LLC, + a1: LLC, + b0: LLC, + b1: LLC +): boolean; +export function greatCircleArcIntersectByLatLngs(...args: (LLC | LLC[])[]) { + const [a0, a1, b0, b1] = args.flat(); // 0) quick checks // zero length line if (equals(a0, a1)) return false; @@ -47,18 +145,10 @@ export function greatCircleArcIntersectByLatLngs(a0, a1, b0, b1) { if (Math.max(a0.lng, a1.lng) < Math.min(b0.lng, b1.lng)) return false; // a) convert into 3D coordinates on a unit sphere & cache into latLng object - const ca0 = (a0._cartesian = a0._cartesian - ? a0._cartesian - : toCartesian(a0.lat, a0.lng)); - const ca1 = (a1._cartesian = a1._cartesian - ? a1._cartesian - : toCartesian(a1.lat, a1.lng)); - const cb0 = (b0._cartesian = b0._cartesian - ? b0._cartesian - : toCartesian(b0.lat, b0.lng)); - const cb1 = (b1._cartesian = b1._cartesian - ? b1._cartesian - : toCartesian(b1.lat, b1.lng)); + const ca0 = extendLatLngToLLC(a0)._cartesian; + const ca1 = extendLatLngToLLC(a1)._cartesian; + const cb0 = extendLatLngToLLC(b0)._cartesian; + const cb1 = extendLatLngToLLC(b1)._cartesian; // b) two planes: ca0,ca1,0/0/0 and cb0,cb1,0/0/0 // find the intersetion line @@ -118,30 +208,26 @@ export function greatCircleArcIntersectByLatLngs(a0, a1, b0, b1) { return false; } -// takes WasabeeLink or L.geodesicPolyline format -export function greatCircleArcIntersect(existing, drawn) { - const eLL = existing.getLatLngs(); - const dLL = drawn.getLatLngs(); - - const a0 = eLL[0]; - const a1 = eLL[1]; - const b0 = dLL[0]; - const b1 = dLL[1]; - - return greatCircleArcIntersectByLatLngs(a0, a1, b0, b1); -} - -function testPolyLine(wasabeeLink, realLink, operation) { - if (greatCircleArcIntersect(realLink, wasabeeLink)) { +function testPolyLine( + wasabeeLink: WasabeeLink, + realLink: IITC.Link, + operation: WasabeeOp +) { + if ( + greatCircleArcIntersectByLatLngs( + realLink.getLatLngs(), + wasabeeLink.getLatLngs(operation) + ) + ) { if (!operation.markers || operation.markers.length == 0) { return true; } for (const marker of operation.markers) { if ( - marker.type == Wasabee.static.constants.MARKER_TYPE_DESTROY || - marker.type == Wasabee.static.constants.MARKER_TYPE_VIRUS || - marker.type == Wasabee.static.constants.MARKER_TYPE_DECAY + marker.type == WasabeeMarker.constants.MARKER_TYPE_DESTROY || + marker.type == WasabeeMarker.constants.MARKER_TYPE_VIRUS || + marker.type == WasabeeMarker.constants.MARKER_TYPE_DECAY ) { if ( marker.portalId == realLink.options.data.dGuid || @@ -156,9 +242,9 @@ function testPolyLine(wasabeeLink, realLink, operation) { return false; } -function showCrossLink(link, operation) { +function showCrossLink(link: IITC.Link) { // this should be in static.js or skin - const blocked = L.geodesicPolyline(link.getLatLngs(operation), { + const blocked = L.geodesicPolyline(link.getLatLngs(), { color: "#d22", opacity: 0.7, weight: 5, @@ -171,7 +257,7 @@ function showCrossLink(link, operation) { window.plugin.wasabee._crosslinkCache.set(link.options.guid, blocked); } -function testLink(link, operation) { +function testLink(link: IITC.Link, operation: WasabeeOp) { // if the crosslink already exists, do not recheck if (window.plugin.wasabee._crosslinkCache.has(link.options.guid)) { return; @@ -179,45 +265,40 @@ function testLink(link, operation) { for (const drawnLink of operation.links) { if (testPolyLine(drawnLink, link, operation)) { - showCrossLink(link, operation); - let fromPortal = WasabeePortal.get(link.options.data.oGuid); + showCrossLink(link); + let fromPortal = PortalUI.get(link.options.data.oGuid); if (!fromPortal) fromPortal = WasabeePortal.fake( (link.options.data.oLatE6 / 1e6).toFixed(6), (link.options.data.oLngE6 / 1e6).toFixed(6), link.options.data.oGuid ); - operation._addPortal(fromPortal); - let toPortal = WasabeePortal.get(link.options.data.dGuid); + let toPortal = PortalUI.get(link.options.data.dGuid); if (!toPortal) toPortal = WasabeePortal.fake( (link.options.data.dLatE6 / 1e6).toFixed(6), (link.options.data.dLngE6 / 1e6).toFixed(6), link.options.data.dGuid ); - operation._addPortal(toPortal); - const blocker = new WasabeeLink( - { fromPortalId: fromPortal.id, toPortalId: toPortal.id }, - operation - ); - operation.addBlocker(blocker); // op.update() is called here + WasabeeBlocker.addBlocker(operation, fromPortal, toPortal); break; } } } -function testSelfBlock(incoming, operation) { +export function testSelfBlock(incoming: WasabeeLink, operation: WasabeeOp) { for (const against of operation.links) { if (incoming.ID == against.ID) continue; - if (greatCircleArcIntersect(against, incoming)) { - const blocked = L.geodesicPolyline( + if ( + greatCircleArcIntersectByLatLngs( against.getLatLngs(operation), - window.plugin.wasabee.skin.selfBlockStyle - ); - blocked.options.interactive = false; - blocked.addTo(window.plugin.wasabee.crossLinkLayers); + incoming.getLatLngs(operation) + ) + ) { + return true; } } + return false; } // lets see if using a generator makes the GUI more responsive on large ops @@ -248,12 +329,19 @@ export function checkAllLinks() { } for (const l of operation.links) { - testSelfBlock(l, operation); + if (testSelfBlock(l, operation)) { + const blocked = L.geodesicPolyline( + l.getLatLngs(operation), + window.plugin.wasabee.skin.selfBlockStyle + ); + blocked.options.interactive = false; + blocked.addTo(window.plugin.wasabee.crossLinkLayers); + } } window.map.fire("wasabee:crosslinks:done"); } -function onLinkAdded(data) { +function onLinkAdded(data: EventLinkAdded) { testLink(data.link, getSelectedOperation()); } @@ -300,8 +388,16 @@ export function initCrossLinks() { } export class GeodesicLine { - constructor(start, end) { - let d2r = Math.PI / 180.0; + lat1: number; + lat2: number; + lng1: number; + lng2: number; + sinLat1CosLat2: number; + sinLat2CosLat1: number; + cosLat1CosLat2SinDLng: number; + + constructor(start: L.LatLng, end: L.LatLng) { + const d2r = Math.PI / 180.0; // let r2d = 180.0 / Math.PI; //eslint-disable-line // maths based on http://williams.best.vwh.net/avform.htm#Int if (start.lng == end.lng) { @@ -312,11 +408,11 @@ export class GeodesicLine { this.lat2 = end.lat * d2r; this.lng1 = start.lng * d2r; this.lng2 = end.lng * d2r; - let dLng = this.lng1 - this.lng2; - let sinLat1 = Math.sin(this.lat1); - let sinLat2 = Math.sin(this.lat2); - let cosLat1 = Math.cos(this.lat1); - let cosLat2 = Math.cos(this.lat2); + const dLng = this.lng1 - this.lng2; + const sinLat1 = Math.sin(this.lat1); + const sinLat2 = Math.sin(this.lat2); + const cosLat1 = Math.cos(this.lat1); + const cosLat2 = Math.cos(this.lat2); this.sinLat1CosLat2 = sinLat1 * cosLat2; this.sinLat2CosLat1 = sinLat2 * cosLat1; this.cosLat1CosLat2SinDLng = cosLat1 * cosLat2 * Math.sin(dLng); @@ -326,9 +422,9 @@ export class GeodesicLine { return this.lng1 == this.lng2; } - latAtLng(lng) { + latAtLng(lng: number) { lng = (lng * Math.PI) / 180; //to radians - let lat; + let lat: number; // if we're testing the start/end point, return that directly rather than calculating // 1. this may be fractionally faster, no complex maths // 2. there's odd rounding issues that occur on some browsers (noticed on IITC MObile) for very short links - this may help diff --git a/src/code/css/autodraws.css b/src/code/css/autodraws.css index 79843b2d5..b9fefe748 100644 --- a/src/code/css/autodraws.css +++ b/src/code/css/autodraws.css @@ -11,8 +11,8 @@ } .wasabee-dialog-fanfield .container, +.wasabee-dialog-flipflop .container, .wasabee-dialog-homogeneous .container, -.wasabee-dialog-link .container, .wasabee-dialog-madrid .container, .wasabee-dialog-multimax .container, .wasabee-dialog-onion .container, @@ -22,9 +22,18 @@ grid-gap: 0.2em 0.5em; align-items: center; grid-template-columns: minmax(min-content, 10em) min-content auto; + max-width: 700px; +} + +.wasabee-dialog-link .container { + display: grid; + grid-gap: 0.2em 0.5em; + align-items: center; + max-width: 700px; } .wasabee-dialog-fanfield label, +.wasabee-dialog-flipflop label, .wasabee-dialog-link label, .wasabee-dialog-madrid label, .wasabee-dialog-multimax label, @@ -32,9 +41,11 @@ .wasabee-dialog-starburst label, .wasabee-dialog-savelinks label { grid-column: 1; + text-decoration: dotted underline; } .wasabee-dialog-fanfield button, +.wasabee-dialog-flipflop button, .wasabee-dialog-homogeneous button, .wasabee-dialog-link button, .wasabee-dialog-madrid button, @@ -51,8 +62,13 @@ grid-column: 4; } -.wasabee-dialog-link .drawb, +.wasabee-dialog-link .drawb { + grid-column: 1/3; +} + .wasabee-dialog-fanfield .drawb, +.wasabee-dialog-flipflop .drawb, +.wasabee-dialog-onion .drawb, .wasabee-dialog-madrid .drawb, .wasabee-dialog-multimax .drawb, .wasabee-dialog-onion .drawb, @@ -62,6 +78,7 @@ } .wasabee-dialog-fanfield .desc, +.wasabee-dialog-flipflop .desc, .wasabee-dialog-madrid .desc, .wasabee-dialog-multimax .desc, .wasabee-dialog-onion .desc, @@ -70,31 +87,27 @@ grid-column: 1 / 4; } -.wasabee-dialog-starburst .desc2, -.wasabee-dialog-fanfield .desc2 { - grid-column: 1 / 3; +.wasabee-dialog-starburst .desc.secondary, +.wasabee-dialog-fanfield .desc.secondary { + color: lightgrey; } .wasabee-dialog-homogeneous .desc { grid-column: 1 / 5; } -.wasabee-dialog-homogeneous .portal { +.wasabee-dialog-homogeneous .set-portal-display { grid-column: 3 / 5; } .wasabee-dialog-link .portal { - grid-column: 3; + grid-column: 1/4; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } .wasabee-dialog-link .add, .wasabee-dialog-link .desc { - grid-column: 4; -} - -.wasabee-dialog-madrid .set_label { - grid-column: 1 / 4; + grid-column: 3; } -.wasabee-dialog-starburst .desc2 { - color: lightgrey; -} diff --git a/src/code/css/map.css b/src/code/css/map.css new file mode 100644 index 000000000..66c22f4ec --- /dev/null +++ b/src/code/css/map.css @@ -0,0 +1,364 @@ +/* wasabee-tooltip is used for the quickdraw mouse follower */ +.wasabee-tooltip { + background: rgba(30, 130, 76, 0.66); + border: 1px solid transparent; + -webkit-border-radius: 4px; + border-radius: 4px; + color: #fff; + /* font: 12px/18px "Helvetica Neue",Arial,Helvetica,sans-serif; */ + margin-left: 20px; + margin-top: -21px; + padding: 2px 4px; + position: absolute; + white-space: nowrap; + z-index: 6; +} +.wasabee-tooltip:before { + border-right: 6px solid #000; + border-right-color: rgba(99, 99, 88, 0.66); + border-top: 6px solid transparent; + border-bottom: 6px solid transparent; + content: ""; + position: absolute; + top: 7px; + left: -7px; +} +.wasabee-tooltip-single { + margin-top: -12px; +} +.wasabee-error-tooltip { + background-color: #f2dede; + border: 1px solid #e6b6bd; + color: #b94a48; +} +.wasabee-error-tooltip:before { + border-right-color: #e6b6bd; +} + +/* this class is appended to leaflet-popup so we can adjust without stepping on other plugins */ +.leaflet-popup.wasabee-popup .leaflet-popup-content-wrapper { + background: rgba(235, 235, 235, 0.75) !important; + -webkit-border-radius: 6px !important; + font-weight: bolder; +} + +#map .wasabee-popup .leaflet-popup-content { + color: black; +} + +.wasabee-popup a.enl { + color: rgb(56, 142, 60) !important; +} +.wasabee-popup a.res { + color: rgb(0, 135, 255) !important; +} + +.wasabee-link-popup .buttonset { + display: grid; +} + +.wasabee-marker-popup { +} +.wasabee-marker-popup div.desc { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: #000; + padding: 4px 4px; +} + +.wasabee-popup-assignment { + padding: 0px 4px 0px 4px; + text-overflow: ellipsis; + white-space: nowrap; + color: #000; +} + +.wasabee-popup-assignment a.wasabee-agent-label { + margin-left: 4px; +} + +.wasabee-marker-popup-kind { + margin-right: 4px; + text-overflow: ellipsis; + white-space: nowrap; + color: #000; +} + +.wasabee-marker-popup-comment { + font-weight: initial; + cursor: pointer; +} + +.wasabee-marker-popup-comment:hover { + text-decoration: underline; +} + +.wasabee-marker-popup-kind { + cursor: pointer; +} + +.wasabee-marker-popup-kind:hover { + text-decoration: underline; +} + +.wasabee-marker-buttonset { +} +.wasabee-marker-buttonset button { + display: block; + width: 100%; +} + +.wasabee-agent-popup { +} +.wasabee-agent-popup div.desc { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: #000; + padding: 0px 4px; +} + +.wasabee-agent-popup button { + display: block; + width: 100%; +} + +.wasabee-agent-popup ul.assignments { + color: rgb(56, 142, 60); +} + +.wasabee-agent-popup li.assignment { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +.wasabee-anchor-popup { +} +.wasabee-anchor-popup div.desc { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + color: #000; + padding: 0px 4px; +} + +.wasabee-anchor-buttonset { +} +.wasabee-anchor-buttonset button { + display: block; + width: 100%; +} + +.wasabee-wd-popup ul { + padding-left: 1em; +} + +.wasabee-marker-icon { + background-size: cover; +} + +.wasabee-marker-icon.CapturePortalMarker { + background-image: url(../images/wasabee_markers_capture_pending.svg) +} +.wasabee-marker-icon.CapturePortalMarker.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_capture_assigned.svg) +} +.wasabee-marker-icon.CapturePortalMarker.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_capture_acknowledge.svg) +} +.wasabee-marker-icon.CapturePortalMarker.wasabee-status-completed { + background-image: url(../images/wasabee_markers_capture_done.svg) +} +.wasabee-marker-icon.LetDecayPortalAlert { + background-image: url(../images/wasabee_markers_decay_pending.svg) +} +.wasabee-marker-icon.LetDecayPortalAlert.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_decay_assigned.svg) +} +.wasabee-marker-icon.LetDecayPortalAlert.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_decay_acknowledge.svg) +} +.wasabee-marker-icon.LetDecayPortalAlert.wasabee-status-completed { + background-image: url(../images/wasabee_markers_decay_done.svg) +} +.wasabee-marker-icon.DestroyPortalAlert { + background-image: url(../images/wasabee_markers_destroy_pending.svg) +} +.wasabee-marker-icon.DestroyPortalAlert.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_destroy_assigned.svg) +} +.wasabee-marker-icon.DestroyPortalAlert.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_destroy_acknowledge.svg) +} +.wasabee-marker-icon.DestroyPortalAlert.wasabee-status-completed { + background-image: url(../images/wasabee_markers_destroy_done.svg) +} +.wasabee-marker-icon.FarmPortalMarker { + background-image: url(../images/wasabee_markers_farm_pending.svg) +} +.wasabee-marker-icon.FarmPortalMarker.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_farm_assigned.svg) +} +.wasabee-marker-icon.FarmPortalMarker.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_farm_acknowledge.svg) +} +.wasabee-marker-icon.FarmPortalMarker.wasabee-status-completed { + background-image: url(../images/wasabee_markers_farm_done.svg) +} +.wasabee-marker-icon.GotoPortalMarker { + background-image: url(../images/wasabee_markers_goto_pending.svg) +} +.wasabee-marker-icon.GotoPortalMarker.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_goto_assigned.svg) +} +.wasabee-marker-icon.GotoPortalMarker.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_goto_acknowledged.svg) +} +.wasabee-marker-icon.GotoPortalMarker.wasabee-status-completed { + background-image: url(../images/wasabee_markers_goto_done.svg) +} +.wasabee-marker-icon.GetKeyPortalMarker { + background-image: url(../images/wasabee_markers_key_pending.svg) +} +.wasabee-marker-icon.GetKeyPortalMarker.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_key_assigned.svg) +} +.wasabee-marker-icon.GetKeyPortalMarker.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_key_acknowledged.svg) +} +.wasabee-marker-icon.GetKeyPortalMarker.wasabee-status-completed { + background-image: url(../images/wasabee_markers_key_done.svg) +} +.wasabee-marker-icon.CreateLinkAlert { + background-image: url(../images/wasabee_markers_link_pending.svg) +} +.wasabee-marker-icon.CreateLinkAlert.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_link_assigned.svg) +} +.wasabee-marker-icon.CreateLinkAlert.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_link_acknowledged.svg) +} +.wasabee-marker-icon.CreateLinkAlert.wasabee-status-completed { + background-image: url(../images/wasabee_markers_link_done.svg) +} +.wasabee-marker-icon.MeetAgentPortalMarker { + background-image: url(../images/wasabee_markers_meetagent_pending.svg) +} +.wasabee-marker-icon.MeetAgentPortalMarker.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_meetagent_assigned.svg) +} +.wasabee-marker-icon.MeetAgentPortalMarker.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_meetagent_acknowledge.svg) +} +.wasabee-marker-icon.MeetAgentPortalMarker.wasabee-status-completed { + background-image: url(../images/wasabee_markers_meetagent_done.svg) +} +.wasabee-marker-icon.OtherPortalAlert { + background-image: url(../images/wasabee_markers_other_pending.svg) +} +.wasabee-marker-icon.OtherPortalAlert.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_other_assigned.svg) +} +.wasabee-marker-icon.OtherPortalAlert.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_other_acknowledge.svg) +} +.wasabee-marker-icon.OtherPortalAlert.wasabee-status-completed { + background-image: url(../images/wasabee_markers_other_done.svg) +} +.wasabee-marker-icon.RechargePortalAlert { + background-image: url(../images/wasabee_markers_recharge_pending.svg) +} +.wasabee-marker-icon.RechargePortalAlert.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_recharge_assigned.svg) +} +.wasabee-marker-icon.RechargePortalAlert.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_recharge_acknowledge.svg) +} +.wasabee-marker-icon.RechargePortalAlert.wasabee-status-completed { + background-image: url(../images/wasabee_markers_recharge_done.svg) +} +.wasabee-marker-icon.UpgradePortalAlert { + background-image: url(../images/wasabee_markers_upgrade_pending.svg) +} +.wasabee-marker-icon.UpgradePortalAlert.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_upgrade_assigned.svg) +} +.wasabee-marker-icon.UpgradePortalAlert.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_upgrade_acknowledge.svg) +} +.wasabee-marker-icon.UpgradePortalAlert.wasabee-status-completed { + background-image: url(../images/wasabee_markers_upgrade_done.svg) +} +.wasabee-marker-icon.UseVirusPortalAlert { + background-image: url(../images/wasabee_markers_virus_pending.svg) +} +.wasabee-marker-icon.UseVirusPortalAlert.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_virus_assigned.svg) +} +.wasabee-marker-icon.UseVirusPortalAlert.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_virus_acknowledge.svg) +} +.wasabee-marker-icon.UseVirusPortalAlert.wasabee-status-completed { + background-image: url(../images/wasabee_markers_virus_done.svg) +} +.wasabee-marker-icon.ExcludeMarker { + background-image: url(../images/wasabee_markers_exclude_pending.svg) +} +.wasabee-marker-icon.ExcludeMarker.wasabee-status-assigned { + background-image: url(../images/wasabee_markers_exclude_assigned.svg) +} +.wasabee-marker-icon.ExcludeMarker.wasabee-status-acknowledged { + background-image: url(../images/wasabee_markers_exclude_assigned.svg) +} +.wasabee-marker-icon.ExcludeMarker.wasabee-status-completed { + background-image: url(../images/wasabee_markers_exclude_done.svg) +} + +.wasabee-defense-icon { + background-size: cover; + background-image: url(../images/wasabee_markers_key_done.svg) +} + +.wasabee-anchor-icon { + background-size: 25px 41px; +} +.wasabee-anchor-icon.wasabee-layer-main { + background-image: url(../images/pin_red.svg) +} +.wasabee-anchor-icon.wasabee-layer-groupa { + background-image: url(../images/pin_orange.svg) +} +.wasabee-anchor-icon.wasabee-layer-groupb { + background-image: url(../images/pin_yellow.svg) +} +.wasabee-anchor-icon.wasabee-layer-groupc { + background-image: url(../images/pin_tan.svg) +} +.wasabee-anchor-icon.wasabee-layer-groupd { + background-image: url(../images/pin_purple.svg) +} +.wasabee-anchor-icon.wasabee-layer-groupe { + background-image: url(../images/pin_teal.svg) +} +.wasabee-anchor-icon.wasabee-layer-groupf { + background-image: url(../images/pin_magenta.svg) +} + +.wasabee-portal-comment { + font-size: smaller; + font-weight: lighter; + margin-left: 12px; +} + +.wasabee-portal-hardness { + font-size: smaller; + font-weight: lighter; + margin-left: 12px; +} + +.wasabee-portal-hardness a { + color: #f00 !important; +} + diff --git a/src/code/css/smallscreen.css b/src/code/css/smallscreen.css index 37f004550..65c2c3785 100644 --- a/src/code/css/smallscreen.css +++ b/src/code/css/smallscreen.css @@ -18,20 +18,23 @@ vertical-align: bottom; } -.wasabee-dialog-checklist.wasabee-small-screen .wasabee-table td:nth-child(2) > div { +.wasabee-dialog-checklist.wasabee-small-screen .wasabee-table td:nth-child(2) > div, +.wasabee-dialog-linklist.wasabee-small-screen .wasabee-table td:nth-child(2) > div { display: grid; grid-template-columns: auto auto auto; grid-column-gap: 2px; align-items: center; } -.wasabee-dialog-checklist.wasabee-small-screen .wasabee-table td:nth-child(2) a.wasabee-portal { +.wasabee-dialog-checklist.wasabee-small-screen .wasabee-table td:nth-child(2) a.wasabee-portal, +.wasabee-dialog-linklist.wasabee-small-screen .wasabee-table td:nth-child(2) a.wasabee-portal { overflow: hidden; white-space: nowrap; text-overflow: ellipsis; } -.wasabee-dialog-checklist.wasabee-small-screen .wasabee-table td:nth-child(2) > a.wasabee-portal { +.wasabee-dialog-checklist.wasabee-small-screen .wasabee-table td:nth-child(2) > a.wasabee-portal +.wasabee-dialog-linklist.wasabee-small-screen .wasabee-table td:nth-child(2) > a.wasabee-portal { display: inline-block; vertical-align: bottom; width: calc(100vw - 13em - 24px); @@ -45,3 +48,8 @@ white-space: nowrap; text-overflow: ellipsis; } + +/* tool-bar */ +.leaflet-touch li.wasabee-subactions a { + width: inherit; +} \ No newline at end of file diff --git a/src/code/css/toolbar.css b/src/code/css/toolbar.css index 09a07589b..095514c74 100644 --- a/src/code/css/toolbar.css +++ b/src/code/css/toolbar.css @@ -72,6 +72,19 @@ background-color: #3c9; } +.wasabee-buttons.leaflet-control a.wasabee-toolbar-quickdelete.active { + background-color: #e66; +} + +.wasabee-buttons.leaflet-control a.wasabee-toolbar-quickdelete.active.blink { + animation: blink 2s infinite; +} +@keyframes blink { + 50% { + background-color: red; + } +} + /* align verticaly button subactions */ .wasabee-actions li { display: block; @@ -119,6 +132,10 @@ background-image: url(../images/toolbar_quickdraw.svg); background-size: 60%; } +.wasabee-toolbar-quickdelete { + background-image: url(../images/toolbar_quickdelete.svg); + background-size: 60%; +} .wasabee-toolbar-link { background-image: url(../images/toolbar_addlinks.svg) } @@ -129,7 +146,8 @@ /*background-image: url(../images/toolbar_sync.png)*/ background-image: url(../images/toolbar_download.svg) } -.wasabee-toolbar-sync.loading { +.wasabee-toolbar-sync.loading, +.wasabee-toolbar-upload.loading { background-image: url(../images/loading.gif) } diff --git a/src/code/css/wasabee.css b/src/code/css/wasabee.css index 65347432a..9ee0dde06 100644 --- a/src/code/css/wasabee.css +++ b/src/code/css/wasabee.css @@ -1,40 +1,3 @@ -/* wasabee-tooltip is used for the quickdraw mouse follower */ -.wasabee-tooltip { - background: rgba(30, 130, 76, 0.66); - border: 1px solid transparent; - -webkit-border-radius: 4px; - border-radius: 4px; - color: #fff; - /* font: 12px/18px "Helvetica Neue",Arial,Helvetica,sans-serif; */ - margin-left: 20px; - margin-top: -21px; - padding: 2px 4px; - position: absolute; - white-space: nowrap; - z-index: 6; -} -.wasabee-tooltip:before { - border-right: 6px solid #000; - border-right-color: rgba(99, 99, 88, 0.66); - border-top: 6px solid transparent; - border-bottom: 6px solid transparent; - content: ""; - position: absolute; - top: 7px; - left: -7px; -} -.wasabee-tooltip-single { - margin-top: -12px; -} -.wasabee-error-tooltip { - background-color: #f2dede; - border: 1px solid #e6b6bd; - color: #b94a48; -} -.wasabee-error-tooltip:before { - border-right-color: #e6b6bd; -} - /* used in anything that is a sortable table */ /* .wasabee-table tbody tr:nth-child(2n + 1) td { border-color: rgba(50, 0, 125, 1); } */ .wasabee-table tr { @@ -87,7 +50,15 @@ .wasabee-table > thead .sortable.desc:before { content: "\25bc"; } -// .wasabee-table td.menu { position: relative; min-height: 20px; min-width: 24px; } +/* .wasabee-table td.menu { position: relative; min-height: 20px; min-width: 24px; } */ + +.wasabee-dialog-agent ul { + padding-left: 0; +} + +.wasabee-dialog-agent li { + list-style: none; +} /* defined in agent.js, always on an -- can this be pruned ? */ .wasabee-agent-label a { @@ -104,306 +75,8 @@ pointer-events: none; } -/* this class is appended to leaflet-popup so we can adjust without stepping on other plugins */ -.wasabee-popup { - background: rgba(235, 235, 235, 0.75) !important; - -webkit-border-radius: 6px !important; - font-weight: bolder; -} - -#map .wasabee-popup .leaflet-popup-content { - color: black; -} - -.wasabee-popup a.enl { - color: rgb(56, 142, 60) !important; -} -.wasabee-popup a.res { - color: rgb(0, 135, 255) !important; -} - -.wasabee-marker-popup { -} -.wasabee-marker-popup div.desc { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: #000; - padding: 4px 4px; -} - -.wasabee-popup-assignment { - padding: 0px 4px 0px 4px; - text-overflow: ellipsis; - white-space: nowrap; - color: #000; -} - -.wasabee-popup-assignment a.wasabee-agent-label { - margin-left: 4px; -} - -.wasabee-marker-popup-kind { - margin-right: 4px; - text-overflow: ellipsis; - white-space: nowrap; - color: #000; -} - -.wasabee-marker-popup-comment { - font-weight: initial; -} - -.wasabee-marker-popup-kind { - cursor: pointer; -} - -.wasabee-marker-popup-kind:hover { - text-decoration: underline; -} - -.wasabee-marker-buttonset { -} -.wasabee-marker-buttonset button { - display: block; - width: 100%; -} - -.wasabee-agent-popup { -} -.wasabee-agent-popup div.desc { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: #000; - padding: 0px 4px; -} - -.wasabee-agent-popup button { - display: block; - width: 100%; -} - -.wasabee-agent-popup ul.assignments { - color: rgb(56, 142, 60); -} - -.wasabee-agent-popup li.assignment { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; -} - -.wasabee-anchor-popup { -} -.wasabee-anchor-popup div.desc { - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - color: #000; - padding: 0px 4px; -} - -.wasabee-anchor-buttonset { -} -.wasabee-anchor-buttonset button { - display: block; - width: 100%; -} - -.wasabee-wd-popup ul { - padding-left: 1em; -} - -.wasabee-marker-icon { - background-size: cover; -} - -.wasabee-marker-icon.CapturePortalMarker { - background-image: url(../images/wasabee_markers_capture_pending.svg) -} -.wasabee-marker-icon.CapturePortalMarker.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_capture_assigned.svg) -} -.wasabee-marker-icon.CapturePortalMarker.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_capture_acknowledge.svg) -} -.wasabee-marker-icon.CapturePortalMarker.wasabee-status-completed { - background-image: url(../images/wasabee_markers_capture_done.svg) -} -.wasabee-marker-icon.LetDecayPortalAlert { - background-image: url(../images/wasabee_markers_decay_pending.svg) -} -.wasabee-marker-icon.LetDecayPortalAlert.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_decay_assigned.svg) -} -.wasabee-marker-icon.LetDecayPortalAlert.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_decay_acknowledge.svg) -} -.wasabee-marker-icon.LetDecayPortalAlert.wasabee-status-completed { - background-image: url(../images/wasabee_markers_decay_done.svg) -} -.wasabee-marker-icon.DestroyPortalAlert { - background-image: url(../images/wasabee_markers_destroy_pending.svg) -} -.wasabee-marker-icon.DestroyPortalAlert.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_destroy_assigned.svg) -} -.wasabee-marker-icon.DestroyPortalAlert.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_destroy_acknowledge.svg) -} -.wasabee-marker-icon.DestroyPortalAlert.wasabee-status-completed { - background-image: url(../images/wasabee_markers_destroy_done.svg) -} -.wasabee-marker-icon.FarmPortalMarker { - background-image: url(../images/wasabee_markers_farm_pending.svg) -} -.wasabee-marker-icon.FarmPortalMarker.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_farm_assigned.svg) -} -.wasabee-marker-icon.FarmPortalMarker.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_farm_acknowledge.svg) -} -.wasabee-marker-icon.FarmPortalMarker.wasabee-status-completed { - background-image: url(../images/wasabee_markers_farm_done.svg) -} -.wasabee-marker-icon.GotoPortalMarker { - background-image: url(../images/wasabee_markers_goto_pending.svg) -} -.wasabee-marker-icon.GotoPortalMarker.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_goto_assigned.svg) -} -.wasabee-marker-icon.GotoPortalMarker.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_goto_acknowledged.svg) -} -.wasabee-marker-icon.GotoPortalMarker.wasabee-status-completed { - background-image: url(../images/wasabee_markers_goto_done.svg) -} -.wasabee-marker-icon.GetKeyPortalMarker { - background-image: url(../images/wasabee_markers_key_pending.svg) -} -.wasabee-marker-icon.GetKeyPortalMarker.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_key_assigned.svg) -} -.wasabee-marker-icon.GetKeyPortalMarker.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_key_acknowledged.svg) -} -.wasabee-marker-icon.GetKeyPortalMarker.wasabee-status-completed { - background-image: url(../images/wasabee_markers_key_done.svg) -} -.wasabee-marker-icon.CreateLinkAlert { - background-image: url(../images/wasabee_markers_link_pending.svg) -} -.wasabee-marker-icon.CreateLinkAlert.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_link_assigned.svg) -} -.wasabee-marker-icon.CreateLinkAlert.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_link_acknowledged.svg) -} -.wasabee-marker-icon.CreateLinkAlert.wasabee-status-completed { - background-image: url(../images/wasabee_markers_link_done.svg) -} -.wasabee-marker-icon.MeetAgentPortalMarker { - background-image: url(../images/wasabee_markers_meetagent_pending.svg) -} -.wasabee-marker-icon.MeetAgentPortalMarker.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_meetagent_assigned.svg) -} -.wasabee-marker-icon.MeetAgentPortalMarker.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_meetagent_acknowledge.svg) -} -.wasabee-marker-icon.MeetAgentPortalMarker.wasabee-status-completed { - background-image: url(../images/wasabee_markers_meetagent_done.svg) -} -.wasabee-marker-icon.OtherPortalAlert { - background-image: url(../images/wasabee_markers_other_pending.svg) -} -.wasabee-marker-icon.OtherPortalAlert.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_other_assigned.svg) -} -.wasabee-marker-icon.OtherPortalAlert.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_other_acknowledge.svg) -} -.wasabee-marker-icon.OtherPortalAlert.wasabee-status-completed { - background-image: url(../images/wasabee_markers_other_done.svg) -} -.wasabee-marker-icon.RechargePortalAlert { - background-image: url(../images/wasabee_markers_recharge_pending.svg) -} -.wasabee-marker-icon.RechargePortalAlert.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_recharge_assigned.svg) -} -.wasabee-marker-icon.RechargePortalAlert.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_recharge_acknowledge.svg) -} -.wasabee-marker-icon.RechargePortalAlert.wasabee-status-completed { - background-image: url(../images/wasabee_markers_recharge_done.svg) -} -.wasabee-marker-icon.UpgradePortalAlert { - background-image: url(../images/wasabee_markers_upgrade_pending.svg) -} -.wasabee-marker-icon.UpgradePortalAlert.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_upgrade_assigned.svg) -} -.wasabee-marker-icon.UpgradePortalAlert.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_upgrade_acknowledge.svg) -} -.wasabee-marker-icon.UpgradePortalAlert.wasabee-status-completed { - background-image: url(../images/wasabee_markers_upgrade_done.svg) -} -.wasabee-marker-icon.UseVirusPortalAlert { - background-image: url(../images/wasabee_markers_virus_pending.svg) -} -.wasabee-marker-icon.UseVirusPortalAlert.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_virus_assigned.svg) -} -.wasabee-marker-icon.UseVirusPortalAlert.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_virus_acknowledge.svg) -} -.wasabee-marker-icon.UseVirusPortalAlert.wasabee-status-completed { - background-image: url(../images/wasabee_markers_virus_done.svg) -} -.wasabee-marker-icon.ExcludeMarker { - background-image: url(../images/wasabee_markers_exclude_pending.svg) -} -.wasabee-marker-icon.ExcludeMarker.wasabee-status-assigned { - background-image: url(../images/wasabee_markers_exclude_assigned.svg) -} -.wasabee-marker-icon.ExcludeMarker.wasabee-status-acknowledged { - background-image: url(../images/wasabee_markers_exclude_assigned.svg) -} -.wasabee-marker-icon.ExcludeMarker.wasabee-status-completed { - background-image: url(../images/wasabee_markers_exclude_done.svg) -} - -.wasabee-defense-icon { - background-size: cover; - background-image: url(../images/wasabee_markers_key_done.svg) -} - -.wasabee-anchor-icon { - background-size: 25px 41px; -} -.wasabee-anchor-icon.wasabee-layer-main { - background-image: url(../images/pin_red.svg) -} -.wasabee-anchor-icon.wasabee-layer-groupa { - background-image: url(../images/pin_orange.svg) -} -.wasabee-anchor-icon.wasabee-layer-groupb { - background-image: url(../images/pin_yellow.svg) -} -.wasabee-anchor-icon.wasabee-layer-groupc { - background-image: url(../images/pin_tan.svg) -} -.wasabee-anchor-icon.wasabee-layer-groupd { - background-image: url(../images/pin_purple.svg) -} -.wasabee-anchor-icon.wasabee-layer-groupe { - background-image: url(../images/pin_teal.svg) -} -.wasabee-anchor-icon.wasabee-layer-groupf { - background-image: url(../images/pin_magenta.svg) +.wasabee-dialog .container { + align-items: center; } /* all dialogs get this class -- do global stuff with it */ @@ -610,6 +283,10 @@ margin: 0px 25px; } +.wasabee-dialog-markeradd div.bulk { + grid-column: 2; +} + .wasabee-dialog-markeradd div.content input { grid-column: 1 / span 2; } @@ -664,7 +341,11 @@ .wasabee-dialog-ops .wasabee-table.hideOps .visibility { display: none; } -.wasabee-dialog-checklist { +.wasabee-dialog-checklist .wasabee-table .actions { + white-space: nowrap; +} +.wasabee-dialog-checklist .wasabee-table .actions a { + padding: .25em } .wasabee-dialog-perms .add-perm { display: grid; @@ -696,33 +377,23 @@ padding: 4px; width: 96%; } -.wasabee-dialog-settings { - max-width: min-content; + +.wasabee-dialog-settings div.container > * { + display: block; + width: 100%; + margin: 0.3em 0; } -.wasabee-dialog-settings div.container { - display: grid; - grid-template-columns: 1fr 1fr; +.wasabee-dialog-settings div.container > :first-child { + border: none; + margin: 0; } .wasabee-dialog-settings label { - grid-column-start: 1; - grid-column-end: 2; -} -.wasabee-dialog-settings select { - grid-column-start: 2; - grid-column-end: 3; -} -.wasabee-dialog-settings input { - grid-column-start: 2; - grid-column-end: 3; -} -.wasabee-dialog-settings div.desc { - grid-column-start: 1; - grid-column-end: 3; + border-top: solid 1px #fff5; + padding: 0.3em 0 0 0; } - -.wasabee-dialog-settings button { - grid-column-start: 1; - grid-column-end: 3; +.wasabee-dialog-settings label.checkbox input { + margin-right: .5rem; + vertical-align: middle; } .wasabee-dialog-trawl div.container { @@ -780,24 +451,15 @@ list-style-position:inside; } -.wasabee-link-seperator:before { - content: " ➾ "; -} - -.wasabee-portal-comment { - font-size: smaller; - font-weight: lighter; - margin-left: 12px; +.wasabee-dialog-zone .wasabee-table .actions { + white-space: nowrap; } - -.wasabee-portal-hardness { - font-size: smaller; - font-weight: lighter; - margin-left: 12px; +.wasabee-dialog-zone .wasabee-table .actions a { + padding: .25em } -.wasabee-portal-hardness a { - color: #f00 !important; +.wasabee-link-seperator:before { + content: " ➾ "; } /* in our dialogs and popups, use a darker green for ENL for better contrast */ @@ -861,31 +523,58 @@ a.wasabee-portal.res { color: rgb(0, 135, 255) !important; } padding-left: 1em; } +.field-count li.inner-link > div { + display: inline; +} + .field-count ul { padding-left: 1em; } -/* merge dialog */ -@media (min-width: 700px) { - .wasabee-dialog-merge .details { - display: grid; - grid-template-columns: auto auto auto; - } +.wasabee-dialog-merge .conflicts { + border-collapse: collapse; + empty-cells: show; + width: 100%; + clear: both; + background: #0004; } -.wasabee-dialog-merge .details .wasabee-table { - margin-bottom: auto; - border: 1px solid white; - margin-right: 2px; - margin-left: 2px; +.wasabee-dialog-merge .conflicts tr:nth-child(2n + 1) { + background: #0004; } -.wasabee-dialog-merge .details .wasabee-table code { - display: block; +.wasabee-dialog-merge .conflicts td, +.wasabee-dialog-merge .conflicts th { + border-width: 0 1px; + border-style: solid; + padding: 3px 4px; + text-align: left; + vertical-align: baseline; +} +.wasabee-dialog-merge .conflicts td:first-child, +.wasabee-dialog-merge .conflicts th:first-child { + border-left-width: 0; +} +.wasabee-dialog-merge .conflicts td:last-child, +.wasabee-dialog-merge .conflicts th:last-child { + border-right-width: 0; +} + +.wasabee-dialog-merge .conflicts th:nth-child(2), +.wasabee-dialog-merge .conflicts th:nth-child(3) { + width: 2em; +} + +.wasabee-dialog-merge .strike { + text-decoration: line-through red; + padding-right: .5em; +} +.wasabee-dialog-merge .diff-label { + padding-right: .5em; } /* color pickers */ -.hidden-color-picker { +input[type=color].hidden-color-picker { visibility: hidden; width: 0; height: 0; diff --git a/src/code/db.ts b/src/code/db.ts new file mode 100644 index 000000000..ffe77251e --- /dev/null +++ b/src/code/db.ts @@ -0,0 +1,117 @@ +import { deleteDB, openDB } from "idb"; + +import type { DBSchema } from "idb"; +import type WasabeeAgent from "./model/agent"; +import type { IBlockerPortal } from "./model/blocker"; +import type WasabeeBlocker from "./model/blocker"; +import type { ILocalOp } from "./model/operation"; +import type WasabeeTeam from "./model/team"; +import type { WDKey } from "./wd"; + +const version = 3; + +interface WasabeeDB extends DBSchema { + agents: { + key: GoogleID; + value: WasabeeAgent; + indexes: { + date: string; + fetched: string; + }; + }; + teams: { + key: TeamID; + value: WasabeeTeam; + indexes: { + fetched: string; + }; + }; + defensivekeys: { + key: [GoogleID, PortalID]; + value: WDKey; + indexes: { + PortalID: string; + Count: number; + }; + }; + operations: { + key: OpID; + value: ILocalOp; + indexes: { + fetched: string; + server: string; + }; + }; + blockers: { + key: [OpID, PortalID, PortalID]; + value: WasabeeBlocker; + indexes: { + opID: OpID; + from: PortalID; + to: PortalID; + }; + }; + blockers_portals: { + key: [OpID, PortalID]; + value: IBlockerPortal; + indexes: { + opID: OpID; + }; + }; +} + +// XXX audit these to make sure all the various indexes are used +const db = openDB("wasabee", version, { + upgrade(db, oldVersion, newVersion, tx) { + if (oldVersion < 1) { + const agents = db.createObjectStore("agents", { keyPath: "id" }); + agents.createIndex("date", "date"); // last location change + agents.createIndex("fetched", "fetched"); // last pull from server + const teams = db.createObjectStore("teams", { keyPath: "id" }); + teams.createIndex("fetched", "fetched"); // last pull from server + + // do not set an implied key, explicitly set GID/PortalID on insert + // XXX we can do this with a keyPath https://stackoverflow.com/questions/33852508/how-to-create-an-indexeddb-composite-key + // const defensivekeys = db.createObjectStore("defensivekeys"); + const defensivekeys = db.createObjectStore("defensivekeys", { + keyPath: ["GID", "PortalID"], + }); + defensivekeys.createIndex("PortalID", "PortalID"); + defensivekeys.createIndex("Count", "Count"); // To be used to remove 0-count entries + // defensivekeys.createIndex("pk", ["GID", "PortalID"], { unique: true }); + } + if (oldVersion < 2) { + const ops = db.createObjectStore("operations", { keyPath: "ID" }); + ops.createIndex("fetched", "fetched"); + ops.createIndex("server", "server"); + } + if (oldVersion < 3) { + // { opID, from, to } + const blockers = db.createObjectStore("blockers", { + keyPath: ["opID", "from", "to"], + }); + blockers.createIndex("opID", "opID", { unique: false }); + blockers.createIndex("from", ["opID", "from"], { unique: false }); + blockers.createIndex("to", ["opID", "to"], { unique: false }); + + // portals for blockers + // { id, lat, lng, name } + const portals = db.createObjectStore("blockers_portals", { + keyPath: ["opID", "id"], + }); + portals.createIndex("opID", "opID", { unique: false }); + } + /* if (oldVersion < 3) { + const teams = tx.objectStore("teams"); + teams.createIndex("_agents", "_agents[].id"); + } */ + console.debug(newVersion, tx); + }, +}); + +export async function deleteDatabase() { + (await db).close(); + return deleteDB("wasabee"); +} + +export default db; diff --git a/src/code/dialogs/about.d.ts b/src/code/dialogs/about.d.ts new file mode 100644 index 000000000..30c9f0e60 --- /dev/null +++ b/src/code/dialogs/about.d.ts @@ -0,0 +1,3 @@ +import { WDialog } from "../leafletClasses"; +declare class AboutDialog extends WDialog {} +export default AboutDialog; diff --git a/src/code/dialogs/about.js b/src/code/dialogs/about.js index aa9223491..1e08f8359 100644 --- a/src/code/dialogs/about.js +++ b/src/code/dialogs/about.js @@ -12,13 +12,7 @@ const AboutDialog = WDialog.extend({ addHooks: function () { // this pulls in the addHooks from the parent class WDialog.prototype.addHooks.call(this); - // put any per-open setup here - // this is the call to actually do our work - if (this._smallScreen) { - this._displaySmallDialog(); - } else { - this._displayDialog(); - } + this._displayDialog(); }, // define our work in _displayDialog @@ -29,6 +23,11 @@ const AboutDialog = WDialog.extend({ // wX is the translation call, it looks up the string in the agent's chosen language support.innerHTML = wX("SUPPORT_INSTRUCT"); + if (this._smallScreen) { + const mobileApp = L.DomUtil.create("div", null, html); + mobileApp.innerHTML = wX("dialog.about.download_mobile_app"); + } + const tips = L.DomUtil.create("div", null, html); tips.innerHTML = "

Show your love

Patreon"; @@ -43,7 +42,7 @@ const AboutDialog = WDialog.extend({ // Since the JqueryUI dialog buttons are hard-coded, we have to override them to translate them const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -59,12 +58,6 @@ const AboutDialog = WDialog.extend({ buttons: buttons, }); }, - - // small-screen versions go in _displaySmallDialog - _displaySmallDialog: function () { - // for this dialog, the small screen is the same as the normal - this._displayDialog(); - }, }); // this line allows other files to import our dialog diff --git a/src/code/dialogs/agentDialog.d.ts b/src/code/dialogs/agentDialog.d.ts new file mode 100644 index 000000000..c6872b750 --- /dev/null +++ b/src/code/dialogs/agentDialog.d.ts @@ -0,0 +1,9 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +interface AgentDialogOptions extends WDialogOptions { + gid: string; +} +declare class AgentDialog extends WDialog { + options: AgentDialogOptions; + constructor(options: AgentDialogOptions); +} +export default AgentDialog; diff --git a/src/code/dialogs/agentDialog.js b/src/code/dialogs/agentDialog.js index 1e8434814..8cf8ac20a 100644 --- a/src/code/dialogs/agentDialog.js +++ b/src/code/dialogs/agentDialog.js @@ -1,6 +1,7 @@ import { WDialog } from "../leafletClasses"; import wX from "../wX"; -import WasabeeAgent from "../agent"; +import WasabeeAgent from "../model/agent"; +import { appendFAIcon } from "../auxiliar"; const AgentDialog = WDialog.extend({ statics: { @@ -18,27 +19,40 @@ const AgentDialog = WDialog.extend({ _displayDialog: async function () { const html = L.DomUtil.create("div", null); - const agent = L.DomUtil.create("div", null, html); try { const data = await WasabeeAgent.get(this.options.gid); - const name = L.DomUtil.create("h2", "enl, wasabee-agent-label", agent); - name.textContent = data.name; - const vLabel = L.DomUtil.create("label", null, agent); - vLabel.textContent = "V Verified: "; - L.DomUtil.create("div", null, vLabel).textContent = data.Vverified; - const rocksLabel = L.DomUtil.create("label", null, agent); - rocksLabel.textContent = "Rocks Verified: "; - L.DomUtil.create("div", null, rocksLabel).textContent = data.rocks; - const img = L.DomUtil.create("img", null, agent); + L.DomUtil.create("h2", "wasabee-agent-label", html).textContent = + data.getName(); + + const ul = L.DomUtil.create("ul", "", html); + const rows = [ + ["Server name: ", data.name], + ["Ingress name: ", data.communityname], + ["V name: ", data.vname], + ["V verified: ", data.Vverified], + ["Rocks name: ", data.rocksname], + ["Rocks Verified: ", data.rocks], + ]; + for (const [label, value] of rows) { + const li = L.DomUtil.create("li", "", ul); + L.DomUtil.create("label", null, li).textContent = label; + if (value === true) { + appendFAIcon("check", li); + } else { + L.DomUtil.create("span", null, li).textContent = value; + } + } + + const img = L.DomUtil.create("img", null, html); img.src = data.pic; } catch (e) { console.error(e); - agent.innerHTML = e.toString(); + html.innerHTML = e.toString(); } const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; diff --git a/src/code/dialogs/assignDialog.d.ts b/src/code/dialogs/assignDialog.d.ts new file mode 100644 index 000000000..39240323c --- /dev/null +++ b/src/code/dialogs/assignDialog.d.ts @@ -0,0 +1,13 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; +import WasabeePortal from "../model/portal"; +interface AssignDialogOptions extends WDialogOptions { + target: WasabeeLink | WasabeeMarker | WasabeePortal; +} +declare class AssignDialog extends WDialog { + needWritePermission: true; + options: AssignDialogOptions; + constructor(options: AssignDialogOptions); +} +export default AssignDialog; diff --git a/src/code/dialogs/assignDialog.js b/src/code/dialogs/assignDialog.js index cd949330d..0d4738cc6 100644 --- a/src/code/dialogs/assignDialog.js +++ b/src/code/dialogs/assignDialog.js @@ -1,12 +1,15 @@ import { WDialog } from "../leafletClasses"; -import WasabeeLink from "../link"; -import WasabeeMarker from "../marker"; -import WasabeeAnchor from "../anchor"; -import WasabeeMe from "../me"; -import WasabeeTeam from "../team"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; +import WasabeePortal from "../model/portal"; +import WasabeeMe from "../model/me"; +import WasabeeTeam from "../model/team"; import wX from "../wX"; import { getSelectedOperation } from "../selectedOp"; +import PortalUI from "../ui/portal"; +import LinkUI from "../ui/link"; + const AssignDialog = WDialog.extend({ statics: { TYPE: "assignDialog", @@ -29,13 +32,11 @@ const AssignDialog = WDialog.extend({ this.closeDialog(); }; - // create container then setup asynchronously - this._html = L.DomUtil.create("div", "container"); - this._setup(); + const html = this._buildContent(); this.createDialog({ title: this._name, - html: this._html, + html: html, width: "auto", dialogClass: "assign", buttons: buttons, @@ -43,95 +44,85 @@ const AssignDialog = WDialog.extend({ }); }, - _setup: async function () { + _buildContent: function () { + const html = L.DomUtil.create("div", "container"); + const target = this.options.target; const operation = getSelectedOperation(); this._targetID = target.ID; - const divtitle = L.DomUtil.create("div", "desc", this._html); - const menu = await this._getAgentMenu(target.assignedTo); + + const divtitle = L.DomUtil.create("div", "desc", html); + const menu = L.DomUtil.create("div", "wasabee-agent-menu", html); if (target instanceof WasabeeLink) { const portal = operation.getPortal(target.fromPortalId); this._type = "Link"; - this._name = wX("ASSIGN LINK PROMPT", { portalName: portal.displayName }); - divtitle.appendChild(target.displayFormat(operation, this._smallScreen)); - const t = L.DomUtil.create("label", null); + this._name = wX("ASSIGN LINK PROMPT", { + portalName: PortalUI.displayName(portal), + }); + divtitle.appendChild(LinkUI.displayFormat(target, operation)); + const t = L.DomUtil.create("label", null, menu); t.textContent = wX("LINK ASSIGNMENT"); - menu.prepend(t); } if (target instanceof WasabeeMarker) { const portal = operation.getPortal(target.portalId); this._type = "Marker"; this._name = wX("ASSIGN MARKER PROMPT", { - portalName: portal.displayName, + portalName: PortalUI.displayName(portal), }); - divtitle.appendChild(portal.displayFormat(this._smallScreen)); - const t = L.DomUtil.create("label", null); + divtitle.appendChild(PortalUI.displayFormat(portal)); + const t = L.DomUtil.create("label", null, menu); t.textContent = wX("MARKER ASSIGNMENT"); - menu.prepend(t); } - if (target instanceof WasabeeAnchor) { - const portal = operation.getPortal(target.portalId); + if (target instanceof WasabeePortal) { + const portal = target; this._type = "Anchor"; this._name = wX("ASSIGN OUTBOUND PROMPT", { - portalName: portal.displayName, + portalName: PortalUI.displayName(portal), }); - divtitle.appendChild(portal.displayFormat(this._smallScreen)); - const t = L.DomUtil.create("label", null); + divtitle.appendChild(PortalUI.displayFormat(portal)); + const t = L.DomUtil.create("label", null, menu); t.textContent = wX("ANCHOR ASSIGNMENT"); - menu.prepend(t); } - this._html.appendChild(menu); - }, - - _buildContent: function () { - const content = L.DomUtil.create("div"); - if (typeof this._label == "string") { - content.textContent = this._label; - } else { - content.appendChild(this._label); - } - return content; - }, - - _getAgentMenu: async function (current) { - const container = L.DomUtil.create("div", "wasabee-agent-menu"); - const menu = L.DomUtil.create("select", null, container); - let option = menu.appendChild(L.DomUtil.create("option", null)); + const select = L.DomUtil.create("select", null, menu); + const option = L.DomUtil.create("option", null, select); option.value = ""; option.textContent = wX("UNASSIGNED"); - const alreadyAdded = new Array(); - menu.addEventListener("change", (value) => { + L.DomEvent.on(select, "change", (value) => { this.localAssign(value); }); + this._populateAgentSelect(select, target.assignedTo); + + return html; + }, + + _populateAgentSelect: async function (select, current) { + const alreadyAdded = new Array(); + const me = await WasabeeMe.waitGet(); for (const t of getSelectedOperation().teamlist) { if (me.teamJoined(t.teamid) == false) continue; try { // allow teams to be 5 minutes cached const tt = await WasabeeTeam.get(t.teamid, 5 * 60); - const agents = tt.getAgents(); - for (const a of agents) { + for (const a of tt.agents) { if (!alreadyAdded.includes(a.id)) { alreadyAdded.push(a.id); - option = L.DomUtil.create("option"); + const option = L.DomUtil.create("option", "", select); option.value = a.id; - option.textContent = a.name; + option.textContent = a.getName(); if (a.id == current) option.selected = true; - menu.appendChild(option); } } } catch (e) { console.error(e); } } - - return container; }, localAssign: function (value) { @@ -143,11 +134,9 @@ const AssignDialog = WDialog.extend({ operation.assignLink(this._targetID, value.srcElement.value); } if (this._type == "Anchor") { - const links = operation.getLinkListFromPortal( - operation.getPortal(this._targetID) - ); + const links = operation.getLinkListFromPortal(this.options.target); for (const l of links) { - if (l.fromPortalId == this._targetID) { + if (l.fromPortalId == this.options.target.id) { operation.assignLink(l.ID, value.srcElement.value); } } diff --git a/src/code/dialogs/authDialog.d.ts b/src/code/dialogs/authDialog.d.ts new file mode 100644 index 000000000..16459ee4a --- /dev/null +++ b/src/code/dialogs/authDialog.d.ts @@ -0,0 +1,3 @@ +import { WDialog } from "../leafletClasses"; +declare class AuthDialog extends WDialog {} +export default AuthDialog; diff --git a/src/code/dialogs/authDialog.js b/src/code/dialogs/authDialog.js index bb8e9f141..790ddc72d 100644 --- a/src/code/dialogs/authDialog.js +++ b/src/code/dialogs/authDialog.js @@ -1,16 +1,18 @@ import { WDialog } from "../leafletClasses"; -import { - SendAccessTokenAsync, - GetWasabeeServer, - SetWasabeeServer, - oneTimeToken, - setIntelID, -} from "../server"; +import { GetWasabeeServer, SetWasabeeServer, setIntelID } from "../server"; import PromptDialog from "./promptDialog"; import { sendLocation, fullSync } from "../uiCommands"; import { wX } from "../wX"; import { postToFirebase } from "../firebaseSupport"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; +import { displayError, ServerError } from "../error"; +import { + isAuthAvailable, + getAccessToken, + sendAccessToken, + sendOneTimeToken, +} from "../auth"; +import { constants } from "../static"; const AuthDialog = WDialog.extend({ statics: { @@ -31,25 +33,25 @@ const AuthDialog = WDialog.extend({ sendLocation(); }, - _successLogin: async function (me) { - const newme = me ? new WasabeeMe(me) : await WasabeeMe.waitGet(true); - newme.store(); + _successLogin: function (me) { + me.store(); window.map.fire("wasabee:login"); this.closeDialog(); fullSync(); - setIntelID(window.PLAYER.nickname, window.PLAYER.team, newme.querytoken); // no need to await + if (me.querytoken) + setIntelID(window.PLAYER.nickname, window.PLAYER.team, me.querytoken); }, _displayDialog: function () { - const syncLoggedIn = window.gapi.auth2.getAuthInstance(); - if (syncLoggedIn) { - alert(wX("AUTH INCOMPAT")); + if (isAuthAvailable()) { + displayError(wX("AUTH INCOMPAT")); return; } const content = L.DomUtil.create("div", "content"); - this._server = L.DomUtil.create("div", null, content); - this._server.textContent = GetWasabeeServer(); + this._server = L.DomUtil.create("input", "", content); + this._server.readOnly = true; + this._server.value = GetWasabeeServer(); const ua = L.DomUtil.create("div", "useragent", content); this._android = false; @@ -77,34 +79,16 @@ const AuthDialog = WDialog.extend({ } } - const title = L.DomUtil.create("div", "desc", content); - if (this._ios) { - title.textContent = wX("AUTH IOS"); - } - if (this._android) { - title.textContent = wX("AUTH ANDROID"); - } - const gapiButton = L.DomUtil.create("button", "gapi", content); gapiButton.textContent = wX("LOG IN"); - // XXX until we can figure out why IITC-M iOS doesn't set the cookie very often - if (this._ios) gapiButton.style.display = "none"; L.DomEvent.on(gapiButton, "click", (ev) => { L.DomEvent.stop(ev); gapiButton.disabled = true; gapiButton.textContent = "... loading ..."; - this.gapiAuth.call(this); + this.gapiAuth(); }); - // XXX this needs to go away - const menus = L.DomUtil.create("div", "options", content); - menus.innerHTML = - "Login Settings:   " + - ": " + - ": "; - if (!this._android) menus.style.display = "none"; - if (!this._android && !this._ios) { const gapiSelectButton = L.DomUtil.create("button", "gapi", content); gapiSelectButton.textContent = wX("AUTH_SELECT_ACCOUNT"); @@ -112,33 +96,7 @@ const AuthDialog = WDialog.extend({ L.DomEvent.stop(ev); gapiSelectButton.disabled = true; gapiSelectButton.textContent = "... loading ..."; - this.gsapiAuthChoose.call(this); - }); - } - - // webview cannot work on android IITC-M - if (this._ios) { - const webviewButton = L.DomUtil.create("button", "webview", content); - webviewButton.textContent = wX("WEBVIEW"); - L.DomEvent.on(webviewButton, "click", (ev) => { - L.DomEvent.stop(ev); - window.open(GetWasabeeServer()); - webviewButton.style.display = "none"; - postwebviewButton.style.display = "block"; - }); - const postwebviewButton = L.DomUtil.create("button", "webview", content); - postwebviewButton.textContent = wX("WEBVIEW VERIFY"); - postwebviewButton.style.display = "none"; - L.DomEvent.on(postwebviewButton, "click", async (ev) => { - L.DomEvent.stop(ev); - try { - await this._successLogin(); - postToFirebase({ id: "wasabeeLogin", method: "iOS" }); - } catch (e) { - console.error(e); - alert(e.toString()); - } - window.map.fire("wasabee:defensivekeys"); + this.gsapiAuthChoose(); }); } @@ -156,7 +114,7 @@ const AuthDialog = WDialog.extend({ callback: () => { if (serverDialog.inputField.value) { SetWasabeeServer(serverDialog.inputField.value); - this._server.textContent = GetWasabeeServer(); + this._server.value = GetWasabeeServer(); WasabeeMe.purge(); } window.map.fire("wasabee:defensivekeys"); @@ -167,21 +125,25 @@ const AuthDialog = WDialog.extend({ }); const oneTimeButton = L.DomUtil.create("button", "server", content); - oneTimeButton.textContent = "One Time Token Login"; + oneTimeButton.textContent = wX("dialog.auth.ott.button"); L.DomEvent.on(oneTimeButton, "click", (ev) => { L.DomEvent.stop(ev); + const text = L.DomUtil.create("span"); + text.innerHTML = wX("dialog.auth.ott.text", { + url: `${constants.WEBUI_DEFAULT}/#/settings`, + }); const ottDialog = new PromptDialog({ - title: "One Time Token", - label: "One Time Token", + title: wX("dialog.auth.ott.title"), + label: text, callback: async () => { if (ottDialog.inputField.value) { try { - await oneTimeToken(ottDialog.inputField.value); - await this._successLogin(); + const me = await sendOneTimeToken(ottDialog.inputField.value); + this._successLogin(me); postToFirebase({ id: "wasabeeLogin", method: "One Time Token" }); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } } window.map.fire("wasabee:defensivekeys"); @@ -192,7 +154,7 @@ const AuthDialog = WDialog.extend({ }); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -208,101 +170,40 @@ const AuthDialog = WDialog.extend({ // this works in most cases // but fails on android if the account logged into intel is different than the one used for Wasabee - gapiAuth: function () { - const options = { - client_id: window.plugin.wasabee.static.constants.OAUTH_CLIENT_ID, - scope: "email profile openid", - response_type: "id_token permission", - }; - const immediate = document.getElementById("auth-immediate"); - if (immediate && immediate.value != "unset") - options.immediate = immediate.value; - const uxmode = document.getElementById("ux-mode"); - if (uxmode && uxmode.value != "unset") options.ux_mode = uxmode.value; - const gPrompt = document.getElementById("auth-prompt"); - if (gPrompt && gPrompt.value != "unset") options.prompt = gPrompt.value; - window.gapi.auth2.authorize(options, async (response) => { - if (response.error) { - postToFirebase({ id: "exception", error: response.error }); - if (response.error === "idpiframe_initialization_failed") { - alert("You need enable cookies or allow [*.]google.com"); - } - if ( - response.error == "user_logged_out" || - response.error == "immediate_failed" - ) { - options.prompt = "select_account"; // try again, forces prompt but preserves "immediate" selection - window.gapi.auth2.authorize(options, async (responseSelect) => { - if (responseSelect.error) { - postToFirebase({ id: "exception", error: response.error }); - const err = `error from gapiAuth (immediate_failed): ${responseSelect.error}: ${responseSelect.error_subtype}`; - alert(err); - console.log(err); - return; - } - try { - const r = await SendAccessTokenAsync(responseSelect.access_token); - await this._successLogin(r); - postToFirebase({ - id: "wasabeeLogin", - method: "gsapiAuth (immediate_failed)", - }); - } catch (e) { - alert(wX("AUTH TOKEN REJECTED", { error: e.toString() })); - console.error(e); - this.closeDialog(); - } - }); - } else { - this.closeDialog(); - const err = `error from gapiAuth: ${response.error}: ${response.error_subtype}`; - postToFirebase({ id: "exception", error: err }); - console.log(err); - alert(err); - } - return; - } - try { - const r = await SendAccessTokenAsync(response.access_token); - await this._successLogin(r); - postToFirebase({ id: "wasabeeLogin", method: "gsapiAuth" }); - } catch (e) { - postToFirebase({ id: "exception", error: e.toString() }); - console.error(e); - alert(e.toString()); - this.closeDialog(); + gapiAuth: async function () { + try { + const token = await getAccessToken(false); + const me = await sendAccessToken(token); + postToFirebase({ id: "wasabeeLogin", method: "gapiAuth" }); + this._successLogin(me); + } catch (e) { + this.disable(); + this.enable(); + if (e instanceof ServerError) { + displayError(wX("AUTH TOKEN REJECTED", { error: e.toString() })); + } else { + displayError(e); + postToFirebase({ id: "exception", error: e }); } - }); + } }, - gsapiAuthChoose: function () { - window.gapi.auth2.authorize( - { - prompt: "select_account", - client_id: window.plugin.wasabee.static.constants.OAUTH_CLIENT_ID, - scope: "email profile openid", - response_type: "id_token permission", - // immediate: false // this seems to break everything - }, - async (response) => { - if (response.error) { - this.closeDialog(); - const err = `error from gsapiAuthChoose: ${response.error}: ${response.error_subtype}`; - alert(err); - postToFirebase({ id: "exception", error: err }); - return; - } - try { - const r = await SendAccessTokenAsync(response.access_token); - await this._successLogin(r); - postToFirebase({ id: "wasabeeLogin", method: "gsapiAuthChoose" }); - } catch (e) { - console.error(e); - alert(`send access token failed (gsapiAuthChoose): ${e.toString()}`); - postToFirebase({ id: "exception", error: e.toString() }); - } + gsapiAuthChoose: async function () { + try { + const token = await getAccessToken(true); + const me = await sendAccessToken(token); + postToFirebase({ id: "wasabeeLogin", method: "gsapiAuthChoose" }); + this._successLogin(me); + } catch (e) { + this.disable(); + this.enable(); + if (e instanceof ServerError) { + displayError(wX("AUTH TOKEN REJECTED", { error: e.toString() })); + } else { + displayError(e); + postToFirebase({ id: "exception", error: e }); } - ); + } }, }); diff --git a/src/code/dialogs/autodraws.d.ts b/src/code/dialogs/autodraws.d.ts new file mode 100644 index 000000000..2571cf38c --- /dev/null +++ b/src/code/dialogs/autodraws.d.ts @@ -0,0 +1,7 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; + +declare class AutodrawsDialog extends WDialog { + needWritePermission: true; + constructor(options?: WDialogOptions); +} +export default AutodrawsDialog; diff --git a/src/code/dialogs/autodraws.js b/src/code/dialogs/autodraws.js index 83999ef6e..75e8233ea 100644 --- a/src/code/dialogs/autodraws.js +++ b/src/code/dialogs/autodraws.js @@ -1,12 +1,13 @@ import { WDialog } from "../leafletClasses"; import wX from "../wX"; -import MultimaxDialog from "../dialogs/multimaxDialog"; -import FanfieldDialog from "../dialogs/fanfield"; -import StarburstDialog from "../dialogs/starburst"; -import SaveLinksDialog from "../dialogs/saveLinks"; -import OnionfieldDialog from "../dialogs/onionfield"; -import HomogeneousDialog from "../dialogs/homogeneous"; -import MadridDialog from "../dialogs/madrid"; +import MultimaxDialog from "./autodraws/multimaxDialog"; +import FanfieldDialog from "./autodraws/fanfield"; +import StarburstDialog from "./autodraws/starburst"; +import SaveLinksDialog from "./autodraws/saveLinks"; +import OnionfieldDialog from "./autodraws/onionfield"; +import HomogeneousDialog from "./autodraws/homogeneous"; +import MadridDialog from "./autodraws/madrid"; +import FlipFlopDialog from "./autodraws/flipflop"; // This file documents the minimum requirements of a dialog in wasabee const AutodrawsDialog = WDialog.extend({ @@ -76,16 +77,20 @@ const AutodrawsDialog = WDialog.extend({ sl.enable(); }, }, + { + text: wX("FLIP_FLOP_NAME"), + callback: () => { + this.closeDialog(); + const ff = new FlipFlopDialog(); + ff.enable(); + }, + }, ]; }, addHooks: function () { WDialog.prototype.addHooks.call(this); - if (this._smallScreen) { - this._displaySmallDialog(); - } else { - this._displayDialog(); - } + this._displayDialog(); }, _displayDialog: function () { @@ -102,7 +107,7 @@ const AutodrawsDialog = WDialog.extend({ } const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -115,10 +120,6 @@ const AutodrawsDialog = WDialog.extend({ id: window.plugin.wasabee.static.dialogNames.autodraws, }); }, - - _displaySmallDialog: function () { - this._displayDialog(); - }, }); export default AutodrawsDialog; diff --git a/src/code/dialogs/autodraws/algorithm.ts b/src/code/dialogs/autodraws/algorithm.ts new file mode 100644 index 000000000..9bdf7bfa2 --- /dev/null +++ b/src/code/dialogs/autodraws/algorithm.ts @@ -0,0 +1,239 @@ +import { fieldSign, GeodesicLine } from "../../crosslinks"; +import type WasabeePortal from "../../model/portal"; + +type Poset = Map; + +/** + given two anchor, build a map that shows which and how many portals are covered by each possible field by guid + note: a portal always covers itself +*/ +export function buildPoset( + anchor1: WasabeePortal, + anchor2: WasabeePortal, + portals: WasabeePortal[] +) { + const posetPositive: Poset = new Map(); + const posetNegative: Poset = new Map(); + + for (const i of portals) { + if (i.id === anchor1.id || i.id === anchor2.id) continue; + const result = []; + const sign = fieldSign(anchor1, anchor2, i); + for (const j of portals) { + if (j.id === anchor1.id || j.id === anchor2.id) continue; + if (i === j) result.push(j.id); + else if ( + fieldSign(anchor1, anchor2, j) * sign > 0 && + fieldSign(anchor2, i, j) * sign > 0 && + fieldSign(i, anchor1, j) * sign > 0 + ) + result.push(j.id); + } + if (sign > 0) posetPositive.set(i.id, result); + else posetNegative.set(i.id, result); + } + + return [posetPositive, posetNegative]; +} + +interface LongestSequences { + children: T[]; + length: number; + number: number; +} +/** + given a poset, compute the maximal paths from all elements + the result contains a map that gives for any element the next ones and the list of the elements + that have the longest paths +*/ +function longestSequencesPoset(poset: Poset) { + const alreadyCalculatedChildren = new Map< + T | "__start__", + LongestSequences + >(); + const preds_from = (c: T | "__start__") => { + if (alreadyCalculatedChildren.get(c) === undefined) { + const res: LongestSequences = { + children: [], + length: 1, + number: 1, + }; + const preds = + c === "__start__" + ? Array.from(poset.keys()) + : poset.get(c).filter((i) => i !== c); + for (const id of preds) { + const val = preds_from(id); + if (val.length + 1 > res.length) { + res.length = val.length + 1; + res.children = []; + res.number = 0; + } + if (val.length + 1 == res.length) { + res.children.push(id); + res.number += val.number; + } + } + alreadyCalculatedChildren.set(c, res); + } + return alreadyCalculatedChildren.get(c); + }; + + return { + maxima: preds_from("__start__").children, + poset: alreadyCalculatedChildren, + number: preds_from("__start__").number, + }; +} + +interface LongestSequence { + seq: T[]; + dist: number; +} +/** + given a poset, find the longest sequence p1,p2,...pk such that poset(p2) contains p1, poset(p3) contains p2 etc + that minimizes the flight distance + notes: + - the result is an empty sequence only if the poset is empty or if poset(p) is empty for any p + - if the poset is given by buildPOSet, the first element is the guid of a portal that doesn't cover any other portal, + and the last element is the portal that covers all portals of the sequence and isn't covered by any other portal + (inner to outer) +*/ +export function longestSequence( + poset: Poset, + start?: T, + dist?: (a: T, b: T) => number +) { + const maximalPaths = longestSequencesPoset(poset); + if (!maximalPaths.maxima.length) return []; + const alreadyCalculatedSequences = new Map>(); + if (!dist) dist = () => 0; + const sequence_from = (c: T) => { + if (alreadyCalculatedSequences.get(c) === undefined) { + const mP = maximalPaths.poset.get(c); + if (mP.length == 1) + alreadyCalculatedSequences.set(c, { seq: [c], dist: 0 }); + else { + const best = mP.children + .map(sequence_from) + .reduce((S1, S2) => + S1.dist + dist(c, S1.seq[S1.seq.length - 1]) < + S2.dist + dist(c, S2.seq[S2.seq.length - 1]) + ? S1 + : S2 + ); + const res = { + seq: Array.from(best.seq), + dist: best.dist, + }; + res.dist += dist(res.seq[res.seq.length - 1], c); + res.seq.push(c); + alreadyCalculatedSequences.set(c, res); + } + } + return alreadyCalculatedSequences.get(c); + }; + + if (start) { + console.debug( + maximalPaths.poset.get(start).number, + "possible paths from the given start" + ); + return sequence_from(start).seq; + } + + console.debug(maximalPaths.number, "possible paths"); + return maximalPaths.maxima + .map(sequence_from) + .reduce((S1, S2) => (S1.dist < S2.dist ? S1 : S2)).seq; +} + +/** Returns longest spines from each side of the base `pOne/pTwo` */ +export function getSignedSpine( + pOne: WasabeePortal, + pTwo: WasabeePortal, + portals: WasabeePortal[], + bothSide = false +) { + const portalsMap = new Map(portals.map((p) => [p.id, p])); + const [pPos, pNeg] = buildPoset(pOne, pTwo, portals); + const sequencePos = longestSequence(pPos, null, (a, b) => + window.map.distance(portalsMap.get(a).latLng, portalsMap.get(b).latLng) + ); + const sequenceNeg = longestSequence(pNeg, null, (a, b) => + window.map.distance(portalsMap.get(a).latLng, portalsMap.get(b).latLng) + ); + + if (bothSide) + return [ + sequencePos.map((id) => portalsMap.get(id)), + sequenceNeg.map((id) => portalsMap.get(id)), + ]; + + const sequence = + sequencePos.length > sequenceNeg.length ? sequencePos : sequenceNeg; + return [sequence.map((id) => portalsMap.get(id))]; +} + +/** Returns bearing of link a-p */ +export function angle(a: WasabeePortal, p: WasabeePortal) { + if (a.id == p.id) throw Error("same portal"); + if (a.latLng.lng == p.latLng.lng) { + if (a.latLng.lat > p.latLng.lat) return 0; + else return Math.PI; + } + const link = new GeodesicLine(a.latLng, p.latLng); + return link.bearing(); +} + +/** Sort portals by angle from anchor */ +export function sortPortalsByAngle( + anchor: WasabeePortal, + portals: WasabeePortal[] +) { + const good = new Map(); + for (const p of portals) { + if (p.id == anchor.id) continue; + const pAngle = angle(anchor, p); + good.set(pAngle, p); + } + + const sorted = new Array(...good.entries()) + .sort((a, b) => a[0] - b[0]) + .map((v) => v[1]); + + return sorted; +} + +/** + * Select portals in the interval start-end wrt their angle from anchor. + * The portals must be sorted by angle and contains start/end + */ +export function selectAngleInterval( + anchor: WasabeePortal, + portalsSorted: WasabeePortal[], + start: WasabeePortal, + end: WasabeePortal +) { + const startAngle = angle(anchor, start); + const endAngle = angle(anchor, end); + + // swap start/end if more than 180Β° + if ( + (((endAngle - startAngle) % (2 * Math.PI)) + 2 * Math.PI) % (2 * Math.PI) > + Math.PI + ) { + [start, end] = [end, start]; + } + + // Build the sequence of portals between start/end + const slice = new Array(); + let s = 0; + for (s = 0; portalsSorted[s].id != start.id; s++); + for (; portalsSorted[s % portalsSorted.length].id != end.id; s++) { + slice.push(portalsSorted[s % portalsSorted.length]); + } + slice.push(end); + + return slice; +} diff --git a/src/code/dialogs/autodraws/drawRoutines.ts b/src/code/dialogs/autodraws/drawRoutines.ts new file mode 100644 index 000000000..daf4a4402 --- /dev/null +++ b/src/code/dialogs/autodraws/drawRoutines.ts @@ -0,0 +1,72 @@ +import type WasabeeLink from "../../model/link"; +import type WasabeeOp from "../../model/operation"; +import type WasabeePortal from "../../model/portal"; + +/** Return the description of links for the given spine */ +function getSpineLinks( + anchor1: WasabeePortal, + anchor2: WasabeePortal, + spine: WasabeePortal[], + options: { + backlink?: boolean; + } = {} +) { + const linksDesc: { + from: WasabeePortal; + to: WasabeePortal; + back?: boolean; + }[] = []; + let prev = null; + for (const p of spine) { + linksDesc.push({ from: p, to: anchor1 }); + linksDesc.push({ from: p, to: anchor2 }); + if (options.backlink && prev) + linksDesc.push({ from: p, to: prev, back: true }); + prev = p; + } + return linksDesc; +} + +/** Insert in `op` the links after the order `order` */ +export function insertLinks( + op: WasabeeOp, + links: WasabeeLink[], + order: number, + noShift = false +) { + for (const l of links) l.order = 0; + // shift current op tasks order + if (!noShift && order < op.nextOrder - 1) { + for (const l of op.links) if (l.order > order) l.order += links.length; + for (const m of op.markers) if (m.order > order) m.order += links.length; + } + for (const l of links) l.order = ++order; + return order; +} + +/** Insert a spine in `op` after order `order` */ +export function drawSpine( + op: WasabeeOp, + anchor1: WasabeePortal, + anchor2: WasabeePortal, + spine: WasabeePortal[], + order: number, + options: { + backlink?: boolean; + commentPrefix?: string; + noShift?: boolean; + } = {} +) { + const links = getSpineLinks(anchor1, anchor2, spine, options); + + const commentPrefix = options.commentPrefix || ""; + const wlinks = links + .map((l) => + op.addLink(l.from, l.to, { + description: commentPrefix + (l.back ? "backlink" : "link"), + }) + ) + .filter((l) => l); + + return insertLinks(op, wlinks, order, options.noShift); +} diff --git a/src/code/dialogs/autodraws/fanfield.d.ts b/src/code/dialogs/autodraws/fanfield.d.ts new file mode 100644 index 000000000..e8602aaa2 --- /dev/null +++ b/src/code/dialogs/autodraws/fanfield.d.ts @@ -0,0 +1,11 @@ +import type WasabeePortal from "../../model/portal"; +import type { AutoDraw } from "./tools"; + +export function angle(a: WasabeePortal, p: WasabeePortal): number; + +export default class FanfieldDialog extends AutoDraw { + _anchor: WasabeePortal; + _start: WasabeePortal; + _end: WasabeePortal; + constructor(); +} diff --git a/src/code/dialogs/autodraws/fanfield.js b/src/code/dialogs/autodraws/fanfield.js new file mode 100644 index 000000000..6c2a3c8c6 --- /dev/null +++ b/src/code/dialogs/autodraws/fanfield.js @@ -0,0 +1,197 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; +import { getSelectedOperation } from "../../selectedOp"; +import { greatCircleArcIntersectByLatLngs } from "../../crosslinks"; +import { clearAllLinks } from "../../uiCommands"; +import wX from "../../wX"; +import { displayError, displayInfo } from "../../error"; + +import { sortPortalsByAngle, selectAngleInterval } from "./algorithm"; +import { insertLinks } from "./drawRoutines"; + +function sortPortals(anchor, portals, start, end) { + if (!portals.find((p) => p.id === start.id)) portals.push(start); + if (!portals.find((p) => p.id === end.id)) portals.push(end); + const sorted = sortPortalsByAngle(anchor, portals); + return selectAngleInterval(anchor, sorted, start, end); +} + +/** + * Return the link descriptions for fanfield + * @param {WasabeePortal} anchor + * @param {WasabeePortal[]} portals + * @param {WasabeePortal} start + * @param {WasabeePortal} end + * @returns {[{ from: WasabeePortal, to: WasabeePortal, comment: string}[], number]} + */ +function fanfield(anchor, portals, start, end) { + let fields = 0; + const links = []; + + const sorted = sortPortals(anchor, portals, start, end); + + const available = Array.from(sorted); + available.reverse(); + + for (let i = available.length - 1; i >= 0; i--) { + const wp = available[i]; + links.push({ from: wp, to: anchor, comment: "anchor" }); + + if (i + 1 == available.length) continue; + + // Find the interval of portals that are linkable + let j = i + 1; + let prev = null; + for (; j < available.length; j++) { + const p = available[j]; + if ( + prev && + greatCircleArcIntersectByLatLngs( + anchor.latLng, + prev.latLng, + wp.latLng, + p.latLng + ) + ) + break; + prev = p; + } + j--; + links.push({ + from: wp, + to: available[j], + comment: "subfield", + }); + fields++; + + for (var k = j - 1; k > i; k--) { + links.push({ + from: wp, + to: available[k], + comment: "double subfield", + }); + fields += 2; + } + // remove covered portals + available.splice(i + 1, j - i - 1); + } + return [links, fields]; +} + +const FanfieldDialog = AutoDraw.extend({ + statics: { + TYPE: "FanfieldDialog", + }, + + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + let p = localStorage["wasabee-anchor-1"]; + if (p) this._anchor = new WasabeePortal(p); + p = localStorage["wasabee-fanfield-start"]; + if (p) this._start = new WasabeePortal(p); + p = localStorage["wasabee-fanfield-end"]; + if (p) this._end = new WasabeePortal(p); + }, + + addHooks: function () { + AutoDraw.prototype.addHooks.call(this); + this._displayDialog(); + this._updatePortalSet(); + }, + + _displayDialog: function () { + const container = L.DomUtil.create("div", "container"); + const description = L.DomUtil.create("div", "desc", container); + description.textContent = wX("SELECT_FAN_PORTALS"); + + this._addSetPortal( + wX("ANCHOR_PORTAL"), + "_anchor", + container, + "wasabee-anchor-1" + ); + this._addSetPortal( + wX("START_PORT"), + "_start", + container, + "wasabee-fanfield-start" + ); + this._addSetPortal( + wX("END_PORT"), + "_end", + container, + "wasabee-fanfield-end" + ); + + this._addSelectSet(wX("AUTODRAW_PORTALS_SET"), "set", container, "all"); + + const description2 = L.DomUtil.create("div", "desc secondary", container); + description2.textContent = wX("SELECT_FAN_PORTALS2"); + + // Bottom buttons bar + // Go button + const button = L.DomUtil.create("button", "drawb", container); + button.textContent = wX("FANFIELD"); + L.DomEvent.on(button, "click", (ev) => { + L.DomEvent.stop(ev); + this.fanfield.call(this); + }); + const buttons = {}; + buttons[wX("CLOSE")] = () => { + this.closeDialog(); + }; + buttons[wX("CLEAR LINKS")] = () => { + clearAllLinks(getSelectedOperation()); + }; + + this.createDialog({ + title: wX("FANFIELD2"), + html: container, + width: "auto", + dialogClass: "fanfield", + buttons: buttons, + id: window.plugin.wasabee.static.dialogNames.fanfield, + }); + }, + + // fanfiled determines the portals between start/end and their angle (and order) + fanfield: function () { + if (!this._anchor || !this._start || !this._end) { + displayError(wX("SET_3_PORT")); + return; + } + + const [links, fields] = fanfield( + this._anchor, + this._portalSets["set"].portals, + this._start, + this._end + ); + + const op = getSelectedOperation(); + + op.startBatchMode(); + const wlinks = links + .map((l) => + op.addLink(l.from, l.to, { + description: "fanfield " + l.comment, + }) + ) + .filter((l) => l); + + insertLinks(op, wlinks, 0); + op.endBatchMode(); + + const ap = 313 * links.length + 1250 * fields; + // too many parameters for wX(); + displayInfo( + wX("autodraw.fanfield.result", { + links: links.length, + fields: fields, + ap: ap, + }) + ); + }, +}); + +export default FanfieldDialog; diff --git a/src/code/dialogs/autodraws/flipflop.d.ts b/src/code/dialogs/autodraws/flipflop.d.ts new file mode 100644 index 000000000..14908f7f2 --- /dev/null +++ b/src/code/dialogs/autodraws/flipflop.d.ts @@ -0,0 +1,8 @@ +import type WasabeePortal from "../../model/portal"; +import type { AutoDraw } from "./tools"; + +export default class FlipFlopDialog extends AutoDraw { + _anchorOne: WasabeePortal; + _nbSbul: HTMLInputElement; + constructor(); +} diff --git a/src/code/dialogs/autodraws/flipflop.js b/src/code/dialogs/autodraws/flipflop.js new file mode 100644 index 000000000..3673eaf2c --- /dev/null +++ b/src/code/dialogs/autodraws/flipflop.js @@ -0,0 +1,314 @@ +import { AutoDraw } from "./tools"; +import wX from "../../wX"; +import { getSelectedOperation } from "../../selectedOp"; +import { getAllPortalsOnScreen, clearAllLinks } from "../../uiCommands"; + +import WasabeePortal from "../../model/portal"; +import WasabeeMarker from "../../model/marker"; + +import { selectAngleInterval, sortPortalsByAngle } from "./algorithm"; +import { greatCircleArcIntersectByLatLngs } from "../../crosslinks"; +import { displayError, displayInfo } from "../../error"; + +function fastFan(anchor, two, three, portalsSorted, offset, revSortAngle) { + const res = []; + const inserted = [two, three]; + if (revSortAngle.get(two.id) > revSortAngle.get(three.id)) inserted.reverse(); + for (let i = offset; i < portalsSorted.length; i++) { + const p = portalsSorted[i]; + if (!revSortAngle.has(p.id)) continue; + let prev = inserted.length - 1; + let next = 0; + while ( + prev >= 0 && + revSortAngle.get(inserted[prev].id) > revSortAngle.get(p.id) + ) + prev--; + while ( + next < inserted.length && + revSortAngle.get(inserted[next].id) < revSortAngle.get(p.id) + ) + next++; + if ( + !greatCircleArcIntersectByLatLngs( + anchor, + p, + inserted[prev], + inserted[next] + ) + ) { + res.push([p, inserted[prev], inserted[next]]); + inserted.splice(prev + 1, 0, p); + } + } + return res; +} + +// now that the formerly external mm functions are in the class, some of the logic can be cleaned up +// to not require passing values around when we can get them from this.XXX +const FlipFlopDialog = AutoDraw.extend({ + statics: { + TYPE: "flipflopDialog", + }, + + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + let p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; + if (p) this._anchorOne = new WasabeePortal(p); + }, + + addHooks: function () { + AutoDraw.prototype.addHooks.call(this); + this._displayDialog(); + this._updatePortalSet(); + }, + + _buildContent: function () { + const container = L.DomUtil.create("div", "container"); + const description = L.DomUtil.create("div", "desc", container); + description.textContent = wX("FLIP_FLOP_DESC"); + + const description2 = L.DomUtil.create("div", "desc", container); + description2.textContent = wX("FLIP_FLOP_INSTRUCTION"); + + this._addSetPortal( + wX("ANCHOR1"), + "_anchorOne", + container, + window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY + ); + + this._addSelectSet(wX("AUTODRAW_PORTALS_SET"), "set", container, "all"); + + L.DomUtil.create("label", null, container).textContent = "#SBUL"; + this._nbSbul = L.DomUtil.create("input", null, container); + this._nbSbul.type = "number"; + this._nbSbul.value = 2; + this._nbSbul.size = 1; + this._nbSbul.min = 0; + this._nbSbul.max = 4; + + // Go button + const button = L.DomUtil.create("button", "drawb", container); + button.textContent = wX("autodraw.common.draw_button"); + L.DomEvent.on(button, "click", () => { + const total = this.doFanGun(); + displayInfo(wX("autodraw.flipflop.result", { count: total })); + }); + + return container; + }, + + _displayDialog: function () { + const container = this._buildContent(); + + const buttons = {}; + buttons[wX("CLOSE")] = () => { + this.closeDialog(); + }; + buttons[wX("FLIP_FLOP_FIND_ANCHORS")] = () => { + this.findOtherAnchors(); + }; + buttons[wX("CLEAR LINKS")] = () => { + clearAllLinks(getSelectedOperation()); + }; + + this.createDialog({ + title: wX("FLIP_FLOP_TITLE"), + html: container, + width: "auto", + dialogClass: "flipflop", + buttons: buttons, + id: "flipflop", + }); + }, + + findOtherAnchors: function () { + if (!this.best) return; + + this._operation = getSelectedOperation(); + const portals = getAllPortalsOnScreen(this._operation); + + const sequencePortals = this.best.steps.map((s) => s[0]); + const linkedPortals = sequencePortals.concat([ + this.best.two, + this.best.three, + ]); + const portalsMatch = []; + for (const a of portals) { + let match = true; + + // check distance order + for (const [p, p1, p2] of this.best.steps) { + if ( + a.latLng.distanceTo(p.latLng) > a.latLng.distanceTo(p1.latLng) || + a.latLng.distanceTo(p.latLng) > a.latLng.distanceTo(p2.latLng) + ) { + match = false; + break; + } + } + if (!match) continue; + + // check angle order + const sortedAngle = sortPortalsByAngle(a, linkedPortals); + const interval = selectAngleInterval( + a, + sortedAngle, + this.best.two, + this.best.three + ); + if (interval.length !== linkedPortals.length) continue; + + const angleSort = interval.map((p) => p.id); + let i = 0, + j = 0; + while (i < angleSort.length && j < this.best.angleSort.length) { + if (this.best.angleSort[j] === angleSort[i]) i++; + j++; + } + match = i == angleSort.length; + + if (match) portalsMatch.push(a); + } + for (const a of portalsMatch) { + this._operation.addMarker(WasabeeMarker.constants.MARKER_TYPE_LINK, a, { + comment: "flipflop anchor", + }); + } + }, + + getDistances: function (anchor, portals) { + if (this.distCache && this.distCache.has(anchor.id)) + return this.distCache.get(anchor.id); + const dists = new Map( + portals.map((p) => [p.id, p.latLng.distanceTo(anchor.latLng)]) + ); + if (this.distCache) this.distCache.set(anchor.id, dists); + return dists; + }, + + createFanLinks: function (one, two, three, steps, order = 0) { + this._operation.addLink(two, three, { + description: "flipflop origin", + order: order + 1, + }); + for (const [p, a, b] of steps) { + this._operation.addLink(p, a, { + description: "flipflop origin", + order: order + 1, + }); + this._operation.addLink(p, b, { + description: "flipflop origin", + order: order + 1, + }); + } + + order++; + this._operation.addLink(one, two, { + description: "flipflop fire", + order: ++order, + }); + this._operation.addLink(one, three, { + description: "flipflop fire", + order: ++order, + }); + for (const s of steps) { + const p = s[0]; + this._operation.addLink(one, p, { + description: "flipflop fire", + order: ++order, + }); + } + }, + + doFanGun: function () { + // Calculate the multimax + if (!this._anchorOne) { + displayError(wX("INVALID REQUEST")); + return 0; + } + + this._operation = getSelectedOperation(); + const portals = this._portalSets["set"].portals.filter( + (p) => p.id != this._anchorOne.id + ); + + const nbSbul = + +this._nbSbul.value < 0 + ? 0 + : +this._nbSbul.value > 4 + ? 4 + : +this._nbSbul.value; + + console.log("starting fastfan"); + this.distCache = new Map(); + const distances = this.getDistances(this._anchorOne, portals); + portals.sort((a, b) => distances.get(b.id) - distances.get(a.id)); + + const sortedAngle = sortPortalsByAngle(this._anchorOne, portals); + + const best = { + two: null, + three: null, + steps: [], + }; + const maxSteps = 8 * (nbSbul + 1) - 2; + + for (let i = 0; i < portals.length; i++) { + const pTwo = portals[i]; + for (let j = i + 1; j < portals.length; j++) { + const pThree = portals[j]; + const interval = selectAngleInterval( + this._anchorOne, + sortedAngle, + pTwo, + pThree + ); + const revAngleSort = new Map(interval.map((p, i) => [p.id, i])); + const res = fastFan( + this._anchorOne, + pTwo, + pThree, + portals, + j + 1, + revAngleSort + ); + if (!best.two || best.steps.length < res.length) { + best.steps = res; + best.two = pTwo; + best.three = pThree; + best.angleSort = interval.map((p) => p.id); + if (best.steps.length >= maxSteps) break; + } + } + if (best.steps.length >= maxSteps) break; + } + + if (best.steps.length > maxSteps) + best.steps = best.steps.slice(0, maxSteps); + + if (!best.two) { + displayError(wX("INVALID REQUEST")); + return 0; + } + + this.best = best; + + this._operation.startBatchMode(); + this.createFanLinks( + this._anchorOne, + best.two, + best.three, + best.steps, + this._operation.nextOrder - 1 + ); + console.log("fastfan done"); + + this._operation.endBatchMode(); // save and run crosslinks + + return best.steps.length + 2; + }, +}); + +export default FlipFlopDialog; diff --git a/src/code/dialogs/autodraws/homogeneous.d.ts b/src/code/dialogs/autodraws/homogeneous.d.ts new file mode 100644 index 000000000..527df4402 --- /dev/null +++ b/src/code/dialogs/autodraws/homogeneous.d.ts @@ -0,0 +1,28 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; + +/** Tree-like strucure holding a HF configuration */ +export interface Tree { + /** true if complete with respect to the request depth */ + success: boolean; + /** anchors of the field */ + anchors: [WasabeePortal, WasabeePortal, WasabeePortal]; + /** number of split found (tree size) */ + split: number; + /** portal used to split the field into three sub field */ + portal: WasabeePortal; + /** sub tree using `portal` */ + children: [Tree, Tree, Tree]; +} + +export default class HomogeneousDialog extends AutoDraw { + _anchorOne: WasabeePortal; + _anchorTwo: WasabeePortal; + _anchorThree: WasabeePortal; + depthMenu: HTMLSelectElement; + orderMenu: HTMLSelectElement; + _fullSearch: boolean; + _urp: L.LatLng; + + constructor(); +} diff --git a/src/code/dialogs/autodraws/homogeneous.js b/src/code/dialogs/autodraws/homogeneous.js new file mode 100644 index 000000000..1d1340d3f --- /dev/null +++ b/src/code/dialogs/autodraws/homogeneous.js @@ -0,0 +1,793 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; +import { getSelectedOperation } from "../../selectedOp"; +import { + extendLatLngToLLC, + greatCircleArcIntersectByLatLngs, + portalInField, + dist2, + fieldCenter, +} from "../../crosslinks"; +import { clearAllLinks, getAllPortalsOnScreen } from "../../uiCommands"; +import wX from "../../wX"; + +import { displayError, displayWarning } from "../../error"; + +/** + * Split a set of portals inside a field into three sets with respect to a portal in the field + * @param {WasabeePortal} centerPoint Portal inside the field one/two/three + * @param {WasabeePortal[]} possibles Portals inside the field one/two/three + * @param {WasabeePortal} one + * @param {WasabeePortal} two + * @param {WasabeePortal} three + * @returns {[WasabeePortal[],WasabeePortal[],WasabeePortal[]]} Sets of portals inside one/two/centerPoint, two/three/centerPoint and three/one/centerPoint + */ +function getSubregions(centerPoint, possibles, one, two, three) { + const possibleExceptAnchors = new Array(); + for (const p of possibles) { + const guid = p.id || p.options.guid; + if ( + guid !== centerPoint.id && + guid !== one.id && + guid !== two.id && + guid !== three.id + ) + possibleExceptAnchors.push(p); + } + + const onePortals = new Array(); + const twoPortals = new Array(); + const threePortals = new Array(); + for (const p of possibleExceptAnchors) { + if ( + greatCircleArcIntersectByLatLngs( + p.latLng, + one.latLng, + centerPoint.latLng, + two.latLng + ) || + greatCircleArcIntersectByLatLngs( + p.latLng, + one.latLng, + centerPoint.latLng, + three.latLng + ) + ) + twoPortals.push(p); + else if ( + greatCircleArcIntersectByLatLngs( + p.latLng, + two.latLng, + centerPoint.latLng, + one.latLng + ) || + greatCircleArcIntersectByLatLngs( + p.latLng, + two.latLng, + centerPoint.latLng, + three.latLng + ) + ) + threePortals.push(p); + else onePortals.push(p); + } + + return [onePortals, twoPortals, threePortals]; +} + +/** + * Sort in place by distance to point + * @param {WasabeePortal[]} portals + * @param {import("leaflet").LatLng} point + */ +function sortByDistance(portals, point) { + // straight square distance is good enough in 3D + const cp = extendLatLngToLLC(point)._cartesian; + const cPs = new Map( + portals.map((p) => [ + p.id, + dist2(cp, extendLatLngToLLC(p.latLng)._cartesian), + ]) + ); + return portals.sort((a, b) => cPs.get(a.id) - cPs.get(b.id)); +} + +function numInnerPortalsPerDepth(depth) { + return (3 ** (depth - 1) - 1) / 2; +} + +/** + * Find one of the best (in terms of splits) HF configuration as a Tree decomposition + * @param {WasabeePortal[]} portalsCovered + * @param {WasabeePortal} one + * @param {WasabeePortal} two + * @param {WasabeePortal} three + * @param {number} depth + * @returns {import("./homogeneous").Tree} + */ +function fullRecurser(portalsCovered, one, two, three, depth) { + const alreadyCalculatedCover = new Map(); + + console.log( + "Expect at least", + Math.max(0, numInnerPortalsPerDepth(depth) - portalsCovered.length), + "missing splits" + ); + + /** + * Find one of the best (in terms of splits) HF configuration as a Tree decomposition + * @param {number} depth + * @param {WasabeePortal[]} portalsCovered + * @param {WasabeePortal} one + * @param {WasabeePortal} two + * @param {WasabeePortal} three + * @returns {import("./homogeneous").Tree} + */ + const homogeneousFrom = (depth, portalsCovered, one, two, three) => { + if (depth <= 1) + return { success: true, anchors: [one, two, three], split: 0 }; + + const key = [depth, one.id, two.id, three.id].sort().toString(); + if (alreadyCalculatedCover.get(key) === undefined) { + const maxNbSplit = Math.min( + numInnerPortalsPerDepth(depth), + portalsCovered.length + ); + /** @type {import("./homogeneous").Tree} */ + let bestResult = { + success: false, + anchors: [one, two, three], + split: 0, + portal: null, + children: null, + }; + sortByDistance(portalsCovered, fieldCenter(one, two, three)); + for (const wp of portalsCovered) { + const subregions = getSubregions( + wp, + new Array(...portalsCovered), + one, + two, + three + ); + const maxNbSplitSubregions = + Math.min(numInnerPortalsPerDepth(depth - 1), subregions[0].length) + + Math.min(numInnerPortalsPerDepth(depth - 1), subregions[1].length) + + Math.min(numInnerPortalsPerDepth(depth - 1), subregions[2].length); + if (maxNbSplitSubregions + 1 <= bestResult.split) { + // Skip the portal since it will induce less splits than the current best choice + continue; + } + + let ret1 = homogeneousFrom( + depth - 1, + new Array(...subregions[0]), + one, + two, + wp + ); + let ret2 = homogeneousFrom( + depth - 1, + new Array(...subregions[1]), + two, + three, + wp + ); + let ret3 = homogeneousFrom( + depth - 1, + new Array(...subregions[2]), + one, + three, + wp + ); + + const nbSplit = ret1.split + ret2.split + ret3.split + 1; + + if (nbSplit > bestResult.split) { + bestResult.success = ret1.success && ret2.success && ret3.success; + bestResult.split = nbSplit; + bestResult.portal = wp; + bestResult.children = [ret1, ret2, ret3]; + } + + if (nbSplit == maxNbSplit) { + // we cannot do more split so it is one of the best choice + break; + } + } + alreadyCalculatedCover.set(key, bestResult); + } + return alreadyCalculatedCover.get(key); + }; + return homogeneousFrom(depth, portalsCovered, one, two, three); +} + +/** + * Find a HF Tree decomposition with a greedy heuristic, may fail even if HF exists + * @param {WasabeePortal[]} portalsCovered + * @param {WasabeePortal} one + * @param {WasabeePortal} two + * @param {WasabeePortal} three + * @param {number} depth + * @returns {import("./homogeneous").Tree} + */ +function greedy(portalsCovered, one, two, three, depth) { + if (depth <= 1) + return { success: true, anchors: [one, two, three], split: 0 }; + + // empty tree + /** @type {import("./homogeneous").Tree} */ + let bestResult = { + success: false, + anchors: [one, two, three], + split: 0, + portal: null, + children: null, + }; + + if (!portalsCovered.length) { + return bestResult; + } + + // sort first by distance to center + sortByDistance(portalsCovered, fieldCenter(one, two, three)); + + // greedy heuristic: + // find the portal that divides the area into regions with the closest number of portals + // starts at the center-most and works outwards + let differential = portalsCovered.length; + let best = []; + let bestp = {}; + // for each of the portals in play + for (const wp of portalsCovered) { + const subregions = getSubregions( + wp, + new Array(...portalsCovered), + one, + two, + three + ); + // smallest difference in the number of portals between the greatest and least, 0 being ideal + const temp = + Math.max( + subregions[0].length, + subregions[1].length, + subregions[2].length + ) - + Math.min( + subregions[0].length, + subregions[1].length, + subregions[2].length + ); + if (temp < differential) { + best = subregions; + differential = temp; + bestp = wp; + } + // found one with equal number of portals in all 3, quit digging + if (differential == 0) break; + } + + bestResult.portal = bestp; + + bestResult.children = [ + greedy(new Array(...best[0]), one, two, bestp, depth - 1), + greedy(new Array(...best[1]), two, three, bestp, depth - 1), + greedy(new Array(...best[2]), one, three, bestp, depth - 1), + ]; + bestResult.success = + bestResult.children[0].success && + bestResult.children[1].success && + bestResult.children[2].success; + bestResult.split = + 1 + + bestResult.children[0].split + + bestResult.children[1].split + + bestResult.children[2].split; + return bestResult; +} + +const HomogeneousDialog = AutoDraw.extend({ + statics: { + TYPE: "HomogeneousDialog", + }, + + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + let p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; + if (p) this._anchorOne = new WasabeePortal(p); + p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY]; + if (p) this._anchorTwo = new WasabeePortal(p); + p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_THREE_KEY]; + if (p) this._anchorThree = new WasabeePortal(p); + this._failed = 0; + }, + + addHooks: function () { + AutoDraw.prototype.addHooks.call(this); + this._layerGroup = new L.LayerGroup(); + window.addLayerGroup("Wasabee H-G Debug", this._layerGroup, true); + this._displayDialog(); + this._updatePortalSet(); + }, + + _updatePortalSet: function () { + AutoDraw.prototype._updatePortalSet.call(this); + if (this._anchorOne && this._anchorTwo && this._anchorThree) { + this._portalSets.portals.portals = + this._portalSets.portals.portals.filter((p) => + portalInField(this._anchorOne, this._anchorTwo, this._anchorThree, p) + ); + + this._portalSets.portals.display.textContent = wX("PORTAL_COUNT", { + count: this._portalSets.portals.portals.length, + }); + } + }, + + removeHooks: function () { + window.removeLayerGroup(this._layerGroup); + AutoDraw.prototype.removeHooks.call(this); + }, + + _displayDialog: function () { + const container = L.DomUtil.create("div", "container"); + const description2 = L.DomUtil.create("div", "desc", container); + description2.textContent = wX("H-GEN_INST"); + + this._addSetPortal( + wX("ANCHOR_PORTAL"), + "_anchorOne", + container, + window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY, + this._updatePortalSet.bind(this) + ); + this._addSetPortal( + wX("ANCHOR_PORTAL2"), + "_anchorTwo", + container, + window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY, + this._updatePortalSet.bind(this) + ); + this._addSetPortal( + wX("ANCHOR_PORTAL3"), + "_anchorThree", + container, + window.plugin.wasabee.static.constants.ANCHOR_THREE_KEY, + this._updatePortalSet.bind(this) + ); + + this._addSelectSet(wX("AUTODRAW_PORTALS_SET"), "portals", container, "all"); + this.spanPortalNeeded = L.DomUtil.create("span", "", container); + + const depthLabel = L.DomUtil.create("label", null, container); + depthLabel.textContent = wX("MAX_SPLITS"); + this.depthMenu = L.DomUtil.create("input", null, container); + this.depthMenu.type = "number"; + this.depthMenu.min = 2; + this.depthMenu.value = 4; + + L.DomEvent.on(this.depthMenu, "change", () => { + this.spanPortalNeeded.textContent = wX( + "autodraw.homogeneous.portals_required", + { count: numInnerPortalsPerDepth(+this.depthMenu.value) } + ); + }); + + const orderLabel = L.DomUtil.create("label", null, container); + orderLabel.textContent = wX("autodraw.homogeneous.order"); + this.orderMenu = L.DomUtil.create("select", null, container); + for (const [text, value] of [ + [wX("FROM_DEPTH"), "core"], // need wX on first column + [wX("FROM_1-2"), "base12"], + [wX("FROM_1-3"), "base13"], + [wX("FROM_2-3"), "base23"], + ]) { + const orderOption = L.DomUtil.create("option", null, this.orderMenu); + orderOption.value = value; + orderOption.textContent = text; + } + + this._addCheckbox( + wX("HF_DEEP_SEARCH"), + "wasabee-homogeneous-deep", + "_fullSearch", + container, + true + ); + + const spanRedraw = L.DomUtil.create("div", null, container); + this._redrawButton = L.DomUtil.create("button", null, spanRedraw); + this._redrawButton.textContent = wX("HF_REDRAW_BUTTON"); + this._redrawButton.style.display = "none"; + L.DomEvent.on(this._redrawButton, "click", (ev) => { + L.DomEvent.stop(ev); + this._operation = getSelectedOperation(); + if (this._tree) this._draw.call(this); + }); + + // Go button + const drawButton = L.DomUtil.create("button", "drawb", container); + drawButton.textContent = wX("HF_DRAW_BUTTON"); + L.DomEvent.on(drawButton, "click", (ev) => { + L.DomEvent.stop(ev); + this._operation = getSelectedOperation(); + if (+this.depthMenu.value < 2) return; + if (this._fullSearch) this.hdeepfield(); + else this.hfield(); + }); + + const buttons = {}; + buttons[wX("CLOSE")] = () => { + this.closeDialog(); + }; + buttons[wX("CLEAR LINKS")] = () => { + this._layerGroup.clearLayers(); + clearAllLinks(getSelectedOperation()); + }; + + this.createDialog({ + title: wX("HG"), + html: container, + width: "auto", + dialogClass: "homogeneous", + buttons: buttons, + }); + }, + + hfield: function () { + this._failed = 0; + this._layerGroup.clearLayers(); + + if (!this._anchorOne || !this._anchorTwo || !this._anchorThree) { + displayError("please select three anchors"); + return; + } + + const portals = new Array(); + for (const p of getAllPortalsOnScreen(this._operation)) { + if (portalInField(this._anchorOne, this._anchorTwo, this._anchorThree, p)) + portals.push(p); + } + + console.time("HF greedy"); + const tree = greedy( + portals, + this._anchorOne, + this._anchorTwo, + this._anchorThree, + +this.depthMenu.value + ); + console.timeEnd("HF greedy"); + + this._tree = tree; + this._failed = numInnerPortalsPerDepth(+this.depthMenu.value) - tree.split; + + this._draw(); + + if (this._failed > 0) { + displayWarning( + wX("autodraw.homogeneous.missing_split", { count: this._failed }) + ); + } + }, + + hdeepfield: function () { + this._failed = 0; + this._layerGroup.clearLayers(); + + if (!this._anchorOne || !this._anchorTwo || !this._anchorThree) { + displayError("please select three anchors"); + return; + } + + const portals = new Array(); + for (const p of getAllPortalsOnScreen(this._operation)) { + if (portalInField(this._anchorOne, this._anchorTwo, this._anchorThree, p)) + portals.push(p); + } + + console.time("HF deep recurser"); + const tree = fullRecurser( + portals, + this._anchorOne, + this._anchorTwo, + this._anchorThree, + +this.depthMenu.value + ); + console.timeEnd("HF deep recurser"); + + this._tree = tree; + this._failed = + numInnerPortalsPerDepth(+this.depthMenu.value) / 2 - tree.split; + + this._draw(); + + if (this._failed > 0) { + displayWarning( + wX("autodraw.homogeneous.missing_split", { count: this._failed }) + ); + } + + this._failed = 0; + + if (!this._anchorOne || !this._anchorTwo || !this._anchorThree) { + displayError("please select three anchors"); + return; + } + }, + + _draw: function () { + this._colors = [ + "#f80c12", + "#ee1100", + "#ff3311", + "#ff4422", + "#ff6644", + "#ff9933", + "#feae2d", + "#ccbb33", + "#d0c310", + "#aacc22", + "#69d025", + "#22ccaa", + "#12bdb9", + "#11aabb", + "#4444dd", + "#3311bb", + "#3b0cbd", + "#442299", + ]; + + this._operation.startBatchMode(); + if (this.orderMenu.value == "base12") + this._drawTreeBase(this._tree, this._anchorOne, this._anchorTwo); + else if (this.orderMenu.value == "base13") + this._drawTreeBase(this._tree, this._anchorOne, this._anchorThree); + else if (this.orderMenu.value == "base23") + this._drawTreeBase(this._tree, this._anchorTwo, this._anchorThree); + else this._drawTreeCore(this._tree); + this._operation.endBatchMode(); + + // this._operation.cleanAnchorList(); + // now, remove the portals that are unused + this._operation.cleanPortalList(); + + this._redrawButton.style.display = ""; + }, + + _drawTreeCore: function (tree) { + const depthValue = +this.depthMenu.value - 1; + const [one, two, three] = tree.anchors; + const computeDepth = (depth, tree, map) => { + if (tree.portal) { + map.set(tree.portal.id, depth); + for (const child of tree.children) computeDepth(depth + 1, child, map); + } + }; + + const portalDepth = new Map([ + [one.id, 0], + [two.id, 0], + [three.id, 0], + ]); + computeDepth(1, tree, portalDepth); + + // the order follows this process (consider only op links) + // (0) if max depth is 1, goto (9) + // (1) start from maximal depth D portals + // (2) for each portals of depth D: + // (3) link to the _only_ portal deepless by 1 (D-1) + // (4) if the second deepless portal isn't an anchor + // (5) link to the second deepest portal + // (6) for each of the 1 deepless portals: + // (7) link to all the deeper portals by _increasing_ depth (D+1, D+2 etc) + // (8) if D > 1 then goto (2) with D = D-1 + // (9) for each anchor: + // (A) deploy it (or don't link it before this step) + // (B) link to previous anchors + // (C) link to all deeper portals by _increasing_ depth (1, 2 etc) + // NB: rules 4/5 were added to reduce the number of outbound links the center portal. Those links can be done earlier because they are not backlinks + const orderByDepth = (a, b) => { + let ad = portalDepth.get(a.id); + let bd = portalDepth.get(b.id); + + const baseOrder = ((depthValue - bd) * (depthValue - bd - 1)) / 2 + 1; + + if (bd != 0 || b.id == one.id) return baseOrder + ad - bd - 1; + + if (b.id == two.id) return baseOrder + depthValue + ad; + + return baseOrder + 2 * depthValue + ad + 1; + }; + + const draw = (depth, r) => { + if (r.portal) { + const [first, second, father] = r.anchors + .map((p) => [portalDepth.get(p.id), p]) + .sort() + .map((a) => a[1]); + const firstOrder = orderByDepth(r.portal, first); + const secondOrder = orderByDepth(r.portal, second); + const fatherOrder = orderByDepth(r.portal, father); + const data = [ + portalDepth.get(first.id) // not outer anchor + ? [first, r.portal, "intern", firstOrder] + : [first, r.portal, "anchor intern", firstOrder], + // not an intern link (no double field) + portalDepth.get(second.id) > 0 + ? [r.portal, second, "early", fatherOrder] + : [second, r.portal, "anchor intern", secondOrder], + portalDepth.get(father.id) == 0 + ? [father, r.portal, "anchor intern", fatherOrder] + : [r.portal, father, "to father", fatherOrder], + ]; + for (const [from, to, comment, order] of data) { + this._operation.addLink(from, to, { + description: comment, + order: order, + color: this._colors[order % this._colors.length], + replace: true, + }); + } + for (const child of r.children) draw(depth + 1, child); + } + }; + + const drawDebug = (depth, r) => { + if (r.portal) for (const child of r.children) drawDebug(depth - 1, child); + if (!r.portal && !r.success) { + // debug layer + const color = depth == 1 ? "orange" : "red"; + const latlngs = [ + r.anchors[0].latLng, + r.anchors[1].latLng, + r.anchors[2].latLng, + r.anchors[0].latLng, + ]; + const polygon = L.polygon(latlngs, { color: color }); + polygon.addTo(this._layerGroup); + } + }; + drawDebug(depthValue, tree); + + this._operation.addPortal(one); + this._operation.addPortal(two); + this._operation.addPortal(three); + this._operation.addLink(two, one, { + description: "Outer 1", + order: (depthValue * (depthValue - 1)) / 2 + depthValue + 1, + color: + this._colors[ + ((depthValue * (depthValue - 1)) / 2 + depthValue + 1) % + this._colors.length + ], + replace: true, + }); + this._operation.addLink(three, one, { + description: "Outer 2", + order: (depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2, + color: + this._colors[ + ((depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2) % + this._colors.length + ], + replace: true, + }); + this._operation.addLink(three, two, { + description: "Outer 3", + order: (depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2, + color: + this._colors[ + ((depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2) % + this._colors.length + ], + replace: true, + }); + draw(1, tree); + }, + + _drawTreeBase: function (tree, one, two) { + const depthValue = +this.depthMenu.value - 1; + + const drawFractal = (depth, r, pOne, pTwo, order) => { + if (r.portal) { + // draw inner HF on base 1-2 + const pThree = r.anchors.filter( + (p) => p.id !== pOne.id && p.id !== pTwo.id + )[0]; + for (const child of r.children) + if (child.anchors.every((p) => p.id !== pThree.id)) + order = draw(depth + 1, child, pOne, pTwo, order); + + let order1, order2; + // draw fractal on 1-p + for (const child of r.children) + if (child.anchors.every((p) => p.id !== pTwo.id)) + order1 = drawFractal(depth + 1, child, pOne, r.portal, order); + + // draw fractal on 2-p + for (const child of r.children) + if (child.anchors.every((p) => p.id !== pOne.id)) + order2 = drawFractal(depth + 1, child, pTwo, r.portal, order); + + // should be computed with a formula + order = Math.max(order1, order2); + } + return order; + }; + + // link an anchor to inner portals in depth order + const drawBackLink = (depth, r, anchor, order) => { + if (r.portal) { + this._operation.addLink(anchor, r.portal, { + description: "intern link", + order: order + 1, + color: this._colors[order % this._colors.length], + replace: true, + }); + for (const child of r.children) + if (child.anchors.includes(anchor)) + drawBackLink(depth + 1, child, anchor, order + 1); + } + return order + depthValue - depth + 1; + }; + + // draw a HF from base + const draw = (depth, r, pOne, pTwo, order = 1) => { + // draw fratal on 1-2 + order = drawFractal(depth, r, pOne, pTwo, order); + const pThree = r.anchors.filter( + (p) => p.id !== pOne.id && p.id !== pTwo.id + )[0]; + // draw outer link + for (const anchor of [pOne, pTwo]) { + this._operation.addLink(pThree, anchor, { + order: order + 1, + color: this._colors[order % this._colors.length], + replace: true, + }); + } + if (!r.portal) return order + 1; + // draw inner link from 3 + return drawBackLink(depth, r, pThree, order + 1); + }; + + const drawDebug = (depth, r) => { + if (r.portal) for (const child of r.children) drawDebug(depth - 1, child); + if (!r.portal && !r.success) { + // debug layer + const color = depth == 1 ? "orange" : "red"; + const latlngs = [ + r.anchors[0].latLng, + r.anchors[1].latLng, + r.anchors[2].latLng, + r.anchors[0].latLng, + ]; + const polygon = L.polygon(latlngs, { color: color }); + polygon.addTo(this._layerGroup); + } + }; + drawDebug(depthValue, tree); + + for (const p of tree.anchors) this._operation.addPortal(p); + this._operation.addLink(two, one, { + description: "Outer base", + order: 1, + color: this._colors[0], + replace: true, + }); + draw(1, tree, one, two); + }, + + _getCenter: function (a, b, c) { + const A = window.map.project(a.latLng || a._latlng); + const B = window.map.project(b.latLng || b._latlng); + const C = window.map.project(c.latLng || c._latlng); + + const point = L.point((A.x + B.x + C.x) / 3, (A.y + B.y + C.y) / 3); + return window.map.unproject(point); + }, +}); + +export default HomogeneousDialog; diff --git a/src/code/dialogs/autodraws/madrid.d.ts b/src/code/dialogs/autodraws/madrid.d.ts new file mode 100644 index 000000000..0b59c490a --- /dev/null +++ b/src/code/dialogs/autodraws/madrid.d.ts @@ -0,0 +1,6 @@ +import MultimaxDialog from "./multimaxDialog"; + +export default class MadridDialog extends MultimaxDialog { + _balancedcheck: boolean; + constructor(); +} diff --git a/src/code/dialogs/autodraws/madrid.js b/src/code/dialogs/autodraws/madrid.js new file mode 100644 index 000000000..f7997c6ee --- /dev/null +++ b/src/code/dialogs/autodraws/madrid.js @@ -0,0 +1,332 @@ +import { portalInField } from "../../crosslinks"; +import { displayError, displayInfo } from "../../error"; +import { getSelectedOperation } from "../../selectedOp"; +import { clearAllLinks } from "../../uiCommands"; +import wX from "../../wX"; +import { getSignedSpine } from "./algorithm"; +import { drawSpine, insertLinks } from "./drawRoutines"; +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; + +/** + * Return the spines in set 1, 2 and 3: + * - 1: starting from anchorOne, with anchorTwo and last portal of spine 3 as anchors + * - 2: starting from anchortwo, with last portals of spines 1/3 as anchors + * - 3: in set 3, with anchorOne and anchorTwo as anchors + * Spines are thrown in order 3-1-2 + * @param {WasabeePortal} anchorOne + * @param {WasabeePortal} anchorTwo + * @param {WasabeePortal[]} setOne + * @param {WasabeePortal[]} setTwo + * @param {WasabeePortal[]} setThree + * @returns {[WasabeePortal[], WasabeePortal[], WasabeePortal[]]} + */ +function getSpines(anchorOne, anchorTwo, setOne, setTwo, setThree) { + const [spineThree] = getSignedSpine(anchorOne, anchorTwo, setThree, false); + const lastThree = spineThree[spineThree.length - 1]; + + const [spineOne] = getSignedSpine( + anchorTwo, + lastThree, + setOne.filter( + (p) => + anchorOne.id == p.id || + portalInField(anchorTwo, lastThree, p, anchorOne) + ), + false + ); + const lastOne = spineOne[spineOne.length - 1]; + + const [spineTwo] = getSignedSpine( + lastThree, + lastOne, + setTwo.filter( + (p) => + anchorTwo.id == p.id || portalInField(lastThree, lastOne, p, anchorTwo) + ), + false + ); + + return [spineOne, spineTwo, spineThree]; +} + +const MadridDialog = AutoDraw.extend({ + statics: { + TYPE: "madridDialog", + }, + + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + let p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; + if (p) this._anchorOne = new WasabeePortal(p); + p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY]; + if (p) this._anchorTwo = new WasabeePortal(p); + }, + + addHooks: function () { + AutoDraw.prototype.addHooks.call(this); + + this._displayDialog(); + this._updatePortalSet(); + }, + + _buildContent: function () { + const container = L.DomUtil.create("div", "container"); + const description = L.DomUtil.create("div", "desc", container); + description.textContent = wX("SELECT_INSTRUCTIONS"); + + this._addSetPortal( + wX("ANCHOR1"), + "_anchorOne", + container, + window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY + ); + this._addSelectSet(wX("MADRID_SET_1"), "setOne", container, "all"); + + this._addSetPortal( + wX("ANCHOR2"), + "_anchorTwo", + container, + window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY + ); + this._addSelectSet(wX("MADRID_SET_2"), "setTwo", container, "all"); + + const anchorThreeLabel = L.DomUtil.create("label", null, container); + anchorThreeLabel.textContent = wX("ANCHOR3"); + const anchorThreeDisplay = L.DomUtil.create("span", null, container); + anchorThreeDisplay.textContent = wX("autodraw.madrid.auto_determined"); + this._addSelectSet(wX("MADRID_SET_3"), "setThree", container, "all"); + + this._addCheckbox( + wX("ADD_BL"), + "wasabee-madrid-backlink", + "_flcheck", + container + ); + this._addCheckbox( + wX("autodraw.madrid.balanced"), + "wasabee-madrid-balanced", + "_balancedcheck", + container + ); + + const newLine = L.DomUtil.create("label", "newline", container); + const dividerBeforeDraw = L.DomUtil.create("span", null, container); + newLine.textContent = "\u0000"; + dividerBeforeDraw.textContent = "\u0000"; + // dividerBeforeDraw.textContent = ""; + + const placeholder = L.DomUtil.create("label", "placeholder", container); + placeholder.textContent = "\u2063"; + // Go button + const button = L.DomUtil.create("button", "drawb", container); + button.textContent = wX("MADRID"); + L.DomEvent.on(button, "click", () => { + this._operation = getSelectedOperation(); + const total = this._balancedcheck + ? this.doBalancedMadrid.call(this) + : this.doMadrid.call(this); + displayInfo(wX("autodraw.madrid.result", { count: total })); + // this.closeDialog(); + }); + + return container; + }, + + // addHooks inherited from MultimaxDialog + _displayDialog: function () { + const container = this._buildContent(); + + const buttons = {}; + buttons[wX("CLOSE")] = () => { + this.closeDialog(); + }; + buttons[wX("CLEAR LINKS")] = () => { + clearAllLinks(getSelectedOperation()); + }; + + this.createDialog({ + title: wX("MADRID_TITLE"), + html: container, + width: "auto", + dialogClass: "madrid", + buttons: buttons, + id: window.plugin.wasabee.static.dialogNames.madrid, + }); + }, + + doBalancedMadrid: function () { + // Calculate the multimax + if ( + !this._anchorOne || + !this._anchorTwo || + !this._portalSets.setOne.portals.length || + !this._portalSets.setTwo.portals.length || + !this._portalSets.setThree.portals.length + ) { + displayError(wX("INVALID REQUEST")); + return 0; + } + + // the set 1 must contain anchor 1 (first back link) + if ( + this._portalSets.setOne.portals.find((p) => this._anchorOne.id == p.id) == + undefined + ) + this._portalSets.setOne.portals.push(this._anchorOne); + // the set 2 must contain anchor 2 (first back link) + if ( + this._portalSets.setTwo.portals.find((p) => this._anchorTwo.id == p.id) == + undefined + ) + this._portalSets.setTwo.portals.push(this._anchorTwo); + + const spines = getSpines( + this._anchorOne, + this._anchorTwo, + this._portalSets.setOne.portals, + this._portalSets.setTwo.portals, + this._portalSets.setThree.portals + ); + const step = spines.map((s) => 1 / s.length); + + this._operation.startBatchMode(); + + // ignore order + direction + this._operation.addLink(spines[0][0], spines[1][0], { + description: "inner field", + }); + this._operation.addLink(spines[1][0], spines[2][0], { + description: "inner field", + }); + this._operation.addLink(spines[2][0], spines[0][0], { + description: "inner field", + }); + + const indices = [1, 1, 1]; + + while (indices.some((v, i) => v < spines[i].length)) { + let spineOrder = [0, 1, 2].sort( + (a, b) => indices[a] * step[a] - indices[b] * step[b] + ); + let p = spines[spineOrder[0]][indices[spineOrder[0]]]; + let pOne = spines[spineOrder[0]][indices[spineOrder[0]] - 1]; + let pTwo = spines[spineOrder[1]][indices[spineOrder[1]] - 1]; + let pThree = spines[spineOrder[2]][indices[spineOrder[2]] - 1]; + + // hackish, I have no proof of this working in all cases + for ( + let i = 0; + (!p || !portalInField(p, pTwo, pThree, pOne)) && i < 3; + i++ + ) { + this._operation.setPortalComment(pOne, "point of disbalance"); + + spineOrder = [spineOrder[1], spineOrder[2], spineOrder[0]]; + p = spines[spineOrder[0]][indices[spineOrder[0]]]; + pOne = spines[spineOrder[0]][indices[spineOrder[0]] - 1]; + pTwo = spines[spineOrder[1]][indices[spineOrder[1]] - 1]; + pThree = spines[spineOrder[2]][indices[spineOrder[2]] - 1]; + } + if (!portalInField(p, pTwo, pThree, pOne)) + console.log("well, this doesn't work here..."); + const toTwo = this._operation.addLink(p, pTwo, { description: "link" }); + const toThree = this._operation.addLink(p, pThree, { + description: "link", + }); + toTwo.zone = spineOrder[0] + 1; + toThree.zone = spineOrder[0] + 1; + + indices[spineOrder[0]] += 1; + } + + this._operation.endBatchMode(); + + return indices[0] + indices[1] + indices[2] - 2; + }, + + doMadrid: function () { + // Calculate the multimax + if ( + !this._anchorOne || + !this._anchorTwo || + !this._portalSets.setOne.portals.length || + !this._portalSets.setTwo.portals.length || + !this._portalSets.setThree.portals.length + ) { + displayError(wX("INVALID REQUEST")); + return 0; + } + // the set 1 must contain anchor 1 (first back link) + if ( + this._portalSets.setOne.portals.find((p) => this._anchorOne.id == p.id) == + undefined + ) + this._portalSets.setOne.portals.push(this._anchorOne); + // the set 2 must contain anchor 2 (first back link) + if ( + this._portalSets.setTwo.portals.find((p) => this._anchorTwo.id == p.id) == + undefined + ) + this._portalSets.setTwo.portals.push(this._anchorTwo); + + const spines = getSpines( + this._anchorOne, + this._anchorTwo, + this._portalSets.setOne.portals, + this._portalSets.setTwo.portals, + this._portalSets.setThree.portals + ); + + this._operation.startBatchMode(); // bypass save and crosslinks checks + let order = insertLinks( + this._operation, + [ + this._operation.addLink(this._anchorOne, this._anchorTwo, { + description: "madrid base", + }), + ], + this._operation.nextOrder - 1 + ); + + order = drawSpine( + this._operation, + this._anchorOne, + this._anchorTwo, + spines[2], + order, + { + commentPrefix: "madrid ", + backlink: this._flcheck, + } + ); + order = drawSpine( + this._operation, + this._anchorTwo, + spines[2][spines[2].length - 1], + spines[0].slice(1), + order, + { + commentPrefix: "madrid ", + backlink: this._flcheck, + } + ); + /* order = */ drawSpine( + this._operation, + spines[2][spines[2].length - 1], + spines[0][spines[0].length - 1], + spines[1].slice(1), + order, + { + commentPrefix: "madrid ", + backlink: this._flcheck, + } + ); + + this._operation.endBatchMode(); // save and run crosslinks + + return spines[0].length + spines[1].length + spines[2].length - 2; + }, +}); + +export default MadridDialog; diff --git a/src/code/dialogs/autodraws/multimaxDialog.d.ts b/src/code/dialogs/autodraws/multimaxDialog.d.ts new file mode 100644 index 000000000..7675adbfe --- /dev/null +++ b/src/code/dialogs/autodraws/multimaxDialog.d.ts @@ -0,0 +1,12 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; + +export default class MultimaxDialog extends AutoDraw { + _anchorOne: WasabeePortal; + _anchorTwo: WasabeePortal; + _flcheck: boolean; + _orderFromEnd: boolean; + _bothSide: boolean; + + constructor(); +} diff --git a/src/code/dialogs/autodraws/multimaxDialog.js b/src/code/dialogs/autodraws/multimaxDialog.js new file mode 100644 index 000000000..ade0151ba --- /dev/null +++ b/src/code/dialogs/autodraws/multimaxDialog.js @@ -0,0 +1,188 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; +import { getSelectedOperation } from "../../selectedOp"; +import wX from "../../wX"; +import { clearAllLinks } from "../../uiCommands"; +import { displayError, displayInfo } from "../../error"; +import { getSignedSpine } from "./algorithm"; +import { drawSpine, insertLinks } from "./drawRoutines"; + +// now that the formerly external mm functions are in the class, some of the logic can be cleaned up +// to not require passing values around when we can get them from this.XXX +const MultimaxDialog = AutoDraw.extend({ + statics: { + TYPE: "multimaxDialog", + }, + + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + let p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; + if (p) this._anchorOne = new WasabeePortal(p); + p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY]; + if (p) this._anchorTwo = new WasabeePortal(p); + }, + + addHooks: function () { + AutoDraw.prototype.addHooks.call(this); + + this._displayDialog(); + this._updatePortalSet(); + }, + + _buildContent: function () { + const container = L.DomUtil.create("div", "container"); + const description = L.DomUtil.create("div", "desc", container); + description.textContent = wX("SELECT_INSTRUCTIONS"); + + const description2 = L.DomUtil.create("div", "desc", container); + description2.textContent = wX("SEL_SB_ANCHOR2"); + + this._addSetPortal( + wX("ANCHOR1"), + "_anchorOne", + container, + window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY + ); + this._addSetPortal( + wX("ANCHOR2"), + "_anchorTwo", + container, + window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY + ); + + this._addCheckbox( + wX("ADD_BL"), + "wasabee-multimax-backlink", + "_flcheck", + container + ); + + this._addCheckbox( + wX("MM_INSERT_ORDER"), + "wasabee-multimax-insert-order", + "_orderFromEnd", + container, + true + ); + + this._addCheckbox( + wX("MM_BOTH_SIDE"), + "wasabee-multimax-both-side", + "_bothSide", + container, + false + ); + + this._addSelectSet(wX("MM_SPINE"), "spine", container, "all"); + + // Go button + const button = L.DomUtil.create("button", "drawb", container); + button.textContent = wX("MULTI_M"); + L.DomEvent.on(button, "click", () => { + const total = this.doMultimax.call(this); + if (total.length === 2) { + displayInfo( + wX("autodraw.multimax.result_both_side", { + count1: total[0], + count2: total[1], + }) + ); + } else { + displayInfo( + wX("autodraw.multimax.result", { + count: total[0], + }) + ); + } + // this.closeDialog(); + }); + + return container; + }, + + _displayDialog: function () { + const container = this._buildContent(); + + const buttons = {}; + buttons[wX("CLOSE")] = () => { + this.closeDialog(); + }; + buttons[wX("CLEAR LINKS")] = () => { + clearAllLinks(getSelectedOperation()); + }; + + this.createDialog({ + title: wX("MULTI_M_TITLE"), + html: container, + width: "auto", + dialogClass: "multimax", + buttons: buttons, + id: window.plugin.wasabee.static.dialogNames.multimaxButton, + }); + }, + + /* + Calculate, given two anchors and a set of portals, the deepest sequence of nested fields. + */ + MM: function ( + pOne, + pTwo, + portals, + order = 0, // first link is order + 1 + base = true, + commentPrefix = "multimax ", + bothSide = false + ) { + const spines = getSignedSpine(pOne, pTwo, portals, bothSide); + + if (base) { + order = insertLinks( + this._operation, + [ + this._operation.addLink(pOne, pTwo, { + description: commentPrefix + "base", + }), + ], + order + ); + } + + for (const s of spines) { + order = drawSpine(this._operation, pOne, pTwo, s, order, { + commentPrefix: "multimax ", + backlink: this._flcheck, + }); + } + return spines.map((s) => s.length); + }, + + doMultimax: function () { + const portals = this._portalSets.spine.portals; + + // Calculate the multimax + if (!this._anchorOne || !this._anchorTwo || !portals.length) { + displayError(wX("INVALID REQUEST")); + return 0; + } + + this._operation.startBatchMode(); + + console.log("starting multimax"); + const lengths = this.MM( + this._anchorOne, + this._anchorTwo, + portals, + this._orderFromEnd ? this._operation.nextOrder - 1 : 0, + true, + "multimax ", + this._bothSide + ); + console.log("multimax done"); + + this._operation.endBatchMode(); // save and run crosslinks + + return lengths; + }, +}); + +export default MultimaxDialog; diff --git a/src/code/dialogs/autodraws/onionfield.d.ts b/src/code/dialogs/autodraws/onionfield.d.ts new file mode 100644 index 000000000..22aeefdb8 --- /dev/null +++ b/src/code/dialogs/autodraws/onionfield.d.ts @@ -0,0 +1,10 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; + +export default class OnionfieldDialog extends AutoDraw { + _anchor: WasabeePortal; + _colors: string[]; + _colorIterator: number; + _color: string; + constructor(); +} diff --git a/src/code/dialogs/autodraws/onionfield.js b/src/code/dialogs/autodraws/onionfield.js new file mode 100644 index 000000000..8860e4112 --- /dev/null +++ b/src/code/dialogs/autodraws/onionfield.js @@ -0,0 +1,235 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; +import { getSelectedOperation } from "../../selectedOp"; +import { portalInField } from "../../crosslinks"; +import { clearAllLinks, getAllPortalsOnScreen } from "../../uiCommands"; +import wX from "../../wX"; +import { displayError } from "../../error"; + +/** + * Sort trangle vertices by widest angle + * @param {WasabeePortal} one + * @param {WasabeePortal} two + * @param {WasabeePortal} three + * @returns {[WasabeePortal, WasabeePortal, WasabeePortal]} + */ +function sortAnchors(one, two, three) { + const a = [ + [one, euclideanAngle(one, two, three)], + [two, euclideanAngle(two, three, one)], + [three, euclideanAngle(three, one, two)], + ]; + return a.sort((a, b) => b[1] - a[1]).map((a) => a[0]); +} + +/** + * Returns the angle a p.id !== anchor.id); + if (portals.length < 2) return []; + + const m = new Map(); + for (const p of portals) { + const pDist = window.map.distance(anchor.latLng, p.latLng); + m.set(pDist, p); + } + const sorted = [...m.entries()].sort((a, b) => a[0] - b[0]).map((a) => a[1]); + + let [one, two, three] = sortAnchors(anchor, sorted[0], sorted[1]); + const path = [ + { + from: two, + to: one, + }, + { + from: three, + to: one, + }, + { + from: three, + to: two, + }, + ]; + + portals = portals.filter((p) => p.id !== two.id && p.id !== three.id); + + const round = type === "grow" ? 3 : 1; + + let running = round; + while (running > 0 && portals.length > 0) { + running = running - 1; + + // sorted remaining by distance to one + const m = new Map(); + for (const p of portals) { + const pDist = window.map.distance(one.latLng, p.latLng); + m.set(pDist, p); + } + const sorted = [...m.entries()] + .sort((a, b) => a[0] - b[0]) + .map((a) => a[1]); + + // for each of the portals in play + const wp = sorted.find((p) => portalInField(p, two, three, one)); + if (wp) { + running = round; + portals = portals.filter((p) => p.id !== wp.id); + + path.push({ from: wp, to: two }); + path.push({ from: wp, to: three }); + path.push({ from: wp, to: one }); + + if (type === "balanced") { + [one, two, three] = [two, three, wp]; + } else { + // determine the widest angle, wp<23, use that to determine next covered portal + [one, two, three] = sortAnchors(two, three, wp); + } + } + if (running < round) { + if (type == "grow") { + // drop the widest angle constraint, take the next one + [one, two, three] = [two, three, one]; + } + } + } + // console.log("hit bottom", thisPath.length); + return path; +} + +const OnionfieldDialog = AutoDraw.extend({ + statics: { + TYPE: "OnionDialog", + }, + + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + const p = + localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; + if (p) this._anchor = new WasabeePortal(p); + }, + + addHooks: function () { + AutoDraw.prototype.addHooks.call(this); + this._displayDialog(); + }, + + _displayDialog: function () { + const container = L.DomUtil.create("div", "container"); + const description = L.DomUtil.create("div", "desc", container); + description.textContent = wX("SELECT_ONION_PORTALS"); + const description3 = L.DomUtil.create("div", "desc", container); + description3.textContent = wX("SEL_SB_ANCHOR2"); + + this._addSetPortal( + wX("ANCHOR_PORTAL"), + "_anchor", + container, + window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY + ); + + const optionLabel = L.DomUtil.create("label", null, container); + optionLabel.textContent = wX("autodraw.onion.variant"); + this.optionMenu = L.DomUtil.create("select", null, container); + for (const [text, value] of [ + [wX("autodraw.onion.variant.equilateral"), "equi"], + [wX("autodraw.onion.variant.grow"), "grow"], + [wX("autodraw.onion.variant.balanced"), "balanced"], + ]) { + const option = L.DomUtil.create("option", null, this.optionMenu); + option.value = value; + option.textContent = text; + } + + // Go button + const button = L.DomUtil.create("button", "drawb", container); + button.textContent = wX("ONION"); + L.DomEvent.on(button, "click", (ev) => { + L.DomEvent.stop(ev); + this.onion.call(this); + }); + const buttons = {}; + buttons[wX("CLOSE")] = () => { + this.closeDialog(); + }; + buttons[wX("CLEAR LINKS")] = () => { + clearAllLinks(getSelectedOperation()); + }; + + this.createDialog({ + title: wX("ONION_WAS_TAKEN"), + html: container, + width: "auto", + dialogClass: "onion", + buttons: buttons, + }); + }, + + onion: function () { + // this._operation is OK here + this._operation = getSelectedOperation(); + if (!this._anchor) { + displayError("no anchor selected"); + return; + } + const colors = [ + "#f80c12", + "#ee1100", + "#ff3311", + "#ff4422", + "#ff6644", + "#ff9933", + "#feae2d", + "#ccbb33", + "#d0c310", + "#aacc22", + "#69d025", + "#22ccaa", + "#12bdb9", + "#11aabb", + "#4444dd", + "#3311bb", + "#3b0cbd", + "#442299", + ]; + const allPortals = getAllPortalsOnScreen(this._operation); + + const links = onion(this._anchor, allPortals, this.optionMenu.value); + + this._operation.startBatchMode(); + links.forEach((l, i) => + this._operation.addLink(l.from, l.to, { + order: i + 1, + color: colors[i % colors.length], + }) + ); + this._operation.endBatchMode(); + }, +}); + +export default OnionfieldDialog; diff --git a/src/code/dialogs/autodraws/saveLinks.d.ts b/src/code/dialogs/autodraws/saveLinks.d.ts new file mode 100644 index 000000000..edc63c92e --- /dev/null +++ b/src/code/dialogs/autodraws/saveLinks.d.ts @@ -0,0 +1,7 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; + +export default class SaveLinksDialog extends AutoDraw { + _anchor: WasabeePortal; + constructor(); +} diff --git a/src/code/dialogs/saveLinks.js b/src/code/dialogs/autodraws/saveLinks.js similarity index 54% rename from src/code/dialogs/saveLinks.js rename to src/code/dialogs/autodraws/saveLinks.js index 26af69fb1..c1d9a0455 100644 --- a/src/code/dialogs/saveLinks.js +++ b/src/code/dialogs/autodraws/saveLinks.js @@ -1,18 +1,24 @@ -import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import { getSelectedOperation } from "../selectedOp"; -import { clearAllLinks, getAllPortalsLinked } from "../uiCommands"; -import wX from "../wX"; - -const SaveLinksDialog = WDialog.extend({ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; +import { getSelectedOperation } from "../../selectedOp"; +import { clearAllLinks, getAllPortalsLinked } from "../../uiCommands"; +import wX from "../../wX"; +import { displayError } from "../../error"; + +const SaveLinksDialog = AutoDraw.extend({ statics: { TYPE: "SaveLinksDialog", }, - needWritePermission: true, + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + const p = + localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; + if (p) this._anchor = new WasabeePortal(p); + }, addHooks: function () { - WDialog.prototype.addHooks.call(this); + AutoDraw.prototype.addHooks.call(this); this._displayDialog(); }, @@ -22,38 +28,12 @@ const SaveLinksDialog = WDialog.extend({ const description = L.DomUtil.create("div", "desc", container); description.textContent = wX("SEL_SL_ANCHOR"); - //anchor portal text - const anchorLabel = L.DomUtil.create("label", null, container); - anchorLabel.textContent = wX("ANCHOR_PORTAL"); - - //Set Button - const anchorButton = L.DomUtil.create("button", null, container); - anchorButton.textContent = wX("SET"); - this._anchorDisplay = L.DomUtil.create("div", "anchor", container); - - //do magic - if (this._anchor) { - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - this._anchorDisplay.textContent = wX("NOT_SET"); - } - - L.DomEvent.on(anchorButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._anchor = WasabeePortal.getSelected(); - if (this._anchor) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY] = - JSON.stringify(this._anchor); - this._anchorDisplay.textContent = ""; - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); + this._addSetPortal( + wX("ANCHOR_PORTAL"), + "_anchor", + container, + window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY + ); const button = L.DomUtil.create("button", "drawb", container); button.textContent = wX("SAVELINKS_DRAW"); @@ -80,16 +60,9 @@ const SaveLinksDialog = WDialog.extend({ }); }, - initialize: function (options) { - WDialog.prototype.initialize.call(this, options); - const p = - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; - if (p) this._anchor = new WasabeePortal(p); - }, - saveLinks: function () { if (!this._anchor) { - alert("Select an anchor portal"); + displayError("Select an anchor portal"); return; } diff --git a/src/code/dialogs/autodraws/starburst.d.ts b/src/code/dialogs/autodraws/starburst.d.ts new file mode 100644 index 000000000..e8db36576 --- /dev/null +++ b/src/code/dialogs/autodraws/starburst.d.ts @@ -0,0 +1,7 @@ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; + +export default class StarburstDialog extends AutoDraw { + _anchor: WasabeePortal; + constructor(); +} diff --git a/src/code/dialogs/starburst.js b/src/code/dialogs/autodraws/starburst.js similarity index 50% rename from src/code/dialogs/starburst.js rename to src/code/dialogs/autodraws/starburst.js index bd6e148de..29033fe80 100644 --- a/src/code/dialogs/starburst.js +++ b/src/code/dialogs/autodraws/starburst.js @@ -1,18 +1,24 @@ -import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import { getSelectedOperation } from "../selectedOp"; -import { clearAllLinks, getAllPortalsOnScreen } from "../uiCommands"; -import wX from "../wX"; - -const StarburstDialog = WDialog.extend({ +import { AutoDraw } from "./tools"; +import WasabeePortal from "../../model/portal"; +import { getSelectedOperation } from "../../selectedOp"; +import { clearAllLinks, getAllPortalsOnScreen } from "../../uiCommands"; +import wX from "../../wX"; +import { displayError } from "../../error"; + +const StarburstDialog = AutoDraw.extend({ statics: { TYPE: "StarburstDialog", }, - needWritePermission: true, + initialize: function (options) { + AutoDraw.prototype.initialize.call(this, options); + const p = + localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; + if (p) this._anchor = new WasabeePortal(p); + }, addHooks: function () { - WDialog.prototype.addHooks.call(this); + AutoDraw.prototype.addHooks.call(this); this._displayDialog(); }, @@ -22,40 +28,14 @@ const StarburstDialog = WDialog.extend({ const description = L.DomUtil.create("div", "desc", container); description.textContent = wX("SEL_SB_ANCHOR"); - //anchor portal text - const anchorLabel = L.DomUtil.create("label", null, container); - anchorLabel.textContent = wX("ANCHOR_PORTAL"); - - //Set Button - const anchorButton = L.DomUtil.create("button", null, container); - anchorButton.textContent = wX("SET"); - this._anchorDisplay = L.DomUtil.create("div", "anchor", container); - - //do magic - if (this._anchor) { - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - this._anchorDisplay.textContent = wX("NOT_SET"); - } - - L.DomEvent.on(anchorButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._anchor = WasabeePortal.getSelected(); - if (this._anchor) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY] = - JSON.stringify(this._anchor); - this._anchorDisplay.textContent = ""; - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); + this._addSetPortal( + wX("ANCHOR_PORTAL"), + "_anchor", + container, + window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY + ); - const description2 = L.DomUtil.create("div", "desc2", container); + const description2 = L.DomUtil.create("div", "desc secondary", container); description2.textContent = wX("SEL_SB_ANCHOR2"); const button = L.DomUtil.create("button", "drawb", container); @@ -83,16 +63,9 @@ const StarburstDialog = WDialog.extend({ }); }, - initialize: function (options) { - WDialog.prototype.initialize.call(this, options); - const p = - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; - if (p) this._anchor = new WasabeePortal(p); - }, - starburst: function () { if (!this._anchor) { - alert("Select an anchor portal"); + displayError("Select an anchor portal"); return; } diff --git a/src/code/dialogs/autodraws/tools.d.ts b/src/code/dialogs/autodraws/tools.d.ts new file mode 100644 index 000000000..31be0a3d4 --- /dev/null +++ b/src/code/dialogs/autodraws/tools.d.ts @@ -0,0 +1,44 @@ +import { WDialog, WDialogOptions } from "../../leafletClasses"; +import WasabeeOp from "../../model/operation"; +import WasabeePortal from "../../model/portal"; + +export class AutoDraw extends WDialog { + needWritePermission: true; + _operation: WasabeeOp; + _portalSets: { + [name: string]: { + zone: ZoneID; + keys: boolean; + portals: WasabeePortal[]; + display: HTMLSpanElement; + }; + }; + _mapRefreshHook: () => void; + + constructor(options?: WDialogOptions); + initialize(options?: WDialogOptions): void; + + _opChange(): void; + _initPortalSet(setKey: string, zone: ZoneID, keys: boolean): void; + _updatePortalSet(): void; + _addSetPortal( + text: string, + thisKey: string, + container: HTMLDivElement, + storageKey: string, + callback?: () => void + ): void; + _addCheckbox( + text: string, + id: string, + thisKey: string, + container: HTMLDivElement, + defaultValue: boolean + ): void; + _addSelectSet( + text: string, + setKey: string, + container: HTMLDivElement, + defaultValue: string + ): void; +} diff --git a/src/code/dialogs/autodraws/tools.js b/src/code/dialogs/autodraws/tools.js new file mode 100644 index 000000000..d859d2dc9 --- /dev/null +++ b/src/code/dialogs/autodraws/tools.js @@ -0,0 +1,184 @@ +import { WDialog } from "../../leafletClasses"; +import WasabeeMarker from "../../model/marker"; +import { getSelectedOperation } from "../../selectedOp"; +import wX from "../../wX"; +import { getAllPortalsOnScreen } from "../../uiCommands"; + +import PortalUI from "../../ui/portal"; +import { displayError } from "../../error"; + +// now that the formerly external mm functions are in the class, some of the logic can be cleaned up +// to not require passing values around when we can get them from this.XXX +export const AutoDraw = WDialog.extend({ + statics: { + TYPE: "autodraw", + }, + + needWritePermission: true, + + initialize: function (options) { + WDialog.prototype.initialize.call(this, options); + this._portalSets = {}; + }, + + addHooks: function () { + WDialog.prototype.addHooks.call(this); + window.map.on("wasabee:op:select wasabee:op:change", this._opChange, this); + + this._mapRefreshHook = this._updatePortalSet.bind(this); + window.addHook("mapDataRefreshEnd", this._mapRefreshHook); + + this._operation = getSelectedOperation(); + }, + + removeHooks: function () { + WDialog.prototype.removeHooks.call(this); + window.map.off("wasabee:op:select wasabee:op:change", this._opChange, this); + + window.removeHook("mapDataRefreshEnd", this._mapRefreshHook); + }, + + _opChange: function () { + this._operation = getSelectedOperation(); + this._updatePortalSet(); + }, + + _initPortalSet: function (setKey, zone, keys) { + const portalSet = this._portalSets[setKey]; + portalSet.zone = zone; + portalSet.keys = keys; + portalSet.portals = []; + }, + + _updatePortalSet: function () { + for (const setKey in this._portalSets) { + const portalSet = this._portalSets[setKey]; + if (portalSet.keys) { + const keys = this._operation.markers.filter( + (m) => m.type === WasabeeMarker.constants.MARKER_TYPE_KEY + ); + portalSet.portals = keys.map((m) => + this._operation.getPortal(m.portalId) + ); + + if (portalSet.zone) { + const zone = this._operation.getZone(portalSet.zone); + if (zone) { + //failsafe + portalSet.portals = portalSet.portals.filter((p) => + zone.contains(p.latLng) + ); + } + } + } else { + const portals = getAllPortalsOnScreen(this._operation); + if (portalSet.zone == 0) portalSet.portals = portals; + else { + const ids = new Set(portalSet.portals.map((p) => p.id)); + for (const p of portals) { + if (!ids.has(p.id)) portalSet.portals.push(p); + } + const zone = this._operation.getZone(portalSet.zone); + if (zone) { + // filter all, if zone shape changed + portalSet.portals = portalSet.portals.filter((p) => + zone.contains(p.latLng) + ); + } + } + } + portalSet.display.textContent = wX("PORTAL_COUNT", { + count: portalSet.portals.length, + }); + } + }, + + _addSetPortal: function (text, thisKey, container, storageKey, callback) { + const label = L.DomUtil.create("label", "set-portal-label", container); + label.textContent = text; + const button = L.DomUtil.create("button", "set-portal-button", container); + button.textContent = wX("SET"); + const display = L.DomUtil.create("span", "set-portal-display", container); + if (this[thisKey]) { + display.appendChild(PortalUI.displayFormat(this[thisKey])); + } else { + display.textContent = wX("NOT_SET"); + } + L.DomEvent.on(button, "click", () => { + this[thisKey] = PortalUI.getSelected(); + if (this[thisKey]) { + if (storageKey) + localStorage[storageKey] = JSON.stringify(this[thisKey]); + display.textContent = ""; + display.appendChild(PortalUI.displayFormat(this[thisKey])); + } else { + display.textContent = wX("NOT_SET"); + displayError(wX("PLEASE_SELECT_PORTAL")); + } + if (callback) callback(); + }); + }, + + _addCheckbox: function (text, id, thisKey, container, defaultValue) { + const label = L.DomUtil.create("label", "checkbox-label", container); + label.textContent = text; + label.htmlFor = id; + const checkbox = L.DomUtil.create("input", "checkbox-input", container); + checkbox.type = "checkbox"; + checkbox.id = id; + checkbox.checked = defaultValue; + this[thisKey] = defaultValue; + L.DomEvent.on(checkbox, "change", () => { + this[thisKey] = checkbox.checked; + }); + }, + + _addSelectSet: function (text, setKey, container, defaultValue) { + const label = L.DomUtil.create("label", "select-set-label", container); + label.textContent = text; + const select = L.DomUtil.create("select", "select-set-input", container); + const display = L.DomUtil.create("span", "select-set-display", container); + display.textContent = wX("NOT_SET"); + { + const o = L.DomUtil.create("option", null, select); + o.textContent = wX("MM_SET_ALL_PORTALS"); + o.value = "all"; + o.selected = defaultValue == o.value; + } + { + const o = L.DomUtil.create("option", null, select); + o.textContent = wX("MM_SET_ALL_KEYS"); + o.value = "keys"; + o.selected = defaultValue == o.value; + } + for (const zone of this._operation.zones) { + const o = L.DomUtil.create("option", null, select); + o.textContent = zone.name; + o.value = zone.id; + o.selected = defaultValue == o.value; + } + for (const zone of this._operation.zones) { + const o = L.DomUtil.create("option", null, select); + o.textContent = wX("MM_SET_KEYS_ZONE", { zoneName: zone.name }); + o.value = "keys" + zone.id; + o.selected = defaultValue == o.value; + } + L.DomEvent.on(select, "change", (ev) => { + L.DomEvent.stop(ev); + const keys = select.value.slice(0, 4) === "keys"; + const zone = + select.value === "all" || select.value === "keys" + ? 0 + : +(keys ? select.value.slice(4) : select.value); + this._initPortalSet(setKey, zone, keys); + this._updatePortalSet(); + }); + + this._portalSets[setKey] = { + portals: [], + zone: 0, + keys: false, + display: display, + }; + }, +}); diff --git a/src/code/dialogs/blockersList.d.ts b/src/code/dialogs/blockersList.d.ts new file mode 100644 index 000000000..b766b0455 --- /dev/null +++ b/src/code/dialogs/blockersList.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class BlockerList extends WDialog {} +export default BlockerList; diff --git a/src/code/dialogs/blockersList.js b/src/code/dialogs/blockersList.js index 2bc5e841b..3fc03cc70 100644 --- a/src/code/dialogs/blockersList.js +++ b/src/code/dialogs/blockersList.js @@ -4,11 +4,14 @@ import { getSelectedOperation } from "../selectedOp"; import { listenForAddedPortals, listenForPortalDetails, - loadFaked, + loadBlockerFaked, blockerAutomark, } from "../uiCommands"; import wX from "../wX"; import TrawlDialog from "./trawl"; +import WasabeeBlocker from "../model/blocker"; + +import PortalUI from "../ui/portal"; const BlockerList = WDialog.extend({ statics: { @@ -22,6 +25,7 @@ const BlockerList = WDialog.extend({ addHooks: function () { WDialog.prototype.addHooks.call(this); window.map.on("wasabee:op:select wasabee:op:change", this.update, this); + window.map.on("wasabee:crosslinks:update", this.update, this); window.map.on("wasabee:crosslinks:done", this.update, this); window.addHook("portalAdded", listenForAddedPortals); @@ -32,45 +36,52 @@ const BlockerList = WDialog.extend({ removeHooks: function () { WDialog.prototype.removeHooks.call(this); window.map.off("wasabee:op:select wasabee:op:change", this.update, this); + window.map.off("wasabee:crosslinks:update", this.update, this); window.map.off("wasabee:crosslinks:done", this.update, this); window.removeHook("portalAdded", listenForAddedPortals); window.removeHook("portalDetailLoaded", listenForPortalDetails); }, - _displayDialog: function () { + _displayDialog: async function () { const operation = getSelectedOperation(); - this.sortable = this._getListDialogContent(0, false); // defaults to sorting by op order - loadFaked(operation); + this.sortable = await this._getListDialogContent(0, false); // defaults to sorting by op order + loadBlockerFaked(operation); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; - buttons[wX("AUTOMARK")] = () => { - const operation = getSelectedOperation(); - blockerAutomark(operation); - }; - buttons[wX("RESET")] = () => { + // doesn't support op select event + if (operation.canWrite()) { + buttons[wX("AUTOMARK")] = () => { + const operation = getSelectedOperation(); + blockerAutomark(operation); + }; + } + buttons[wX("RESET")] = async () => { const operation = getSelectedOperation(); - operation.blockers = new Array(); + await WasabeeBlocker.removeBlockers(operation.ID); this.update(); - operation.update(false); // blockers do not need to be sent to server window.map.fire("wasabee:crosslinks"); }; buttons[wX("LOAD PORTALS")] = () => { const operation = getSelectedOperation(); - loadFaked(operation, true); // force + loadBlockerFaked(operation, true); // force }; buttons[wX("TRAWL TITLE")] = () => { const td = new TrawlDialog(); td.enable(); }; - buttons["Clear Automark"] = () => { - const operation = getSelectedOperation(); - for (const m of operation.markers) { - if (m.comment == "auto-marked") operation.removeMarker(m); - } - }; + if (operation.canWrite()) { + buttons[wX("dialog.blockers.clear_automark")] = () => { + const operation = getSelectedOperation(); + operation.startBatchMode(); + for (const m of operation.markers) { + if (m.comment == "auto-marked") operation.removeMarker(m); + } + operation.endBatchMode(); + }; + } this.createDialog({ title: wX("KNOWN_BLOCK", { opName: operation.name }), @@ -83,10 +94,11 @@ const BlockerList = WDialog.extend({ }, // when op changed or crosslink ended - update: function () { - const operation = getSelectedOperation(); + update: async function () { if (!this._enabled) return; - this.sortable = this._getListDialogContent( + if (!this.sortable) return; + const operation = getSelectedOperation(); + this.sortable = await this._getListDialogContent( this.sortable.sortBy, this.sortable.sortAsc ); @@ -95,28 +107,29 @@ const BlockerList = WDialog.extend({ }, // because the sortable values depend on the operation, we can't have it created at addHooks unless we want a lot of getSelectedOperations embedded here - _getListDialogContent(sortBy, sortAsc) { + async _getListDialogContent(sortBy, sortAsc) { const operation = getSelectedOperation(); const content = new Sortable(); + + const blockers = await WasabeeBlocker.getAll(operation); + content.fields = [ { name: wX("FROM_PORT"), - value: (blocker) => { - return operation.getPortal(blocker.fromPortalId).name; - }, + value: (blocker) => + blocker.fromPortal ? blocker.fromPortal.name : blocker.from, sort: (a, b) => a.localeCompare(b), format: (row, value, blocker) => { - const p = operation.getPortal(blocker.fromPortalId); - row.appendChild(p.displayFormat()); + if (blocker.fromPortal) + row.appendChild(PortalUI.displayFormat(blocker.fromPortal)); + else row.textContent = value; }, }, { name: this._smallScreen ? "#" : wX("COUNT"), value: (blocker) => { - const c = operation.blockers.filter( - (b) => - b.fromPortalId == blocker.fromPortalId || - b.toPortalID == blocker.fromPortalId + const c = blockers.filter( + (b) => b.from == blocker.from || b.to == blocker.from ); return c.length; }, @@ -124,22 +137,20 @@ const BlockerList = WDialog.extend({ }, { name: wX("TO_PORT"), - value: (blocker) => { - return operation.getPortal(blocker.toPortalId).name; - }, + value: (blocker) => + blocker.toPortal ? blocker.toPortal.name : blocker.to, sort: (a, b) => a.localeCompare(b), format: (row, value, blocker) => { - const p = operation.getPortal(blocker.toPortalId); - row.appendChild(p.displayFormat()); + if (blocker.toPortal) + row.appendChild(PortalUI.displayFormat(blocker.toPortal)); + else row.textContent = value; }, }, { name: this._smallScreen ? "#" : wX("COUNT"), value: (blocker) => { - const c = operation.blockers.filter( - (b) => - b.fromPortalId == blocker.toPortalId || - b.toPortalId == blocker.toPortalId + const c = blockers.filter( + (b) => b.from == blocker.to || b.to == blocker.to ); return c.length; }, @@ -148,7 +159,7 @@ const BlockerList = WDialog.extend({ ]; content.sortBy = sortBy; content.sortAsc = sortAsc; - content.items = operation.blockers; + content.items = blockers; return content; }, }); diff --git a/src/code/dialogs/checklist.d.ts b/src/code/dialogs/checklist.d.ts new file mode 100644 index 000000000..566dbb037 --- /dev/null +++ b/src/code/dialogs/checklist.d.ts @@ -0,0 +1,16 @@ +import { WDialog } from "../leafletClasses"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; +import Sortable, { SortableField } from "../sortable"; +import type WasabeeOp from "../model/operation"; + +declare class OperationChecklistDialog extends WDialog { + getFields(operation: WasabeeOp): SortableField[]; + getListDialogContent( + operation: WasabeeOp, + items: Array, + sortBy: number, + sortAsc: boolean + ): Sortable; +} +export default OperationChecklistDialog; diff --git a/src/code/dialogs/checklist.js b/src/code/dialogs/checklist.js index cc8280427..94d95cec9 100644 --- a/src/code/dialogs/checklist.js +++ b/src/code/dialogs/checklist.js @@ -1,7 +1,7 @@ import { WDialog } from "../leafletClasses"; -import WasabeeAgent from "../agent"; -import WasabeeLink from "../link"; -import WasabeeMarker from "../marker"; +import WasabeeAgent from "../model/agent"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; import Sortable from "../sortable"; import AssignDialog from "./assignDialog"; import StateDialog from "./stateDialog"; @@ -17,11 +17,19 @@ import { import { getSelectedOperation } from "../selectedOp"; import wX from "../wX"; +import PortalUI from "../ui/portal"; +import LinkUI from "../ui/link"; +import { displayInfo, displayWarning } from "../error"; +import { appendFAIcon } from "../auxiliar"; + const OperationChecklistDialog = WDialog.extend({ statics: { TYPE: "operationChecklist", }, + SORTBY_KEY: "wasabee-checklist-sortby", + SORTASC_KEY: "wasabee-checklist-sortasc", + options: { usePane: true, }, @@ -47,21 +55,22 @@ const OperationChecklistDialog = WDialog.extend({ _displayDialog: async function () { const operation = getSelectedOperation(); loadFaked(operation); + this.sortable = this.getListDialogContent( operation, operation.links.concat(operation.markers), - 0, - false - ); // defaults to sorting by op order + this.SORTBY_KEY, + this.SORTASC_KEY + ); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; buttons[wX("LOAD PORTALS")] = () => { loadFaked(getSelectedOperation(), true); // force }; - buttons["Count fields"] = () => { + buttons[wX("dialog.checklist.count_fields")] = () => { this.countFields(getSelectedOperation(), true); }; buttons[wX("SET_MARKERS_ZONES")] = () => { @@ -84,14 +93,16 @@ const OperationChecklistDialog = WDialog.extend({ }, update: async function () { + if (!this.sortable) return; const operation = getSelectedOperation(); this.setTitle(wX("OP_CHECKLIST", { opName: operation.name })); this.sortable = this.getListDialogContent( operation, operation.links.concat(operation.markers), - this.sortable.sortBy, - this.sortable.sortAsc + this.SORTBY_KEY, + this.SORTASC_KEY ); + await this.sortable.done; this.setContent(this.sortable.table); }, @@ -101,7 +112,7 @@ const OperationChecklistDialog = WDialog.extend({ const columns = [ { name: this._smallScreen ? "#" : wX("ORDER"), - value: (thing) => thing.opOrder, + value: (thing) => thing.order, // sort: (a, b) => a - b, format: (cell, value, thing) => { const oif = L.DomUtil.create("input"); @@ -111,9 +122,9 @@ const OperationChecklistDialog = WDialog.extend({ L.DomEvent.on(oif, "change", (ev) => { L.DomEvent.stop(ev); if (thing instanceof WasabeeLink) { - operation.setLinkOrder(thing.ID, oif.value); + operation.setLinkOrder(thing.ID, +oif.value); } else { - operation.setMarkerOrder(thing.ID, oif.value); + operation.setMarkerOrder(thing.ID, +oif.value); } }); cell.appendChild(oif); @@ -127,11 +138,11 @@ const OperationChecklistDialog = WDialog.extend({ sort: (a, b) => a.localeCompare(b), format: (cell, value, thing) => { if (thing instanceof WasabeeLink) { - cell.appendChild(thing.displayFormat(operation)); - if (this._smallScreen) cell.colSpan = 2; + cell.appendChild(LinkUI.displayFormat(thing, operation)); + cell.colSpan = 2; } else { cell.appendChild( - operation.getPortal(thing.portalId).displayFormat() + PortalUI.displayFormat(operation.getPortal(thing.portalId)) ); } }, @@ -140,7 +151,7 @@ const OperationChecklistDialog = WDialog.extend({ name: wX("TYPE"), value: (thing) => { if (thing instanceof WasabeeLink) { - return "Link"; + return operation.getPortal(thing.toPortalId).name; } else { // push this shit into the marker class return wX(thing.type); @@ -153,7 +164,7 @@ const OperationChecklistDialog = WDialog.extend({ span.textContent = value; if (thing instanceof WasabeeLink) { - if (this._smallScreen) cell.style.display = "none"; + cell.style.display = "none"; } else if (thing instanceof WasabeeMarker && canWrite) { L.DomEvent.on(cell, "click", (ev) => { L.DomEvent.stop(ev); @@ -164,7 +175,7 @@ const OperationChecklistDialog = WDialog.extend({ }, }, { - name: "Zone", + name: wX("ZONE"), value: (thing) => thing.zone, sort: (a, b) => a - b, format: (cell, value, thing) => { @@ -209,7 +220,7 @@ const OperationChecklistDialog = WDialog.extend({ value: async (thing) => { if (thing.assignedTo != null && thing.assignedTo != "") { const agent = await WasabeeAgent.get(thing.assignedTo); - if (agent != null) return agent.name; + if (agent != null) return agent.getName(); return "GID: [" + thing.assignedTo + "]"; } return ". . ."; @@ -255,13 +266,17 @@ const OperationChecklistDialog = WDialog.extend({ ]; if (canWrite) columns.push({ - name: this._smallScreen ? "Cmds" : "Commands", + name: this._smallScreen + ? wX("dialog.common.commands_short") + : wX("dialog.common.commands"), + className: "actions", value: (obj) => typeof obj, format: (cell, value, obj) => { if (obj instanceof WasabeeLink) { const rev = L.DomUtil.create("a", null, cell); rev.href = "#"; - rev.textContent = "πŸ”„"; + rev.title = wX("REVERSE"); + appendFAIcon("arrows-alt-h", rev); L.DomEvent.on(rev, "click", (ev) => { L.DomEvent.stop(ev); operation.reverseLink(obj.fromPortalId, obj.toPortalId); @@ -269,7 +284,8 @@ const OperationChecklistDialog = WDialog.extend({ const del = L.DomUtil.create("a", null, cell); del.href = "#"; - del.textContent = "πŸ—‘"; + del.title = wX("dialog.common.delete"); + appendFAIcon("trash", del); L.DomEvent.on(del, "click", (ev) => { L.DomEvent.stop(ev); operation.removeLink(obj.fromPortalId, obj.toPortalId); @@ -277,7 +293,8 @@ const OperationChecklistDialog = WDialog.extend({ } else { const del = L.DomUtil.create("a", null, cell); del.href = "#"; - del.textContent = "πŸ—‘"; + del.title = wX("dialog.common.delete"); + appendFAIcon("trash", del); L.DomEvent.on(del, "click", (ev) => { L.DomEvent.stop(ev); operation.removeMarker(obj); @@ -288,86 +305,81 @@ const OperationChecklistDialog = WDialog.extend({ return columns; }, - getListDialogContent: function (operation, items, sortBy, sortAsc) { + getListDialogContent: function ( + operation, + items, + sortByStoreKey, + sortAscStoreKey + ) { const content = new Sortable(); content.fields = this.getFields(operation); - content.sortBy = sortBy; - content.sortAsc = sortAsc; + content.sortByStoreKey = sortByStoreKey; + content.sortAscStoreKey = sortAscStoreKey; content.items = items; return content; }, countFields: function (operation, doAlert) { - const links = Array.from(operation.links); - links.sort((a, b) => a.opOrder - b.opOrder); - - let fieldCount = 0; - let emptyCount = 0; + const { + fieldCount, + emptyCount, + emptyFieldLinks, + linksFromInner, + coveredPortals, + } = operation.getOrderInfo(); - // maps a portal id to its linked portals - const portalLinks = new Map(); - const emptyFieldLinks = []; - for (const link of links) { - if (!portalLinks.has(link.fromPortalId)) - portalLinks.set(link.fromPortalId, new Set()); - if (!portalLinks.has(link.toPortalId)) - portalLinks.set(link.toPortalId, new Set()); - const a = portalLinks.get(link.fromPortalId); - const b = portalLinks.get(link.toPortalId); - - // common neighbors portal - const intersect = new Set(); - for (const p of a) if (b.has(p)) intersect.add(p); - - // update the mapping - a.add(link.toPortalId); - b.add(link.fromPortalId); - - // ignore link with order 0 - if (link.opOrder > 0) { - // the link closes at least one field - const p1 = operation.getPortal(link.fromPortalId); - const p2 = operation.getPortal(link.toPortalId); - const positive = []; - const negative = []; - // ignore earth curvature (todo: use it) - for (const pid of intersect) { - const p = operation.getPortal(pid); - const det = - (p1.lat - p2.lat) * (p.lng - p2.lng) - - (p1.lng - p2.lng) * (p.lat - p2.lat); - if (det > 0) positive.push(p); - else negative.push(p); - } - if (positive.length) fieldCount += 1; - if (negative.length) fieldCount += 1; - // if the link closes multiple fields on the same side of the link, we have empty fields. - if (positive.length > 1 || negative.length > 1) { - let count = 0; - if (positive.length > 1) count += positive.length - 1; - if (negative.length > 1) count += negative.length - 1; - emptyFieldLinks.push([link, count]); - emptyCount += count; - } - } - } if (doAlert) { - if (emptyFieldLinks.length > 0) { - const container = L.DomUtil.create("div", "field-count"); + const container = L.DomUtil.create("div", "field-count"); + if (emptyFieldLinks.length) { const header = L.DomUtil.create("div", null, container); - header.textContent = `Found ${fieldCount} fields and ${emptyCount} empty field(s) on ${emptyFieldLinks.length} link(s)`; + header.textContent = wX("dialog.checklist.count_fields.with_empty", { + fieldCount: fieldCount, + emptyCount: emptyCount, + linkCount: emptyFieldLinks.length, + }); const content = L.DomUtil.create("ul", null, container); for (const [link, c] of emptyFieldLinks) { const li = L.DomUtil.create("li", "empty-field-link", content); li.textContent = c; - li.appendChild(link.displayFormat(operation)); + li.appendChild(LinkUI.displayFormat(link, operation)); + } + } else { + const header = L.DomUtil.create("div", null, container); + header.textContent = wX("dialog.checklist.count_fields.no_empty", { + fieldCount: fieldCount, + }); + } + if (linksFromInner.length) { + const header = L.DomUtil.create("div", null, container); + header.textContent = wX( + "dialog.checklist.count_fields.link_from_inside", + { + count: linksFromInner.length, + } + ); + const content = L.DomUtil.create("ul", null, container); + for (const link of linksFromInner) { + const cl = coveredPortals.get(link.fromPortalId); + const li = L.DomUtil.create("li", "inner-link", content); + li.append(`${link.order}: `); + li.appendChild(LinkUI.displayFormat(link, operation)); + li.append( + wX( + "dialog.checklist.count_fields.link_from_inside.covered_at_order", + { + order: cl.order, + } + ) + ); + li.appendChild(LinkUI.displayFormat(cl, operation)); } - alert(container, true); + } + if (emptyFieldLinks.length || linksFromInner.length) { + displayWarning(container, true); } else { - alert(`Found ${fieldCount} fields and no empty fields.`); + displayInfo(container, true); } } - return { field: fieldCount, empty: emptyCount }; }, }); diff --git a/src/code/dialogs/confirmDialog.d.ts b/src/code/dialogs/confirmDialog.d.ts new file mode 100644 index 000000000..19bf3be6f --- /dev/null +++ b/src/code/dialogs/confirmDialog.d.ts @@ -0,0 +1,13 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +interface ConfirmDialogOptions extends WDialogOptions { + title: string; + label: string | HTMLElement; + type?: "agent" | "anchor" | "link" | "marker" | "zone" | "operation" | "team"; + callback?: () => void; + cancelCallback?: () => void; +} +declare class ConfirmDialog extends WDialog { + options: ConfirmDialogOptions; + constructor(options: ConfirmDialogOptions); +} +export default ConfirmDialog; diff --git a/src/code/dialogs/defensiveKeysDialog.d.ts b/src/code/dialogs/defensiveKeysDialog.d.ts new file mode 100644 index 000000000..fefb41941 --- /dev/null +++ b/src/code/dialogs/defensiveKeysDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class DefensiveKeysDialog extends WDialog {} +export default DefensiveKeysDialog; diff --git a/src/code/dialogs/defensiveKeysDialog.js b/src/code/dialogs/defensiveKeysDialog.js index c71925665..aa9392b41 100644 --- a/src/code/dialogs/defensiveKeysDialog.js +++ b/src/code/dialogs/defensiveKeysDialog.js @@ -1,19 +1,21 @@ import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; import { dKeyPromise } from "../server"; import wX from "../wX"; import WasabeeDList from "./wasabeeDlist"; import { getAgentPortalWasabeeDkeys } from "../wd"; +import PortalUI from "../ui/portal"; +import { displayError, displayInfo } from "../error"; + const DefensiveKeysDialog = WDialog.extend({ statics: { TYPE: "defensiveKeysDialog", }, - addHooks: async function () { + addHooks: function () { WDialog.prototype.addHooks.call(this); - this._me = await WasabeeMe.waitGet(); + this._me = WasabeeMe.localGet(); this._pch = (portal) => { this._portalClickedHook(portal); }; @@ -28,14 +30,12 @@ const DefensiveKeysDialog = WDialog.extend({ }, _portalClickedHook: async function () { - this._selectedPortal = WasabeePortal.getSelected(); + this._selectedPortal = PortalUI.getSelected(); if (this._selectedPortal) { this._portal.textContent = ""; - this._portal.appendChild( - this._selectedPortal.displayFormat(this._smallScreen) - ); + this._portal.appendChild(PortalUI.displayFormat(this._selectedPortal)); const mine = await getAgentPortalWasabeeDkeys( - this._me.GoogleID, + this._me.id, this._selectedPortal.id ); if (mine) { @@ -83,7 +83,7 @@ const DefensiveKeysDialog = WDialog.extend({ const content = this._buildContent(); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -111,11 +111,11 @@ const DefensiveKeysDialog = WDialog.extend({ const j = JSON.stringify(dk); console.log(j); await dKeyPromise(j); - alert("Registered with server"); + displayInfo("Registered with server"); window.map.fire("wasabee:defensivekeys"); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } }, }); diff --git a/src/code/dialogs/exportDialog.d.ts b/src/code/dialogs/exportDialog.d.ts new file mode 100644 index 000000000..dc569b067 --- /dev/null +++ b/src/code/dialogs/exportDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class ExportDialog extends WDialog {} +export default ExportDialog; diff --git a/src/code/dialogs/exportDialog.js b/src/code/dialogs/exportDialog.js index a818ab23d..e6e39f479 100644 --- a/src/code/dialogs/exportDialog.js +++ b/src/code/dialogs/exportDialog.js @@ -1,5 +1,6 @@ import { WDialog } from "../leafletClasses"; import { getSelectedOperation } from "../selectedOp"; +import { convertColorToHex } from "../auxiliar"; import wX from "../wX"; // export screen @@ -16,7 +17,7 @@ const ExportDialog = WDialog.extend({ _displayDialog: function () { const operation = getSelectedOperation(); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; buttons[wX("DRAW TOOLS FORMAT")] = () => { @@ -51,7 +52,7 @@ const ExportDialog = WDialog.extend({ for (const link of operation.links) { const l = {}; l.type = "polyline"; - l.color = link.getColor(operation); + l.color = convertColorToHex(link.getColor(operation)); l.latLngs = link.getLatLngs(operation); output.push(l); } diff --git a/src/code/dialogs/fanfield.js b/src/code/dialogs/fanfield.js deleted file mode 100644 index 8195d8850..000000000 --- a/src/code/dialogs/fanfield.js +++ /dev/null @@ -1,259 +0,0 @@ -import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import { getSelectedOperation } from "../selectedOp"; -import { greatCircleArcIntersect, GeodesicLine } from "../crosslinks"; -import WasabeeLink from "../link"; -import { clearAllLinks, getAllPortalsOnScreen } from "../uiCommands"; -import wX from "../wX"; - -const FanfieldDialog = WDialog.extend({ - statics: { - TYPE: "FanfieldDialog", - }, - - addHooks: function () { - WDialog.prototype.addHooks.call(this); - this._displayDialog(); - }, - - _displayDialog: function () { - const container = L.DomUtil.create("div", "container"); - const description = L.DomUtil.create("div", "desc", container); - description.textContent = wX("SELECT_FAN_PORTALS"); - - const anchorLabel = L.DomUtil.create("label", null, container); - anchorLabel.textContent = wX("ANCHOR_PORTAL"); - const anchorButton = L.DomUtil.create("button", null, container); - anchorButton.textContent = wX("SET"); - this._anchorDisplay = L.DomUtil.create("span", null, container); - if (this._anchor) { - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - this._anchorDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._anchor = WasabeePortal.getSelected(); - if (this._anchor) { - localStorage["wasabee-anchor-1"] = JSON.stringify(this._anchor); - this._anchorDisplay.textContent = ""; - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const startLabel = L.DomUtil.create("label", null, container); - startLabel.textContent = wX("START_PORT"); - const startButton = L.DomUtil.create("button", null, container); - startButton.textContent = wX("SET"); - this._startDisplay = L.DomUtil.create("span", null, container); - if (this._start) { - this._startDisplay.appendChild( - this._start.displayFormat(this._smallScreen) - ); - } else { - this._startDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(startButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._start = WasabeePortal.getSelected(); - if (this._start) { - localStorage["wasabee-fanfield-start"] = JSON.stringify(this._start); - this._startDisplay.textContent = ""; - this._startDisplay.appendChild( - this._start.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const endLabel = L.DomUtil.create("label", null, container); - endLabel.textContent = wX("END_PORT"); - const endButton = L.DomUtil.create("button", null, container); - endButton.textContent = wX("SET"); - this._endDisplay = L.DomUtil.create("span", null, container); - if (this._end) { - this._endDisplay.appendChild(this._end.displayFormat(this._smallScreen)); - } else { - this._endDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(endButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._end = WasabeePortal.getSelected(); - if (this._end) { - localStorage["wasabee-fanfield-end"] = JSON.stringify(this._end); - this._endDisplay.textContent = ""; - this._endDisplay.appendChild( - this._end.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const description2 = L.DomUtil.create("div", "desc2", container); - description2.textContent = wX("SELECT_FAN_PORTALS2"); - - // Bottom buttons bar - // Go button - const button = L.DomUtil.create("button", "drawb", container); - button.textContent = wX("FANFIELD"); - L.DomEvent.on(button, "click", (ev) => { - L.DomEvent.stop(ev); - this.fanfield.call(this); - }); - const buttons = {}; - buttons[wX("CLOSE")] = () => { - this.closeDialog(); - }; - buttons[wX("CLEAR LINKS")] = () => { - clearAllLinks(getSelectedOperation()); - }; - - this.createDialog({ - title: wX("FANFIELD2"), - html: container, - width: "auto", - dialogClass: "fanfield", - buttons: buttons, - id: window.plugin.wasabee.static.dialogNames.fanfield, - }); - }, - - initialize: function (options) { - WDialog.prototype.initialize.call(this, options); - this.title = wX("FAN_FIELD3"); - this.label = wX("FAN_FIELD3"); - let p = localStorage["wasabee-anchor-1"]; - if (p) this._anchor = new WasabeePortal(p); - p = localStorage["wasabee-fanfield-start"]; - if (p) this._start = new WasabeePortal(p); - p = localStorage["wasabee-fanfield-end"]; - if (p) this._end = new WasabeePortal(p); - }, - - // fanfiled determines the portals between start/end and their angle (and order) - fanfield: function () { - if (!this._anchor || !this._start || !this._end) { - alert(wX("SET_3_PORT")); - return; - } - - const startAngle = this._angle(this._anchor, this._start); - const endAngle = this._angle(this._anchor, this._end); - - // swap start/end if more than 180Β° - this._invert = false; - if ( - (((endAngle - startAngle) % (2 * Math.PI)) + 2 * Math.PI) % - (2 * Math.PI) > - Math.PI - ) { - this._invert = true; - } - - const good = new Map(); - const op = getSelectedOperation(); - for (const p of getAllPortalsOnScreen(op)) { - if (p.id == this._anchor.id) continue; - const pAngle = this._angle(this._anchor, p); - - good.set(pAngle, p); // what are the odds of two having EXACTLY the same angle? - } - // add start and end portals just in case - good.set(startAngle, this._start); - good.set(endAngle, this._end); - - const sorted = new Array(...good.entries()) - .sort((a, b) => a[0] - b[0]) - .map((v) => v[1]); - - if (this._invert) { - sorted.reverse(); - } - // Build the sequence of portals between start/end - const slice = new Array(); - let start = 0; - for (start = 0; sorted[start].id != this._start.id; start++); - for (; sorted[start % sorted.length].id != this._end.id; start++) { - slice.push(sorted[start % sorted.length]); - } - slice.push(this._end); - - this._draw(slice); - }, - - // draw takes the sorted list of poratls and draws the links - // determining any sub-fields can be added - _draw: function (sorted) { - const op = getSelectedOperation(); - op.startBatchMode(); - let order = 0; - let fields = 0; - - const available = Array.from(sorted); - available.reverse(); - - for (let i = available.length - 1; i >= 0; i--) { - const wp = available[i]; - order++; - op.addLink(wp, this._anchor, { description: "fan anchor", order: order }); - - // skip back links if first portal - if (i + 1 == available.length) continue; - - // Find the interval of portals that are linkable - let j = i + 1; - for (; j < available.length; j++) { - const testlink = new WasabeeLink( - { fromPortalId: wp.id, toPortalId: available[j].id }, - op - ); - let crossed = false; - for (const real of op.links) { - // Check links to anchor only - if (real.toPortalId != this._anchor.id) continue; - if (greatCircleArcIntersect(real, testlink)) { - crossed = true; - break; - } - } - if (crossed) break; - } - j--; - op.addLink(wp, available[j], { - description: "fan subfield", - order: ++order, - }); - fields++; - - for (var k = j - 1; k > i; k--) { - const check = available[k]; - op.addLink(wp, check, { - description: "fan double subfield", - order: ++order, - }); - fields += 2; - } - // remove covered portals - available.splice(i + 1, j - i - 1); - } - op.endBatchMode(); - const ap = 313 * order + 1250 * fields; - // too many parameters for wX(); - alert(`Fanfield found ${order} links and ${fields} fields for ${ap} AP`); - }, - - _angle: function (a, p) { - const link = new GeodesicLine(a.latLng, p.latLng); - return link.bearing(); - }, -}); - -export default FanfieldDialog; diff --git a/src/code/dialogs/homogeneous.js b/src/code/dialogs/homogeneous.js deleted file mode 100644 index e3eb19064..000000000 --- a/src/code/dialogs/homogeneous.js +++ /dev/null @@ -1,855 +0,0 @@ -import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import { getSelectedOperation } from "../selectedOp"; -import { greatCircleArcIntersectByLatLngs } from "../crosslinks"; -// import WasabeeLink from "../link"; -import { - clearAllLinks, - getAllPortalsOnScreen, - testPortal, -} from "../uiCommands"; -import wX from "../wX"; - -const HomogeneousDialog = WDialog.extend({ - statics: { - TYPE: "HomogeneousDialog", - }, - - needWritePermission: true, - - addHooks: function () { - this._layerGroup = new L.LayerGroup(); - window.addLayerGroup("Wasabee H-G Debug", this._layerGroup, true); - this._displayDialog(); - }, - - removeHooks: function () { - window.removeLayerGroup(this._layerGroup); - WDialog.prototype.removeHooks.call(this); - }, - - _displayDialog: function () { - const container = L.DomUtil.create("div", "container"); - const description2 = L.DomUtil.create("div", "desc", container); - description2.textContent = wX("H-GEN_INST"); - - const anchorLabelOne = L.DomUtil.create("label", null, container); - anchorLabelOne.textContent = wX("ANCHOR_PORTAL"); - const anchorButtonOne = L.DomUtil.create("button", null, container); - anchorButtonOne.textContent = wX("SET"); - this._anchorDisplayOne = L.DomUtil.create("span", "portal", container); - if (this._anchorOne) { - this._anchorDisplayOne.appendChild( - this._anchorOne.displayFormat(this._smallScreen) - ); - } else { - this._anchorDisplayOne.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorButtonOne, "click", (ev) => { - L.DomEvent.stop(ev); - this._anchorOne = WasabeePortal.getSelected(); - if (this._anchorOne) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY] = - JSON.stringify(this._anchorOne); - this._anchorDisplayOne.textContent = ""; - this._anchorDisplayOne.appendChild( - this._anchorOne.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const anchorLabelTwo = L.DomUtil.create("label", null, container); - anchorLabelTwo.textContent = wX("ANCHOR_PORTAL2"); - const anchorButtonTwo = L.DomUtil.create("button", null, container); - anchorButtonTwo.textContent = wX("SET"); - this._anchorDisplayTwo = L.DomUtil.create("span", "portal", container); - if (this._anchorTwo) { - this._anchorDisplayTwo.appendChild( - this._anchorTwo.displayFormat(this._smallScreen) - ); - } else { - this._anchorDisplayTwo.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorButtonTwo, "click", (ev) => { - L.DomEvent.stop(ev); - this._anchorTwo = WasabeePortal.getSelected(); - if (this._anchorTwo) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY] = - JSON.stringify(this._anchorTwo); - this._anchorDisplayTwo.textContent = ""; - this._anchorDisplayTwo.appendChild( - this._anchorTwo.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const anchorLabelThree = L.DomUtil.create("label", null, container); - anchorLabelThree.textContent = wX("ANCHOR_PORTAL3"); - const anchorButtonThree = L.DomUtil.create("button", null, container); - anchorButtonThree.textContent = wX("SET"); - this._anchorDisplayThree = L.DomUtil.create("span", "portal", container); - if (this._anchorThree) { - this._anchorDisplayThree.appendChild( - this._anchorThree.displayFormat(this._smallScreen) - ); - } else { - this._anchorDisplayThree.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorButtonThree, "click", (ev) => { - L.DomEvent.stop(ev); - this._anchorThree = WasabeePortal.getSelected(); - if (this._anchorThree) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_THREE_KEY] = - JSON.stringify(this._anchorThree); - this._anchorDisplayThree.textContent = ""; - this._anchorDisplayThree.appendChild( - this._anchorThree.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const depthLabel = L.DomUtil.create("label", null, container); - depthLabel.textContent = wX("MAX_SPLITS"); - this.depthMenu = L.DomUtil.create("select", null, container); - let dc = 2; - while (dc <= 6) { - const depthOption = L.DomUtil.create("option", null, this.depthMenu); - depthOption.value = dc; - depthOption.textContent = dc; - dc++; - } // no need for an event, we will read the value directly below - - const orderLabel = L.DomUtil.create("label", null, container); - orderLabel.textContent = "Order"; - this.orderMenu = L.DomUtil.create("select", null, container); - for (const [text, value] of [ - [wX("FROM_DEPTH"), "core"], // need wX on first column - [wX("FROM_1-2"), "base12"], - [wX("FROM_1-3"), "base13"], - [wX("FROM_2-3"), "base23"], - ]) { - const orderOption = L.DomUtil.create("option", null, this.orderMenu); - orderOption.value = value; - orderOption.textContent = text; - } - - const fullSearchLabel = L.DomUtil.create("label", null, container); - fullSearchLabel.textContent = wX("HF_DEEP_SEARCH"); - fullSearchLabel.htmlFor = "wasabee-homogeneous-deep"; - this._fullSearchCheck = L.DomUtil.create("input", null, container); - this._fullSearchCheck.type = "checkbox"; - this._fullSearchCheck.id = "wasabee-homogeneous-deep"; - - const spanRedraw = L.DomUtil.create("div", null, container); - this._redrawButton = L.DomUtil.create("button", null, spanRedraw); - this._redrawButton.textContent = wX("HF_REDRAW_BUTTON"); - this._redrawButton.style.display = "none"; - L.DomEvent.on(this._redrawButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._operation = getSelectedOperation(); - if (this._tree) this._draw.call(this); - }); - - // Go button - const drawButton = L.DomUtil.create("button", "drawb", container); - drawButton.textContent = wX("HF_DRAW_BUTTON"); - L.DomEvent.on(drawButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._operation = getSelectedOperation(); - if (this._fullSearchCheck.checked) this.hdeepfield.call(this); - else this.hfield.call(this); - }); - - const buttons = {}; - buttons[wX("CLOSE")] = () => { - this.closeDialog(); - }; - buttons[wX("CLEAR LINKS")] = () => { - this._layerGroup.clearLayers(); - clearAllLinks(getSelectedOperation()); - }; - - this.createDialog({ - title: "Homogeneous", - html: container, - width: "auto", - dialogClass: "homogeneous", - buttons: buttons, - }); - }, - - initialize: function (options) { - WDialog.prototype.initialize.call(this, options); - this.title = "Homogeneous"; - this.label = "Homogeneous"; - let p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; - if (p) this._anchorOne = new WasabeePortal(p); - p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY]; - if (p) this._anchorTwo = new WasabeePortal(p); - p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_THREE_KEY]; - if (p) this._anchorThree = new WasabeePortal(p); - - this._urp = L.latLng(testPortal()); - this._failed = 0; - }, - - hfield: function () { - this._failed = 0; - this._layerGroup.clearLayers(); - - if (!this._anchorOne || !this._anchorTwo || !this._anchorThree) { - alert("please select three anchors"); - return; - } - - const portals = new Array(); - for (const p of getAllPortalsOnScreen(this._operation)) { - if ( - this._fieldCovers( - this._anchorOne, - this._anchorTwo, - this._anchorThree, - p - ) - ) - portals.push(p); - } - - console.time("HF recurser"); - const tree = this._recurser( - 1, - portals, - this._anchorOne, - this._anchorTwo, - this._anchorThree - ); - console.timeEnd("HF recurser"); - - this._tree = tree; - this._failed = (3 ** (+this.depthMenu.value - 1) - 1) / 2 - tree.split; - - this._draw(); - - if (this._failed > 0) { - alert( - `Unable to find ${this._failed} splits, try less depth or a different region` - ); - } - }, - - hdeepfield: function () { - this._failed = 0; - this._layerGroup.clearLayers(); - - if (!this._anchorOne || !this._anchorTwo || !this._anchorThree) { - alert("please select three anchors"); - return; - } - - const portals = new Array(); - for (const p of getAllPortalsOnScreen(this._operation)) { - if ( - this._fieldCovers( - this._anchorOne, - this._anchorTwo, - this._anchorThree, - p - ) - ) - portals.push(p); - } - - console.time("HF deep recurser"); - const tree = this._fullRecurser( - portals, - this._anchorOne, - this._anchorTwo, - this._anchorThree - ); - console.timeEnd("HF deep recurser"); - - this._tree = tree; - this._failed = (3 ** (+this.depthMenu.value - 1) - 1) / 2 - tree.split; - - this._draw(); - - if (this._failed > 0) { - alert( - `Unable to find ${this._failed} splits, try less depth or a different region` - ); - } - - this._failed = 0; - - if (!this._anchorOne || !this._anchorTwo || !this._anchorThree) { - alert("please select three anchors"); - return; - } - }, - - _draw: function () { - this._colors = [ - "#f80c12", - "#ee1100", - "#ff3311", - "#ff4422", - "#ff6644", - "#ff9933", - "#feae2d", - "#ccbb33", - "#d0c310", - "#aacc22", - "#69d025", - "#22ccaa", - "#12bdb9", - "#11aabb", - "#4444dd", - "#3311bb", - "#3b0cbd", - "#442299", - ]; - - this._operation.startBatchMode(); - if (this.orderMenu.value == "base12") - this._drawTreeBase(this._tree, this._anchorOne, this._anchorTwo); - else if (this.orderMenu.value == "base13") - this._drawTreeBase(this._tree, this._anchorOne, this._anchorThree); - else if (this.orderMenu.value == "base23") - this._drawTreeBase(this._tree, this._anchorTwo, this._anchorThree); - else this._drawTreeCore(this._tree); - this._operation.endBatchMode(); - - // this._operation.cleanAnchorList(); - // now, remove the portals that are unused - this._operation.cleanPortalList(); - - this._redrawButton.style.display = ""; - }, - - _recurser: function (depth, portalsCovered, one, two, three) { - if (depth >= this.depthMenu.value) - return { success: true, anchors: [one, two, three], split: 0 }; - - // empty tree - let bestResult = { - success: false, - anchors: [one, two, three], - split: 0, - portal: null, - children: null, - }; - - // console.log(depth, "portals in consideration", portalsCovered); - - // build a map of all portals coverd by field one,two,three - // keyed by distance to the centeroid of the field - // does this get us much in reality? doesn't seem like it - const m = new Map(); - const center = this._getCenter(one, two, three); - for (const p of portalsCovered) { - if (p.id === one.id || p.id === two.id || p.id === three.id) continue; - const cDist = window.map.distance(center, p.latLng || p._latlng); - m.set(cDist, p); - } - // sort by distance to centeroid the field - const sorted = new Map([...m.entries()].sort((a, b) => a[0] - b[0])); - if (sorted.size == 0) { - // console.log("empty set"); - return bestResult; - } - - // find the portal that divides the area into regions with the closest number of portals - // starts at the center-most and works outwards - let differential = portalsCovered.length; - let best = []; - let bestp = {}; - // for each of the portals in play - for (const [k, wp] of sorted) { - // silence lint - this._trash = k; - const subregions = this._getSubregions( - wp, - new Array(...portalsCovered), - one, - two, - three - ); - // one of the regions didn't have enough - // if (!subregions) continue; // never - // is this one better than the previous? - // smallest difference in the number of portals between the greatest and least, 0 being ideal - const temp = - Math.max( - subregions[0].length, - subregions[1].length, - subregions[2].length - ) - - Math.min( - subregions[0].length, - subregions[1].length, - subregions[2].length - ); - if (temp < differential) { - best = subregions; - differential = temp; - bestp = wp; - } - // found one with equal number of portals in all 3, quit digging - // if (differential == 0) break; - } - - // console.log("best balance: ", bestp.name, differential, best); - bestResult.portal = bestp; - - bestResult.children = [ - this._recurser(depth + 1, new Array(...best[0]), one, two, bestp), - this._recurser(depth + 1, new Array(...best[1]), two, three, bestp), - this._recurser(depth + 1, new Array(...best[2]), one, three, bestp), - ]; - bestResult.success = - bestResult.children[0].success && - bestResult.children[1].success && - bestResult.children[2].success; - bestResult.split = - 1 + - bestResult.children[0].split + - bestResult.children[1].split + - bestResult.children[2].split; - return bestResult; - }, - - _fullRecurser: function (portalsCovered, one, two, three) { - const alreadyCalculatedCover = new Map(); - const getNbSplitPerDepth = (depth) => (3 ** (depth - 1) - 1) / 2; - - console.log( - "Expect at least", - Math.max( - 0, - getNbSplitPerDepth(this.depthMenu.value) - portalsCovered.length - ), - "missing splits" - ); - - const homogeneousFrom = (depth, portalsCovered, one, two, three) => { - if (depth <= 1) - return { success: true, anchors: [one, two, three], split: 0 }; - - const key = [depth, one.id, two.id, three.id].sort().toString(); - if (alreadyCalculatedCover.get(key) === undefined) { - // sort portals according to the balance between the regions - const m = new Map(); - // for each of the portals in play - for (const wp of portalsCovered) { - const subregions = this._getSubregions( - wp, - new Array(...portalsCovered), - one, - two, - three - ); - // one of the regions didn't have enough - if (!subregions) continue; - // is this one better than the previous? - // smallest difference in the number of portals between the greatest and least, 0 being ideal - const differential = - Math.max( - subregions[0].length, - subregions[1].length, - subregions[2].length - ) - - Math.min( - subregions[0].length, - subregions[1].length, - subregions[2].length - ); - m.set(wp.id, differential); - } - - const sorted = new Map([...m.entries()].sort((a, b) => a[1] - b[1])); - - const maxNbSplit = Math.min( - getNbSplitPerDepth(depth), - portalsCovered.length - ); - let bestResult = { - success: false, - anchors: [one, two, three], - split: 0, - portal: null, - children: null, - }; - for (const k of sorted.keys()) { - const wp = WasabeePortal.get(k); - const subregions = this._getSubregions( - wp, - new Array(...portalsCovered), - one, - two, - three - ); - const maxNbSplitSubregions = - Math.min(getNbSplitPerDepth(depth - 1), subregions[0].length) + - Math.min(getNbSplitPerDepth(depth - 1), subregions[1].length) + - Math.min(getNbSplitPerDepth(depth - 1), subregions[2].length); - if (maxNbSplitSubregions + 1 <= bestResult.split) { - // Skip the portal since it will induce less splits than the current best choice - continue; - } - - let ret1 = homogeneousFrom( - depth - 1, - new Array(...subregions[0]), - one, - two, - wp - ); - let ret2 = homogeneousFrom( - depth - 1, - new Array(...subregions[1]), - two, - three, - wp - ); - let ret3 = homogeneousFrom( - depth - 1, - new Array(...subregions[2]), - one, - three, - wp - ); - - const nbSplit = ret1.split + ret2.split + ret3.split + 1; - - if (nbSplit > bestResult.split) { - bestResult.success = ret1.success && ret2.success && ret3.success; - bestResult.split = nbSplit; - bestResult.portal = wp; - bestResult.children = [ret1, ret2, ret3]; - } - - if (nbSplit == maxNbSplit) { - // we cannot do more split so it is one of the best choice - break; - } - } - alreadyCalculatedCover.set(key, bestResult); - } - return alreadyCalculatedCover.get(key); - }; - return homogeneousFrom( - this.depthMenu.value, - portalsCovered, - one, - two, - three - ); - }, - - _drawTreeCore: function (tree) { - const depthValue = +this.depthMenu.value - 1; - const [one, two, three] = tree.anchors; - const computeDepth = (depth, tree, map) => { - if (tree.portal) { - map.set(tree.portal.id, depth); - for (const child of tree.children) computeDepth(depth + 1, child, map); - } - }; - - const portalDepth = new Map([ - [one.id, 0], - [two.id, 0], - [three.id, 0], - ]); - computeDepth(1, tree, portalDepth); - - // the order follows this process (consider only op links) - // (0) if max depth is 1, goto (9) - // (1) start from maximal depth D portals - // (2) for each portals of depth D: - // (3) link to the _only_ portal deepless by 1 (D-1) - // (4) if the second deepless portal isn't an anchor - // (5) link to the second deepest portal - // (6) for each of the 1 deepless portals: - // (7) link to all the deeper portals by _increasing_ depth (D+1, D+2 etc) - // (8) if D > 1 then goto (2) with D = D-1 - // (9) for each anchor: - // (A) deploy it (or don't link it before this step) - // (B) link to previous anchors - // (C) link to all deeper portals by _increasing_ depth (1, 2 etc) - // NB: rules 4/5 were added to reduce the number of outbound links the center portal. Those links can be done earlier because they are not backlinks - const orderByDepth = (a, b) => { - let ad = portalDepth.get(a.id); - let bd = portalDepth.get(b.id); - - const baseOrder = ((depthValue - bd) * (depthValue - bd - 1)) / 2 + 1; - - if (bd != 0 || b.id == one.id) return baseOrder + ad - bd - 1; - - if (b.id == two.id) return baseOrder + depthValue + ad; - - return baseOrder + 2 * depthValue + ad + 1; - }; - - const draw = (depth, r) => { - if (r.portal) { - const [first, second, father] = r.anchors - .map((p) => [portalDepth.get(p.id), p]) - .sort() - .map((a) => a[1]); - const firstOrder = orderByDepth(r.portal, first); - const secondOrder = orderByDepth(r.portal, second); - const fatherOrder = orderByDepth(r.portal, father); - const data = [ - portalDepth.get(first.id) // not outer anchor - ? [first, r.portal, "intern", firstOrder] - : [first, r.portal, "anchor intern", firstOrder], - // not an intern link (no double field) - portalDepth.get(second.id) > 0 - ? [r.portal, second, "early", fatherOrder] - : [second, r.portal, "anchor intern", secondOrder], - portalDepth.get(father.id) == 0 - ? [father, r.portal, "anchor intern", fatherOrder] - : [r.portal, father, "to father", fatherOrder], - ]; - for (const [from, to, comment, order] of data) { - this._operation.addLink(from, to, { - description: comment, - order: order, - color: this._colors[order % this._colors.length], - replace: true, - }); - } - for (const child of r.children) draw(depth + 1, child); - } - }; - - const drawDebug = (depth, r) => { - if (r.portal) for (const child of r.children) drawDebug(depth - 1, child); - if (!r.portal && !r.success) { - // debug layer - const color = depth == 1 ? "orange" : "red"; - const latlngs = [ - r.anchors[0].latLng, - r.anchors[1].latLng, - r.anchors[2].latLng, - r.anchors[0].latLng, - ]; - const polygon = L.polygon(latlngs, { color: color }); - polygon.addTo(this._layerGroup); - } - }; - drawDebug(depthValue, tree); - - this._operation.addPortal(one); - this._operation.addPortal(two); - this._operation.addPortal(three); - this._operation.addLink(two, one, { - description: "Outer 1", - order: (depthValue * (depthValue - 1)) / 2 + depthValue + 1, - color: - this._colors[ - ((depthValue * (depthValue - 1)) / 2 + depthValue + 1) % - this._colors.length - ], - replace: true, - }); - this._operation.addLink(three, one, { - description: "Outer 2", - order: (depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2, - color: - this._colors[ - ((depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2) % - this._colors.length - ], - replace: true, - }); - this._operation.addLink(three, two, { - description: "Outer 3", - order: (depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2, - color: - this._colors[ - ((depthValue * (depthValue - 1)) / 2 + 2 * depthValue + 2) % - this._colors.length - ], - replace: true, - }); - draw(1, tree); - }, - - _drawTreeBase: function (tree, one, two) { - const depthValue = +this.depthMenu.value - 1; - - const drawFractal = (depth, r, pOne, pTwo, order) => { - if (r.portal) { - // draw inner HF on base 1-2 - const pThree = r.anchors.filter( - (p) => p.id !== pOne.id && p.id !== pTwo.id - )[0]; - for (const child of r.children) - if (child.anchors.every((p) => p.id !== pThree.id)) - order = draw(depth + 1, child, pOne, pTwo, order); - - let order1, order2; - // draw fractal on 1-p - for (const child of r.children) - if (child.anchors.every((p) => p.id !== pTwo.id)) - order1 = drawFractal(depth + 1, child, pOne, r.portal, order); - - // draw fractal on 2-p - for (const child of r.children) - if (child.anchors.every((p) => p.id !== pOne.id)) - order2 = drawFractal(depth + 1, child, pTwo, r.portal, order); - - // should be computed with a formula - order = Math.max(order1, order2); - } - return order; - }; - - // link an anchor to inner portals in depth order - const drawBackLink = (depth, r, anchor, order) => { - if (r.portal) { - this._operation.addLink(anchor, r.portal, { - description: "intern link", - order: order + 1, - color: this._colors[order % this._colors.length], - replace: true, - }); - for (const child of r.children) - if (child.anchors.includes(anchor)) - drawBackLink(depth + 1, child, anchor, order + 1); - } - return order + depthValue - depth + 1; - }; - - // draw a HF from base - const draw = (depth, r, pOne, pTwo, order = 1) => { - // draw fratal on 1-2 - order = drawFractal(depth, r, pOne, pTwo, order); - const pThree = r.anchors.filter( - (p) => p.id !== pOne.id && p.id !== pTwo.id - )[0]; - // draw outer link - for (const anchor of [pOne, pTwo]) { - this._operation.addLink(pThree, anchor, { - order: order + 1, - color: this._colors[order % this._colors.length], - replace: true, - }); - } - if (!r.portal) return order + 1; - // draw inner link from 3 - return drawBackLink(depth, r, pThree, order + 1); - }; - - const drawDebug = (depth, r) => { - if (r.portal) for (const child of r.children) drawDebug(depth - 1, child); - if (!r.portal && !r.success) { - // debug layer - const color = depth == 1 ? "orange" : "red"; - const latlngs = [ - r.anchors[0].latLng, - r.anchors[1].latLng, - r.anchors[2].latLng, - r.anchors[0].latLng, - ]; - const polygon = L.polygon(latlngs, { color: color }); - polygon.addTo(this._layerGroup); - } - }; - drawDebug(depthValue, tree); - - for (const p of tree.anchors) this._operation.addPortal(p); - this._operation.addLink(two, one, { - description: "Outer base", - order: 1, - color: this._colors[0], - replace: true, - }); - draw(1, tree, one, two); - }, - - _getSubregions: function (centerPoint, possibles, one, two, three) { - const possibleExceptAnchors = new Array(); - for (const p of possibles) { - const guid = p.id || p.options.guid; - if ( - guid !== centerPoint.id && - guid !== one.id && - guid !== two.id && - guid !== three.id - ) - possibleExceptAnchors.push(p); - } - - const onePortals = new Array(); - const twoPortals = new Array(); - const threePortals = new Array(); - for (const p of possibleExceptAnchors) { - if ( - greatCircleArcIntersectByLatLngs( - p.latLng, - one.latLng, - centerPoint.latLng, - two.latLng - ) || - greatCircleArcIntersectByLatLngs( - p.latLng, - one.latLng, - centerPoint.latLng, - three.latLng - ) - ) - twoPortals.push(p); - else if ( - greatCircleArcIntersectByLatLngs( - p.latLng, - two.latLng, - centerPoint.latLng, - one.latLng - ) || - greatCircleArcIntersectByLatLngs( - p.latLng, - two.latLng, - centerPoint.latLng, - three.latLng - ) - ) - threePortals.push(p); - else onePortals.push(p); - } - - return [onePortals, twoPortals, threePortals]; - }, - - _getCenter: function (a, b, c) { - const A = window.map.project(a.latLng || a._latlng); - const B = window.map.project(b.latLng || b._latlng); - const C = window.map.project(c.latLng || c._latlng); - - const point = L.point((A.x + B.x + C.x) / 3, (A.y + B.y + C.y) / 3); - return window.map.unproject(point); - }, - - _fieldCovers: function (a, b, c, p) { - const urp = this._urp; - - let crossings = 0; - if (greatCircleArcIntersectByLatLngs(urp, p.latLng, a.latLng, b.latLng)) - crossings++; - if (greatCircleArcIntersectByLatLngs(urp, p.latLng, a.latLng, c.latLng)) - crossings++; - if (greatCircleArcIntersectByLatLngs(urp, p.latLng, b.latLng, c.latLng)) - crossings++; - return crossings == 1; // crossing 0 or 2 is OK, crossing 3 is - }, -}); - -export default HomogeneousDialog; diff --git a/src/code/dialogs/importDialog.d.ts b/src/code/dialogs/importDialog.d.ts new file mode 100644 index 000000000..c958e3577 --- /dev/null +++ b/src/code/dialogs/importDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class ImportDialog extends WDialog {} +export default ImportDialog; diff --git a/src/code/dialogs/importDialog.js b/src/code/dialogs/importDialog.js index ff32232e4..f2efb9fcf 100644 --- a/src/code/dialogs/importDialog.js +++ b/src/code/dialogs/importDialog.js @@ -1,11 +1,12 @@ -import WasabeeOp from "../operation"; -import WasabeePortal from "../portal"; +import WasabeeOp from "../model/operation"; +import WasabeePortal from "../model/portal"; import { WDialog } from "../leafletClasses"; import OperationChecklistDialog from "./checklist"; import wX from "../wX"; import { makeSelectedOperation } from "../selectedOp"; import PromptDialog from "./promptDialog"; import { zoomToOperation } from "../uiCommands"; +import { displayError, displayInfo } from "../error"; const ImportDialog = WDialog.extend({ statics: { @@ -54,8 +55,7 @@ const ImportDialog = WDialog.extend({ buttons[wX("GET DT")] = () => { this.drawToolsFormat(); }; - // wX - buttons["Fill from URL"] = () => { + buttons[wX("dialog.import.url")] = () => { this.fillFromURL(); }; @@ -83,7 +83,7 @@ const ImportDialog = WDialog.extend({ fillFromURL() { // todo: wX const prompt = new PromptDialog({ - title: "Fill from URL", + title: wX("dialog.import.url"), label: "URL", callback: async () => { try { @@ -91,7 +91,7 @@ const ImportDialog = WDialog.extend({ const rq = await fetch(url, { mode: "cors" }); this._textarea.value = await rq.text(); } catch (e) { - alert("Unable to fetch data from the given url."); + displayError("Unable to fetch data from the given url."); return; } }, @@ -103,10 +103,10 @@ const ImportDialog = WDialog.extend({ let string = this._textarea.value; if ( string.match( - new RegExp("^(https?://)?(www\\.)?intel.ingress.com/intel.*") + new RegExp("^(https?://)?(www|intel)\\.ingress\\.com/(intel)?.*") ) ) { - alert(wX("NO_STOCK_INTEL")); + displayError(wX("NO_STOCK_INTEL")); return; } @@ -141,12 +141,22 @@ const ImportDialog = WDialog.extend({ try { const data = JSON.parse(string); const importedOp = new WasabeeOp(data); - await importedOp.store(); - await makeSelectedOperation(importedOp.ID); - alert(wX("IMPORT_OP_SUCCESS", { opName: importedOp.name })); + const localOp = await WasabeeOp.load(importedOp.ID); + if (localOp) { + displayError( + wX("IMP_NOPE", { + error: "op already exists, either delete it or duplicate", + }) + ); + await makeSelectedOperation(importedOp.ID); + } else { + await importedOp.store(); + await makeSelectedOperation(importedOp.ID); + displayInfo(wX("IMPORT_OP_SUCCESS", { opName: importedOp.name })); + } } catch (e) { console.error("WasabeeTools: failed to import data", e); - alert(wX("IMP_NOPE")); + displayError(wX("IMP_NOPE", { error: "data invalid" })); } }, @@ -164,7 +174,7 @@ const ImportDialog = WDialog.extend({ data = JSON.parse(string); } catch (e) { console.error("Failed parseDrawTools", e); - alert(e.toString()); + displayError(e); return null; } @@ -214,8 +224,8 @@ const ImportDialog = WDialog.extend({ newop.addLink(prev, first); } } - alert( - wX("IMP_COMP") + found + wX("PORT_FAKE") + faked + wX("USE_SWAP_INSTRUCT") + displayInfo( + wX("dialog.import.success_message", { count: found, faked: faked }) ); // get the op out of batchmode, but do not update UI or run crosslinks yet diff --git a/src/code/dialogs/keyListPortal.d.ts b/src/code/dialogs/keyListPortal.d.ts new file mode 100644 index 000000000..929aa196b --- /dev/null +++ b/src/code/dialogs/keyListPortal.d.ts @@ -0,0 +1,10 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; + +interface KeyListPortalOptions extends WDialogOptions { + portalID: string; +} +declare class KeyListPortal extends WDialog { + options: KeyListPortalOptions; + constructor(options: KeyListPortalOptions); +} +export default KeyListPortal; diff --git a/src/code/dialogs/keyListPortal.js b/src/code/dialogs/keyListPortal.js index 2a4d8e3dc..57fa8cb09 100644 --- a/src/code/dialogs/keyListPortal.js +++ b/src/code/dialogs/keyListPortal.js @@ -1,9 +1,11 @@ import { WDialog } from "../leafletClasses"; import Sortable from "../sortable"; -import WasabeeAgent from "../agent"; +import WasabeeAgent from "../model/agent"; import { getSelectedOperation } from "../selectedOp"; import wX from "../wX"; +import PortalUI from "../ui/portal"; + const KeyListPortal = WDialog.extend({ statics: { TYPE: "keyListPortal", @@ -33,7 +35,7 @@ const KeyListPortal = WDialog.extend({ this._sortable = this.getSortable(); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -41,7 +43,9 @@ const KeyListPortal = WDialog.extend({ const portal = op.getPortal(this.options.portalID); this.createDialog({ - title: wX("PORTAL KEY LIST", { portalName: portal.displayName }), + title: wX("PORTAL KEY LIST", { + portalName: PortalUI.displayName(portal), + }), html: this.getListDialogContent(this.options.portalID), width: "auto", dialogClass: "keylistportal", @@ -63,7 +67,9 @@ const KeyListPortal = WDialog.extend({ const table = this.getListDialogContent(this.options.portalID); this.setContent(table); - this.setTitle(wX("PORTAL KEY LIST", { portalName: portal.displayName })); + this.setTitle( + wX("PORTAL KEY LIST", { portalName: PortalUI.displayName(portal) }) + ); }, getSortable: function () { @@ -75,7 +81,7 @@ const KeyListPortal = WDialog.extend({ sort: (a, b) => a.localeCompare(b), format: async (cell, value, key) => { const agent = await WasabeeAgent.get(key.gid); - cell.textContent = agent ? agent.name : key.gid; + cell.textContent = agent ? agent.getName() : key.gid; }, }, { diff --git a/src/code/dialogs/keysList.d.ts b/src/code/dialogs/keysList.d.ts new file mode 100644 index 000000000..7a2e890cb --- /dev/null +++ b/src/code/dialogs/keysList.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class KeysList extends WDialog {} +export default KeysList; diff --git a/src/code/dialogs/keysList.js b/src/code/dialogs/keysList.js index b602257f1..a8a270094 100644 --- a/src/code/dialogs/keysList.js +++ b/src/code/dialogs/keysList.js @@ -1,11 +1,14 @@ import { WDialog } from "../leafletClasses"; import Sortable from "../sortable"; import { opKeyPromise } from "../server"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; +import WasabeeMarker from "../model/marker"; import KeyListPortal from "./keyListPortal"; import { getSelectedOperation } from "../selectedOp"; import wX from "../wX"; +import PortalUI from "../ui/portal"; + const KeysList = WDialog.extend({ statics: { TYPE: "keysList", @@ -15,13 +18,13 @@ const KeysList = WDialog.extend({ usePane: true, }, - addHooks: async function () { + addHooks: function () { WDialog.prototype.addHooks.call(this); const operation = getSelectedOperation(); this._opID = operation.ID; window.map.on("wasabee:op:select wasabee:op:change", this.update, this); if (WasabeeMe.isLoggedIn()) { - this._me = await WasabeeMe.waitGet(); + this._me = WasabeeMe.localGet(); } else { this._me = null; } @@ -36,13 +39,13 @@ const KeysList = WDialog.extend({ _displayDialog: function () { const operation = getSelectedOperation(); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; this.createDialog({ title: wX("KEY_LIST2", { opName: operation.name }), - html: this.getListDialogContent(operation, 0, false).table, + html: this.getListDialogContent(operation, 0, true).table, width: "auto", dialogClass: "keyslist", buttons: buttons, @@ -50,12 +53,12 @@ const KeysList = WDialog.extend({ }); }, - update: async function () { + update: function () { const operation = getSelectedOperation(); if (operation.ID != this._opID) console.log("operation changed"); // update me if needed - if (WasabeeMe.isLoggedIn()) this._me = await WasabeeMe.waitGet(); + if (WasabeeMe.isLoggedIn()) this._me = WasabeeMe.localGet(); else this._me = null; this.setTitle(wX("KEY_LIST2", { opName: operation.name })); @@ -75,7 +78,7 @@ const KeysList = WDialog.extend({ value: (key) => operation.getPortal(key.id).name, sort: (a, b) => a.localeCompare(b), format: (cell, value, key) => { - cell.appendChild(operation.getPortal(key.id).displayFormat()); + cell.appendChild(PortalUI.displayFormat(operation.getPortal(key.id))); }, }, { @@ -114,7 +117,7 @@ const KeysList = WDialog.extend({ let gid = "no-user"; if (this._me) { - gid = this._me.GoogleID; + gid = this._me.id; this.sortable.fields = always.concat([ { name: wX("MY_COUNT"), @@ -184,9 +187,7 @@ const KeysList = WDialog.extend({ } for (const p of operation.markers.filter(function (marker) { - return ( - marker.type == window.plugin.wasabee.static.constants.MARKER_TYPE_KEY - ); + return marker.type == WasabeeMarker.constants.MARKER_TYPE_KEY; })) { const k = {}; k.id = p.portalId; diff --git a/src/code/dialogs/linkDialog.d.ts b/src/code/dialogs/linkDialog.d.ts new file mode 100644 index 000000000..52647e178 --- /dev/null +++ b/src/code/dialogs/linkDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; + +declare class LinkDialog extends WDialog {} +export default LinkDialog; diff --git a/src/code/dialogs/linkDialog.js b/src/code/dialogs/linkDialog.js index aab280908..0a735cb5a 100644 --- a/src/code/dialogs/linkDialog.js +++ b/src/code/dialogs/linkDialog.js @@ -1,8 +1,11 @@ import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; +import WasabeePortal from "../model/portal"; import { getSelectedOperation } from "../selectedOp"; import wX from "../wX"; +import PortalUI from "../ui/portal"; +import { displayError } from "../error"; + const LinkDialog = WDialog.extend({ statics: { TYPE: "linkDialog", @@ -37,24 +40,20 @@ const LinkDialog = WDialog.extend({ sourceButton.textContent = wX("SET"); this._sourceDisplay = L.DomUtil.create("span", "portal", container); if (this._source) { - this._sourceDisplay.appendChild( - this._source.displayFormat(this._smallScreen) - ); + this._sourceDisplay.appendChild(PortalUI.displayFormat(this._source)); } else { this._sourceDisplay.textContent = wX("NOT_SET"); } L.DomEvent.on(sourceButton, "click", (ev) => { L.DomEvent.stop(ev); - this._source = WasabeePortal.getSelected(); + this._source = PortalUI.getSelected(); if (this._source) { localStorage[window.plugin.wasabee.static.constants.LINK_SOURCE_KEY] = JSON.stringify(this._source); this._sourceDisplay.textContent = ""; - this._sourceDisplay.appendChild( - this._source.displayFormat(this._smallScreen) - ); + this._sourceDisplay.appendChild(PortalUI.displayFormat(this._source)); } else { - alert(wX("PLEASE_SELECT_PORTAL")); + displayError(wX("PLEASE_SELECT_PORTAL")); } }); @@ -62,81 +61,73 @@ const LinkDialog = WDialog.extend({ anchor1Label.textContent = wX("ANCHOR1"); const anchor1Button = L.DomUtil.create("button", "set", container); anchor1Button.textContent = wX("SET"); + const anchor1AddButton = L.DomUtil.create("button", "add", container); + anchor1AddButton.textContent = wX("ADD1"); + L.DomEvent.on(anchor1AddButton, "click", (ev) => { + L.DomEvent.stop(ev); + if (this._source && this._anchor1) { + const operation = getSelectedOperation(); + operation.addLink(this._source, this._anchor1, { + description: this._desc.value, + order: operation.nextOrder, + }); + } else { + displayError("Select both Source and Anchor 1"); + } + }); this._anchor1Display = L.DomUtil.create("span", "portal", container); if (this._anchor1) { - this._anchor1Display.appendChild( - this._anchor1.displayFormat(this._smallScreen) - ); + this._anchor1Display.appendChild(PortalUI.displayFormat(this._anchor1)); } else { this._anchor1Display.textContent = wX("NOT_SET"); } L.DomEvent.on(anchor1Button, "click", (ev) => { L.DomEvent.stop(ev); - this._anchor1 = WasabeePortal.getSelected(); + this._anchor1 = PortalUI.getSelected(); if (this._anchor1) { localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY] = JSON.stringify(this._anchor1); this._anchor1Display.textContent = ""; - this._anchor1Display.appendChild( - this._anchor1.displayFormat(this._smallScreen) - ); + this._anchor1Display.appendChild(PortalUI.displayFormat(this._anchor1)); } else { - alert(wX("PLEASE_SELECT_PORTAL")); + displayError(wX("PLEASE_SELECT_PORTAL")); } }); - const anchor1AddButton = L.DomUtil.create("button", "add", container); - anchor1AddButton.textContent = wX("ADD1"); - L.DomEvent.on(anchor1AddButton, "click", (ev) => { + + const anchor2Label = L.DomUtil.create("label", null, container); + anchor2Label.textContent = wX("ANCHOR2"); + const anchor2Button = L.DomUtil.create("button", "set", container); + anchor2Button.textContent = wX("SET"); + const anchor2AddButton = L.DomUtil.create("button", "add", container); + anchor2AddButton.textContent = wX("ADD2"); + L.DomEvent.on(anchor2AddButton, "click", (ev) => { L.DomEvent.stop(ev); - if (this._source && this._anchor1) { + if (this._source && this._anchor2) { const operation = getSelectedOperation(); - operation.addLink(this._source, this._anchor1, { + operation.addLink(this._source, this._anchor2, { description: this._desc.value, order: operation.nextOrder, }); } else { - alert("Select both Source and Anchor 1"); + displayError(wX("SEL_SRC_ANC2")); } }); - - const anchor2Label = L.DomUtil.create("label", null, container); - anchor2Label.textContent = wX("ANCHOR2"); - const anchor2Button = L.DomUtil.create("button", "set", container); - anchor2Button.textContent = wX("SET"); this._anchor2Display = L.DomUtil.create("span", "portal", container); if (this._anchor2) { - this._anchor2Display.appendChild( - this._anchor2.displayFormat(this._smallScreen) - ); + this._anchor2Display.appendChild(PortalUI.displayFormat(this._anchor2)); } else { this._anchor2Display.textContent = wX("NOT_SET"); } L.DomEvent.on(anchor2Button, "click", (ev) => { L.DomEvent.stop(ev); - this._anchor2 = WasabeePortal.getSelected(); + this._anchor2 = PortalUI.getSelected(); if (this._anchor2) { localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY] = JSON.stringify(this._anchor2); this._anchor2Display.textContent = ""; - this._anchor2Display.appendChild( - this._anchor2.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - const anchor2AddButton = L.DomUtil.create("button", "add", container); - anchor2AddButton.textContent = wX("ADD2"); - L.DomEvent.on(anchor2AddButton, "click", (ev) => { - L.DomEvent.stop(ev); - if (this._source && this._anchor2) { - const operation = getSelectedOperation(); - operation.addLink(this._source, this._anchor2, { - description: this._desc.value, - order: operation.nextOrder, - }); + this._anchor2Display.appendChild(PortalUI.displayFormat(this._anchor2)); } else { - alert(wX("SEL_SRC_ANC2")); + displayError(wX("PLEASE_SELECT_PORTAL")); } }); @@ -145,7 +136,7 @@ const LinkDialog = WDialog.extend({ button.textContent = wX("ADD_BUTTON_LINKS"); L.DomEvent.on(button, "click", (ev) => { L.DomEvent.stop(ev); - if (!this._source) alert(wX("SEL_SRC_PORT")); + if (!this._source) displayError(wX("SEL_SRC_PORT")); const operation = getSelectedOperation(); if (this._anchor1) { operation.addLink(this._source, this._anchor1, { diff --git a/src/code/dialogs/linkListDialog.d.ts b/src/code/dialogs/linkListDialog.d.ts new file mode 100644 index 000000000..23f07fd47 --- /dev/null +++ b/src/code/dialogs/linkListDialog.d.ts @@ -0,0 +1,12 @@ +import OperationChecklistDialog from "./checklist"; +import type { WDialogOptions } from "../leafletClasses"; +import type WasabeePortal from "../model/portal"; + +interface LinkListDialogOptions extends WDialogOptions { + portal: WasabeePortal; +} +declare class LinkListDialog extends OperationChecklistDialog { + options: LinkListDialogOptions; + constructor(options: LinkListDialogOptions); +} +export default LinkListDialog; diff --git a/src/code/dialogs/linkListDialog.js b/src/code/dialogs/linkListDialog.js index 85364e2c5..a21214afc 100644 --- a/src/code/dialogs/linkListDialog.js +++ b/src/code/dialogs/linkListDialog.js @@ -3,11 +3,17 @@ import wX from "../wX"; import { loadFaked } from "../uiCommands"; import { getSelectedOperation } from "../selectedOp"; +import PortalUI from "../ui/portal"; +import LinkUI from "../ui/link"; + const LinkListDialog = OperationChecklistDialog.extend({ statics: { TYPE: "linkListDialog", }, + SORTBY_KEY: "wasabee-linklist-sortby", + SORTASC_KEY: "wasabee-linklist-sortasc", + options: { usePane: true, // portal @@ -18,9 +24,10 @@ const LinkListDialog = OperationChecklistDialog.extend({ this, operation ); + fields[2].name = ""; const linkFields = [ { - name: "Length", + name: wX("dialog.link_list.length"), value: (link) => link.length(operation), format: (cell, data) => { cell.classList.add("length"); @@ -30,19 +37,19 @@ const LinkListDialog = OperationChecklistDialog.extend({ smallScreenHide: true, }, { - name: "Min Lvl", + name: wX("dialog.link_list.level"), title: wX("MIN_SRC_PORT_LVL"), value: (link) => link.length(operation), format: (cell, data, link) => { - cell.appendChild(link.minLevel(operation)); + cell.appendChild(LinkUI.minLevel(link, operation)); }, smallScreenHide: true, }, ]; - return fields.slice(0, 2).concat(linkFields, fields.slice(3)); + return fields.slice(0, 3).concat(linkFields, fields.slice(3)); }, - _displayDialog: function () { + _displayDialog: async function () { const operation = getSelectedOperation(); loadFaked(operation); const links = operation.getLinkListFromPortal(this.options.portal); @@ -51,16 +58,23 @@ const LinkListDialog = OperationChecklistDialog.extend({ ).length; const toCount = links.length - fromCount; - this.sortable = this.getListDialogContent(operation, links, 0, false); // defaults to sorting by op order + this.sortable = this.getListDialogContent( + operation, + links, + this.SORTBY_KEY, + this.SORTASC_KEY + ); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; + await this.sortable.done; + this.createDialog({ title: wX("LINKS2", { - portalName: this.options.portal.displayName, + portalName: PortalUI.displayName(this.options.portal), outgoing: fromCount, incoming: toCount, }), @@ -73,6 +87,7 @@ const LinkListDialog = OperationChecklistDialog.extend({ }, update: async function () { + if (!this.sortable) return; const operation = getSelectedOperation(); const links = operation.getLinkListFromPortal(this.options.portal); const fromCount = links.filter( @@ -82,14 +97,14 @@ const LinkListDialog = OperationChecklistDialog.extend({ this.sortable = this.getListDialogContent( operation, links, - this.sortable.sortBy, - this.sortable.sortAsc + this.SORTBY_KEY, + this.SORTASC_KEY ); await this.sortable.done; this.setContent(this.sortable.table); this.setTitle( wX("LINKS2", { - portalName: this.options.portal.displayName, + portalName: PortalUI.displayName(this.options.portal), outgoing: fromCount, incoming: toCount, }) diff --git a/src/code/dialogs/madrid.js b/src/code/dialogs/madrid.js deleted file mode 100644 index c90885b1a..000000000 --- a/src/code/dialogs/madrid.js +++ /dev/null @@ -1,402 +0,0 @@ -import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import { getSelectedOperation } from "../selectedOp"; -import { - getAllPortalsOnScreen, - testPortal, - clearAllLinks, -} from "../uiCommands"; -import wX from "../wX"; -import MultimaxDialog from "./multimaxDialog"; - -// now that the formerly external mm functions are in the class, some of the logic can be cleaned up -// to not require passing values around when we can get them from this.XXX -const MadridDialog = MultimaxDialog.extend({ - statics: { - TYPE: "madridDialog", - }, - - needWritePermission: true, - - // addHooks inherited from MultimaxDialog - _displayDialog: function () { - const container = L.DomUtil.create("div", "container"); - const description = L.DomUtil.create("div", "desc", container); - description.textContent = wX("SELECT_INSTRUCTIONS"); - - const anchorOneLabel = L.DomUtil.create("label", null, container); - anchorOneLabel.textContent = wX("ANCHOR1"); - const anchorOneButton = L.DomUtil.create("button", null, container); - anchorOneButton.textContent = wX("SET"); - this._anchorOneDisplay = L.DomUtil.create("span", null, container); - if (this._anchorOne) { - this._anchorOneDisplay.appendChild( - this._anchorOne.displayFormat(this._smallScreen) - ); - } else { - this._anchorOneDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorOneButton, "click", () => { - this._anchorOne = WasabeePortal.getSelected(); - if (this._anchorOne) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY] = - JSON.stringify(this._anchorOne); - this._anchorOneDisplay.textContent = ""; - this._anchorOneDisplay.appendChild( - this._anchorOne.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const setOneLabel = L.DomUtil.create("div", "set_label", container); - setOneLabel.textContent = wX("MADRID_SET_1"); - const setOneButton = L.DomUtil.create("button", null, container); - setOneButton.textContent = wX("SET"); - this._setOneDisplay = L.DomUtil.create("span", null, container); - if (this._portalSetOne) { - this._setOneDisplay.textContent = wX("PORTAL_COUNT", { - count: this._portalSetOne.length, - }); - } else { - this._setOneDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(setOneButton, "click", () => { - this._portalSetOne = getAllPortalsOnScreen(getSelectedOperation()); - // XXX this is not enough, need to cache them in case IITC purges them - this._setOneDisplay.textContent = wX("PORTAL_COUNT", { - count: this._portalSetOne.length, - }); - }); - - const anchorTwoLabel = L.DomUtil.create("label", null, container); - anchorTwoLabel.textContent = wX("ANCHOR2"); - const anchorTwoButton = L.DomUtil.create("button", null, container); - anchorTwoButton.textContent = wX("SET"); - this._anchorTwoDisplay = L.DomUtil.create("span", null, container); - if (this._anchorTwo) { - this._anchorTwoDisplay.appendChild( - this._anchorTwo.displayFormat(this._smallScreen) - ); - } else { - this._anchorTwoDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorTwoButton, "click", () => { - this._anchorTwo = WasabeePortal.getSelected(); - if (this._anchorTwo) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY] = - JSON.stringify(this._anchorTwo); - this._anchorTwoDisplay.textContent = ""; - this._anchorTwoDisplay.appendChild( - this._anchorTwo.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const setTwoLabel = L.DomUtil.create("div", "set_label", container); - setTwoLabel.textContent = wX("MADRID_SET_2"); - const setTwoButton = L.DomUtil.create("button", null, container); - setTwoButton.textContent = wX("SET"); - this._setTwoDisplay = L.DomUtil.create("span", null, container); - if (this._portalSetTwo) { - this._setTwoDisplay.textContent = wX("PORTAL_COUNT", { - count: this._portalSetTwo.length, - }); - } else { - this._setTwoDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(setTwoButton, "click", () => { - this._portalSetTwo = getAllPortalsOnScreen(getSelectedOperation()); - // XXX cache - this._setTwoDisplay.textContent = wX("PORTAL_COUNT", { - count: this._portalSetTwo.length, - }); - }); - - const anchorThreeLabel = L.DomUtil.create("label", null, container); - anchorThreeLabel.textContent = wX("ANCHOR3"); - const anchorThreeDisplay = L.DomUtil.create("span", null, container); - anchorThreeDisplay.textContent = "Auto-determined"; - - const setThreeLabel = L.DomUtil.create("div", "set_label", container); - setThreeLabel.textContent = wX("MADRID_SET_3"); - const setThreeButton = L.DomUtil.create("button", null, container); - setThreeButton.textContent = wX("SET"); - this._setThreeDisplay = L.DomUtil.create("span", null, container); - if (this._portalSetThree) { - this._setThreeDisplay.textContent = wX("PORTAL_COUNT", { - count: this._portalSetThree.length, - }); - } else { - this._setThreeDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(setThreeButton, "click", () => { - this._portalSetThree = getAllPortalsOnScreen(getSelectedOperation()); - // XXX cache - this._setThreeDisplay.textContent = wX("PORTAL_COUNT", { - count: this._portalSetThree.length, - }); - }); - - //Add backlinks after all the rest is set up - const fllabel = L.DomUtil.create("label", null, container); - fllabel.textContent = wX("ADD_BL"); - fllabel.htmlFor = "wasabee-madrid-backlink"; - this._flcheck = L.DomUtil.create("input", null, container); - this._flcheck.type = "checkbox"; - this._flcheck.id = "wasabee-madrid-backlink"; - - const balancedLabel = L.DomUtil.create("label", null, container); - balancedLabel.textContent = "Balanced"; - balancedLabel.htmlFor = "wasabee-madrid-balanced"; - this._balancedcheck = L.DomUtil.create("input", null, container); - this._balancedcheck.type = "checkbox"; - this._balancedcheck.id = "wasabee-madrid-balanced"; - - const newLine = L.DomUtil.create("label", "newline", container); - const dividerBeforeDraw = L.DomUtil.create("span", null, container); - newLine.textContent = "\u0000"; - dividerBeforeDraw.textContent = "\u0000"; - // dividerBeforeDraw.textContent = ""; - - const placeholder = L.DomUtil.create("label", "placeholder", container); - placeholder.textContent = "\u2063"; - // Go button - const button = L.DomUtil.create("button", "drawb", container); - button.textContent = wX("MADRID"); - L.DomEvent.on(button, "click", () => { - this._operation = getSelectedOperation(); - const total = this._balancedcheck.checked - ? this.doBalancedMadrid.call(this) - : this.doMadrid.call(this); - alert(`Madrid found ${total} layers`); - // this.closeDialog(); - }); - - const buttons = {}; - buttons[wX("CLOSE")] = () => { - this.closeDialog(); - }; - buttons[wX("CLEAR LINKS")] = () => { - clearAllLinks(getSelectedOperation()); - }; - - this.createDialog({ - title: wX("MADRID_TITLE"), - html: container, - width: "auto", - dialogClass: "madrid", - buttons: buttons, - id: window.plugin.wasabee.static.dialogNames.madrid, - }); - }, - - initialize: function (options) { - WDialog.prototype.initialize.call(this, options); - this.title = wX("MADRID"); - this.label = wX("MADRID"); - let p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; - if (p) this._anchorOne = new WasabeePortal(p); - p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY]; - if (p) this._anchorTwo = new WasabeePortal(p); - this._urp = testPortal(); - }, - - getSpine: function (pOne, pTwo, portals) { - const portalsMap = new Map(portals.map((p) => [p.id, p])); - const poset = this.buildPOSet(pOne, pTwo, portals); - const sequence = this.longestSequence(poset, null, (a, b) => - window.map.distance(portalsMap.get(a).latLng, portalsMap.get(b).latLng) - ); - - return sequence.map((id) => portalsMap.get(id)); - }, - - doBalancedMadrid: function () { - // Calculate the multimax - if ( - !this._anchorOne || - !this._anchorTwo || - !this._portalSetOne || - !this._portalSetTwo || - !this._portalSetThree - ) { - alert(wX("INVALID REQUEST")); - return 0; - } - - // the set 1 must contain anchor 1 (first back link) - if (this._portalSetOne.find((p) => this._anchorOne.id == p.id) == undefined) - this._portalSetOne.push(this._anchorOne); - // the set 2 must contain anchor 2 (first back link) - if (this._portalSetTwo.find((p) => this._anchorTwo.id == p.id) == undefined) - this._portalSetTwo.push(this._anchorTwo); - - const spineThree = this.getSpine( - this._anchorOne, - this._anchorTwo, - this._portalSetThree - ); - const lastThree = spineThree[spineThree.length - 1]; - - const spineOne = this.getSpine( - this._anchorTwo, - lastThree, - this._portalSetOne.filter( - (p) => - this._anchorOne.id == p.id || - this.fieldCoversPortal(this._anchorTwo, lastThree, p, this._anchorOne) - ) - ); - const lastOne = spineOne[spineOne.length - 1]; - - const spineTwo = this.getSpine( - lastThree, - lastOne, - this._portalSetTwo.filter( - (p) => - this._anchorTwo.id == p.id || - this.fieldCoversPortal(lastThree, lastOne, p, this._anchorTwo) - ) - ); - // const lastTwo = spineTwo[spineTwo.length - 1]; - - const spines = [spineOne, spineTwo, spineThree]; - const step = spines.map((s) => 1 / s.length); - - this._operation.startBatchMode(); - - // ignore order + direction - this._operation.addLink(spines[0][0], spines[1][0], { - description: "inner field", - }); - this._operation.addLink(spines[1][0], spines[2][0], { - description: "inner field", - }); - this._operation.addLink(spines[2][0], spines[0][0], { - description: "inner field", - }); - - const indices = [1, 1, 1]; - - while (indices.some((v, i) => v < spines[i].length)) { - let spineOrder = [0, 1, 2].sort( - (a, b) => indices[a] * step[a] - indices[b] * step[b] - ); - let p = spines[spineOrder[0]][indices[spineOrder[0]]]; - let pOne = spines[spineOrder[0]][indices[spineOrder[0]] - 1]; - let pTwo = spines[spineOrder[1]][indices[spineOrder[1]] - 1]; - let pThree = spines[spineOrder[2]][indices[spineOrder[2]] - 1]; - - // hackish, I have no proof of this working in all cases - for ( - let i = 0; - (!p || !this.fieldCoversPortal(p, pTwo, pThree, pOne)) && i < 3; - i++ - ) { - this._operation.setPortalComment(pOne, "point of disbalance"); - - spineOrder = [spineOrder[1], spineOrder[2], spineOrder[0]]; - p = spines[spineOrder[0]][indices[spineOrder[0]]]; - pOne = spines[spineOrder[0]][indices[spineOrder[0]] - 1]; - pTwo = spines[spineOrder[1]][indices[spineOrder[1]] - 1]; - pThree = spines[spineOrder[2]][indices[spineOrder[2]] - 1]; - } - if (!this.fieldCoversPortal(p, pTwo, pThree, pOne)) - console.log("well, this doesn't work here..."); - const toTwo = this._operation.addLink(p, pTwo, { description: "link" }); - const toThree = this._operation.addLink(p, pThree, { - description: "link", - }); - toTwo.zone = spineOrder[0] + 1; - toThree.zone = spineOrder[0] + 1; - - indices[spineOrder[0]] += 1; - } - - this._operation.endBatchMode(); - - return indices[0] + indices[1] + indices[2] - 2; - }, - - // fieldCoversPortal inherited from MultimaxDialog - // MM " - - doMadrid: function () { - // Calculate the multimax - if ( - !this._anchorOne || - !this._anchorTwo || - !this._portalSetOne || - !this._portalSetTwo || - !this._portalSetThree - ) { - alert(wX("INVALID REQUEST")); - return 0; - } - this._operation.startBatchMode(); // bypass save and crosslinks checks - this._operation.addLink(this._anchorOne, this._anchorTwo, { - description: "madrid base", - order: 1, - }); - - let len = 0; - const [len1, order1, last1] = this.MM( - this._anchorOne, - this._anchorTwo, - this._portalSetThree, - 1, - false, - "madrid protocol " - ); - len += len1; - - const newThree = last1; - // the set 1 must contain anchor 1 (first back link) - if (this._portalSetOne.find((p) => this._anchorOne.id == p.id) == undefined) - this._portalSetOne.push(this._anchorOne); - - const [len2, order2, last2] = this.MM( - this._anchorTwo, - newThree, - this._portalSetOne.filter( - (p) => - this._anchorOne.id == p.id || - this.fieldCoversPortal(this._anchorTwo, newThree, p, this._anchorOne) - ), - order1, - false, - "madrid protocol " - ); - len += len2 - 1; - - // _anchorOne is no longer useful, use last2 - const newOne = last2; - // the set 2 must contain anchor 2 (first back link) - if (this._portalSetTwo.find((p) => this._anchorTwo.id == p.id) == undefined) - this._portalSetTwo.push(this._anchorTwo); - - const len3 = this.MM( - newThree, - newOne, - this._portalSetTwo.filter( - (p) => - this._anchorTwo.id == p.id || - this.fieldCoversPortal(newThree, newOne, p, this._anchorTwo) - ), - order2, - false, - "madrid protocol " - )[0]; - len += len3 - 1; - - this._operation.endBatchMode(); // save and run crosslinks - - return len; - }, -}); - -export default MadridDialog; diff --git a/src/code/dialogs/manageTeamDialog.d.ts b/src/code/dialogs/manageTeamDialog.d.ts new file mode 100644 index 000000000..71c9d1a55 --- /dev/null +++ b/src/code/dialogs/manageTeamDialog.d.ts @@ -0,0 +1,11 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import { MeTeam } from "../model/me"; + +interface ManageTeamDialogOptions extends WDialogOptions { + team: MeTeam; +} +declare class ManageTeamDialog extends WDialog { + options: ManageTeamDialogOptions; + constructor(options: ManageTeamDialogOptions); +} +export default ManageTeamDialog; diff --git a/src/code/dialogs/manageTeamDialog.js b/src/code/dialogs/manageTeamDialog.js index 3b0e53e3b..2783d2d24 100644 --- a/src/code/dialogs/manageTeamDialog.js +++ b/src/code/dialogs/manageTeamDialog.js @@ -10,12 +10,16 @@ import { deleteJoinLinkPromise, createJoinLinkPromise, } from "../server"; -import WasabeeMe from "../me"; -import WasabeeTeam from "../team"; +import WasabeeMe from "../model/me"; +import WasabeeTeam from "../model/team"; import Sortable from "../sortable"; import PromptDialog from "./promptDialog"; import wX from "../wX"; import ConfirmDialog from "./confirmDialog"; +import { constants } from "../static"; + +import AgentUI from "../ui/agent"; +import { displayError, displayInfo } from "../error"; // The update method here is the best so far, bring all the others up to this one const ManageTeamDialog = WDialog.extend({ @@ -24,7 +28,7 @@ const ManageTeamDialog = WDialog.extend({ }, options: { - // team + // team : MeTeam }, addHooks: function () { @@ -40,25 +44,24 @@ const ManageTeamDialog = WDialog.extend({ window.map.off("wasabee:logout", this.closeDialog, this); }, - _setupTable: function () { + _setupTable: async function () { const table = new Sortable(); table.fields = [ { name: wX("AGENT"), - value: (agent) => agent.name, + value: (agent) => agent.getName(), sort: (a, b) => a.localeCompare(b), - format: async (cell, value, agent) => - cell.appendChild(await agent.formatDisplay(this.options.team.id)), + format: (cell, value, agent) => + cell.appendChild(AgentUI.formatDisplay(agent)), }, { name: wX("TEAM STATE"), - value: (agent) => agent.state, + value: (agent) => agent.shareLocation, sort: (a, b) => a && !b, - // , format: (cell, value) => (cell.textContent = value) }, { - name: wX("SQUAD"), - value: (agent) => agent.squad, + name: wX("COMMENT"), + value: (agent) => agent.comment, sort: (a, b) => a.localeCompare(b), format: (cell, value, obj) => { const button = L.DomUtil.create("a", null, cell); @@ -66,27 +69,22 @@ const ManageTeamDialog = WDialog.extend({ L.DomEvent.on(button, "click", (ev) => { L.DomEvent.stop(ev); const squadDialog = new PromptDialog({ - title: `Set Squad for ${obj.name}`, - label: "Squad", + title: wX("dialog.agent_comment.title", { agentName: obj.name }), + label: wX("dialog.agent_comment.text"), callback: async () => { - if (squadDialog.inputField.value) { - try { - await setAgentTeamSquadPromise( - obj.id, - this.options.team.ID, - squadDialog.inputField.value - ); - alert( - `squad updated to ${squadDialog.inputField.value} for ${obj.name}` - ); - } catch (e) { - console.error(e); - alert(e.toString()); - } - } else { - alert(wX("INPUT_SQUAD_NAME")); + try { + await setAgentTeamSquadPromise( + obj.id, + this.options.team.ID, + squadDialog.inputField.value + ); + // refresh team data + await WasabeeTeam.get(this.options.team.ID, 0); + window.map.fire("wasabee:team:update"); + } catch (e) { + console.error(e); + displayError(e); } - this.update(); }, current: value, placeholder: "boots", @@ -105,12 +103,17 @@ const ManageTeamDialog = WDialog.extend({ L.DomEvent.on(button, "click", (ev) => { L.DomEvent.stop(ev); const con = new ConfirmDialog({ - title: `${button.textContent}: ${obj.name}`, - label: `${button.textContent}: ${obj.name}?`, + title: wX("dialog.remove_agent.title", { agentName: obj.name }), + label: wX("dialog.remove_agent.text", { + agentName: obj.name, + teamName: this.options.team.Name, + }), type: "agent", callback: async () => { try { await removeAgentFromTeamPromise(value, this.options.team.ID); + // refresh team data + await WasabeeTeam.get(this.options.team.ID, 0); } catch (e) { console.error(e); } @@ -124,8 +127,7 @@ const ManageTeamDialog = WDialog.extend({ ]; table.sortBy = 0; - // async populate - this._refreshTeam(table); + await this._refreshTeam(table); return table; }, @@ -134,7 +136,7 @@ const ManageTeamDialog = WDialog.extend({ try { // max 5 seconds cache for this screen const teamdata = await WasabeeTeam.get(this.options.team.ID, 5); - const agents = teamdata.getAgents(); + const agents = teamdata.agents; if (agents && agents.length > 0) { table.items = agents; } @@ -143,19 +145,23 @@ const ManageTeamDialog = WDialog.extend({ } }, - update: function () { - const container = this._dialogContent(); // build the UI + update: async function () { + const container = await this._dialogContent(); // build the UI // this is the correct way to change out a dialog's contents, audit the entire codebase making this change this.setContent(container); this.setTitle(wX("MANAGE_TEAM", { teamName: this.options.team.Name })); }, - _dialogContent: function () { + _dialogContent: async function () { const container = L.DomUtil.create("div", "container"); const list = L.DomUtil.create("div", "list", container); - const table = this._setupTable(); + const table = await this._setupTable(); list.appendChild(table.table); + await table.done; + + const team = await WasabeeTeam.get(this.options.team.ID); + this.options.team.Name = team.name; const addlabel = L.DomUtil.create("label", null, container); addlabel.textContent = wX("ADD_AGENT"); @@ -167,11 +173,13 @@ const ManageTeamDialog = WDialog.extend({ L.DomEvent.stop(ev); try { await addAgentToTeamPromise(addField.value, this.options.team.ID); - alert(wX("ADD_SUCC_INSTR")); + // refresh team data + await WasabeeTeam.get(this.options.team.ID, 0); + displayInfo(wX("ADD_SUCC_INSTR")); window.map.fire("wasabee:team:update"); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } }); @@ -179,19 +187,19 @@ const ManageTeamDialog = WDialog.extend({ renamelabel.textContent = wX("RENAME_TEAM"); const renameField = L.DomUtil.create("input", null, container); renameField.placeholder = wX("BAT_TOAD"); - renameField.value = this.options.team.Name; + renameField.value = team.name; const renameButton = L.DomUtil.create("button", null, container); renameButton.textContent = wX("RENAME"); L.DomEvent.on(renameButton, "click", async (ev) => { L.DomEvent.stop(ev); try { - await renameTeamPromise(this.options.team.ID, renameField.value); - alert(`renamed to ${renameField.value}`); - this.options.team.Name = renameField.value; // for display + await renameTeamPromise(team.id, renameField.value); + // refresh team data + await WasabeeTeam.get(this.options.team.ID, 0); window.map.fire("wasabee:team:update"); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } }); @@ -199,59 +207,52 @@ const ManageTeamDialog = WDialog.extend({ rockslabel.textContent = wX("ROCKS_COM"); const rockscommField = L.DomUtil.create("input", null, container); rockscommField.placeholder = "xxyyzz.com"; - if (this.options.team.RocksComm) - rockscommField.value = this.options.team.RocksComm; + if (team.rc) rockscommField.value = team.rc; const rocksapilabel = L.DomUtil.create("label", null, container); rocksapilabel.textContent = wX("API_KEY"); const rocksapiField = L.DomUtil.create("input", null, container); rocksapiField.placeholder = "..."; - if (this.options.team.RocksKey) - rocksapiField.value = this.options.team.RocksKey; + if (team.rk) rocksapiField.value = team.rk; const rocksButton = L.DomUtil.create("button", null, container); rocksButton.textContent = wX("SET"); L.DomEvent.on(rocksButton, "click", async (ev) => { L.DomEvent.stop(ev); try { - await rocksPromise( - this.options.team.ID, - rockscommField.value, - rocksapiField.value - ); - alert("updated rocks info"); - this.options.team.RocksComm = rockscommField.value; // for display - this.options.team.RocksKey = rocksapiField.value; // for display + await rocksPromise(team.id, rockscommField.value, rocksapiField.value); + displayInfo("updated rocks info"); this.update(); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } }); const joinlinklabel = L.DomUtil.create("label", null, container); - joinlinklabel.textContent = "Join Link"; - if (this.options.team.JoinLinkToken != "") { + joinlinklabel.textContent = wX("dialog.team_manage.join_link"); + if (team.jlt) { const joinlink = L.DomUtil.create("input", null, container); const server = GetWasabeeServer(); - joinlink.value = `${server}/api/v1/team/${this.options.team.ID}/join/${this.options.team.JoinLinkToken}`; + joinlink.value = L.Util.template(constants.JOIN_TEAM_TEMPLATE, { + server: server, + teamid: team.id, + token: team.jlt, + }); joinlink.readOnly = true; L.DomEvent.on(joinlink, "click", (ev) => ev.target.select()); const joinlinkdel = L.DomUtil.create("button", null, container); - joinlinkdel.textContent = "Revoke"; + joinlinkdel.textContent = wX("dialog.team_manage.join_link.revoke"); L.DomEvent.on(joinlinkdel, "click", async (ev) => { L.DomEvent.stop(ev); - await deleteJoinLinkPromise(this.options.team.ID); - this.options.team.JoinLinkToken = ""; + await deleteJoinLinkPromise(team.id); this.update(); }); } else { - L.DomUtil.create("span", null, container).textContent = "not set"; + L.DomUtil.create("span", null, container).textContent = wX("NOT_SET"); const joinlinkadd = L.DomUtil.create("button", null, container); - joinlinkadd.textContent = "Create"; + joinlinkadd.textContent = wX("dialog.team_manage.join_link.create"); L.DomEvent.on(joinlinkadd, "click", async (ev) => { L.DomEvent.stop(ev); - const response = await createJoinLinkPromise(this.options.team.ID); - const j = JSON.parse(response); - this.options.team.JoinLinkToken = j.Key; + await createJoinLinkPromise(team.id); this.update(); }); } @@ -264,20 +265,19 @@ const ManageTeamDialog = WDialog.extend({ L.DomEvent.stop(ev); const cd = new ConfirmDialog({ title: wX("REMOVE_TEAM_CONFIRM_TITLE", { - teamName: this.options.team.Name, + teamName: team.name, }), label: wX("REMOVE_TEAM_CONFIRM_LABEL", { - teamName: this.options.team.Name, + teamName: team.name, }), callback: async () => { try { - await deleteTeamPromise(this.options.team.ID); - alert(`${this.options.team.Name} removed`); + await deleteTeamPromise(team.id); this.closeDialog(); await WasabeeMe.waitGet(true); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } window.map.fire("wasabee:teams"); }, @@ -285,24 +285,11 @@ const ManageTeamDialog = WDialog.extend({ cd.enable(); }); - if (this.options.team.jkt) { - const joinLinkLabel = L.DomUtil.create("label", null, container); - joinLinkLabel.textContent = wX("JOIN_LINK"); - const joinLink = L.DomUtil.create("a", null, container); - const jl = - GetWasabeeServer() + - "/api/v1/team/" + - this.options.team.ID + - "/join/" + - this.options.team.jkt; - joinLink.href = jl; - joinLink.textContent = jl; - } return container; }, - _displayDialog: function () { - const container = this._dialogContent(); + _displayDialog: async function () { + const container = await this._dialogContent(); const buttons = {}; buttons[wX("CLOSE")] = () => { this.closeDialog(); diff --git a/src/code/dialogs/markerAddDialog.d.ts b/src/code/dialogs/markerAddDialog.d.ts new file mode 100644 index 000000000..7d6b926d5 --- /dev/null +++ b/src/code/dialogs/markerAddDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class MarkerAddDialog extends WDialog {} +export default MarkerAddDialog; diff --git a/src/code/dialogs/markerAddDialog.js b/src/code/dialogs/markerAddDialog.js index 8233595a8..a088076f0 100644 --- a/src/code/dialogs/markerAddDialog.js +++ b/src/code/dialogs/markerAddDialog.js @@ -1,10 +1,14 @@ import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import WasabeeMe from "../me"; -import WasabeeTeam from "../team"; +import WasabeeMe from "../model/me"; +import WasabeeTeam from "../model/team"; +import WasabeeMarker from "../model/marker"; +import WasabeeBlocker from "../model/blocker"; import { getSelectedOperation } from "../selectedOp"; import wX from "../wX"; +import PortalUI from "../ui/portal"; +import { displayError } from "../error"; + const MarkerAddDialog = WDialog.extend({ statics: { TYPE: "markerButton", @@ -29,13 +33,31 @@ const MarkerAddDialog = WDialog.extend({ }, update: async function () { - this._type.innerHTML = ""; + // updating with a new portal selected and in bulk mode? + if ( + this._selectedPortal && + PortalUI.getSelected() && + this._selectedPortal.id != PortalUI.getSelected().id && + this._bulk.checked + ) { + this._selectedPortal = PortalUI.getSelected(); + if (WasabeeMarker.markerTypes.has(this._type.value)) + await this._addMarker( + this._type.value, + this._comment.value, + this._zones.value, + this._assign.value + ); + return; + } + + this._type.textContent = ""; // zones can be populated even if portal not selected - this._zones.innerHTML = ""; // do we need to do this every time? the zone list can change while this dialog is open. + this._zones.textContent = ""; // do we need to do this every time? the zone list can change while this dialog is open. const zoneAll = L.DomUtil.create("option", null, this._zones); zoneAll.value = 0; - zoneAll.textContent = "All"; // wX this + zoneAll.textContent = wX("dialog.common.zone_all"); for (const z of getSelectedOperation().zones) { const o = L.DomUtil.create("option", null, this._zones); o.value = z.id; @@ -43,25 +65,22 @@ const MarkerAddDialog = WDialog.extend({ } // clean and rebuild - this._assign.innerHTML = ""; - await this._getAgentMenu(this._assign); + const options = await this._getAgentMenu(); + this._assign.textContent = ""; + for (const option of options) { + this._assign.appendChild(option); + } - this._selectedPortal = WasabeePortal.getSelected(); + this._selectedPortal = PortalUI.getSelected(); if (this._selectedPortal) { this._portal.textContent = ""; this._portal.textContent = ""; - this._portal.appendChild( - this._selectedPortal.displayFormat(this._smallScreen) - ); + this._portal.appendChild(PortalUI.displayFormat(this._selectedPortal)); this._zones.value = getSelectedOperation().determineZone( this._selectedPortal.latLng ); - const markers = getSelectedOperation().getPortalMarkers( - this._selectedPortal - ); - let defaultType = window.plugin.wasabee.static.constants.DEFAULT_MARKER_TYPE; if ( @@ -71,14 +90,11 @@ const MarkerAddDialog = WDialog.extend({ defaultType = localStorage[window.plugin.wasabee.static.constants.LAST_MARKER_KEY]; } - defaultType = markers.has(defaultType) ? null : defaultType; - for (const k of window.plugin.wasabee.static.markerTypes) { + for (const k of WasabeeMarker.markerTypes) { const o = L.DomUtil.create("option", null, this._type); o.value = k; o.textContent = wX(k); - if (markers.has(k)) o.disabled = true; - else if (!defaultType) defaultType = k; } this._type.value = defaultType; } else { @@ -103,6 +119,11 @@ const MarkerAddDialog = WDialog.extend({ L.DomUtil.create("label", null, content).textContent = wX("AGENT"); this._assign = L.DomUtil.create("select", null, content); + L.DomUtil.create("label", null, content).textContent = wX("ADD_BULK"); + const bulk = L.DomUtil.create("div", "bulk", content); + this._bulk = L.DomUtil.create("input", "checkbox-input", bulk); + this._bulk.type = "checkbox"; + this._comment = L.DomUtil.create("input", null, content); this._comment.placeholder = wX("SET_COMMENT"); @@ -113,7 +134,7 @@ const MarkerAddDialog = WDialog.extend({ L.DomEvent.on(addMarkerButton, "click", (ev) => { L.DomEvent.stop(ev); - if (window.plugin.wasabee.static.markerTypes.has(this._type.value)) + if (WasabeeMarker.markerTypes.has(this._type.value)) this._addMarker( this._type.value, this._comment.value, @@ -123,7 +144,7 @@ const MarkerAddDialog = WDialog.extend({ }); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -147,21 +168,26 @@ const MarkerAddDialog = WDialog.extend({ }; // XXX remove comment from args in 0.20 - operation.addMarker(selectedType, WasabeePortal.getSelected(), options); - await this.update(); - localStorage[window.plugin.wasabee.static.constants.LAST_MARKER_KEY] = - selectedType; + if (operation.addMarker(selectedType, PortalUI.getSelected(), options)) { + localStorage[window.plugin.wasabee.static.constants.LAST_MARKER_KEY] = + selectedType; + if (WasabeeMarker.isDestructMarkerType(selectedType)) + WasabeeBlocker.removeBlocker(operation, PortalUI.getSelected().id); + await this.update(); + } else displayError(wX("ALREADY_HAS_MARKER")); }, - _getAgentMenu: async function (menu) { - let option = menu.appendChild(L.DomUtil.create("option", null)); + _getAgentMenu: async function () { + const options = []; + const option = L.DomUtil.create("option", null); option.value = ""; option.textContent = wX("UNASSIGNED"); + options.push(option); - if (!WasabeeMe.isLoggedIn()) return; + if (!WasabeeMe.isLoggedIn()) return options; const operation = getSelectedOperation(); - if (!operation.isOnCurrentServer()) return; + if (!operation.isOnCurrentServer()) return options; const alreadyAdded = new Set(); const me = await WasabeeMe.waitGet(); @@ -170,20 +196,20 @@ const MarkerAddDialog = WDialog.extend({ try { // allow teams to be 5 minutes cached const tt = await WasabeeTeam.get(t.teamid, 5 * 60); - const agents = tt.getAgents(); - for (const a of agents) { + for (const a of tt.agents) { if (!alreadyAdded.has(a.id)) { alreadyAdded.add(a.id); - option = L.DomUtil.create("option"); + const option = L.DomUtil.create("option"); option.value = a.id; - option.textContent = a.name; - menu.appendChild(option); + option.textContent = a.getName(); + options.push(option); } } } catch (e) { console.error(e); } } + return options; }, }); diff --git a/src/code/dialogs/markerChangeDialog.d.ts b/src/code/dialogs/markerChangeDialog.d.ts new file mode 100644 index 000000000..773648b1b --- /dev/null +++ b/src/code/dialogs/markerChangeDialog.d.ts @@ -0,0 +1,11 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import WasabeeMarker from "../model/marker"; + +interface MarkerChangeDialogOptions extends WDialogOptions { + marker: WasabeeMarker; +} +declare class MarkerChangeDialog extends WDialog { + options: MarkerChangeDialogOptions; + constructor(options: MarkerChangeDialogOptions); +} +export default MarkerChangeDialog; diff --git a/src/code/dialogs/markerChangeDialog.js b/src/code/dialogs/markerChangeDialog.js index aa2788ec1..7f0145183 100644 --- a/src/code/dialogs/markerChangeDialog.js +++ b/src/code/dialogs/markerChangeDialog.js @@ -1,6 +1,10 @@ import { WDialog } from "../leafletClasses"; import wX from "../wX"; import { getSelectedOperation } from "../selectedOp"; +import WasabeeMarker from "../model/marker"; +import WasabeeBlocker from "../model/blocker"; + +import PortalUI from "../ui/portal"; const MarkerChangeDialog = WDialog.extend({ statics: { @@ -25,31 +29,30 @@ const MarkerChangeDialog = WDialog.extend({ const portal = operation.getPortal(this.options.marker.portalId); const portalDisplay = L.DomUtil.create("div", "portal", content); - portalDisplay.appendChild(portal.displayFormat(this._smallScreen)); + portalDisplay.appendChild(PortalUI.displayFormat(portal)); this._type = L.DomUtil.create("select", null, content); - const markers = operation.getPortalMarkers(portal); - for (const k of window.plugin.wasabee.static.markerTypes) { + for (const k of WasabeeMarker.markerTypes) { const o = L.DomUtil.create("option", null, this._type); o.value = k; o.textContent = wX(k); - if (markers.has(k) && k != this.options.marker.type) o.disabled = true; } this._type.value = this.options.marker.type; const buttons = {}; buttons[wX("OK")] = () => { - if ( - window.plugin.wasabee.static.markerTypes.has(this._type.value) && - !markers.has(this._type.value) - ) { + if (WasabeeMarker.markerTypes.has(this._type.value)) { + operation.startBatchMode(); operation.removeMarker(this.options.marker); operation.addMarker(this._type.value, portal, { zone: this.options.marker.zone, comment: this.options.marker.comment, assign: this.options.marker.assignedTo, }); + if (WasabeeMarker.isDestructMarkerType(this._type.value)) + WasabeeBlocker.removeBlocker(operation, portal.id); + operation.endBatchMode(); } this.closeDialog(); }; diff --git a/src/code/dialogs/markerList.d.ts b/src/code/dialogs/markerList.d.ts new file mode 100644 index 000000000..01f8fd582 --- /dev/null +++ b/src/code/dialogs/markerList.d.ts @@ -0,0 +1,4 @@ +import OperationChecklistDialog from "./checklist"; + +declare class MarkerList extends OperationChecklistDialog {} +export default MarkerList; diff --git a/src/code/dialogs/markerList.js b/src/code/dialogs/markerList.js index 461583125..0da9cd4a2 100644 --- a/src/code/dialogs/markerList.js +++ b/src/code/dialogs/markerList.js @@ -8,25 +8,31 @@ const MarkerList = OperationChecklistDialog.extend({ TYPE: "markerList", }, - _displayDialog: function () { + SORTBY_KEY: "wasabee-markerlist-sortby", + SORTASC_KEY: "wasabee-markerlist-sortasc", + + _displayDialog: async function () { const operation = getSelectedOperation(); loadFaked(operation); + this.sortable = this.getListDialogContent( operation, operation.markers, - 0, - false - ); // defaults to sorting by op order + this.SORTBY_KEY, + this.SORTASC_KEY + ); const buttons = {}; buttons[wX("CLEAR MARKERS")] = () => { clearAllMarkers(getSelectedOperation()); }; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; + await this.sortable.done; + this.createDialog({ title: wX("MARKER_LIST", { opName: operation.name }), html: this.sortable.table, @@ -38,13 +44,14 @@ const MarkerList = OperationChecklistDialog.extend({ }, update: async function () { + if (!this.sortable) return; const operation = getSelectedOperation(); this.setTitle(wX("MARKER_LIST", { opName: operation.name })); this.sortable = this.getListDialogContent( operation, operation.markers, - this.sortable.sortBy, - this.sortable.sortAsc + this.SORTBY_KEY, + this.SORTASC_KEY ); await this.sortable.done; this.setContent(this.sortable.table); diff --git a/src/code/dialogs/mergeDialog.d.ts b/src/code/dialogs/mergeDialog.d.ts new file mode 100644 index 000000000..ad6ec167e --- /dev/null +++ b/src/code/dialogs/mergeDialog.d.ts @@ -0,0 +1,14 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import WasabeeOp from "../model/operation"; +interface MergeDialogOptions extends WDialogOptions { + title?: string; + opOwn: WasabeeOp; + opRemote: WasabeeOp; + updateCallback?: (op: WasabeeOp) => void; + cancelText?: string; +} +declare class MergeDialog extends WDialog { + options: MergeDialogOptions; + constructor(options: MergeDialogOptions); +} +export default MergeDialog; diff --git a/src/code/dialogs/mergeDialog.js b/src/code/dialogs/mergeDialog.js index d14a7d202..221af0ced 100644 --- a/src/code/dialogs/mergeDialog.js +++ b/src/code/dialogs/mergeDialog.js @@ -1,10 +1,15 @@ import { WDialog } from "../leafletClasses"; import wX from "../wX"; -import WasabeeAgent from "../agent"; -import WasabeeOp from "../operation"; -import Sortable from "../sortable"; +import WasabeeAgent from "../model/agent"; +import WasabeeOp from "../model/operation"; import { getSelectedOperation, makeSelectedOperation } from "../selectedOp"; -import { drawBackgroundOp } from "../mapDrawing"; + +import { computeRebaseChanges, applyRebaseChanges } from "../model/changes"; + +import PortalUI from "../ui/portal"; +import LinkUI from "../ui/link"; +import MarkerUI from "../ui/marker"; +import { sanitizeState } from "../model/task"; const MergeDialog = WDialog.extend({ statics: { @@ -15,7 +20,8 @@ const MergeDialog = WDialog.extend({ // title // opOwn // opRemote - // updateCallback + // updateCallback? + // cancelText? }, addHooks: function () { @@ -30,7 +36,8 @@ const MergeDialog = WDialog.extend({ this._layer.remove(); }, - rebase: async function () { + rebase: async function (changes) { + applyRebaseChanges(this._opRebase, this.options.opOwn, changes); await this._opRebase.store(); if (getSelectedOperation().ID == this._opRebase.ID) await makeSelectedOperation(this._opRebase.ID); @@ -40,8 +47,6 @@ const MergeDialog = WDialog.extend({ }, useServer: async function () { - // merge blockers and related portals - this.options.opRemote.mergeBlockers(this.options.opOwn); await this.options.opRemote.store(); if (getSelectedOperation().ID == this.options.opRemote.ID) await makeSelectedOperation(this.options.opRemote.ID); @@ -57,66 +62,173 @@ const MergeDialog = WDialog.extend({ _displayDialog: function () { this._opRebase = new WasabeeOp(this.options.opRemote); - const origin = new WasabeeOp(this.options.opOwn.fetchedOp); - const changes = this.options.opOwn.changes(origin); - const summary = this._opRebase.applyChanges(changes, this.options.opOwn); - this._opRebase.cleanAll(); - this._opRebase.remoteChanged = this.options.opOwn.remoteChanged; - this._opRebase.localchanged = this.options.opOwn.localchanged; + this._origin = this.options.opOwn.getFetchedOp() + ? new WasabeeOp(this.options.opOwn.getFetchedOp()) + : new WasabeeOp({ + // dummy op + ID: this.options.opOwn.ID, + name: this.options.opOwn.name, + comment: this.options.opOwn.comment, + color: this.options.opOwn.color, + referencetime: this.options.opOwn.referencetime, + }); + const changes = computeRebaseChanges( + this._origin, + this._opRebase, + this.options.opOwn + ); + console.debug(changes); + const conflicts = []; - const remoteChanges = this.options.opRemote.changes(origin); - const rebaseChanges = this._opRebase.changes(origin); + for (const pc of changes.portals.conflict) { + if (pc.type === "edition/edition") { + conflicts.push({ + kind: "portal", + conflict: pc, + masterValue: this._opRebase.getPortal(pc.id), + followerValue: this.options.opOwn.getPortal(pc.id), + }); + } + } + for (const zc of changes.zones.conflict) { + if (zc.type === "edition/edition") { + conflicts.push({ + kind: "zone", + conflict: zc, + masterValue: this._opRebase.getZone(zc.id), + followerValue: this.options.opOwn.getZone(zc.id), + }); + } + } + // don't show double addition, caused by old export + for (const mc of changes.markers.conflict) { + if (mc.type !== "addition/addition") { + conflicts.push({ + kind: "marker", + conflict: mc, + masterValue: this._opRebase.getMarker(mc.id), + followerValue: this.options.opOwn.getMarker(mc.id), + }); + } + } + for (const lc of changes.links.conflict) { + if (lc.type !== "addition/addition") { + conflicts.push({ + kind: "link", + conflict: lc, + masterValue: this._opRebase.getLinkById(lc.id), + followerValue: this.options.opOwn.getLinkById(lc.id), + }); + } + } - // if nothing was deleted on the server, - // and if portal swaps do not end up to 1-portal link - // auto merge - if ( - remoteChanges.deletion.length === 0 && - summary.edition.singlePortalLink === 0 - ) { - this.rebase(); + if (conflicts.length === 0) { + this.rebase(changes); return; } - const style = { - dashArray: [2, 8], - opacity: 0.86, - weight: 4, - color: "blue", - interactive: false, - }; - drawBackgroundOp(this._opRebase, this._layer, style); - const content = L.DomUtil.create("div", "container"); const desc = L.DomUtil.create("div", "desc", content); - desc.textContent = wX("MERGE_MESSAGE", { opName: this.options.opOwn.name }); - content.appendChild(this.formatSummary(summary)); + desc.textContent = wX("MERGE_MESSAGE"); - const details = L.DomUtil.create("div", "details", content); - { - const div = L.DomUtil.create("div", "local", details); - div.innerHTML = "" + wX("MERGE_CHANGES_LOCAL") + ""; - div.appendChild(this.formatChanges(changes, origin, this.options.opOwn)); - } - { - const div = L.DomUtil.create("div", "merge", details); - div.innerHTML = "" + wX("MERGE_CHANGES_MERGE") + ""; - div.appendChild( - this.formatChanges(rebaseChanges, origin, this._opRebase) + L.DomUtil.create("h3", "", content).textContent = wX( + "dialog.merge.conflicts" + ); + + const details = L.DomUtil.create("table", "conflicts", content); + const head = L.DomUtil.create("tr", "", details); + // master head + const masterHead = L.DomUtil.create("th", "master", head); + masterHead.textContent = wX("dialog.merge.server"); + const masterRadioHead = L.DomUtil.create( + "input", + "", + L.DomUtil.create("th", "master", head) + ); + masterRadioHead.type = "radio"; + masterRadioHead.name = this.options.opOwn.ID; + // follower head + const followerRadioHead = L.DomUtil.create( + "input", + "", + L.DomUtil.create("th", "follower", head) + ); + followerRadioHead.type = "radio"; + followerRadioHead.name = this.options.opOwn.ID; + const followerHead = L.DomUtil.create("th", "follower", head); + followerHead.textContent = wX("dialog.merge.local"); + + L.DomEvent.on(masterRadioHead, "change", () => { + if (masterRadioHead.checked) { + details + .querySelectorAll("td.master input") + .forEach((el) => (el.checked = true)); + for (const c of conflicts) c.conflict.value = c.masterValue; + } + }); + L.DomEvent.on(followerRadioHead, "change", () => { + if (followerRadioHead.checked) { + details + .querySelectorAll("td.follower input") + .forEach((el) => (el.checked = true)); + for (const c of conflicts) c.conflict.value = c.followerValue; + } + }); + + for (const c of conflicts) { + const row = L.DomUtil.create("tr", "", details); + // master props + this.formatConflict( + c, + c.conflict.master, + this._opRebase, + L.DomUtil.create("td", "master", row) ); - } - { - const div = L.DomUtil.create("div", "server", details); - div.innerHTML = "" + wX("MERGE_CHANGES_REMOTE") + ""; - div.appendChild( - this.formatChanges(remoteChanges, origin, this.options.opRemote) + // master radio + const masterRadio = L.DomUtil.create( + "input", + "", + L.DomUtil.create("td", "master", row) + ); + masterRadio.type = "radio"; + masterRadio.name = c.conflict.id; + masterRadio.value = "master"; + masterRadio.checked = true; + // follower radio + const followerRadio = L.DomUtil.create( + "input", + "", + L.DomUtil.create("td", "follower", row) ); + followerRadio.type = "radio"; + followerRadio.name = c.conflict.id; + followerRadio.value = "master"; + // follower props + this.formatConflict( + c, + c.conflict.follower, + this.options.opOwn, + L.DomUtil.create("td", "follower", row) + ); + + L.DomEvent.on(masterRadio, "change", () => { + if (masterRadio.checked) { + c.conflict.value = c.masterValue; + followerRadioHead.checked = false; + } + }); + L.DomEvent.on(followerRadio, "change", () => { + if (followerRadio.checked) { + c.conflict.value = c.followerValue; + masterRadioHead.checked = false; + } + }); } const buttons = []; buttons.push({ text: wX("MERGE_REBASE"), - click: () => this.rebase(), + click: () => this.rebase(changes), }); buttons.push({ text: wX("MERGE_REPLACE"), @@ -126,10 +238,12 @@ const MergeDialog = WDialog.extend({ text: wX("MERGE_LOCAL"), click: () => this.useLocal(), }); - buttons.push({ - text: wX("CANCEL"), - click: () => this.closeDialog(), - }); + if (this.options.updateCallback || this.options.cancelText) { + buttons.push({ + text: this.options.cancelText || wX("CANCEL"), + click: () => this.closeDialog(), + }); + } this.createDialog({ title: this.options.title || wX("MERGE_TITLE"), html: content, @@ -139,151 +253,115 @@ const MergeDialog = WDialog.extend({ }); }, - formatSummary: function (summary) { - // wX - const list = []; - if (!summary.compatibility.ok) - list.push( - `old OP detected, merge ${summary.compatibility.rewrite.link} links and ${summary.compatibility.rewrite.marker} markers` - ); - if ( - summary.addition.link + summary.addition.marker + summary.addition.zone > - 0 - ) - list.push( - `add ${summary.addition.link} links, ${summary.addition.marker} markers and ${summary.addition.zone} zones` - ); - if (summary.addition.ignored > 0) - list.push( - `ignore ${summary.addition.ignored} new portals/links/markers already present on remote` - ); - if (summary.deletion.link + summary.deletion.marker > 0) - list.push( - `delete ${summary.deletion.link} links and ${summary.deletion.marker} markers` - ); - if ( - summary.edition.portal + summary.edition.link + summary.edition.marker > - 0 - ) - list.push( - `edit ${summary.edition.portal} portals, ${summary.edition.link} links and ${summary.edition.marker} markers` - ); - if (summary.edition.duplicate > 0) - list.push(`ignore ${summary.edition.duplicate} new duplicates`); - if (summary.edition.removed > 0) - list.push( - `ignore ${summary.edition.removed} links and markers removed from remote` - ); - if (summary.edition.singlePortalLink > 0) - list.push( - `delete ${summary.edition.singlePortalLink} single portal links` - ); - if (summary.edition.assignment > 0) - list.push(`change ${summary.edition.assignment} assignments`); - - const rebaseMessage = L.DomUtil.create("div"); - rebaseMessage.append("Rebase summary:"); - - if (list.length > 0) { - const rebaseList = L.DomUtil.create("ul", null, rebaseMessage); - for (const item of list) - L.DomUtil.create("li", null, rebaseList).textContent = item; - } else { - rebaseMessage.textContent = - "The local changes don't alter the server version."; + formatConflict(conflict, change, op, container) { + // fail safe for now + try { + if (conflict.kind === "link") { + const link = this._origin.getLinkById(change.id); + const linkDisplay = LinkUI.displayFormat(link, this._origin); + container.appendChild(linkDisplay); + if (change.type === "deletion") linkDisplay.classList.add("strike"); + else { + const list = L.DomUtil.create("ul", "", container); + for (const k in change.props) { + this.formatProp(k, link, change.props, op, list); + } + } + } else if (conflict.kind === "marker") { + const marker = this._origin.getMarker(change.id); + const markerDisplay = MarkerUI.displayFormat(marker, this._origin); + container.appendChild(markerDisplay); + if (change.type === "deletion") markerDisplay.classList.add("strike"); + else { + const list = L.DomUtil.create("ul", "", container); + for (const k in change.props) { + this.formatProp(k, marker, change.props, op, list); + } + } + } else if (conflict.kind === "portal") { + const portal = this._origin.getPortal(change.id); + const portalDisplay = PortalUI.displayFormat(portal); + container.appendChild(portalDisplay); + // only edition/edition + const list = L.DomUtil.create("ul", "", container); + for (const k in change.props) { + this.formatProp(k, portal, change.props, op, list); + } + } else if (conflict.kind === "zone") { + const zone = this._origin.getZone(change.id); + const zoneDisplay = L.DomUtil.create("span"); + zoneDisplay.textContent = wX("dialog.merge.zone", { name: zone.name }); + container.appendChild(zoneDisplay); + // only edition/edition + const list = L.DomUtil.create("ul", "", container); + for (const k in change.props) { + this.formatProp(k, zone, change.props, op, list); + } + } + } catch (e) { + console.error(e); + container.append(JSON.stringify(change.props)); } - - return rebaseMessage; }, - formatChanges: function (changes, origin, operation) { - const sortable = new Sortable(); - sortable.fields = [ - { - name: "β€―", - value: (e) => e.type, - format: (cell, value) => { - cell.textContent = value; - }, - }, - { - name: "β€―", - value: (e) => { - let v = ""; - if (e.data.type === "link") { - v = e.data.link.ID; - } else if (e.data.type === "portal") { - v = e.data.portal.id; - } else if (e.data.type === "marker") { - v = e.data.marker.ID; - } - return v.slice(0, 4); - }, - format: (cell, value) => { - cell.innerHTML = `${value}`; - }, - }, - { - name: "Entry", - value: (e) => e.data.type, - format: async (cell, value, e) => { - const op = e.type === "-" ? origin : operation; - if (e.data.type === "link") { - cell.appendChild(e.data.link.displayFormat(op)); - } else if (e.data.type === "portal") { - cell.appendChild(e.data.portal.displayFormat()); - } else if (e.data.type === "marker") { - const portal = op.getPortal(e.data.marker.portalId); - cell.appendChild(portal.displayFormat()); - } else { - cell.textContent = value; - } - if (e.type === "~") { - const pre = L.DomUtil.create("code", null, cell); - const diff = []; - for (const [k, v] of e.data.diff) { - let item = e.data.link || e.data.portal || e.data.marker; - let prev = v; - let cur = item[k]; - if (k.endsWith("ortalId")) { - prev = origin.getPortal(prev).name; - cur = operation.getPortal(cur).name; - } else if (k === "assignedTo") { - if (prev !== "") prev = await WasabeeAgent.get(prev); - if (cur !== "") cur = await WasabeeAgent.get(cur); - if (prev) prev = prev.name; - if (cur) cur = cur.name; - } - diff.push([k, prev, cur]); - } - pre.textContent = JSON.stringify(diff); - } - }, - }, - ]; + formatProp(key, old, next, op, container) { + const li = L.DomUtil.create("li", "", container); + // content with default value + const keySpan = L.DomUtil.create("span", "diff-label", li); + keySpan.textContent = key + ":"; + const oldSpan = L.DomUtil.create("span", "strike", li); + oldSpan.textContent = old[key]; + const newSpan = L.DomUtil.create("span", "", li); + newSpan.textContent = next[key]; - const items = []; - for (const a of changes.addition) { - items.push({ - type: "+", - data: a, - }); + // TODO wX + if (key === "hardness") { + keySpan.textContent = wX("dialog.merge.prop.hardness"); + } else if (key === "comment") { + keySpan.textContent = wX("dialog.merge.prop.comment"); + } else if (key === "assignedTo") { + keySpan.textContent = wX("dialog.merge.prop.assignedTo"); + } else if (key === "state") { + keySpan.textContent = wX("dialog.merge.prop.state"); + oldSpan.textContent = wX(sanitizeState(old[key])); + newSpan.textContent = wX(sanitizeState(next[key])); + } else if (key === "color") { + keySpan.textContent = wX("dialog.merge.prop.color"); + } else if (key === "order") { + keySpan.textContent = wX("dialog.merge.prop.order"); + } else if (key === "zone") { + keySpan.textContent = wX("dialog.merge.prop.zone"); + } else if (key === "points") { + keySpan.textContent = wX("dialog.merge.prop.zone_points"); + oldSpan.textContent = ""; + newSpan.textContent = ""; + } else if (key === "fromPortalId") { + keySpan.textContent = wX("dialog.merge.prop.fromPortal"); + } else if (key === "toPortalId") { + keySpan.textContent = wX("dialog.merge.prop.toPortal"); + } else if (key === "deltaminutes") { + keySpan.textContent = wX("dialog.merge.prop.deltaminutes"); } - for (const e of changes.edition) { - items.push({ - type: "~", - data: e, - }); - } - for (const d of changes.deletion) { - items.push({ - type: "-", - data: d, - }); + + if (key === "assignedTo" || key === "completedID") { + if (old[key]) + WasabeeAgent.get(old[key]).then( + (a) => (oldSpan.textContent = a.getName()) + ); + if (next[key]) + WasabeeAgent.get(next[key]).then( + (a) => (newSpan.textContent = a.getName()) + ); } - sortable.items = items; - return sortable.table; + if (key === "fromPortalId" || key === "toPortalId") { + oldSpan.textContent = ""; + oldSpan.appendChild( + PortalUI.displayFormat(this._origin.getPortal(old[key])) + ); + newSpan.textContent = ""; + newSpan.appendChild(PortalUI.displayFormat(op.getPortal(next[key]))); + } }, }); diff --git a/src/code/dialogs/multimaxDialog.js b/src/code/dialogs/multimaxDialog.js deleted file mode 100644 index abeee322e..000000000 --- a/src/code/dialogs/multimaxDialog.js +++ /dev/null @@ -1,331 +0,0 @@ -import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import { getSelectedOperation } from "../selectedOp"; -import wX from "../wX"; -import { - getAllPortalsOnScreen, - testPortal, - clearAllLinks, -} from "../uiCommands"; -import { greatCircleArcIntersectByLatLngs } from "../crosslinks"; - -// now that the formerly external mm functions are in the class, some of the logic can be cleaned up -// to not require passing values around when we can get them from this.XXX -const MultimaxDialog = WDialog.extend({ - statics: { - TYPE: "multimaxDialog", - }, - - needWritePermission: true, - - addHooks: function () { - WDialog.prototype.addHooks.call(this); - this._displayDialog(); - }, - - _displayDialog: function () { - const container = L.DomUtil.create("div", "container"); - const description = L.DomUtil.create("div", "desc", container); - description.textContent = wX("SELECT_INSTRUCTIONS"); - - const description2 = L.DomUtil.create("div", "desc", container); - description2.textContent = wX("SEL_SB_ANCHOR2"); - - const anchorOneLabel = L.DomUtil.create("label", null, container); - anchorOneLabel.textContent = wX("ANCHOR1"); - const anchorOneButton = L.DomUtil.create("button", null, container); - anchorOneButton.textContent = wX("SET"); - this._anchorOneDisplay = L.DomUtil.create("span", null, container); - if (this._anchorOne) { - this._anchorOneDisplay.appendChild( - this._anchorOne.displayFormat(this._smallScreen) - ); - } else { - this._anchorOneDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorOneButton, "click", () => { - this._anchorOne = WasabeePortal.getSelected(); - if (this._anchorOne) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY] = - JSON.stringify(this._anchorOne); - this._anchorOneDisplay.textContent = ""; - this._anchorOneDisplay.appendChild( - this._anchorOne.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const anchorTwoLabel = L.DomUtil.create("label", null, container); - anchorTwoLabel.textContent = wX("ANCHOR2"); - const anchorTwoButton = L.DomUtil.create("button", null, container); - anchorTwoButton.textContent = wX("SET"); - this._anchorTwoDisplay = L.DomUtil.create("span", null, container); - if (this._anchorTwo) { - this._anchorTwoDisplay.appendChild( - this._anchorTwo.displayFormat(this._smallScreen) - ); - } else { - this._anchorTwoDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorTwoButton, "click", () => { - this._anchorTwo = WasabeePortal.getSelected(); - if (this._anchorTwo) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY] = - JSON.stringify(this._anchorTwo); - this._anchorTwoDisplay.textContent = ""; - this._anchorTwoDisplay.appendChild( - this._anchorTwo.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - - const fllabel = L.DomUtil.create("label", null, container); - fllabel.textContent = wX("ADD_BL"); - fllabel.htmlFor = "wasabee-multimax-backlink"; - this._flcheck = L.DomUtil.create("input", null, container); - this._flcheck.type = "checkbox"; - this._flcheck.id = "wasabee-multimax-backlink"; - - // Go button - const button = L.DomUtil.create("button", "drawb", container); - button.textContent = wX("MULTI_M"); - L.DomEvent.on(button, "click", () => { - const total = this.doMultimax.call(this); - alert(`Multimax found ${total} layers`); - // this.closeDialog(); - }); - - const buttons = {}; - buttons[wX("CLOSE")] = () => { - this.closeDialog(); - }; - buttons[wX("CLEAR LINKS")] = () => { - clearAllLinks(getSelectedOperation()); - }; - - this.createDialog({ - title: wX("MULTI_M_TITLE"), - html: container, - width: "auto", - dialogClass: "multimax", - buttons: buttons, - id: window.plugin.wasabee.static.dialogNames.multimaxButton, - }); - }, - - initialize: function (options) { - WDialog.prototype.initialize.call(this, options); - this.title = wX("MULTI_M"); - this.label = wX("MULTI_M"); - let p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; - if (p) this._anchorOne = new WasabeePortal(p); - p = localStorage[window.plugin.wasabee.static.constants.ANCHOR_TWO_KEY]; - if (p) this._anchorTwo = new WasabeePortal(p); - this._urp = L.latLng(testPortal()); - }, - - /* - Calculate, given two anchors and a set of portals, the deepest sequence of nested fields. - */ - MM: function ( - pOne, - pTwo, - portals, - order = 0, - base = true, - commentPrefix = "multimax " - ) { - const portalsMap = new Map(portals.map((p) => [p.id, p])); - - const poset = this.buildPOSet(pOne, pTwo, portals); - - const sequence = this.longestSequence(poset, null, (a, b) => - window.map.distance(portalsMap.get(a).latLng, portalsMap.get(b).latLng) - ); - - if (base) - this._operation.addLink(pOne, pTwo, { - description: commentPrefix + "base", - oder: ++order, - }); - - if (!Array.isArray(sequence) || !sequence.length) { - // alert("No layers found"); - return [0, order, null]; - } - - let prev = null; - - for (const node of sequence) { - const p = portalsMap.get(node); - if (!p) { - console.log("skipping: " + node); - continue; - } - this._operation.addLink(p, pOne, { - description: commentPrefix + "link", - order: ++order, - }); - this._operation.addLink(p, pTwo, { - description: commentPrefix + "link", - order: ++order, - }); - if (this._flcheck.checked && prev) { - this._operation.addLink(p, prev, { - description: commentPrefix + "back link", - order: ++order, - }); - } - prev = p; - } - // return number of layers, last link order and last portal - return [sequence.length, order, prev]; - }, - - doMultimax: function () { - // this._operation is OK here - this._operation = getSelectedOperation(); - const portals = getAllPortalsOnScreen(this._operation); - - // Calculate the multimax - if (!this._anchorOne || !this._anchorTwo || !portals) { - alert(wX("INVALID REQUEST")); - return 0; - } - - this._operation.startBatchMode(); - - console.log("starting multimax"); - const length = this.MM(this._anchorOne, this._anchorTwo, portals)[0]; - console.log("multimax done"); - - this._operation.endBatchMode(); // save and run crosslinks - - return length; - }, - - fieldCoversPortal: function (a, b, c, p) { - const urp = this._urp; - - let crossings = 0; - if (greatCircleArcIntersectByLatLngs(urp, p.latLng, a.latLng, b.latLng)) - crossings++; - if (greatCircleArcIntersectByLatLngs(urp, p.latLng, a.latLng, c.latLng)) - crossings++; - if (greatCircleArcIntersectByLatLngs(urp, p.latLng, b.latLng, c.latLng)) - crossings++; - return crossings == 1; // crossing 0 or 2 is OK, crossing 3 is impossible - }, - - // given two anchor, build a map that shows which and how many portals are covered by each possible field by guid - // note: a portal always covers itself - buildPOSet: function (anchor1, anchor2, visible) { - const poset = new Map(); - - for (const i of visible) { - const result = []; - for (const j of visible) { - if (i === j) result.push(j.id); - else if (this.fieldCoversPortal(anchor1, anchor2, i, j)) - result.push(j.id); - } - poset.set(i.id, result); - } - - return poset; - }, - - // given a poset, compute the maximal paths from all elements - // the result contains a map that gives for any element the next ones and the list of the elements - // that have the longest paths - longestSequencesPoset: function (poset) { - const alreadyCalculatedChildren = new Map(); - const preds_from = (c) => { - if (alreadyCalculatedChildren.get(c) === undefined) { - const res = { - children: [], - length: 1, - number: 1, - }; - for (const id of poset.get(c).filter((i) => i !== c)) { - const val = preds_from(id); - if (val.length + 1 > res.length) { - res.length = val.length + 1; - res.children = []; - res.number = 0; - } - if (val.length + 1 == res.length) { - res.children.push(id); - res.number += val.number; - } - } - alreadyCalculatedChildren.set(c, res); - } - return alreadyCalculatedChildren.get(c); - }; - - poset.set("__start__", Array.from(poset.keys())); - return { - maxima: preds_from("__start__").children, - poset: alreadyCalculatedChildren, - number: preds_from("__start__").number, - }; - }, - - // given a poset, find the longest sequence p1,p2,...pk such that poset(p2) contains p1, poset(p3) contains p2 etc - // that minimizes the flight distance - // notes: - // - the result is an empty sequence only if the poset is empty or if poset(p) is empty for any p - // - if the poset is given by buildPOSet, the first element is the guid of a portal that doesn't cover any other portal, - // and the last element is the portal that covers all portals of the sequence and isn't covered by any other portal - // (inner to outer) - longestSequence: function (poset, start, dist) { - const maximalPaths = this.longestSequencesPoset(poset); - const alreadyCalculatedSequences = new Map(); - if (!dist) dist = () => 0; - const sequence_from = (c) => { - if (alreadyCalculatedSequences.get(c) === undefined) { - const mP = maximalPaths.poset.get(c); - if (mP.length == 1) - alreadyCalculatedSequences.set(c, { seq: [c], dist: 0 }); - else { - const best = mP.children - .map(sequence_from) - .reduce((S1, S2) => - S1.dist + dist(c, S1.seq[S1.seq.length - 1]) < - S2.dist + dist(c, S2.seq[S2.seq.length - 1]) - ? S1 - : S2 - ); - const res = { - seq: Array.from(best.seq), - dist: best.dist, - }; - res.dist += dist(res.seq[res.seq.length - 1], c); - res.seq.push(c); - alreadyCalculatedSequences.set(c, res); - } - } - return alreadyCalculatedSequences.get(c); - }; - - if (start) { - console.debug( - maximalPaths.poset.get(start).number, - "possible paths from the given start" - ); - return sequence_from(start).seq; - } - - console.debug(maximalPaths.number, "possible paths"); - return maximalPaths.maxima - .map(sequence_from) - .reduce((S1, S2) => (S1.dist < S2.dist ? S1 : S2)).seq; - }, -}); - -export default MultimaxDialog; diff --git a/src/code/dialogs/newopDialog.d.ts b/src/code/dialogs/newopDialog.d.ts new file mode 100644 index 000000000..a60fd39b2 --- /dev/null +++ b/src/code/dialogs/newopDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class NewopDialog extends WDialog {} +export default NewopDialog; diff --git a/src/code/dialogs/newopDialog.js b/src/code/dialogs/newopDialog.js index 906ed4536..30e3d4d48 100644 --- a/src/code/dialogs/newopDialog.js +++ b/src/code/dialogs/newopDialog.js @@ -1,9 +1,10 @@ import { WDialog } from "../leafletClasses"; -import WasabeeOp from "../operation"; +import WasabeeOp from "../model/operation"; import ImportDialog from "./importDialog"; import PromptDialog from "./promptDialog"; import { makeSelectedOperation } from "../selectedOp"; import wX from "../wX"; +import { displayError } from "../error"; const NewopDialog = WDialog.extend({ statics: { @@ -45,16 +46,17 @@ const NewopDialog = WDialog.extend({ await newop.store(); await makeSelectedOperation(newop.ID); } else { - alert(wX("OP_NAME_UNSET")); + displayError(wX("OP_NAME_UNSET")); } }, placeholder: wX("MUST_NOT_BE_EMPTY"), + nonEmpty: true, }); addDialog.enable(); }); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; diff --git a/src/code/dialogs/onionfield.js b/src/code/dialogs/onionfield.js deleted file mode 100644 index d089c1a3e..000000000 --- a/src/code/dialogs/onionfield.js +++ /dev/null @@ -1,339 +0,0 @@ -import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import { getSelectedOperation } from "../selectedOp"; -import { greatCircleArcIntersect } from "../crosslinks"; -import WasabeeLink from "../link"; -import { clearAllLinks, getAllPortalsOnScreen } from "../uiCommands"; -import wX from "../wX"; - -const OnionfieldDialog = WDialog.extend({ - statics: { - TYPE: "OnionDialog", - }, - - needWritePermission: true, - - addHooks: function () { - WDialog.prototype.addHooks.call(this); - this._displayDialog(); - }, - - _displayDialog: function () { - const container = L.DomUtil.create("div", "container"); - const description = L.DomUtil.create("div", "desc", container); - description.textContent = wX("SELECT_ONION_PORTALS"); - const description3 = L.DomUtil.create("div", "desc", container); - description3.textContent = wX("SEL_SB_ANCHOR2"); - - const dividerBeforePortals = L.DomUtil.create("span", null, container); - dividerBeforePortals.textContent = ""; - - const anchorLabel = L.DomUtil.create("label", null, container); - anchorLabel.textContent = wX("ANCHOR_PORTAL"); - const anchorButton = L.DomUtil.create("button", null, container); - anchorButton.textContent = wX("SET"); - this._anchorDisplay = L.DomUtil.create("span", null, container); - if (this._anchor) { - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - this._anchorDisplay.textContent = wX("NOT_SET"); - } - L.DomEvent.on(anchorButton, "click", (ev) => { - L.DomEvent.stop(ev); - this._anchor = WasabeePortal.getSelected(); - if (this._anchor) { - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY] = - JSON.stringify(this._anchor); - this._anchorDisplay.textContent = ""; - this._anchorDisplay.appendChild( - this._anchor.displayFormat(this._smallScreen) - ); - } else { - alert(wX("PLEASE_SELECT_PORTAL")); - } - }); - const dividerBeforeDraw = L.DomUtil.create("span", null, container); - dividerBeforeDraw.textContent = ""; - - // Bottom buttons bar - const placeholder = L.DomUtil.create("label", "placeholder", container); - placeholder.textContent = "\u2063"; - - // Go button - const button = L.DomUtil.create("button", "drawb", container); - button.textContent = wX("ONION"); - L.DomEvent.on(button, "click", (ev) => { - L.DomEvent.stop(ev); - this.onion.call(this); - }); - const buttons = {}; - buttons[wX("CLOSE")] = () => { - this.closeDialog(); - }; - buttons[wX("CLEAR LINKS")] = () => { - clearAllLinks(getSelectedOperation()); - }; - - this.createDialog({ - title: "Onion/Rose", - html: container, - width: "auto", - dialogClass: "onion", - buttons: buttons, - }); - }, - - initialize: function (options) { - WDialog.prototype.initialize.call(this, options); - this.title = "Onion/Rose"; - this.label = "Onion/Rose"; - const p = - localStorage[window.plugin.wasabee.static.constants.ANCHOR_ONE_KEY]; - if (p) this._anchor = new WasabeePortal(p); - }, - - onion: function () { - // this._operation is OK here - this._operation = getSelectedOperation(); - if (!this._anchor) { - alert("no anchor selected"); - return; - } - this._colors = [ - "#f80c12", - "#ee1100", - "#ff3311", - "#ff4422", - "#ff6644", - "#ff9933", - "#feae2d", - "#ccbb33", - "#d0c310", - "#aacc22", - "#69d025", - "#22ccaa", - "#12bdb9", - "#11aabb", - "#4444dd", - "#3311bb", - "#3b0cbd", - "#442299", - ]; - this._colorIterator = 0; - this._color = this._colors[this._colorIterator]; - const allPortals = getAllPortalsOnScreen(this._operation); - - // batch mode isn't strictly necessary since we are loading the links in one operation, but portals are added during the recursion - this._operation.startBatchMode(); - - // add the anchor to the operation, needed to check for crosslinks - this._operation.addPortal(this._anchor); - // start digging for onions - const onion = this._recurser(allPortals, [], this._anchor); - - // add all the found links at once - // this is a minor abuse of the _operation object since we aren't using the operation.addLink() method to add links - this._operation.links.push(...onion); - // that didn't add the anchors, so we have to do that here - this._operation.cleanAnchorList(); - // now, remove the portals that are unused - this._operation.cleanPortalList(); - // signal to the operation that we are done abusing it - this._operation.endBatchMode(); - }, - - // no longer operates on a a class var, different paths (if not using the fast route) have different lists - _removeFromList: function (portalsRemaining, guid) { - const x = new Array(); - for (const p of portalsRemaining) { - if (p.id != guid) x.push(p); - } - return x; - }, - - // the data passing for this (portalsRemaining, thisPath) - // is designed to allow for determining optimum path, the fast route is quick - // and gets a reasonable set, optimum path determination is VERY slow and nets - // only a few extra layers - _recurser: function (portalsRemaining, thisPath, one, two, three) { - this._colorIterator = (this._colorIterator + 1) % this._colors.length; - this._color = this._colors[this._colorIterator]; - - // build a map of all portals still in-play - const m = new Map(); - for (const p of portalsRemaining) { - if ( - (two && p.id == two.id) || - (three && p.id == three.id) || - p.id == one.id - ) { - portalsRemaining = this._removeFromList(portalsRemaining, p.id); - continue; - } - - const pDist = window.map.distance(one.latLng, p.latLng); - m.set(pDist, p); - } - // sort by distance - const sorted = new Map([...m.entries()].sort((a, b) => a[0] - b[0])); - if (sorted.length == 0) return null; - - // for each of the portals in play - for (const [k, wp] of sorted) { - // silence lint - this._trash = k; - - // we need it in the op (this prevents dupes) for links later - this._operation.addPortal(wp); - // unused ones will be purged at the end - - // do the intial field - if (!two) { - portalsRemaining = this._removeFromList(portalsRemaining, wp.id); - const a = new WasabeeLink( - { fromPortalId: one.id, toPortalId: wp.id }, - this._operation - ); - a.color = this._color; - a.throwOrderPos = 1; - thisPath.push(a); - return this._recurser(portalsRemaining, thisPath, one, wp); - } - if (!three) { - portalsRemaining = this._removeFromList(portalsRemaining, wp.id); - const a = new WasabeeLink( - { fromPortalId: one.id, toPortalId: wp.id }, - this._operation - ); - a.color = this._color; - a.throwOrderPos = 2; - thisPath.push(a); - const b = new WasabeeLink( - { fromPortalId: two.id, toPortalId: wp.id }, - this._operation - ); - b.color = this._color; - b.throwOrderPos = 3; - thisPath.push(b); - // now we are bootstrapped, dive in - return this._recurser(portalsRemaining, thisPath, one, two, wp); - } - // initial field done - - // create the three links, this does not add them to the operation - const a = new WasabeeLink( - { fromPortalId: one.id, toPortalId: wp.id }, - this._operation - ); - const b = new WasabeeLink( - { fromPortalId: two.id, toPortalId: wp.id }, - this._operation - ); - const c = new WasabeeLink( - { fromPortalId: three.id, toPortalId: wp.id }, - this._operation - ); - a.color = this._color; - b.color = this._color; - c.color = this._color; - - // testBlock does not look in the op or live map data, but in thisPath - const aBlock = this._testBlock(thisPath, a); - const bBlock = this._testBlock(thisPath, b); - const cBlock = this._testBlock(thisPath, c); - - // if none of the links are blocked by existing linkes in thisPath, we found an option - if (!aBlock && !bBlock && !cBlock) { - portalsRemaining = this._removeFromList(portalsRemaining, wp.id); - - let Y = one; - let Z = two; - // determine the widest angle, wp= angTwoThree && angOneTwo >= angThreeOne) { - Y = one; - Z = two; - thisPath.push(a); - a.throwOrderPos = thisPath.length; - thisPath.push(b); - b.throwOrderPos = thisPath.length; - // XXX add back-link to c if requested - } else if (angTwoThree >= angThreeOne) { - Y = two; - Z = three; - thisPath.push(b); - b.throwOrderPos = thisPath.length; - thisPath.push(c); - c.throwOrderPos = thisPath.length; - // XXX add back-link to a if requested - } else { - Y = three; - Z = one; - thisPath.push(c); - c.throwOrderPos = thisPath.length; - thisPath.push(a); - a.throwOrderPos = thisPath.length; - // XXX add back-link to b if requested - } - - // allow users to turn this on if they want... - if ( - localStorage["wasabee-onion-recursive"] && - localStorage["wasabee-onion-recursive"] == "slowAF" - ) { - // you might find 2 or 3 more layers on a small field, but it takes an hour to run - // two is enough, three gets crazy even with a small number of portals - const pathOne = this._recurser( - new Array(...portalsRemaining), - new Array(...thisPath), - Y, - Z, - wp - ); - const pathTwo = this._recurser( - new Array(...portalsRemaining), - new Array(...thisPath), - Z, - Y, - wp - ); - // console.log(pathOne.length, pathTwo.length); - if (pathTwo.length > pathOne.lenght) return pathTwo; - return pathOne; - } - // default to the fast route, which gets gets us 90+% in my testing - return this._recurser(portalsRemaining, thisPath, Y, Z, wp); - } - } - // console.log("hit bottom", thisPath.length); - return thisPath; - }, - - // looks only at links in current (not op or live data) - _testBlock: function (current, testing) { - for (const against of current) { - if (greatCircleArcIntersect(against, testing)) return true; - } - return false; - }, - - // angle a { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; this.update(); this.createDialog({ - title: "Online Agents", + title: wX("dialog.online_agents.title"), html: this._table.table, width: "auto", dialogClass: "teamlist", @@ -43,21 +45,21 @@ const OnlineAgentList = WDialog.extend({ this._table.fields = [ { name: wX("AGENT"), - value: (agent) => agent.name, + value: (agent) => agent.getName(), sort: (a, b) => a.localeCompare(b), - format: async (cell, value, agent) => - cell.appendChild(await agent.formatDisplay(0)), + format: (cell, value, agent) => + cell.appendChild(AgentUI.formatDisplay(agent)), }, { - name: "Last Seen", + name: wX("dialog.online_agents.last_seen"), value: (agent) => agent.date, sort: (a, b) => a.localeCompare(b), format: (cell, value, agent) => { - if (agent) cell.textContent = agent.timeSinceformat(); + if (agent) cell.textContent = AgentUI.timeSinceformat(agent); }, }, { - name: "Actions", + name: wX("dialog.online_agents.actions"), value: (agent) => agent.id, format: (cell, value, agent) => { if (value) { diff --git a/src/code/dialogs/opPerms.d.ts b/src/code/dialogs/opPerms.d.ts new file mode 100644 index 000000000..0afac860c --- /dev/null +++ b/src/code/dialogs/opPerms.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class OpPermList extends WDialog {} +export default OpPermList; diff --git a/src/code/dialogs/opPerms.js b/src/code/dialogs/opPerms.js index 2d07067a1..47413efa2 100644 --- a/src/code/dialogs/opPerms.js +++ b/src/code/dialogs/opPerms.js @@ -1,10 +1,11 @@ import { WDialog } from "../leafletClasses"; import Sortable from "../sortable"; import { getSelectedOperation } from "../selectedOp"; -import WasabeeTeam from "../team"; -import WasabeeMe from "../me"; +import WasabeeTeam from "../model/team"; +import WasabeeMe from "../model/me"; import { addPermPromise, delPermPromise } from "../server"; import wX from "../wX"; +import { displayError } from "../error"; const OpPermList = WDialog.extend({ statics: { @@ -54,6 +55,7 @@ const OpPermList = WDialog.extend({ this.createDialog({ title: wX("PERMS", { opName: operation.name }), html: html, + width: "auto", height: "auto", dialogClass: "perms", buttons: buttons, @@ -61,59 +63,8 @@ const OpPermList = WDialog.extend({ }, buildHTML: function (operation) { - const html = L.DomUtil.create("div"); - html.appendChild(this.buildTable(operation)); - - if (this._me && operation.isOwnedOp() && operation.isOnCurrentServer()) { - const already = new Set(); - for (const a of operation.teamlist) already.add(a.teamid); - - const addArea = L.DomUtil.create("div", "add-perm", html); - const teamMenu = L.DomUtil.create("select", null, addArea); - for (const t of this._me.Teams) { - // if (already.has(t.ID)) continue; - const o = L.DomUtil.create("option", null, teamMenu); - o.value = t.ID; - o.textContent = t.Name; - } - const permMenu = L.DomUtil.create("select", null, addArea); - const read = L.DomUtil.create("option", null, permMenu); - read.value = "read"; - read.textContent = wX("READ"); - const write = L.DomUtil.create("option", null, permMenu); - write.value = "write"; - write.textContent = wX("WRITE"); - const ao = L.DomUtil.create("option", null, permMenu); - ao.value = "assignedonly"; - ao.textContent = wX("ASSIGNED_ONLY"); - - const zoneMenu = L.DomUtil.create("select", null, addArea); - const zoneAll = L.DomUtil.create("option", null, zoneMenu); - zoneAll.value = "0"; - zoneAll.textContent = "All"; - for (const oz of operation.zones) { - const z = L.DomUtil.create("option", null, zoneMenu); - z.value = oz.id; - z.textContent = oz.name; - } - - const ab = L.DomUtil.create("button", null, addArea); - ab.type = "button"; - ab.name = "Add"; - ab.value = "Add"; - ab.textContent = wX("ADD"); - - L.DomEvent.on(ab, "click", (ev) => { - L.DomEvent.stop(ev); - this.addPerm(teamMenu.value, permMenu.value, +zoneMenu.value); // async, but no need to await - // addPerm calls wasabee:op:change, which redraws the screen - }); - } - - return html; - }, - - buildTable: function (operation) { + const isOwner = + this._me && operation.isOwnedOp() && operation.isOnCurrentServer(); const sortable = new Sortable(); const fields = [ { @@ -135,24 +86,60 @@ const OpPermList = WDialog.extend({ }, sort: (a, b) => a.localeCompare(b), // , format: (cell, value) => (cell.textContent = value) + foot: (cell) => { + this.teamMenu = L.DomUtil.create("select", null, cell); + for (const t of this._me.Teams) { + const o = L.DomUtil.create("option", null, this.teamMenu); + o.value = t.ID; + o.textContent = t.Name; + } + }, }, { name: wX("ROLE"), value: (perm) => perm.role, sort: (a, b) => a.localeCompare(b), // , format: (cell, value) => (cell.textContent = value) + foot: (cell) => { + this.permMenu = L.DomUtil.create("select", null, cell); + const read = L.DomUtil.create("option", null, this.permMenu); + read.value = "read"; + read.textContent = wX("READ"); + const write = L.DomUtil.create("option", null, this.permMenu); + write.value = "write"; + write.textContent = wX("WRITE"); + const ao = L.DomUtil.create("option", null, this.permMenu); + ao.value = "assignedonly"; + ao.textContent = wX("ASSIGNED_ONLY"); + }, }, { - name: "Zone", - value: (perm) => operation.zoneName(perm.zone), + name: wX("ZONE"), + value: (perm) => { + if (perm.zone === 0) return wX("dialog.common.zone_all"); + return operation.zoneName(perm.zone); + }, sort: (a, b) => a.localeCompare(b), // , format: (cell, value) => (cell.textContent = value) + foot: (cell) => { + this.zoneMenu = L.DomUtil.create("select", null, cell); + const zoneAll = L.DomUtil.create("option", null, this.zoneMenu); + zoneAll.value = "0"; + zoneAll.textContent = wX("dialog.common.zone_all"); + for (const oz of operation.zones) { + const z = L.DomUtil.create("option", null, this.zoneMenu); + z.value = oz.id; + z.textContent = oz.name; + } + }, }, ]; - if (operation.isOwnedOp()) { + if (!isOwner) { + for (const field of fields) delete field.foot; + } else { fields.push({ - name: wX("REMOVE"), + name: wX("dialog.common.commands"), value: () => wX("REMOVE"), format: (cell, value, obj) => { const link = L.DomUtil.create("a", null, cell); @@ -163,6 +150,19 @@ const OpPermList = WDialog.extend({ this.delPerm(obj); // calls wasabee:op:change -- async but no need to await }); }, + foot: (cell) => { + const link = L.DomUtil.create("a", null, cell); + link.href = "#"; + link.textContent = wX("ADD"); + L.DomEvent.on(link, "click", (ev) => { + L.DomEvent.stop(ev); + this.addPerm( + this.teamMenu.value, + this.permMenu.value, + +this.zoneMenu.value + ); + }); + }, }); } @@ -175,7 +175,7 @@ const OpPermList = WDialog.extend({ addPerm: async function (teamID, role, zone) { if (!WasabeeMe.isLoggedIn()) { - alert(wX("NOT LOGGED IN SHORT")); + displayError(wX("NOT LOGGED IN SHORT")); return; } const operation = getSelectedOperation(); @@ -196,13 +196,13 @@ const OpPermList = WDialog.extend({ window.map.fire("wasabee:op:change"); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } }, delPerm: async function (obj) { if (!WasabeeMe.isLoggedIn()) { - alert(wX("NOT LOGGED IN SHORT")); + displayError(wX("NOT LOGGED IN SHORT")); return; } const operation = getSelectedOperation(); @@ -220,7 +220,7 @@ const OpPermList = WDialog.extend({ window.map.fire("wasabee:op:change"); } catch (e) { console.error(e); - alert(e); + displayError(e); } }, }); diff --git a/src/code/dialogs/opSettings.d.ts b/src/code/dialogs/opSettings.d.ts new file mode 100644 index 000000000..9c1678786 --- /dev/null +++ b/src/code/dialogs/opSettings.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class OpSettingDialog extends WDialog {} +export default OpSettingDialog; diff --git a/src/code/dialogs/opSettings.js b/src/code/dialogs/opSettings.js index 65db6421c..f0315a120 100644 --- a/src/code/dialogs/opSettings.js +++ b/src/code/dialogs/opSettings.js @@ -13,9 +13,10 @@ import { import OpPermList from "./opPerms"; import wX from "../wX"; import { addToColorList } from "../skin"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; import { convertColorToHex } from "../auxiliar"; +import { displayError } from "../error"; const OpSettingDialog = WDialog.extend({ statics: { @@ -75,7 +76,7 @@ const OpSettingDialog = WDialog.extend({ L.DomEvent.on(input, "change", async (ev) => { L.DomEvent.stop(ev); if (!input.value || input.value == "") { - alert(wX("USE_VALID_NAME")); + displayError(wX("USE_VALID_NAME")); } else { const so = getSelectedOperation(); so.name = input.value; @@ -144,7 +145,7 @@ const OpSettingDialog = WDialog.extend({ window.map.fire("wasabee:op:change"); } catch (e) { console.log(e); - alert("Invalid date format"); + displayError("Invalid date format"); } }); } else { @@ -202,7 +203,7 @@ const OpSettingDialog = WDialog.extend({ console.log("delete from server successful"); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } } await removeOperation(so.ID); @@ -227,7 +228,7 @@ const OpSettingDialog = WDialog.extend({ const zoneDiv = L.DomUtil.create("div", null, buttonSection); const zoneButton = L.DomUtil.create("button", null, zoneDiv); - zoneButton.textContent = "Zones"; + zoneButton.textContent = wX("dialog.op_settings.zones"); L.DomEvent.on(zoneButton, "click", (ev) => { L.DomEvent.stop(ev); const z = new ZoneDialog(); diff --git a/src/code/dialogs/opsDialog.d.ts b/src/code/dialogs/opsDialog.d.ts new file mode 100644 index 000000000..2bb768d25 --- /dev/null +++ b/src/code/dialogs/opsDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class OpsDialog extends WDialog {} +export default OpsDialog; diff --git a/src/code/dialogs/opsDialog.js b/src/code/dialogs/opsDialog.js index b1a2807ef..1e35c09c4 100644 --- a/src/code/dialogs/opsDialog.js +++ b/src/code/dialogs/opsDialog.js @@ -1,4 +1,4 @@ -import WasabeeOp from "../operation"; +import WasabeeOp from "../model/operation"; import { WDialog } from "../leafletClasses"; import { getSelectedOperation, @@ -12,16 +12,22 @@ import { } from "../selectedOp"; import OpPermList from "./opPerms"; import wX from "../wX"; -import WasabeeMe from "../me"; -import WasabeeAgent from "../agent"; +import WasabeeMe from "../model/me"; +import WasabeeAgent from "../model/agent"; import { syncOp, deleteLocalOp, zoomToOperation } from "../uiCommands"; import Sortable from "../sortable"; +import AgentUI from "../ui/agent"; +import { appendFAIcon } from "../auxiliar"; + const OpsDialog = WDialog.extend({ statics: { TYPE: "opsDialog", }, + SORTBY_KEY: "wasabee-opslist-sortby", + SORTASC_KEY: "wasabee-opslist-sortasc", + options: { usePane: true, }, @@ -45,15 +51,16 @@ const OpsDialog = WDialog.extend({ _displayDialog: async function () { this.initSortable(); - await this.updateSortable(0, false); + + await this.updateSortable(); const buttons = {}; // wX - buttons["Unhide all OPs"] = () => { + buttons[wX("dialog.ops_list.unhide_ops")] = () => { resetHiddenOps(); this.update(); }; - buttons["Toggle Show/Hide"] = () => { + buttons[wX("dialog.ops_list.toggle_hide")] = () => { const showHiddenOps = localStorage[ window.plugin.wasabee.static.constants.OPS_SHOW_HIDDEN_OPS @@ -79,7 +86,7 @@ const OpsDialog = WDialog.extend({ update: async function () { if (this._enabled) { - await this.updateSortable(this.sortable.sortBy, this.sortable.sortAsc); + await this.updateSortable(); // this.setContent(this.sortable.table); } }, @@ -96,7 +103,7 @@ const OpsDialog = WDialog.extend({ }, }, { - name: "Name", + name: wX("dialog.common.name"), value: (op) => op.name, sort: (a, b) => a.localeCompare(b), format: (cell, value, op) => { @@ -104,9 +111,12 @@ const OpsDialog = WDialog.extend({ link.href = "#"; link.textContent = op.name; if (!op.local) { - link.title = `Last fetched: ${op.fetched}\n`; - if (op.localchanged) link.title += "Local has changed\n"; - if (op.remotechanged) link.title += "Remote has changed"; + link.title = + wX("dialog.ops_list.last_fetched", { date: op.fetched }) + "\n"; + if (op.localchanged) + link.title += wX("dialog.ops_list.local_change") + "\n"; + if (op.remotechanged) + link.title += wX("dialog.ops_list.remote_change") + "\n"; } if (op.id == getSelectedOperation().ID) link.classList.add("enl"); L.DomEvent.on(link, "click", async (ev) => { @@ -123,24 +133,19 @@ const OpsDialog = WDialog.extend({ 1 * op.local + 2 * op.localchanged + 4 * op.remotechanged, // sort: (a, b) => a - b, format: (cell, value, op) => { - const status = L.DomUtil.create("span", "", cell); - status.textContent = ""; if (!op.local) { - if (op.localchanged) { - status.textContent = "β˜€"; - status.style.color = "green"; - status.title = "Local changes"; - } - if (op.remotechanged) { - status.textContent = "β›…"; - status.style.color = "red"; - status.title = "Local&remote changes"; + if (op.localchanged && !op.remotechanged) { + appendFAIcon("desktop", cell); + cell.title = wX("dialog.ops_list.local_change"); + } else if (op.remotechanged) { + appendFAIcon("server", cell); + cell.title = wX("dialog.ops_list.remote_change"); } } }, }, { - name: "Owner", + name: wX("dialog.common.owner"), value: (op) => op.owner, sort: (a, b) => a.localeCompare(b), format: (cell, value, op) => { @@ -179,23 +184,23 @@ const OpsDialog = WDialog.extend({ const background = L.DomUtil.create("input", null, cell); background.type = "checkbox"; background.checked = op.background; - // wX + background.title = op.background - ? "Disable background" - : "Show in background"; + ? wX("dialog.ops_list.background_disable") + : wX("dialog.ops_list.background_enable"); L.DomEvent.on(background, "change", (ev) => { L.DomEvent.stop(ev); const background = ev.target; // wX background.title = background.checked - ? "Disable background" - : "Show in background"; + ? wX("dialog.ops_list.background_disable") + : wX("dialog.ops_list.background_enable"); setOpBackground(op.id, background.checked); }); }, }, { - name: "Cmds", + name: wX("dialog.common.commands_short"), value: () => null, sort: null, className: "actions", @@ -203,7 +208,7 @@ const OpsDialog = WDialog.extend({ // delete locally const deleteLocaly = L.DomUtil.create("a", "", cell); deleteLocaly.href = "#"; - deleteLocaly.textContent = "πŸ—‘οΈ"; + appendFAIcon("trash", deleteLocaly); deleteLocaly.title = wX("REM_LOC_CP", { opName: op.name }); L.DomEvent.on(deleteLocaly, "click", (ev) => { L.DomEvent.stop(ev); @@ -214,8 +219,10 @@ const OpsDialog = WDialog.extend({ // download op const download = L.DomUtil.create("a", "", cell); download.href = "#"; - download.textContent = "↻"; - download.title = "Download " + op.name; + appendFAIcon("sync", download); + download.title = wX("dialog.ops_list.download", { + opName: op.name, + }); L.DomEvent.on(download, "click", (ev) => { L.DomEvent.stop(ev); syncOp(op.id); @@ -241,10 +248,12 @@ const OpsDialog = WDialog.extend({ }, }, ]; + content.sortByStoreKey = this.SORTBY_KEY; + content.sortAscStoreKey = this.SORTASC_KEY; this.sortable = content; }, - updateSortable: async function (sortBy, sortAsc) { + updateSortable: async function () { if (!this.sortable) return; // collapse markers and links into one array. const showHiddenOps = @@ -279,8 +288,8 @@ const OpsDialog = WDialog.extend({ }; if (sum.currentserver) { const agent = await WasabeeAgent.get(tmpOp.creator); - sum.owner = agent.name; - sum.ownerDisplay = await agent.formatDisplay(); + sum.owner = agent.getName(); + sum.ownerDisplay = AgentUI.formatDisplay(agent); } else { sum.owner = window.PLAYER.nickname; } @@ -290,8 +299,7 @@ const OpsDialog = WDialog.extend({ } ops.push(sum); } - this.sortable.sortBy = sortBy; - this.sortable.sortAsc = sortAsc; + this.sortable.items = ops; await this.sortable.done; diff --git a/src/code/dialogs/promptDialog.d.ts b/src/code/dialogs/promptDialog.d.ts new file mode 100644 index 000000000..e5d331676 --- /dev/null +++ b/src/code/dialogs/promptDialog.d.ts @@ -0,0 +1,21 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; + +interface PromptDialogOptions extends WDialogOptions { + title: string; + label: string; + placeholder?: string; + current?: string; + suggestions?: { + text: string; + value: string; + }[]; + nonEmpty?: boolean; + callback?: () => void; + cancelCallback?: () => void; +} +declare class PromptDialog extends WDialog { + inputField: HTMLInputElement; + options: PromptDialogOptions; + constructor(options: PromptDialogOptions); +} +export default PromptDialog; diff --git a/src/code/dialogs/promptDialog.js b/src/code/dialogs/promptDialog.js index 9f6472683..f78c88f23 100644 --- a/src/code/dialogs/promptDialog.js +++ b/src/code/dialogs/promptDialog.js @@ -14,6 +14,7 @@ const PromptDialog = WDialog.extend({ placeholder: "", current: "", suggestions: [], + nonEmpty: false, // callback // cancelCallback }, @@ -30,6 +31,7 @@ const PromptDialog = WDialog.extend({ _displayDialog: function () { const buttons = {}; buttons[wX("OK")] = () => { + if (this.options.nonEmpty && !this.inputField.value) return; if (this.options.callback) this.options.callback(); // callback must fire appropriate ui update events this.closeDialog(); @@ -61,6 +63,7 @@ const PromptDialog = WDialog.extend({ this.inputField.id = "inputField"; this.inputField.placeholder = this.options.placeholder; this.inputField.value = this.options.current; + this.inputField.required = this.options.nonEmpty; if (this.options.suggestions) { const datalist = L.DomUtil.create("datalist", null, content); diff --git a/src/code/dialogs/sendTargetDialog.d.ts b/src/code/dialogs/sendTargetDialog.d.ts new file mode 100644 index 000000000..2bddfa7ad --- /dev/null +++ b/src/code/dialogs/sendTargetDialog.d.ts @@ -0,0 +1,12 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import WasabeeMarker from "../model/marker"; +import WasabeePortal from "../model/portal"; + +interface SendTargetDialogOptions extends WDialogOptions { + target: WasabeeMarker | WasabeePortal; +} +declare class SendTargetDialog extends WDialog { + options: SendTargetDialogOptions; + constructor(options: SendTargetDialogOptions); +} +export default SendTargetDialog; diff --git a/src/code/dialogs/sendTargetDialog.js b/src/code/dialogs/sendTargetDialog.js index 2664c8de6..2ee751706 100644 --- a/src/code/dialogs/sendTargetDialog.js +++ b/src/code/dialogs/sendTargetDialog.js @@ -1,12 +1,15 @@ import { WDialog } from "../leafletClasses"; -import WasabeeMarker from "../marker"; -import WasabeeAnchor from "../anchor"; -import WasabeeMe from "../me"; -import WasabeeTeam from "../team"; +import WasabeeMarker from "../model/marker"; +import WasabeePortal from "../model/portal"; +import WasabeeMe from "../model/me"; +import WasabeeTeam from "../model/team"; import { targetPromise } from "../server"; import wX from "../wX"; import { getSelectedOperation } from "../selectedOp"; +import PortalUI from "../ui/portal"; +import { displayError, displayInfo } from "../error"; + const SendTargetDialog = WDialog.extend({ statics: { TYPE: "sendTargetDialog", @@ -48,18 +51,18 @@ const SendTargetDialog = WDialog.extend({ const operation = getSelectedOperation(); if (this.options.target instanceof WasabeeMarker) { - const portal = operation.getPortal(this.options.target.portalId); + this._portal = operation.getPortal(this.options.target.portalId); this._targettype = this.options.target.type; - divtitle.appendChild(portal.displayFormat(this._smallScreen)); + divtitle.appendChild(PortalUI.displayFormat(this._portal)); const t = L.DomUtil.create("label", null); t.textContent = wX("SEND TARGET AGENT"); menu.prepend(t); } - if (this.options.target instanceof WasabeeAnchor) { - const portal = operation.getPortal(this.options.target.portalId); + if (this.options.target instanceof WasabeePortal) { + this._portal = this.options.target; this._targettype = "anchor"; - divtitle.appendChild(portal.displayFormat(this._smallScreen)); + divtitle.appendChild(PortalUI.displayFormat(this._portal)); const t = L.DomUtil.create("label", null); t.textContent = wX("SEND TARGET AGENT"); menu.prepend(t); @@ -98,13 +101,12 @@ const SendTargetDialog = WDialog.extend({ try { // allow teams to be 5 minutes cached const tt = await WasabeeTeam.get(t.teamid, 5 * 60); - const agents = tt.getAgents(); - for (const a of agents) { + for (const a of tt.agents) { if (!alreadyAdded.includes(a.id)) { alreadyAdded.push(a.id); option = L.DomUtil.create("option"); option.value = a.id; - option.textContent = a.name; + option.textContent = a.getName(); if (a.id == current) option.selected = true; menu.appendChild(option); } @@ -118,18 +120,16 @@ const SendTargetDialog = WDialog.extend({ }, _sendTarget: function () { - if (!this._value) { + if (!this._value || !this._portal) { this.closeDialog(); return; } - const operation = getSelectedOperation(); - const portal = operation.getPortal(this.options.target.portalId); - targetPromise(this._value, portal, this._targettype) + targetPromise(this._value, this._portal, this._targettype) .then(() => { - alert(wX("TARGET SENT")); + displayInfo(wX("TARGET SENT")); this.closeDialog(); }) - .catch((e) => alert(e)); + .catch((e) => displayError(e)); }, }); diff --git a/src/code/dialogs/setCommentDialog.d.ts b/src/code/dialogs/setCommentDialog.d.ts new file mode 100644 index 000000000..066928b55 --- /dev/null +++ b/src/code/dialogs/setCommentDialog.d.ts @@ -0,0 +1,14 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import WasabeePortal from "../model/portal"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; +import type WasabeeOp from "../model/operation"; +interface SetCommentDialogOptions extends WDialogOptions { + target: WasabeeMarker | WasabeeLink | WasabeePortal; + operation: WasabeeOp; +} +export declare class SetCommentDialog extends WDialog { + options: SetCommentDialogOptions; + constructor(options: SetCommentDialogOptions); +} +export default SetCommentDialog; diff --git a/src/code/dialogs/setCommentDialog.js b/src/code/dialogs/setCommentDialog.js index 7fe0e2690..4aef2e7fd 100644 --- a/src/code/dialogs/setCommentDialog.js +++ b/src/code/dialogs/setCommentDialog.js @@ -1,9 +1,12 @@ import { WDialog } from "../leafletClasses"; -import WasabeePortal from "../portal"; -import WasabeeLink from "../link"; -import WasabeeMarker from "../marker"; +import WasabeePortal from "../model/portal"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; import wX from "../wX"; +import PortalUI from "../ui/portal"; +import LinkUI from "../ui/link"; + export const SetCommentDialog = WDialog.extend({ statics: { TYPE: "setCommentDialog", @@ -33,14 +36,14 @@ export const SetCommentDialog = WDialog.extend({ this.options.target.portalId ); this.dialogTitle = wX("SET_MCOMMENT", { - portalName: this.portal.displayName, + portalName: PortalUI.displayName(this.portal), }); } if (this.options.target instanceof WasabeePortal) { this.commentType = "portal"; this.dialogTitle = wX("SET_PCOMMENT", { - portalName: this.options.target.displayName, + portalName: PortalUI.displayName(this.options.target), }); this.portal = this.options.target; } @@ -76,15 +79,12 @@ export const SetCommentDialog = WDialog.extend({ const container = L.DomUtil.create("div", "container"); const desc = L.DomUtil.create("div", "desc", container); const input = L.DomUtil.create("input", null, container); - input.placeholder = "comment"; + input.placeholder = wX("COMMENT"); if (this.commentType == "link") { desc.textContent = wX("SET_LINK_COMMENT"); desc.appendChild( - this.options.target.displayFormat( - this.options.operation, - this._smallScreen - ) + LinkUI.displayFormat(this.options.target, this.options.operation) ); if (this.options.target.comment) input.value = this.options.target.comment; @@ -102,7 +102,7 @@ export const SetCommentDialog = WDialog.extend({ if (this.commentType == "marker") { desc.textContent = wX("SET_MARKER_COMMENT"); - desc.appendChild(this.portal.displayFormat(this.options.operation)); + desc.appendChild(PortalUI.displayFormat(this.portal)); if (this.options.target.comment) input.value = this.options.target.comment; @@ -120,7 +120,7 @@ export const SetCommentDialog = WDialog.extend({ if (this.commentType == "portal") { desc.textContent = wX("SET_PORT_COMMENT"); - desc.appendChild(this.portal.displayFormat(this._smallScreen)); + desc.appendChild(PortalUI.displayFormat(this.portal)); if (this.portal.comment) input.value = this.portal.comment; input.addEventListener( @@ -135,7 +135,7 @@ export const SetCommentDialog = WDialog.extend({ ); const hardnessInput = L.DomUtil.create("input", null, container); - hardnessInput.placeholder = "hardness"; + hardnessInput.placeholder = wX("dialog.setcomment.portal_hardness"); if (this.portal.hardness) hardnessInput.value = this.portal.hardness; hardnessInput.addEventListener( "change", diff --git a/src/code/dialogs/settingsDialog.d.ts b/src/code/dialogs/settingsDialog.d.ts new file mode 100644 index 000000000..c52b9dd9a --- /dev/null +++ b/src/code/dialogs/settingsDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class SettingsDialog extends WDialog {} +export default SettingsDialog; diff --git a/src/code/dialogs/settingsDialog.js b/src/code/dialogs/settingsDialog.js index c20244945..7ee0f8e97 100644 --- a/src/code/dialogs/settingsDialog.js +++ b/src/code/dialogs/settingsDialog.js @@ -1,9 +1,10 @@ import { WDialog } from "../leafletClasses"; import wX from "../wX"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; import { GetWasabeeServer, SetWasabeeServer } from "../server"; import PromptDialog from "./promptDialog"; import SkinDialog from "./skinDialog"; +import { clearAllData } from "../uiCommands"; const SettingsDialog = WDialog.extend({ statics: { @@ -12,11 +13,7 @@ const SettingsDialog = WDialog.extend({ addHooks: function () { WDialog.prototype.addHooks.call(this); - if (this._smallScreen) { - this._displaySmallDialog(); - } else { - this._displayDialog(); - } + this._displayDialog(); }, removeHooks: function () { @@ -25,16 +22,15 @@ const SettingsDialog = WDialog.extend({ update: function () { this.setContent(this._getContent()); - // TODO also update the title + this.setTitle(wX("SETTINGS_TITLE")); }, _addCheckBox(container, label, id, storageKey, onChange, defValue) { - const title = L.DomUtil.create("label", null, container); - title.textContent = label; - title.htmlFor = id; - const check = L.DomUtil.create("input", null, container); + const title = L.DomUtil.create("label", "checkbox", container); + const check = L.DomUtil.create("input", "", title); check.type = "checkbox"; check.id = id; + L.DomUtil.create("span", "", title).textContent = label; const sl = localStorage[storageKey]; if (!defValue && sl === "true") check.checked = true; if (defValue && sl !== "false") check.checked = true; @@ -83,13 +79,6 @@ const SettingsDialog = WDialog.extend({ } ); - this._addCheckBox( - container, - wX("SEND LOCATION"), - "wasabee-setting-sendloc", - window.plugin.wasabee.static.constants.SEND_LOCATION_KEY - ); - this._addSelect( container, wX("SKIP_CONFIRM"), @@ -101,26 +90,15 @@ const SettingsDialog = WDialog.extend({ ] ); - this._addCheckBox( - container, - wX("SEND ANALYTICS"), - "wasabee-setting-analytics", - window.plugin.wasabee.static.constants.SEND_ANALYTICS_KEY - ); - - const urpKey = - window.plugin.wasabee.static.constants.MULTIMAX_UNREACHABLE_KEY; - if (!localStorage[urpKey]) { - localStorage[urpKey] = '{"lat": -74.2,"lng:"-143.4}'; + // send location on mobile + if (window.plugin.userLocation) { + this._addCheckBox( + container, + wX("SEND LOCATION"), + "wasabee-setting-sendloc", + window.plugin.wasabee.static.constants.SEND_LOCATION_KEY + ); } - const pairs = [ - ["Antarctic West", '{"lat":-74.2,"lng":-143.4}'], - ["Antarctic East", '{"lat":-74.2,"lng":30.0}'], - ["Equatorial Atlantic", '{"lat":-2.66,"lng":-4.28}'], - ["Arctic West", '{"lat":74.2,"lng":-143.4}'], - ["Arctic East", '{"lat":78.5,"lng":143.4}'], - ]; - this._addSelect(container, "Multimax test point", urpKey, pairs); this._addCheckBox( container, @@ -138,6 +116,22 @@ const SettingsDialog = WDialog.extend({ window.plugin.wasabee.static.constants.AUTO_LOAD_FAKED ); + if (window.isSmartphone()) { + this._addCheckBox( + container, + wX("USE PANES ON MOBILE"), + "wasabee-setting-usepanes", + window.plugin.wasabee.static.constants.USE_PANES + ); + } + + this._addCheckBox( + container, + wX("SEND ANALYTICS"), + "wasabee-setting-analytics", + window.plugin.wasabee.static.constants.SEND_ANALYTICS_KEY + ); + this._addSelect( container, wX("AUTOLOAD_RATE"), @@ -145,14 +139,6 @@ const SettingsDialog = WDialog.extend({ [1, 100, 250, 500, 750, 1000].map((v) => [v, v]) ); - const serverInfo = L.DomUtil.create("button", "server", container); - serverInfo.textContent = wX("WSERVER", { url: GetWasabeeServer() }); - serverInfo.href = "#"; - L.DomEvent.on(serverInfo, "click", (ev) => { - L.DomEvent.stop(ev); - this.setServer(); - }); - this._addSelect( container, wX("TRAWL SKIP TILES"), @@ -160,20 +146,19 @@ const SettingsDialog = WDialog.extend({ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14].map((v) => [v, v]) ); - if (window.isSmartphone()) { - this._addCheckBox( - container, - wX("USE PANES ON MOBILE"), - "wasabee-setting-usepanes", - window.plugin.wasabee.static.constants.USE_PANES - ); - } + const serverInfo = L.DomUtil.create("button", "server", container); + serverInfo.textContent = wX("WSERVER", { url: GetWasabeeServer() }); + serverInfo.href = "#"; + L.DomEvent.on(serverInfo, "click", (ev) => { + L.DomEvent.stop(ev); + this.setServer(); + }); const skinsButton = L.DomUtil.create("button", null, container); skinsButton.textContent = wX("SKINS_BUTTON"); L.DomEvent.on(skinsButton, "click", (ev) => { L.DomEvent.stop(ev); - const skinDialog = new SkinDialog(window.map); + const skinDialog = new SkinDialog(); skinDialog.enable(); }); @@ -207,9 +192,13 @@ const SettingsDialog = WDialog.extend({ buttons[wX("OK")] = () => { this.closeDialog(); }; + buttons[wX("CLEAROPS BUTTON")] = () => { + this.closeDialog(); + clearAllData(); + }; this.createDialog({ - title: wX("SETTINGS"), + title: wX("SETTINGS_TITLE"), html: container, width: "auto", dialogClass: "settings", @@ -217,12 +206,6 @@ const SettingsDialog = WDialog.extend({ id: window.plugin.wasabee.static.dialogNames.settings, }); }, - - // small-screen versions go in _displaySmallDialog - _displaySmallDialog: function () { - // for this dialog, the small screen is the same as the normal - this._displayDialog(); - }, }); // this line allows other files to import our dialog diff --git a/src/code/dialogs/skinDialog.d.ts b/src/code/dialogs/skinDialog.d.ts new file mode 100644 index 000000000..02bdeb001 --- /dev/null +++ b/src/code/dialogs/skinDialog.d.ts @@ -0,0 +1,3 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +declare class SkinDialog extends WDialog {} +export default SkinDialog; diff --git a/src/code/dialogs/stateDialog.d.ts b/src/code/dialogs/stateDialog.d.ts new file mode 100644 index 000000000..4310debff --- /dev/null +++ b/src/code/dialogs/stateDialog.d.ts @@ -0,0 +1,12 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; +interface StateDialogOptions extends WDialogOptions { + target: WasabeeMarker | WasabeeLink; + opID: string; +} +declare class StateDialog extends WDialog { + options: StateDialogOptions; + constructor(options: StateDialogOptions); +} +export default StateDialog; diff --git a/src/code/dialogs/stateDialog.js b/src/code/dialogs/stateDialog.js index 2f0f7d4e1..e90ce29df 100644 --- a/src/code/dialogs/stateDialog.js +++ b/src/code/dialogs/stateDialog.js @@ -1,9 +1,12 @@ import { WDialog } from "../leafletClasses"; -import WasabeeLink from "../link"; -import WasabeeMarker from "../marker"; +import WasabeeLink from "../model/link"; +import WasabeeMarker from "../model/marker"; import wX from "../wX"; import { getSelectedOperation } from "../selectedOp"; +import PortalUI from "../ui/portal"; +import LinkUI from "../ui/link"; + const StateDialog = WDialog.extend({ statics: { TYPE: "stateDialog", @@ -53,11 +56,10 @@ const StateDialog = WDialog.extend({ } if (this.options.target instanceof WasabeeLink) { - const portal = operation.getPortal(this.options.target.fromPortalId); this._type = "Link"; - this._name = wX("LINK STATE PROMPT", portal.name); + this._name = wX("LINK STATE PROMPT"); divtitle.appendChild( - this.options.target.displayFormat(operation, this._smallScreen) + LinkUI.displayFormat(this.options.target, operation) ); const t = L.DomUtil.create("label", null); t.textContent = wX("LINK STATE"); @@ -67,8 +69,8 @@ const StateDialog = WDialog.extend({ if (this.options.target instanceof WasabeeMarker) { const portal = operation.getPortal(this.options.target.portalId); this._type = "Marker"; - this._name = wX("MARKER STATE PROMPT", portal.name); - divtitle.appendChild(portal.displayFormat(this._smallScreen)); + this._name = wX("MARKER STATE PROMPT"); + divtitle.appendChild(PortalUI.displayFormat(portal)); const t = L.DomUtil.create("label", null); t.textContent = wX("MARKER STATE"); menu.prepend(t); diff --git a/src/code/dialogs/teamListDialog.d.ts b/src/code/dialogs/teamListDialog.d.ts new file mode 100644 index 000000000..883317201 --- /dev/null +++ b/src/code/dialogs/teamListDialog.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class TeamListDialog extends WDialog {} +export default TeamListDialog; diff --git a/src/code/dialogs/teamListDialog.js b/src/code/dialogs/teamListDialog.js index a3f3f8720..5c0b66e63 100644 --- a/src/code/dialogs/teamListDialog.js +++ b/src/code/dialogs/teamListDialog.js @@ -1,5 +1,5 @@ import { WDialog } from "../leafletClasses"; -import WasabeeMe from "../me"; +import WasabeeMe from "../model/me"; import Sortable from "../sortable"; import { SetTeamState, @@ -9,11 +9,11 @@ import { SetTeamLoadWD, } from "../server"; import PromptDialog from "./promptDialog"; -import AuthDialog from "./authDialog"; import TeamMembershipList from "./teamMembershipList"; import ConfirmDialog from "./confirmDialog"; import ManageTeamDialog from "./manageTeamDialog"; import wX from "../wX"; +import { displayError, displayInfo } from "../error"; const TeamListDialog = WDialog.extend({ statics: { @@ -22,7 +22,7 @@ const TeamListDialog = WDialog.extend({ addHooks: async function () { WDialog.prototype.addHooks.call(this); - this._me = await WasabeeMe.waitGet(true); // no cache + this._me = await WasabeeMe.waitGet(true, true); // no cache unless server error window.map.on("wasabee:teams", this.update, this); window.map.on("wasabee:logout", this.closeDialog, this); this._displayDialog(); @@ -34,9 +34,9 @@ const TeamListDialog = WDialog.extend({ window.map.off("wasabee:logout", this.closeDialog, this); }, - update: async function () { + update: function () { if (!this._enabled) return; - this._me = await WasabeeMe.waitGet(); // cache is fine -- this can probably be removed + this._me = WasabeeMe.localGet(); this.setContent(this._buildContent()); }, @@ -61,45 +61,45 @@ const TeamListDialog = WDialog.extend({ { name: wX("TEAM STATE"), value: (team) => team.State, - sort: (a, b) => a.localeCompare(b), format: (row, value, obj) => { const link = L.DomUtil.create("a", null, row); - let curstate = obj.State; - link.textContent = curstate; - if (curstate == "On") L.DomUtil.addClass(link, "enl"); + link.textContent = value + ? wX("dialog.common.on") + : wX("dialog.common.off"); + if (value) L.DomUtil.addClass(link, "enl"); link.onclick = async () => { - await this.toggleTeam(obj.ID, curstate); + await this.toggleTeam(obj.ID, value); this.update(); }; }, }, { - name: "Share W-D Keys", + name: wX("dialog.team_list.share_wd_keys"), value: (team) => team.ShareWD, - sort: (a, b) => a.localeCompare(b), format: (row, value, obj) => { const link = L.DomUtil.create("a", null, row); - let curshare = obj.ShareWD; - link.textContent = curshare; - if (curshare == "On") L.DomUtil.addClass(link, "enl"); + link.textContent = value + ? wX("dialog.common.on") + : wX("dialog.common.off"); + if (value) L.DomUtil.addClass(link, "enl"); link.onclick = async () => { - await this.toggleShareWD(obj.ID, curshare); + await this.toggleShareWD(obj.ID, value); this.update(); window.map.fire("wasabee:defensivekeys"); }; }, }, { - name: "Load W-D Keys", + name: wX("dialog.team_list.load_wd_keys"), value: (team) => team.LoadWD, - sort: (a, b) => a.localeCompare(b), format: (row, value, obj) => { const link = L.DomUtil.create("a", null, row); - let curload = obj.LoadWD; - link.textContent = curload; - if (curload == "On") L.DomUtil.addClass(link, "enl"); + link.textContent = value + ? wX("dialog.common.on") + : wX("dialog.common.off"); + if (value) L.DomUtil.addClass(link, "enl"); link.onclick = async () => { - await this.toggleLoadWD(obj.ID, curload); + await this.toggleLoadWD(obj.ID, value); this.update(); window.map.fire("wasabee:defensivekeys"); }; @@ -107,18 +107,18 @@ const TeamListDialog = WDialog.extend({ }, { name: "", - value: (team) => team.State, + value: () => "", sort: null, format: (row, value, obj) => { const link = L.DomUtil.create("a", null, row); link.textContent = ""; - if (this._me.GoogleID != obj.Owner) { + if (this._me.id != obj.Owner) { link.textContent = wX("LEAVE"); L.DomEvent.on(link, "click", (ev) => { L.DomEvent.stop(ev); const cd = new ConfirmDialog({ - title: `Leave ${obj.Name}?`, - label: `If you leave ${obj.Name} you cannot rejoin unless the owner re-adds you.`, + title: wX("dialog.leave_team.title", { teamName: obj.Name }), + label: wX("dialog.leave_team.text", { teamName: obj.Name }), type: "team", callback: async () => { try { @@ -156,13 +156,11 @@ const TeamListDialog = WDialog.extend({ _displayDialog: function () { if (!this._me) { this.disable(); - const ad = new AuthDialog(); - ad.enable(); return; } const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; buttons[wX("NEW_TEAM")] = () => { @@ -172,16 +170,16 @@ const TeamListDialog = WDialog.extend({ callback: async () => { const newname = p.inputField.value; if (!newname) { - alert(wX("NAME_REQ")); + displayError(wX("NAME_REQ")); return; } try { await newTeamPromise(newname); - alert(wX("TEAM_CREATED", { teamName: newname })); + displayInfo(wX("TEAM_CREATED", { teamName: newname })); this._me = await WasabeeMe.waitGet(true); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } window.map.fire("wasabee:teams"); }, @@ -202,40 +200,37 @@ const TeamListDialog = WDialog.extend({ }, toggleTeam: async function (teamID, currentState) { - let newState = "Off"; - if (currentState == "Off") newState = "On"; + const newState = currentState ? "Off" : "On"; try { await SetTeamState(teamID, newState); this._me = await WasabeeMe.waitGet(true); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } return newState; }, toggleShareWD: async function (teamID, currentState) { - let newState = "Off"; - if (currentState == "Off") newState = "On"; + const newState = currentState ? "Off" : "On"; try { await SetTeamShareWD(teamID, newState); await WasabeeMe.waitGet(true); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } return newState; }, toggleLoadWD: async function (teamID, currentState) { - let newState = "Off"; - if (currentState == "Off") newState = "On"; + const newState = currentState ? "Off" : "On"; try { await SetTeamLoadWD(teamID, newState); await WasabeeMe.waitGet(true); } catch (e) { console.error(e); - alert(e.toString()); + displayError(e); } return newState; }, diff --git a/src/code/dialogs/teamMembershipList.d.ts b/src/code/dialogs/teamMembershipList.d.ts new file mode 100644 index 000000000..ce212b909 --- /dev/null +++ b/src/code/dialogs/teamMembershipList.d.ts @@ -0,0 +1,10 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; + +interface TeamMembershipListOptions extends WDialogOptions { + teamID: string; +} +declare class TeamMembershipList extends WDialog { + options: TeamMembershipListOptions; + constructor(options: TeamMembershipListOptions); +} +export default TeamMembershipList; diff --git a/src/code/dialogs/teamMembershipList.js b/src/code/dialogs/teamMembershipList.js index 7a47146ce..de39c565f 100644 --- a/src/code/dialogs/teamMembershipList.js +++ b/src/code/dialogs/teamMembershipList.js @@ -1,8 +1,11 @@ import { WDialog } from "../leafletClasses"; import Sortable from "../sortable"; -import WasabeeTeam from "../team"; +import WasabeeTeam from "../model/team"; import wX from "../wX"; +import AgentUI from "../ui/agent"; +import { displayError } from "../error"; + const TeamMembershipList = WDialog.extend({ statics: { TYPE: "teamMembershipList", @@ -14,65 +17,72 @@ const TeamMembershipList = WDialog.extend({ addHooks: function () { WDialog.prototype.addHooks.call(this); + window.map.on("wasabee:team:update", this.update, this); window.map.on("wasabee:logout", this.closeDialog, this); this._displayDialog().catch((e) => { console.error(e); - alert(e.toString()); + displayError(e); }); }, removeHooks: function () { WDialog.prototype.removeHooks.call(this); + window.map.off("wasabee:team:update", this.update, this); window.map.off("wasabee:logout", this.closeDialog, this); }, _displayDialog: async function () { - const table = this._setupTable(); + this._table = this._setupTable(); const team = await WasabeeTeam.get(this.options.teamID, 10); // max cache age of 10 seconds - table.items = team.getAgents(); + this._table.items = team.agents; const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; this.createDialog({ title: team.name, - html: table.table, + html: this._table.table, width: "auto", dialogClass: "teamlist", buttons: buttons, }); }, + update: async function () { + const team = await WasabeeTeam.get(this.options.teamID, 10); + this._table.items = team.agents; + this.setTitle(team.name); + }, + _setupTable: function () { const table = new Sortable(); table.fields = [ { name: wX("AGENT"), - value: (agent) => agent.name, + value: (agent) => agent.getName(), sort: (a, b) => a.localeCompare(b), - format: async (cell, value, agent) => - cell.appendChild(await agent.formatDisplay(this.options.teamID)), + format: (cell, value, agent) => + cell.appendChild(AgentUI.formatDisplay(agent)), }, { - name: wX("SQUAD"), - value: (agent) => agent.squad, + name: wX("COMMENT"), + value: (agent) => agent.comment, sort: (a, b) => a.localeCompare(b), - // , format: (cell, value) => (cell.textContent = value) }, { - name: "Sharing Location", - value: (agent) => agent.state, + name: wX("dialog.team_members.location"), + value: (agent) => agent.shareLocation, sort: (a, b) => a.localeCompare(b), format: (cell, value) => { if (value) cell.textContent = "βœ…"; }, }, { - name: "Sharing W-D Keys", - value: (agent) => agent.ShareWD, + name: wX("dialog.team_members.wd_keys"), + value: (agent) => agent.shareWDKeys, sort: (a, b) => a.localeCompare(b), format: (cell, value) => { if (value) cell.textContent = "βœ…"; diff --git a/src/code/dialogs/trawl.d.ts b/src/code/dialogs/trawl.d.ts new file mode 100644 index 000000000..617a8332c --- /dev/null +++ b/src/code/dialogs/trawl.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class TrawlDialog extends WDialog {} +export default TrawlDialog; diff --git a/src/code/dialogs/trawl.js b/src/code/dialogs/trawl.js index 569ca5939..b2516a6ab 100644 --- a/src/code/dialogs/trawl.js +++ b/src/code/dialogs/trawl.js @@ -3,6 +3,9 @@ import wX from "../wX"; import { getSelectedOperation } from "../selectedOp"; import { blockerAutomark } from "../uiCommands"; import VLatLon from "geodesy/latlon-ellipsoidal-vincenty"; +import WasabeeMarker from "../model/marker"; +import WasabeeBlocker from "../model/blocker"; +import { displayInfo } from "../error"; const TrawlerDialog = WDialog.extend({ statics: { @@ -43,14 +46,14 @@ const TrawlerDialog = WDialog.extend({ const container = L.DomUtil.create("div", "container"); const warning = L.DomUtil.create("label", null, container); - warning.textContent = wX("TRAWLING", tiles); + warning.textContent = wX("TRAWLING"); const stat = L.DomUtil.create("div", null, container); this.remaining = L.DomUtil.create("span", null, stat); this.remaining.textContent = wX("TRAWL_REMAINING", { count: tiles }); // same as dialogs/settings.js const trawlTitle = L.DomUtil.create("label", null, container); - trawlTitle.textContent = "Trawl Skip Tiles"; + trawlTitle.textContent = wX("TRAWL SKIP TILES"); const trawlSelect = L.DomUtil.create("select", null, container); const tss = Number( localStorage[window.plugin.wasabee.static.constants.TRAWL_SKIP_STEPS] @@ -76,7 +79,7 @@ const TrawlerDialog = WDialog.extend({ const content = this._buildContent(); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog("close"); }; @@ -185,7 +188,7 @@ const TrawlerDialog = WDialog.extend({ window.removeHook("mapDataRefreshEnd", this._mapRefreshHook); if (this.options.automark) blockerAutomark(getSelectedOperation()); this.closeDialog(); - alert("trawl done"); + displayInfo("trawl done"); }, }); @@ -197,11 +200,13 @@ const TrawlDialog = WDialog.extend({ // WDialog is a leaflet L.Handler, which takes add/removeHooks addHooks: function () { WDialog.prototype.addHooks.call(this); + window.map.on("wasabee:op:select", this.closeDialog, this); this._displayDialog(); }, // define our work in _displayDialog _displayDialog: function () { + const operation = getSelectedOperation(); const container = L.DomUtil.create("div", "container"); const options = L.DomUtil.create("div", null, container); @@ -221,15 +226,19 @@ const TrawlDialog = WDialog.extend({ this.automark.checked = false; this.automark.id = "wasabee-trawl-automark"; + if (!operation.canWrite()) { + options.style.display = "none"; + } + const warning = L.DomUtil.create("h4", null, container); warning.textContent = wX("TRAWL WARNING"); const button = L.DomUtil.create("button", null, container); button.textContent = wX("TRAWL"); - L.DomEvent.on(button, "click", () => { + L.DomEvent.on(button, "click", async () => { const op = getSelectedOperation(); if (clearMarkers.checked == true) this._clearMarkers(); - op.blockers = Array(); + await WasabeeBlocker.removeBlockers(op.ID); const points = this._getTrawlPoints(); const td = new TrawlerDialog({ points: points, @@ -244,9 +253,9 @@ const TrawlDialog = WDialog.extend({ crazyWarning.textContent = wX("TRAWL_BULK_LOAD_WARNING"); const crazyButton = L.DomUtil.create("button", null, container); crazyButton.textContent = wX("TRAWL_BULK_LOAD"); - L.DomEvent.on(crazyButton, "click", () => { + L.DomEvent.on(crazyButton, "click", async () => { const op = getSelectedOperation(); - op.blockers = Array(); + await WasabeeBlocker.removeBlockers(op.ID); if (clearMarkers.checked == true) this._clearMarkers(); const points = this._getTrawlPoints(); this._bulkLoad(points, 14); @@ -254,7 +263,7 @@ const TrawlDialog = WDialog.extend({ }); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -315,8 +324,8 @@ const TrawlDialog = WDialog.extend({ operation.startBatchMode(); for (const m of operation.markers) { if ( - m.type == window.plugin.wasabee.static.constants.MARKER_TYPE_DESTROY || - m.type == window.plugin.wasabee.static.constants.MARKER_TYPE_VIRUS + m.type == WasabeeMarker.constants.MARKER_TYPE_DESTROY || + m.type == WasabeeMarker.constants.MARKER_TYPE_VIRUS ) operation.removeMarker(m); } @@ -362,7 +371,7 @@ const TrawlDialog = WDialog.extend({ // render the results mdr.pauseRenderQueue(false); - this.bulkAlert = alert( + this.bulkAlert = displayInfo( "please wait until status says 'done'; If the first didn't trigger a load, close this dialog and try again" ); }, @@ -371,7 +380,7 @@ const TrawlDialog = WDialog.extend({ if (this.automark.checked == true) blockerAutomark(getSelectedOperation()); window.mapDataRequest.debugTiles = this.oldDebugTiles; this.bulkAlert.dialog("close"); - alert("bulk data load done"); + displayInfo("bulk data load done"); window.removeHook("mapDataRefreshEnd", this._mapRefreshHook); }, }); diff --git a/src/code/dialogs/wasabeeDlist.d.ts b/src/code/dialogs/wasabeeDlist.d.ts new file mode 100644 index 000000000..8b6520f10 --- /dev/null +++ b/src/code/dialogs/wasabeeDlist.d.ts @@ -0,0 +1,4 @@ +import { WDialog } from "../leafletClasses"; + +declare class WasabeeDList extends WDialog {} +export default WasabeeDList; diff --git a/src/code/dialogs/wasabeeDlist.js b/src/code/dialogs/wasabeeDlist.js index 9e99bcea9..042736ac1 100644 --- a/src/code/dialogs/wasabeeDlist.js +++ b/src/code/dialogs/wasabeeDlist.js @@ -1,10 +1,12 @@ import { WDialog } from "../leafletClasses"; import Sortable from "../sortable"; import wX from "../wX"; -import WasabeeMe from "../me"; -import WasabeePortal from "../portal"; +import WasabeeMe from "../model/me"; +import WasabeePortal from "../model/portal"; import { getAgentWasabeeDkeys } from "../wd"; +import PortalUI from "../ui/portal"; + const WasabeeDList = WDialog.extend({ statics: { TYPE: "wasabeeDList", @@ -35,7 +37,7 @@ const WasabeeDList = WDialog.extend({ const sortable = await this.getListDialogContent(); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -66,7 +68,7 @@ const WasabeeDList = WDialog.extend({ lat: n.Lat, lng: n.Lng, }); - cell.appendChild(p.displayFormat(this._smallScreen)); + cell.appendChild(PortalUI.displayFormat(p)); }, }, { @@ -88,7 +90,7 @@ const WasabeeDList = WDialog.extend({ ]; content.sortBy = 0; - content.items = await getAgentWasabeeDkeys(this._me.GoogleID); + content.items = await getAgentWasabeeDkeys(this._me.id); return content; }, diff --git a/src/code/dialogs/zoneDialog.d.ts b/src/code/dialogs/zoneDialog.d.ts new file mode 100644 index 000000000..d625cd983 --- /dev/null +++ b/src/code/dialogs/zoneDialog.d.ts @@ -0,0 +1,14 @@ +import { WDialog } from "../leafletClasses"; + +declare class ZoneDialog extends WDialog { + ZonedrawHandler: ZonedrawHandler; +} +export default ZoneDialog; + +interface ZonedrawHandlerOptions { + parent: ZoneDialog; +} +declare class ZonedrawHandler extends L.Handler { + zoneID: number; + constructor(options: ZonedrawHandlerOptions); +} diff --git a/src/code/dialogs/zoneDialog.js b/src/code/dialogs/zoneDialog.js index 1ca3427a1..a954a1b0b 100644 --- a/src/code/dialogs/zoneDialog.js +++ b/src/code/dialogs/zoneDialog.js @@ -3,7 +3,7 @@ import wX from "../wX"; import { getSelectedOperation } from "../selectedOp"; import { addToColorList } from "../skin"; import ZoneSetColorDialog from "./zoneSetColor"; -import { convertColorToHex } from "../auxiliar"; +import { appendFAIcon, convertColorToHex } from "../auxiliar"; import { setMarkersToZones, setLinksToZones } from "../uiCommands"; const ZoneDialog = WDialog.extend({ @@ -16,11 +16,7 @@ const ZoneDialog = WDialog.extend({ WDialog.prototype.addHooks.call(this); window.map.on("wasabee:op:change wasabee:op:select", this.update, this); - if (this._smallScreen) { - this._displaySmallDialog(); - } else { - this._displayDialog(); - } + this._displayDialog(); }, removeHooks: function () { @@ -38,7 +34,7 @@ const ZoneDialog = WDialog.extend({ const html = this.buildList(); const buttons = {}; - buttons[wX("OK")] = () => { + buttons[wX("CLOSE")] = () => { this.closeDialog(); }; @@ -55,7 +51,7 @@ const ZoneDialog = WDialog.extend({ }; this.createDialog({ - title: "Zones", + title: wX("dialog.zones.title"), html: html, width: "auto", dialogClass: "zone", @@ -64,10 +60,6 @@ const ZoneDialog = WDialog.extend({ }); }, - _displaySmallDialog: function () { - this._displayDialog(); - }, - buildList: function () { const op = getSelectedOperation(); const canWrite = op.getPermission() === "write"; @@ -78,10 +70,13 @@ const ZoneDialog = WDialog.extend({ L.DomUtil.create("table", "wasabee-table", container) ); const hr = L.DomUtil.create("tr", null, tbody); - L.DomUtil.create("th", null, hr).textContent = "ID"; - L.DomUtil.create("th", null, hr).textContent = "Name"; - L.DomUtil.create("th", null, hr).textContent = "Color"; - if (canWrite) L.DomUtil.create("th", null, hr).textContent = "Commands"; + L.DomUtil.create("th", null, hr).textContent = wX("dialog.zones.id"); + L.DomUtil.create("th", null, hr).textContent = wX("dialog.common.name"); + L.DomUtil.create("th", null, hr).textContent = wX("dialog.zones.color"); + if (canWrite) + L.DomUtil.create("th", null, hr).textContent = wX( + "dialog.common.commands" + ); for (const z of op.zones) { const tr = L.DomUtil.create("tr", null, tbody); @@ -112,11 +107,11 @@ const ZoneDialog = WDialog.extend({ }); if (canWrite) { - const commandcell = L.DomUtil.create("td", null, tr); - + const commandcell = L.DomUtil.create("td", "actions", tr); const color = L.DomUtil.create("a", null, commandcell); - color.textContent = "πŸ–Œ"; color.href = "#"; + color.title = wX("dialog.zones.color_links"); + appendFAIcon("palette", color); L.DomEvent.on(color, "click", (ev) => { L.DomEvent.stop(ev); const zoneSetColorDialog = new ZoneSetColorDialog({ @@ -126,40 +121,50 @@ const ZoneDialog = WDialog.extend({ }); if (z.id != 1) { const del = L.DomUtil.create("a", null, commandcell); - del.textContent = "πŸ—‘"; del.href = "#"; + del.title = wX("dialog.common.delete"); + appendFAIcon("trash", del); L.DomEvent.on(del, "click", (ev) => { L.DomEvent.stop(ev); getSelectedOperation().removeZone(z.id); }); } - if (z.points.length == 0) { - const addPoints = L.DomUtil.create("a", null, commandcell); - addPoints.textContent = " πŸ–"; - addPoints.href = "#"; - L.DomEvent.on(addPoints, "click", (ev) => { - L.DomEvent.stop(ev); - this.ZonedrawHandler.zoneID = z.id; - this.ZonedrawHandler.enable(); - }); - } else { - const delPoints = L.DomUtil.create("a", null, commandcell); - delPoints.textContent = " 🧽"; - delPoints.href = "#"; - L.DomEvent.on(delPoints, "click", (ev) => { - L.DomEvent.stop(ev); - getSelectedOperation().removeZonePoints(z.id); - }); - } - if (this.ZonedrawHandler && this.ZonedrawHandler.enabled()) { + if ( + this.ZonedrawHandler && + this.ZonedrawHandler.zoneID === z.id && + this.ZonedrawHandler.enabled() + ) { const stopDrawing = L.DomUtil.create("a", null, commandcell); stopDrawing.href = "#"; - stopDrawing.textContent = " πŸ›‘"; + stopDrawing.title = wX("dialog.zones.stop_drawing"); + appendFAIcon("ban", stopDrawing); L.DomEvent.on(stopDrawing, "click", (ev) => { L.DomEvent.stop(ev); this.ZonedrawHandler.disable(); this.update(); }); + } else { + if (z.points.length == 0) { + const addPoints = L.DomUtil.create("a", null, commandcell); + addPoints.title = wX("dialog.zones.draw_zone_shape"); + appendFAIcon("pen", addPoints); + addPoints.href = "#"; + L.DomEvent.on(addPoints, "click", (ev) => { + L.DomEvent.stop(ev); + this.ZonedrawHandler.zoneID = z.id; + this.ZonedrawHandler.enable(); + this.update(); + }); + } else { + const delPoints = L.DomUtil.create("a", null, commandcell); + delPoints.title = wX("dialog.zones.delete_zone_shape"); + appendFAIcon("eraser", delPoints); + delPoints.href = "#"; + L.DomEvent.on(delPoints, "click", (ev) => { + L.DomEvent.stop(ev); + getSelectedOperation().removeZonePoints(z.id); + }); + } } } } @@ -199,7 +204,6 @@ const ZonedrawHandler = L.Handler.extend({ window.map.on("click", this._click, this); window.map.on("wasabee:op:select", this._opchange, this); window.map.on("keyup", this._keyUpListener, this); - window.map.on("mousemove", this._onMouseMove, this); }, removeHooks: function () { @@ -210,7 +214,6 @@ const ZonedrawHandler = L.Handler.extend({ window.map.off("click", this._click, this); window.map.off("wasabee:op:select", this._opchange, this); window.map.off("keyup", this._keyUpListener, this); - window.map.off("mousemove", this._onMouseMove, this); }, _opchange: function () { @@ -236,14 +239,7 @@ const ZonedrawHandler = L.Handler.extend({ getSelectedOperation().addZonePoint(this.zoneID, e.latlng); }, - _onMouseMove: function (e) { - if (e.latlng) { - this._tooltip.updatePosition(e.latlng); - } - L.DomEvent.preventDefault(e.originalEvent); - }, - _getTooltipText: function () { - return { text: wX("ZONE_DRAW") }; + return wX("ZONE_DRAW"); }, }); diff --git a/src/code/dialogs/zoneSetColor.d.ts b/src/code/dialogs/zoneSetColor.d.ts new file mode 100644 index 000000000..efaeb6905 --- /dev/null +++ b/src/code/dialogs/zoneSetColor.d.ts @@ -0,0 +1,11 @@ +import { WDialog, WDialogOptions } from "../leafletClasses"; +import type WasabeeZone from "../model/zone"; + +interface ZoneSetColorDialogOptions extends WDialogOptions { + zone: WasabeeZone; +} +declare class ZoneSetColorDialog extends WDialog { + options: ZoneSetColorDialogOptions; + constructor(options: ZoneSetColorDialogOptions); +} +export default ZoneSetColorDialog; diff --git a/src/code/dialogs/zoneSetColor.js b/src/code/dialogs/zoneSetColor.js index a6d092d19..12ecc3bc4 100644 --- a/src/code/dialogs/zoneSetColor.js +++ b/src/code/dialogs/zoneSetColor.js @@ -1,6 +1,7 @@ import { WDialog } from "../leafletClasses"; import { getSelectedOperation } from "../selectedOp"; import { addToColorList } from "../skin"; +import wX from "../wX"; const ZoneSetColorDialog = WDialog.extend({ statics: { @@ -20,7 +21,7 @@ const ZoneSetColorDialog = WDialog.extend({ _displayDialog: function () { this.createDialog({ - title: "Zone color", + title: wX("dialog.zone_color.title"), html: this._buildContent(), width: "auto", dialogClass: "zone-color", @@ -30,8 +31,9 @@ const ZoneSetColorDialog = WDialog.extend({ _buildContent: function () { const container = L.DomUtil.create("div", "container"); const desc = L.DomUtil.create("div", "desc", container); - desc.textContent = - "Set the color of all links in zone " + this.options.zone.name; + desc.textContent = wX("dialog.zone_color.text", { + zoneName: this.options.zone.name, + }); const picker = L.DomUtil.create("input", "picker", container); picker.type = "color"; diff --git a/src/code/error.ts b/src/code/error.ts new file mode 100644 index 000000000..f8661782b --- /dev/null +++ b/src/code/error.ts @@ -0,0 +1,73 @@ +import wX from "./wX"; + +interface IServerError { + code: number; + text: string; + error?: string; +} + +export function displayInfo(content: string | HTMLElement, isHTML?: boolean) { + return window.dialog({ + title: "Wasabee info", + text: isHTML ? null : content.toString(), + html: isHTML ? content : null, + }); +} + +export function displayWarning( + content: string | HTMLElement, + isHTML?: boolean +) { + return window.dialog({ + title: "Wasabee warning", + text: isHTML ? null : content.toString(), + html: isHTML ? content : null, + }); +} + +export function displayError(err: { toString(): string }) { + return window.dialog({ + title: "Wasabee error", + text: err.toString(), + }); +} + +// no stacktrace error +export class ServerError implements IServerError { + code: number; + text: string; + error?: string; + + constructor(obj: IServerError) { + this.code = obj.code; + this.text = obj.text; + this.error = obj.error; + + if (!this.code) { + this.code = -1; + this.text = "Unknown error"; + } + } + + toString() { + switch (this.code) { + case 401: + if (this.error) return wX("NOT LOGGED IN", this as { error: string }); + return wX("NOT LOGGED IN SHORT"); + case 403: + if (this.error) return wX("PERM DENIED", this as { error: string }); + return wX("PERM DENIED SHORT"); + case 410: + if (this.error) + return wX("NO LONGER AVAILABLE", this as { error: string }); + return wX("NO LONGER AVAILABLE SHORT"); + case 412: + // for internal use only + if (this.error) return "Mismatch version: " + this.error; + return "Mismatch version"; + default: + if (this.error) return this.text + ": " + this.error; + return this.text; + } + } +} diff --git a/src/code/firebaseSupport.js b/src/code/firebaseSupport.js deleted file mode 100644 index d9f7fcf5a..000000000 --- a/src/code/firebaseSupport.js +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Since we can't run a service worker from https://intel.ingress.com, we - * are creating an iframe that loads content hosted on server.wasabee.com. - * This way we can setup a service worker under a domain we control and - * simply pass the messages along using window.parent.postMessage. - */ -import { drawSingleTeam, drawSingleAgent } from "./mapDrawing"; -import { opPromise, GetWasabeeServer } from "./server"; -import { - makeSelectedOperation, - getSelectedOperation, - removeOperation, - loadNewDefaultOp, -} from "./selectedOp"; -import { updateLocalOp } from "./uiCommands"; -import WasabeeOp from "./operation"; -import WasabeePortal from "./portal"; - -// TODO: use a dedicated message channel: https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API/Using_channel_messaging - -const frameID = "wasabeeFirebaseFrame"; - -export function initFirebase() { - const server = GetWasabeeServer(); - - const iframe = L.DomUtil.create("iframe"); - iframe.width = 0; - iframe.height = 0; - iframe.src = server + "/static/firebase/index.html"; - iframe.id = frameID; - - $(document.body).append(iframe); - - window.addEventListener("message", async (event) => { - // ignore anything not from our server - if (event.origin.indexOf(server) === -1) return; - - const operation = getSelectedOperation(); - switch (event.data.data.cmd) { - case "Agent Location Change": - if (event.data.data.gid != null) { - console.debug( - "firebase update of single agent location: ", - event.data.data - ); - drawSingleAgent(event.data.data.gid); - } else { - console.debug( - "firebase update of whole team location: ", - event.data.data - ); - drawSingleTeam(event.data.data.msg); - } - break; - case "Delete": - console.warn("server requested op delete: ", event.data.data.opID); - if (event.data.data.opID == operation.ID) await loadNewDefaultOp(); - await removeOperation(event.data.data.opID); - break; - case "Generic Message": - alert(JSON.stringify(event.data.data)); - break; - case "Login": - console.debug("server reported teammate login: ", event.data.data.gid); - window.map.fire("wasabee:agentlocations"); - break; - case "Map Change": - if (!window.plugin.wasabee._updateList.has(event.data.data.updateID)) { - try { - // update the list to avoid race from slow network - window.plugin.wasabee._updateList.set( - event.data.data.updateID, - Date.now() - ); - const localop = await WasabeeOp.load(event.data.data.opID); - const refreshed = await opPromise(event.data.data.opID); - const reloadSOp = await updateLocalOp(localop, refreshed); - if (reloadSOp) { - console.log( - "firebase trigger reload of current op: ", - event.data.data - ); - await makeSelectedOperation(refreshed.ID); - } else { - console.debug( - "firebase trigger update of op", - event.data.data.opID - ); - } - } catch (e) { - console.error(e); - } - } else { - console.debug( - "skipping firebase requested update of op since it was our change", - event.data.data.updateID - ); - } - break; - case "Target": - try { - const target = JSON.parse(event.data.data.msg); - const raw = { - id: target.ID, - name: target.Name, - lat: target.Lat, - lng: target.Lon, - }; - const portal = new WasabeePortal(raw); - const f = portal.displayFormat(); - alert(f.outerHTML + "
Sent by: " + target.Sender, true); - } catch (e) { - console.error(e); - } - break; - default: - console.warn("unknown firebase command: ", event.data.data); - } - }); -} - -export function postToFirebase(message) { - // prevent analytics data from being sent if not enabled by the user: GPDR - /* if ( - message.id == "analytics" && - localStorage[window.plugin.wasabee.static.constants.SEND_ANALYTICS_KEY] != - "true" - ) - return; */ - - message.app_name = "Wasabee-IITC"; - message.app_version = window.plugin.wasabee.info.version; - - window.frames[frameID].contentWindow.postMessage(message, GetWasabeeServer()); -} diff --git a/src/code/firebaseSupport.ts b/src/code/firebaseSupport.ts new file mode 100644 index 000000000..60cc31e75 --- /dev/null +++ b/src/code/firebaseSupport.ts @@ -0,0 +1,357 @@ +/* + * Since we can't run a service worker from https://intel.ingress.com, we + * are creating an iframe that loads content hosted on server.wasabee.com. + * This way we can setup a service worker under a domain we control and + * simply pass the messages along using window.parent.postMessage. + */ +import { drawSingleTeam } from "./mapDrawing"; +import { + opPromise, + GetWasabeeServer, + getLinkPromise, + getMarkerPromise, +} from "./server"; +import { + makeSelectedOperation, + removeOperation, + changeOpIfNeeded, + getSelectedOperation, +} from "./selectedOp"; +import { updateLocalOp } from "./uiCommands"; +import WasabeeOp from "./model/operation"; +import WasabeePortal from "./model/portal"; + +import PortalUI from "./ui/portal"; +import { displayInfo, displayWarning } from "./error"; +import WasabeeAgent from "./model/agent"; +import { getJWT } from "./auth"; +import WasabeeMe from "./model/me"; +import { constants } from "./static"; +import WasabeeLink from "./model/link"; +import WasabeeMarker from "./model/marker"; +import wX from "./wX"; + +// TODO: use a dedicated message channel: https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API/Using_channel_messaging + +const frameID = "wasabeeFirebaseFrame"; + +const channel = new MessageChannel(); +const port = channel.port1; + +export function initFirebase() { + const iframe = L.DomUtil.create("iframe"); + iframe.width = "0"; + iframe.height = "0"; + iframe.src = constants.FIREBASE_IFRAME; + iframe.id = frameID; + + iframe.addEventListener("load", () => { + port.onmessage = (ev) => { + if (ev.data === "ready") { + port.onmessage = onMessage; + if (WasabeeMe.isLoggedIn()) { + postToFirebase({ + id: "wasabeeLogin", + method: "auto", + }); + } + } + }; + iframe.contentWindow.postMessage("init", "*", [channel.port2]); + }); + + $(document.body).append(iframe); +} + +async function onMessage( + event: MessageEvent<{ data: WMessage } | "permission-blocked"> +) { + if (event.data === "permission-blocked") { + displayWarning( + wX("dialog.firebase.setup", { + url: `${constants.FIREBASE_IFRAME}`, + }), + true + ); + return; + } + const data = event.data.data; + switch (data.cmd) { + case "Agent Location Change": + console.debug("firebase update of whole team location: ", data); + drawSingleTeam(data.msg); + break; + case "Delete": + console.warn("server requested op delete: ", data.opID); + await removeOperation(data.opID); + await changeOpIfNeeded(); + break; + case "Generic Message": + { + const agent = await WasabeeAgent.get(data.sender); + const name = agent ? agent.name : "[unknown sender]"; + displayInfo( + wX("dialog.team_message", { message: data.msg, sender: name }) + ); + } + break; + case "Login": + console.debug("server reported teammate login: ", data.gid); + window.map.fire("wasabee:agentlocations"); + break; + case "Link Assignment Change": + // fallthrough + case "Link Status Change": + // fallthrough + case "Marker Assignment Change": + // fallthrough + case "Task Status Change": + // fallthrough + case "Task Assignment Change": + // fallthrough + case "Marker Status Change": + // fallthrough + case "Map Change": + opDataChange(data); + break; + case "Target": + try { + const target = JSON.parse(data.msg); + const raw = { + id: target.ID, + name: target.Name, + lat: target.Lat, + lng: target.Lon, + }; + const portal = new WasabeePortal(raw); + const f = PortalUI.displayFormat(portal); + displayInfo(f.outerHTML + "
Sent by: " + target.Sender, true); + } catch (e) { + console.error(e); + } + break; + default: + console.warn("unknown firebase command: ", data); + } +} + +async function opDataChange( + data: + | LinkAssignment + | LinkState + | MarkerAssignment + | MarkerState + | TaskAssignment + | TaskState + | OpChange +) { + let uid = data.updateID; + if (data.cmd !== "Map Change") uid += data.cmd; + + if (window.plugin.wasabee._updateList.has(uid)) { + console.debug( + "skipping firebase requested update of op since it was our change", + data.cmd, + data.updateID + ); + return; + } + // update the list to avoid race from slow network + window.plugin.wasabee._updateList.set(uid, Date.now()); + const operation = WasabeeOp.load(data.opID); + if (!operation) { + console.warn("Got operation change for an unknown op", data.opID); + return; + } + + const sop = getSelectedOperation(); + const cur = sop.ID === data.opID; + + switch (data.cmd) { + case "Link Assignment Change": + if (cur) handleLinkAssignement(sop, data); + console.log(data); + break; + case "Link Status Change": + if (cur) handleLinkStatus(sop, data); + console.log(data); + break; + case "Marker Assignment Change": + if (cur) handleMarkerAssignement(sop, data); + console.log(data); + break; + case "Marker Status Change": + if (cur) handleMarkerStatus(sop, data); + console.log(data); + break; + case "Map Change": + try { + const localop = await WasabeeOp.load(data.opID); + const refreshed = await opPromise(data.opID); + const reloadSOp = await updateLocalOp(localop, refreshed); + if (reloadSOp) { + console.log("firebase trigger reload of current op: ", data); + await makeSelectedOperation(refreshed.ID); + } else { + console.debug("firebase trigger update of op", data.opID); + } + } catch (e) { + console.error(e); + } + break; + default: + console.log(data); + } +} + +async function handleLinkAssignement( + operation: WasabeeOp, + data: LinkAssignment +) { + const link = new WasabeeLink(await getLinkPromise(data.opID, data.linkID)); + operation.assignLink(link.ID, link.assignedTo); +} + +async function handleLinkStatus(operation: WasabeeOp, data: LinkState) { + const link = new WasabeeLink(await getLinkPromise(data.opID, data.linkID)); + operation.setLinkState(link.ID, link.state); +} + +async function handleMarkerAssignement( + operation: WasabeeOp, + data: MarkerAssignment +) { + const marker = new WasabeeMarker( + await getMarkerPromise(data.opID, data.markerID) + ); + operation.assignMarker(marker.ID, marker.assignedTo); +} + +async function handleMarkerStatus(operation: WasabeeOp, data: MarkerState) { + const marker = new WasabeeMarker( + await getMarkerPromise(data.opID, data.markerID) + ); + operation.setMarkerState(marker.ID, marker.state); +} + +type AgentLocation = { + cmd: "Agent Location Change"; + msg: TeamID; +}; + +type Annoucement = { + cmd: "Generic Message"; + msg: string; + sender: GoogleID; +}; + +type Target = { + cmd: "Target"; + msg: string; +}; + +type Login = { + cmd: "Login"; + gid: GoogleID; +}; + +type DeleteOp = { + cmd: "Delete"; + opID: OpID; +}; + +type Update = { + updateID: string; +}; + +type LinkAssignment = Update & { + cmd: "Link Assignment Change"; + opID: OpID; + linkID: LinkID; + msg: string; +}; + +type LinkState = Update & { + cmd: "Link Status Change"; + opID: OpID; + linkID: LinkID; + msg: string; +}; + +type MarkerAssignment = Update & { + cmd: "Marker Assignment Change"; + opID: OpID; + markerID: MarkerID; + msg: string; +}; + +type MarkerState = Update & { + cmd: "Marker Status Change"; + opID: OpID; + markerID: MarkerID; + msg: string; +}; + +type TaskAssignment = Update & { + cmd: "Task Assignment Change"; + opID: OpID; + taskID: TaskID; + msg: string; +}; + +type TaskState = Update & { + cmd: "Task Status Change"; + opID: OpID; + taskID: TaskID; + msg: string; +}; + +type OpChange = Update & { + cmd: "Map Change"; + opID: OpID; +}; + +type WMessage = + | AgentLocation + | Annoucement + | Target + | Login + | DeleteOp + | LinkAssignment + | LinkState + | MarkerAssignment + | MarkerState + | TaskAssignment + | TaskState + | OpChange; + +interface FirebaseMessage { + id: string; + method: string; + action: string; + error: string; + app_name: string; + app_version: string; + server: string; + jwt: string; +} + +export function postToFirebase(message: Partial) { + // prevent analytics data from being sent if not enabled by the user: GPDR + if ( + message.id == "analytics" && + localStorage[window.plugin.wasabee.static.constants.SEND_ANALYTICS_KEY] != + "true" + ) + return; + + if (message.id == "wasabeeLogin") { + message.server = GetWasabeeServer(); + message.jwt = getJWT(); + } + + message.app_name = "Wasabee-IITC"; + message.app_version = window.plugin.wasabee.info.version; + + port.postMessage(message); +} diff --git a/src/code/global.d.ts b/src/code/global.d.ts new file mode 100644 index 000000000..1bc7a680a --- /dev/null +++ b/src/code/global.d.ts @@ -0,0 +1,14 @@ +declare module "*.css" { + const content: string; + export default content; +} + +declare module "*.json" { + const content: any; + export default content; +} + +declare module "*.svg" { + const content: string; + export default content; +} diff --git a/src/code/images/toolbar_quickdelete.svg b/src/code/images/toolbar_quickdelete.svg new file mode 100644 index 000000000..15035f468 --- /dev/null +++ b/src/code/images/toolbar_quickdelete.svg @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/src/code/index.d.ts b/src/code/index.d.ts new file mode 100644 index 000000000..095943f71 --- /dev/null +++ b/src/code/index.d.ts @@ -0,0 +1,15 @@ +export {}; + +declare global { + type OpID = string; + type PortalID = string; + type TeamID = string; + type TaskID = string; + type LinkID = TaskID; + type MarkerID = TaskID; + type GoogleID = string; + type ZoneID = number; + + const plugin_info: any; + var wasabeewebui: any; +} diff --git a/src/code/init.js b/src/code/init.ts similarity index 70% rename from src/code/init.js rename to src/code/init.ts index 62f39e9e7..dfe37a28b 100644 --- a/src/code/init.js +++ b/src/code/init.ts @@ -1,6 +1,11 @@ +import statics from "./static"; import { initCrossLinks } from "./crosslinks"; -import initServer from "./server"; -import { setupLocalStorage, initSelectedOperation } from "./selectedOp"; +import initServer, { locationPromise } from "./server"; +import { + setupLocalStorage, + initSelectedOperation, + removeNonOwnedOps, +} from "./selectedOp"; import { drawMap, drawAgents, @@ -15,12 +20,44 @@ import { listenForPortalDetails, sendLocation } from "./uiCommands"; import { initSkin, changeSkin } from "./skin"; import { WPane } from "./leafletClasses"; import OperationChecklist from "./dialogs/checklist"; -import WasabeeMe from "./me"; -import WasabeeOp from "./operation"; -import { openDB } from "idb"; +import WasabeeMe from "./model/me"; +import WasabeeOp from "./model/operation"; +import db from "./db"; import polyfill from "./polyfill"; +import { displayError, displayWarning } from "./error"; +import { deleteJWT } from "./auth"; + +import type { FeatureGroup, LayerEvent, LayerGroup } from "leaflet"; +import type { WLAnchor } from "./ui/anchor"; +import type { WLLink } from "./ui/link"; +import type { WLMarker } from "./ui/marker"; +import type { WLAgent } from "./ui/agent"; +import type { WLZone } from "./ui/zone"; +import type { ButtonsControl } from "./leafletClasses"; +import { checkVersion } from "./version"; +import wX from "./wX"; + +type Awaited = T extends PromiseLike ? U : T; +export interface Wasabee { + static: any; + _inited: boolean; + _selectedOp: WasabeeOp; + _updateList: Map; + idb: Awaited; + portalDetailQueue: PortalID[]; + portalLayerGroup: LayerGroup; + linkLayerGroup: LayerGroup; + markerLayerGroup: LayerGroup; + agentLayerGroup: LayerGroup; + zoneLayerGroup: FeatureGroup; + backgroundOpsGroup: LayerGroup; + buttons: ButtonsControl; + defensiveLayers: LayerGroup; + crossLinkLayers: LayerGroup; +} -const Wasabee = window.plugin.wasabee; +const Wasabee: Wasabee = window.plugin.wasabee; +Wasabee.static = statics; window.plugin.wasabee.init = async () => { // polyfill @@ -34,16 +71,23 @@ window.plugin.wasabee.init = async () => { window.iitcBuildDate == undefined || window.iitcBuildDate < "2020-01-18-170317" ) { - alert( + displayError( "Wasabee won't work on this version of IITC; please update to 0.30.1 or newer from https://iitc.app. On desktop, do not use the IITC button, use the TamperMonkey/GreaseMonkey method." ); return; } - await initIdb(); + try { + Wasabee.idb = await db; + } catch (e) { + displayError("Wasabee: unable to access the storage: " + e.toString()); + plugin_info.error = e; //eslint-disable-line + return; + } + Wasabee._selectedOp = null; // the in-memory working op; Wasabee._updateList = new Map(); - Wasabee.portalDetailQueue = new Array(); + Wasabee.portalDetailQueue = []; initSkin(); // can this be moved to the auth dialog? @@ -52,7 +96,7 @@ window.plugin.wasabee.init = async () => { await initSelectedOperation(); initServer(); - const skins = []; + const skins: string[] = []; const ss = localStorage[Wasabee.static.constants.SKIN_KEY]; try { const l = JSON.parse(ss); @@ -115,6 +159,10 @@ window.plugin.wasabee.init = async () => { window.map.on("wasabee:agentlocations", drawAgents); window.map.on("wasabee:logout", drawAgents); + window.map.on("wasabee:logout", removeNonOwnedOps); + + window.map.on("wasabee:logout", deleteJWT); + // when the UI is woken from sleep on many devices window.addResumeFunction(() => { // check if still logged in @@ -148,8 +196,13 @@ window.plugin.wasabee.init = async () => { }); } + // location update on mobile + if (window.plugin.userLocation) { + window.addHook("pluginUserLocation", onLocationChange); + } + // hooks called when layers are enabled/disabled - window.map.on("layeradd", (obj) => { + window.map.on("layeradd", (obj: LayerEvent) => { if ( obj.layer === Wasabee.portalLayerGroup || obj.layer === Wasabee.linkLayerGroup || @@ -163,14 +216,14 @@ window.plugin.wasabee.init = async () => { } }); - window.map.on("layerremove", (obj) => { + window.map.on("layerremove", (obj: LayerEvent) => { if ( obj.layer === Wasabee.portalLayerGroup || obj.layer === Wasabee.linkLayerGroup || obj.layer === Wasabee.markerLayerGroup || obj.layer === Wasabee.zoneLayerGroup ) { - obj.layer.clearLayers(); + (obj.layer as LayerGroup).clearLayers(); } }); @@ -209,16 +262,38 @@ window.plugin.wasabee.init = async () => { window.map.fire("wasabee:defensivekeys"); } - window.map.on("wdialog", (dialog) => { - postToFirebase({ id: "analytics", action: dialog.constructor.TYPE }); + window.map.on("wdialog", (event) => { + postToFirebase({ id: "analytics", action: event.dialogType }); + }); + + checkVersion().then((v) => { + if (v) { + displayWarning(wX("dialog.update_warning")); + } }); }; +let lastUpdate = 0; +function onLocationChange(e: EventUserLocation) { + const { event, data } = e; + if (event !== "onLocationChange" || !data.latlng) return; + + const sl = localStorage[Wasabee.static.constants.SEND_LOCATION_KEY]; + if (sl !== "true") return; + + // do not update more than once per 5s + if (Date.now() - lastUpdate < 5000) return; + + if (!WasabeeMe.isLoggedIn()) return; + locationPromise(data.latlng.lat, data.latlng.lng); + lastUpdate = Date.now(); +} + // this can be moved to auth dialog, no need to init it for people who never log in // and use webpack, rather than importing it ourself function initGoogleAPI() { if (typeof window.gapi !== "undefined") { - alert( + displayError( "Wasabee detected another GAPI instance; there may be authentication issues" ); window.gapi.load("auth2", () => { @@ -241,40 +316,3 @@ function initGoogleAPI() { script ); } - -async function initIdb() { - const version = 2; - - // XXX audit these to make sure all the various indexes are used - Wasabee.idb = await openDB("wasabee", version, { - upgrade(db, oldVersion, newVersion, tx) { - if (oldVersion < 1) { - const agents = db.createObjectStore("agents", { keyPath: "id" }); - agents.createIndex("date", "date"); // last location change - agents.createIndex("fetched", "fetched"); // last pull from server - const teams = db.createObjectStore("teams", { keyPath: "id" }); - teams.createIndex("fetched", "fetched"); // last pull from server - - // do not set an implied key, explicitly set GID/PortalID on insert - // XXX we can do this with a keyPath https://stackoverflow.com/questions/33852508/how-to-create-an-indexeddb-composite-key - // const defensivekeys = db.createObjectStore("defensivekeys"); - const defensivekeys = db.createObjectStore("defensivekeys", { - keyPath: ["GID", "PortalID"], - }); - defensivekeys.createIndex("PortalID", "PortalID"); - defensivekeys.createIndex("Count", "Count"); // To be used to remove 0-count entries - // defensivekeys.createIndex("pk", ["GID", "PortalID"], { unique: true }); - } - if (oldVersion < 2) { - const ops = db.createObjectStore("operations", { keyPath: "ID" }); - ops.createIndex("fetched", "fetched"); - ops.createIndex("server", "server"); - } - /* if (oldVersion < 3) { - const teams = tx.objectStore("teams"); - teams.createIndex("_agents", "_agents[].id"); - } */ - console.debug(newVersion, tx); - }, - }); -} diff --git a/src/code/leafletClasses.d.ts b/src/code/leafletClasses.d.ts new file mode 100644 index 000000000..c0dadaa19 --- /dev/null +++ b/src/code/leafletClasses.d.ts @@ -0,0 +1,95 @@ +/// +/// + +export declare class WTooltip extends L.Class { + _pane: HTMLElement; + _container: HTMLDivElement; + constructor(map: L.Map); + dispose(): void; + updateContent(labelText: string): this; + updatePosition(latlng: L.LatLngExpression): this; + showAsError(): this; + removeError(): this; +} +declare type WPaneOptions = { + paneId: string; + paneName: string; + default?: () => WDialog; +}; +export declare class WPane extends L.Handler { + options: WPaneOptions; + _dialog: WDialog; + _container: HTMLDivElement; + constructor(options: WPaneOptions); + addHooks(): void; + removeHooks(): void; +} +export interface WDialogOptions { + [propName: string]: unknown; +} +export declare class WDialog extends L.Handler { + needWritePermission: boolean; // todo: set static + usePane: boolean; + paneId: string; + options: WDialogOptions; + _smallScreen: boolean; + _dialog: JQuery | null; + _container: HTMLDivElement; + _header: HTMLDivElement; + _content: HTMLDivElement; + _buttons: HTMLDivElement; + constructor(options?: WDialogOptions); + initialize(options?: WDialogOptions); + addHooks(): void; + removeHooks(): void; + onOpChange(): void; + enable(): any; + update(): void; + createDialog(options: DialogOptions): void; + setTitle(title: string): void; + setContent(content: HTMLElement | string): void; + closeDialog(): void; + _isMobile(): boolean; +} +export interface ButtonsControlOptions extends L.ControlOptions { + buttons: Map; + container: HTMLElement; +} +export declare class ButtonsControl extends L.Control { + options: ButtonsControlOptions; + constructor(options: ButtonsControlOptions); + onAdd(): HTMLDivElement; + onRemove(): void; + update(): void; + disableAllExcept(name: any): void; +} +export declare type ButtonOptions = { + text?: string; + html?: HTMLElement; + title?: string; + container?: HTMLElement; + callback: () => void; + context: unknown; + buttonImage?: string; + className?: string; + img?: string; +}; +export declare class WButton extends L.Class { + title: string; + type: string; + needWritePermission: boolean; + _enabled: boolean; + actionsContainer: HTMLElement; + control: ButtonsControl; + button: HTMLAnchorElement; + _container: HTMLElement; + constructor(container: HTMLElement); + update(): void; + _toggleActions(): void; + setControl(control: any): void; + disable(): void; + enable(): void; + setSubActions(actions: ButtonOptions[]): void; + _createButton(options: ButtonOptions): HTMLAnchorElement; +} +export {}; diff --git a/src/code/leafletClasses.js b/src/code/leafletClasses.js index f862a0407..68f6e0c0a 100644 --- a/src/code/leafletClasses.js +++ b/src/code/leafletClasses.js @@ -6,19 +6,27 @@ export const WTooltip = L.Class.extend({ this._container = L.DomUtil.create("div", "wasabee-tooltip", this._pane); L.DomUtil.addClass(this._container, "wasabee-tooltip-single"); + window.map.on("mousemove", this._onMouseMove, this); }, dispose: function () { + window.map.off("mousemove", this._onMouseMove, this); this._pane.removeChild(this._container); this._container = null; }, updateContent: function (labelText) { // const span = L.DomUtil.create("span", null, this._container); - this._container.textContent = labelText.text; + this._container.textContent = labelText; return this; }, + _onMouseMove: function (event) { + if (event.layerPoint) { + L.DomUtil.setPosition(this._container, event.layerPoint); + } + }, + updatePosition: function (latlng) { const pos = this._map.latLngToLayerPoint(latlng); L.DomUtil.setPosition(this._container, pos); @@ -100,7 +108,7 @@ export const WDialog = L.Handler.extend({ L.setOptions(this, options); // determine large or small screen dialog sizes this._smallScreen = this._isMobile(); - window.map.fire("wdialog", this); + window.map.fire("wdialog", { dialogType: this.constructor.TYPE }); this.options.usePane = this.options.usePane && window.isSmartphone() && @@ -301,6 +309,7 @@ export const WButton = L.Class.extend({ this.handler = this._toggleActions; // this.actionsContainer == the sub menu items created by the individual buttons + /* this.button = this._createButton({ container: container, // buttonImage: null, @@ -308,6 +317,7 @@ export const WButton = L.Class.extend({ context: this, // className: ..., }); + */ }, update: function () { @@ -349,6 +359,25 @@ export const WButton = L.Class.extend({ } }, + setSubActions: function (actions) { + if (!this.actionsContainer) { + this.actionsContainer = L.DomUtil.create( + "ul", + "wasabee-actions", + this._container + ); + } + this.actionsContainer.textContent = ""; + for (const action of actions) { + const li = L.DomUtil.create( + "li", + "wasabee-subactions", + this.actionsContainer + ); + this._createButton({ ...action, container: li }); + } + }, + _createButton: function (options) { const link = L.DomUtil.create( "a", @@ -374,22 +403,4 @@ export const WButton = L.Class.extend({ return link; }, - - _createSubActions: function (buttons) { - const container = L.DomUtil.create("ul", "wasabee-actions"); - for (const b of buttons) { - const li = L.DomUtil.create("li", "wasabee-subactions", container); - this._createButton({ - title: b.title, - text: b.text, - html: b.html, - buttonImage: b.img, - container: li, - callback: b.callback, - context: b.context, - className: "wasabee-subactions", - }); - } - return container; - }, }); diff --git a/src/code/link.js b/src/code/link.js deleted file mode 100644 index d51fe30cd..000000000 --- a/src/code/link.js +++ /dev/null @@ -1,228 +0,0 @@ -import { generateId, convertColorToHex, newColors } from "./auxiliar"; -import { getSelectedOperation } from "./selectedOp"; -import wX from "./wX"; -import AssignDialog from "./dialogs/assignDialog"; -import { addToColorList } from "./skin"; - -export default class WasabeeLink { - constructor(obj) { - this.ID = obj.ID ? obj.ID : generateId(); - this.fromPortalId = obj.fromPortalId; - this.toPortalId = obj.toPortalId; - this.description = obj.description ? obj.description : null; - this.assignedTo = obj.assignedTo ? obj.assignedTo : ""; - this.throwOrderPos = obj.throwOrderPos ? Number(obj.throwOrderPos) : 0; - this.color = obj.color ? obj.color : "main"; - this.completed = obj.completed ? !!obj.completed : false; - this.zone = obj.zone ? Number(obj.zone) : 1; - } - - // build object to serialize - toJSON() { - return { - ID: this.ID, - fromPortalId: this.fromPortalId, - toPortalId: this.toPortalId, - description: this.description, - assignedTo: this.assignedTo, - throwOrderPos: Number(this.throwOrderPos), - color: this.color, - completed: !!this.completed, // !! forces a boolean value - zone: Number(this.zone), - }; - } - - // for interface consistency, the other types use comment - // we can't rename them here w/o making the corresponding changes on the server - get comment() { - return this.description; - } - - set comment(c) { - this.description = c; - } - - // for interface consistency, other types use order - get opOrder() { - return this.throwOrderPos; - } - - set opOrder(o) { - this.throwOrderPos = Number.parseInt(o, 10); - } - - // make the interface match (kinda) what markers do - // 'pending','assigned','acknowledged','completed' - // THESE ARE INTERNAL VALUES AND SHOULD NOT BE wX'd!!! - get state() { - if (this.completed) return "completed"; - if (this.assignedTo) return "assigned"; - return "pending"; - } - - set state(s) { - if (s == "completed") { - this.completed = true; - } else { - this.completed = false; - } - } - - // kludge to make the interface work - get portalId() { - return this.fromPortalId; - } - - getLatLngs(operation) { - if (!operation) operation = getSelectedOperation(); - - const returnArray = Array(); - - const fromPortal = operation.getPortal(this.fromPortalId); - if (!fromPortal || !fromPortal.lat) { - console.log("unable to get source portal"); - return null; - } - returnArray.push(fromPortal.latLng); - - const toPortal = operation.getPortal(this.toPortalId); - if (!toPortal || !toPortal.lat) { - console.log("unable to get destination portal"); - return null; - } - returnArray.push(toPortal.latLng); - - return returnArray; - } - - get latLngs() { - return this.getLatLngs(getSelectedOperation()); - } - - // returns a DOM object appropriate for display - // do we still need the operation here? - displayFormat(operation, smallScreen = false) { - const d = L.DomUtil.create("div", null); - d.appendChild( - operation.getPortal(this.fromPortalId).displayFormat(smallScreen) - ); - const arrow = L.DomUtil.create("span", "wasabee-link-seperator", d); - arrow.style.color = this.getColor(operation); - const picker = L.DomUtil.create("input", "hidden-color-picker", arrow); - picker.type = "color"; - picker.value = convertColorToHex(this.getColor(operation)); - picker.setAttribute("list", "wasabee-colors-datalist"); - picker.disabled = !operation.canWrite(); - - L.DomEvent.on(arrow, "click", () => { - picker.click(); - }); - - L.DomEvent.on(picker, "change", (ev) => { - this.setColor(ev.target.value, operation); - }); - - d.appendChild( - operation.getPortal(this.toPortalId).displayFormat(smallScreen) - ); - return d; - } - - setColor(color, operation) { - this.color = color; - if (this.color == operation.color) this.color = "main"; - operation.update(); - addToColorList(color); - } - - getColor(operation) { - // 0.17 -- use the old names internally no matter what we are sent - let color = this.color; - if (color == "main") color = operation.color; - color = newColors(color); - if (window.plugin.wasabee.skin.layerTypes.has(color)) - color = window.plugin.wasabee.skin.layerTypes.get(color).color; - return color; - } - - length(operation) { - const latlngs = this.getLatLngs(operation); - return L.latLng(latlngs[0]).distanceTo(latlngs[1]); - } - - minLevel(operation) { - const b = this.length(operation); - let s = wX("UNKNOWN"); - const a = L.DomUtil.create("span", null); - - if (b > 6881280) { - s = wX("IMPOSSIBLE"); - } else { - if (b > 1966080) { - s = wX("VRLA"); - a.title = wX("VRLA DESC"); - a.classList.add("help"); - } else { - if (b > 655360) { - s = wX("LA"); - a.title = wX("LA DESC"); - a.classList.add("help"); - } else { - const d = Math.max(1, Math.ceil(8 * Math.pow(b / 160, 0.25)) / 8); - const msd = 8 * (d - Math.floor(d)); - s = "L" + d; - if (0 != msd) { - if (!(1 & msd)) { - s = s + "\u2007"; - } - if (!(1 & msd || 2 & msd)) { - s = s + "\u2007"; - } - s = - s + - (" = L" + - Math.floor(d) + - "0\u215b\u00bc\u215c\u00bd\u215d\u00be\u215e".charAt(msd)); - } - } - } - } - a.textContent = s; - return a; - } - - getPopup(operation) { - const div = L.DomUtil.create("div", null); - L.DomUtil.create("div", null, div).appendChild( - this.displayFormat(operation, true) - ); - if (this.description) - L.DomUtil.create("div", "enl", div).textContent = this.description; - L.DomUtil.create("div", "enl", div).textContent = "# " + this.throwOrderPos; - if (operation.canWrite()) { - const del = L.DomUtil.create("button", null, div); - del.textContent = wX("DELETE_LINK"); - L.DomEvent.on(del, "click", (ev) => { - L.DomEvent.stop(ev); - operation.removeLink(this.fromPortalId, this.toPortalId); - }); - const rev = L.DomUtil.create("button", null, div); - rev.textContent = wX("REVERSE"); - L.DomEvent.on(rev, "click", (ev) => { - L.DomEvent.stop(ev); - operation.reverseLink(this.fromPortalId, this.toPortalId); - }); - } - - if (operation.canWriteServer()) { - const assignButton = L.DomUtil.create("button", null, div); - assignButton.textContent = wX("ASSIGN"); - L.DomEvent.on(assignButton, "click", (ev) => { - L.DomEvent.stop(ev); - const ad = new AssignDialog({ target: this }); - ad.enable(); - }); - } - return div; - } -} diff --git a/src/code/mapDrawing.js b/src/code/mapDrawing.js deleted file mode 100644 index 970edd4f4..000000000 --- a/src/code/mapDrawing.js +++ /dev/null @@ -1,451 +0,0 @@ -import WasabeeMe from "./me"; -import WasabeeAnchor from "./anchor"; -import WasabeeTeam from "./team"; -import WasabeeAgent from "./agent"; -import WasabeeOp from "./operation"; -import { newColors } from "./auxiliar"; -import { getSelectedOperation, opsList } from "./selectedOp"; - -const Wasabee = window.plugin.wasabee; - -// draws all anchors, markers, and links -export function drawMap() { - const operation = getSelectedOperation(); - updateAnchors(operation); - updateMarkers(operation); - resetLinks(operation); - resetZones(operation); -} - -// updates all existing markers, adding any that need to be added, removing any that need to be removed -function updateMarkers(op) { - if (window.isLayerGroupDisplayed("Wasabee Draw Markers") === false) return; // yes, === false, undefined == true - if (!op.markers || op.markers.length == 0) { - Wasabee.markerLayerGroup.clearLayers(); - return; - } - - // get a list of every currently drawn marker - const layerMap = new Map(); - for (const l of Wasabee.markerLayerGroup.getLayers()) { - layerMap.set(l.options.id, l._leaflet_id); - } - - // add any new ones, remove any existing from the list - // markers don't change, so this doesn't need to be too smart - for (const m of op.markers) { - if (layerMap.has(m.ID)) { - const ll = Wasabee.markerLayerGroup.getLayer(layerMap.get(m.ID)); - if (m.state != ll.options.state) { - L.DomUtil.removeClass(ll._icon, `wasabee-status-${ll.options.state}`); - L.DomUtil.addClass(ll._icon, `wasabee-status-${m.state}`); - ll.options.state = m.state; - } - layerMap.delete(m.ID); - } else { - addMarker(m, op); - } - } - - // remove any that were not processed - for (const v of layerMap.values()) { - // for (const v of layerMap) { - Wasabee.markerLayerGroup.removeLayer(v); - } -} - -// adds a new marker -function addMarker(target, operation) { - const targetPortal = operation.getPortal(target.portalId); - const marker = L.marker(targetPortal.latLng, { - title: targetPortal.name, - id: target.ID, - state: target.state, - icon: L.divIcon({ - className: `wasabee-marker-icon ${target.type} wasabee-status-${target.state}`, - shadowUrl: null, - iconSize: L.point(24, 40), - iconAnchor: L.point(12, 40), - popupAnchor: L.point(-1, -48), - }), - }); - - // register the marker for spiderfied click - window.registerMarkerForOMS(marker); - marker.bindPopup("loading...", { - className: "wasabee-popup", - closeButton: false, - }); - // marker.off("click", marker.openPopup, marker); - marker.on( - "click spiderfiedclick", - async function (ev) { - /* eslint-disable no-invalid-this */ - L.DomEvent.stop(ev); - if (this.isPopupOpen()) return; - const sop = getSelectedOperation(); - const target = sop.getMarker(this.options.id); - const c = await target.popupContent(this); - this.setPopupContent(c); - this._popup._wrapper.classList.add("wasabee-popup"); - this.update(); - this.openPopup(); - /* eslint-enable no-invalid-this */ - }, - marker - ); - marker.addTo(Wasabee.markerLayerGroup); -} - -// resetting is consistently 1ms faster than trying to update -function resetLinks(operation) { - if (window.isLayerGroupDisplayed("Wasabee Draw Links") === false) return; // yes, === false, undefined == true - Wasabee.linkLayerGroup.clearLayers(); - - if (!operation.links || operation.links.length == 0) return; - - for (const l of operation.links) { - addLink(l, operation); - } -} - -export async function drawBackgroundOps(opIDs) { - if (window.isLayerGroupDisplayed("Wasabee Background Ops") === false) return; - Wasabee.backgroundOpsGroup.clearLayers(); - - const sop = getSelectedOperation().ID; - if (opIDs === undefined) opIDs = await opsList(); - - for (const opID of opIDs) { - if (opID === sop) continue; - const op = await WasabeeOp.load(opID); - if (op.background) drawBackgroundOp(op); - } -} - -export function drawBackgroundOp(operation, layerGroup, style) { - if (!operation) return; - if (!operation.links || operation.links.length == 0) return; - - if (!layerGroup) layerGroup = Wasabee.backgroundOpsGroup; - if (!style) style = Wasabee.skin.backgroundLinkStyle; - - for (const link of operation.links) { - const latLngs = link.getLatLngs(operation); - if (!latLngs) continue; - - const newlink = new L.GeodesicPolyline(latLngs, style); - newlink.addTo(layerGroup); - } -} - -function resetZones(operation) { - Wasabee.zoneLayerGroup.clearLayers(); - - if (!operation.zones || operation.zones.length == 0) return; - - for (const z of operation.zones) { - if (z.points.length == 1) { - L.marker(z.points[0], { color: z.color }).addTo(Wasabee.zoneLayerGroup); - continue; - } - if (z.points.length == 2) { - L.polyline(z.points, { color: z.color }).addTo(Wasabee.zoneLayerGroup); - continue; - } - z.points.sort((a, b) => { - return a.position - b.position; - }); - L.polygon(z.points, { - color: z.color, - shapeOptions: { - stroke: false, - opacity: 0.7, - fill: true, - interactive: false, - }, - }).addTo(Wasabee.zoneLayerGroup); - } - Wasabee.zoneLayerGroup.bringToBack(); -} - -// draw a single link -function addLink(wlink, operation) { - const latLngs = wlink.getLatLngs(operation); - if (!latLngs) { - console.log("LatLngs was null: op missing portal data?"); - return; - } - - const color = wlink.getColor(operation); - - const style = L.extend( - { - color: color, - }, - Wasabee.skin.linkStyle - ); - - if (wlink.assignedTo) style.dashArray = style.assignedDashArray; - - const newlink = new L.GeodesicPolyline(latLngs, style); - - newlink.bindPopup("loading...", { - className: "wasabee-popup", - closeButton: false, - }); - - newlink.on( - "click", - (ev) => { - L.DomEvent.stop(ev); - if (ev.target._popup._wrapper) - ev.target._popup._wrapper.classList.add("wasabee-popup"); - const div = wlink.getPopup(operation); - ev.target.setPopupContent(div); - ev.target.openPopup(ev.latlng); - return true; - }, - newlink - ); - newlink.addTo(Wasabee.linkLayerGroup); - - // setText only works on polylines, not geodesic ones. - // newlink.on("mouseover", () => { console.log(newlink); // newlink.setText(" β–Ί ", { repeat: true, attributes: { fill: "red" } }); }); - // newlink.on("mouseout", () => { newlink.setText(null); }); -} - -// fetch and draw agent locations -export async function drawAgents() { - if (window.isLayerGroupDisplayed("Wasabee Agents") === false) return; // yes, === false, undefined == true - if (!WasabeeMe.isLoggedIn()) return; - - const layerMap = agentLayerMap(); - - let doneAgents = new Array(); - const me = await WasabeeMe.waitGet(); // cache hold-time age is 24 hours... not too frequent - for (const t of me.Teams) { - const freshlyDone = await drawSingleTeam(t.ID, layerMap, doneAgents); - doneAgents = doneAgents.concat(freshlyDone); - } - - // remove those not found in this fetch - for (const d of doneAgents) layerMap.delete(d); - for (const agent in layerMap) { - console.debug("removing stale agent", agent); - Wasabee.agentLayerGroup.removeLayer(agent); - } -} - -// map agent GID to leaflet layer ID -function agentLayerMap() { - const layerMap = new Map(); - for (const agent of Wasabee.agentLayerGroup.getLayers()) { - layerMap.set(agent.options.id, agent._leaflet_id); - } - return layerMap; -} - -// use alreadyDone to reduce processing when using this in a loop, otherwise leave it unset -export async function drawSingleTeam(teamID, layerMap, alreadyDone) { - const done = new Array(); - if (window.isLayerGroupDisplayed("Wasabee Agents") === false) return done; // yes, === false, undefined == true - if (alreadyDone === undefined) alreadyDone = new Array(); - if (layerMap === undefined) layerMap = agentLayerMap(); - - /* this also caches the team into Wasabee.teams for uses elsewhere */ - try { - const team = await WasabeeTeam.get(teamID, 15); // hold time is 15 seconds here, probably too aggressive now that firebase works well - // common case: team was enabled here, but was since disabled in another client and the pull returned an error - if (team == null) return done; - // we don't need to draw if pulled from cache - if (team.cached === true) return done; - - const agents = team.getAgents(); - for (const agent of agents) { - if (!alreadyDone.includes(agent.id) && _drawAgent(agent, layerMap)) - done.push(agent.id); - } - } catch (err) { - console.error(err); - } - // report the icons successfully drawn to the caller, drawAgents uses this to remove stale icons - return done; -} - -// draws a single agent -- can be triggered by firebase -export async function drawSingleAgent(gid) { - if (window.isLayerGroupDisplayed("Wasabee Agents") === false) return; // yes, === false, undefined == true - const agent = await WasabeeAgent.get(gid, 10); // cache default is 1 day, we can be faster if firebase tells us of an update - if (agent != null) _drawAgent(agent); -} - -// returns true if drawn, false if ignored -function _drawAgent(agent, layerMap = agentLayerMap()) { - if (!agent.id || !agent.lat || !agent.lng) { - return false; - } - - const zoom = window.map.getZoom(); - if (!layerMap.has(agent.id)) { - // new, add to map - const marker = L.marker(agent.latLng, { - title: agent.name, - icon: L.divIcon({ - className: "wasabee-agent-icon", - iconSize: agent.iconSize(zoom), - iconAnchor: agent.iconAnchor(zoom), - popupAnchor: L.point(0, -70), - html: agent.icon(zoom), - }), - id: agent.id, - zoom: zoom, - }); - - window.registerMarkerForOMS(marker); - marker.bindPopup("Loading...", { - className: "wasabee-popup", - closeButton: false, - }); - // marker.off("click", agent.openPopup, agent); - marker.on( - "click spiderfiedclick", - async (ev) => { - L.DomEvent.stop(ev); - if (marker.isPopupOpen && marker.isPopupOpen()) return; - const a = await WasabeeAgent.get(agent.id); - marker.setPopupContent(await a.getPopup()); - if (marker._popup._wrapper) - marker._popup._wrapper.classList.add("wasabee-popup"); - marker.update(); - marker.openPopup(); - }, - marker - ); - marker.addTo(Wasabee.agentLayerGroup); - } else { - // move existing icons, if they actually moved - const a = layerMap.get(agent.id); - const al = Wasabee.agentLayerGroup.getLayer(a); - // if the location is different... - const ll = al.getLatLng(); - if (agent.lat != ll.lat || agent.lng != ll.lng) { - // console.debug("moving ", agent.name, agent.latLng, al.getLatLng()); - al.setLatLng(agent.latLng); - al.update(); - } - - // if the zoom factor changed, refresh the icon - if (zoom != al.options.zoom) { - // console.debug("changing icon zoom: ", zoom, al.options.zoom); - al.setIcon( - L.divIcon({ - className: "wasabee-agent-icon", - iconSize: agent.iconSize(zoom), - iconAnchor: agent.iconAnchor(zoom), - popupAnchor: L.point(0, -70), - html: agent.icon(zoom), - }) - ); - al.options.zoom = zoom; - al.update(); - } - } - return true; -} - -// update all anchors, adding missing and removing unneeded -function updateAnchors(op) { - if (window.isLayerGroupDisplayed("Wasabee Draw Portals") === false) return; // yes, === false, undefined == true - if (!op.anchors || op.anchors.length == 0) { - Wasabee.portalLayerGroup.clearLayers(); - return; - } - - const layerMap = new Map(); - for (const l of Wasabee.portalLayerGroup.getLayers()) { - if (l.options.color != op.color) { - // if the op color changed, remove and re-add - Wasabee.portalLayerGroup.removeLayer(l._leaflet_id); - } else { - layerMap.set(l.options.id, l._leaflet_id); - } - } - - for (const a of op.anchors) { - if (layerMap.has(a)) { - layerMap.delete(a); - } else { - addAnchorToMap(a, op); - } - } - - for (const v of layerMap.values()) { - Wasabee.portalLayerGroup.removeLayer(v); - } -} - -// adds a single anchor to the map -function addAnchorToMap(portalId, operation) { - const anchor = new WasabeeAnchor(portalId, operation); - // use newColors(anchor.color) for 0.19 - let layer = anchor.color; - if (newColors(layer) == layer) layer = "custom"; - let marker; - if (layer != "custom") { - marker = L.marker(anchor.latLng, { - title: anchor.name, - alt: anchor.name, - id: portalId, - color: anchor.color, - icon: L.divIcon({ - className: `wasabee-anchor-icon wasabee-layer-${layer}`, - shadowUrl: null, - iconAnchor: [12, 41], - iconSize: [25, 41], - popupAnchor: [0, -35], - }), - }); - } else { - const svg = L.Util.template( - '', - { color: anchor.color } - ); - marker = L.marker(anchor.latLng, { - title: anchor.name, - alt: anchor.name, - id: portalId, - color: anchor.color, - icon: L.divIcon({ - className: "wasabee-anchor-icon", - shadowUrl: null, - iconAnchor: [12, 41], - iconSize: [25, 41], - popupAnchor: [0, -35], - html: svg, - }), - }); - } - - window.registerMarkerForOMS(marker); - marker.bindPopup("loading...", { - className: "wasabee-popup", - closeButton: false, - }); - // marker.off("click", marker.openPopup, marker); - marker.on( - "click spiderfiedclick", - (ev) => { - L.DomEvent.stop(ev); - if (marker.isPopupOpen && marker.isPopupOpen()) return; - const content = anchor.popupContent(marker); - marker.setPopupContent(content); - if (marker._popup._wrapper) - marker._popup._wrapper.classList.add("wasabee-popup"); - marker.update(); - marker.openPopup(); - }, - marker - ); - marker.addTo(Wasabee.portalLayerGroup); -} diff --git a/src/code/mapDrawing.ts b/src/code/mapDrawing.ts new file mode 100644 index 000000000..957126737 --- /dev/null +++ b/src/code/mapDrawing.ts @@ -0,0 +1,239 @@ +import WasabeeMe from "./model/me"; +import WasabeeTeam from "./model/team"; +import WasabeeAgent from "./model/agent"; +import WasabeeOp from "./model/operation"; +import { getSelectedOperation, opsList } from "./selectedOp"; + +import LinkUI from "./ui/link"; +import AnchorUI from "./ui/anchor"; +import AgentUI from "./ui/agent"; +import MarkerUI from "./ui/marker"; +import ZoneUI from "./ui/zone"; +import type { PathOptions } from "leaflet"; + +const Wasabee = window.plugin.wasabee; + +// draws all anchors, markers, and links +export function drawMap() { + const operation = getSelectedOperation(); + updateAnchors(operation); + updateMarkers(operation); + resetLinks(operation); + resetZones(operation); +} + +// updates all existing markers, adding any that need to be added, removing any that need to be removed +function updateMarkers(op: WasabeeOp) { + if (window.isLayerGroupDisplayed("Wasabee Draw Markers") === false) return; // yes, === false, undefined == true + if (!op.markers || op.markers.length == 0) { + Wasabee.markerLayerGroup.clearLayers(); + return; + } + + // get a list of every currently drawn marker + const layerMap = new Map(); + for (const l of Wasabee.markerLayerGroup.getLayers()) { + layerMap.set(l.options.id, l._leaflet_id); + } + + // add any new ones, remove any existing from the list + // markers don't change, so this doesn't need to be too smart + for (const m of op.markers) { + if (layerMap.has(m.ID)) { + const ll = Wasabee.markerLayerGroup.getLayer(layerMap.get(m.ID)); + ll.setState(m.state); + layerMap.delete(m.ID); + } else { + const lMarker = new MarkerUI.WLMarker(m); + lMarker.addTo(Wasabee.markerLayerGroup); + } + } + + // remove any that were not processed + for (const v of layerMap.values()) { + // for (const v of layerMap) { + Wasabee.markerLayerGroup.removeLayer(v); + } +} + +// resetting is consistently 1ms faster than trying to update +function resetLinks(operation: WasabeeOp) { + if (window.isLayerGroupDisplayed("Wasabee Draw Links") === false) return; // yes, === false, undefined == true + Wasabee.linkLayerGroup.clearLayers(); + + if (!operation.links || operation.links.length == 0) return; + + for (const l of operation.links) { + const link = new LinkUI.WLLink(l, operation); + link.addTo(Wasabee.linkLayerGroup); + } +} + +export async function drawBackgroundOps(opIDs?: OpID[]) { + if (window.isLayerGroupDisplayed("Wasabee Background Ops") === false) return; + Wasabee.backgroundOpsGroup.clearLayers(); + + const sop = getSelectedOperation().ID; + if (opIDs === undefined) opIDs = await opsList(); + + for (const opID of opIDs) { + if (opID === sop) continue; + const op = await WasabeeOp.load(opID); + if (op.background) drawBackgroundOp(op); + } +} + +export function drawBackgroundOp( + operation?: WasabeeOp, + layerGroup?: L.LayerGroup, + style?: PathOptions +) { + if (!operation) return; + if (!operation.links || operation.links.length == 0) return; + + if (!layerGroup) layerGroup = Wasabee.backgroundOpsGroup; + if (!style) style = Wasabee.skin.backgroundLinkStyle; + + for (const link of operation.links) { + const latLngs = link.getLatLngs(operation); + if (!latLngs) continue; + + const newlink = new L.GeodesicPolyline(latLngs, style); + newlink.addTo(layerGroup); + } +} + +function resetZones(operation: WasabeeOp) { + Wasabee.zoneLayerGroup.clearLayers(); + + if (!operation.zones || operation.zones.length == 0) return; + + for (const z of operation.zones) { + const l = new ZoneUI.WLZone(z); + l.addTo(Wasabee.zoneLayerGroup); + } + Wasabee.zoneLayerGroup.bringToBack(); +} + +// fetch and draw agent locations +export async function drawAgents() { + if (window.isLayerGroupDisplayed("Wasabee Agents") === false) return; // yes, === false, undefined == true + if (!WasabeeMe.isLoggedIn()) return; + + const layerMap = agentLayerMap(); + + let doneAgents = []; + const me = await WasabeeMe.waitGet(); // cache hold-time age is 24 hours... not too frequent + for (const t of me.Teams) { + const freshlyDone = await drawSingleTeam(t.ID, layerMap, doneAgents); + doneAgents = doneAgents.concat(freshlyDone); + } + + // remove those not found in this fetch + for (const d of doneAgents) layerMap.delete(d); + for (const [aid, lid] of layerMap) { + console.debug("removing stale agent", aid); + Wasabee.agentLayerGroup.removeLayer(lid); + } +} + +// map agent GID to leaflet layer ID +function agentLayerMap() { + const layerMap = new Map(); + for (const marker of Wasabee.agentLayerGroup.getLayers()) { + layerMap.set(marker.options.id, Wasabee.agentLayerGroup.getLayerId(marker)); + } + return layerMap; +} + +// use alreadyDone to reduce processing when using this in a loop, otherwise leave it unset +export async function drawSingleTeam( + teamID: TeamID, + layerMap?: Map, + alreadyDone?: GoogleID[] +) { + const done = []; + if (window.isLayerGroupDisplayed("Wasabee Agents") === false) return done; // yes, === false, undefined == true + if (alreadyDone === undefined) alreadyDone = []; + if (layerMap === undefined) layerMap = agentLayerMap(); + + /* this also caches the team into Wasabee.teams for uses elsewhere */ + try { + const team = await WasabeeTeam.get(teamID, 15); // hold time is 15 seconds here, probably too aggressive now that firebase works well + // common case: team was enabled here, but was since disabled in another client and the pull returned an error + if (team == null) return done; + + for (const agent of team.agents) { + if (!alreadyDone.includes(agent.id) && _drawAgent(agent, layerMap)) + done.push(agent.id); + } + } catch (err) { + console.error(err); + } + // report the icons successfully drawn to the caller, drawAgents uses this to remove stale icons + return done; +} + +// draws a single agent -- can be triggered by firebase +export async function drawSingleAgent(gid: GoogleID) { + if (window.isLayerGroupDisplayed("Wasabee Agents") === false) return; // yes, === false, undefined == true + const agent = await WasabeeAgent.get(gid, 10); // cache default is 1 day, we can be faster if firebase tells us of an update + if (agent != null) _drawAgent(agent); +} + +// returns true if drawn, false if ignored +function _drawAgent(agent: WasabeeAgent, layerMap = agentLayerMap()) { + if (!agent.id || (!agent.lat && !agent.lng)) { + return false; + } + + if (!layerMap.has(agent.id)) { + // new, add to map + const marker = new AgentUI.WLAgent(agent); + marker.addTo(Wasabee.agentLayerGroup); + layerMap.set(agent.id, Wasabee.agentLayerGroup.getLayerId(marker)); + } else { + // move existing icons, if they actually moved + const a = layerMap.get(agent.id); + const al = Wasabee.agentLayerGroup.getLayer(a); + // if the location is different... + const ll = al.getLatLng(); + if (agent.lat != ll.lat || agent.lng != ll.lng) { + // console.debug("moving ", agent.name, agent.latLng, al.getLatLng()); + al.setLatLng(agent.latLng); + } + } + return true; +} + +// update all anchors, adding missing and removing unneeded +function updateAnchors(op: WasabeeOp) { + if (window.isLayerGroupDisplayed("Wasabee Draw Portals") === false) return; // yes, === false, undefined == true + if (!op.anchors || op.anchors.length == 0) { + Wasabee.portalLayerGroup.clearLayers(); + return; + } + + const layerMap = new Map(); + for (const l of Wasabee.portalLayerGroup.getLayers()) { + if (l.options.color != op.color) { + // if the op color changed, remove and re-add + Wasabee.portalLayerGroup.removeLayer(l._leaflet_id); + } else { + layerMap.set(l.options.id, l._leaflet_id); + } + } + + for (const a of op.anchors) { + if (layerMap.has(a)) { + layerMap.delete(a); + } else { + const lAnchor = new AnchorUI.WLAnchor(a, op); + lAnchor.addTo(Wasabee.portalLayerGroup); + } + } + + for (const v of layerMap.values()) { + Wasabee.portalLayerGroup.removeLayer(v); + } +} diff --git a/src/code/marker.js b/src/code/marker.js deleted file mode 100644 index e30aa768e..000000000 --- a/src/code/marker.js +++ /dev/null @@ -1,281 +0,0 @@ -import { generateId } from "./auxiliar"; -import { deleteMarker } from "./uiCommands"; -import WasabeeAgent from "./agent"; -import AssignDialog from "./dialogs/assignDialog"; -import SendTargetDialog from "./dialogs/sendTargetDialog"; -import wX from "./wX"; -import SetCommentDialog from "./dialogs/setCommentDialog"; -import MarkerChangeDialog from "./dialogs/markerChangeDialog"; -import StateDialog from "./dialogs/stateDialog"; -import { getSelectedOperation } from "./selectedOp"; - -const STATE_UNASSIGNED = "pending"; -const STATE_ASSIGNED = "assigned"; -const STATE_ACKNOWLEDGED = "acknowledged"; -const STATE_COMPLETED = "completed"; - -export default class WasabeeMarker { - constructor(obj) { - this.ID = obj.ID ? obj.ID : generateId(); - this.portalId = obj.portalId; - this.type = obj.type; - this.comment = obj.comment ? obj.comment : ""; // why "" and not null? This isn't go - this.completedID = obj.completedID ? obj.completedID : ""; - this.order = obj.order ? Number(obj.order) : 0; - this.zone = obj.zone ? Number(obj.zone) : 1; - - this.assign(obj.assignedTo); // WAS this.assignedTo = obj.assignedTo ? obj.assignedTo : ""; - // if ._state then it came from indexeddb, otherwise from server/localStorage - if (obj._state) { - this.state = obj._state; - } else this.state = obj.state ? obj.state : null; - } - - // not called when pushing to indexeddb, but used when sending to server - toJSON() { - return { - ID: this.ID, - portalId: this.portalId, - type: this.type, - comment: this.comment, - state: this._state, // no need to validate here - completedID: this.completedID, - assignedTo: this.assignedTo, - order: Number(this.order), - zone: Number(this.zone), - }; - } - - get opOrder() { - return this.order; - } - - set opOrder(o) { - this.order = Number.parseInt(o, 10); - } - - assign(gid) { - if (!gid || gid == "") { - this._state = STATE_UNASSIGNED; - this.assignedTo = ""; - return; - } - - this.assignedTo = gid; - this._state = STATE_ASSIGNED; - return; - } - - set state(state) { - switch (state) { - case STATE_UNASSIGNED: - this.assignedTo = null; - this._state = STATE_UNASSIGNED; - break; - case STATE_ASSIGNED: // fall-through - case STATE_ACKNOWLEDGED: - if (!this.assignedTo || this.assignedTo == "") { - this._state = STATE_UNASSIGNED; - break; - } - this._state = state; - break; - case STATE_COMPLETED: - this._state = STATE_COMPLETED; - break; - default: - this._state = STATE_UNASSIGNED; - break; - } - } - - get state() { - return this._state; - } - - async popupContent(marker, operation) { - if (!operation) operation = getSelectedOperation(); - const canWrite = operation.canWrite(); - - const portal = operation.getPortal(this.portalId); - if (portal == null) { - console.log("null portal getting marker popup"); - return (L.DomUtil.create("div", "wasabee-marker-popup").textContent = - "invalid portal"); - } - - const content = L.DomUtil.create("div", "wasabee-marker-popup"); - content.appendChild(this._getPopupBodyWithType(portal, operation, marker)); - - const assignment = L.DomUtil.create( - "div", - "wasabee-popup-assignment", - content - ); - if (this.state != "completed" && this.assignedTo) { - try { - const a = await WasabeeAgent.get(this.assignedTo); - assignment.textContent = wX("ASS_TO"); // FIXME convert formatDisplay to html and add as value to wX - if (a) assignment.appendChild(await a.formatDisplay()); - else assignment.textContent += " " + this.assignedTo; - } catch (err) { - console.error(err); - } - } - if (this.state == "completed" && this.completedID) { - try { - const a = await WasabeeAgent.get(this.completedID); - assignment.innerHTML = wX("COMPLETED BY", { - agentName: a ? a.name : this.completedID, - }); - } catch (e) { - console.error(e); - } - } - - const buttonSet = L.DomUtil.create( - "div", - "wasabee-marker-buttonset", - content - ); - if (canWrite) { - const deleteButton = L.DomUtil.create("button", null, buttonSet); - deleteButton.textContent = wX("DELETE_ANCHOR"); - L.DomEvent.on(deleteButton, "click", (ev) => { - L.DomEvent.stop(ev); - deleteMarker(operation, this, portal); - marker.closePopup(); - }); - } - - if (operation.canWriteServer()) { - const assignButton = L.DomUtil.create("button", null, buttonSet); - assignButton.textContent = wX("ASSIGN"); - L.DomEvent.on(assignButton, "click", (ev) => { - L.DomEvent.stop(ev); - const ad = new AssignDialog({ target: this }); - ad.enable(); - marker.closePopup(); - }); - } - - if (canWrite) { - const stateButton = L.DomUtil.create("button", null, buttonSet); - stateButton.textContent = wX("MARKER STATE"); - L.DomEvent.on(stateButton, "click", (ev) => { - L.DomEvent.stop(ev); - const sd = new StateDialog({ target: this, opID: operation.ID }); - sd.enable(); - marker.closePopup(); - }); - } - - if (operation.isOnCurrentServer()) { - const sendTargetButton = L.DomUtil.create("button", null, buttonSet); - sendTargetButton.textContent = wX("SEND TARGET"); - L.DomEvent.on(sendTargetButton, "click", (ev) => { - L.DomEvent.stop(ev); - const std = new SendTargetDialog({ target: this }); - std.enable(); - marker.closePopup(); - }); - } - - const gmapButton = L.DomUtil.create("button", null, buttonSet); - gmapButton.textContent = wX("ANCHOR_GMAP"); - L.DomEvent.on(gmapButton, "click", (ev) => { - L.DomEvent.stop(ev); - marker.closePopup(); - // use intent on android - if ( - typeof window.android !== "undefined" && - window.android && - window.android.intentPosLink - ) { - window.android.intentPosLink( - +portal.lat, - +portal.lng, - window.map.getZoom(), - portal.name, - true - ); - } else { - window.open( - "https://www.google.com/maps/search/?api=1&query=" + - portal.lat + - "," + - portal.lng - ); - } - }); - - return content; - } - - _getPopupBodyWithType(portal, operation, marker) { - const title = L.DomUtil.create("div", "desc"); - const kind = L.DomUtil.create("span", "wasabee-marker-popup-kind", title); - L.DomUtil.addClass(kind, this.type); - kind.textContent = wX(this.type); - title.appendChild(portal.displayFormat()); - - kind.href = "#"; - L.DomEvent.on(kind, "click", (ev) => { - L.DomEvent.stop(ev); - const ch = new MarkerChangeDialog({ marker: this }); - ch.enable(); - marker.closePopup(); - }); - - if (this.comment) { - const comment = L.DomUtil.create( - "div", - "wasabee-marker-popup-comment", - title - ); - comment.textContent = this.comment; - L.DomEvent.on(comment, "click", (ev) => { - L.DomEvent.stop(ev); - const scd = new SetCommentDialog({ - target: this, - operation: operation, - }); - scd.enable(); - marker.closePopup(); - }); - } - const comment = L.DomUtil.create("div", "wasabee-portal-comment", title); - const cl = L.DomUtil.create("a", null, comment); - cl.textContent = portal.comment || wX("SET_PORTAL_COMMENT"); - cl.href = "#"; - L.DomEvent.on(cl, "click", (ev) => { - L.DomEvent.stop(ev); - const scd = new SetCommentDialog({ - target: portal, - operation: operation, - }); - scd.enable(); - marker.closePopup(); - }); - if (portal.hardness) { - const hardness = L.DomUtil.create( - "div", - "wasabee-portal-hardness", - title - ); - const hl = L.DomUtil.create("a", null, hardness); - hl.textContent = portal.hardness; - hl.href = "#"; - L.DomEvent.on(hl, "click", (ev) => { - L.DomEvent.stop(ev); - const scd = new SetCommentDialog({ - target: portal, - operation: operation, - }); - scd.enable(); - marker.closePopup(); - }); - } - return title; - } -} diff --git a/src/code/model/agent.ts b/src/code/model/agent.ts new file mode 100644 index 000000000..97ba33248 --- /dev/null +++ b/src/code/model/agent.ts @@ -0,0 +1,230 @@ +import { agentPromise } from "../server"; +import WasabeeMe from "./me"; +import db from "../db"; + +interface BaseAgent { + id: GoogleID; + name: string; + intelname?: string; + intelfaction: "unset" | "ENLIGHTENED" | "RESISTANCE"; + communityname?: string; + pic?: string; + lat: number; + lng: number; + date: string; +} + +interface RockAgent extends BaseAgent { + rocksname?: string; + rocks: boolean; +} + +interface VAgent extends BaseAgent { + enlid?: string; + vname?: string; + Vverified: boolean; + level: number; + blacklisted: boolean; +} + +interface ServerTeamAgent extends BaseAgent { + shareWD?: boolean; + loadWD?: boolean; + state?: boolean; + squad?: string; +} + +export interface ServerAgent + extends BaseAgent, + RockAgent, + VAgent, + ServerTeamAgent {} + +// local model +interface TeamAgent extends BaseAgent { + shareWDKeys?: boolean; + loadWDKeys?: boolean; + shareLocation?: boolean; + comment?: string; +} + +interface Agent extends BaseAgent, RockAgent, VAgent, TeamAgent { + fetched?: number; +} + +// convert agent in server model to client model +function serverAgentToAgent(agent: ServerAgent) { + return { + ...agent, + shareWDKeys: agent.shareWD, + loadWDKeys: agent.loadWD, + shareLocation: agent.state, + comment: agent.squad, + }; +} + +export default class WasabeeAgent implements Agent { + id: GoogleID; + name: string; + pic?: string; + lat: number; + lng: number; + date: string; + + // Community (strong) + communityname?: string; + + // intel (weak) + intelname?: string; + intelfaction: "unset" | "ENLIGHTENED" | "RESISTANCE"; + + // V + enlid?: string; + vname?: string; + Vverified: boolean; + level: number; + blacklisted: boolean; + + // rocks + rocksname?: string; + rocks: boolean; + + // per team data + shareWDKeys?: boolean; + loadWDKeys?: boolean; + shareLocation?: boolean; + comment?: string; + + fetched: number; + + constructor(obj: Agent) { + if (typeof obj == "string") { + console.trace("agent waits for an object"); + return null; + } + // if ServerAgent + if ("shareWD" in obj || "squad" in obj) obj = serverAgentToAgent(obj); + // console.debug("passed to constructor", obj); + + // things which are stable across all teams + this.id = obj.id; + this.name = obj.name; + this.intelname = obj.intelname !== "unset" ? obj.intelname : ""; + this.intelfaction = obj.intelfaction; + this.communityname = obj.communityname || ""; + this.pic = obj.pic ? obj.pic : null; + this.lat = obj.lat ? obj.lat : 0; + this.lng = obj.lng ? obj.lng : 0; + this.date = obj.date ? obj.date : null; // last location sub, not fetched + // V + this.enlid = obj.enlid ? obj.enlid : null; + this.vname = obj.vname; + this.Vverified = !!obj.Vverified; + this.level = obj.level ? Number(obj.level) : 0; + this.blacklisted = !!obj.blacklisted; + // rocks + this.rocksname = obj.rocksname; + this.rocks = !!obj.rocks; + + if (this.communityname) this.name = this.communityname; + else if (this.Vverified) this.name = this.vname || this.name; + else if (this.rocks) this.name = this.rocksname || this.name; + else if (this.intelname) this.name = this.intelname + " [!]"; + else this.name = this.name || "[unknown name]"; + + /* what did we decide to do with these? + this.startlat = obj.startlat ? obj.startlat : 0; + this.startlng = obj.startlng ? obj.startlng : 0; + this.startradius = obj.startradius ? Number(obj.startradius) : 0; + this.sharestart = obj.sharestart ? obj.sharestart : false; */ + + // vary per-team, don't set on direct pulls + if (obj.shareWDKeys) this.shareWDKeys = obj.shareWDKeys; + if (obj.loadWDKeys) this.loadWDKeys = obj.loadWDKeys; + if (obj.shareLocation) this.shareLocation = obj.shareLocation; + if (obj.comment) this.comment = obj.comment; + // this.distance = obj.distance ? Number(obj.distance) : 0; // don't use this + + // not sent by server, but preserve if from cache + this.fetched = obj.fetched ? obj.fetched : Date.now(); + + // push the new data into the agent cache + // do not await this, let it happen in the background + this._updateCache(); + } + + getName() { + if (this.communityname) return this.communityname; + if (this.Vverified && this.vname) return this.vname; + if (this.rocks && this.rocksname) return this.rocksname; + if (this.intelname) return this.intelname; + return this.name; + } + + async _updateCache() { + // load anything currently cached + const cached = await (await db).get("agents", this.id); + + // nothing already in the cache, just dump this in and call it good + // will contain the extras, but that's fine for now + if (cached == null) { + // console.debug("not cached, adding"); + try { + await (await db).put("agents", this); + } catch (e) { + console.error(e); + } + return; + } + + // if the cached version is newer, do not update + if (cached.fetched >= this.fetched) { + // console.debug("incoming is older, not updating cache"); + return; + } + // update data + Object.assign(cached, this); + + // remove things which make no sense in the global cache + delete cached.shareWDKeys; + delete cached.loadWDKeys; + delete cached.comment; + delete cached.shareLocation; + + try { + await (await db).put("agents", cached); + } catch (e) { + console.error(e); + } + } + + get latLng() { + if (this.lat && this.lng) return new L.LatLng(this.lat, this.lng); + return null; + } + + // hold agent data up to 24 hours by default -- don't bother the server if all we need to do is resolve GID -> name + static async get(gid: string, maxAgeSeconds = 86400) { + const cached = await (await db).get("agents", gid); + if (cached && cached.fetched > Date.now() - 1000 * maxAgeSeconds) { + const a = new WasabeeAgent(cached); + // console.debug("returning from cache", a); + return a; + } + + if (!WasabeeMe.isLoggedIn()) { + // console.debug("not logged in, giving up"); + return null; + } + + // console.debug("pulling server for new agent data (no team)"); + try { + const result = await agentPromise(gid); + return new WasabeeAgent(result); + } catch (e) { + console.error(e); + } + // console.debug("giving up"); + return null; + } +} diff --git a/src/code/model/blocker.ts b/src/code/model/blocker.ts new file mode 100644 index 000000000..b9ea9f82c --- /dev/null +++ b/src/code/model/blocker.ts @@ -0,0 +1,137 @@ +import db from "../db"; +import type WasabeeOp from "./operation"; +import type WasabeePortal from "./portal"; + +export interface IBlockerPortal { + opID: OpID; + id: PortalID; + name: string; + lat: string; + lng: string; +} + +export default class WasabeeBlocker { + opID: OpID; + from: PortalID; + to: PortalID; + + fromPortal?: WasabeePortal; + toPortal?: WasabeePortal; + + constructor(obj) { + this.opID = obj.opID; + this.from = obj.fromPortal.id; + this.to = obj.toPortal.id; + } + + static async addPortal(op: WasabeeOp, portal: WasabeePortal) { + const store = (await db).transaction("blockers_portals", "readwrite").store; + const ent = { + opID: op.ID, + id: portal.id, + name: portal.name, + lat: portal.lat, + lng: portal.lng, + }; + if (ent.id === ent.name) { + const p = await store.get([op.ID, ent.id]); + if (p && p.name !== p.id) ent.name = p.name; + } + await store.put(ent); + } + + // return true if a blocker portal is updated + static async updatePortal(op: WasabeeOp, portal: WasabeePortal) { + const store = (await db).transaction("blockers_portals", "readwrite").store; + if (portal.name === portal.id) return false; + const p = await store.get([op.ID, portal.id]); + if (!p) return false; + if (p.lat !== portal.lat || p.lng !== portal.lng) { + // portal move, drop blockers + await WasabeeBlocker.removeBlocker(op, portal.id); + return true; + } + if (p.name === portal.name) return false; + await store.put({ + opID: op.ID, + id: portal.id, + name: portal.name, + lat: portal.lat, + lng: portal.lng, + }); + return true; + } + + static async removeBlocker(op, portalId) { + const store = (await db).transaction("blockers", "readwrite").store; + let cfrom = await store + .index("from") + .openKeyCursor(IDBKeyRange.only([op.ID, portalId])); + while (cfrom) { + store.delete(cfrom.primaryKey); + cfrom = await cfrom.continue(); + } + let cto = await store + .index("to") + .openKeyCursor(IDBKeyRange.only([op.ID, portalId])); + while (cto) { + store.delete(cto.primaryKey); + cto = await cto.continue(); + } + await (await db).delete("blockers_portals", [op.ID, portalId]); + } + + static async removeBlockers(opID: string) { + const sb = (await db).transaction("blockers", "readwrite").store; + let co = await sb.index("opID").openKeyCursor(IDBKeyRange.only(opID)); + while (co) { + sb.delete(co.primaryKey); + co = await co.continue(); + } + const sp = (await db).transaction("blockers_portals", "readwrite").store; + let cp = await sp.index("opID").openKeyCursor(IDBKeyRange.only(opID)); + while (cp) { + sp.delete(cp.primaryKey); + cp = await cp.continue(); + } + } + + static async addBlocker( + op: WasabeeOp, + fromPortal: WasabeePortal, + toPortal: WasabeePortal + ) { + const blocker = new WasabeeBlocker({ + opID: op.ID, + fromPortal: fromPortal, + toPortal: toPortal, + }); + await (await db).put("blockers", blocker); + // to store portals + await WasabeeBlocker.addPortal(op, fromPortal); + await WasabeeBlocker.addPortal(op, toPortal); + } + + static async getPortals(op: WasabeeOp) { + const portals = await ( + await db + ).getAllFromIndex("blockers_portals", "opID", op.ID); + return portals; + } + + static async getAll(op: WasabeeOp) { + const blockers = await ( + await db + ).getAllFromIndex("blockers", "opID", op.ID); + const portals = await WasabeeBlocker.getPortals(op); + const portalsMap = new Map(); + for (const p of portals) { + portalsMap.set(p.id, p); + } + for (const b of blockers) { + b.fromPortal = portalsMap.get(b.from); + b.toPortal = portalsMap.get(b.to); + } + return blockers; + } +} diff --git a/src/code/model/changes.ts b/src/code/model/changes.ts new file mode 100644 index 000000000..415bf3a80 --- /dev/null +++ b/src/code/model/changes.ts @@ -0,0 +1,609 @@ +import WasabeeLink from "./link"; +import WasabeePortal from "./portal"; +import type WasabeeOp from "./operation"; +import WasabeeMarker from "./marker"; +import WasabeeZone from "./zone"; + +type Change = { + id: string | number; + props?: Partial>; + value?: T; + type: "addition" | "edition" | "deletion"; +}; + +type MarkerChange = Change< + WasabeeMarker, + | "type" + | "zone" + | "order" + | "assignedTo" + | "state" + | "comment" + | "deltaminutes" +>; +type LinkChange = Change< + WasabeeLink, + | "fromPortalId" + | "toPortalId" + | "color" + | "zone" + | "order" + | "assignedTo" + | "state" + | "comment" + | "deltaminutes" +>; + +type PortalChange = Change; + +type ZoneChange = Change; + +type OperationChange = Change< + WasabeeOp, + "name" | "comment" | "referencetime" | "color" +> & { + type: "edition"; + portals: PortalChange[]; + links: LinkChange[]; + markers: MarkerChange[]; + zones: ZoneChange[]; +}; + +/** + * @param origin Origin object + * @param current Object to compare with `origin` + * @param keys Keys of the object to compare the content + * @returns subset of `current` that differs from `origin` + */ +function computeDiff(origin: T, current: T, keys: K[]) { + const props: Partial = {}; + let once = false; + for (const key of keys) { + if (JSON.stringify(origin[key]) !== JSON.stringify(current[key])) { + props[key] = current[key]; + once = true; + } + } + if (once) return props; + return null; +} + +/** + * @returns summary of link differences, including the link ID + */ +function linkChanges(origin: WasabeeLink, current: WasabeeLink) { + const changes: LinkChange = { + id: origin.ID, + type: "edition", + props: computeDiff(origin, current, [ + "fromPortalId", + "toPortalId", + "color", + "zone", + "order", + "assignedTo", + "comment", + "state", + "deltaminutes", + ]), + }; + return changes; +} + +/** + * @returns summary of marker differences, including the marker ID + */ +function markerChanges(origin: WasabeeMarker, current: WasabeeMarker) { + const changes: MarkerChange = { + id: origin.ID, + type: "edition", + props: computeDiff(origin, current, [ + "type", + /*"portalId",*/ // unlikely because we don't swap marker yet + "zone", + "order", + "assignedTo", + "comment", + "state", + "deltaminutes", + ]), + }; + return changes; +} + +/** + * @returns summary of portal differences, including the portal ID + */ +function portalChanges(origin: WasabeePortal, current: WasabeePortal) { + const changes: PortalChange = { + id: origin.id, + type: "edition", + props: computeDiff(origin, current, ["comment", "hardness"]), + }; + return changes; +} + +/** + * @returns summary of zone differences, including the zone ID + */ +function zoneChanges(origin: WasabeeZone, current: WasabeeZone) { + const changes: ZoneChange = { + id: origin.id, + type: "edition", + props: computeDiff(origin, current, ["name", "color", "points"]), + }; + return changes; +} + +/** + * Compare two lists of object identified by their ID/id. + * Either an object is: + * - in both lists, then compute the object difference and records an `"edition"` + * - in `origin` only, then records a `"deletion"` + * - in `current` only, then records a `"addition"` + * @returns list of addition/deletion and edition (drop object without difference). + */ +function compareList< + T extends { id?: string | number; ID?: string }, + K extends keyof T +>( + origin: T[], + current: T[], + keyID: keyof T & ("id" | "ID"), + cmp: (o: T, c: T) => Change +) { + const olist = origin.slice(); + const clist = current.slice(); + olist.sort((a, b) => + a[keyID] < b[keyID] ? -1 : a[keyID] > b[keyID] ? 1 : 0 + ); + clist.sort((a, b) => + a[keyID] < b[keyID] ? -1 : a[keyID] > b[keyID] ? 1 : 0 + ); + + const result: Change[] = []; + + let i = 0; + let j = 0; + while (i < olist.length && j < clist.length) { + const oTop = olist[i]; + const cTop = clist[j]; + if (oTop[keyID] < cTop[keyID]) { + result.push({ + id: oTop[keyID], + type: "deletion", + }); + i += 1; + } else if (oTop[keyID] > cTop[keyID]) { + result.push({ + id: cTop[keyID], + type: "addition", + value: cTop, + }); + j += 1; + } else { + const diff = cmp(oTop, cTop); + if (diff.props) result.push(diff); + i += 1; + j += 1; + } + } + + while (i < olist.length) { + result.push({ + id: olist[i][keyID], + type: "deletion", + }); + i += 1; + } + + while (j < clist.length) { + result.push({ + id: clist[j][keyID], + type: "addition", + value: clist[j], + }); + j += 1; + } + + return result; +} + +/** + * @returns operation difference from `origin` to `current` + */ +export function operationChanges(origin: WasabeeOp, current: WasabeeOp) { + const changes: OperationChange = { + id: origin.ID, + type: "edition", // always + props: computeDiff(origin, current, [ + "name", + "comment", + "referencetime", + "color", + "localchanged", + ]), + portals: compareList( + origin.opportals, + current.opportals, + "id", + portalChanges + ), + links: compareList(origin.links, current.links, "ID", linkChanges), + markers: compareList(origin.markers, current.markers, "ID", markerChanges), + zones: compareList(origin.zones, current.zones, "id", zoneChanges), + }; + return changes; +} + +/** + * Given two changes `master` and `follower`, compute the subset of `follower` + * that is not already in `master` + * @returns `follower` minus `master` + */ +function rebaseDiff(master: Partial, follower: Partial) { + const props: Partial = {}; + let once = false; + for (const k in follower) { + if (!master || JSON.stringify(master[k]) !== JSON.stringify(follower[k])) { + props[k] = follower[k]; + once = true; + } + } + if (once) return props; + return null; +} + +/** + * Given two lists of changes `master` and `follower`, compute the subset of + * `follower` that is not already in `master` and the list of conflicts, where + * a conflict occurs if: + * - double addition (ex: two markers with same IDs) + * - edition/deletion or deletion/edition + * - double editions where both editions have common fields (ex: comment + * changed both on remote and local) + * + * @param conflictOnDoubleEditOnly + * if true, double additions are degraded at double editions (if differ) + * and deletion/edition are kept as edition (for portal and zone) + * @param concurrentEditKeys + * set of keys that raises a conflict on double editions even if + * differences don't conflict + * @returns pair of `follower` minus `master` and conflicts + */ +function rebaseChanges( + master: Change[], + follower: Change[], + conflictOnDoubleEditOnly = false, // portal and zone + concurrentEditKeys: K[] = [] +) { + master.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)); + follower.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)); + const result: Change[] = []; + const conflict: { + id: string | number; + type: + | "addition/addition" + | "edition/edition" + | "edition/deletion" + | "deletion/edition"; + value?: T; + master?: Change; + follower?: Change; + }[] = []; + + let i = 0; + let j = 0; + while (i < master.length && j < follower.length) { + const masterTop = master[i]; + const followerTop = follower[j]; + if (masterTop.id < followerTop.id) { + i += 1; + } else if (masterTop.id > followerTop.id) { + result.push(followerTop); + j += 1; + } else { + if (masterTop.type === "addition" || followerTop.type === "addition") { + // id cannot be created on both end except for portals (what about zones?) + if (conflictOnDoubleEditOnly) { + const p = rebaseDiff(masterTop.props, followerTop.props); + if (p) { + result.push({ + id: followerTop.id, + type: "edition", + props: p, + }); + } + } else { + conflict.push({ + id: followerTop.id, + type: "addition/addition", + }); + } + } else if ( + masterTop.type === "deletion" && + followerTop.type === "deletion" + ) { + // this is easy, both agree + } else if ( + masterTop.type === "edition" && + followerTop.type === "edition" + ) { + const p = rebaseDiff(masterTop.props, followerTop.props); + if (p) { + let ok = true; + // if edit same fields + for (const k in p) { + if (k in masterTop.props) { + ok = false; + break; + } + } + // or touch a field to be cautious about + for (const k in masterTop.props) { + if (!ok || concurrentEditKeys.includes(k)) { + ok = false; + break; + } + } + for (const k in followerTop.props) { + if (!ok || concurrentEditKeys.includes(k)) { + ok = false; + break; + } + } + // then don't solve + if (!ok) { + // concurrent edition on the same field + // of triggered on specific field + conflict.push({ + id: followerTop.id, + type: "edition/edition", + master: masterTop, + follower: followerTop, + }); + } else { + // looks good so far + result.push({ + id: followerTop.id, + type: "edition", + props: p, + }); + } + } + } else { + // edition/deletion or deletion/edition conflict + if (conflictOnDoubleEditOnly) { + if (followerTop.type === "edition") { + // should this be promoted to "addition" instead ? + result.push(followerTop); + } + } else { + conflict.push({ + id: followerTop.id, + type: (masterTop.type + + "/" + + followerTop.type) as typeof conflict[number]["type"], + master: masterTop, + follower: followerTop, + }); + } + } + i += 1; + j += 1; + } + } + + while (j < follower.length) { + result.push(follower[j]); + j += 1; + } + + return { + result, + conflict, + }; +} + +/** + * Change `follower` additions id to match `master` if equals. + * This is used for links if portals are the same while IDs differ + */ +function unifyAdditions>( + master: C[], + follower: C[], + eq: (a: C["value"], b: C["value"]) => boolean +) { + const masterAdd = master.filter((c) => c.type === "addition"); + const followerAdd = follower.filter((c) => c.type === "addition"); + for (const a of followerAdd) { + for (const b of masterAdd) { + if (eq(a.value, b.value)) { + a.id = b.id; + break; + } + } + } +} + +/** + * + * @param origin Common ancestor + * @param master Master copy that will be used to apply `follower` changes on + * @param follower Our copy + * @returns (`follower` - `origin`) - (`master` - `origin`) and conflicts + */ +export function computeRebaseChanges( + origin: WasabeeOp, + master: WasabeeOp, + follower: WasabeeOp +) { + // add "deleted" portal + for (const p of origin.opportals) { + master._addPortal(p); + follower._addPortal(p); + } + const masterChanges = operationChanges(origin, master); + const followerChanges = operationChanges(origin, follower); + + // use master ID if links are added at both ends + unifyAdditions( + masterChanges.links, + followerChanges.links, + (a, b) => + (a.fromPortalId === b.fromPortalId && a.toPortalId === b.toPortalId) || + (a.fromPortalId === b.toPortalId && a.toPortalId === b.fromPortalId) + ); + + const changes = { + props: rebaseDiff(masterChanges.props, followerChanges.props), + portals: rebaseChanges( + masterChanges.portals, + followerChanges.portals, + true + ), + links: rebaseChanges(masterChanges.links, followerChanges.links, false, [ + "fromPortalId", + "toPortalId", + ]), + markers: rebaseChanges( + masterChanges.markers, + followerChanges.markers, + false + ), + zones: rebaseChanges(masterChanges.zones, followerChanges.zones, true), + }; + + // define conflict default resolution value + defaultChangeChoice(master, changes); + + return changes; +} + +/** + * Merge `props` on `obj` + */ +function applyChanges(obj: T, props: Partial) { + for (const k in props) { + obj[k] = props[k]; + } +} + +/** + * Add a value to all conflicts that matches the given op content + */ +export function defaultChangeChoice( + masterOrCurrent: WasabeeOp, + changes: ReturnType +) { + for (const pc of changes.portals.conflict) { + pc.value = masterOrCurrent.getPortal(pc.id as string); + } + for (const zc of changes.zones.conflict) { + zc.value = masterOrCurrent.getZone(zc.id as number); + } + for (const mc of changes.markers.conflict) { + mc.value = masterOrCurrent.getMarker(mc.id as string); + } + for (const lc of changes.links.conflict) { + lc.value = masterOrCurrent.getLinkById(lc.id as string); + } +} + +/* + current properties that are preserved on master: + - Task.dependsOn + - Marker.attributes +*/ + +/** + * Apply the given changes on `master`. Use `current` to add missing portals + * and missing zones. + */ +export function applyRebaseChanges( + master: WasabeeOp, + current: WasabeeOp, + changes: ReturnType +) { + applyChanges(master, changes.props); + // add possible missing portals + for (const p of current.opportals) { + master._addPortal(new WasabeePortal(p)); + } + // add missing zone (deleted) + for (const z of current.zones) { + const mz = master.getZone(z.id); + if (!mz) master.zones.push(new WasabeeZone(z)); + } + // edit portals + for (const pc of changes.portals.result) { + if (pc.type === "addition") { + // already done, be safe + master._addPortal(pc.value); + } else if (pc.type === "edition") { + const p = master.getPortal(pc.id as string); + if (p) applyChanges(p, pc.props); + } + } + // edit zones + for (const zc of changes.zones.result) { + if (zc.type === "addition") { + // already done, be safe + const mz = master.getZone(zc.id as number); + if (!mz) master.zones.push(new WasabeeZone(zc.value)); + } else if (zc.type === "edition") { + const mz = master.getZone(zc.id as number); + if (mz) applyChanges(mz, zc.props); + } + } + // apply marker changes + for (const mc of changes.markers.result) { + if (mc.type === "deletion") { + master.markers = master.markers.filter((m) => m.ID === mc.id); + } else if (mc.type === "addition") { + master.markers.push(new WasabeeMarker(mc.value)); + } else { + const m = master.getMarker(mc.id as string); + if (m) applyChanges(m, mc.props); + } + } + // apply link changes + for (const lc of changes.links.result) { + if (lc.type === "deletion") { + master.links = master.links.filter((l) => l.ID === lc.id); + } else if (lc.type === "addition") { + master.links.push(new WasabeeLink(lc.value)); + } else { + const l = master.getLinkById(lc.id as string); + if (l) applyChanges(l, lc.props); + } + } + // Conflicts + for (const pc of changes.portals.conflict) { + // no deletion + if (pc.value) master._updatePortal(pc.value); + } + for (const zc of changes.zones.conflict) { + // no deletion + if (zc.value) { + master.zones = master.zones.filter((z) => z.id !== zc.id); + master.zones.push(zc.value); + } + } + for (const mc of changes.markers.conflict) { + master.markers = master.markers.filter((m) => m.ID !== mc.id); + if (mc.value) master.markers.push(mc.value); + } + for (const lc of changes.links.conflict) { + master.links = master.links.filter((l) => l.ID !== lc.id); + if (lc.value) master.links.push(lc.value); + } + + // remove duplicates + master.links = master.links.filter( + (l) => master.getLinkByPortalIDs(l.fromPortalId, l.toPortalId) === l + ); + + master.cleanAnchorList(); + master.cleanPortalList(); +} diff --git a/src/code/model/evented.ts b/src/code/model/evented.ts new file mode 100644 index 000000000..1a7075687 --- /dev/null +++ b/src/code/model/evented.ts @@ -0,0 +1,58 @@ +/* + light es6 version of L.Evented + current design to fail safe is: + - events array is increaing only, removed listeners are replaced by a null function + - loop are prevented by removing listeners during its call + - try/catch +*/ + +function doNothing() {} + +export default class Evented { + _events: { + [event: string]: { + fct: (data: unknown) => void; + context: unknown; + }[]; + }; + + constructor() { + this._events = {}; + } + + on(event: string, func: (data: unknown) => void, context?: unknown) { + if (!(event in this._events)) this._events[event] = []; + this._events[event].push({ fct: func, context: context }); + return this; + } + + off(event: string, func: (data: unknown) => void, context?: unknown) { + const listeners = this._events[event].slice(); + if (listeners) { + for (const listener of listeners) { + if (listener.fct === func && listener.context === context) { + listener.fct = doNothing; + delete listener.context; + } + } + } + return this; + } + + fire(event: string, data?: unknown) { + const listeners = this._events[event].slice(); + if (listeners) { + for (const listener of listeners) { + const fct = listener.fct; + listener.fct = doNothing; + try { + fct.call(listener.context, data); + } catch (e) { + console.error(e); + } + listener.fct = fct; + } + } + return this; + } +} diff --git a/src/code/model/link.ts b/src/code/model/link.ts new file mode 100644 index 000000000..0f9c25f9c --- /dev/null +++ b/src/code/model/link.ts @@ -0,0 +1,85 @@ +import { getSelectedOperation } from "../selectedOp"; +import type WasabeeOp from "./operation"; + +import Task from "./task"; + +function fromServer(obj: any) { + // convert link task + obj.order = +obj.throwOrderPos || 0; + obj.state = "pending"; + obj.completedID = obj.completed ? obj.assignedTo : null; + if (obj.completedID) obj.state = "completed"; + else if (obj.assignedTo) obj.state = "assigned"; + if (obj.description) obj.comment = obj.description; + return obj; +} + +export default class WasabeeLink extends Task { + fromPortalId: PortalID; + toPortalId: PortalID; + color: string; + + constructor(obj: any) { + if (obj.throwOrderPos !== undefined) { + obj = fromServer(obj); + } + super(obj); + this.fromPortalId = obj.fromPortalId; + this.toPortalId = obj.toPortalId; + this.color = obj.color ? obj.color : "main"; + } + + // build object to serialize + toJSON() { + return { + ...super.toJSON(), + + fromPortalId: this.fromPortalId, + toPortalId: this.toPortalId, + color: this.color, + }; + } + + // kludge to make the interface work + get portalId() { + return this.fromPortalId; + } + + getLatLngs(operation: WasabeeOp) { + operation = operation || getSelectedOperation(); + const returnArray: L.LatLng[] = []; + + const fromPortal = operation.getPortal(this.fromPortalId); + if (!fromPortal || !fromPortal.lat) { + console.log("unable to get source portal"); + return null; + } + returnArray.push(fromPortal.latLng); + + const toPortal = operation.getPortal(this.toPortalId); + if (!toPortal || !toPortal.lat) { + console.log("unable to get destination portal"); + return null; + } + returnArray.push(toPortal.latLng); + + return returnArray; + } + + setColor(color: string, operation: WasabeeOp) { + this.color = color; + if (this.color == operation.color) this.color = "main"; + operation.update(); + } + + getColor(operation: WasabeeOp) { + let color = this.color; + if (color == "main") color = operation.color; + return color; + } + + length(operation: WasabeeOp) { + const latlngs = this.getLatLngs(operation); + return L.latLng(latlngs[0]).distanceTo(latlngs[1]); + } +} diff --git a/src/code/model/marker.ts b/src/code/model/marker.ts new file mode 100644 index 000000000..898dd25c0 --- /dev/null +++ b/src/code/model/marker.ts @@ -0,0 +1,87 @@ +import Task from "./task"; + +const markers = { + MARKER_TYPE_CAPTURE: "CapturePortalMarker", + MARKER_TYPE_DECAY: "LetDecayPortalAlert", + MARKER_TYPE_EXCLUDE: "ExcludeMarker", + MARKER_TYPE_DESTROY: "DestroyPortalAlert", + MARKER_TYPE_FARM: "FarmPortalMarker", + MARKER_TYPE_GOTO: "GotoPortalMarker", + MARKER_TYPE_KEY: "GetKeyPortalMarker", + MARKER_TYPE_LINK: "CreateLinkAlert", + MARKER_TYPE_MEETAGENT: "MeetAgentPortalMarker", + MARKER_TYPE_OTHER: "OtherPortalAlert", + MARKER_TYPE_RECHARGE: "RechargePortalAlert", + MARKER_TYPE_UPGRADE: "UpgradePortalAlert", + MARKER_TYPE_VIRUS: "UseVirusPortalAlert", +}; + +const destructMarkerTypes = [ + markers.MARKER_TYPE_DECAY, + markers.MARKER_TYPE_DESTROY, + markers.MARKER_TYPE_VIRUS, +]; + +const markerTypes = new Set(Object.values(markers)); + +const iconTypes = { + CapturePortalMarker: "capture", + LetDecayPortalAlert: "decay", + ExcludeMarker: "exclude", + DestroyPortalAlert: "destroy", + FarmPortalMarker: "farm", + GotoPortalMarker: "goto", + GetKeyPortalMarker: "key", + CreateLinkAlert: "link", + MeetAgentPortalMarker: "meetagent", + OtherPortalAlert: "other", + RechargePortalAlert: "recharge", + UpgradePortalAlert: "upgrade", + UseVirusPortalAlert: "virus", +}; + +export default class WasabeeMarker extends Task { + portalId: PortalID; + type: string; + // future compatibility + attributes?: any[]; + + // static properties is not supported by eslint yet + static get markerTypes() { + return markerTypes; + } + + static get constants() { + return markers; + } + + constructor(obj: any) { + super(obj); + this.portalId = obj.portalId; + this.type = obj.type; + this.attributes = obj.attributes || []; + } + + toJSON(): any { + return { + ...super.toJSON(), + + portalId: this.portalId, + type: this.type, + // preserve data + attributes: this.attributes, + }; + } + + get friendlyType() { + return iconTypes[this.type]; + } + + isDestructMarker() { + return destructMarkerTypes.includes(this.type); + } + + static isDestructMarkerType(type) { + return destructMarkerTypes.includes(type); + } +} diff --git a/src/code/me.js b/src/code/model/me.ts similarity index 56% rename from src/code/me.js rename to src/code/model/me.ts index 5a6bcda4d..e2de5947e 100644 --- a/src/code/me.js +++ b/src/code/model/me.ts @@ -1,46 +1,78 @@ -import { mePromise } from "./server"; +import { mePromise } from "../server"; +import db from "../db"; + +import { constants } from "../static"; +import WasabeeAgent from "./agent"; + +export interface MeTeam { + ID: string; + Name: string; + RocksComm: string; + RocksKey: string; + JoinLinkToken: string; + ShareWD: boolean; + LoadWD: boolean; + State: boolean; + Owner: string; + VTeam: string; + VTeamRole: string; +} + +interface MeOp { + ID: OpID; + Name: string; + IsOwner: boolean; + Color: string; // ?? + TeamID: TeamID; +} + +export default class WasabeeMe extends WasabeeAgent { + querytoken?: string; + lockey?: string; + vapi?: string; + + Telegram: { + ID: string; + Verified: boolean; + Authtoken: string; + }; + + Teams: MeTeam[]; + Ops: MeOp[]; -const Wasabee = window.plugin.wasabee; + _teamMap: Map; -export default class WasabeeMe { constructor(data) { if (typeof data == "string") { - try { - data = JSON.parse(data); - } catch (e) { - console.error(e); - return null; - } + console.trace("me waits for an object"); + return null; } - this.GoogleID = data.GoogleID; - this.name = data.name; - this.vname = data.vname; - this.rocksname = data.rocksname; - this.intelname = data.intelname; - this.level = data.level ? data.level : 0; - this.Teams = Array(); - this.Ops = Array(); - this.fetched = Date.now(); - this.Vverified = data.Vverified; - this.blacklisted = data.blacklisted; - this.enlid = data.enlid; - this._teamMap = null; - // RAID and RISC are unused by clients + data.id = data.GoogleID || data.id; + super(data); + this.querytoken = data.querytoken; this.pic = data.pic; this.intelfaction = data.intelfaction; - this.querytoken = data.querytoken; + this.lockey = data.lockey; + this.vapi = data.vapi; + this.Teams = []; if (data.Teams && data.Teams.length > 0) { for (const team of data.Teams) { + team.ShareWD = team.ShareWD == "On" || team.ShareWD === true; + team.LoadWD = team.LoadWD == "On" || team.LoadWD === true; + team.State = team.State == "On" || team.State === true; this.Teams.push(team); } } + + this.Ops = []; if (data.Ops && data.Ops.length > 0) { for (const op of data.Ops) { this.Ops.push(op); } } this.fetched = data.fetched ? data.fetched : Date.now(); + this._teamMap = null; } static maxCacheAge() { @@ -53,18 +85,17 @@ export default class WasabeeMe { } store() { - localStorage[Wasabee.static.constants.AGENT_INFO_KEY] = - JSON.stringify(this); + localStorage[constants.AGENT_INFO_KEY] = JSON.stringify(this); } remove() { - delete localStorage[Wasabee.static.constants.AGENT_INFO_KEY]; + delete localStorage[constants.AGENT_INFO_KEY]; } static localGet() { - const lsme = localStorage[Wasabee.static.constants.AGENT_INFO_KEY]; + const lsme = localStorage[constants.AGENT_INFO_KEY]; if (typeof lsme == "string") { - return new WasabeeMe(lsme); // do not store + return new WasabeeMe(JSON.parse(lsme)); // do not store } return null; } @@ -100,9 +131,9 @@ export default class WasabeeMe { } // use waitGet with "force == true" if you want a fresh value now - static async waitGet(force) { - let me = WasabeeMe.localGet(); - + // may throw if force == true + static async waitGet(force?: boolean, noFail?: boolean) { + const me = WasabeeMe.localGet(); if ( me === null || me.fetched == undefined || @@ -113,22 +144,20 @@ export default class WasabeeMe { const response = await mePromise(); const newme = new WasabeeMe(response); newme.store(); - me = newme; } catch (e) { - WasabeeMe.purge(); - console.error(e); - // alert(e.toString()); - me = null; + if (force && !noFail) throw e; } } - return me; + // use updated (or null) me object + return WasabeeMe.localGet(); } static async purge() { - delete localStorage[Wasabee.static.constants.AGENT_INFO_KEY]; + const me = WasabeeMe.localGet(); + delete localStorage[constants.AGENT_INFO_KEY]; delete localStorage["sentToServer"]; // resend firebase token on login - const tr = window.plugin.wasabee.idb.transaction( + const tr = (await db).transaction( ["agents", "teams", "defensivekeys"], "readwrite" ); @@ -137,7 +166,7 @@ export default class WasabeeMe { const dkos = tr.objectStore("defensivekeys"); await Promise.all([agentos.clear(), teamos.clear(), dkos.clear(), tr.done]); - window.map.fire("wasabee:logout"); + window.map.fire("wasabee:logout", { GID: me ? me.id : null }); } teamJoined(teamID) { @@ -146,15 +175,6 @@ export default class WasabeeMe { return false; } - teamEnabled(teamID) { - if (this._teamMap == null) this.makeTeamMap(); - if (this._teamMap.has(teamID)) { - const m = this._teamMap.get(teamID); - if (m == "On") return true; - } - return false; - } - makeTeamMap() { this._teamMap = new Map(); for (const t of this.Teams) { diff --git a/src/code/operation.js b/src/code/model/operation.ts similarity index 62% rename from src/code/operation.js rename to src/code/model/operation.ts index 44c3a5160..34f0cde48 100644 --- a/src/code/operation.js +++ b/src/code/model/operation.ts @@ -3,40 +3,117 @@ import WasabeePortal from "./portal"; import WasabeeMarker from "./marker"; import WasabeeMe from "./me"; import WasabeeZone from "./zone"; -import { generateId, newColors } from "./auxiliar"; -import { GetWasabeeServer } from "./server"; -import { getSelectedOperation } from "./selectedOp"; +import Evented from "./evented"; +import { generateId } from "../auxiliar"; +import { GetWasabeeServer } from "../server"; +import { getSelectedOperation } from "../selectedOp"; +import db from "../db"; + +// 0.20->0.21 blocker migration +import WasabeeBlocker from "./blocker"; +import type Task from "./task"; +import { displayWarning } from "../error"; +import { fieldSign, portalInField } from "../crosslinks"; + +export type KeyOnHand = { + portalId: string; + gid: string; + capsule: string; + onhand: number; +}; + +export type OpPermItem = { + role: "read" | "write" | "assignonly"; + teamid: string; + zone: number; +}; + +interface IOperation { + ID: OpID; + name: string; + creator: string | GoogleID; + opportals: WasabeePortal[]; + anchors: string[]; + links: WasabeeLink[]; + markers: WasabeeMarker[]; + color: string; + comment: string; + zones: WasabeeZone[]; + referencetime: string; +} -import wX from "./wX"; +export interface IServerOp extends IOperation { + creator: GoogleID; + teamlist: OpPermItem[]; + keysonhand: KeyOnHand[]; + lasteditid: string; + fetched: string; + modified: string; +} -const Wasabee = window.plugin.wasabee; +export interface ILocalOp extends IOperation { + teamlist: OpPermItem[]; + keysonhand: KeyOnHand[]; + lasteditid: string; + fetched: string; + fetchedOp: string; + server: string; + localchanged: boolean; + remoteChanged: boolean; + background: boolean; + stored: number; +} + +export default class WasabeeOp extends Evented implements IOperation { + ID: string; + name: string; + creator: string; + anchors: Array; + links: Array; + markers: Array; + color: string; + comment: string; + teamlist: Array; + fetched: string; + stored: number; + localchanged: boolean; + blockers: Array; + keysonhand: Array; + zones: Array; + + referencetime: string; + lasteditid: string; + remoteChanged: boolean; + server: string; + fetchedOp: string; + background: boolean; + + _idToOpportals: Map; + _coordsToOpportals: Map; + + _dirtyCoordsTable = false; + _batchmode = false; -export default class WasabeeOp { constructor(obj) { + super(); if (typeof obj == "string") { - try { - obj = JSON.parse(obj); - } catch (e) { - console.error("corrupted operation", e); - return null; - } + console.trace("op waits for an object"); + return null; } this.ID = obj.ID ? obj.ID : generateId(); this.name = obj.name ? obj.name : "unnamed op"; this.creator = obj.creator ? obj.creator : "unset"; - this.anchors = obj.anchors ? obj.anchors : Array(); + this.anchors = obj.anchors ? obj.anchors : []; this.links = this.convertLinksToObjs(obj.links); this.markers = this.convertMarkersToObjs(obj.markers); - this.color = obj.color ? obj.color : Wasabee.skin.defaultOperationColor; - this.color = newColors(this.color); + this.color = obj.color ? obj.color : "main"; this.comment = obj.comment ? obj.comment : null; - this.teamlist = obj.teamlist ? obj.teamlist : Array(); + this.teamlist = obj.teamlist ? obj.teamlist : []; this.fetched = obj.fetched ? obj.fetched : null; this.stored = obj.stored ? obj.stored : null; - this.localchanged = obj.localchanged === false ? obj.localchanged : true; - this.blockers = this.convertBlockersToObjs(obj.blockers); - this.keysonhand = obj.keysonhand ? obj.keysonhand : Array(); + this.localchanged = !!obj.localchanged; + this.keysonhand = obj.keysonhand ? obj.keysonhand : []; this.zones = this.convertZonesToObjs(obj.zones); // this.modified = obj.modified ? obj.modified : null; this.referencetime = obj.referencetime ? obj.referencetime : null; @@ -50,9 +127,8 @@ export default class WasabeeOp { this.background = !!obj.background; - if (!this.links) this.links = new Array(); - if (!this.markers) this.markers = new Array(); - if (!this.blockers) this.blockers = new Array(); + if (!this.links) this.links = []; + if (!this.markers) this.markers = []; const opportals = this.convertPortalsToObjs(obj.opportals); this._idToOpportals = new Map(); @@ -60,13 +136,24 @@ export default class WasabeeOp { if (opportals) for (const p of opportals) this._idToOpportals.set(p.id, p); this.buildCoordsLookupTable(); + // 0.20->0.21 blocker migration + if (obj.blockers) { + for (const blocker of obj.blockers) { + WasabeeBlocker.addBlocker( + this, + this.getPortal(blocker.fromPortalId), + this.getPortal(blocker.toPortalId) + ); + } + } + this.cleanAnchorList(); this.cleanPortalList(); } - static async load(opID) { + static async load(opID: OpID) { try { - const raw = await window.plugin.wasabee.idb.get("operations", opID); + const raw = await (await db).get("operations", opID); if (raw == null) //throw new Error("invalid operation ID"); return null; @@ -79,14 +166,14 @@ export default class WasabeeOp { return null; } - static async delete(opID) { + static async delete(opID: OpID) { delete localStorage[opID]; // leave for now - await window.plugin.wasabee.idb.delete("operations", opID); + await (await db).delete("operations", opID); } - static async migrate(opID) { + static async migrate(opID: OpID) { // skip ones already completed - const have = await window.plugin.wasabee.idb.get("operations", opID); + const have = await (await db).get("operations", opID); if (have != null) { delete localStorage[opID]; // active now return; @@ -118,7 +205,6 @@ export default class WasabeeOp { json.fetched = this.fetched; json.stored = this.stored; json.localchanged = this.localchanged; - json.blockers = this.blockers; json.keysonhand = this.keysonhand; json.teamlist = this.teamlist; json.background = this.background; @@ -128,7 +214,7 @@ export default class WasabeeOp { // store to idb try { - await window.plugin.wasabee.idb.put("operations", json); + await (await db).put("operations", json); } catch (e) { console.error(e); } @@ -146,12 +232,12 @@ export default class WasabeeOp { } // build object to serialize, shallow copy, local-only values excluded - toJSON() { + toJSON(): any { return { ID: this.ID, name: this.name, creator: this.creator, - opportals: Array.from(this._idToOpportals.values()), // includes blocker portals + opportals: Array.from(this._idToOpportals.values()), anchors: this.anchors, links: this.links, markers: this.markers, @@ -165,11 +251,21 @@ export default class WasabeeOp { // JSON with everything optional removed -- inception grade logic here toExport() { // round-trip through JSON.stringify to ensure a deep copy - const o = new WasabeeOp(JSON.stringify(this)); - o.cleanPortalList(); // remove portals which are only relevant to blockers + const o = new WasabeeOp(JSON.parse(JSON.stringify(this))); return JSON.stringify(o); } + getFetchedOp() { + if (!this.fetchedOp) return null; + try { + const json = JSON.parse(this.fetchedOp); + return new WasabeeOp(json); + } catch (e) { + console.error("corrupted fetched op", e); + return null; + } + } + // read only (for inspection) get opportals() { return Array.from(this._idToOpportals.values()); @@ -201,7 +297,7 @@ export default class WasabeeOp { if (this._dirtyCoordsTable) { console.debug("operation: removing duplicates"); - const toRemove = new Array(); + const toRemove = []; const rename = new Map(); for (const [id, p] of this._idToOpportals) { @@ -223,10 +319,6 @@ export default class WasabeeOp { m.portalId = rename.get(m.portalId); } this.anchors = this.anchors.map((a) => rename.get(a)); - for (const b of this.blockers) { - b.fromPortalId = rename.get(b.fromPortalId); - b.toPortalId = rename.get(b.toPortalId); - } for (const id of toRemove) this._idToOpportals.delete(id); } @@ -236,25 +328,25 @@ export default class WasabeeOp { getColor() { if (this.color == null) { - return Wasabee.skin.defaultOperationColor; + return "main"; } else { return this.color; } } - containsPortal(portal) { + containsPortal(portal: WasabeePortal) { return this._idToOpportals.has(portal.id); } // assume lat and lng are strings from .toFixed(6) - getPortalByLatLng(lat, lng) { + getPortalByLatLng(lat: string, lng: string) { if (this._dirtyCoordsTable) { this.buildCoordsLookupTable(); } return this._coordsToOpportals.get(lat + "/" + lng); } - containsLinkFromTo(fromPortalId, toPortalId) { + containsLinkFromTo(fromPortalId: PortalID, toPortalId: PortalID) { if (this.links.length == 0) return false; for (const l of this.links) { @@ -268,15 +360,15 @@ export default class WasabeeOp { return false; } - containsLink(link) { + containsLink(link: WasabeeLink) { return this.containsLinkFromTo(link.fromPortalId, link.toPortalId); } - containsMarker(portal, markerType) { + containsMarker(portal: WasabeePortal, markerType: string) { return this.containsMarkerByID(portal.id, markerType); } - containsMarkerByID(portalID, markerType) { + containsMarkerByID(portalID: PortalID, markerType: string) { if (this.markers.length == 0) return false; for (const m of this.markers) { if (m.portalId == portalID && m.type == markerType) { @@ -286,18 +378,7 @@ export default class WasabeeOp { return false; } - getPortalMarkers(portal) { - const markers = new Map(); - if (!portal) return markers; - for (const m of this.markers) { - if (m.portalId == portal.id) { - markers.set(m.type, m); - } - } - return markers; - } - - getLinkByPortalIDs(portalId1, portalId2) { + getLinkByPortalIDs(portalId1: PortalID, portalId2: PortalID) { for (const l of this.links) { if ( (l.fromPortalId == portalId1 && l.toPortalId == portalId2) || @@ -309,11 +390,20 @@ export default class WasabeeOp { return null; } - getLink(portal1, portal2) { + getLink(portal1: WasabeePortal, portal2: WasabeePortal) { return this.getLinkByPortalIDs(portal1.id, portal2.id); } - getLinkListFromPortal(portal) { + getLinkById(linkID: LinkID) { + for (const l of this.links) { + if (l.ID == linkID) { + return l; + } + } + return null; + } + + getLinkListFromPortal(portal: WasabeePortal) { const links = this.links.filter(function (listLink) { return ( listLink.fromPortalId == portal.id || listLink.toPortalId == portal.id @@ -322,11 +412,11 @@ export default class WasabeeOp { return links; } - getPortal(portalID) { + getPortal(portalID: PortalID) { return this._idToOpportals.get(portalID); } - getMarker(markerID) { + getMarker(markerID: MarkerID) { for (const m of this.markers) { if (m.ID == markerID) { return m; @@ -335,7 +425,7 @@ export default class WasabeeOp { return null; } - removeAnchor(portalId) { + removeAnchor(portalId: PortalID) { this.anchors = this.anchors.filter(function (anchor) { return anchor !== portalId; }); @@ -348,19 +438,23 @@ export default class WasabeeOp { this.cleanAnchorList(); this.cleanPortalList(); this.update(true); - this.runCrosslinks(); + this.updateBlockers(); } - removeMarker(marker) { + removeMarkerByID(markerID: MarkerID) { this.markers = this.markers.filter(function (listMarker) { - return listMarker.ID !== marker.ID; + return listMarker.ID !== markerID; }); this.cleanPortalList(); this.update(true); - this.runCrosslinks(); + this.updateBlockers(); } - setMarkerComment(marker, comment) { + removeMarker(marker: WasabeeMarker) { + this.removeMarkerByID(marker.ID); + } + + setMarkerComment(marker: WasabeeMarker, comment: string) { for (const v of this.markers) { if (v.ID == marker.ID) { v.comment = comment; @@ -369,7 +463,7 @@ export default class WasabeeOp { this.update(true); } - setMarkerState(markerID, state) { + setMarkerState(markerID: MarkerID, state: Task["state"]) { for (const v of this.markers) { if (v.ID == markerID) { // validation happens in the marker class @@ -379,16 +473,16 @@ export default class WasabeeOp { this.update(true); } - setLinkComment(link, comment) { + setLinkComment(link: WasabeeLink, comment: string) { for (const v of this.links) { if (v.ID == link.ID) { - v.description = comment; + v.comment = comment; } } this.update(true); } - setLinkState(linkID, state) { + setLinkState(linkID: LinkID, state: Task["state"]) { for (const v of this.links) { if (v.ID == linkID) { v.state = state; @@ -397,7 +491,7 @@ export default class WasabeeOp { this.update(true); } - setLinkColor(linkID, color) { + setLinkColor(linkID: LinkID, color: string) { for (const v of this.links) { if (v.ID == linkID) { v.color = color; @@ -406,25 +500,25 @@ export default class WasabeeOp { this.update(true); } - setLinkOrder(linkID, order) { + setLinkOrder(linkID: LinkID, order: string | number) { for (const v of this.links) { if (v.ID == linkID) { - v.opOrder = Number(order); + v.setOrder(order); } } this.update(true); } - setMarkerOrder(markerID, order) { + setMarkerOrder(markerID: MarkerID, order: string | number) { for (const v of this.markers) { if (v.ID == markerID) { - v.opOrder = Number(order); + v.setOrder(order); } } this.update(true); } - setPortalComment(portal, comment) { + setPortalComment(portal: WasabeePortal, comment: string) { const p = this.getPortal(portal.id); if (p) { p.comment = comment; @@ -432,7 +526,7 @@ export default class WasabeeOp { } } - setPortalHardness(portal, hardness) { + setPortalHardness(portal: WasabeePortal, hardness: string) { const p = this.getPortal(portal.id); if (p) { p.hardness = hardness; @@ -440,8 +534,16 @@ export default class WasabeeOp { } } + removeLinkByID(linkID: LinkID) { + this.links = this.links.filter((l) => l.ID != linkID); + this.cleanAnchorList(); + this.cleanPortalList(); + this.update(true); + this.updateBlockers(); + } + //Passed in are the start, end, and portal the link is being removed from(so the other portal can be removed if no more links exist to it) - removeLink(startPortal, endPortal) { + removeLink(startPortal: PortalID, endPortal: PortalID) { const newLinks = []; for (const l of this.links) { if (!(l.fromPortalId == startPortal && l.toPortalId == endPortal)) { @@ -452,10 +554,10 @@ export default class WasabeeOp { this.cleanAnchorList(); this.cleanPortalList(); this.update(true); - this.runCrosslinks(); + this.updateBlockers(); } - reverseLink(startPortalID, endPortalID) { + reverseLink(startPortalID: PortalID, endPortalID: PortalID) { const newLinks = []; for (const l of this.links) { if (l.fromPortalId == startPortalID && l.toPortalId == endPortalID) { @@ -474,11 +576,7 @@ export default class WasabeeOp { this.cleanCaches(); } - cleanCaches() { - for (const l of this.links) { - delete l._crosslinksGL; - } - } + cleanCaches() {} cleanAnchorList() { const newAnchorList = []; @@ -493,7 +591,7 @@ export default class WasabeeOp { //This removes opportals with no links and removes duplicates cleanPortalList() { - const newPortals = new Map(); + const newPortals = new Map(); for (const l of this.links) { newPortals.set(l.fromPortalId, this._idToOpportals.get(l.fromPortalId)); newPortals.set(l.toPortalId, this._idToOpportals.get(l.toPortalId)); @@ -504,33 +602,25 @@ export default class WasabeeOp { for (const a of this.anchors) { newPortals.set(a, this._idToOpportals.get(a)); } - for (const b of this.blockers) { - newPortals.set(b.fromPortalId, this._idToOpportals.get(b.fromPortalId)); - newPortals.set(b.toPortalId, this._idToOpportals.get(b.toPortalId)); - } // sanitize OP if it get corrupt by my code elsewhere... - const missingPortal = new Set(); - let corrupt = - this.links.length + this.markers.length + this.blockers.length; + const missingPortal = new Set(); + let corrupt = this.links.length + this.markers.length; for (const [id, v] of newPortals) { if (v === undefined) { this.links = this.links.filter( (l) => l.fromPortalId != id && l.toPortalId != id ); this.markers = this.markers.filter((m) => m.portalId != id); - this.blockers = this.blockers.filter( - (b) => b.fromPortalId != id && b.toPortalId != id - ); missingPortal.add(id); } } - corrupt -= this.links.length + this.markers.length + this.blockers.length; + corrupt -= this.links.length + this.markers.length; if (missingPortal.size > 0) { // leave some trace console.trace("op corruption: missing portals"); - alert( - `Oops, something went wrong and OP ${this.name} got corrupted. Fix by removing ${missingPortal.size} missing portals and ${corrupt} links/markers/blockers. Please check your OP and report to the devs.` + displayWarning( + `Oops, something went wrong and OP ${this.name} got corrupted. Fix by removing ${missingPortal.size} missing portals and ${corrupt} links/markers. Please check your OP and report to the devs.` ); this.cleanAnchorList(); for (const id of missingPortal) newPortals.delete(id); @@ -539,13 +629,13 @@ export default class WasabeeOp { this.buildCoordsLookupTable(); } - addPortal(portal) { + addPortal(portal: WasabeePortal) { if (!this.updatePortal(portal) && this._addPortal(portal)) { this.update(false); // adding a portal may just be due to a blocker } } - _addPortal(portal) { + _addPortal(portal: WasabeePortal) { if (!this.containsPortal(portal)) { const key = portal.lat + "/" + portal.lng; if (this._coordsToOpportals.has(key)) { @@ -568,7 +658,7 @@ export default class WasabeeOp { return false; } - updatePortal(portal) { + updatePortal(portal: WasabeePortal) { if (this._updatePortal(portal)) { this.update(true); return true; @@ -578,7 +668,7 @@ export default class WasabeeOp { // update portal silently if one with mathching ID or with matching position // return true if this update a portal data - _updatePortal(portal) { + _updatePortal(portal: WasabeePortal) { const old = this.getPortal(portal.id); if (old) { if (!portal.faked) { @@ -597,10 +687,7 @@ export default class WasabeeOp { for (const m of this.markers) { if (m.portalId == old.id) m.portalId = fake.id; } - // remove blockers on the old portal - this.blockers = this.blockers.filter( - (b) => b.fromPortalId != old.id && b.toPortalId != old.id - ); + this._idToOpportals.delete(old.id); // add the new portal so any data related to the real portal (keys) still works this._addPortal(portal); @@ -627,10 +714,7 @@ export default class WasabeeOp { for (const m of this.markers) { if (m.portalId == old.id) m.portalId = portal.id; } - for (const b of this.blockers) { - if (b.fromPortalId == old.id) b.fromPortalId = portal.id; - if (b.toPortalId == old.id) b.toPortalId = portal.id; - } + this._idToOpportals.delete(old.id); //this.opportals = Array.from(this._idToOpportals.values()); @@ -643,7 +727,16 @@ export default class WasabeeOp { } // options: {description,order,color,replace} - addLink(fromPortal, toPortal, options = {}) { + addLink( + fromPortal: WasabeePortal, + toPortal: WasabeePortal, + options: { + description?: string; + order?: number; + color?: string; + replace?: boolean; + } = {} + ) { console.assert(fromPortal && toPortal, "missing portal for link"); if (fromPortal.id === toPortal.id) { console.debug( @@ -660,24 +753,21 @@ export default class WasabeeOp { const link = existingLink && options.replace ? existingLink - : new WasabeeLink( - { - fromPortalId: fromPortal.id, - toPortalId: toPortal.id, - }, - this - ); - if (options.description) link.description = options.description; - if (options.order) link.opOrder = options.order; + : new WasabeeLink({ + fromPortalId: fromPortal.id, + toPortalId: toPortal.id, + }); + if (options.description) link.comment = options.description; + if (options.order) link.setOrder(options.order); if (options.color) link.color = options.color; if (!existingLink) { this.links.push(link); this.update(true); - this.runCrosslinks(); + this.updateBlockers(); } else if (options.replace) { this.update(true); - this.runCrosslinks(); + this.updateBlockers(); } else { console.debug( "Link Already Exists In Operation -> " + JSON.stringify(link) @@ -687,7 +777,7 @@ export default class WasabeeOp { return link; } - containsAnchor(portalId) { + containsAnchor(portalId: string) { if (this.anchors.length == 0) return false; for (const a of this.anchors) { if (a == portalId) { @@ -697,7 +787,7 @@ export default class WasabeeOp { return false; } - addAnchor(portal) { + addAnchor(portal: WasabeePortal) { // doing this ourselves saves a trip to update(); this._addPortal(portal); if (!this.containsAnchor(portal.id)) { @@ -705,36 +795,13 @@ export default class WasabeeOp { } } - containsBlocker(link) { - if (!this.blockers || this.blockers.length == 0) return false; - - for (const l of this.blockers) { - if ( - l.fromPortalId == link.fromPortalId && - l.toPortalId == link.toPortalId - ) { - return true; - } - } - return false; - } - - addBlocker(link) { - if (!link.fromPortalId || !link.toPortalId) return; - if (!this.containsBlocker(link)) { - this.blockers.push(link); - // this.update(false); // can trigger a redraw-storm, just skip - // this.store(); // do not await, let it happen in the background -- ideally now blockers should not be part of the op json, but stored independently in indexeddb - } - } - get fakedPortals() { const c = Array.from(this._idToOpportals.values()).filter((p) => p.faked); return c; } // silently swap two anchors - _swapPortal(originalPortal, newPortal) { + _swapPortal(originalPortal: WasabeePortal, newPortal: WasabeePortal) { this.anchors = this.anchors.filter(function (listAnchor) { return listAnchor !== originalPortal.id; }); @@ -742,11 +809,6 @@ export default class WasabeeOp { const linksToRemove = []; for (const l of this.links) { - // purge any crosslink check cache - if (l._crosslinksGL) { - delete l._crosslinksGL; - } - if (l.fromPortalId == originalPortal.id) { if (l.toPortalId === newPortal.id) { console.debug( @@ -783,51 +845,36 @@ export default class WasabeeOp { ); } - swapPortal(originalPortal, newPortal) { + swapPortal(originalPortal: WasabeePortal, newPortal: WasabeePortal) { this._addPortal(newPortal); this._swapPortal(originalPortal, newPortal); this.update(true); - this.runCrosslinks(); + this.updateBlockers(); } - addMarker(markerType, portal, options) { - if (!portal) return; - if (this.containsMarker(portal, markerType)) { - alert(wX("ALREADY_HAS_MARKER")); - } else { - // save a trip to update() - this._addPortal(portal); - const marker = new WasabeeMarker({ - type: markerType, - portalId: portal.id, - }); - if (options && options.comment) marker.comment = options.comment; - if (options && options.zone) marker.zone = options.zone; - if (options && options.assign && options.assign != 0) - marker.assign(options.assign); - this.markers.push(marker); - - // only need this for virus/destroy/decay -- this should be in the marker class - const destructMarkerTypes = [ - window.plugin.wasabee.static.constants.MARKER_TYPE_DECAY, - window.plugin.wasabee.static.constants.MARKER_TYPE_DESTROY, - window.plugin.wasabee.static.constants.MARKER_TYPE_VIRUS, - ]; - if (destructMarkerTypes.includes(markerType)) { - // remove related blockers - this.blockers = this.blockers.filter( - (b) => b.fromPortalId !== portal.id && b.toPortalId !== portal.id - ); - } + addMarker(markerType: string, portal: WasabeePortal, options) { + if (!portal) return false; - this.update(true); - // run crosslink to update the layer - // XXX: we don't need to check, only redraw, so we need something clever, probably in mapDraw or crosslink.js - if (destructMarkerTypes.includes(markerType)) this.runCrosslinks(); - } + // save a trip to update() + this._addPortal(portal); + const marker = new WasabeeMarker({ + type: markerType, + portalId: portal.id, + }); + if (options && options.comment) marker.comment = options.comment; + if (options && options.zone) marker.zone = options.zone; + if (options && options.assign && options.assign != 0) + marker.assign(options.assign); + this.markers.push(marker); + + this.update(true); + // run crosslink to update the layer + // XXX: we don't need to check, only redraw, so we need something clever, probably in mapDraw or crosslink.js + if (marker.isDestructMarker()) this.updateBlockers(); + return true; } - assignMarker(id, gid) { + assignMarker(id: MarkerID, gid: GoogleID) { for (const v of this.markers) { if (v.ID == id) { v.assign(gid); @@ -836,20 +883,19 @@ export default class WasabeeOp { } } - assignLink(id, gid) { + assignLink(id: LinkID, gid: GoogleID) { for (const v of this.links) { if (v.ID == id) { - v.assignedTo = gid; + v.assign(gid); this.update(true); } } } clearAllItems() { - this.anchors = Array(); - this.links = Array(); - this.markers = Array(); - this.blockers = Array(); + this.anchors = []; + this.links = []; + this.markers = []; this._idToOpportals.clear(); this._coordsToOpportals.clear(); @@ -857,15 +903,14 @@ export default class WasabeeOp { } clearAllLinks() { - this.links = Array(); - this.blockers = Array(); + this.links = []; this.cleanAnchorList(); this.cleanPortalList(); this.update(true); } clearAllMarkers() { - this.markers = Array(); + this.markers = []; this.cleanPortalList(); this.update(true); } @@ -880,12 +925,12 @@ export default class WasabeeOp { } this.store(); // no await, let it happen in the background unless we see races - window.map.fire("wasabee:op:change"); + this.fire("update"); } - runCrosslinks() { + updateBlockers() { if (this._batchmode === true) return; - window.map.fire("wasabee:crosslinks"); + this.fire("blockers"); } startBatchMode() { @@ -895,29 +940,20 @@ export default class WasabeeOp { endBatchMode() { this._batchmode = false; this.update(true); - this.runCrosslinks(); - } - - convertLinksToObjs(links) { - const tmpLinks = new Array(); - if (!links || links.length == 0) return tmpLinks; - for (const l of links) { - tmpLinks.push(new WasabeeLink(l, this)); - } - return tmpLinks; + this.updateBlockers(); } - convertBlockersToObjs(links) { - const tmpLinks = new Array(); + convertLinksToObjs(links: any[]) { + const tmpLinks = []; if (!links || links.length == 0) return tmpLinks; for (const l of links) { - tmpLinks.push(new WasabeeLink(l, this)); + tmpLinks.push(new WasabeeLink(l)); } return tmpLinks; } - convertMarkersToObjs(markers) { - const tmpMarkers = new Array(); + convertMarkersToObjs(markers: any[]) { + const tmpMarkers = []; if (!markers || markers.length == 0) return tmpMarkers; if (markers) { for (const m of markers) { @@ -927,8 +963,8 @@ export default class WasabeeOp { return tmpMarkers; } - convertPortalsToObjs(portals) { - const tmpPortals = Array(); + convertPortalsToObjs(portals: any[]) { + const tmpPortals = []; if (!portals || portals.length == 0) return tmpPortals; for (const p of portals) { if (p instanceof WasabeePortal) { @@ -941,7 +977,7 @@ export default class WasabeeOp { return tmpPortals; } - convertZonesToObjs(zones) { + convertZonesToObjs(zones: any[]) { if (!zones || zones.length == 0) { // if not set, use the defaults return [ @@ -949,7 +985,7 @@ export default class WasabeeOp { { id: 2, name: "Secondary", color: "yellow" }, ].map((obj) => new WasabeeZone(obj)); } - const tmpZones = Array(); + const tmpZones = []; for (const z of zones) { if (z instanceof WasabeeZone) { tmpZones.push(z); @@ -998,7 +1034,7 @@ export default class WasabeeOp { // if current user is op creator, it is always writable const me = WasabeeMe.cacheGet(); if (!me) return false; - if (me.GoogleID == this.creator) return true; + if (me.id == this.creator) return true; // if the user has no teams enabled, it can't be writable if (!me.Teams || me.Teams.length == 0) return false; // if on a write-allowed team, is writable @@ -1029,7 +1065,7 @@ export default class WasabeeOp { // if current user is op creator, it is always writable const me = WasabeeMe.cacheGet(); if (!me) return "read"; // fail safe - if (me.GoogleID == this.creator) return "write"; + if (me.id == this.creator) return "write"; const teamsID = new Set(me.Teams.map((t) => t.ID)); // look for team permission @@ -1057,17 +1093,17 @@ export default class WasabeeOp { const me = WasabeeMe.cacheGet(); if (!me) return false; - if (me.GoogleID == this.creator) return true; + if (me.id == this.creator) return true; return false; } get nextOrder() { let o = 0; for (const l of this.links) { - o = Math.max(o, l.opOrder); + o = Math.max(o, l.order); } for (const m of this.markers) { - o = Math.max(o, m.opOrder); + o = Math.max(o, m.order); } return ++o; } @@ -1075,7 +1111,12 @@ export default class WasabeeOp { // this is only for local display if FireBase doesn't trigger a refresh // KOH always takes place on the server because non-write-access // agents need to make changes & sync - keyOnHand(portalId, gid, onhand, capsule) { + keyOnHand( + portalId: PortalID, + gid: GoogleID, + onhand: number, + capsule: string + ) { if (typeof onhand == "string") { onhand = Number.parseInt(onhand, 10); } @@ -1094,7 +1135,7 @@ export default class WasabeeOp { } } - const k = { + const k: KeyOnHand = { portalId: portalId, gid: gid, onhand: onhand, @@ -1104,35 +1145,40 @@ export default class WasabeeOp { this.update(false); } - KeysOnHandForPortal(portalId) { + KeysOnHandForPortal(portalId: PortalID) { let i = 0; for (const k of this.keysonhand) if (k.portalId == portalId) i += k.onhand; return i; } - KeysRequiredForPortal(portalId) { + KeysRequiredForPortal(portalId: PortalID) { let i = 0; for (const l of this.links) if (l.toPortalId == portalId) i++; return i; } - zoneName(zoneID) { - if (zoneID == "0") - // All zone - return "All"; + zoneName(zoneID: ZoneID) { + if (zoneID === 0) return 0; for (const z of this.zones) { if (z.id == zoneID) return z.name; } return zoneID; } + getZone(zoneID: ZoneID) { + for (const z of this.zones) { + if (z.id == zoneID) return z; + } + return null; + } + // a wrapper to set WasabeePortal or WasabeeLink zone and update - setZone(thing, zoneID) { + setZone(thing: Task, zoneID: ZoneID) { thing.zone = Number(zoneID); this.update(true); } - removeZone(zoneID) { + removeZone(zoneID: ZoneID) { if (zoneID == 1) { console.log("cannot remove zone 1"); return; @@ -1149,7 +1195,7 @@ export default class WasabeeOp { this.update(true); } - removeZonePoints(zoneID) { + removeZonePoints(zoneID: ZoneID) { for (const z of this.zones) { if (z.id == zoneID) { z.points = []; @@ -1158,7 +1204,7 @@ export default class WasabeeOp { this.update(true); } - renameZone(zoneID, name) { + renameZone(zoneID: ZoneID, name: string) { for (const z of this.zones) { if (z.id == zoneID) { z.name = name; @@ -1169,7 +1215,7 @@ export default class WasabeeOp { } addZone() { - const ids = new Set(); + const ids = new Set(); for (const z of this.zones) { ids.add(z.id); } @@ -1179,7 +1225,7 @@ export default class WasabeeOp { return newid; } - addZonePoint(zoneID, latlng) { + addZonePoint(zoneID: number, latlng: L.LatLng) { for (const z of this.zones) { if (z.id == zoneID) { z.points.push({ @@ -1193,14 +1239,9 @@ export default class WasabeeOp { this.update(true); } - changes(origin) { - const changes = { - addition: new Array(), - edition: new Array(), - deletion: new Array(), - }; + changes(origin?: WasabeeOp) { // empty op if old OP (or local OP) - const oldOp = new WasabeeOp(origin ? origin : this.fetchedOp || {}); + const oldOp = new WasabeeOp(origin ? origin : this.getFetchedOp() || {}); const oldLinks = new Map(oldOp.links.map((l) => [l.ID, l])); const oldMarkers = new Map(oldOp.markers.map((m) => [m.ID, m])); @@ -1208,10 +1249,9 @@ export default class WasabeeOp { const newMarkers = new Map(this.markers.map((m) => [m.ID, m])); // Note: teams/keyonhand are atomic - if (oldOp.name != this.name) changes.name = this.name; - if (oldOp.color != this.color) changes.color = this.color; - if (oldOp.comment != this.comment) changes.comment = this.comment; - // blockers: ignored by the server, handle them later + if (oldOp.name != this.name) return true; + if (oldOp.color != this.color) return true; + if (oldOp.comment != this.comment) return true; // zones: handle them later for (const [id, p] of this._idToOpportals) { @@ -1220,96 +1260,81 @@ export default class WasabeeOp { const fields = ["comment", "hardness"]; const diff = fields .filter((k) => oldPortal[k] != p[k]) - .map((k) => [k, oldPortal[k]]); - if (diff.length > 0) - changes.edition.push({ type: "portal", portal: p, diff: diff }); + .map((k) => [k, oldPortal[k]] as [string, any]); + if (diff.length > 0) return true; } } - for (const [id, l] of oldLinks) { + for (const id of oldLinks.keys()) { if (!newLinks.has(id)) { - changes.deletion.push({ type: "link", link: l, id: id }); + return true; } } for (const l of this.links) { if (!oldLinks.has(l.ID)) { - changes.addition.push({ type: "link", link: l }); + return true; } else { const oldLink = oldLinks.get(l.ID); const fields = [ "fromPortalId", "toPortalId", - "assignedTo", - "description", - "throwOrderPos", "color", - "completed", "zone", + "order", + "assignedTo", + "completedID", + "comment", + "state", ]; const diff = fields .filter((k) => oldLink[k] != l[k]) - .map((k) => [k, oldLink[k]]); - if (diff.length > 0) - changes.edition.push({ type: "link", link: l, diff: diff }); + .map((k) => [k, oldLink[k]] as [string, any]); + if (diff.length > 0) return true; } } - for (const [id, m] of oldMarkers) { + for (const id of oldMarkers.keys()) { if (!newMarkers.has(id)) { - changes.deletion.push({ type: "marker", marker: m, id: id }); + return true; } } for (const m of this.markers) { if (!oldMarkers.has(m.ID)) { - changes.addition.push({ type: "marker", marker: m }); + return true; } else { const oldMarker = oldMarkers.get(m.ID); const fields = [ + /* "portalId", */ // unlikely because we don't swap marker yet "type", - "comment", + "zone", + "order", "assignedTo", + "completedID", + "comment", "state", - "order", - "zone", ]; const diff = fields .filter((k) => oldMarker[k] != m[k]) - .map((k) => [k, oldMarker[k]]); - if (diff.length > 0) - changes.edition.push({ type: "marker", marker: m, diff: diff }); + .map((k) => [k, oldMarker[k]] as [string, any]); + if (diff.length > 0) return true; } } - return changes; + return false; } checkChanges() { if (this.localchanged) { - const changes = this.changes(); - if ( - changes.addition.length + - changes.edition.length + - changes.deletion.length == - 0 - ) - this.localchanged = false; + this.localchanged = this.changes(); } return this.localchanged; } - mergeBlockers(op) { - // merge portals - for (const p of op.opportals) { - this._addPortal(p); - } - for (const b of op.blockers) this.blockers.push(b); // do not use addBlocker - } - - mergeZones(op) { - const ids = new Set(); + mergeZones(op: WasabeeOp) { + const ids = new Map(); let count = 0; for (const z of this.zones) { - ids.add(z.id); + ids.set(z.id, z); } for (const z of op.zones) { if (!ids.has(z.id)) { @@ -1320,213 +1345,98 @@ export default class WasabeeOp { return count; } - // assume that `this` is a server OP (no blockers, teams/keys are correct) - applyChanges(changes, op) { - const summary = { - compatibility: { - ok: true, - rewrite: { - link: 0, - marker: 0, - }, - }, - addition: { - link: 0, - marker: 0, - zone: 0, - ignored: 0, - }, - deletion: { - link: 0, - marker: 0, - }, - edition: { - portal: 0, - link: 0, - marker: 0, - assignment: 0, - duplicate: 0, - singlePortalLink: 0, - removed: 0, - }, - }; - - // merge *portals* and blockers - this.mergeBlockers(op); - - // add missing zones - summary.addition.zone = this.mergeZones(op); + determineZone(latlng: { lat: number; lng: number }) { + // sort first, lowest ID wins if a marker is in 2 overlapping zones + this.zones.sort((a, b) => { + return a.id - b.id; + }); + for (const z of this.zones) { + if (z.contains(latlng)) return z.id; + } + // default to primary zone + return 1; + } - // try to detect 0.18 ops with inconsistent IDs - { - const ids = new Set(); - for (const l of this.links) { - ids.add(l.ID); - } - for (const m of this.markers) { - ids.add(m.ID); - } - let foundCollision = false; - for (const d of changes.deletion) { - if (d.type == "link" || d.type == "marker") - if (ids.has(d.id)) { - foundCollision = true; - break; - } - } - if (!foundCollision && op.links.some((l) => ids.has(l.ID))) - foundCollision = true; - if (!foundCollision && op.markers.some((m) => ids.has(m.ID))) - foundCollision = true; - - // foundCollision: either there is a collision in IDs, or everything fine - if (!foundCollision) { - // unless someone deleted everything and rebuild an OP, IDs differ between op and `this` - // we need to use the server IDs so everyone use the same IDs - // this will occur with old client editing the ops, and old ops with always parallel writers (none is sync; bound to disappear) - summary.compatibility.ok = false; - for (const d of changes.deletion) { - if (d.type == "link") { - const link = this.getLinkByPortalIDs( - d.link.fromPortalId, - d.link.toPortalId - ); - if (link) { - d.id = link.ID; - summary.compatibility.rewrite.link += 1; - } - } - if (d.type == "marker") { - const marker = this.getPortalMarkers(d.marker.portalId).get( - d.marker.type - ); - if (marker) { - d.id = marker.ID; - summary.compatibility.rewrite.marker += 1; - } - } + getOrderInfo() { + const links = Array.from(this.links); + links.sort((a, b) => a.order - b.order); + + // map portal id to link they got covered + const coveredPortals = new Map(); + const linksFromInner: WasabeeLink[] = []; + + let fieldCount = 0; + let emptyCount = 0; + + // maps a portal id to its linked portals + const portalLinks = new Map>(); + const emptyFieldLinks: [WasabeeLink, number][] = []; + for (const link of links) { + if (!portalLinks.has(link.fromPortalId)) + portalLinks.set(link.fromPortalId, new Set()); + if (!portalLinks.has(link.toPortalId)) + portalLinks.set(link.toPortalId, new Set()); + const a = portalLinks.get(link.fromPortalId); + const b = portalLinks.get(link.toPortalId); + + // common neighbors portal + const intersect = new Set(); + for (const p of a) if (b.has(p)) intersect.add(p); + + // update the mapping + a.add(link.toPortalId); + b.add(link.fromPortalId); + + // ignore link with order 0 + if (link.order > 0) { + // the link closes at least one field + const p1 = this.getPortal(link.fromPortalId); + const p2 = this.getPortal(link.toPortalId); + const positive: WasabeePortal[] = []; + const negative: WasabeePortal[] = []; + // ignore earth curvature (todo: use it) + for (const pid of intersect) { + const p = this.getPortal(pid); + const sign = fieldSign(p, p1, p2); + if (sign > 0) positive.push(p); + else negative.push(p); } - for (const e of changes.edition) { - if (e.type == "link") { - const link = this.getLinkByPortalIDs( - e.link.fromPortalId, - e.link.toPortalId - ); - if (link) { - e.id = link.ID; - summary.compatibility.rewrite.link += 1; - } - } - if (e.type == "marker") { - const marker = this.getPortalMarkers(e.marker.portalId).get( - e.marker.type - ); - if (marker) { - e.id = marker.ID; - summary.compatibility.rewrite.marker += 1; - } - } + if (positive.length) fieldCount += 1; + if (negative.length) fieldCount += 1; + // if the link closes multiple fields on the same side of the link, we have empty fields. + // doesn't support crossed links configuration yet + if (positive.length > 1 || negative.length > 1) { + let count = 0; + if (positive.length > 1) count += positive.length - 1; + if (negative.length > 1) count += negative.length - 1; + emptyFieldLinks.push([link, count]); + emptyCount += count; } - } - } - for (const d of changes.deletion) { - if (d.type == "link") { - const links = this.links.filter((l) => l.ID != d.id); - summary.deletion.link += this.links.length - links.length; - this.links = links; - } else if (d.type == "marker") { - const markers = this.markers.filter((m) => m.ID != d.id); - summary.deletion.marker += this.markers.length - markers.length; - this.markers = markers; - } - } - // links/markers absent from `this` are not added back - for (const e of changes.edition) { - if (e.type == "portal") { - const portal = this.getPortal(e.portal.id); - for (const kv of e.diff) portal[kv[0]] = e.portal[kv[0]]; - summary.edition.portal += 1; - } else if (e.type == "link") { - let found = false; - for (const l of this.links) { - if (l.ID == e.link.ID) { - const link = this.getLinkByPortalIDs( - e.link.fromPortalId, - e.link.toPortalId - ); - if (link && link != l) { - // remove the link if leading to a duplicate - // note: in some unexpected situation, this could lead to link loses (when user swap portal a LOT on the same spines) - this.links = this.links.filter((l) => l.ID != e.link.ID); - summary.edition.duplicate += 1; - } else { - for (const kv of e.diff) l[kv[0]] = e.link[kv[0]]; - if (l.fromPortalId == l.toPortalId) { - this.links = this.links.filter((link) => link.ID != l.ID); - summary.edition.singlePortalLink += 1; - } else { - summary.edition.link += 1; - if (e.diff.some((kv) => kv[0] == "assignedTo")) - summary.edition.assignment += 1; - } - } - found = true; - break; - } - } - if (!found) summary.edition.removed += 1; - } else if (e.type == "marker") { - let found = false; - for (const m of this.markers) { - if (m.ID == e.marker.ID) { - const markers = this.getPortalMarkers(e.marker.portalId); - const marker = markers.get(e.marker.type); - if (marker && marker != m) { - // remove the marker if leading to a duplicate - this.markers = this.markers.filter((m) => m.ID != e.marker.ID); - summary.edition.duplicate += 1; - } else { - for (const kv of e.diff) m[kv[0]] = e.marker[kv[0]]; - summary.edition.marker += 1; - if (e.diff.some((kv) => kv[0] == "assignedTo")) - summary.edition.assignment += 1; + // record covering time + for (const pid of intersect) { + const p = this.getPortal(pid); + for (const a of this.anchors) { + if (a === pid || a === p1.id || a === p2.id) continue; + if (!coveredPortals.has(a)) { + const ap = this.getPortal(a); + if (portalInField(p1, p2, p, ap)) coveredPortals.set(a, link); } - found = true; - break; } } - if (!found) summary.edition.removed += 1; } - } - // `this` takes over `changes` for additions - for (const a of changes.addition) { - if (a.type == "portal") { - // already done - } else if (a.type == "link") { - if (!this.getLinkByPortalIDs(a.link.fromPortalId, a.link.toPortalId)) { - this.links.push(a.link); - summary.addition.link += 1; - } else summary.addition.ignored += 1; - } else if (a.type == "marker") { - if (!this.containsMarkerByID(a.marker.portalId, a.marker.type)) { - this.markers.push(a.marker); - summary.addition.marker += 1; - } else summary.addition.ignored += 1; + + if (coveredPortals.has(link.fromPortalId)) { + linksFromInner.push(link); } } - return summary; - } - determineZone(latlng) { - // sort first, lowest ID wins if a marker is in 2 overlapping zones - this.zones.sort((a, b) => { - return a.id - b.id; - }); - for (const z of this.zones) { - if (z.contains(latlng)) return z.id; - } - // default to primary zone - return 1; + return { + fieldCount, + emptyFieldLinks, + emptyCount, + linksFromInner, + coveredPortals, + }; } } diff --git a/src/code/model/portal.ts b/src/code/model/portal.ts new file mode 100644 index 000000000..4e61c73c2 --- /dev/null +++ b/src/code/model/portal.ts @@ -0,0 +1,82 @@ +import type { LatLng } from "leaflet"; +import { generateId } from "../auxiliar"; + +export default class WasabeePortal { + id: PortalID; + name: string; + lat: string; + lng: string; + comment: string; + hardness: string; + + _latLng: LatLng; + + constructor(obj) { + if (typeof obj == "string") { + try { + obj = JSON.parse(obj); + } catch (e) { + console.error(e); + return null; + } + } + + this.id = obj.id; + + // migration: don't use a locale dependent name -- remove for 0.19 + if (obj.name.includes(obj.id)) obj.name = obj.id; + // check window.portals[id].options.data for updated name ? + this.name = obj.name; + + // make sure we are using 6-digits precision "number" + this.lat = (+obj.lat).toFixed(6); + this.lng = (+obj.lng).toFixed(6); + + this.comment = obj.comment ? obj.comment : ""; + this.hardness = obj.hardness ? obj.hardness : ""; + + this._latLng = new L.LatLng(parseFloat(this.lat), parseFloat(this.lng)); + } + + // build object to serialize + toJSON() { + return { + id: this.id, + name: this.name, + lat: this.lat, + lng: this.lng, + comment: this.comment, + hardness: this.hardness, + }; + } + + get latLng() { + return this._latLng; + } + + static fake( + lat: number | string, + lng: number | string, + id?: string, + name?: string + ) { + console.assert(lat && lng, "WasabeePortal.fake called w/o lat/lng"); + + if (!id) id = generateId(); + if (!name) name = id; + const n = new WasabeePortal({ id: id, name: name, lat: lat, lng: lng }); + return n; + } + + get faked() { + return this.id.length != 35 || this.id == this.name; + } + + get loading() { + return this.id.length == 35 && this.id == this.name; + } + + get pureFaked() { + return this.id.length != 35; + } +} diff --git a/src/code/model/task.ts b/src/code/model/task.ts new file mode 100644 index 000000000..53476bd88 --- /dev/null +++ b/src/code/model/task.ts @@ -0,0 +1,109 @@ +import { generateId } from "../auxiliar"; + +export type TaskState = "pending" | "assigned" | "acknowledged" | "completed"; + +const States: TaskState[] = ["pending" , "assigned" , "acknowledged" , "completed"]; + +export function sanitizeState(v: string): TaskState { + return States.find((s) => s === v) || "pending" +} + +export default class Task { + ID: TaskID; + order: number; + zone: ZoneID; + assignedTo?: GoogleID; + comment?: string; + dependsOn?: TaskID[]; + deltaminutes?: number; + + _state: TaskState; + + constructor(obj: any) { + this.ID = obj.ID || generateId(); + this.zone = +obj.zone || 1; + this.order = +obj.order || 0; + // to be replaced by .assignments + this.assignedTo = obj.assignedTo ? obj.assignedTo : null; + this.comment = obj.comment ? obj.comment : ""; + this.state = obj._state || obj.state; + // need UI + this.deltaminutes = obj.deltaminutes; + + // future compatibility + this.dependsOn = obj.dependsOn || []; + + // for raw task + if (!this.assignedTo && obj.assignments && obj.assignments.length > 0) + this.assignedTo = obj.assignments[0]; + } + + toServer() { + return this.toJSON(); + } + + toJSON(): any { + return { + ID: this.ID, + zone: Number(this.zone), + order: Number(this.order), + assignedTo: this.assignedTo, + state: this._state, + comment: this.comment, + // preserve data + deltaminutes: this.deltaminutes, + dependsOn: this.dependsOn, + }; + } + + get state() { + return this._state; + } + + set state(state: TaskState) { + switch (state) { + case "assigned": // fall-through + case "acknowledged": + if (!this.assignedTo || this.assignedTo == "") { + this._state = "pending"; + break; + } + this._state = state; + break; + case "completed": + this.complete(); + break; + case "pending": + default: + this.assignedTo = null; + this._state = "pending"; + break; + } + } + + setOrder(o: number | string) { + this.order = +o || 0; + } + + assign(gid?: GoogleID) { + if (gid !== this.assignedTo) { + this._state = gid ? "assigned" : "pending"; + } + this.assignedTo = gid ? gid : null; + } + + complete(gid?: GoogleID) { + this._state = "completed"; + } + + get completed() { + return this._state == "completed"; + } + + set completed(v) { + if (v) this.complete(); + else { + this.state = "assigned"; + } + } +} diff --git a/src/code/model/team.ts b/src/code/model/team.ts new file mode 100644 index 000000000..88aed338f --- /dev/null +++ b/src/code/model/team.ts @@ -0,0 +1,102 @@ +import WasabeeAgent, { ServerAgent } from "./agent"; +import WasabeeMe from "./me"; +import { teamPromise } from "../server"; +import db from "../db"; + +interface RocksTeam { + rc: string; + rk: string; +} + +interface VTeam { + vt: string; + vr: string; +} + +interface ServerTeam extends RocksTeam, VTeam { + id: TeamID; + name: string; + agents: ServerAgent[]; + jlt: string; +} + +interface Team extends RocksTeam, VTeam { + id: TeamID; + name: string; + agents: WasabeeAgent[]; + jlt: string; + + fetched?: number; +} + +export default class WasabeeTeam implements Team { + id: TeamID; + name: string; + agents: WasabeeAgent[]; + jlt: string; + // Rocks + rc: string; + rk: string; + // V + vt: string; + vr: string; + + fetched: number; + + constructor(data: Team | ServerTeam) { + if (typeof data == "string") { + console.trace("team waits for an object"); + return; + } + + let fromServer = false; + if ("fetched" in data) { + this.fetched = data.fetched; + } else { + this.fetched = Date.now(); + fromServer = true; + } + + this.id = data.id; + this.name = data.name; + this.rc = data.rc; + this.rk = data.rk; + this.jlt = data.jlt; + this.vt = data.vt; + this.vr = data.vr; + this.agents = data.agents.map( + (a) => new WasabeeAgent({ ...a, fetched: this.fetched }) + ); + + if (fromServer) this._updateCache(); + } + + async _updateCache() { + try { + await (await db).put("teams", this); + } catch (e) { + console.error(e); + } + } + + // 60 seconds seems too short for the default here... + static async get(teamID, maxAgeSeconds = 60) { + const cached = await (await db).get("teams", teamID); + if (cached) { + const t = new WasabeeTeam(cached); + if (t.fetched > Date.now() - 1000 * maxAgeSeconds) { + return t; + } + } + + if (!WasabeeMe.isLoggedIn()) return null; + + try { + const t = await teamPromise(teamID); + return new WasabeeTeam(t); + } catch (e) { + console.error(e); + } + return null; + } +} diff --git a/src/code/zone.js b/src/code/model/zone.ts similarity index 76% rename from src/code/zone.js rename to src/code/model/zone.ts index 9d5a9a5a8..3d4b35b69 100644 --- a/src/code/zone.js +++ b/src/code/model/zone.ts @@ -1,4 +1,9 @@ export default class WasabeeZone { + id: ZoneID; + name: string; + color: string; + points: ZonePoint[]; + constructor(obj) { this.id = Number(obj.id); this.name = obj.name; @@ -7,14 +12,14 @@ export default class WasabeeZone { if (obj.points) { for (const p of obj.points) { - this.points.push(new zonePoint(p)); + this.points.push(new ZonePoint(p)); } } } toJSON() { return { - id: Number(this.id), + id: +this.id, name: `${this.name}`, color: this.color, points: this.points, @@ -22,7 +27,7 @@ export default class WasabeeZone { } //ray casting algo - contains(latlng) { + contains(latlng: { lat: number; lng: number }) { this.points.sort((a, b) => { return a.position - b.position; }); @@ -50,10 +55,14 @@ export default class WasabeeZone { } } -class zonePoint { +export class ZonePoint { + position: number; + lat: number; + lng: number; + constructor(obj) { this.position = Number(obj.position); - this.lat = Number(obj.lat); - this.lng = Number(obj.lng); + this.lat = +obj.lat; + this.lng = +obj.lng; } } diff --git a/src/code/polyfill.d.ts b/src/code/polyfill.d.ts new file mode 100644 index 000000000..5fcaa65e1 --- /dev/null +++ b/src/code/polyfill.d.ts @@ -0,0 +1 @@ +export default function polyfill(): void; diff --git a/src/code/portal.js b/src/code/portal.js deleted file mode 100644 index 63db0e0d8..000000000 --- a/src/code/portal.js +++ /dev/null @@ -1,160 +0,0 @@ -import { generateId } from "./auxiliar"; -import wX from "./wX"; - -export default class WasabeePortal { - constructor(obj) { - if (typeof obj == "string") { - try { - obj = JSON.parse(obj); - } catch (e) { - console.error(e); - return null; - } - } - - this.id = obj.id; - - // migration: don't use a locale dependent name -- remove for 0.19 - if (obj.name.includes(obj.id)) obj.name = obj.id; - // check window.portals[id].options.data for updated name ? - this.name = obj.name; - - // make sure we are using 6-digits precision "number" - this.lat = (+obj.lat).toFixed(6); - this.lng = (+obj.lng).toFixed(6); - - this.comment = obj.comment ? obj.comment : ""; - this.hardness = obj.hardness ? obj.hardness : ""; - - this._latLng = new L.LatLng(parseFloat(this.lat), parseFloat(this.lng)); - } - - // build object to serialize - toJSON() { - return { - id: this.id, - name: this.name, - lat: this.lat, - lng: this.lng, - comment: this.comment, - hardness: this.hardness, - }; - } - - // create a wasabee portal from a IITC portal (leaflet marker) - static fromIITC(p) { - // we have all the details - if (p && p.options && p.options.data && p.options.guid) { - const data = p.options.data; - const id = p.options.guid; - if (data.title) { - return new WasabeePortal({ - id: id, - name: data.title, - lat: (data.latE6 / 1e6).toFixed(6), - lng: (data.lngE6 / 1e6).toFixed(6), - }); - } - // do we have enough to fake it? - if (data.latE6) { - return WasabeePortal.fake( - (data.latE6 / 1e6).toFixed(6), - (data.lngE6 / 1e6).toFixed(6), - id - ); - } - } - // nothing to get - return null; - } - - get latLng() { - return this._latLng; - } - - get team() { - if (window.portals[this.id] && window.portals[this.id].options.data) - return window.portals[this.id].options.data.team; - return ""; - } - - get displayName() { - if (this.pureFaked) return wX("FAKED", { portalId: this.id }); - if (this.loading) return wX("LOADING1", { portalGuid: this.id }); - return this.name; - } - - displayFormat(shortName = false) { - const pt = this.latLng; - const v = `${this.lat},${this.lng}`; - const name = this.displayName; - const e = L.DomUtil.create("a", "wasabee-portal"); - if (shortName === true && this.name.length > 12) { - e.textContent = name.slice(0, 8) + "..."; - } else { - e.textContent = name; - } - - const team = this.team; - if (team == "E") { - e.classList.add("enl"); - } - if (team == "R") { - e.classList.add("res"); - } - if (team == "N") { - e.classList.add("unclaimed"); - } - - // e.title = this.name; - e.href = `/intel?ll=${v}&pll=${v}`; - - L.DomEvent.on(e, "click", (event) => { - if (window.selectedPortal != this.id && this.id.length == 35) - window.renderPortalDetails(this.id); - else window.map.panTo(pt); - event.preventDefault(); - return false; - }).on(e, "dblclick", (event) => { - if (window.selectedPortal != this.id && this.id.length == 35) - window.renderPortalDetails(this.id); - if (window.map.getBounds().contains(pt)) - window.zoomToAndShowPortal(this.id, pt); - else window.map.panTo(pt); - event.preventDefault(); - return false; - }); - return e; - } - - static get(id) { - return WasabeePortal.fromIITC(window.portals[id]); - } - - static fake(lat, lng, id, name) { - console.assert(lat && lng, "WasabeePortal.fake called w/o lat/lng"); - - if (!id) id = generateId(); - if (!name) name = id; - const n = new WasabeePortal({ id: id, name: name, lat: lat, lng: lng }); - return n; - } - - get faked() { - return this.id.length != 35 || this.id == this.name; - } - - get loading() { - return this.id.length == 35 && this.id == this.name; - } - - get pureFaked() { - return this.id.length != 35; - } - - static getSelected() { - return window.selectedPortal - ? WasabeePortal.get(window.selectedPortal) - : null; - } -} diff --git a/src/code/selectedOp.js b/src/code/selectedOp.ts similarity index 77% rename from src/code/selectedOp.js rename to src/code/selectedOp.ts index b482d258f..1a8914841 100644 --- a/src/code/selectedOp.js +++ b/src/code/selectedOp.ts @@ -1,16 +1,19 @@ -import WasabeeOp from "./operation"; +import WasabeeOp from "./model/operation"; +import WasabeeBlocker from "./model/blocker"; import wX from "./wX"; import { generateId } from "./auxiliar"; +import { displayError } from "./error"; +import type { LeafletEvent } from "leaflet"; -function setRestoreOpID(opID) { +function setRestoreOpID(opID: OpID) { localStorage[window.plugin.wasabee.static.constants.SELECTED_OP_KEY] = opID; } -function getRestoreOpID() { +function getRestoreOpID(): OpID { return localStorage[window.plugin.wasabee.static.constants.SELECTED_OP_KEY]; } -export function getSelectedOperation() { +export function getSelectedOperation(): WasabeeOp { return window.plugin.wasabee._selectedOp; } @@ -21,7 +24,7 @@ export async function initSelectedOperation() { await loadNewDefaultOp(); } else { // verify it exists before trying to load - let tmp = await WasabeeOp.load(toLoad); + const tmp = await WasabeeOp.load(toLoad); if (tmp == null) { console.log( "most recently loaded up not present in local store, starting with new default op" @@ -32,7 +35,7 @@ export async function initSelectedOperation() { } } } - return window.plugin.wasabee._selectedOp; + return getSelectedOperation(); } export async function changeOpIfNeeded() { @@ -42,23 +45,23 @@ export async function changeOpIfNeeded() { if (ops.length == 0) await loadNewDefaultOp(); else await makeSelectedOperation(ops[ops.length - 1]); } - return window.plugin.wasabee._selectedOp; + return getSelectedOperation(); } // create a new op and set it as selected export async function loadNewDefaultOp() { const newOp = new WasabeeOp({ creator: PLAYER.nickname, - name: wX("DEFAULT OP NAME", { date: new Date().toGMTString() }), + name: wX("DEFAULT OP NAME", { date: new Date().toUTCString() }), }); await newOp.store(); await makeSelectedOperation(newOp.ID); - return window.plugin.wasabee._selectedOp; + return getSelectedOperation(); } // this is the function that loads an op from the store, makes it the selected op and draws it to the screen // only this should write to _selectedOp -export async function makeSelectedOperation(opID) { +export async function makeSelectedOperation(opID: OpID) { // _selectedOp is null at first load (or page reload), should never be after that let previousID; if (window.plugin.wasabee._selectedOp != null) { @@ -79,8 +82,14 @@ export async function makeSelectedOperation(opID) { const op = await WasabeeOp.load(opID); if (op == null) { console.log("makeSelectedOperation called on invalid opID"); - alert("attempted to load invalid opID"); + displayError("attempted to load invalid opID"); + return; } + + // remove old listeners ? old object should never .store + op.on("update", () => window.map.fire("wasabee:op:change")); + op.on("blockers", () => window.map.fire("wasabee:crosslinks")); + // the only place we should change the selected op. delete window.plugin.wasabee._selectedOp; window.plugin.wasabee._selectedOp = op; @@ -114,7 +123,7 @@ export async function setupLocalStorage() { ops = await opsList(); } - const migrations = Array(); + const migrations = []; for (const opID of ops) { migrations.push(WasabeeOp.migrate(opID)); } @@ -130,13 +139,14 @@ export async function setupLocalStorage() { } //** This function removes an operation from the main list */ -export async function removeOperation(opID) { +export async function removeOperation(opID: OpID) { await WasabeeOp.delete(opID); + WasabeeBlocker.removeBlockers(opID); // no need to await window.map.fire("wasabee:op:delete", opID); } //** This function shows an operation to the main list */ -export function showOperation(opID) { +export function showOperation(opID: OpID) { const hiddenOps = hiddenOpsList(); if (hiddenOps.includes(opID)) { localStorage[window.plugin.wasabee.static.constants.OPS_LIST_HIDDEN_KEY] = @@ -146,7 +156,7 @@ export function showOperation(opID) { } //** This function hides an operation to the main list */ -export function hideOperation(opID) { +export function hideOperation(opID: OpID) { const hiddenOps = hiddenOpsList(); if (!hiddenOps.includes(opID)) { hiddenOps.push(opID); @@ -166,9 +176,10 @@ export async function resetOps() { const ops = await opsList(); // don't fire event here await Promise.all(ops.map(WasabeeOp.delete)); + ops.map(WasabeeBlocker.removeBlockers); // no need to await } -export function hiddenOpsList() { +export function hiddenOpsList(): OpID[] { try { const raw = localStorage[window.plugin.wasabee.static.constants.OPS_LIST_HIDDEN_KEY]; @@ -178,7 +189,7 @@ export function hiddenOpsList() { } } -export async function setOpBackground(opID, background) { +export async function setOpBackground(opID: OpID, background: boolean) { const sop = getSelectedOperation(); const op = sop.ID === opID ? sop : await WasabeeOp.load(opID); if (op.background == background) return; @@ -192,7 +203,7 @@ export async function setOpBackground(opID, background) { export async function opsList(hidden = true) { // after 0.19, remove the list and just query the idb keys - let ops = []; + let ops: OpID[] = []; try { const raw = localStorage[window.plugin.wasabee.static.constants.OPS_LIST_KEY]; @@ -212,8 +223,8 @@ export async function opsList(hidden = true) { return ops; } -export async function duplicateOperation(opID) { - let op = null; +export async function duplicateOperation(opID: OpID) { + let op: WasabeeOp = null; if (opID == window.plugin.wasabee._selectedOp.ID) { op = window.plugin.wasabee._selectedOp; await op.store(); @@ -224,22 +235,31 @@ export async function duplicateOperation(opID) { // XXX op.toExport() might be helpful here op.ID = generateId(); - op.name = op.name + " " + new Date().toGMTString(); + op.name = op.name + " " + new Date().toUTCString(); op.creator = window.PLAYER.nickname; op.teamlist = null; op.fetched = null; - op.keysonhand = new Array(); + op.keysonhand = []; op.cleanAll(); await op.store(); return op; } -// this checks me from cache; if not logged in, no op is owned and all on server will be deleted, which may confuse users -export async function removeNonOwnedOps() { +// use the provided GID to delete server ops +export async function removeNonOwnedOps( + data: LeafletEvent & { GID: GoogleID } +) { + // no GID provided, likely following a server change while not logged in + if (!data.GID) { + return; + } for (const opID of await opsList()) { const op = await WasabeeOp.load(opID); // don't fire event here - if (!op || !op.isOwnedOp()) await WasabeeOp.delete(opID); + if (!op || (op.isServerOp() && op.creator !== data.GID)) { + await WasabeeOp.delete(opID); + WasabeeBlocker.removeBlockers(opID); // no need to await + } } await changeOpIfNeeded(); } diff --git a/src/code/server.js b/src/code/server.js deleted file mode 100644 index ca4da1d3a..000000000 --- a/src/code/server.js +++ /dev/null @@ -1,752 +0,0 @@ -import WasabeeMe from "./me"; -import WasabeeOp from "./operation"; -import { getSelectedOperation, removeOperation } from "./selectedOp"; -import wX from "./wX"; -import WasabeeMarker from "./marker"; - -export default function () { - return GetWasabeeServer(); -} - -// uploads an op to the server -// refreshed op stored to localStorage; "me" upated to reflect new op in list -export async function uploadOpPromise() { - const operation = getSelectedOperation(); - const json = operation.toExport(); - - const response = await genericPost( - "/api/v1/draw", - json, - "application/json;charset=UTF-8" - ); - const newme = new WasabeeMe(response); - newme.store(); - const newop = await opPromise(operation.ID); - // merge blockers and related portals - newop.mergeBlockers(operation); - newop.localchanged = false; - await newop.store(); - return newop; -} - -// sends a changed op to the server -export async function updateOpPromise(operation) { - const json = operation.toExport(); - - try { - const construct = { - method: "PUT", - mode: "cors", - cache: "default", - credentials: "include", - redirect: "manual", - referrerPolicy: "origin", - body: json, - headers: { "Content-Type": "application/json;charset=UTF-8" }, - }; - if (operation.lasteditid) - construct.headers["If-Match"] = operation.lasteditid; - - const response = await fetch( - GetWasabeeServer() + `/api/v1/draw/${operation.ID}`, - construct - ); - - switch (response.status) { - case 200: - try { - const text = await response.text(); - const obj = JSON.parse(text); - if (obj.updateID) GetUpdateList().set(obj.updateID, Date.now()); - operation.lasteditid = obj.updateID; - operation.remoteChanged = false; - operation.fetched = new Date().toUTCString(); - return Promise.resolve(true); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - case 412: - // mismatch etag - try { - return Promise.resolve(false); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - case 401: - WasabeeMe.purge(); - try { - const err = await response.json(); - return Promise.reject(wX("NOT LOGGED IN", { error: err.error })); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - default: - try { - const err = await response.json(); - return Promise.reject(err.error); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - } - } catch (e) { - console.error(e); - return Promise.reject(e); - } -} - -// removes an op from the server -export function deleteOpPromise(opID) { - return genericDelete(`/api/v1/draw/${opID}`, new FormData()); -} - -// returns a promise to op stat from the server -export function statOpPromise(opID) { - return genericGet(`/api/v1/draw/${opID}/stat`); -} - -// returns a promise to a WasabeeTeam -- used only by WasabeeTeam.get -// use WasabeeTeam.get -export function teamPromise(teamid) { - return genericGet(`/api/v1/team/${teamid}`); -} - -// returns a promise to fetch a WasabeeOp -// local change: If the server's copy is newer than the local copy, otherwise none -// not generic since 304 result processing and If-Modified-Since header -export async function opPromise(opID) { - let ims = "Sat, 29 Oct 1994 19:43:31 GMT"; // the dawn of time... - const localop = await WasabeeOp.load(opID); - if (localop != null && localop.fetched) ims = localop.fetched; - - try { - const server = GetWasabeeServer(); - const headers = {}; - // ops synced since 0.19: prefer lasteditid if available - if (localop && localop.lasteditid) - headers["If-None-Match"] = localop.lasteditid; - else headers["If-Modified-Since"] = ims; - const response = await fetch(server + `/api/v1/draw/${opID}`, { - method: "GET", - mode: "cors", - cache: "default", - credentials: "include", - redirect: "manual", - referrerPolicy: "origin", - headers: headers, - }); - - let raw = null; - let newop = null; // I hate javascript - switch (response.status) { - case 200: - raw = await response.json(); - newop = new WasabeeOp(raw); - newop.localchanged = false; - newop.server = server; - newop.fetchedOp = JSON.stringify(raw); - return Promise.resolve(newop); - case 304: // If-None-Match or If-Modified-Since replied NotModified - console.warn("server copy is older/unmodified, keeping local copy"); - localop.server = server; - return Promise.resolve(localop); - case 401: - WasabeeMe.purge(); - raw = await response.json(); - return Promise.reject(wX("NOT LOGGED IN", { error: raw.error })); - case 403: - await removeOperation(opID); - raw = await response.json(); - return Promise.reject( - wX("OP PERM DENIED", { opID: opID }) + ": " + raw.error - ); - case 410: - await removeOperation(opID); - raw = await response.json(); - return Promise.reject( - wX("OP DELETED", { opID: opID }) + ": " + raw.error - ); - default: - try { - const err = await response.json(); - return Promise.reject(err.error); - } catch (e) { - console.error(e); - raw = await response.text(); - return Promise.reject(raw); - } - } - } catch (e) { - console.error(e); - return Promise.reject(e); - } -} - -// returns a promise to WasabeeMe -- should be called only by WasabeeMe.waitGet() -// use WasabeeMe.cacheGet or WasabeeMe.waitGet for caching -export function mePromise() { - return genericGet("/me?json=y"); -} - -// returns a promise to get the agent's JSON data from the server -- should be called only by WasabeeAgent.get() -export function agentPromise(GID) { - return genericGet(`/api/v1/agent/${GID}`); -} - -// local change: none // cache: none -export function assignMarkerPromise(opID, markerID, agentID) { - const fd = new FormData(); - fd.append("agent", agentID); - return genericPost(`/api/v1/draw/${opID}/marker/${markerID}/assign`, fd); -} - -// performs a link assignment on the server, sending notifications -export function assignLinkPromise(opID, linkID, agentID) { - const fd = new FormData(); - fd.append("agent", agentID); - return genericPost(`/api/v1/draw/${opID}/link/${linkID}/assign`, fd); -} - -// sends a target (portal) to the server to notify the agent -export function targetPromise(agentID, portal, type = "ad hoc") { - return genericPost( - `/api/v1/agent/${agentID}/target`, - JSON.stringify({ - Name: portal.name, - Lat: portal.lat, - Lng: portal.lng, - ID: portal.id, - Type: type, - }), - "application/json;charset=UTF-8" - ); -} - -// work in progress -- server support not finished -export function routePromise(agentID, portal) { - const ll = portal.lat + "," + portal.lng; - const fd = new FormData(); - fd.append("id", agentID); - fd.append("portal", portal.name); - fd.append("ll", ll); - return genericPost(`/api/v1/agent/${agentID}/route`, fd); -} - -// returns a promise to /me if the access token is valid -export function SendAccessTokenAsync(accessToken) { - return genericPost( - "/aptok", - JSON.stringify({ accessToken: accessToken }), - "application/json;charset=UTF-8" - ); -} - -// changes agent's team state on the server; return value is status message -export function SetTeamState(teamID, state) { - return genericGet(`/api/v1/me/${teamID}?state=${state}`); -} - -export function SetTeamShareWD(teamID, state) { - return genericGet(`/api/v1/me/${teamID}/wdshare?state=${state}`); -} - -export function SetTeamLoadWD(teamID, state) { - return genericGet(`/api/v1/me/${teamID}/wdload?state=${state}`); -} - -// changes a markers status on the server, sending relevant notifications -export function SetMarkerState(opID, markerID, state) { - let action = "incomplete"; - switch (state) { - case "acknowledged": - action = "acknowledge"; - break; - case "pending": - action = "incomplete"; - break; - case "completed": - action = "complete"; - break; - default: - action = "incomplete"; - } - - return genericGet(`/api/v1/draw/${opID}/marker/${markerID}/${action}`); -} - -// changes a link's status on the server, sending relevant notifications -export function SetLinkState(opID, linkID, state) { - let action = "incomplete"; - switch (state) { - // no acknowledge for links -- use incomplete - case "pending": - action = "incomplete"; - break; - case "completed": - action = "complete"; - break; - default: - action = "incomplete"; - } - - return genericGet(`/api/v1/draw/${opID}/link/${linkID}/${action}`); -} - -// updates an agent's key count, return value is status code -export function opKeyPromise(opID, portalID, onhand, capsule) { - const fd = new FormData(); - fd.append("count", onhand); - fd.append("capsule", capsule); - return genericPost(`/api/v1/draw/${opID}/portal/${portalID}/keyonhand`, fd); -} - -// updates an agent's single defensive key -export function dKeyPromise(json) { - return genericPost("/api/v1/d", json, "application/json;charset=UTF-8"); -} - -// many d-keys at once -export function dKeyBulkPromise(json) { - return genericPost("/api/v1/d/bulk", json, "application/json;charset=UTF-8"); -} - -// returns a promise to a list of defensive keys for all enabled teams -export function dKeylistPromise() { - return genericGet("/api/v1/d"); -} - -// updates an agent's location ; return value is status code -export function locationPromise(lat, lng) { - return genericGet(`/api/v1/me?lat=${lat}&lon=${lng}`); -} - -// sets logout status on the server; return value is status code -export function logoutPromise() { - return genericGet("/api/v1/me/logout"); -} - -// adds a permission to an op; return value is status code -export function addPermPromise(opID, teamID, role, zone) { - const fd = new FormData(); - fd.append("team", teamID); - fd.append("role", role); - fd.append("zone", zone); - return genericPost(`/api/v1/draw/${opID}/perms`, fd); -} - -// removes a permission from an op; return value is status code -export function delPermPromise(opID, teamID, role, zone) { - const fd = new FormData(); - fd.append("team", teamID); - fd.append("role", role); - fd.append("zone", zone); - return genericDelete(`/api/v1/draw/${opID}/perms`, fd); -} - -// removes the agent from the team; return value is status code -export function leaveTeamPromise(teamID) { - return genericDelete(`/api/v1/me/${teamID}`, new FormData()); -} - -// removes another agent from an owned team ; return value is status code -export function removeAgentFromTeamPromise(agentID, teamID) { - return genericDelete(`/api/v1/team/${teamID}/${agentID}`, new FormData()); -} - -// local change: none // cache: none -export function setAgentTeamSquadPromise(agentID, teamID, squad) { - const fd = new FormData(); - fd.append("squad", squad); - return genericPost(`/api/v1/team/${teamID}/${agentID}/squad`, fd); -} - -// local change: none // cache: none -export function addAgentToTeamPromise(agentID, teamID) { - return genericPost(`/api/v1/team/${teamID}/${agentID}`, new FormData()); -} - -// local change: none // cache: none -export function renameTeamPromise(teamID, name) { - const fd = new FormData(); - fd.append("teamname", name); - return genericPut(`/api/v1/team/${teamID}/rename`, fd); -} - -// local change: none // cache: none -export function rocksPromise(teamID, community, apikey) { - return genericGet( - `/api/v1/team/${teamID}/rockscfg?rockscomm=${community}&rockskey=${apikey}` - ); -} - -// local change: none // cache: none -export function newTeamPromise(name) { - return genericGet(`/api/v1/team/new?name=${name}`); -} - -// local change: none // cache: none -export function deleteTeamPromise(teamID) { - return genericDelete(`/api/v1/team/${teamID}`, new FormData()); -} - -// local change: none // cache: none -export function oneTimeToken(token) { - const url = "/oneTimeToken"; - const fd = new FormData(); - fd.append("token", token); - return genericPost(url, fd); -} - -async function genericPut(url, formData, contentType) { - try { - const construct = { - method: "PUT", - mode: "cors", - cache: "default", - credentials: "include", - redirect: "manual", - referrerPolicy: "origin", - body: formData, - }; - if (contentType != null) { - construct.headers = { "Content-Type": contentType }; - } - const response = await fetch(GetWasabeeServer() + url, construct); - - switch (response.status) { - case 200: - try { - const text = await response.text(); - const obj = JSON.parse(text); - if (obj.updateID) GetUpdateList().set(obj.updateID, Date.now()); - // returns a promise to the content - return Promise.resolve(text); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - case 401: - WasabeeMe.purge(); - try { - const err = await response.json(); - return Promise.reject(wX("NOT LOGGED IN", { error: err.error })); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - default: - try { - const err = await response.json(); - return Promise.reject(err.error); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - } - } catch (e) { - console.error(e); - return Promise.reject(e); - } -} - -async function genericPost(url, formData, contentType) { - try { - const construct = { - method: "POST", - mode: "cors", - cache: "default", - credentials: "include", - redirect: "manual", - referrerPolicy: "origin", - body: formData, - }; - if (contentType != null) { - construct.headers = { "Content-Type": contentType }; - } - const response = await fetch(GetWasabeeServer() + url, construct); - - switch (response.status) { - case 200: - try { - const text = await response.text(); - const obj = JSON.parse(text); - if (obj.updateID) GetUpdateList().set(obj.updateID, Date.now()); - // returns a promise to the content - return Promise.resolve(text); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - case 401: - WasabeeMe.purge(); - try { - const err = await response.json(); - return Promise.reject(wX("NOT LOGGED IN", { error: err.error })); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - default: - try { - const err = await response.json(); - return Promise.reject(err.error); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - } - } catch (e) { - console.error(e); - return Promise.reject(e); - } -} - -async function genericDelete(url, formData, contentType) { - try { - const construct = { - method: "DELETE", - mode: "cors", - cache: "default", - credentials: "include", - redirect: "manual", - referrerPolicy: "origin", - body: formData, - }; - if (contentType != null) { - construct.headers = { "Content-Type": contentType }; - } - const response = await fetch(GetWasabeeServer() + url, construct); - - switch (response.status) { - case 200: - try { - const text = await response.text(); - const obj = JSON.parse(text); - if (obj.updateID) GetUpdateList().set(obj.updateID, Date.now()); - // returns a promise to the content - return Promise.resolve(text); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - case 401: - WasabeeMe.purge(); - try { - const err = await response.json(); - return Promise.reject(wX("NOT LOGGED IN", { error: err.error })); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - default: - try { - const err = await response.json(); - return Promise.reject(err.error); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - } - } catch (e) { - console.error(e); - return Promise.reject(e); - } -} - -async function genericGet(url) { - try { - const response = await fetch(GetWasabeeServer() + url, { - method: "GET", - mode: "cors", - cache: "default", - credentials: "include", - redirect: "manual", - referrerPolicy: "origin", - }); - - switch (response.status) { - case 200: - try { - const text = await response.text(); - if ( - response.headers.get("Content-Type").includes("application/json") - ) { - const obj = JSON.parse(text); - if (obj.updateID) GetUpdateList().set(obj.updateID, Date.now()); - } - // returns a promise to the content - return Promise.resolve(text); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - case 401: - WasabeeMe.purge(); - try { - const err = await response.json(); - return Promise.reject(wX("NOT LOGGED IN", { error: err.error })); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - case 403: - try { - const err = await response.json(); - return Promise.reject("forbidden: " + err.error); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - default: - console.log(response); - try { - const err = await response.json(); - return Promise.reject(err.error); - } catch (e) { - console.error(e); - return Promise.reject(e); - } - // break; - } - } catch (e) { - console.error(e); - return Promise.reject(e); - } -} - -export function GetWasabeeServer() { - // Wasabee-IITC, use the configured server - if (window.plugin && window.plugin.wasabee) { - let server = - localStorage[window.plugin.wasabee.static.constants.SERVER_BASE_KEY]; - if (server == null) { - server = window.plugin.wasabee.static.constants.SERVER_BASE_DEFAULT; - localStorage[window.plugin.wasabee.static.constants.SERVER_BASE_KEY] = - server; - } - return server; - } - // Wasabee-WebUI doesn't need to specify the server - return ""; -} - -export function GetUpdateList() { - if (window.plugin && window.plugin.wasabee) { - return window.plugin.wasabee._updateList; - } - return window.wasabeewebui._updateList; -} - -export function SetWasabeeServer(server) { - server = server.trim(); - if (!server.startsWith("http")) server = "https://" + server; - if (server.endsWith("/")) server = server.slice(0, -1); - localStorage[window.plugin.wasabee.static.constants.SERVER_BASE_KEY] = server; -} - -/* The following are for Wasabee-WebUI and not used in Wasabee-IITC */ - -// in the service-worker for IITC -export function sendTokenToWasabee(token) { - // no need for a form-data, just send the raw token - return genericPost(`/api/v1/me/firebase`, token); -} - -export function getCustomTokenFromServer() { - return genericGet(`/api/v1/me/firebase`); -} - -export function loadConfig() { - return genericGet(`/static/wasabee-webui-config.json`); -} - -export function changeTeamOwnerPromise(teamID, newOwner) { - return genericGet(`/api/v1/team/${teamID}/chown?to=${newOwner}`); -} - -export function createJoinLinkPromise(teamID) { - return genericGet(`/api/v1/team/${teamID}/genJoinKey`); -} - -export function deleteJoinLinkPromise(teamID) { - return genericGet(`/api/v1/team/${teamID}/delJoinKey`); -} - -export function setAssignmentStatus(op, object, completed) { - let type = "link"; - if (object instanceof WasabeeMarker) type = "marker"; - let c = "incomplete"; - if (completed) c = "complete"; - - return genericGet(`/api/v1/draw/${op.ID}/${type}/${object.ID}/${c}`); -} - -export function sendAnnounce(teamID, message) { - const fd = new FormData(); - fd.append("m", message); - return genericPost(`/api/v1/team/${teamID}/announce`, fd); -} - -export function pullRocks(teamID) { - return genericGet(`/api/v1/team/${teamID}/rocks`); -} - -export function reverseLinkDirection(opID, linkID) { - return genericGet(`/api/v1/draw/${opID}/link/${linkID}/swap`); -} - -export function setOpInfo(opID, info) { - const fd = new FormData(); - fd.append("info", info); - return genericPost(`/api/v1/draw/${opID}/info`, fd); -} - -export function setMarkerComment(opID, markerID, comment) { - const fd = new FormData(); - fd.append("comment", comment); - return genericPost(`/api/v1/draw/${opID}/marker/${markerID}/comment`, fd); -} - -export function setLinkComment(opID, linkID, desc) { - const fd = new FormData(); - fd.append("desc", desc); - return genericPost(`/api/v1/draw/${opID}/link/${linkID}/desc`, fd); -} - -export function setLinkZone(opID, linkID, zone) { - const fd = new FormData(); - fd.append("zone", zone); - return genericPost(`/api/v1/draw/${opID}/link/${linkID}/zone`, fd); -} - -export function setMarkerZone(opID, markerID, zone) { - const fd = new FormData(); - fd.append("zone", zone); - return genericPost(`/api/v1/draw/${opID}/marker/${markerID}/zone`, fd); -} - -export function setIntelID(name, faction, querytoken) { - const fd = new FormData(); - fd.append("name", name); - fd.append("faction", faction); - fd.append("qt", querytoken); - return genericPut(`/api/v1/me/intelid`, fd); -} diff --git a/src/code/server.ts b/src/code/server.ts new file mode 100644 index 000000000..dc9e035e3 --- /dev/null +++ b/src/code/server.ts @@ -0,0 +1,776 @@ +import WasabeeMe from "./model/me"; +import WasabeeOp from "./model/operation"; +import { getSelectedOperation, removeOperation } from "./selectedOp"; +import { ServerError } from "./error"; +import type { TaskState } from "./model/task"; +import type WasabeePortal from "./model/portal"; +import type WasabeeAgent from "./model/agent"; +import type WasabeeTeam from "./model/team"; +import type { WDKey } from "./wd"; +import { getJWT } from "./auth"; +import type Task from "./model/task"; +import type WasabeeLink from "./model/link"; +import type WasabeeMarker from "./model/marker"; + +export default function () { + return GetWasabeeServer(); +} + +export function GetWasabeeServer() { + // Wasabee-IITC, use the configured server + if (window.plugin && window.plugin.wasabee) { + let server = + localStorage[window.plugin.wasabee.static.constants.SERVER_BASE_KEY]; + if (server == null) { + server = window.plugin.wasabee.static.constants.SERVER_BASE_DEFAULT; + localStorage[window.plugin.wasabee.static.constants.SERVER_BASE_KEY] = + server; + } + return server; + } + // Wasabee-WebUI doesn't need to specify the server + return ""; +} + +export function GetUpdateList() { + if (window.plugin && window.plugin.wasabee) { + return window.plugin.wasabee._updateList; + } + return window.wasabeewebui._updateList; +} + +export function SetWasabeeServer(server) { + server = server.trim(); + if (!server.startsWith("http")) server = "https://" + server; + if (server.endsWith("/")) server = server.slice(0, -1); + localStorage[window.plugin.wasabee.static.constants.SERVER_BASE_KEY] = server; +} + +interface IServerStatus { + status: string; +} + +interface IServerUpdate extends IServerStatus { + updateID: string; +} + +/* +On fail, all promises reject an ServerError { code: number, text: string, error?: string } +If http code is 401: request Me.purge (fire wasabee:logout) +On success, it may returns: + - the requested data as string + - the requested object + - 304 (if modified) + - true/false (updateOp) +*/ + +export function loadConfig() { + return genericGet(`/static/wasabee-webui-config.json`); +} + +// returns a promise to /me if the access token is valid +export function SendAccessTokenAsync(accessToken) { + return genericPost( + "/aptok", + JSON.stringify({ accessToken: accessToken }), + "application/json;charset=UTF-8" + ); +} + +// sets logout status on the server; return value is status code +export function logoutPromise() { + return genericGet("/api/v1/me/logout"); +} + +// local change: none // cache: none +export function oneTimeToken(token) { + const url = "/oneTimeToken"; + const fd = new FormData(); + fd.append("token", token); + return genericPost(url, fd); +} + +/**** me & d ****/ + +// returns a promise to WasabeeMe -- should be called only by WasabeeMe.waitGet() +// use WasabeeMe.cacheGet or WasabeeMe.waitGet for caching +export function mePromise() { + return genericGet("/api/v1/me"); +} + +// returns a promise to a list of defensive keys for all enabled teams +export function dKeylistPromise() { + return genericGet<{ + DefensiveKeys: WDKey[]; + }>("/api/v1/d"); +} + +// removes the agent from the team; return value is status code +export function leaveTeamPromise(teamID: TeamID) { + return genericDelete(`/api/v1/me/${teamID}`); +} + +// updates an agent's location ; return value is status code +export function locationPromise(lat: number, lng: number) { + return genericGet(`/api/v1/me?lat=${lat}&lon=${lng}`); +} + +export function setIntelID(name: string, faction: string, querytoken: string) { + const fd = new FormData(); + fd.append("name", name); + fd.append("faction", faction); + fd.append("qt", querytoken); + return genericPut(`/api/v1/me/intelid`, fd); +} + +// changes agent's team state on the server; return value is status message +export function SetTeamState(teamID: TeamID, state: "On" | "Off") { + return genericGet(`/api/v1/me/${teamID}?state=${state}`); +} + +export function SetTeamShareWD(teamID: TeamID, state: "On" | "Off") { + return genericGet(`/api/v1/me/${teamID}/wdshare?state=${state}`); +} + +export function SetTeamLoadWD(teamID: TeamID, state: "On" | "Off") { + return genericGet(`/api/v1/me/${teamID}/wdload?state=${state}`); +} + +// updates an agent's single defensive key +export function dKeyPromise(json: string) { + return genericPost("/api/v1/d", json, "application/json;charset=UTF-8"); +} + +// many d-keys at once +export function dKeyBulkPromise(json: string) { + return genericPost("/api/v1/d/bulk", json, "application/json;charset=UTF-8"); +} + +/* agent */ + +// returns a promise to get the agent's JSON data from the server -- should be called only by WasabeeAgent.get() +export function agentPromise(GID: GoogleID) { + return genericGet(`/api/v1/agent/${GID}`); +} + +// sends a target (portal) to the server to notify the agent +export function targetPromise( + agentID: GoogleID, + portal: WasabeePortal, + type = "ad hoc" +) { + return genericPost( + `/api/v1/agent/${agentID}/target`, + JSON.stringify({ + Name: portal.name, + Lat: portal.lat, + Lng: portal.lng, + ID: portal.id, + Type: type, + }), + "application/json;charset=UTF-8" + ); +} + +/* team */ + +// returns a promise to a WasabeeTeam -- used only by WasabeeTeam.get +// use WasabeeTeam.get +export function teamPromise(teamid: TeamID) { + return genericGet(`/api/v1/team/${teamid}`); +} + +export function sendAnnounce(teamID: TeamID, message: string) { + const fd = new FormData(); + fd.append("m", message); + return genericPost(`/api/v1/team/${teamID}/announce`, fd); +} + +export function pullRocks(teamID: TeamID) { + return genericGet(`/api/v1/team/${teamID}/rocks`); +} + +// local change: none // cache: none +export function newTeamPromise(name: string) { + return genericGet(`/api/v1/team/new?name=${name}`); +} + +// local change: none // cache: none +export function renameTeamPromise(teamID: TeamID, name: string) { + const fd = new FormData(); + fd.append("teamname", name); + return genericPut(`/api/v1/team/${teamID}/rename`, fd); +} + +// local change: none // cache: none +export function deleteTeamPromise(teamID: TeamID) { + return genericDelete(`/api/v1/team/${teamID}`); +} + +export function changeTeamOwnerPromise(teamID: TeamID, newOwner: GoogleID) { + return genericGet(`/api/v1/team/${teamID}/chown?to=${newOwner}`); +} + +// local change: none // cache: none +export function addAgentToTeamPromise(agentID: GoogleID, teamID: TeamID) { + return genericPost(`/api/v1/team/${teamID}/${agentID}`, new FormData()); +} + +// removes another agent from an owned team ; return value is status code +export function removeAgentFromTeamPromise(agentID: GoogleID, teamID: TeamID) { + return genericDelete(`/api/v1/team/${teamID}/${agentID}`); +} + +// local change: none // cache: none +export function rocksPromise( + teamID: TeamID, + community: string, + apikey: string +) { + return genericGet( + `/api/v1/team/${teamID}/rockscfg?rockscomm=${community}&rockskey=${apikey}` + ); +} + +// local change: none // cache: none +export function setAgentTeamSquadPromise( + agentID: GoogleID, + teamID: TeamID, + squad: string +) { + const fd = new FormData(); + fd.append("squad", squad); + return genericPost(`/api/v1/team/${teamID}/${agentID}/squad`, fd); +} + +export function createJoinLinkPromise(teamID: TeamID) { + return genericGet<{ Key: string }>(`/api/v1/team/${teamID}/genJoinKey`); +} + +export function deleteJoinLinkPromise(teamID: TeamID) { + return genericGet(`/api/v1/team/${teamID}/delJoinKey`); +} + +// returns a promise to fetch a WasabeeOp +// local change: If the server's copy is newer than the local copy, otherwise none +// not generic since 304 result processing and If-Modified-Since header +export async function opPromise(opID: OpID) { + let ims = "Sat, 29 Oct 1994 19:43:31 GMT"; // the dawn of time... + const localop = await WasabeeOp.load(opID); + if (localop != null && localop.fetched) ims = localop.fetched; + + try { + const raw = await generic({ + url: `/api/v1/draw/${opID}`, + method: "GET", + headers: localop + ? localop.lasteditid + ? { + "If-None-Match": localop.lasteditid, + } + : { + "If-Modified-Since": ims, + } + : null, + }); + + const newop = new WasabeeOp(raw); + newop.localchanged = false; + newop.server = GetWasabeeServer(); + newop.fetchedOp = JSON.stringify(raw); + return newop; + } catch (e) { + if (!(e instanceof ServerError)) { + // unexpected error + console.error(e); + return Promise.reject( + new ServerError({ + code: -1, + text: `Unexpected error: ${e}`, + }) + ); + } + switch (e.code) { + case 304: + localop.server = GetWasabeeServer(); + return localop; + case 403: + // fallthrough + case 410: + await removeOperation(opID); + // fallthrough + default: + return Promise.reject(e); + } + } +} + +// uploads an op to the server +// refreshed op stored to localStorage; "me" upated to reflect new op in list +export async function uploadOpPromise() { + const operation = getSelectedOperation(); + const json = operation.toExport(); + + const response = await genericPost( + "/api/v1/draw", + json, + "application/json;charset=UTF-8" + ); + const newme = new WasabeeMe(response); + newme.store(); + const newop = await opPromise(operation.ID); + newop.localchanged = false; + await newop.store(); + return newop; +} + +// sends a changed op to the server +export async function updateOpPromise(operation: WasabeeOp) { + const json = operation.toExport(); + + try { + const update = await generic({ + url: `/api/v1/draw/${operation.ID}`, + method: "PUT", + body: json, + headers: operation.lasteditid + ? { + "Content-Type": "application/json;charset=UTF-8", + "If-Match": operation.lasteditid, + } + : { + "Content-Type": "application/json;charset=UTF-8", + }, + }); + operation.lasteditid = update.updateID; + operation.remoteChanged = false; + operation.fetched = new Date().toUTCString(); + operation.fetchedOp = JSON.stringify(operation); + return true; + } catch (e) { + if (!(e instanceof ServerError)) { + // unexpected error + console.error(e); + return Promise.reject( + new ServerError({ + code: -1, + text: `Unexpected error: ${e}`, + }) + ); + } + switch (e.code) { + case 412: + return false; + // break; + case 410: + await removeOperation(operation.ID); + // fallthrough + default: + return Promise.reject(e); + } + } +} + +// removes an op from the server +export function deleteOpPromise(opID: OpID) { + return genericDelete(`/api/v1/draw/${opID}`); +} + +export function setOpInfo(opID: OpID, info: string) { + const fd = new FormData(); + fd.append("info", info); + return genericPost(`/api/v1/draw/${opID}/info`, fd); +} + +// adds a permission to an op; return value is status code +export function addPermPromise( + opID: OpID, + teamID: TeamID, + role: string, + zone: ZoneID +) { + const fd = new FormData(); + fd.append("team", teamID); + fd.append("role", role); + fd.append("zone", `${zone}`); + return genericPost(`/api/v1/draw/${opID}/perms`, fd); +} + +// removes a permission from an op; return value is status code +export function delPermPromise( + opID: OpID, + teamID: TeamID, + role: string, + zone: ZoneID +) { + const fd = new FormData(); + fd.append("team", teamID); + fd.append("role", role); + fd.append("zone", `${zone}`); + return genericDelete(`/api/v1/draw/${opID}/perms`, fd); +} + +export function getLinkPromise(opID: OpID, taskID: TaskID) { + return genericGet(`/api/v1/draw/${opID}/link/${taskID}`); +} + +export function getMarkerPromise(opID: OpID, taskID: TaskID) { + return genericGet(`/api/v1/draw/${opID}/marker/${taskID}`); +} + +// tasks + +export function taskGetPromise(opID: OpID, taskID: TaskID) { + return genericGet(`/api/v1/draw/${opID}/task/${taskID}`); +} + +export function taskOrderPromise(opID: OpID, taskID: TaskID, order: number) { + const fd = new FormData(); + fd.append("order", `${order}`); + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/order`, + fd + ); +} + +export function taskAssignPromise( + opID: OpID, + taskID: TaskID, + gids: GoogleID[] +) { + const fd = new FormData(); + for (const gid of gids) { + fd.append("agent[]", gid); + } + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/assign`, + fd + ); +} + +export function taskDeleteAssignPromise(opID: OpID, taskID: TaskID) { + return genericDelete( + `/api/v1/draw/${opID}/task/${taskID}/assign` + ); +} + +export function taskCommentPromise( + opID: OpID, + taskID: TaskID, + comment: string +) { + const fd = new FormData(); + fd.append("comment", comment); + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/comment`, + fd + ); +} + +export function taskCompletePromise( + opID: OpID, + taskID: TaskID, + complete: boolean +) { + const action = complete ? "complete" : "incomplete"; + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/${action}` + ); +} + +export function taskAckPromise(opID: OpID, taskID: TaskID) { + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/acknowledge` + ); +} + +export function taskRejectPromise(opID: OpID, taskID: TaskID) { + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/reject` + ); +} + +export function taskClaimPromise(opID: OpID, taskID: TaskID) { + return genericPut(`/api/v1/draw/${opID}/task/${taskID}/claim`); +} + +export function taskZonePromise(opID: OpID, taskID: TaskID, zone: ZoneID) { + const fd = new FormData(); + fd.append("zone", `${zone}`); + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/zone`, + fd + ); +} + +export function taskDeltaPromise(opID: OpID, taskID: TaskID, delta: number) { + const fd = new FormData(); + fd.append("delta", `${delta}`); + return genericPut(`/api/v1/draw/${opID}/task/${taskID}/delta`); +} + +export function taskAddDependPromise(opID: OpID, taskID: TaskID, dep: TaskID) { + return genericPut( + `/api/v1/draw/${opID}/task/${taskID}/depend/${dep}` + ); +} + +export function taskDelDependPromise(opID: OpID, taskID: TaskID, dep: TaskID) { + return genericDelete( + `/api/v1/draw/${opID}/task/${taskID}/depend/${dep}` + ); +} + +// local change: none // cache: none +export function assignMarkerPromise( + opID: OpID, + markerID: MarkerID, + agentID: GoogleID +) { + const fd = new FormData(); + fd.append("agent", agentID); + return genericPost(`/api/v1/draw/${opID}/marker/${markerID}/assign`, fd); +} + +// performs a link assignment on the server, sending notifications +export function assignLinkPromise( + opID: OpID, + linkID: LinkID, + agentID: GoogleID +) { + const fd = new FormData(); + fd.append("agent", agentID); + return genericPost(`/api/v1/draw/${opID}/link/${linkID}/assign`, fd); +} + +// changes a markers status on the server, sending relevant notifications +export function SetMarkerState( + opID: OpID, + markerID: MarkerID, + state: TaskState +) { + let action: "incomplete" | "acknowledge" | "complete" = "incomplete"; + switch (state) { + case "acknowledged": + action = "acknowledge"; + break; + case "pending": + action = "incomplete"; + break; + case "completed": + action = "complete"; + break; + default: + action = "incomplete"; + } + + return genericGet(`/api/v1/draw/${opID}/marker/${markerID}/${action}`); +} + +// changes a link's status on the server, sending relevant notifications +export function SetLinkState(opID: OpID, linkID: LinkID, state: TaskState) { + let action: "incomplete" | "acknowledge" | "complete" = "incomplete"; + switch (state) { + // no acknowledge for links -- use incomplete + case "pending": + action = "incomplete"; + break; + case "completed": + action = "complete"; + break; + default: + action = "incomplete"; + } + + return genericGet(`/api/v1/draw/${opID}/link/${linkID}/${action}`); +} + +export function reverseLinkDirection(opID: OpID, linkID: LinkID) { + return genericGet(`/api/v1/draw/${opID}/link/${linkID}/swap`); +} + +export function setMarkerComment( + opID: OpID, + markerID: MarkerID, + comment: string +) { + const fd = new FormData(); + fd.append("comment", comment); + return genericPost(`/api/v1/draw/${opID}/marker/${markerID}/comment`, fd); +} + +export function setLinkComment(opID: OpID, linkID: LinkID, desc: string) { + const fd = new FormData(); + fd.append("desc", desc); + return genericPost(`/api/v1/draw/${opID}/link/${linkID}/desc`, fd); +} + +export function setLinkZone(opID: OpID, linkID: LinkID, zone: ZoneID) { + const fd = new FormData(); + fd.append("zone", `${zone}`); + return genericPost(`/api/v1/draw/${opID}/link/${linkID}/zone`, fd); +} + +export function setMarkerZone(opID: OpID, markerID: MarkerID, zone: ZoneID) { + const fd = new FormData(); + fd.append("zone", `${zone}`); + return genericPost(`/api/v1/draw/${opID}/marker/${markerID}/zone`, fd); +} + +// updates an agent's key count, return value is status code +export function opKeyPromise( + opID: OpID, + portalID: PortalID, + onhand: number, + capsule: string +) { + const fd = new FormData(); + fd.append("count", `${onhand}`); + fd.append("capsule", capsule); + return genericPost(`/api/v1/draw/${opID}/portal/${portalID}/keyonhand`, fd); +} + +/* The following are for Wasabee-WebUI and not used in Wasabee-IITC */ + +// in the service-worker for IITC +export function sendTokenToWasabee(token: string) { + // no need for a form-data, just send the raw token + return genericPost(`/api/v1/me/firebase`, token); +} + +export function getCustomTokenFromServer() { + return generic({ + url: `/api/v1/me/firebase`, + method: "GET", + raw: true, + }); +} + +/* generic method */ +/** + * Generic fetch method against wasabee server + */ +async function generic(request: { + url: string; + method: "GET" | "POST" | "PUT" | "DELETE"; + body?: FormData | string; + headers?: HeadersInit; + raw?: boolean; + retried?: boolean; +}): Promise { + const requestInit: RequestInit = { + method: request.method, + mode: "cors", + cache: "default", + credentials: "include", + redirect: "manual", + referrerPolicy: "origin", + headers: {}, + }; + if (request.body) requestInit.body = request.body; + if (request.headers) requestInit.headers = request.headers; + + if (request.url.startsWith("/api")) { + const jwt = getJWT(); + if (jwt) requestInit.headers["Authorization"] = `Bearer ${jwt}`; + } + + try { + const response = await fetch(GetWasabeeServer() + request.url, requestInit); + /** @type Object | string */ + const payload: string = await response.text(); + + let jsonPayload; + if (!request.raw) { + if (!payload && !request.retried && response.ok) { + // server shouldn't reply empty string + console.warn( + `server answers is empty on[${request.url}], retry once, just in case ` + ); + return generic({ ...request, retried: true }); + } + try { + jsonPayload = JSON.parse(payload); + } catch { + if (response.ok) + return Promise.reject( + new ServerError({ + code: -1, + text: "unexpected server answer", + }) + ); + } + } + + switch (response.status) { + case 200: + if (!request.raw && jsonPayload.updateID) + GetUpdateList().set(jsonPayload.updateID, Date.now()); + return Promise.resolve((request.raw ? payload : jsonPayload) as T); + // break; + case 401: + WasabeeMe.purge(); + // fallthrough; + case 403: // forbidden + // fallthrough + case 410: // Gone + // fallthrough + case 412: // mismatch etag + // fallthrough + case 304: // If-None-Match or If-Modified-Since replied NotModified + // fallthrough; + default: + return Promise.reject( + new ServerError({ + code: response.status, + text: response.statusText, + error: jsonPayload ? jsonPayload.error : null, + }) + ); + } + } catch (e) { + console.error(e); + return Promise.reject( + new ServerError({ + code: -1, + text: "Network error", + }) + ); + } +} + +function genericGet(url: string) { + return generic({ + method: "GET", + url: url, + }); +} + +function genericPost( + url: string, + formData: FormData | string, + contentType?: string +) { + return generic({ + url: url, + method: "POST", + body: formData, + headers: contentType ? { "Content-Type": contentType } : null, + }); +} + +function genericPut(url: string, formData?: FormData) { + return generic({ + url: url, + method: "PUT", + body: formData, + }); +} + +function genericDelete(url: string, formData?: FormData) { + return generic({ + url: url, + method: "DELETE", + body: formData, + }); +} diff --git a/src/code/skin.js b/src/code/skin.ts similarity index 92% rename from src/code/skin.js rename to src/code/skin.ts index 0d4409797..fd3c7486e 100644 --- a/src/code/skin.js +++ b/src/code/skin.ts @@ -19,7 +19,7 @@ export function initSkin() { } function addCSS(name, content) { - if (!Wasabee._css) Wasabee._css = new Array(); + if (!Wasabee._css) Wasabee._css = []; if (Wasabee._css.includes(name)) { document.getElementById("wasabee-css-" + name).remove(); Wasabee._css.splice(Wasabee._css.indexOf(name)); @@ -36,7 +36,7 @@ function resetCSS() { for (const name of Wasabee._css) { document.getElementById("wasabee-css-" + name).remove(); } - Wasabee._css = new Array(); + Wasabee._css = []; } // const addFallback = () => { @@ -51,7 +51,7 @@ function resetCSS() { // Wasabee.skin.selfBlockStyle = Wasabee.static.selfBlockStyle; // }; -export function changeSkin(names) { +export function changeSkin(names: string[]) { if (!window.plugin.wasabeeSkins) window.plugin.wasabeeSkins = {}; if (names.length == 0) { @@ -117,7 +117,7 @@ function initAnchorIcon() { const tmp = L.DomUtil.create("div"); tmp.innerHTML = iconHTML; - const icon = tmp.firstChild; + const icon = tmp.firstChild as HTMLElement; icon.id = "wasabee-anchor-svg"; document.body.appendChild(icon); } @@ -135,13 +135,15 @@ function initOpsColor() { } } -export function addToColorList(color) { - const datalist = document.getElementById("wasabee-colors-datalist"); +export function addToColorList(color: string) { + const datalist = document.getElementById( + "wasabee-colors-datalist" + ) as HTMLDataListElement; // fail safe if (!datalist) return; for (const c of datalist.children) { - if (c.value == color) { + if ((c as HTMLOptionElement).value == color) { datalist.insertBefore(c, datalist.firstChild); return; } diff --git a/src/code/sortable.js b/src/code/sortable.ts similarity index 62% rename from src/code/sortable.js rename to src/code/sortable.ts index c4b4e2bb4..0ec5269e1 100644 --- a/src/code/sortable.js +++ b/src/code/sortable.ts @@ -1,18 +1,52 @@ -export default class Sortable { +interface SortableItem { + obj: T; + row: HTMLTableRowElement; + index: number; + values: unknown[]; + sortValues: unknown[]; +} + +export interface SortableField { + name: string; + className?: string; + value: (thing: T) => unknown; + sortValue?: (value: unknown, thing: T) => unknown; + sort?: (a: unknown, b: unknown, aobj?: T, bobj?: T) => number; + format?: (cell: HTMLTableCellElement, value: unknown, thing?: T) => void; + smallScreenHide?: boolean; + foot?: (cell: HTMLTableCellElement) => void; +} + +export default class Sortable { + _items: Array>; + _fields: Array>; + _sortBy: number; + _sortAsc: boolean; + _table: HTMLTableElement; + _head: HTMLTableSectionElement; + _body: HTMLTableSectionElement; + _foot: HTMLTableSectionElement; + _smallScreen: boolean; + _done: Promise | boolean; + _sortByStoreKey: string; + _sortAscStoreKey: string; + constructor() { this._items = []; this._fields = []; this._sortBy = 0; // which field/column number to sort by - this._sortAsc = false; // ascending or descending + this._sortAsc = true; // ascending or descending this._table = L.DomUtil.create("table", "wasabee-table"); // create this once for all this._head = L.DomUtil.create("thead", null, this._table); this._body = L.DomUtil.create("tbody", null, this._table); + this._foot = L.DomUtil.create("tfoot", null, this._table); // if IITC-Mobile is detected... this is a kludge this._smallScreen = window.plugin.userLocation ? true : false; - + this._sortByStoreKey = ""; + this._sortAscStoreKey = ""; this._done = true; } @@ -37,6 +71,7 @@ export default class Sortable { set sortBy(property) { this._sortBy = Number(property); + this.renderHead(); this.sort(); } @@ -47,9 +82,26 @@ export default class Sortable { set sortAsc(b) { if (b !== true) b = false; this._sortAsc = b; + this.renderHead(); this.sort(); } + set sortByStoreKey(b) { + this._sortByStoreKey = b; + if (localStorage[this._sortByStoreKey] == null) { + localStorage[this._sortByStoreKey] = 0; + } + this.sortBy = localStorage[this._sortByStoreKey]; + } + + set sortAscStoreKey(b) { + this._sortAscStoreKey = b; + if (localStorage[this._sortAscStoreKey] == null) { + localStorage[this._sortAscStoreKey] = "true"; + } + this.sortAsc = localStorage[this._sortAscStoreKey] == "true"; + } + get table() { return this._table; } @@ -67,6 +119,7 @@ export default class Sortable { // class getters and setter's can't be async, // this lets us build each row as a promise, then resolve them all together + const instantValues = []; const promises = incoming.map(async (obj) => { const row = L.DomUtil.create("tr"); const data = { @@ -80,15 +133,14 @@ export default class Sortable { for (const field of this._fields) { // calculate the value using the field's rules let value = field.value(obj); - if (value != null && typeof value.then === "function") - value = await value; // resolve promises + if (value != null && value instanceof Promise) value = await value; // resolve promises data.values.push(value); // calculate sortValue using the field's rules if required let sortValue = value; if (field.sortValue) { sortValue = field.sortValue(value, obj); - if (sortValue != null && typeof sortValue.then === "function") + if (sortValue != null && sortValue instanceof Promise) sortValue = await sortValue; // resolve promises } data.sortValues.push(sortValue); @@ -99,29 +151,38 @@ export default class Sortable { if (field.format) { field.format(cell, value, obj); } else { - cell.textContent = value; + cell.textContent = value as string; } if (field.smallScreenHide && this._smallScreen) { cell.style.display = "none"; } } + instantValues.push(data); return data; }); // resolve all rows at once // XXX convert to allSettled and check for individual errors rather than failing hard if any row fails // console.log(promises); - this._done = Promise.all(promises).then( - (values) => { - this._items = values; - this.sort(); - return true; - }, - (reject) => { - console.log("rejected", reject); - this._done = false; - } - ); + if (instantValues.length === promises.length) { + // all promises are already fulfilled, dont use async Promise.all + this._items = instantValues; + this.sort(); + this._done = true; + } else { + // always async + this._done = Promise.all(promises).then( + (values) => { + this._items = values; + this.sort(); + return true; + }, + (reject) => { + console.log("rejected", reject); + this._done = false; + } + ); + } } get fields() { @@ -131,6 +192,7 @@ export default class Sortable { set fields(value) { this._fields = value; this.renderHead(); + this.renderFoot(); } get done() { @@ -148,22 +210,28 @@ export default class Sortable { cell.style.display = "none"; if (field.sort !== null) { L.DomUtil.addClass(cell, "sortable"); + if (index == this._sortBy) { + L.DomUtil.addClass(cell, this._sortAsc ? "asc" : "desc"); + } L.DomEvent.on( cell, "click", (ev) => { L.DomEvent.stop(ev); for (const element of titleRow.children) { - L.DomUtil.removeClass(element, "sorted"); - L.DomUtil.removeClass(element, "asc"); - L.DomUtil.removeClass(element, "desc"); + L.DomUtil.removeClass(element as HTMLElement, "asc"); + L.DomUtil.removeClass(element as HTMLElement, "desc"); } if (index == this._sortBy) { this._sortAsc = !this._sortAsc; - L.DomUtil.addClass(cell, "sorted"); - L.DomUtil.addClass(cell, this._sortAsc ? "asc" : "desc"); } + L.DomUtil.addClass(cell, this._sortAsc ? "asc" : "desc"); + this._sortBy = index; + if (this._sortByStoreKey != null) + localStorage[this._sortByStoreKey] = this._sortBy; + if (this._sortAscStoreKey != null) + localStorage[this._sortAscStoreKey] = this._sortAsc.toString(); this.sort(); }, false @@ -172,6 +240,16 @@ export default class Sortable { } } + renderFoot() { + this._foot.textContent = ""; + if (this._fields.every((f) => !f.foot)) return; + const footerRow = this._foot.insertRow(-1); + for (const field of this._fields) { + const cell = L.DomUtil.create("td", field.className, footerRow); + if (field.foot) field.foot(cell); + } + } + sort() { const sortfield = this._fields[this._sortBy]; @@ -195,7 +273,7 @@ export default class Sortable { } // if two values are the same, preserve previous order if (l == 0) l = a.index - b.index; - return this._sortAsc ? -l : l; + return this._sortAsc ? l : -l; }); for (const [index, item] of this._items.entries()) { diff --git a/src/code/static.js b/src/code/static.ts similarity index 66% rename from src/code/static.js rename to src/code/static.ts index f279431a6..4c041e6a2 100644 --- a/src/code/static.js +++ b/src/code/static.ts @@ -1,11 +1,16 @@ -// this file is loaded by the build system -const W = window.plugin.wasabee || {}; +// todo complete/rework +type Statics = { + CSS: { [name: string]: string }; + dialogNames: { [name: string]: string }; + [name: string]: any; +}; -W.static = { +const statics: Statics = { CSS: { main: require("./css/wasabee.css"), autodraws: require("./css/autodraws.css"), toolbar: require("./css/toolbar.css"), + map: require("./css/map.css"), panes: require("./css/panes.css"), smallScreen: require("./css/smallscreen.css"), // fix for dialogs on mobile from iitc dev version @@ -50,7 +55,6 @@ W.static = { LANGUAGE_KEY: "wasabee-language", DEFAULT_LANGUAGE: "English", AGENT_INFO_KEY: "wasabee-me", - MULTIMAX_UNREACHABLE_KEY: "wasabee-mm-unreachable", LINK_SOURCE_KEY: "wasabee-link-source", ANCHOR_ONE_KEY: "wasabee-anchor-1", ANCHOR_TWO_KEY: "wasabee-anchor-2", @@ -67,19 +71,6 @@ W.static = { SERVER_BASE_KEY: "wasabee-server", SERVER_BASE_DEFAULT: "https://am.wasabee.rocks", REBASE_UPDATE_KEY: "wasabee-rebase-on-update", - MARKER_TYPE_CAPTURE: "CapturePortalMarker", - MARKER_TYPE_DECAY: "LetDecayPortalAlert", - MARKER_TYPE_EXCLUDE: "ExcludeMarker", - MARKER_TYPE_DESTROY: "DestroyPortalAlert", - MARKER_TYPE_FARM: "FarmPortalMarker", - MARKER_TYPE_GOTO: "GotoPortalMarker", - MARKER_TYPE_KEY: "GetKeyPortalMarker", - MARKER_TYPE_LINK: "CreateLinkAlert", - MARKER_TYPE_MEETAGENT: "MeetAgentPortalMarker", - MARKER_TYPE_OTHER: "OtherPortalAlert", - MARKER_TYPE_RECHARGE: "RechargePortalAlert", - MARKER_TYPE_UPGRADE: "UpgradePortalAlert", - MARKER_TYPE_VIRUS: "UseVirusPortalAlert", DEFAULT_MARKER_TYPE: "DestroyPortalAlert", QUICKDRAW_GUIDE_STYLE: { color: "#0f0", @@ -89,6 +80,10 @@ W.static = { smoothFactor: 1, interactive: false, }, + WEBUI_DEFAULT: "https://webui.wasabee.rocks", + JOIN_TEAM_TEMPLATE: + "https://webui.wasabee.rocks/?server={server}#/team/{teamid}/join/{token}", + FIREBASE_IFRAME: "https://cdn2.wasabee.rocks/iitcplugin/firebase/", }, publicServers: [ { name: "Americas", url: "https://am.wasabee.rocks", short: "πŸ‡ΊπŸ‡Έ" }, @@ -97,47 +92,34 @@ W.static = { ], }; -W.static.strings = {}; // empty object, fill it below -W.static.strings.Deutsch = require("./translations/german.json"); -W.static.strings.Espanol = require("./translations/spanish.json"); -W.static.strings.English = require("./translations/english.json"); -W.static.strings.Italiano = require("./translations/italian.json"); -W.static.strings.Tagalog = require("./translations/filipino.json"); -W.static.strings.French = require("./translations/french.json"); - -W.static.markerTypes = new Set([ - W.static.constants.MARKER_TYPE_CAPTURE, - W.static.constants.MARKER_TYPE_DECAY, - W.static.constants.MARKER_TYPE_DESTROY, - W.static.constants.MARKER_TYPE_FARM, - W.static.constants.MARKER_TYPE_GOTO, - W.static.constants.MARKER_TYPE_KEY, - W.static.constants.MARKER_TYPE_LINK, - W.static.constants.MARKER_TYPE_MEETAGENT, - W.static.constants.MARKER_TYPE_OTHER, - W.static.constants.MARKER_TYPE_RECHARGE, - W.static.constants.MARKER_TYPE_UPGRADE, - W.static.constants.MARKER_TYPE_VIRUS, - W.static.constants.MARKER_TYPE_EXCLUDE, -]); +statics.strings = {}; // empty object, fill it below +statics.strings["Deutsch"] = require("./translations/German.json"); +statics.strings["Espanol"] = require("./translations/Spanish.json"); +statics.strings["English"] = require("./translations/English.json"); +statics.strings["Italiano"] = require("./translations/Italian.json"); +statics.strings["Tagalog"] = require("./translations/Filipino.json"); +statics.strings["FranΓ§ais"] = require("./translations/French.json"); +statics.strings["PortuguΓͺs"] = require("./translations/Portuguese.json"); +statics.strings["Русский"] = require("./translations/Russian.json"); +statics.strings["Dansk"] = require("./translations/Danish.json"); -W.static.defaultOperationColor = "orange"; +statics.defaultOperationColor = "orange"; -W.static.linkStyle = { +statics.linkStyle = { dashArray: [5, 5, 1, 5], assignedDashArray: [4, 2, 1], opacity: 1, weight: 2, }; -W.static.selfBlockStyle = { +statics.selfBlockStyle = { color: "#ff1111", dashArray: [1, 5], opacity: 4, weight: 3, }; -W.static.backgroundLinkStyle = { +statics.backgroundLinkStyle = { dashArray: [8, 5], opacity: 0.4, weight: 2, @@ -145,10 +127,10 @@ W.static.backgroundLinkStyle = { interactive: false, }; -W.static.anchorTemplate = require("!raw-loader?esModule=false!./images/pin_custom.svg"); +statics.anchorTemplate = require("!raw-loader?esModule=false!./images/pin_custom.svg"); // https://leafletjs.com/reference-1.0.3.html#path -W.static.layerTypes = new Map([ +statics.layerTypes = new Map([ [ "main", { @@ -206,3 +188,6 @@ W.static.layerTypes = new Map([ }, ], ]); + +export const constants = statics.constants; +export default statics; diff --git a/src/code/team.js b/src/code/team.js deleted file mode 100644 index a7f3b5e30..000000000 --- a/src/code/team.js +++ /dev/null @@ -1,71 +0,0 @@ -import WasabeeAgent from "./agent"; -import WasabeeMe from "./me"; -import { teamPromise } from "./server"; - -export default class WasabeeTeam { - constructor(data) { - if (typeof data == "string") { - try { - data = JSON.parse(data); - } catch (e) { - console.error(e); - return; - } - } - - let fromServer = false; - if (data.fetched == null) fromServer = true; - this.fetched = data.fetched ? data.fetched : Date.now(); - - this.id = data.id; - this.name = data.name; - this.rc = data.rc; - this.rk = data.rk; - this.jlt = data.jlt; - this.agents = data.agents; // raw agent data - - // this block (1) adds agent to agents cache and (2) populates _a - // _a is a buffer of pre-built WasabeeAgents we can return via getAgents() w/o having to await - this._a = new Array(); - for (const agent of data.agents) { - agent.fetched = this.fetched; - this._a.push(new WasabeeAgent(agent)); // add to agent cache - } - - if (fromServer) this._updateCache(); - } - - getAgents() { - return this._a; - } - - async _updateCache() { - try { - await window.plugin.wasabee.idb.put("teams", this); - } catch (e) { - console.error(e); - } - } - - // 60 seconds seems too short for the default here... - static async get(teamID, maxAgeSeconds = 60) { - const cached = await window.plugin.wasabee.idb.get("teams", teamID); - if (cached) { - const t = new WasabeeTeam(cached); - if (t.fetched > Date.now() - 1000 * maxAgeSeconds) { - t.cached = true; - return t; - } - } - - if (!WasabeeMe.isLoggedIn()) return null; - - try { - const t = await teamPromise(teamID); - return new WasabeeTeam(t); - } catch (e) { - console.error(e); - } - return null; - } -} diff --git a/src/code/toolbox.js b/src/code/toolbox.ts similarity index 74% rename from src/code/toolbox.js rename to src/code/toolbox.ts index a19ac9f82..1c4481d3b 100644 --- a/src/code/toolbox.js +++ b/src/code/toolbox.ts @@ -3,12 +3,13 @@ import SettingsDialog from "./dialogs/settingsDialog"; import OnlineAgentList from "./dialogs/onlineAgentList"; import wX from "./wX"; import { locationPromise } from "./server"; +import { displayInfo } from "./error"; /* This function adds the Wasabee options to the IITC toolbox */ export function setupToolbox() { const toolbox = document.getElementById("toolbox"); - const aboutLink = L.DomUtil.create("a", null, toolbox); + const aboutLink = L.DomUtil.create("a", "wasabee", toolbox); aboutLink.href = "#"; aboutLink.textContent = wX("ABOUT_WASABEE"); L.DomEvent.on(aboutLink, "click", (ev) => { @@ -17,9 +18,9 @@ export function setupToolbox() { ad.enable(); }); - const settingsLink = L.DomUtil.create("a", null, toolbox); + const settingsLink = L.DomUtil.create("a", "wasabee", toolbox); settingsLink.href = "#"; - settingsLink.textContent = wX("SETTINGS"); + settingsLink.textContent = wX("SETTINGS_TOOLBOX"); L.DomEvent.on(settingsLink, "click", (ev) => { L.DomEvent.stop(ev); @@ -27,7 +28,7 @@ export function setupToolbox() { sd.enable(); }); - const locationLink = L.DomUtil.create("a", null, toolbox); + const locationLink = L.DomUtil.create("a", "wasabee", toolbox); locationLink.textContent = wX("SEND_LOC"); L.DomEvent.on(locationLink, "click", (ev) => { L.DomEvent.stop(ev); @@ -38,7 +39,7 @@ export function setupToolbox() { position.coords.latitude, position.coords.longitude ); - alert(wX("LOC_PROC")); + displayInfo(wX("LOC_PROC")); } catch (e) { console.error(e); } @@ -49,8 +50,8 @@ export function setupToolbox() { ); }); - const onlineAgentLink = L.DomUtil.create("a", null, toolbox); - onlineAgentLink.textContent = "Teammates Online"; + const onlineAgentLink = L.DomUtil.create("a", "wasabee", toolbox); + onlineAgentLink.textContent = wX("toolbox.teammates"); L.DomEvent.on(onlineAgentLink, "click", (ev) => { L.DomEvent.stop(ev); const oll = new OnlineAgentList(); diff --git a/src/code/translations/Danish.json b/src/code/translations/Danish.json new file mode 100644 index 000000000..fed4717a7 --- /dev/null +++ b/src/code/translations/Danish.json @@ -0,0 +1,514 @@ +{ + "ABOUT_WASABEE": "Om Wasabee", + "acknowledged": "Anerkendt", + "ADD LINK TITLE": "TilfΓΈj Links", + "ADD MARKER TITLE": "TilfΓΈj MarkΓΈrer", + "ADD_AGENT": "TilfΓΈj Agent:", + "ADD_BL": "TilfΓΈj baglinie:", + "ADD_BULK": "MassetilfΓΈj", + "ADD_BUTTON_LINKS": "TilfΓΈj alle links med det samme.", + "ADD_LINKS": "TilfΓΈj Links", + "ADD_MARKER": "+ MarkΓΈr", + "ADD_NEW_OP": "TilfΓΈj Ny Op", + "ADD_SUCC_INSTR": "Agent tilfΓΈjet", + "ADD_ZONE": "TilfΓΈj Zone", + "ADD": "TilfΓΈj", + "ADD1": "TilfΓΈj fΓΈrste link", + "ADD2": "TilfΓΈj andet link", + "AGENT_STATS": "Agent Statistik", + "AGENT": "Agent", + "AGES": " (for lΓ¦nge siden)", + "ALREADY_HAS_MARKER": "Denne portal har allerede en markΓΈr, vΓ¦lg en anden Portal.", + "AMAZ_TEAM_NAME": "Fantastisk holdnavn.", + "ANCHOR ASSIGNMENT": "Tilknyt alle udgΓ₯ende links til:", + "ANCHOR_GMAP": "Google Maps", + "ANCHOR_PORTAL": "Anker Portal", + "ANCHOR_PORTAL2": "Anker Portal 2", + "ANCHOR_PORTAL3": "Anker Portal 3", + "ANCHOR1": "Anker 1", + "ANCHOR2": "Anker 2", + "ANCHOR3": "Anker 3", + "ANCHORS_AS_BOOKMARKS": "Ankere som bookmarks", + "API_KEY": "Rocks API-nΓΈgle:", + "ASS_TO": "Tildelt", + "ASSIGN LINK PROMPT": "TilfΓΈj link fra: {portalName}", + "ASSIGN MARKER PROMPT": "Tildel markΓΈr fra: {portalName}", + "ASSIGN OUTBOUND PROMPT": "Tildel alle udgΓ₯ende links fra: {portalName}", + "ASSIGN OUTBOUND": "Tildel udgΓ₯ende links", + "ASSIGN": "Tildel", + "ASSIGNED_ONLY_SHORT": "KT", + "ASSIGNED_ONLY": "Kun tildelt", + "assigned": "Tildelt", + "AUTH INCOMPAT": "Du har aktiveret et plugin i TamperMonkey, der er inkompatibelt med Wasabee", + "AUTH REQUIRED": "Godkendelse pΓ₯krΓ¦vet", + "AUTH TOKEN REJECTED": "Afsendelse af godkendelsestoken til serveren blev afvist: {error}", + "AUTH_SELECT_ACCOUNT": "VΓ¦lg konto", + "AUTO_DRAWS": "Auto-tegne", + "AUTODRAWS": "Wasabee Indstillinger for automatisk tegning", + "AUTODRAW_PORTALS_SET": "Portaler", + "autodraw.common.draw_button": "Tegn", + "autodraw.fanfield.result": "Fanfield found {links} links and {fields} fields for {ap} AP", + "autodraw.flipflop.result": "Flip flop: fundet {count} links", + "autodraw.homogeneous.missing_split": "Unable to find {count} splits, try less depth or a different region", + "autodraw.homogeneous.order": "Order", + "autodraw.homogeneous.portals_required": "{count} required", + "autodraw.madrid.auto_determined": "Auto-determined", + "autodraw.madrid.balanced": "Balanced", + "autodraw.madrid.result": "Madrid found {count} layers", + "autodraw.multimax.result": "Multimax found {count} layers", + "autodraw.multimax.result_both_side": "Multimax found {count1} and {count2} layers", + "autodraw.onion.variant": "Valg", + "autodraw.onion.variant.equilateral": "~Ligesidet", + "autodraw.onion.variant.grow": "Lad det vokse", + "autodraw.onion.variant.balanced": "Perfekt balanceret", + "AUTOLOAD_RATE": "Rate for anmodning om portaldetaljer (ms)", + "AUTOLOAD": "IndlΓ¦s automatisk manglende portaloplysninger", + "AUTOMARK STOP": "Auto-markering stoppede pΓ₯ grund af, at portaler ikke blev indlΓ¦st", + "AUTOMARK": "Auto-mΓ¦rke", + "BAT_TOAD": "Battle Toads/manglende oversΓ¦ttelse", + "BLOCKER LIST TITLE": "Vis alle blokkere", + "BLOCKER TITLE": "Blokere", + "CANCEL": "Annuller", + "CAPSULE": "Kapsel", + "CapturePortalMarker": "erobre", + "CHANGE SERVER PROMPT": "Ny Wasabee Server", + "CHANGE SERVER": "Skift Server", + "CHANGE_WAS_SERVER": "Skift Wasabee Server", + "CHECKLIST BUTTON TITLE": "Operation Tjekliste", + "CHECKLIST BUTTON": "Tjekliste", + "CLEAR LINKS": "Ryd links", + "CLEAR MARKERS": "Ryd markΓΈrer", + "CLEAR_EVERYTHING": "Ryd portaler/links/markΓΈrer for aktuel OP", + "CLEAROPS BUTTON TITLE": "Ryd Data", + "CLEAROPS BUTTON": "Ryd Data", + "CLEAROPS PROMPT": "Ryd alle lokale OPS. Ops vil blive gendannet ved nΓ¦ste download.", + "CLOSE": "Luk", + "COMMENT": "Kommentar", + "COMPLETED BY": "FΓ¦rdiggjort af {agentName}", + "completed": "FΓ¦rdiggjort", + "CON_DEL": "BekrΓ¦ft sletning: {opName}", + "COUNT": "OptΓ¦lling", + "CREATE_NEW_TEAM": "Opret nyt team", + "CreateLinkAlert": "Link", + "CUR_USER_INFO": "Aktuelle brugeroplysninger", + "D_SHOW_LIST": "Input defensive nΓΈgler", + "DEFAULT OP NAME": "Ny Op: {date}", + "DELETE ANCHOR PROMPT": "Ønsker du at slette dette anker og alle tilhΓΈrende links:", + "DELETE ANCHOR TITLE": "Slet anker", + "DELETE MARKER PROMPT": "Vil du slette denne markΓΈr:", + "DELETE MARKER TITLE": "Slet markΓΈr", + "DELETE_ANCHOR": "Slet", + "DELETE_LINK": "Slet", + "DELETE_OP": "Slet {opName}", + "DESCRIP_PLACEHOLD": "Beskrivelse (valgfri)", + "DestroyPortalAlert": "ØdelΓ¦g/Skyd", + "dialog.about.download_mobile_app": "

Wasabee App:

", + "dialog.agent_comment.text": "Comment:", + "dialog.agent_comment.title": "Set comment for {agentName}", + "dialog.auth.ott.button": "One Time Token Login", + "dialog.auth.ott.text": "Get a token from the Wasabee Server, then paste it here", + "dialog.auth.ott.title": "One Time Token", + "dialog.blockers.clear_automark": "Clear Automark", + "dialog.clear_all.text": "Do you want to reset {opName}?", + "dialog.clear_all.title": "Clear: {opName}", + "dialog.clear_links.text": "Do you want to remove all links from {opName}?", + "dialog.clear_links.title": "Clear Links: {opName}", + "dialog.clear_markers.text": "Do you want to remove all markers from {opName}?", + "dialog.clear_markers.title": "Clear Markers: {opName}", + "dialog.checklist.count_fields": "Count fields", + "dialog.checklist.count_fields.no_empty": "Found {fieldCount} fields and no empty field", + "dialog.checklist.count_fields.with_empty": "Found {fieldCount} fields and {emptyCount} empty field(s) on {linkCount} link(s)", + "dialog.checklist.count_fields.link_from_inside": "Found {count} links from covered portals", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " at {order} by link ", + "dialog.common.commands": "Commands", + "dialog.common.commands_short": "Cmds", + "dialog.common.delete": "Delete", + "dialog.common.name": "Name", + "dialog.common.off": "Off", + "dialog.common.on": "On", + "dialog.common.owner": "Owner", + "dialog.common.zone_all": "All", + "dialog.firebase.setup": "Visit {url} and press the button to authorize live updates. You will need to reload IITC afterward.", + "dialog.import.url": "Fill from URL", + "dialog.import.success_message": "Import fuldfΓΈrt. Fandt {count} portaler og brugte {faked} forfalskede. Brug venligst swap-funktionen til at flytte forfalskede portaler til de rigtige portaler pΓ₯ samme sted. Zoom ind pΓ₯ 'IndlΓ¦ser' portaler i tjeklisten kan tvinge dem til at indlΓ¦se.", + "dialog.leave_team.text": "If you leave {teamName} you cannot rejoin unless the owner re-adds you.", + "dialog.leave_team.title": "Leave: {teamName}", + "dialog.link_list.length": "Length", + "dialog.link_list.level": "Min Lvl", + "dialog.merge.cancel_upload": "Cancel upload", + "dialog.merge.conflicts": "Conflicts:", + "dialog.merge.local": "Local copy", + "dialog.merge.server": "Server copy", + "dialog.merge.zone": "Zone: {name}", + "dialog.merge.prop.assignedTo": "Assign:", + "dialog.merge.prop.comment": "Comment:", + "dialog.merge.prop.color": "Color:", + "dialog.merge.prop.deltaminutes": "Delta:", + "dialog.merge.prop.fromPortal": "From:", + "dialog.merge.prop.hardness": "Hard:", + "dialog.merge.prop.order": "Order:", + "dialog.merge.prop.state": "State:", + "dialog.merge.prop.toPortal": "To:", + "dialog.merge.prop.zone": "Zone:", + "dialog.merge.prop.zone_points": "Shape has changed", + "dialog.online_agents.actions": "Actions", + "dialog.online_agents.last_seen": "Last Seen", + "dialog.online_agents.title": "Online Agents", + "dialog.op_settings.zones": "Zones", + "dialog.ops_list.background_disable": "Disable background", + "dialog.ops_list.background_enable": "Show in background", + "dialog.ops_list.download": "Download {opName}", + "dialog.ops_list.last_fetched": "Last fetched: {date}", + "dialog.ops_list.local_change": "Local has changed", + "dialog.ops_list.remote_change": "Remote has changed", + "dialog.ops_list.toggle_hide": "Toggle Show/Hide", + "dialog.ops_list.unhide_ops": "Unhide all OPs", + "dialog.remove_agent.text": "Do you want to remove {agentName} from {teamName}?", + "dialog.remove_agent.title": "Remove: {agentName}", + "dialog.setcomment.portal_hardness": "SvΓ¦rhedsgrad", + "dialog.team_list.load_wd_keys": "Load W-D Keys", + "dialog.team_list.share_wd_keys": "Share W-D Keys", + "dialog.team_manage.join_link": "Join Link", + "dialog.team_manage.join_link.create": "Create", + "dialog.team_manage.join_link.revoke": "Revoke", + "dialog.team_members.location": "Sharing Location", + "dialog.team_members.wd_keys": "Sharing W-D Keys", + "dialog.team_message": "Team announcement: β€œ{message}” from {sender}", + "dialog.update_warning": "Wasabee is out of date. Please update using your plugin manager or by going to https://wasabee.rocks", + "dialog.zone_color.title": "Zone Color", + "dialog.zone_color.text": "Set the color of all links in zone {zoneName}", + "dialog.zones.color": "Color", + "dialog.zones.color_links": "Color links", + "dialog.zones.delete_zone_shape": "Reset the shape", + "dialog.zones.draw_zone_shape": "Draw the boundaries", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Stop drawing", + "dialog.zones.title": "Zones", + "DRAW TOOLS FORMAT": "Draw Tools Format", + "DUPE_OP": "Duplikere Operation", + "END_PORT": "Slut Portal ", + "ExcludeMarker": "Udelad fra Auto-Tegn/Marker", + "EXPORT OP TITLE": "Eksporter aktuel Op", + "EXPORT OP": "Eksporter Op", + "EXPORT": "Eksporter:", + "FAKED": "forfalsket: [{portalId}]", + "FANFIELD": "Tegn", + "FANFIELD2": "Tegn Fan Field", + "FarmPortalMarker": "Farm", + "FLIP_FLOP_NAME": "Flip flop", + "FLIP_FLOP_TITLE": "Flip flop", + "FLIP_FLOP_DESC": "Fra et givet anker, et sΓ¦t synlige portaler og et antal SBUL, find et fanefelt til at smide links fra anker ved at mindske afstanden for at undgΓ₯ at sΓΈge nΓΈgler.", + "FLIP_FLOP_INSTRUCTION": "VΓ¦lg en portal, zoom for at se nok portaler og tryk pΓ₯ Tegn. NΓ₯r et fanfelt er fundet, du kan sΓΈge efter andre ankre for gentagne linkninger", + "FLIP_FLOP_FIND_ANCHORS": "Find andre ankre", + "FROM_1-2": "fra basislinie 1-2", + "FROM_1-3": "fra basislinie 1-3", + "FROM_2-3": "fra basislinie 2-3", + "FROM_DEPTH": "fra center", + "FROM_PORT": "Fra Portal", + "GET DT": "FΓ₯ eksisterende DrawTools-tegning", + "GetKeyPortalMarker": "Hent nΓΈgler", + "GotoPortalMarker": "GΓ₯ Til", + "H-GEN_INST": "SΓ¦t portaler til det ydre lag. VΓ¦lg antal opdelinger. Klik pΓ₯ tegn", + "HF_DEEP_SEARCH": "Omfattende sΓΈgning", + "HF_DRAW_BUTTON": "Tegn", + "HF_REDRAW_BUTTON": "Gentegn", + "HG": "Homogent felt", + "HOURS": " ({hours} timer siden)", + "HOW_TO_VIDS": "

SΓ₯dan-gΓΈr-du videoer:

", + "IMP_NOPE": "Import mislykkedes.", + "IMP_WAS_OP": "Importer Wasabee Operation", + "IMPORT_OP_SUCCESS": "Importeret Operation: {opName} lykkedes.", + "IMPORT_OP_TITLE": "Importer Op: {date}", + "IMPORT_OP": "Importer Operation", + "IMPOSSIBLE": "Umulig", + "INGNAME_GID": "Ingress navn eller GoogleID", + "INPUT_DT_KEY_COUNT": "Input antal defensiv nΓΈgler", + "INVALID REQUEST": "Ugyldig forespΓΈrgsel", + "IOS NEED FAKE UA": "Du skal indstille en 'Custom UserAgent for Webviews' i IITC-Mobile-indstillingerne, ellers mislykkes login", + "KEY_LIST2": "NΓΈgleliste til Operationen: {opName}", + "KEYS": "NΓΈgler", + "KNOWN_BLOCK": "Kendte blokkere: {opName}", + "LA DESC": "AfhΓ¦ngigt af antallet og typen af ​​anvendte Link Amps, kan et lavere kildeportal level vΓ¦re tilstrΓ¦kkeligt.", + "LA": "L8+ nogle LA", + "LANG": "Sprog", + "LEAVE": "Forlad", + "LetDecayPortalAlert": "Lad forfalde", + "LINK ASSIGNMENT": "Tildel link til:", + "LINK STATE PROMPT": "Link tilstand", + "LINK STATE": "Angiv link-status:", + "LINKS BUTTON TITLE": "Links", + "LINKS": "Links", + "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", + "LOAD PORTALS": "Load Portaler", + "LOADING": "[loader]", + "LOADING1": "Loader: [{portalGuid}]", + "LOC_PROC": "Beliggenhed behandlet", + "LOCATION SUB": "Lokation registreret", + "LOCFRMSER": " (lokalt og fra server)", + "LOG IN": "Log Ind", + "LOG_OUT": "Log Ud", + "MADRID_SET_1": "VΓ¦lg regionen for basislinket Anker 2 til Anker 3", + "MADRID_SET_2": "VΓ¦lg regionen for basislinket Anker 3 til Anker 1", + "MADRID_SET_3": "VΓ¦lg regionen for basislinket Anker 1 til Anker 2", + "MADRID_TITLE": "Madrid Protokol", + "MADRID_WAS_TAKEN": "Madrid Protocol", + "MADRID": "Tegn", + "MANAGE_TEAM": "Administrer {teamName}", + "MANAGE": "Administrer", + "MARKER ASSIGNMENT": "Tildel markΓΈr til:", + "MARKER LIST TITLE": "MarkΓΈr Liste", + "MARKER LIST": "MarkΓΈrer", + "MARKER STATE PROMPT": "MarkΓΈr Status", + "MARKER STATE": "Angiv markΓΈrtilstand:", + "MARKER_LIST": "MarkΓΈr Liste: {opName}", + "MARKERS BUTTON TITLE": "MarkΓΈrer", + "MAX_SPLITS": "Max Delinger", + "MAX": "Fane Felt", + "MeetAgentPortalMarker": "MΓΈd Agent", + "MERGE ON UPDATE": "Flet ved opdatering", + "MERGE_CHANGES_LOCAL": "Lokale Γ¦ndringer", + "MERGE_CHANGES_MERGE": "Flet resultat", + "MERGE_CHANGES_REMOTE": "FjernΓ¦ndringer", + "MERGE_LOCAL": "Behold lokale", + "MERGE_MESSAGE": "Det ser ud til, at {opName} har lokale Γ¦ndringer. Vil du flette dine Γ¦ndringer med server-OP'en, bruge serverversionen eller beholde den lokale version?", + "MERGE_REBASE": "Flet", + "MERGE_REPLACE": "Brug server", + "MERGE_TITLE": "Flet lokal&fjern OP", + "MIN_SRC_PORT_LVL": "Minimums level pΓ₯krΓ¦vet pΓ₯ kildeportalen", + "MINUTES": " ({minutes} minutter siden)", + "MM": "Multimaks", + "MM_BOTH_SIDE": "Brug begge base sider", + "MM_INSERT_ORDER": "IndsΓ¦t i slutningen", + "MM_SET_ALL_PORTALS": "Alle synlige portaler", + "MM_SET_ALL_KEYS": "Alle GetKey-MarkΓΈrer", + "MM_SET_KEYS_ZONE": "GetKey: {zoneName}", + "MM_SPINE": "Rygrad", + "MULTI_M_TITLE": "Tegn Max Lag", + "MULTI_M": "Tegn", + "MUST_NOT_BE_EMPTY": "MΓ₯ ikke vΓ¦re tom", + "MY_CAP_ID": "Mit kapsel ID", + "MY_COUNT": "Mit Antal", + "NAME_REQ": "Navn pΓ₯krΓ¦vet", + "NAME": "Navn:", + "NEW_OP": "Ny operation", + "NEW_TEAM_NAME": "Nyt holdnavn", + "NEW_TEAM": "Nyt hold", + "NEW_WAS_SERVER": "Ny Wasabee Server", + "NEWOP BUTTON TITLE": "Opret en ny operation", + "NEWOP BUTTON": "Ny Op", + "NO_DT_ITEMS": "Ingen DrawTools tegnede elementer fundet", + "NO_LABEL": "Ingen etiket sat", + "NO_STOCK_INTEL": "Wasabee understΓΈtter ikke stock intel tegninger", + "NO_TITLE": "Ingen titel angivet", + "NO LONGER AVAILABLE": "Ressource fjernet fra serveren: {error}", + "NO LONGER AVAILABLE SHORT": "Ressource fjernet fra serveren", + "NOT LOGGED IN SHORT": "Ikke logget ind", + "NOT LOGGED IN": "Ikke logget ind: {error}", + "NOT_LOADED": "Ikke fuldt indlΓ¦st, prΓΈv igen.", + "NOT_SET": "ikke indstillet", + "NTNAME": "Navn", + "OK": "OK", + "ON_HAND": "Har Allerede", + "ONION_WAS_TAKEN": "Onion/lΓΈg", + "ONION": "Tegn", + "ONLY_DT_IMP": " (kun for DrawTools-import)", + "OP DELETED": "Operationen fjernet fra serveren: {opID}", + "OP PERM DENIED": "Tilladelse nΓ¦gtet til operationen: {opID}", + "OP_BUTTON": "Operation", + "OP_CHECKLIST": "Operation Tjekliste: {opName}", + "OP_NAME_UNSET": "Operationsnavn blev deaktiveret", + "OP_PERMS": "Op Tilladelser", + "OP_SETTINGS_BUTTON": "Op Indstillinger βš™", + "OP_SETTINGS_TITLE": "Op Indstillinger", + "OPEN_REQUEST": "[Γ₯bn anmodning]", + "OPER_COLOR": "Operation Farve:", + "OPER_NAME": "Operation Navn:", + "OPERATIONS": "Operationer", + "OPS BUTTON TITLE": "Operations Liste", + "OPS BUTTON": "VΓ¦lg OP", + "ORDER": "Sorter", + "OtherPortalAlert": "Andet", + "PASTE_INSTRUCT": "IndsΓ¦t en Wasabee draw-eksport her.\n\nWasabee kan ikke importere stock intel-formatet.\n\nDer er eksperimentel understΓΈttelse af import af IITC DrawTools-formatet.\n\nFΓΈr du importerer DrawTools-formatet, skal du forhΓ₯ndsvise omrΓ₯derne og sΓΈrge for, at alle portalerne indlΓ¦ses sΓ₯ IITC har dem cachelagret. Alle portaler, der ikke er pre-cached, vil blive forfalsket.\n\nDu bliver nΓΈdt til at bruge 'swap'-funktionen til at flytte ankre fra de falske portaler til de rigtige portaler (de bΓΈr vΓ¦re pΓ₯ den korrekte placering, bare ikke forbundet med portal.\n\nCachede portaler er muligvis ikke korrekt navngivet.", + "pending": "Afventer", + "PERM DENIED": "Tilladelse nΓ¦gtet: {error}", + "PERM DENIED SHORT": "Tilladelse nΓ¦gtet", + "PERMS": "{opName} tilladelser", + "PLEASE_SELECT_PORTAL": "VΓ¦lg venligst en portal", + "popup.anchor.keys": "Keys: {onHand} / {required}", + "popup.marker.state_button": "Set State", + "PORTAL KEY LIST": "NΓΈgleliste for portal {portalName}", + "PORTAL_COUNT": "{count} portaler", + "PORTAL": "Portal", + "QD BUTTON CHANGE COLOR": "Klik for at Γ¦ndre farve pΓ₯ nΓ¦ste link", + "QD BUTTON END": "Klik for at stoppe med at tegne felter", + "QD BUTTON TOGGLE MODE": "Klik for at Γ¦ndre tegnetilstand", + "QD CHANGE COLOR": "Skift farve", + "QD END": "Slut", + "QD TITLE": "Hurtig tegn lag", + "QD TOGGLE MODE": "Skift tilstand", + "QDBASE": "Base Link", + "QDCONT": "Klik pΓ₯ en baglinieportal for at tegne et felt.", + "QDNEXT": "Klik pΓ₯ den anden ankerportal.", + "QDSTART": "Klik pΓ₯ den fΓΈrste ankerportal.", + "READ_SHORT": "L", + "READ": "LΓ¦s", + "RechargePortalAlert": "Genoplad", + "REFERENCE_TIME": "Referencetid:", + "REM_LOC_CP": "Fjern lokal kopi af {opName}", + "REMOVE_TEAM_CONFIRM_LABEL": "Vil du permanent fjerne {team Name} fra Wasabi-serveren?", + "REMOVE_TEAM_CONFIRM_TITLE": "Fjern hold {teamName}", + "REMOVE_TEAM": "Fjern hold:", + "REMOVE": "Fjern", + "RENAME_TEAM": "OmdΓΈb hold:", + "RENAME": "OmdΓΈb", + "REQUIRED": "PΓ₯krΓ¦vet", + "RESET": "Nulstil", + "REVERSE": "Endevend", + "ROCKS_COM": "enl.rocks fΓ¦llesskab:", + "ROLE": "Rolle", + "SAVELINKS TITLE": "Gem Links", + "SAVELINKS_DRAW": "Gem Links", + "SAVELINKS": "Gem Links", + "SECONDS": " ({seconds} sekunder siden)", + "SEL_SB_ANCHOR": "VΓ¦lg ankerportal.", + "SEL_SB_ANCHOR2": "Zoom ud. SΓΈrg for, at alle portaler er indlΓ¦st, og klik derefter pΓ₯ Tegn.", + "SEL_SL_ANCHOR": "VΓ¦lg den portal, du vil gemme links til. Klik pΓ₯ knappen Gem links og se pΓ₯ tjeklisten.", + "SEL_SRC_ANC2": "VΓ¦lg bΓ₯de Kilde og Anker 2", + "SEL_SRC_PORT": "VΓ¦lg en kildeportal", + "SELECT PORTAL": "VΓ¦lg venligst en portal fΓΈrst", + "SELECT_FAN_PORTALS": "VΓ¦lg en ankerportal, en startportal og en slutportal, og fokuser over markomrΓ₯det.", + "SELECT_FAN_PORTALS2": "Vent pΓ₯, at alle portaler er indlΓ¦st, og klik derefter pΓ₯ tegn.", + "SELECT_INSTRUCTIONS": "VΓ¦lg to ankerportaler, og zoom derefter over rygsΓΈjlen.", + "SELECT_ONION_PORTALS": "Lag bygges indefra og ud. Zoom ind til midten, og vΓ¦lg startportal, og zoom derefter ud til omrΓ₯det.", + "SELF SWAP": "Kan ikke bytte en portal med sig selv! VΓ¦lg en anden portal.", + "SEND ANALYTICS": "Send anonyme analysedata", + "SEND LOCATION": "Share Location (only when IITC is in foreground)", + "SEND TARGET AGENT": "VΓ¦lg modtager agent", + "SEND TARGET CONFIRM": "Vil du sende {portalName}-mΓ₯let til {agent}?", + "SEND TARGET": "Send mΓ₯l", + "SEND_LOC": "Send placering", + "SET_3_PORT": "Indstil venligst de tre portaler fΓΈrst!", + "SET_COMMENT": "Indstil kommentar", + "SET_LCOMMENT": "Indstil linkkommentar", + "SET_LINK_COMMENT": "Indstil kommentar til link:", + "SET_LINKS_ZONES": "SΓ¦t links til zoner", + "SET_MARKER_COMMENT": "SΓ¦t kommentar til markΓΈr pΓ₯:", + "SET_MARKER_TYPE_TITLE": "Skift markΓΈrtype", + "SET_MARKERS_ZONES": "Indstil markΓΈrer til zoner", + "SET_MCOMMENT": "Indstil markΓΈrkommentar: {portalName}", + "SET_NEW_OP": "Indstil venligst det nye operationsnavn", + "SET_PCOMMENT": "Indstil portalkommentar: {portalName}", + "SET_PORT_COMMENT": "Indstil kommentar til portal:", + "SET_PORTAL_COMMENT": "Indstil portalkommentar", + "SET": "indstil", + "SETTINGS_TOOLBOX": "Wasabee Settings", + "SETTINGS_TITLE": "Advanced Settings", + "SKINS_AVAILABLE": "Der er {count} tilgΓ¦ngelige skins.", + "SKINS_BUTTON": "Konfigurer skins", + "SKINS_DESCRIPTION": "TilgΓ¦ngelige skin packs er placeret i hΓΈjre kolonner. Flyt skins, du ΓΈnsker at bruge, til venstre kolonne.", + "SKINS_MANAGE_TITLE": "Administrer skins", + "SKIP_CONFIRM_ALWAYS": "SpΓΈrg aldrig (brug med forsigtighed)", + "SKIP_CONFIRM_ENTITY": "SpΓΈrg kun for hold/op", + "SKIP_CONFIRM_NEVER": "SpΓΈrg altid", + "SKIP_CONFIRM": "Spring bekrΓ¦ftelse over", + "SOURCE_PORT": "Kildeportal", + "STARBURST TITLE": "Starburst", + "STARBURST_DRAW": "Tegn", + "STARBURST": "Starburst", + "START_PORT": "Start Portal ", + "STATE": "Status", + "SUPPORT_INSTRUCT": "For at fΓ₯ support, tilmeld dig Wasabee bruger Telegram kanal", + "SWAP PROMPT": "Vil du bytte:", + "SWAP TITLE": "Byt portaler", + "SWAP WITH": " med ", + "SWAP": "Byt", + "SYNC DONE": "Download Komplet
Klik HER for tips, tips og dokumentation.", + "SYNC": "Download tilgΓ¦ngelige operationer", + "TARGET SENT": "MΓ₯l sendt", + "TEAM STATE": "Del placering", + "TEAM_CREATED": "Hold {teamName} oprettet", + "TEAM_NAME": "Hold navn", + "TEAM": "Hold", + "TEAMS BUTTON TITLE": "Liste over Wasabee-holdene", + "TEAMS BUTTON": "Hold", + "TO_PORT": "Til Portal", + "toolbar.quick_delete.apply.text": "Anvend", + "toolbar.quick_delete.apply.title": "Slet valgte links/markΓΈrer", + "toolbar.quick_delete.cancel.text": "Annuller", + "toolbar.quick_delete.cancel.title": "Annuller", + "toolbar.quick_delete.stop.text": "Stop", + "toolbar.quick_delete.stop.title": "Afslut slettetilstand", + "toolbar.quick_delete.title": "Hurtigt slet", + "toolbar.quick_delete.tooltip.toggle_mode": "Click on features to mark for deletion", + "toolbar.quick_delete.tooltip.quick_mode": "Click on features to delete instantly", + "toolbar.quick_draw.tooltip.star_mode.anchor": "VΓ¦lg stjerneanker", + "toolbar.quick_draw.tooltip.star_mode.portal": "VΓ¦lg en portal", + "toolbar.quick_draw.tooltip.single_mode.first": "Klik pΓ₯ den fΓΈrste portal", + "toolbar.quick_draw.tooltip.single_mode.next": "Klik pΓ₯ den nΓ¦ste portal", + "toolbar.quick_draw.tooltip.portal_fail": "Portaldata ikke indlΓ¦st, prΓΈv venligst igen", + "toolbar.wasabee.settings": "Settings", + "toolbox.teammates": "Teammates Online", + "TRAWL SKIP TILES": "Trawl Skip fliser", + "TRAWL TITLE": "Trawl baner", + "TRAWL WARNING": "Dette vil indlΓ¦se flisedataene under alle tegnede links. Dette er en langsom proces.", + "TRAWL_AUTOMARK": "AutomΓ¦rke blokere efter trawl", + "TRAWL_BULK_LOAD_WARNING": "Denne metode indlΓ¦ser flisedataene sΓ₯ hurtigt som muligt. Brug pΓ₯ eget ansvar.", + "TRAWL_BULK_LOAD": "MasseindlΓ¦sning af flisedata", + "TRAWL_CLEAR_MARKERS": "Ryd virus/ΓΈdelΓ¦ggelsesmarkΓΈrer fΓΈr trawl", + "TRAWL_REMAINING": "{count} fliser tilbage", + "TRAWL": "Trawl efter blokere", + "TRAWLING": "NΓ₯r du trawler banerne efter blokeringer, luk denne dialog for at stoppe", + "TYPE": "Type", + "UNASSIGNED": "Ikke tildelt", + "UNKNOWN": "Ukendt", + "UPDATE HOVER": "OPDATER {opName} pΓ₯ serveren", + "UPDATE PERM DENIED": "Du har ikke rettigheder til at opdatere", + "UPDATE_CONFLICT_DESC": "OP er blevet Γ¦ndret pΓ₯ serveren siden sidste synkronisering. Ønsker du at erstatte serverversionen med den nuvΓ¦rende?", + "UPDATE_CONFLICT_TITLE": "Konflikt opdaget med server", + "UPDATE_COUNT": "Opdater optΓ¦lling", + "UPDATED": "Opdateret", + "UpgradePortalAlert": "Upgrader", + "UPLOAD BUTTON HOVER": "UPLOAD {opName} (ikke pΓ₯ serveren i ΓΈjeblikket)", + "UPLOADED": "Uploadet", + "USE PANES ON MOBILE": "Brug rammer (skal genindlΓ¦ses)", + "USE_VALID_NAME": "Brug venligst et gyldigt operationsnavn", + "UseVirusPortalAlert": "Brug Virus", + "VRLA DESC": "AfhΓ¦ngigt af antallet og typen af anvendte linkforstΓ¦rkere kan et lavere kildeportal level vΓ¦re tilstrΓ¦kkeligt.", + "VRLA": "L8+nogle VRLA", + "WASABEE BUTTON TITLE": "Wasabee: den er grΓΈn og fΓ₯r smΓΈlfer til at grΓ¦de.", + "WASABEE_D_LIST": "Input antal forsvarsnΓΈgler", + "WD BUTTON TITLE": "Log forsvarsnΓΈgler", + "WD BUTTON": "W-D NΓΈgler", + "WRITE_SHORT": "S", + "WRITE": "Skrive", + "WSERVER": "Server: {url}", + "YESNO_DEL": "Er du sikker pΓ₯, at du vil slette {opName}?", + "ZONE_DRAW": "Klik for at indstille zonegrΓ¦nserne", + "ZONE": "Zone", + "smallScreen": { + "ADD_LINKS": "+ Links", + "ADD_MARKER": "+ MarkΓΈr", + "BLOCKER TITLE": "Blokere", + "CHECKLIST BUTTON": "Kontrollere", + "CLEAROPS BUTTON": "Klar", + "EXPORT OP": "Eksporter", + "FANFIELD": "Tegn", + "FANFIELD2": "Tegn Fan Field", + "KEYS": "NΓΈgler", + "LOG IN": "Log Ind", + "LOG_OUT": "Log Ud", + "MARKER LIST": "MarkΓΈrere", + "MARKERS BUTTON TITLE": "MarkΓΈrere", + "MAX": "Fan/Vifte", + "MM": "Multi", + "MULTI_M_TITLE": "Tegn Max Lag", + "MULTI_M": "Tegn", + "NEWOP BUTTON": "Ny Op", + "OPS BUTTON": "VΓ¦lg OP", + "QD END": "Stop", + "STARBURST_DRAW": "Tegn", + "STARBURST": "Stjerne", + "TEAMS BUTTON": "Hold", + "WD BUTTON": "W-D NΓΈgler" + } +} \ No newline at end of file diff --git a/src/code/translations/english.json b/src/code/translations/English.json similarity index 59% rename from src/code/translations/english.json rename to src/code/translations/English.json index e857f71b1..1936af7ee 100644 --- a/src/code/translations/english.json +++ b/src/code/translations/English.json @@ -1,11 +1,11 @@ { - "ABOUT WASABEE-IITC": "About Wasabee-IITC", "ABOUT_WASABEE": "About Wasabee", "acknowledged": "Acknowledged", "ADD LINK TITLE": "Add Links", "ADD MARKER TITLE": "Add Markers", - "ADD_AGENT": "Add Agent: ", - "ADD_BL": "Add Back Links: ", + "ADD_AGENT": "Add Agent:", + "ADD_BL": "Add Back Links:", + "ADD_BULK": "Bulk add", "ADD_BUTTON_LINKS": "Add all links at once.", "ADD_LINKS": "Add Links", "ADD_MARKER": "+ Marker", @@ -20,16 +20,16 @@ "AGES": " (ages ago)", "ALREADY_HAS_MARKER": "This portal already has a marker. Choose a different portal.", "AMAZ_TEAM_NAME": "Amazing Team Name.", - "ANCHOR ASSIGNMENT": " all outbound links", + "ANCHOR ASSIGNMENT": "Assign all outbound links to:", "ANCHOR_GMAP": "Google Map", - "ANCHOR_PORTAL": "Anchor Portal ", + "ANCHOR_PORTAL": "Anchor Portal", "ANCHOR_PORTAL2": "Anchor Portal 2", "ANCHOR_PORTAL3": "Anchor Portal 3", - "ANCHOR1": "Anchor 1 ", - "ANCHOR2": "Anchor 2 ", - "ANCHOR3": "Anchor 3 ", + "ANCHOR1": "Anchor 1", + "ANCHOR2": "Anchor 2", + "ANCHOR3": "Anchor 3", "ANCHORS_AS_BOOKMARKS": "Anchors as bookmarks", - "API_KEY": " api key: ", + "API_KEY": "Rocks API key:", "ASS_TO": "Assigned To", "ASSIGN LINK PROMPT": "Assign link from: {portalName}", "ASSIGN MARKER PROMPT": "Assign marker from: {portalName}", @@ -39,15 +39,28 @@ "ASSIGNED_ONLY_SHORT": "AO", "ASSIGNED_ONLY": "Assigned Only", "assigned": "Assigned", - "ASSIGNED": "Assigned", - "AUTH ANDROID": "On Android, try 'quick' first. If that fails, try the main login with 'select_account'.", "AUTH INCOMPAT": "You have activated a plugin in TamperMonkey that is incompatable with Wasabee", - "AUTH IOS": "On iOS, use the main 'Log In' option. If that fails, use 'Webview Login' then use the 'Verify Webview' button to complete the process.", "AUTH REQUIRED": "Authentication Required", "AUTH TOKEN REJECTED": "Sending auth token to server rejected: {error}", "AUTH_SELECT_ACCOUNT": "Select account", "AUTO_DRAWS": "Auto-draw", "AUTODRAWS": "Wasabee Auto-draw Options", + "AUTODRAW_PORTALS_SET": "Portals", + "autodraw.common.draw_button": "Draw", + "autodraw.fanfield.result": "Fanfield found {links} links and {fields} fields for {ap} AP", + "autodraw.flipflop.result": "Flip flop: found {count} links", + "autodraw.homogeneous.missing_split": "Unable to find {count} splits, try less depth or a different region", + "autodraw.homogeneous.order": "Order", + "autodraw.homogeneous.portals_required": "{count} required", + "autodraw.madrid.auto_determined": "Auto-determined", + "autodraw.madrid.balanced": "Balanced", + "autodraw.madrid.result": "Madrid found {count} layers", + "autodraw.multimax.result": "Multimax found {count} layers", + "autodraw.multimax.result_both_side": "Multimax found {count1} and {count2} layers", + "autodraw.onion.variant": "Option", + "autodraw.onion.variant.equilateral": "~Equilateral", + "autodraw.onion.variant.grow": "Let it grow", + "autodraw.onion.variant.balanced": "Perfectly balanced", "AUTOLOAD_RATE": "Portal Detail Request Rate (ms)", "AUTOLOAD": "Automatically Load Missing Portal Details", "AUTOMARK STOP": "Auto-Mark stopped due to portals not being loaded", @@ -66,72 +79,143 @@ "CLEAR LINKS": "Clear Links", "CLEAR MARKERS": "Clear Markers", "CLEAR_EVERYTHING": "Clear Portals/Links/Markers for current OP", - "CLEAR": "Clear selection", "CLEAROPS BUTTON TITLE": "Clear Data", "CLEAROPS BUTTON": "Clear Data", - "CLEAROPS PROMPT": "Clear all local OPS. Ops will be restored at next download.", + "CLEAROPS PROMPT": "Clear all local OPS. Ops will be restored at next download. Wasabee will be disabled until next page reload.", "CLOSE": "Close", "COMMENT": "Comment", "COMPLETED BY": "Completed by {agentName}", "completed": "Completed", - "COMPLETED": "Completed", "CON_DEL": "Confirm Delete: {opName}", - "CONFIRM_DELETE": "Do you really want to delete this link: ", "COUNT": "Count", "CREATE_NEW_TEAM": "Create New Team", "CreateLinkAlert": "Link", "CUR_USER_INFO": "Current User Information", "D_SHOW_LIST": "Input Defensive Keys", "DEFAULT OP NAME": "New Op: {date}", - "DELETE ANCHOR PROMPT": "Do you want to delete this anchor and all associated links: ", + "DELETE ANCHOR PROMPT": "Do you want to delete this anchor and all associated links:", "DELETE ANCHOR TITLE": "Delete Anchor", - "DELETE MARKER PROMPT": "Do you want to delete this marker: ", + "DELETE MARKER PROMPT": "Do you want to delete this marker:", "DELETE MARKER TITLE": "Delete Marker", - "DELETE PERM DENIED": "Permission to delete denied.", "DELETE_ANCHOR": "Delete", "DELETE_LINK": "Delete", - "DELETE_MARKER": "Delete", "DELETE_OP": "Delete {opName}", - "DELETED": "Successfully deleted.", "DESCRIP_PLACEHOLD": "Description (optional)", "DestroyPortalAlert": "Destroy", - "DISABLE_SYNC": "The IITC Sync plugin is not compatible with Wasabee. Please disable Sync.", - "DISABLED": "This feature is not ready for users", - "DONE": "Done", + "dialog.about.download_mobile_app": "

Wasabee App:

", + "dialog.agent_comment.text": "Comment:", + "dialog.agent_comment.title": "Set comment for {agentName}", + "dialog.auth.ott.button": "One Time Token Login", + "dialog.auth.ott.text": "Get a token from the Wasabee Server, then paste it here", + "dialog.auth.ott.title": "One Time Token", + "dialog.blockers.clear_automark": "Clear Automark", + "dialog.clear_all.text": "Do you want to reset {opName}?", + "dialog.clear_all.title": "Clear: {opName}", + "dialog.clear_links.text": "Do you want to remove all links from {opName}?", + "dialog.clear_links.title": "Clear Links: {opName}", + "dialog.clear_markers.text": "Do you want to remove all markers from {opName}?", + "dialog.clear_markers.title": "Clear Markers: {opName}", + "dialog.checklist.count_fields": "Count fields", + "dialog.checklist.count_fields.no_empty": "Found {fieldCount} fields and no empty field", + "dialog.checklist.count_fields.with_empty": "Found {fieldCount} fields and {emptyCount} empty field(s) on {linkCount} link(s)", + "dialog.checklist.count_fields.link_from_inside": "Found {count} links from covered portals", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " at {order} by link ", + "dialog.common.commands": "Commands", + "dialog.common.commands_short": "Cmds", + "dialog.common.delete": "Delete", + "dialog.common.name": "Name", + "dialog.common.off": "Off", + "dialog.common.on": "On", + "dialog.common.owner": "Owner", + "dialog.common.zone_all": "All", + "dialog.firebase.setup": "Visit {url} and press the button to authorize live updates. You will need to reload IITC afterward.", + "dialog.import.url": "Fill from URL", + "dialog.import.success_message": "Import Complete. Found {count} portals and used {faked} faked. Please use the swap feature to move faked portals to the real portals at the same location. Zooming in on the 'Loading' portals in the checklist might force them to load.", + "dialog.leave_team.text": "If you leave {teamName} you cannot rejoin unless the owner re-adds you.", + "dialog.leave_team.title": "Leave: {teamName}", + "dialog.link_list.length": "Length", + "dialog.link_list.level": "Min Lvl", + "dialog.merge.cancel_upload": "Cancel upload", + "dialog.merge.conflicts": "Conflicts:", + "dialog.merge.local": "Local copy", + "dialog.merge.server": "Server copy", + "dialog.merge.zone": "Zone: {name}", + "dialog.merge.prop.assignedTo": "Assign:", + "dialog.merge.prop.comment": "Comment:", + "dialog.merge.prop.color": "Color:", + "dialog.merge.prop.deltaminutes": "Delta:", + "dialog.merge.prop.fromPortal": "From:", + "dialog.merge.prop.hardness": "Hard:", + "dialog.merge.prop.order": "Order:", + "dialog.merge.prop.state": "State:", + "dialog.merge.prop.toPortal": "To:", + "dialog.merge.prop.zone": "Zone:", + "dialog.merge.prop.zone_points": "Shape has changed", + "dialog.online_agents.actions": "Actions", + "dialog.online_agents.last_seen": "Last Seen", + "dialog.online_agents.title": "Online Agents", + "dialog.op_settings.zones": "Zones", + "dialog.ops_list.background_disable": "Disable background", + "dialog.ops_list.background_enable": "Show in background", + "dialog.ops_list.download": "Download {opName}", + "dialog.ops_list.last_fetched": "Last fetched: {date}", + "dialog.ops_list.local_change": "Local has changed", + "dialog.ops_list.remote_change": "Remote has changed", + "dialog.ops_list.toggle_hide": "Toggle Show/Hide", + "dialog.ops_list.unhide_ops": "Unhide all OPs", + "dialog.remove_agent.text": "Do you want to remove {agentName} from {teamName}?", + "dialog.remove_agent.title": "Remove: {agentName}", + "dialog.setcomment.portal_hardness": "Hardness", + "dialog.team_list.load_wd_keys": "Load W-D Keys", + "dialog.team_list.share_wd_keys": "Share W-D Keys", + "dialog.team_manage.join_link": "Join Link", + "dialog.team_manage.join_link.create": "Create", + "dialog.team_manage.join_link.revoke": "Revoke", + "dialog.team_members.location": "Sharing Location", + "dialog.team_members.wd_keys": "Sharing W-D Keys", + "dialog.team_message": "Team announcement: β€œ{message}” from {sender}", + "dialog.update_warning": "Wasabee is out of date. Please update using your plugin manager or by going to https://wasabee.rocks", + "dialog.zone_color.title": "Zone Color", + "dialog.zone_color.text": "Set the color of all links in zone {zoneName}", + "dialog.zones.color": "Color", + "dialog.zones.color_links": "Color links", + "dialog.zones.delete_zone_shape": "Reset the shape", + "dialog.zones.draw_zone_shape": "Draw the boundaries", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Stop drawing", + "dialog.zones.title": "Zones", "DRAW TOOLS FORMAT": "Draw Tools Format", - "DT_FORMAT": "Draw Tools Format", "DUPE_OP": "Duplicate Operation", - "END_PORT": "End Portal ", + "END_PORT": "End Portal", "ExcludeMarker": "Exclude from Auto-Draw/Mark", "EXPORT OP TITLE": "Export current Op", "EXPORT OP": "Export Op", - "EXPORT": "Export: ", + "EXPORT": "Export:", "FAKED": "Faked: [{portalId}]", - "FAN_FIELD3": "Fan Field", - "FANFIELD TITLE": "Fanfield", "FANFIELD": "Draw", "FANFIELD2": "Draw Fan Field", "FarmPortalMarker": "Farm", + "FLIP_FLOP_NAME": "Flip flop", + "FLIP_FLOP_TITLE": "Flip flop", + "FLIP_FLOP_DESC": "From a given anchor, a set of visible portal and a number of SBUL, find a fanfield to throw links from the anchor by decreasing distance to avoid searching keys.", + "FLIP_FLOP_INSTRUCTION": "Select a portal, zoom to see enough portals and press Draw. Once a fanfield is found, you can search for other anchors for consecutive rethrow", + "FLIP_FLOP_FIND_ANCHORS": "Find other anchors", "FROM_1-2": "from base 1-2", "FROM_1-3": "from base 1-3", "FROM_2-3": "from base 2-3", "FROM_DEPTH": "from the depth", "FROM_PORT": "From Portal", "GET DT": "Get existing DrawTools draw", - "GET_DT_DRAW": "Import draw from IITC Draw Tools", "GetKeyPortalMarker": "Get Keys", "GotoPortalMarker": "Go To", "H-GEN_INST": "Set portals for the outside layer. Choose number of splits. Click draw", "HF_DEEP_SEARCH": "Exhaustive search", "HF_DRAW_BUTTON": "Draw", - "HF_DRAW_DEEP_BUTTON": "Draw with deep recursion", "HF_REDRAW_BUTTON": "Redraw", "HG": "Homogeneous Field", "HOURS": " ({hours} hours ago)", - "HOW_TO_VIDS": "

How-To Videos:

", - "IMP_COMP": "Import Complete. Found ", - "IMP_DT_OP": "Imported Drawtools Op: ", - "IMP_NOPE": "Import Failed.", + "HOW_TO_VIDS": "

How-To Videos:

", + "IMP_NOPE": "Import Failed: {error}", "IMP_WAS_OP": "Import Wasabee Operation", "IMPORT_OP_SUCCESS": "Imported Operation: {opName} successfuly.", "IMPORT_OP_TITLE": "Import Op: {date}", @@ -139,7 +223,6 @@ "IMPOSSIBLE": "Impossible", "INGNAME_GID": "Ingress name or GoogleID", "INPUT_DT_KEY_COUNT": "Input Defensive Key Count", - "INPUT_SQUAD_NAME": "Input a Squad name", "INVALID REQUEST": "Invalid Request", "IOS NEED FAKE UA": "You must set a 'Custom UserAgent for Webviews' in the IITC-Mobile settings or login will fail", "KEY_LIST2": "Key List for Operation: {opName}", @@ -150,9 +233,9 @@ "LANG": "Language", "LEAVE": "Leave", "LetDecayPortalAlert": "Let Decay", - "LINK ASSIGNMENT": " Link Assignment", + "LINK ASSIGNMENT": "Assign link to:", "LINK STATE PROMPT": "Link State", - "LINK STATE": "Set link status", + "LINK STATE": "Set link status:", "LINKS BUTTON TITLE": "Links", "LINKS": "Links", "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", @@ -160,10 +243,8 @@ "LOADING": "[loading]", "LOADING1": "Loading: [{portalGuid}]", "LOC_PROC": "location processed", - "LOC_UPDATE": "Location Update", "LOCATION SUB": "Location registered", "LOCFRMSER": " (locally and from server)", - "LOG IN QUICK": "Log In (quick; for Android)", "LOG IN": "Log In", "LOG_OUT": "Log Out", "MADRID_SET_1": "Select the region for baselink Anchor 2 to Anchor 3", @@ -174,11 +255,11 @@ "MADRID": "Draw", "MANAGE_TEAM": "Manage {teamName}", "MANAGE": "Manage", - "MARKER ASSIGNMENT": " Marker Assignment", + "MARKER ASSIGNMENT": "Assign marker to:", "MARKER LIST TITLE": "Marker List", "MARKER LIST": "Markers", "MARKER STATE PROMPT": "Marker Status", - "MARKER STATE": " Set marker state", + "MARKER STATE": "Set marker state:", "MARKER_LIST": "Marker List: {opName}", "MARKERS BUTTON TITLE": "Markers", "MAX_SPLITS": "Max Splits", @@ -189,35 +270,38 @@ "MERGE_CHANGES_MERGE": "Merge result", "MERGE_CHANGES_REMOTE": "Remote changes", "MERGE_LOCAL": "Keep local", - "MERGE_MESSAGE": "It seems that {opName} has local changes. Do you want to merge your modifications with the server OP, use the server version or keep the local version?", + "MERGE_MESSAGE": "Local and server modifications are clashing. You need to resolve the conflicts that Wasabee failed to resolve itself. Select which version in the following list to keep for every unresolved conflicts. You can also ignore all conflicts and use the server copy, or you can just keep the local copy intact.", "MERGE_REBASE": "Merge", "MERGE_REPLACE": "Use server", "MERGE_TITLE": "Merge local&remote OP", "MIN_SRC_PORT_LVL": "Minimum level required on source portal", "MINUTES": " ({minutes} minutes ago)", "MM": "Multimax", + "MM_BOTH_SIDE": "Use both base sides", + "MM_INSERT_ORDER": "Insert at the end", + "MM_SET_ALL_PORTALS": "All visible portals", + "MM_SET_ALL_KEYS": "All GetKey Markers", + "MM_SET_KEYS_ZONE": "GetKey: {zoneName}", + "MM_SPINE": "Spine", "MULTI_M_TITLE": "Draw Max Layers", "MULTI_M": "Draw", - "MULTIMAX": "Multimax!", - "MULTIMAX2": "Multimax", "MUST_NOT_BE_EMPTY": "Must Not Be Empty", "MY_CAP_ID": "My Capsule ID", "MY_COUNT": "My Count", "NAME_REQ": "Name Required", - "NAME": "Name: ", + "NAME": "Name:", "NEW_OP": "New Operation", "NEW_TEAM_NAME": "New Team Name", "NEW_TEAM": "New Team", "NEW_WAS_SERVER": "New Wasabee Server", "NEWOP BUTTON TITLE": "Create a new Operation", "NEWOP BUTTON": "New Op", - "NO_DATA": "No data", "NO_DT_ITEMS": "No DrawTools drawn items detected", "NO_LABEL": "No label set", - "NO_PORT_SEL": "No Portal Selected.", "NO_STOCK_INTEL": "Wasabee doesn't support stock intel draw imports", "NO_TITLE": "No title set", - "NO": "No", + "NO LONGER AVAILABLE": "Resource removed from server: {error}", + "NO LONGER AVAILABLE SHORT": "Resource removed from server", "NOT LOGGED IN SHORT": "Not Logged in", "NOT LOGGED IN": "Not Logged in: {error}", "NOT_LOADED": "Not fully loaded, try again.", @@ -237,8 +321,8 @@ "OP_SETTINGS_BUTTON": "Op βš™", "OP_SETTINGS_TITLE": "Operation Settings", "OPEN_REQUEST": "[open request]", - "OPER_COLOR": "Operation Color: ", - "OPER_NAME": "Operation Name: ", + "OPER_COLOR": "Operation Color:", + "OPER_NAME": "Operation Name:", "OPERATIONS": "Operations", "OPS BUTTON TITLE": "Operations List", "OPS BUTTON": "Select OP", @@ -246,13 +330,12 @@ "OtherPortalAlert": "Other", "PASTE_INSTRUCT": "Paste a Wasabee draw export here.\n\nWasabee cannot import the stock intel format.\n\nThere is experimental support for importing the IITC DrawTools format.\n\nBefore importing DrawTools format, preview the areas and make sure all the portals load so IITC has them cached. Any portals that are not pre-cached will be faked.\n\nYou will need to use the 'swap' feature to move anchors from the faked portals to the real portals (they should be in the correct location, just not associated with the portal.\n\nCached portals might not be properly named.", "pending": "Pending", - "PENDING": "Pending", + "PERM DENIED": "Permission denied: {error}", + "PERM DENIED SHORT": "Permission denied", "PERMS": "{opName} permissions", - "PICK_DEST_FIRST": "Please select a destination portal first!", - "PICK_TAR_FIRST": "Please select a target portal first!", - "PICK_TARGETDEST_Portals": "Please select target and destination portals first!", "PLEASE_SELECT_PORTAL": "Please select a portal", - "PORT_FAKE": " portals. Faked ", + "popup.anchor.keys": "Keys: {onHand} / {required}", + "popup.marker.state_button": "Set State", "PORTAL KEY LIST": "Key list for portal {portalName}", "PORTAL_COUNT": "{count} portals", "PORTAL": "Portal", @@ -264,35 +347,31 @@ "QD TITLE": "Quick Draw Layers", "QD TOGGLE MODE": "Change mode", "QDBASE": "Base Link", - "QDCANCEL": "Cancel Drawing Fields", "QDCONT": "Click a spine portal to draw a field.", - "QDEND": "Click again on the same portal to finish drawing.", "QDNEXT": "Click the second anchor portal.", "QDSTART": "Click the first anchor portal.", "READ_SHORT": "RO", "READ": "Read", "RechargePortalAlert": "Recharge", - "REFERENCE_TIME": "Reference Time: ", + "REFERENCE_TIME": "Reference Time:", "REM_LOC_CP": "Remove local copy of {opName}", "REMOVE_TEAM_CONFIRM_LABEL": "Do you want to permenantly remove {teamName} from the Wasabee Server?", "REMOVE_TEAM_CONFIRM_TITLE": "Remove Team {teamName}", - "REMOVE_TEAM": "Remove Team: ", + "REMOVE_TEAM": "Remove Team:", "REMOVE": "Remove", - "RENAME_TEAM": "Rename Team: ", + "RENAME_TEAM": "Rename Team:", "RENAME": "Rename", "REQUIRED": "Required", "RESET": "Reset", "REVERSE": "Reverse", - "ROCKS_COM": "enl.rocks community: ", + "ROCKS_COM": "enl.rocks community:", "ROLE": "Role", "SAVELINKS TITLE": "Save Links", "SAVELINKS_DRAW": "Save Links", "SAVELINKS": "Save Links", "SECONDS": " ({seconds} seconds ago)", - "SEL_PORT_FIRST": "Please select anchor portals first!", "SEL_SB_ANCHOR": "Select the anchor.", "SEL_SB_ANCHOR2": "Zoom out. Make sure portals have all loaded, then click draw.", - "SEL_SB_ANCHOR3": "Please be patient, it can take a bit.", "SEL_SL_ANCHOR": "Select the portal to save the links of. Click save links button and look at checklist.", "SEL_SRC_ANC2": "Select both Source and Anchor 2", "SEL_SRC_PORT": "Select a source portal", @@ -300,11 +379,10 @@ "SELECT_FAN_PORTALS": "Select an anchor portal, a start portal, and an end portal, then position the view over the field area.", "SELECT_FAN_PORTALS2": "Wait for all portals to load, then click draw.", "SELECT_INSTRUCTIONS": "Select two anchor portals, then zoom over the spine area.", - "SELECT_MADRID_INSTRUCTIONS": "Select three anchor portals, zoom in on the area near the selected anchor, wait until the portals are loaded (portals must be on screen to be considered) then select the 'define spine region' button for the corresponding base links.", "SELECT_ONION_PORTALS": "Layers build from the inside out. Zoom in to center and select starting portal, then zoom out to area.", "SELF SWAP": "Cannot swap a portal with itself! Select a different portal.", "SEND ANALYTICS": "Send Anonymous Analytics", - "SEND LOCATION": "Send Location", + "SEND LOCATION": "Share Location (only when IITC is in foreground)", "SEND TARGET AGENT": "Select target recipient", "SEND TARGET CONFIRM": "Do you want to send {portalName} target to {agent}?", "SEND TARGET": "Send Target", @@ -312,18 +390,19 @@ "SET_3_PORT": "Please set the three portals first!", "SET_COMMENT": "Set Comment", "SET_LCOMMENT": "Set Link Comment", - "SET_LINK_COMMENT": "Set comment for link: ", - "SET_LINKS_ZONES": "Set Links to Zones ", - "SET_MARKER_COMMENT": "Set comment for marker on: ", + "SET_LINK_COMMENT": "Set comment for link:", + "SET_LINKS_ZONES": "Set Links to Zones", + "SET_MARKER_COMMENT": "Set comment for marker on:", "SET_MARKER_TYPE_TITLE": "Change marker type", "SET_MARKERS_ZONES": "Set Markers to Zones", "SET_MCOMMENT": "Set Marker Comment: {portalName}", "SET_NEW_OP": "Please Set the New Operation Name", "SET_PCOMMENT": "Set Portal Comment: {portalName}", - "SET_PORT_COMMENT": "Set comment for portal: ", + "SET_PORT_COMMENT": "Set comment for portal:", "SET_PORTAL_COMMENT": "Set Portal Comment", "SET": "set", - "SETTINGS": "Wasabee Settings", + "SETTINGS_TOOLBOX": "Wasabee Settings", + "SETTINGS_TITLE": "Advanced Settings", "SKINS_AVAILABLE": "There are {count} available skins.", "SKINS_BUTTON": "Configure Skins", "SKINS_DESCRIPTION": "Available skin packs are located in the right columns. Move skins you wish to use to the left columns.", @@ -332,31 +411,43 @@ "SKIP_CONFIRM_ENTITY": "Only ask for team/op", "SKIP_CONFIRM_NEVER": "Always ask", "SKIP_CONFIRM": "Skip confirmation", - "SOURCE_PORT": "Source Portal ", - "SQUAD": "Squad", + "SOURCE_PORT": "Source Portal", "STARBURST TITLE": "Starburst", "STARBURST_DRAW": "Draw", "STARBURST": "Starburst", - "START_PORT": "Start Portal ", + "START_PORT": "Start Portal", "STATE": "State", - "SUPPORT_INSTRUCT": "For support, please join the The Wasabee User Telegram Channel", - "SWAP PROMPT": "Do you want to swap: ", + "SUPPORT_INSTRUCT": "For support, please join the Wasabee User Telegram Channel", + "SWAP PROMPT": "Do you want to swap:", "SWAP TITLE": "Swap Portals", "SWAP WITH": " with ", "SWAP": "Swap", "SYNC DONE": "Download Complete
Click HERE for hints, tips, and documentation.", "SYNC": "Download Available Operations", - "TARDEST_DIFF": "Target and destination portals must be different.", "TARGET SENT": "Target sent", - "TEAM PERM DENIED": "Permission denied to team: {error}", "TEAM STATE": "Share Location", "TEAM_CREATED": "Team {teamName} created", "TEAM_NAME": "Team Name", "TEAM": "Team", "TEAMS BUTTON TITLE": "List Wasabee Teams", "TEAMS BUTTON": "Teams", - "TITLE": "title", "TO_PORT": "To Portal", + "toolbar.quick_delete.apply.text": "Apply", + "toolbar.quick_delete.apply.title": "Delete selected links/markers", + "toolbar.quick_delete.cancel.text": "Cancel", + "toolbar.quick_delete.cancel.title": "Cancel", + "toolbar.quick_delete.stop.text": "Stop", + "toolbar.quick_delete.stop.title": "Exit delete mode", + "toolbar.quick_delete.title": "Quick delete", + "toolbar.quick_delete.tooltip.toggle_mode": "Click on features to mark for deletion", + "toolbar.quick_delete.tooltip.quick_mode": "Click on features to delete instantly", + "toolbar.quick_draw.tooltip.star_mode.anchor": "Select the star anchor", + "toolbar.quick_draw.tooltip.star_mode.portal": "Select a portal", + "toolbar.quick_draw.tooltip.single_mode.first": "Click first portal", + "toolbar.quick_draw.tooltip.single_mode.next": "Click next portal", + "toolbar.quick_draw.tooltip.portal_fail": "Portal data not loaded, please try again", + "toolbar.wasabee.settings": "Settings", + "toolbox.teammates": "Teammates Online", "TRAWL SKIP TILES": "Trawl Skip Tiles", "TRAWL TITLE": "Trawl Lanes", "TRAWL WARNING": "This will load the tile data under all drawn links. This is a slow process.", @@ -370,33 +461,27 @@ "TYPE": "Type", "UNASSIGNED": "Unassigned", "UNKNOWN": "Unknown", - "UPDATE HOVER NOT CHANGED": "{opName} not changed locally", "UPDATE HOVER": "UPDATE {opName} on the server", "UPDATE PERM DENIED": "You do not have permission to update", - "UPDATE_CONFLICT_DESC": "The OP has been modified on server since last sync. Do you want to replace the server version by the current one?", + "UPDATE_CONFLICT_DESC": "The OP has been modified on the server since last sync. Do you want to replace the server version with the current one?", "UPDATE_CONFLICT_TITLE": "Conflict detected with server", "UPDATE_COUNT": "Update Count", "UPDATED": "Successfully updated", "UpgradePortalAlert": "Upgrade", "UPLOAD BUTTON HOVER": "UPLOAD {opName} (not currently on server)", - "UPLOAD PERM DENIED": "Permission to upload denied", "UPLOADED": "Successfully uploaded", "USE PANES ON MOBILE": "Use panes (need reload)", - "USE_SWAP_INSTRUCT": ". Please use the swap feature to move faked portals to the real portals at the same location. Zooming in on the 'Loading' portals in the checklist might force them to load.", "USE_VALID_NAME": "Please use a valid operation name", "UseVirusPortalAlert": "Use Virus", "VRLA DESC": "Depending on the number and type of Link Amps used, a lower source portal level might suffice.", "VRLA": "L8+some VRLA", - "WASABEE BUTTON TITLE": "Wasabee: it is green and makes smurfs cry.", + "WASABEE BUTTON TITLE": "Wasabee: It is green and makes smurfs cry.", "WASABEE_D_LIST": "Input Defensive Key Count", "WD BUTTON TITLE": "Log Defensive Keys", "WD BUTTON": "W-D Keys", - "WEBVIEW VERIFY": "Verify Webview", - "WEBVIEW": "Webview Log In (iOS)", "WRITE_SHORT": "RW", "WRITE": "write", "WSERVER": "Server: {url}", - "YES": "Yes", "YESNO_DEL": "Are you sure you want to delete {opName}?", "ZONE_DRAW": "Click to set the zone boundaries", "ZONE": "Zone", @@ -407,7 +492,6 @@ "CHECKLIST BUTTON": "Check", "CLEAROPS BUTTON": "Clear", "EXPORT OP": "Xport", - "FAN_FIELD3": "Fan", "FANFIELD": "Draw", "FANFIELD2": "Draw Fan Field", "KEYS": "Keys", @@ -427,4 +511,4 @@ "TEAMS BUTTON": "Teams", "WD BUTTON": "W-D Keys" } -} +} \ No newline at end of file diff --git a/src/code/translations/filipino.json b/src/code/translations/Filipino.json similarity index 65% rename from src/code/translations/filipino.json rename to src/code/translations/Filipino.json index 1cbb3df65..9c8ec9a52 100644 --- a/src/code/translations/filipino.json +++ b/src/code/translations/Filipino.json @@ -1,16 +1,16 @@ { - "ABOUT WASABEE-IITC": "Tungkol sa Wasabee-IITC", "ABOUT_WASABEE": "Tungkol sa Wasabee", "acknowledged": "Natanggap", "ADD LINK TITLE": "Magdagdag ng Links", "ADD MARKER TITLE": "Magdagdag ng Markers", - "ADD_AGENT": "Magdagdag ng Agent: ", - "ADD_BL": "Magdagdag ng Back Links: ", + "ADD_AGENT": "Magdagdag ng Agent:", + "ADD_BL": "Magdagdag ng Back Links:", + "ADD_BULK": "Maramihang idagdag", "ADD_BUTTON_LINKS": "Sabay-sabay idagdag ang lahat ng link", "ADD_LINKS": "Magdagdag ng Link", "ADD_MARKER": "Magdagdag ng Marker", "ADD_NEW_OP": "Magdagdag ng Bagong Op", - "ADD_SUCC_INSTR": "Matagumpay na naidagdag, kailangan paganahin ng mga miyembro ng pangkat sa Wasabee website bago it lumabas sa listahan nila", + "ADD_SUCC_INSTR": "Matagumpay na naidagdag", "ADD_ZONE": "Add Zone", "ADD": "Magdagdag", "ADD1": "Add first link", @@ -20,16 +20,16 @@ "AGES": " (matagal na panahon)", "ALREADY_HAS_MARKER": "May Marker ang portal na ito. Pumili ng ibang portal.", "AMAZ_TEAM_NAME": "Malupet na Pangalan ng Pangkat", - "ANCHOR ASSIGNMENT": " lahat ng outbound links", + "ANCHOR ASSIGNMENT": "Assign all outbound links to:", "ANCHOR_GMAP": "Google Map", - "ANCHOR_PORTAL": "Anchor Portal ", + "ANCHOR_PORTAL": "Anchor Portal", "ANCHOR_PORTAL2": "Anchor Portal 2", "ANCHOR_PORTAL3": "Anchor Portal 3", - "ANCHOR1": "Anchor 1 ", - "ANCHOR2": "Anchor 2 ", - "ANCHOR3": "Anchor 3 ", + "ANCHOR1": "Anchor 1", + "ANCHOR2": "Anchor 2", + "ANCHOR3": "Anchor 3", "ANCHORS_AS_BOOKMARKS": "Anchors as bookmarks", - "API_KEY": " api key: ", + "API_KEY": "Rocks API key:", "ASS_TO": "Nakatalaga kay", "ASSIGN LINK PROMPT": "Magatalaga ng link mula: {portalName}", "ASSIGN MARKER PROMPT": "Magtalaga ng marker mula: {portalName}", @@ -39,15 +39,28 @@ "ASSIGNED_ONLY_SHORT": "AO", "ASSIGNED_ONLY": "Assigned Only", "assigned": "Naitalaga", - "ASSIGNED": "Naitalaga", - "AUTH ANDROID": "Sa Android, subukan muna ang 'quick'. Kung hindi gumana, subukan ang main login gamit ang 'select_account'.", "AUTH INCOMPAT": "May ginagamit kang plugin sa TamperMonkey na hindi angkop sa Wasabee", - "AUTH IOS": "Sa iOS, subukan muna ang 'Log In'. Kung hindi gumana, gawin ang 'Webview Log in', mag-log in, tapos gamitin ang 'Verify Webview' button para makumpleto ang proseso.", "AUTH REQUIRED": "Kailangan ng Authentication", "AUTH TOKEN REJECTED": "Pagpapadala ng auth token sa server natanggihan {error}", "AUTH_SELECT_ACCOUNT": "Select account", "AUTO_DRAWS": "Auto-draw", "AUTODRAWS": "Wasabee Auto-draw Options", + "AUTODRAW_PORTALS_SET": "Portals", + "autodraw.common.draw_button": "Draw", + "autodraw.fanfield.result": "Fanfield found {links} links and {fields} fields for {ap} AP", + "autodraw.flipflop.result": "Flip flop: found {count} links", + "autodraw.homogeneous.missing_split": "Unable to find {count} splits, try less depth or a different region", + "autodraw.homogeneous.order": "Order", + "autodraw.homogeneous.portals_required": "{count} required", + "autodraw.madrid.auto_determined": "Auto-determined", + "autodraw.madrid.balanced": "Balanced", + "autodraw.madrid.result": "Madrid found {count} layers", + "autodraw.multimax.result": "Multimax found {count} layers", + "autodraw.multimax.result_both_side": "Multimax found {count1} and {count2} layers", + "autodraw.onion.variant": "Option", + "autodraw.onion.variant.equilateral": "~Equilateral", + "autodraw.onion.variant.grow": "Let it grow", + "autodraw.onion.variant.balanced": "Perfectly balanced", "AUTOLOAD_RATE": "Portal Detail Request Rate (ms)", "AUTOLOAD": "Automatically Load Missing Portal Details", "AUTOMARK STOP": "Itinigil ang pag Auto-Mark dahil hindi maiload ang mga portals", @@ -66,7 +79,6 @@ "CLEAR LINKS": "Clear Links", "CLEAR MARKERS": "Clear Markers", "CLEAR_EVERYTHING": "Burahin Portals/Links/Markers", - "CLEAR": "Burahin ang Pinili", "CLEAROPS BUTTON TITLE": "Burahin lahat ng locally stored na operasyon", "CLEAROPS BUTTON": "Burahin Local Ops", "CLEAROPS PROMPT": "Nais mo bang tangalin ang lahat ng opersyon sa local storage? Ang mga Ops na nakalagay sa server ay mababawi sa susunod na sync.", @@ -74,64 +86,136 @@ "COMMENT": "Komentaryo", "COMPLETED BY": "Nakumpleto ni {agentName}", "completed": "Naikumpleto", - "COMPLETED": "Naikumpleto", "CON_DEL": "Kumpirmahin ang Pagtangal: {opName}", - "CONFIRM_DELETE": "Gusto mo bang tangalin ang link: ", "COUNT": "Bilang", "CREATE_NEW_TEAM": "Magbuo ng bagong Pangkat", "CreateLinkAlert": "Link", "CUR_USER_INFO": "Kasalukuyang Impormasyon ng User", "D_SHOW_LIST": "Ipasok ang Defensive Keys", "DEFAULT OP NAME": "Bagong Op {date}", - "DELETE ANCHOR PROMPT": "Gusto mo bang tangalin ang anchor na ito at ang lahat ng links na nakakabit: ", + "DELETE ANCHOR PROMPT": "Gusto mo bang tangalin ang anchor na ito at ang lahat ng links na nakakabit:", "DELETE ANCHOR TITLE": "Tanggalin ang Anchor", - "DELETE MARKER PROMPT": "Gusto mo bang tangalin ang marker na ito: ", + "DELETE MARKER PROMPT": "Gusto mo bang tangalin ang marker na ito:", "DELETE MARKER TITLE": "Tanggalin ang Marker", - "DELETE PERM DENIED": "Walang pahintulot para mag tangal", "DELETE_ANCHOR": "Tangalin", "DELETE_LINK": "Tangalin", - "DELETE_MARKER": "Tangalin", "DELETE_OP": "Tangalin {opName}", - "DELETED": "Matagumpay na naitangal", "DESCRIP_PLACEHOLD": "Description (opsyonal)", "DestroyPortalAlert": "Sirain", - "DISABLE_SYNC": "Ang Wasabee at stock sync plugin ay hindi compatible. Paki disable sync para gamitin ang Wasabee", - "DISABLED": "Hindi pa handa ang feature na ito", - "DONE": "Tapos", + "dialog.about.download_mobile_app": "

Wasabee App:

", + "dialog.agent_comment.text": "Comment:", + "dialog.agent_comment.title": "Set comment for {agentName}", + "dialog.auth.ott.button": "One Time Token Login", + "dialog.auth.ott.text": "Get a token from the Wasabee Server, then paste it here", + "dialog.auth.ott.title": "One Time Token", + "dialog.blockers.clear_automark": "Clear Automark", + "dialog.clear_all.text": "Do you want to reset {opName}?", + "dialog.clear_all.title": "Clear: {opName}", + "dialog.clear_links.text": "Do you want to remove all links from {opName}?", + "dialog.clear_links.title": "Clear Links: {opName}", + "dialog.clear_markers.text": "Do you want to remove all markers from {opName}?", + "dialog.clear_markers.title": "Clear Markers: {opName}", + "dialog.checklist.count_fields": "Count fields", + "dialog.checklist.count_fields.no_empty": "Found {fieldCount} fields and no empty field", + "dialog.checklist.count_fields.with_empty": "Found {fieldCount} fields and {emptyCount} empty field(s) on {linkCount} link(s)", + "dialog.checklist.count_fields.link_from_inside": "Found {count} links from covered portals", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " at {order} by link ", + "dialog.common.commands": "Commands", + "dialog.common.commands_short": "Cmds", + "dialog.common.delete": "Delete", + "dialog.common.name": "Name", + "dialog.common.off": "Off", + "dialog.common.on": "On", + "dialog.common.owner": "Owner", + "dialog.common.zone_all": "All", + "dialog.firebase.setup": "Visit {url} and press the button to authorize live updates. You will need to reload IITC afterward.", + "dialog.import.url": "Fill from URL", + "dialog.import.success_message": "Import Complete. Found {count} portals and used {faked} faked. Please use the swap feature to move faked portals to the real portals at the same location. Zooming in on the 'Loading' portals in the checklist might force them to load.", + "dialog.leave_team.text": "If you leave {teamName} you cannot rejoin unless the owner re-adds you.", + "dialog.leave_team.title": "Leave: {teamName}", + "dialog.link_list.length": "Length", + "dialog.link_list.level": "Min Lvl", + "dialog.merge.cancel_upload": "Cancel upload", + "dialog.merge.conflicts": "Conflicts:", + "dialog.merge.local": "Local copy", + "dialog.merge.server": "Server copy", + "dialog.merge.zone": "Zone: {name}", + "dialog.merge.prop.assignedTo": "Assign:", + "dialog.merge.prop.comment": "Comment:", + "dialog.merge.prop.color": "Color:", + "dialog.merge.prop.deltaminutes": "Delta:", + "dialog.merge.prop.fromPortal": "From:", + "dialog.merge.prop.hardness": "Hard:", + "dialog.merge.prop.order": "Order:", + "dialog.merge.prop.state": "State:", + "dialog.merge.prop.toPortal": "To:", + "dialog.merge.prop.zone": "Zone:", + "dialog.merge.prop.zone_points": "Shape has changed", + "dialog.online_agents.actions": "Actions", + "dialog.online_agents.last_seen": "Last Seen", + "dialog.online_agents.title": "Online Agents", + "dialog.op_settings.zones": "Zones", + "dialog.ops_list.background_disable": "Disable background", + "dialog.ops_list.background_enable": "Show in background", + "dialog.ops_list.download": "Download {opName}", + "dialog.ops_list.last_fetched": "Last fetched: {date}", + "dialog.ops_list.local_change": "Local has changed", + "dialog.ops_list.remote_change": "Remote has changed", + "dialog.ops_list.toggle_hide": "Toggle Show/Hide", + "dialog.ops_list.unhide_ops": "Unhide all OPs", + "dialog.remove_agent.text": "Do you want to remove {agentName} from {teamName}?", + "dialog.remove_agent.title": "Remove: {agentName}", + "dialog.setcomment.portal_hardness": "Hardness", + "dialog.team_list.load_wd_keys": "Load W-D Keys", + "dialog.team_list.share_wd_keys": "Share W-D Keys", + "dialog.team_manage.join_link": "Join Link", + "dialog.team_manage.join_link.create": "Create", + "dialog.team_manage.join_link.revoke": "Revoke", + "dialog.team_members.location": "Sharing Location", + "dialog.team_members.wd_keys": "Sharing W-D Keys", + "dialog.team_message": "Team announcement: β€œ{message}” from {sender}", + "dialog.update_warning": "Wasabee is out of date. Please update using your plugin manager or by going to https://wasabee.rocks", + "dialog.zone_color.title": "Zone Color", + "dialog.zone_color.text": "Set the color of all links in zone {zoneName}", + "dialog.zones.color": "Color", + "dialog.zones.color_links": "Color links", + "dialog.zones.delete_zone_shape": "Reset the shape", + "dialog.zones.draw_zone_shape": "Draw the boundaries", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Stop drawing", + "dialog.zones.title": "Zones", "DRAW TOOLS FORMAT": "Draw Tools Format", - "DT_FORMAT": "Draw Tools Format", "DUPE_OP": "Kopyahin ang Operasyon", "END_PORT": "End Portal ", "ExcludeMarker": "Ibukod sa Auto-Draw/Pag-marka", "EXPORT OP TITLE": "I-Export ang kasalukuyang op", "EXPORT OP": "I-Export ang Op", - "EXPORT": "Export: ", + "EXPORT": "Export:", "FAKED": "Faked: [{portalId}]", - "FAN_FIELD3": "Fan Field", - "FANFIELD TITLE": "Fanfield", "FANFIELD": "Guhit", "FANFIELD2": "Iguhit ang Fanfield", "FarmPortalMarker": "Farm", + "FLIP_FLOP_NAME": "Flip flop", + "FLIP_FLOP_TITLE": "Flip flop", + "FLIP_FLOP_DESC": "From a given anchor, a set of visible portal and a number of SBUL, find a fanfield to throw links from the anchor by decreasing distance to avoid searching keys.", + "FLIP_FLOP_INSTRUCTION": "Select a portal, zoom to see enough portals and press Draw. Once a fanfield is found, you can search for other anchors for consecutive rethrow", + "FLIP_FLOP_FIND_ANCHORS": "Find other anchors", "FROM_1-2": "from base 1-2", "FROM_1-3": "from base 1-3", "FROM_2-3": "from base 2-3", "FROM_DEPTH": "from the depth", "FROM_PORT": "Mula sa Portal", "GET DT": "Get existing DrawTools draw", - "GET_DT_DRAW": "Kunin ang current DrawTools draw", "GetKeyPortalMarker": "Kunin ang Keys", "GotoPortalMarker": "Pumunta", "H-GEN_INST": "Set portals for the outside layer. Choose number of splits. Click draw", "HF_DEEP_SEARCH": "Exhaustive search", "HF_DRAW_BUTTON": "Draw", - "HF_DRAW_DEEP_BUTTON": "Draw with deep recursion", "HF_REDRAW_BUTTON": "Redraw", "HG": "Homogeneous Field", "HOURS": " ({hours} oras nakalipas)", "HOW_TO_VIDS": "

How-To Videos:

", - "IMP_COMP": "Natapos ang Pag Import. ", - "IMP_DT_OP": "Na-Import na Drawtools Op: ", - "IMP_NOPE": "Pag-I-Import Hindi Matagumpay.", + "IMP_NOPE": "Pag-I-Import Hindi Matagumpay: {error}", "IMP_WAS_OP": "I-Import ang Wasabee operasyon", "IMPORT_OP_SUCCESS": "Na-Import na Operasyon: {opName} Matagumpay.", "IMPORT_OP_TITLE": "Na-Import na Op: {date}", @@ -139,7 +223,6 @@ "IMPOSSIBLE": "Imposible", "INGNAME_GID": "Pangalan sa Ingress o GoogleID", "INPUT_DT_KEY_COUNT": "Ilagay ang Bilang ng Pangharang na Keys", - "INPUT_SQUAD_NAME": "Maglagay ng pangalan ng Squad", "INVALID REQUEST": "Hindi wastong Request", "IOS NEED FAKE UA": "Kailangang pumili ng 'Custom UserAgent for Webviews' sa IITC-Mobile settings para makapag-login ng maayos", "KEY_LIST2": "Litahan ng Keys para sa Operation: {opName}", @@ -150,9 +233,9 @@ "LANG": "Wika", "LEAVE": "Ialis", "LetDecayPortalAlert": "Ipa-decay", - "LINK ASSIGNMENT": " Link Pagtatalaga", + "LINK ASSIGNMENT": "Assign link to:", "LINK STATE PROMPT": "estado ng Link", - "LINK STATE": "Italaga estado ng Link", + "LINK STATE": "Set link status:", "LINKS BUTTON TITLE": "Links", "LINKS": "Links", "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", @@ -160,10 +243,8 @@ "LOADING": "[loading]", "LOADING1": "Loading: [{portalGuid}]", "LOC_PROC": "Lokasyon nai-proseso", - "LOC_UPDATE": "Pag-update ng Lokasyon", "LOCATION SUB": "Nairehistro ang lokasyon", "LOCFRMSER": " (locally at sa server)", - "LOG IN QUICK": "Log In (quick; for Android)", "LOG IN": "Mag Log In", "LOG_OUT": "Log Out", "MADRID_SET_1": "Select the region for baselink Anchor 2 to Anchor 3", @@ -174,11 +255,11 @@ "MADRID": "Draw", "MANAGE_TEAM": "Ipamahala {teamName}", "MANAGE": "Ipamahala", - "MARKER ASSIGNMENT": " Marker Pagtatalaga", + "MARKER ASSIGNMENT": "Assign marker to:", "MARKER LIST TITLE": "Listahan ng Marker", "MARKER LIST": "Markers", "MARKER STATE PROMPT": "Estado ng Marker", - "MARKER STATE": " Italaga estado ng marker", + "MARKER STATE": "Set marker state:", "MARKER_LIST": "Listahan ng Marker: {opName}", "MARKERS BUTTON TITLE": "Markers", "MAX_SPLITS": "Max Splits", @@ -196,28 +277,31 @@ "MIN_SRC_PORT_LVL": "Pinakamababang level kailangan sa on panimulang portal", "MINUTES": " ({minutes} minutong nakalipas)", "MM": "Multimax", + "MM_BOTH_SIDE": "Use both base sides", + "MM_INSERT_ORDER": "Insert at the end", + "MM_SET_ALL_PORTALS": "All visible portals", + "MM_SET_ALL_KEYS": "All GetKey Markers", + "MM_SET_KEYS_ZONE": "GetKey: {zoneName}", + "MM_SPINE": "Spine", "MULTI_M_TITLE": "Gumuhit ng Max Layers", "MULTI_M": "Multimax", - "MULTIMAX": "Multimax!", - "MULTIMAX2": "Multimax", "MUST_NOT_BE_EMPTY": "Hindi maari na walang laman", "MY_CAP_ID": "Aking Capsule ID", "MY_COUNT": "Aking Bilang", "NAME_REQ": "Kilanakailangan ng Pangalan", - "NAME": "Pangalan: ", + "NAME": "Pangalan:", "NEW_OP": "Bagong Operasyon", "NEW_TEAM_NAME": "Bagong Pangalan ng Pangkat", "NEW_TEAM": "New Team", "NEW_WAS_SERVER": "Bagong Waasbee Server", "NEWOP BUTTON TITLE": "Bumuo ng bagong Operasyon", "NEWOP BUTTON": "Bagong Op", - "NO_DATA": "Walang Data", "NO_DT_ITEMS": "Walang DrawTools drawn items na nakita", "NO_LABEL": "Walang tatak", - "NO_PORT_SEL": "Walang napili na Portal.", "NO_STOCK_INTEL": "Hindi suportado ng Wasabee ang stock intel draw imports", "NO_TITLE": "Walang Pamagat", - "NO": "Hindi", + "NO LONGER AVAILABLE": "Resource removed from server: {error}", + "NO LONGER AVAILABLE SHORT": "Resource removed from server", "NOT LOGGED IN SHORT": "Hindi naka-Logged in", "NOT LOGGED IN": "Hindi naka-Logged in {error}", "NOT_LOADED": "Hindi nai-load, ulitin muli.", @@ -237,8 +321,8 @@ "OP_SETTINGS_BUTTON": "Op βš™", "OP_SETTINGS_TITLE": "Operation Settings", "OPEN_REQUEST": "[open request]", - "OPER_COLOR": "Kulay ng Operasyon: ", - "OPER_NAME": "Pangalan ng Operasyon: ", + "OPER_COLOR": "Kulay ng Operasyon:", + "OPER_NAME": "Pangalan ng Operasyon:", "OPERATIONS": "Mga Operasyon", "OPS BUTTON TITLE": "Operasyon", "OPS BUTTON": "Ops", @@ -246,13 +330,12 @@ "OtherPortalAlert": "Iba", "PASTE_INSTRUCT": "I-Paste ang Wasabee draw export dito.\n\nHindi ma-import ng Wasabee ang stock intel format.\n\nMerong experimental na suporta para sa pag-import ng IITC DrawTools format.\n\nBago i-import ang DrawTools format, tignan ang mga areas at siguraduhing lahat ng portals naka-load para naka-cached ito sa IITC. Ang mga portals na hindi pre-cached ay that are not pre-cached ay ipapalit ng 'fake' portal.\n\nKailangan mong gamitin ang 'Ipagpalit' feature para ipatlit ang mga anchor mula sa fake portal sa tamang portal. (ang portal ay dapat nasa tamang lokasyon.\n\nAng mga pangalan ng naka-Cached na portals ay hindi maaring nakapangalan ng tama.)", "pending": "Nakabinbin", - "PENDING": "Nakabinbin", + "PERM DENIED": "Walang pahintulot: {error}", + "PERM DENIED SHORT": "Walang pahintulot", "PERMS": "{opName} permisyo", - "PICK_DEST_FIRST": "Pumili muna ng destinasyon na portal!", - "PICK_TAR_FIRST": "Pumili muna ng simulang portal!", - "PICK_TARGETDEST_Portals": "Pumili muna ng simula and destinasyon na portals!", "PLEASE_SELECT_PORTAL": "Pumili ng portal", - "PORT_FAKE": " portals ang nakita. Faked ", + "popup.anchor.keys": "Keys: {onHand} / {required}", + "popup.marker.state_button": "Set State", "PORTAL KEY LIST": "Listahan ng Key para sa Portal {portalName}", "PORTAL_COUNT": "{count} portals", "PORTAL": "Portal", @@ -264,35 +347,31 @@ "QD TITLE": "Mabilisang Pagukit ng Layers", "QD TOGGLE MODE": "Change mode", "QDBASE": "Base Link", - "QDCANCEL": "Kanselahin Pagukit ng Fields", "QDCONT": "I-Click ang mga spine portal para I-drawing ang field.", - "QDEND": "I-Click muli ang kaparehong portal para tapusin ang pagukit.", "QDNEXT": "I-Click ang pangalawang anchor portal.", "QDSTART": "I-Click ang unang anchor portal.", "READ_SHORT": "RO", "READ": "basahin", "RechargePortalAlert": "Recharge", - "REFERENCE_TIME": "Reference Time: ", + "REFERENCE_TIME": "Reference Time:", "REM_LOC_CP": "Tangalin ang local copy ng {opName}", "REMOVE_TEAM_CONFIRM_LABEL": "Gusto mong permanenteng tanggalin {teamName} sa Wasabee Server?", "REMOVE_TEAM_CONFIRM_TITLE": "Tanggalin Pangkat {teamName}", - "REMOVE_TEAM": "Tanggalin Pangkat: ", + "REMOVE_TEAM": "Tanggalin Pangkat:", "REMOVE": "Tangalin", - "RENAME_TEAM": "Palitan ang Pangalan ng Pangkat: ", + "RENAME_TEAM": "Palitan ang Pangalan ng Pangkat:", "RENAME": "Palitan ang Pangalan", "REQUIRED": "Kinakailangan", "RESET": "Reset", "REVERSE": "Reverse", - "ROCKS_COM": "enl.rocks community: ", + "ROCKS_COM": "enl.rocks community:", "ROLE": "Papel", "SAVELINKS TITLE": "Save Links", "SAVELINKS_DRAW": "Save Links", "SAVELINKS": "Save Links", "SECONDS": " ({seconds} segundong nakalipas)", - "SEL_PORT_FIRST": "Pumili muna ng anchor portals!", "SEL_SB_ANCHOR": "Pillin ang anchor, I-zoom sa area para dagdagan sa starburst", "SEL_SB_ANCHOR2": "Zoom out. Make sure portals have all loaded, then click draw.", - "SEL_SB_ANCHOR3": "Please be patient, it can take a bit.", "SEL_SL_ANCHOR": "Select the portal to save the links of. Click save links button and look at checklist.", "SEL_SRC_ANC2": "Piliin ang Panimula at Anchor 2", "SEL_SRC_PORT": "Pumili ng panimulang portal", @@ -300,11 +379,10 @@ "SELECT_FAN_PORTALS": "Pumili ng mga anchor portals, (isang panimulang portal at panghuling portal) tapos i-zoom in sa lugar na i-fan field, hintayin na mag load ang mga portals (dapat nasa screen ang mga portals) at pindutin ang Fanfield button.", "SELECT_FAN_PORTALS2": "Wait for all portals to load, then click draw.", "SELECT_INSTRUCTIONS": "Pumili ng dalawang anchor portals, tapos i-zoom in sa lugar para sa spine, hintayin mag-load ang mga portals (dapat nasa screen ang mga portals para gumana) tapos pindutin ang Multimax button.", - "SELECT_MADRID_INSTRUCTIONS": "Select three anchor portals, zoom in on the area near the selected anchor, wait until the portals are loaded (portals must be on screen to be considered) then select the 'define spine region' button for the corresponding base links.", "SELECT_ONION_PORTALS": "Layers build from the inside out. Zoom in to center and select starting portal, then zoom out to area.", "SELF SWAP": "Hindi maaari ipagpalit ang portal sa sarili! Pumili ng ibang portal.", "SEND ANALYTICS": "Send Anonymous Analytics", - "SEND LOCATION": "Ipaladala ang Lokasyon", + "SEND LOCATION": "Share Location (only when IITC is in foreground)", "SEND TARGET AGENT": "Select target recipient", "SEND TARGET CONFIRM": "Gusto mong ipadala ang {portalName} target sa {agent}?", "SEND TARGET": "Ipadala ang Target", @@ -312,18 +390,19 @@ "SET_3_PORT": "Pumili muna ng tatlong portals!", "SET_COMMENT": "Magatalaga ng Komentayro", "SET_LCOMMENT": "Italaga ang commento sa Link", - "SET_LINK_COMMENT": "Komento para sa link: ", - "SET_LINKS_ZONES": "Set Links to Zones ", - "SET_MARKER_COMMENT": "Komento para sa marker: ", + "SET_LINK_COMMENT": "Komento para sa link:", + "SET_LINKS_ZONES": "Set Links to Zones", + "SET_MARKER_COMMENT": "Komento para sa marker:", "SET_MARKER_TYPE_TITLE": "Change marker type", "SET_MARKERS_ZONES": "Set Markers to Zones", "SET_MCOMMENT": "Italaga ang commento sa Marker: {portalName}", "SET_NEW_OP": "Bigyan ng pangalan ang bagong operasyon", "SET_PCOMMENT": "Italaga ang commento sa Portal: {portalName}", - "SET_PORT_COMMENT": "Komento para sa portal: ", + "SET_PORT_COMMENT": "Komento para sa portal:", "SET_PORTAL_COMMENT": "Magtalaga komento sa portal", "SET": "italaga", - "SETTINGS": "Settings ng Wasabee", + "SETTINGS_TOOLBOX": "Wasabee Settings", + "SETTINGS_TITLE": "Advanced Settings", "SKINS_AVAILABLE": "There are {count} available skins.", "SKINS_BUTTON": "Configure Skins", "SKINS_DESCRIPTION": "Available skin packs are located in the right columns. Move skins you wish to use to the left columns.", @@ -332,31 +411,43 @@ "SKIP_CONFIRM_ENTITY": "Only ask for team/op", "SKIP_CONFIRM_NEVER": "Always ask", "SKIP_CONFIRM": "Skip confirmation", - "SOURCE_PORT": "Panimulang Portal", - "SQUAD": "Squad", + "SOURCE_PORT": "Source Portal", "STARBURST TITLE": "Starburst ", "STARBURST_DRAW": "Iguhit", "STARBURST": "Starburst", "START_PORT": "Panimulang Portal", "STATE": "Estado", "SUPPORT_INSTRUCT": "Para sa karagdagang tulong, sumali sa Ang Wasabee User Telegram Channel", - "SWAP PROMPT": "Gusto mo ba ipagpalit: ", + "SWAP PROMPT": "Gusto mo ba ipagpalit:", "SWAP TITLE": "Ipagpalit ang Portals", "SWAP WITH": " sa ", "SWAP": "Ipagpalit", "SYNC DONE": "Matagumpay na i-Download
Mag-click DITO para sa mga pahiwatig, tip, at dokumentasyon.", "SYNC": "I-Download ang Matatamo na mga Operasyon", - "TARDEST_DIFF": "Dapat magkaiba ang simula at destinasyon na portals.", "TARGET SENT": "Naipadala ang Target", - "TEAM PERM DENIED": "Walang pahintulot sa pangkat {error}", "TEAM STATE": "Share Location", "TEAM_CREATED": "Pangkat {teamName} nabuo", "TEAM_NAME": "Pangalan ng Pangkat", "TEAM": "Pangkat", "TEAMS BUTTON TITLE": "I-Lista mga Wasabee Pangkat", "TEAMS BUTTON": "Pangkat", - "TITLE": "Pamagat", "TO_PORT": "Papunta sa Portal", + "toolbar.quick_delete.apply.text": "Apply", + "toolbar.quick_delete.apply.title": "Delete selected links/markers", + "toolbar.quick_delete.cancel.text": "Cancel", + "toolbar.quick_delete.cancel.title": "Cancel", + "toolbar.quick_delete.stop.text": "Stop", + "toolbar.quick_delete.stop.title": "Exit delete mode", + "toolbar.quick_delete.title": "Quick delete", + "toolbar.quick_delete.tooltip.toggle_mode": "Click on features to mark for deletion", + "toolbar.quick_delete.tooltip.quick_mode": "Click on features to delete instantly", + "toolbar.quick_draw.tooltip.star_mode.anchor": "Select the star anchor", + "toolbar.quick_draw.tooltip.star_mode.portal": "Select a portal", + "toolbar.quick_draw.tooltip.single_mode.first": "Click first portal", + "toolbar.quick_draw.tooltip.single_mode.next": "Click next portal", + "toolbar.quick_draw.tooltip.portal_fail": "Portal data not loaded, please try again", + "toolbar.wasabee.settings": "Settings", + "toolbox.teammates": "Teammates Online", "TRAWL SKIP TILES": "Trawl Skip Tiles", "TRAWL TITLE": "Trawl Lanes", "TRAWL WARNING": "This will load the tile data under all drawn links. This is a slow process.", @@ -370,7 +461,6 @@ "TYPE": "Uri", "UNASSIGNED": "Hindi Nakatalaga", "UNKNOWN": "Nakatago", - "UPDATE HOVER NOT CHANGED": "{opName} hindi naipalit locally", "UPDATE HOVER": "UPDATE {opName} sa server", "UPDATE PERM DENIED": "Walang pahintulot para sa pag-update", "UPDATE_CONFLICT_DESC": "The OP has been modified on server since last sync. Do you want to replace the server version by the current one?", @@ -379,10 +469,8 @@ "UPDATED": "Matagumpay na i-update", "UpgradePortalAlert": "Upgrade", "UPLOAD BUTTON HOVER": "UPLOAD {opName} (kasalukuyang wala sa server)", - "UPLOAD PERM DENIED": "Walang pahintulot para sa pag-upload", "UPLOADED": "Matagumpay na i-upload", "USE PANES ON MOBILE": "Use panes (need reload)", - "USE_SWAP_INSTRUCT": ". Gamitin ang 'Ipagpalit' na feature para ipalit ang 'faked' portals sa totoong portals. Ang pag zoom sa 'Loading' portals sa listahan ay posibleng ma-'force load' ito.", "USE_VALID_NAME": "Gumamit ng naaayon na pangalan ng operasyon", "UseVirusPortalAlert": "Gumamit ng Virus", "VRLA DESC": "Depende sa dami at uri ng Link Amp, ang mas mababang panimulang portal level ay maaaring piliin.", @@ -391,12 +479,9 @@ "WASABEE_D_LIST": "Ipasok ang Bilang ng Defensive Key", "WD BUTTON TITLE": "Ilagay mga Pangharang na Keys", "WD BUTTON": "W-D Keys", - "WEBVIEW VERIFY": "I-Verify Webview", - "WEBVIEW": "Webview Log In (iOS)", "WRITE_SHORT": "RW", "WRITE": "isulat", "WSERVER": "Server: {url}", - "YES": "Oo", "YESNO_DEL": "Sigurado ka na gusto mo burahin ang {opName}?", "ZONE_DRAW": "Click to set the zone boundaries", "ZONE": "Zoned", @@ -407,7 +492,6 @@ "CHECKLIST BUTTON": "Check", "CLEAROPS BUTTON": "Clear", "EXPORT OP": "Xport", - "FAN_FIELD3": "Fan", "FANFIELD": "Draw", "FANFIELD2": "Draw Fan Field", "KEYS": "Keys", @@ -427,4 +511,4 @@ "TEAMS BUTTON": "Teams", "WD BUTTON": "W-D Keys" } -} +} \ No newline at end of file diff --git a/src/code/translations/french.json b/src/code/translations/French.json similarity index 54% rename from src/code/translations/french.json rename to src/code/translations/French.json index db4872166..7c16d04bc 100644 --- a/src/code/translations/french.json +++ b/src/code/translations/French.json @@ -1,35 +1,35 @@ { - "ABOUT WASABEE-IITC": "Γ€ propos de Wasabee-IITC", - "ABOUT_WASABEE": "Au sujet de Wasabee", + "ABOUT_WASABEE": "Γ€ propos de Wasabee", "acknowledged": "NotΓ©", "ADD LINK TITLE": "Ajouter des liens", "ADD MARKER TITLE": "Ajouter des marqueurs", - "ADD_AGENT": "Ajouter agent:", - "ADD_BL": "Ajouter les back links :", + "ADD_AGENT": "Ajouter l'agent :", + "ADD_BL": "Ajouter les backlinks :", + "ADD_BULK": "Ajouter en masse", "ADD_BUTTON_LINKS": "Ajouter les liens", "ADD_LINKS": "Ajouter des liens", "ADD_MARKER": "+ Marqueur", "ADD_NEW_OP": "Ajouter une nouvelle opΓ©", - "ADD_SUCC_INSTR": "L'agent a bien Γ©tΓ© ajoutΓ© Γ  l'Γ©quipe. Il doit maintenant l'activer pour pouvoir Γͺtre affectΓ© Γ  des actions sur les OPs de l'Γ©quipe.", - "ADD_ZONE": "Add Zone", + "ADD_SUCC_INSTR": "L'agent a bien Γ©tΓ© ajoutΓ© Γ  l'Γ©quipe", + "ADD_ZONE": "Ajouter une zone", "ADD": "Ajouter", "ADD1": "Ajouter le premier lien", "ADD2": "Ajouter le second lien", "AGENT_STATS": "Informations de l'agent", "AGENT": "Agent", - "AGES": "(il y a longtemps)", - "ALREADY_HAS_MARKER": "Ce portail porte dΓ©jΓ  un marqueur. Choissisez un autre portail.", + "AGES": " (il y a longtemps)", + "ALREADY_HAS_MARKER": "Ce portail porte dΓ©jΓ  un marqueur. Choisissez un autre portail.", "AMAZ_TEAM_NAME": "Nom de l'Γ©quipe", - "ANCHOR ASSIGNMENT": "tous les liens sortants", - "ANCHOR_GMAP": "Google Map", - "ANCHOR_PORTAL": "Portail Ancre", + "ANCHOR ASSIGNMENT": "Affecter tous les liens sortants Γ  :", + "ANCHOR_GMAP": "Google Maps", + "ANCHOR_PORTAL": "Ancre", "ANCHOR_PORTAL2": "Portail Ancre 2", "ANCHOR_PORTAL3": "Portail Ancre 3", "ANCHOR1": "Ancre 1", "ANCHOR2": "Ancre 2", "ANCHOR3": "Ancre 3", "ANCHORS_AS_BOOKMARKS": "Ancres vers Bookmarks", - "API_KEY": "ClΓ©e API", + "API_KEY": "ClΓ© API Rocks :", "ASS_TO": "AssignΓ© Γ ", "ASSIGN LINK PROMPT": "Assigner le lien de {portalName}", "ASSIGN MARKER PROMPT": "Assigner le marqueur sur {portalName}", @@ -39,25 +39,38 @@ "ASSIGNED_ONLY_SHORT": "AO", "ASSIGNED_ONLY": "Seulement les affectations", "assigned": "AssignΓ©", - "ASSIGNED": "AssignΓ©", - "AUTH ANDROID": "On Android, try 'quick' first. If that fails, try the main login with 'select_account'.", - "AUTH INCOMPAT": "You have activated a plugin in TamperMonkey that is incompatable with Wasabee", - "AUTH IOS": "On iOS, use the main 'Log In' option. If that fails, use 'Webview Login' then use the 'Verify Webview' button to complete the process.", - "AUTH REQUIRED": "Autentification requise", - "AUTH TOKEN REJECTED": "Jeton d'autentification rejetΓ© par le serveur : {error}", + "AUTH INCOMPAT": "Vous avez activΓ© un plugin dans TamperMonkey (ou Γ©quivalent) qui est incompatible avec Wasabee", + "AUTH REQUIRED": "Authentification requise", + "AUTH TOKEN REJECTED": "Jeton d’authentification rejetΓ© par le serveur : {error}", "AUTH_SELECT_ACCOUNT": "SΓ©lectionner le compte", "AUTO_DRAWS": "Auto-Draw", "AUTODRAWS": "Choix d'Auto-draw", + "AUTODRAW_PORTALS_SET": "Portails", + "autodraw.common.draw_button": "Tracer", + "autodraw.fanfield.result": "Fanfield a trouvΓ© {links} liens et {fields} fields pour {ap} AP", + "autodraw.flipflop.result": "Flip flop: {count} liens trouvΓ©s", + "autodraw.homogeneous.missing_split": "Il manque {count} portails pour une configuration complΓ¨te", + "autodraw.homogeneous.order": "Order", + "autodraw.homogeneous.portals_required": "{count} requis", + "autodraw.madrid.auto_determined": "Auto-dΓ©terminΓ©e", + "autodraw.madrid.balanced": "Γ‰quilibrΓ©", + "autodraw.madrid.result": "Madrid a trouvΓ© {count} couches", + "autodraw.multimax.result": "Multimax a trouvΓ© {count} couches", + "autodraw.multimax.result_both_side": "Multimax a trouvΓ© {count1} et {count2} couches", + "autodraw.onion.variant": "Variante", + "autodraw.onion.variant.equilateral": "~Γ‰quilatΓ©ral", + "autodraw.onion.variant.grow": "Un plus grand", + "autodraw.onion.variant.balanced": "Γ‰quilibrΓ©", "AUTOLOAD_RATE": "DΓ©lai entre deux requΓͺtes", "AUTOLOAD": "Charger automatiquement les donnΓ©es manquantes de portails", "AUTOMARK STOP": "Le processus d'Auto-Mark s'est arrΓͺtΓ© suite Γ  l'absence de donnΓ©e pour certains portails.", - "AUTOMARK": "Auto-Mark", + "AUTOMARK": "Auto-Marque", "BAT_TOAD": "Les grenouilles masquΓ©es", "BLOCKER LIST TITLE": "Afficher les bloquants", "BLOCKER TITLE": "Bloquants", "CANCEL": "Annuler", "CAPSULE": "Capsule", - "CapturePortalMarker": "Capture", + "CapturePortalMarker": "Capturer", "CHANGE SERVER PROMPT": "Nouveau serveur Wasabee", "CHANGE SERVER": "Changer de serveur", "CHANGE_WAS_SERVER": "Changer de serveur Wasabee", @@ -65,73 +78,144 @@ "CHECKLIST BUTTON": "Checklist", "CLEAR LINKS": "Supprimer les liens", "CLEAR MARKERS": "Supprimer les marqueurs", - "CLEAR_EVERYTHING": "Supprimer Portails/Links et Marquers", - "CLEAR": "Effacer", + "CLEAR_EVERYTHING": "Supprimer Portails/Links et Marqueurs", "CLEAROPS BUTTON TITLE": "Supprimer TOUTES les donnΓ©es Wasabee", "CLEAROPS BUTTON": "Supprimer les donnΓ©es Wasabee", - "CLEAROPS PROMPT": "Toutes les opΓ©rations et donnΓ©es relatives Γ  Wasabee seront supprimΓ©es de cet appareil. Seules les donnΓ©es prΓ©sentes sur le/les serveurs seront rΓ©cupΓ©rΓ©es Γ  la prochaine synchronisation.", + "CLEAROPS PROMPT": "Toutes les opΓ©rations et donnΓ©es relatives Γ  Wasabee seront supprimΓ©es de cet appareil. Seules les donnΓ©es prΓ©sentes sur le/les serveurs seront rΓ©cupΓ©rΓ©es Γ  la prochaine synchronisation. Wasabee sera dΓ©sactivΓ© jusqu'au prochain rechargement d'IITC.", "CLOSE": "Fermer", "COMMENT": "Commentaire", "COMPLETED BY": "Fait par {agentName}", "completed": "CompletΓ©e", - "COMPLETED": "CompletΓ©e", "CON_DEL": "Confirmer la suppression : {opName}", - "CONFIRM_DELETE": "Voulez-vous vraiment supprimer ce lien :", "COUNT": "Nombre", "CREATE_NEW_TEAM": "CrΓ©er une Γ©quipe", "CreateLinkAlert": "Lien", "CUR_USER_INFO": "Information sur l'utilisateur courant", - "D_SHOW_LIST": "Entrer les clΓ©es dΓ©fensive", + "D_SHOW_LIST": "Entrer les clΓ©s dΓ©fensive", "DEFAULT OP NAME": "OpΓ©ration {date}", - "DELETE ANCHOR PROMPT": "Voulez vous supprimer cette ancre et tous les liens associΓ©s : ", + "DELETE ANCHOR PROMPT": "Voulez vous supprimer cette ancre et tous les liens associΓ©s :", "DELETE ANCHOR TITLE": "Supprimer une ancre", "DELETE MARKER PROMPT": "Voulez vous supprimer le marqueur :", "DELETE MARKER TITLE": "Supprimer un marqueur", - "DELETE PERM DENIED": "Suppression interdite", "DELETE_ANCHOR": "Supprimer", "DELETE_LINK": "Supprimer", - "DELETE_MARKER": "Supprimer", "DELETE_OP": "Supprimer {opName}", - "DELETED": "Suppression faite.", "DESCRIP_PLACEHOLD": "Description (optionnelle)", "DestroyPortalAlert": "Casse", - "DISABLE_SYNC": "Le plugin \"Sync\" n'est pas compatible avec Wassabe. DΓ©sactiver le pour continuer", - "DISABLED": "Cette fonction n'est pas encore disponible", - "DONE": "Fait", + "dialog.about.download_mobile_app": "

Application Wasabee :

", + "dialog.agent_comment.text": "Comment:", + "dialog.agent_comment.title": "DΓ©finir le commentaire de {agentName}", + "dialog.auth.ott.button": "Connexion Γ  jeton unique", + "dialog.auth.ott.text": "RΓ©cupΓ©rez un jeton (One time Token) depuis le server wasabee, puis collez-le ici", + "dialog.auth.ott.title": "Connexion Γ  jeton unique", + "dialog.blockers.clear_automark": "Supprimer les Auto-Mark", + "dialog.clear_all.text": "Voulez-vous supprimer les liens et marqueurs de {opName} ?", + "dialog.clear_all.title": "RΓ©initialisation de {opName}", + "dialog.clear_links.text": "Voulez-vous supprimer tous les liens de {opName} ?", + "dialog.clear_links.title": "Effacer les liens : {opName}", + "dialog.clear_markers.text": "Voulez-vous supprimer tous les marqueurs de {opName} ?", + "dialog.clear_markers.title": "Effacer les marqueurs : {opName}", + "dialog.checklist.count_fields": "Nombre de fields", + "dialog.checklist.count_fields.no_empty": "{fieldCount} fields trouvΓ©s et aucun champ vide", + "dialog.checklist.count_fields.with_empty": "{fieldCount} fields trouvΓ©s et {emptyCount} champ(s) vide(s) sur {linkCount} lien(s)", + "dialog.checklist.count_fields.link_from_inside": "{count} liens trouvΓ©s depuis des portails sous fields", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " Γ  {order} par le lien ", + "dialog.common.commands": "Commandes", + "dialog.common.commands_short": "Cmds", + "dialog.common.delete": "Supprimer", + "dialog.common.name": "Nom", + "dialog.common.off": "Off", + "dialog.common.on": "On", + "dialog.common.owner": "PropriΓ©taire", + "dialog.common.zone_all": "Toutes les zones", + "dialog.firebase.setup": "Visitez {url} et cliquez sur le bouton pour autoriser les mises Γ  jour en direct. Vous devrez recharger l'IITC ensuite.", + "dialog.import.url": "Charger l’URL", + "dialog.import.success_message": "Importation terminΓ©e. {count} portails trouvΓ©s et {faked} faux portails utilisΓ©s. Veuillez utiliser la fonction d'Γ©change pour dΓ©placer les faux portails vers les vrais portails au mΓͺme endroit. Faire un zoom avant sur les portails 'Chargement' dans la liste de contrΓ΄le peut les forcer Γ  charger.", + "dialog.leave_team.text": "Si vous quittez {teamName} vous ne pouvez pas rejoindre Γ  moins que le propriΓ©taire vous rajoute.", + "dialog.leave_team.title": "Quitter : {teamName}", + "dialog.link_list.length": "Longueur", + "dialog.link_list.level": "Niv Min", + "dialog.merge.cancel_upload": "Annuler", + "dialog.merge.conflicts": "Conflits :", + "dialog.merge.local": "Copie locale", + "dialog.merge.server": "Copie du serveur", + "dialog.merge.zone": "Zone : {name}", + "dialog.merge.prop.assignedTo": "AssignΓ© :", + "dialog.merge.prop.comment": "Commentaire :", + "dialog.merge.prop.color": "CouleurΒ :", + "dialog.merge.prop.deltaminutes": "Delta :", + "dialog.merge.prop.fromPortal": "De :", + "dialog.merge.prop.hardness": "DifficultΓ© :", + "dialog.merge.prop.order": "Ordre :", + "dialog.merge.prop.state": "Γ‰tatΒ :", + "dialog.merge.prop.toPortal": "Vers :", + "dialog.merge.prop.zone": "Zone :", + "dialog.merge.prop.zone_points": "La forme a Γ©tΓ© modifiΓ©e", + "dialog.online_agents.actions": "Action", + "dialog.online_agents.last_seen": "DerniΓ¨re activitΓ©", + "dialog.online_agents.title": "Agents en ligne", + "dialog.op_settings.zones": "Zones", + "dialog.ops_list.background_disable": "Cacher en arriΓ¨re-plan", + "dialog.ops_list.background_enable": "Afficher en arriΓ¨re-plan", + "dialog.ops_list.download": "TΓ©lΓ©charger {opName}", + "dialog.ops_list.last_fetched": "DerniΓ¨re rΓ©cupΓ©ration : {date}", + "dialog.ops_list.local_change": "La version locale a Γ©tΓ© modifiΓ©e", + "dialog.ops_list.remote_change": "Modifications sur le serveur", + "dialog.ops_list.toggle_hide": "Afficher/Masquer", + "dialog.ops_list.unhide_ops": "DΓ©masquer tout", + "dialog.remove_agent.text": "Voulez-vous retirer {agentName} de {teamName}?", + "dialog.remove_agent.title": "Retirer : {agentName}", + "dialog.setcomment.portal_hardness": "DifficultΓ©", + "dialog.team_list.load_wd_keys": "Charger les clΓ©s W-D", + "dialog.team_list.share_wd_keys": "Partager les clΓ©s W-D", + "dialog.team_manage.join_link": "Lien pour rejoindre", + "dialog.team_manage.join_link.create": "CrΓ©er", + "dialog.team_manage.join_link.revoke": "RΓ©voquer", + "dialog.team_members.location": "Partage de position", + "dialog.team_members.wd_keys": "Partage de clΓ©s W-D", + "dialog.team_message": "Message d'Γ©quipe: Β« {message} Β» de {sender}", + "dialog.update_warning": "Wasabee est obsolΓ¨te. Veuillez mettre Γ  jour en utilisant votre gestionnaire de plugin ou en allant sur https://wasabee.rocks", + "dialog.zone_color.title": "Colorier la zone", + "dialog.zone_color.text": "Colorier tous les liens dans la zone {zoneName}", + "dialog.zones.color": "Couleur", + "dialog.zones.color_links": "Colorier les liens", + "dialog.zones.delete_zone_shape": "RΓ©initialiser la forme", + "dialog.zones.draw_zone_shape": "Dessiner la zone", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Terminer le dessin", + "dialog.zones.title": "Zones", "DRAW TOOLS FORMAT": "Format DrawTools", - "DT_FORMAT": "Format DrawTools", "DUPE_OP": "Dupliquer l'opΓ©ration", "END_PORT": "Portail de fin", "ExcludeMarker": "Exclure d'Auto-Draw/Mark", "EXPORT OP TITLE": "Exporter l'opΓ©ration", "EXPORT OP": "Exporter", - "EXPORT": "Exporter : ", + "EXPORT": "Exporter :", "FAKED": "Faux [{portalId}]", - "FAN_FIELD3": "Fan Field", - "FANFIELD TITLE": "Fanfield", - "FANFIELD": "Draw", - "FANFIELD2": "Draw Fan Field", - "FarmPortalMarker": "Farm", + "FANFIELD": "Tracer", + "FANFIELD2": "Fan Field", + "FarmPortalMarker": "Farmer", + "FLIP_FLOP_NAME": "Flip Flop", + "FLIP_FLOP_TITLE": "Flip Flop", + "FLIP_FLOP_DESC": "Γ€ partir d'une ancre, d'un ensemble de portails visibles et d'un nombre de SBUL, cherche un fanfield Γ  tirer depuis l'ancre par distance dΓ©croissante pour Γ©viter de rechercher les clΓ©s dans le carrousel.", + "FLIP_FLOP_INSTRUCTION": "SΓ©lectionner un portal, se placer dans la zone des portails cibles afin qu'ils soient visibles, puis presser Tracer. Une fois un fanfield trouvΓ©, vous pouvez trouver d'autres ancres compatibles pour des re-tirs consΓ©cutifs", + "FLIP_FLOP_FIND_ANCHORS": "Trouver d'autres ancres", "FROM_1-2": "depuis la base 1-2", "FROM_1-3": "depuis la base 1-3", "FROM_2-3": "depuis la base 2-3", "FROM_DEPTH": "depuis l'intΓ©rieur vers l'extΓ©rieur", "FROM_PORT": "Depuis le Portail", "GET DT": "RΓ©cupΓ©rer le dessin actuel", - "GET_DT_DRAW": "Importer une dessin de DrawTools", "GetKeyPortalMarker": "ClΓ©s", "GotoPortalMarker": "Aller Γ ", "H-GEN_INST": "Choisissez les 3 portails du field englobant, le nombre de couches et cliquez sur Draw.", "HF_DEEP_SEARCH": "Recherche exhaustive", - "HF_DRAW_BUTTON": "Draw", - "HF_DRAW_DEEP_BUTTON": "Draw with deep recursion", + "HF_DRAW_BUTTON": "Tracer", "HF_REDRAW_BUTTON": "Re-Draw", "HG": "Field homogΓ¨ne", "HOURS": "(il y a {hours} heures)", "HOW_TO_VIDS": "

Tuto:

", - "IMP_COMP": "Importation reussi. ", - "IMP_DT_OP": "Op Drawtools: ", - "IMP_NOPE": "Echec de l'importation", + "IMP_NOPE": "Echec de l'importation: {error}", "IMP_WAS_OP": "Importer les opΓ©rations Wasabee", "IMPORT_OP_SUCCESS": "Importer l'opΓ©ration : {opName} Reussi.", "IMPORT_OP_TITLE": "Importer l'opΓ©ration : {date}", @@ -139,9 +223,8 @@ "IMPOSSIBLE": "Impossible", "INGNAME_GID": "Pseudo Ingress ou Identifiants Google", "INPUT_DT_KEY_COUNT": "Entrer le nombre de clΓ©s dΓ©fensive", - "INPUT_SQUAD_NAME": "Entrer le nom de l'Γ©quipe", "INVALID REQUEST": "RequΓͺte invalide", - "IOS NEED FAKE UA": "You must set a 'Custom UserAgent for Webviews' in the IITC-Mobile settings or login will fail", + "IOS NEED FAKE UA": "Vous devez dΓ©finir un 'Custom UserAgent for Webviews' dans les options de IITC-Mobile pour que la connexion Γ  Wasabee fonctionne", "KEY_LIST2": "Liste des clΓ©es pour l'opΓ©ration : {opName}", "KEYS": "ClΓ©es", "KNOWN_BLOCK": "Liens bloquants connus : {opName}", @@ -150,9 +233,9 @@ "LANG": "Langue", "LEAVE": "Quitter", "LetDecayPortalAlert": "Γ€ decay", - "LINK ASSIGNMENT": "Assigner Γ ", + "LINK ASSIGNMENT": "Affecter le lien Γ  :", "LINK STATE PROMPT": "Statut du lien", - "LINK STATE": "Statut", + "LINK STATE": "DΓ©finir l'Γ©tat du lien :", "LINKS BUTTON TITLE": "Liens", "LINKS": "Liens", "LINKS2": "{portalName} : Liens ({outgoing}↑/{incoming}↓)", @@ -160,10 +243,8 @@ "LOADING": "[chargement]", "LOADING1": "Chargement: {portalGuid}", "LOC_PROC": "Emplacement traitΓ©", - "LOC_UPDATE": "Emplacement mis Γ  jour", - "LOCATION SUB": "Location registered", + "LOCATION SUB": "Position envoyΓ©e", "LOCFRMSER": "(Localement et sur le serveur)", - "LOG IN QUICK": "Log In (quick; for Android)", "LOG IN": "Connexion", "LOG_OUT": "DΓ©connexion", "MADRID_SET_1": "DΓ©finir la zone pour le multifield de base 2-3", @@ -171,17 +252,17 @@ "MADRID_SET_3": "DΓ©finir la zone pour le multifield de base 1-2", "MADRID_TITLE": "Madrid Protocol", "MADRID_WAS_TAKEN": "Madrid Protocol", - "MADRID": "Draw", + "MADRID": "Tracer", "MANAGE_TEAM": "GΓ©rer {teamName}", "MANAGE": "GΓ©rer", - "MARKER ASSIGNMENT": "Assigner Γ ", + "MARKER ASSIGNMENT": "Affecter le marqueur Γ  :", "MARKER LIST TITLE": "Liste des marqueurs", "MARKER LIST": "Marqueurs", "MARKER STATE PROMPT": "Statut du marqueur", - "MARKER STATE": "DΓ©finir le type de marqueur", + "MARKER STATE": "DΓ©finir l'Γ©tat du marqueur :", "MARKER_LIST": "Liste des marqueurs : {opName}", "MARKERS BUTTON TITLE": "Marqueurs", - "MAX_SPLITS": "Max Splits", + "MAX_SPLITS": "Nb Couches", "MAX": "Fan Field", "MeetAgentPortalMarker": "Rencontrer un agent", "MERGE ON UPDATE": "Fusion Γ  la mise Γ  jour d'une OP", @@ -189,17 +270,21 @@ "MERGE_CHANGES_MERGE": "RΓ©sultat aprΓ¨s fusion", "MERGE_CHANGES_REMOTE": "Changements sur le serveur", "MERGE_LOCAL": "Locale", - "MERGE_MESSAGE": "L'opΓ©ration \"{opName}\" a changΓ© localement ainsi que sur le serveur. Voulez vous fusionnΓ© vos modifications Γ  la version du serveur, ou utiliser la version du server ou bien conserver la version locale intacte ? (ou ne rien faire et laisser Γ§a Γ  plus tard)", + "MERGE_MESSAGE": "Les modifications locales et du serveur sont en conflit. Vous devez rΓ©soudre les conflits que Wasabee n'a pas rΓ©ussi Γ  rΓ©soudre lui-mΓͺme. SΓ©lectionnez la version Γ  conserver pour chaque conflit non rΓ©solu. Vous pouvez Γ©galement ignorer tous les conflits et utiliser la copie du serveur, ou vous pouvez simplement garder la copie locale intacte.", "MERGE_REBASE": "Fusion", "MERGE_REPLACE": "Remplacer", "MERGE_TITLE": "Fusion des versions locale et serveur", - "MIN_SRC_PORT_LVL": "Level minimum requis pour le portail source", - "MINUTES": "(il y a {minutes} minute(s))", + "MIN_SRC_PORT_LVL": "Niveau minimum requis pour le portail source", + "MINUTES": " (il y a {minutes} minute(s))", "MM": "Multimax", + "MM_BOTH_SIDE": "Utiliser les deux cΓ΄tΓ©s de la base", + "MM_INSERT_ORDER": "InsΓ©rer Γ  la fin", + "MM_SET_ALL_PORTALS": "Tous les portails visibles", + "MM_SET_ALL_KEYS": "Tous les marqueurs GetKey", + "MM_SET_KEYS_ZONE": "GetKey: {zoneName}", + "MM_SPINE": "Alignement", "MULTI_M_TITLE": "Dessiner le maximum de couches", - "MULTI_M": "Draw", - "MULTIMAX": "Multimax!", - "MULTIMAX2": "Multimax", + "MULTI_M": "Tracer", "MUST_NOT_BE_EMPTY": "Ne dois pas Γͺtre vide", "MY_CAP_ID": "ID de ma capsule", "MY_COUNT": "Mon nombre de clΓ©s", @@ -211,22 +296,21 @@ "NEW_WAS_SERVER": "Nouveau serveur Wasabee", "NEWOP BUTTON TITLE": "CrΓ©er une opΓ©ration", "NEWOP BUTTON": "+ Op", - "NO_DATA": "Pas de donnΓ©es", "NO_DT_ITEMS": "Pas de Draw dΓ©tectΓ©", "NO_LABEL": "Pas de nom donnΓ©", - "NO_PORT_SEL": "Aucun portail sΓ©lectionnΓ©", "NO_STOCK_INTEL": "Wasabee ne supporte pas les draws de l'intel stock.", "NO_TITLE": "Titre non dΓ©fini", - "NO": "Non", + "NO LONGER AVAILABLE": "Ressource supprimΓ©e du serveur : {error}", + "NO LONGER AVAILABLE SHORT": "Ressource supprimΓ©e du serveur", "NOT LOGGED IN SHORT": "DΓ©connectΓ©", "NOT LOGGED IN": "DΓ©connectΓ© : {error}", - "NOT_LOADED": "N'a pas chargΓ© entierement, essayer Γ  nouveau", + "NOT_LOADED": "N'a pas chargΓ© entiΓ¨rement, essayer Γ  nouveau.", "NOT_SET": "non dΓ©fini", "NTNAME": "Nom", - "OK": "OK", + "OK": "Ok", "ON_HAND": "En main", "ONION_WAS_TAKEN": "Oignon", - "ONION": "Draw", + "ONION": "Tracer", "ONLY_DT_IMP": "(Uniquement pour les imports de DrawTools)", "OP DELETED": "Operation supprimΓ©e du serveur: {opID}", "OP PERM DENIED": "Permission refusΓ©e pour l'opΓ©ration : {opID}", @@ -244,15 +328,14 @@ "OPS BUTTON": "Ops", "ORDER": "Ordre", "OtherPortalAlert": "Autre", - "PASTE_INSTRUCT": "Paste a Wasabee draw export here.\n\nWasabee cannot import the stock intel format.\n\nThere is experimental support for importing the IITC DrawTools format.\n\nBefore importing DrawTools format, preview the areas and make sure all the portals load so IITC has them cached. Any portals that are not pre-cached will be faked.\n\nYou will need to use the 'swap' feature to move anchors from the faked portals to the real portals (they should be in the correct location, just not associated with the portal.\n\nCached portals might not be properly named.", + "PASTE_INSTRUCT": "Coller un export de dessin Wasabee ici.\n\nWasabee ne peut pas importer le format Intel.\n\nIl existe un support expΓ©rimental pour importer le format IITC DrawTools.\n\nAvant d'importer le format DrawTools, prΓ©visualisez les zones et assurez-vous que tous les portails sont chargΓ©s de sorte que l'IITC les a mis en cache. Les portails utilisΓ©s qui ne sont pas mis en cache correspondront Γ  de faux portails.\n\nVous devrez utiliser la fonctionnalitΓ© 'swap' pour dΓ©placer les ancres des faux portails vers les vrais portails (ils devraient Γͺtre dans les bons emplacements, mais pas associΓ©s aux portails).\n\nLes portails mis en cache peuvent ne pas Γͺtre correctement nommΓ©s.", "pending": "En attente", - "PENDING": "En attente", + "PERM DENIED": "Permission refusΓ©e: {error}", + "PERM DENIED SHORT": "Permission refusΓ©e", "PERMS": "Permissions de {opName}", - "PICK_DEST_FIRST": "Vous devez d'abord sΓ©lectionner un portail de destination!", - "PICK_TAR_FIRST": "Vous devez d'abord sΓ©lectionner un portail cible!", - "PICK_TARGETDEST_Portals": "Please select target and destination portals first!", "PLEASE_SELECT_PORTAL": "Selectionner un portail", - "PORT_FAKE": "portails trouvΓ©s. ", + "popup.anchor.keys": "ClΓ©s : {onHand} / {required}", + "popup.marker.state_button": "DΓ©finir l'Γ©tat", "PORTAL KEY LIST": "ClΓ©s du portail {portalName}", "PORTAL_COUNT": "{count} portails", "PORTAL": "Portail", @@ -264,15 +347,13 @@ "QD TITLE": "Quick Draw", "QD TOGGLE MODE": "Changer de mode", "QDBASE": "Base", - "QDCANCEL": "Annuler le draw du field", "QDCONT": "Cliquez sur un portail pour faire un field", - "QDEND": "Click again on the same portal to finish drawing.", "QDNEXT": "Cliquez sur la seconde ancre", "QDSTART": "Cliquez sur la premiΓ¨re ancre", "READ_SHORT": "RO", "READ": "lire", "RechargePortalAlert": "Recharge", - "REFERENCE_TIME": "Reference Time: ", + "REFERENCE_TIME": "Temps de rΓ©fΓ©rence :", "REM_LOC_CP": "Supprimer la copie locale de {opName}", "REMOVE_TEAM_CONFIRM_LABEL": "Voulez vous vraiment supprimer {teamName} du serveur Wasabee ?", "REMOVE_TEAM_CONFIRM_TITLE": "supprimer l'Γ©quipe {teamName}", @@ -284,15 +365,13 @@ "RESET": "Reset", "REVERSE": "Inverser", "ROCKS_COM": "CommunautΓ© enl.rocks :", - "ROLE": "Role", + "ROLE": "RΓ΄le", "SAVELINKS TITLE": "Copie de liens", "SAVELINKS_DRAW": "Copier les liens", "SAVELINKS": "Copie de liens intel", "SECONDS": "(il y a {seconds} secondes)", - "SEL_PORT_FIRST": "Selectionnez d'abord les ancres !", "SEL_SB_ANCHOR": "SΓ©lectionner l'ancre.", "SEL_SB_ANCHOR2": "DΓ©zoomer en laissant charger les portails de la zone puis cliquer sur Draw.", - "SEL_SB_ANCHOR3": "Patience, cela peut prendre du temps", "SEL_SL_ANCHOR": "SΓ©lectionner le portail dont vous voulez copier les liens vers l'opΓ©ration courante.", "SEL_SRC_ANC2": "Selectionnez le portail source ET la seconde ancre", "SEL_SRC_PORT": "Selectionnez le portail source.", @@ -300,11 +379,10 @@ "SELECT_FAN_PORTALS": "Selectionner une ancre, le premier portail et le dernier portail du Fanfield. Le reste sera calculΓ© Γ  partir des portails visibles.", "SELECT_FAN_PORTALS2": "Attendez le chargement des portails et cliquer sur Draw.", "SELECT_INSTRUCTIONS": "Selectionner deux ancres, puis zoomer sur la zone contenant l'alignement.", - "SELECT_MADRID_INSTRUCTIONS": "Selectionner les trois zones contenant les alignements ainsi que le premier portail chacun des deux premiers alignements.", "SELECT_ONION_PORTALS": "Les couches sont construites de la plus petite Γ  la plus grande, avec au plus trois fields par portail en commenΓ§ant par le portal dΓ©fini, puis en utilisant les portails visibles.", "SELF SWAP": "Le portail selectionnΓ© est le mΓͺme. Selectionnez un autre portail.", "SEND ANALYTICS": "Envoyer des statistiques anonymes", - "SEND LOCATION": "Partager sa position", + "SEND LOCATION": "Partager sa position (uniquement lorsque l'IITC est au premier plan)", "SEND TARGET AGENT": "SΓ©lectionner l'agent cible.", "SEND TARGET CONFIRM": "Voulez vous signaler la cible {portalName} Γ  {agent} ?", "SEND TARGET": "Envoyer la cible", @@ -312,18 +390,19 @@ "SET_3_PORT": "SΓ©lectionner d'abord trois portails", "SET_COMMENT": "Entrer un commentaire", "SET_LCOMMENT": "Commentaires du liens", - "SET_LINK_COMMENT": "Entrer un commentaire pour le lien : ", - "SET_LINKS_ZONES": "Set Links to Zones ", - "SET_MARKER_COMMENT": "Entrer un commentaire pour le marqueur : ", + "SET_LINK_COMMENT": "Entrer un commentaire pour le lien :", + "SET_LINKS_ZONES": "Affecter les liens aux zones", + "SET_MARKER_COMMENT": "Entrer un commentaire pour le marqueur :", "SET_MARKER_TYPE_TITLE": "Changer le type de marqueur", - "SET_MARKERS_ZONES": "Set Markers to Zones", + "SET_MARKERS_ZONES": "Affecter les marqueurs aux zones", "SET_MCOMMENT": "Commentaire pour ce marqueur : {portalName}", "SET_NEW_OP": "Donner un nom Γ  cette nouvelle opΓ©ration", "SET_PCOMMENT": "Entrer un commentaire pour ce portail : {portalName}", "SET_PORT_COMMENT": "Entrer un commentaire pour ce portail", "SET_PORTAL_COMMENT": "Entrer un commentaire", "SET": "DΓ©finir", - "SETTINGS": "Parametres Wasabee", + "SETTINGS_TOOLBOX": "ParamΓ¨tres Wasabee", + "SETTINGS_TITLE": "ParamΓ¨tres avancΓ©s", "SKINS_AVAILABLE": "Il y a {count} thΓ¨mes disponibles.", "SKINS_BUTTON": "Choisir les thΓ¨mes", "SKINS_DESCRIPTION": "DΓ©placer les thΓ¨mes de la colonne de droite vers la colonne de gauche pour les activer. L'ordre permet de les combiner. Le thΓ¨me le plus bas est le dernier appliquΓ©.", @@ -332,12 +411,11 @@ "SKIP_CONFIRM_ENTITY": "Seulement les OP/Γ©quipes", "SKIP_CONFIRM_NEVER": "Tout", "SKIP_CONFIRM": "Demander confirmation pour", - "SOURCE_PORT": "Portail Source", - "SQUAD": "Squad", + "SOURCE_PORT": "Portail source", "STARBURST TITLE": "Starburst", - "STARBURST_DRAW": "Draw", + "STARBURST_DRAW": "Tracer", "STARBURST": "Starburst", - "START_PORT": "Start Portal", + "START_PORT": "Portail de dΓ©part", "STATE": "Etat", "SUPPORT_INSTRUCT": "Pour obtenir de l'aide rejoindre ce channel Telegram (en Anglais) The Wasabee User Telegram Channel", "SWAP PROMPT": "Voulez vous remplacer ", @@ -346,18 +424,31 @@ "SWAP": "DΓ©placer", "SYNC DONE": "TΓ©lΓ©chargement terminΓ©
Cliquez ICI pour obtenir des conseils, des astuces et de la documentation.", "SYNC": "Telecharger les opΓ©rations disponibles", - "TARDEST_DIFF": "La source et la cible doivent etre differentes.", "TARGET SENT": "Cible transmise", - "TEAM PERM DENIED": "Permission refusΓ©e pour l'Γ©quipe : {error}", "TEAM STATE": "Partage de position", "TEAM_CREATED": "Γ‰quipe {teamName} créée", "TEAM_NAME": "Nom d'Γ©quipe", "TEAM": "Γ‰quipe", "TEAMS BUTTON TITLE": "Liste des Γ©quipes", "TEAMS BUTTON": "Γ‰quipes", - "TITLE": "titre", "TO_PORT": "Vers le portail", - "TRAWL SKIP TILES": "Trawl Skip Tiles", + "toolbar.quick_delete.apply.text": "Appliquer", + "toolbar.quick_delete.apply.title": "Supprime les liens et marqueurs sΓ©lectionnΓ©s", + "toolbar.quick_delete.cancel.text": "Annuler", + "toolbar.quick_delete.cancel.title": "Annuler", + "toolbar.quick_delete.stop.text": "Stop", + "toolbar.quick_delete.stop.title": "Quitter le mode Suppression", + "toolbar.quick_delete.title": "Suppression Rapide", + "toolbar.quick_delete.tooltip.toggle_mode": "SΓ©lectionnez les Γ©lΓ©ments Γ  supprimer", + "toolbar.quick_delete.tooltip.quick_mode": "Cliquez pour supprimer", + "toolbar.quick_draw.tooltip.star_mode.anchor": "SΓ©lectionnez l'ancre de la Starburst", + "toolbar.quick_draw.tooltip.star_mode.portal": "Cliquez sur les autres portails", + "toolbar.quick_draw.tooltip.single_mode.first": "SΓ©lectionnez le premier portail", + "toolbar.quick_draw.tooltip.single_mode.next": "SΓ©lectionnez le portail suivant", + "toolbar.quick_draw.tooltip.portal_fail": "DonnΓ©es de portail incomplΓ¨tes, rΓ©essayez", + "toolbar.wasabee.settings": "Options", + "toolbox.teammates": "CoΓ©quipiers en ligne", + "TRAWL SKIP TILES": "Fouille: sauter des tuiles", "TRAWL TITLE": "Fouille des bloquants", "TRAWL WARNING": "Ceci va charger les tuiles de donnΓ©es sous les liens dessinΓ©s. C'est un processus lent.", "TRAWL_AUTOMARK": "Marquer automatiquement les portails aprΓ¨s la fouille.", @@ -370,19 +461,16 @@ "TYPE": "Type", "UNASSIGNED": "Non assignΓ©", "UNKNOWN": "Inconnu", - "UPDATE HOVER NOT CHANGED": "{opName} n'a pas changΓ© localement", "UPDATE HOVER": "Mettre Γ  jour {opName} sur le serveur", - "UPDATE PERM DENIED": "You do not have permission to update", + "UPDATE PERM DENIED": "Vous n'avez pas la permission de mettre Γ  jour", "UPDATE_CONFLICT_DESC": "L'opΓ©ration a Γ©tΓ© modifiΓ© sur le serveur depuis la derniΓ¨re synchronisation. Voulez-vous Γ©craser la version du serveur par la votre ?", "UPDATE_CONFLICT_TITLE": "Conflit avec le serveur", "UPDATE_COUNT": "Nombre mis un jour", "UPDATED": "Mise Γ  jour reussi", - "UpgradePortalAlert": "Upgrade", + "UpgradePortalAlert": "Upper", "UPLOAD BUTTON HOVER": "Envoyer {opName} au serveur", - "UPLOAD PERM DENIED": "Permission d'upload refusΓ©e", "UPLOADED": "Envoi reussi", - "USE PANES ON MOBILE": "Use panes (need reload)", - "USE_SWAP_INSTRUCT": " faux portails ajoutΓ©s. Utilisez la fonction de Swap pour placer les faux portails ceux existants (au mΓͺme positions). Zoomer sur les portails en chargement dans la checklist devrait permettre d'obtenir leurs informations manquantes.", + "USE PANES ON MOBILE": "Volet latΓ©ral (rechargement nΓ©cessaire)", "USE_VALID_NAME": "Utiliser un nom d'opΓ©ration valide", "UseVirusPortalAlert": "Virus", "VRLA DESC": "Le niveau nΓ©cessaire du portail peut Γͺtre plus faible en fonction du type des Link Amp utilisΓ©s.", @@ -391,40 +479,36 @@ "WASABEE_D_LIST": "Entrer le nombre de clΓ©s dΓ©fensive", "WD BUTTON TITLE": "Enregistrer des clΓ©s dΓ©fensives", "WD BUTTON": "ClΓ©s W-D", - "WEBVIEW": "Webview Login (iOS)", - "WEBVIEW": "Webview Log In (iOS)", "WRITE_SHORT": "RW", "WRITE": "modifier", "WSERVER": "Serveur: {url}", - "YES": "Oui", "YESNO_DEL": "Voulez vous vraiment supprimer {opName} ?", - "ZONE_DRAW": "Click to set the zone boundaries", + "ZONE_DRAW": "Cliquer pour dΓ©finir les limites de la zone", "ZONE": "Zone", "smallScreen": { "ADD_LINKS": "+ Liens", "ADD_MARKER": "+ Marqueur", "BLOCKER TITLE": "Bloquants", - "CHECKLIST BUTTON": "Check", + "CHECKLIST BUTTON": "Checklist", "CLEAROPS BUTTON": "Effacer", - "EXPORT OP": "Xport", - "FAN_FIELD3": "Fan", - "FANFIELD": "Draw", - "FANFIELD2": "Draw Fan Field", + "EXPORT OP": "Exporter", + "FANFIELD": "Tracer", + "FANFIELD2": "Fan Field", "KEYS": "ClΓ©s", "LOG IN": "Se connecter", "LOG_OUT": "Se dΓ©connecter", "MARKER LIST": "Marqueurs", "MARKERS BUTTON TITLE": "Marqueurs", - "MAX": "Fan", - "MM": "Multi", + "MAX": "Fan Field", + "MM": "MultiMax", "MULTI_M_TITLE": "Maximiser le nombre de couche", - "MULTI_M": "Draw", + "MULTI_M": "Tracer", "NEWOP BUTTON": "+ Op", "OPS BUTTON": "Ops", "QD END": "Fin", - "STARBURST_DRAW": "Draw", + "STARBURST_DRAW": "Tracer", "STARBURST": "Etoile", "TEAMS BUTTON": "Γ‰quipe", "WD BUTTON": "ClΓ©s W-D" } -} +} \ No newline at end of file diff --git a/src/code/translations/German.json b/src/code/translations/German.json new file mode 100644 index 000000000..81f9be093 --- /dev/null +++ b/src/code/translations/German.json @@ -0,0 +1,514 @@ +{ + "ABOUT_WASABEE": "Über Wasabee", + "acknowledged": "BestΓ€tigt", + "ADD LINK TITLE": "Dialog - Links hinzufΓΌgen", + "ADD MARKER TITLE": "Dialog - Markierung hinzufΓΌgen", + "ADD_AGENT": "FΓΌge Agent hinzu:", + "ADD_BL": "FΓΌge Portal zur Ankerkette hinzu:", + "ADD_BULK": "Bulk hinzufΓΌgen", + "ADD_BUTTON_LINKS": "Alle Links auf einmal hinzufΓΌgen.", + "ADD_LINKS": "FΓΌge Links hinzu", + "ADD_MARKER": "FΓΌge Markierung hinzu", + "ADD_NEW_OP": "FΓΌge Op hinzu", + "ADD_SUCC_INSTR": "Erfolgreich hinzugefΓΌgt", + "ADD_ZONE": "Zone hinzufΓΌgen", + "ADD": "HinzufΓΌgen", + "ADD1": "Ersten Link hinzufΓΌgen", + "ADD2": "Zweiten Link hinzufΓΌgen", + "AGENT_STATS": "Agent Stats", + "AGENT": "Agent", + "AGES": "vor langer Zeit", + "ALREADY_HAS_MARKER": "Dieses Portal hat bereits eine Markierung. Bitte wΓ€hle ein anderes Portal.", + "AMAZ_TEAM_NAME": "Toller Teamname", + "ANCHOR ASSIGNMENT": "Alle ausgehenden Links zuweisen an:", + "ANCHOR_GMAP": "Google Map", + "ANCHOR_PORTAL": "Anker Portal", + "ANCHOR_PORTAL2": "Anker Portal 2", + "ANCHOR_PORTAL3": "Anker Portal 3", + "ANCHOR1": "Anker 1", + "ANCHOR2": "Anker 2", + "ANCHOR3": "Anker 3", + "ANCHORS_AS_BOOKMARKS": "Anker als Lesezeichen", + "API_KEY": "Rocks API-SchlΓΌssel:", + "ASS_TO": "Zugewiesen an", + "ASSIGN LINK PROMPT": "Link zugewiesenen von: {portalName}", + "ASSIGN MARKER PROMPT": "Markierung zugewiesenen von: {portalName}", + "ASSIGN OUTBOUND PROMPT": "Alle ausgehenden Links zugewiesenen von: {portalName}", + "ASSIGN OUTBOUND": "Ordne ausgehende Links zu", + "ASSIGN": "Zuweisen", + "ASSIGNED_ONLY_SHORT": "nz", + "ASSIGNED_ONLY": "Nur zugewiesen", + "assigned": "Zugewiesen", + "AUTH INCOMPAT": "Du hast ein Plugin aktiviert welches inkompatibel zu Wasabee ist.", + "AUTH REQUIRED": "Authorisierung benΓΆtigt", + "AUTH TOKEN REJECTED": "Senden des Autorisierungcodes ist fehlgeschlagen: {error}", + "AUTH_SELECT_ACCOUNT": "Benutzerkonto auswΓ€hlen", + "AUTO_DRAWS": "Auto-draw", + "AUTODRAWS": "Wasabee Auto-draw Optionen", + "AUTODRAW_PORTALS_SET": "Portale", + "autodraw.common.draw_button": "Draw", + "autodraw.fanfield.result": "Fanfield hat {links} Links und {fields} Felder fΓΌr {ap} AP gefunden", + "autodraw.flipflop.result": "Flip flop: hat {count} Links gefunden", + "autodraw.homogeneous.missing_split": "Konnte {count} Teilungen nicht finden, versuche weniger Tiefe oder eine andere Region", + "autodraw.homogeneous.order": "Ordnung", + "autodraw.homogeneous.portals_required": "{count} erforderlich", + "autodraw.madrid.auto_determined": "Automatisch bestimmt", + "autodraw.madrid.balanced": "Ausgeglichen", + "autodraw.madrid.result": "Madrid hat {count} Ebenen gefunden", + "autodraw.multimax.result": "Multimax hat {count} Ebenen gefunden", + "autodraw.multimax.result_both_side": "Multimax hat {count1} und {count2} Ebenen gefunden", + "autodraw.onion.variant": "Option", + "autodraw.onion.variant.equilateral": "~Gleichseitig", + "autodraw.onion.variant.grow": "Los!", + "autodraw.onion.variant.balanced": "Perfekt ausgeglichen", + "AUTOLOAD_RATE": "Portaldetail-Anfragerate (ms)", + "AUTOLOAD": "Fehlende Portal-Details automatisch laden", + "AUTOMARK STOP": "Automatische Markierung gestoppt - Portale nicht vollstΓ€ndig geladen.", + "AUTOMARK": "Auto-Markieren", + "BAT_TOAD": "KampffrΓΆsche", + "BLOCKER LIST TITLE": "Zeige alle Blocker an", + "BLOCKER TITLE": "Blocker", + "CANCEL": "Abbrechen", + "CAPSULE": "Kapsel", + "CapturePortalMarker": "Capture", + "CHANGE SERVER PROMPT": "Neuer Wasabee Server", + "CHANGE SERVER": "Wechsle Server", + "CHANGE_WAS_SERVER": "Wechsle Wasabee Server", + "CHECKLIST BUTTON TITLE": "Checkliste Operationen", + "CHECKLIST BUTTON": "Checliste", + "CLEAR LINKS": "Links lΓΆschen", + "CLEAR MARKERS": "Markierung aufheben", + "CLEAR_EVERYTHING": "LΓΆsche Portale/Links/Marker fΓΌr aktuelle OP", + "CLEAROPS BUTTON TITLE": "LΓΆsche alle Wasabee Daten", + "CLEAROPS BUTTON": "LΓΆsche Wasabee Daten", + "CLEAROPS PROMPT": "Das wird alle Wasabee Daten LΓΆschen. Bei dem nΓ€chsten Sync wird alles wiederhergestellt.", + "CLOSE": "Schließen", + "COMMENT": "Kommentar", + "COMPLETED BY": "Abgeschlossen von {agentName}", + "completed": "Abgeschlossen", + "CON_DEL": "BestΓ€tige LΓΆschen: {opName}", + "COUNT": "Anzahl", + "CREATE_NEW_TEAM": "Erstelle neues Team", + "CreateLinkAlert": "Link", + "CUR_USER_INFO": "Aktuelle Nutzer Informationen", + "D_SHOW_LIST": "Defensive SchlΓΌssel eingeben", + "DEFAULT OP NAME": "Neue Operation: {date}", + "DELETE ANCHOR PROMPT": "MΓΆchtest du den Anker mit allen zugewiesenen Links lΓΆschen? :", + "DELETE ANCHOR TITLE": "Anker lΓΆschen", + "DELETE MARKER PROMPT": "MΓΆchtest du die Markierung lΓΆschen? :", + "DELETE MARKER TITLE": "Markierung lΓΆschen", + "DELETE_ANCHOR": "LΓΆschen", + "DELETE_LINK": "LΓΆschen", + "DELETE_OP": "LΓΆsche {opName}", + "DESCRIP_PLACEHOLD": "Beschreibung (optional)", + "DestroyPortalAlert": "ZerstΓΆren", + "dialog.about.download_mobile_app": "

Wasabee App:

", + "dialog.agent_comment.text": "Comment:", + "dialog.agent_comment.title": "Kommentar fΓΌr {agentName} einfΓΌgen", + "dialog.auth.ott.button": "Einmal-Token Login", + "dialog.auth.ott.text": "Holen Sie sich einen Token vom Wasabee Server, dann fΓΌgen Sie diesen hier ein", + "dialog.auth.ott.title": "Einmal-Token", + "dialog.blockers.clear_automark": "Automarkierung lΓΆschen", + "dialog.clear_all.text": "MΓΆchten Sie {opName} zurΓΌcksetzen?", + "dialog.clear_all.title": "Clear: {opName}", + "dialog.clear_links.text": "MΓΆchten Sie alle Links von {opName} entfernen?", + "dialog.clear_links.title": "Links lΓΆschen: {opName}", + "dialog.clear_markers.text": "MΓΆchten Sie alle Markierungen von {opName} entfernen?", + "dialog.clear_markers.title": "Clear Markers: {opName}", + "dialog.checklist.count_fields": "Count fields", + "dialog.checklist.count_fields.no_empty": "Found {fieldCount} fields and no empty field", + "dialog.checklist.count_fields.with_empty": "Found {fieldCount} fields and {emptyCount} empty field(s) on {linkCount} link(s)", + "dialog.checklist.count_fields.link_from_inside": "Found {count} links from covered portals", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " bei {order} per Link ", + "dialog.common.commands": "Befehle", + "dialog.common.commands_short": "Cmds", + "dialog.common.delete": "LΓΆschen", + "dialog.common.name": "Name", + "dialog.common.off": "Aus", + "dialog.common.on": "Ein", + "dialog.common.owner": "EigentΓΌmer", + "dialog.common.zone_all": "All", + "dialog.firebase.setup": "Besuche {url} und drΓΌcke den Button, um Live-Updates zu autorisieren. Du musst IITC spΓ€ter neu laden.", + "dialog.import.url": "Von URL befΓΌllen", + "dialog.import.success_message": "Import abgeschlossen. {count} Portale gefunden und {faked} gefΓ€lscht verwendet. Bitte nutze die Swap-Funktion, um gefΓ€lschte Portale zu den echten Portalen am gleichen Ort zu bewegen. Das Einzoomen der 'Laden'-Portale in der Checkliste kann sie zum Laden zwingen.", + "dialog.leave_team.text": "If you leave {teamName} you cannot rejoin unless the owner re-adds you.", + "dialog.leave_team.title": "Verlassen: {teamName}", + "dialog.link_list.length": "LΓ€nge", + "dialog.link_list.level": "Min Lvl", + "dialog.merge.cancel_upload": "Upload abbrechen", + "dialog.merge.conflicts": "Konflikte:", + "dialog.merge.local": "Lokale Kopie", + "dialog.merge.server": "Server-Kopie", + "dialog.merge.zone": "Zone: {name}", + "dialog.merge.prop.assignedTo": "Zuweisen:", + "dialog.merge.prop.comment": "Kommentar:", + "dialog.merge.prop.color": "Farbe:", + "dialog.merge.prop.deltaminutes": "Delta:", + "dialog.merge.prop.fromPortal": "Von:", + "dialog.merge.prop.hardness": "Schwiergkeitsgrad:", + "dialog.merge.prop.order": "Reihenfolge:", + "dialog.merge.prop.state": "Status:", + "dialog.merge.prop.toPortal": "Nach:", + "dialog.merge.prop.zone": "Zone:", + "dialog.merge.prop.zone_points": "Shape has changed", + "dialog.online_agents.actions": "Actions", + "dialog.online_agents.last_seen": "Zuletzt gesehen", + "dialog.online_agents.title": "Agenten online", + "dialog.op_settings.zones": "Zonen", + "dialog.ops_list.background_disable": "Disable background", + "dialog.ops_list.background_enable": "Im Hintergrund anzeigen", + "dialog.ops_list.download": "{opName} herunterladen", + "dialog.ops_list.last_fetched": "Zuletzt abgerufen: {date}", + "dialog.ops_list.local_change": "Local has changed", + "dialog.ops_list.remote_change": "Remote has changed", + "dialog.ops_list.toggle_hide": "Ein-/Ausblenden umschalten", + "dialog.ops_list.unhide_ops": "Alle OPs anzeigen", + "dialog.remove_agent.text": "MΓΆchten Sie {agentName} aus {teamName} entfernen?", + "dialog.remove_agent.title": "Remove: {agentName}", + "dialog.setcomment.portal_hardness": "Schwierigkeitsgrad", + "dialog.team_list.load_wd_keys": "W-D-SchlΓΌssel laden", + "dialog.team_list.share_wd_keys": "W-D SchlΓΌssel teilen", + "dialog.team_manage.join_link": "Beitrittslink", + "dialog.team_manage.join_link.create": "Erzeugen", + "dialog.team_manage.join_link.revoke": "Widerrufen", + "dialog.team_members.location": "Standort wird geteilt", + "dialog.team_members.wd_keys": "W-D SchlΓΌssel teilen", + "dialog.team_message": "TeamankΓΌndigung: β€ž{message}β€œ von {sender}", + "dialog.update_warning": "Wasabee ist veraltet. Bitte aktualisiere ΓΌber deinen Plugin Manager oder gehe zu https://wasabee.rocks", + "dialog.zone_color.title": "Zonenfarbe", + "dialog.zone_color.text": "Set the color of all links in zone {zoneName}", + "dialog.zones.color": "Farbe", + "dialog.zones.color_links": "Color links", + "dialog.zones.delete_zone_shape": "Reset the shape", + "dialog.zones.draw_zone_shape": "Draw the boundaries", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Stop drawing", + "dialog.zones.title": "Zonen", + "DRAW TOOLS FORMAT": "Draw Tools Format", + "DUPE_OP": "Dupliziere Operation", + "END_PORT": "Endportal", + "ExcludeMarker": "Von Auto-Draw/Markieren ausschließen", + "EXPORT OP TITLE": "Exportiere aktuelle Operation ", + "EXPORT OP": "Exportiere Op", + "EXPORT": "Exportieren:", + "FAKED": "Gefaked: [{portalId}]", + "FANFIELD": "FΓ€cherfeld!", + "FANFIELD2": "FΓ€cherfeld", + "FarmPortalMarker": "Farm", + "FLIP_FLOP_NAME": "Flip flop", + "FLIP_FLOP_TITLE": "Flip flop", + "FLIP_FLOP_DESC": "Findet fΓΌr einen gegebenen Anker, eine Reihe von sichtbaren Portalen und einer Anzahl von SBUL ein FΓ€cher-Feld, um Portale vom Anker in absteigender Reihenfolge (nach Distanz) anzulinken, um die Suche nach dem nΓ€chsten korrekten SchlΓΌssel zu vermeiden.", + "FLIP_FLOP_INSTRUCTION": "WΓ€hle ein Portal aus, zoome nach genug, um genug Portale zu sehen und klicke auf Zeichnen. Sobald ein FΓ€cher-Feld gefunden wurde, kannst du nach anderen Ankern fΓΌr einen darauf folgenden Wiederaufbau suchen", + "FLIP_FLOP_FIND_ANCHORS": "Finde andere Anker", + "FROM_1-2": "von Basis 1-2", + "FROM_1-3": "von Basis 1-3", + "FROM_2-3": "von Basis 2-3", + "FROM_DEPTH": "von innen heraus", + "FROM_PORT": "Von Portal", + "GET DT": "Existierenden DrawTools Draw erhalten", + "GetKeyPortalMarker": "SchlΓΌssel beziehen", + "GotoPortalMarker": "Gehe zu", + "H-GEN_INST": "Portale fΓΌr das Γ€ußere Layer festlegen. WΓ€hle die Anzahl der Aufteilungen. Klicke auf Zeichnen", + "HF_DEEP_SEARCH": "AusfΓΌhrliche Suche", + "HF_DRAW_BUTTON": "Zeichnen", + "HF_REDRAW_BUTTON": "Neu zeichnen", + "HG": "Homogenes Feld", + "HOURS": "vor ({hours} Stunden)", + "HOW_TO_VIDS": "

ErklΓ€rungsvideos:

", + "IMP_NOPE": "Import Fehlgeschlagen: {error}", + "IMP_WAS_OP": "Importiere Wasabee Operation", + "IMPORT_OP_SUCCESS": "Importierte Operation: {opName}. Erfolgreich.", + "IMPORT_OP_TITLE": "Importierte Op: {date}", + "IMPORT_OP": "Importiere Operation", + "IMPOSSIBLE": "UnmΓΆglich", + "INGNAME_GID": "Ingress name oder GoogleID", + "INPUT_DT_KEY_COUNT": "Eingabe defensiver SchlΓΌssel", + "INVALID REQUEST": "UngΓΌltige Anfrage", + "IOS NEED FAKE UA": "Du musst 'Custom UserAgent for Webviews' in den IITC-Mobile Einstellungen aktivieren der Login wird fehlgeschlagen", + "KEY_LIST2": "SchlΓΌsselliste: {opName}", + "KEYS": "SchlΓΌssel", + "KNOWN_BLOCK": "Bekannte Blocker: {opName}", + "LA DESC": "Ausgehend von der Anzahl und Typ von Link-Amps kΓΆnnte ein niedrigeres Portallevel ausreichen", + "LA": "L8+ einige LA", + "LANG": "Sprache", + "LEAVE": "Verlassen", + "LetDecayPortalAlert": "Decayen lassen", + "LINK ASSIGNMENT": "Link zuweisen an:", + "LINK STATE PROMPT": "Linkstatus", + "LINK STATE": "Linkstatus festlegen:", + "LINKS BUTTON TITLE": "Links", + "LINKS": "Links", + "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", + "LOAD PORTALS": "Portale laden", + "LOADING": "[laden]", + "LOADING1": "Lade: [{portalGuid}]", + "LOC_PROC": "Standort verarbeitet", + "LOCATION SUB": "Standort registriert", + "LOCFRMSER": " (lokal und vom Server)", + "LOG IN": "Einloggen", + "LOG_OUT": "Ausloggen", + "MADRID_SET_1": "WΓ€hle die Region fΓΌr den Baselink-Anker 2 zu Anker 3", + "MADRID_SET_2": "WΓ€hle die Region fΓΌr den Baselink-Anker 3 zu Anker 1", + "MADRID_SET_3": "WΓ€hle die Region fΓΌr den Baselink-Anker 1 zu Anker 2", + "MADRID_TITLE": "Madrid Protokoll", + "MADRID_WAS_TAKEN": "Madrid Protokoll", + "MADRID": "Zeichnen", + "MANAGE_TEAM": "Verwalten {teamName}", + "MANAGE": "Verwalten", + "MARKER ASSIGNMENT": "Marker zuweisen an:", + "MARKER LIST TITLE": "Liste der Markierungen", + "MARKER LIST": "Markierungen", + "MARKER STATE PROMPT": "Marker Status", + "MARKER STATE": "Marker-Status setzen:", + "MARKER_LIST": "Liste Makerierungen: {opName}", + "MARKERS BUTTON TITLE": "Markierungen", + "MAX_SPLITS": "Max. Aufteilungen", + "MAX": "FΓ€cherfeld", + "MeetAgentPortalMarker": "Treffe Agenten", + "MERGE ON UPDATE": "Beim Update zusammenfΓΌhren", + "MERGE_CHANGES_LOCAL": "Lokale Γ„nderungen", + "MERGE_CHANGES_MERGE": "Ergebnis zusammenfΓΌhren", + "MERGE_CHANGES_REMOTE": "Γ„nderungen Dritter", + "MERGE_LOCAL": "Lokal speichern", + "MERGE_MESSAGE": "It seems that {opName} has local changes. Do you want to merge your modifications with the server OP, replace the local version with the server version, or cancel?", + "MERGE_REBASE": "Rebase", + "MERGE_REPLACE": "Replace", + "MERGE_TITLE": "Lokal&Remote-OP zusammenfΓΌhren", + "MIN_SRC_PORT_LVL": "Minimaler benΓΆtigter Level im Ausgangsportal", + "MINUTES": "vor ({minutes} Minuten)", + "MM": "Maximale Feldanzahl", + "MM_BOTH_SIDE": "Benutze beide Basisseiten", + "MM_INSERT_ORDER": "Am Ende einfΓΌgen", + "MM_SET_ALL_PORTALS": "Alle sichtbaren Portale", + "MM_SET_ALL_KEYS": "All GetKey Markers", + "MM_SET_KEYS_ZONE": "GetKey: {zoneName}", + "MM_SPINE": "Spine", + "MULTI_M_TITLE": "Draw Max Layers", + "MULTI_M": "Maximale Feldanzahl", + "MUST_NOT_BE_EMPTY": "Darf nicht leer sein.", + "MY_CAP_ID": "Kapsel ID", + "MY_COUNT": "Meine Anzahl", + "NAME_REQ": "Name benΓΆtigt", + "NAME": "Name:", + "NEW_OP": "Neue Operation", + "NEW_TEAM_NAME": "Neuer Teamname", + "NEW_TEAM": "New Team", + "NEW_WAS_SERVER": "Neuer Wasabee Server", + "NEWOP BUTTON TITLE": "Neue Operation erstellen", + "NEWOP BUTTON": "Neue Op", + "NO_DT_ITEMS": "Keine DrawTools Daten erkannt", + "NO_LABEL": "No label set", + "NO_STOCK_INTEL": "Wasabee unterstΓΌtzt keine Standard Intel imports", + "NO_TITLE": "No title set", + "NO LONGER AVAILABLE": "Ressource vom Server entfernt: {error}", + "NO LONGER AVAILABLE SHORT": "Ressource vom Server entfernt", + "NOT LOGGED IN SHORT": "Nicht eingeloggt.", + "NOT LOGGED IN": "Nicht eingeloggt: {error}", + "NOT_LOADED": "Nicht vollstΓ€ndig geladen - bitte erneut probieren.", + "NOT_SET": "nicht gesetzt", + "NTNAME": "Name", + "OK": "OK", + "ON_HAND": "VerfΓΌgbar", + "ONION_WAS_TAKEN": "Zwiebel", + "ONION": "Zeichnen", + "ONLY_DT_IMP": " (nur fΓΌr DrawTools imports)", + "OP DELETED": "Operation vom Server entfernt: {opID}", + "OP PERM DENIED": "Keine Berechtigung fΓΌr Operation: {opID}", + "OP_BUTTON": "Operation", + "OP_CHECKLIST": "Operation Checkliste: {opName}", + "OP_NAME_UNSET": "Operationsname ist leer.", + "OP_PERMS": "OP-Berechtigungen", + "OP_SETTINGS_BUTTON": "OP βš™", + "OP_SETTINGS_TITLE": "Operationseinstellungen", + "OPEN_REQUEST": "[ΓΆffne Anfrage]", + "OPER_COLOR": "Operation Color:", + "OPER_NAME": "Operation Name:", + "OPERATIONS": "Operationen", + "OPS BUTTON TITLE": "Operationen", + "OPS BUTTON": "Ops", + "ORDER": "Reihenfolge", + "OtherPortalAlert": "Sonstiges", + "PASTE_INSTRUCT": "FΓΌge einen Wasabee Drawtools export hier ein.\n\nWasabee kann nicht mit dem Standard intel format umgehen.\n\nEs gibt einen Experimentellen Import vom IITC-DrawTools format.\n\n Vor dem Importieren bitte sicherstellen das alles geladen ist und die IITC es zwischengespeichert hat. Jedes nicht zwischengespeicherte Portal wird verfΓ€lscht. \n\nDu musst die 'Wechsel' Funktion verwenden um die verfΓ€lschten Portale zu korrigieren. (Sie sollten bereits an der richtigen Position sein - aber dem falschen Portal zugeordnet).", + "pending": "Ausstehend", + "PERM DENIED": "Keine Berechtigung: {error}", + "PERM DENIED SHORT": "Keine Berechtigung", + "PERMS": "{opName} Berechtigungen", + "PLEASE_SELECT_PORTAL": "Bitte wΓ€hle ein Portal", + "popup.anchor.keys": "SchlΓΌssel: {onHand} / {required}", + "popup.marker.state_button": "Status setzen", + "PORTAL KEY LIST": "SchlΓΌsselliste fΓΌr Portal {portalName}", + "PORTAL_COUNT": "{count} Portale", + "PORTAL": "Portal", + "QD BUTTON CHANGE COLOR": "Klicken, um die nΓ€chste Linkfarbe zu Γ€ndern", + "QD BUTTON END": "Klicken um das Feld zeichnen zu beenden", + "QD BUTTON TOGGLE MODE": "Klicken, um den Zeichenmodus zu Γ€ndern", + "QD CHANGE COLOR": "Farbe Γ€ndern", + "QD END": "Ende", + "QD TITLE": "Schnelle Layer Zeichnung", + "QD TOGGLE MODE": "Modus Γ€ndern", + "QDBASE": "Basis Link", + "QDCONT": "Klicke auf ein Portal der Kette.", + "QDNEXT": "Klicke auf das zweite Ankerportal.", + "QDSTART": "Klicke auf das erste Ankerportal.", + "READ_SHORT": "RO", + "READ": "lesen", + "RechargePortalAlert": "Aufladen", + "REFERENCE_TIME": "Reference Time:", + "REM_LOC_CP": "Lokale Kopie von {opName} entfernen", + "REMOVE_TEAM_CONFIRM_LABEL": "MΓΆchtest du {teamName} permanent vom Server entfernen?", + "REMOVE_TEAM_CONFIRM_TITLE": "Entferne Team {teamName}", + "REMOVE_TEAM": "Team entfernen:", + "REMOVE": "Entfernen", + "RENAME_TEAM": "Team umbenennen:", + "RENAME": "Umbenennen", + "REQUIRED": "BenΓΆtigt", + "RESET": "Reset", + "REVERSE": "Umkehren", + "ROCKS_COM": "enl.rocks community:", + "ROLE": "Rolle", + "SAVELINKS TITLE": "Links speichern", + "SAVELINKS_DRAW": "Links speichern", + "SAVELINKS": "Links speichern", + "SECONDS": "vor ({seconds} Sekunden)", + "SEL_SB_ANCHOR": "WΓ€hle einen Anker, Zomme in das Areal und fΓΌge es zum Starburst hinzu.", + "SEL_SB_ANCHOR2": "Zoomen Sie heraus. Stellen Sie sicher, dass Portale alle geladen sind, und klicken Sie dann auf zeichnen.", + "SEL_SL_ANCHOR": "Select the portal to save the links of. Click save links button and look at checklist.", + "SEL_SRC_ANC2": "Lege Quelle und Anker 2 fest", + "SEL_SRC_PORT": "WΓ€hle ein Quellportal", + "SELECT PORTAL": "Portal zum senden auswΓ€hlen", + "SELECT_FAN_PORTALS": "WΓ€hle ein Ankerportal, wΓ€hle ein Startportal und ein Endportal, danach zoome in die Gegend des FΓ€chers. Warte bis alle Portale geladen sind. DrΓΌcke anschließend den 'FΓ€cherfeld' Knopf.", + "SELECT_FAN_PORTALS2": "Warten Sie, bis alle Portale geladen wurden, und klicken Sie dann auf Zeichen.", + "SELECT_INSTRUCTIONS": "WΓ€hle zwei Ankerportale. Zoome in die Gegend der Portalkette - warte bis die Portale geladen sind und drΓΌcke den 'Maximale Feldanzahl' Knopf.", + "SELECT_ONION_PORTALS": "Layers build from the inside out. Zoom in to center and select starting portal, then zoom out to area.", + "SELF SWAP": "Du kannst das Portal nicht mit sich selbst tauschen - WΓ€hle ein anderes.", + "SEND ANALYTICS": "Anonymisierte Analysedaten senden", + "SEND LOCATION": "Share Location (only when IITC is in foreground)", + "SEND TARGET AGENT": "Select target recipient", + "SEND TARGET CONFIRM": "MΓΆchtest du {portalName} an {agent} senden?", + "SEND TARGET": "Sende Ziel", + "SEND_LOC": "Sende Standort", + "SET_3_PORT": "Bitte wΓ€hle zuerst drei Portale!", + "SET_COMMENT": "FΓΌge Kommentar hinzu", + "SET_LCOMMENT": "Setze Kommentar fΓΌr Link:", + "SET_LINK_COMMENT": "Set comment for link:", + "SET_LINKS_ZONES": "Set Links to Zones", + "SET_MARKER_COMMENT": "Set comment for marker on:", + "SET_MARKER_TYPE_TITLE": "Markierungstyp Γ€ndern", + "SET_MARKERS_ZONES": "Set Markers to Zones", + "SET_MCOMMENT": "Setze Kommentar fΓΌr Markierung: {portalName}", + "SET_NEW_OP": "Bitte gebe einen neuen Operationnamen ein", + "SET_PCOMMENT": "Setze Kommentar fΓΌr Portal: {portalName}", + "SET_PORT_COMMENT": "Set comment for portal:", + "SET_PORTAL_COMMENT": "Portalkommentar festlegen", + "SET": "setzen", + "SETTINGS_TOOLBOX": "Wasabee-Einstellungen", + "SETTINGS_TITLE": "Erweiterte Einstellungen", + "SKINS_AVAILABLE": "Es gibt {count} verfΓΌgbare Skins.", + "SKINS_BUTTON": "Skins konfigurieren", + "SKINS_DESCRIPTION": "VerfΓΌgbare Skins befinden sich in der rechten Spalte. Verschieben Sie Skins, die Sie verwenden mΓΆchten, auf die linke Spalte.", + "SKINS_MANAGE_TITLE": "Skins verwalten", + "SKIP_CONFIRM_ALWAYS": "Nie nachfragen (mit Vorsicht zu verwenden)", + "SKIP_CONFIRM_ENTITY": "Nur nach Team/Op fragen", + "SKIP_CONFIRM_NEVER": "Immer nachfragen", + "SKIP_CONFIRM": "BestΓ€tigung ΓΌberspringen", + "SOURCE_PORT": "Quellportal", + "STARBURST TITLE": "Starburst ", + "STARBURST_DRAW": "Zeichnen", + "STARBURST": "Linkstern", + "START_PORT": "Startportal", + "STATE": "Status", + "SUPPORT_INSTRUCT": "FΓΌr Hilfe trete bitte der Telegram Gruppe bei The Wasabee User Telegram Channel ", + "SWAP PROMPT": "MΓΆchtest du tauschen?:", + "SWAP TITLE": "Portale tauschen", + "SWAP WITH": " mit ", + "SWAP": "Wechseln", + "SYNC DONE": "Download abgeschlossen
Klicken Sie HIER für Hinweise, Tipps und Dokumentation.", + "SYNC": "Download verfügbarer Operationen", + "TARGET SENT": "Ziel gesendet", + "TEAM STATE": "Standort teilen", + "TEAM_CREATED": "Team {teamName} erstellt.", + "TEAM_NAME": "Team-Name", + "TEAM": "Team", + "TEAMS BUTTON TITLE": "Auflistung Wasabee Teams", + "TEAMS BUTTON": "Teams", + "TO_PORT": "zu Portal", + "toolbar.quick_delete.apply.text": "Übernehmen", + "toolbar.quick_delete.apply.title": "AusgewÀhlte Links/Marker lâschen", + "toolbar.quick_delete.cancel.text": "Abbrechen", + "toolbar.quick_delete.cancel.title": "Abbrechen", + "toolbar.quick_delete.stop.text": "Stoppen", + "toolbar.quick_delete.stop.title": "Lâschmodus beenden", + "toolbar.quick_delete.title": "Schnell-Lâschen", + "toolbar.quick_delete.tooltip.toggle_mode": "Auf Objekte klicken um diese zur Lâschung zu markieren", + "toolbar.quick_delete.tooltip.quick_mode": "Klicken Sie auf Objekte um diese sofort zu lâschen", + "toolbar.quick_draw.tooltip.star_mode.anchor": "WÀhlen Sie den Linkstern-Anker", + "toolbar.quick_draw.tooltip.star_mode.portal": "Ein Portal auswÀhlen", + "toolbar.quick_draw.tooltip.single_mode.first": "Erstes Portal anklicken", + "toolbar.quick_draw.tooltip.single_mode.next": "NÀchstes Portal anklicken", + "toolbar.quick_draw.tooltip.portal_fail": "Portaldaten nicht geladen, bitte versuchen Sie es erneut", + "toolbar.wasabee.settings": "Einstellungen", + "toolbox.teammates": "Teammitglieder online", + "TRAWL SKIP TILES": "Trawl Skip Tiles", + "TRAWL TITLE": "Trawl Lanes", + "TRAWL WARNING": "Dies wird die Daten alle Quadranten unter allen gezeichneten Links laden. Dies ist ein langsamer Prozess.", + "TRAWL_AUTOMARK": "Blocker nach Suche automatisch markieren", + "TRAWL_BULK_LOAD_WARNING": "Diese Methode lÀdt die Daten der Quadranten so schnell wie mâglich. Die Verwendung erfolgt auf eigene Gefahr.", + "TRAWL_BULK_LOAD": "Bulk Load Tile Data", + "TRAWL_CLEAR_MARKERS": "Clear virus/destroy markers before trawling", + "TRAWL_REMAINING": "Noch {count} Quadranten", + "TRAWL": "Suche nach Blockern", + "TRAWLING": "Suche die Linkschneisen nach Blockern ab, schließen Sie diesen Dialog um abzubrechen", + "TYPE": "Typ", + "UNASSIGNED": "Nicht zugewiesenen", + "UNKNOWN": "Unbekannt", + "UPDATE HOVER": "UPDATE {opName} auf dem Server", + "UPDATE PERM DENIED": "You do not have permission to update", + "UPDATE_CONFLICT_DESC": "The OP has been modified on server since last sync. Do you want to replace the server version by the current one?", + "UPDATE_CONFLICT_TITLE": "Konflikt mit Server gefunden", + "UPDATE_COUNT": "Aktualisiere Anzahl", + "UPDATED": "Erfolgreich aktualisiert", + "UpgradePortalAlert": "Upgrade", + "UPLOAD BUTTON HOVER": "UPLOAD {opName} (aktuell nicht auf dem Server)", + "UPLOADED": "Erfolgreich hochgeladen", + "USE PANES ON MOBILE": "Use panes (need reload)", + "USE_VALID_NAME": "Bitte verwende einen gültigen Operationsnamen", + "UseVirusPortalAlert": "Virus benutzen", + "VRLA DESC": "Ausgehend von der Anzahl und Typ von Link-Amps kânnte ein niedrigeres Portallevel ausreichen", + "VRLA": "L8+ einige VRLA", + "WASABEE BUTTON TITLE": "Wasabee: Es ist grün und bringt Schlümpfe zum heulen.", + "WASABEE_D_LIST": "Eingabe defensiver Schlüssel", + "WD BUTTON TITLE": "Speicher Verteidigungs Schlüssel", + "WD BUTTON": "W-D Schlüssel", + "WRITE_SHORT": "RW", + "WRITE": "schreiben", + "WSERVER": "Server: {url}", + "YESNO_DEL": "Bist du dir sicher das du {opName} lâschen willst?", + "ZONE_DRAW": "Click to set the zone boundaries", + "ZONE": "Zoniert", + "smallScreen": { + "ADD_LINKS": "+ Links", + "ADD_MARKER": "+ Markierungen", + "BLOCKER TITLE": "Blocker", + "CHECKLIST BUTTON": "Überprüfen", + "CLEAROPS BUTTON": "Lâschen", + "EXPORT OP": "Xport", + "FANFIELD": "Draw", + "FANFIELD2": "FÀcherfeld zeichnen", + "KEYS": "Schlüssel", + "LOG IN": "Einloggen", + "LOG_OUT": "Ausloggen", + "MARKER LIST": "Markierungen", + "MARKERS BUTTON TITLE": "Markierungen", + "MAX": "Fan", + "MM": "Multi", + "MULTI_M_TITLE": "Draw Max Layers", + "MULTI_M": "Zeichnen", + "NEWOP BUTTON": "Neue Op", + "OPS BUTTON": "OP wÀhlen", + "QD END": "Ende", + "STARBURST_DRAW": "Zeichnen", + "STARBURST": "Stern", + "TEAMS BUTTON": "Teams", + "WD BUTTON": "W-D Schlüssel" + } +} \ No newline at end of file diff --git a/src/code/translations/italian.json b/src/code/translations/Italian.json similarity index 56% rename from src/code/translations/italian.json rename to src/code/translations/Italian.json index 055f43a13..251993885 100644 --- a/src/code/translations/italian.json +++ b/src/code/translations/Italian.json @@ -1,17 +1,17 @@ { - "ABOUT WASABEE-IITC": "Info su Wasabee-IITC", "ABOUT_WASABEE": "Info su Wasabee", "acknowledged": "Ricevuto", "ADD LINK TITLE": "Aggiunta Link", "ADD MARKER TITLE": "Aggiunta Marker", - "ADD_AGENT": "Aggiungi Agente: ", - "ADD_BL": "Aggiungi Link all'indietro: ", + "ADD_AGENT": "Aggiungi Agente:", + "ADD_BL": "Aggiungi Link all'indietro:", + "ADD_BULK": "Aggiungi in blocco", "ADD_BUTTON_LINKS": "Aggiungi tutti i link assieme.", "ADD_LINKS": "Aggiungi Link", "ADD_MARKER": "+ Marker", "ADD_NEW_OP": "Aggiungi Nuova Op", - "ADD_SUCC_INSTR": "Aggiunto con successo, dovrà abilitare il team sul sito di Wasabee per apparire in questa lista", - "ADD_ZONE": "Add Zone", + "ADD_SUCC_INSTR": "Aggiunto con successo", + "ADD_ZONE": "Aggiungi Zona", "ADD": "Aggiungi", "ADD1": "Aggiungi primo link", "ADD2": "Aggiungi secondo link", @@ -20,38 +20,51 @@ "AGES": " (epoche fa)", "ALREADY_HAS_MARKER": "Questo portale ha già un marker. Scegli un altro portale.", "AMAZ_TEAM_NAME": "Fantastico Nome del Team.", - "ANCHOR ASSIGNMENT": " tutti i link a uscire", + "ANCHOR ASSIGNMENT": "Assegna tutti i link in uscita a:", "ANCHOR_GMAP": "Mappa Google", - "ANCHOR_PORTAL": "Portale Ancora ", + "ANCHOR_PORTAL": "Portale Ancora", "ANCHOR_PORTAL2": "Portale Ancora 2", "ANCHOR_PORTAL3": "Portale Ancora 3", - "ANCHOR1": "Ancora 1 ", - "ANCHOR2": "Ancora 2 ", - "ANCHOR3": "Ancora 3 ", + "ANCHOR1": "Ancora 1", + "ANCHOR2": "Ancora 2", + "ANCHOR3": "Ancora 3", "ANCHORS_AS_BOOKMARKS": "Ancore come bookmark", - "API_KEY": " chiave api: ", + "API_KEY": "Chiave API Rocks:", "ASS_TO": "Assegnato a", "ASSIGN LINK PROMPT": "Assegna link da: {portalName}", "ASSIGN MARKER PROMPT": "Assegna marker da: {portalName}", "ASSIGN OUTBOUND PROMPT": "Assegna tutti i link in uscita da: {portalName}", "ASSIGN OUTBOUND": "Assegna Link in uscita", "ASSIGN": "Assegna", - "ASSIGNED_ONLY_SHORT": "AO", + "ASSIGNED_ONLY_SHORT": "SA", "ASSIGNED_ONLY": "Solo Assegnati", "assigned": "Assegnato", - "ASSIGNED": "Assegnato", - "AUTH ANDROID": "Su Android, prova prima il login 'rapido'. Se fallisce, prova ad accedere con 'select_account'.", "AUTH INCOMPAT": "Hai attivato un plugin in TamperMonkey incompatibile con Wasabee", - "AUTH IOS": "Su iOS, usa 'Log In'. Se fallisce, prova 'Webview Log in'; poi premi 'Verify Webview' per completare il processo.", "AUTH REQUIRED": "Autenticazione Richiesta", "AUTH TOKEN REJECTED": "Invio token di autenticazione rifiutato: {error}", "AUTH_SELECT_ACCOUNT": "Seleziona account", - "AUTO_DRAWS": "Auto-draw", + "AUTO_DRAWS": "Auto-disegna", "AUTODRAWS": "Opzioni Wasabee Auto-draw", + "AUTODRAW_PORTALS_SET": "Portali", + "autodraw.common.draw_button": "Disegna", + "autodraw.fanfield.result": "Fanfield ha trovato {links} link e {fields} field per {ap} AP", + "autodraw.flipflop.result": "Flip flop: trovati {count} link", + "autodraw.homogeneous.missing_split": "Impossibile trovare {count} suddivisioni, prova meno profondità o una regione diversa", + "autodraw.homogeneous.order": "Ordina", + "autodraw.homogeneous.portals_required": "{count} richiesti", + "autodraw.madrid.auto_determined": "Auto-determinato", + "autodraw.madrid.balanced": "Bilanciato", + "autodraw.madrid.result": "Madrid ha trovato {count} strati", + "autodraw.multimax.result": "Multimax ha trovato {count} strati", + "autodraw.multimax.result_both_side": "Multimax ha trovato {count1} e {count2} strati", + "autodraw.onion.variant": "Alternativo", + "autodraw.onion.variant.equilateral": "~Equilatero", + "autodraw.onion.variant.grow": "Lascia che cresca", + "autodraw.onion.variant.balanced": "Perfettamente bilanciato", "AUTOLOAD_RATE": "Frequenza Richiesta dettagli Portali (ms)", "AUTOLOAD": "Carica Automaticamente Dettagli dei Portali Mancanti", "AUTOMARK STOP": "Auto-Mark interrotto, i portali non sono caricati", - "AUTOMARK": "Auto-Mark", + "AUTOMARK": "Auto-Segna", "BAT_TOAD": "Rospi da Battaglia", "BLOCKER LIST TITLE": "Mostra tutti i bloccanti", "BLOCKER TITLE": "Bloccanti", @@ -66,7 +79,6 @@ "CLEAR LINKS": "Elimina Link", "CLEAR MARKERS": "Elimina Marker", "CLEAR_EVERYTHING": "Elimina tutti i Portali/Link/Marker", - "CLEAR": "Deseleziona", "CLEAROPS BUTTON TITLE": "Elimina TUTTI i dati di Wasabee", "CLEAROPS BUTTON": "Elimina i dati di Wasabee", "CLEAROPS PROMPT": "Questo eliminerà tutte le OP e i dati relativi a Wasabee. Saranno ripristinati alla prossima sincronizzazione.", @@ -74,64 +86,136 @@ "COMMENT": "Commento", "COMPLETED BY": "Completato da {agentName}", "completed": "Completato", - "COMPLETED": "Completato", "CON_DEL": "Conferma eliminazione: {opName}", - "CONFIRM_DELETE": "Vuoi davvero eliminare questo link: ", "COUNT": "Conteggio", "CREATE_NEW_TEAM": "Crea Nuovo Team", "CreateLinkAlert": "Linkare", "CUR_USER_INFO": "Informazioni utente attuale", "D_SHOW_LIST": "Inserisci chiavi difensive", "DEFAULT OP NAME": "Nuova Op: {date}", - "DELETE ANCHOR PROMPT": "Vuoi eliminare quest'ancora e tutti i link associati: ", + "DELETE ANCHOR PROMPT": "Vuoi eliminare quest'ancora e tutti i link associati:", "DELETE ANCHOR TITLE": "Elimina Ancora", - "DELETE MARKER PROMPT": "Vuoi eliminare questo Marker: ", + "DELETE MARKER PROMPT": "Vuoi eliminare questo Marker:", "DELETE MARKER TITLE": "Elimina Marker", - "DELETE PERM DENIED": "Permesso di eliminare negato.", "DELETE_ANCHOR": "Elimina", "DELETE_LINK": "Elimina", - "DELETE_MARKER": "Elimina", "DELETE_OP": "Eliminare {opName}", - "DELETED": "Eliminato con successo.", "DESCRIP_PLACEHOLD": "Descrizione (facoltativo)", "DestroyPortalAlert": "Distruggere", - "DISABLE_SYNC": "Il plugin Sync stock non è compatibile con Wasabee. Per favore disabilita Sync.", - "DISABLED": "Questa funzione non è pronta per gli utenti", - "DONE": "Fatto", + "dialog.about.download_mobile_app": "

App Wasabee:

", + "dialog.agent_comment.text": "Comment:", + "dialog.agent_comment.title": "Imposta commento per {agentName}", + "dialog.auth.ott.button": "Login con One Time Token", + "dialog.auth.ott.text": "Ottieni un token dal Server Wasabee, quindi incollalo qui", + "dialog.auth.ott.title": "One Time Token", + "dialog.blockers.clear_automark": "Pulisci Automark", + "dialog.clear_all.text": "Vuoi resettare {opName}?", + "dialog.clear_all.title": "Pulisci: {opName}", + "dialog.clear_links.text": "Vuoi rimuovere tutti i link da {opName}?", + "dialog.clear_links.title": "Pulisci link: {opName}", + "dialog.clear_markers.text": "Vuoi rimuovere tutti i marker da {opName}?", + "dialog.clear_markers.title": "Clear Markers: {opName}", + "dialog.checklist.count_fields": "Conta field", + "dialog.checklist.count_fields.no_empty": "Trovati {fieldCount} field e nessun field vuoto", + "dialog.checklist.count_fields.with_empty": "Trovati {fieldCount} field e {emptyCount} field vuoti su {linkCount} link", + "dialog.checklist.count_fields.link_from_inside": "Trovati {count} link da portali coperti", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " a {order} tramite link ", + "dialog.common.commands": "Comandi", + "dialog.common.commands_short": "Cmd", + "dialog.common.delete": "Delete", + "dialog.common.name": "Nome", + "dialog.common.off": "Off", + "dialog.common.on": "On", + "dialog.common.owner": "Proprietario", + "dialog.common.zone_all": "Tutto", + "dialog.firebase.setup": "Visita {url} e premi il pulsante per autorizzare gli aggiornamenti live. Dovrai ricaricare IITC.", + "dialog.import.url": "Importa da URL", + "dialog.import.success_message": "Importazione completata. Trovati {count} portali e usati {faked} finti. Si prega di utilizzare la funzione di scambio per spostare i portali finti sui portali reali alla stessa posizione. Zoomando sui portali 'Caricamento' nella checklist potrebbe forzarne il caricamento.", + "dialog.leave_team.text": "Se lasci {teamName} non potrai ricollegarti a meno che il proprietario non ti aggiunga nuovamente.", + "dialog.leave_team.title": "Lascia: {teamName}", + "dialog.link_list.length": "Lunghezza", + "dialog.link_list.level": "Livello minimo", + "dialog.merge.cancel_upload": "Cancel upload", + "dialog.merge.conflicts": "Conflicts:", + "dialog.merge.local": "Local copy", + "dialog.merge.server": "Server copy", + "dialog.merge.zone": "Zone: {name}", + "dialog.merge.prop.assignedTo": "Assign:", + "dialog.merge.prop.comment": "Comment:", + "dialog.merge.prop.color": "Color:", + "dialog.merge.prop.deltaminutes": "Delta:", + "dialog.merge.prop.fromPortal": "From:", + "dialog.merge.prop.hardness": "Hard:", + "dialog.merge.prop.order": "Order:", + "dialog.merge.prop.state": "State:", + "dialog.merge.prop.toPortal": "To:", + "dialog.merge.prop.zone": "Zone:", + "dialog.merge.prop.zone_points": "Shape has changed", + "dialog.online_agents.actions": "Azioni", + "dialog.online_agents.last_seen": "Ultimo accesso", + "dialog.online_agents.title": "Agenti Online", + "dialog.op_settings.zones": "Zone", + "dialog.ops_list.background_disable": "Disabilita background", + "dialog.ops_list.background_enable": "Mostra in background", + "dialog.ops_list.download": "Scarica {opName}", + "dialog.ops_list.last_fetched": "Ultimo scarico: {date}", + "dialog.ops_list.local_change": "Locale modificato", + "dialog.ops_list.remote_change": "Remoto modificato", + "dialog.ops_list.toggle_hide": "Toggle Show/Hide", + "dialog.ops_list.unhide_ops": "Unhide all OPs", + "dialog.remove_agent.text": "Do you want to remove {agentName} from {teamName}?", + "dialog.remove_agent.title": "Remove: {agentName}", + "dialog.setcomment.portal_hardness": "Durezza", + "dialog.team_list.load_wd_keys": "Load W-D Keys", + "dialog.team_list.share_wd_keys": "Share W-D Keys", + "dialog.team_manage.join_link": "Join Link", + "dialog.team_manage.join_link.create": "Create", + "dialog.team_manage.join_link.revoke": "Revoke", + "dialog.team_members.location": "Sharing Location", + "dialog.team_members.wd_keys": "Sharing W-D Keys", + "dialog.team_message": "Team announcement: β€œ{message}” from {sender}", + "dialog.update_warning": "Wasabee is out of date. Please update using your plugin manager or by going to https://wasabee.rocks", + "dialog.zone_color.title": "Zone Color", + "dialog.zone_color.text": "Set the color of all links in zone {zoneName}", + "dialog.zones.color": "Color", + "dialog.zones.color_links": "Color links", + "dialog.zones.delete_zone_shape": "Reset the shape", + "dialog.zones.draw_zone_shape": "Draw the boundaries", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Stop drawing", + "dialog.zones.title": "Zones", "DRAW TOOLS FORMAT": "Formato Draw Tools", - "DT_FORMAT": "Formato Draw Tools", "DUPE_OP": "Duplica Operazione", "END_PORT": "Portale di fine ", "ExcludeMarker": "Escludi da Auto-Draw/Mark", "EXPORT OP TITLE": "Esporta Op attuale", "EXPORT OP": "Esporta Op", - "EXPORT": "Esporta: ", + "EXPORT": "Esporta:", "FAKED": "Simulato: [{portalId}]", - "FAN_FIELD3": "Fan Field", - "FANFIELD TITLE": "Fanfield", "FANFIELD": "Fanfield!", "FANFIELD2": "Fanfield", "FarmPortalMarker": "Farmare", + "FLIP_FLOP_NAME": "Flip flop", + "FLIP_FLOP_TITLE": "Flip flop", + "FLIP_FLOP_DESC": "Da una data ancora, un insieme di portali visibili e un certo numero di SBUL, trova un fanfield per tirare link dall'ancora diminuendo la distanza per evitare di cercare chiavi.", + "FLIP_FLOP_INSTRUCTION": "Seleziona un portale, zooma per vedere abbastanza portali e premi Disegna. Una volta trovato un fanfield, puoi cercare altre ancore per tiri successivi", + "FLIP_FLOP_FIND_ANCHORS": "Trova altre ancore", "FROM_1-2": "dalla base 1-2", "FROM_1-3": "dalla base 1-3", "FROM_2-3": "dalla base 2-3", "FROM_DEPTH": "dalla profonditΓ ", "FROM_PORT": "Portale di origine", "GET DT": "Usa disegno DrawTools esistente", - "GET_DT_DRAW": "Importa disegno DrawTools", "GetKeyPortalMarker": "Ottienere Chiavi", "GotoPortalMarker": "Andare A", "H-GEN_INST": "Seleziona Portali per lo strato esterno. Scegli il numero di split. Clicca Disegna", "HF_DEEP_SEARCH": "Ricerca esaustiva", "HF_DRAW_BUTTON": "Disegna", - "HF_DRAW_DEEP_BUTTON": "Disegna con ricorsione profonda", "HF_REDRAW_BUTTON": "Ridisegna", "HG": "Field Omogeneo", "HOURS": " ({hours} ore fa)", "HOW_TO_VIDS": "

Video tutorial:

", - "IMP_COMP": "Importazione Completata. Trovato ", - "IMP_DT_OP": "Importata Operazione Drawtools: ", - "IMP_NOPE": "Importazione Fallita.", + "IMP_NOPE": "Importazione Fallita: {error}", "IMP_WAS_OP": "Importa Operazione Wasabee", "IMPORT_OP_SUCCESS": "Importata Operazione: {opName} con successo.", "IMPORT_OP_TITLE": "Importa Op: {date}", @@ -139,7 +223,6 @@ "IMPOSSIBLE": "Impossibile", "INGNAME_GID": "Nome Ingress o GoogleID", "INPUT_DT_KEY_COUNT": "Inserisci numero Chiavi difensive", - "INPUT_SQUAD_NAME": "Inserisci un nome per la Squadra", "INVALID REQUEST": "Richiesta non valida", "IOS NEED FAKE UA": "Devi impostare un 'Custom UserAgent for Webviews' nelle impostazioni di IITC-Mobile o il login fallirΓ ", "KEY_LIST2": "Lista Chiavi per Operazione: {opName}", @@ -150,20 +233,18 @@ "LANG": "Lingua", "LEAVE": "Esci", "LetDecayPortalAlert": "Lasciare Decadere", - "LINK ASSIGNMENT": " Assegnamento Link", + "LINK ASSIGNMENT": "Assegna link a:", "LINK STATE PROMPT": "Stato Link", - "LINK STATE": "Imposta stato link", + "LINK STATE": "Imposta stato link:", "LINKS BUTTON TITLE": "Link", "LINKS": "Link", - "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", + "LINKS2": "{portalName} : Link ({outgoing}↑/{incoming}↓)", "LOAD PORTALS": "Carica Portali", "LOADING": "[caricamento]", "LOADING1": "Caricamento: [{portalGuid}]", "LOC_PROC": "posizione processata", - "LOC_UPDATE": "Aggiornamento posizione", "LOCATION SUB": "Posizione registrata", "LOCFRMSER": " (locale e dal server)", - "LOG IN QUICK": "Accedi (rapido; per Android)", "LOG IN": "Accedi", "LOG_OUT": "Logout", "MADRID_SET_1": "Seleziona l'area per la base da Ancora 2 a Ancora 3", @@ -174,21 +255,21 @@ "MADRID": "Disegna", "MANAGE_TEAM": "Gestisci {teamName}", "MANAGE": "Gestisci", - "MARKER ASSIGNMENT": " Assegnamento Marker", + "MARKER ASSIGNMENT": "Assegna marker a:", "MARKER LIST TITLE": "Lista Marker", "MARKER LIST": "Marker", "MARKER STATE PROMPT": "Stato Marker", - "MARKER STATE": " Imposta stato marker", + "MARKER STATE": "Imposta stato marker:", "MARKER_LIST": "Lista Marker: {opName}", "MARKERS BUTTON TITLE": "Marker", "MAX_SPLITS": "PiΓΉ Split possibili", "MAX": "Fan Field", "MeetAgentPortalMarker": "Incontrare Agente", - "MERGE ON UPDATE": "Merge on update", - "MERGE_CHANGES_LOCAL": "Local changes", - "MERGE_CHANGES_MERGE": "Merge result", - "MERGE_CHANGES_REMOTE": "Remote changes", - "MERGE_LOCAL": "Keep local", + "MERGE ON UPDATE": "Unisci all'aggiornamento", + "MERGE_CHANGES_LOCAL": "Modifiche locali", + "MERGE_CHANGES_MERGE": "Risultato unione", + "MERGE_CHANGES_REMOTE": "Modifiche remote", + "MERGE_LOCAL": "Mantieni in locale", "MERGE_MESSAGE": "It seems that {opName} has local changes. Do you want to merge your modifications with the server OP, replace the local version with the server version, or cancel?", "MERGE_REBASE": "Rebase", "MERGE_REPLACE": "Replace", @@ -196,28 +277,31 @@ "MIN_SRC_PORT_LVL": "Livello minimo richiesto sul portale d'origine", "MINUTES": " ({minutes} minuti fa)", "MM": "Multimax", + "MM_BOTH_SIDE": "Usa entrambi i lati della base", + "MM_INSERT_ORDER": "Inserisci alla fine", + "MM_SET_ALL_PORTALS": "Tutti i portali visibili", + "MM_SET_ALL_KEYS": "Tutti i Marker OttieniChiave", + "MM_SET_KEYS_ZONE": "OttieniChiave: {zoneName}", + "MM_SPINE": "Filotto", "MULTI_M_TITLE": "Disegna piΓΉ strati possibile", "MULTI_M": "Disegna", - "MULTIMAX": "Multimax!", - "MULTIMAX2": "Multimax", "MUST_NOT_BE_EMPTY": "Non puΓ² essere vuoto", "MY_CAP_ID": "ID Capsula", "MY_COUNT": "Conteggio", "NAME_REQ": "Nome Richiesto", - "NAME": "Nome: ", + "NAME": "Nome:", "NEW_OP": "Nuova Operazione", "NEW_TEAM_NAME": "Nuovo nome Team", "NEW_TEAM": "Clicca per creare un nuovo Team", "NEW_WAS_SERVER": "Nuovo Server Wasabee", "NEWOP BUTTON TITLE": "Crea una nuova Operazione", "NEWOP BUTTON": "Nuova Op", - "NO_DATA": "Dati mancanti", "NO_DT_ITEMS": "Disegni DrawTools non rilevati", "NO_LABEL": "Etichetta non impostata", - "NO_PORT_SEL": "Portale non selezionato.", "NO_STOCK_INTEL": "Wasabee non supporta importazioni di disegni dalla intel stock", "NO_TITLE": "Titolo non impostato", - "NO": "No", + "NO LONGER AVAILABLE": "Risorsa rimossa dal server: {error}", + "NO LONGER AVAILABLE SHORT": "Risorsa rimossa dal server", "NOT LOGGED IN SHORT": "Non loggato", "NOT LOGGED IN": "Non loggato: {error}", "NOT_LOADED": "Caricamento incompleto, riprova.", @@ -237,8 +321,8 @@ "OP_SETTINGS_BUTTON": "Op βš™", "OP_SETTINGS_TITLE": "Impostazioni Operazione", "OPEN_REQUEST": "[apri richiesta]", - "OPER_COLOR": "Colore Operazione: ", - "OPER_NAME": "Nome Operazione: ", + "OPER_COLOR": "Colore Operazione:", + "OPER_NAME": "Nome Operazione:", "OPERATIONS": "Operationi", "OPS BUTTON TITLE": "Operazioni", "OPS BUTTON": "Ops", @@ -246,53 +330,48 @@ "OtherPortalAlert": "Altro", "PASTE_INSTRUCT": "Incolla un disegno esportato da Wasabee qui.\n\nWasabee non puΓ² importare il formato intel stock.\n\nL'importazione di disegni in formato IITC DrawTools Γ¨ supportata in modo sperimentale.\n\nPrima di importare in formato DrawTools, controlla l'area e fai in modo che tutti i portali carichino, cosΓ¬ da essere nella cache di IITC. Ogni Portale non nella cache sarΓ  'finto'.\n\nDovrete usare la funzione 'swap' per spostare le ancore dai portali 'finti' a quelli veri (dovrebbero essere al posto giusto, solo non associate al Portale).\n\nI Portali nella cache potrebbero non avere il giusto nome.", "pending": "In corso", - "PENDING": "In corso", + "PERM DENIED": "Accesso negato: {error}", + "PERM DENIED SHORT": "Accesso negato", "PERMS": "{opName} permessi", - "PICK_DEST_FIRST": "Seleziona prima un Portale di destinazione!", - "PICK_TAR_FIRST": "Seleziona prima un portale target!", - "PICK_TARGETDEST_Portals": "Seleziona prima i Portali target e destinazione!", "PLEASE_SELECT_PORTAL": "Seleziona un portale", - "PORT_FAKE": " portali. Simulati ", + "popup.anchor.keys": "Keys: {onHand} / {required}", + "popup.marker.state_button": "Set State", "PORTAL KEY LIST": "Lista Chiavi per Portale: {portalName}", "PORTAL_COUNT": "{count} Portali", "PORTAL": "Portale", - "QD BUTTON CHANGE COLOR": "Click to change next links color", + "QD BUTTON CHANGE COLOR": "Clicca per cambiare il colore dei prossimi link", "QD BUTTON END": "Clicca per interrompere il disegno dei field", - "QD BUTTON TOGGLE MODE": "Click to change draw mode", - "QD CHANGE COLOR": "Change color", + "QD BUTTON TOGGLE MODE": "Clicca per cambiare la modalitΓ  di disegno", + "QD CHANGE COLOR": "Cambia colore", "QD END": "Fine", "QD TITLE": "Disegno Rapido Strati", - "QD TOGGLE MODE": "Change mode", + "QD TOGGLE MODE": "Cambia modalitΓ ", "QDBASE": "Link Base", - "QDCANCEL": "Annulla disegno Field", "QDCONT": "Clicca su un portale del filotto per disegnare un field.", - "QDEND": "Clicca di nuovo sullo stesso portale per terminare il disegno.", "QDNEXT": "Clicca il secondo Portale Ancora.", "QDSTART": "Clicca il primo Portale Ancora.", - "READ_SHORT": "RO", + "READ_SHORT": "SL", "READ": "Lettura", "RechargePortalAlert": "Ricaricare", - "REFERENCE_TIME": "Reference Time: ", + "REFERENCE_TIME": "Ora riferimento:", "REM_LOC_CP": "Elimina copia locale di {opName}", "REMOVE_TEAM_CONFIRM_LABEL": "Vuoi eliominare definitivamente {teamName} dal Server Wasabee?", "REMOVE_TEAM_CONFIRM_TITLE": "Elimina team {teamName}", - "REMOVE_TEAM": "Elimina Team: ", + "REMOVE_TEAM": "Elimina Team:", "REMOVE": "Elimina", - "RENAME_TEAM": "Rinomina Team: ", + "RENAME_TEAM": "Rinomina Team:", "RENAME": "Rinomina", "REQUIRED": "Richieste", "RESET": "Reset", "REVERSE": "Inverti", - "ROCKS_COM": "community enl.rocks: ", + "ROCKS_COM": "community enl.rocks:", "ROLE": "Ruolo", "SAVELINKS TITLE": "Salva Link", "SAVELINKS_DRAW": "Salva Link", "SAVELINKS": "Salva Link", "SECONDS": " ({seconds} secondi fa)", - "SEL_PORT_FIRST": "Seleziona un portale prima!", "SEL_SB_ANCHOR": "Imposta l'ancora.", "SEL_SB_ANCHOR2": "Zooma indietro. Assicurati che tutti i Portali siano caricati, poi clicca Disegna.", - "SEL_SB_ANCHOR3": "Sii paziente. Ci vorrΓ  un po'.", "SEL_SL_ANCHOR": "Seleziona il portale di cui salvare il link. Clicca il pulsante Salva Link e guarda la checklist.", "SEL_SRC_ANC2": "Seleziona Origine e Ancora 2", "SEL_SRC_PORT": "Seleziona un Portale di Origine", @@ -300,11 +379,10 @@ "SELECT_FAN_PORTALS": "Seleziona un'ancora, un Portale di inizio e uno di fine, poi zooma su un'area per il fanfield.", "SELECT_FAN_PORTALS2": "Aspetta che i Portali siano caricati, poi clicca Disegna.", "SELECT_INSTRUCTIONS": "Seleziona due ancore, poi zooma sul filotto", - "SELECT_MADRID_INSTRUCTIONS": "Seleziona tre Portali Ancora, zoomma sull'area vicino all'ancora selezionata, aspetta finchΓ¨ i portali siano caricati (devono essere sullo schermo per essere considerati) poi seleziona il pulsante 'imposta area filotto' per il link base corrispondente.", "SELECT_ONION_PORTALS": "Strati creati da dentro a fuori. Zooma sul centro e seleziona il portale di inizio, poi zooma indietro sull'area.", "SELF SWAP": "Non si puΓ² scambiare un portale con se stesso! Seleziona un altro portale.", "SEND ANALYTICS": "Invia dati di utilizzo anonimi", - "SEND LOCATION": "Invia posizione", + "SEND LOCATION": "Share Location (only when IITC is in foreground)", "SEND TARGET AGENT": "Seleziona destinatario target", "SEND TARGET CONFIRM": "Vuoi inviare il target {portalName} a {agent}?", "SEND TARGET": "Invia target", @@ -312,52 +390,65 @@ "SET_3_PORT": "Imposta prima i tre portali", "SET_COMMENT": "Imposta Commento", "SET_LCOMMENT": "Imposta commento Link", - "SET_LINK_COMMENT": "Imposta commento per il link: ", - "SET_LINKS_ZONES": "Set Links to Zones ", - "SET_MARKER_COMMENT": "Imposta commento per il marker su: ", + "SET_LINK_COMMENT": "Imposta commento per il link:", + "SET_LINKS_ZONES": "Imposta Link alle Zone", + "SET_MARKER_COMMENT": "Imposta commento per il marker su:", "SET_MARKER_TYPE_TITLE": "Cambia tipo marker", - "SET_MARKERS_ZONES": "Set Markers to Zones", + "SET_MARKERS_ZONES": "Imposta Marker alle Zone", "SET_MCOMMENT": "Imposta commento Marker: {portalName}", "SET_NEW_OP": "Impostare il nuovo Nome Operazione", "SET_PCOMMENT": "Imposta commento Portale: {portalName}", - "SET_PORT_COMMENT": "Imposta il commento per il Portale: ", + "SET_PORT_COMMENT": "Imposta il commento per il Portale:", "SET_PORTAL_COMMENT": "Imposta commento Portale", "SET": "impostato", - "SETTINGS": "Impostazioni Wasabee", + "SETTINGS_TOOLBOX": "Wasabee Settings", + "SETTINGS_TITLE": "Advanced Settings", "SKINS_AVAILABLE": "Sono disponibili {count} skin.", "SKINS_BUTTON": "Configura Skin", "SKINS_DESCRIPTION": "Gestisci le skin disponibili spostandole nella colonna di sinistra. Le skin piΓΉ in basso hanno prioritΓ  piΓΉ alta sulla UI.", "SKINS_MANAGE_TITLE": "Gestisci skin", - "SKIP_CONFIRM_ALWAYS": "Never ask (use with caution)", - "SKIP_CONFIRM_ENTITY": "Only ask for team/op", - "SKIP_CONFIRM_NEVER": "Always ask", - "SKIP_CONFIRM": "Skip confirmation", - "SOURCE_PORT": "Portale di Origine ", - "SQUAD": "Squadra", + "SKIP_CONFIRM_ALWAYS": "Non chiedere mai (usare con cautela)", + "SKIP_CONFIRM_ENTITY": "Chiedi solo per squadra/op", + "SKIP_CONFIRM_NEVER": "Chiedi sempre", + "SKIP_CONFIRM": "Salta conferma", + "SOURCE_PORT": "Portale di Origine", "STARBURST TITLE": "Starburst ", "STARBURST_DRAW": "Disegna", "STARBURST": "Starburst", "START_PORT": "Portale di Partenza ", "STATE": "Stato", "SUPPORT_INSTRUCT": "Per assistenza, entrate nel Canale Telegram per Utenti di Wasabee", - "SWAP PROMPT": "Vuoi scambiare: ", + "SWAP PROMPT": "Vuoi scambiare:", "SWAP TITLE": "Scambia portali", "SWAP WITH": " con ", "SWAP": "Scambia", "SYNC DONE": "Download Completato
Fare clic QUI per suggerimenti, suggerimenti e documentazione.", "SYNC": "Scarica Operazioni disponibili", - "TARDEST_DIFF": "I Portali Target e Destinazione devono essere diversi.", "TARGET SENT": "Target inviato", - "TEAM PERM DENIED": "Accesso negato al team: {error}", "TEAM STATE": "Condividi Posizione", "TEAM_CREATED": "Team {teamName} creato", "TEAM_NAME": "Nome Team", - "TEAM": "Team", + "TEAM": "Squadra", "TEAMS BUTTON TITLE": "Lista Team Wasabee", "TEAMS BUTTON": "Team", - "TITLE": "titolo", "TO_PORT": "Al Portale", - "TRAWL SKIP TILES": "Trawl Skip Tiles", + "toolbar.quick_delete.apply.text": "Applica", + "toolbar.quick_delete.apply.title": "Elimina link/marker selezionati", + "toolbar.quick_delete.cancel.text": "Annulla", + "toolbar.quick_delete.cancel.title": "Annulla", + "toolbar.quick_delete.stop.text": "Stop", + "toolbar.quick_delete.stop.title": "Esci dalla modalitΓ  eliminazione", + "toolbar.quick_delete.title": "Eliminazione rapida", + "toolbar.quick_delete.tooltip.toggle_mode": "Clicca sugli oggetti per segnarli \"da eliminare\"", + "toolbar.quick_delete.tooltip.quick_mode": "Clicca sugli oggetti per eliminarli", + "toolbar.quick_draw.tooltip.star_mode.anchor": "Seleziona l'ancora della star", + "toolbar.quick_draw.tooltip.star_mode.portal": "Seleziona un portale", + "toolbar.quick_draw.tooltip.single_mode.first": "Clicca il primo portale", + "toolbar.quick_draw.tooltip.single_mode.next": "Clicca il portale successivo", + "toolbar.quick_draw.tooltip.portal_fail": "Dati portale non caricati, riprova", + "toolbar.wasabee.settings": "Settings", + "toolbox.teammates": "Teammates Online", + "TRAWL SKIP TILES": "Salta tile durante controllo", "TRAWL TITLE": "Controllo corridoi", "TRAWL WARNING": "Verranno caricati i dati delle tile sotto i link disegnati. SarΓ  un processo lento.", "TRAWL_AUTOMARK": "Auto-mark dei bloccanti dopo controllo", @@ -370,19 +461,16 @@ "TYPE": "Tipo", "UNASSIGNED": "Non Assegnato", "UNKNOWN": "Sconosciuto", - "UPDATE HOVER NOT CHANGED": "{opName} non modificato localmente", "UPDATE HOVER": "AGGIORNA {opName} sul server", - "UPDATE PERM DENIED": "You do not have permission to update", + "UPDATE PERM DENIED": "Non hai il permesso di aggiornare", "UPDATE_CONFLICT_DESC": "L'OP Γ¨ stata modificata sul server dopo la tua ultima sincronizzazione. Vuoi sostituire la versione sul server con la attuale?", "UPDATE_CONFLICT_TITLE": "Rilevato conflitto con il server", "UPDATE_COUNT": "Aggiorna conteggio", "UPDATED": "Aggiornato con successo", "UpgradePortalAlert": "Upgradare", "UPLOAD BUTTON HOVER": "CARICA {opName} (al momento non sul server)", - "UPLOAD PERM DENIED": "Accesso negato all'upload", "UPLOADED": "Caricato con successo", - "USE PANES ON MOBILE": "Use panes (need reload)", - "USE_SWAP_INSTRUCT": ". Usare la funzione Scambio per spostare i Portali finti sui Portali veri nella stessa posizione. Zoomare sui Portali 'in caricamento' nella checklist potrebbe forzarli al caricamento.", + "USE PANES ON MOBILE": "Usa riquadri (richiede reload)", "USE_VALID_NAME": "Usa un nome operazione valido", "UseVirusPortalAlert": "Usare Virus", "VRLA DESC": "In base al tipo e al numero di Link Amp usati, potrebbe bastare un portale di origine di livello piΓΉ basso.", @@ -391,40 +479,36 @@ "WASABEE_D_LIST": "Inserisci numero chiavi difensive", "WD BUTTON TITLE": "Registra chiavi difensive", "WD BUTTON": "Chiavi W-D", - "WEBVIEW VERIFY": "Verifica Webview", - "WEBVIEW": "Log In Webview (iOS)", - "WRITE_SHORT": "RW", + "WRITE_SHORT": "LS", "WRITE": "scrittura", "WSERVER": "Server: {url}", - "YES": "SΓ¬", "YESNO_DEL": "Sei sicuro di voler eliminare {opName}?", - "ZONE_DRAW": "Click to set the zone boundaries", + "ZONE_DRAW": "Clicca per impostare i confini della zona", "ZONE": "Area", "smallScreen": { - "ADD_LINKS": "+ Links", + "ADD_LINKS": "+ Link", "ADD_MARKER": "+ Marker", - "BLOCKER TITLE": "Blockers", - "CHECKLIST BUTTON": "Check", - "CLEAROPS BUTTON": "Clear", - "EXPORT OP": "Xport", - "FAN_FIELD3": "Fan", - "FANFIELD": "Draw", - "FANFIELD2": "Draw Fan Field", - "KEYS": "Keys", - "LOG IN": "Log In", - "LOG_OUT": "Log Out", - "MARKER LIST": "Markers", - "MARKERS BUTTON TITLE": "Markers", + "BLOCKER TITLE": "Bloccanti", + "CHECKLIST BUTTON": "Spunta", + "CLEAROPS BUTTON": "Svuota", + "EXPORT OP": "Esporta", + "FANFIELD": "Disegna", + "FANFIELD2": "Disegna Fan Field", + "KEYS": "Chiavi", + "LOG IN": "Accedi", + "LOG_OUT": "Esci", + "MARKER LIST": "Marker", + "MARKERS BUTTON TITLE": "Marker", "MAX": "Fan", "MM": "Multi", - "MULTI_M_TITLE": "Draw Max Layers", - "MULTI_M": "Draw", - "NEWOP BUTTON": "New Op", - "OPS BUTTON": "Select OP", - "QD END": "End", - "STARBURST_DRAW": "Draw", + "MULTI_M_TITLE": "Disegna piΓΉ strati possibile", + "MULTI_M": "Disegna", + "NEWOP BUTTON": "Nuova Op", + "OPS BUTTON": "Seleziona OP", + "QD END": "Fine", + "STARBURST_DRAW": "Disegna", "STARBURST": "Star", - "TEAMS BUTTON": "Teams", - "WD BUTTON": "W-D Keys" + "TEAMS BUTTON": "Squadre", + "WD BUTTON": "Chiavi W-D" } -} +} \ No newline at end of file diff --git a/src/code/translations/Portuguese.json b/src/code/translations/Portuguese.json new file mode 100644 index 000000000..28526bfb2 --- /dev/null +++ b/src/code/translations/Portuguese.json @@ -0,0 +1,514 @@ +{ + "ABOUT_WASABEE": "Sobre Wasabee", + "acknowledged": "Reconhecido", + "ADD LINK TITLE": "Adicionar Links", + "ADD MARKER TITLE": "Adicionar Marcadores", + "ADD_AGENT": "Adicionar Agente:", + "ADD_BL": "Adicionar links para trΓ‘s:", + "ADD_BULK": "Adição em massa", + "ADD_BUTTON_LINKS": "Adicionar todos os links de uma vez.", + "ADD_LINKS": "Adicionar Links", + "ADD_MARKER": "+ Marcador", + "ADD_NEW_OP": "Adicionar Nova Op", + "ADD_SUCC_INSTR": "Agente adicionado com sucesso", + "ADD_ZONE": "Adicionar zona", + "ADD": "Adicionar", + "ADD1": "Adicionar primeiro link", + "ADD2": "Adicionar segundo link", + "AGENT_STATS": "Agente Stats", + "AGENT": "Agente", + "AGES": " (hΓ‘ muito tempo)", + "ALREADY_HAS_MARKER": "Este portal jΓ‘ tem um marcador. Escolha um portal diferente.", + "AMAZ_TEAM_NAME": "Nome incrΓ­vel da equipe.", + "ANCHOR ASSIGNMENT": "Atribuir todos os links de saΓ­da para:", + "ANCHOR_GMAP": "Mapa Google", + "ANCHOR_PORTAL": "Portal Γ‚ncora", + "ANCHOR_PORTAL2": "Γ‚ncora Portal 2", + "ANCHOR_PORTAL3": "Γ‚ncora Portal 3", + "ANCHOR1": "Γ‚ncora 1", + "ANCHOR2": "Γ‚ncora 2", + "ANCHOR3": "Γ‚ncora 3", + "ANCHORS_AS_BOOKMARKS": "Γ‚ncora como bookmarks", + "API_KEY": "Chave API do Rocks:", + "ASS_TO": "Atrubuir a:", + "ASSIGN LINK PROMPT": "Atribuir link para: {portalName}", + "ASSIGN MARKER PROMPT": "Atrubuir marcador para: {portalName}", + "ASSIGN OUTBOUND PROMPT": "Atribuir todos os links externos de: {portalName}", + "ASSIGN OUTBOUND": "Atribuir links externos", + "ASSIGN": "Atribuir", + "ASSIGNED_ONLY_SHORT": "A", + "ASSIGNED_ONLY": "SΓ³ Atribuir", + "assigned": "AtribuΓ­do", + "AUTH INCOMPAT": "VocΓͺ ativou um plugin no TamperMonkey que Γ© incompatΓ­vel com o Wasabee", + "AUTH REQUIRED": "Autentificação Requerida", + "AUTH TOKEN REJECTED": "Envio de token de autenticação rejeitado pelo servidor: {error}", + "AUTH_SELECT_ACCOUNT": "Selecionar conta", + "AUTO_DRAWS": "Auto-desenhar", + "AUTODRAWS": "Wasabee Auto-draw Opçáes", + "AUTODRAW_PORTALS_SET": "Portais", + "autodraw.common.draw_button": "Desenhar", + "autodraw.fanfield.result": "Fanfield encontrado {links} links e {fields} campos para {ap} AP", + "autodraw.flipflop.result": "Flip flop: {count} links encontrados", + "autodraw.homogeneous.missing_split": "NΓ£o foi possΓ­vel encontrar {count} divisΓ΅es, tente menos profundidade ou uma regiΓ£o diferente", + "autodraw.homogeneous.order": "Pedido", + "autodraw.homogeneous.portals_required": "{count} necessΓ‘rio", + "autodraw.madrid.auto_determined": "Auto-determinado", + "autodraw.madrid.balanced": "Equilibrado", + "autodraw.madrid.result": "Madri encontrou {count} camadas", + "autodraw.multimax.result": "Multimax encontrou {count} camadas", + "autodraw.multimax.result_both_side": "Multimax encontrou {count1} e {count2} camadas", + "autodraw.onion.variant": "Opção", + "autodraw.onion.variant.equilateral": "~Equalizador", + "autodraw.onion.variant.grow": "Deixe crescer", + "autodraw.onion.variant.balanced": "Perfeitamente equilibrado", + "AUTOLOAD_RATE": "Taxa de solicitação de detalhes do portal (ms)", + "AUTOLOAD": "Carregar automaticamente os detalhes do portal em falta", + "AUTOMARK STOP": "Auto-Marcar interrompido devido a portais nΓ£o serem carregados", + "AUTOMARK": "Auto-Marcar", + "BAT_TOAD": "Brinquedos de batalha", + "BLOCKER LIST TITLE": "Mostrar todos os blockers", + "BLOCKER TITLE": "Bloqueadores", + "CANCEL": "Cancelar", + "CAPSULE": "Capsula", + "CapturePortalMarker": "Capturado", + "CHANGE SERVER PROMPT": "Novo servidro Wasabee", + "CHANGE SERVER": "Trocar de Servidor", + "CHANGE_WAS_SERVER": "Mudar servidor Wasabee", + "CHECKLIST BUTTON TITLE": "Checklist da Operação", + "CHECKLIST BUTTON": "Checklist", + "CLEAR LINKS": "Limpar Links", + "CLEAR MARKERS": "Limpar Markers", + "CLEAR_EVERYTHING": "limpar Portais/Links/Marcadores", + "CLEAROPS BUTTON TITLE": "limpar TODOS os dados Wasabee", + "CLEAROPS BUTTON": "Limpar dados Wasabee", + "CLEAROPS PROMPT": "Isto limparΓ‘ todas as OPS e dados relacionados a Wasabee. Tudo serΓ‘ restaurado apartir do servidor na prΓ³xima sincronização.", + "CLOSE": "Perto", + "COMMENT": "Comentario", + "COMPLETED BY": "Completo por {agentName}", + "completed": "Completo", + "CON_DEL": "Confirmar Apagar: {opName}", + "COUNT": "Contar", + "CREATE_NEW_TEAM": "Criar Nova Equipa", + "CreateLinkAlert": "Link", + "CUR_USER_INFO": "Informaçáes do usuΓ‘rio atual", + "D_SHOW_LIST": "Chaves de defesa de entrada", + "DEFAULT OP NAME": "Nova Op: {date}", + "DELETE ANCHOR PROMPT": "Desejas excluir esta Γ’ncora e todos os links associados:", + "DELETE ANCHOR TITLE": "Apagar Γ‚ncora", + "DELETE MARKER PROMPT": "VocΓͺ deseja excluir este marcador:", + "DELETE MARKER TITLE": "Apagar Marcador", + "DELETE_ANCHOR": "Apagar", + "DELETE_LINK": "Apagar", + "DELETE_OP": "Apagar {opName}", + "DESCRIP_PLACEHOLD": "Descrição (opcional)", + "DestroyPortalAlert": "Destroir", + "dialog.about.download_mobile_app": "

Aplicativo Wasabee:

", + "dialog.agent_comment.text": "Comentario:", + "dialog.agent_comment.title": "Definir comentΓ‘rio para {agentName}", + "dialog.auth.ott.button": "Login ΓΊnico para o Token", + "dialog.auth.ott.text": "Obtenha um token do servidor Wasabee, e entΓ£o cole-o aqui", + "dialog.auth.ott.title": "Usar Token Único", + "dialog.blockers.clear_automark": "Limpar Automark", + "dialog.clear_all.text": "VocΓͺ quer resetar o {opName}?", + "dialog.clear_all.title": "Limpar: {opName}", + "dialog.clear_links.text": "VocΓͺ quer remover todos os links de {opName}?", + "dialog.clear_links.title": "Limpar Links: {opName}", + "dialog.clear_markers.text": "Deseja remover todos os marcadores de {opName}?", + "dialog.clear_markers.title": "Limpar Links: {opName}", + "dialog.checklist.count_fields": "Contar campos", + "dialog.checklist.count_fields.no_empty": "Encontrados {fieldCount} campos e sem campo vazio", + "dialog.checklist.count_fields.with_empty": "Encontrados {fieldCount} campos e {emptyCount} campo(s) vazio(s) no link {linkCount}", + "dialog.checklist.count_fields.link_from_inside": "Encontrados {count} links dos portais cobertos", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " em {order} por link ", + "dialog.common.commands": "Comandos", + "dialog.common.commands_short": "Cmds", + "dialog.common.delete": "Apagar", + "dialog.common.name": "Nome", + "dialog.common.off": "Desligar", + "dialog.common.on": "Ligar", + "dialog.common.owner": "Dono", + "dialog.common.zone_all": "Todos", + "dialog.firebase.setup": "Visite {url} e pressione o botΓ£o para autorizar atualizaçáes ao vivo. VocΓͺ precisarΓ‘ recarregar o IITC depois.", + "dialog.import.url": "Preencher do URL", + "dialog.import.success_message": "Importação completa. Encontrados {count} portais e usados {faked} falsificados. Por favor, use o recurso de troca para mover portais falsos para os portais reais no mesmo local. Ampliar os portais de 'Carregamento' na lista de verificação pode forçÑ-los a carregar.", + "dialog.leave_team.text": "Se vocΓͺ sair do {teamName}, vocΓͺ nΓ£o pode entrar novamente a menos que o dono adicione vocΓͺ novamente.", + "dialog.leave_team.title": "Deixar: {teamName}", + "dialog.link_list.length": "Comprimento", + "dialog.link_list.level": "Min Lvl", + "dialog.merge.cancel_upload": "Cancelar carregamento", + "dialog.merge.conflicts": "Conflitos:", + "dialog.merge.local": "CΓ³pia local", + "dialog.merge.server": "CΓ³pia do servidor", + "dialog.merge.zone": "Zona: {name}", + "dialog.merge.prop.assignedTo": "Atribuir:", + "dialog.merge.prop.comment": "Comentario:", + "dialog.merge.prop.color": "Cor:", + "dialog.merge.prop.deltaminutes": "Delta:", + "dialog.merge.prop.fromPortal": "De:", + "dialog.merge.prop.hardness": "DifΓ­cil:", + "dialog.merge.prop.order": "Pedido:", + "dialog.merge.prop.state": "Estado:", + "dialog.merge.prop.toPortal": "Para:", + "dialog.merge.prop.zone": "Zona:", + "dialog.merge.prop.zone_points": "A forma foi alterada", + "dialog.online_agents.actions": "Açáes", + "dialog.online_agents.last_seen": "Visto pela ΓΊltima vez", + "dialog.online_agents.title": "Agentes Online", + "dialog.op_settings.zones": "Zonas", + "dialog.ops_list.background_disable": "Desat. dados seg. plano", + "dialog.ops_list.background_enable": "Mostrar plano de fundo", + "dialog.ops_list.download": "Descarregar {opName}", + "dialog.ops_list.last_fetched": "Última pesquisa: {date}", + "dialog.ops_list.local_change": "Local foi alterado", + "dialog.ops_list.remote_change": "Controle remoto foi alterado", + "dialog.ops_list.toggle_hide": "Alternar Mostrar/Ocultar", + "dialog.ops_list.unhide_ops": "Exibir todas as OPs", + "dialog.remove_agent.text": "VocΓͺ deseja remover {agentName} de {teamName}?", + "dialog.remove_agent.title": "Remover: {agentName}", + "dialog.setcomment.portal_hardness": "DifΓ­culdade", + "dialog.team_list.load_wd_keys": "Carregar chaves W-D", + "dialog.team_list.share_wd_keys": "Partilhar chaves W-D", + "dialog.team_manage.join_link": "Link de entrada", + "dialog.team_manage.join_link.create": "Criar", + "dialog.team_manage.join_link.revoke": "Revogar", + "dialog.team_members.location": "A partilhar a localização", + "dialog.team_members.wd_keys": "Partilhar chaves W-D", + "dialog.team_message": "AnΓΊncio de equipa: β€œ{message}” de {sender}", + "dialog.update_warning": "O Wasabee estΓ‘ desatualizado. Atualize a usar seu gerenciador de plugins ou indo para https://wasabee.rocks", + "dialog.zone_color.title": "Cor da zona", + "dialog.zone_color.text": "Definir a cor de todos os links na zona {zoneName}", + "dialog.zones.color": "Cor", + "dialog.zones.color_links": "Cor de Link", + "dialog.zones.delete_zone_shape": "Resetar a forma", + "dialog.zones.draw_zone_shape": "Desenhar limites dos blocos", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Parar de desenhar", + "dialog.zones.title": "Zonas", + "DRAW TOOLS FORMAT": "Formato Draw Tools", + "DUPE_OP": "Duplicar Operação", + "END_PORT": "Portal final", + "ExcludeMarker": "Excluir de Auto-Desenhar / Marcar", + "EXPORT OP TITLE": "Exportar Op Actual", + "EXPORT OP": "Exportar Op", + "EXPORT": "Exportar:", + "FAKED": "Falsificado: [{portalId}]", + "FANFIELD": "Desenhar", + "FANFIELD2": "Desenhar Fan Field", + "FarmPortalMarker": "Farmar", + "FLIP_FLOP_NAME": "Inverter Flop", + "FLIP_FLOP_TITLE": "Inverter Flop", + "FLIP_FLOP_DESC": "De uma determinada Γ’ncora, um conjunto de portal visΓ­vel e um nΓΊmero de SBUL, encontre um fanfield para arremessar links da Γ’ncora diminuindo distΓ’ncia para evitar procurar chaves.", + "FLIP_FLOP_INSTRUCTION": "Selecione um portal, zoom para ver portais suficientes e pressione Desenhar. Uma vez que um fanfield for encontrado, vocΓͺ poderΓ‘ procurar por outras Γ’ncoras por jogadas consecutivas", + "FLIP_FLOP_FIND_ANCHORS": "Encontrar outras Γ’ncoras", + "FROM_1-2": "A Partir da base 1-2", + "FROM_1-3": "A Partir da base 1-3", + "FROM_2-3": "A Partir da base 2-3", + "FROM_DEPTH": "da profundidade", + "FROM_PORT": "A Partir do Portal", + "GET DT": "Obtenha o desenho existente do DrawTools", + "GetKeyPortalMarker": "Retirar Chaves", + "GotoPortalMarker": "Ir para", + "H-GEN_INST": "Define portais para a camada externa. Escolhe o nΓΊmero de divisΓ΅es. Clica para desenhar", + "HF_DEEP_SEARCH": "Pesquisa exaustiva", + "HF_DRAW_BUTTON": "Desenhar", + "HF_REDRAW_BUTTON": "Redesenhar", + "HG": "Campo HomogΓͺneo", + "HOURS": " ({hours} horas atrΓ‘s)", + "HOW_TO_VIDS": "

Vídeos de instruçáes:

", + "IMP_NOPE": "A Importação Falhou: {error}", + "IMP_WAS_OP": "Importar Operação Wasabee", + "IMPORT_OP_SUCCESS": "OP Importada: {opName} successfuly.", + "IMPORT_OP_TITLE": "Importar Op: {date}", + "IMPORT_OP": "Importar Operação", + "IMPOSSIBLE": "ImpossΓ­vel", + "INGNAME_GID": "Nome de entrada ou GoogleID", + "INPUT_DT_KEY_COUNT": "Contagem de chaves defensivas de entrada", + "INVALID REQUEST": "Pedido invΓ‘lido", + "IOS NEED FAKE UA": "Deves definir um 'Agente de usuΓ‘rio personalizado para visualizaçáes da Web' nas configuraçáes do IITC-Mobile ou o login falharΓ‘", + "KEY_LIST2": "Lista de chaves para operação: {opName}", + "KEYS": "Chaves", + "KNOWN_BLOCK": "Blockers conhecidos: {opName}", + "LA DESC": "Dependendo do nΓΊmero e tipo de Link Amps usados, um nΓ­vel de portal de origem inferior pode ser suficiente.", + "LA": "L8+ alguns LA", + "LANG": "LΓ­ngua", + "LEAVE": "Deixar", + "LetDecayPortalAlert": "Deixar caΓ­r", + "LINK ASSIGNMENT": "Atribuir link a:", + "LINK STATE PROMPT": "Estado do link", + "LINK STATE": "Definir status do link:", + "LINKS BUTTON TITLE": "Links", + "LINKS": "Links", + "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", + "LOAD PORTALS": "Carregar Portais", + "LOADING": "[a carregar]", + "LOADING1": "a carregar: [{portalGuid}]", + "LOC_PROC": "localização processada", + "LOCATION SUB": "Localização registrada", + "LOCFRMSER": " (localmente e do servidor)", + "LOG IN": "Iniciar SessΓ£o", + "LOG_OUT": "Terminar SessΓ£o", + "MADRID_SET_1": "Selecione a regiΓ£o para a ligação de base Γ‚ncora 2 Γ  Γ‚ncora 3", + "MADRID_SET_2": "Selecione a regiΓ£o para a ligação de base Γ‚ncora 3 Γ  Γ‚ncora 1", + "MADRID_SET_3": "Selecione a regiΓ£o para a ligação de base Γ‚ncora 1 a Γ‚ncora 2", + "MADRID_TITLE": "Madrid Protocol", + "MADRID_WAS_TAKEN": "Madrid Protocol", + "MADRID": "Desenhar", + "MANAGE_TEAM": "Gerenciar {teamName}", + "MANAGE": "Gerenciar", + "MARKER ASSIGNMENT": "Atribuir marcador a:", + "MARKER LIST TITLE": "Lista de Marcadores", + "MARKER LIST": "Marcadores", + "MARKER STATE PROMPT": "Status do marcador", + "MARKER STATE": "Definir estado do marcador:", + "MARKER_LIST": "Lista de Marcadores: {opName}", + "MARKERS BUTTON TITLE": "Marcadores", + "MAX_SPLITS": "DivisΓ΅es mΓ‘ximas", + "MAX": "Fan Field", + "MeetAgentPortalMarker": "Conhecer Agente", + "MERGE ON UPDATE": "Unir na atualização", + "MERGE_CHANGES_LOCAL": "Alteraçáes locais", + "MERGE_CHANGES_MERGE": "Combinar resultado", + "MERGE_CHANGES_REMOTE": "MudanΓ§as remotas", + "MERGE_LOCAL": "Manter localmente", + "MERGE_MESSAGE": "It seems that {opName} has local changes. Do you want to merge your modifications with the server OP, use the server version or keep the local version?", + "MERGE_REBASE": "Unir", + "MERGE_REPLACE": "Usar servidor", + "MERGE_TITLE": "Combinar OP local&remoto", + "MIN_SRC_PORT_LVL": "NΓ­vel mΓ­nimo exigido no portal de origem", + "MINUTES": " ({minutes} minutos atrΓ‘s)", + "MM": "MultimΓ‘x", + "MM_BOTH_SIDE": "Usar ambos os lados base", + "MM_INSERT_ORDER": "Inserir no final", + "MM_SET_ALL_PORTALS": "Todos os portais visΓ­veis", + "MM_SET_ALL_KEYS": "Todos os Marcadores GetKey", + "MM_SET_KEYS_ZONE": "GetKey: {zoneName}", + "MM_SPINE": "Espinha", + "MULTI_M_TITLE": "Desenhar camadas mΓ‘ximas", + "MULTI_M": "Desenhar", + "MUST_NOT_BE_EMPTY": "NΓ£o deve estar vazio", + "MY_CAP_ID": "Minha Capsula ID", + "MY_COUNT": "Minha Conta", + "NAME_REQ": "Nome Requerido", + "NAME": "Nome:", + "NEW_OP": "Nova Operação", + "NEW_TEAM_NAME": "Novo nome de Equipa", + "NEW_TEAM": "Nova Equipa", + "NEW_WAS_SERVER": "Novo servidor Waasbee", + "NEWOP BUTTON TITLE": "Criar uma nova operação", + "NEWOP BUTTON": "Nova Op", + "NO_DT_ITEMS": "Nenhum item desenhado do DrawTools foi detectado", + "NO_LABEL": "Nenhum rΓ³tulo definido", + "NO_STOCK_INTEL": "Wasabee nΓ£o suporta importaçáes de desenho de inteligΓͺncia de stoque", + "NO_TITLE": "Nenhum tΓ­tulo definido", + "NO LONGER AVAILABLE": "Recurso removido do servidor: {error}", + "NO LONGER AVAILABLE SHORT": "Recurso removido do servidor", + "NOT LOGGED IN SHORT": "NΓ£o logado", + "NOT LOGGED IN": "NΓ£o logado: {error}", + "NOT_LOADED": "NΓ£o totalmente carregado, tente novamente.", + "NOT_SET": "nΓ£o configurado", + "NTNAME": "Nome", + "OK": "OK", + "ON_HAND": "Na MΓ£o", + "ONION_WAS_TAKEN": "Cebola", + "ONION": "Desenhar", + "ONLY_DT_IMP": " (apenas para importaçáes do DrawTools)", + "OP DELETED": "Operação removida do servidor: {opID}", + "OP PERM DENIED": "PermissΓ£o negada para operação: {opID}", + "OP_BUTTON": "Operação", + "OP_CHECKLIST": "Lista de verificação de operação: {opName}", + "OP_NAME_UNSET": "O nome da operação nΓ£o estava definido", + "OP_PERMS": "PermissΓ΅es de operação", + "OP_SETTINGS_BUTTON": "Op βš™", + "OP_SETTINGS_TITLE": "Configuraçáes de operação", + "OPEN_REQUEST": "[pedido aberto]", + "OPER_COLOR": "Cor da operação:", + "OPER_NAME": "Nome da Operação:", + "OPERATIONS": "Operaçáes", + "OPS BUTTON TITLE": "Operaçáes", + "OPS BUTTON": "Ops", + "ORDER": "Pedido", + "OtherPortalAlert": "Otros", + "PASTE_INSTRUCT": "Cola uma exportação de desenho Wasabee aqui.\n\nWasabee cannot import the stock intel format.\n\nThere is experimental support for importing the IITC DrawTools format.\n\nBefore importing DrawTools format, preview the areas and make sure all the portals load so IITC has them cached. Any portals that are not pre-cached will be faked.\n\nYou will need to use the 'swap' feature to move anchors from the faked portals to the real portals (they should be in the correct location, just not associated with the portal.\n\nCached portals might not be properly named.", + "pending": "Pendente", + "PERM DENIED": "PermissΓ£o negada: {error}", + "PERM DENIED SHORT": "PermissΓ£o negada", + "PERMS": "{opName} permissΓ΅es", + "PLEASE_SELECT_PORTAL": "Seleciona um portal", + "popup.anchor.keys": "Chaves: {onHand} / {required}", + "popup.marker.state_button": "Definir estado", + "PORTAL KEY LIST": "Lista de chaves para portal {portalName}", + "PORTAL_COUNT": "{count} portais", + "PORTAL": "Portal", + "QD BUTTON CHANGE COLOR": "Clique para alterar a cor dos prΓ³ximos links", + "QD BUTTON END": "Clique para parar de desenhar campos", + "QD BUTTON TOGGLE MODE": "Clique para alterar o modo de desenho", + "QD CHANGE COLOR": "Alterar a cor", + "QD END": "FIM", + "QD TITLE": "Camadas de desenho rΓ‘pido", + "QD TOGGLE MODE": "Alterar o modo", + "QDBASE": "Link Base", + "QDCONT": "Clica num portal espinha para desenhar um campo.", + "QDNEXT": "Clica no segundo portal de Γ’ncora.", + "QDSTART": "Clica no primeiro portal de Γ’ncora.", + "READ_SHORT": "Ler Abreviado", + "READ": "Ler", + "RechargePortalAlert": "Recarregar", + "REFERENCE_TIME": "Tempo de ReferΓͺncia:", + "REM_LOC_CP": "Remover cΓ³pia local de {opName}", + "REMOVE_TEAM_CONFIRM_LABEL": "VocΓͺ deseja remover permanentemente {teamName} do servidor Wasabee?", + "REMOVE_TEAM_CONFIRM_TITLE": "Remover Equipe {teamName}", + "REMOVE_TEAM": "Remover Equipa:", + "REMOVE": "Remover", + "RENAME_TEAM": "Renomear Equipe:", + "RENAME": "Renomear", + "REQUIRED": "Requerido", + "RESET": "Redefinir", + "REVERSE": "Inverter", + "ROCKS_COM": "comunidade enl.rocks:", + "ROLE": "Função", + "SAVELINKS TITLE": "Salvar Links", + "SAVELINKS_DRAW": "Salvar Links", + "SAVELINKS": "Salvar Links", + "SECONDS": " ({seconds} segundos atrΓ‘s)", + "SEL_SB_ANCHOR": "Seleciona a Γ’ncora.", + "SEL_SB_ANCHOR2": "Reduzir o zoom. Verifica se todos os portais foram carregados e clica em desenhar.", + "SEL_SL_ANCHOR": "Selecione o portal para salvar os links de. Clique no botΓ£o salvar links e veja a lista de seleção.", + "SEL_SRC_ANC2": "Selecionar a fonte e a Γ’ncora 2", + "SEL_SRC_PORT": "Selecionar um portal de origem", + "SELECT PORTAL": "Seleciona um portal primeiro", + "SELECT_FAN_PORTALS": "Selecionar um portal de Γ’ncora, um portal inicial e um portal final e, em seguida, posiciona a visualização sobre a Γ‘rea do campo.", + "SELECT_FAN_PORTALS2": "Espere todos os portais carregarem e clique em desenhar.", + "SELECT_INSTRUCTIONS": "Selecione dois portais de Γ’ncora, e entΓ£o aumente o zoom sobre a Γ‘rea giratΓ³ria.", + "SELECT_ONION_PORTALS": "As camadas sΓ£o construΓ­das de dentro para fora. Aumenta o zoom para o centro e seleciona o portal inicial, em seguida, diminui o zoom para a Γ‘rea.", + "SELF SWAP": "NΓ£o Γ© possΓ­vel trocar um portal contigo mesmo! Seleciona um portal diferente.", + "SEND ANALYTICS": "Enviar anΓ‘lises anΓ΄nimas", + "SEND LOCATION": "Partilhar localização (somente quando o IITC estiver em primeiro plano)", + "SEND TARGET AGENT": "Selecionar o destinatΓ‘rio alvo", + "SEND TARGET CONFIRM": "Queres enviar {portalName} alvo para {agent}?", + "SEND TARGET": "Enviar alvo", + "SEND_LOC": "Enviar localização", + "SET_3_PORT": "Defina os trΓͺs portais primeiro!", + "SET_COMMENT": "Definir ComentΓ‘rio", + "SET_LCOMMENT": "Definir comentΓ‘rio do link", + "SET_LINK_COMMENT": "Definir comentΓ‘rio para o link:", + "SET_LINKS_ZONES": "Definir links para zonas", + "SET_MARKER_COMMENT": "Definir comentΓ‘rio para marcador em:", + "SET_MARKER_TYPE_TITLE": "Alterar o tipo de marcador", + "SET_MARKERS_ZONES": "Definir Marcadores para Zonas", + "SET_MCOMMENT": "Definir comentΓ‘rio do marcador: {portalName}", + "SET_NEW_OP": "Define o novo nome da operação", + "SET_PCOMMENT": "Definir comentΓ‘rio do portal: {portalName}", + "SET_PORT_COMMENT": "Definir comentΓ‘rio para portal:", + "SET_PORTAL_COMMENT": "Definir comentΓ‘rio do portal", + "SET": "definir", + "SETTINGS_TOOLBOX": "Configuraçáes do Wasabee", + "SETTINGS_TITLE": "Definiçáes avanΓ§adas", + "SKINS_AVAILABLE": "Existem {count} skins disponΓ­veis.", + "SKINS_BUTTON": "Configurar Skins", + "SKINS_DESCRIPTION": "Gerenciar as skins disponΓ­veis movendo o tema para a coluna da esquerda. Quanto mais baixo na coluna, maior serΓ‘ a prioridade para o UI.", + "SKINS_MANAGE_TITLE": "Gerenciar skins", + "SKIP_CONFIRM_ALWAYS": "Nunca perguntar (use com cuidado)", + "SKIP_CONFIRM_ENTITY": "Apenas perguntar para equipa/op", + "SKIP_CONFIRM_NEVER": "Perguntar sempre", + "SKIP_CONFIRM": "Confirmação de salto", + "SOURCE_PORT": "Portal Fonte", + "STARBURST TITLE": "Starburst", + "STARBURST_DRAW": "Desenhar", + "STARBURST": "Starburst", + "START_PORT": "Portal inicial", + "STATE": "Estado", + "SUPPORT_INSTRUCT": "Para obter suporte, por favor, junte-se ao The Wasabee User Telegram Channel", + "SWAP PROMPT": "Queres trocar:", + "SWAP TITLE": "Trocar Portais", + "SWAP WITH": " com ", + "SWAP": "Troca", + "SYNC DONE": "Download Completo", + "SYNC": "Download operaçáes disponΓ­veis", + "TARGET SENT": "Alvo Enviado", + "TEAM STATE": "Partilhar localização", + "TEAM_CREATED": "Equipa {teamName} created", + "TEAM_NAME": "Nome Equipa", + "TEAM": "Equipa", + "TEAMS BUTTON TITLE": "Listar equipas Wasabee", + "TEAMS BUTTON": "Equipas", + "TO_PORT": "Para o Portal", + "toolbar.quick_delete.apply.text": "Aplicar", + "toolbar.quick_delete.apply.title": "Apagar links/marcadores selecionados", + "toolbar.quick_delete.cancel.text": "Cancelar", + "toolbar.quick_delete.cancel.title": "Cancelar", + "toolbar.quick_delete.stop.text": "Parar", + "toolbar.quick_delete.stop.title": "Sair do modo de eliminação", + "toolbar.quick_delete.title": "Eliminação rΓ‘pida", + "toolbar.quick_delete.tooltip.toggle_mode": "Clique nos recursos para marcar para exclusΓ£o", + "toolbar.quick_delete.tooltip.quick_mode": "Clique nos recursos para excluir instantaneamente", + "toolbar.quick_draw.tooltip.star_mode.anchor": "Selecionar a Γ’ncora da Estrela", + "toolbar.quick_draw.tooltip.star_mode.portal": "Selecionar um portal", + "toolbar.quick_draw.tooltip.single_mode.first": "Clique no primeiro portal", + "toolbar.quick_draw.tooltip.single_mode.next": "Clique no prΓ³ximo portal", + "toolbar.quick_draw.tooltip.portal_fail": "Dados do portal nΓ£o carregados, por favor, tente novamente", + "toolbar.wasabee.settings": "Configuraçáes", + "toolbox.teammates": "Companheiros Online", + "TRAWL SKIP TILES": "Pular blocos para armadilha", + "TRAWL TITLE": "Trawl Lanes", + "TRAWL WARNING": "Isto carregarΓ‘ os dados do bloco em todos os links desenhados. Este Γ© um processo lento.", + "TRAWL_AUTOMARK": "Auto-mark blockers depois da procura", + "TRAWL_BULK_LOAD_WARNING": "Este mΓ©todo carrega os dados do bloco o mais rΓ‘pido possΓ­vel. Usa por sua conta e risco.", + "TRAWL_BULK_LOAD": "Carregar rapidamente Dados do Bloco", + "TRAWL_CLEAR_MARKERS": "Limpa vΓ­rus / destroi marcadores antes da procura", + "TRAWL_REMAINING": "{count} Restantes", + "TRAWL": "Procurar por Blockers", + "TRAWLING": "A Varrer os links a procura de blockers, fecha esta caixa de diΓ‘logo para parar", + "TYPE": "Tipo", + "UNASSIGNED": "NΓ£o atribuΓ­do", + "UNKNOWN": "Desconhecido", + "UPDATE HOVER": "UPDATE {opName} no servidor", + "UPDATE PERM DENIED": "VocΓͺ nΓ£o possui permissΓ£o para editar", + "UPDATE_CONFLICT_DESC": "A OP foi modificada no servidor desde a ΓΊltima sincronização. Queres substituir a versΓ£o do servidor pela atual?", + "UPDATE_CONFLICT_TITLE": "Conflito detectado com o servidor", + "UPDATE_COUNT": "Contagem de atualização", + "UPDATED": "Atualizado com sucesso", + "UpgradePortalAlert": "Atualizar", + "UPLOAD BUTTON HOVER": "UPLOAD {opName} (atualmente nΓ£o estΓ‘ no servidor)", + "UPLOADED": "Carregado com sucesso", + "USE PANES ON MOBILE": "Usar painΓ©is (precisa recarregar)", + "USE_VALID_NAME": "Usa um nome de operação vΓ‘lido", + "UseVirusPortalAlert": "Usar Virus", + "VRLA DESC": "Dependendo do nΓΊmero e tipo de Link Amps usados, um nΓ­vel de portal de origem inferior pode ser suficiente.", + "VRLA": "L8+alguns VRLA", + "WASABEE BUTTON TITLE": "Wasabee: Γ‰ VERDE E FAZ SMURFS CHORAREM.", + "WASABEE_D_LIST": "Contagem de chaves defensivas de entrada", + "WD BUTTON TITLE": "Log de chaves defensivas", + "WD BUTTON": "W-D Chaves", + "WRITE_SHORT": "RW", + "WRITE": "escrita", + "WSERVER": "Servidor: {url}", + "YESNO_DEL": "Tem certeza de que deseja excluir {opName}?", + "ZONE_DRAW": "Clique para definir os limites da zona", + "ZONE": "Zona", + "smallScreen": { + "ADD_LINKS": "+ Links", + "ADD_MARKER": "+ Marcador", + "BLOCKER TITLE": "Bloqueadores", + "CHECKLIST BUTTON": "Verificar", + "CLEAROPS BUTTON": "Limpar", + "EXPORT OP": "Exportar", + "FANFIELD": "Desenhar", + "FANFIELD2": "Desenhar Fan Field", + "KEYS": "Chaves", + "LOG IN": "Iniciar SessΓ£o", + "LOG_OUT": "Terminar SessΓ£o", + "MARKER LIST": "Marcadores", + "MARKERS BUTTON TITLE": "Marcadores", + "MAX": "Fan", + "MM": "Multi", + "MULTI_M_TITLE": "Desenhar Maximo de Layers", + "MULTI_M": "Desenhar", + "NEWOP BUTTON": "Nova Op", + "OPS BUTTON": "Ops", + "QD END": "Fim", + "STARBURST_DRAW": "Desenhar", + "STARBURST": "Estrela", + "TEAMS BUTTON": "Equipas", + "WD BUTTON": "W-D Chaves" + } +} \ No newline at end of file diff --git a/src/code/translations/Russian.json b/src/code/translations/Russian.json new file mode 100644 index 000000000..7a627ac46 --- /dev/null +++ b/src/code/translations/Russian.json @@ -0,0 +1,514 @@ +{ + "ABOUT_WASABEE": "О Wasabee", + "acknowledged": "Ρ†Π΅Π»ΡŒ ΠΏΠΎΠ»ΡƒΡ‡Π΅Π½Π°", + "ADD LINK TITLE": "Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ Π»ΠΈΠ½ΠΊΠΎΠ²", + "ADD MARKER TITLE": "Π”ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€ΠΎΠ²", + "ADD_AGENT": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π°Π³Π΅Π½Ρ‚Π°:", + "ADD_BL": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π΅ΠΌΡ‹Ρ‡ΠΊΠΈ:", + "ADD_BULK": "МассовоС Π΄ΠΎΠ±Π°Π²Π»Π΅Π½ΠΈΠ΅", + "ADD_BUTTON_LINKS": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ всС Π»ΠΈΠ½ΠΊΠΈ сразу.", + "ADD_LINKS": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊΠΈ", + "ADD_MARKER": "+ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€", + "ADD_NEW_OP": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ОПРЦ", + "ADD_SUCC_INSTR": "АгСнт Π΄ΠΎΠ±Π°Π²Π»Π΅Π½", + "ADD_ZONE": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π·ΠΎΠ½Ρƒ", + "ADD": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ", + "ADD1": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ Π»ΠΈΠ½ΠΊ", + "ADD2": "Π”ΠΎΠ±Π°Π²ΠΈΡ‚ΡŒ Π²Ρ‚ΠΎΡ€ΠΎΠΉ Π»ΠΈΠ½ΠΊ", + "AGENT_STATS": "Π”Π°Π½Π½Ρ‹Π΅ Π°Π³Π΅Π½Ρ‚Π°", + "AGENT": "АгСнт", + "AGES": " (Π΄Π°Π²Π½ΠΎ)", + "ALREADY_HAS_MARKER": "Π£ этого ΠΏΠΎΡ€Ρ‚Π°Π»Π° ΡƒΠΆΠ΅ Π΅ΡΡ‚ΡŒ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€. Π’Ρ‹Π±Π΅Ρ€ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΏΠΎΡ€Ρ‚Π°Π».", + "AMAZ_TEAM_NAME": "ΠžΡ‚Π»ΠΈΡ‡Π½ΠΎΠ΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅.", + "ANCHOR ASSIGNMENT": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ всС исходящиС Π»ΠΈΠ½ΠΊΠΈ:", + "ANCHOR_GMAP": "Google-ΠΊΠ°Ρ€Ρ‚Ρ‹", + "ANCHOR_PORTAL": "ΠžΠΏΠΎΡ€Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»", + "ANCHOR_PORTAL2": "ΠžΠΏΠΎΡ€Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π» 2", + "ANCHOR_PORTAL3": "ΠžΠΏΠΎΡ€Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π» 3", + "ANCHOR1": "ΠžΠΏΠΎΡ€Π½ΠΈΠΊ 1", + "ANCHOR2": "ΠžΠΏΠΎΡ€Π½ΠΈΠΊ 2", + "ANCHOR3": "ΠžΠΏΠΎΡ€Π½ΠΈΠΊ 3", + "ANCHORS_AS_BOOKMARKS": "ΠžΠΏΠΎΡ€Π½ΠΈΠΊΠΈ Π² Π·Π°ΠΊΠ»Π°Π΄ΠΊΠΈ", + "API_KEY": "API ΠΊΠ»ΡŽΡ‡ Rocks:", + "ASS_TO": "НазначСно Π°Π³Π΅Π½Ρ‚Ρƒ", + "ASSIGN LINK PROMPT": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊ с ΠΏΠΎΡ€Ρ‚Π°Π»Π°: {portalName}", + "ASSIGN MARKER PROMPT": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€ с {portalName}", + "ASSIGN OUTBOUND PROMPT": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ всС исходящиС Π»ΠΈΠ½ΠΊΠΈ с {portalName}", + "ASSIGN OUTBOUND": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ исходящиС Π»ΠΈΠ½ΠΊΠΈ", + "ASSIGN": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ", + "ASSIGNED_ONLY_SHORT": "НазначСнныС", + "ASSIGNED_ONLY": "Волько Π½Π°Π·Π½Π°Ρ‡Π΅Π½Π½Ρ‹Π΅", + "assigned": "НазначСно", + "AUTH INCOMPAT": "Π’Ρ‹ Π°ΠΊΡ‚ΠΈΠ²ΠΈΡ€ΠΎΠ²Π°Π» Π² TamperMonkey ΠΏΠ»Π°Π³ΠΈΠ½, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹ΠΉ нСсовмСстим с Wasabee", + "AUTH REQUIRED": "НСобходима аутСнтификация", + "AUTH TOKEN REJECTED": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΊΠ° Π°ΡƒΡ‚Π΅Π½Ρ‚ΠΈΡ„ΠΈΠΊΠ°Ρ†ΠΈΠΎΠ½Π½ΠΎΠ³ΠΎ Ρ‚ΠΎΠΊΠ΅Π½Π° Π½Π° сСрвСр ΠΎΡ‚ΠΊΠ»ΠΎΠ½Π΅Π½Π°: {error}", + "AUTH_SELECT_ACCOUNT": "Π’Ρ‹Π±Π΅Ρ€ΠΈ Π°ΠΊΠΊΠ°ΡƒΠ½Ρ‚", + "AUTO_DRAWS": "Авто-рисовка", + "AUTODRAWS": "ΠžΠΏΡ†ΠΈΠΈ Π°Π²Ρ‚ΠΎ-рисовки Wasabee", + "AUTODRAW_PORTALS_SET": "ΠŸΠΎΡ€Ρ‚Π°Π»Ρ‹", + "autodraw.common.draw_button": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "autodraw.fanfield.result": "НайдСно fanfield с {links} Π»ΠΈΠ½ΠΊΠ°ΠΌΠΈ ΠΈ {fields} полями для {ap} AP", + "autodraw.flipflop.result": "Flip flop: Π½Π°ΠΉΠ΄Π΅Π½ΠΎ {count} Π»ΠΈΠ½ΠΊΠΎΠ²", + "autodraw.homogeneous.missing_split": "НСвозмоТно Π½Π°ΠΉΡ‚ΠΈ ΠΏΠΎΠ»Π΅ {count} уровня, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉ ΡƒΡ€ΠΎΠ²Π½ΠΈ Π½ΠΈΠΆΠ΅ΠΈΠ»ΠΈ Π² Π΄Ρ€ΡƒΠ³ΠΎΠΌ мСстС", + "autodraw.homogeneous.order": "ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ", + "autodraw.homogeneous.portals_required": "НуТно {count}", + "autodraw.madrid.auto_determined": "Авто-ΠΎΠΏΡ€Π΅Π΄Π΅Π»Ρ‘Π½Π½Ρ‹ΠΉ", + "autodraw.madrid.balanced": "Ббалансированный", + "autodraw.madrid.result": "Для ΠœΠ°Π΄Ρ€ΠΈΠ΄Π° Π½Π°ΠΉΠ΄Π΅Π½ΠΎ {count} ΠΏΠΎΠ»Π΅ΠΉ", + "autodraw.multimax.result": "Для multimax Π½Π°ΠΉΠ΄Π΅Π½ΠΎ {count} ΠΏΠΎΠ»Π΅ΠΉ", + "autodraw.multimax.result_both_side": "Для multimax Π½Π°ΠΉΠ»Π΅Π½ΠΎ {count1} ΠΈ {count2} ΠΏΠΎΠ»Π΅ΠΉ", + "autodraw.onion.variant": "ΠžΠΏΡ†ΠΈΠΈ", + "autodraw.onion.variant.equilateral": "~Равносторонний", + "autodraw.onion.variant.grow": "ΠŸΡƒΡΡ‚ΡŒ растСт", + "autodraw.onion.variant.balanced": "Π‘Π΅Π·ΡƒΠΏΡ€Π΅Ρ‡Π½Ρ‹ΠΉ баланс", + "AUTOLOAD_RATE": "Π‘ΠΊΠΎΡ€ΠΎΡΡ‚ΡŒ запроса Π΄Π°Π½Π½Ρ‹Ρ… ΠΏΠΎΡ€Ρ‚Π°Π»Π° (ms)", + "AUTOLOAD": "АвтоматичСски Π·Π°Π³Ρ€ΡƒΠΆΠ°Ρ‚ΡŒ Π½Π΅Π΄ΠΎΡΡ‚Π°ΡŽΡ‰ΠΈΠ΅ Π΄Π°Π½Π½Ρ‹Π΅ ΠΏΠΎΡ€Ρ‚Π°Π»Π°", + "AUTOMARK STOP": "Авто-ΠΌΠ°Ρ€ΠΊΠΈΡ€ΠΎΠ²ΠΊΠ° остановлСна, Ρ‚.ΠΊ. ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ Π½Π΅ Π±Ρ‹Π»ΠΈ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Ρ‹", + "AUTOMARK": "Авто-ΠΌΠ°Ρ€ΠΊΠΈΡ€ΠΎΠ²ΠΊΠ°", + "BAT_TOAD": "Π‘ΠΎΠ΅Π²Ρ‹Π΅ ΠΆΠ°Π±Ρ‹", + "BLOCKER LIST TITLE": "ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ всС кроссы", + "BLOCKER TITLE": "кроссы", + "CANCEL": "ΠžΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ", + "CAPSULE": "ΠšΠ°ΠΏΡΡƒΠ»Π°", + "CapturePortalMarker": "Π—Π°Ρ…Π²Π°Ρ‚ΠΈΡ‚ΡŒ", + "CHANGE SERVER PROMPT": "Новый сСрвСр Wasabee", + "CHANGE SERVER": "Π‘ΠΌΠ΅Π½ΠΈΡ‚ΡŒ сСрвСр", + "CHANGE_WAS_SERVER": "Π‘ΠΌΠ΅Π½ΠΈΡ‚ΡŒ сСрвСр Wasabee", + "CHECKLIST BUTTON TITLE": "Π§Π΅ΠΊ-лист ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ", + "CHECKLIST BUTTON": "Π§Π΅ΠΊ-лист", + "CLEAR LINKS": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊΠΈ", + "CLEAR MARKERS": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹", + "CLEAR_EVERYTHING": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹/Π»ΠΈΠ½ΠΊΠΈ/ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹ для Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ ОПРЦ", + "CLEAROPS BUTTON TITLE": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅", + "CLEAROPS BUTTON": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅", + "CLEAROPS PROMPT": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ всС Π»ΠΎΠΊΠ°Π»ΡŒΠ½Ρ‹Π΅ ОПРЦ. ОПРЦ Π±ΡƒΠ΄ΡƒΡ‚ восстановлСны ΠΏΡ€ΠΈ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅ΠΉ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ΅.", + "CLOSE": "Π—Π°ΠΊΡ€Ρ‹Ρ‚ΡŒ", + "COMMENT": "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ", + "COMPLETED BY": "Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ Π°Π³Π΅Π½Ρ‚ΠΎΠΌ {agentName}", + "completed": "Π’Ρ‹ΠΏΠΎΠ»Π½Π΅Π½ΠΎ", + "CON_DEL": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€Π΄ΠΈ ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅: {opName}", + "COUNT": "ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ", + "CREATE_NEW_TEAM": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ", + "CreateLinkAlert": "Π›ΠΈΠ½ΠΊ", + "CUR_USER_INFO": "Π˜Π½Ρ„ΠΎΡ€ΠΌΠ°Ρ†ΠΈΡ ΠΎ ΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»Π΅", + "D_SHOW_LIST": "ВвСсти ΠΊΠ»ΡŽΡ‡ΠΈ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "DEFAULT OP NAME": "Новая ОПРЦ: {date}", + "DELETE ANCHOR PROMPT": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ этот ΠΏΠΎΡ€Ρ‚Π°Π» ΠΈ всС связанныС Π»ΠΈΠ½ΠΊΠΈ:", + "DELETE ANCHOR TITLE": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΏΠΎΡ€Ρ‚Π°Π»", + "DELETE MARKER PROMPT": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ этот ΠΌΠ°Ρ€ΠΊΠ΅Ρ€:", + "DELETE MARKER TITLE": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€", + "DELETE_ANCHOR": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "DELETE_LINK": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "DELETE_OP": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ {opName}", + "DESCRIP_PLACEHOLD": "ОписаниС (ΠΎΠΏΡ†ΠΈΠΎΠ½Π°Π»ΡŒΠ½ΠΎ)", + "DestroyPortalAlert": "БнСсти", + "dialog.about.download_mobile_app": "

ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ Wasabee:

", + "dialog.agent_comment.text": "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ:", + "dialog.agent_comment.title": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ для {agentName}", + "dialog.auth.ott.button": "Π’Ρ…ΠΎΠ΄ с ΠΎΠ΄Π½ΠΎΡ€Π°Π·ΠΎΠ²Ρ‹ΠΌ Ρ‚ΠΎΠΊΠ΅Π½ΠΎΠΌ", + "dialog.auth.ott.text": "ΠŸΠΎΠ»ΡƒΡ‡ΠΈ Ρ‚ΠΎΠΊΠ΅Π½ Π½Π° сСрвСрС Wasabee, Π·Π°Ρ‚Π΅ΠΌ Π²ΡΡ‚Π°Π²ΡŒ Π΅Π³ΠΎ здСсь", + "dialog.auth.ott.title": "ΠžΠ΄Π½ΠΎΡ€Π°Π·ΠΎΠ²Ρ‹ΠΉ Ρ‚ΠΎΠΊΠ΅Π½", + "dialog.blockers.clear_automark": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ Π°Π²Ρ‚ΠΎΠΌΠ΅Ρ‚ΠΊΠΈ", + "dialog.clear_all.text": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΡΠ±Ρ€ΠΎΡΠΈΡ‚ΡŒ {opName}?", + "dialog.clear_all.title": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ: {opName}", + "dialog.clear_links.text": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ всС Π»ΠΈΠ½ΠΊΠΈ Π² {opName}?", + "dialog.clear_links.title": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊΠΈ: {opName}", + "dialog.clear_markers.text": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ всС ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹ Π² {opName}?", + "dialog.clear_markers.title": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊΠΈ: {opName}", + "dialog.checklist.count_fields": "ΠŸΠΎΡ‡ΡΠΈΡ‚Π°Ρ‚ΡŒ поля", + "dialog.checklist.count_fields.no_empty": "НайдСно {fieldCount} ΠΏΠΎΠ»Π΅ΠΉ ΠΈ пустых ΠΏΠΎΠ»Π΅ΠΉ Π½Π΅Ρ‚", + "dialog.checklist.count_fields.with_empty": "НайдСно {fieldCount} ΠΏΠΎΠ»Π΅ΠΉ ΠΈ {emptyCount} пустых ΠΏΠΎΠ»Π΅ΠΉ Π½Π° {linkCount} Π»ΠΈΠ½ΠΊΠ°Ρ…", + "dialog.checklist.count_fields.link_from_inside": "НайдСно {count} Π»ΠΈΠ½ΠΊΠΎΠ² с Π½Π°ΠΊΡ€Ρ‹Ρ‚Ρ‹Ρ… ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ²", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " Π½Π° шагС {order} Π»ΠΈΠ½ΠΊΠΎΠΌ ", + "dialog.common.commands": "ΠšΠΎΠΌΠ°Π½Π΄Ρ‹", + "dialog.common.commands_short": "ΠšΠΎΠΌΠ°Π½Π΄Ρ‹", + "dialog.common.delete": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "dialog.common.name": "НазваниС", + "dialog.common.off": "Π’Ρ‹ΠΊΠ».", + "dialog.common.on": "Π’ΠΊΠ».", + "dialog.common.owner": "Π’Π»Π°Π΄Π΅Π»Π΅Ρ†", + "dialog.common.zone_all": "ВсС", + "dialog.firebase.setup": "ΠŸΠΎΡΠ΅Ρ‚ΠΈ {url} ΠΈ Π½Π°ΠΆΠΌΠΈ ΠΊΠ½ΠΎΠΏΠΊΡƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π°Π²Ρ‚ΠΎΡ€ΠΈΠ·ΠΎΠ²Π°Ρ‚ΡŒ обновлСния Π² Ρ€Π΅Π°Π»ΡŒΠ½ΠΎΠΌ Π²Ρ€Π΅ΠΌΠ΅Π½ΠΈ. ПослС этого ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΈ IITC.", + "dialog.import.url": "Π—Π°ΠΏΠΎΠ»Π½ΠΈΡ‚ΡŒ ΠΈΠ· URL", + "dialog.import.success_message": "Π˜ΠΌΠΏΠΎΡ€Ρ‚ Π·Π°Π²Π΅Ρ€ΡˆΡ‘Π½. НайдСно {count} ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ² ΠΈ {faked} ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ² Π±Ρ‹Π»ΠΎ Π½Π΅ ΠΏΠΎΠ΄Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ Π·Π°ΠΌΠ΅Π½Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π½Π΅ΠΏΠΎΠ΄Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ Π½Π° настоящиС Π½Π° Ρ‚Π΅Ρ… ΠΆΠ΅ мСстах. Π£Π²Π΅Π»ΠΈΡ‡Π΅Π½ΠΈΠ΅ ΠΌΠ°ΡΡˆΡ‚Π°Π±Π° Π½Π° ΠΏΠΎΡ€Ρ‚Π°Π»Π°Ρ… Ρ‡Π΅ΠΊ-листа с ΠΌΠ΅Ρ‚ΠΊΠΎΠΉ 'Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ°' ΠΌΠΎΠΆΠ΅Ρ‚ Π·Π°ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ ΠΈΡ… Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒΡΡ.", + "dialog.leave_team.text": "Если покинСшь {teamName}, Ρ‚ΠΎ Π½Π΅ смоТСшь снова ΠΏΡ€ΠΈΡΠΎΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒΡΡ ΠΏΠΎΠΊΠ° Π²Π»Π°Π΄Π΅Π½Π΅Ρ† Π½Π΅ Π΄ΠΎΠ±Π°Π²ΠΈΡ‚ тСбя.", + "dialog.leave_team.title": "ΠŸΠΎΠΊΠΈΠ½ΡƒΡ‚ΡŒ: {teamName}", + "dialog.link_list.length": "Π”Π»ΠΈΠ½Π°", + "dialog.link_list.level": "Мин. ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ", + "dialog.merge.cancel_upload": "ΠžΡ‚ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π·Π°Π³Ρ€ΡƒΠ·ΠΊΡƒ", + "dialog.merge.conflicts": "ΠšΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚Ρ‹:", + "dialog.merge.local": "Π›ΠΎΠΊΠ°Π»ΡŒΠ½Π°Ρ копия", + "dialog.merge.server": "БСрвСрная копия", + "dialog.merge.zone": "Π—ΠΎΠ½Π°: {name}", + "dialog.merge.prop.assignedTo": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ:", + "dialog.merge.prop.comment": "ΠšΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ:", + "dialog.merge.prop.color": "Π¦Π²Π΅Ρ‚:", + "dialog.merge.prop.deltaminutes": "Π”Π΅Π»ΡŒΡ‚Π°:", + "dialog.merge.prop.fromPortal": "ΠžΡ‚:", + "dialog.merge.prop.hardness": "Hard:", + "dialog.merge.prop.order": "ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ:", + "dialog.merge.prop.state": "Бтатус:", + "dialog.merge.prop.toPortal": "К:", + "dialog.merge.prop.zone": "Π—ΠΎΠ½Π°:", + "dialog.merge.prop.zone_points": "Π€ΠΎΡ€ΠΌΠ° измСнилась", + "dialog.online_agents.actions": "ДСйствия", + "dialog.online_agents.last_seen": "ПослСдняя Π°ΠΊΡ‚ΠΈΠ²Π½ΠΎΡΡ‚ΡŒ", + "dialog.online_agents.title": "АгСнты ΠΎΠ½Π»Π°ΠΉΠ½", + "dialog.op_settings.zones": "Π—ΠΎΠ½Ρ‹", + "dialog.ops_list.background_disable": "ΠžΡ‚ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ Ρ„ΠΎΠ½", + "dialog.ops_list.background_enable": "ΠŸΠΎΠΊΠ°Π·Ρ‹Π²Π°Ρ‚ΡŒ Π² Ρ„ΠΎΠ½Π΅", + "dialog.ops_list.download": "Π‘ΠΊΠ°Ρ‡Π°Ρ‚ΡŒ {opName}", + "dialog.ops_list.last_fetched": "ΠŸΠΎΠ»ΡƒΡ‡Π΅Π½ΠΎ: {date}", + "dialog.ops_list.local_change": "Π›ΠΎΠΊΠ°Π»ΡŒΠ½Π°Ρ вСрсия измСнилась", + "dialog.ops_list.remote_change": "ВСрсия Π½Π° сСрвСрС измСнилась", + "dialog.ops_list.toggle_hide": "ΠŸΠ΅Ρ€Π΅ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ/Π‘ΠΊΡ€Ρ‹Ρ‚ΡŒ", + "dialog.ops_list.unhide_ops": "ΠŸΠΎΠΊΠ°Π·Π°Ρ‚ΡŒ всС ОПРЦ", + "dialog.remove_agent.text": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ {agentName} ΠΈΠ· {teamName}?", + "dialog.remove_agent.title": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ: {agentName}", + "dialog.setcomment.portal_hardness": "Π‘Π»ΠΎΠΆΠ½ΠΎΡΡ‚ΡŒ", + "dialog.team_list.load_wd_keys": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡ΠΈ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "dialog.team_list.share_wd_keys": "ΠŸΠΎΠ΄Π΅Π»ΠΈΡ‚ΡŒΡΡ ΠΊΠ»ΡŽΡ‡Π°ΠΌΠΈ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "dialog.team_manage.join_link": "Бсылка для присоСдинСния", + "dialog.team_manage.join_link.create": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ", + "dialog.team_manage.join_link.revoke": "ΠžΡ‚ΠΎΠ·Π²Π°Ρ‚ΡŒ", + "dialog.team_members.location": "ДСлится мСстополоТСниСм", + "dialog.team_members.wd_keys": "ДСлится ΠΊΠ»ΡŽΡ‡Π°ΠΌΠΈ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "dialog.team_message": "ОбъявлСниС ΠΊΠΎΠΌΠ°Π½Π΄Π΅: \"{message}\" ΠΎΡ‚ {sender}", + "dialog.update_warning": "Wasabee устарСло. ΠŸΠΎΠΆΠ°Π»ΡƒΠΉΡΡ‚Π°, ΠΎΠ±Π½ΠΎΠ²ΠΈ Ρ‡Π΅Ρ€Π΅Π· ΠΌΠ΅Π½Π΅Π΄ΠΆΠ΅Ρ€ ΠΏΠ»Π°Π³ΠΈΠ½ΠΎΠ² ΠΈΠ»ΠΈ ΠΏΠΎ ссылкС https://wasabee.rocks", + "dialog.zone_color.title": "Π¦Π²Π΅Ρ‚ Π·ΠΎΠ½Ρ‹", + "dialog.zone_color.text": "Π—Π°Π΄Π°Ρ‚ΡŒ Ρ†Π²Π΅Ρ‚ всСм Π»ΠΈΠ½ΠΊΠ°ΠΌ Π² Π·ΠΎΠ½Π΅ {zoneName}", + "dialog.zones.color": "Π¦Π²Π΅Ρ‚", + "dialog.zones.color_links": "Π—Π°Π΄Π°Ρ‚ΡŒ Ρ†Π²Π΅Ρ‚ Π»ΠΈΠ½ΠΊΠ°ΠΌ", + "dialog.zones.delete_zone_shape": "Π‘Π±Ρ€ΠΎΡΠΈΡ‚ΡŒ ΠΎΡ‡Π΅Ρ€Ρ‚Π°Π½ΠΈΠ΅ Π·ΠΎΠ½Ρ‹", + "dialog.zones.draw_zone_shape": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ Π³Ρ€Π°Π½ΠΈΡ†Ρ‹", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Π—Π°ΠΊΠΎΠ½Ρ‡ΠΈΡ‚ΡŒ Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "dialog.zones.title": "Π—ΠΎΠ½Ρ‹", + "DRAW TOOLS FORMAT": "Π€ΠΎΡ€ΠΌΠ°Ρ‚ Π”Π’", + "DUPE_OP": "Π”ΡƒΠ±Π»ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ", + "END_PORT": "ΠšΠΎΠ½Π΅Ρ‡Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»", + "ExcludeMarker": "Π˜ΡΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ ΠΈΠ· Π°Π²Ρ‚ΠΎ-рисовки/ΠΌΠ°Ρ€ΠΊΠΈΡ€ΠΎΠ²ΠΊΠΈ", + "EXPORT OP TITLE": "Π­ΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Ρ‚Π΅ΠΊΡƒΡ‰ΡƒΡŽ ОПРЦ", + "EXPORT OP": "Π­ΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ОПРЦ", + "EXPORT": "Π­ΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ:", + "FAKED": "НСподгруТСн: [{portalId}]", + "FANFIELD": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "FANFIELD2": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ Fan Field", + "FarmPortalMarker": "ΠžΡ‚Ρ„Π°Ρ€ΠΌΠΈΡ‚ΡŒ", + "FLIP_FLOP_NAME": "Flip flop", + "FLIP_FLOP_TITLE": "Flip flop", + "FLIP_FLOP_DESC": "Π˜ΡΡ…ΠΎΠ΄Ρ ΠΈΠ· Π·Π°Π΄Π°Π½Π½ΠΎΠ³ΠΎ ΠΎΠΏΠΎΡ€Π½ΠΈΠΊΠ°, Π²ΠΈΠ΄ΠΈΠΌΡ‹Ρ… ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ² ΠΈ количСства SBUL, Π½Π°ΠΉΡ‚ΠΈ fanfield, Π² ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠΌ ΠΎΡ‡Π΅Ρ€Π΅Π΄Π½ΠΎΡΡ‚ΡŒ пСрСнавСса с ΠΎΠΏΠΎΡ€Π½ΠΈΠΊΠ° Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΠ΄Ρ‚ΠΈ ΠΏΠΎ ΡƒΠΌΠ΅Π½ΡŒΡˆΠ΅Π½ΠΈΡŽ Π΄Π»ΠΈΠ½Ρ‹ Π»ΠΈΠ½ΠΊΠΎΠ² для Ρ‚ΠΎΠ³ΠΎ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·Π±Π΅ΠΆΠ°Ρ‚ΡŒ поиска ΠΊΠ»ΡŽΡ‡Π΅ΠΉ.", + "FLIP_FLOP_INSTRUCTION": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΏΠΎΡ€Ρ‚Π°Π», ΠΏΡ€ΠΈΠ±Π»ΠΈΠ·ΡŒ ΠΊΠ°Ρ€Ρ‚Ρƒ, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²ΠΈΠ΄Π΅Ρ‚ΡŒ достаточно ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ² ΠΈ Π½Π°ΠΆΠΌΠΈ Π ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ. Как Ρ‚ΠΎΠ»ΡŒΠΊΠΎ fanfield Π±ΡƒΠ΄Π΅Ρ‚ Π½Π°ΠΉΠ΄Π΅Π½ΠΎ, ΠΌΠΎΠΆΠ½ΠΎ Π±ΡƒΠ΄Π΅Ρ‚ ΠΏΠΎΠΈΡΠΊΠ°Ρ‚ΡŒ Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΎΠΏΠΎΡ€Π½ΠΈΠΊΠΈ для ΠΏΠΎΡΠ»Π΅Π΄ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒΠ½ΠΎΠ³ΠΎ пСрСнавСса.", + "FLIP_FLOP_FIND_ANCHORS": "Найти Π΄Ρ€ΡƒΠ³ΠΈΠ΅ ΠΎΠΏΠΎΡ€Π½ΠΈΠΊΠΈ", + "FROM_1-2": "ΠΎΡ‚ ΠΎΠΏΠΎΡ€Π½ΠΎΠ³ΠΎ Π»ΠΈΠ½ΠΊΠ° 1-2", + "FROM_1-3": "ΠΎΡ‚ ΠΎΠΏΠΎΡ€Π½ΠΎΠ³ΠΎ Π»ΠΈΠ½ΠΊΠ° 1-3", + "FROM_2-3": "ΠΎΡ‚ ΠΎΠΏΠΎΡ€Π½ΠΎΠ³ΠΎ Π»ΠΈΠ½ΠΊΠ° 2-3", + "FROM_DEPTH": "ΠΈΠ· Π³Π»ΡƒΠ±ΠΈΠ½Ρ‹", + "FROM_PORT": "Π‘ ΠΏΠΎΡ€Ρ‚Π°Π»Π°", + "GET DT": "ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΡΡƒΡ‰Π΅ΡΡ‚Π²ΡƒΡŽΡ‰Π΅Π΅ Π”Π’", + "GetKeyPortalMarker": "ΠŸΠΎΠ»ΡƒΡ‡ΠΈΡ‚ΡŒ ΠΊΠ»ΡŽΡ‡ΠΈ", + "GotoPortalMarker": "ΠŸΠ΅Ρ€Π΅ΠΉΡ‚ΠΈ ΠΊ", + "H-GEN_INST": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ для внСшнСго слоя. Π’Ρ‹Π±Π΅Ρ€ΠΈ порядок гомогСнности. НаТми 'Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ'.", + "HF_DEEP_SEARCH": "Π˜Π½ΡΡ‡Π΅Ρ€ΠΏΡ‹Π²Π°ΡŽΡ‰ΠΈΠΉ поиск", + "HF_DRAW_BUTTON": "Π ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "HF_REDRAW_BUTTON": "ΠŸΠ΅Ρ€Π΅Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "HG": "Π“ΠΎΠΌΠΎΠ³Π΅Π½Π½ΠΎΠ΅ ΠΏΠΎΠ»Π΅", + "HOURS": " ({hours} часов Π½Π°Π·Π°Π΄)", + "HOW_TO_VIDS": "

ΠžΠ±ΡƒΡ‡Π°ΡŽΡ‰ΠΈΠ΅ Π²ΠΈΠ΄Π΅ΠΎ:

", + "IMP_NOPE": "Ошибка ΠΈΠΌΠΏΠΎΡ€Ρ‚Π°.", + "IMP_WAS_OP": "Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ОПРЦ Wasabee", + "IMPORT_OP_SUCCESS": "ОПРЦ: {opName} ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Π½Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ.", + "IMPORT_OP_TITLE": "Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ОПРЦ: {date}", + "IMPORT_OP": "Π˜ΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ", + "IMPOSSIBLE": "НСвозмоТно", + "INGNAME_GID": "Ник Ingress ΠΈΠ»ΠΈ GoogleID", + "INPUT_DT_KEY_COUNT": "Π’Π²Π΅Π΄ΠΈ количСство ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "INVALID REQUEST": "НСвСрный запрос", + "IOS NEED FAKE UA": "НуТно ΡƒΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ 'Custom UserAgent for Webviews' Π² настройках IITC-Mobile, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ…ΠΎΠ΄ удался", + "KEY_LIST2": "Бписок ΠΊΠ»ΡŽΡ‡Π΅ΠΉ для ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ: {opName}", + "KEYS": "ΠšΠ»ΡŽΡ‡ΠΈ", + "KNOWN_BLOCK": "Π˜Π·Π²Π΅ΡΡ‚Π½Ρ‹Π΅ кроссы: {opName}", + "LA DESC": "Π’ зависимости ΠΎΡ‚ количСства ΠΈ Ρ‚ΠΈΠΏΠ° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½Ρ‹Ρ… Π»Π°ΠΌΠΏ для Π»ΠΈΠ½ΠΊΠΎΠ²ΠΊΠΈ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ достаточно Π±ΠΎΠ»Π΅Π΅ Π½ΠΈΠ·ΠΊΠΎΠ³ΠΎ уровня ΠΏΠΎΡ€Ρ‚Π°Π»Π°.", + "LA": "П8 с нСсколькими LA", + "LANG": "Π―Π·Ρ‹ΠΊ", + "LEAVE": "Π’Ρ‹ΠΉΡ‚ΠΈ", + "LetDecayPortalAlert": "ΠŸΡ€ΠΎΡΠ°Π΄ΠΈΡ‚ΡŒ", + "LINK ASSIGNMENT": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊ:", + "LINK STATE PROMPT": "Бтатус Π»ΠΈΠ½ΠΊΠ°", + "LINK STATE": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ статус Π»ΠΈΠ½ΠΊΠ°:", + "LINKS BUTTON TITLE": "Π›ΠΈΠ½ΠΊΠΈ", + "LINKS": "Π›ΠΈΠ½ΠΊΠΈ", + "LINKS2": "{portalName} : Π›ΠΈΠ½ΠΊΠΈ ({outgoing}↑/{incoming}↓)", + "LOAD PORTALS": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹", + "LOADING": "[Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ°]", + "LOADING1": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ°: [{portalGuid}]", + "LOC_PROC": "ΠœΠ΅ΡΡ‚ΠΎΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΎΠ±Ρ€Π°Π±ΠΎΡ‚Π°Π½ΠΎ", + "LOCATION SUB": "ΠœΠ΅ΡΡ‚ΠΎΠΏΠΎΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ зарСгистрировано", + "LOCFRMSER": " (локально ΠΈ с сСрвСра)", + "LOG IN": "Π›ΠΎΠ³ΠΈΠ½", + "LOG_OUT": "Π’Ρ‹Ρ…ΠΎΠ΄", + "MADRID_SET_1": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ для ΠΎΠΏΠΎΡ€Π½ΠΎΠ³ΠΎ Π»ΠΈΠ½ΠΊΠ° сопорника 2 Π½Π° ΠΎΠΏΠΎΡ€Π½ΠΈΠΊ 3", + "MADRID_SET_2": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ для ΠΎΠΏΠΎΡ€Π½ΠΎΠ³ΠΎ Π»ΠΈΠ½ΠΊΠ° сопорника 3 Π½Π° ΠΎΠΏΠΎΡ€Π½ΠΈΠΊ 1", + "MADRID_SET_3": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ для ΠΎΠΏΠΎΡ€Π½ΠΎΠ³ΠΎ Π»ΠΈΠ½ΠΊΠ° сопорника 1 Π½Π° ΠΎΠΏΠΎΡ€Π½ΠΈΠΊ 2", + "MADRID_TITLE": "ΠœΠ°Π΄Ρ€ΠΈΠ΄ΡΠΊΠΈΠΉ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»", + "MADRID_WAS_TAKEN": "ΠœΠ°Π΄Ρ€ΠΈΠ΄ΡΠΊΠΈΠΉ ΠΏΡ€ΠΎΡ‚ΠΎΠΊΠΎΠ»", + "MADRID": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "MANAGE_TEAM": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ {teamName}", + "MANAGE": "Π Π΅Π΄Π°ΠΊΡ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "MARKER ASSIGNMENT": "ΠΠ°Π·Π½Π°Ρ‡ΠΈΡ‚ΡŒ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€:", + "MARKER LIST TITLE": "Бписок ΠΌΠ°Ρ€ΠΊΠ΅Ρ€ΠΎΠ²", + "MARKER LIST": "ΠœΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹", + "MARKER STATE PROMPT": "Бтатус ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Π°", + "MARKER STATE": "Π£ΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ статус ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Π°:", + "MARKER_LIST": "Бписок ΠΌΠ°Ρ€ΠΊΠ΅Ρ€ΠΎΠ²: {opName}", + "MARKERS BUTTON TITLE": "ΠœΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹", + "MAX_SPLITS": "ΠœΠ°ΠΊΡΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ", + "MAX": "FanField", + "MeetAgentPortalMarker": "Π’ΡΡ‚Ρ€Π΅Ρ‚ΠΈΡ‚ΡŒ Π°Π³Π΅Π½Ρ‚Π°", + "MERGE ON UPDATE": "ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ ΠΏΡ€ΠΈ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΈ", + "MERGE_CHANGES_LOCAL": "ИзмСнСния Π½Π° устройствС", + "MERGE_CHANGES_MERGE": "ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ Ρ€Π΅Π·ΡƒΠ»ΡŒΡ‚Π°Ρ‚", + "MERGE_CHANGES_REMOTE": "ИзмСнСния Π½Π° сСрвСрС", + "MERGE_LOCAL": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π²Π΅Ρ€ΡΠΈΡŽ с устройства", + "MERGE_MESSAGE": "ΠŸΠΎΡ…ΠΎΠΆΠ΅, Ρ‡Ρ‚ΠΎ Π² ОПРЦ{opName} внСсСны измСнСния Π½Π° устройствС. Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΠΎΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ измСнСния с ОПРЦ Π½Π° сСрвСрС, ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π²Π΅Ρ€ΡΠΈΡŽ с сСрвСра ΠΈΠ»ΠΈ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π²Π΅Ρ€ΡΠΈΡŽ с устройства?", + "MERGE_REBASE": "ΠžΠ±ΡŠΠ΅Π΄ΠΈΠ½ΠΈΡ‚ΡŒ", + "MERGE_REPLACE": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Π²Π΅Ρ€ΡΠΈΡŽ с сСрвСра", + "MERGE_TITLE": "ОбъСдинСниС вСрсий ОПРЦ Π½Π° устройствС ΠΈ Π½Π° сСрвСрС", + "MIN_SRC_PORT_LVL": "ΠœΠΈΠ½ΠΈΠΌΠ°Π»ΡŒΠ½Ρ‹ΠΉ Ρ‚Ρ€Π΅Π±ΡƒΠ΅ΠΌΡ‹ΠΉ ΡƒΡ€ΠΎΠ²Π΅Π½ΡŒ ΠΏΠΎΡ€Ρ‚Π°Π»Π° для Π»ΠΈΠ½ΠΊΠΎΠ²ΠΊΠΈ", + "MINUTES": " ({minutes} ΠΌΠΈΠ½ΡƒΡ‚ Π½Π°Π·Π°Π΄)", + "MM": "Multimax", + "MM_BOTH_SIDE": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΎΠ±Π΅ стороны ΠΎΠΏΠΎΡ€Π½ΠΎΠ³ΠΎ Π»ΠΈΠ½ΠΊΠ°", + "MM_INSERT_ORDER": "Π’ΡΡ‚Π°Π²ΠΈΡ‚ΡŒ Π² ΠΊΠΎΠ½Ρ†Π΅", + "MM_SET_ALL_PORTALS": "ВсС Π²ΠΈΠ΄ΠΈΠΌΡ‹Π΅ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹", + "MM_SET_ALL_KEYS": "ВсС ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹ GetKey", + "MM_SET_KEYS_ZONE": "GetKey: {zoneName}", + "MM_SPINE": "Грядка", + "MULTI_M_TITLE": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ максимальноС количСство слоёв", + "MULTI_M": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "MUST_NOT_BE_EMPTY": "НС Π΄ΠΎΠ»ΠΆΠ½ΠΎ Π±Ρ‹Ρ‚ΡŒ пустым", + "MY_CAP_ID": "ID ΠΌΠΎΠ΅ΠΉ капсулы", + "MY_COUNT": "ΠœΠΎΡ‘ количСство", + "NAME_REQ": "ВрСбуСтся имя", + "NAME": "НазваниС:", + "NEW_OP": "Новая опСрация", + "NEW_TEAM_NAME": "НовоС имя ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹", + "NEW_TEAM": "Новая ΠΊΠΎΠΌΠ°Π½Π΄Π°", + "NEW_WAS_SERVER": "Новый сСрвСр Wasabee", + "NEWOP BUTTON TITLE": "Π‘ΠΎΠ·Π΄Π°Ρ‚ΡŒ Π½ΠΎΠ²ΡƒΡŽ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΡŽ", + "NEWOP BUTTON": "Новая ОПРЦ", + "NO_DT_ITEMS": "НС ΠΎΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ΠΎ элСмСнтов Π”Π’", + "NO_LABEL": "ΠœΠ΅Ρ‚ΠΊΠ° Π½Π΅ установлСна", + "NO_STOCK_INTEL": "Wasabee Π½Π΅ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΈΠ²Π°Π΅Ρ‚ ΠΈΠΌΠΏΠΎΡ€Ρ‚ ΠΈΠ· Intel", + "NO_TITLE": "НазваниС Π½Π΅ установлСно", + "NO LONGER AVAILABLE": "РСсурс ΡƒΠ΄Π°Π»Π΅Π½ с сСрвСра: {error}", + "NO LONGER AVAILABLE SHORT": "РСсурс ΡƒΠ΄Π°Π»Π΅Π½ с сСрвСра", + "NOT LOGGED IN SHORT": "НС Π·Π°Π»ΠΎΠ³ΠΈΠ½Π΅Π½", + "NOT LOGGED IN": "НС Π·Π°Π»ΠΎΠ³ΠΈΠ½Π΅Π½: {error}", + "NOT_LOADED": "НС ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉ Π΅Ρ‰Π΅ Ρ€Π°Π·.", + "NOT_SET": "Π½Π΅ установлСно", + "NTNAME": "НазваниС", + "OK": "ОК", + "ON_HAND": "На Ρ€ΡƒΠΊΠ°Ρ…", + "ONION_WAS_TAKEN": "Onion", + "ONION": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "ONLY_DT_IMP": " (Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΈΠΌΠΏΠΎΡ€Ρ‚Π° Π”Π’)", + "OP DELETED": "ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΡ ΡƒΠ΄Π°Π»Π΅Π½Π° с сСрвСра: {opID}", + "OP PERM DENIED": "ΠžΡ‚ΠΊΠ°Π·Π°Π½ΠΎ Π² доступС ΠΊ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ: {opID}", + "OP_BUTTON": "ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΡ", + "OP_CHECKLIST": "Π§Π΅ΠΊ-лист ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ: {opName}", + "OP_NAME_UNSET": "НазваниС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ Π½Π΅ Π·Π°Π΄Π°Π½ΠΎ", + "OP_PERMS": "Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ ОПРЦ", + "OP_SETTINGS_BUTTON": "ОПРЦ βš™", + "OP_SETTINGS_TITLE": "Настройки ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ", + "OPEN_REQUEST": "[ΠΎΡ‚ΠΊΡ€Ρ‹Ρ‚Ρ‹ΠΉ запрос]", + "OPER_COLOR": "Π¦Π²Π΅Ρ‚ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ:", + "OPER_NAME": "НазваниС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ:", + "OPERATIONS": "ΠžΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ", + "OPS BUTTON TITLE": "Бписок ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΉ", + "OPS BUTTON": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ОПРЦ", + "ORDER": "ΠŸΠΎΡ€ΡΠ΄ΠΎΠΊ", + "OtherPortalAlert": "Π”Ρ€ΡƒΠ³ΠΎΠ΅", + "PASTE_INSTRUCT": "Π’ΡΡ‚Π°Π²ΡŒ экспортируСмыС Π΄Π°Π½Π½Ρ‹Π΅ Wasabee здСсь.\n\nWasabee Π½Π΅ ΠΌΠΎΠΆΠ΅Ρ‚ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ ΠΈΠ½Ρ‚Π΅Π»Π°.\n\nΠ•ΡΡ‚ΡŒ ΡΠΊΡΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Ρ‚Π°Π»ΡŒΠ½Π°Ρ ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠ° Π”Π’ Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π° IITC.\n\nΠŸΡ€Π΅ΠΆΠ΄Π΅ Ρ‡Π΅ΠΌ ΠΈΠΌΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ Π”Π’ Π² Ρ„ΠΎΡ€ΠΌΠ°Ρ‚Π΅ IITC, просмотри ΠΎΠ±Π»Π°ΡΡ‚ΡŒ Π”Π’ ΠΈ ΡƒΠ±Π΅Π΄ΠΈΡΡŒ, Ρ‡Ρ‚ΠΎ всС ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Ρ‹ ΠΈ ΠΊΡΡˆΠΈΡ€ΠΎΠ²Π°Π½Ρ‹ Π² IITC. Π›ΡŽΠ±ΠΎΠΉ Π½Π΅ΠΏΠΎΠ΄Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π» Π±ΡƒΠ΄Π΅Ρ‚ Π½Π΅ΠΏΠΎΠ΄Π³Ρ€ΡƒΠΆΠ΅Π½.\n\nНуТно Π±ΡƒΠ΄Π΅Ρ‚ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ Ρ„ΡƒΠ½ΠΊΡ†ΠΈΡŽ 'Π·Π°ΠΌΠ΅Π½Π°', Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈΡ‚ΡŒ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ со Π½Π΅ΠΏΠΎΠ΄Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Ρ… Π½Π° настоящиС (мСстополоТСниС ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ² Π±ΡƒΠ΄Π΅Ρ‚ ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½Ρ‹ΠΌ, ΠΎΠ΄Π½Π°ΠΊΠΎ Π½Π΅ΠΏΠΎΠ΄Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Π΅ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ Π½Π΅ Π±ΡƒΠ΄ΡƒΡ‚ связаны с Ρ€Π΅Π°Π»ΡŒΠ½Ρ‹ΠΌΠΈ).\n\nΠšΡΡˆΠΈΡ€ΠΎΠ²Π°Π½Π½Ρ‹Π΅ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ ΠΌΠΎΠ³ΡƒΡ‚ Π½Π΅ΠΊΠΎΡ€Ρ€Π΅ΠΊΡ‚Π½ΠΎ Π½Π°Π·Ρ‹Π²Π°Ρ‚ΡŒΡΡ.", + "pending": "ΠžΠΆΠΈΠ΄Π°Π΅Ρ‚ΡΡ", + "PERM DENIED": "Доступ Π·Π°ΠΏΡ€Π΅Ρ‰Π΅Π½: {error}", + "PERM DENIED SHORT": "Доступ Π·Π°ΠΏΡ€Π΅Ρ‰Π΅Π½", + "PERMS": "Π Π°Π·Ρ€Π΅ΡˆΠ΅Π½ΠΈΡ {opName}", + "PLEASE_SELECT_PORTAL": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΏΠΎΡ€Ρ‚Π°Π»", + "popup.anchor.keys": "ΠšΠ»ΡŽΡ‡ΠΈ: {onHand} / {required}", + "popup.marker.state_button": "Π—Π°Π΄Π°Ρ‚ΡŒ статус", + "PORTAL KEY LIST": "Бписок ΠΊΠ»ΡŽΡ‡Π΅ΠΉ для ΠΏΠΎΡ€Ρ‚Π°Π»Π° {portalName}", + "PORTAL_COUNT": "{count} ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ²", + "PORTAL": "ΠŸΠΎΡ€Ρ‚Π°Π»", + "QD BUTTON CHANGE COLOR": "Кликни, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΈΠ·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ†Π²Π΅Ρ‚ ΡΠ»Π΅Π΄ΡƒΡŽΡ‰Π΅Π³ΠΎ Π»ΠΈΠ½ΠΊΠ°", + "QD BUTTON END": "Кликни, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ прорисовку ΠΏΠΎΠ»Π΅ΠΉ", + "QD BUTTON TOGGLE MODE": "Кликни, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΏΠΎΠΌΠ΅Π½ΡΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌ рисовки", + "QD CHANGE COLOR": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ†Π²Π΅Ρ‚", + "QD END": "Π‘Ρ‚ΠΎΠΏ", + "QD TITLE": "Π‘Π»ΠΎΠΈ быстрой рисовки", + "QD TOGGLE MODE": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ€Π΅ΠΆΠΈΠΌ", + "QDBASE": "ΠžΠΏΠΎΡ€Π½Ρ‹ΠΉ Π»ΠΈΠ½ΠΊ", + "QDCONT": "Кликни ΠΏΠΎΡ€Ρ‚Π°Π» Π² грядкС, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠΎΠ»Π΅.", + "QDNEXT": "Кликни Π½Π° Π²Ρ‚ΠΎΡ€ΠΎΠΉ ΠΎΠΏΠΎΡ€Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π».", + "QDSTART": "Кликни Π½Π° ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΎΠΏΠΎΡ€Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π».", + "READ_SHORT": "RO", + "READ": "Ρ‚ΠΎΠ»ΡŒΠΊΠΎ Ρ‡Ρ‚Π΅Π½ΠΈΠ΅", + "RechargePortalAlert": "Π—Π°Ρ€ΡΠ΄ΠΈΡ‚ΡŒ", + "REFERENCE_TIME": "РСфСрСнсноС врСмя:", + "REM_LOC_CP": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π»ΠΎΠΊΠ°Π»ΡŒΠ½ΡƒΡŽ копию {opName}", + "REMOVE_TEAM_CONFIRM_LABEL": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ навсСгда ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ {teamName} с сСрвСра Wasabee?", + "REMOVE_TEAM_CONFIRM_TITLE": "Π£Π΄Π°Π»Π΅Π½ΠΈΠ΅ ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹ {teamName}", + "REMOVE_TEAM": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ:", + "REMOVE": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ", + "RENAME_TEAM": "ΠŸΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠ°Π½Π΄Ρƒ:", + "RENAME": "ΠŸΠ΅Ρ€Π΅ΠΈΠΌΠ΅Π½ΠΎΠ²Π°Ρ‚ΡŒ", + "REQUIRED": "ВрСбуСтся", + "RESET": "Бброс", + "REVERSE": "ΠžΠ±Ρ€Π°Ρ‚ΠΈΡ‚ΡŒ", + "ROCKS_COM": "БообщСство enl.rocks:", + "ROLE": "Роль", + "SAVELINKS TITLE": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊΠΈ", + "SAVELINKS_DRAW": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊΠΈ", + "SAVELINKS": "Π‘ΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ Π»ΠΈΠ½ΠΊΠΈ", + "SECONDS": " ({seconds} сСкунд Π½Π°Π·Π°Π΄)", + "SEL_SB_ANCHOR": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΎΠΏΠΎΡ€Π½ΠΈΠΊ.", + "SEL_SB_ANCHOR2": "УмСньши ΠΌΠ°ΡΡˆΡ‚Π°Π±. УбСдись, Ρ‡Ρ‚ΠΎ ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ ΠΏΠΎΠ»Π½ΠΎΡΡ‚ΡŒΡŽ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΠ»ΠΈΡΡŒ, Π·Π°Ρ‚Π΅ΠΌ ΠΊΠ»ΠΈΠΊΠ½ΠΈ рисовку.", + "SEL_SL_ANCHOR": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΏΠΎΡ€Ρ‚Π°Π», Π»ΠΈΠ½ΠΊΠΈ ΠΊΠΎΡ‚ΠΎΡ€ΠΎΠ³ΠΎ Π½ΡƒΠΆΠ½ΠΎ ΡΠΎΡ…Ρ€Π°Π½ΠΈΡ‚ΡŒ. Кликни Π½Π° ΠΊΠ½ΠΎΠΏΠΊΡƒ сохранСния Π»ΠΈΠ½ΠΊΠΎΠ² ΠΈ посмотри Π² Ρ‡Π΅ΠΊ-лист.", + "SEL_SRC_ANC2": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΎΠ±Π° ΠΏΠΎΡ€Ρ‚Π°Π»Π°: Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΈ ΠΎΠΏΠΎΡ€Π½ΠΈΠΊ 2", + "SEL_SRC_PORT": "Π’Ρ‹Π±Π΅Ρ€ΠΈ Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»", + "SELECT PORTAL": "Π‘Π½Π°Ρ‡Π°Π»Π° Π²Ρ‹Π±Π΅Ρ€ΠΈ ΠΏΠΎΡ€Ρ‚Π°Π»", + "SELECT_FAN_PORTALS": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΎΠΏΠΎΡ€Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π», стартовый ΠΏΠΎΡ€Ρ‚Π°Π» ΠΈ ΠΊΠΎΠ½Π΅Ρ‡Π½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π», Π° Π·Π°Ρ‚Π΅ΠΌ ΠΏΠΎΠ·ΠΈΡ†ΠΈΠΎΠ½ΠΈΡ€ΡƒΠΉΡ‚Π΅ ΠΊΠ°Ρ€Ρ‚Ρƒ Π½Π°Π΄ ΠΎΠ±Π»Π°ΡΡ‚ΡŒΡŽ ΠΏΠΎΠ»Π΅ΠΉ.", + "SELECT_FAN_PORTALS2": "ПодоТди, ΠΏΠΎΠΊΠ° всС ΠΏΠΎΡ€Ρ‚Π°Π»Ρ‹ загрузятся, Π·Π°Ρ‚Π΅ΠΌ ΠΊΠ»ΠΈΠΊΠ½ΠΈ рисовку.", + "SELECT_INSTRUCTIONS": "Π’Ρ‹Π±Π΅Ρ€ΠΈ Π΄Π²Π° ΠΎΠΏΠΎΡ€Π½Ρ‹Ρ… ΠΏΠΎΡ€Ρ‚Π°Π»Π°, Π·Π°Ρ‚Π΅ΠΌ ΡƒΠ²Π΅Π»ΠΈΡ‡ΡŒ ΠΎΠ±Π»Π°ΡΡ‚ΡŒ грядки.", + "SELECT_ONION_PORTALS": "Π‘Π»ΠΎΠΈ строятся ΠΈΠ·Π½ΡƒΡ‚Ρ€ΠΈ Π½Π°Ρ€ΡƒΠΆΡƒ. ΠŸΡ€ΠΈΠ±Π»ΠΈΠ·ΡŒ ΠΌΠ°ΡΡˆΡ‚Π°Π± Π² Ρ†Π΅Π½Ρ‚Ρ€ ΠΈ Π²Ρ‹Π±Π΅Ρ€ΠΈ Π½Π°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π», Π·Π°Ρ‚Π΅ΠΌ ΠΎΡ‚Π΄Π°Π»ΠΈ ΠΌΠ°ΡΡˆΡ‚Π°Π± Π½Π° всю ΠΎΠ±Π»Π°ΡΡ‚ΡŒ.", + "SELF SWAP": "НСльзя Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ ΠΏΠΎΡ€Ρ‚Π°Π» Π½Π° Ρ‚ΠΎΡ‚ ΠΆΠ΅ самый! Π’Ρ‹Π±Π΅Ρ€ΠΈ Π΄Ρ€ΡƒΠ³ΠΎΠΉ ΠΏΠΎΡ€Ρ‚Π°Π».", + "SEND ANALYTICS": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Π°Π½Π°Π»ΠΈΡ‚ΠΈΠΊΡƒ Π°Π½ΠΎΠ½ΠΈΠΌΠ½ΠΎ", + "SEND LOCATION": "Share Location (only when IITC is in foreground)", + "SEND TARGET AGENT": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ получатСля Ρ†Π΅Π»ΠΈ", + "SEND TARGET CONFIRM": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ ΠΎΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Ρ†Π΅Π»ΡŒ {portalName} Π°Π³Π΅Π½Ρ‚Ρƒ {agent}?", + "SEND TARGET": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ Ρ†Π΅Π»ΡŒ", + "SEND_LOC": "ΠžΡ‚ΠΏΡ€Π°Π²ΠΈΡ‚ΡŒ мСстополоТСниС", + "SET_3_PORT": "Π‘Π½Π°Ρ‡Π°Π»Π° Π·Π°Π΄Π°ΠΉ Ρ‚Ρ€ΠΈ ΠΏΠΎΡ€Ρ‚Π°Π»Π°!", + "SET_COMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ", + "SET_LCOMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ ΠΊ Π»ΠΈΠ½ΠΊΡƒ", + "SET_LINK_COMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ для Π»ΠΈΠ½ΠΊΠ°:", + "SET_LINKS_ZONES": "Π—Π°Π΄Π°Ρ‚ΡŒ Π»ΠΈΠ½ΠΊΠ°ΠΌ Π·ΠΎΠ½Ρ‹", + "SET_MARKER_COMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ для ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Π° Π½Π°:", + "SET_MARKER_TYPE_TITLE": "Π˜Π·ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Ρ‚ΠΈΠΏ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Π°", + "SET_MARKERS_ZONES": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹ Π² Π·ΠΎΠ½Ρ‹", + "SET_MCOMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ коммСнтария ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρƒ: {portalName}", + "SET_NEW_OP": "Π—Π°Π΄Π°ΠΉ имя для Π½ΠΎΠ²ΠΎΠΉ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ", + "SET_PCOMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»Ρƒ: {portalName}", + "SET_PORT_COMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»Ρƒ:", + "SET_PORTAL_COMMENT": "Π—Π°Π΄Π°Ρ‚ΡŒ ΠΊΠΎΠΌΠΌΠ΅Π½Ρ‚Π°Ρ€ΠΈΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»Ρƒ", + "SET": "Π·Π°Π΄Π°Ρ‚ΡŒ", + "SETTINGS_TOOLBOX": "Настройки Wasabee", + "SETTINGS_TITLE": "Π Π°ΡΡˆΠΈΡ€Π΅Π½Π½Ρ‹Π΅ настройки", + "SKINS_AVAILABLE": "Π•ΡΡ‚ΡŒ {count} доступных скинов.", + "SKINS_BUTTON": "ΠΠ°ΡΡ‚Ρ€ΠΎΠΈΡ‚ΡŒ скины", + "SKINS_DESCRIPTION": "ΠŸΠ°ΠΊΠ΅Ρ‚Ρ‹ доступных скинов Ρ€Π°Π·ΠΌΠ΅Ρ‰Π΅Π½Ρ‹ Π² ΠΏΡ€Π°Π²ΠΎΠΉ ΠΊΠΎΠ»ΠΎΠ½ΠΊΠ΅. ΠŸΠ΅Ρ€Π΅ΠΌΠ΅ΡΡ‚ΠΈ Π² Π»Π΅Π²ΡƒΡŽ ΠΊΠΎΠ»ΠΎΠ½ΠΊΡƒ Ρ‚Π΅, ΠΊΠΎΡ‚ΠΎΡ€Ρ‹Π΅ Ρ…ΠΎΡ‡Π΅ΡˆΡŒ ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ.", + "SKINS_MANAGE_TITLE": "Π£ΠΏΡ€Π°Π²Π»Π΅Π½ΠΈΠ΅ скинами", + "SKIP_CONFIRM_ALWAYS": "Никогда Π½Π΅ ΡΠΏΡ€Π°ΡˆΠΈΠ²Π°Ρ‚ΡŒ (ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ остороТно)", + "SKIP_CONFIRM_ENTITY": "Π‘ΠΏΡ€Π°ΡˆΠΈΠ²Π°Ρ‚ΡŒ Ρ‚ΠΎΠ»ΡŒΠΊΠΎ для ΠΊΠΎΠΌΠ°Π½Π΄/ОПРЦ", + "SKIP_CONFIRM_NEVER": "ВсСгда ΡΠΏΡ€Π°ΡˆΠΈΠ²Π°Ρ‚ΡŒ", + "SKIP_CONFIRM": "ΠŸΠΎΠ΄Ρ‚Π²Π΅Ρ€ΠΆΠ΄Π΅Π½ΠΈΠ΅ пропуска", + "SOURCE_PORT": "ΠΠ°Ρ‡Π°Π»ΡŒΠ½Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»", + "STARBURST TITLE": "Π—Π²Π΅Π·Π΄Π°", + "STARBURST_DRAW": "Рисовка", + "STARBURST": "Π—Π²Π΅Π·Π΄Π°", + "START_PORT": "Π‘Ρ‚Π°Ρ€Ρ‚ΠΎΠ²Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»", + "STATE": "Бтатус", + "SUPPORT_INSTRUCT": "Для ΠΏΠΎΠ΄Π΄Π΅Ρ€ΠΆΠΊΠΈ, присоСдиняйся ΠΊ The Wasabee User Telegram Channel", + "SWAP PROMPT": "Π₯ΠΎΡ‡Π΅ΡˆΡŒ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ:", + "SWAP TITLE": "Π—Π°ΠΌΠ΅Π½Π° ΠΏΠΎΡ€Ρ‚Π°Π»ΠΎΠ²", + "SWAP WITH": " Π½Π° ", + "SWAP": "Π—Π°ΠΌΠ΅Π½Π°", + "SYNC DONE": "Π—Π°Π³Ρ€ΡƒΠ·ΠΊΠ° Π·Π°Π²Π΅Ρ€ΡˆΠ΅Π½Π°
Кликни Π—Π”Π•Π‘Π¬ для подсказок, совСтов ΠΈ Π΄ΠΎΠΊΡƒΠΌΠ΅Π½Ρ‚Π°Ρ†ΠΈΠΈ.", + "SYNC": "Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ доступныС ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ", + "TARGET SENT": "ЦСль ΠΎΡ‚ΠΏΡ€Π°Π²Π»Π΅Π½Π°", + "TEAM STATE": "Π”Π΅Π»ΠΈΡ‚ΡŒΡΡ мСстополоТСниСм", + "TEAM_CREATED": "Команда {teamName} создана", + "TEAM_NAME": "НазваниС ΠΊΠΎΠΌΠ°Π½Π΄Ρ‹", + "TEAM": "Команда", + "TEAMS BUTTON TITLE": "Бписок ΠΊΠΎΠΌΠ°Π½Π΄ Wasabee", + "TEAMS BUTTON": "ΠšΠΎΠΌΠ°Π½Π΄Ρ‹", + "TO_PORT": "На ΠΏΠΎΡ€Ρ‚Π°Π»", + "toolbar.quick_delete.apply.text": "ΠŸΡ€ΠΈΠΌΠ΅Π½ΠΈΡ‚ΡŒ", + "toolbar.quick_delete.apply.title": "Π£Π΄Π°Π»ΠΈΡ‚ΡŒ Π²Ρ‹Π±Ρ€Π°Π½Π½Ρ‹Π΅ Π»ΠΈΠ½ΠΊΠΈ/ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹", + "toolbar.quick_delete.cancel.text": "ΠžΡ‚ΠΌΠ΅Π½Π°", + "toolbar.quick_delete.cancel.title": "ΠžΡ‚ΠΌΠ΅Π½Π°", + "toolbar.quick_delete.stop.text": "Π‘Ρ‚ΠΎΠΏ", + "toolbar.quick_delete.stop.title": "Π’Ρ‹ΠΉΡ‚ΠΈ ΠΈΠ· Ρ€Π΅ΠΆΠΈΠΌΠ° удалСния", + "toolbar.quick_delete.title": "БыстроС ΡƒΠ΄Π°Π»Π΅Π½ΠΈΠ΅", + "toolbar.quick_delete.tooltip.toggle_mode": "Кликни Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π²Ρ‹Π΄Π΅Π»ΠΈΡ‚ΡŒ ΠΈΡ… для удалСния", + "toolbar.quick_delete.tooltip.quick_mode": "Кликни Π½Π° ΠΎΠ±ΡŠΠ΅ΠΊΡ‚Ρ‹, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π½Π΅ΠΌΠ΅Π΄Π»Π΅Π½Π½ΠΎ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ ΠΈΡ…", + "toolbar.quick_draw.tooltip.star_mode.anchor": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΎΠΏΠΎΡ€Π½ΠΈΠΊ Π·Π²Π΅Π·Π΄Ρ‹", + "toolbar.quick_draw.tooltip.star_mode.portal": "Π’Ρ‹Π±Π΅Ρ€ΠΈ ΠΏΠΎΡ€Ρ‚Π°Π»", + "toolbar.quick_draw.tooltip.single_mode.first": "НаТми Π½Π° ΠΏΠ΅Ρ€Π²Ρ‹ΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»", + "toolbar.quick_draw.tooltip.single_mode.next": "НаТми Π½Π° ΡΠ»Π΅Π΄ΡƒΡŽΡ‰ΠΈΠΉ ΠΏΠΎΡ€Ρ‚Π°Π»", + "toolbar.quick_draw.tooltip.portal_fail": "Π”Π°Π½Π½Ρ‹Π΅ ΠΎ ΠΏΠΎΡ€Ρ‚Π°Π»Π΅ Π½Π΅ Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Ρ‹, ΠΏΠΎΠΏΡ€ΠΎΠ±ΡƒΠΉ Π΅Ρ‰Π΅ Ρ€Π°Π·", + "toolbar.wasabee.settings": "Настройки", + "toolbox.teammates": "Π‘ΠΎΠΊΠΎΠΌΠ°Π½Π΄Π½ΠΈΠΊΠΈ ΠΎΠ½Π»Π°ΠΉΠ½", + "TRAWL SKIP TILES": "Π¨Π°Π³ Ρ‚Π°ΠΉΠ»ΠΎΠ² для Π²Ρ‹Π²Π΅Ρ€ΠΊΠΈ", + "TRAWL TITLE": "Π’Ρ‹Π²Π΅Ρ€ΠΊΠ° трасс", + "TRAWL WARNING": "Π­Ρ‚ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ Π΄Π°Π½Π½Ρ‹Π΅ Ρ‚Π°ΠΉΠ»ΠΎΠ² ΠΏΠΎΠ΄ всСми нарисованными Π»ΠΈΠ½ΠΊΠ°ΠΌΠΈ. Π­Ρ‚ΠΎ ΠΌΠ΅Π΄Π»Π΅Π½Π½Ρ‹ΠΉ процСсс.", + "TRAWL_AUTOMARK": "АвтоматичСски ΠΌΠ°Ρ€ΠΊΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ кроссы послС Π²Ρ‹Π²Π΅Ρ€ΠΊΠΈ", + "TRAWL_BULK_LOAD_WARNING": "Π­Ρ‚ΠΎΡ‚ ΠΌΠ΅Ρ‚ΠΎΠ΄ Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ Π΄Π°Π½Π½Ρ‹Π΅ Ρ‚Π°ΠΉΠ»ΠΎΠ² Ρ‚Π°ΠΊ быстро, ΠΊΠ°ΠΊ это Π²ΠΎΠ·ΠΌΠΎΠΆΠ½ΠΎ. Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ Π΅Π³ΠΎ Π½Π° свой страх ΠΈ риск.", + "TRAWL_BULK_LOAD": "Массово Π·Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ Π΄Π°Π½Π½Ρ‹Π΅ Ρ‚Π°ΠΉΠ»ΠΎΠ²", + "TRAWL_CLEAR_MARKERS": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ ΠΌΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹ вирусов ΠΈ сноса ΠΏΠ΅Ρ€Π΅Π΄ Π²Ρ‹Π²Π΅Ρ€ΠΊΠΎΠΉ", + "TRAWL_REMAINING": "{count} Ρ‚Π°ΠΉΠ»ΠΎΠ² ΠΎΡΡ‚Π°Π»ΠΎΡΡŒ", + "TRAWL": "Π’Ρ‹Π²Π΅Ρ€ΠΊΠ° для поиска кроссов", + "TRAWLING": "Π’Ρ‹Π²Π΅Ρ€ΠΊΠ° трасс для поиска кроссов, Π·Π°ΠΊΡ€ΠΎΠΉ этот Π΄ΠΈΠ°Π»ΠΎΠ³, Ρ‡Ρ‚ΠΎΠ±Ρ‹ ΠΎΡΡ‚Π°Π½ΠΎΠ²ΠΈΡ‚ΡŒ процСсс", + "TYPE": "Π’ΠΈΠΏ", + "UNASSIGNED": "НС Π½Π°Π·Π½Π°Ρ‡Π΅Π½", + "UNKNOWN": "НСизвСстСн", + "UPDATE HOVER": "ΠžΠ‘ΠΠžΠ’Π˜Π’Π¬ {opName} Π½Π° сСрвСрС", + "UPDATE PERM DENIED": "Π£ тСбя нСдостаточно ΠΏΡ€Π°Π² для обновлСния", + "UPDATE_CONFLICT_DESC": "ОПРЦ измСнилась Π½Π° сСрвСрС с ΠΌΠΎΠΌΠ΅Π½Ρ‚Π° послСднСй синхронизации. Π₯ΠΎΡ‡Π΅ΡˆΡŒ Π·Π°ΠΌΠ΅Π½ΠΈΡ‚ΡŒ Π²Π΅Ρ€ΡΠΈΡŽ Π½Π° сСрвСрС Ρ‚Π΅ΠΊΡƒΡ‰Π΅ΠΉ?", + "UPDATE_CONFLICT_TITLE": "ΠžΠ±Π½Π°Ρ€ΡƒΠΆΠ΅Π½ ΠΊΠΎΠ½Ρ„Π»ΠΈΠΊΡ‚ с сСрвСром", + "UPDATE_COUNT": "ΠšΠΎΠ»ΠΈΡ‡Π΅ΡΡ‚Π²ΠΎ ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΈΠΉ", + "UPDATED": "УспСшно ΠΎΠ±Π½ΠΎΠ²Π»Π΅Π½ΠΎ", + "UpgradePortalAlert": "ΠΠΏΠ½ΡƒΡ‚ΡŒ", + "UPLOAD BUTTON HOVER": "Π—ΠΠ“Π Π£Π—Π˜Π’Π¬ {opName} Π½Π° сСрвСр (ΠΏΠΎΠΊΠ° Ρ‡Ρ‚ΠΎ Π΅Ρ‘ Ρ‚Π°ΠΌ Π½Π΅Ρ‚)", + "UPLOADED": "УспСшно Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½ΠΎ Π½Π° сСрвСр", + "USE PANES ON MOBILE": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ ΠΏΠ°Π½Π΅Π»ΠΈ (Π½ΡƒΠΆΠ½Π° ΠΏΠ΅Ρ€Π΅Π·Π°Π³Ρ€ΡƒΠ·ΠΊΠ°)", + "USE_VALID_NAME": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΡƒΠΉ Π΄Π΅ΠΉΡΡ‚Π²ΠΈΡ‚Π΅Π»ΡŒΠ½ΠΎΠ΅ Π½Π°Π·Π²Π°Π½ΠΈΠ΅ ΠΎΠΏΠ΅Ρ€Π°Ρ†ΠΈΠΈ", + "UseVirusPortalAlert": "Π˜ΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚ΡŒ вирус", + "VRLA DESC": "Π’ зависимости ΠΎΡ‚ количСства ΠΈ Ρ‚ΠΈΠΏΠ° ΠΈΡΠΏΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Π½Π½Ρ‹Ρ… Π»Π°ΠΌΠΏ ΠΌΠΎΠΆΠ΅Ρ‚ Π±Ρ‹Ρ‚ΡŒ достаточно Π±ΠΎΠ»Π΅Π΅ Π½ΠΈΠ·ΠΊΠΎΠ³ΠΎ уровня ΠΏΠΎΡ€Ρ‚Π°Π»Π° для Π»ΠΈΠ½ΠΊΠΎΠ²ΠΊΠΈ.", + "VRLA": "П8 с нСсколькими VRLA", + "WASABEE BUTTON TITLE": "Wasabee: Π·Π΅Π»Ρ‘Π½Ρ‹ΠΉ ΠΈ заставляСт смурфов ΠΏΠ»Π°ΠΊΠ°Ρ‚ΡŒ.", + "WASABEE_D_LIST": "Π’Π²ΠΎΠ΄ количСства ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "WD BUTTON TITLE": "Бписок ΠΊΠ»ΡŽΡ‡Π΅ΠΉ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "WD BUTTON": "ΠšΠ»ΡŽΡ‡ΠΈ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…", + "WRITE_SHORT": "RW", + "WRITE": "Ρ‡Ρ‚Π΅Π½ΠΈΠ΅ ΠΈ запись", + "WSERVER": "Π‘Π΅Ρ€Π²Π΅Ρ€: {url}", + "YESNO_DEL": "Π£Π²Π΅Ρ€Π΅Π½, Ρ‡Ρ‚ΠΎ Ρ…ΠΎΡ‡Π΅ΡˆΡŒ ΡƒΠ΄Π°Π»ΠΈΡ‚ΡŒ {opName}?", + "ZONE_DRAW": "Кликни, Ρ‡Ρ‚ΠΎΠ±Ρ‹ Π·Π°Π΄Π°Ρ‚ΡŒ Π³Ρ€Π°Π½ΠΈΡ†Ρ‹ Π·ΠΎΠ½Ρ‹", + "ZONE": "Π—ΠΎΠ½Π°", + "smallScreen": { + "ADD_LINKS": "+ Π›ΠΈΠ½ΠΊΠΈ", + "ADD_MARKER": "+ ΠœΠ°Ρ€ΠΊΠ΅Ρ€", + "BLOCKER TITLE": "кроссы", + "CHECKLIST BUTTON": "Π§Π΅ΠΊ-лист", + "CLEAROPS BUTTON": "ΠžΡ‡ΠΈΡΡ‚ΠΈΡ‚ΡŒ", + "EXPORT OP": "Π­ΠΊΡΠΏΠΎΡ€Ρ‚ΠΈΡ€ΠΎΠ²Π°Ρ‚ΡŒ", + "FANFIELD": "Рисовка", + "FANFIELD2": "ΠΠ°Ρ€ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ Fan Field", + "KEYS": "ΠšΠ»ΡŽΡ‡ΠΈ", + "LOG IN": "Π›ΠΎΠ³ΠΈΠ½", + "LOG_OUT": "Π’Ρ‹Ρ…ΠΎΠ΄", + "MARKER LIST": "ΠœΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹", + "MARKERS BUTTON TITLE": "ΠœΠ°Ρ€ΠΊΠ΅Ρ€Ρ‹", + "MAX": "Fanfield", + "MM": "Multimax", + "MULTI_M_TITLE": "Π ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ максимальноС количСство слоёв", + "MULTI_M": "Π ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "NEWOP BUTTON": "Новая ОПРЦ", + "OPS BUTTON": "Π’Ρ‹Π±Ρ€Π°Ρ‚ΡŒ ОПРЦ", + "QD END": "ΠšΠΎΠ½Π΅Ρ†", + "STARBURST_DRAW": "Π ΠΈΡΠΎΠ²Π°Ρ‚ΡŒ", + "STARBURST": "Π—Π²Π΅Π·Π΄Π°", + "TEAMS BUTTON": "ΠšΠΎΠΌΠ°Π½Π΄Ρ‹", + "WD BUTTON": "ΠšΠ»ΡŽΡ‡ΠΈ Π½Π° Ρ€ΡƒΠΊΠ°Ρ…" + } +} \ No newline at end of file diff --git a/src/code/translations/spanish.json b/src/code/translations/Spanish.json similarity index 51% rename from src/code/translations/spanish.json rename to src/code/translations/Spanish.json index a0efc0981..d62b246bd 100644 --- a/src/code/translations/spanish.json +++ b/src/code/translations/Spanish.json @@ -1,57 +1,70 @@ { - "ABOUT WASABEE-IITC": "Sobre Wasabee-IITC", "ABOUT_WASABEE": "Sobre Wasabee", - "acknowledged": "Acknowledged", + "acknowledged": "Recibido", "ADD LINK TITLE": "Texto de Agregar Links", "ADD MARKER TITLE": "Texto de Agregar Marcadores", "ADD_AGENT": "Agregar Agente", "ADD_BL": "Agregar Links Anidados", + "ADD_BULK": "Agregar en bloque", "ADD_BUTTON_LINKS": "Agregar todos los links a la vez.", "ADD_LINKS": "Agregar Links", "ADD_MARKER": "Agregar Marcador", "ADD_NEW_OP": "Agregar Nueva Op", - "ADD_SUCC_INSTR": "Agregado satisfactoriamente, se necesitarΓ‘ habilitar al equipo en el sitio web de Wasabee antes de que aparezcan en esta lista", - "ADD_ZONE": "Add Zone", + "ADD_SUCC_INSTR": "Agente aΓ±adido correctamente", + "ADD_ZONE": "AΓ±adir Zona", "ADD": "Agregar", - "ADD1": "Add first link", - "ADD2": "Add second link", - "AGENT_STATS": "Agent Stats", + "ADD1": "AΓ±adir primer enlace", + "ADD2": "AΓ±adir segundo enlace", + "AGENT_STATS": "EstadΓ­sticas de agente", "AGENT": "Agente", "AGES": "(Hace demasiado tiempo)", "ALREADY_HAS_MARKER": "Este portal ya tiene un marcador. Elige un portal diferente.", "AMAZ_TEAM_NAME": "Excelente nombre de equipo", - "ANCHOR ASSIGNMENT": "todos los links de salida", + "ANCHOR ASSIGNMENT": "Assign all outbound links to:", "ANCHOR_GMAP": "Google Map", "ANCHOR_PORTAL": "Portal Ancla", - "ANCHOR_PORTAL2": "Anchor Portal 2", - "ANCHOR_PORTAL3": "Anchor Portal 3", + "ANCHOR_PORTAL2": "Portal Ancla 2", + "ANCHOR_PORTAL3": "Portal Ancla 3", "ANCHOR1": "Ancla 1", "ANCHOR2": "Ancla 2", - "ANCHOR3": "Anchor 3 ", - "ANCHORS_AS_BOOKMARKS": "Anchors as bookmarks", - "API_KEY": "api key", + "ANCHOR3": "Ancla 3", + "ANCHORS_AS_BOOKMARKS": "Anclas a Marcadores", + "API_KEY": "Rocks API key:", "ASS_TO": "Asignado A", "ASSIGN LINK PROMPT": "Asignar link de {portalName}", "ASSIGN MARKER PROMPT": "Asignar marcador de {portalName}", "ASSIGN OUTBOUND PROMPT": "Asignar todos los links de salida de {portalName}", "ASSIGN OUTBOUND": "Asignar Links de salida", "ASSIGN": "Asignar", - "ASSIGNED_ONLY_SHORT": "AO", - "ASSIGNED_ONLY": "Assigned Only", + "ASSIGNED_ONLY_SHORT": "SA", + "ASSIGNED_ONLY": "SΓ³lo asignados", "assigned": "Asignado", - "ASSIGNED": "Asignado", - "AUTH ANDROID": "On En Android, prueba 'rΓ‘pido' primero. Si eso falla, intenta el inicio de sesiΓ³n principal con 'select_account'.", "AUTH INCOMPAT": "Has activado un plugin en TamperMonkey que es incompatible con Wasabee", - "AUTH IOS": "En iOS, usa el 'Iniciar SesiΓ³n' principal. Si eso falla intenta usar 'Inicio de SesiΓ³n Vista Web'; luego usa el botΓ³n 'Verificar Vista Web' para completar el proceso.", "AUTH REQUIRED": "AutenticaciΓ³n Requerida", "AUTH TOKEN REJECTED": "EnvΓ­o de token de autorizaciΓ³n al servidor rechazado: {error}", - "AUTH_SELECT_ACCOUNT": "Select account", - "AUTO_DRAWS": "Auto-draw", - "AUTODRAWS": "Wasabee Auto-draw Options", - "AUTOLOAD_RATE": "Portal Detail Request Rate (ms)", - "AUTOLOAD": "Automatically Load Missing Portal Details", + "AUTH_SELECT_ACCOUNT": "Seleccionar cuenta", + "AUTO_DRAWS": "Autodibujar", + "AUTODRAWS": "Opciones de dibujo automΓ‘tico de Wasabee", + "AUTODRAW_PORTALS_SET": "Portales", + "autodraw.common.draw_button": "Dibujar", + "autodraw.fanfield.result": "Fanfield ha encontrado {links} enlaces y {fields} campos para {ap} AP", + "autodraw.flipflop.result": "Flip flop: encontrΓ³ {count} enlaces", + "autodraw.homogeneous.missing_split": "Imposible encontrar {count} divisiones, prueba menos nivel o una regiΓ³n diferente", + "autodraw.homogeneous.order": "Orden", + "autodraw.homogeneous.portals_required": "{count} requeridos", + "autodraw.madrid.auto_determined": "Auto-determinado", + "autodraw.madrid.balanced": "Equilibrado", + "autodraw.madrid.result": "Madrid ha encontrado {count} capas", + "autodraw.multimax.result": "Multimax ha encontrado {count} capas", + "autodraw.multimax.result_both_side": "Multimax encontrΓ³ {count1} y {count2} capas", + "autodraw.onion.variant": "OpciΓ³n", + "autodraw.onion.variant.equilateral": "~EquilΓ‘tero", + "autodraw.onion.variant.grow": "Permitir que crezca", + "autodraw.onion.variant.balanced": "Equilibrio perfecto", + "AUTOLOAD_RATE": "Tasa de solicitud de detalles de portales (ms)", + "AUTOLOAD": "Cargar automΓ‘ticamente los detalles del portal faltante", "AUTOMARK STOP": "El Marcado-AutomΓ‘tico se detuvo debido a que los portales no estaban cargado", - "AUTOMARK": "Auto-Mark", + "AUTOMARK": "Automarcar", "BAT_TOAD": "Sapitos de Batalla", "BLOCKER LIST TITLE": "Mostrar todos los bloqueos", "BLOCKER TITLE": "Bloqueos", @@ -63,20 +76,17 @@ "CHANGE_WAS_SERVER": "Cambiar Servidor de Wasabee", "CHECKLIST BUTTON TITLE": "Lista de VerificaciΓ³n de la OperaciΓ³n", "CHECKLIST BUTTON": "Lista de VerificaciΓ³n", - "CLEAR LINKS": "Clear Links", - "CLEAR MARKERS": "Clear Markers", + "CLEAR LINKS": "Borrar Enlaces", + "CLEAR MARKERS": "Borrar marcadores", "CLEAR_EVERYTHING": "Borrar Portales/Links/Marcadores", - "CLEAR": "Borrar selecciΓ³n", "CLEAROPS BUTTON TITLE": "Borrar TODOS los Datos de Wasabee", "CLEAROPS BUTTON": "Borrar Datos de Wasabee", "CLEAROPS PROMPT": "Esta opciΓ³n borrarΓ‘ todas las OPS y datos relacionados a Wasabee. Todo serΓ‘ restaurado desde el servidor en la prΓ³xima sincronizaciΓ³n.", - "CLOSE": "Close", + "CLOSE": "Cerrar", "COMMENT": "Comentario", "COMPLETED BY": "Completado por {agentName}", "completed": "Completo", - "COMPLETED": "Completo", "CON_DEL": "Confirmar Borrado {opName}", - "CONFIRM_DELETE": "EstΓ‘s seguro de querer borrar este link", "COUNT": "Contar", "CREATE_NEW_TEAM": "Crear Nuevo Equipo", "CreateLinkAlert": "Linkear", @@ -87,51 +97,125 @@ "DELETE ANCHOR TITLE": "Borrar Ancla", "DELETE MARKER PROMPT": "Quisieras borrar este marcador", "DELETE MARKER TITLE": "Borrar Marcador", - "DELETE PERM DENIED": "Permiso para borrar denegado", "DELETE_ANCHOR": "Borrar", "DELETE_LINK": "Borrar", - "DELETE_MARKER": "Borrar", "DELETE_OP": "Borrar {opName}", - "DELETED": "Borrado exitosamente", "DESCRIP_PLACEHOLD": "DescripciΓ³n (opcional)", "DestroyPortalAlert": "Destruir", - "DISABLE_SYNC": "El plugin estΓ‘ndar de SincronizaciΓ³n no es compatible con Wassabe. Por favor, deshabilitar Sync.", - "DISABLED": "Esta opciΓ³n no estΓ‘ lista para los usuarios", - "DONE": "Hecho", - "DRAW TOOLS FORMAT": "Draw Tools Format", - "DT_FORMAT": "Formato Draw Tools", + "dialog.about.download_mobile_app": "

AplicaciΓ³n Wasabee:

", + "dialog.agent_comment.text": "Comment:", + "dialog.agent_comment.title": "Establecer comentario para {agentName}", + "dialog.auth.ott.button": "Inicio de sesiΓ³n con token de un ΓΊnico uso", + "dialog.auth.ott.text": "ObtΓ©n un token en el Servidor Wasabee y pΓ©galo aquΓ­ despuΓ©s", + "dialog.auth.ott.title": "Token de un sΓ³lo uso", + "dialog.blockers.clear_automark": "Limpiar Automarcado", + "dialog.clear_all.text": "ΒΏQuieres reiniciar {opName}?", + "dialog.clear_all.title": "Limpiar: {opName}", + "dialog.clear_links.text": "ΒΏQuieres eliminar todos los enlaces de {opName}?", + "dialog.clear_links.title": "Eliminar enlaces: {opName}", + "dialog.clear_markers.text": "ΒΏQuieres eliminar todos los marcadores de {opName}?", + "dialog.clear_markers.title": "Eliminar marcadores: {opName}", + "dialog.checklist.count_fields": "Contar campos", + "dialog.checklist.count_fields.no_empty": "Se encontraron {fieldCount} campos y ningΓΊn campo vacΓ­o", + "dialog.checklist.count_fields.with_empty": "Se encontraron {fieldCount} campos y {emptyCount} campo(s) vacΓ­o(s) con {linkCount} enlace(s)", + "dialog.checklist.count_fields.link_from_inside": "Se han encontrado {count} enlaces desde portales cubiertos", + "dialog.checklist.count_fields.link_from_inside.covered_at_order": " at {order} by link ", + "dialog.common.commands": "Commands", + "dialog.common.commands_short": "Cmds", + "dialog.common.delete": "Delete", + "dialog.common.name": "Nombre", + "dialog.common.off": "Desactivado", + "dialog.common.on": "Activado", + "dialog.common.owner": "Propietario", + "dialog.common.zone_all": "All", + "dialog.firebase.setup": "Visit {url} and press the button to authorize live updates. You will need to reload IITC afterward.", + "dialog.import.url": "Fill from URL", + "dialog.import.success_message": "Import Complete. Found {count} portals and used {faked} faked. Please use the swap feature to move faked portals to the real portals at the same location. Zooming in on the 'Loading' portals in the checklist might force them to load.", + "dialog.leave_team.text": "If you leave {teamName} you cannot rejoin unless the owner re-adds you.", + "dialog.leave_team.title": "Leave: {teamName}", + "dialog.link_list.length": "Longitud", + "dialog.link_list.level": "Nivel min.", + "dialog.merge.cancel_upload": "Cancelar subida", + "dialog.merge.conflicts": "Conflictos:", + "dialog.merge.local": "Copia local", + "dialog.merge.server": "Copia del servidor", + "dialog.merge.zone": "Zona: {name}", + "dialog.merge.prop.assignedTo": "Asignar:", + "dialog.merge.prop.comment": "Comentario:", + "dialog.merge.prop.color": "Color:", + "dialog.merge.prop.deltaminutes": "Delta:", + "dialog.merge.prop.fromPortal": "Desde:", + "dialog.merge.prop.hardness": "Dificultad:", + "dialog.merge.prop.order": "Orden:", + "dialog.merge.prop.state": "Estado:", + "dialog.merge.prop.toPortal": "Hasta:", + "dialog.merge.prop.zone": "Zona:", + "dialog.merge.prop.zone_points": "La forma ha cambiado", + "dialog.online_agents.actions": "Acciones", + "dialog.online_agents.last_seen": "Visto por ΓΊltima vez", + "dialog.online_agents.title": "Agentes activos", + "dialog.op_settings.zones": "Zonas", + "dialog.ops_list.background_disable": "Disable background", + "dialog.ops_list.background_enable": "Show in background", + "dialog.ops_list.download": "Descargar {opName}", + "dialog.ops_list.last_fetched": "Last fetched: {date}", + "dialog.ops_list.local_change": "OP local ha cambiado", + "dialog.ops_list.remote_change": "OP remota ha cambiado", + "dialog.ops_list.toggle_hide": "Mostrar / Ocultar", + "dialog.ops_list.unhide_ops": "Mostrar todas las OPs", + "dialog.remove_agent.text": "Do you want to remove {agentName} from {teamName}?", + "dialog.remove_agent.title": "Remove: {agentName}", + "dialog.setcomment.portal_hardness": "Dificultad", + "dialog.team_list.load_wd_keys": "Load W-D Keys", + "dialog.team_list.share_wd_keys": "Share W-D Keys", + "dialog.team_manage.join_link": "Enlace de uniΓ³n", + "dialog.team_manage.join_link.create": "Crear", + "dialog.team_manage.join_link.revoke": "Anular", + "dialog.team_members.location": "Sharing Location", + "dialog.team_members.wd_keys": "Sharing W-D Keys", + "dialog.team_message": "Team announcement: β€œ{message}” from {sender}", + "dialog.update_warning": "Wasabee estΓ‘ desactualizado. Por favor, actualice usando su gestor de complementos o vaya a https://wasabee.rocks", + "dialog.zone_color.title": "Zone Color", + "dialog.zone_color.text": "Set the color of all links in zone {zoneName}", + "dialog.zones.color": "Color", + "dialog.zones.color_links": "Color links", + "dialog.zones.delete_zone_shape": "Reset the shape", + "dialog.zones.draw_zone_shape": "Draw the boundaries", + "dialog.zones.id": "ID", + "dialog.zones.stop_drawing": "Stop drawing", + "dialog.zones.title": "Zones", + "DRAW TOOLS FORMAT": "Formato Draw Tools", "DUPE_OP": "Duplicar OperaciΓ³n", "END_PORT": "Portal de Fin", "ExcludeMarker": "Excluir del Dibujo/Marcado AutomΓ‘tico", "EXPORT OP TITLE": "Exportar Op actual", "EXPORT OP": "Exportar Op", "EXPORT": "Exportar", - "FAKED": "Faked: [{portalId}]", - "FAN_FIELD3": "Fan Field", - "FANFIELD TITLE": "Fanfield", + "FAKED": "Virtual: [{portalId}]", "FANFIELD": "Β‘Dibujar!", "FANFIELD2": "Fanfield", "FarmPortalMarker": "Farmear", - "FROM_1-2": "from base 1-2", - "FROM_1-3": "from base 1-3", - "FROM_2-3": "from base 2-3", - "FROM_DEPTH": "from the depth", + "FLIP_FLOP_NAME": "Flip flop", + "FLIP_FLOP_TITLE": "Flip flop", + "FLIP_FLOP_DESC": "Dados un ancla determinado, un conjunto de portales visibles y una cantidad de SBUL, encuentra un fanfield para lanzar enlaces desde el ancla en orden de distancia descendente para evitar buscar llaves.", + "FLIP_FLOP_INSTRUCTION": "Select a portal, zoom to see enough portals and press Draw. Once a fanfield is found, you can search for other anchors for consecutive rethrow", + "FLIP_FLOP_FIND_ANCHORS": "Encontrar otros anclas", + "FROM_1-2": "desde la base 1-2", + "FROM_1-3": "desde la base 1-3", + "FROM_2-3": "desde la base 2-3", + "FROM_DEPTH": "desde el interior", "FROM_PORT": "Desde el Portal", - "GET DT": "Get existing DrawTools draw", - "GET_DT_DRAW": "Obtener dibujo existente de DrawTools", + "GET DT": "Obtener el dibujo existente de DrawTools", "GetKeyPortalMarker": "Obtener Keys", "GotoPortalMarker": "Ir A", - "H-GEN_INST": "Set portals for the outside layer. Choose number of splits. Click draw", - "HF_DEEP_SEARCH": "Exhaustive search", - "HF_DRAW_BUTTON": "Draw", - "HF_DRAW_DEEP_BUTTON": "Draw with deep recursion", - "HF_REDRAW_BUTTON": "Redraw", - "HG": "Homogeneous Field", + "H-GEN_INST": "Establece portales para la capa exterior. Elige el nΓΊmero de divisiones. Haz clic en dibujar", + "HF_DEEP_SEARCH": "BΓΊsqueda exhaustiva", + "HF_DRAW_BUTTON": "Dibujar", + "HF_REDRAW_BUTTON": "Redibujar", + "HG": "Campo homogΓ©neo", "HOURS": "(Hace {hours} horas)", "HOW_TO_VIDS": "

Videos de CΓ³mo Se Hace:

", - "IMP_COMP": "ImportaciΓ³n Completa. Se encontrΓ³", - "IMP_DT_OP": "Op en Drawtools Importada", - "IMP_NOPE": "ImportaciΓ³n FallΓ³.", + "IMP_NOPE": "ImportaciΓ³n FallΓ³: {error}", "IMP_WAS_OP": "Importar OperaciΓ³n Wasabee", "IMPORT_OP_SUCCESS": "OperaciΓ³n {opName} Importada Exitosamente.", "IMPORT_OP_TITLE": "Importar Op {date}", @@ -139,7 +223,6 @@ "IMPOSSIBLE": "Imposible", "INGNAME_GID": "Nombre de Ingress o GoogleID", "INPUT_DT_KEY_COUNT": "Ingresa el Conteo de Llaves Defensivas", - "INPUT_SQUAD_NAME": "Ingresa un nombre de EscuadrΓ³n", "INVALID REQUEST": "Solicitud No VΓ‘lida", "IOS NEED FAKE UA": "Debes configurar un 'UsuarioAgente Personalizado para Vista Web' en las opciones de configuraciΓ³n de IITC-Mobile o el inicio de sesiΓ³n fallarΓ‘", "KEY_LIST2": "Lista de Llaves {opName}", @@ -150,56 +233,58 @@ "LANG": "Idioma", "LEAVE": "Salir", "LetDecayPortalAlert": "Dejar Decaer", - "LINK ASSIGNMENT": "AsignaciΓ³n de Link", + "LINK ASSIGNMENT": "Assign link to:", "LINK STATE PROMPT": "Estado del Link", - "LINK STATE": "Definir estado del link", - "LINKS BUTTON TITLE": "Links", - "LINKS": "Links", - "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", - "LOAD PORTALS": "Load Portals", + "LINK STATE": "Set link status:", + "LINKS BUTTON TITLE": "Enlaces", + "LINKS": "Enlaces", + "LINKS2": "{portalName}: Enlaces ({outgoing}↑/{incoming}↓)", + "LOAD PORTALS": "Cargar Portales", "LOADING": "[cargando]", "LOADING1": "Cargando: [{portalGuid}]", "LOC_PROC": "ubicaciΓ³n procesada", - "LOC_UPDATE": "ActualizaciΓ³n de UbicaciΓ³n", "LOCATION SUB": "UbicaciΓ³n registrada", "LOCFRMSER": "(localmente y del servidor)", - "LOG IN QUICK": "Iniciar SesiΓ³n (rΓ‘pido; para Android)", "LOG IN": "Iniciar SesiΓ³n", "LOG_OUT": "Cerrar sesiΓ³n", "MADRID_SET_1": "Select the region for baselink Anchor 2 to Anchor 3", "MADRID_SET_2": "Select the region for baselink Anchor 3 to Anchor 1", "MADRID_SET_3": "Select the region for baselink Anchor 1 to Anchor 2", - "MADRID_TITLE": "Madrid Protocol", - "MADRID_WAS_TAKEN": "Madrid Protocol", - "MADRID": "Draw", + "MADRID_TITLE": "Protocolo Madrid", + "MADRID_WAS_TAKEN": "Protocolo Madrid", + "MADRID": "Dibujar", "MANAGE_TEAM": "Gestionar {teamName}", "MANAGE": "Gestionar", - "MARKER ASSIGNMENT": "AsignaciΓ³n de Marcador", + "MARKER ASSIGNMENT": "Assign marker to:", "MARKER LIST TITLE": "Lista de Marcadores", "MARKER LIST": "Marcadores", "MARKER STATE PROMPT": "Estado Del Marcador", - "MARKER STATE": " Definir estado del marcador", + "MARKER STATE": "Set marker state:", "MARKER_LIST": "Listad de Marcadores {opName}", "MARKERS BUTTON TITLE": "Marcadores", - "MAX_SPLITS": "Max Splits", + "MAX_SPLITS": "Divisiones mΓ‘ximas", "MAX": "Fan Field", "MeetAgentPortalMarker": "Encontrar Agent", - "MERGE ON UPDATE": "Merge on update", - "MERGE_CHANGES_LOCAL": "Local changes", - "MERGE_CHANGES_MERGE": "Merge result", - "MERGE_CHANGES_REMOTE": "Remote changes", - "MERGE_LOCAL": "Keep local", + "MERGE ON UPDATE": "Combinar al actualizar", + "MERGE_CHANGES_LOCAL": "Cambios locales", + "MERGE_CHANGES_MERGE": "Combinar resultado", + "MERGE_CHANGES_REMOTE": "Cambios remotos", + "MERGE_LOCAL": "Mantener local", "MERGE_MESSAGE": "It seems that {opName} has local changes. Do you want to merge your modifications with the server OP, replace the local version with the server version, or cancel?", "MERGE_REBASE": "Rebase", "MERGE_REPLACE": "Replace", - "MERGE_TITLE": "Merge local&remote OP", + "MERGE_TITLE": "Combinar OP local y remota", "MIN_SRC_PORT_LVL": "Nivel mΓ­nimo requerido para el portal fuente", "MINUTES": "(Hace {minutes} minutos)", "MM": "Multimax", - "MULTI_M_TITLE": "Draw Max Layers", + "MM_BOTH_SIDE": "Usar ambos lados de la base", + "MM_INSERT_ORDER": "Insertar al final", + "MM_SET_ALL_PORTALS": "Todos los portales visibles", + "MM_SET_ALL_KEYS": "Todos los marcadores de Obtener llave", + "MM_SET_KEYS_ZONE": "Obtener llave: {zoneName}", + "MM_SPINE": "Espinazo", + "MULTI_M_TITLE": "Dibujar MΓ‘ximas Capas", "MULTI_M": "Multimax", - "MULTIMAX": "Β‘Multimax!", - "MULTIMAX2": "Multimax", "MUST_NOT_BE_EMPTY": "No Debe Quedar VacΓ­o", "MY_CAP_ID": "ID de Mi CΓ‘psula", "MY_COUNT": "Mi Conteo", @@ -207,35 +292,34 @@ "NAME": "Nombre", "NEW_OP": "Nueva OperaciΓ³n", "NEW_TEAM_NAME": "Nuevo Nombre de Equipo", - "NEW_TEAM": "New Team", + "NEW_TEAM": "Nuevo equipo", "NEW_WAS_SERVER": "Nuevo Servidor de Wasabee", "NEWOP BUTTON TITLE": "Crear una nueva OperaciΓ³n", "NEWOP BUTTON": "Nueva Op", - "NO_DATA": "Sin data", "NO_DT_ITEMS": "No se detectΓ³ elementos dibujados con DrawTools", "NO_LABEL": "Sin etiqueta definida", - "NO_PORT_SEL": "NingΓΊn Portal Portal Seleccionado.", "NO_STOCK_INTEL": "Wasabee no soporta la importaciΓ³n de dibujos trazados en intel regular", "NO_TITLE": "Sin tΓ­tulo definido", - "NO": "No", + "NO LONGER AVAILABLE": "Recurso eliminado del servidor: {error}", + "NO LONGER AVAILABLE SHORT": "Recurso eliminado del servidor", "NOT LOGGED IN SHORT": "SesiΓ³n No Iniciada", "NOT LOGGED IN": "SesiΓ³n No Iniciada: {error}", "NOT_LOADED": "No estΓ‘ cargado completamente, intentar de nuevo.", "NOT_SET": "no definido", "NTNAME": "Nombre", - "OK": "OK", + "OK": "Aceptar", "ON_HAND": "En Mano", "ONION_WAS_TAKEN": "Onion", - "ONION": "Draw", + "ONION": "Dibujar", "ONLY_DT_IMP": "(solo para importaciones de DrawTools)", - "OP DELETED": "Operation removed from server: {opID}", + "OP DELETED": "OperaciΓ³n eliminada del servidor: {opID}", "OP PERM DENIED": "Permiso denegado a la operaciΓ³n: {opID}", - "OP_BUTTON": "Operation", + "OP_BUTTON": "OperaciΓ³n", "OP_CHECKLIST": "Lista de VerificaciΓ³n de la OperaciΓ³n {opName}", "OP_NAME_UNSET": "Se RemoviΓ³ el Nombre de OperaciΓ³n", "OP_PERMS": "Permisos para la Op", "OP_SETTINGS_BUTTON": "Op βš™", - "OP_SETTINGS_TITLE": "Operation Settings", + "OP_SETTINGS_TITLE": "Ajustes de OperaciΓ³n", "OPEN_REQUEST": "[abrir solicitud]", "OPER_COLOR": "Color de la OperaciΓ³n", "OPER_NAME": "Nombre de la OperaciΓ³n", @@ -246,33 +330,30 @@ "OtherPortalAlert": "Otro", "PASTE_INSTRUCT": "Pega un dibujo exportado de Wasabee aquΓ­.\n\nWasabee no puede importar del formato normal de intel.\n\nHay soporte experimental para importar del formato DrawTools de IITC.\n\nAntes de importar del formato DrawTools, revise las Γ‘reas y asegΓΊrese que todos los portales carguen para que estΓ©n en la cachΓ© de IITC. Cualquier portal que no haya estado pre-cargado serΓ‘ falsificado. TendrΓ‘s que usar la opciΓ³n 'intercambiar' para mover las anclas de los portales falsos a los portales reales (estarΓ‘n en la ubicaciΓ³n correcta, pero no asociados con el portal.\n\nPortales en la cachΓ© puede que no estΓ©n nombrados correctamente.", "pending": "Pendiente", - "PENDING": "Pendiente", + "PERM DENIED": "Permiso denegado: {error}", + "PERM DENIED SHORT": "Permiso denegado", "PERMS": "{opName} permisos", - "PICK_DEST_FIRST": "Β‘Por favor, primero elige un portal de destino!", - "PICK_TAR_FIRST": "Β‘Por favor, primero elige un portal objetivo!", - "PICK_TARGETDEST_Portals": "Β‘Por favor, primero selecciona portales de origen y de destino!", "PLEASE_SELECT_PORTAL": "Por favor, seleccionar un portal", - "PORT_FAKE": "portales. Falsificados", + "popup.anchor.keys": "Keys: {onHand} / {required}", + "popup.marker.state_button": "Set State", "PORTAL KEY LIST": "Lista de Llaves del Portal {portalName}", - "PORTAL_COUNT": "{count} portals", + "PORTAL_COUNT": "{count} portales", "PORTAL": "Portal", - "QD BUTTON CHANGE COLOR": "Click to change next links color", + "QD BUTTON CHANGE COLOR": "Haz clic para cambiar el color de los siguientes enlaces", "QD BUTTON END": "Dar click para detener dibujo de campos", - "QD BUTTON TOGGLE MODE": "Click to change draw mode", - "QD CHANGE COLOR": "Change color", - "QD END": "Fin", + "QD BUTTON TOGGLE MODE": "Haz clic para cambiar el modo de dibujo", + "QD CHANGE COLOR": "Cambiar color", + "QD END": "Finalizar", "QD TITLE": "Dibujar Capas RΓ‘pido", - "QD TOGGLE MODE": "Change mode", + "QD TOGGLE MODE": "Cambiar modo", "QDBASE": "Link Base", - "QDCANCEL": "Cancelar Dibujar Campos", "QDCONT": "Dar click a un portal anidado para dibujar el campo.", - "QDEND": "Dar click nuevamente al mismo portal para finalizar el dibujo.", "QDNEXT": "Dar click al segundo portal ancla.", "QDSTART": "Dar click al primer portal ancla.", - "READ_SHORT": "RO", + "READ_SHORT": "SL", "READ": "Leer", "RechargePortalAlert": "Recargar", - "REFERENCE_TIME": "Reference Time: ", + "REFERENCE_TIME": "Hora de referencia:", "REM_LOC_CP": "Borrar copia local de {opName}", "REMOVE_TEAM_CONFIRM_LABEL": "ΒΏDeseas remover {teamName} permanentemente del Servidor Wasabee?", "REMOVE_TEAM_CONFIRM_TITLE": "Remover Equipo {teamName}", @@ -281,31 +362,28 @@ "RENAME_TEAM": "Renombrar Equipo", "RENAME": "Renombrar", "REQUIRED": "Requeridas", - "RESET": "Reset", - "REVERSE": "Reverse", + "RESET": "Restablecer", + "REVERSE": "Invertir", "ROCKS_COM": "comunidad enl.rocks", "ROLE": "Rol", - "SAVELINKS TITLE": "Save Links", - "SAVELINKS_DRAW": "Save Links", - "SAVELINKS": "Save Links", + "SAVELINKS TITLE": "Guardar Enlaces", + "SAVELINKS_DRAW": "Guardar Enlaces", + "SAVELINKS": "Guardar Enlaces", "SECONDS": "(Hace {seconds} segundos)", - "SEL_PORT_FIRST": "Β‘Por favor, primero seleccionar portal ancla!", - "SEL_SB_ANCHOR ": "Selecciona el Γ‘rea del ancla para hacer acercamiento para aΓ±adir a la supernova", - "SEL_SB_ANCHOR2": "Zoom out. Make sure portals have all loaded, then click draw.", - "SEL_SB_ANCHOR3": "Please be patient, it can take a bit.", - "SEL_SL_ANCHOR": "Select the portal to save the links of. Click save links button and look at checklist.", + "SEL_SB_ANCHOR": "Selecciona el Γ‘rea del ancla para hacer acercamiento para aΓ±adir a la supernova.", + "SEL_SB_ANCHOR2": "Aleja el zoom. AsegΓΊrate de que los portales se han cargado completamente y haz clic en Dibujar.", + "SEL_SL_ANCHOR": "Selecciona el portal del que quieres guardar los enlaces. Haz clic en el botΓ³n de Guardar Enlaces y revisa la lista de comprobaciΓ³n.", "SEL_SRC_ANC2": "Selecciona tanto la Fuente como el Ancla 2", "SEL_SRC_PORT": "Selecciona un portal fuente", "SELECT PORTAL": "Seleccionar un portal para enviar", "SELECT_FAN_PORTALS": "Selecciona un portal ancla, un portal de inicio y un portal de fin, luego haz un acercamiento en el Γ‘rea para el fan field. Espera hasta que los portales hayan cargado (los portales deben estar en la pantalla para ser considerados) y presiona el botΓ³n Fanfield.", - "SELECT_FAN_PORTALS2": "Wait for all portals to load, then click draw.", + "SELECT_FAN_PORTALS2": "Espera a que todos los portales se carguen. Luego haz clic en dibujar.", "SELECT_INSTRUCTIONS": "Selecciona dos portales ancla, luego luego haz un acercamiento en el Γ‘rea para los nodos de las capas. Espera hasta que los portales hayan cargado (los portales deben estar en la pantalla para ser considerados) y presiona el botΓ³n Multimax.", - "SELECT_MADRID_INSTRUCTIONS": "Select three anchor portals, zoom in on the area near the selected anchor, wait until the portals are loaded (portals must be on screen to be considered) then select the 'define spine region' button for the corresponding base links.", - "SELECT_ONION_PORTALS": "Layers build from the inside out. Zoom in to center and select starting portal, then zoom out to area.", + "SELECT_ONION_PORTALS": "Las capas se hacen de dentro hacia afuera. AcΓ©rcate al centro y selecciona el portal de inicio. Luego alΓ©jate para ver un Γ‘rea mayor.", "SELF SWAP": "Β‘No se puede intercambiar un portal consigo mismo! Selecciona un portal diferente.", - "SEND ANALYTICS": "Send Anonymous Analytics", - "SEND LOCATION": "Enviar UbicaciΓ³n", - "SEND TARGET AGENT": "Select target recipient", + "SEND ANALYTICS": "Enviar analΓ­ticas anΓ³nimas", + "SEND LOCATION": "Share Location (only when IITC is in foreground)", + "SEND TARGET AGENT": "Selecciona un destinatario", "SEND TARGET CONFIRM": "ΒΏQuieres enviar el {portalName} objetivo a {agent}?", "SEND TARGET": "Enviar Objetivo", "SEND_LOC": "Enviar UbicaciΓ³n", @@ -313,29 +391,29 @@ "SET_COMMENT": "Definir Comentario", "SET_LCOMMENT": "Definir Comentario de Link", "SET_LINK_COMMENT": "Definir comentario para el link", - "SET_LINKS_ZONES": "Set Links to Zones ", + "SET_LINKS_ZONES": "Set Links to Zones", "SET_MARKER_COMMENT": "Definir comentario para el marcador en", - "SET_MARKER_TYPE_TITLE": "Change marker type", - "SET_MARKERS_ZONES": "Set Markers to Zones", + "SET_MARKER_TYPE_TITLE": "Cambiar tipo de marcador", + "SET_MARKERS_ZONES": "Asignar marcadores a zonas", "SET_MCOMMENT": "Definir Comentario de Marcador {portalName}", "SET_NEW_OP": "Por favor, define el Nuevo Nombre de la OperaciΓ³n", "SET_PCOMMENT": "Definir Comentario de Portal {portalName}", "SET_PORT_COMMENT": "Definir comentario para el portal", "SET_PORTAL_COMMENT": "Definir comentarios del portal", "SET": "definir", - "SETTINGS": "ConfiguraciΓ³n de Wasabee", - "SKINS_AVAILABLE": "There are {count} available skins.", - "SKINS_BUTTON": "Configure Skins", + "SETTINGS_TOOLBOX": "Ajustes de Wasabee", + "SETTINGS_TITLE": "Ajustes avanzados", + "SKINS_AVAILABLE": "Hay {count} skins disponibles.", + "SKINS_BUTTON": "Configurar skins", "SKINS_DESCRIPTION": "Available skin packs are located in the right columns. Move skins you wish to use to the left columns.", - "SKINS_MANAGE_TITLE": "Manage skins", - "SKIP_CONFIRM_ALWAYS": "Never ask (use with caution)", - "SKIP_CONFIRM_ENTITY": "Only ask for team/op", - "SKIP_CONFIRM_NEVER": "Always ask", - "SKIP_CONFIRM": "Skip confirmation", - "SOURCE_PORT": "Portal Fuente", - "SQUAD": "EscuadrΓ³n", + "SKINS_MANAGE_TITLE": "Gestionar skins", + "SKIP_CONFIRM_ALWAYS": "Nunca preguntar (usar con precauciΓ³n)", + "SKIP_CONFIRM_ENTITY": "SΓ³lo pedir equipo/op", + "SKIP_CONFIRM_NEVER": "Preguntar siempre", + "SKIP_CONFIRM": "Omitir confirmaciΓ³n", + "SOURCE_PORT": "Portal de origen", "STARBURST TITLE": "Supernova", - "STARBURST_DRAW": "Draw", + "STARBURST_DRAW": "Dibujar", "STARBURST": "Supernova", "START_PORT": "Portal de Inicio", "STATE": "Estado", @@ -346,17 +424,30 @@ "SWAP": "Intercambiar", "SYNC DONE": "Descarga Completa
Haga clic AQUÍ para obtener sugerencias, consejos y documentación.", "SYNC": "Descargar Operaciones Disponibles", - "TARDEST_DIFF": "Los portales objetivo y de destino deben ser diferentes.", "TARGET SENT": "Objetivo enviado", - "TEAM PERM DENIED": "Permiso denegeado al equipo: {error}", - "TEAM STATE": "Share Location", + "TEAM STATE": "Compartir ubicación", "TEAM_CREATED": "Equipo {teamName} creado", "TEAM_NAME": "Nombre de Equipo", "TEAM": "Equipo", "TEAMS BUTTON TITLE": "Listar Equipos Wasabee", "TEAMS BUTTON": "Equipos", - "TITLE": "título", "TO_PORT": "Hacia el Portal", + "toolbar.quick_delete.apply.text": "Aplicar", + "toolbar.quick_delete.apply.title": "Eliminar los enlaces/marcadores seleccionados", + "toolbar.quick_delete.cancel.text": "Cancelar", + "toolbar.quick_delete.cancel.title": "Cancelar", + "toolbar.quick_delete.stop.text": "Parar", + "toolbar.quick_delete.stop.title": "Salir del modo borrar", + "toolbar.quick_delete.title": "Borrado rÑpido", + "toolbar.quick_delete.tooltip.toggle_mode": "Haz clic en los objetos que quieres marcar para eliminar", + "toolbar.quick_delete.tooltip.quick_mode": "Haz clic en los objetos para eliminar inmediatamente", + "toolbar.quick_draw.tooltip.star_mode.anchor": "Seleccione el ancla de la estrella", + "toolbar.quick_draw.tooltip.star_mode.portal": "Selecciona un portal", + "toolbar.quick_draw.tooltip.single_mode.first": "Haz clic en el primer portal", + "toolbar.quick_draw.tooltip.single_mode.next": "Haz clic en el siguiente portal", + "toolbar.quick_draw.tooltip.portal_fail": "Portal data not loaded, please try again", + "toolbar.wasabee.settings": "Ajustes", + "toolbox.teammates": "Teammates Online", "TRAWL SKIP TILES": "Trawl Skip Tiles", "TRAWL TITLE": "Trawl Lanes", "TRAWL WARNING": "This will load the tile data under all drawn links. This is a slow process.", @@ -370,19 +461,16 @@ "TYPE": "Tipo", "UNASSIGNED": "No Asignado", "UNKNOWN": "Desconocido", - "UPDATE HOVER NOT CHANGED": "{opName} no ha sido cambiada localmente", "UPDATE HOVER": "{opName} en el servidor", "UPDATE PERM DENIED": "Permiso para acutalizar denegado", "UPDATE_CONFLICT_DESC": "The OP has been modified on server since last sync. Do you want to replace the server version by the current one?", - "UPDATE_CONFLICT_TITLE": "Conflict detected with server", + "UPDATE_CONFLICT_TITLE": "Conflicto detectado con el servidor", "UPDATE_COUNT": "Actualizar Conteo", "UPDATED": "Actualizado exitosamente", "UpgradePortalAlert": "Actualizar", "UPLOAD BUTTON HOVER": "CARGAR {opName} (no se encuentra actualmente en el servidor)", - "UPLOAD PERM DENIED": "Permiso para cargar denegado", "UPLOADED": "Cargado exitosamente", - "USE PANES ON MOBILE": "Use panes (need reload)", - "USE_SWAP_INSTRUCT": "Por favor, usa la opción de intercambiar portales para mover los portales falsificados hacia los portales reales en la misma ubicación. Hacer un acercamiento en los portales que estÑn 'Cargando' en la lista de verificación puede forzarlos a cargar.", + "USE PANES ON MOBILE": "Usar paneles (es necesario recargar)", "USE_VALID_NAME": "Por favor, utiliza un nombre de operación vÑlido", "UseVirusPortalAlert": "Usar Virus", "VRLA DESC": "Dependiendo del número y tipo de Link Amps usados, un portal de origen de menor nivel puede ser suficiente.", @@ -391,23 +479,19 @@ "WASABEE_D_LIST": "Ingresar Conteo de Llaves de Defensa", "WD BUTTON TITLE": "Registrar Llaves de Defensa", "WD BUTTON": "Llaves W-D", - "WEBVIEW VERIFY": "Verificar Vista Web", - "WEBVIEW": "Iniciar Sesión Vista Web (iOS)", - "WRITE_SHORT": "RW", + "WRITE_SHORT": "LE", "WRITE": "escribir", "WSERVER": "Servidor {url}", - "YES": "Sí", "YESNO_DEL": "EstÑs seguro de querer borrar {opName}", - "ZONE_DRAW": "Click to set the zone boundaries", + "ZONE_DRAW": "Haga clic para establecer los límites de la zona", "ZONE": "Zona", "smallScreen": { - "ADD_LINKS": "+ Links", + "ADD_LINKS": "+ Enlaces", "ADD_MARKER": "+ Marcador", "BLOCKER TITLE": "Bloqueos", "CHECKLIST BUTTON": "Verificar", "CLEAROPS BUTTON": "Borrar", "EXPORT OP": "Exportar", - "FAN_FIELD3": "Fan", "FANFIELD": "Dibujar", "FANFIELD2": "Dibujar Fan Field", "KEYS": "Llaves", @@ -423,8 +507,8 @@ "OPS BUTTON": "Ops", "QD END": "Fin", "STARBURST_DRAW": "Dibujar", - "STARBURST": "Star", + "STARBURST": "Estrella", "TEAMS BUTTON": "Equipos", "WD BUTTON": "Llaves W-D" } -} +} \ No newline at end of file diff --git a/src/code/translations/german.json b/src/code/translations/german.json deleted file mode 100644 index eac07999a..000000000 --- a/src/code/translations/german.json +++ /dev/null @@ -1,430 +0,0 @@ -{ - "ABOUT WASABEE-IITC": "Über Wasabee-IITC", - "ABOUT_WASABEE": "Über Wasabee", - "acknowledged": "Acknowledged", - "ADD LINK TITLE": "Dialog - Links hinzufügen", - "ADD MARKER TITLE": "Dialog - Markierung hinzufügen", - "ADD_AGENT": "Füge Agent hinzu: ", - "ADD_BL": "Füge Portal zur Ankerkette hinzu: ", - "ADD_BUTTON_LINKS": "Add all links at once.", - "ADD_LINKS": "Füge Links hinzu", - "ADD_MARKER": "Füge Markierung hinzu", - "ADD_NEW_OP": "Füge Op hinzu", - "ADD_SUCC_INSTR": "Erfolgreich hinzugefügt. Sie müssen das Team auf der Wassabe Webseite aktivieren, bevor es in der Liste auftaucht.", - "ADD_ZONE": "Add Zone", - "ADD": "Hinzufügen", - "ADD1": "Add first link", - "ADD2": "Add second link", - "AGENT_STATS": "Agent Stats", - "AGENT": "Agent", - "AGES": "vor langer Zeit", - "ALREADY_HAS_MARKER": "Dieses Portal hat bereits eine Markierung. Bitte wÀhle ein anderes Portal.", - "AMAZ_TEAM_NAME": "Toller Teamname", - "ANCHOR ASSIGNMENT": " alle ausgehenden Links", - "ANCHOR_GMAP": "Google Map", - "ANCHOR_PORTAL": "Anker Portal", - "ANCHOR_PORTAL2": "Anchor Portal 2", - "ANCHOR_PORTAL3": "Anchor Portal 3", - "ANCHOR1": "Anker 1", - "ANCHOR2": "Anker 2", - "ANCHOR3": "Anchor 3 ", - "ANCHORS_AS_BOOKMARKS": "Anchors as bookmarks", - "API_KEY": " api key: ", - "ASS_TO": "Zugewiesen an", - "ASSIGN LINK PROMPT": "Link zugewiesenen von: {portalName}", - "ASSIGN MARKER PROMPT": "Markierung zugewiesenen von: {portalName}", - "ASSIGN OUTBOUND PROMPT": "Alle ausgehenden Links zugewiesenen von: {portalName}", - "ASSIGN OUTBOUND": "Ordne ausgehende Links zu", - "ASSIGN": "Zuweisen", - "ASSIGNED_ONLY_SHORT": "AO", - "ASSIGNED_ONLY": "Assigned Only", - "assigned": "Zugewiesen", - "ASSIGNED": "Zugewiesen", - "AUTH ANDROID": "Mit Android versuche 'quick' zuerst. Wenn das fehlschlÀgt, versuche es mit 'select_account' ", - "AUTH INCOMPAT": "Du hast ein Plugin aktiviert welches inkompatibel zu Wasabee ist.", - "AUTH IOS": "Mit IOS nutze 'Log in'. Wenn das fehlschlÀgt nutze 'Webview Log in'; Danach nutze den 'Verify Webview' Knopf um den Prozess abzuschließen", - "AUTH REQUIRED": "Authorisierung benâtigt", - "AUTH TOKEN REJECTED": "Senden des Autorisierungcodes ist fehlgeschlagen: {error}", - "AUTH_SELECT_ACCOUNT": "Select account", - "AUTO_DRAWS": "Auto-draw", - "AUTODRAWS": "Wasabee Auto-draw Options", - "AUTOLOAD_RATE": "Portal Detail Request Rate (ms)", - "AUTOLOAD": "Automatically Load Missing Portal Details", - "AUTOMARK STOP": "Automatische Markierung gestoppt - Portale nicht vollstÀndig geladen.", - "AUTOMARK": "Auto-Mark", - "BAT_TOAD": "Kampffrâsche", - "BLOCKER LIST TITLE": "Zeige alle Blocker an", - "BLOCKER TITLE": "Blocker", - "CANCEL": "Abbrechen", - "CAPSULE": "Kapsel", - "CapturePortalMarker": "Capture", - "CHANGE SERVER PROMPT": "Neuer Wasabee Server", - "CHANGE SERVER": "Wechsle Server", - "CHANGE_WAS_SERVER": "Wechsle Wasabee Server", - "CHECKLIST BUTTON TITLE": "Checkliste Operationen", - "CHECKLIST BUTTON": "Checliste", - "CLEAR LINKS": "Clear Links", - "CLEAR MARKERS": "Clear Markers", - "CLEAR_EVERYTHING": "Clear Portals/Links/Markers for current OP", - "CLEAR": "Clear selection", - "CLEAROPS BUTTON TITLE": "Lâsche alle Wasabee Daten", - "CLEAROPS BUTTON": "Lâsche Wasabee Daten", - "CLEAROPS PROMPT": "Das wird alle Wasabee Daten Lâschen. Bei dem nÀchsten Sync wird alles wiederhergestellt.", - "CLOSE": "Close", - "COMMENT": "Kommentar", - "COMPLETED BY": "Abgeschlossen von {agentName}", - "completed": "Abgeschlossen", - "COMPLETED": "Abgeschlossen", - "CON_DEL": "BestÀtige Lâschen: {opName}", - "CONFIRM_DELETE": "Do you really want to delete this link: ", - "COUNT": "Anzahl", - "CREATE_NEW_TEAM": "Erstelle neues Team", - "CreateLinkAlert": "Link", - "CUR_USER_INFO": "Aktuelle Nutzer Informationen", - "D_SHOW_LIST": "Input Defensive Keys", - "DEFAULT OP NAME": "Neue Operation: {date}", - "DELETE ANCHOR PROMPT": "Mâchtest du den Anker mit allen zugewiesenen Links lâschen? : ", - "DELETE ANCHOR TITLE": "Anker lâschen", - "DELETE MARKER PROMPT": "Mâchtest du die Markierung lâschen? : ", - "DELETE MARKER TITLE": "Markierung lâschen", - "DELETE PERM DENIED": "Keine Berechtigung zum lâschen", - "DELETE_ANCHOR": "Lâschen", - "DELETED": "Erfolgreich gelâscht", - "DELETE_MARKER": "Delete", - "DELETE_OP": "Delete {opName}", - "DELETED": "Successfully deleted.", - "DESCRIP_PLACEHOLD": "Beschreibung (optional)", - "DestroyPortalAlert": "Destroy", - "DISABLE_SYNC": "Das Standard Synchronisations Plugin ist nicht mit Wasabee kompatibel - Bitte deaktiveren", - "DISABLED": "Diese Eigenschaft steht den Nutzern nicht zu verfügung", - "DONE": "Fertig", - "DRAW TOOLS FORMAT": "Draw Tools Format", - "DT_FORMAT": "Draw Tools Format", - "DUPE_OP": "Duplicate Operation", - "END_PORT": "Endportal", - "ExcludeMarker": "Exclude from Auto-Draw/Mark", - "EXPORT OP TITLE": "Exportiere aktuelle Operation ", - "EXPORT OP": "Exportiere Op", - "EXPORT": "Exportieren: ", - "FAKED": "Faked: [{portalId}]", - "FAN_FIELD3": "Fan Field", - "FANFIELD TITLE": "FÀcherfeld", - "FANFIELD": "FÀcherfeld!", - "FANFIELD2": "FÀcherfeld", - "FarmPortalMarker": "Farm", - "FROM_1-2": "from base 1-2", - "FROM_1-3": "from base 1-3", - "FROM_2-3": "from base 2-3", - "FROM_DEPTH": "from the depth", - "FROM_PORT": "Von Portal", - "GET DT": "Get existing DrawTools draw", - "GET_DT_DRAW": "Erhalte aktuelle DrawTools Zeichnung", - "GetKeyPortalMarker": "Get Keys", - "GotoPortalMarker": "Go To", - "H-GEN_INST": "Set portals for the outside layer. Choose number of splits. Click draw", - "HF_DEEP_SEARCH": "Exhaustive search", - "HF_DRAW_BUTTON": "Draw", - "HF_DRAW_DEEP_BUTTON": "Draw with deep recursion", - "HF_REDRAW_BUTTON": "Redraw", - "HG": "Homogeneous Field", - "HOURS": "vor ({hours} Stunden)", - "HOW_TO_VIDS": "

ErklΓ€rungsvideos:

", - "IMP_COMP": "Import Komplett. Gefunden ", - "IMP_DT_OP": "Importierte Drawtools Op: ", - "IMP_NOPE": "Import Fehlgeschlagen.", - "IMP_WAS_OP": "Importiere Wasabee Operation", - "IMPORT_OP_SUCCESS": "Importierte Operation: {opName}. Erfolgreich.", - "IMPORT_OP_TITLE": "Importierte Op: {date}", - "IMPORT_OP": "Importiere Operation", - "IMPOSSIBLE": "UnmΓΆglich", - "INGNAME_GID": "Ingress name oder GoogleID", - "INPUT_DT_KEY_COUNT": "Eingabe defensiver SchlΓΌssel", - "INPUT_SQUAD_NAME": "Name des Kaders", - "INVALID REQUEST": "UngΓΌltige Anfrage", - "IOS NEED FAKE UA": "Du musst 'Custom UserAgent for Webviews' in den IITC-Mobile Einstellungen aktivieren der Login wird fehlgeschlagen", - "KEY_LIST2": "SchlΓΌsselliste: {opName}", - "KEYS": "SchlΓΌssel", - "KNOWN_BLOCK": "Bekannte Blocker: {opName}", - "LA DESC": "Ausgehend von der Anzahl und Typ von Link-Amps kΓΆnnte ein niedrigeres Portallevel ausreichen", - "LA": "L8+ einige LA", - "LANG": "Sprache", - "LEAVE": "Verlassen", - "LetDecayPortalAlert": "Let Decay", - "LINK ASSIGNMENT": " Link zugewiesenen", - "LINK STATE PROMPT": "Link State", - "LINK STATE": "Set link status", - "LINKS BUTTON TITLE": "Links", - "LINKS": "Links", - "LINKS2": "{portalName} : Links ({outgoing}↑/{incoming}↓)", - "LOAD PORTALS": "Load Portals", - "LOADING": "[laden]", - "LOADING1": "Lade: [{portalGuid}]", - "LOC_PROC": "Standort verarbeitet", - "LOC_UPDATE": "Standort aktualisieren", - "LOCATION SUB": "Standort registriert", - "LOCFRMSER": " (locally and from server)", - "LOG IN QUICK": "Einloggen (quick; fΓΌr Android)", - "LOG IN": "Einloggen", - "LOG_OUT": "Log Out", - "MADRID_SET_1": "Select the region for baselink Anchor 2 to Anchor 3", - "MADRID_SET_2": "Select the region for baselink Anchor 3 to Anchor 1", - "MADRID_SET_3": "Select the region for baselink Anchor 1 to Anchor 2", - "MADRID_TITLE": "Madrid Protocol", - "MADRID_WAS_TAKEN": "Madrid Protocol", - "MADRID": "Draw", - "MANAGE_TEAM": "Verwalten {teamName}", - "MANAGE": "Verwalten", - "MARKER ASSIGNMENT": " Markierung zugewiesenen", - "MARKER LIST TITLE": "Liste der Markierungen", - "MARKER LIST": "Markierungen", - "MARKER STATE PROMPT": "Marker Status", - "MARKER STATE": " Set marker state", - "MARKER_LIST": "Liste Makerierungen: {opName}", - "MARKERS BUTTON TITLE": "Markierungen", - "MAX_SPLITS": "Max Splits", - "MAX": "FΓ€cherfeld", - "MeetAgentPortalMarker": "Meet Agent", - "MERGE ON UPDATE": "Merge on update", - "MERGE_CHANGES_LOCAL": "Local changes", - "MERGE_CHANGES_MERGE": "Merge result", - "MERGE_CHANGES_REMOTE": "Remote changes", - "MERGE_LOCAL": "Keep local", - "MERGE_MESSAGE": "It seems that {opName} has local changes. Do you want to merge your modifications with the server OP, replace the local version with the server version, or cancel?", - "MERGE_REBASE": "Rebase", - "MERGE_REPLACE": "Replace", - "MERGE_TITLE": "Merge local&remote OP", - "MIN_SRC_PORT_LVL": "Minimum level required on source portal", - "MINUTES": "vor ({minutes} Minuten)", - "MM": "Maximale Feldanzahl", - "MULTI_M_TITLE": "Draw Max Layers", - "MULTI_M": "Maximale Feldanzahl", - "MULTIMAX": "Maximale Feldanzahl!", - "MULTIMAX2": "Multimax", - "MUST_NOT_BE_EMPTY": "Darf nicht leer sein.", - "MY_CAP_ID": "Kapsel ID", - "MY_COUNT": "Meine Anzahl", - "NAME_REQ": "Name benΓΆtigt", - "NAME": "Name: ", - "NEW_OP": "Neue Operation", - "NEW_TEAM_NAME": "Neuer Teamname", - "NEW_TEAM": "New Team", - "NEW_WAS_SERVER": "Neuer Wasabee Server", - "NEWOP BUTTON TITLE": "Neue Operation erstellen", - "NEWOP BUTTON": "Neue Op", - "NO_DATA": "Keine Daten", - "NO_DT_ITEMS": "Keine DrawTools Daten erkannt", - "NO_LABEL": "No label set", - "NO_PORT_SEL": "Keine Portale ausgewΓ€hlt.", - "NO_STOCK_INTEL": "Wasabee unterstΓΌtzt keine Standard Intel imports", - "NO_TITLE": "No title set", - "NO": "Nein", - "NOT LOGGED IN SHORT": "Nicht eingeloggt.", - "NOT LOGGED IN": "Nicht eingeloggt: {error}", - "NOT_LOADED": "Nicht vollstΓ€ndig geladen - bitte erneut probieren.", - "NOT_SET": "nicht gesetzt", - "NTNAME": "Name", - "OK": "OK", - "ON_HAND": "VerfΓΌgbar", - "ONION_WAS_TAKEN": "Onion", - "ONION": "Draw", - "ONLY_DT_IMP": " (nur fΓΌr DrawTools imports)", - "OP DELETED": "Operation removed from server: {opID}", - "OP PERM DENIED": "Keine Berechtigung fΓΌr Operation: {opID}", - "OP_BUTTON": "Operation", - "OP_CHECKLIST": "Operation Checkliste: {opName}", - "OP_NAME_UNSET": "Operationsname ist leer.", - "OP_PERMS": "Op Permissions", - "OP_SETTINGS_BUTTON": "Op βš™", - "OP_SETTINGS_TITLE": "Operation Settings", - "OPEN_REQUEST": "[ΓΆffne Anfrage]", - "OPER_COLOR": "Operation Color: ", - "OPER_NAME": "Operation Name: ", - "OPERATIONS": "Operationen", - "OPS BUTTON TITLE": "Operationen", - "OPS BUTTON": "Ops", - "ORDER": "Reihenfolge", - "OtherPortalAlert": "Other", - "PASTE_INSTRUCT": "FΓΌge einen Wasabee Drawtools export hier ein.\n\nWasabee kann nicht mit dem Standard intel format umgehen.\n\nEs gibt einen Experimentellen Import vom IITC-DrawTools format.\n\n Vor dem Importieren bitte sicherstellen das alles geladen ist und die IITC es zwischengespeichert hat. Jedes nicht zwischengespeicherte Portal wird verfΓ€lscht. \n\nDu musst die 'Wechsel' Funktion verwenden um die verfΓ€lschten Portale zu korrigieren. (Sie sollten bereits an der richtigen Position sein - aber dem falschen Portal zugeordnet).", - "pending": "Ausstehend", - "PENDING": "Ausstehend", - "PERMS": "{opName} permissions", - "PICK_DEST_FIRST": "Bitte wΓ€hle zuerst ein Zielportal!", - "PICK_TAR_FIRST": "Bitte wΓ€hle zuerst ein Startportal!", - "PICK_TARGETDEST_Portals": "Bitte wΓ€hle zuerst Startportal und Endportal!", - "PLEASE_SELECT_PORTAL": "Bitte wΓ€hle ein Portal", - "PORT_FAKE": " Portale. VerfΓ€lscht ", - "PORTAL KEY LIST": "Key list for portal {portalName}", - "PORTAL_COUNT": "{count} portals", - "PORTAL": "Portal", - "QD BUTTON CHANGE COLOR": "Click to change next links color", - "QD BUTTON END": "Klicken um das Feld zeichnen zu beenden", - "QD BUTTON TOGGLE MODE": "Click to change draw mode", - "QD CHANGE COLOR": "Change color", - "QD END": "Ende", - "QD TITLE": "Schnelle Layer Zeichnung", - "QD TOGGLE MODE": "Change mode", - "QDBASE": "Basis Link", - "QDCANCEL": "Zeichnen von Feld abbrechen", - "QDCONT": "Klicke auf ein Portal der Kette.", - "QDEND": "Erneut auf das Portal klicken, um die Zeichnung zu beenden.", - "QDNEXT": "Klicke auf das zweite Ankerportal.", - "QDSTART": "Klicke auf das erste Ankerportal.", - "READ_SHORT": "RO", - "READ": "lesen", - "RechargePortalAlert": "Recharge", - "REFERENCE_TIME": "Reference Time: ", - "REM_LOC_CP": "Remove local copy of {opName}", - "REMOVE_TEAM_CONFIRM_LABEL": "MΓΆchtest du {teamName} permanent vom Server entfernen?", - "REMOVE_TEAM_CONFIRM_TITLE": "Entferne Team {teamName}", - "REMOVE_TEAM": "Team entfernen: ", - "REMOVE": "Entfernen", - "RENAME_TEAM": "Team umbenennen: ", - "RENAME": "Umbenennen", - "REQUIRED": "BenΓΆtigt", - "RESET": "Reset", - "REVERSE": "Reverse", - "ROCKS_COM": "enl.rocks community: ", - "ROLE": "Rolle", - "SAVELINKS TITLE": "Save Links", - "SAVELINKS_DRAW": "Save Links", - "SAVELINKS": "Save Links", - "SECONDS": "vor ({seconds} Sekunden)", - "SEL_PORT_FIRST": "Bitte wΓ€hle zuerst die Ankerportale aus!", - "SEL_SB_ANCHOR": "WΓ€hle einen Anker, Zomme in das Areal und fΓΌge es zum Starburst hinzu.", - "SEL_SB_ANCHOR2": "Zoom out. Make sure portals have all loaded, then click draw.", - "SEL_SB_ANCHOR3": "Please be patient, it can take a bit.", - "SEL_SL_ANCHOR": "Select the portal to save the links of. Click save links button and look at checklist.", - "SEL_SRC_ANC2": "Lege Quelle und Anker 2 fest", - "SEL_SRC_PORT": "WΓ€hle ein Quellportal", - "SELECT PORTAL": "Portal zum senden auswΓ€hlen", - "SELECT_FAN_PORTALS": "WΓ€hle ein Ankerportal, wΓ€hle ein Startportal und ein Endportal, danach zoome in die Gegend des FΓ€chers. Warte bis alle Portale geladen sind. DrΓΌcke anschließend den 'FΓ€cherfeld' Knopf.", - "SELECT_FAN_PORTALS2": "Wait for all portals to load, then click draw.", - "SELECT_INSTRUCTIONS": "WΓ€hle zwei Ankerportale. Zoome in die Gegend der Portalkette - warte bis die Portale geladen sind und drΓΌcke den 'Maximale Feldanzahl' Knopf.", - "SELECT_MADRID_INSTRUCTIONS": "Select three anchor portals, zoom in on the area near the selected anchor, wait until the portals are loaded (portals must be on screen to be considered) then select the 'define spine region' button for the corresponding base links.", - "SELECT_ONION_PORTALS": "Layers build from the inside out. Zoom in to center and select starting portal, then zoom out to area.", - "SELF SWAP": "Du kannst das Portal nicht mit sich selbst tauschen - WΓ€hle ein anderes.", - "SEND ANALYTICS": "Send Anonymous Analytics", - "SEND LOCATION": "Sende Standort", - "SEND TARGET AGENT": "Select target recipient", - "SEND TARGET CONFIRM": "MΓΆchtest du {portalName} an {agent} senden?", - "SEND TARGET": "Sende Ziel", - "SEND_LOC": "Sende Standort", - "SET_3_PORT": "Bitte wΓ€hle zuerst drei Portale!", - "SET_COMMENT": "FΓΌge Kommentar hinzu", - "SET_LCOMMENT": "Setze Kommentar fΓΌr Link: ", - "SET_LINK_COMMENT": "Set comment for link: ", - "SET_LINKS_ZONES": "Set Links to Zones ", - "SET_MARKER_COMMENT": "Set comment for marker on: ", - "SET_MARKER_TYPE_TITLE": "Change marker type", - "SET_MARKERS_ZONES": "Set Markers to Zones", - "SET_MCOMMENT": "Setze Kommentar fΓΌr Markierung: {portalName}", - "SET_NEW_OP": "Bitte gebe einen neuen Operationnamen ein", - "SET_PCOMMENT": "Setze Kommentar fΓΌr Portal: {portalName}", - "SET_PORT_COMMENT": "Set comment for portal: ", - "SET_PORTAL_COMMENT": "Set Portal Comment", - "SET": "setzen", - "SETTINGS": "Wasabee Settings", - "SKINS_AVAILABLE": "There are {count} available skins.", - "SKINS_BUTTON": "Configure Skins", - "SKINS_DESCRIPTION": "Available skin packs are located in the right columns. Move skins you wish to use to the left columns.", - "SKINS_MANAGE_TITLE": "Manage skins", - "SKIP_CONFIRM_ALWAYS": "Never ask (use with caution)", - "SKIP_CONFIRM_ENTITY": "Only ask for team/op", - "SKIP_CONFIRM_NEVER": "Always ask", - "SKIP_CONFIRM": "Skip confirmation", - "SOURCE_PORT": "Quellportal", - "SQUAD": "Kader", - "STARBURST TITLE": "Starburst ", - "STARBURST_DRAW": "Draw", - "STARBURST": "Starburst", - "START_PORT": "Startportal", - "STATE": "Status", - "SUPPORT_INSTRUCT": "FΓΌr Hilfe trete bitte der Telegram Gruppe bei The Wasabee User Telegram Channel ", - "SWAP PROMPT": "MΓΆchtest du tauschen?: ", - "SWAP TITLE": "Portale tauschen", - "SWAP WITH": " mit ", - "SWAP": "Wechseln", - "SYNC DONE": "Download abgeschlossen
Klicken Sie HIER fΓΌr Hinweise, Tipps und Dokumentation.", - "SYNC": "Download verfΓΌgbarer Operationen", - "TARDEST_DIFF": "Start und Ziel mΓΌssen sich unterscheiden.", - "TARGET SENT": "Ziel gesendet", - "TEAM PERM DENIED": "Keine Berechtigung fΓΌr Team: {error}", - "TEAM STATE": "Share Location", - "TEAM_CREATED": "Team {teamName} erstellt.", - "TEAM_NAME": "Team Name", - "TEAM": "Team", - "TEAMS BUTTON TITLE": "Auflistung Wasabee Teams", - "TEAMS BUTTON": "Teams", - "TITLE": "title", - "TO_PORT": "zu Portal", - "TRAWL SKIP TILES": "Trawl Skip Tiles", - "TRAWL TITLE": "Trawl Lanes", - "TRAWL WARNING": "This will load the tile data under all drawn links. This is a slow process.", - "TRAWL_AUTOMARK": "Auto-mark blockers after trawling", - "TRAWL_BULK_LOAD_WARNING": "This method loads the tile data as quickly as possible. Use at your own risk.", - "TRAWL_BULK_LOAD": "Bulk Load Tile Data", - "TRAWL_CLEAR_MARKERS": "Clear virus/destroy markers before trawling", - "TRAWL_REMAINING": "{count} tiles remaining", - "TRAWL": "Trawl for Blockers", - "TRAWLING": "Trawling the lanes for blockers, close this dialog to stop", - "TYPE": "Typ", - "UNASSIGNED": "Nicht zugewiesenen", - "UNKNOWN": "Unbekannt", - "UPDATE HOVER NOT CHANGED": "{opName} lokal nicht verΓ€ndert", - "UPDATE HOVER": "UPDATE {opName} auf dem Server", - "UPDATE PERM DENIED": "Keine Berechtigung zum aktualisieren", - "UPDATE_CONFLICT_DESC": "The OP has been modified on server since last sync. Do you want to replace the server version by the current one?", - "UPDATE_CONFLICT_TITLE": "Conflict detected with server", - "UPDATE_COUNT": "Aktualisiere Anzahl", - "UPDATED": "Erfolgreich aktualisiert", - "UpgradePortalAlert": "Upgrade", - "UPLOAD BUTTON HOVER": "UPLOAD {opName} (aktuell nicht auf dem Server)", - "UPLOAD PERM DENIED": "Keine Berechtigung zum hochladen", - "UPLOADED": "Erfolgreich hochgeladen", - "USE PANES ON MOBILE": "Use panes (need reload)", - "USE_SWAP_INSTRUCT": ".Bitte nutze die Wechsel Funktion, um das verfΓ€lschte Portal mit dem korrekten Portal, um Fehler zu beseitigen.", - "USE_VALID_NAME": "Bitte verwende einen gΓΌltigen Operationsnamen", - "UseVirusPortalAlert": "Use Virus", - "VRLA DESC": "Ausgehend von der Anzahl und Typ von Link-Amps kΓΆnnte ein niedrigeres Portallevel ausreichen", - "VRLA": "L8+ einige VRLA", - "WASABEE BUTTON TITLE": "Wasabee: Es ist grΓΌn und bringt SchlΓΌmpfe zum heulen.", - "WASABEE_D_LIST": "Input Defensive Key Count", - "WD BUTTON TITLE": "Speicher Verteidigungs SchlΓΌssel", - "WD BUTTON": "W-D SchlΓΌssel", - "WEBVIEW VERIFY": "Verify Webview", - "WEBVIEW": "Webview Log In (iOS)", - "WRITE_SHORT": "RW", - "WRITE": "schreiben", - "WSERVER": "Server: {url}", - "YES": "Ja", - "YESNO_DEL": "Bist du dir sicher das du {opName} lΓΆschen willst?", - "ZONE_DRAW": "Click to set the zone boundaries", - "ZONE": "Zoniert", - "smallScreen": { - "ADD_LINKS": "+ Links", - "ADD_MARKER": "+ Marker", - "BLOCKER TITLE": "Blockers", - "CHECKLIST BUTTON": "Check", - "CLEAROPS BUTTON": "Clear", - "EXPORT OP": "Xport", - "FAN_FIELD3": "Fan", - "FANFIELD": "Draw", - "FANFIELD2": "Draw Fan Field", - "KEYS": "Keys", - "LOG IN": "Log In", - "LOG_OUT": "Log Out", - "MARKER LIST": "Markers", - "MARKERS BUTTON TITLE": "Markers", - "MAX": "Fan", - "MM": "Multi", - "MULTI_M_TITLE": "Draw Max Layers", - "MULTI_M": "Draw", - "NEWOP BUTTON": "New Op", - "OPS BUTTON": "Select OP", - "QD END": "End", - "STARBURST_DRAW": "Draw", - "STARBURST": "Star", - "TEAMS BUTTON": "Teams", - "WD BUTTON": "W-D Keys" - } -} diff --git a/src/code/ui/agent.d.ts b/src/code/ui/agent.d.ts new file mode 100644 index 000000000..42fbb6ccf --- /dev/null +++ b/src/code/ui/agent.d.ts @@ -0,0 +1,21 @@ +import WasabeeAgent from "../model/agent"; + +export function formatDisplay( + agent: WasabeeAgent, + teamID?: number | string +): HTMLAnchorElement; + +export function timeSinceformat(agent: WasabeeAgent): string; + +interface WLAgentOptions extends L.MarkerOptions { + agent: WasabeeAgent; + id: string; + zoom: number; +} + +export class WLAgent extends L.Marker { + options: WLAgentOptions; + constructor(agent: WasabeeAgent); + update(): this; + _getPopup(): HTMLDivElement; +} diff --git a/src/code/ui/agent.js b/src/code/ui/agent.js new file mode 100644 index 000000000..ef253b0ab --- /dev/null +++ b/src/code/ui/agent.js @@ -0,0 +1,252 @@ +import PortalUI from "./portal"; +import ConfirmDialog from "../dialogs/confirmDialog"; +import AgentDialog from "../dialogs/agentDialog"; +import { targetPromise } from "../server"; +import { getSelectedOperation } from "../selectedOp"; +import wX from "../wX"; + +import WasabeeAgent from "../model/agent"; +import { displayInfo, displayWarning } from "../error"; + +/** + * @param {WasabeeAgent} agent + * @returns html anchor with agent name (and verification states) + */ +function formatDisplay(agent) { + const display = L.DomUtil.create("a", "wasabee-agent-label"); + if (agent.Vverified || agent.rocks) { + L.DomUtil.addClass(display, "enl"); + } + if (agent.blacklisted) { + L.DomUtil.addClass(display, "res"); + } + L.DomEvent.on(display, "click", (ev) => { + L.DomEvent.stop(ev); + const ad = new AgentDialog({ gid: agent.id }); + ad.enable(); + }); + + let prefix = ""; + if (agent.communityname) prefix += "C"; + if (agent.Vverified) prefix += "V"; + else if (agent.vname === agent.name) prefix += "v"; + if (agent.rocks) prefix += "R"; + else if (agent.rocksname === agent.name) prefix += "r"; + if (agent.intelname) { + // no identity source exept intel + if (!agent.rocksname && !agent.vname) prefix += "I"; + // no verified source + else if (!agent.rocks && !agent.Vverified) prefix += "I"; + // match server preference + else if (agent.intelname === agent.name) prefix += "I"; + // match server preference, in lower case + else if (agent.intelname.toLowerCase() === agent.name.toLowerCase()) + prefix += "i"; + } + + display.textContent = prefix + ? `[${prefix}] ` + agent.getName() + : agent.getName(); + return display; +} + +function timeSinceformat(agent) { + if (!agent.date) return ""; + const date = Date.parse(agent.date + "Z"); + if (Number.isNaN(date)) return `(${agent.date} UTC)`; // FireFox Date.parse no good + if (date == 0) return ""; + + const seconds = Math.floor((Date.now() - date) / 1000); + if (seconds < 0) return ""; + let interval = Math.floor(seconds / 31536000 / 2592000 / 86400); + + if (interval > 1) return wX("AGES"); + interval = Math.floor(seconds / 3600); + if (interval > 1) return wX("HOURS", { hours: interval }); + interval = Math.floor(seconds / 60); + if (interval > 1) return wX("MINUTES", { minutes: interval }); + interval = Math.floor(seconds); + return wX("SECONDS", { seconds: interval }); +} + +// change this to return an L.Marker() to make the logic in mapDrawing simpler +function icon(agent, z = 7) { + if (z < 6) return globalIcon(); + if (z >= 6 && z < 9) return smallIcon(agent); + if (z >= 9 && z < 15) return mediumIcon(agent); + return bigIcon(agent); +} + +function iconSize(z = 7) { + if (z < 6) return [30, 30]; + if (z >= 6 && z < 9) return [36, 47]; + if (z >= 9 && z < 15) return [40, 52]; + return [46, 60]; +} + +function iconAnchor(z = 7) { + if (z < 6) return [15, 30]; + if (z >= 6 && z < 9) return [18, 47]; + if (z >= 9 && z < 15) return [20, 52]; + return [23, 60]; +} + +// XXX there has to be a way to apply the viewBox onto the paths, to get rid of that extra nonsense +function globalIcon() { + const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); + icon.setAttribute("viewBox", "200 70 630 520"); + icon.setAttribute("height", "30"); + icon.setAttribute("width", "30"); + icon.setAttribute( + "style", + "fill-rule: evenodd; clip-rule: evenodd; stroke-miterlimit: 10;" + ); + icon.innerHTML = ``; + return icon; +} + +// XXX resize this properly +function smallIcon(agent) { + const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); + icon.setAttribute("viewBox", "0 0 52 68"); + icon.innerHTML = ` + + + `; + return icon; +} + +// XXX resize this properly +function mediumIcon(agent) { + const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); + icon.setAttribute("viewBox", "0 0 52 68"); + icon.innerHTML = ` + + + `; + return icon; +} + +function bigIcon(agent) { + const icon = document.createElementNS("http://www.w3.org/2000/svg", "svg"); + icon.setAttribute("xmlns", "http://www.w3.org/2000/svg"); + icon.setAttribute("viewBox", "0 0 52 68"); + icon.innerHTML = ` + + + `; + return icon; +} + +const WLAgent = L.Marker.extend({ + initialize: function (agent) { + const zoom = window.map.getZoom(); + L.Marker.prototype.initialize.call(this, agent.latLng, { + title: agent.getName(), + icon: L.divIcon({ + className: "wasabee-agent-icon", + iconSize: iconSize(zoom), + iconAnchor: iconAnchor(zoom), + popupAnchor: L.point(0, -70), + html: icon(agent, zoom), + }), + id: agent.id, + agent: agent, + zoom: zoom, + }); + + this.bindPopup((layer) => layer._getPopup(), { + className: "wasabee-popup", + closeButton: false, + }); + + this.off("click", this._openPopup); + window.registerMarkerForOMS(this); + this.on("spiderfiedclick", this._openPopup); + }, + + update: function () { + const zoom = window.map.getZoom(); + if (this.options.zoom != zoom) { + this.options.zoom = zoom; + this.setIcon( + L.divIcon({ + className: "wasabee-agent-icon", + iconSize: iconSize(zoom), + iconAnchor: iconAnchor(zoom), + popupAnchor: L.point(0, -70), + html: icon(this.options.agent, zoom), + }) + ); + } else L.Marker.prototype.update.call(this); + }, + + _getPopup: function () { + const agent = this.options.agent; + const content = L.DomUtil.create("div", "wasabee-agent-popup"); + const title = L.DomUtil.create("div", "desc", content); + title.id = agent.id; + title.textContent = agent.getName(); + const time = L.DomUtil.create("div", "desc", content); + time.id = agent.id; + time.textContent = timeSinceformat(agent); + + WasabeeAgent.get(this.options.id) + .then(formatDisplay) + .then((fd) => { + title.textContent = ""; + title.appendChild(fd); + time.textContent = timeSinceformat(agent); + }); + + const sendTarget = L.DomUtil.create("button", null, content); + sendTarget.textContent = wX("SEND TARGET"); + L.DomEvent.on(sendTarget, "click", (ev) => { + L.DomEvent.stop(ev); + const selectedPortal = PortalUI.getSelected(); + if (!selectedPortal) { + displayWarning(wX("SELECT PORTAL")); + return; + } + + const d = new ConfirmDialog({ + title: wX("SEND TARGET"), + label: wX("SEND TARGET CONFIRM", { + portalName: PortalUI.displayName(selectedPortal), + agent: agent.getName(), + }), + type: "agent", + callback: async () => { + try { + await targetPromise(agent.id, selectedPortal); + displayInfo(wX("TARGET SENT")); + } catch (e) { + console.error(e); + } + }, + }); + d.enable(); + }); + + const op = getSelectedOperation(); + const assignments = L.DomUtil.create("ul", "assignments", content); + for (const m of op.markers) { + if (m.assignedTo != agent.id) continue; + const a = L.DomUtil.create("li", "assignment", assignments); + const portal = op.getPortal(m.portalId); + a.textContent = `${m.order}: ${wX(m.type)} `; + a.appendChild(PortalUI.displayFormat(portal)); + } + + return content; + }, +}); + +export default { + formatDisplay, + WLAgent, + timeSinceformat, +}; diff --git a/src/code/ui/anchor.d.ts b/src/code/ui/anchor.d.ts new file mode 100644 index 000000000..426aba2d6 --- /dev/null +++ b/src/code/ui/anchor.d.ts @@ -0,0 +1,10 @@ +import type WasabeeOp from "../model/operation"; +import PortalUI from "./portal"; + +export class WLAnchor extends PortalUI.WLPortal { + constructor(portalId: string, operation: WasabeeOp); + _popupContent(): any; + _linksButton(container: any): void; + _swapButton(container: any): void; + _deleteAction(): void; +} diff --git a/src/code/ui/anchor.js b/src/code/ui/anchor.js new file mode 100644 index 000000000..e717d59dd --- /dev/null +++ b/src/code/ui/anchor.js @@ -0,0 +1,101 @@ +import LinkListDialog from "../dialogs/linkListDialog"; +import { getSelectedOperation } from "../selectedOp"; +import { swapPortal, deletePortal } from "../uiCommands"; +import wX from "../wX"; + +import PortalUI from "./portal"; + +const WLAnchor = PortalUI.WLPortal.extend({ + type: "anchor", + + initialize: function (portalId, operation) { + let color = operation.color; + if (color == "main") + color = window.plugin.wasabee.skin.defaultOperationColor; + const icon = L.divIcon({ + className: "wasabee-anchor-icon", + shadowUrl: null, + iconAnchor: [12, 41], + iconSize: [25, 41], + popupAnchor: [0, -35], + html: L.Util.template( + '', + { color: color } + ), + }); + PortalUI.WLPortal.prototype.initialize.call(this, { + portalId: portalId, + id: portalId, + icon: icon, + }); + }, + + _popupContent: function () { + const operation = getSelectedOperation(); + const canWrite = operation.canWrite(); + const portal = operation.getPortal(this.options.portalId); + + const content = PortalUI.WLPortal.prototype._popupContent.call(this); + const desc = L.DomUtil.create("div", "desc", content); + desc.appendChild(PortalUI.displayFormat(portal)); + this._popupPortalComments(desc, portal, canWrite); + + const requiredKeys = L.DomUtil.create("div", "desc", content); + const onHand = operation.KeysOnHandForPortal(portal.id); + const required = operation.KeysRequiredForPortal(portal.id); + requiredKeys.textContent = wX("popup.anchor.keys", { onHand, required }); + + const buttonSet = L.DomUtil.create( + "div", + "wasabee-marker-buttonset", + content + ); + this._linksButton(buttonSet); + if (canWrite) { + this._swapButton(buttonSet); + this._deleteButton(buttonSet, wX("DELETE_ANCHOR")); + } + this._mapButton(buttonSet, wX("ANCHOR_GMAP")); + if (operation.canWriteServer()) + this._assignButton(buttonSet, wX("ASSIGN OUTBOUND"), portal); + if (operation.isOnCurrentServer()) + this._sendTargetButton(buttonSet, wX("SEND TARGET"), portal); + + return content; + }, + + _linksButton: function (container) { + const operation = getSelectedOperation(); + const portal = operation.getPortal(this.options.portalId); + const linksButton = L.DomUtil.create("button", null, container); + linksButton.textContent = wX("LINKS"); + L.DomEvent.on(linksButton, "click", (ev) => { + L.DomEvent.stop(ev); + const lld = new LinkListDialog({ portal: portal }); + lld.enable(); + this.closePopup(); + }); + }, + + _swapButton: function (container) { + const operation = getSelectedOperation(); + const portal = operation.getPortal(this.options.portalId); + const swapButton = L.DomUtil.create("button", null, container); + swapButton.textContent = wX("SWAP"); + L.DomEvent.on(swapButton, "click", (ev) => { + L.DomEvent.stop(ev); + swapPortal(operation, portal); + this.closePopup(); + }); + }, + + _deleteAction: function () { + const operation = getSelectedOperation(); + const portal = operation.getPortal(this.options.portalId); + deletePortal(operation, portal); + }, +}); + +export default { + WLAnchor, +}; diff --git a/src/code/ui/link.d.ts b/src/code/ui/link.d.ts new file mode 100644 index 000000000..1f674dbb4 --- /dev/null +++ b/src/code/ui/link.d.ts @@ -0,0 +1,25 @@ +import type WasabeeOp from "../model/operation"; +import type WasabeeLink from "../model/link"; + +export function displayFormat( + link: WasabeeLink, + operation: WasabeeOp, + smallScreen?: boolean +): HTMLDivElement; + +export function minLevel( + link: WasabeeLink, + operation: WasabeeOp +): HTMLSpanElement; + +interface WLLinkOptions extends L.PolylineOptions { + opID: OpID; + linkID: LinkID; +} + +export class WLLink extends L.GeodesicPolyline { + _wlink: WasabeeLink; + options: WLLinkOptions; + constructor(link: WasabeeLink, operation: WasabeeOp); + _getPopup(): HTMLDivElement; +} diff --git a/src/code/ui/link.js b/src/code/ui/link.js new file mode 100644 index 000000000..d132f6384 --- /dev/null +++ b/src/code/ui/link.js @@ -0,0 +1,148 @@ +import AssignDialog from "../dialogs/assignDialog"; +import { getSelectedOperation } from "../selectedOp"; +import { convertColorToHex } from "../auxiliar"; +import { addToColorList } from "../skin"; +import wX from "../wX"; + +import PortalUI from "./portal"; + +// returns a DOM object appropriate for display +// do we still need the operation here? +function displayFormat(link, operation, smallScreen = false) { + const d = L.DomUtil.create("div", null); + d.appendChild( + PortalUI.displayFormat(operation.getPortal(link.fromPortalId), smallScreen) + ); + const arrow = L.DomUtil.create("span", "wasabee-link-seperator", d); + arrow.style.color = convertColorToHex(link.getColor(operation)); + const picker = L.DomUtil.create("input", "hidden-color-picker", arrow); + picker.type = "color"; + picker.value = convertColorToHex(link.getColor(operation)); + picker.setAttribute("list", "wasabee-colors-datalist"); + picker.disabled = !operation.canWrite(); + + L.DomEvent.on(arrow, "click", () => { + picker.click(); + }); + + L.DomEvent.on(picker, "change", (ev) => { + link.setColor(ev.target.value, operation); + addToColorList(ev.target.value); + }); + + d.appendChild( + PortalUI.displayFormat(operation.getPortal(link.toPortalId), smallScreen) + ); + return d; +} + +function minLevel(link, operation) { + const b = link.length(operation); + let s = wX("UNKNOWN"); + const a = L.DomUtil.create("span", null); + + if (b > 6881280) { + s = wX("IMPOSSIBLE"); + } else { + if (b > 1966080) { + s = wX("VRLA"); + a.title = wX("VRLA DESC"); + a.classList.add("help"); + } else { + if (b > 655360) { + s = wX("LA"); + a.title = wX("LA DESC"); + a.classList.add("help"); + } else { + const d = Math.max(1, Math.ceil(8 * Math.pow(b / 160, 0.25)) / 8); + const msd = 8 * (d - Math.floor(d)); + s = "L" + d; + if (0 != msd) { + if (!(1 & msd)) { + s = s + "\u2007"; + } + if (!(1 & msd || 2 & msd)) { + s = s + "\u2007"; + } + s = + s + + (" = L" + + Math.floor(d) + + "0\u215b\u00bc\u215c\u00bd\u215d\u00be\u215e".charAt(msd)); + } + } + } + } + a.textContent = s; + return a; +} + +const WLLink = L.GeodesicPolyline.extend({ + initialize: function (link, operation) { + const latLngs = link.getLatLngs(operation); + let color = link.getColor(operation); + if (color == "main") + color = window.plugin.wasabee.skin.defaultOperationColor; + const options = L.extend( + { + color: color, + opID: operation.ID, + linkID: link.ID, + }, + window.plugin.wasabee.skin.linkStyle + ); + if (link.assignedTo) options.dashArray = options.assignedDashArray; + + L.GeodesicPolyline.prototype.initialize.call(this, latLngs, options); + + this._wlink = link; + + this.bindPopup((layer) => layer._getPopup(), { + className: "wasabee-popup", + closeButton: false, + }); + }, + + _getPopup: function () { + const operation = getSelectedOperation(); + const link = this._wlink; + const div = L.DomUtil.create("div", "wasabee-link-popup"); + L.DomUtil.create("div", null, div).appendChild( + displayFormat(link, operation) + ); + if (link.comment) + L.DomUtil.create("div", "enl", div).textContent = link.comment; + L.DomUtil.create("div", "enl", div).textContent = "# " + link.order; + const buttonset = L.DomUtil.create("div", "buttonset", div); + if (operation.canWrite()) { + const del = L.DomUtil.create("button", null, buttonset); + del.textContent = wX("DELETE_LINK"); + L.DomEvent.on(del, "click", (ev) => { + L.DomEvent.stop(ev); + operation.removeLink(link.fromPortalId, link.toPortalId); + }); + const rev = L.DomUtil.create("button", null, buttonset); + rev.textContent = wX("REVERSE"); + L.DomEvent.on(rev, "click", (ev) => { + L.DomEvent.stop(ev); + operation.reverseLink(link.fromPortalId, link.toPortalId); + }); + } + if (operation.canWriteServer()) { + const assignButton = L.DomUtil.create("button", null, buttonset); + assignButton.textContent = wX("ASSIGN"); + L.DomEvent.on(assignButton, "click", (ev) => { + L.DomEvent.stop(ev); + const ad = new AssignDialog({ target: link }); + ad.enable(); + }); + } + return div; + }, +}); + +export default { + displayFormat, + minLevel, + WLLink, +}; diff --git a/src/code/ui/marker.d.ts b/src/code/ui/marker.d.ts new file mode 100644 index 000000000..6844f7365 --- /dev/null +++ b/src/code/ui/marker.d.ts @@ -0,0 +1,18 @@ +import type { WLPortal } from "./portal"; +import type WasabeeMarker from "../model/marker"; +import type WasabeeOp from "../model/operation"; + +export class WLMarker extends WLPortal { + state: string; + constructor(marker: WasabeeMarker); + setState(state: string): void; + _popupContent(): any; + _popupMarkerComment(container: any, marker: any, canWrite: any): void; + _popupAssignState(container: any, marker: any): Promise; + _stateButton(container: any, marker: any): void; + _deleteAction(): void; + _setComment(ev: any): void; + _setMarkerType(ev: any): void; +} + +export function displayFormat(marker: WasabeeMarker, operation: WasabeeOp): HTMLSpanElement; diff --git a/src/code/ui/marker.js b/src/code/ui/marker.js new file mode 100644 index 000000000..bee205f1b --- /dev/null +++ b/src/code/ui/marker.js @@ -0,0 +1,175 @@ +import WasabeeAgent from "../model/agent"; + +import SetCommentDialog from "../dialogs/setCommentDialog"; +import MarkerChangeDialog from "../dialogs/markerChangeDialog"; +import StateDialog from "../dialogs/stateDialog"; +import { getSelectedOperation } from "../selectedOp"; +import { deleteMarker } from "../uiCommands"; + +import AgentUI from "./agent"; +import PortalUI from "./portal"; + +import wX from "../wX"; + +function displayFormat(marker, operation) { + const portal = operation.getPortal(marker.portalId); + + if (portal == null) { + console.log("null portal getting marker popup"); + return (L.DomUtil.create("div", "").textContent = "invalid portal"); + } + + const desc = L.DomUtil.create("span"); + const kind = L.DomUtil.create("span", `${marker.type}`, desc); + kind.textContent = wX(marker.type); + desc.appendChild(PortalUI.displayFormat(portal)); + return desc; +} + +const WLMarker = PortalUI.WLPortal.extend({ + type: "marker", + + initialize: function (marker) { + PortalUI.WLPortal.prototype.initialize.call(this, { + portalId: marker.portalId, + id: marker.ID, + state: marker.state, + icon: L.divIcon({ + className: `wasabee-marker-icon ${marker.type} wasabee-status-${marker.state}`, + shadowUrl: null, + iconSize: L.point(24, 40), + iconAnchor: L.point(12, 40), + popupAnchor: L.point(-1, -48), + }), + }); + }, + + setState: function (state) { + if (state != this.options.state) { + L.DomUtil.removeClass(this._icon, `wasabee-status-${this.options.state}`); + L.DomUtil.addClass(this._icon, `wasabee-status-${state}`); + this.options.state = state; + } + }, + + _popupContent: function () { + const operation = getSelectedOperation(); + const marker = operation.getMarker(this.options.id); + const portal = operation.getPortal(marker.portalId); + + if (portal == null) { + console.log("null portal getting marker popup"); + return (L.DomUtil.create("div", "wasabee-marker-popup").textContent = + "invalid portal"); + } + + const canWrite = operation.canWrite(); + + const content = PortalUI.WLPortal.prototype._popupContent.call(this); + + const desc = L.DomUtil.create("div", "desc", content); + const kind = L.DomUtil.create( + "span", + `wasabee-marker-popup-kind ${marker.type}`, + desc + ); + kind.textContent = wX(marker.type); + desc.appendChild(PortalUI.displayFormat(portal)); + if (canWrite) { + kind.href = "#"; + L.DomEvent.on(kind, "click", this._setMarkerType, this); + } + this._popupMarkerComment(desc, marker, canWrite); + this._popupPortalComments(desc, portal, canWrite); + + this._popupAssignState(content, marker); + + const buttonSet = L.DomUtil.create( + "div", + "wasabee-marker-buttonset", + content + ); + if (canWrite) this._deleteButton(buttonSet, wX("DELETE_ANCHOR")); + if (operation.canWriteServer()) + this._assignButton(buttonSet, wX("ASSIGN"), marker); + if (canWrite) this._stateButton(buttonSet, marker); + if (operation.isOnCurrentServer()) + this._sendTargetButton(buttonSet, wX("SEND TARGET"), marker); + this._mapButton(buttonSet, wX("ANCHOR_GMAP")); + + return content; + }, + + _popupMarkerComment: function (container, marker, canWrite) { + const comment = L.DomUtil.create( + "div", + "wasabee-marker-popup-comment", + container + ); + comment.textContent = marker.comment || wX("SET_COMMENT"); + if (canWrite) L.DomEvent.on(comment, "click", this._setComment, this); + }, + + _popupAssignState: async function (container, marker) { + const assignment = L.DomUtil.create( + "div", + "wasabee-popup-assignment", + container + ); + if (marker.state != "completed" && marker.assignedTo) { + try { + const a = await WasabeeAgent.get(marker.assignedTo); + assignment.textContent = wX("ASS_TO"); // FIXME convert formatDisplay to html and add as value to wX + if (a) assignment.appendChild(AgentUI.formatDisplay(a)); + else assignment.textContent += " " + marker.assignedTo; + } catch (err) { + console.error(err); + } + } + }, + + _stateButton: function (container, marker) { + const operation = getSelectedOperation(); + const stateButton = L.DomUtil.create("button", null, container); + stateButton.textContent = wX("popup.marker.state_button"); + L.DomEvent.on(stateButton, "click", (ev) => { + L.DomEvent.stop(ev); + const sd = new StateDialog({ target: marker, opID: operation.ID }); + sd.enable(); + this.closePopup(); + }); + }, + + _deleteAction: function () { + const operation = getSelectedOperation(); + const portal = operation.getPortal(this.options.portalId); + const marker = operation.getMarker(this.options.id); + deleteMarker(operation, marker, portal); + }, + + _setComment: function (ev) { + L.DomEvent.stop(ev); + const operation = getSelectedOperation(); + const marker = operation.getMarker(this.options.id); + const scd = new SetCommentDialog({ + target: marker, + operation: operation, + }); + scd.enable(); + this.closePopup(); + }, + + _setMarkerType: function (ev) { + L.DomEvent.stop(ev); + const operation = getSelectedOperation(); + const marker = operation.getMarker(this.options.id); + const ch = new MarkerChangeDialog({ marker: marker }); + ch.enable(); + this.closePopup(); + }, +}); + +export default { + WLMarker, + displayFormat, +}; diff --git a/src/code/ui/portal.d.ts b/src/code/ui/portal.d.ts new file mode 100644 index 000000000..a38578cf6 --- /dev/null +++ b/src/code/ui/portal.d.ts @@ -0,0 +1,37 @@ +import WasabeePortal from "../model/portal"; +import { IITC } from "../../types/iitc"; + +export function fromIITC(p: IITC.Portal): WasabeePortal; + +export function team(portal: any): string; + +export function displayName(portal: any): any; + +export function displayFormat( + portal: any, + shortName?: boolean +): HTMLAnchorElement; + +export function get(id: any): WasabeePortal; + +export function getSelected(): WasabeePortal; + +interface WLPortalOptions extends L.MarkerOptions { + portalId: string; + title?: string; + id: string; +} + +export class WLPortal extends L.Marker { + type: string; + options: WLPortalOptions; + constructor(options: WLPortalOptions); + _popupContent(): HTMLDivElement; + _popupPortalComments(container: any, portal: any, canWrite: any): void; + _setPortalComment(ev: any): void; + _assignButton(container: any, text: any, target: any): void; + _deleteAction(): void; + _deleteButton(container: any, text: any): void; + _sendTargetButton(container: any, text: any, target: any): void; + _mapButton(container: any, text: any): void; +} diff --git a/src/code/ui/portal.js b/src/code/ui/portal.js new file mode 100644 index 000000000..95bbff0dd --- /dev/null +++ b/src/code/ui/portal.js @@ -0,0 +1,233 @@ +import WasabeePortal from "../model/portal"; + +import { getSelectedOperation } from "../selectedOp"; +import AssignDialog from "../dialogs/assignDialog"; +import SendTargetDialog from "../dialogs/sendTargetDialog"; +import SetCommentDialog from "../dialogs/setCommentDialog"; +import wX from "../wX"; + +function fromIITC(p) { + // we have all the details + if (p && p.options && p.options.data && p.options.guid) { + const data = p.options.data; + const id = p.options.guid; + if (data.title) { + return new WasabeePortal({ + id: id, + name: data.title, + lat: (data.latE6 / 1e6).toFixed(6), + lng: (data.lngE6 / 1e6).toFixed(6), + }); + } + // do we have enough to fake it? + if (data.latE6) { + return WasabeePortal.fake( + (data.latE6 / 1e6).toFixed(6), + (data.lngE6 / 1e6).toFixed(6), + id + ); + } + } + // nothing to get + return null; +} + +function team(portal) { + if (window.portals[portal.id] && window.portals[portal.id].options.data) + return window.portals[portal.id].options.data.team; + return ""; +} + +function displayName(portal) { + if (portal.pureFaked) return wX("FAKED", { portalId: portal.id }); + if (portal.loading) return wX("LOADING1", { portalGuid: portal.id }); + return portal.name; +} + +function displayFormat(portal, shortName = false) { + const pt = portal.latLng; + const v = `${portal.lat},${portal.lng}`; + const name = displayName(portal); + const e = L.DomUtil.create("a", "wasabee-portal"); + if (shortName === true && portal.name.length > 12) { + e.textContent = name.slice(0, 8) + "..."; + } else { + e.textContent = name; + } + + const t = team(portal); + if (t == "E") { + e.classList.add("enl"); + } + if (t == "R") { + e.classList.add("res"); + } + if (t == "N") { + e.classList.add("unclaimed"); + } + + // e.title = this.name; + e.href = `/intel?ll=${v}&pll=${v}`; + + L.DomEvent.on(e, "click", (event) => { + if (window.selectedPortal != portal.id && portal.id.length == 35) + window.renderPortalDetails(portal.id); + else window.map.panTo(pt); + event.preventDefault(); + return false; + }).on(e, "dblclick", (event) => { + if (window.selectedPortal != portal.id && portal.id.length == 35) + window.renderPortalDetails(portal.id); + if (window.map.getBounds().contains(pt)) + window.zoomToAndShowPortal(portal.id, pt); + else window.map.panTo(pt); + event.preventDefault(); + return false; + }); + return e; +} + +function get(id) { + return fromIITC(window.portals[id]); +} + +function getSelected() { + return window.selectedPortal ? get(window.selectedPortal) : null; +} + +// common part for marker and anchors +const WLPortal = L.Marker.extend({ + type: "portal", + + initialize: function (options) { + const operation = getSelectedOperation(); + const portal = operation.getPortal(options.portalId); + options.title = portal.name; + L.Marker.prototype.initialize.call(this, portal.latLng, options); + this.bindPopup((layer) => layer._popupContent(), { + className: "wasabee-popup", + closeButton: false, + }); + + this.off("click", this._openPopup); + window.registerMarkerForOMS(this); + this.on("spiderfiedclick", this._openPopup); + }, + + _popupContent: function () { + const div = L.DomUtil.create("div", `wasabee-${this.type}-popup`); + return div; + }, + + _popupPortalComments: function (container, portal, canWrite) { + const portalComment = L.DomUtil.create( + "div", + "wasabee-portal-comment", + container + ); + const pcLink = L.DomUtil.create("a", null, portalComment); + pcLink.textContent = portal.comment || wX("SET_PORTAL_COMMENT"); + if (canWrite) { + pcLink.href = "#"; + L.DomEvent.on(pcLink, "click", this._setPortalComment, this); + } + if (portal.hardness) { + const portalHardness = L.DomUtil.create( + "div", + "wasabee-portal-hardness", + container + ); + const phLink = L.DomUtil.create("a", null, portalHardness); + phLink.textContent = portal.hardness; + if (canWrite) { + phLink.href = "#"; + L.DomEvent.on(phLink, "click", this._setPortalComment, this); + } + } + }, + + _setPortalComment: function (ev) { + L.DomEvent.stop(ev); + const operation = getSelectedOperation(); + const portal = operation.getPortal(this.options.portalId); + const scd = new SetCommentDialog({ + target: portal, + operation: operation, + }); + scd.enable(); + this.closePopup(); + }, + + _assignButton: function (container, text, target) { + const assignButton = L.DomUtil.create("button", null, container); + assignButton.textContent = text; + L.DomEvent.on(assignButton, "click", (ev) => { + L.DomEvent.stop(ev); + const ad = new AssignDialog({ target: target }); + ad.enable(); + this.closePopup(); + }); + }, + + _deleteButton: function (container, text) { + const deleteButton = L.DomUtil.create("button", null, container); + deleteButton.textContent = text; + L.DomEvent.on(deleteButton, "click", (ev) => { + L.DomEvent.stop(ev); + if (this._deleteAction) this._deleteAction(); + this.closePopup(); + }); + }, + + _sendTargetButton: function (container, text, target) { + const sendButton = L.DomUtil.create("button", null, container); + sendButton.textContent = text; + L.DomEvent.on(sendButton, "click", (ev) => { + L.DomEvent.stop(ev); + const std = new SendTargetDialog({ target: target }); + std.enable(); + this.closePopup(); + }); + }, + + _mapButton: function (container, text) { + const gmapButton = L.DomUtil.create("button", null, container); + gmapButton.textContent = text; + L.DomEvent.on(gmapButton, "click", (ev) => { + L.DomEvent.stop(ev); + this.closePopup(); + const latLng = this.getLatLng(); + // use intent on android + if ( + typeof window.android !== "undefined" && + window.android && + window.android.intentPosLink + ) { + window.android.intentPosLink( + +latLng.lat, + +latLng.lng, + window.map.getZoom(), + this.options.title, + true + ); + } else { + window.open( + "https://www.google.com/maps/search/?api=1&query=" + + latLng.lat + + "," + + latLng.lng + ); + } + }); + }, +}); + +export default { + fromIITC, + displayName, + displayFormat, + get, + getSelected, + team, + WLPortal, +}; diff --git a/src/code/ui/zone.d.ts b/src/code/ui/zone.d.ts new file mode 100644 index 000000000..e51e08f99 --- /dev/null +++ b/src/code/ui/zone.d.ts @@ -0,0 +1,5 @@ +import type WasabeeZone from "../model/zone"; + +export class WLZone extends L.LayerGroup { + constructor(zone: WasabeeZone); +} diff --git a/src/code/ui/zone.js b/src/code/ui/zone.js new file mode 100644 index 000000000..a74c60d7e --- /dev/null +++ b/src/code/ui/zone.js @@ -0,0 +1,31 @@ +const zoneShape = { + stroke: false, + opacity: 0.7, + fill: true, +}; + +const WLZone = L.LayerGroup.extend({ + initialize: function (zone) { + zone.points.sort((a, b) => { + return a.position - b.position; + }); + let layer; + if (zone.points.length == 1) + layer = L.marker(zone.points[0], { + icon: new L.DivIcon.ColoredSvg(zone.color), + }); + else if (zone.points.length == 2) + layer = L.polyline(zone.points, { color: zone.color }); + else + layer = L.polygon(zone.points, { + color: zone.color, + shapeOptions: zoneShape, + interactive: false, + }); + L.LayerGroup.prototype.initialize.call(this, [layer]); + }, +}); + +export default { + WLZone, +}; diff --git a/src/code/uiCommands.js b/src/code/uiCommands.ts similarity index 61% rename from src/code/uiCommands.js rename to src/code/uiCommands.ts index 2b0bfcf8f..ddf157cf6 100644 --- a/src/code/uiCommands.js +++ b/src/code/uiCommands.ts @@ -1,8 +1,10 @@ -import WasabeeOp from "./operation"; -import WasabeePortal from "./portal"; +import WasabeeOp from "./model/operation"; +import WasabeePortal from "./model/portal"; +import WasabeeBlocker from "./model/blocker"; +import WasabeeMarker from "./model/marker"; import ConfirmDialog from "./dialogs/confirmDialog"; import MergeDialog from "./dialogs/mergeDialog"; -import WasabeeMe from "./me"; +import WasabeeMe from "./model/me"; import wX from "./wX"; import { opPromise, GetWasabeeServer, locationPromise } from "./server"; import AuthDialog from "./dialogs/authDialog"; @@ -15,30 +17,41 @@ import { duplicateOperation, } from "./selectedOp"; -export function addPortal(operation, portal) { +import PortalUI from "./ui/portal"; +import { + displayError, + displayInfo, + displayWarning, + ServerError, +} from "./error"; +import { deleteDatabase } from "./db"; +import { constants } from "./static"; +import type { Wasabee } from "./init"; + +export function addPortal(operation: WasabeeOp, portal: WasabeePortal) { if (!portal) { - alert(wX("SELECT PORTAL")); + displayError(wX("SELECT PORTAL")); return; } operation.addPortal(portal); } -export function swapPortal(operation, portal) { - const selectedPortal = WasabeePortal.getSelected(); +export function swapPortal(operation: WasabeeOp, portal: WasabeePortal) { + const selectedPortal = PortalUI.getSelected(); if (!selectedPortal) { - alert(wX("SELECT PORTAL")); + displayError(wX("SELECT PORTAL")); return; } if (portal.id === selectedPortal.id) { - alert(wX("SELF SWAP")); + displayError(wX("SELF SWAP")); return; } const pr = L.DomUtil.create("div", null); pr.textContent = wX("SWAP PROMPT"); - pr.appendChild(portal.displayFormat()); + pr.appendChild(PortalUI.displayFormat(portal)); L.DomUtil.create("span", null, pr).textContent = wX("SWAP WITH"); - pr.appendChild(selectedPortal.displayFormat()); + pr.appendChild(PortalUI.displayFormat(selectedPortal)); L.DomUtil.create("span", null, pr).textContent = "?"; const con = new ConfirmDialog({ title: wX("SWAP TITLE"), @@ -51,10 +64,10 @@ export function swapPortal(operation, portal) { con.enable(); } -export function deletePortal(operation, portal) { +export function deletePortal(operation: WasabeeOp, portal: WasabeePortal) { const pr = L.DomUtil.create("div", null); pr.textContent = wX("DELETE ANCHOR PROMPT"); - pr.appendChild(portal.displayFormat()); + pr.appendChild(PortalUI.displayFormat(portal)); const con = new ConfirmDialog({ title: wX("DELETE ANCHOR TITLE"), label: pr, @@ -67,10 +80,14 @@ export function deletePortal(operation, portal) { con.enable(); } -export function deleteMarker(operation, marker, portal) { +export function deleteMarker( + operation: WasabeeOp, + marker: WasabeeMarker, + portal: WasabeePortal +) { const pr = L.DomUtil.create("div", null); pr.textContent = wX("DELETE MARKER PROMPT"); - pr.appendChild(portal.displayFormat()); + pr.appendChild(PortalUI.displayFormat(portal)); const con = new ConfirmDialog({ title: wX("DELETE MARKER TITLE"), label: pr, @@ -83,10 +100,10 @@ export function deleteMarker(operation, marker, portal) { con.enable(); } -export function clearAllItems(operation) { +export function clearAllItems(operation: WasabeeOp) { const con = new ConfirmDialog({ - title: `Clear: ${operation.name}`, - label: `Do you want to reset ${operation.name}?`, + title: wX("dialog.clear_all.title", { opName: operation.name }), + label: wX("dialog.clear_all.text", { opName: operation.name }), type: "operation", callback: () => { operation.clearAllItems(); @@ -96,10 +113,10 @@ export function clearAllItems(operation) { con.enable(); } -export function clearAllLinks(operation) { +export function clearAllLinks(operation: WasabeeOp) { const con = new ConfirmDialog({ - title: `Clear Links: ${operation.name}`, - label: `Do you want to remove all links from ${operation.name}?`, + title: wX("dialog.clear_links.title", { opName: operation.name }), + label: wX("dialog.clear_links.text", { opName: operation.name }), type: "operation", callback: () => { operation.clearAllLinks(); @@ -109,10 +126,10 @@ export function clearAllLinks(operation) { con.enable(); } -export function clearAllMarkers(operation) { +export function clearAllMarkers(operation: WasabeeOp) { const con = new ConfirmDialog({ - title: `Clear Markers: ${operation.name}`, - label: `Do you want to remove all markers from ${operation.name}?`, + title: wX("dialog.clear_markers.title", { opName: operation.name }), + label: wX("dialog.clear_markers.text", { opName: operation.name }), type: "operation", callback: () => { operation.clearAllMarkers(); @@ -126,20 +143,26 @@ export function listenForAddedPortals(newPortal) { if (!newPortal.portal.options.data.title) return; const op = getSelectedOperation(); - op.updatePortal(WasabeePortal.fromIITC(newPortal.portal)); + const portal = PortalUI.fromIITC(newPortal.portal); + op.updatePortal(portal); + WasabeeBlocker.updatePortal(op, portal).then((r) => { + if (r) window.map.fire("wasabee:crosslinks:update"); + }); } export function listenForPortalDetails(e) { if (!e.success) return; + const portal = new WasabeePortal({ + id: e.guid, + name: e.details.title, + lat: (e.details.latE6 / 1e6).toFixed(6), + lng: (e.details.lngE6 / 1e6).toFixed(6), + }); const op = getSelectedOperation(); - op.updatePortal( - new WasabeePortal({ - id: e.guid, - name: e.details.title, - lat: (e.details.latE6 / 1e6).toFixed(6), - lng: (e.details.lngE6 / 1e6).toFixed(6), - }) - ); + op.updatePortal(portal); + WasabeeBlocker.updatePortal(op, portal).then((r) => { + if (r) window.map.fire("wasabee:crosslinks:update"); + }); } // This is what should be called to add to the queue @@ -191,7 +214,8 @@ function pdqDoNext() { window.portalDetail.request(p); } -export function loadFaked(operation, force = false) { +// load faked op portals +export function loadFaked(operation: WasabeeOp, force = false) { const flag = localStorage[window.plugin.wasabee.static.constants.AUTO_LOAD_FAKED] || false; @@ -199,11 +223,25 @@ export function loadFaked(operation, force = false) { // local storage always returns as string if (flag !== "true" && !force) return; - const f = new Array(); + const f = []; for (const x of operation.fakedPortals) f.push(x.id); if (f.length > 0) getPortalDetails(f); } +// load faked blocker portals +export async function loadBlockerFaked(operation: WasabeeOp, force = false) { + const flag = + localStorage[window.plugin.wasabee.static.constants.AUTO_LOAD_FAKED] || + false; + + // local storage always returns as string + if (flag !== "true" && !force) return; + + const bp = await WasabeeBlocker.getPortals(operation); + const f = bp.filter((p) => p.id === p.name).map((p) => p.id); + if (f.length > 0) getPortalDetails(f); +} + export function sendLocation() { if (!WasabeeMe.isLoggedIn()) return; const sl = @@ -228,7 +266,7 @@ export function sendLocation() { ); } -export function getAllPortalsOnScreen(operation) { +export function getAllPortalsOnScreen(operation: WasabeeOp) { const bounds = window.map.getBounds(); const x = []; for (const portal in window.portals) { @@ -236,22 +274,30 @@ export function getAllPortalsOnScreen(operation) { if ( operation.containsMarkerByID( window.portals[portal].options.guid, - window.plugin.wasabee.static.constants.MARKER_TYPE_EXCLUDE + WasabeeMarker.constants.MARKER_TYPE_EXCLUDE ) ) continue; - const wp = WasabeePortal.fromIITC(window.portals[portal]); + const wp = PortalUI.fromIITC(window.portals[portal]); if (wp) x.push(wp); } } return x; } -export function getAllPortalsLinked(operation, originPortal) { +export function getAllPortalsLinked( + operation: WasabeeOp, + originPortal: WasabeePortal +) { const x = []; for (const link in window.links) { const p = window.links[link]; + if ( + operation.containsLinkFromTo(p.options.data.oGuid, p.options.data.dGuid) + ) + continue; + const linkPortal1 = new WasabeePortal({ id: p.options.data.oGuid, lat: (p.options.data.oLatE6 / 1e6).toFixed(6), @@ -268,9 +314,6 @@ export function getAllPortalsLinked(operation, originPortal) { comment: "out", }); - if (operation.containsLinkFromTo(linkPortal1, linkPortal2)) { - continue; - } if (linkPortal1.id === originPortal.id) { x.push(linkPortal2); } @@ -282,59 +325,50 @@ export function getAllPortalsLinked(operation, originPortal) { return x; } -// this is the test point used in several auto-draws -// settings allow there to be several different due to -// rouding errors resulting from long distances -export function testPortal(recursed = false) { - let urp = - localStorage[ - window.plugin.wasabee.static.constants.MULTIMAX_UNREACHABLE_KEY - ]; - if (!urp) { - urp = '{"lat":-74.2,"lng":-143.4}'; - localStorage[ - window.plugin.wasabee.static.constants.MULTIMAX_UNREACHABLE_KEY - ] = urp; - } - - let parsed = null; - try { - parsed = JSON.parse(urp); - } catch (err) { - if (!recursed) { - delete localStorage[ - window.plugin.wasabee.static.constants.MULTIMAX_UNREACHABLE_KEY - ]; - return testPortal(true); +// recursive function to auto-mark blockers +export async function blockerAutomark(operation: WasabeeOp, first = true) { + const blockers = await WasabeeBlocker.getAll(operation); + if (first) { + operation.startBatchMode(); + // add blocker portals + for (const b of blockers) { + operation._addPortal( + new WasabeePortal({ + id: b.from, + name: b.fromPortal.name, + lat: b.fromPortal.lat, + lng: b.fromPortal.lng, + }) + ); + operation._addPortal( + new WasabeePortal({ + id: b.to, + name: b.toPortal.name, + lat: b.toPortal.lat, + lng: b.toPortal.lng, + }) + ); } } - - // if recrused and still getting garbage, we have a problem - return parsed; -} - -// recursive function to auto-mark blockers -export function blockerAutomark(operation, first = true) { - if (first) operation.startBatchMode(); // build count list - const portals = new Array(); - for (const b of operation.blockers) { + const portals: PortalID[] = []; + for (const b of blockers) { if ( !operation.containsMarkerByID( - b.fromPortalId, - window.plugin.wasabee.static.constants.MARKER_TYPE_EXCLUDE + b.from, + WasabeeMarker.constants.MARKER_TYPE_EXCLUDE ) ) - portals.push(b.fromPortalId); + portals.push(b.from); if ( !operation.containsMarkerByID( - b.toPortalId, - window.plugin.wasabee.static.constants.MARKER_TYPE_EXCLUDE + b.to, + WasabeeMarker.constants.MARKER_TYPE_EXCLUDE ) ) - portals.push(b.toPortalId); + portals.push(b.to); } - const reduced = {}; + const reduced: { [id: PortalID]: number } = {}; for (const p of portals) { if (!reduced[p]) reduced[p] = 0; reduced[p]++; @@ -354,36 +388,34 @@ export function blockerAutomark(operation, first = true) { // get WasabeePortal for portalId let wportal = operation.getPortal(portalId); - if (!wportal) wportal = WasabeePortal.get(portalId); + if (!wportal) wportal = PortalUI.get(portalId); if (!wportal) { - alert(wX("AUTOMARK STOP")); + displayInfo(wX("AUTOMARK STOP")); return; } // console.log(wportal); // add marker - let type = window.plugin.wasabee.static.constants.MARKER_TYPE_DESTROY; - if (wportal.team == "E") { - type = window.plugin.wasabee.static.constants.MARKER_TYPE_VIRUS; + let type = WasabeeMarker.constants.MARKER_TYPE_DESTROY; + if (PortalUI.team(wportal) == "E") { + type = WasabeeMarker.constants.MARKER_TYPE_VIRUS; } const zone = operation.determineZone(wportal.latLng); operation.addMarker(type, wportal, { comment: "auto-marked", zone: zone }); // remove nodes from blocker list - operation.blockers = operation.blockers.filter((b) => { - if (b.fromPortalId == portalId || b.toPortalId == portalId) return false; - return true; - }); + await WasabeeBlocker.removeBlocker(operation, portalId); + // recurse - blockerAutomark(operation, false); + await blockerAutomark(operation, false); if (first) operation.endBatchMode(); } -export function zoomToOperation(operation) { +export function zoomToOperation(operation: WasabeeOp) { if (!operation) return; const mbr = operation.mbr; - if (mbr && isFinite(mbr._southWest.lat) && isFinite(mbr._northEast.lat)) { + if (mbr && mbr.isValid()) { window.map.fitBounds(mbr); } } @@ -404,8 +436,6 @@ export async function updateLocalOp(local, remote) { // no changes if (!op.checkChanges()) { - // merge blockers and related portals - remote.mergeBlockers(op); await remote.store(); // if selected op, reload from the new op return remote.ID === so.ID; @@ -436,12 +466,11 @@ export async function fullSync() { try { let reloadOpID = null; const me = await WasabeeMe.waitGet(true); - const promises = new Array(); const opsID = new Set(me.Ops.map((o) => o.ID)); // delete operations absent from server unless the owner const ol = await opsList(); - const serverOps = new Array(); + const serverOps = []; for (const opID of ol) { const op = await WasabeeOp.load(opID); if (op && op.server === server && !opsID.has(op.ID)) serverOps.push(op); @@ -464,12 +493,13 @@ export async function fullSync() { serverOps.map((op) => op.ID) ); + const promises: Promise[] = []; for (const opID of opsID) { promises.push(opPromise(opID)); } const ops = (await Promise.allSettled(promises)) .filter((p) => p.status === "fulfilled") - .map((p) => p.value); + .map((p: PromiseFulfilledResult) => p.value); for (const newop of ops) { const localOp = await WasabeeOp.load(newop.ID); const reloadSO = await updateLocalOp(localOp, newop); @@ -484,25 +514,24 @@ export async function fullSync() { if (op !== so) zoomToOperation(op); } - // update UI to reflect new ops list - window.map.fire("wasabee:fullsync"); window.map.fire("wasabee:teams"); // if any team dialogs are open - alert(wX("SYNC DONE")); + displayInfo(wX("SYNC DONE")); } catch (e) { console.error(e); - new AuthDialog().enable(); - alert("You are not logged in."); + if (e instanceof ServerError) displayError(e); + if (WasabeeMe.isLoggedIn()) displayWarning(wX("NOT_LOADED")); + else new AuthDialog().enable(); } + // update UI to reflect new ops list + window.map.fire("wasabee:fullsync"); } -export async function syncOp(opID) { +export async function syncOp(opID: OpID) { const localOp = await WasabeeOp.load(opID); const remoteOp = await opPromise(opID); if (remoteOp.lasteditid != localOp.lasteditid) { if (!localOp.localchanged) { - // merge blockers and related portals - remoteOp.mergeBlockers(localOp); await remoteOp.store(); } else { const con = new MergeDialog({ @@ -514,7 +543,7 @@ export async function syncOp(opID) { } } -export function deleteLocalOp(opname, opid) { +export function deleteLocalOp(opname: string, opid: OpID) { const con = new ConfirmDialog({ title: wX("REM_LOC_CP", { opName: opname }), label: wX("YESNO_DEL", { opName: opname }), @@ -528,10 +557,65 @@ export function deleteLocalOp(opname, opid) { con.enable(); } -export async function resetCaches() { - await window.plugin.wasabee.idb.clear("agents"); - await window.plugin.wasabee.idb.clear("teams"); - await window.plugin.wasabee.idb.clear("defensivekeys"); +export function clearAllData() { + const con = new ConfirmDialog({ + title: wX("CLEAROPS BUTTON TITLE"), + label: wX("CLEAROPS PROMPT"), + type: "operation", + callback: async () => { + // remove database + deleteDatabase(); + // cleanup localStorage + for (const key of [ + constants.SELECTED_OP_KEY, + constants.OPS_LIST_KEY, + constants.OPS_LIST_HIDDEN_KEY, + constants.OPS_SHOW_HIDDEN_OPS, + constants.SEND_LOCATION_KEY, + constants.SEND_ANALYTICS_KEY, + constants.EXPERT_MODE_KEY, + constants.LANGUAGE_KEY, + constants.AGENT_INFO_KEY, + constants.MULTIMAX_UNREACHABLE_KEY, + constants.LINK_SOURCE_KEY, + constants.ANCHOR_ONE_KEY, + constants.ANCHOR_TWO_KEY, + constants.ANCHOR_THREE_KEY, + constants.PORTAL_DETAIL_RATE_KEY, + constants.SKIN_KEY, + constants.LAST_MARKER_KEY, + constants.AUTO_LOAD_FAKED, + constants.TRAWL_SKIP_STEPS, + constants.USE_PANES, + constants.SKIP_CONFIRM, + constants.SERVER_BASE_KEY, + constants.REBASE_UPDATE_KEY, + ]) { + delete localStorage[key]; + } + + const Wasabee: Wasabee = window.plugin.wasabee; + + // remove buttons + Wasabee.buttons.remove(); + + // remove toolbox + document + .querySelectorAll("#toolbox a.wasabee") + .forEach((e) => e.remove()); + + // remove layers + window.removeLayerGroup(Wasabee.portalLayerGroup); + window.removeLayerGroup(Wasabee.linkLayerGroup); + window.removeLayerGroup(Wasabee.markerLayerGroup); + window.removeLayerGroup(Wasabee.agentLayerGroup); + window.removeLayerGroup(Wasabee.zoneLayerGroup); + window.removeLayerGroup(Wasabee.backgroundOpsGroup); + window.removeLayerGroup(Wasabee.defensiveLayers); + window.removeLayerGroup(Wasabee.crossLinkLayers); + }, + }); + con.enable(); } export function setMarkersToZones() { diff --git a/src/code/version.ts b/src/code/version.ts new file mode 100644 index 000000000..80f0e921c --- /dev/null +++ b/src/code/version.ts @@ -0,0 +1,23 @@ +const metaURL = "https://cdn2.wasabee.rocks/iitcplugin/prod/wasabee.meta.js"; + +function getCurrentVersion() { + return window.plugin.wasabee.info.version; +} + +function simpleSemVer(a: string, b: string) { + const av = a.split(".", 3); + const bv = b.split(".", 3); + return +av[0] < +bv[0] || (+av[0] == +bv[0] && +av[1] < +bv[1]); +} + +export async function checkVersion() { + const data = await (await fetch(metaURL)).text(); + for (const line of data.split("\n")) { + if (line.startsWith("// @version")) { + const version = line.slice(11).trim(); + const curVer = getCurrentVersion(); + return simpleSemVer(curVer, version); + } + } + return false; +} diff --git a/src/code/wX.js b/src/code/wX.js deleted file mode 100644 index a400ee813..000000000 --- a/src/code/wX.js +++ /dev/null @@ -1,63 +0,0 @@ -// aliases to make review easier -let strings = window.plugin.wasabee.static.strings; -const defaultLang = window.plugin.wasabee.static.constants.DEFAULT_LANGUAGE; -const localStoreKey = window.plugin.wasabee.static.constants.LANGUAGE_KEY; - -const templateRe = /\{ *([\w_ -]+) *\}/g; - -export function wX(key, data) { - const lang = getLanguage(); - - // if the skin system is initialized, switch to it - if (window.plugin.wasabee.skin && window.plugin.wasabee.skin.strings) - strings = window.plugin.wasabee.skin.strings; - - let s = null; - if (strings[lang] && strings[lang][key]) s = strings[lang][key]; - if (!s && strings[defaultLang] && strings[defaultLang][key]) - s = strings[defaultLang][key]; - - // detect smallScreen here - let smallScreen = false; - if (window.plugin.userLocation) smallScreen = true; - if (smallScreen) { - if ( - strings[lang] && - strings[lang].smallScreen && - strings[lang].smallScreen[key] - ) - s = strings[lang].smallScreen[key]; - } - if (!s) s = `${key} not in ${lang} or ${defaultLang}`; - - return s.replace(templateRe, function (str, key) { - const value = data[key]; - if (value === undefined) return `{${key}}`; - return value; - }); -} - -export function getLanguage() { - // if the skin system is initialized, switch to it - if (window.plugin.wasabee.skin && window.plugin.wasabee.skin.strings) - strings = window.plugin.wasabee.skin.strings; - - // load the selected language, or use DEFAULT_LANGUAGE if not set - let lang = localStorage[localStoreKey]; - if (!lang) { - lang = defaultLang; - localStorage[localStoreKey] = defaultLang; - console.log("no language set, using default"); - } - - // if the langauge doesn't exist in either list, clear it and use DEFAULT_LANGUAGE - if (!strings[lang]) { - lang = defaultLang; - localStorage[localStoreKey] = defaultLang; - console.log("invalid language set, changing to default"); - } - - return lang; -} - -export default wX; diff --git a/src/code/wX.ts b/src/code/wX.ts new file mode 100644 index 000000000..3822814a3 --- /dev/null +++ b/src/code/wX.ts @@ -0,0 +1,253 @@ +import statics from "./static"; + +let strings = statics.strings; +const defaultLang = statics.constants.DEFAULT_LANGUAGE; +const localStoreKey = statics.constants.LANGUAGE_KEY; + +const templateRe = /\{ *([\w_ -]+) *\}/g; + +export function wX(key: string): string; +export function wX( + key: "ASSIGN LINK PROMPT", + data: { portalName: string } +): string; +export function wX( + key: "ASSIGN MARKER PROMPT", + data: { portalName: string } +): string; +export function wX( + key: "ASSIGN OUTBOUND PROMPT", + data: { portalName: string } +): string; +export function wX(key: "AUTH TOKEN REJECTED", data: { error: string }): string; +export function wX( + key: "autodraw.fanfield.result", + data: { ap: number; fields: number; links: number } +): string; +export function wX( + key: "autodraw.flipflop.result", + data: { count: number } +): string; +export function wX( + key: "autodraw.homogeneous.missing_split", + data: { count: number } +): string; +export function wX( + key: "autodraw.homogeneous.portals_required", + data: { count: number } +): string; +export function wX( + key: "autodraw.madrid.result", + data: { count: number } +): string; +export function wX( + key: "autodraw.multimax.result", + data: { count: number } +): string; +export function wX( + key: "autodraw.multimax.result_both_side", + data: { count1: number; count2: number } +): string; +export function wX(key: "COMPLETED BY", data: { agentName: string }): string; +export function wX(key: "CON_DEL", data: { opName: string }): string; +export function wX(key: "DEFAULT OP NAME", data: { date: string }): string; +export function wX(key: "DELETE_OP", data: { opName: string }): string; +export function wX( + key: "dialog.agent_comment.title", + data: { agentName: string } +): string; +export function wX(key: "dialog.auth.ott.text", data: { url: string }): string; +export function wX( + key: "dialog.clear_all.text", + data: { opName: string } +): string; +export function wX( + key: "dialog.clear_all.title", + data: { opName: string } +): string; +export function wX( + key: "dialog.clear_links.text", + data: { opName: string } +): string; +export function wX( + key: "dialog.clear_links.title", + data: { opName: string } +): string; +export function wX( + key: "dialog.clear_markers.text", + data: { opName: string } +): string; +export function wX( + key: "dialog.clear_markers.title", + data: { opName: string } +): string; +export function wX( + key: "dialog.checklist.count_fields.no_empty", + data: { fieldCount: number } +): string; +export function wX( + key: "dialog.checklist.count_fields.with_empty", + data: { emptyCount: number; fieldCount: number; linkCount: number } +): string; +export function wX( + key: "dialog.checklist.count_fields.link_from_inside", + data: { count: number } +): string; +export function wX( + key: "dialog.checklist.count_fields.link_from_inside.covered_at_order", + data: { order: number } +): string; +export function wX(key: "dialog.firebase.setup", data: { url: string }): string; +export function wX( + key: "dialog.import.success_message", + data: { count: number; faked: number } +): string; +export function wX( + key: "dialog.leave_team.text", + data: { teamName: string } +): string; +export function wX( + key: "dialog.leave_team.title", + data: { teamName: string } +): string; +export function wX(key: "dialog.merge.zone", data: { name: string }): string; +export function wX( + key: "dialog.ops_list.download", + data: { opName: string } +): string; +export function wX( + key: "dialog.ops_list.last_fetched", + data: { date: string } +): string; +export function wX( + key: "dialog.remove_agent.text", + data: { agentName: string; teamName: string } +): string; +export function wX( + key: "dialog.remove_agent.title", + data: { agentName: string } +): string; +export function wX( + key: "dialog.team_message", + data: { message: string; sender: string } +): string; +export function wX( + key: "dialog.zone_color.text", + data: { zoneName: string } +): string; +export function wX(key: "FAKED", data: { portalId: string }): string; +export function wX(key: "HOURS", data: { hours: number }): string; +export function wX(key: "IMP_NOPE", data: { error: string }): string; +export function wX(key: "IMPORT_OP_SUCCESS", data: { opName: string }): string; +export function wX(key: "IMPORT_OP_TITLE", data: { date: string }): string; +export function wX(key: "KEY_LIST2", data: { opName: string }): string; +export function wX(key: "KNOWN_BLOCK", data: { opName: string }): string; +export function wX( + key: "LINKS2", + data: { portalName: string; incoming: number; outgoing: number } +): string; +export function wX(key: "LOADING1", data: { portalGuid: string }): string; +export function wX(key: "MANAGE_TEAM", data: { teamName: string }): string; +export function wX(key: "MARKER_LIST", data: { opName: string }): string; +export function wX(key: "MINUTES", data: { minutes: number }): string; +export function wX(key: "MM_SET_KEYS_ZONE", data: { zoneName: string }): string; +export function wX(key: "NO LONGER AVAILABLE", data: { error: string }): string; +export function wX(key: "NOT LOGGED IN", data: { error: string }): string; +export function wX(key: "OP DELETED", data: { opID: string }): string; +export function wX(key: "OP PERM DENIED", data: { opID: string }): string; +export function wX(key: "OP_CHECKLIST", data: { opName: string }): string; +export function wX(key: "PERM DENIED", data: { error: string }): string; +export function wX(key: "PERMS", data: { opName: string }): string; +export function wX( + key: "popup.anchor.keys", + data: { onHand: number; required: number } +): string; +export function wX( + key: "PORTAL KEY LIST", + data: { portalName: string } +): string; +export function wX(key: "PORTAL_COUNT", data: { count: number }): string; +export function wX(key: "REM_LOC_CP", data: { opName: string }): string; +export function wX( + key: "REMOVE_TEAM_CONFIRM_LABEL", + data: { teamName: string } +): string; +export function wX( + key: "REMOVE_TEAM_CONFIRM_TITLE", + data: { teamName: string } +): string; +export function wX(key: "SECONDS", data: { seconds: number }): string; +export function wX( + key: "SEND TARGET CONFIRM", + data: { agent: string; portalName: string } +): string; +export function wX(key: "SET_MCOMMENT", data: { portalName: string }): string; +export function wX(key: "SET_PCOMMENT", data: { portalName: string }): string; +export function wX(key: "SKINS_AVAILABLE", data: { count: number }): string; +export function wX(key: "TEAM_CREATED", data: { teamName: string }): string; +export function wX(key: "TRAWL_REMAINING", data: { count: number }): string; +export function wX(key: "UPDATE HOVER", data: { opName: string }): string; +export function wX( + key: "UPLOAD BUTTON HOVER", + data: { opName: string } +): string; +export function wX(key: "WSERVER", data: { url: string }): string; +export function wX(key: "YESNO_DEL", data: { opName: string }): string; +export function wX(key: string, data?: { [key: string]: number | string }) { + const lang = getLanguage(); + + // if the skin system is initialized, switch to it + if (window.plugin.wasabee.skin && window.plugin.wasabee.skin.strings) + strings = window.plugin.wasabee.skin.strings; + + let s: string = null; + if (strings[lang] && strings[lang][key]) s = strings[lang][key]; + if (!s && strings[defaultLang] && strings[defaultLang][key]) + s = strings[defaultLang][key]; + + // detect smallScreen here + let smallScreen = false; + if (window.plugin.userLocation) smallScreen = true; + if (smallScreen) { + if ( + strings[lang] && + strings[lang].smallScreen && + strings[lang].smallScreen[key] + ) + s = strings[lang].smallScreen[key]; + } + if (!s) s = `${key} not in ${lang} or ${defaultLang}`; + + if (!data) return s; + + return s.replace(templateRe, function (str, key) { + const value = data[key]; + if (value === undefined) return `{${key}}`; + return "" + value; + }); +} + +export function getLanguage() { + // if the skin system is initialized, switch to it + if (window.plugin.wasabee.skin && window.plugin.wasabee.skin.strings) + strings = window.plugin.wasabee.skin.strings; + + // load the selected language, or use DEFAULT_LANGUAGE if not set + let lang = localStorage[localStoreKey]; + if (!lang) { + lang = defaultLang; + localStorage[localStoreKey] = defaultLang; + console.log("no language set, using default"); + } + + // if the langauge doesn't exist in either list, clear it and use DEFAULT_LANGUAGE + if (!strings[lang]) { + lang = defaultLang; + localStorage[localStoreKey] = defaultLang; + console.log("invalid language set, changing to default"); + } + + return lang; +} + +export default wX; diff --git a/src/code/wd.js b/src/code/wd.ts similarity index 64% rename from src/code/wd.js rename to src/code/wd.ts index ab2cc4eed..e4cc01d86 100644 --- a/src/code/wd.js +++ b/src/code/wd.ts @@ -1,54 +1,66 @@ -import WasabeeMe from "./me"; +import WasabeeMe from "./model/me"; import { dKeylistPromise } from "./server"; -import WasabeeAgent from "./agent"; +import WasabeeAgent from "./model/agent"; import wX from "./wX"; // import { getPortalDetails } from "./uiCommands"; +import AgentUI from "./ui/agent"; +import type { LayerEvent, LayerGroup } from "leaflet"; + +import db from "./db"; + +export type WDKey = { + Name: string; + PortalID: string; + GID: string; + Lat: string; + Lng: string; + Count: number; + CapID: string; +}; + +let defensiveLayer: LayerGroup; + // setup function export function initWasabeeD() { - window.plugin.wasabee.defensiveLayers = new L.LayerGroup(); - window.addLayerGroup( - "Wasabee-D Keys", - window.plugin.wasabee.defensiveLayers, - false - ); + window.plugin.wasabee.defensiveLayers = defensiveLayer = new L.LayerGroup(); + window.addLayerGroup("Wasabee-D Keys", defensiveLayer, false); // hook called in init.js after load window.map.on("wasabee:defensivekeys", drawWasabeeDkeys); - window.map.on("layeradd", (obj) => { - if (obj.layer === window.plugin.wasabee.defensiveLayers) { + window.map.on("layeradd", (obj: LayerEvent) => { + if (obj.layer === defensiveLayer) { window.map.fire("wasabee:defensivekeys"); } }); - window.map.on("layerremove", (obj) => { - if (obj.layer === window.plugin.wasabee.defensiveLayers) { + window.map.on("layerremove", (obj: LayerEvent) => { + if (obj.layer === defensiveLayer) { // clearLayers doesn't actually remove the data, just hides it from the map - window.plugin.wasabee.defensiveLayers.clearLayers(); + defensiveLayer.clearLayers(); } }); } -export function getAllWasabeeDkeys() { - return window.plugin.wasabee.idb.getAll("defensivekeys"); +export async function getAllWasabeeDkeys() { + return (await db).getAll("defensivekeys"); } -export async function getAgentWasabeeDkeys(gid) { +export async function getAgentWasabeeDkeys(gid: GoogleID) { const dks = await getAllWasabeeDkeys(); return dks.filter((dk) => dk.GID == gid); } -export function getAllPortalWasabeeDkeys(portalid) { - return window.plugin.wasabee.idb.getAllFromIndex( - "defensivekeys", - "PortalID", - portalid - ); +export async function getAllPortalWasabeeDkeys(portalid: PortalID) { + return (await db).getAllFromIndex("defensivekeys", "PortalID", portalid); } -export function getAgentPortalWasabeeDkeys(gid, portalid) { - return window.plugin.wasabee.idb.get("defensivekeys", [gid, portalid]); +export async function getAgentPortalWasabeeDkeys( + gid: GoogleID, + portalid: PortalID +) { + return (await db).get("defensivekeys", [gid, portalid]); } // This is the primary hook that is called on map refresh @@ -57,15 +69,14 @@ export function getAgentPortalWasabeeDkeys(gid, portalid) { export async function drawWasabeeDkeys() { if (window.isLayerGroupDisplayed("Wasabee-D Keys") === false) return; console.debug("running drawWasabeeDkeys"); - window.plugin.wasabee.defensiveLayers.clearLayers(); + defensiveLayer.clearLayers(); if (WasabeeMe.isLoggedIn()) { try { - const data = await dKeylistPromise(); - const list = JSON.parse(data); + const list = await dKeylistPromise(); if (!list || !list.DefensiveKeys || list.DefensiveKeys.length == 0) return; - + window.plugin.wasabee.idb.clear("defensivekeys"); for (const n of list.DefensiveKeys) { try { await window.plugin.wasabee.idb.put("defensivekeys", n); @@ -84,25 +95,20 @@ export async function drawWasabeeDkeys() { // draws each distinct portalID once async function drawMarkers() { const dks = await getAllWasabeeDkeys(); - const done = new Map(); + const done = new Set(); for (const dk of dks) { if (done.has(dk.PortalID)) continue; - done.set(dk.PortalID, true); + done.add(dk.PortalID); drawMarker(dk); } } // remove and re-add each marker -function drawMarker(dk) { - if ( - window.plugin.wasabee.defensiveLayers[dk.PortalID] && - window.plugin.wasabee.defensiveLayers[dk.PortalID]._leaflet_id - ) - window.plugin.wasabee.defensiveLayers.removeLayer( - window.plugin.wasabee.defensiveLayers[dk.PortalID] - ); - - const marker = L.marker([dk.Lat, dk.Lng], { +function drawMarker(dk: WDKey) { + if (defensiveLayer[dk.PortalID] && defensiveLayer[dk.PortalID]._leaflet_id) + defensiveLayer.removeLayer(defensiveLayer[dk.PortalID]); + + const marker = L.marker([+dk.Lat, +dk.Lng], { title: dk.Name, icon: L.divIcon({ className: "wasabee-defense-icon", @@ -112,8 +118,8 @@ function drawMarker(dk) { popupAnchor: L.point(-1, -48), }), }); - window.plugin.wasabee.defensiveLayers[dk.PortalID] = marker; - marker.addTo(window.plugin.wasabee.defensiveLayers); + defensiveLayer[dk.PortalID] = marker; + marker.addTo(defensiveLayer); window.registerMarkerForOMS(marker); marker.bindPopup("loading...", { @@ -142,7 +148,7 @@ function drawMarker(dk) { } // draw the popup, display the individual agents and their counts -async function getMarkerPopup(PortalID) { +async function getMarkerPopup(PortalID: PortalID) { const container = L.DomUtil.create("div", "wasabee-wd-popup"); // leaflet-draw-tooltip would be cool const ul = L.DomUtil.create("ul", null, container); @@ -153,7 +159,7 @@ async function getMarkerPopup(PortalID) { const a = await WasabeeAgent.get(dk.GID); const li = L.DomUtil.create("li", null, ul); if (a) { - li.appendChild(await a.formatDisplay()); + li.appendChild(AgentUI.formatDisplay(a)); } else { const fake = L.DomUtil.create("span", null, li); fake.textContent = wX("LOADING"); diff --git a/src/headers.js b/src/headers.js deleted file mode 100644 index 1b853dbab..000000000 --- a/src/headers.js +++ /dev/null @@ -1,13 +0,0 @@ -// ==UserScript== -// @id set -// @name set -// @namespace set -// @version set -// @updateURL set -// @downloadURL set -// @description set -// @author set -// @include https://intel.ingress.com/* -// @category set -// @grant none -// ==/UserScript== diff --git a/src/main.js b/src/main.js deleted file mode 100644 index 5c2fbd415..000000000 --- a/src/main.js +++ /dev/null @@ -1,19 +0,0 @@ -/* eslint-disable */ -function wrapper(plugin_info) { - /* inject: ./wrapper/pluginStart.js */ - - window.plugin.Wasabee = window.plugin.wasabee = {}; - window.plugin.wasabee.info = plugin_info.script; - - // Code injection - let setup = function () { - /* inject: ../dist/static-bundle.js */ - - /* inject: ../dist/init-bundle.js */ - - window.plugin.wasabee.init(); - }; - - /* inject: ./wrapper/pluginEnd.js */ -} -/* inject: ./wrapper/afterWrapper.js */ diff --git a/src/types/iitc/LICENSE b/src/types/iitc/LICENSE new file mode 100755 index 000000000..9e841e7a2 --- /dev/null +++ b/src/types/iitc/LICENSE @@ -0,0 +1,21 @@ + MIT License + + Copyright (c) Microsoft Corporation. + + Permission is hereby granted, free of charge, to any person obtaining a copy + of this software and associated documentation files (the "Software"), to deal + in the Software without restriction, including without limitation the rights + to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all + copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + SOFTWARE diff --git a/src/types/iitc/README.md b/src/types/iitc/README.md new file mode 100755 index 000000000..b54336725 --- /dev/null +++ b/src/types/iitc/README.md @@ -0,0 +1,21 @@ +# Installation + +> `npm install --save @types/iitc` + +# Summary + +This package contains type definitions for IITC (Ingress Intel Total Conversation) (https://github.com/IITC-CE/ingress-intel-total-conversion). + +# Details + +Files were exported from https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/iitc. + +### Additional Details + +- Last updated: Tue, 07 Sep 2021 07:31:40 GMT +- Dependencies: [@types/leaflet](https://npmjs.com/package/@types/leaflet), [@types/spectrum](https://npmjs.com/package/@types/spectrum), [@types/jquery](https://npmjs.com/package/@types/jquery), [@types/jqueryui](https://npmjs.com/package/@types/jqueryui) +- Global values: none + +# Credits + +These definitions were written by [McBen](https://github.com/McBen). diff --git a/src/types/iitc/core/android.d.ts b/src/types/iitc/core/android.d.ts new file mode 100755 index 000000000..cd471b666 --- /dev/null +++ b/src/types/iitc/core/android.d.ts @@ -0,0 +1,57 @@ +export {}; + +declare global { + class Android { + saveFile(filename: string, mime: string, content: string): void; + + // open dialog to send geo intent for navigation apps like gmaps or waze etc... + intentPosLink( + lat: number, + lng: number, + zoom: number, + title: string, + isPortal: boolean + ): void; + + // share a string to the IITC share activity. only uses the share tab. + shareString(text: string): void; + + // disable javascript injection while spinner is enabled prevent the spinner from closing automatically + spinnerEnabled(enable: boolean): void; + + copy(text: string): void; + + getVersionCode(): number; + getVersionName(): string; + + addPane( + id: string, + label: string, + icon?: string /*= "ic_action_new_event"*/ + ): void; + switchToPane(id: string): void; + + dialogFocused(id: string): void; + dialogOpened(id: string, open: boolean): void; + + setLayers(base_layer: string, overlay_layer: string): void; + + addPortalHighlighter(name: string): void; + setActiveHighlighter(name: string): void; + + // IITC-Version check plugin + updateIitc(fileUrl: string): void; + + showZoom(): boolean; + setFollowMode(follow: boolean): void; + + setProgress(progress: number): void; + + getFileRequestUrlPrefix(): string; + setPermalink(href: string): void; + + reloadIITC(clearCache?: boolean /*= false*/): void; + } + + var android: Android; +} diff --git a/src/types/iitc/core/artifact.d.ts b/src/types/iitc/core/artifact.d.ts new file mode 100755 index 000000000..a3e9ceb00 --- /dev/null +++ b/src/types/iitc/core/artifact.d.ts @@ -0,0 +1,44 @@ +import * as L from "leaflet"; + +export {}; + +declare global { + class Artifact { + // private _layer: L.LayerGroup; + REFRESH_JITTER: number; // 2 minute random period so not all users refresh at once + REFRESH_SUCCESS: number; // 60 minutes on success + REFRESH_FAILURE: number; // 2 minute retry on failure + portalInfo: {}; + artifactTypes: { [type: string]: any }; + entities: []; + + setup(): void; + requestData(): void; + idleResume(): void; + // private handleSuccess(data): void; + // private handleFailure(data): void; + // private processData(data): void; + // private processResult(portals): void; + clearData(): void; + + getArtifactTypes(): string[]; + isArtifact(type: string): boolean; + + /** used to render portals that would otherwise be below the visible level */ + getArtifactEntities(): []; + getInterestingPortals(): string[]; + + /** quick test for portal being relevant to artifacts - of any type */ + isInterestingPortal(guid: string): boolean; + + /** get the artifact data for a specified artifact id (e.g. 'jarvis'), if it exists - otherwise returns something 'false' */ + getPortalData(guid: string, artifactId: any): any; + + updateLayer(): void; + + /** show artifact dialog */ + showArtifactList(): void; + } + + var artifact: Artifact; +} diff --git a/src/types/iitc/core/boot.d.ts b/src/types/iitc/core/boot.d.ts new file mode 100755 index 000000000..d643d0dae --- /dev/null +++ b/src/types/iitc/core/boot.d.ts @@ -0,0 +1,46 @@ +export {}; + +declare global { + function setupLargeImagePreview(): void; + + /** + * adds listeners to the layer chooser such that a long press hides + * all custom layers except the long pressed one. + */ + function setupLayerChooserSelectOne(): void; + + /** Setup the function to record the on/off status of overlay layerGroups */ + function setupLayerChooserStatusRecorder(): void; + + function setupStyles(): void; + function setupIcons(): void; + function createDefaultBaseMapLayers(): void; + function setupMap(): void; + + /** adds a base layer to the map. done separately from the above, so that plugins that add base layers can be the default */ + function setMapBaseLayer(): void; + + /** + * renders player details into the website. Since the player info is + * included as inline script in the original site, the data is static + * and cannot be updated. + */ + function setupPlayerStat(): void; + + function setupSidebarToggle(): void; + function setupTooltips(): void; + function setupLayerChooserApi(): void; + function extendLeaflet(): void; + + // BOOTING /////////////////////////////////////////////////////////// + function prepPluginsToLoad(): void; + function boot(): void; + + /** + * OMS doesn't cancel the original click event, so the topmost marker will get a click event while spiderfying. + * Also, OMS only supports a global callback for all managed markers. Therefore, we will use a custom event that gets fired + * for each marker. + */ + function setupOMS(): void; + function registerMarkerForOMS(marker: L.Marker): void; +} diff --git a/src/types/iitc/core/chat.d.ts b/src/types/iitc/core/chat.d.ts new file mode 100755 index 000000000..e6e96c987 --- /dev/null +++ b/src/types/iitc/core/chat.d.ts @@ -0,0 +1,138 @@ +import { Intel } from "./inteltypes"; + +export {}; + +declare global { + type ChatChannels = "all" | "faction" | "alerts"; + + class Chat { + /** @return name of active tab */ + getActive(): string; + + /** Expand or collapse chat window */ + toggle(): void; + + handleTabCompletion(): void; + + genPostData( + channel: ChatChannels, + storageHash: chatStorage, + getOlderMsgs: boolean + ): any; + + // faction + _faction: chatStorage; + _requestFactionRunning: boolean; + requestFaction(getOlderMsgs: boolean, isRetry: boolean): void; + handleFaction(data: any, olderMsgs: boolean): void; + renderFaction(oldMsgsWereAdded: boolean): void; + + // all + _public: chatStorage; + _requestPublicRunning: boolean; + requestPublic(getOlderMsgs: boolean, isRetry: boolean): void; + handlePublic(data: any, olderMsgs: boolean): void; + renderPublic(oldMsgsWereAdded: boolean): void; + + // alerts + _alerts: chatStorage; + _requestAlertsRunning: boolean; + requestAlerts(getOlderMsgs: boolean, isRetry: boolean): void; + handleAlerts(data: any, olderMsgs: boolean): void; + renderAlerts(oldMsgsWereAdded: boolean): void; + + /** if user clicked a agent name */ + nicknameClicked(event: MouseEvent, nickname: string): void; + + /** store incoming data */ + writeDataToHash( + newData: any, + storageHash: chatStorage, + isPublicChannel: boolean, + isOlderMsgs: boolean + ): void; + + /** Override portal names that are used over and over, such as 'US Post Office' */ + getChatPortalName(markup: Intel.MarkUpPortalType): string; + + /** + * renders data from the data-hash to the element defined by the given + * ID. Set 3rd argument to true if it is likely that old data has been + * added. Latter is only required for scrolling. + */ + renderData( + data: any, + element: "chatfaction" | "chatall" | "chatalerts", + likelyWereOldMsgs: boolean + ): void; + + renderDivider(text: string): string; + + renderMsg( + msg: string, + nick: string, + time: number, + team: 0 | 1 | 2, + msgToPlayer: boolean, + systemNarrowcast: boolean + ): string; + + /** add nickname to chat-input line */ + addNickname(nick: string): void; + + tabToChannel(tab: ChatChannels | string): ChatChannels; + + /** + * called by plugins (or other things?) that need to monitor COMM data streams when the user is not viewing them + * instance: a unique string identifying the plugin requesting background COMM + * channel: either 'all', 'faction' or (soon) 'alerts' - others possible in the future + * flag: true for data wanted, false for not wanted + */ + backgroundChannelData( + instance: string, + channel: ChatChannels, + flag: boolean + ): void; + + backgroundInstanceChannel: {}; // [instance][channel] = flag; + + request(): void; + + /** + * checks if there are enough messages in the selected chat tab and + * loads more if not. + */ + needMoreMessages(): void; + + /** activate a chat tab */ + show(tab: ChatChannels): void; + + chooseTab(tab: ChatChannels): void; + + /** mouse event handler */ + chooser(event: MouseEvent): void; + + /** contains the logic to keep the correct scroll position. */ + keepScrollPosition( + box: JQuery, + scrollBefore: number, + isOldMsgs: boolean + ): void; + + /** init */ + setup(): void; + setupTime(): void; + setupPosting(): void; + + /** send current message of current chat to server */ + postMsg(): void; + } + + interface chatStorage { + data: {}; + oldestTimestamp: number; + newestTimestamp: number; + } + + var chat: Chat; +} diff --git a/src/types/iitc/core/constants.d.ts b/src/types/iitc/core/constants.d.ts new file mode 100755 index 000000000..d515bbe6c --- /dev/null +++ b/src/types/iitc/core/constants.d.ts @@ -0,0 +1,115 @@ +import { IITC, PortalGUID } from "./iitctypes"; + +export {}; + +declare global { + var script_info: any; + var iitcBuildDate: string; + + // CONFIG OPTIONS //////////////////////////////////////////////////// + const REFRESH: number; /** @default = 30; // refresh view every 30s (base time) */ + const ZOOM_LEVEL_ADJ: number; /** @default = 5; // add 5 seconds per zoom level */ + const ON_MOVE_REFRESH: number; /** @default = 2.5; //refresh time to use after a movement event */ + const MINIMUM_OVERRIDE_REFRESH: number; /** @default = 10; //limit on refresh time since previous refresh, limiting repeated move refresh rate */ + const REFRESH_GAME_SCORE: number; /** @default = 15 * 60; // refresh game score every 15 minutes */ + const MAX_IDLE_TIME: number; /** @default = 15 * 60; // stop updating map after 15min idling */ + const HIDDEN_SCROLLBAR_ASSUMED_WIDTH: number; /** @default = 20; */ + const SIDEBAR_WIDTH: number; /** @default = 300; */ + + // how many pixels to the top before requesting new data + const CHAT_REQUEST_SCROLL_TOP: number; /** @default = 200; */ + const CHAT_SHRINKED: number; /** @default = 60; */ + + // Minimum area to zoom ratio that field MU's will display + const FIELD_MU_DISPLAY_AREA_ZOOM_RATIO: number; /** @default 0.001; */ + + // Point tolerance for displaying MU's + const FIELD_MU_DISPLAY_POINT_TOLERANCE: number; /** @default = 60 */ + + const COLOR_SELECTED_PORTAL: string; /** @default '#f0f' */ + + /** + * Team colors + * @default ['#FF6600','#0088FF','#03DC03'] + */ + const COLORS: [string, string, string]; + const COLORS_LVL: string[]; /** @default ['#000',...,'#9627F4'] */ + const COLORS_MOD: {}; /** @default {VERY_RARE:'#b08cff',RARE:'#73a8ff',COMMON:'#8cffbf'} */ + + const MOD_TYPE: {}; // { RES_SHIELD: 'Shield', MULTIHACK: 'Multi-hack', FORCE_AMP: 'Force Amp', HEATSINK: 'Heat Sink', TURRET: 'Turret', LINK_AMPLIFIER: 'Link Amp' }; + + // circles around a selected portal that show from where you can hack + // it and how far the portal reaches (i.e. how far links may be made + // from this portal) + const ACCESS_INDICATOR_COLOR: string; // = 'orange'; + const RANGE_INDICATOR_COLOR: string; // = 'red' + + // min zoom for intel map - should match that used by stock intel + const MIN_ZOOM: number; // = 3; + + // used when zoom level is not specified explicitly (must contain all the portals) + const DEFAULT_ZOOM: number; // = 15; + + const DEFAULT_PORTAL_IMG: string; // '//commondatastorage.googleapis.com/ingress.com/img/default-portal-image.png'; + const NOMINATIM: string; // '//nominatim.openstreetmap.org/search?format=json&polygon_geojson=1&q='; + + // INGRESS CONSTANTS ///////////////////////////////////////////////// + // http://decodeingress.me/2012/11/18/ingress-portal-levels-and-link-range/ + const RESO_NRG: number[]; /** @default [0,1000,1500,2000,2500,3000,4000,5000,6000] */ + const HACK_RANGE: number; /** @default 40 in meters, max. distance from portal to be able to access it */ + const OCTANTS: string[]; /** @default ['E', 'NE', 'N', 'NW', 'W', 'SW', 'S', 'SE'] */ + const OCTANTS_ARROW: string[]; /** @default ['β†’', 'β†—', '↑', 'β†–', '←', '↙', '↓', 'β†˜'] */ + const DESTROY_RESONATOR: number; /** @default 75 AP for destroying portal */ + const DESTROY_LINK: number; /** @default 187 AP for destroying link */ + const DESTROY_FIELD: number; /** @default 750 AP for destroying field */ + const CAPTURE_PORTAL: number; /** @default 500 AP for capturing a portal */ + const DEPLOY_RESONATOR: number; /** @default 125 AP for deploying a resonator */ + const COMPLETION_BONUS: number; /** @default 250; AP for deploying all resonators on portal */ + const UPGRADE_ANOTHERS_RESONATOR: number; /** @default 65; AP for upgrading another's resonator */ + const MAX_PORTAL_LEVEL: number; /** @default 8 */ + const MAX_RESO_PER_PLAYER: number[]; /** @default [0, 8, 4, 4, 4, 2, 2, 1, 1] */ + + // OTHER MORE-OR-LESS CONSTANTS ////////////////////////////////////// + /** Team constants */ + const TEAM_ENL: number; /** @default 2 */ + const TEAM_RES: number; /** @default 1 */ + const TEAM_NONE: number; /** @default 0 */ + + /** Team CSS = ['none', 'res', 'enl'] */ + const TEAM_TO_CSS: [string, string, string]; + + /** ['Neutral', 'Resistance', 'Enlightened'] */ + const TEAM_NAMES: [string, string, string]; + + // STORAGE /////////////////////////////////////////////////////////// + // global constiables used for storage. Most likely READ ONLY. Proper + // way would be to encapsulate them in an anonymous function and write + // getters/setters, but if you are careful enough, this works. + var refreshTimeout: any; // = undefined; + var urlPortal: any; // = null; + var urlPortalLL: any; // = null; + + /** guid of current selected portal */ + var selectedPortal: PortalGUID | null; + + var portalRangeIndicator: any; // = null; + var portalAccessIndicator: any; // = null; + var mapRunsUserAction: any; // = false; + + const portalsFactionLayers: L.LayerGroup; + const linksFactionLayers: L.LayerGroup; + const fieldsFactionLayers: L.LayerGroup; + + /** list of all loaded portals */ + var portals: { [guid: string /* PortalGUID */]: IITC.Portal }; + + /** list of all loaded links */ + var links: { [guid: string /* LinkGUID */]: IITC.Link }; + + /** list of all fields */ + var fields: { [guid: string /* FieldGUID */]: IITC.Field }; + + // contain current status(on/off) of overlay layerGroups. + // But you should use isLayerGroupDisplayed(name) to check the status + var overlayStatus: {}; +} diff --git a/src/types/iitc/core/data_cache.d.ts b/src/types/iitc/core/data_cache.d.ts new file mode 100755 index 000000000..bf74866f2 --- /dev/null +++ b/src/types/iitc/core/data_cache.d.ts @@ -0,0 +1,30 @@ +/** cache for map data tiles. */ +export class DataCache { + /** + * if younger than this, use data in the cache rather than fetching from the server + * @default 180 + */ + REQUEST_CACHE_FRESH_AGE: number; + + /** + * maximum cache age. entries are deleted from the cache after this time + * @default 300 + */ + REQUEST_CACHE_MAX_AGE: number; + + /** if more than this many entries, expire early */ + REQUEST_CACHE_MAX_ITEMS: number; + /** or more than this total size */ + REQUEST_CACHE_MAX_CHARS: number; + + store(key: string, data: any, freshTime?: number): void; + remove(key: string): void; + get(key: string): any; + getTime(key: string): number; + getFresh(key: string): boolean | undefined; + startExpireInterval(periodInSecond: number): void; + stopExpireInterval(): void; + private runExpire(): void; + + debug(): string; +} diff --git a/src/types/iitc/core/dialog.d.ts b/src/types/iitc/core/dialog.d.ts new file mode 100755 index 000000000..0a4993b0b --- /dev/null +++ b/src/types/iitc/core/dialog.d.ts @@ -0,0 +1,105 @@ +import "jqueryui"; + +declare global { + /** The global ID of onscreen dialogs. */ + var DIALOG_ID: number; + + /** All onscreen dialogs, keyed by their ID. */ + var DIALOGS: {}; + + /** The number of dialogs on screen. */ + var DIALOG_COUNT: number; + + /** The dialog that has focus. */ + var DIALOG_FOCUS: any; + + /** + * Controls how quickly the slide toggle animation + * should play for dialog collapsing and expanding. + * @default 100 + */ + var DIALOG_SLIDE_DURATION: number; + + /** Create and show dialog */ + function dialog(data: DialogOptions): JQuery; + + // see https://jqueryui.com/dialog/ + interface DialogOptions { + /** If set only one dialog can be open */ + id?: string | undefined; + + /** Dialog title */ + title?: string | undefined; + + /** + * Dialog contents - converted by convertTextToTableMagic + * \n will be line breaks \t will be table fields + */ + text?: string | undefined; + + /** Dialog contents (if no text) */ + html?: string | HTMLElement | JQuery | undefined; + + dialogClass?: string | undefined; + classes?: any; + + /** + * single dialog + * default: false + */ + modal?: boolean | undefined; + + /** + * moveable dialog + * default: true + */ + draggable?: boolean | undefined; + + /** + * resizeable dialog (won't work in iitc out-of-the-box) + * default: false + */ + resizable?: boolean | undefined; + + /** position, see: https://api.jqueryui.com/position/ */ + position?: any; + + /** size */ + height?: string | number | undefined; + width?: string | number | undefined; + maxHeight?: string | undefined; + maxWidth?: string | undefined; + minHeight?: string | undefined; + minWidth?: string | undefined; + + autoOpen?: boolean | undefined; + closeOnEscape?: boolean | undefined; + hide?: any; + appendTo?: any; + + /** Specifies the text for the close button */ + closeText?: string | undefined; + + closeCallback?: any; + collapseCallback?: any; + expandCallback?: any; + collapseExpandCallback?: any; + focusCallback?: any; + blurCallback?: any; + + buttons?: + | JQueryUI.ButtonOptions[] + | { [key: string]: () => void } + | undefined; + } + + /** custom alert box */ + function alert( + text: string | HTMLElement, + isHTML?: boolean, + closeCallback?: any + ): JQuery; + + /** init */ + function setupDialogs(): void; +} diff --git a/src/types/iitc/core/entity_decode.d.ts b/src/types/iitc/core/entity_decode.d.ts new file mode 100755 index 000000000..9873be997 --- /dev/null +++ b/src/types/iitc/core/entity_decode.d.ts @@ -0,0 +1,25 @@ +import { IITC } from "./iitctypes"; + +export {}; + +declare global { + /** + * decode the on-network array entity format into an object format closer to that used before + * makes much more sense as an object, means that existing code didn't need to change, and it's what the + * stock intel site does internally too (the array format is only on the network) + */ + class DecodeArray { + portalSummary( + data: any[] + ): IITC.PortalData | IITC.PortalDataCore | undefined; + portalDetail(data: any[]): IITC.PortalDataDetail | undefined; + } + + // private but exposed: + // function parseMod(arr: null | any[]): IITC.Mod | null; + // function parseResonator(arr: null | any[]): IITC.Resonator | null; + // function parseArtifactBrief(arr: null | any[]): { fragment: any, target: any }; + // function parseArtifactDetail(arr: null | any[]): IITC.ArtifactDetail | null; + + var decodeArray: DecodeArray; +} diff --git a/src/types/iitc/core/entity_info.d.ts b/src/types/iitc/core/entity_info.d.ts new file mode 100755 index 000000000..5ee1681ac --- /dev/null +++ b/src/types/iitc/core/entity_info.d.ts @@ -0,0 +1,9 @@ +import { IITC } from "./iitctypes"; + +declare global { + /** + * given the entity detail data, returns the team the entity belongs to. Uses TEAM_* enum values. + */ + function getTeam(details: IITC.PortalData): 0 | 1 | 2; + function teamStringToId(teamStr: string): 0 | 1 | 2; +} diff --git a/src/types/iitc/core/extract_niantic_parameters.d.ts b/src/types/iitc/core/extract_niantic_parameters.d.ts new file mode 100755 index 000000000..586044e78 --- /dev/null +++ b/src/types/iitc/core/extract_niantic_parameters.d.ts @@ -0,0 +1,10 @@ +export {}; + +declare global { + /** + * as of 2014-08-14, Niantic have returned to minifying the javascript. This means we no longer get the nemesis object + * and it's various member objects, functions, etc. + * so we need to extract some essential parameters from the code for IITC to use + */ + function extractFromStock(): void; +} diff --git a/src/types/iitc/core/game_status.d.ts b/src/types/iitc/core/game_status.d.ts new file mode 100755 index 000000000..644e7a6ff --- /dev/null +++ b/src/types/iitc/core/game_status.d.ts @@ -0,0 +1,6 @@ +export {}; + +declare global { + /** MindUnit display */ + function updateGameScore(data?: JQuery.jqXHR): void; +} diff --git a/src/types/iitc/core/hooks.d.ts b/src/types/iitc/core/hooks.d.ts new file mode 100755 index 000000000..a95f19551 --- /dev/null +++ b/src/types/iitc/core/hooks.d.ts @@ -0,0 +1,293 @@ +import { IITC } from "./iitctypes"; +import { Intel } from "./inteltypes"; + +declare global { + /** + * register a callback for an event + * called when portal on map is selected/unselected + */ + function addHook( + event: "portalSelected", + callback: (e: EventPortalSelected) => void + ): void; + + /** + * register a callback for an event + * this hook runs after data for any of the public chats has been received and processed, but not + * yet been displayed. The data hash contains both the unprocessed raw ajax response as well as the processed + * chat data that is going to be used for display. + */ + function addHook( + event: "publicChatDataAvailable", + callback: (e: EventPublicChatDataAvailable) => void + ): void; + + /** + * register a callback for an event + * this hook runs after data for the faction chat has been received and processed, but not yet been + * displayed. The data hash contains both the unprocessed raw ajax response as well as the processed chat data + * that is going to be used for display. + */ + function addHook( + event: "factionChatDataAvailable", + callback: (e: EventFactionChatDataAvailable) => void + ): void; + + /** + * register a callback for an event + * fired after the details in the sidebar have been (re-)rendered Provides data about the portal + * that has been selected. + */ + function addHook( + event: "portalDetailsUpdated", + callback: (e: EventPortalDetailsUpdated) => void + ): void; + + /** + * register a callback for an event + * called when the set of artifacts (including targets) has changed. + */ + function addHook( + event: "artifactsUpdated", + callback: (e: EventArtifactsUpdated) => void + ): void; + + /** + * register a callback for an event + * called when we start refreshing map data + */ + function addHook( + event: "mapDataRefreshStart", + callback: (e: EventMapDataRefreshStart) => void + ): void; + + /** + * register a callback for an event + * called just as we start to render data. has callback to inject cached entities into the map render + */ + function addHook( + event: "mapDataEntityInject", + callback: (e: EventMapDataEntityInject) => void + ): void; + + /** + * register a callback for an event + * called when we complete the map data load + */ + function addHook( + event: "mapDataRefreshEnd", + callback: (e: EventMapDataRefreshEnd) => void + ): void; + + /** + * register a callback for an event + * called when a portal has been received and is about to be added to its layer group. + * Note that this does NOT mean it is already visible or will be, shortly after. + * If a portal is added to a hidden layer it may never be shown at all. + */ + function addHook( + event: "portalAdded", + callback: (e: EventPortalAdded) => void + ): void; + + /** + * register a callback for an event + * called when a link is about to be added to the map + */ + function addHook( + event: "linkAdded", + callback: (e: EventLinkAdded) => void + ): void; + + /** + * register a callback for an event + * called when a field is about to be added to the map + */ + function addHook( + event: "fieldAdded", + callback: (e: EventFieldAdded) => void + ): void; + + /** + * register a callback for an event + * called when a portal has been removed + */ + function addHook( + event: "portalRemoved", + callback: (e: EventPortalRemoved) => void + ): void; + + /** + * register a callback for an event + * called when a link has been removed + */ + function addHook( + event: "linkRemoved", + callback: (e: EventLinkRemoved) => void + ): void; + + /** + * register a callback for an event + * called when a field has been removed + */ + function addHook( + event: "fieldRemoved", + callback: (e: EventFieldRemoved) => void + ): void; + + /** + * register a callback for an event + * called after each map data request finished. + */ + function addHook( + event: "requestFinished", + callback: (e: EventRequestFinished) => void + ): void; + function addHook( + event: "nicknameClicked", + callback: (e: EventNicknameClicked) => boolean + ): void; + function addHook(event: "search", callback: (e: EventSearch) => void): void; + + /** + * register a callback for an event + * called after IITC and all plugins loaded + * NOTE: if iitc is already loaded this event never happens. Check the @see iitcLoaded flag + */ + function addHook(event: "iitcLoaded", callback: () => void): void; + + /** + * register a callback for an event + * alled when a request to load full portal detail completes. + */ + function addHook( + event: "portalDetailLoaded", + callback: (e: EventPortalDetailLoaded) => void + ): void; + + /** + * register a callback for an event + * called when the current pane has changed. On desktop, this only selects the current chat pane; on mobile, it + * also switches between map, info and other panes defined by plugins + */ + function addHook( + event: "paneChanged", + callback: (e: EventPaneChanged) => void + ): void; + + /** + * register a callback for an event + * called when the user location or orientation changed. + */ + function addHook( + event: "pluginUserLocation", + callback: (e: EventUserLocation) => void + ): void; + + /** + * register a callback for an event + * (user defined hooks) + */ + function addHook(event: string, callback: HookCallback): void; + + /** remove a registered a callback */ + function removeHook(event: string, callback: HookCallback): void; + + /** trigger event */ + function runHooks(event: string, data: any): boolean; + + /** register a custom event */ + function pluginCreateHook(event: string): void; + + /** private hook table */ + var _hooks: { [event: string]: HookCallback[] }; + + type HookCallback = (data: any) => boolean | void; + + interface EventPortalSelected { + selectedPortalGuid: string; + unselectedPortalGuid: string; + } + interface EventPublicChatDataAvailable { + raw: any; + result: Intel.ChatLine[]; + processed: any; + } + interface EventFactionChatDataAvailable { + raw: any; + result: Intel.ChatLine[]; + processed: any; + } + interface EventPortalDetailsUpdated { + guid: string; + portal: IITC.Portal; + portalDetails: any /* class portalDetail */; + portalData: IITC.PortalData; + } + interface EventArtifactsUpdated { + old: any; + new: any; + } + interface EventMapDataRefreshStart { + bounds: L.LatLngBounds; + mapZoom: number; + dataZoom: number; + minPortalLevel: number; + tileBounds: L.LatLngBounds; + } + interface EventMapDataEntityInject { + callback: (ents: any) => void; + } // TODO: ents = portalDetailLoaded.ent + // tslint:disable-next-line:no-empty-interface + interface EventMapDataRefreshEnd {} + interface EventPortalAdded { + portal: IITC.Portal; + previousData: IITC.PortalData; + } + interface EventLinkAdded { + link: IITC.Link; + } + interface EventFieldAdded { + field: IITC.Field; + } + interface EventPortalRemoved { + portal: IITC.Portal; + data: IITC.PortalData; + } + interface EventLinkRemoved { + link: IITC.Link; + data: IITC.LinkData; + } + interface EventFieldRemoved { + field: IITC.Field; + data: IITC.FieldData; + } + interface EventRequestFinished { + success: boolean; + } + interface EventNicknameClicked { + event: MouseEvent; + nickname: string; + } + type EventSearch = any; /* class search.Query */ + type EventPaneChanged = string; + + type PortalDetailEnt = [ + /*guid*/ string, + /*dict.timestamp*/ number, + /*data.result*/ Intel.PortalDetails + ]; + type EventPortalDetailLoaded = + | { + guid: string; + success: true; + details: IITC.PortalDataDetail; + ent: PortalDetailEnt; + } + | { guid: string; success: false; details: never; ent: never }; + + interface EventUserLocation { + event: "setup" | "onLocationChange" | "onOrientationChange"; + data: { latlng: L.LatLng; direction: number }; + } +} diff --git a/src/types/iitc/core/idle.d.ts b/src/types/iitc/core/idle.d.ts new file mode 100755 index 000000000..c24a4932b --- /dev/null +++ b/src/types/iitc/core/idle.d.ts @@ -0,0 +1,20 @@ +export {}; + +declare global { + var idleTime: number; // in seconds + + /** default MAX_IDLE_TIME */ + var _idleTimeLimit: number; + var IDLE_POLL_TIME: number; + + function idlePoll(): void; + function idleReset(): void; + function idleSet(): void; + function setupIdle(): void; + + /** + * add your function here if you want to be notified when the user + * resumes from being idle + */ + function addResumeFunction(fct: () => void): void; +} diff --git a/src/types/iitc/core/iitctypes.d.ts b/src/types/iitc/core/iitctypes.d.ts new file mode 100755 index 000000000..1e8bdc2e3 --- /dev/null +++ b/src/types/iitc/core/iitctypes.d.ts @@ -0,0 +1,148 @@ +import * as L from "leaflet"; +import "leafletExtension"; +import * as jQuery from "jquery"; + +export type PortalGUID = string; +export type LinkGUID = string; +export type FieldGUID = string; + +export namespace IITC { + /** Portal-Marker */ + class Portal extends L.CircleMarker { + options: PortalOptions; + } + + interface PortalOptions extends L.PathOptions { + guid: PortalGUID; + ent: any; + level: number; + team: number; + timestamp: number; + data: PortalDataDetail; + } + + interface PortalDataCore { + team: string; + latE6: number; + lngE6: number; + } + + interface PortalData extends PortalDataCore { + artifactBrief: { fragment: any; target: any } | null; + health: number; + image: string; // url + level: number; + mission: boolean; + mission50plus: boolean; + ornaments: string[]; + resCount: number; + timestamp: number; + title: string; + } + + interface PortalDataDetail extends PortalData { + artifactDetail: ArtifactDetail; + mods: [Mod | null, Mod | null, Mod | null, Mod | null]; + owner: string; + resonators: Resonator[]; + history: PortalHistory; + } + + interface PortalHistory { + _raw: number; + visited: boolean; + captured: boolean; + scoutControlled: boolean; + } + + interface Mod { + owner: string; + name: string; + rarity: ModRarity; + stats: { [k: string /*ModStats*/]: string }; + } + type ModStats = + | "REMOVAL_STICKNESS" /* all */ + /* Shield */ + | "MIGRATION" + /* Turret */ + | "ATTACK_FREQUENCY" + | "HIT_BONUS" + /* Forceamp */ + | "FORCE_AMPLIFIER" + /* ito- */ + | "XM_SPIN" + /* Multihack */ + | "BURNOUT_INSULATION" + /* Heat sink */ + | "HACK_SPEED" + /* Linkamp */ + | "LINK_RANGE_MULTIPLIER" + /* sbul */ + | "LINK_DEFENSE_BOOST" + | string; /* dummy for future stuff */ + type ModRarity = "COMMON" | "RARE" | "VERY_RARE"; + + type ModType = + | "RES_SHIELD" + | "MULTIHACK" + | "FORCE_AMP" + | "HEATSINK" + | "TURRET" + | "LINK_AMPLIFIER"; + + interface Resonator { + energy: number; + level: number; + owner: string; + } + + interface ArtifactDetail { + type: string; + displayName: string; + fragments: any[]; + } + + /** Link-Marker */ + class Link extends L.GeodesicPolyline { + options: LinkOptions; + } + + interface LinkOptions extends L.PathOptions { + team: number; + guid: string; + timestamp: number; + data: LinkData; + } + + interface LinkData { + dGuid: string; + dLatE6: number; + dLngE6: number; + oGuid: string; + oLatE6: number; + oLngE6: number; + team: string; + } + + /** Field-Polygon */ + class Field extends L.GeodesicPolygon { + options: FieldOptions; + } + + interface FieldOptions extends L.PathOptions { + team: number; + guid: string; + timestamp: number; + data: FieldData; + } + + interface FieldData { + team: string; + points: Array<{ + guid: string; + latE6: number; + lngE6: number; + }>; + } +} diff --git a/src/types/iitc/core/inteltypes.d.ts b/src/types/iitc/core/inteltypes.d.ts new file mode 100755 index 000000000..0619db71e --- /dev/null +++ b/src/types/iitc/core/inteltypes.d.ts @@ -0,0 +1,58 @@ +export namespace Intel { + // PLAYER + interface PlayerInfo { + nickname: string; + team: string; + ap: string; + available_invites: number; + energy: number; + level: number; + min_ap_for_current_level: string; + min_ap_for_next_level: string; + nickMatcher: RegExp; + verified_level: number; + xm_capacity: string; + } + + // ENTITY + type PortalDetails = []; + type FieldDetails = []; + type LinkDetails = []; + + // CHAT + interface ChatCallback { + result: ChatLine[]; + } + + type ChatLine = [/*guid*/ string, /*time*/ number, PlextContainer]; + + interface PlextContainer { + plext: { + plextType: "SYSTEM_BROADCAST" | "SYSTEM_NARROWCAST" | "PLAYER_GENERATED"; + markup: Array; + team: "RESISTANCE" | "ENLIGHTENED"; + text: string; + }; + } + + type MarkUpPlayer = ["PLAYER", MarkUpPlayerType]; + interface MarkUpPlayerType { + team: string; + plain: string; + } + + type MarkUpText = ["TEXT", MarkUpTextType]; + interface MarkUpTextType { + plain: string; + } + + type MarkUpPortal = ["PORTAL", MarkUpPortalType]; + interface MarkUpPortalType { + latE6: number; + lngE6: number; + team: string; + plain: string; + name: string; + address: string; + } +} diff --git a/src/types/iitc/core/location.d.ts b/src/types/iitc/core/location.d.ts new file mode 100755 index 000000000..14dc3088c --- /dev/null +++ b/src/types/iitc/core/location.d.ts @@ -0,0 +1,13 @@ +export {}; + +declare global { + /** retrieves current position from map and stores it cookies */ + function storeMapPosition(): void; + + /** + * either retrieves the last shown position from a cookie, from the + * URL or if neither is present, via Geolocation. If that fails, it + * returns a map that shows the whole world. + */ + function getPosition(): void; +} diff --git a/src/types/iitc/core/main.d.ts b/src/types/iitc/core/main.d.ts new file mode 100755 index 000000000..ad6c6b9c4 --- /dev/null +++ b/src/types/iitc/core/main.d.ts @@ -0,0 +1,91 @@ +import { FieldGUID, IITC, LinkGUID, PortalGUID } from "./iitctypes"; +import * as jQuery from "jquery"; +import { Intel } from "./inteltypes"; +import { MapDataRequest } from "./map_data_request"; + +export interface IPlugin { + [pluginName: string]: any; +} + +declare global { + /** All iitc Pluigns */ + var plugin: IPlugin; + + /** iitc-Pluigns setup/initialize function */ + var bootPlugins: BootCallback[]; + type BootCallback = () => void; + + /** if true iitc main script was already loaded (plugin need to trigger setup on iths own) */ + var iitcLoaded: boolean; + + /** the Leaflet Map */ + var map: L.Map; + + /** google-api */ + var gapi: any; + + /** Layer visibilty control */ + var layerChooser: L.Control.Layers; + + /** Info about current player/agent */ + var PLAYER: Intel.PlayerInfo; + + /** Request handler */ + var mapDataRequest: MapDataRequest; + var DEFAULT_MAX_IDLE_TIME: number; + var DEFAULT_REFRESH: number; + + function startRefreshTimeout(): void; + + /** Load & show Portal Details Window */ + function renderPortalDetails(guid: PortalGUID | null): void; + + /** Make sure Portal is visible in Window */ + function zoomToAndShowPortal(guid: PortalGUID, position: L.LatLng): void; + + /** Create Portal-Marker */ + function createMarker( + position: L.LatLng, + options: IITC.PortalOptions + ): L.CircleMarker; + + // Map Stuff + function selectPortalByLatLng(lat: number, lng: number): void; + + /** add Layergroup to leaflets layer-chooser */ + function addLayerGroup( + name: string, + layer: L.LayerGroup, + defaultVisibile: boolean, + groupname?: string + ): void; + + /** remove a layer */ + function removeLayerGroup(layer: L.LayerGroup): void; + + /** get layer visiblity */ + function isLayerGroupDisplayed( + name: string, + defaultDisplay?: boolean + ): boolean; + + /** set layer visiblity */ + function updateDisplayedLayerGroup(name: string, display: boolean): void; + + /** escape Html string */ + function escapeHtmlSpecialChars(name: string): string; + + /** prepare marker for OverlappingMarkerSpiderfier */ + function registerMarkerForOMS(marker: L.Marker): void; + + /** convert team string to id */ + function teamStringToId(team: string): number; + + // Android + function useAndroidPanes(): boolean; + var currentPane: string; + function show(paneID: string): void; + + /** update status bar */ + function renderUpdateStatus(): void; +} diff --git a/src/types/iitc/core/map_data_calc_tools.d.ts b/src/types/iitc/core/map_data_calc_tools.d.ts new file mode 100755 index 000000000..30243d0ab --- /dev/null +++ b/src/types/iitc/core/map_data_calc_tools.d.ts @@ -0,0 +1,59 @@ +export {}; + +declare global { + var TILE_PARAMS: { + /** + * @default [200000,200000,200000,200000,200000,60000,60000,10000,5000,2500,2500,800,300,0,0]; + */ + ZOOM_TO_LINK_LENGTH: number[]; + + /** + * @default [8,8,8,8,7,7,7,6,6,5,4,4,3,2,2,1,1]; + */ + ZOOM_TO_LEVEL: number[]; + + /** + * @default [1,1,1,40,40,80,80,320,1000,2000,2000,4000,8000,16000,16000,32000]; + */ + TILES_PER_EDGE: number[]; + }; + + /** + * Ingress Intel splits up requests for map data (portals, links,fields) into tiles. To get data for the current viewport + * (i.e. what is currently visible) it first calculates which tiles intersect. + * For all those tiles, it then calculates the lat/lng bounds of that tile and a quadkey. + * Both the bounds and the quadkey are β€œsomewhat” required to get complete data. + * + * Conversion functions courtesy of @link http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames + */ + function setupDataTileParams(): void; + + interface MapZoomTileParameters { + level: number; + tilesPerEdge: number; + minLinkLength: number; + hasPortals: boolean; + zoom: number; + } + + function getMapZoomTileParameters(zoom: number): MapZoomTileParameters; + + /** + * we can fetch data at a zoom level different to the map zoom. + * To improve the cacheing performance, we try and limit the number of zoom levels we retrieve data for + * to avoid impacting server load, we keep ourselves restricted to a zoom level with the sane number + * of tilesPerEdge and portal levels visible + */ + function getDataZoomForMapZoom(mapZoom: number): number; + + function lngToTile(lng: number, params: MapZoomTileParameters): number; + function latToTile(lat: number, params: MapZoomTileParameters): number; + function tileToLng(x: number, params: MapZoomTileParameters): number; + function tileToLat(y: number, params: MapZoomTileParameters): number; + + function pointToTileId( + params: MapZoomTileParameters, + x: number, + y: number + ): string; +} diff --git a/src/types/iitc/core/map_data_debug.d.ts b/src/types/iitc/core/map_data_debug.d.ts new file mode 100755 index 000000000..6dc788b0f --- /dev/null +++ b/src/types/iitc/core/map_data_debug.d.ts @@ -0,0 +1,36 @@ +/** useful bits to assist debugging map data tiles */ +export type DebugTileState = + | "ok" + | "error" + | "cache-fresh" + | "cache-stale" + | "requested" + | "retrying" + | "request-fail" + | "tile-fail" + | "tile-timeout" + | "render-queue"; + +declare global { + export class RenderDebugTiles { + CLEAR_CHECK_TIME: number; // = 0.1; + FADE_TIME: number; // = 1.0; + + private debugTileLayer: L.LayerGroup; + private debugTileToRectangle: {}; + private debugTileClearTimes: {}; + private timer?: number | undefined; + + reset(): void; + create(id: string, bounds: L.LatLngBounds): void; + setColour(id: string, borercol: string, fillcol: string): void; + setState(id: string, state: DebugTileState): void; + + /** + * @param waitTime in msec + */ + startTimer(waitTime: number): void; + + runClearPass(): void; + } +} diff --git a/src/types/iitc/core/map_data_render.d.ts b/src/types/iitc/core/map_data_render.d.ts new file mode 100755 index 000000000..302633d11 --- /dev/null +++ b/src/types/iitc/core/map_data_render.d.ts @@ -0,0 +1,66 @@ +import * as L from "leaflet"; +import { IITC } from "./iitctypes"; +import { Intel } from "./inteltypes"; + +/** class to handle rendering into leaflet the JSON data from the servers */ +export class Render { + portalMarkerScale?: number | undefined; + + private isRendering: boolean; + + /** object - represents the set of all deleted game entity GUIDs seen in a render pass */ + private deletedGuid: {}; + private seenPortalsGuid: {}; + private seenLinksGuid: {}; + private seenFieldsGuid: {}; + private bounds: L.LatLngBounds; + private level: number; + + /** start a render pass. called as we start to make the batch of data requests to the servers */ + startRenderPass(level: number, bounds: L.LatLngBounds): void; + + clearPortalsOutsideBounds(bounds: L.LatLngBounds): void; + clearFieldsOutsideBounds(bounds: L.LatLngBounds): void; + + /** process deleted entity list and entity data */ + processTileData(tiledata: any): void; + + processDeletedGameEntityGuids(deleted: {}): void; + processGameEntities(entities: {}): void; + + /** + * End a render pass. does any cleaning up required, postponed processing of data, etc. called when the render + * is considered complete + */ + endRenderPass(): void; + + bringPortalsToFront(): void; + deleteEntity(guid: string): void; + deletePortalEntity(guid: string): void; + deleteLinkEntity(guid: string): void; + deleteFieldEntity(guid: string): void; + + /** + * intel no longer returns portals at anything but the closest zoom + * stock intel creates 'placeholder' portals from the data in links/fields - IITC needs to do the same + * we only have the portal guid, lat/lng coords, and the faction - no other data + * having the guid, at least, allows the portal details to be loaded once it's selected. however, + * no highlighters, portal level numbers, portal names, useful counts of portals, etc are possible + */ + createPlaceholderPortalEntity( + guid: string, + latE6: number, + lngE6: number, + team: "E" | "R" | "N" + ): void; + + createPortalEntity(ent: Intel.PortalDetails): void; + createFieldEntity(ent: Intel.FieldDetails): void; + createLinkEntity(ent: Intel.LinkDetails): void; + + rescalePortalMarkers(): void; + + /** add the portal to the visible map layer */ + addPortalToMapLayer(portal: IITC.Portal): void; + removePortalFromMapLayer(portal: IITC.Portal): void; +} diff --git a/src/types/iitc/core/map_data_request.d.ts b/src/types/iitc/core/map_data_request.d.ts new file mode 100755 index 000000000..cf8111484 --- /dev/null +++ b/src/types/iitc/core/map_data_request.d.ts @@ -0,0 +1,159 @@ +import { DataCache } from "./data_cache"; +//import { RenderDebugTiles } from './map_data_debug'; +import { Render } from "./map_data_render"; + +export interface MapDataRequestStatus { + short: string; + long?: string | undefined; + progress?: number | undefined; +} + +/** + * class to request the map data tiles from the Ingress servers + * and then pass it on to the render class for display purposes + * Uses the map data cache class to reduce network requests + */ +export class MapDataRequest { + cache: DataCache; + render: Render; + debugTiles: RenderDebugTiles; + + activeRequestCount: number; + requestedTiles: {}; + renderQueue: []; + renderQueueTimer?: number | undefined; + renderQueuePaused: boolean; + idle: boolean; + + cachedTileCount: number; + requestedTileCount: number; + successTileCount: number; + failedTileCount: number; + staleTileCount: number; + + private status: MapDataRequestStatus; + + /** a 'set' to keep track of hard failures for tiles */ + tileErrorCount: {}; + + /** + * the 'set' of requested tile QKs + */ + queuedTiles: {}; + + /** store the parameters used for fetching the data. used to prevent unneeded refreshes after move/zoom */ + private fetchedDataParams: any; + + /** + * no more than this many requests in parallel. stock site seems to rely on browser limits (6, usually), sending + * many requests at once. + * using our own queue limit ensures that other requests (e.g. chat, portal details) don't get delayed + * @default 5 + */ + MAX_REQUESTS: number; + + /** + * this many tiles in one request + * @default 25 + */ + NUM_TILES_PER_REQUEST: number; + + /** + * number of times to retry a tile after an error (including "error: TIMEOUT" now - as stock intel does) + * TODO? different retry counters for TIMEOUT vs other errors..? + * @default 5 + */ + MAX_TILE_RETRIES: number; + + // refresh timers + MOVE_REFRESH: number; // = 3; //time, after a map move (pan/zoom) before starting the refresh processing + STARTUP_REFRESH: number; // = 3; //refresh time used on first load of IITC + IDLE_RESUME_REFRESH: number; // = 5; //refresh time used after resuming from idle + + /** + * after one of the above, there's an additional delay between preparing the refresh (clearing out of bounds, + * processing cache, etc) and actually sending the first network requests + * delay after preparing the data download before tile requests are sent + * @default 1 + */ + DOWNLOAD_DELAY: number; + + /** + * a short delay between one request finishing and the queue being run for the next request. + * @default 0 + */ + RUN_QUEUE_DELAY: number; + + /** + * delay before processing the queue after failed requests + * longer delay before doing anything after errors (other than TIMEOUT) + * @default 5 + */ + BAD_REQUEST_RUN_QUEUE_DELAY: number; + + /** + * delay before processing the queue after empty responses + * also long delay - empty responses are likely due to some server issues + * @default 5 + */ + EMPTY_RESPONSE_RUN_QUEUE_DELAY: number; + + /** + * delay before processing the queue after error==TIMEOUT requests. this is 'expected', so minimal extra delay over the regular RUN_QUEUE_DELAY + * @default 0 + */ + TIMEOUT_REQUEST_RUN_QUEUE_DELAY: number; + + /** + * render queue + * number of items to process in each render pass. there are pros and cons to smaller and larger values + * (however, if using leaflet canvas rendering, it makes sense to push as much as possible through every time) + */ + RENDER_BATCH_SIZE: number; + + /** + * delay before repeating the render loop. this gives a better chance for user interaction + * 0.1sec desktop, 0.2sec mobile + */ + RENDER_PAUSE: number; + + /** + * refresh time to use for close views z>12 when not idle and not moving + * @default 300 + */ + REFRESH_CLOSE: number; + + /** + * refresh time for far views z <= 12 + * @default 900 + */ + REFRESH_FAR: number; + + /** + * minimum refresh time is based on the time to complete a data fetch, times this value + * @default 2 + */ + FETCH_TO_REFRESH_FACTOR: number; + + start(): void; + mapMoveStart(): void; + mapMoveEnd(): void; + idleResume(): void; + clearTimeout(): void; + refreshOnTimeout(delayInSeconds: number): void; + setStatus(short: string, long?: string, progress?: number): void; + getStatus(): MapDataRequestStatus; + refresh(): void; + + delayProcessRequestQueue(delayInSeconds: number): void; + processRequestQueue(boolean): void; + sendTileRequest(tiles: string[]): void; + requeueTile(id: string, error: boolean): void; + private handleResponse(data: any, tiles: string[], success: boolean): void; + resetRenderQueue(): void; + pushRenderQueue(id: string, data: any, status: any): void; + + startQueueTimer(delayInSecond: number): void; + pauseRenderQueue(pause: boolean): void; + processRenderQueue(): void; +} diff --git a/src/types/iitc/core/ornaments.d.ts b/src/types/iitc/core/ornaments.d.ts new file mode 100755 index 000000000..afe1d9748 --- /dev/null +++ b/src/types/iitc/core/ornaments.d.ts @@ -0,0 +1,36 @@ +import { IITC } from "./iitctypes"; + +export {}; + +declare global { + /** + * Added as part of the Ingress #Helios in 2014, ornaments + * are additional image overlays for portals. + * + * currently there are 6 known types of ornaments: ap$x$suffix + * - cluster portals (without suffix) + * - volatile portals (_v) + * - meeting points (_start) + * - finish points (_end) + * + * Beacons and Frackers were introduced at the launch of the Ingress + * ingame store on November 1st, 2015 + * - Beacons (pe$TAG - $NAME) ie: 'peNIA - NIANTIC' + * - Frackers ('peFRACK') + * (there are 7 different colors for each of them) + */ + class Ornaments { + _portals: {}; + _layer: L.LayerGroup; + _beacons: L.LayerGroup; + _frackers: L.LayerGroup; + OVERLAY_SIZE: number; // 60, + OVERLAY_OPACITY: number; // 0.6, + + setup(): void; + addPortal(portal: IITC.Portal): void; + removePortal(portal: IITC.Portal): void; + } + + const ornaments: Ornaments; +} diff --git a/src/types/iitc/core/panes.d.ts b/src/types/iitc/core/panes.d.ts new file mode 100755 index 000000000..127b598fb --- /dev/null +++ b/src/types/iitc/core/panes.d.ts @@ -0,0 +1,8 @@ +export {}; + +declare global { + var currentPane: string; + + function show(id: string): void; + function hideall(): void; +} diff --git a/src/types/iitc/core/player_names.d.ts b/src/types/iitc/core/player_names.d.ts new file mode 100755 index 000000000..b2317402c --- /dev/null +++ b/src/types/iitc/core/player_names.d.ts @@ -0,0 +1,8 @@ +export {}; + +declare global { + /** + * test to see if a specific player GUID is a special system account (e.g. __JARVIS__, __ADA__) that shouldn't be listed as a player + */ + function isSystemPlayer(name: string): boolean; +} diff --git a/src/types/iitc/core/portal_data.d.ts b/src/types/iitc/core/portal_data.d.ts new file mode 100755 index 000000000..76857b6b7 --- /dev/null +++ b/src/types/iitc/core/portal_data.d.ts @@ -0,0 +1,61 @@ +import { FieldGUID, LinkGUID, PortalGUID } from "./iitctypes"; +export {}; + +declare global { + /** + * Get Links of portal + * search through the links data for all that link from or to a portal. returns an object with separate lists of in + * and out links. may or may not be as accurate as the portal details, depending on how much data the API returns + */ + function getPortalLinks(guid: PortalGUID): { + in: LinkGUID[]; + out: LinkGUID[]; + }; + function getPortalLinksCount(guid: PortalGUID): number; + + /** + * Get Fields of portal + * search through the fields for all that reference a portal + */ + function getPortalFields(guid: PortalGUID): FieldGUID[]; + function getPortalFields(guid: PortalGUID): number; + + /** + * find the lat/lon for a portal, using any and all available data + * (we have the list of portals, the cached portal details, plus links and fields as sources of portal locations) + */ + function findPortalLatLng(guid: PortalGUID): L.LatLng | undefined; + + /** find guid by position E6 */ + function findPortalGuidByPositionE6( + latE6: number, + lngE6: number + ): PortalGUID | null; + function pushPortalGuidPositionCache( + guid: PortalGUID, + latE6: number, + lngE6: number + ): void; + + /** + * get the AP gains from a portal, based only on the brief summary data from portals, links and fields + * not entirely accurate - but available for all portals on the screen + */ + function getPortalApGain(guid: PortalGUID): number | undefined; + + /** + * given counts of resonators, links and fields, calculate the available AP + * doesn't take account AP for resonator upgrades or AP for adding mods + */ + function portalApGainMaths( + resCount: number, + linkCount: number, + fieldCount: number + ): { + friendlyAp: number; + enemyAp: number; + destroyAp: number; + destroyResoAp: number; + captureAp: number; + }; +} diff --git a/src/types/iitc/core/portal_detail.d.ts b/src/types/iitc/core/portal_detail.d.ts new file mode 100755 index 000000000..af0710095 --- /dev/null +++ b/src/types/iitc/core/portal_detail.d.ts @@ -0,0 +1,23 @@ +import { IITC } from "./iitctypes"; + +export {}; + +declare global { + class PortalDetail { + setup(): void; + + /** Get portal detail from cache */ + get(guid: string): IITC.PortalDataDetail | undefined; + + /** Get portal detail from cache */ + isFresh(guid: string): boolean | undefined; + + /** + * Request Portal details from server + * NB: you shouldn't use it. + */ + request(guid: string): JQuery.Promise; + } + + var portalDetail: PortalDetail; +} diff --git a/src/types/iitc/core/portal_detail_display.d.ts b/src/types/iitc/core/portal_detail_display.d.ts new file mode 100755 index 000000000..c0170e59c --- /dev/null +++ b/src/types/iitc/core/portal_detail_display.d.ts @@ -0,0 +1,26 @@ +import { IITC, PortalGUID } from "./iitctypes"; + +export {}; + +declare global { + function resetScrollOnNewPortal(): void; + + function renderPortalDetails(guid: PortalGUID): void; + function getPortalMiscDetails( + guid: PortalGUID, + details?: IITC.PortalDataDetail + ): string; + + /** + * draws link-range and hack-range circles around the portal with the + * given details. Clear them if parameter 'd' is null. + */ + function setPortalIndicators(p: IITC.Portal): void; + + /** + * highlights portal with given GUID. Automatically clears highlights + * on old selection. Returns false if the selected portal changed. + * @returns true if it's still the same portal that just needs an update. + */ + function selectPortal(guid: PortalGUID): boolean; +} diff --git a/src/types/iitc/core/portal_detail_display_tools.d.ts b/src/types/iitc/core/portal_detail_display_tools.d.ts new file mode 100755 index 000000000..9ec72598a --- /dev/null +++ b/src/types/iitc/core/portal_detail_display_tools.d.ts @@ -0,0 +1,57 @@ +import { IITC } from "./iitctypes"; + +export {}; + +declare global { + /** + * returns displayable text+link about portal range + */ + function getRangeText(d: IITC.PortalDataDetail): string[]; + + /** + * given portal details, returns html code to display mod details. + */ + function getModDetails(d: IITC.PortalDataDetail): string; + + function getEnergyText(d: IITC.PortalDataDetail): string[]; + + /** + * octant=slot: 0=E, 1=NE, 2=N, 3=NW, 4=W, 5=SW, 6=S, SE=7 + * resos in the display should be ordered like this: + * N NE Since the view is displayed in rows, they + * NW E need to be ordered like this: N NE NW E W SE SW S + * W SE i.e. 2 1 3 0 4 7 5 6 + * SW S + * note: as of 2014-05-23 update, this is not true for portals with empty slots! + */ + function getResonatorDetails(d: IITC.PortalDataDetail): string; + + /** + * helper function that renders the HTML for a given resonator. Does + * not work with raw details-hash. Needs digested infos instead: + * slot: which slot this resonator occupies. Starts with 0 (east) and + * rotates clockwise. So, last one is 7 (southeast). + */ + function renderResonatorDetails( + slot: number, + level: number, + nrg: string, + nick: string + ): string[]; + + /** + * calculate AP gain from destroying portal and then capturing it by deploying resonators + */ + function getAttackApGainText( + d: IITC.PortalDataDetail, + fieldCount: number, + linkCount: number + ): string[]; + + function getHackDetailsText(d: IITC.PortalDataDetail): string[]; + + function getMitigationText( + d: IITC.PortalDataDetail, + linkCount: number + ): string[]; +} diff --git a/src/types/iitc/core/portal_highlighter.d.ts b/src/types/iitc/core/portal_highlighter.d.ts new file mode 100755 index 000000000..a9597f5e6 --- /dev/null +++ b/src/types/iitc/core/portal_highlighter.d.ts @@ -0,0 +1,29 @@ +import { IITC } from "./iitctypes"; + +export {}; + +declare global { + interface Hightligher { + hightlight: (portal: IITC.Portal) => void; + } + + /** an object mapping highlighter names to the object containing callback functions */ + var _highlighters: { [name: string]: Hightligher } | null; + + /** the name of the current highlighter */ + var _current_highlighter: string; + + /** + * = "No Highlights" + */ + var _no_highlighter: string; + + function addPortalHighlighter(name: string, data: Hightligher): void; + + // (re)creates the highlighter dropdown list + function updatePortalHighlighterControl(): void; + function changePortalHighlights(name: string): void; + + function highlightPortal(p: IITC.Portal): void; + function resetHighlightedPortals(): void; +} diff --git a/src/types/iitc/core/portal_info.d.ts b/src/types/iitc/core/portal_info.d.ts new file mode 100755 index 000000000..f0084749d --- /dev/null +++ b/src/types/iitc/core/portal_info.d.ts @@ -0,0 +1,93 @@ +import { IITC } from "./iitctypes"; + +export {}; + +declare global { + /** + * returns a float. Displayed portal level is always rounded down from that value. + */ + function getPortalLevel(d: IITC.PortalDataDetail): number; + + function getTotalPortalEnergy(d: IITC.PortalDataDetail): number; + + /** + * @deprecated use getTotalPortalEnergy (just renamed) + */ + function getPortalEnergy(d: IITC.PortalDataDetail): number; + + function getCurrentPortalEnergy(d: IITC.PortalDataDetail): number; + + /** + * formula by the great gals and guys at + * @link http://decodeingress.me/2012/11/18/ingress-portal-levels-and-link-range/ + */ + function getPortalRange(d: IITC.PortalDataDetail): number; + + /** additional range boost calculation */ + function getLinkAmpRangeBoost(d: IITC.PortalDataDetail): number; + + function getAttackApGain( + d: IITC.PortalDataDetail, + fieldCount: number, + linkCount: number + ): { + friendlyAp: number; + deployCount: number; + upgradeCount: number; + enemyAp: number; + destroyAp: number; + resoAp: number; + captureAp: number; + }; + + /** This function will return the potential level a player can upgrade it to */ + function potentialPortalLevel(d: IITC.PortalDataDetail): number; + + function fixPortalImageUrl(url: string): string; + + function getPortalModsByType( + d: IITC.PortalDataDetail, + type: IITC.ModType + ): IITC.Mod[]; + + function getPortalShieldMitigation(d: IITC.PortalDataDetail): number; + function getPortalLinkDefenseBoost(d: IITC.PortalDataDetail): number; + function getPortalLinksMitigation(linkCount: number): number; + function getPortalMitigationDetails( + d: IITC.PortalDataDetail, + linkCount: number + ): { + shields: number; + links: number; + linkDefenseBoost: number; + excess: number; + }; + function getMaxOutgoingLinks(d: IITC.PortalDataDetail): number; + + function getPortalHackDetails(d: IITC.PortalDataDetail): { + cooldown: number; + hacks: number; + burnout: number; + }; + + /** + * given a detailed portal structure, return summary portal data, as seen in the map tile data + */ + function getPortalSummaryData(d: IITC.PortalDataDetail): { + level: number; + title: string; + image: string; + resCount: number; + latE6: number; + health: number; + team: number; + lngE6: number; + type: "portal"; + }; + + function getPortalAttackValues(d: IITC.PortalDataDetail): { + hit_bonus: number; + force_amplifier: number; + attack_frequency: number; + }; +} diff --git a/src/types/iitc/core/portal_marker.d.ts b/src/types/iitc/core/portal_marker.d.ts new file mode 100755 index 000000000..bb9fc4f2c --- /dev/null +++ b/src/types/iitc/core/portal_marker.d.ts @@ -0,0 +1,16 @@ +import { IITC } from "./iitctypes"; + +export {}; + +declare global { + function portalMarkerScale(): number; + + /** + * create a new marker. 'data' contain the IITC-specific entity data to be stored in the object options + */ + function createMarker(latlng: L.LatLng, data: IITC.PortalData): IITC.Portal; + + function setMarkerStyle(marker: IITC.Portal, selected: boolean): void; + + function getMarkerStyleOptions(details: IITC.PortalOptions): L.PathOptions; +} diff --git a/src/types/iitc/core/redeeming.d.ts b/src/types/iitc/core/redeeming.d.ts new file mode 100755 index 000000000..e7dfadd1a --- /dev/null +++ b/src/types/iitc/core/redeeming.d.ts @@ -0,0 +1,25 @@ +export {}; + +declare global { + interface ResultData { + other: string[]; + xm: string; + ap: string; + inventory: any; + } + var REDEEM_SHORT_NAMES: { [key: string]: string }; + + /** These are HTTP status codes returned by the redemption API. */ + var REDEEM_STATUSES: { [key: number]: string }; + + function handleRedeemResponse( + data: ResultData, + textStatus: any, + jqXHR: JQuery.jqXHR + ): void; + + function formatPasscodeLong(data: ResultData): void; + function formatPasscodeShort(data: ResultData): void; + + function setupRedeem(): void; +} diff --git a/src/types/iitc/core/region_scoreboard.d.ts b/src/types/iitc/core/region_scoreboard.d.ts new file mode 100755 index 000000000..460ae644c --- /dev/null +++ b/src/types/iitc/core/region_scoreboard.d.ts @@ -0,0 +1,15 @@ +export {}; + +declare global { + class RegionScoreboard_ { + HistoryChart: HistoryChart_; + setup(): void; + shwoDialog(): void; + } + + class HistoryChart_ { + create(_regionScore: RegionScoreboard_, logscale: boolean): void; + } + + var RegionScoreboard: RegionScoreboard_; +} diff --git a/src/types/iitc/core/request_handling.d.ts b/src/types/iitc/core/request_handling.d.ts new file mode 100755 index 000000000..0654b6e25 --- /dev/null +++ b/src/types/iitc/core/request_handling.d.ts @@ -0,0 +1,37 @@ +export {}; + +declare global { + var activeRequests: JQuery.jqXHR[]; + + /** failed data requests calls */ + var failedRequestCount: number; + + var statusTotalMapTiles: number; + var statusCachedMapTiles: number; + var statusSuccessMapTiles: number; + var statusStaleMapTiles: number; + var statusErrorMapTiles: number; + + class Requests { + add(ajax: JQuery.jqXHR): void; + remove(ajax: JQuery.jqXHR): void; + abort(): void; + + /** + * sets the timer for the next auto refresh. Ensures only one timeout + * is queued. May be given 'override' in milliseconds if time should + * not be guessed automatically. Especially useful if a little delay + * is required, for example when zooming. + */ + startRefreshTimeout(override: number): void; + + /** + * add method here to be notified of auto-refreshes + */ + addRefreshFunction(fct: () => void): void; + + isLastRequest(ajax: JQuery.jqXHR): boolean; + } + + var requests: Requests; +} diff --git a/src/types/iitc/core/search.d.ts b/src/types/iitc/core/search.d.ts new file mode 100755 index 000000000..b2f55a1b1 --- /dev/null +++ b/src/types/iitc/core/search.d.ts @@ -0,0 +1,72 @@ +export {}; + +declare global { + /** + * you can implement your own result provider by listing to the search @see hook: + * addHook('search', function(query: SearchQuery) {}); + */ + class SearchQuery { + /** the term for which the user has searched */ + term: string; + + /** + * indicating if the user has pressed enter after searching. You should not search online or + * do heavy processing unless the user has confirmed the search term + */ + confirmed: boolean; + + /** called to add a result to the query */ + addResult(result: SearchResult): void; + + private init(): void; + private show(): void; + private hide(): void; + private resultLayer(result: SearchResult): L.LayerGroup; + private onResultSelected(result: SearchResult, event: any): void; + private removeSelectedResult(): void; + private onResultHoverStart(result: SearchResult, event: any): void; + private removeHoverResult(): void; + private onResultHoverEnd(result: SearchResult, event: any): void; + } + + type SearchResult = SearchResultPosition | SearchResultBounds; + interface SearchResultPosition extends SearchResultBase { + position: L.LatLngExpression; + } + + interface SearchResultBounds extends SearchResultBase { + bounds: L.LatLngBoundsExpression; + } + + interface SearchResultBase { + /** Will be interpreted as HTML, so make sure to escape properly. */ + title: string; + /** secondary information for this result.Will be interpreted as HTML, so make sure to escape properly. */ + description: JQuery | any[] | Element | Text | string; + /** a ILayer to be added to the map when the user selects this search result. Will be generated if not set. Set to `null` to prevent the result from being added to the map. */ + layer?: L.Layer | undefined; + /** a URL to a icon to display in the result list. Should be 12x12. */ + icon?: string | undefined; + /** + * a handler to be called when the result is selected. May return `true` to prevent the map from being repositioned. + * You may reposition the map yourself or do other work. + */ + onSelected?: + | ((result: SearchResult, event: UIEvent) => boolean | undefined) + | undefined; + /** + * a handler to be called when the result is removed from the map(because another result has been + * selected or the search was cancelled by the user). + */ + onRemove?: ((result: SearchResult) => void) | undefined; + } + + class Search { + lastSearch: SearchQuery | null; + + doSearch(term: string, confirmed: boolean): void; + setup(): void; + } + + var search: Search; +} diff --git a/src/types/iitc/core/send_request.d.ts b/src/types/iitc/core/send_request.d.ts new file mode 100755 index 000000000..770ad839e --- /dev/null +++ b/src/types/iitc/core/send_request.d.ts @@ -0,0 +1,28 @@ +export {}; + +declare global { + /** + * posts AJAX request to Ingress API. + * @param action last part of the actual URL, the rpc/dashboard. is added automatically + * @param data JSON data to post. method will be derived automatically from action, but may + * be overridden. Expects to be given Hash. Strings are not supported. + * @param successCallback method to call on success. See jQuery API docs for available arguments: http://api.jquery.com/jQuery.ajax/ + * @param errorCallback see above. Additionally it is logged if the request failed. + */ + function postAjax( + action: string, + data: any, + successCallback: ( + data: any, + textStatus: string, + jqXHR: JQuery.jqXHR + ) => void, + errorCallback: ( + jqXHR: JQuery.jqXHR, + textStatus: string, + errorThrown: string + ) => void + ): any; + + function outOfDateUserPrompt(): void; +} diff --git a/src/types/iitc/core/smartphone.d.ts b/src/types/iitc/core/smartphone.d.ts new file mode 100755 index 000000000..ec70241be --- /dev/null +++ b/src/types/iitc/core/smartphone.d.ts @@ -0,0 +1,24 @@ +import { PortalGUID } from "./iitctypes"; + +export {}; + +declare global { + /** + * this check is also used in main.js. Note it should not detect + * tablets because their display is large enough to use the desktop version. + * + * The stock intel site allows forcing mobile/full sites with a vp=m or vp=f + * parameter - let's support the same. (stock only allows this for some + * browsers - e.g. android phone/tablet. let's allow it for all, but + * no promises it'll work right) + */ + function isSmartphone(): boolean; + + function runOnSmartphonesBeforeBoot(): void; + function runOnSmartphonesAfterBoot(): void; + + function smartphoneInfo(data: { selectedPortalGuid: PortalGUID }): void; + + function setAndroidPermalink(): void; + function useAndroidPanes(): boolean; +} diff --git a/src/types/iitc/core/utils_file.d.ts b/src/types/iitc/core/utils_file.d.ts new file mode 100755 index 000000000..649d8a619 --- /dev/null +++ b/src/types/iitc/core/utils_file.d.ts @@ -0,0 +1,11 @@ +export {}; + +declare global { + function saveAs(data: any, filename: string, dataType: string): void; + + /** + * Save data to file with given filename, using IITCm file chooser, or generic browser routine. + * `dataType` can be set to filter IITCm file chooser filetypes. + */ + function saveFile(data: string, filename?: string, dataType?: string): void; +} diff --git a/src/types/iitc/core/utils_misc.d.ts b/src/types/iitc/core/utils_misc.d.ts new file mode 100755 index 000000000..dcd76bd97 --- /dev/null +++ b/src/types/iitc/core/utils_misc.d.ts @@ -0,0 +1,146 @@ +import * as L from "leaflet"; + +declare global { + /** + * Show about dialog + * + * Plugins metadata come from 2 sources: + * - buildName, pluginId, dateTimeVersion: inserted in plugin body by build script + * (only standard plugins) + * - script.name/version/description: from GM_info object, passed to wrapper + * `script` may be not available if userscript manager does not provede GM_info + * (atm: IITC-Mobile for iOS) + */ + function aboutIITC(): void; + + function layerGroupLength(layerGroup: L.LayerGroup): number; + + /** retrieves parameter from the URL?query=string. */ + function getURLParam(param: string): string; + + /** + * read cookie by name. + * https://stackoverflow.com/a/5639455/1684530 by cwolves + */ + function readCookie(name: string): string; + + function writeCookie(name: string, val: string): void; + + function eraseCookie(name: string): void; + + /** + * certain values were stored in cookies, but we're better off using localStorage instead - make it easy to convert + */ + function convertCookieToLocalStorage(name: string): void; + + /** + * add thousand separators to given number. + * https://stackoverflow.com/a/1990590/1684530 by Doug Neiner. + */ + function digits(d: number | string): string; + + function zeroPad(num: number, pad: number): string; + + function unixTimeToString( + time?: string | number | Date, + full?: boolean + ): string; + + /** + * convert time to string + * converts a javascript time to a precise date and time (optionally with millisecond precision) + * formatted in ISO-style YYYY-MM-DD hh:mm:ss.mmm - but using local timezone + */ + function unixTimeToDateTimeString( + ticks: number | string | Date, + millisecond?: boolean + ): string; + + /** convert time to string */ + function unixTimeToHHmm(time: number | string | Date): string; + + /** format time difference */ + function formatInterval(seconds: number, maxTerms?: number): string; + + function rangeLinkClick(): void; + function showPortalPosLinks(lat: number, lng: number, name?: string): void; + + function isTouchDevice(): boolean; + + function androidCopy(text: string): boolean; + + function getCurrentZoomTileParameters(): any; // return getMapZoomTileParameters() + + /** returns number of pixels left to scroll down before reaching the bottom. */ + function scrollBottom(element: string | JQuery): number; + + function zoomToAndShowPortal(guid: string, latlng: L.LatLng): void; + + function selectPortalByLatLng( + lat: number | L.LatLng | [number, number], + lng?: number + ): void; + + /** + * escape a javascript string, so quotes and backslashes are escaped with a backslash + * (for strings passed as parameters to html onclick="..." for example) + */ + function escapeJavascriptString(str: string): string; + + /** escape special characters, such as tags */ + function escapeHtmlSpecialChars(str: string): string; + + function prettyEnergy(nrg: number): string; + + function uniqueArray(arr: any[]): any[]; + + function genFourColumnTable(blocks: any[]): string; + + /** converts given text with newlines (\n) and tabs (\t) to a HTML table automatically. */ + function convertTextToTableMagic(text: string): string; + + /** + * Given 3 sets of points in an array[3]{lat, lng} returns the area of the triangle + * NOTE: not geodesic area! + */ + function calcTriArea(p: [L.LatLng, L.LatLng, L.LatLng]): number; + + /** Update layerGroups display status to window.overlayStatus and localStorage 'ingress.intelmap.layergroupdisplayed' */ + function updateDisplayedLayerGroup(name: string, display: boolean): void; + + /** + * Read layerGroup status from window.overlayStatus if it was added to map, + * read from cookie if it has not added to map yet. + * @return 'defaultDisplay' if both overlayStatus and cookie didn't have the record + */ + function isLayerGroupDisplayed( + name: string, + defaultDisplay: boolean + ): boolean; + + function addLayerGroup( + name: string, + layerGroup: L.LayerGroup, + defaultDisplay?: boolean + ): void; + + function removeLayerGroup(layerGroup: L.LayerGroup): void; + + function clampLatLng(latlng: L.LatLng): L.LatLng; + + function clampLatLngBounds(bounds: L.LatLngBounds): L.LatLngBounds; + + /** + * Makes the permalink for the portal with specified latlng, possibly including current map view. + * Portal latlng can be omitted to create mapview-only permalink. + * @param option: + * - includeMapView: Boolean = null + * Use to add zoom level and latlng of current map center. + * - fullURL: Boolean = null + * Use to make absolute fully qualified URL (default: relative link). + */ + function makePermalink(latlng: L.LatLng, options?: {}): string; + + // TODO: String.prototype.capitalize = (): string; + // TODO: String.prototype.startsWith = (string): boolean; +} diff --git a/src/types/iitc/index.d.ts b/src/types/iitc/index.d.ts new file mode 100755 index 000000000..abe0215de --- /dev/null +++ b/src/types/iitc/index.d.ts @@ -0,0 +1,58 @@ +// Type definitions for IITC (Ingress Intel Total Conversation) 0.30 +// Project: https://github.com/IITC-CE/ingress-intel-total-conversion +// Definitions by: McBen +// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// Minimum TypeScript Version: 3.6 + +// generate docs: npx typedoc --mode file --includeDeclarations --excludeExternals core/ + +// dependencies FIXME: triggers error +// export * as L from "leaflet"; +import * as L from "leaflet"; +import "leafletExtentions"; + +import "spectrum"; + +// base +export * from "./core/main"; +export * from "./core/constants"; +export * from "./core/iitctypes"; +export * from "./core/inteltypes"; + +// direct file conversation +export * from "./core/android"; // from mobile +export * from "./core/artifact"; +export * from "./core/dialog"; +export * from "./core/hooks"; +export * from "./core/chat"; +export * from "./core/utils_misc"; +export * from "./core/data_cache"; +export * from "./core/map_data_request"; +export * from "./core/map_data_render"; +export * from "./core/map_data_debug"; +export * from "./core/player_names"; +export * from "./core/entity_info"; +export * from "./core/region_scoreboard"; +export * from "./core/map_data_calc_tools"; +export * from "./core/search"; +export * from "./core/game_status"; +export * from "./core/entity_decode"; +export * from "./core/portal_data"; +export * from "./core/portal_highlighter"; +export * from "./core/portal_detail"; +export * from "./core/portal_info"; +export * from "./core/send_request"; +export * from "./core/portal_marker"; +export * from "./core/portal_detail_display"; +export * from "./core/portal_detail_display_tools"; +export * from "./core/smartphone"; +export * from "./core/panes"; +export * from "./core/extract_niantic_parameters"; +export * from "./core/idle"; +export * from "./core/utils_file"; +export * from "./core/request_handling"; +export * from "./core/redeeming"; +export * from "./core/ornaments"; +export * from "./core/location"; +export * from "./core/boot"; +export * from "./core/constants"; diff --git a/src/types/iitc/package.json b/src/types/iitc/package.json new file mode 100755 index 000000000..259f31817 --- /dev/null +++ b/src/types/iitc/package.json @@ -0,0 +1,26 @@ +{ + "contributors": [ + { + "name": "McBen", + "url": "https://github.com/McBen" + } + ], + "dependencies": { + "@types/jquery": "*", + "@types/jqueryui": "*", + "@types/leaflet": "*", + "@types/spectrum": "*" + }, + "description": "TypeScript definitions for IITC (Ingress Intel Total Conversation)", + "homepage": "https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/iitc", + "license": "MIT", + "main": "", + "name": "iitc", + "repository": { + "type": "git", + "url": "git+https://github.com/DefinitelyTyped/DefinitelyTyped.git", + "directory": "types/iitc" + }, + "types": "index.d.ts", + "version": "0.30.2" +} \ No newline at end of file diff --git a/src/types/leafletExtentions/index.d.ts b/src/types/leafletExtentions/index.d.ts new file mode 100755 index 000000000..272eb58f3 --- /dev/null +++ b/src/types/leafletExtentions/index.d.ts @@ -0,0 +1,61 @@ +import * as L from "leaflet"; + +declare module "leaflet" { + // geodesic + function geodesicPolyline( + latlngs: LatLng[], + options?: PolylineOptions + ): GeodesicPolyline; + function geodesicPolygon( + latlngs: LatLng[], + options?: PolylineOptions + ): GeodesicPolygon; + + class GeodesicPolyline extends Polyline { + getLatLngs(): LatLng[]; + } + + // tslint:disable-next-line:no-empty-interface + class GeodesicPolygon extends GeodesicPolyline { } + + // tslint:disable-next-line:no-empty-interface + class GeodesicCircle extends Polyline { } + + interface Polyline { + initialize: typeof L.Polyline.prototype.constructor; + } + interface Marker { + initialize: typeof L.Marker.prototype.constructor; + } + interface LayerGroup { + initialize: typeof L.LayerGroup.prototype.constructor; + } + interface Layer { + _popup: Popup; + } + interface Popup { + _wrapper: HTMLDivElement; + } + + // extends PolynineOption to any prop + interface PolylineOptions { + /* guid: string */ + [propName: string]: any; + } + + interface LeafletEvent { + /* opID: string */ + /* background: boolean */ + [propName: string]: any; + } + + interface Marker { + update(): this; + } + + namespace DivIcon { + class ColoredSvg extends DivIcon { + constructor(color: string, options?: MarkerOptions); + } + } +} diff --git a/src/wrapper/afterWrapper.js b/src/wrapper/afterWrapper.js deleted file mode 100644 index 13a3eec1e..000000000 --- a/src/wrapper/afterWrapper.js +++ /dev/null @@ -1,19 +0,0 @@ -//wrapper end - -// inject code into site context -var script = document.createElement("script"); -var info = {}; -if (typeof GM_info !== "undefined" && GM_info && GM_info.script) { - info.script = { - version: GM_info.script.version, - name: GM_info.script.name, - description: GM_info.script.description, - }; -} - -script.appendChild( - document.createTextNode("(" + wrapper + ")(" + JSON.stringify(info) + ");") -); -(document.body || document.head || document.documentElement).appendChild( - script -); diff --git a/src/wrapper/pluginEnd.js b/src/wrapper/pluginEnd.js deleted file mode 100644 index 4585b7e52..000000000 --- a/src/wrapper/pluginEnd.js +++ /dev/null @@ -1,10 +0,0 @@ -// PLUGIN END ---------------------------------------------------------- -setup.info = plugin_info; //add the script info data to the function as a property -if (!window.bootPlugins) { - window.bootPlugins = []; -} -window.bootPlugins.push(setup); -// if IITC has already booted, immediately run the 'setup' function -if (window.iitcLoaded && typeof setup === "function") { - setup(); -} diff --git a/src/wrapper/pluginStart.js b/src/wrapper/pluginStart.js deleted file mode 100644 index e342c8a16..000000000 --- a/src/wrapper/pluginStart.js +++ /dev/null @@ -1,6 +0,0 @@ -// ensure plugin framework is there, even if iitc is not yet loaded -if (typeof window.plugin !== "function") { - window.plugin = function () {}; -} - -// PLUGIN START -------------------------------------------------------- diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 000000000..e37bdd922 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "outDir": "./built", + "sourceMap": true, + "target": "ES2020", + "moduleResolution": "node", + "importsNotUsedAsValues": "error", + "esModuleInterop": true, + "isolatedModules": true, + "strict": false, + "typeRoots": [ + "./src/types", + "node_modules/@types" + ], + "skipLibCheck": false, + "forceConsistentCasingInFileNames": true, + "downlevelIteration": true, + "allowJs": true, + "checkJs": false, + "allowUmdGlobalAccess": true, + "noUnusedLocals": true + }, + "include": [ + "src/**/*" + ], + "exclude": [ + "node_modules/*" + ] +} \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js index 1271d2b77..bdffafe58 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,21 +1,154 @@ const path = require("path"); -const outputPath = path.join(__dirname, "dist"); +const outputPath = path.join(__dirname, "releases"); +const ESLintPlugin = require("eslint-webpack-plugin"); +const childProcess = require("child_process"); -module.exports = { - mode: "production", +const { ConcatSource } = require("webpack-sources"); +const Compilation = require("webpack/lib/Compilation"); + +const wrapPrefix = ` +function wrapper(plugin_info) { + if (typeof window.plugin !== "function") { + window.plugin = function () {}; + } + + window.plugin.Wasabee = window.plugin.wasabee = {}; + window.plugin.wasabee.info = plugin_info.script; + + // Code injection + function setup () { +`; +const wrapSuffix = ` + window.plugin.wasabee.init(); + }; + + setup.info = plugin_info; //add the script info data to the function as a property + if (!window.bootPlugins) { + window.bootPlugins = []; + } + window.bootPlugins.push(setup); + // if IITC has already booted, immediately run the 'setup' function + if (window.iitcLoaded && typeof setup === "function") { + setup(); + } +} + +var script = document.createElement("script"); +var info = {}; +if (typeof GM_info !== "undefined" && GM_info && GM_info.script) { + info.script = { + version: GM_info.script.version, + name: GM_info.script.name, + description: GM_info.script.description, + }; +} + +script.appendChild( + document.createTextNode("(" + wrapper + ")(" + JSON.stringify(info) + ");") +); +(document.body || document.head || document.documentElement).appendChild( + script +); +`; + +class IITCScript { + constructor(options) { + this.options = options || {}; + this.header = ""; + this.header += "// ==UserScript==\n"; + const keys = [ + "id", + "name", + "namespace", + "version", + "updateURL", + "downloadURL", + "description", + "author", + "match", + "category", + "grant", + ]; + const meta = { + match: "https://intel.ingress.com/*", + grant: "none", + version: "", + }; + Object.assign(meta, options.meta); + meta.version = meta.version.replace( + "BUILDDATE", + new Date() + .toISOString() + .replace(/[^0-9]/g, "") + .slice(0, 14) + ); + keys.forEach((key) => { + Array.prototype.concat + .apply([], meta[key] && [meta[key]]) + .forEach((value) => { + if (value) this.header += `// @${key.padEnd(13)} ${value}\n`; + }); + }); + this.header += "// ==/UserScript==\n\n"; + } + + apply(compiler) { + compiler.hooks.compilation.tap("Userscript", (compilation) => { + compilation.hooks.processAssets.tap( + { + name: "Userscript", + stage: Compilation.PROCESS_ASSETS_STAGE_OPTIMIZE_INLINE, + }, + () => { + compilation.chunks.forEach((chunk) => { + chunk.files.forEach((file) => { + compilation.updateAsset( + file, + new ConcatSource( + this.header, + wrapPrefix, + compilation.assets[file], + wrapSuffix + ) + ); + }); + }); + if (this.options.withMeta) { + compilation.chunks.forEach((chunk) => { + chunk.files.forEach((file) => { + if (file.match(/user.js$/)) + compilation.emitAsset( + file.replace(/user.js$/, "meta.js"), + new ConcatSource(this.header), + { minimized: true } + ); + }); + }); + } + } + ); + }); + } +} + +const config = { entry: { - static: "./src/code/static.js", - init: "./src/code/init.js", + init: "./src/code/init.ts", }, output: { - path: outputPath, - filename: "[name]-bundle.js", + filename: "wasabee.user.js", }, resolve: { modules: ["node_modules"], + extensions: [".ts", ".js"], }, module: { rules: [ + { + test: /\.tsx?$/, + use: "ts-loader", + exclude: /node_modules/, + }, { test: /\.(png|gif|svg)$/, use: "url-loader", @@ -36,4 +169,49 @@ module.exports = { }, ], }, + plugins: [new ESLintPlugin({ fix: true })], +}; + +function getCommitShort() { + try { + const commit = childProcess + .execSync("git rev-parse --short HEAD") + .toString() + .trim(); + return commit; + } catch { + return null; + } +} + +module.exports = (env, argv) => { + const pluginConfig = require("./plugin.config.json"); + const meta = pluginConfig.headers.common; + const build = env.build; + if (build in pluginConfig.headers) + Object.assign(meta, pluginConfig.headers[build]); + switch (build) { + case "prod": + case "dev": + case "testing": + case "scot": + config.output.path = path.join(outputPath, build); + break; + case "pr": + meta.version += env.pr; + config.output.path = path.join(outputPath, "dev"); + default: + } + + if (build !== "prod") { + const commit = getCommitShort(); + if (commit) meta.version += `-${commit}`; + config.devtool = "eval-source-map"; + config.mode = "development"; + } else { + config.mode = "production"; + } + + config.plugins.push(new IITCScript({ meta: meta, withMeta: true })); + return config; };